gossipd: don't hang if we try to connect to already-connected peer.

Closes: #287
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2018-01-10 16:00:54 +10:30
committed by Christian Decker
parent 43c97187a4
commit d4c8210a9e
5 changed files with 39 additions and 7 deletions

View File

@@ -167,7 +167,7 @@ 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 void try_reach_peer(struct daemon *daemon, const struct pubkey *id);
static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id);
static void destroy_peer(struct peer *peer)
{
@@ -1474,16 +1474,17 @@ static void try_connect(struct reaching *reach)
io_new_conn(reach, fd, conn_init, reach);
}
static void try_reach_peer(struct daemon *daemon, const struct pubkey *id)
/* Returns true if we're already connected. */
static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id)
{
struct reaching *reach;
struct peer *peer;
if (find_reaching(daemon, id)) {
/* FIXME: Perhaps kick timer in this case? */
status_trace("try_reach_peer: already reaching %s",
status_trace("try_reach_peer: already trying to reach %s",
type_to_string(trc, struct pubkey, id));
return;
return false;
}
/* Master might find out before we do that a peer is dead; if we
@@ -1493,7 +1494,7 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id)
status_trace("reach_peer: have %s, will retry if it dies",
type_to_string(trc, struct pubkey, id));
peer->reach_again = true;
return;
return true;
}
reach = tal(daemon, struct reaching);
@@ -1504,6 +1505,7 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id)
tal_add_destructor(reach, destroy_reaching);
try_connect(reach);
return false;
}
/* This catches all kinds of failures, like network errors. */
@@ -1515,7 +1517,12 @@ static struct io_plan *reach_peer(struct io_conn *conn,
if (!fromwire_gossipctl_reach_peer(msg, NULL, &id))
master_badmsg(WIRE_GOSSIPCTL_REACH_PEER, msg);
try_reach_peer(daemon, &id);
/* Master can't check this itself, because that's racy. */
if (try_reach_peer(daemon, &id)) {
daemon_conn_send(&daemon->master,
take(towire_gossip_peer_already_connected(conn,
&id)));
}
return daemon_conn_read_next(conn, &daemon->master);
}
@@ -1632,6 +1639,7 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
case WIRE_GOSSIP_PING_REPLY:
case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY:
case WIRE_GOSSIP_PEER_CONNECTED:
case WIRE_GOSSIP_PEER_ALREADY_CONNECTED:
case WIRE_GOSSIP_PEER_NONGOSSIP:
case WIRE_GOSSIP_GET_UPDATE:
case WIRE_GOSSIP_GET_UPDATE_REPLY:

View File

@@ -22,7 +22,8 @@ gossipctl_peer_addrhint,3014
gossipctl_peer_addrhint,,id,struct pubkey
gossipctl_peer_addrhint,,addr,struct wireaddr
# Master -> gossipd: connect to a peer. We may get a peer_connected.
# Master -> gossipd: connect to a peer. We may get a peer_connected or
# peer_already_connected
gossipctl_reach_peer,3001
gossipctl_reach_peer,,id,struct pubkey
@@ -37,6 +38,10 @@ gossip_peer_connected,,gfeatures,gflen*u8
gossip_peer_connected,,lflen,u16
gossip_peer_connected,,lfeatures,lflen*u8
# Gossipd -> master: you asked to reach a peer, we already had.
gossip_peer_already_connected,3015
gossip_peer_already_connected,,id,struct pubkey
# Gossipd -> master: peer sent non-gossip packet. Two fds: peer and gossip
gossip_peer_nongossip,3003
gossip_peer_nongossip,,id,struct pubkey
1 #include <common/cryptomsg.h>
22 # Master -> gossipd: connect to a peer. We may get a peer_connected. # Master -> gossipd: connect to a peer. We may get a peer_connected or
23 gossipctl_reach_peer,3001 # peer_already_connected
24 gossipctl_reach_peer,,id,struct pubkey gossipctl_reach_peer,3001
25 # Gossipd -> master: we got a peer. Two fds: peer and gossip gossipctl_reach_peer,,id,struct pubkey
26 # Gossipd -> master: we got a peer. Two fds: peer and gossip
27 gossip_peer_connected,3002
28 gossip_peer_connected,,id,struct pubkey
29 gossip_peer_connected,,addr,struct wireaddr
38 gossip_peer_nongossip,,id,struct pubkey gossip_peer_already_connected,,id,struct pubkey
39 gossip_peer_nongossip,,addr,struct wireaddr # Gossipd -> master: peer sent non-gossip packet. Two fds: peer and gossip
40 gossip_peer_nongossip,,crypto_state,struct crypto_state gossip_peer_nongossip,3003
41 gossip_peer_nongossip,,id,struct pubkey
42 gossip_peer_nongossip,,addr,struct wireaddr
43 gossip_peer_nongossip,,crypto_state,struct crypto_state
44 gossip_peer_nongossip,,gossip_index,u64
45 gossip_peer_nongossip,,gossip_index,u64 gossip_peer_nongossip,,gflen,u16
46 gossip_peer_nongossip,,gflen,u16 gossip_peer_nongossip,,gfeatures,gflen*u8
47 gossip_peer_nongossip,,gfeatures,gflen*u8 gossip_peer_nongossip,,lflen,u16

View File

@@ -120,6 +120,9 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
return 2;
peer_connected(gossip->ld, msg, fds[0], fds[1]);
break;
case WIRE_GOSSIP_PEER_ALREADY_CONNECTED:
peer_already_connected(gossip->ld, msg);
break;
case WIRE_GOSSIP_PEER_NONGOSSIP:
if (tal_count(fds) != 2)
return 2;

View File

@@ -667,6 +667,19 @@ send_error:
subd_send_fd(ld->gossip, gossip_fd);
}
/* Gossipd tells us peer was already connected. */
void peer_already_connected(struct lightningd *ld, const u8 *msg)
{
struct pubkey id;
if (!fromwire_gossip_peer_already_connected(msg, NULL, &id))
fatal("Gossip gave bad GOSSIP_PEER_ALREADY_CONNECTED message %s",
tal_hex(msg, msg));
/* If we were waiting for connection, we succeeded. */
connect_succeeded(ld, &id);
}
void peer_sent_nongossip(struct lightningd *ld,
const struct pubkey *id,
const struct wireaddr *addr,

View File

@@ -173,6 +173,9 @@ void peer_last_tx(struct peer *peer, struct bitcoin_tx *tx,
void peer_connected(struct lightningd *ld, const u8 *msg,
int peer_fd, int gossip_fd);
/* This simply means we asked to reach a peer, but we already have it */
void peer_already_connected(struct lightningd *ld, const u8 *msg);
void peer_sent_nongossip(struct lightningd *ld,
const struct pubkey *id,
const struct wireaddr *addr,