mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-01 17:47:30 +01:00
subd: simplify and cleanup lifetime handling.
There are now only two kinds of subdaemons: global ones (hsmd, gossipd) and per-peer ones. We can handle many callbacks internally now. We can have a handler to set a new peer owner, and automatically do the cleanup of the old one if necessary, since we now know which ones are per-peer. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
a117d595a4
commit
5a256c724a
7 changed files with 194 additions and 166 deletions
|
@ -19,14 +19,6 @@
|
|||
#include <wire/gen_peer_wire.h>
|
||||
#include <wire/wire_sync.h>
|
||||
|
||||
static void gossip_finished(struct subd *gossip, int status)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
errx(1, "Gossip failed (exit status %i), exiting.",
|
||||
WEXITSTATUS(status));
|
||||
errx(1, "Gossip failed (signal %u), exiting.", WTERMSIG(status));
|
||||
}
|
||||
|
||||
static void peer_nongossip(struct subd *gossip, const u8 *msg,
|
||||
int peer_fd, int gossip_fd)
|
||||
{
|
||||
|
@ -117,10 +109,9 @@ void gossip_init(struct lightningd *ld)
|
|||
if (hsmfd < 0)
|
||||
fatal("Could not read fd from HSM: %s", strerror(errno));
|
||||
|
||||
ld->gossip = new_subd(ld, "lightning_gossipd", NULL,
|
||||
gossip_wire_type_name,
|
||||
gossip_msg, NULL, gossip_finished,
|
||||
take(&hsmfd), NULL);
|
||||
ld->gossip = new_global_subd(ld, "lightning_gossipd",
|
||||
gossip_wire_type_name, gossip_msg,
|
||||
take(&hsmfd), NULL);
|
||||
if (!ld->gossip)
|
||||
err(1, "Could not subdaemon gossip");
|
||||
|
||||
|
|
|
@ -196,10 +196,8 @@ static void shutdown_subdaemons(struct lightningd *ld)
|
|||
close(ld->hsm_fd);
|
||||
subd_shutdown(ld->gossip, 10);
|
||||
|
||||
/* Duplicates are OK: no need to check here. */
|
||||
list_for_each(&ld->peers, p, list)
|
||||
if (p->owner)
|
||||
subd_shutdown(p->owner, 0);
|
||||
while ((p = list_top(&ld->peers, struct peer, list)) != NULL)
|
||||
tal_free(p);
|
||||
}
|
||||
|
||||
struct chainparams *get_chainparams(const struct lightningd *ld)
|
||||
|
|
|
@ -54,7 +54,6 @@ struct connect {
|
|||
|
||||
/* FIXME: Reorder */
|
||||
struct funding_channel;
|
||||
static void peer_owner_finished(struct subd *subd, int status);
|
||||
static void peer_offer_channel(struct lightningd *ld,
|
||||
struct funding_channel *fc,
|
||||
const struct crypto_state *cs,
|
||||
|
@ -76,11 +75,19 @@ static void peer_accept_channel(struct lightningd *ld,
|
|||
int peer_fd, int gossip_fd,
|
||||
const u8 *open_msg);
|
||||
|
||||
static void peer_set_owner(struct peer *peer, struct subd *owner)
|
||||
{
|
||||
struct subd *old_owner = peer->owner;
|
||||
peer->owner = owner;
|
||||
|
||||
if (old_owner)
|
||||
subd_release_peer(old_owner, peer);
|
||||
}
|
||||
|
||||
static void destroy_peer(struct peer *peer)
|
||||
{
|
||||
/* Don't leave owner pointer dangling. */
|
||||
if (peer->owner && peer->owner->peer == peer)
|
||||
peer->owner->peer = NULL;
|
||||
/* Free any old owner still hanging around. */
|
||||
peer_set_owner(peer, NULL);
|
||||
list_del_from(&peer->ld->peers, &peer->list);
|
||||
}
|
||||
|
||||
|
@ -137,7 +144,7 @@ static void drop_to_chain(struct peer *peer)
|
|||
broadcast_tx(peer->ld->topology, peer, peer->last_tx, NULL);
|
||||
}
|
||||
|
||||
void peer_fail_permanent(struct peer *peer, const u8 *msg)
|
||||
void peer_fail_permanent(struct peer *peer, const u8 *msg TAKES)
|
||||
{
|
||||
/* BOLT #1:
|
||||
*
|
||||
|
@ -150,7 +157,7 @@ void peer_fail_permanent(struct peer *peer, const u8 *msg)
|
|||
peer_state_name(peer->state),
|
||||
(int)tal_len(msg), (char *)msg);
|
||||
peer->error = towire_error(peer, &all_channels, msg);
|
||||
peer->owner = tal_free(peer->owner);
|
||||
peer_set_owner(peer, NULL);
|
||||
if (taken(msg))
|
||||
tal_free(msg);
|
||||
|
||||
|
@ -198,7 +205,7 @@ void peer_fail_transient(struct peer *peer, const char *fmt, ...)
|
|||
return;
|
||||
}
|
||||
|
||||
peer->owner = NULL;
|
||||
peer_set_owner(peer, NULL);
|
||||
|
||||
/* If we haven't reached awaiting locked, we don't need to reconnect */
|
||||
if (!peer_persists(peer)) {
|
||||
|
@ -220,17 +227,6 @@ void peer_fail_transient(struct peer *peer, const char *fmt, ...)
|
|||
}
|
||||
}
|
||||
|
||||
/* When daemon reports a STATUS_FAIL_PEER_BAD, it goes here. */
|
||||
static void bad_peer(struct subd *subd, const char *msg)
|
||||
{
|
||||
struct peer *peer = subd->peer;
|
||||
|
||||
/* Don't close peer->owner, subd will clean that up. */
|
||||
peer->owner = NULL;
|
||||
subd->peer = NULL;
|
||||
peer_fail_permanent_str(peer, msg);
|
||||
}
|
||||
|
||||
void peer_set_condition(struct peer *peer, enum peer_state old_state,
|
||||
enum peer_state state)
|
||||
{
|
||||
|
@ -530,8 +526,6 @@ void peer_connected(struct lightningd *ld, const u8 *msg,
|
|||
/* Now, do we already know this peer? */
|
||||
peer = peer_by_id(ld, &id);
|
||||
if (peer) {
|
||||
struct subd *owner;
|
||||
|
||||
log_debug(peer->log, "Peer has reconnected, state %s",
|
||||
peer_state_name(peer->state));
|
||||
|
||||
|
@ -548,9 +542,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg,
|
|||
|
||||
/* Reconnect: discard old one. */
|
||||
case OPENINGD:
|
||||
/* This kills daemon (frees peer!) */
|
||||
tal_free(peer->owner);
|
||||
peer = NULL;
|
||||
peer = tal_free(peer);
|
||||
goto return_to_gossipd;
|
||||
|
||||
case ONCHAIND_CHEATED:
|
||||
|
@ -567,9 +559,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg,
|
|||
case CHANNELD_SHUTTING_DOWN:
|
||||
/* Stop any existing daemon, without triggering error
|
||||
* on this peer. */
|
||||
owner = peer->owner;
|
||||
peer->owner = NULL;
|
||||
tal_free(owner);
|
||||
peer_set_owner(peer, NULL);
|
||||
|
||||
peer_start_channeld(peer, &cs, peer_fd, gossip_fd, NULL,
|
||||
true);
|
||||
|
@ -579,9 +569,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg,
|
|||
case CLOSINGD_COMPLETE:
|
||||
/* Stop any existing daemon, without triggering error
|
||||
* on this peer. */
|
||||
owner = peer->owner;
|
||||
peer->owner = NULL;
|
||||
tal_free(owner);
|
||||
peer_set_owner(peer, NULL);
|
||||
|
||||
peer_start_closingd(peer, &cs, peer_fd, gossip_fd,
|
||||
true);
|
||||
|
@ -705,24 +693,6 @@ struct peer *peer_by_id(struct lightningd *ld, const struct pubkey *id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* When a per-peer subdaemon exits, see if we need to do anything. */
|
||||
static void peer_owner_finished(struct subd *subd, int status)
|
||||
{
|
||||
/* If peer has moved on, do nothing (can be NULL if it errored out) */
|
||||
if (!subd->peer || subd->peer->owner != subd) {
|
||||
log_debug(subd->ld->log, "Subdaemon %s died (%i), peer moved",
|
||||
subd->name, status);
|
||||
return;
|
||||
}
|
||||
|
||||
subd->peer->owner = NULL;
|
||||
|
||||
/* Don't do a transient error if it's already perm failed. */
|
||||
if (!subd->peer->error)
|
||||
peer_fail_transient(subd->peer, "Owning subdaemon %s died (%i)",
|
||||
subd->name, status);
|
||||
}
|
||||
|
||||
static void json_connect(struct command *cmd,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
|
@ -1085,10 +1055,8 @@ static enum watch_result onchain_tx_watched(struct peer *peer,
|
|||
struct sha256_double txid;
|
||||
|
||||
if (depth == 0) {
|
||||
struct subd *old_onchaind = peer->owner;
|
||||
log_unusual(peer->log, "Chain reorganization!");
|
||||
peer->owner = NULL;
|
||||
tal_free(old_onchaind);
|
||||
peer_set_owner(peer, NULL);
|
||||
|
||||
/* FIXME!
|
||||
topology_rescan(peer->ld->topology, peer->funding_txid);
|
||||
|
@ -1330,12 +1298,11 @@ static enum watch_result funding_spent(struct peer *peer,
|
|||
/* We could come from almost any state. */
|
||||
peer_set_condition(peer, peer->state, FUNDING_SPEND_SEEN);
|
||||
|
||||
peer->owner = new_subd(peer->ld,
|
||||
"lightning_onchaind", peer,
|
||||
onchain_wire_type_name,
|
||||
onchain_msg,
|
||||
NULL, peer_owner_finished,
|
||||
NULL, NULL);
|
||||
peer_set_owner(peer, new_peer_subd(peer->ld,
|
||||
"lightning_onchaind", peer,
|
||||
onchain_wire_type_name,
|
||||
onchain_msg,
|
||||
NULL));
|
||||
|
||||
if (!peer->owner) {
|
||||
log_broken(peer->log, "Could not subdaemon onchain: %s",
|
||||
|
@ -1890,14 +1857,11 @@ static void peer_start_closingd(struct peer *peer,
|
|||
return;
|
||||
}
|
||||
|
||||
peer->owner = new_subd(peer->ld,
|
||||
"lightning_closingd", peer,
|
||||
closing_wire_type_name,
|
||||
closing_msg,
|
||||
bad_peer,
|
||||
peer_owner_finished,
|
||||
take(&peer_fd),
|
||||
take(&gossip_fd), NULL);
|
||||
peer_set_owner(peer, new_peer_subd(peer->ld,
|
||||
"lightning_closingd", peer,
|
||||
closing_wire_type_name, closing_msg,
|
||||
take(&peer_fd), take(&gossip_fd),
|
||||
NULL));
|
||||
if (!peer->owner) {
|
||||
log_unusual(peer->log, "Could not subdaemon closing: %s",
|
||||
strerror(errno));
|
||||
|
@ -2066,15 +2030,14 @@ static bool peer_start_channeld(struct peer *peer,
|
|||
if (hsmfd < 0)
|
||||
fatal("Could not read fd from HSM: %s", strerror(errno));
|
||||
|
||||
peer->owner = new_subd(peer->ld,
|
||||
"lightning_channeld", peer,
|
||||
channel_wire_type_name,
|
||||
channel_msg,
|
||||
bad_peer,
|
||||
peer_owner_finished,
|
||||
take(&peer_fd),
|
||||
take(&gossip_fd),
|
||||
take(&hsmfd), NULL);
|
||||
peer_set_owner(peer, new_peer_subd(peer->ld,
|
||||
"lightning_channeld", peer,
|
||||
channel_wire_type_name,
|
||||
channel_msg,
|
||||
take(&peer_fd),
|
||||
take(&gossip_fd),
|
||||
take(&hsmfd), NULL));
|
||||
|
||||
if (!peer->owner) {
|
||||
log_unusual(peer->log, "Could not subdaemon channel: %s",
|
||||
strerror(errno));
|
||||
|
@ -2267,7 +2230,8 @@ static bool opening_funder_finished(struct subd *opening, const u8 *resp,
|
|||
utxos);
|
||||
tal_free(utxos);
|
||||
|
||||
fc->peer->owner = NULL;
|
||||
/* Unowned (will free openingd). */
|
||||
peer_set_owner(fc->peer, NULL);
|
||||
|
||||
if (!wire_sync_write(fc->peer->ld->hsm_fd, take(msg)))
|
||||
fatal("Could not write to HSM: %s", strerror(errno));
|
||||
|
@ -2275,7 +2239,7 @@ static bool opening_funder_finished(struct subd *opening, const u8 *resp,
|
|||
msg = hsm_sync_read(fc, fc->peer->ld);
|
||||
opening_got_hsm_funding_sig(fc, fds[0], fds[1], msg, &cs);
|
||||
|
||||
/* Tell opening daemon to exit. */
|
||||
/* openingd already exited. */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2341,14 +2305,14 @@ static bool opening_fundee_finished(struct subd *opening,
|
|||
watch_txo(peer, peer->ld->topology, peer, peer->funding_txid,
|
||||
peer->funding_outnum, funding_spent, NULL);
|
||||
|
||||
/* Unowned. */
|
||||
peer->owner = NULL;
|
||||
/* Unowned (will free openingd). */
|
||||
peer_set_owner(peer, NULL);
|
||||
|
||||
/* On to normal operation! */
|
||||
peer_start_channeld(peer, &cs, fds[0], fds[1], funding_signed, false);
|
||||
peer_set_condition(peer, OPENINGD, CHANNELD_AWAITING_LOCKIN);
|
||||
|
||||
/* Tell opening daemon to exit. */
|
||||
/* openingd already exited. */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2365,7 +2329,6 @@ static void peer_accept_channel(struct lightningd *ld,
|
|||
u8 *errmsg;
|
||||
u8 *msg;
|
||||
struct peer *peer;
|
||||
struct subd *opening;
|
||||
|
||||
assert(fromwire_peektype(open_msg) == WIRE_OPEN_CHANNEL);
|
||||
|
||||
|
@ -2380,17 +2343,15 @@ static void peer_accept_channel(struct lightningd *ld,
|
|||
}
|
||||
|
||||
peer_set_condition(peer, UNINITIALIZED, OPENINGD);
|
||||
opening = new_subd(ld,
|
||||
"lightning_openingd", peer,
|
||||
opening_wire_type_name,
|
||||
NULL, bad_peer, peer_owner_finished,
|
||||
take(&peer_fd), take(&gossip_fd), NULL);
|
||||
if (!opening) {
|
||||
peer_set_owner(peer,
|
||||
new_peer_subd(ld, "lightning_openingd", peer,
|
||||
opening_wire_type_name, NULL,
|
||||
take(&peer_fd), take(&gossip_fd), NULL));
|
||||
if (!peer->owner) {
|
||||
peer_fail_transient(peer, "Failed to subdaemon opening: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
peer->owner = opening;
|
||||
|
||||
/* They will open channel. */
|
||||
peer->funder = REMOTE;
|
||||
|
@ -2449,7 +2410,6 @@ static void peer_offer_channel(struct lightningd *ld,
|
|||
int peer_fd, int gossip_fd)
|
||||
{
|
||||
u8 *msg;
|
||||
struct subd *opening;
|
||||
u32 max_to_self_delay, max_minimum_depth;
|
||||
u64 min_effective_htlc_capacity_msat;
|
||||
struct utxo *utxos;
|
||||
|
@ -2470,19 +2430,18 @@ static void peer_offer_channel(struct lightningd *ld,
|
|||
fc->peer->push_msat = fc->push_msat;
|
||||
|
||||
peer_set_condition(fc->peer, UNINITIALIZED, OPENINGD);
|
||||
opening = new_subd(ld,
|
||||
"lightning_openingd", fc->peer,
|
||||
opening_wire_type_name,
|
||||
NULL, bad_peer, peer_owner_finished,
|
||||
take(&peer_fd), take(&gossip_fd), NULL);
|
||||
if (!opening) {
|
||||
peer_set_owner(fc->peer,
|
||||
new_peer_subd(ld,
|
||||
"lightning_openingd", fc->peer,
|
||||
opening_wire_type_name, NULL,
|
||||
take(&peer_fd), take(&gossip_fd), NULL));
|
||||
if (!fc->peer->owner) {
|
||||
fc->peer = tal_free(fc->peer);
|
||||
command_fail(fc->cmd,
|
||||
"Failed to launch openingd: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
fc->peer->owner = opening;
|
||||
|
||||
/* FIXME: This is wrong in several ways.
|
||||
*
|
||||
|
@ -2516,7 +2475,7 @@ static void peer_offer_channel(struct lightningd *ld,
|
|||
max_to_self_delay,
|
||||
min_effective_htlc_capacity_msat,
|
||||
cs, fc->peer->seed);
|
||||
subd_send_msg(opening, take(msg));
|
||||
subd_send_msg(fc->peer->owner, take(msg));
|
||||
|
||||
utxos = from_utxoptr_arr(fc, fc->utxomap);
|
||||
|
||||
|
@ -2532,7 +2491,8 @@ static void peer_offer_channel(struct lightningd *ld,
|
|||
tal_steal(fc->peer, fc);
|
||||
tal_add_destructor(fc, fail_fundchannel_command);
|
||||
|
||||
subd_req(fc, opening, take(msg), -1, 2, opening_funder_finished, fc);
|
||||
subd_req(fc, fc->peer->owner,
|
||||
take(msg), -1, 2, opening_funder_finished, fc);
|
||||
}
|
||||
|
||||
/* Peer has been released from gossip. Start opening. */
|
||||
|
|
|
@ -47,7 +47,7 @@ struct peer {
|
|||
/* Inside ld->peers. */
|
||||
struct list_node list;
|
||||
|
||||
/* What stage is this in? NULL during first creation. */
|
||||
/* Is there a single subdaemon responsible for us? */
|
||||
struct subd *owner;
|
||||
|
||||
/* History */
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <ccan/err/err.h>
|
||||
#include <ccan/io/fdpass/fdpass.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
|
@ -433,9 +434,15 @@ static struct io_plan *sd_msg_read(struct io_conn *conn, struct subd *sd)
|
|||
}
|
||||
|
||||
/* If they care, tell them about invalid peer behavior */
|
||||
if (sd->peerbadcb && type == STATUS_FAIL_PEER_BAD) {
|
||||
const char *errmsg = tal_fmt(sd, "%.*s", str_len, str);
|
||||
sd->peerbadcb(sd, errmsg);
|
||||
if (sd->peer && type == STATUS_FAIL_PEER_BAD) {
|
||||
/* Don't free ourselves; we're about to do that. */
|
||||
struct peer *peer = sd->peer;
|
||||
sd->peer = NULL;
|
||||
|
||||
peer_fail_permanent(peer,
|
||||
take(tal_dup_arr(peer, u8,
|
||||
(u8 *)str, str_len,
|
||||
0)));
|
||||
}
|
||||
return io_close(conn);
|
||||
}
|
||||
|
@ -495,9 +502,23 @@ static void destroy_subd(struct subd *sd)
|
|||
if (sd->conn)
|
||||
sd->conn = tal_free(sd->conn);
|
||||
|
||||
log_debug(sd->log, "finishing: %p", sd->finished);
|
||||
if (sd->finished)
|
||||
sd->finished(sd, status);
|
||||
/* Peer still attached? */
|
||||
if (sd->peer) {
|
||||
/* Don't loop back when we fail it. */
|
||||
struct peer *peer = sd->peer;
|
||||
sd->peer = NULL;
|
||||
peer_fail_transient(peer,
|
||||
"Owning subdaemon %s died (%i)",
|
||||
sd->name, status);
|
||||
}
|
||||
|
||||
if (sd->must_not_exit) {
|
||||
if (WIFEXITED(status))
|
||||
errx(1, "%s failed (exit status %i), exiting.",
|
||||
sd->name, WEXITSTATUS(status));
|
||||
errx(1, "%s failed (signal %u), exiting.",
|
||||
sd->name, WTERMSIG(status));
|
||||
}
|
||||
}
|
||||
|
||||
static struct io_plan *msg_send_next(struct io_conn *conn, struct subd *sd)
|
||||
|
@ -524,23 +545,18 @@ static struct io_plan *msg_setup(struct io_conn *conn, struct subd *sd)
|
|||
msg_send_next(conn, sd));
|
||||
}
|
||||
|
||||
struct subd *new_subd(struct lightningd *ld,
|
||||
const char *name,
|
||||
struct peer *peer,
|
||||
const char *(*msgname)(int msgtype),
|
||||
int (*msgcb)(struct subd *, const u8 *, const int *fds),
|
||||
void (*peerbadcb)(struct subd *, const char *),
|
||||
void (*finished)(struct subd *, int),
|
||||
...)
|
||||
static struct subd *new_subd(struct lightningd *ld,
|
||||
const char *name,
|
||||
struct peer *peer,
|
||||
const char *(*msgname)(int msgtype),
|
||||
int (*msgcb)(struct subd *, const u8 *, const int *fds),
|
||||
va_list *ap)
|
||||
{
|
||||
va_list ap;
|
||||
struct subd *sd = tal(ld, struct subd);
|
||||
int msg_fd;
|
||||
|
||||
va_start(ap, finished);
|
||||
sd->pid = subd(ld->daemon_dir, name, ld->dev_debug_subdaemon,
|
||||
&msg_fd, ld->dev_disconnect_fd, &ap);
|
||||
va_end(ap);
|
||||
&msg_fd, ld->dev_disconnect_fd, ap);
|
||||
if (sd->pid == (pid_t)-1) {
|
||||
log_unusual(ld->log, "subd %s failed: %s",
|
||||
name, strerror(errno));
|
||||
|
@ -549,10 +565,9 @@ struct subd *new_subd(struct lightningd *ld,
|
|||
sd->ld = ld;
|
||||
sd->log = new_log(sd, ld->log_book, "%s(%u):", name, sd->pid);
|
||||
sd->name = name;
|
||||
sd->finished = finished;
|
||||
sd->must_not_exit = false;
|
||||
sd->msgname = msgname;
|
||||
sd->msgcb = msgcb;
|
||||
sd->peerbadcb = peerbadcb;
|
||||
sd->fds_in = NULL;
|
||||
msg_queue_init(&sd->outq, sd);
|
||||
tal_add_destructor(sd, destroy_subd);
|
||||
|
@ -568,6 +583,40 @@ struct subd *new_subd(struct lightningd *ld,
|
|||
return sd;
|
||||
}
|
||||
|
||||
struct subd *new_global_subd(struct lightningd *ld,
|
||||
const char *name,
|
||||
const char *(*msgname)(int msgtype),
|
||||
int (*msgcb)(struct subd *, const u8 *,
|
||||
const int *fds),
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
struct subd *sd;
|
||||
|
||||
va_start(ap, msgcb);
|
||||
sd = new_subd(ld, name, NULL, msgname, msgcb, &ap);
|
||||
va_end(ap);
|
||||
|
||||
sd->must_not_exit = true;
|
||||
return sd;
|
||||
}
|
||||
|
||||
struct subd *new_peer_subd(struct lightningd *ld,
|
||||
const char *name,
|
||||
struct peer *peer,
|
||||
const char *(*msgname)(int msgtype),
|
||||
int (*msgcb)(struct subd *, const u8 *,
|
||||
const int *fds), ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct subd *sd;
|
||||
|
||||
va_start(ap, msgcb);
|
||||
sd = new_subd(ld, name, peer, msgname, msgcb, &ap);
|
||||
va_end(ap);
|
||||
return sd;
|
||||
}
|
||||
|
||||
void subd_send_msg(struct subd *sd, const u8 *msg_out)
|
||||
{
|
||||
/* FIXME: We should use unique upper bits for each daemon, then
|
||||
|
@ -600,33 +649,37 @@ void subd_req_(const tal_t *ctx,
|
|||
|
||||
void subd_shutdown(struct subd *sd, unsigned int seconds)
|
||||
{
|
||||
/* Idempotent. */
|
||||
if (!sd->conn)
|
||||
return;
|
||||
|
||||
log_debug(sd->log, "Shutting down");
|
||||
|
||||
/* No finished callback any more. */
|
||||
sd->finished = NULL;
|
||||
/* Don't let destroy_peer dereference us */
|
||||
if (sd->peer) {
|
||||
sd->peer->owner = NULL;
|
||||
sd->peer = NULL;
|
||||
}
|
||||
/* Don't free sd when we close connection manually. */
|
||||
tal_del_destructor(sd, destroy_subd);
|
||||
|
||||
/* This should make it exit; steal so it stays around. */
|
||||
tal_steal(sd->ld, sd);
|
||||
/* Close connection: should begin shutdown now. */
|
||||
sd->conn = tal_free(sd->conn);
|
||||
|
||||
/* Do we actually want to wait? */
|
||||
/* Wait for a while. */
|
||||
while (seconds) {
|
||||
if (waitpid(sd->pid, NULL, WNOHANG) > 0) {
|
||||
tal_del_destructor(sd, destroy_subd);
|
||||
return;
|
||||
}
|
||||
sleep(1);
|
||||
seconds--;
|
||||
}
|
||||
|
||||
/* Didn't die? This will kill it harder */
|
||||
sd->must_not_exit = false;
|
||||
destroy_subd(sd);
|
||||
tal_free(sd);
|
||||
}
|
||||
|
||||
void subd_release_peer(struct subd *owner, struct peer *peer)
|
||||
{
|
||||
/* If owner is a per-peer-daemon, and not already freeing itself... */
|
||||
if (owner->peer) {
|
||||
assert(owner->peer == peer);
|
||||
owner->peer = NULL;
|
||||
tal_free(owner);
|
||||
}
|
||||
}
|
||||
|
||||
char *opt_subd_debug(const char *optarg, struct lightningd *ld)
|
||||
|
|
|
@ -34,10 +34,6 @@ struct subd {
|
|||
/* Callback when non-reply message comes in. */
|
||||
int (*msgcb)(struct subd *, const u8 *, const int *);
|
||||
const char *(*msgname)(int msgtype);
|
||||
void (*finished)(struct subd *sd, int status);
|
||||
|
||||
/* Callback when the peer misbehaves. */
|
||||
void (*peerbadcb)(struct subd *, const char *what);
|
||||
|
||||
/* Buffer for input. */
|
||||
u8 *msg_in;
|
||||
|
@ -46,6 +42,9 @@ struct subd {
|
|||
size_t num_fds_in_read;
|
||||
int *fds_in;
|
||||
|
||||
/* For global daemons: we fail if they fail. */
|
||||
bool must_not_exit;
|
||||
|
||||
/* Messages queue up here. */
|
||||
struct msg_queue outq;
|
||||
|
||||
|
@ -54,14 +53,11 @@ struct subd {
|
|||
};
|
||||
|
||||
/**
|
||||
* new_subd - create a new subdaemon.
|
||||
* new_global_subd - create a new global subdaemon.
|
||||
* @ld: global state
|
||||
* @name: basename of daemon
|
||||
* @peer: peer to associate (if any).
|
||||
* @msgname: function to get name from messages
|
||||
* @msgcb: function to call when non-fatal message received (or NULL)
|
||||
* @peerbadcb: function to call for STATUS_FAIL_PEER_BAD (or NULL for none)
|
||||
* @finished: function to call when it's finished (with exit status).
|
||||
* @...: NULL-terminated list of pointers to fds to hand as fd 3, 4...
|
||||
* (can be take, if so, set to -1)
|
||||
*
|
||||
|
@ -69,13 +65,34 @@ struct subd {
|
|||
* that many @fds are received before calling again. If it returns -1, the
|
||||
* subdaemon is shutdown.
|
||||
*/
|
||||
struct subd *new_subd(struct lightningd *ld,
|
||||
const char *name,
|
||||
struct peer *peer,
|
||||
const char *(*msgname)(int msgtype),
|
||||
int (*msgcb)(struct subd *, const u8 *, const int *fds),
|
||||
void (*peerbadcb)(struct subd *, const char *),
|
||||
void (*finished)(struct subd *, int), ...);
|
||||
struct subd *new_global_subd(struct lightningd *ld,
|
||||
const char *name,
|
||||
const char *(*msgname)(int msgtype),
|
||||
int (*msgcb)(struct subd *, const u8 *,
|
||||
const int *fds),
|
||||
...);
|
||||
|
||||
/**
|
||||
* new_peer_subd - create a new subdaemon for a specific peer.
|
||||
* @ld: global state
|
||||
* @name: basename of daemon
|
||||
* @peer: peer to associate.
|
||||
* @msgname: function to get name from messages
|
||||
* @msgcb: function to call when non-fatal message received (or NULL)
|
||||
* @...: NULL-terminated list of pointers to fds to hand as fd 3, 4...
|
||||
* (can be take, if so, set to -1)
|
||||
*
|
||||
* @msgcb gets called with @fds set to NULL: if it returns a positive number,
|
||||
* that many @fds are received before calling again. If it returns -1, the
|
||||
* subdaemon is shutdown.
|
||||
*/
|
||||
struct subd *new_peer_subd(struct lightningd *ld,
|
||||
const char *name,
|
||||
struct peer *peer,
|
||||
const char *(*msgname)(int msgtype),
|
||||
int (*msgcb)(struct subd *, const u8 *,
|
||||
const int *fds),
|
||||
...);
|
||||
|
||||
/**
|
||||
* subd_raw - raw interface to get a subdaemon on an fd (for HSM)
|
||||
|
@ -126,6 +143,16 @@ void subd_req_(const tal_t *ctx,
|
|||
bool (*replycb)(struct subd *, const u8 *, const int *, void *),
|
||||
void *replycb_data);
|
||||
|
||||
/**
|
||||
* subd_release_peer - try to politely shut down a subdaemon.
|
||||
* @owner: subd which owned peer.
|
||||
* @peer: peer to release.
|
||||
*
|
||||
* If the subdaemon is not already shutting down, and it is a per-peer
|
||||
* subdaemon, this shuts it down.
|
||||
*/
|
||||
void subd_release_peer(struct subd *owner, struct peer *peer);
|
||||
|
||||
/**
|
||||
* subd_shutdown - try to politely shut down a subdaemon.
|
||||
* @subd: subd to shutdown.
|
||||
|
|
|
@ -1252,16 +1252,15 @@ class LightningDTests(BaseLightningDTests):
|
|||
# Reconnect.
|
||||
l1.rpc.connect(l2.info['id'], 'localhost:{}'.format(l2.info['port']))
|
||||
|
||||
# We should get a message about old one exiting.
|
||||
# We should get a message about reconnecting.
|
||||
l2.daemon.wait_for_log('Peer has reconnected, state OPENINGD')
|
||||
l2.daemon.wait_for_log('Owning subdaemon lightning_openingd died')
|
||||
|
||||
# Should work fine.
|
||||
l1.rpc.fundchannel(l2.info['id'], 20000)
|
||||
l1.daemon.wait_for_log('sendrawtx exit 0')
|
||||
|
||||
# Just to be sure, second openingd hand over to channeld.
|
||||
l2.daemon.wait_for_log('Subdaemon lightning_openingd died \(0\)')
|
||||
l2.daemon.wait_for_log('lightning_openingd.*REPLY WIRE_OPENING_FUNDEE_REPLY with 2 fds')
|
||||
|
||||
def test_reconnect_normal(self):
|
||||
# Should reconnect fine even if locked message gets lost.
|
||||
|
|
Loading…
Add table
Reference in a new issue