From b4ed954435b4a99d9018a22bfc14384a8dd65f0a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Jul 2018 15:48:58 +0930 Subject: [PATCH] connectd: do socket binding during initial setup. gossipd does a two-step initialization: it only tries to create the listening sockets when it's activated. This means it doesn't know the addresses to announce until this point. Now connectd is doing this, this would mean we'd have to tell gossipd later ("oh, BTW here are your addresses") since we need to start gossipd before connectd activation. So make connectd do all the setup, but only actually listen on the fds once we activate it. We clone the gossip_init message into connect_wire.csv. The master daemon still waits for a reply from connectd for the activate message, since it wants to be listening before it prints "Server started". Signed-off-by: Rusty Russell --- connectd/connect.c | 67 +++++++++++++++++++++++++-------------- connectd/connect_wire.csv | 38 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 24 deletions(-) diff --git a/connectd/connect.c b/connectd/connect.c index ae2704bb9..54d149935 100644 --- a/connectd/connect.c +++ b/connectd/connect.c @@ -162,6 +162,9 @@ struct daemon { /* The address that the broken response returns instead of * NXDOMAIN. NULL if we have not detected a broken resolver. */ struct sockaddr *broken_resolver_response; + + /* File descriptors to listen on once we're activated. */ + int *listen_fds; }; /* Peers we're trying to reach. */ @@ -989,11 +992,6 @@ static int make_listen_fd(int domain, void *addr, socklen_t len, bool mayfail) } } - if (listen(fd, 5) != 0) { - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed to listen on %u socket: %s", - domain, strerror(errno)); - } return fd; fail: @@ -1038,6 +1036,13 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon init_new_peer, daemon); } +static void add_listen_fd(struct daemon *daemon, int fd) +{ + size_t n = tal_count(daemon->listen_fds); + tal_resize(&daemon->listen_fds, n+1); + daemon->listen_fds[n] = fd; +} + /* Return true if it created socket successfully. */ static bool handle_wireaddr_listen(struct daemon *daemon, const struct wireaddr *wireaddr, @@ -1055,7 +1060,7 @@ static bool handle_wireaddr_listen(struct daemon *daemon, if (fd >= 0) { status_trace("Created IPv4 listener on port %u", wireaddr->port); - io_new_listener(daemon, fd, connection_in, daemon); + add_listen_fd(daemon, fd); return true; } return false; @@ -1065,7 +1070,7 @@ static bool handle_wireaddr_listen(struct daemon *daemon, if (fd >= 0) { status_trace("Created IPv6 listener on port %u", wireaddr->port); - io_new_listener(daemon, fd, connection_in, daemon); + add_listen_fd(daemon, fd); return true; } return false; @@ -1276,8 +1281,9 @@ static struct io_plan *gossip_init(struct daemon_conn *master, struct bitcoin_blkid chain_hash; u32 update_channel_interval; struct wireaddr *proxyaddr; + struct wireaddr_internal *binding; - if (!fromwire_gossipctl_init( + if (!fromwire_connectctl_init( daemon, msg, &daemon->broadcast_interval, &chain_hash, &daemon->id, &daemon->globalfeatures, &daemon->localfeatures, &daemon->proposed_wireaddr, @@ -1286,7 +1292,7 @@ static struct io_plan *gossip_init(struct daemon_conn *master, &proxyaddr, &daemon->use_proxy_always, &daemon->dev_allow_localhost, &daemon->use_dns, &daemon->tor_password)) { - master_badmsg(WIRE_GOSSIPCTL_INIT, msg); + master_badmsg(WIRE_CONNECTCTL_INIT, msg); } /* Resolve Tor proxy address if any */ @@ -1302,6 +1308,13 @@ static struct io_plan *gossip_init(struct daemon_conn *master, "dummy replies"); } + binding = setup_listeners(tmpctx, daemon); + + daemon_conn_send(&daemon->master, + take(towire_connectctl_init_reply(NULL, + binding, + daemon->announcable))); + return daemon_conn_read_next(master->conn, master); } @@ -1309,23 +1322,26 @@ static struct io_plan *gossip_activate(struct daemon_conn *master, struct daemon *daemon, const u8 *msg) { - bool listen; - struct wireaddr_internal *binding; + bool do_listen; - if (!fromwire_gossipctl_activate(msg, &listen)) - master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg); + if (!fromwire_connectctl_activate(msg, &do_listen)) + master_badmsg(WIRE_CONNECTCTL_ACTIVATE, msg); - if (listen) - binding = setup_listeners(tmpctx, daemon); - else - binding = NULL; + if (do_listen) { + for (size_t i = 0; i < tal_count(daemon->listen_fds); i++) { + if (listen(daemon->listen_fds[i], 5) != 0) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to listen on socket: %s", + strerror(errno)); + io_new_listener(daemon, daemon->listen_fds[i], + connection_in, daemon); + } + } + daemon->listen_fds = tal_free(daemon->listen_fds); /* OK, we're ready! */ daemon_conn_send(&daemon->master, - take(towire_gossipctl_activate_reply(NULL, - binding, - daemon->announcable))); - + take(towire_connectctl_activate_reply(NULL))); return daemon_conn_read_next(master->conn, master); } @@ -1813,13 +1829,14 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master struct daemon *daemon = container_of(master, struct daemon, master); enum gossip_wire_type t= fromwire_peektype(master->msg_in); + /* FIXME: Move away from gossip wiretypes */ + if (fromwire_peektype(master->msg_in) == WIRE_CONNECTCTL_ACTIVATE) + return gossip_activate(master, daemon, master->msg_in); + switch (t) { case WIRE_GOSSIPCTL_INIT: return gossip_init(master, daemon, master->msg_in); - case WIRE_GOSSIPCTL_ACTIVATE: - return gossip_activate(master, daemon, master->msg_in); - case WIRE_GOSSIPCTL_RELEASE_PEER: return release_peer(conn, daemon, master->msg_in); @@ -1845,6 +1862,7 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master return disconnect_peer(conn, daemon, master->msg_in); /* FIXME: We don't really do these, gossipd does */ + case WIRE_GOSSIPCTL_ACTIVATE: case WIRE_GOSSIP_GETNODES_REQUEST: case WIRE_GOSSIP_PING: case WIRE_GOSSIP_QUERY_SCIDS: @@ -1917,6 +1935,7 @@ int main(int argc, char *argv[]) timers_init(&daemon->timers, time_mono()); daemon->broadcast_interval = 30000; daemon->broken_resolver_response = NULL; + daemon->listen_fds = tal_arr(daemon, int, 0); /* stdin == control */ daemon_conn_init(daemon, &daemon->master, STDIN_FILENO, recv_req, master_gone); diff --git a/connectd/connect_wire.csv b/connectd/connect_wire.csv index a8ac059d5..8bd75c97c 100644 --- a/connectd/connect_wire.csv +++ b/connectd/connect_wire.csv @@ -1,3 +1,41 @@ +#include + +connectctl_init,2000 +connectctl_init,,broadcast_interval,u32 +connectctl_init,,chain_hash,struct bitcoin_blkid +connectctl_init,,id,struct pubkey +connectctl_init,,gflen,u16 +connectctl_init,,gfeatures,gflen*u8 +connectctl_init,,lflen,u16 +connectctl_init,,lfeatures,lflen*u8 +connectctl_init,,num_wireaddrs,u16 +connectctl_init,,wireaddrs,num_wireaddrs*struct wireaddr_internal +connectctl_init,,listen_announce,num_wireaddrs*enum addr_listen_announce +connectctl_init,,rgb,3*u8 +connectctl_init,,alias,32*u8 +connectctl_init,,update_channel_interval,u32 +connectctl_init,,reconnect,bool +connectctl_init,,tor_proxyaddr,?struct wireaddr +connectctl_init,,use_tor_proxy_always,bool +connectctl_init,,dev_allow_localhost,bool +connectctl_init,,use_dns,bool +connectctl_init,,tor_password,wirestring + +# Connectd->master, here are the addresses I bound, can announce. +connectctl_init_reply,2100 +connectctl_init_reply,,num_bindings,u16 +connectctl_init_reply,,bindings,num_bindings*struct wireaddr_internal +connectctl_init_reply,,num_announcable,u16 +connectctl_init_reply,,announcable,num_announcable*struct wireaddr + +# Activate the connect daemon, so others can connect. +connectctl_activate,2025 +# Do we listen? +connectctl_activate,,listen,bool + +# Connectd->master, I am ready. +connectctl_activate_reply,2125 + # connectd->master: disconnect this peer please (due to reconnect). connect_reconnected,2112 connect_reconnected,,id,struct pubkey