diff --git a/common/peer_failed.c b/common/peer_failed.c index 375891d8f..c01356687 100644 --- a/common/peer_failed.c +++ b/common/peer_failed.c @@ -33,7 +33,7 @@ void peer_failed_(int peer_fd, int gossip_fd, msg = towire_status_peer_error(NULL, channel_id, desc, cs, gossip_index, msg); tal_free(desc); - status_send_fatal(take(msg)); + status_send_fatal(take(msg), peer_fd, gossip_fd); } /* We're failing because peer sent us an error message */ @@ -44,10 +44,11 @@ void peer_failed_received_errmsg(int peer_fd, int gossip_fd, { u8 *msg = towire_status_peer_error(NULL, channel_id, desc, cs, gossip_index, NULL); - status_send_fatal(take(msg)); + status_send_fatal(take(msg), peer_fd, gossip_fd); } void peer_failed_connection_lost(void) { - status_send_fatal(take(towire_status_peer_connection_lost(NULL))); + status_send_fatal(take(towire_status_peer_connection_lost(NULL)), + -1, -1); } diff --git a/common/status.c b/common/status.c index 6a425042d..10adc6767 100644 --- a/common/status.c +++ b/common/status.c @@ -122,12 +122,19 @@ static NORETURN void flush_and_exit(int reason) exit(0x80 | (reason & 0xFF)); } -void status_send_fatal(const u8 *msg TAKES) +void status_send_fatal(const u8 *msg TAKES, int fd1, int fd2) { int reason = fromwire_peektype(msg); breakpoint(); status_send(msg); + /* We don't support async fd passing here. */ + if (fd1 != -1) { + assert(!status_conn); + fdpass_send(status_fd, fd1); + fdpass_send(status_fd, fd2); + } + flush_and_exit(reason); } @@ -141,7 +148,8 @@ void status_failed(enum status_failreason reason, const char *fmt, ...) str = tal_vfmt(NULL, fmt, ap); va_end(ap); - status_send_fatal(take(towire_status_fail(NULL, reason, str))); + status_send_fatal(take(towire_status_fail(NULL, reason, str)), + -1, -1); } void master_badmsg(u32 type_expected, const u8 *msg) diff --git a/common/status.h b/common/status.h index 16ff558f5..4a3f2e3ff 100644 --- a/common/status.h +++ b/common/status.h @@ -51,5 +51,5 @@ void status_failed(enum status_failreason code, * msg NULL == read failure. */ void master_badmsg(u32 type_expected, const u8 *msg) NORETURN; -void status_send_fatal(const u8 *msg TAKES) NORETURN; +void status_send_fatal(const u8 *msg TAKES, int fd1, int fd2) NORETURN; #endif /* LIGHTNING_COMMON_STATUS_H */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 8460f3486..49a1b7d81 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -364,28 +364,60 @@ static void channel_config(struct lightningd *ld, }; static void channel_errmsg(struct channel *channel, - enum side sender, - const struct channel_id *channel_id, - const char *desc, - const u8 *errmsg) -{ - if (sender == LOCAL) { - /* If this is NULL, it means subd died. */ - if (!errmsg) { - channel_fail_transient(channel, "%s: %s", - channel->owner->name, desc); - return; - } + int peer_fd, int gossip_fd, + const struct crypto_state *cs, + u64 gossip_index, + const struct channel_id *channel_id, + const char *desc, + const u8 *err_for_them) +{ + struct lightningd *ld = channel->peer->ld; + u8 *msg; - /* Otherwise overwrite any error we have */ - if (!channel->error) - channel->error = tal_dup_arr(channel, u8, - errmsg, tal_len(errmsg), 0); + /* No peer fd means a subd crash or disconnection. */ + if (peer_fd == -1) { + channel_fail_transient(channel, "%s: %s", + channel->owner->name, desc); + return; } + /* Do we have an error to send? */ + if (err_for_them && !channel->error) + channel->error = tal_dup_arr(channel, u8, + err_for_them, + tal_len(err_for_them), 0); + + /* BOLT #1: + * + * A sending node: + *... + * - when `channel_id` is 0: + * - MUST fail all channels. + * - MUST close the connection. + */ + /* FIXME: Gossipd closes connection, but doesn't fail channels. */ + + /* BOLT #1: + * + * A sending node: + * - when sending `error`: + * - MUST fail the channel referred to by the error message. + *... + * The receiving node: + * - upon receiving `error`: + * - MUST fail the channel referred to by the error message. + */ channel_fail_permanent(channel, "%s: %s ERROR %s", channel->owner->name, - sender == LOCAL ? "sent" : "received", desc); + err_for_them ? "sent" : "received", desc); + + /* Hand back to gossipd, with any error packet. */ + msg = towire_gossipctl_hand_back_peer(NULL, &channel->peer->id, + cs, gossip_index, + err_for_them); + subd_send_msg(ld->gossip, take(msg)); + subd_send_fd(ld->gossip, peer_fd); + subd_send_fd(ld->gossip, gossip_fd); } /* Gossipd tells us a peer has connected */ @@ -1340,10 +1372,12 @@ static bool tell_if_missing(const struct channel *channel, /* Only error onchaind can get is if it dies. */ static void onchain_error(struct channel *channel, - enum side sender, + int peer_fd, int gossip_fd, + const struct crypto_state *cs, + u64 gossip_index, const struct channel_id *channel_id, const char *desc, - const u8 *errmsg) + const u8 *err_for_them) { /* FIXME: re-launch? */ log_broken(channel->log, "%s", desc); @@ -2472,21 +2506,23 @@ static unsigned int opening_negotiation_failed(struct subd *openingd, return 0; } -/* errmsg == NULL for local if daemon died */ +/* peer_fd == -1 for local if daemon died */ static void opening_channel_errmsg(struct uncommitted_channel *uc, - enum side sender, + int peer_fd, int gossip_fd, + const struct crypto_state *cs, + u64 gossip_index, const struct channel_id *channel_id, const char *desc, - const u8 *errmsg) + const u8 *err_for_them) { if (uc->fc) command_fail(uc->fc->cmd, "%sERROR %s", - sender == LOCAL ? (errmsg ? "sent " : "") - : "received ", + peer_fd == -1 ? "" + : (err_for_them ? "sent " : "received "), desc); log_info(uc->log, "%sERROR %s", - sender == LOCAL ? (errmsg ? "sent " : "") : "received ", + peer_fd == -1 ? "" : (err_for_them ? "sent " : "received "), desc); tal_free(uc); } diff --git a/lightningd/subd.c b/lightningd/subd.c index c14085b29..c2c46177d 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -388,7 +388,7 @@ static bool log_status_fail(struct subd *sd, const u8 *msg) return true; } -static bool handle_peer_error(struct subd *sd, const u8 *msg) +static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[2]) { void *channel = sd->channel; struct channel_id channel_id; @@ -402,11 +402,9 @@ static bool handle_peer_error(struct subd *sd, const u8 *msg) &cs, &gossip_index, &err_for_them)) return false; - /* FIXME: hand back to gossipd! */ - /* Don't free sd; we're may be about to free channel. */ sd->channel = NULL; - sd->errcb(channel, err_for_them ? LOCAL : REMOTE, + sd->errcb(channel, fds[0], fds[1], &cs, gossip_index, &channel_id, desc, err_for_them); return true; } @@ -463,7 +461,15 @@ static struct io_plan *sd_msg_read(struct io_conn *conn, struct subd *sd) if (sd->channel) { switch ((enum peer_status)type) { case WIRE_STATUS_PEER_ERROR: - if (!handle_peer_error(sd, sd->msg_in)) + /* We expect 2 fds after this */ + if (!sd->fds_in) { + /* Don't free msg_in: we go around again. */ + tal_steal(sd, sd->msg_in); + tal_free(tmpctx); + plan = sd_collect_fds(conn, sd, 2); + goto out; + } + if (!handle_peer_error(sd, sd->msg_in, sd->fds_in)) goto malformed; goto close; } @@ -564,7 +570,7 @@ static void destroy_subd(struct subd *sd) if (!outer_transaction) db_begin_transaction(db); if (sd->errcb) - sd->errcb(channel, LOCAL, NULL, + sd->errcb(channel, -1, -1, NULL, 0, NULL, tal_fmt(sd, "Owning subdaemon %s died (%i)", sd->name, status), NULL); @@ -613,10 +619,12 @@ static struct subd *new_subd(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - enum side sender, + int peer_fd, int gossip_fd, + const struct crypto_state *cs, + u64 gossip_index, const struct channel_id *channel_id, const char *desc, - const u8 *errmsg), + const u8 *err_for_them), va_list *ap) { struct subd *sd = tal(ld, struct subd); @@ -690,10 +698,12 @@ struct subd *new_channel_subd_(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - enum side sender, + int peer_fd, int gossip_fd, + const struct crypto_state *cs, + u64 gossip_index, const struct channel_id *channel_id, const char *desc, - const u8 *errmsg), + const u8 *err_for_them), ...) { va_list ap; diff --git a/lightningd/subd.h b/lightningd/subd.h index 1177e18f0..7cc9f0b27 100644 --- a/lightningd/subd.h +++ b/lightningd/subd.h @@ -8,6 +8,7 @@ #include #include +struct crypto_state; struct io_conn; /* By convention, replies are requests + 100 */ @@ -36,12 +37,16 @@ struct subd { unsigned (*msgcb)(struct subd *, const u8 *, const int *); const char *(*msgname)(int msgtype); - /* Callback when an errormsg sent/received, or subd died. */ + /* If peer_fd == -1, it was a disconnect/crash. Otherwise, + * sufficient information to hand back to gossipd, including the + * error message we sent them if any. */ void (*errcb)(void *channel, - enum side sender, + int peer_fd, int gossip_fd, + const struct crypto_state *cs, + u64 gossip_index, const struct channel_id *channel_id, const char *desc, - const u8 *errmsg); + const u8 *err_for_them); /* Buffer for input. */ u8 *msg_in; @@ -103,16 +108,20 @@ struct subd *new_channel_subd_(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - enum side sender, + int peer_fd, int gossip_fd, + const struct crypto_state *cs, + u64 gossip_index, const struct channel_id *channel_id, const char *desc, - const u8 *errmsg), + const u8 *err_for_them), ...); #define new_channel_subd(ld, name, channel, log, msgname, msgcb, errcb, ...) \ new_channel_subd_((ld), (name), (channel), (log), (msgname), (msgcb), \ typesafe_cb_postargs(void, void *, (errcb), \ - (channel), enum side, \ + (channel), int, int, \ + const struct crypto_state *, \ + u64, \ const struct channel_id *, \ const char *, const u8 *), \ __VA_ARGS__) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index a7381eebd..15c4adc6a 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -334,10 +334,12 @@ struct subd *new_channel_subd_(struct lightningd *ld UNNEEDED, unsigned int (*msgcb)(struct subd * UNNEEDED, const u8 * UNNEEDED, const int *fds) UNNEEDED, void (*errcb)(void *channel UNNEEDED, - enum side sender UNNEEDED, + int peer_fd UNNEEDED, int gossip_fd UNNEEDED, + const struct crypto_state *cs UNNEEDED, + u64 gossip_index UNNEEDED, const struct channel_id *channel_id UNNEEDED, const char *desc UNNEEDED, - const u8 *errmsg) UNNEEDED, + const u8 *err_for_them) UNNEEDED, ...) { fprintf(stderr, "new_channel_subd_ called!\n"); abort(); } /* Generated stub for new_json_result */