Skip to content

Commit 899df00

Browse files
authored
Simplify the idle timeout logic & don't short-circuit in handle_msg_send_datagram (#3678)
Intended for merging into #3676 - Makes `idle_timeout` always be a `time::Sleep` that is `.reset` once there is any activity. I find this much easier to reason about. - Fixes a bug where `handle_msg_send_datagram` short-circuits when sending on one path fails. Instead, it should *try* all paths, even if some of them fail.
1 parent 7c11665 commit 899df00

File tree

1 file changed

+28
-22
lines changed

1 file changed

+28
-22
lines changed

iroh/src/magicsock/remote_map/remote_state.rs

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ impl RemoteStateActor {
212212
/// discipline is needed to not turn pending for a long time.
213213
async fn run(mut self, mut inbox: GuardedReceiver<RemoteStateMessage>) {
214214
trace!("actor started");
215-
let idle_timeout = MaybeFuture::None;
216-
tokio::pin!(idle_timeout);
215+
let idle_timeout = time::sleep(ACTOR_MAX_IDLE_TIMEOUT);
216+
n0_future::pin!(idle_timeout);
217217
loop {
218218
let scheduled_path_open = match self.scheduled_open_path {
219219
Some(when) => MaybeFuture::Some(time::sleep_until(when)),
@@ -225,6 +225,11 @@ impl RemoteStateActor {
225225
None => MaybeFuture::None,
226226
};
227227
n0_future::pin!(scheduled_hp);
228+
if !inbox.is_idle() || !self.connections.is_empty() {
229+
idle_timeout
230+
.as_mut()
231+
.reset(Instant::now() + ACTOR_MAX_IDLE_TIMEOUT);
232+
}
228233
tokio::select! {
229234
biased;
230235
msg = inbox.recv() => {
@@ -264,20 +269,12 @@ impl RemoteStateActor {
264269
if self.connections.is_empty() && inbox.close_if_idle() {
265270
trace!("idle timeout expired and still idle: terminate actor");
266271
break;
272+
} else {
273+
// Seems like we weren't really idle, so we reset
274+
idle_timeout.as_mut().reset(Instant::now() + ACTOR_MAX_IDLE_TIMEOUT);
267275
}
268276
}
269277
}
270-
271-
let is_idle = self.connections.is_empty() && inbox.is_idle();
272-
if idle_timeout.is_none() && is_idle {
273-
trace!("start idle timeout");
274-
idle_timeout
275-
.as_mut()
276-
.set_future(time::sleep(ACTOR_MAX_IDLE_TIMEOUT));
277-
} else if idle_timeout.is_some() && !is_idle {
278-
trace!("abort idle timeout");
279-
idle_timeout.as_mut().set_none()
280-
}
281278
}
282279
trace!("actor terminating");
283280
}
@@ -290,9 +287,7 @@ impl RemoteStateActor {
290287
// trace!("handling message");
291288
match msg {
292289
RemoteStateMessage::SendDatagram(transmit) => {
293-
if let Err(err) = self.handle_msg_send_datagram(transmit).await {
294-
warn!("failed to send datagram: {err:#}");
295-
}
290+
self.handle_msg_send_datagram(transmit).await;
296291
}
297292
RemoteStateMessage::AddConnection(handle, tx) => {
298293
self.handle_msg_add_connection(handle, tx).await;
@@ -333,25 +328,36 @@ impl RemoteStateActor {
333328
}
334329

335330
/// Handles [`RemoteStateMessage::SendDatagram`].
336-
///
337-
/// Error returns are fatal and kill the actor.
338-
async fn handle_msg_send_datagram(&mut self, transmit: OwnedTransmit) -> n0_error::Result<()> {
331+
async fn handle_msg_send_datagram(&mut self, transmit: OwnedTransmit) {
332+
// Sending datagrams might fail, e.g. because we don't have the right transports set
333+
// up to handle sending this owned transmit to.
334+
// After all, we try every single path that we know (relay URL, IP address), even
335+
// though we might not have a relay transport or ip-capable transport set up.
336+
// So these errors must not be fatal for this actor (or even this operation).
337+
339338
if let Some(addr) = self.selected_path.get() {
340339
trace!(?addr, "sending datagram to selected path");
341-
self.send_datagram(addr, transmit).await?;
340+
341+
if let Err(err) = self.send_datagram(addr.clone(), transmit).await {
342+
debug!(?addr, "failed to send datagram on selected_path: {err:#}");
343+
}
342344
} else {
343345
trace!(
344346
paths = ?self.paths.keys().collect::<Vec<_>>(),
345347
"sending datagram to all known paths",
346348
);
349+
if self.paths.is_empty() {
350+
warn!("Cannot send datagrams: No paths to remote endpoint known");
351+
}
347352
for addr in self.paths.keys() {
348-
self.send_datagram(addr.clone(), transmit.clone()).await?;
353+
if let Err(err) = self.send_datagram(addr.clone(), transmit.clone()).await {
354+
debug!(?addr, "failed to send datagram: {err:#}");
355+
}
349356
}
350357
// This message is received *before* a connection is added. So we do
351358
// not yet have a connection to holepunch. Instead we trigger
352359
// holepunching when AddConnection is received.
353360
}
354-
Ok(())
355361
}
356362

357363
/// Handles [`RemoteStateMessage::AddConnection`].

0 commit comments

Comments
 (0)