gossipd: don't hand out fds.

Gossipd now simply gets told by channeld when peers arrive or leave.
(it only needs to know for the seeker).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-01-29 14:03:05 +10:30
parent 3c5d27e3e9
commit 3121cebf4c
5 changed files with 54 additions and 187 deletions

View file

@ -210,57 +210,6 @@ static void peer_connected_in(struct daemon *daemon,
tal_free(connect);
}
/*~ Every per-peer daemon needs a connection to the gossip daemon; this allows
* it to forward gossip to/from the peer. The gossip daemon needs to know a
* few of the features of the peer and its id (for reporting).
*
* Every peer also has read-only access to the gossip_store, which is handed
* out by gossipd too, and also a "gossip_state" indicating where we're up to.
*
* 'features' is a field in the `init` message, indicating properties of the
* node.
*/
static int get_gossipfd(struct daemon *daemon,
const struct node_id *id,
const u8 *their_features)
{
bool gossip_queries_feature, success;
u8 *msg;
/*~ The way features generally work is that both sides need to offer it;
* we always offer `gossip_queries`, but this check is explicit. */
gossip_queries_feature
= feature_negotiated(daemon->our_features, their_features,
OPT_GOSSIP_QUERIES);
/*~ We do this communication sync, since gossipd is our friend and
* it's easier. If gossipd fails, we fail. */
msg = towire_gossipd_new_peer(NULL, id, gossip_queries_feature);
if (!wire_sync_write(GOSSIPCTL_FD, take(msg)))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed writing to gossipctl: %s",
strerror(errno));
msg = wire_sync_read(tmpctx, GOSSIPCTL_FD);
if (!fromwire_gossipd_new_peer_reply(msg, &success))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed parsing msg gossipctl: %s",
tal_hex(tmpctx, msg));
/* Gossipd might run out of file descriptors, so it tells us, and we
* give up on connecting this peer. */
if (!success) {
status_broken("Gossipd did not give us an fd: losing peer %s",
type_to_string(tmpctx, struct node_id, id));
return -1;
}
/* Otherwise, the next thing in the socket will be the file descriptor
* for the per-peer daemon. */
return fdpass_recv(GOSSIPCTL_FD);
}
/*~ This is an ad-hoc marshalling structure where we store arguments so we
* can call peer_connected again. */
struct peer_reconnected {
@ -336,8 +285,6 @@ static struct io_plan *peer_reconnected(struct io_conn *conn,
/*~ When we free a peer, we remove it from the daemon's hashtable */
static void destroy_peer(struct peer *peer, struct daemon *daemon)
{
if (peer->gossip_fd >= 0)
close(peer->gossip_fd);
peer_htable_del(&daemon->peers, peer);
}
@ -398,6 +345,7 @@ struct io_plan *peer_connected(struct io_conn *conn,
int unsup;
size_t depender, missing;
int subd_fd;
bool option_gossip_queries;
peer = peer_htable_get(&daemon->peers, id);
if (peer)
@ -455,12 +403,12 @@ struct io_plan *peer_connected(struct io_conn *conn,
if (!peer)
return io_close(conn);
/* If gossipd can't give us a file descriptor, we give up connecting. */
peer->gossip_fd = get_gossipfd(daemon, id, their_features);
if (peer->gossip_fd < 0) {
close(subd_fd);
return tal_free(peer);
}
/* Tell gossipd it can ask query this new peer for gossip */
option_gossip_queries = feature_negotiated(daemon->our_features,
their_features,
OPT_GOSSIP_QUERIES);
msg = towire_gossipd_new_peer(NULL, id, option_gossip_queries);
daemon_conn_send(daemon->gossipd, take(msg));
/* Get ready for streaming gossip from the store */
setup_peer_gossip_store(peer, daemon->our_features, their_features);
@ -1846,6 +1794,10 @@ void peer_conn_closed(struct peer *peer)
assert(!peer->to_peer);
assert(peer->told_to_close);
/* Tell gossipd to stop asking this peer gossip queries */
daemon_conn_send(peer->daemon->gossipd,
take(towire_gossipd_peer_gone(NULL, &peer->id)));
/* Wake up in case there's a reconnecting peer waiting in io_wait. */
io_wake(peer);

View file

@ -81,9 +81,6 @@ struct peer {
/* Random ping timer, to detect dead connections. */
struct oneshot *ping_timer;
/* FIXME: remove! */
int gossip_fd;
#if DEVELOPER
bool dev_read_enabled;
/* If non-NULL, this counts down; 0 means disable */

View file

@ -8,9 +8,9 @@ msgdata,gossipd_new_peer,id,node_id,
# Did we negotiate OPT_GOSSIP_QUERIES?
msgdata,gossipd_new_peer,gossip_queries_feature,bool,
# if success: + gossip fd
msgtype,gossipd_new_peer_reply,4100
msgdata,gossipd_new_peer_reply,success,bool,
# peer is done
msgtype,gossipd_peer_gone,4101
msgdata,gossipd_peer_gone,id,node_id,
# connectd tells gossipd a gossip msg it received for peer.
msgtype,gossipd_recv_gossip,4002

1 #include <common/node_id.h>
8 msgdata,gossipd_new_peer,gossip_queries_feature,bool,
9 # if success: + gossip fd # peer is done
10 msgtype,gossipd_new_peer_reply,4100 msgtype,gossipd_peer_gone,4101
11 msgdata,gossipd_new_peer_reply,success,bool, msgdata,gossipd_peer_gone,id,node_id,
12 # connectd tells gossipd a gossip msg it received for peer.
13 msgtype,gossipd_recv_gossip,4002
14 msgdata,gossipd_recv_gossip,id,node_id,
15 msgdata,gossipd_recv_gossip,len,u16,
16 msgdata,gossipd_recv_gossip,msg,byte,len

View file

@ -89,12 +89,6 @@ static void destroy_peer(struct peer *peer)
node = get_node(peer->daemon->rstate, &peer->id);
if (node)
peer_disable_channels(peer->daemon, node);
/* This is tricky: our lifetime is tied to the daemon_conn; it's our
* parent, so we are freed if it is, but we need to free it if we're
* freed manually. tal_free() treats this as a noop if it's already
* being freed */
tal_free(peer->dc);
}
/* Search for a peer. */
@ -347,103 +341,26 @@ static void handle_local_private_channel(struct daemon *daemon, const u8 *msg)
}
}
/*~ This is where the per-peer daemons send us messages. It's either forwarded
* gossip, or a request for information. We deliberately use non-overlapping
* message types so we can distinguish them. */
static struct io_plan *peer_msg_in(struct io_conn *conn,
const u8 *msg,
struct peer *peer)
/*~ This is where connectd tells us about a new peer we might want to
* gossip with. */
static void connectd_new_peer(struct daemon *daemon, const u8 *msg)
{
/* These are messages relayed from peer */
switch ((enum peer_wire)fromwire_peektype(msg)) {
/* These are not sent by peer (connectd sends us gossip msgs) */
case WIRE_CHANNEL_ANNOUNCEMENT:
case WIRE_CHANNEL_UPDATE:
case WIRE_NODE_ANNOUNCEMENT:
case WIRE_QUERY_CHANNEL_RANGE:
case WIRE_REPLY_CHANNEL_RANGE:
case WIRE_QUERY_SHORT_CHANNEL_IDS:
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
case WIRE_WARNING:
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_PING:
case WIRE_PONG:
case WIRE_OPEN_CHANNEL:
case WIRE_ACCEPT_CHANNEL:
case WIRE_FUNDING_CREATED:
case WIRE_FUNDING_SIGNED:
case WIRE_FUNDING_LOCKED:
case WIRE_SHUTDOWN:
case WIRE_CLOSING_SIGNED:
case WIRE_UPDATE_ADD_HTLC:
case WIRE_UPDATE_FULFILL_HTLC:
case WIRE_UPDATE_FAIL_HTLC:
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
case WIRE_COMMITMENT_SIGNED:
case WIRE_REVOKE_AND_ACK:
case WIRE_UPDATE_FEE:
case WIRE_UPDATE_BLOCKHEIGHT:
case WIRE_CHANNEL_REESTABLISH:
case WIRE_ANNOUNCEMENT_SIGNATURES:
case WIRE_GOSSIP_TIMESTAMP_FILTER:
case WIRE_TX_ADD_INPUT:
case WIRE_TX_REMOVE_INPUT:
case WIRE_TX_ADD_OUTPUT:
case WIRE_TX_REMOVE_OUTPUT:
case WIRE_TX_COMPLETE:
case WIRE_TX_SIGNATURES:
case WIRE_OPEN_CHANNEL2:
case WIRE_ACCEPT_CHANNEL2:
case WIRE_INIT_RBF:
case WIRE_ACK_RBF:
case WIRE_OBS2_ONION_MESSAGE:
case WIRE_ONION_MESSAGE:
#if EXPERIMENTAL_FEATURES
case WIRE_STFU:
#endif
status_broken("peer %s: relayed unexpected msg of type %s",
type_to_string(tmpctx, struct node_id, &peer->id),
peer_wire_name(fromwire_peektype(msg)));
return io_close(conn);
}
/* Anything else should not have been sent to us: close on it */
status_peer_broken(&peer->id, "unexpected cmd of type %i",
fromwire_peektype(msg));
return io_close(conn);
}
/*~ This is where connectd tells us about a new peer, and we hand back an fd for
* it to send us messages via peer_msg_in above */
static struct io_plan *connectd_new_peer(struct io_conn *conn,
struct daemon *daemon,
const u8 *msg)
{
struct peer *peer = tal(conn, struct peer);
struct peer *peer = tal(daemon, struct peer);
struct node *node;
int fds[2];
if (!fromwire_gossipd_new_peer(msg, &peer->id,
&peer->gossip_queries_feature)) {
status_broken("Bad new_peer msg from connectd: %s",
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Bad new_peer msg from connectd: %s",
tal_hex(tmpctx, msg));
return io_close(conn);
}
/* This can happen: we handle it gracefully, returning a `failed` msg. */
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
status_broken("Failed to create socketpair: %s",
strerror(errno));
daemon_conn_send(daemon->connectd,
take(towire_gossipd_new_peer_reply(NULL,
false)));
goto done;
if (find_peer(daemon, &peer->id)) {
status_broken("Peer %s already here?",
type_to_string(tmpctx, struct node_id, &peer->id));
tal_free(find_peer(daemon, &peer->id));
}
/* We might not have noticed old peer is dead; kill it now. */
tal_free(find_peer(daemon, &peer->id));
/* Populate the rest of the peer info. */
peer->daemon = daemon;
peer->gossip_counter = 0;
@ -459,27 +376,30 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn,
list_add_tail(&peer->daemon->peers, &peer->list);
tal_add_destructor(peer, destroy_peer);
/* This is the new connection. */
peer->dc = daemon_conn_new(daemon, fds[0],
peer_msg_in,
NULL, peer);
/* Free peer if conn closed (destroy_peer closes conn if peer freed) */
tal_steal(peer->dc, peer);
node = get_node(daemon->rstate, &peer->id);
if (node)
peer_enable_channels(daemon, node);
/* This sends the initial timestamp filter. */
seeker_setup_peer_gossip(daemon->seeker, peer);
}
/* Reply with success, and the new fd and gossip_state. */
daemon_conn_send(daemon->connectd,
take(towire_gossipd_new_peer_reply(NULL, true)));
daemon_conn_send_fd(daemon->connectd, fds[1]);
static void connectd_peer_gone(struct daemon *daemon, const u8 *msg)
{
struct node_id id;
struct peer *peer;
done:
return daemon_conn_read_next(conn, daemon->connectd);
if (!fromwire_gossipd_peer_gone(msg, &id)) {
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Bad peer_gone msg from connectd: %s",
tal_hex(tmpctx, msg));
}
peer = find_peer(daemon, &id);
if (!peer)
status_broken("Peer %s already gone?",
type_to_string(tmpctx, struct node_id, &id));
tal_free(peer);
}
/*~ lightningd asks us if we know any addresses for a given id. */
@ -520,12 +440,11 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg)
tal_hex(tmpctx, outermsg));
}
/* FIXME: happens when peer closes! */
peer = find_peer(daemon, &id);
if (!peer) {
status_debug("connectd sent gossip msg %s for unknown peer %s",
peer_wire_name(fromwire_peektype(msg)),
type_to_string(tmpctx, struct node_id, &id));
status_broken("connectd sent gossip msg %s for unknown peer %s",
peer_wire_name(fromwire_peektype(msg)),
type_to_string(tmpctx, struct node_id, &id));
return;
}
@ -613,20 +532,17 @@ static struct io_plan *connectd_req(struct io_conn *conn,
enum connectd_gossipd_wire t = fromwire_peektype(msg);
switch (t) {
case WIRE_GOSSIPD_NEW_PEER:
return connectd_new_peer(conn, daemon, msg);
/* This is not for this fd! */
case WIRE_GOSSIPD_RECV_GOSSIP:
case WIRE_GOSSIPD_NEW_PEER:
case WIRE_GOSSIPD_PEER_GONE:
/* We send these, don't receive them. */
case WIRE_GOSSIPD_NEW_PEER_REPLY:
case WIRE_GOSSIPD_SEND_GOSSIP:
break;
}
status_broken("Bad msg from connectd: %s",
tal_hex(tmpctx, msg));
return io_close(conn);
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Bad msg from connectd: %s", tal_hex(tmpctx, msg));
}
/*~ connectd's input handler is very simple. */
@ -641,10 +557,15 @@ static struct io_plan *connectd_gossip_req(struct io_conn *conn,
handle_recv_gossip(daemon, msg);
goto handled;
/* This is not for this fd! */
case WIRE_GOSSIPD_NEW_PEER:
connectd_new_peer(daemon, msg);
goto handled;
case WIRE_GOSSIPD_PEER_GONE:
connectd_peer_gone(daemon, msg);
goto handled;
/* We send these, don't receive them. */
case WIRE_GOSSIPD_NEW_PEER_REPLY:
case WIRE_GOSSIPD_SEND_GOSSIP:
break;
}

View file

@ -109,9 +109,6 @@ struct peer {
void (*query_channel_range_cb)(struct peer *peer,
u32 first_blocknum, u32 number_of_blocks,
const struct range_query_reply *replies);
/* The daemon_conn used to queue messages to/from the peer. */
struct daemon_conn *dc;
};
/* Search for a peer. */