connectd: rely on the master to tell us to reconnect.

connectd tells master about every disconnection, and master knows
whether it's important to reconnect.  Just get the master to invoke a new
connect command if it considers the peer important!

The only twist is timeouts: we don't want to immediately reconnect if
we've failed to connect.  To solve this, connectd passes a 'delaytime'
to the master when a connection fails, and the master passes it back
when it asks for a connection.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2018-08-09 09:55:29 +09:30 committed by Christian Decker
parent 30f08cc2b0
commit 8939a5001b
14 changed files with 116 additions and 190 deletions

View file

@ -67,43 +67,6 @@
#define INITIAL_WAIT_SECONDS 1 #define INITIAL_WAIT_SECONDS 1
#define MAX_WAIT_SECONDS 300 #define MAX_WAIT_SECONDS 300
/* We put everything in this struct (redundantly) to pass it to timer cb */
struct important_peerid {
struct daemon *daemon;
struct pubkey id;
/* How long to wait after failed connect */
unsigned int wait_seconds;
/* The timer we're using to reconnect */
struct oneshot *reconnect_timer;
};
/* We keep a set of peer ids we're always trying to reach. */
static const struct pubkey *
important_peerid_keyof(const struct important_peerid *imp)
{
return &imp->id;
}
static bool important_peerid_eq(const struct important_peerid *imp,
const struct pubkey *key)
{
return pubkey_eq(&imp->id, key);
}
static size_t important_peerid_hash(const struct pubkey *id)
{
return siphash24(siphash_seed(), id, sizeof(*id));
}
HTABLE_DEFINE_TYPE(struct important_peerid,
important_peerid_keyof,
important_peerid_hash,
important_peerid_eq,
important_peerid_map);
struct listen_fd { struct listen_fd {
int fd; int fd;
/* If we bind() IPv6 then IPv4 to same port, we *may* fail to listen() /* If we bind() IPv6 then IPv4 to same port, we *may* fail to listen()
@ -151,15 +114,9 @@ struct daemon {
struct timers timers; struct timers timers;
/* Important peers */
struct important_peerid_map important_peerids;
/* Local and global features to offer to peers. */ /* Local and global features to offer to peers. */
u8 *localfeatures, *globalfeatures; u8 *localfeatures, *globalfeatures;
/* Automatically reconnect. */
bool reconnect;
/* Allow localhost to be considered "public" */ /* Allow localhost to be considered "public" */
bool dev_allow_localhost; bool dev_allow_localhost;
@ -192,6 +149,9 @@ struct reaching {
/* How far did we get? */ /* How far did we get? */
const char *connstate; const char *connstate;
/* How many seconds did we wait this time? */
u32 seconds_waited;
}; };
struct peer { struct peer {
@ -225,9 +185,6 @@ struct addrhint {
struct wireaddr_internal addr; struct wireaddr_internal addr;
}; };
/* FIXME: Reorder */
static void retry_important(struct important_peerid *imp);
static struct peer *find_reconnecting_peer(struct daemon *daemon, static struct peer *find_reconnecting_peer(struct daemon *daemon,
const struct pubkey *id) const struct pubkey *id)
{ {
@ -865,7 +822,7 @@ static struct io_plan *connect_init(struct daemon_conn *master,
daemon, msg, daemon, msg,
&daemon->id, &daemon->globalfeatures, &daemon->id, &daemon->globalfeatures,
&daemon->localfeatures, &proposed_wireaddr, &daemon->localfeatures, &proposed_wireaddr,
&proposed_listen_announce, &daemon->reconnect, &proposed_listen_announce,
&proxyaddr, &daemon->use_proxy_always, &proxyaddr, &daemon->use_proxy_always,
&daemon->dev_allow_localhost, &daemon->use_dns, &daemon->dev_allow_localhost, &daemon->use_dns,
&tor_password)) { &tor_password)) {
@ -955,48 +912,40 @@ struct io_plan *connection_out(struct io_conn *conn, struct reaching *reach)
handshake_out_success, reach); handshake_out_success, reach);
} }
static void PRINTF_FMT(3,4) static void PRINTF_FMT(4,5)
connect_failed(struct daemon *daemon, connect_failed(struct daemon *daemon,
const struct pubkey *id, const struct pubkey *id,
u32 seconds_waited,
const char *errfmt, ...) const char *errfmt, ...)
{ {
u8 *msg; u8 *msg;
struct important_peerid *imp;
va_list ap; va_list ap;
char *err; char *err;
u32 wait_seconds;
va_start(ap, errfmt); va_start(ap, errfmt);
err = tal_vfmt(tmpctx, errfmt, ap); err = tal_vfmt(tmpctx, errfmt, ap);
va_end(ap); va_end(ap);
/* Wait twice as long to reconnect, between min and max. */
wait_seconds = seconds_waited * 2;
if (wait_seconds > MAX_WAIT_SECONDS)
wait_seconds = MAX_WAIT_SECONDS;
if (wait_seconds < INITIAL_WAIT_SECONDS)
wait_seconds = INITIAL_WAIT_SECONDS;
/* Tell any connect command what happened. */ /* Tell any connect command what happened. */
msg = towire_connectctl_connect_failed(NULL, id, err); msg = towire_connectctl_connect_failed(NULL, id, err, wait_seconds);
daemon_conn_send(&daemon->master, take(msg)); daemon_conn_send(&daemon->master, take(msg));
status_trace("Failed connected out for %s: %s", status_trace("Failed connected out for %s: %s",
type_to_string(tmpctx, struct pubkey, id), type_to_string(tmpctx, struct pubkey, id),
err); err);
/* If we want to keep trying, do so. */
imp = important_peerid_map_get(&daemon->important_peerids, id);
if (imp) {
imp->wait_seconds *= 2;
if (imp->wait_seconds > MAX_WAIT_SECONDS)
imp->wait_seconds = MAX_WAIT_SECONDS;
status_trace("...will try again in %u seconds",
imp->wait_seconds);
/* If important_id freed, this will be removed too */
imp->reconnect_timer
= new_reltimer(&daemon->timers, imp,
time_from_sec(imp->wait_seconds),
retry_important, imp);
}
} }
static void destroy_io_conn(struct io_conn *conn, struct reaching *reach) static void destroy_io_conn(struct io_conn *conn, struct reaching *reach)
{ {
connect_failed(reach->daemon, &reach->id, connect_failed(reach->daemon, &reach->id, reach->seconds_waited,
"%s: %s", reach->connstate, strerror(errno)); "%s: %s", reach->connstate, strerror(errno));
tal_free(reach); tal_free(reach);
} }
@ -1128,7 +1077,9 @@ gossip_resolve_addr(const tal_t *ctx, const struct pubkey *id)
return addr; return addr;
} }
static void try_reach_peer(struct daemon *daemon, const struct pubkey *id) static void try_reach_peer(struct daemon *daemon,
const struct pubkey *id,
u32 seconds_waited)
{ {
struct wireaddr_internal *a; struct wireaddr_internal *a;
struct addrhint *hint; struct addrhint *hint;
@ -1166,7 +1117,7 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id)
} }
if (!a) { if (!a) {
connect_failed(daemon, id, "No address known"); connect_failed(daemon, id, seconds_waited, "No address known");
return; return;
} }
@ -1221,7 +1172,7 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id)
fd = socket(af, SOCK_STREAM, 0); fd = socket(af, SOCK_STREAM, 0);
if (fd < 0) { if (fd < 0) {
connect_failed(daemon, id, connect_failed(daemon, id, seconds_waited,
"Can't open %i socket for %s (%s)", "Can't open %i socket for %s (%s)",
af, af,
type_to_string(tmpctx, struct pubkey, id), type_to_string(tmpctx, struct pubkey, id),
@ -1235,6 +1186,7 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id)
reach->id = *id; reach->id = *id;
reach->addr = *a; reach->addr = *a;
reach->connstate = "Connection establishment"; reach->connstate = "Connection establishment";
reach->seconds_waited = seconds_waited;
list_add_tail(&daemon->reaching, &reach->list); list_add_tail(&daemon->reaching, &reach->list);
tal_add_destructor(reach, destroy_reaching); tal_add_destructor(reach, destroy_reaching);
@ -1244,34 +1196,16 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id)
io_new_conn(reach, fd, conn_init, reach); io_new_conn(reach, fd, conn_init, reach);
} }
/* Called from timer, so needs single-arg declaration */
static void retry_important(struct important_peerid *imp)
{
/* In case we've come off a timer, don't leave dangling pointer */
imp->reconnect_timer = NULL;
/* With --dev-no-reconnect or --offline, we only want explicit
* connects */
if (!imp->daemon->reconnect)
return;
try_reach_peer(imp->daemon, &imp->id);
}
static struct io_plan *connect_to_peer(struct io_conn *conn, static struct io_plan *connect_to_peer(struct io_conn *conn,
struct daemon *daemon, const u8 *msg) struct daemon *daemon, const u8 *msg)
{ {
struct pubkey id; struct pubkey id;
struct important_peerid *imp; u32 seconds_waited;
if (!fromwire_connectctl_connect_to_peer(msg, &id)) if (!fromwire_connectctl_connect_to_peer(msg, &id, &seconds_waited))
master_badmsg(WIRE_CONNECTCTL_CONNECT_TO_PEER, msg); master_badmsg(WIRE_CONNECTCTL_CONNECT_TO_PEER, msg);
/* If this is an important peer, free any outstanding timer */ try_reach_peer(daemon, &id, seconds_waited);
imp = important_peerid_map_get(&daemon->important_peerids, &id);
if (imp)
imp->reconnect_timer = tal_free(imp->reconnect_timer);
try_reach_peer(daemon, &id);
return daemon_conn_read_next(conn, &daemon->master); return daemon_conn_read_next(conn, &daemon->master);
} }
@ -1292,46 +1226,11 @@ static struct io_plan *addr_hint(struct io_conn *conn,
return daemon_conn_read_next(conn, &daemon->master); return daemon_conn_read_next(conn, &daemon->master);
} }
static struct io_plan *peer_important(struct io_conn *conn,
struct daemon *daemon, const u8 *msg)
{
struct pubkey id;
bool important;
struct important_peerid *imp;
if (!fromwire_connectctl_peer_important(msg, &id, &important))
master_badmsg(WIRE_CONNECTCTL_PEER_IMPORTANT, msg);
imp = important_peerid_map_get(&daemon->important_peerids, &id);
if (important) {
if (!imp) {
imp = tal(daemon, struct important_peerid);
imp->id = id;
imp->daemon = daemon;
imp->wait_seconds = INITIAL_WAIT_SECONDS;
important_peerid_map_add(&daemon->important_peerids,
imp);
/* Start trying to reaching it now. */
retry_important(imp);
}
} else {
if (imp) {
important_peerid_map_del(&daemon->important_peerids,
imp);
/* Stop trying to reach it (if we are) */
tal_free(find_reaching(daemon, &imp->id));
}
}
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *peer_disconnected(struct io_conn *conn, static struct io_plan *peer_disconnected(struct io_conn *conn,
struct daemon *daemon, const u8 *msg) struct daemon *daemon, const u8 *msg)
{ {
struct pubkey id, *key; struct pubkey id, *key;
struct peer *peer; struct peer *peer;
struct important_peerid *imp;
if (!fromwire_connectctl_peer_disconnected(msg, &id)) if (!fromwire_connectctl_peer_disconnected(msg, &id))
master_badmsg(WIRE_CONNECTCTL_PEER_DISCONNECTED, msg); master_badmsg(WIRE_CONNECTCTL_PEER_DISCONNECTED, msg);
@ -1352,11 +1251,6 @@ static struct io_plan *peer_disconnected(struct io_conn *conn,
if (peer) if (peer)
io_wake(peer); io_wake(peer);
imp = important_peerid_map_get(&daemon->important_peerids, &id);
if (imp) {
imp->wait_seconds = INITIAL_WAIT_SECONDS;
retry_important(imp);
}
return daemon_conn_read_next(conn, &daemon->master); return daemon_conn_read_next(conn, &daemon->master);
} }
@ -1378,9 +1272,6 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
case WIRE_CONNECTCTL_PEER_ADDRHINT: case WIRE_CONNECTCTL_PEER_ADDRHINT:
return addr_hint(conn, daemon, master->msg_in); return addr_hint(conn, daemon, master->msg_in);
case WIRE_CONNECTCTL_PEER_IMPORTANT:
return peer_important(conn, daemon, master->msg_in);
case WIRE_CONNECTCTL_PEER_DISCONNECTED: case WIRE_CONNECTCTL_PEER_DISCONNECTED:
return peer_disconnected(conn, daemon, master->msg_in); return peer_disconnected(conn, daemon, master->msg_in);
@ -1418,7 +1309,6 @@ int main(int argc, char *argv[])
list_head_init(&daemon->reconnecting); list_head_init(&daemon->reconnecting);
list_head_init(&daemon->reaching); list_head_init(&daemon->reaching);
list_head_init(&daemon->addrhints); list_head_init(&daemon->addrhints);
important_peerid_map_init(&daemon->important_peerids);
timers_init(&daemon->timers, time_mono()); timers_init(&daemon->timers, time_mono());
daemon->broken_resolver_response = NULL; daemon->broken_resolver_response = NULL;
daemon->listen_fds = tal_arr(daemon, struct listen_fd, 0); daemon->listen_fds = tal_arr(daemon, struct listen_fd, 0);

View file

@ -11,7 +11,6 @@ connectctl_init,,lfeatures,lflen*u8
connectctl_init,,num_wireaddrs,u16 connectctl_init,,num_wireaddrs,u16
connectctl_init,,wireaddrs,num_wireaddrs*struct wireaddr_internal connectctl_init,,wireaddrs,num_wireaddrs*struct wireaddr_internal
connectctl_init,,listen_announce,num_wireaddrs*enum addr_listen_announce connectctl_init,,listen_announce,num_wireaddrs*enum addr_listen_announce
connectctl_init,,reconnect,bool
connectctl_init,,tor_proxyaddr,?struct wireaddr connectctl_init,,tor_proxyaddr,?struct wireaddr
connectctl_init,,use_tor_proxy_always,bool connectctl_init,,use_tor_proxy_always,bool
connectctl_init,,dev_allow_localhost,bool connectctl_init,,dev_allow_localhost,bool
@ -45,16 +44,13 @@ connectctl_peer_addrhint,,addr,struct wireaddr_internal
# Master -> connectd: connect to a peer. # Master -> connectd: connect to a peer.
connectctl_connect_to_peer,2001 connectctl_connect_to_peer,2001
connectctl_connect_to_peer,,id,struct pubkey connectctl_connect_to_peer,,id,struct pubkey
connectctl_connect_to_peer,,seconds_waited,u32
# Connectd->master: connect failed. # Connectd->master: connect failed.
connectctl_connect_failed,2020 connectctl_connect_failed,2020
connectctl_connect_failed,,id,struct pubkey connectctl_connect_failed,,id,struct pubkey
connectctl_connect_failed,,failreason,wirestring connectctl_connect_failed,,failreason,wirestring
connectctl_connect_failed,,seconds_to_delay,u32
# Master -> connectd: try to always maintain connection to this peer (or not)
connectctl_peer_important,2010
connectctl_peer_important,,id,struct pubkey
connectctl_peer_important,,important,bool
# Connectd -> master: we got a peer. Two fds: peer and gossip # Connectd -> master: we got a peer. Two fds: peer and gossip
connect_peer_connected,2002 connect_peer_connected,2002

1 #include <common/cryptomsg.h>
11 connectctl_init,,wireaddrs,num_wireaddrs*struct wireaddr_internal
12 connectctl_init,,listen_announce,num_wireaddrs*enum addr_listen_announce
13 connectctl_init,,reconnect,bool connectctl_init,,tor_proxyaddr,?struct wireaddr
connectctl_init,,tor_proxyaddr,?struct wireaddr
14 connectctl_init,,use_tor_proxy_always,bool
15 connectctl_init,,dev_allow_localhost,bool
16 connectctl_init,,use_dns,bool
44 # Master -> connectd: try to always maintain connection to this peer (or not) connectctl_connect_failed,,failreason,wirestring
45 connectctl_peer_important,2010 connectctl_connect_failed,,seconds_to_delay,u32
46 connectctl_peer_important,,id,struct pubkey # Connectd -> master: we got a peer. Two fds: peer and gossip
47 connect_peer_connected,2002
48 connectctl_peer_important,,important,bool connect_peer_connected,,id,struct pubkey
49 # Connectd -> master: we got a peer. Two fds: peer and gossip connect_peer_connected,,addr,struct wireaddr_internal
50 connect_peer_connected,2002 connect_peer_connected,,crypto_state,struct crypto_state
51 connect_peer_connected,,id,struct pubkey connect_peer_connected,,gflen,u16
52 connect_peer_connected,,addr,struct wireaddr_internal connect_peer_connected,,gfeatures,gflen*u8
53 connect_peer_connected,,crypto_state,struct crypto_state connect_peer_connected,,lflen,u16
connect_peer_connected,,gflen,u16
connect_peer_connected,,gfeatures,gflen*u8
connect_peer_connected,,lflen,u16
connect_peer_connected,,lfeatures,lflen*u8
54 # master -> connectd: peer has disconnected. connect_peer_connected,,lfeatures,lflen*u8
55 connectctl_peer_disconnected,2015 # master -> connectd: peer has disconnected.
56 connectctl_peer_disconnected,,id,struct pubkey connectctl_peer_disconnected,2015

View file

@ -7,6 +7,7 @@
#include <hsmd/gen_hsm_client_wire.h> #include <hsmd/gen_hsm_client_wire.h>
#include <inttypes.h> #include <inttypes.h>
#include <lightningd/channel.h> #include <lightningd/channel.h>
#include <lightningd/connect_control.h>
#include <lightningd/gen_channel_state_names.h> #include <lightningd/gen_channel_state_names.h>
#include <lightningd/hsm_control.h> #include <lightningd/hsm_control.h>
#include <lightningd/jsonrpc.h> #include <lightningd/jsonrpc.h>
@ -22,7 +23,8 @@ static bool connects_to_peer(struct subd *owner)
return owner && owner->talks_to_peer; return owner && owner->talks_to_peer;
} }
void channel_set_owner(struct channel *channel, struct subd *owner) void channel_set_owner(struct channel *channel, struct subd *owner,
bool reconnect)
{ {
struct subd *old_owner = channel->owner; struct subd *old_owner = channel->owner;
channel->owner = owner; channel->owner = owner;
@ -33,7 +35,12 @@ void channel_set_owner(struct channel *channel, struct subd *owner)
u8 *msg = towire_connectctl_peer_disconnected(NULL, u8 *msg = towire_connectctl_peer_disconnected(NULL,
&channel->peer->id); &channel->peer->id);
subd_send_msg(channel->peer->ld->connectd, take(msg)); subd_send_msg(channel->peer->ld->connectd, take(msg));
channel->connected = false; }
if (reconnect) {
/* Reconnect after 1 second: prevents some spurious
* reconnects during tests. */
delay_then_reconnect(channel, 1);
} }
} }
channel->connected = connects_to_peer(owner); channel->connected = connects_to_peer(owner);
@ -88,7 +95,7 @@ static void destroy_channel(struct channel *channel)
htlc_state_name(hin->hstate)); htlc_state_name(hin->hstate));
/* Free any old owner still hanging around. */ /* Free any old owner still hanging around. */
channel_set_owner(channel, NULL); channel_set_owner(channel, NULL, false);
list_del_from(&channel->peer->channels, &channel->list); list_del_from(&channel->peer->channels, &channel->list);
} }
@ -342,7 +349,7 @@ void channel_fail_permanent(struct channel *channel, const char *fmt, ...)
channel->error = towire_errorfmt(channel, &cid, "%s", why); channel->error = towire_errorfmt(channel, &cid, "%s", why);
} }
channel_set_owner(channel, NULL); channel_set_owner(channel, NULL, false);
/* Drop non-cooperatively (unilateral) to chain. */ /* Drop non-cooperatively (unilateral) to chain. */
drop_to_chain(ld, channel, false); drop_to_chain(ld, channel, false);
tal_free(why); tal_free(why);
@ -405,5 +412,5 @@ void channel_fail_transient(struct channel *channel, const char *fmt, ...)
} }
#endif #endif
channel_set_owner(channel, NULL); channel_set_owner(channel, NULL, true);
} }

View file

@ -152,7 +152,8 @@ void delete_channel(struct channel *channel);
const char *channel_state_name(const struct channel *channel); const char *channel_state_name(const struct channel *channel);
const char *channel_state_str(enum channel_state state); const char *channel_state_str(enum channel_state state);
void channel_set_owner(struct channel *channel, struct subd *owner); void channel_set_owner(struct channel *channel, struct subd *owner,
bool reconnect);
/* Channel has failed, but can try again. */ /* Channel has failed, but can try again. */
PRINTF_FMT(2,3) void channel_fail_transient(struct channel *channel, PRINTF_FMT(2,3) void channel_fail_transient(struct channel *channel,

View file

@ -206,7 +206,8 @@ bool peer_start_channeld(struct channel *channel,
channel_set_billboard, channel_set_billboard,
take(&peer_fd), take(&peer_fd),
take(&gossip_fd), take(&gossip_fd),
take(&hsmfd), NULL)); take(&hsmfd), NULL),
false);
if (!channel->owner) { if (!channel->owner) {
log_unusual(channel->log, "Could not subdaemon channel: %s", log_unusual(channel->log, "Could not subdaemon channel: %s",

View file

@ -89,7 +89,7 @@ static void peer_closing_complete(struct channel *channel, const u8 *msg)
} }
/* Don't report spurious failure when closingd exits. */ /* Don't report spurious failure when closingd exits. */
channel_set_owner(channel, NULL); channel_set_owner(channel, NULL, false);
/* Clear any transient negotiation messages */ /* Clear any transient negotiation messages */
channel_set_billboard(channel, false, NULL); channel_set_billboard(channel, false, NULL);
@ -155,7 +155,9 @@ void peer_start_closingd(struct channel *channel,
channel_set_billboard, channel_set_billboard,
take(&peer_fd), take(&gossip_fd), take(&peer_fd), take(&gossip_fd),
take(&hsmfd), take(&hsmfd),
NULL)); NULL),
false);
if (!channel->owner) { if (!channel->owner) {
log_unusual(channel->log, "Could not subdaemon closing: %s", log_unusual(channel->log, "Could not subdaemon closing: %s",
strerror(errno)); strerror(errno));

View file

@ -4,6 +4,8 @@
#include <ccan/list/list.h> #include <ccan/list/list.h>
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
#include <common/features.h> #include <common/features.h>
#include <common/memleak.h>
#include <common/timeout.h>
#include <common/wireaddr.h> #include <common/wireaddr.h>
#include <connectd/gen_connect_wire.h> #include <connectd/gen_connect_wire.h>
#include <errno.h> #include <errno.h>
@ -174,7 +176,7 @@ static void json_connect(struct command *cmd,
subd_send_msg(cmd->ld->connectd, take(msg)); subd_send_msg(cmd->ld->connectd, take(msg));
} }
msg = towire_connectctl_connect_to_peer(NULL, &id); msg = towire_connectctl_connect_to_peer(NULL, &id, 0);
subd_send_msg(cmd->ld->connectd, take(msg)); subd_send_msg(cmd->ld->connectd, take(msg));
/* Leave this here for peer_connected or connect_failed. */ /* Leave this here for peer_connected or connect_failed. */
@ -190,13 +192,52 @@ static const struct json_command connect_command = {
}; };
AUTODATA(json_command, &connect_command); AUTODATA(json_command, &connect_command);
struct delayed_reconnect {
struct channel *channel;
u32 seconds_delayed;
};
static void maybe_reconnect(struct delayed_reconnect *d)
{
struct peer *peer = d->channel->peer;
/* Might have gone onchain since we started timer. */
if (channel_active(d->channel)) {
u8 *msg = towire_connectctl_connect_to_peer(NULL, &peer->id,
d->seconds_delayed);
subd_send_msg(peer->ld->connectd, take(msg));
}
tal_free(d);
}
void delay_then_reconnect(struct channel *channel, u32 seconds_delay)
{
struct delayed_reconnect *d;
struct lightningd *ld = channel->peer->ld;
if (!ld->reconnect)
return;
d = tal(channel, struct delayed_reconnect);
d->channel = channel;
d->seconds_delayed = seconds_delay;
log_debug(channel->log, "Will try reconnect in %u seconds",
seconds_delay);
notleak(new_reltimer(&ld->timers, d, time_from_sec(seconds_delay),
maybe_reconnect, d));
}
static void connect_failed(struct lightningd *ld, const u8 *msg) static void connect_failed(struct lightningd *ld, const u8 *msg)
{ {
struct pubkey id; struct pubkey id;
char *err; char *err;
struct connect *c; struct connect *c;
u32 seconds_to_delay;
struct channel *channel;
if (!fromwire_connectctl_connect_failed(tmpctx, msg, &id, &err)) if (!fromwire_connectctl_connect_failed(tmpctx, msg, &id, &err,
&seconds_to_delay))
fatal("Connect gave bad CONNECTCTL_CONNECT_FAILED message %s", fatal("Connect gave bad CONNECTCTL_CONNECT_FAILED message %s",
tal_hex(msg, msg)); tal_hex(msg, msg));
@ -205,6 +246,11 @@ static void connect_failed(struct lightningd *ld, const u8 *msg)
/* They delete themselves from list */ /* They delete themselves from list */
command_fail(c->cmd, LIGHTNINGD, "%s", err); command_fail(c->cmd, LIGHTNINGD, "%s", err);
} }
/* If we have an active channel, then reconnect. */
channel = active_channel_by_id(ld, &id, NULL);
if (channel)
delay_then_reconnect(channel, seconds_to_delay);
} }
void connect_succeeded(struct lightningd *ld, const struct pubkey *id) void connect_succeeded(struct lightningd *ld, const struct pubkey *id)
@ -244,7 +290,6 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd
case WIRE_CONNECTCTL_ACTIVATE: case WIRE_CONNECTCTL_ACTIVATE:
case WIRE_CONNECTCTL_PEER_ADDRHINT: case WIRE_CONNECTCTL_PEER_ADDRHINT:
case WIRE_CONNECTCTL_CONNECT_TO_PEER: case WIRE_CONNECTCTL_CONNECT_TO_PEER:
case WIRE_CONNECTCTL_PEER_IMPORTANT:
case WIRE_CONNECTCTL_PEER_DISCONNECTED: case WIRE_CONNECTCTL_PEER_DISCONNECTED:
/* This is a reply, so never gets through to here. */ /* This is a reply, so never gets through to here. */
case WIRE_CONNECTCTL_INIT_REPLY: case WIRE_CONNECTCTL_INIT_REPLY:
@ -333,7 +378,7 @@ int connectd_init(struct lightningd *ld)
tmpctx, &ld->id, tmpctx, &ld->id,
get_offered_global_features(tmpctx), get_offered_global_features(tmpctx),
get_offered_local_features(tmpctx), wireaddrs, get_offered_local_features(tmpctx), wireaddrs,
listen_announce, ld->reconnect, listen_announce,
ld->proxyaddr, ld->use_proxy_always || ld->pure_tor_setup, ld->proxyaddr, ld->use_proxy_always || ld->pure_tor_setup,
allow_localhost, ld->config.use_dns, allow_localhost, ld->config.use_dns,
ld->tor_service_password ? ld->tor_service_password : ""); ld->tor_service_password ? ld->tor_service_password : "");

View file

@ -9,6 +9,7 @@ struct pubkey;
int connectd_init(struct lightningd *ld); int connectd_init(struct lightningd *ld);
void connectd_activate(struct lightningd *ld); void connectd_activate(struct lightningd *ld);
void delay_then_reconnect(struct channel *channel, u32 seconds_delay);
void connect_succeeded(struct lightningd *ld, const struct pubkey *id); void connect_succeeded(struct lightningd *ld, const struct pubkey *id);
void gossip_connect_result(struct lightningd *ld, const u8 *msg); void gossip_connect_result(struct lightningd *ld, const u8 *msg);

View file

@ -82,7 +82,7 @@ static enum watch_result onchain_tx_watched(struct channel *channel,
u32 blockheight = channel->peer->ld->topology->tip->height; u32 blockheight = channel->peer->ld->topology->tip->height;
if (depth == 0) { if (depth == 0) {
log_unusual(channel->log, "Chain reorganization!"); log_unusual(channel->log, "Chain reorganization!");
channel_set_owner(channel, NULL); channel_set_owner(channel, NULL, false);
/* FIXME! /* FIXME!
topology_rescan(peer->ld->topology, peer->funding_txid); topology_rescan(peer->ld->topology, peer->funding_txid);
@ -377,7 +377,7 @@ static void onchain_error(struct channel *channel,
/* FIXME: re-launch? */ /* FIXME: re-launch? */
log_broken(channel->log, "%s", desc); log_broken(channel->log, "%s", desc);
channel_set_billboard(channel, true, desc); channel_set_billboard(channel, true, desc);
channel_set_owner(channel, NULL); channel_set_owner(channel, NULL, false);
} }
/* With a reorg, this can get called multiple times; each time we'll kill /* With a reorg, this can get called multiple times; each time we'll kill
@ -412,7 +412,8 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
onchain_error, onchain_error,
channel_set_billboard, channel_set_billboard,
take(&hsmfd), take(&hsmfd),
NULL)); NULL),
false);
if (!channel->owner) { if (!channel->owner) {
log_broken(channel->log, "Could not subdaemon onchain: %s", log_broken(channel->log, "Could not subdaemon onchain: %s",

View file

@ -218,16 +218,6 @@ static void funding_broadcast_failed(struct channel *channel,
exitstatus, err); exitstatus, err);
} }
void tell_connectd_peer_is_important(struct lightningd *ld,
const struct channel *channel)
{
u8 *msg;
/* Tell connectd we need to keep connection to this peer */
msg = towire_connectctl_peer_important(NULL, &channel->peer->id, true);
subd_send_msg(ld->connectd, take(msg));
}
static void opening_funder_finished(struct subd *openingd, const u8 *resp, static void opening_funder_finished(struct subd *openingd, const u8 *resp,
const int *fds, const int *fds,
struct funding_channel *fc) struct funding_channel *fc)
@ -380,8 +370,6 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp,
channel_watch_funding(ld, channel); channel_watch_funding(ld, channel);
tell_connectd_peer_is_important(ld, channel);
/* Start normal channel daemon. */ /* Start normal channel daemon. */
peer_start_channeld(channel, &cs, fds[0], fds[1], NULL, false); peer_start_channeld(channel, &cs, fds[0], fds[1], NULL, false);
@ -492,8 +480,6 @@ static void opening_fundee_finished(struct subd *openingd,
channel_watch_funding(ld, channel); channel_watch_funding(ld, channel);
tell_connectd_peer_is_important(ld, channel);
/* On to normal operation! */ /* On to normal operation! */
peer_start_channeld(channel, &cs, peer_start_channeld(channel, &cs,
fds[0], fds[1], funding_signed, false); fds[0], fds[1], funding_signed, false);

View file

@ -22,6 +22,4 @@ void opening_peer_no_active_channels(struct peer *peer);
void kill_uncommitted_channel(struct uncommitted_channel *uc, void kill_uncommitted_channel(struct uncommitted_channel *uc,
const char *why); const char *why);
void tell_connectd_peer_is_important(struct lightningd *ld,
const struct channel *channel);
#endif /* LIGHTNING_LIGHTNINGD_OPENING_CONTROL_H */ #endif /* LIGHTNING_LIGHTNINGD_OPENING_CONTROL_H */

View file

@ -360,12 +360,6 @@ register_close_command(struct lightningd *ld,
void drop_to_chain(struct lightningd *ld, struct channel *channel, void drop_to_chain(struct lightningd *ld, struct channel *channel,
bool cooperative) bool cooperative)
{ {
u8 *msg;
/* Tell connectd we no longer need to keep connection to this peer */
msg = towire_connectctl_peer_important(NULL, &channel->peer->id, false);
subd_send_msg(ld->connectd, take(msg));
sign_last_tx(channel); sign_last_tx(channel);
/* Keep broadcasting until we say stop (can fail due to dup, /* Keep broadcasting until we say stop (can fail due to dup,
@ -929,10 +923,12 @@ static void activate_peer(struct peer *peer)
subd_send_msg(peer->ld->connectd, take(msg)); subd_send_msg(peer->ld->connectd, take(msg));
/* We can only have one active channel: make sure connectd /* We can only have one active channel: make sure connectd
* knows to reconnect. */ * knows to try reconnecting. */
channel = peer_active_channel(peer); channel = peer_active_channel(peer);
if (channel) if (channel && ld->reconnect) {
tell_connectd_peer_is_important(ld, channel); msg = towire_connectctl_connect_to_peer(NULL, &peer->id, 0);
subd_send_msg(ld->connectd, take(msg));
}
list_for_each(&peer->channels, channel, list) { list_for_each(&peer->channels, channel, list) {
/* Watching lockin may be unnecessary, but it's harmless. */ /* Watching lockin may be unnecessary, but it's harmless. */
@ -1161,6 +1157,9 @@ static void process_dev_forget_channel(struct bitcoind *bitcoind UNUSED,
json_add_txid(response, "funding_txid", &forget->channel->funding_txid); json_add_txid(response, "funding_txid", &forget->channel->funding_txid);
json_object_end(response); json_object_end(response);
/* Set error so we don't try to reconnect. */
forget->channel->error = towire_errorfmt(forget->channel, NULL,
"dev_forget_channel");
delete_channel(forget->channel); delete_channel(forget->channel);
command_success(forget->cmd, response); command_success(forget->cmd, response);

View file

@ -82,7 +82,7 @@ def test_reconnect_channel_peers(node_factory, executor):
l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
# Wait for exponential backoff to give us a 2 second window. # Wait for exponential backoff to give us a 2 second window.
l1.daemon.wait_for_log('...will try again in 2 seconds') l1.daemon.wait_for_log('Will try reconnect in 2 seconds')
# It should now succeed when it restarts. # It should now succeed when it restarts.
l2.start() l2.start()

View file

@ -62,6 +62,9 @@ void command_success(struct command *cmd UNNEEDED, struct json_result *response
/* Generated stub for connect_succeeded */ /* Generated stub for connect_succeeded */
void connect_succeeded(struct lightningd *ld UNNEEDED, const struct pubkey *id UNNEEDED) void connect_succeeded(struct lightningd *ld UNNEEDED, const struct pubkey *id UNNEEDED)
{ fprintf(stderr, "connect_succeeded called!\n"); abort(); } { fprintf(stderr, "connect_succeeded called!\n"); abort(); }
/* Generated stub for delay_then_reconnect */
void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UNNEEDED)
{ fprintf(stderr, "delay_then_reconnect called!\n"); abort(); }
/* Generated stub for fromwire_connect_peer_connected */ /* Generated stub for fromwire_connect_peer_connected */
bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **gfeatures UNNEEDED, u8 **lfeatures UNNEEDED) bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **gfeatures UNNEEDED, u8 **lfeatures UNNEEDED)
{ fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); } { fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); }
@ -315,25 +318,21 @@ void subd_req_(const tal_t *ctx UNNEEDED,
/* Generated stub for subd_send_msg */ /* Generated stub for subd_send_msg */
void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED)
{ fprintf(stderr, "subd_send_msg called!\n"); abort(); } { fprintf(stderr, "subd_send_msg called!\n"); abort(); }
/* Generated stub for tell_connectd_peer_is_important */
void tell_connectd_peer_is_important(struct lightningd *ld UNNEEDED,
const struct channel *channel UNNEEDED)
{ fprintf(stderr, "tell_connectd_peer_is_important called!\n"); abort(); }
/* Generated stub for towire_channel_dev_reenable_commit */ /* Generated stub for towire_channel_dev_reenable_commit */
u8 *towire_channel_dev_reenable_commit(const tal_t *ctx UNNEEDED) u8 *towire_channel_dev_reenable_commit(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_channel_dev_reenable_commit called!\n"); abort(); } { fprintf(stderr, "towire_channel_dev_reenable_commit called!\n"); abort(); }
/* Generated stub for towire_channel_send_shutdown */ /* Generated stub for towire_channel_send_shutdown */
u8 *towire_channel_send_shutdown(const tal_t *ctx UNNEEDED) u8 *towire_channel_send_shutdown(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_channel_send_shutdown called!\n"); abort(); } { fprintf(stderr, "towire_channel_send_shutdown called!\n"); abort(); }
/* Generated stub for towire_connectctl_connect_to_peer */
u8 *towire_connectctl_connect_to_peer(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, u32 seconds_waited UNNEEDED)
{ fprintf(stderr, "towire_connectctl_connect_to_peer called!\n"); abort(); }
/* Generated stub for towire_connectctl_peer_addrhint */ /* Generated stub for towire_connectctl_peer_addrhint */
u8 *towire_connectctl_peer_addrhint(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, const struct wireaddr_internal *addr UNNEEDED) u8 *towire_connectctl_peer_addrhint(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, const struct wireaddr_internal *addr UNNEEDED)
{ fprintf(stderr, "towire_connectctl_peer_addrhint called!\n"); abort(); } { fprintf(stderr, "towire_connectctl_peer_addrhint called!\n"); abort(); }
/* Generated stub for towire_connectctl_peer_disconnected */ /* Generated stub for towire_connectctl_peer_disconnected */
u8 *towire_connectctl_peer_disconnected(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED) u8 *towire_connectctl_peer_disconnected(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED)
{ fprintf(stderr, "towire_connectctl_peer_disconnected called!\n"); abort(); } { fprintf(stderr, "towire_connectctl_peer_disconnected called!\n"); abort(); }
/* Generated stub for towire_connectctl_peer_important */
u8 *towire_connectctl_peer_important(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, bool important UNNEEDED)
{ fprintf(stderr, "towire_connectctl_peer_important called!\n"); abort(); }
/* Generated stub for towire_errorfmt */ /* Generated stub for towire_errorfmt */
u8 *towire_errorfmt(const tal_t *ctx UNNEEDED, u8 *towire_errorfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED, const struct channel_id *channel UNNEEDED,