diff --git a/lightningd/gossip/gossip.c b/lightningd/gossip/gossip.c index 07119ec1f..e1640b26e 100644 --- a/lightningd/gossip/gossip.c +++ b/lightningd/gossip/gossip.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -438,6 +439,27 @@ static struct io_plan *release_peer(struct io_conn *conn, struct daemon *daemon, "Unknown peer %"PRIu64, unique_id); } +static struct io_plan *getnodes(struct io_conn *conn, struct daemon *daemon) +{ + tal_t *tmpctx = tal_tmpctx(daemon); + u8 *out, *reply = tal_arr(tmpctx, u8, 0); + struct node *n; + struct node_map_iter i; + + n = node_map_first(daemon->rstate->nodes, &i); + while (n != NULL) { + struct gossip_getnodes_entry entry; + entry.nodeid = n->id; + entry.hostname = n->hostname; + entry.port = n->port; + towire_gossip_getnodes_entry(&reply, &entry); + n = node_map_next(daemon->rstate->nodes, &i); + } + out = towire_gossip_getnodes_reply(daemon, reply); + tal_free(tmpctx); + return io_write_wire(conn, take(out), next_req_in, daemon); +} + static struct io_plan *recv_req(struct io_conn *conn, struct daemon *daemon) { enum gossip_wire_type t = fromwire_peektype(daemon->msg_in); @@ -451,7 +473,11 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon *daemon) case WIRE_GOSSIPCTL_RELEASE_PEER: return release_peer(conn, daemon, daemon->msg_in); + case WIRE_GOSSIP_GETNODES_REQUEST: + return getnodes(conn, daemon); + case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: + case WIRE_GOSSIP_GETNODES_REPLY: case WIRE_GOSSIPSTATUS_INIT_FAILED: case WIRE_GOSSIPSTATUS_BAD_NEW_PEER_REQUEST: case WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST: diff --git a/lightningd/gossip/gossip_wire.csv b/lightningd/gossip/gossip_wire.csv index 8cf74da74..d6f3a3135 100644 --- a/lightningd/gossip/gossip_wire.csv +++ b/lightningd/gossip/gossip_wire.csv @@ -46,3 +46,10 @@ gossipstatus_peer_nongossip,0,unique_id,8 gossipstatus_peer_nongossip,10,crypto_state,144,struct crypto_state gossipstatus_peer_nongossip,154,len,2 gossipstatus_peer_nongossip,156,msg,len,u8 + +# Pass JSON-RPC getnodes call through +gossip_getnodes_request,5 + +gossip_getnodes_reply,105 +gossip_getnodes_reply,0,replen,2,u16 +gossip_getnodes_reply,2,reply,replen,u8 diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index a3ddf2b31..406e872ba 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -9,6 +9,7 @@ #include #include #include +#include #include static void gossip_finished(struct subd *gossip, int status) @@ -118,8 +119,10 @@ static enum subd_msg_ret gossip_msg(struct subd *gossip, /* These are messages we send, not them. */ case WIRE_GOSSIPCTL_NEW_PEER: case WIRE_GOSSIPCTL_RELEASE_PEER: + case WIRE_GOSSIP_GETNODES_REQUEST: /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: + case WIRE_GOSSIP_GETNODES_REPLY: break; case WIRE_GOSSIPSTATUS_PEER_BAD_MSG: peer_bad_message(gossip, msg); @@ -147,3 +150,51 @@ void gossip_init(struct lightningd *ld) if (!ld->gossip) err(1, "Could not subdaemon gossip"); } + +static bool json_getnodes_reply(struct subd *gossip, const u8 *reply, + struct command *cmd) +{ + u8 *inner; + const u8 *cursor; + size_t max; + + struct json_result *response = new_json_result(cmd); + fromwire_gossip_getnodes_reply(reply, reply, NULL, &inner); + max = tal_len(inner); + cursor = inner; + json_object_start(response, NULL); + json_array_start(response, "nodes"); + + while (max > 0) { + struct gossip_getnodes_entry *entry = tal(reply, struct gossip_getnodes_entry); + fromwire_gossip_getnodes_entry(&cursor, &max, entry); + json_object_start(response, NULL); + json_add_pubkey(response, "nodeid", &entry->nodeid); + if (tal_len(entry->hostname) > 0) { + json_add_string(response, "hostname", entry->hostname); + } else { + json_add_null(response, "hostname"); + } + json_add_num(response, "port", entry->port); + json_object_end(response); + tal_free(entry); + } + json_array_end(response); + json_object_end(response); + command_success(cmd, response); + tal_free(reply); + return true; +} + +static void json_getnodes(struct command *cmd, const char *buffer, + const jsmntok_t *params) +{ + struct lightningd *ld = ld_from_dstate(cmd->dstate); + u8 *req = towire_gossip_getnodes_request(cmd); + subd_req(ld->gossip, req, -1, NULL, json_getnodes_reply, cmd); +} + +static const struct json_command getnodes_command = { + "getnodes", json_getnodes, "Retrieve all nodes in our local network view", + "Returns a list of all nodes that we know about"}; +AUTODATA(json_command, &getnodes_command);