Skip to content

Commit

Permalink
gossipd: call to return all connected peers.
Browse files Browse the repository at this point in the history
And we report these through the getpeers JSON RPC again (carefully: in
our reconnect tests we can get duplicates which this patch now filters
out).

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Oct 26, 2017
1 parent a7d6326 commit 0c7ca9a
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 25 deletions.
29 changes: 29 additions & 0 deletions gossipd/gossip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,31 @@ static struct io_plan *addr_hint(struct io_conn *conn,
return daemon_conn_read_next(conn, &daemon->master);
}

static struct io_plan *get_peers(struct io_conn *conn,
struct daemon *daemon, const u8 *msg)
{
struct peer *peer;
size_t n = 0;
struct pubkey *id = tal_arr(conn, struct pubkey, n);
struct wireaddr *wireaddr = tal_arr(conn, struct wireaddr, n);

if (!fromwire_gossip_getpeers_request(msg, NULL))
master_badmsg(WIRE_GOSSIPCTL_PEER_ADDRHINT, msg);

list_for_each(&daemon->peers, peer, list) {
tal_resize(&id, n+1);
tal_resize(&wireaddr, n+1);

id[n] = peer->id;
wireaddr[n] = peer->addr;
n++;
}

daemon_conn_send(&daemon->master,
take(towire_gossip_getpeers_reply(conn, id, wireaddr)));
return daemon_conn_read_next(conn, &daemon->master);
}

static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master)
{
struct daemon *daemon = container_of(master, struct daemon, master);
Expand Down Expand Up @@ -1342,11 +1367,15 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
case WIRE_GOSSIPCTL_PEER_ADDRHINT:
return addr_hint(conn, daemon, master->msg_in);

case WIRE_GOSSIP_GETPEERS_REQUEST:
return get_peers(conn, daemon, master->msg_in);

case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL:
case WIRE_GOSSIP_GETNODES_REPLY:
case WIRE_GOSSIP_GETROUTE_REPLY:
case WIRE_GOSSIP_GETCHANNELS_REPLY:
case WIRE_GOSSIP_GETPEERS_REPLY:
case WIRE_GOSSIP_PING_REPLY:
case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY:
case WIRE_GOSSIP_PEER_CONNECTED:
Expand Down
7 changes: 7 additions & 0 deletions gossipd/gossip_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,10 @@ gossip_forwarded_msg,3010
gossip_forwarded_msg,,msglen,u16
gossip_forwarded_msg,,msg,msglen*u8

# The main daemon asks for peers
gossip_getpeers_request,3011

gossip_getpeers_reply,3111
gossip_getpeers_reply,,num,u16
gossip_getpeers_reply,,id,num*struct pubkey
gossip_getpeers_reply,,addr,num*struct wireaddr
2 changes: 2 additions & 0 deletions lightningd/gossip_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIP_GETNODES_REQUEST:
case WIRE_GOSSIP_GETROUTE_REQUEST:
case WIRE_GOSSIP_GETCHANNELS_REQUEST:
case WIRE_GOSSIP_GETPEERS_REQUEST:
case WIRE_GOSSIP_PING:
case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST:
case WIRE_GOSSIP_FORWARDED_MSG:
Expand All @@ -71,6 +72,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIP_GETNODES_REPLY:
case WIRE_GOSSIP_GETROUTE_REPLY:
case WIRE_GOSSIP_GETCHANNELS_REPLY:
case WIRE_GOSSIP_GETPEERS_REPLY:
case WIRE_GOSSIP_PING_REPLY:
case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY:
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
Expand Down
94 changes: 72 additions & 22 deletions lightningd/peer_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,34 +786,31 @@ static void log_to_json(unsigned int skipped,
json_add_string(info->response, NULL, log);
}

static void json_getpeers(struct command *cmd,
const char *buffer, const jsmntok_t *params)
struct getpeers_args {
struct command *cmd;
/* If non-NULL, they want logs too */
enum log_level *ll;
};

static void gossipd_getpeers_complete(struct subd *gossip, const u8 *msg,
const int *fds,
struct getpeers_args *gpa)
{
/* This is a little sneaky... */
struct pubkey *ids;
struct wireaddr *addrs;
struct json_result *response = new_json_result(gpa->cmd);
struct peer *p;
struct json_result *response = new_json_result(cmd);
jsmntok_t *leveltok;
struct log_info info;

json_get_params(buffer, params, "?level", &leveltok, NULL);

if (!leveltok)
;
else if (json_tok_streq(buffer, leveltok, "debug"))
info.level = LOG_DBG;
else if (json_tok_streq(buffer, leveltok, "info"))
info.level = LOG_INFORM;
else if (json_tok_streq(buffer, leveltok, "unusual"))
info.level = LOG_UNUSUAL;
else if (json_tok_streq(buffer, leveltok, "broken"))
info.level = LOG_BROKEN;
else {
command_fail(cmd, "Invalid level param");
if (!fromwire_gossip_getpeers_reply(msg, msg, NULL, &ids, &addrs)) {
command_fail(gpa->cmd, "Bad response from gossipd");
return;
}

/* First the peers not just gossiping. */
json_object_start(response, NULL);
json_array_start(response, "peers");
list_for_each(&cmd->ld->peers, p, list) {
list_for_each(&gpa->cmd->ld->peers, p, list) {
json_object_start(response, NULL);
json_add_string(response, "state", peer_state_name(p->state));
json_add_string(response, "netaddr",
Expand All @@ -832,17 +829,70 @@ static void json_getpeers(struct command *cmd,
p->funding_satoshi * 1000);
}

if (leveltok) {
if (gpa->ll) {
struct log_info info;
info.level = *gpa->ll;
info.response = response;
json_array_start(response, "log");
log_each_line(p->log_book, log_to_json, &info);
json_array_end(response);
}
json_object_end(response);
}

for (size_t i = 0; i < tal_count(ids); i++) {
/* Don't report peers in both, which can happen if they're
* reconnecting */
if (peer_by_id(gpa->cmd->ld, ids + i))
continue;

json_object_start(response, NULL);
/* Fake state. */
json_add_string(response, "state", "GOSSIPING");
json_add_pubkey(response, "peerid", ids+i);
json_add_string(response, "netaddr",
type_to_string(response, struct wireaddr,
addrs + i));
json_add_bool(response, "connected", "true");
json_add_string(response, "owner", gossip->name);
json_object_end(response);
}

json_array_end(response);
json_object_end(response);
command_success(cmd, response);
command_success(gpa->cmd, response);
}

static void json_getpeers(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *leveltok;
struct getpeers_args *gpa = tal(cmd, struct getpeers_args);

gpa->cmd = cmd;
json_get_params(buffer, params, "?level", &leveltok, NULL);

if (leveltok) {
gpa->ll = tal(gpa, enum log_level);
if (json_tok_streq(buffer, leveltok, "debug"))
*gpa->ll = LOG_DBG;
else if (json_tok_streq(buffer, leveltok, "info"))
*gpa->ll = LOG_INFORM;
else if (json_tok_streq(buffer, leveltok, "unusual"))
*gpa->ll = LOG_UNUSUAL;
else if (json_tok_streq(buffer, leveltok, "broken"))
*gpa->ll = LOG_BROKEN;
else {
command_fail(cmd, "Invalid level param");
return;
}
} else
gpa->ll = NULL;

/* Get peers from gossipd. */
subd_req(cmd, cmd->ld->gossip,
take(towire_gossip_getpeers_request(cmd)),
-1, 0, gossipd_getpeers_complete, gpa);
}

static const struct json_command getpeers_command = {
Expand Down
6 changes: 3 additions & 3 deletions tests/test_lightningd.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,9 @@ def test_shutdown(self):
def test_connect(self):
l1,l2 = self.connect()

# Main daemon has no idea about these peers; they're in gossipd.
assert l1.rpc.getpeer(l2.info['id'], 'info') == None
assert l2.rpc.getpeer(l1.info['id'], 'info') == None
# These should be in gossipd.
assert l1.rpc.getpeer(l2.info['id'])['state'] == 'GOSSIPING'
assert l2.rpc.getpeer(l1.info['id'])['state'] == 'GOSSIPING'

# Both gossipds will have them as new peers once handed back.
l1.daemon.wait_for_log('handle_peer {}: new peer'.format(l2.info['id']))
Expand Down

0 comments on commit 0c7ca9a

Please sign in to comment.