lightningd/dev_ping: expand to cover gossipd.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-04-12 11:20:48 -07:00 committed by Christian Decker
parent 8f358b7a91
commit 6d55a17642
5 changed files with 131 additions and 20 deletions

View File

@ -2,6 +2,7 @@
#include <daemon/log.h>
#include <daemon/sphinx.h>
#include <lightningd/channel/gen_channel_wire.h>
#include <lightningd/gossip/gen_gossip_wire.h>
#include <lightningd/htlc_end.h>
#include <lightningd/lightningd.h>
#include <lightningd/peer_control.h>
@ -15,7 +16,10 @@ static bool ping_reply(struct subd *subd, const u8 *msg, const int *fds,
bool ok;
log_debug(subd->ld->log, "Got ping reply!");
ok = fromwire_channel_ping_reply(msg, NULL, &totlen);
if (streq(subd->name, "lightningd_channel"))
ok = fromwire_channel_ping_reply(msg, NULL, &totlen);
else
ok = fromwire_gossip_ping_reply(msg, NULL, &totlen);
if (!ok)
command_fail(cmd, "Bad reply message");
@ -56,7 +60,8 @@ static void json_dev_ping(struct command *cmd,
/* FIXME: These checks are horrible, use a peer flag to say it's
* ready to forward! */
if (peer->owner && !streq(peer->owner->name, "lightningd_channel")) {
if (peer->owner && !streq(peer->owner->name, "lightningd_channel")
&& !streq(peer->owner->name, "lightningd_gossip")) {
command_fail(cmd, "Peer in %s",
peer->owner ? peer->owner->name : "unattached");
return;
@ -76,7 +81,10 @@ static void json_dev_ping(struct command *cmd,
return;
}
msg = towire_channel_ping(cmd, pongbytes, len);
if (streq(peer->owner->name, "lightningd_channel"))
msg = towire_channel_ping(cmd, pongbytes, len);
else
msg = towire_gossip_ping(cmd, peer->unique_id, pongbytes, len);
/* FIXME: If subdaemon dies? */
subd_req(peer->owner, peer->owner, take(msg), -1, 0, ping_reply, cmd);

View File

@ -75,6 +75,9 @@ struct peer {
/* The peer owner will use this to talk to gossipd */
struct daemon_conn owner_conn;
/* How many pongs are we expecting? */
size_t num_pings_outstanding;
/* Are we the owner of the peer? */
bool local;
};
@ -103,6 +106,7 @@ static struct peer *setup_new_peer(struct daemon *daemon, const u8 *msg)
peer->daemon = daemon;
peer->error = NULL;
peer->local = true;
peer->num_pings_outstanding = 0;
msg_queue_init(&peer->peer_out, peer);
list_add_tail(&daemon->peers, &peer->list);
tal_add_destructor(peer, destroy_peer);
@ -183,6 +187,27 @@ static bool handle_ping(struct peer *peer, u8 *ping)
return true;
}
static bool handle_pong(struct peer *peer, const u8 *pong)
{
u8 *ignored;
status_trace("Got pong!");
if (!fromwire_pong(pong, pong, NULL, &ignored)) {
peer->error = "pad pong";
return false;
}
if (!peer->num_pings_outstanding) {
peer->error = "unexpected pong";
return false;
}
peer->num_pings_outstanding--;
daemon_conn_send(&peer->daemon->master,
take(towire_gossip_ping_reply(pong, tal_len(pong))));
return true;
}
static struct io_plan *peer_msgin(struct io_conn *conn,
struct peer *peer, u8 *msg)
{
@ -211,14 +236,9 @@ static struct io_plan *peer_msgin(struct io_conn *conn,
return peer_read_message(conn, &peer->pcs, peer_msgin);
case WIRE_PONG:
/* BOLT #1:
*
* A node receiving a `pong` message MAY fail the channels if
* `byteslen` does not correspond to any `ping`
* `num_pong_bytes` value it has sent.
*/
peer->error = "Unexpected pong received";
return io_close(conn);
if (!handle_pong(peer, msg))
return io_close(conn);
return peer_read_message(conn, &peer->pcs, peer_msgin);
case WIRE_OPEN_CHANNEL:
case WIRE_ACCEPT_CHANNEL:
@ -438,6 +458,16 @@ static struct io_plan *new_peer(struct io_conn *conn, struct daemon *daemon,
return io_recv_fd(conn, &peer->fd, new_peer_got_fd, peer);
}
static struct peer *find_peer(struct daemon *daemon, u64 unique_id)
{
struct peer *peer;
list_for_each(&daemon->peers, peer, list)
if (peer->unique_id == unique_id)
return peer;
return NULL;
}
static struct io_plan *release_peer(struct io_conn *conn, struct daemon *daemon,
const u8 *msg)
{
@ -448,18 +478,17 @@ static struct io_plan *release_peer(struct io_conn *conn, struct daemon *daemon,
status_failed(WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST,
"%s", tal_hex(trc, msg));
list_for_each(&daemon->peers, peer, list) {
if (peer->unique_id == unique_id) {
send_peer_with_fds(peer,
peer = find_peer(daemon, unique_id);
if (!peer)
status_failed(WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST,
"Unknown peer %"PRIu64, unique_id);
send_peer_with_fds(peer,
take(towire_gossipctl_release_peer_reply(msg,
unique_id,
&peer->pcs.cs)));
io_close_taken_fd(peer->conn);
return daemon_conn_read_next(conn, &daemon->master);
}
}
status_failed(WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST,
"Unknown peer %"PRIu64, unique_id);
io_close_taken_fd(peer->conn);
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *getroute_req(struct io_conn *conn, struct daemon *daemon,
@ -546,6 +575,45 @@ static struct io_plan *getnodes(struct io_conn *conn, struct daemon *daemon)
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *ping_req(struct io_conn *conn, struct daemon *daemon,
const u8 *msg)
{
u64 unique_id;
u16 num_pong_bytes, len;
struct peer *peer;
u8 *ping;
if (!fromwire_gossip_ping(msg, NULL, &unique_id, &num_pong_bytes, &len))
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST,
"%s", tal_hex(trc, msg));
peer = find_peer(daemon, unique_id);
if (!peer)
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST,
"Unknown peer %"PRIu64, unique_id);
ping = make_ping(peer, num_pong_bytes, len);
if (tal_len(ping) > 65535)
status_failed(WIRE_GOSSIPSTATUS_BAD_REQUEST, "Oversize ping");
msg_enqueue(&peer->peer_out, take(ping));
status_trace("sending ping expecting %sresponse",
num_pong_bytes >= 65532 ? "no " : "");
/* BOLT #1:
*
* if `num_pong_bytes` is less than 65532 it MUST respond by sending a
* `pong` message with `byteslen` equal to `num_pong_bytes`, otherwise
* it MUST ignore the `ping`.
*/
if (num_pong_bytes >= 65532)
daemon_conn_send(&daemon->master,
take(towire_gossip_ping_reply(peer, 0)));
else
peer->num_pings_outstanding++;
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);
@ -569,10 +637,14 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
case WIRE_GOSSIP_GETCHANNELS_REQUEST:
return getchannels_req(conn, daemon, daemon->master.msg_in);
case WIRE_GOSSIP_PING:
return ping_req(conn, daemon, daemon->master.msg_in);
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
case WIRE_GOSSIP_GETNODES_REPLY:
case WIRE_GOSSIP_GETROUTE_REPLY:
case WIRE_GOSSIP_GETCHANNELS_REPLY:
case WIRE_GOSSIP_PING_REPLY:
case WIRE_GOSSIPSTATUS_INIT_FAILED:
case WIRE_GOSSIPSTATUS_BAD_NEW_PEER_REQUEST:
case WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST:

View File

@ -77,3 +77,13 @@ gossip_getchannels_request,7
gossip_getchannels_reply,107
gossip_getchannels_reply,0,num_channels,u16
gossip_getchannels_reply,2,nodes,num_channels*struct gossip_getchannels_entry
# Ping/pong test.
gossip_ping,8
gossip_ping,0,unique_id,u64
gossip_ping,0,num_pong_bytes,u16
gossip_ping,0,len,u16
gossip_ping_reply,108
gossip_ping_reply,0,totlen,u16

1 # These are fatal.
77
78
79
80
81
82
83
84
85
86
87
88
89

View File

@ -145,11 +145,13 @@ static int 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_PING:
/* This is a reply, so never gets through to here. */
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
case WIRE_GOSSIP_GETNODES_REPLY:
case WIRE_GOSSIP_GETROUTE_REPLY:
case WIRE_GOSSIP_GETCHANNELS_REPLY:
case WIRE_GOSSIP_PING_REPLY:
break;
case WIRE_GOSSIPSTATUS_PEER_BAD_MSG:
peer_bad_message(gossip, msg);

View File

@ -20,6 +20,25 @@ start_lightningd 2 lightningd/lightningd
lcli1 connect localhost $PORT2 $ID2
# Gossipd pings.
# 0-byte pong gives just type + length field.
[ `lcli1 dev-ping $ID2 0 0 | get_field totlen` = 4 ]
# 1000-byte ping, 0-byte pong.
[ `lcli1 dev-ping $ID2 1000 0 | get_field totlen` = 4 ]
# 1000 byte pong.
[ `lcli1 dev-ping $ID2 1000 1000 | get_field totlen` = 1004 ]
# Maximum length pong.
[ `lcli1 dev-ping $ID2 1000 65531 | get_field totlen` = 65535 ]
# Overlength -> no reply.
[ `lcli1 dev-ping $ID2 1000 65532 | get_field totlen` = 0 ]
[ `lcli1 dev-ping $ID2 1000 65533 | get_field totlen` = 0 ]
[ `lcli1 dev-ping $ID2 1000 65534 | get_field totlen` = 0 ]
[ `lcli1 dev-ping $ID2 1000 65535 | get_field totlen` = 0 ]
add_funds lcli1 0.2
# Now fund the channels