From 4185153d813d90b36e558a0fb75bbefcf964efb7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 24 Jun 2017 16:20:23 +0930 Subject: [PATCH] gossipd: interface to get a client gossip_fd for a reconnect. At the moment, master simply keeps the gossip fd open when peer disconnects. That's inefficient, and wrong anyway (it may want a complete new sync, or may not, but we'll currently send all the messages including stale ones). This interface will be required for restart anyway. Signed-off-by: Rusty Russell --- lightningd/gossip/gossip.c | 67 +++++++++++++++++++++++++++++++ lightningd/gossip/gossip_wire.csv | 12 ++++++ lightningd/gossip_control.c | 3 ++ 3 files changed, 82 insertions(+) diff --git a/lightningd/gossip/gossip.c b/lightningd/gossip/gossip.c index 100845e2c..d8c7aca87 100644 --- a/lightningd/gossip/gossip.c +++ b/lightningd/gossip/gossip.c @@ -117,6 +117,28 @@ static struct peer *setup_new_peer(struct daemon *daemon, const u8 *msg) return peer; } +static struct peer *setup_new_remote_peer(struct daemon *daemon, + u64 unique_id, bool sync) +{ + struct peer *peer = tal(daemon, struct peer); + + peer->daemon = daemon; + peer->error = NULL; + peer->local = false; + peer->num_pings_outstanding = 0; + peer->fd = -1; + peer->unique_id = unique_id; + if (sync) + peer->broadcast_index = 0; + else + peer->broadcast_index = daemon->rstate->broadcasts->next_index; + + msg_queue_init(&peer->peer_out, peer); + list_add_tail(&daemon->peers, &peer->list); + tal_add_destructor(peer, destroy_peer); + return peer; +} + static struct io_plan *owner_msg_in(struct io_conn *conn, struct daemon_conn *dc); static struct io_plan *nonlocal_dump_gossip(struct io_conn *conn, @@ -457,6 +479,47 @@ static struct io_plan *fail_peer(struct io_conn *conn, struct daemon *daemon, return daemon_conn_read_next(conn, &daemon->master); } +static void forget_peer(struct io_conn *conn, struct daemon_conn *dc) +{ + /* Free peer. */ + tal_free(dc->ctx); +} + +static struct io_plan *new_peer_fd(struct io_conn *conn, struct daemon *daemon, + const u8 *msg) +{ + int fds[2]; + u8 *out; + u64 unique_id; + bool sync; + struct peer *peer; + + if (!fromwire_gossipctl_get_peer_gossipfd(msg, NULL, + &unique_id, &sync)) + status_failed(WIRE_GOSSIPSTATUS_BAD_FAIL_REQUEST, + "%s", tal_hex(trc, msg)); + + peer = setup_new_remote_peer(daemon, unique_id, sync); + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) { + status_trace("Failed to create socketpair: %s", + strerror(errno)); + out = towire_gossipctl_get_peer_gossipfd_replyfail(msg); + daemon_conn_send(&peer->daemon->master, take(out)); + return daemon_conn_read_next(conn, &daemon->master); + } + + daemon_conn_init(peer, &peer->owner_conn, fds[0], owner_msg_in, + forget_peer); + peer->owner_conn.msg_queue_cleared_cb = nonlocal_dump_gossip; + + out = towire_gossipctl_get_peer_gossipfd_reply(msg); + daemon_conn_send(&peer->daemon->master, out); + daemon_conn_send_fd(&peer->daemon->master, fds[1]); + + return daemon_conn_read_next(conn, &daemon->master); +} + static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon, u8 *msg) { @@ -649,6 +712,8 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master return release_peer(conn, daemon, master->msg_in); case WIRE_GOSSIPCTL_FAIL_PEER: return fail_peer(conn, daemon, master->msg_in); + case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD: + return new_peer_fd(conn, daemon, master->msg_in); case WIRE_GOSSIP_GETNODES_REQUEST: return getnodes(conn, daemon); @@ -670,6 +735,8 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master return daemon_conn_read_next(conn, &daemon->master); case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL: + case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLY: + case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLYFAIL: case WIRE_GOSSIP_GETNODES_REPLY: case WIRE_GOSSIP_GETROUTE_REPLY: case WIRE_GOSSIP_GETCHANNELS_REPLY: diff --git a/lightningd/gossip/gossip_wire.csv b/lightningd/gossip/gossip_wire.csv index ab5915bb3..51a7baca4 100644 --- a/lightningd/gossip/gossip_wire.csv +++ b/lightningd/gossip/gossip_wire.csv @@ -107,3 +107,15 @@ gossip_forwarded_msg,,msg,msglen # If peer is still connected, fail it (master does this for reconnect) gossipctl_fail_peer,11 gossipctl_fail_peer,,unique_id,8 + +# Get a gossip fd for this peer (it has reconnected) +gossipctl_get_peer_gossipfd,12 +gossipctl_get_peer_gossipfd,,unique_id,u64 +# Does it want a full dump of gossip? +gossipctl_get_peer_gossipfd,,sync,bool + +# + fd. +gossipctl_get_peer_gossipfd_reply,112 + +# Failure (can't make new socket) +gossipctl_get_peer_gossipfd_replyfail,212 diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 4cb392063..0f8743fef 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -106,6 +106,7 @@ static int gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPCTL_NEW_PEER: case WIRE_GOSSIPCTL_RELEASE_PEER: case WIRE_GOSSIPCTL_FAIL_PEER: + case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD: case WIRE_GOSSIP_GETNODES_REQUEST: case WIRE_GOSSIP_GETROUTE_REQUEST: case WIRE_GOSSIP_GETCHANNELS_REQUEST: @@ -115,6 +116,8 @@ static int gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL: + case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLY: + case WIRE_GOSSIPCTL_GET_PEER_GOSSIPFD_REPLYFAIL: case WIRE_GOSSIP_GETNODES_REPLY: case WIRE_GOSSIP_GETROUTE_REPLY: case WIRE_GOSSIP_GETCHANNELS_REPLY: