@@ -56,7 +56,7 @@ pub use quinn::{
5656 ConnectionClose , ConnectionError , ConnectionStats , MtuDiscoveryConfig , OpenBi , OpenUni ,
5757 PathStats , ReadDatagram , ReadError , ReadExactError , ReadToEndError , RecvStream , ResetError ,
5858 RetryError , SendDatagramError , SendStream , ServerConfig , StoppedError , StreamId ,
59- TransportConfig , VarInt , WeakConnectionHandle , WriteError ,
59+ TransportConfig as QuinnTransportConfig , VarInt , WeakConnectionHandle , WriteError ,
6060} ;
6161pub use quinn_proto:: {
6262 FrameStats , TransportError , TransportErrorCode , UdpStats , Written ,
@@ -72,6 +72,7 @@ pub use self::connection::{
7272 Incoming , IncomingZeroRttConnection , OutgoingZeroRttConnection , RemoteEndpointIdError ,
7373 ZeroRttStatus ,
7474} ;
75+ pub use crate :: magicsock:: transports:: TransportConfig ;
7576
7677/// The delay to fall back to discovery when direct addresses fail.
7778///
@@ -101,7 +102,6 @@ pub enum PathSelection {
101102#[ derive( Debug ) ]
102103pub struct Builder {
103104 secret_key : Option < SecretKey > ,
104- relay_mode : RelayMode ,
105105 alpn_protocols : Vec < Vec < u8 > > ,
106106 transport_config : quinn:: TransportConfig ,
107107 keylog : bool ,
@@ -112,13 +112,27 @@ pub struct Builder {
112112 dns_resolver : Option < DnsResolver > ,
113113 #[ cfg( any( test, feature = "test-utils" ) ) ]
114114 insecure_skip_relay_cert_verify : bool ,
115- addr_v4 : Option < SocketAddrV4 > ,
116- addr_v6 : Option < SocketAddrV6 > ,
115+ transports : Vec < TransportConfig > ,
117116 #[ cfg( any( test, feature = "test-utils" ) ) ]
118117 path_selection : PathSelection ,
119118 max_tls_tickets : usize ,
120119}
121120
121+ impl From < RelayMode > for Option < TransportConfig > {
122+ fn from ( mode : RelayMode ) -> Self {
123+ match mode {
124+ RelayMode :: Disabled => None ,
125+ RelayMode :: Default => Some ( TransportConfig :: Relay {
126+ relay_map : mode. relay_map ( ) ,
127+ } ) ,
128+ RelayMode :: Staging => Some ( TransportConfig :: Relay {
129+ relay_map : mode. relay_map ( ) ,
130+ } ) ,
131+ RelayMode :: Custom ( relay_map) => Some ( TransportConfig :: Relay { relay_map } ) ,
132+ }
133+ }
134+ }
135+
122136impl Builder {
123137 // The ordering of public methods is reflected directly in the documentation. This is
124138 // roughly ordered by what is most commonly needed by users.
@@ -140,9 +154,18 @@ impl Builder {
140154 pub fn empty ( relay_mode : RelayMode ) -> Self {
141155 let mut transport_config = quinn:: TransportConfig :: default ( ) ;
142156 transport_config. keep_alive_interval ( Some ( Duration :: from_secs ( 1 ) ) ) ;
157+
158+ let mut transports = vec ! [
159+ #[ cfg( not( wasm_browser) ) ]
160+ TransportConfig :: default_ipv4( ) ,
161+ #[ cfg( not( wasm_browser) ) ]
162+ TransportConfig :: default_ipv6( ) ,
163+ ] ;
164+ if let Some ( relay) = relay_mode. into ( ) {
165+ transports. push ( relay) ;
166+ }
143167 Self {
144168 secret_key : Default :: default ( ) ,
145- relay_mode,
146169 alpn_protocols : Default :: default ( ) ,
147170 transport_config : quinn:: TransportConfig :: default ( ) ,
148171 keylog : Default :: default ( ) ,
@@ -153,11 +176,10 @@ impl Builder {
153176 dns_resolver : None ,
154177 #[ cfg( any( test, feature = "test-utils" ) ) ]
155178 insecure_skip_relay_cert_verify : false ,
156- addr_v4 : None ,
157- addr_v6 : None ,
158179 #[ cfg( any( test, feature = "test-utils" ) ) ]
159180 path_selection : PathSelection :: default ( ) ,
160181 max_tls_tickets : DEFAULT_MAX_TLS_TICKETS ,
182+ transports,
161183 }
162184 }
163185
@@ -166,7 +188,6 @@ impl Builder {
166188 /// Binds the magic endpoint.
167189 pub async fn bind ( mut self ) -> Result < Endpoint , BindError > {
168190 let mut rng = rand:: rng ( ) ;
169- let relay_map = self . relay_mode . relay_map ( ) ;
170191 let secret_key = self
171192 . secret_key
172193 . unwrap_or_else ( move || SecretKey :: generate ( & mut rng) ) ;
@@ -194,10 +215,8 @@ impl Builder {
194215 let metrics = EndpointMetrics :: default ( ) ;
195216
196217 let msock_opts = magicsock:: Options {
197- addr_v4 : self . addr_v4 ,
198- addr_v6 : self . addr_v6 ,
218+ transports : self . transports ,
199219 secret_key,
200- relay_map,
201220 discovery_user_data : self . discovery_user_data ,
202221 proxy_url : self . proxy_url ,
203222 #[ cfg( not( wasm_browser) ) ]
@@ -230,25 +249,46 @@ impl Builder {
230249
231250 // # The very common methods everyone basically needs.
232251
233- /// Sets the IPv4 bind address.
252+ /// Adds an IP transport, binding to the provided IPv4 address.
253+ ///
254+ /// If you want to remove the default transports, make sure to call `clear_ip` first.
234255 ///
235256 /// Setting the port to `0` will use a random port.
236257 /// If the port specified is already in use, it will fallback to choosing a random port.
237- ///
238- /// By default will use `0.0.0.0:0` to bind to.
239- pub fn bind_addr_v4 ( mut self , addr : SocketAddrV4 ) -> Self {
240- self . addr_v4 . replace ( addr) ;
258+ #[ cfg( not( wasm_browser) ) ]
259+ pub fn bind_addr_v4 ( mut self , bind_addr : SocketAddrV4 ) -> Self {
260+ self . transports . push ( TransportConfig :: Ip {
261+ bind_addr : bind_addr. into ( ) ,
262+ } ) ;
241263 self
242264 }
243265
244- /// Sets the IPv6 bind address.
266+ /// Adds an IP transport, binding to the provided IPv6 address.
267+ ///
268+ /// If you want to remove the default transports, make sure to call `clear_ip` first.
245269 ///
246270 /// Setting the port to `0` will use a random port.
247271 /// If the port specified is already in use, it will fallback to choosing a random port.
248- ///
249- /// By default will use `[::]:0` to bind to.
250- pub fn bind_addr_v6 ( mut self , addr : SocketAddrV6 ) -> Self {
251- self . addr_v6 . replace ( addr) ;
272+ #[ cfg( not( wasm_browser) ) ]
273+ pub fn bind_addr_v6 ( mut self , bind_addr : SocketAddrV6 ) -> Self {
274+ self . transports . push ( TransportConfig :: Ip {
275+ bind_addr : bind_addr. into ( ) ,
276+ } ) ;
277+ self
278+ }
279+
280+ /// Removes all IP based transports
281+ #[ cfg( not( wasm_browser) ) ]
282+ pub fn clear_ip_transports ( mut self ) -> Self {
283+ self . transports
284+ . retain ( |t| !matches ! ( t, TransportConfig :: Ip { .. } ) ) ;
285+ self
286+ }
287+
288+ /// Removes all relay based transports
289+ pub fn clear_relay_transports ( mut self ) -> Self {
290+ self . transports
291+ . retain ( |t| !matches ! ( t, TransportConfig :: Relay { .. } ) ) ;
252292 self
253293 }
254294
@@ -294,7 +334,24 @@ impl Builder {
294334 /// [crate docs]: crate
295335 /// [number 0]: https://n0.computer
296336 pub fn relay_mode ( mut self , relay_mode : RelayMode ) -> Self {
297- self . relay_mode = relay_mode;
337+ let transport: Option < _ > = relay_mode. into ( ) ;
338+ match transport {
339+ Some ( transport) => {
340+ if let Some ( og) = self
341+ . transports
342+ . iter_mut ( )
343+ . find ( |t| matches ! ( t, TransportConfig :: Relay { .. } ) )
344+ {
345+ * og = transport;
346+ } else {
347+ self . transports . push ( transport) ;
348+ }
349+ }
350+ None => {
351+ self . transports
352+ . retain ( |t| !matches ! ( t, TransportConfig :: Relay { .. } ) ) ;
353+ }
354+ }
298355 self
299356 }
300357
@@ -865,8 +922,6 @@ impl Endpoint {
865922 let endpoint_id = self . id ( ) ;
866923
867924 watch_addrs. or ( watch_relay) . map ( move |( addrs, relays) | {
868- debug_assert ! ( !addrs. is_empty( ) , "direct addresses must never be empty" ) ;
869-
870925 EndpointAddr :: from_parts (
871926 endpoint_id,
872927 relays
@@ -1252,7 +1307,7 @@ impl Endpoint {
12521307/// Options for the [`Endpoint::connect_with_opts`] function.
12531308#[ derive( Default , Debug , Clone ) ]
12541309pub struct ConnectOptions {
1255- transport_config : Option < Arc < TransportConfig > > ,
1310+ transport_config : Option < Arc < quinn :: TransportConfig > > ,
12561311 additional_alpns : Vec < Vec < u8 > > ,
12571312}
12581313
@@ -1266,7 +1321,7 @@ impl ConnectOptions {
12661321 }
12671322
12681323 /// Sets the QUIC transport config options for this connection.
1269- pub fn with_transport_config ( mut self , transport_config : Arc < TransportConfig > ) -> Self {
1324+ pub fn with_transport_config ( mut self , transport_config : Arc < quinn :: TransportConfig > ) -> Self {
12701325 self . transport_config = Some ( transport_config) ;
12711326 self
12721327 }
@@ -1340,6 +1395,7 @@ fn proxy_url_from_env() -> Option<Url> {
13401395#[ derive( Debug , Clone , PartialEq , Eq ) ]
13411396pub enum RelayMode {
13421397 /// Disable relay servers completely.
1398+ /// This means that neither listening nor dialing relays will be available.
13431399 Disabled ,
13441400 /// Use the default relay map, with production relay servers from n0.
13451401 ///
@@ -1837,6 +1893,103 @@ mod tests {
18371893 Ok ( ( ) )
18381894 }
18391895
1896+ #[ tokio:: test]
1897+ #[ traced_test]
1898+ async fn endpoint_two_relay_only_no_ip ( ) -> Result {
1899+ // Connect two endpoints on the same network, via a relay server, without
1900+ // discovery.
1901+ let ( relay_map, _relay_url, _relay_server_guard) = run_relay_server ( ) . await ?;
1902+ let ( node_addr_tx, node_addr_rx) = oneshot:: channel ( ) ;
1903+
1904+ #[ instrument( name = "client" , skip_all) ]
1905+ async fn connect (
1906+ relay_map : RelayMap ,
1907+ node_addr_rx : oneshot:: Receiver < EndpointAddr > ,
1908+ ) -> Result < quinn:: ConnectionError > {
1909+ let mut rng = rand_chacha:: ChaCha8Rng :: seed_from_u64 ( 0u64 ) ;
1910+ let secret = SecretKey :: generate ( & mut rng) ;
1911+ let ep = Endpoint :: builder ( )
1912+ . secret_key ( secret)
1913+ . alpns ( vec ! [ TEST_ALPN . to_vec( ) ] )
1914+ . insecure_skip_relay_cert_verify ( true )
1915+ . relay_mode ( RelayMode :: Custom ( relay_map) )
1916+ . clear_ip_transports ( ) // disable direct
1917+ . bind ( )
1918+ . await ?;
1919+ info ! ( me = %ep. id( ) . fmt_short( ) , "client starting" ) ;
1920+ let dst = node_addr_rx. await . anyerr ( ) ?;
1921+
1922+ info ! ( me = %ep. id( ) . fmt_short( ) , "client connecting" ) ;
1923+ let conn = ep. connect ( dst, TEST_ALPN ) . await ?;
1924+ let mut send = conn. open_uni ( ) . await . anyerr ( ) ?;
1925+ send. write_all ( b"hello" ) . await . anyerr ( ) ?;
1926+ let mut paths = conn. paths ( ) . stream ( ) ;
1927+ info ! ( "Waiting for connection" ) ;
1928+ ' outer: while let Some ( infos) = paths. next ( ) . await {
1929+ info ! ( ?infos, "new PathInfos" ) ;
1930+ for info in infos {
1931+ if info. is_ip ( ) {
1932+ panic ! ( "should not happen: {:?}" , info) ;
1933+ }
1934+ if info. is_relay ( ) {
1935+ break ' outer;
1936+ }
1937+ }
1938+ }
1939+ info ! ( "Have relay connection" ) ;
1940+ send. write_all ( b"close please" ) . await . anyerr ( ) ?;
1941+ send. finish ( ) . anyerr ( ) ?;
1942+ Ok ( conn. closed ( ) . await )
1943+ }
1944+
1945+ #[ instrument( name = "server" , skip_all) ]
1946+ async fn accept (
1947+ relay_map : RelayMap ,
1948+ node_addr_tx : oneshot:: Sender < EndpointAddr > ,
1949+ ) -> Result {
1950+ let mut rng = rand_chacha:: ChaCha8Rng :: seed_from_u64 ( 1u64 ) ;
1951+ let secret = SecretKey :: generate ( & mut rng) ;
1952+ let ep = Endpoint :: builder ( )
1953+ . secret_key ( secret)
1954+ . alpns ( vec ! [ TEST_ALPN . to_vec( ) ] )
1955+ . insecure_skip_relay_cert_verify ( true )
1956+ . relay_mode ( RelayMode :: Custom ( relay_map) )
1957+ . clear_ip_transports ( )
1958+ . bind ( )
1959+ . await ?;
1960+ ep. online ( ) . await ;
1961+ let node_addr = ep. addr ( ) ;
1962+ node_addr_tx. send ( node_addr) . unwrap ( ) ;
1963+
1964+ info ! ( me = %ep. id( ) . fmt_short( ) , "server starting" ) ;
1965+ let conn = ep. accept ( ) . await . anyerr ( ) ?. await . anyerr ( ) ?;
1966+ // let node_id = conn.remote_node_id()?;
1967+ // assert_eq!(node_id, src);
1968+ let mut recv = conn. accept_uni ( ) . await . anyerr ( ) ?;
1969+ let mut msg = [ 0u8 ; 5 ] ;
1970+ recv. read_exact ( & mut msg) . await . anyerr ( ) ?;
1971+ assert_eq ! ( & msg, b"hello" ) ;
1972+ info ! ( "received hello" ) ;
1973+ let msg = recv. read_to_end ( 100 ) . await . anyerr ( ) ?;
1974+ assert_eq ! ( msg, b"close please" ) ;
1975+ info ! ( "received 'close please'" ) ;
1976+ // Dropping the connection closes it just fine.
1977+ Ok ( ( ) )
1978+ }
1979+
1980+ let server_task = tokio:: spawn ( accept ( relay_map. clone ( ) , node_addr_tx) ) ;
1981+ let client_task = tokio:: spawn ( connect ( relay_map, node_addr_rx) ) ;
1982+
1983+ server_task. await . anyerr ( ) ??;
1984+ let conn_closed = dbg ! ( client_task. await . anyerr( ) ??) ;
1985+ assert ! ( matches!(
1986+ conn_closed,
1987+ ConnectionError :: ApplicationClosed ( quinn:: ApplicationClose { .. } )
1988+ ) ) ;
1989+
1990+ Ok ( ( ) )
1991+ }
1992+
18401993 #[ tokio:: test]
18411994 #[ traced_test]
18421995 async fn endpoint_two_direct_add_relay ( ) -> Result {
0 commit comments