@@ -17,7 +17,7 @@ use futures::{
1717} ;
1818use rand:: seq:: IteratorRandom ;
1919use tokio:: {
20- net,
20+ net:: UdpSocket ,
2121 sync:: { self , broadcast, mpsc, RwLock } ,
2222 task:: JoinSet ,
2323 time:: { self , Duration , Instant } ,
@@ -203,13 +203,76 @@ impl Client {
203203 pub async fn get_report (
204204 & mut self ,
205205 dm : & DerpMap ,
206- stun_conn4 : Option < Arc < net :: UdpSocket > > ,
207- stun_conn6 : Option < Arc < net :: UdpSocket > > ,
206+ stun_conn4 : Option < Arc < UdpSocket > > ,
207+ stun_conn6 : Option < Arc < UdpSocket > > ,
208208 ) -> Result < Arc < Report > > {
209- // TODO: consider if DerpMap should be made to easily clone? It is expensive right
210- // now.
209+ // If not given UdpSockets to send stun packets, create them.
210+ // TODO: Is failure really fatal?
211+ let stun_conn4 = match stun_conn4 {
212+ Some ( stun_conn4) => stun_conn4,
213+ None => {
214+ let addr = SocketAddr :: from ( ( Ipv4Addr :: UNSPECIFIED , 0 ) ) ;
215+ let sock = UdpSocket :: bind ( addr)
216+ . await
217+ . context ( "netcheck: failed to bind udp 0.0.0.0:0" ) ?;
218+ let sock = Arc :: new ( sock) ;
219+ self . spawn_udp_listener ( sock. clone ( ) , self . msg_sender . clone ( ) ) ;
220+ sock
221+ }
222+ } ;
223+ let stun_conn6 = match stun_conn6 {
224+ Some ( stun_conn6) => stun_conn6,
225+ None => {
226+ let addr = SocketAddr :: from ( ( Ipv6Addr :: UNSPECIFIED , 0 ) ) ;
227+ let sock = UdpSocket :: bind ( addr)
228+ . await
229+ . context ( "netcheck: failed to bind udp6 [::]:0" ) ?;
230+ let sock = Arc :: new ( sock) ;
231+ self . spawn_udp_listener ( sock. clone ( ) , self . msg_sender . clone ( ) ) ;
232+ sock
233+ }
234+ } ;
235+
236+ // TODO: consider if DerpMap should be made to easily clone? It seems expensive
237+ // right now.
211238 self . actor . run ( dm. clone ( ) , stun_conn4, stun_conn6) . await
212239 }
240+
241+ /// Spawns a tokio task reading stun packets from the UDP socket.
242+ fn spawn_udp_listener ( & self , sock : Arc < UdpSocket > , sender : mpsc:: Sender < ActorMessage > ) {
243+ tokio:: spawn ( async move {
244+ debug ! ( "udp stun socket listener started" ) ;
245+ // TODO: Can we do better for buffers here? Probably doesn't matter
246+ // much.
247+ let mut buf = vec ! [ 0u8 ; 64 << 10 ] ;
248+ loop {
249+ if let Err ( err) = Self :: recv_stun_socket ( & sock, & mut buf, & sender) . await {
250+ // TODO: handle socket closed nicely
251+ warn ! ( %err, "stun recv failed" ) ;
252+ break ;
253+ }
254+ }
255+ debug ! ( "udp stun socket listener stopped" ) ;
256+ } ) ;
257+ }
258+
259+ /// Receive STUN response from a UDP socket, pass it to the actor.
260+ async fn recv_stun_socket (
261+ sock : & UdpSocket ,
262+ buf : & mut [ u8 ] ,
263+ sender : & mpsc:: Sender < ActorMessage > ,
264+ ) -> Result < ( ) > {
265+ let ( count, mut from_addr) = sock
266+ . recv_from ( buf)
267+ . await
268+ . context ( "Error reading from stun socket" ) ?;
269+ let payload = & buf[ ..count] ;
270+ from_addr. set_ip ( to_canonical ( from_addr. ip ( ) ) ) ;
271+ sender
272+ . send ( ActorMessage :: StunPacket ( payload. to_vec ( ) , from_addr) )
273+ . await
274+ . context ( "actor stopped" )
275+ }
213276}
214277
215278async fn measure_https_latency ( _reg : & DerpRegion ) -> Result < ( Duration , IpAddr ) > {
@@ -435,9 +498,9 @@ struct ReportState {
435498 got_hair_stun : broadcast:: Receiver < SocketAddr > ,
436499 // notified on hair pin timeout
437500 hair_timeout : Arc < sync:: Notify > ,
438- pc4 : Option < Arc < net :: UdpSocket > > ,
439- pc6 : Option < Arc < net :: UdpSocket > > ,
440- pc4_hair : Arc < net :: UdpSocket > ,
501+ pc4 : Arc < UdpSocket > ,
502+ pc6 : Arc < UdpSocket > ,
503+ pc4_hair : Arc < UdpSocket > ,
441504 incremental : bool , // doing a lite, follow-up netcheck
442505 stop_probe : Arc < sync:: Notify > ,
443506 wait_port_map : wg:: AsyncWaitGroup ,
@@ -809,8 +872,8 @@ enum ProbeError {
809872async fn run_probe (
810873 report : Arc < RwLock < Report > > ,
811874 resolver : & TokioAsyncResolver ,
812- pc4 : Option < Arc < net :: UdpSocket > > ,
813- pc6 : Option < Arc < net :: UdpSocket > > ,
875+ pc4 : Arc < UdpSocket > ,
876+ pc6 : Arc < UdpSocket > ,
814877 node : DerpNode ,
815878 probe : Probe ,
816879 in_flight : sync:: mpsc:: Sender < Inflight > ,
@@ -850,33 +913,29 @@ async fn run_probe(
850913 Probe :: Ipv4 { .. } => {
851914 // TODO:
852915 // metricSTUNSend4.Add(1)
853- if let Some ( ref pc4) = pc4 {
854- let n = pc4. send_to ( & req, addr) . await ;
855- debug ! ( "sending probe IPV4: {:?} to {}" , n, addr) ;
856- // TODO: || neterror.TreatAsLostUDP(err)
857- if n. is_ok ( ) && n. unwrap ( ) == req. len ( ) {
858- result. ipv4_can_send = true ;
859-
860- let ( delay, addr) = r. await . map_err ( |e| ProbeError :: Transient ( e. into ( ) ) ) ?;
861- result. delay = Some ( delay) ;
862- result. addr = Some ( addr) ;
863- }
916+ let n = pc4. send_to ( & req, addr) . await ;
917+ debug ! ( "sending probe IPV4: {:?} to {}" , n, addr) ;
918+ // TODO: || neterror.TreatAsLostUDP(err)
919+ if n. is_ok ( ) && n. unwrap ( ) == req. len ( ) {
920+ result. ipv4_can_send = true ;
921+
922+ let ( delay, addr) = r. await . map_err ( |e| ProbeError :: Transient ( e. into ( ) ) ) ?;
923+ result. delay = Some ( delay) ;
924+ result. addr = Some ( addr) ;
864925 }
865926 }
866927 Probe :: Ipv6 { .. } => {
867- if let Some ( ref pc6) = pc6 {
868- // TODO:
869- // metricSTUNSend6.Add(1)
870- let n = pc6. send_to ( & req, addr) . await ;
871- debug ! ( "sending probe IPV6: {:?} to {}" , n, addr) ;
872- // TODO: || neterror.TreatAsLostUDP(err)
873- if n. is_ok ( ) && n. unwrap ( ) == req. len ( ) {
874- result. ipv6_can_send = true ;
875-
876- let ( delay, addr) = r. await . map_err ( |e| ProbeError :: Transient ( e. into ( ) ) ) ?;
877- result. delay = Some ( delay) ;
878- result. addr = Some ( addr) ;
879- }
928+ // TODO:
929+ // metricSTUNSend6.Add(1)
930+ let n = pc6. send_to ( & req, addr) . await ;
931+ debug ! ( "sending probe IPV6: {:?} to {}" , n, addr) ;
932+ // TODO: || neterror.TreatAsLostUDP(err)
933+ if n. is_ok ( ) && n. unwrap ( ) == req. len ( ) {
934+ result. ipv6_can_send = true ;
935+
936+ let ( delay, addr) = r. await . map_err ( |e| ProbeError :: Transient ( e. into ( ) ) ) ?;
937+ result. delay = Some ( delay) ;
938+ result. addr = Some ( addr) ;
880939 }
881940 }
882941 Probe :: Https { reg, .. } => {
@@ -1026,8 +1085,8 @@ impl Actor {
10261085 async fn run (
10271086 & mut self ,
10281087 dm : DerpMap ,
1029- stun_sock_v4 : Option < Arc < net :: UdpSocket > > ,
1030- stun_sock_v6 : Option < Arc < net :: UdpSocket > > ,
1088+ stun_sock_v4 : Arc < UdpSocket > ,
1089+ stun_sock_v6 : Arc < UdpSocket > ,
10311090 ) -> Result < Arc < Report > > {
10321091 let report_state = self
10331092 . create_report_state ( & dm, stun_sock_v4. clone ( ) , stun_sock_v6. clone ( ) )
@@ -1043,8 +1102,6 @@ impl Actor {
10431102 . await
10441103 } ) )
10451104 } ;
1046- let mut buf4 = vec ! [ 0u8 ; 64 << 10 ] ;
1047- let mut buf6 = vec ! [ 0u8 ; 64 << 10 ] ;
10481105 let mut in_flight = HashMap :: new ( ) ;
10491106
10501107 loop {
@@ -1059,20 +1116,6 @@ impl Actor {
10591116 self . receive_stun_packet( & mut in_flight, & pkt, source) . await ,
10601117 }
10611118 }
1062- res = maybe_pending( stun_sock_v4. as_ref( ) . map( |c| c. recv_from( & mut buf4) ) ) => {
1063- match res {
1064- Err ( err) => warn!( "failed to read ipv4: {:?}" , err) ,
1065- Ok ( ( n, addr) ) =>
1066- self . process_packet( & mut in_flight, & buf4[ ..n] , addr) . await ,
1067- }
1068- }
1069- res = maybe_pending( stun_sock_v6. as_ref( ) . map( |c| c. recv_from( & mut buf6) ) ) => {
1070- match res {
1071- Err ( err) => warn!( "failed to read ipv6: {:?}" , err) ,
1072- Ok ( ( n, addr) ) =>
1073- self . process_packet( & mut in_flight, & buf6[ ..n] , addr) . await ,
1074- }
1075- }
10761119 res = & mut running => {
10771120 match res {
10781121 Ok ( Ok ( ( report, dm) ) ) => {
@@ -1096,13 +1139,13 @@ impl Actor {
10961139 async fn create_report_state (
10971140 & mut self ,
10981141 dm : & DerpMap ,
1099- pc4 : Option < Arc < net :: UdpSocket > > ,
1100- pc6 : Option < Arc < net :: UdpSocket > > ,
1142+ pc4 : Arc < UdpSocket > ,
1143+ pc6 : Arc < UdpSocket > ,
11011144 ) -> Result < ReportState > {
11021145 let now = Instant :: now ( ) ;
11031146
11041147 // Create a UDP4 socket used for sending to our discovered IPv4 address.
1105- let pc4_hair = net :: UdpSocket :: bind ( "0.0.0.0:0" )
1148+ let pc4_hair = UdpSocket :: bind ( "0.0.0.0:0" )
11061149 . await
11071150 . context ( "udp4: failed to bind" ) ?;
11081151
@@ -1113,12 +1156,6 @@ impl Actor {
11131156
11141157 let got_hair_stun_r = self . got_hair_stun . subscribe ( ) ;
11151158 let if_state = interfaces:: State :: new ( ) . await ;
1116- let pc4 = Some ( self . init_stun_conn4 ( pc4) . await ?) ;
1117- let pc6 = if if_state. have_v6 {
1118- Some ( self . init_stun_conn6 ( pc6) . await ?)
1119- } else {
1120- None
1121- } ;
11221159 let mut do_full = self . reports . next_full
11231160 || now. duration_since ( self . reports . last_full ) > FULL_REPORT_INTERVAL ;
11241161
@@ -1161,34 +1198,6 @@ impl Actor {
11611198 } )
11621199 }
11631200
1164- async fn init_stun_conn4 (
1165- & self ,
1166- pc4 : Option < Arc < net:: UdpSocket > > ,
1167- ) -> Result < Arc < net:: UdpSocket > > {
1168- if let Some ( pc4) = pc4 {
1169- return Ok ( pc4) ;
1170- }
1171- let addr = SocketAddr :: from ( ( Ipv4Addr :: UNSPECIFIED , 0 ) ) ;
1172- let u4 = net:: UdpSocket :: bind ( addr)
1173- . await
1174- . with_context ( || format ! ( "udp4: failed to bind to: {}" , addr) ) ?;
1175- Ok ( Arc :: new ( u4) )
1176- }
1177-
1178- async fn init_stun_conn6 (
1179- & self ,
1180- pc6 : Option < Arc < net:: UdpSocket > > ,
1181- ) -> Result < Arc < net:: UdpSocket > > {
1182- if let Some ( pc6) = pc6 {
1183- return Ok ( pc6) ;
1184- }
1185- let addr = SocketAddr :: from ( ( Ipv6Addr :: UNSPECIFIED , 0 ) ) ;
1186- let u6 = net:: UdpSocket :: bind ( addr)
1187- . await
1188- . with_context ( || format ! ( "udp6: failed to bind to: {}" , addr) ) ?;
1189- Ok ( Arc :: new ( u6) )
1190- }
1191-
11921201 async fn receive_stun_packet (
11931202 & self ,
11941203 in_flight : & mut HashMap < stun:: TransactionId , Inflight > ,
@@ -1230,21 +1239,6 @@ impl Actor {
12301239 }
12311240 }
12321241
1233- /// Reads STUN packets from pc until there's an error. In either case, it closes `pc`.
1234- async fn process_packet (
1235- & self ,
1236- in_flight : & mut HashMap < stun:: TransactionId , Inflight > ,
1237- pkt : & [ u8 ] ,
1238- mut addr : SocketAddr ,
1239- ) {
1240- if !stun:: is ( pkt) {
1241- // ignore non stun packets
1242- return ;
1243- }
1244- addr. set_ip ( to_canonical ( addr. ip ( ) ) ) ;
1245- self . receive_stun_packet ( in_flight, pkt, addr) . await ;
1246- }
1247-
12481242 async fn finish_and_store_report ( & mut self , report : Report , dm : & DerpMap ) -> Arc < Report > {
12491243 let report = self . add_report_history_and_set_preferred_derp ( report) . await ;
12501244 self . log_concise_report ( & report, dm) . await ;
@@ -1401,7 +1395,7 @@ impl Actor {
14011395/// Test if IPv6 works at all, or if it's been hard disabled at the OS level.
14021396async fn os_has_ipv6 ( ) -> bool {
14031397 // TODO: use socket2 to specify binding to ipv6
1404- let udp = net :: UdpSocket :: bind ( "[::1]:0" ) . await ;
1398+ let udp = UdpSocket :: bind ( "[::1]:0" ) . await ;
14051399 udp. is_ok ( )
14061400}
14071401
@@ -1418,14 +1412,6 @@ async fn os_has_ipv6() -> bool {
14181412// metricHTTPSend = clientmetric.NewCounter("netcheck_https_measure")
14191413// )
14201414
1421- /// Resolves to pending if the future is `None`.
1422- async fn maybe_pending < T > ( maybe_fut : Option < impl Future < Output = T > > ) -> T {
1423- match maybe_fut {
1424- Some ( t) => t. await ,
1425- None => futures:: future:: pending ( ) . await ,
1426- }
1427- }
1428-
14291415/// Resolves to pending if the inner is `None`.
14301416#[ derive( Debug ) ]
14311417struct MaybeFuture < T > {
@@ -1554,7 +1540,7 @@ mod tests {
15541540 let local_addr = "127.0.0.1" ;
15551541 let bind_addr = "0.0.0.0" ;
15561542
1557- let server = net :: UdpSocket :: bind ( format ! ( "{bind_addr}:0" ) ) . await ?;
1543+ let server = UdpSocket :: bind ( format ! ( "{bind_addr}:0" ) ) . await ?;
15581544 let addr = server. local_addr ( ) ?;
15591545
15601546 let server_task = tokio:: task:: spawn ( async move {
@@ -1565,7 +1551,7 @@ mod tests {
15651551 server. send_to ( & buf[ ..n] , addr) . await . unwrap ( ) ;
15661552 } ) ;
15671553
1568- let client = net :: UdpSocket :: bind ( format ! ( "{bind_addr}:0" ) ) . await ?;
1554+ let client = UdpSocket :: bind ( format ! ( "{bind_addr}:0" ) ) . await ?;
15691555 let data = b"foobar" ;
15701556 println ! ( "client: send" ) ;
15711557 let server_addr = format ! ( "{local_addr}:{}" , addr. port( ) ) ;
0 commit comments