From 7b0c11efb40eef5b172b30e61e512cef4f7d1e8b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 16 Jul 2022 14:19:30 +0930 Subject: [PATCH] connectd: don't let peer close take forever. Sending any pending messages to peer before hanging up is a courtesy: give it 5 seconds before simply closing. Signed-off-by: Rusty Russell --- connectd/multiplex.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/connectd/multiplex.c b/connectd/multiplex.c index f7fa7d0b3..9976c292b 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -81,19 +81,33 @@ static struct subd *find_subd(struct peer *peer, return NULL; } +/* We try to send the final messages, but if buffer is full and they're + * not reading, we have to give up. */ +static void close_timeout(struct peer *peer) +{ + /* BROKEN means we'll trigger CI if we see it, though it's possible */ + status_peer_broken(&peer->id, "Peer did not close, forcing close"); + tal_free(peer); +} + /* We just want to send these messages out to the peer's connection, * then close. We consider the peer dead to us (can be freed). */ static void drain_peer(struct peer *peer) { assert(!peer->draining); - /* FIXME: Don't drain forever! */ + /* This is a 5-second leak, worst case! */ notleak(peer); /* We no longer want subds feeding us more messages! */ peer->subds = tal_free(peer->subds); peer->draining = true; + /* You have 5 seconds to drain... */ + notleak(new_reltimer(&peer->daemon->timers, + peer, time_from_sec(5), + close_timeout, peer)); + /* Clean peer from hashtable; we no longer exist. */ destroy_peer(peer); tal_del_destructor(peer, destroy_peer); @@ -929,22 +943,6 @@ static void maybe_update_channelid(struct subd *subd, const u8 *msg) } } -static void close_timeout(struct peer *peer) -{ - /* BROKEN means we'll trigger CI if we see it, though it's possible */ - status_peer_broken(&peer->id, "Peer did not close, forcing close"); - tal_free(peer->to_peer); -} - -/* Close this in 5 seconds if it doesn't do so by itself. */ -static void set_closing_timer(struct peer *peer, - struct io_conn *peer_conn) -{ - notleak(new_reltimer(&peer->daemon->timers, - peer_conn, time_from_sec(5), - close_timeout, peer)); -} - static struct io_plan *write_to_peer(struct io_conn *peer_conn, struct peer *peer) { @@ -960,10 +958,8 @@ static struct io_plan *write_to_peer(struct io_conn *peer_conn, /* Still nothing to send? */ if (!msg) { /* Draining? We're done. */ - if (peer->draining) { - set_closing_timer(peer, peer_conn); + if (peer->draining) return io_sock_shutdown(peer_conn); - } /* If they want us to send gossip, do so now. */ msg = maybe_from_gossip_store(NULL, peer);