Skip to content

Commit 3fc1276

Browse files
committed
Add UnboundUdpSocket in std::net to support UDP socket configurations before binding to an address. Once bound, the socket becomes a regular UdpSocket.
1 parent b8b5cae commit 3fc1276

File tree

11 files changed

+604
-61
lines changed

11 files changed

+604
-61
lines changed

library/std/src/net/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,22 @@ pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
2828
#[stable(feature = "rust1", since = "1.0.0")]
2929
pub use self::parser::AddrParseError;
3030
#[stable(feature = "rust1", since = "1.0.0")]
31-
pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
31+
pub use self::socket_addr::{
32+
SocketAddr, SocketAddrFamily, SocketAddrV4, SocketAddrV6, ToSocketAddrs,
33+
};
3234
#[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
3335
pub use self::tcp::IntoIncoming;
3436
#[stable(feature = "rust1", since = "1.0.0")]
3537
pub use self::tcp::{Incoming, TcpListener, TcpStream};
3638
#[stable(feature = "rust1", since = "1.0.0")]
3739
pub use self::udp::UdpSocket;
3840

41+
#[unstable(feature = "unbound_socket", issue = "none")]
42+
pub use self::udp::UnboundUdpSocket;
43+
3944
mod display_buffer;
4045
mod ip_addr;
46+
4147
mod parser;
4248
mod socket_addr;
4349
mod tcp;

library/std/src/net/socket_addr.rs

+20
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,15 @@ impl SocketAddr {
264264
pub const fn is_ipv6(&self) -> bool {
265265
matches!(*self, SocketAddr::V6(_))
266266
}
267+
268+
/// Returns the `SocketAddrFamily` value of this `SocketAddr`.
269+
#[unstable(feature = "unbound_socket", issue = "none")]
270+
pub const fn family(&self) -> SocketAddrFamily {
271+
match *self {
272+
SocketAddr::V4(..) => SocketAddrFamily::InetV4,
273+
SocketAddr::V6(..) => SocketAddrFamily::InetV6,
274+
}
275+
}
267276
}
268277

269278
impl SocketAddrV4 {
@@ -972,3 +981,14 @@ impl ToSocketAddrs for String {
972981
(&**self).to_socket_addrs()
973982
}
974983
}
984+
985+
/// Address family values for an Internet socket address.
986+
#[derive(Debug, Clone, Copy, PartialEq)]
987+
#[non_exhaustive]
988+
#[unstable(feature = "unbound_socket", issue = "none")]
989+
pub enum SocketAddrFamily {
990+
/// Address family of IPv4.
991+
InetV4,
992+
/// Address family of IPv6.
993+
InetV6,
994+
}

library/std/src/net/udp.rs

+98-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod tests;
33

44
use crate::fmt;
55
use crate::io::{self, ErrorKind};
6-
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
6+
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrFamily, ToSocketAddrs};
77
use crate::sys_common::net as net_imp;
88
use crate::sys_common::{AsInner, FromInner, IntoInner};
99
use crate::time::Duration;
@@ -811,3 +811,100 @@ impl fmt::Debug for UdpSocket {
811811
self.0.fmt(f)
812812
}
813813
}
814+
815+
/// A UDP Socket that is not bound to a `SocketAddr` yet.
816+
///
817+
/// This socket is designed to support socket configurations _before_
818+
/// binding to a `SocketAddr`. After configurations, this socket
819+
/// can be bound and translated into a [`UdpSocket`].
820+
///
821+
/// # Example
822+
///
823+
/// ```no_run
824+
/// #![feature(unbound_socket)]
825+
/// use std::net::{SocketAddr, SocketAddrFamily, UnboundUdpSocket};
826+
///
827+
/// fn main() -> std::io::Result<()> {
828+
/// let unbound_socket = UnboundUdpSocket::new(SocketAddrFamily::InetV4)?;
829+
/// unbound_socket.set_reuseaddr(true)?;
830+
/// let addr = SocketAddr::from(([127, 0, 0, 1], 5500));
831+
/// let _udp_socket = unbound_socket.bind(&addr)?;
832+
/// Ok(())
833+
/// }
834+
/// ```
835+
#[unstable(feature = "unbound_socket", issue = "none")]
836+
pub struct UnboundUdpSocket {
837+
inner: net_imp::UnboundUdpSocket,
838+
}
839+
840+
impl UnboundUdpSocket {
841+
/// Creates a new unbound UDP socket with `addr_family`.
842+
#[unstable(feature = "unbound_socket", issue = "none")]
843+
pub fn new(addr_family: SocketAddrFamily) -> io::Result<UnboundUdpSocket> {
844+
let inner = net_imp::UnboundUdpSocket::new(addr_family)?;
845+
Ok(Self { inner })
846+
}
847+
848+
/// Sets `SO_REUSEADDR` option for the socket.
849+
///
850+
/// In general, this option allows a second caller to bind to a `(addr, port)` again,
851+
/// where the `addr` could be the `unspecified` address. However it behaves with subtle
852+
/// differences on different platforms. Please be sure to check your platform for
853+
/// the exact expected behaviors.
854+
///
855+
/// This method can only be called before `bind`, otherwise will fail.
856+
#[unstable(feature = "unbound_socket", issue = "none")]
857+
pub fn set_reuseaddr(&self, enable: bool) -> io::Result<()> {
858+
self.inner.set_reuseaddr(enable)
859+
}
860+
861+
/// Sets `SO_REUSEPORT` option for the socket.
862+
///
863+
/// In general, this option allows a second caller to bind to a same `(addr, port)`
864+
/// pair again, if the first caller has enabled this option too. Please check with
865+
/// your specific platform for the details of the behavior.
866+
///
867+
/// This option is only available for UNIX-like platforms and not Windows platforms.
868+
#[unstable(feature = "unbound_socket", issue = "none")]
869+
pub fn set_reuseport(&self, enable: bool) -> io::Result<()> {
870+
self.inner.set_reuseport(enable)
871+
}
872+
873+
/// Sets `SO_EXCLUSIVEADDRUSE` option for the socket.
874+
///
875+
/// This option is only available in Windows. Its purpose is to prevent
876+
/// any other caller to "reuse" the same (addr, port), even if they call
877+
/// `set_reuseaddr(true)`. This method returns an error on non-Windows platforms.
878+
#[unstable(feature = "unbound_socket", issue = "none")]
879+
pub fn set_exclusiveaddruse(&self, enable: bool) -> io::Result<()> {
880+
self.inner.set_exclusiveaddruse(enable)
881+
}
882+
883+
/// Binds to `addr`, consumes this unbound socket and returns a [`UdpSocket`].
884+
#[unstable(feature = "unbound_socket", issue = "none")]
885+
pub fn bind(self, addr: &SocketAddr) -> io::Result<UdpSocket> {
886+
let net_imp = self.inner.bind(addr)?;
887+
Ok(UdpSocket(net_imp))
888+
}
889+
}
890+
891+
#[unstable(feature = "unbound_socket", issue = "none")]
892+
impl fmt::Debug for UnboundUdpSocket {
893+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
894+
self.inner.fmt(f)
895+
}
896+
}
897+
898+
#[unstable(feature = "unbound_socket", issue = "none")]
899+
impl AsInner<net_imp::UnboundUdpSocket> for UnboundUdpSocket {
900+
fn as_inner(&self) -> &net_imp::UnboundUdpSocket {
901+
&self.inner
902+
}
903+
}
904+
905+
#[unstable(feature = "unbound_socket", issue = "none")]
906+
impl IntoInner<net_imp::UnboundUdpSocket> for UnboundUdpSocket {
907+
fn into_inner(self) -> net_imp::UnboundUdpSocket {
908+
self.inner
909+
}
910+
}

0 commit comments

Comments
 (0)