mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-23 15:04:19 +01:00
gossipd: maintain a separate structure to track important peers.
Rather than using a flag in reaching/peer; we make it self-contained as the next patch puts it straight into a timer callback. Also remove unused 'succeeded' field from struct peer. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
142
gossipd/gossip.c
142
gossipd/gossip.c
@@ -20,6 +20,7 @@
|
||||
#include <common/daemon_conn.h>
|
||||
#include <common/features.h>
|
||||
#include <common/ping.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/status.h>
|
||||
#include <common/subdaemon.h>
|
||||
#include <common/timeout.h>
|
||||
@@ -52,6 +53,36 @@
|
||||
|
||||
#define HSM_FD 3
|
||||
|
||||
struct important_peerid {
|
||||
struct daemon *daemon;
|
||||
|
||||
struct pubkey id;
|
||||
};
|
||||
|
||||
/* 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 daemon {
|
||||
/* Who am I? */
|
||||
struct pubkey id;
|
||||
@@ -75,6 +106,9 @@ struct daemon {
|
||||
|
||||
u32 broadcast_interval;
|
||||
|
||||
/* Important peers */
|
||||
struct important_peerid_map important_peerids;
|
||||
|
||||
/* Local and global features to offer to peers. */
|
||||
u8 *localfeatures, *globalfeatures;
|
||||
|
||||
@@ -102,12 +136,6 @@ struct reaching {
|
||||
/* Where I'm reaching to. */
|
||||
struct wireaddr addr;
|
||||
|
||||
/* Did we succeed? */
|
||||
bool succeeded;
|
||||
|
||||
/* Is this an important peer to keep connected? */
|
||||
bool keep_connected;
|
||||
|
||||
/* How many times have we attempted to connect? */
|
||||
u32 attempts;
|
||||
|
||||
@@ -160,9 +188,6 @@ struct peer {
|
||||
/* Is it time to continue the staggered broadcast? */
|
||||
bool gossip_sync;
|
||||
|
||||
/* If we die, should we reach again? */
|
||||
bool keep_connected;
|
||||
|
||||
/* Only one of these is set: */
|
||||
struct local_peer_state *local;
|
||||
struct daemon_conn *remote;
|
||||
@@ -182,18 +207,17 @@ static struct io_plan *peer_start_gossip(struct io_conn *conn,
|
||||
struct peer *peer);
|
||||
static bool send_peer_with_fds(struct peer *peer, const u8 *msg);
|
||||
static void wake_pkt_out(struct peer *peer);
|
||||
static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id,
|
||||
bool keep_connected);
|
||||
static void retry_important(struct important_peerid *imp);
|
||||
|
||||
static void destroy_peer(struct peer *peer)
|
||||
{
|
||||
struct important_peerid *imp;
|
||||
|
||||
list_del_from(&peer->daemon->peers, &peer->list);
|
||||
#if DEVELOPER
|
||||
if (peer->daemon->no_reconnect)
|
||||
return;
|
||||
#endif
|
||||
if (peer->keep_connected)
|
||||
try_reach_peer(peer->daemon, &peer->id, true);
|
||||
imp = important_peerid_map_get(&peer->daemon->important_peerids,
|
||||
&peer->id);
|
||||
if (imp)
|
||||
retry_important(imp);
|
||||
}
|
||||
|
||||
static struct peer *find_peer(struct daemon *daemon, const struct pubkey *id)
|
||||
@@ -250,7 +274,6 @@ static struct peer *new_peer(const tal_t *ctx,
|
||||
peer->daemon = daemon;
|
||||
peer->local = new_local_peer_state(peer, cs);
|
||||
peer->remote = NULL;
|
||||
peer->keep_connected = false;
|
||||
|
||||
return peer;
|
||||
}
|
||||
@@ -283,17 +306,12 @@ static struct reaching *find_reaching(struct daemon *daemon,
|
||||
|
||||
static void reached_peer(struct peer *peer, struct io_conn *conn)
|
||||
{
|
||||
/* OK, we've reached the peer successfully, stop retrying. */
|
||||
struct reaching *r = find_reaching(peer->daemon, &peer->id);
|
||||
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
/* If this peer was important, remember, so we reconnect. */
|
||||
if (r->keep_connected)
|
||||
peer->keep_connected = true;
|
||||
|
||||
/* OK, we've reached the peer successfully, stop retrying. */
|
||||
|
||||
/* Don't free conn with reach. */
|
||||
tal_steal(peer->daemon, conn);
|
||||
/* Don't call connect_failed */
|
||||
@@ -1585,7 +1603,8 @@ static void connect_failed(struct io_conn *conn, struct reaching *reach)
|
||||
u32 diff = time_now().ts.tv_sec - reach->first_attempt;
|
||||
reach->attempts++;
|
||||
|
||||
if (!reach->keep_connected && reach->attempts >= 10) {
|
||||
if (!important_peerid_map_get(&reach->daemon->important_peerids, &reach->id)
|
||||
&& reach->attempts >= 10) {
|
||||
status_info("Failed to connect after %d attempts, giving up "
|
||||
"after %d seconds",
|
||||
reach->attempts, diff);
|
||||
@@ -1735,17 +1754,13 @@ static void try_connect(struct reaching *reach)
|
||||
}
|
||||
|
||||
/* Returns true if we're already connected. */
|
||||
static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id,
|
||||
bool keep_connected)
|
||||
static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id)
|
||||
{
|
||||
struct reaching *reach;
|
||||
struct peer *peer;
|
||||
|
||||
reach = find_reaching(daemon, id);
|
||||
if (reach) {
|
||||
/* May not have been important before */
|
||||
if (keep_connected)
|
||||
reach->keep_connected = true;
|
||||
status_trace("try_reach_peer: already trying to reach %s",
|
||||
type_to_string(tmpctx, struct pubkey, id));
|
||||
return false;
|
||||
@@ -1754,22 +1769,16 @@ static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id,
|
||||
/* Master might find out before we do that a peer is dead. */
|
||||
peer = find_peer(daemon, id);
|
||||
if (peer) {
|
||||
/* May not have been important before */
|
||||
if (keep_connected)
|
||||
peer->keep_connected = true;
|
||||
status_trace("reach_peer: have peer %s%s",
|
||||
type_to_string(tmpctx, struct pubkey, id),
|
||||
peer->keep_connected ? " (will retry if it dies)" : "");
|
||||
status_trace("reach_peer: have peer %s",
|
||||
type_to_string(tmpctx, struct pubkey, id));
|
||||
return true;
|
||||
}
|
||||
|
||||
reach = tal(daemon, struct reaching);
|
||||
reach->succeeded = false;
|
||||
reach->daemon = daemon;
|
||||
reach->id = *id;
|
||||
reach->first_attempt = time_now().ts.tv_sec;
|
||||
reach->attempts = 0;
|
||||
reach->keep_connected = keep_connected;
|
||||
list_add_tail(&daemon->reaching, &reach->list);
|
||||
tal_add_destructor(reach, destroy_reaching);
|
||||
|
||||
@@ -1777,6 +1786,18 @@ static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Reconnect to peer. */
|
||||
static void retry_important(struct important_peerid *imp)
|
||||
{
|
||||
#if DEVELOPER
|
||||
/* With --dev-no-reconnect, we only want explicit
|
||||
* connects */
|
||||
if (imp->daemon->no_reconnect)
|
||||
return;
|
||||
#endif
|
||||
try_reach_peer(imp->daemon, &imp->id);
|
||||
}
|
||||
|
||||
static struct io_plan *reach_peer(struct io_conn *conn,
|
||||
struct daemon *daemon, const u8 *msg)
|
||||
{
|
||||
@@ -1786,7 +1807,7 @@ static struct io_plan *reach_peer(struct io_conn *conn,
|
||||
master_badmsg(WIRE_GOSSIPCTL_REACH_PEER, msg);
|
||||
|
||||
/* Master can't check this itself, because that's racy. */
|
||||
if (try_reach_peer(daemon, &id, false)) {
|
||||
if (try_reach_peer(daemon, &id)) {
|
||||
daemon_conn_send(&daemon->master,
|
||||
take(towire_gossip_peer_already_connected(NULL,
|
||||
&id)));
|
||||
@@ -1817,30 +1838,30 @@ static struct io_plan *peer_important(struct io_conn *conn,
|
||||
{
|
||||
struct pubkey id;
|
||||
bool important;
|
||||
struct reaching *r;
|
||||
struct peer *p;
|
||||
struct important_peerid *imp;
|
||||
|
||||
if (!fromwire_gossipctl_peer_important(msg, &id, &important))
|
||||
master_badmsg(WIRE_GOSSIPCTL_REACH_PEER, msg);
|
||||
master_badmsg(WIRE_GOSSIPCTL_PEER_IMPORTANT, msg);
|
||||
|
||||
r = find_reaching(daemon, &id);
|
||||
p = find_peer(daemon, &id);
|
||||
|
||||
/* Override keep_connected flag everywhere */
|
||||
if (r)
|
||||
r->keep_connected = important;
|
||||
if (p)
|
||||
p->keep_connected = important;
|
||||
|
||||
#if DEVELOPER
|
||||
/* With --dev-no-reconnect, we only want explicit connects */
|
||||
if (daemon->no_reconnect)
|
||||
important = false;
|
||||
#endif
|
||||
|
||||
/* If it's important and we're not connected/connecting, do so now. */
|
||||
if (important && !r && !p)
|
||||
try_reach_peer(daemon, &id, true);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
@@ -2163,6 +2184,7 @@ int main(int argc, char *argv[])
|
||||
list_head_init(&daemon->peers);
|
||||
list_head_init(&daemon->reaching);
|
||||
list_head_init(&daemon->addrhints);
|
||||
important_peerid_map_init(&daemon->important_peerids);
|
||||
timers_init(&daemon->timers, time_mono());
|
||||
daemon->broadcast_interval = 30000;
|
||||
daemon->last_announce_timestamp = 0;
|
||||
|
||||
Reference in New Issue
Block a user