diff --git a/connectd/connectd.c b/connectd/connectd.c index f932f46a3..f92f2e187 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1591,23 +1591,19 @@ static struct io_plan *connect_to_peer(struct io_conn *conn, return daemon_conn_read_next(conn, daemon->master); } -/* lightningd tells us a peer has disconnected. */ -static struct io_plan *peer_disconnected(struct io_conn *conn, - struct daemon *daemon, const u8 *msg) +/* A peer is gone: clean things up. */ +static void cleanup_dead_peer(struct daemon *daemon, const struct node_id *id) { - struct node_id id, *node; - - if (!fromwire_connectd_peer_disconnected(msg, &id)) - master_badmsg(WIRE_CONNECTD_PEER_DISCONNECTED, msg); + struct node_id *node; /* We should stay in sync with lightningd at all times. */ - node = node_set_get(&daemon->peers, &id); + node = node_set_get(&daemon->peers, id); if (!node) status_failed(STATUS_FAIL_INTERNAL_ERROR, "peer_disconnected unknown peer: %s", - type_to_string(tmpctx, struct node_id, &id)); + type_to_string(tmpctx, struct node_id, id)); node_set_del(&daemon->peers, node); - status_peer_debug(&id, "disconnect"); + status_peer_debug(id, "disconnect"); /* Wake up in case there's a reconnecting peer waiting in io_wait. */ io_wake(node); @@ -1615,6 +1611,69 @@ static struct io_plan *peer_disconnected(struct io_conn *conn, /* Note: deleting from a htable (a-la node_set_del) does not free it: * htable doesn't assume it's a tal object at all. */ tal_free(node); +} + +/* lightningd tells us a peer has disconnected. */ +static struct io_plan *peer_disconnected(struct io_conn *conn, + struct daemon *daemon, const u8 *msg) +{ + struct node_id id; + + if (!fromwire_connectd_peer_disconnected(msg, &id)) + master_badmsg(WIRE_CONNECTD_PEER_DISCONNECTED, msg); + + cleanup_dead_peer(daemon, &id); + + /* Read the next message from lightningd. */ + return daemon_conn_read_next(conn, daemon->master); +} + +/* lightningd tells us to send a final (usually error) message to peer, then + * disconnect. */ +struct final_msg_data { + struct daemon *daemon; + struct node_id id; +}; + +static void destroy_final_msg_data(struct final_msg_data *f) +{ + cleanup_dead_peer(f->daemon, &f->id); +} + +static struct io_plan *send_final_msg(struct io_conn *conn, u8 *msg) +{ + return io_write(conn, msg, tal_bytelen(msg), io_close_cb, NULL); +} + +/* lightningd tells us to send a msg and disconnect. */ +static struct io_plan *peer_final_msg(struct io_conn *conn, + struct daemon *daemon, const u8 *msg) +{ + struct per_peer_state *pps; + struct final_msg_data *f = tal(NULL, struct final_msg_data); + u8 *finalmsg; + int fds[3]; + + /* pps is allocated off f, so fds are closed when f freed. */ + if (!fromwire_connectd_peer_final_msg(f, msg, &f->id, &pps, &finalmsg)) + master_badmsg(WIRE_CONNECTD_PEER_FINAL_MSG, msg); + + /* When f is freed, we want to mark node as dead. */ + tal_add_destructor(f, destroy_final_msg_data); + + /* Get the fds for this peer. */ + for (size_t i = 0; i < ARRAY_SIZE(fds); i++) + fds[i] = fdpass_recv(io_conn_fd(conn)); + /* We put peer fd into conn, but pps needs to free the rest */ + per_peer_state_set_fds(pps, -1, fds[1], fds[2]); + + /* Log and encrypt message for peer. */ + status_peer_io(LOG_IO_OUT, &f->id, finalmsg); + finalmsg = cryptomsg_encrypt_msg(f, &pps->cs, take(finalmsg)); + + /* Organize io loop to write out that message, it will free f + * once closed */ + tal_steal(io_new_conn(daemon, fds[0], send_final_msg, finalmsg), f); /* Read the next message from lightningd. */ return daemon_conn_read_next(conn, daemon->master); @@ -1662,6 +1721,9 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_CONNECTD_PEER_DISCONNECTED: return peer_disconnected(conn, daemon, msg); + case WIRE_CONNECTD_PEER_FINAL_MSG: + return peer_final_msg(conn, daemon, msg); + case WIRE_CONNECTD_DEV_MEMLEAK: #if DEVELOPER return dev_connect_memleak(conn, daemon, msg); diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index 95f7abcdf..093f7d33f 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -65,6 +65,13 @@ msgdata,connectd_peer_connected,features,u8,flen msgtype,connectd_peer_disconnected,2015 msgdata,connectd_peer_disconnected,id,node_id, +# master -> connectd: give message to peer and disconnect. Three fds: peer, gossip and gossip_store +msgtype,connectd_peer_final_msg,2003 +msgdata,connectd_peer_final_msg,id,node_id, +msgdata,connectd_peer_final_msg,pps,per_peer_state, +msgdata,connectd_peer_final_msg,len,u16, +msgdata,connectd_peer_final_msg,msg,u8,len + # master -> connectd: do you have a memleak? msgtype,connectd_dev_memleak,2033 diff --git a/connectd/connectd_wiregen.c b/connectd/connectd_wiregen.c index 7df76a964..a76e3e007 100644 --- a/connectd/connectd_wiregen.c +++ b/connectd/connectd_wiregen.c @@ -29,6 +29,7 @@ const char *connectd_wire_name(int e) case WIRE_CONNECTD_CONNECT_FAILED: return "WIRE_CONNECTD_CONNECT_FAILED"; case WIRE_CONNECTD_PEER_CONNECTED: return "WIRE_CONNECTD_PEER_CONNECTED"; case WIRE_CONNECTD_PEER_DISCONNECTED: return "WIRE_CONNECTD_PEER_DISCONNECTED"; + case WIRE_CONNECTD_PEER_FINAL_MSG: return "WIRE_CONNECTD_PEER_FINAL_MSG"; case WIRE_CONNECTD_DEV_MEMLEAK: return "WIRE_CONNECTD_DEV_MEMLEAK"; case WIRE_CONNECTD_DEV_MEMLEAK_REPLY: return "WIRE_CONNECTD_DEV_MEMLEAK_REPLY"; } @@ -49,6 +50,7 @@ bool connectd_wire_is_defined(u16 type) case WIRE_CONNECTD_CONNECT_FAILED:; case WIRE_CONNECTD_PEER_CONNECTED:; case WIRE_CONNECTD_PEER_DISCONNECTED:; + case WIRE_CONNECTD_PEER_FINAL_MSG:; case WIRE_CONNECTD_DEV_MEMLEAK:; case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:; return true; @@ -368,6 +370,39 @@ bool fromwire_connectd_peer_disconnected(const void *p, struct node_id *id) return cursor != NULL; } +/* WIRE: CONNECTD_PEER_FINAL_MSG */ +/* master -> connectd: give message to peer and disconnect. Three fds: peer */ +u8 *towire_connectd_peer_final_msg(const tal_t *ctx, const struct node_id *id, const struct per_peer_state *pps, const u8 *msg) +{ + u16 len = tal_count(msg); + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_CONNECTD_PEER_FINAL_MSG); + towire_node_id(&p, id); + towire_per_peer_state(&p, pps); + towire_u16(&p, len); + towire_u8_array(&p, msg, len); + + return memcheck(p, tal_count(p)); +} +bool fromwire_connectd_peer_final_msg(const tal_t *ctx, const void *p, struct node_id *id, struct per_peer_state **pps, u8 **msg) +{ + u16 len; + + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_CONNECTD_PEER_FINAL_MSG) + return false; + fromwire_node_id(&cursor, &plen, id); + *pps = fromwire_per_peer_state(ctx, &cursor, &plen); + len = fromwire_u16(&cursor, &plen); + // 2nd case msg + *msg = len ? tal_arr(ctx, u8, len) : NULL; + fromwire_u8_array(&cursor, &plen, *msg, len); + return cursor != NULL; +} + /* WIRE: CONNECTD_DEV_MEMLEAK */ /* master -> connectd: do you have a memleak? */ u8 *towire_connectd_dev_memleak(const tal_t *ctx) @@ -408,4 +443,4 @@ bool fromwire_connectd_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:9bbb0b97a226bd5c85a21bafde42c7fd438b8107d6d30b7c7b17c16a6cbd3557 +// SHA256STAMP:7c9585941825eab65d734eb1c233eee5c78b5792e19ec68f0a9986abca2b0ffe diff --git a/connectd/connectd_wiregen.h b/connectd/connectd_wiregen.h index 6ccfa7bd6..46e1ecb00 100644 --- a/connectd/connectd_wiregen.h +++ b/connectd/connectd_wiregen.h @@ -31,6 +31,8 @@ enum connectd_wire { WIRE_CONNECTD_PEER_CONNECTED = 2002, /* master -> connectd: peer has disconnected. */ WIRE_CONNECTD_PEER_DISCONNECTED = 2015, + /* master -> connectd: give message to peer and disconnect. Three fds: peer */ + WIRE_CONNECTD_PEER_FINAL_MSG = 2003, /* master -> connectd: do you have a memleak? */ WIRE_CONNECTD_DEV_MEMLEAK = 2033, WIRE_CONNECTD_DEV_MEMLEAK_REPLY = 2133, @@ -92,6 +94,11 @@ bool fromwire_connectd_peer_connected(const tal_t *ctx, const void *p, struct no u8 *towire_connectd_peer_disconnected(const tal_t *ctx, const struct node_id *id); bool fromwire_connectd_peer_disconnected(const void *p, struct node_id *id); +/* WIRE: CONNECTD_PEER_FINAL_MSG */ +/* master -> connectd: give message to peer and disconnect. Three fds: peer */ +u8 *towire_connectd_peer_final_msg(const tal_t *ctx, const struct node_id *id, const struct per_peer_state *pps, const u8 *msg); +bool fromwire_connectd_peer_final_msg(const tal_t *ctx, const void *p, struct node_id *id, struct per_peer_state **pps, u8 **msg); + /* WIRE: CONNECTD_DEV_MEMLEAK */ /* master -> connectd: do you have a memleak? */ u8 *towire_connectd_dev_memleak(const tal_t *ctx); @@ -103,4 +110,4 @@ bool fromwire_connectd_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_CONNECTD_CONNECTD_WIREGEN_H */ -// SHA256STAMP:9bbb0b97a226bd5c85a21bafde42c7fd438b8107d6d30b7c7b17c16a6cbd3557 +// SHA256STAMP:7c9585941825eab65d734eb1c233eee5c78b5792e19ec68f0a9986abca2b0ffe diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index f0bec05a9..9d143c968 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -315,6 +315,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_CONNECT_TO_PEER: case WIRE_CONNECTD_PEER_DISCONNECTED: case WIRE_CONNECTD_DEV_MEMLEAK: + case WIRE_CONNECTD_PEER_FINAL_MSG: /* This is a reply, so never gets through to here. */ case WIRE_CONNECTD_INIT_REPLY: case WIRE_CONNECTD_ACTIVATE_REPLY: