@@ -107,23 +107,37 @@ impl Endpoint {
107107
108108 /// Helper to construct an endpoint for use with both incoming and outgoing connections
109109 ///
110- /// Platform defaults for dual-stack sockets vary. For example, any socket bound to a wildcard
111- /// IPv6 address on Windows will not by default be able to communicate with IPv4
112- /// addresses. Portable applications should bind an address that matches the family they wish to
113- /// communicate within.
110+ /// Note that `addr` is the *local* address to bind to, which should usually be a wildcard
111+ /// address like `0.0.0.0:0` or `[::]:0`, which allow communication with any reachable IPv4 or
112+ /// IPv6 address respectively from an OS-assigned port.
113+ ///
114+ /// If an IPv6 address is provided, attempts to make the socket dual-stack so as to allow
115+ /// communication with both IPv4 and IPv6 clients. As such, calling `Endpoint::server` with
116+ /// the address `[::]:0` is a reasonable default to maximize the ability to accept connections
117+ /// from any address.
118+ ///
119+ /// Some environments may not allow creation of dual-stack sockets, in which case an IPv6
120+ /// server will only be able to accept connections from IPv6 clients. An IPv4 server is never
121+ /// dual-stack.
114122 #[ cfg( all(
115123 not( wasm_browser) ,
116124 any( feature = "runtime-tokio" , feature = "runtime-smol" ) ,
117125 any( feature = "aws-lc-rs" , feature = "ring" ) , // `EndpointConfig::default()` is only available with these
118126 ) ) ]
119127 pub fn server ( config : ServerConfig , addr : SocketAddr ) -> io:: Result < Self > {
120- let socket = std:: net:: UdpSocket :: bind ( addr) ?;
128+ let socket = Socket :: new ( Domain :: for_address ( addr) , Type :: DGRAM , Some ( Protocol :: UDP ) ) ?;
129+ if addr. is_ipv6 ( ) {
130+ if let Err ( e) = socket. set_only_v6 ( false ) {
131+ tracing:: debug!( %e, "unable to make socket dual-stack" ) ;
132+ }
133+ }
134+ socket. bind ( & addr. into ( ) ) ?;
121135 let runtime =
122136 default_runtime ( ) . ok_or_else ( || io:: Error :: other ( "no async runtime found" ) ) ?;
123137 Self :: new_with_abstract_socket (
124138 EndpointConfig :: default ( ) ,
125139 Some ( config) ,
126- runtime. wrap_udp_socket ( socket) ?,
140+ runtime. wrap_udp_socket ( socket. into ( ) ) ?,
127141 runtime,
128142 )
129143 }
0 commit comments