1
- use std:: { future:: Future , marker:: PhantomData , ops :: ControlFlow , pin:: Pin , sync:: Arc } ;
1
+ use std:: { future:: Future , marker:: PhantomData , pin:: Pin , sync:: Arc } ;
2
2
3
3
use ntp_proto:: {
4
4
IgnoreReason , NtpClock , NtpHeader , NtpInstant , NtpTimestamp , Peer , PeerSnapshot , ReferenceId ,
@@ -47,6 +47,8 @@ impl ResetEpoch {
47
47
pub enum MsgForSystem {
48
48
/// Received a Kiss-o'-Death and must demobilize
49
49
MustDemobilize ( PeerIndex ) ,
50
+ /// Experienced a network issue and must be restarted
51
+ NetworkIssue ( PeerIndex ) ,
50
52
/// Received an acceptable packet and made a new peer snapshot
51
53
/// A new measurement should try to trigger a clock select
52
54
NewMeasurement ( PeerIndex , ResetEpoch , PeerSnapshot ) ,
@@ -100,6 +102,18 @@ pub(crate) struct PeerTask<C: 'static + NtpClock + Send, T: Wait> {
100
102
reset_epoch : ResetEpoch ,
101
103
}
102
104
105
+ #[ derive( Debug ) ]
106
+ enum PollResult {
107
+ Ok ,
108
+ NetworkGone ,
109
+ }
110
+
111
+ #[ derive( Debug ) ]
112
+ enum PacketResult {
113
+ Ok ,
114
+ Demobilize ,
115
+ }
116
+
103
117
impl < C , T > PeerTask < C , T >
104
118
where
105
119
C : ' static + NtpClock + Send ,
@@ -120,7 +134,7 @@ where
120
134
. reset ( self . last_poll_sent + poll_interval) ;
121
135
}
122
136
123
- async fn handle_poll ( & mut self , poll_wait : & mut Pin < & mut T > ) {
137
+ async fn handle_poll ( & mut self , poll_wait : & mut Pin < & mut T > ) -> PollResult {
124
138
let system_snapshot = * self . channels . system_snapshots . read ( ) . await ;
125
139
let packet = self . peer . generate_poll_message ( system_snapshot) ;
126
140
@@ -145,7 +159,17 @@ where
145
159
146
160
if let Err ( error) = self . socket . send ( & packet. serialize ( ) ) . await {
147
161
warn ! ( ?error, "poll message could not be sent" ) ;
162
+
163
+ match error. raw_os_error ( ) {
164
+ Some ( libc:: EHOSTDOWN )
165
+ | Some ( libc:: EHOSTUNREACH )
166
+ | Some ( libc:: ENETDOWN )
167
+ | Some ( libc:: ENETUNREACH ) => return PollResult :: NetworkGone ,
168
+ _ => { }
169
+ }
148
170
}
171
+
172
+ PollResult :: Ok
149
173
}
150
174
151
175
async fn handle_packet (
@@ -154,7 +178,7 @@ where
154
178
packet : NtpHeader ,
155
179
send_timestamp : NtpTimestamp ,
156
180
recv_timestamp : NtpTimestamp ,
157
- ) -> ControlFlow < ( ) , ( ) > {
181
+ ) -> PacketResult {
158
182
let ntp_instant = NtpInstant :: now ( ) ;
159
183
160
184
let system_snapshot = * self . channels . system_snapshots . read ( ) . await ;
@@ -184,14 +208,14 @@ where
184
208
let msg = MsgForSystem :: MustDemobilize ( self . index ) ;
185
209
self . channels . msg_for_system_sender . send ( msg) . await . ok ( ) ;
186
210
187
- return ControlFlow :: Break ( ( ) ) ;
211
+ return PacketResult :: Demobilize ;
188
212
}
189
213
Err ( ignore_reason) => {
190
214
debug ! ( ?ignore_reason, "packet ignored" ) ;
191
215
}
192
216
}
193
217
194
- ControlFlow :: Continue ( ( ) )
218
+ PacketResult :: Ok
195
219
}
196
220
197
221
async fn run ( & mut self , mut poll_wait : Pin < & mut T > ) {
@@ -200,7 +224,13 @@ where
200
224
201
225
tokio:: select! {
202
226
( ) = & mut poll_wait => {
203
- self . handle_poll( & mut poll_wait) . await ;
227
+ match self . handle_poll( & mut poll_wait) . await {
228
+ PollResult :: Ok => { } ,
229
+ PollResult :: NetworkGone => {
230
+ self . channels. msg_for_system_sender. send( MsgForSystem :: NetworkIssue ( self . index) ) . await . ok( ) ;
231
+ break ;
232
+ }
233
+ }
204
234
} ,
205
235
result = self . channels. reset. changed( ) => {
206
236
if let Ok ( ( ) ) = result {
@@ -214,19 +244,26 @@ where
214
244
}
215
245
}
216
246
result = self . socket. recv( & mut buf) => {
217
- let send_timestamp = match self . last_send_timestamp {
218
- Some ( ts) => ts,
219
- None => {
220
- warn!( "we received a message without having sent one; discarding" ) ;
221
- continue ;
222
- }
223
- } ;
224
-
225
- if let Some ( ( packet, recv_timestamp) ) = accept_packet( result, & buf) {
226
- match self . handle_packet( & mut poll_wait, packet, send_timestamp, recv_timestamp) . await {
227
- ControlFlow :: Continue ( _) => continue ,
228
- ControlFlow :: Break ( _) => break ,
229
- }
247
+ match accept_packet( result, & buf) {
248
+ AcceptResult :: Accept ( packet, recv_timestamp) => {
249
+ let send_timestamp = match self . last_send_timestamp {
250
+ Some ( ts) => ts,
251
+ None => {
252
+ warn!( "we received a message without having sent one; discarding" ) ;
253
+ continue ;
254
+ }
255
+ } ;
256
+
257
+ match self . handle_packet( & mut poll_wait, packet, send_timestamp, recv_timestamp) . await {
258
+ PacketResult :: Ok => { } ,
259
+ PacketResult :: Demobilize => break ,
260
+ }
261
+ } ,
262
+ AcceptResult :: NetworkGone => {
263
+ self . channels. msg_for_system_sender. send( MsgForSystem :: NetworkIssue ( self . index) ) . await . ok( ) ;
264
+ break ;
265
+ } ,
266
+ AcceptResult :: Ignore => { } ,
230
267
}
231
268
} ,
232
269
}
@@ -239,17 +276,26 @@ where
239
276
C : ' static + NtpClock + Send ,
240
277
{
241
278
#[ instrument( skip( clock, channels) ) ]
242
- pub async fn spawn < A : ToSocketAddrs + std:: fmt:: Debug > (
279
+ pub fn spawn < A : ToSocketAddrs + std:: fmt:: Debug + Send + Sync + ' static > (
243
280
index : PeerIndex ,
244
281
addr : A ,
245
282
clock : C ,
283
+ network_wait_period : std:: time:: Duration ,
246
284
mut channels : PeerChannels ,
247
- ) -> std:: io:: Result < tokio:: task:: JoinHandle < ( ) > > {
248
- let socket = UdpSocket :: new ( "0.0.0.0:0" , addr) . await ?;
249
- let our_id = ReferenceId :: from_ip ( socket. as_ref ( ) . local_addr ( ) . unwrap ( ) . ip ( ) ) ;
250
- let peer_id = ReferenceId :: from_ip ( socket. as_ref ( ) . peer_addr ( ) . unwrap ( ) . ip ( ) ) ;
285
+ ) -> tokio:: task:: JoinHandle < ( ) > {
286
+ tokio:: spawn ( async move {
287
+ let socket = loop {
288
+ match UdpSocket :: new ( "0.0.0.0:0" , & addr) . await {
289
+ Ok ( socket) => break socket,
290
+ Err ( error) => {
291
+ warn ! ( ?error, "Could not open socket" ) ;
292
+ tokio:: time:: sleep ( network_wait_period) . await ;
293
+ }
294
+ }
295
+ } ;
296
+ let our_id = ReferenceId :: from_ip ( socket. as_ref ( ) . local_addr ( ) . unwrap ( ) . ip ( ) ) ;
297
+ let peer_id = ReferenceId :: from_ip ( socket. as_ref ( ) . peer_addr ( ) . unwrap ( ) . ip ( ) ) ;
251
298
252
- let handle = tokio:: spawn ( async move {
253
299
let local_clock_time = NtpInstant :: now ( ) ;
254
300
let peer = Peer :: new ( our_id, peer_id, local_clock_time) ;
255
301
@@ -273,16 +319,21 @@ where
273
319
} ;
274
320
275
321
process. run ( poll_wait) . await
276
- } ) ;
277
-
278
- Ok ( handle)
322
+ } )
279
323
}
280
324
}
281
325
326
+ #[ derive( Debug ) ]
327
+ enum AcceptResult {
328
+ Accept ( NtpHeader , NtpTimestamp ) ,
329
+ Ignore ,
330
+ NetworkGone ,
331
+ }
332
+
282
333
fn accept_packet (
283
334
result : Result < ( usize , Option < NtpTimestamp > ) , std:: io:: Error > ,
284
335
buf : & [ u8 ; 48 ] ,
285
- ) -> Option < ( NtpHeader , NtpTimestamp ) > {
336
+ ) -> AcceptResult {
286
337
match result {
287
338
Ok ( ( size, Some ( recv_timestamp) ) ) => {
288
339
// Note: packets are allowed to be bigger when including extensions.
@@ -292,26 +343,32 @@ fn accept_packet(
292
343
if size < 48 {
293
344
warn ! ( expected = 48 , actual = size, "received packet is too small" ) ;
294
345
295
- None
346
+ AcceptResult :: Ignore
296
347
} else {
297
348
match NtpHeader :: deserialize ( buf) {
298
- Ok ( packet) => Some ( ( packet, recv_timestamp) ) ,
349
+ Ok ( packet) => AcceptResult :: Accept ( packet, recv_timestamp) ,
299
350
Err ( e) => {
300
351
warn ! ( "received invalid packet: {}" , e) ;
301
- None
352
+ AcceptResult :: Ignore
302
353
}
303
354
}
304
355
}
305
356
}
306
357
Ok ( ( size, None ) ) => {
307
358
warn ! ( ?size, "received a packet without a timestamp" ) ;
308
359
309
- None
360
+ AcceptResult :: Ignore
310
361
}
311
362
Err ( receive_error) => {
312
363
warn ! ( ?receive_error, "could not receive packet" ) ;
313
364
314
- None
365
+ match receive_error. raw_os_error ( ) {
366
+ Some ( libc:: EHOSTDOWN )
367
+ | Some ( libc:: EHOSTUNREACH )
368
+ | Some ( libc:: ENETDOWN )
369
+ | Some ( libc:: ENETUNREACH ) => AcceptResult :: NetworkGone ,
370
+ _ => AcceptResult :: Ignore ,
371
+ }
315
372
}
316
373
}
317
374
}
@@ -502,15 +559,14 @@ mod tests {
502
559
PeerIndex :: from_inner ( 0 ) ,
503
560
"127.0.0.1:8003" ,
504
561
TestClock { } ,
562
+ std:: time:: Duration :: from_secs ( 60 ) ,
505
563
PeerChannels {
506
564
msg_for_system_sender,
507
565
system_snapshots,
508
566
system_config,
509
567
reset,
510
568
} ,
511
- )
512
- . await
513
- . unwrap ( ) ;
569
+ ) ;
514
570
515
571
let peer_epoch = match msg_for_system_receiver. recv ( ) . await . unwrap ( ) {
516
572
MsgForSystem :: UpdatedSnapshot ( _, peer_epoch, _) => peer_epoch,
0 commit comments