@@ -36,7 +36,7 @@ use futures_util::stream::BoxStream;
36
36
use iroh_base:: key:: NodeId ;
37
37
use iroh_metrics:: { inc, inc_by} ;
38
38
use iroh_relay:: protos:: stun;
39
- use netwatch:: { interfaces, ip:: LocalAddresses , netmon} ;
39
+ use netwatch:: { interfaces, ip:: LocalAddresses , netmon, UdpSocket } ;
40
40
use quinn:: AsyncUdpSocket ;
41
41
use rand:: { seq:: SliceRandom , Rng , SeedableRng } ;
42
42
use smallvec:: { smallvec, SmallVec } ;
@@ -441,11 +441,8 @@ impl MagicSock {
441
441
// Right now however we have one single poller behaving the same for each
442
442
// connection. It checks all paths and returns Poll::Ready as soon as any path is
443
443
// ready.
444
- let ipv4_poller = Arc :: new ( self . pconn4 . clone ( ) ) . create_io_poller ( ) ;
445
- let ipv6_poller = self
446
- . pconn6
447
- . as_ref ( )
448
- . map ( |sock| Arc :: new ( sock. clone ( ) ) . create_io_poller ( ) ) ;
444
+ let ipv4_poller = self . pconn4 . create_io_poller ( ) ;
445
+ let ipv6_poller = self . pconn6 . as_ref ( ) . map ( |sock| sock. create_io_poller ( ) ) ;
449
446
let relay_sender = self . relay_actor_sender . clone ( ) ;
450
447
Box :: pin ( IoPoller {
451
448
ipv4_poller,
@@ -1091,10 +1088,9 @@ impl MagicSock {
1091
1088
Err ( err) if err. kind ( ) == io:: ErrorKind :: WouldBlock => {
1092
1089
// This is the socket .try_send_disco_message_udp used.
1093
1090
let sock = self . conn_for_addr ( dst) ?;
1094
- let sock = Arc :: new ( sock. clone ( ) ) ;
1095
- let mut poller = sock. create_io_poller ( ) ;
1096
- match poller. as_mut ( ) . poll_writable ( cx) ? {
1097
- Poll :: Ready ( ( ) ) => continue ,
1091
+ match sock. as_socket_ref ( ) . poll_writable ( cx) {
1092
+ Poll :: Ready ( Ok ( ( ) ) ) => continue ,
1093
+ Poll :: Ready ( Err ( err) ) => return Poll :: Ready ( Err ( err) ) ,
1098
1094
Poll :: Pending => return Poll :: Pending ,
1099
1095
}
1100
1096
}
@@ -1408,6 +1404,9 @@ impl Handle {
1408
1404
let net_reporter =
1409
1405
net_report:: Client :: new ( Some ( port_mapper. clone ( ) ) , dns_resolver. clone ( ) ) ?;
1410
1406
1407
+ let pconn4_sock = pconn4. as_socket ( ) ;
1408
+ let pconn6_sock = pconn6. as_ref ( ) . map ( |p| p. as_socket ( ) ) ;
1409
+
1411
1410
let ( actor_sender, actor_receiver) = mpsc:: channel ( 256 ) ;
1412
1411
let ( relay_actor_sender, relay_actor_receiver) = mpsc:: channel ( 256 ) ;
1413
1412
let ( udp_disco_sender, mut udp_disco_receiver) = mpsc:: channel ( 256 ) ;
@@ -1431,9 +1430,9 @@ impl Handle {
1431
1430
ipv6_reported : Arc :: new ( AtomicBool :: new ( false ) ) ,
1432
1431
relay_map,
1433
1432
my_relay : Default :: default ( ) ,
1434
- pconn4 : pconn4. clone ( ) ,
1435
- pconn6 : pconn6. clone ( ) ,
1436
1433
net_reporter : net_reporter. addr ( ) ,
1434
+ pconn4,
1435
+ pconn6,
1437
1436
disco_secrets : DiscoSecrets :: default ( ) ,
1438
1437
node_map,
1439
1438
relay_actor_sender : relay_actor_sender. clone ( ) ,
@@ -1481,8 +1480,8 @@ impl Handle {
1481
1480
periodic_re_stun_timer : new_re_stun_timer ( false ) ,
1482
1481
net_info_last : None ,
1483
1482
port_mapper,
1484
- pconn4,
1485
- pconn6,
1483
+ pconn4 : pconn4_sock ,
1484
+ pconn6 : pconn6_sock ,
1486
1485
no_v4_send : false ,
1487
1486
net_reporter,
1488
1487
network_monitor,
@@ -1720,8 +1719,8 @@ struct Actor {
1720
1719
net_info_last : Option < NetInfo > ,
1721
1720
1722
1721
// The underlying UDP sockets used to send/rcv packets.
1723
- pconn4 : UdpConn ,
1724
- pconn6 : Option < UdpConn > ,
1722
+ pconn4 : Arc < UdpSocket > ,
1723
+ pconn6 : Option < Arc < UdpSocket > > ,
1725
1724
1726
1725
/// The NAT-PMP/PCP/UPnP prober/client, for requesting port mappings from NAT devices.
1727
1726
port_mapper : portmapper:: Client ,
@@ -1861,6 +1860,14 @@ impl Actor {
1861
1860
debug ! ( "link change detected: major? {}" , is_major) ;
1862
1861
1863
1862
if is_major {
1863
+ if let Err ( err) = self . pconn4 . rebind ( ) {
1864
+ warn ! ( "failed to rebind Udp IPv4 socket: {:?}" , err) ;
1865
+ } ;
1866
+ if let Some ( ref pconn6) = self . pconn6 {
1867
+ if let Err ( err) = pconn6. rebind ( ) {
1868
+ warn ! ( "failed to rebind Udp IPv6 socket: {:?}" , err) ;
1869
+ } ;
1870
+ }
1864
1871
self . msock . dns_resolver . clear_cache ( ) ;
1865
1872
self . msock . re_stun ( "link-change-major" ) ;
1866
1873
self . close_stale_relay_connections ( ) . await ;
@@ -1893,14 +1900,6 @@ impl Actor {
1893
1900
self . port_mapper . deactivate ( ) ;
1894
1901
self . relay_actor_cancel_token . cancel ( ) ;
1895
1902
1896
- // Ignore errors from pconnN
1897
- // They will frequently have been closed already by a call to connBind.Close.
1898
- debug ! ( "stopping connections" ) ;
1899
- if let Some ( ref conn) = self . pconn6 {
1900
- conn. close ( ) . await . ok ( ) ;
1901
- }
1902
- self . pconn4 . close ( ) . await . ok ( ) ;
1903
-
1904
1903
debug ! ( "shutdown complete" ) ;
1905
1904
return true ;
1906
1905
}
@@ -2206,8 +2205,8 @@ impl Actor {
2206
2205
}
2207
2206
2208
2207
let relay_map = self . msock . relay_map . clone ( ) ;
2209
- let pconn4 = Some ( self . pconn4 . as_socket ( ) ) ;
2210
- let pconn6 = self . pconn6 . as_ref ( ) . map ( |p| p . as_socket ( ) ) ;
2208
+ let pconn4 = Some ( self . pconn4 . clone ( ) ) ;
2209
+ let pconn6 = self . pconn6 . clone ( ) ;
2211
2210
2212
2211
debug ! ( "requesting net_report report" ) ;
2213
2212
match self
@@ -3099,6 +3098,45 @@ mod tests {
3099
3098
Ok ( ( ) )
3100
3099
}
3101
3100
3101
+ #[ tokio:: test]
3102
+ async fn test_regression_network_change_rebind_wakes_connection_driver (
3103
+ ) -> testresult:: TestResult {
3104
+ let _ = iroh_test:: logging:: setup ( ) ;
3105
+ let m1 = MagicStack :: new ( RelayMode :: Disabled ) . await ?;
3106
+ let m2 = MagicStack :: new ( RelayMode :: Disabled ) . await ?;
3107
+
3108
+ println ! ( "Net change" ) ;
3109
+ m1. endpoint . magic_sock ( ) . force_network_change ( true ) . await ;
3110
+ tokio:: time:: sleep ( Duration :: from_secs ( 1 ) ) . await ; // wait for socket rebinding
3111
+
3112
+ let _guard = mesh_stacks ( vec ! [ m1. clone( ) , m2. clone( ) ] ) . await ?;
3113
+
3114
+ let _handle = AbortOnDropHandle :: new ( tokio:: spawn ( {
3115
+ let endpoint = m2. endpoint . clone ( ) ;
3116
+ async move {
3117
+ while let Some ( incoming) = endpoint. accept ( ) . await {
3118
+ println ! ( "Incoming first conn!" ) ;
3119
+ let conn = incoming. await ?;
3120
+ conn. closed ( ) . await ;
3121
+ }
3122
+
3123
+ testresult:: TestResult :: Ok ( ( ) )
3124
+ }
3125
+ } ) ) ;
3126
+
3127
+ println ! ( "first conn!" ) ;
3128
+ let conn = m1
3129
+ . endpoint
3130
+ . connect ( m2. endpoint . node_addr ( ) . await ?, ALPN )
3131
+ . await ?;
3132
+ println ! ( "Closing first conn" ) ;
3133
+ conn. close ( 0u32 . into ( ) , b"bye lolz" ) ;
3134
+ conn. closed ( ) . await ;
3135
+ println ! ( "Closed first conn" ) ;
3136
+
3137
+ Ok ( ( ) )
3138
+ }
3139
+
3102
3140
#[ tokio:: test( flavor = "multi_thread" ) ]
3103
3141
async fn test_two_devices_roundtrip_network_change ( ) -> Result < ( ) > {
3104
3142
time:: timeout (
0 commit comments