Browse Source

lightningd: add dev_ping command for channeld.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
committed by Christian Decker
parent
commit
8f358b7a91
  1. 1
      lightningd/Makefile
  2. 64
      lightningd/channel/channel.c
  3. 9
      lightningd/channel/channel_wire.csv
  4. 91
      lightningd/dev_ping.c
  5. 2
      lightningd/peer_control.c
  6. 4
      lightningd/ping.c
  7. 56
      lightningd/test/test-ping

1
lightningd/Makefile

@ -61,6 +61,7 @@ LIGHTNINGD_LIB_HEADERS := $(LIGHTNINGD_LIB_SRC:.c=.h)
LIGHTNINGD_SRC := \
lightningd/build_utxos.c \
lightningd/dev_newhtlc.c \
lightningd/dev_ping.c \
lightningd/gossip_control.c \
lightningd/htlc_end.c \
lightningd/hsm_control.c \

64
lightningd/channel/channel.c

@ -87,6 +87,9 @@ struct peer {
struct oneshot *commit_timer;
u32 commit_msec;
/* Don't accept a pong we didn't ping for. */
size_t num_pings_outstanding;
/* Announcement related information */
struct pubkey node_ids[NUM_SIDES];
struct short_channel_id short_channel_ids[NUM_SIDES];
@ -830,10 +833,31 @@ static void handle_ping(struct peer *peer, const u8 *msg)
&peer->channel_id,
WIRE_CHANNEL_PEER_BAD_MESSAGE,
"Bad ping");
status_trace("Got ping, sending %s", pong ?
wire_type_name(fromwire_peektype(pong))
: "nothing");
if (pong)
msg_enqueue(&peer->peer_out, take(pong));
}
static void handle_pong(struct peer *peer, const u8 *pong)
{
u8 *ignored;
status_trace("Got pong!");
if (!fromwire_pong(pong, pong, NULL, &ignored))
status_failed(WIRE_CHANNEL_PEER_READ_FAILED, "Bad pong");
if (!peer->num_pings_outstanding)
status_failed(WIRE_CHANNEL_PEER_READ_FAILED, "Unexpected pong");
peer->num_pings_outstanding--;
daemon_conn_send(&peer->master,
take(towire_channel_ping_reply(pong, tal_len(pong))));
}
static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
{
enum wire_type type = fromwire_peektype(msg);
@ -886,9 +910,10 @@ static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
case WIRE_PING:
handle_ping(peer, msg);
goto done;
/* We don't send pings, so don't expect pongs. */
case WIRE_PONG:
handle_pong(peer, msg);
goto done;
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_OPEN_CHANNEL:
@ -1168,6 +1193,36 @@ static void handle_fail(struct peer *peer, const u8 *inmsg)
abort();
}
static void handle_ping_cmd(struct peer *peer, const u8 *inmsg)
{
u16 num_pong_bytes, ping_len;
u8 *ping;
if (!fromwire_channel_ping(inmsg, NULL, &num_pong_bytes, &ping_len))
status_failed(WIRE_CHANNEL_BAD_COMMAND, "Bad channel_ping");
ping = make_ping(peer, num_pong_bytes, ping_len);
if (tal_len(ping) > 65535)
status_failed(WIRE_CHANNEL_BAD_COMMAND, "Oversize channel_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(&peer->master,
take(towire_channel_ping_reply(peer, 0)));
else
peer->num_pings_outstanding++;
}
static struct io_plan *req_in(struct io_conn *conn, struct daemon_conn *master)
{
struct peer *peer = container_of(master, struct peer, master);
@ -1193,6 +1248,9 @@ static struct io_plan *req_in(struct io_conn *conn, struct daemon_conn *master)
case WIRE_CHANNEL_FAIL_HTLC:
handle_fail(peer, master->msg_in);
goto out;
case WIRE_CHANNEL_PING:
handle_ping_cmd(peer, master->msg_in);
goto out;
case WIRE_CHANNEL_BAD_COMMAND:
case WIRE_CHANNEL_HSM_FAILED:
@ -1208,6 +1266,7 @@ static struct io_plan *req_in(struct io_conn *conn, struct daemon_conn *master)
case WIRE_CHANNEL_FULFILLED_HTLC:
case WIRE_CHANNEL_FAILED_HTLC:
case WIRE_CHANNEL_MALFORMED_HTLC:
case WIRE_CHANNEL_PING_REPLY:
case WIRE_CHANNEL_PEER_BAD_MESSAGE:
break;
}
@ -1240,6 +1299,7 @@ int main(int argc, char *argv[])
daemon_conn_init(peer, &peer->master, REQ_FD, req_in);
peer->channel = NULL;
peer->htlc_id = 0;
peer->num_pings_outstanding = 0;
timers_init(&peer->timers, time_mono());
peer->commit_timer = NULL;
peer->commit_index[LOCAL] = peer->commit_index[REMOTE] = 0;

9
lightningd/channel/channel_wire.csv

@ -104,3 +104,12 @@ channel_malformed_htlc,10
channel_malformed_htlc,0,id,8
channel_malformed_htlc,0,sha256_of_onion,32
channel_malformed_htlc,0,failure_code,2
# Ping/pong test.
channel_ping,11
channel_ping,0,num_pong_bytes,u16
channel_ping,0,len,u16
channel_ping_reply,111
channel_ping_reply,0,totlen,u16

Can't render this file because it has a wrong number of fields in line 2.

91
lightningd/dev_ping.c

@ -0,0 +1,91 @@
#include <daemon/jsonrpc.h>
#include <daemon/log.h>
#include <daemon/sphinx.h>
#include <lightningd/channel/gen_channel_wire.h>
#include <lightningd/htlc_end.h>
#include <lightningd/lightningd.h>
#include <lightningd/peer_control.h>
#include <lightningd/subd.h>
#include <utils.h>
static bool ping_reply(struct subd *subd, const u8 *msg, const int *fds,
struct command *cmd)
{
u16 totlen;
bool ok;
log_debug(subd->ld->log, "Got ping reply!");
ok = fromwire_channel_ping_reply(msg, NULL, &totlen);
if (!ok)
command_fail(cmd, "Bad reply message");
else {
struct json_result *response = new_json_result(cmd);
json_object_start(response, NULL);
json_add_num(response, "totlen", totlen);
json_object_end(response);
command_success(cmd, response);
}
return true;
}
static void json_dev_ping(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct lightningd *ld = ld_from_dstate(cmd->dstate);
struct peer *peer;
u8 *msg;
jsmntok_t *peeridtok, *lentok, *pongbytestok;
unsigned int len, pongbytes;
if (!json_get_params(buffer, params,
"peerid", &peeridtok,
"len", &lentok,
"pongbytes", &pongbytestok,
NULL)) {
command_fail(cmd, "Need peerid, len and pongbytes");
return;
}
peer = peer_from_json(ld, buffer, peeridtok);
if (!peer) {
command_fail(cmd, "Could not find peer with that peerid");
return;
}
/* 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")) {
command_fail(cmd, "Peer in %s",
peer->owner ? peer->owner->name : "unattached");
return;
}
if (!json_tok_number(buffer, lentok, &len)) {
command_fail(cmd, "'%.*s' is not a valid number",
(int)(lentok->end - lentok->start),
buffer + lentok->start);
return;
}
if (!json_tok_number(buffer, pongbytestok, &pongbytes)) {
command_fail(cmd, "'%.*s' is not a valid number",
(int)(pongbytestok->end - pongbytestok->start),
buffer + pongbytestok->start);
return;
}
msg = towire_channel_ping(cmd, pongbytes, len);
/* FIXME: If subdaemon dies? */
subd_req(peer->owner, peer->owner, take(msg), -1, 0, ping_reply, cmd);
}
static const struct json_command dev_ping_command = {
"dev-ping",
json_dev_ping,
"Offer {peerid} a ping of length {len} asking for {pongbytes}",
"Returns { totlen: u32 } on success"
};
AUTODATA(json_command, &dev_ping_command);

2
lightningd/peer_control.c

@ -864,8 +864,10 @@ static int channel_msg(struct subd *sd, const u8 *msg, const int *unused)
case WIRE_CHANNEL_OFFER_HTLC:
case WIRE_CHANNEL_FULFILL_HTLC:
case WIRE_CHANNEL_FAIL_HTLC:
case WIRE_CHANNEL_PING:
/* Replies go to requests. */
case WIRE_CHANNEL_OFFER_HTLC_REPLY:
case WIRE_CHANNEL_PING_REPLY:
break;
}

4
lightningd/ping.c

@ -33,7 +33,9 @@ bool check_ping_make_pong(const tal_t *ctx, const u8 *ping, u8 **pong)
ignored = tal_arrz(ctx, u8, num_pong_bytes);
*pong = towire_pong(ctx, ignored);
tal_free(ignored);
}
} else
*pong = NULL;
return true;
}

56
lightningd/test/test-ping

@ -0,0 +1,56 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
add_funds()
{
local NEWADDR=`$1 newaddr | get_field address`
local FUND_INPUT_TXID=`$CLI sendtoaddress $NEWADDR $2`
local FUND_INPUT_TX=`$CLI getrawtransaction $FUND_INPUT_TXID`
$1 addfunds $FUND_INPUT_TX
}
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 2 "$@"
setup_lightning 2
start_lightningd 2 lightningd/lightningd
lcli1 connect localhost $PORT2 $ID2
add_funds lcli1 0.2
# Now fund the channels
CHANNEL_SAT=10000000
CHANNEL_MSAT=$(($CHANNEL_SAT * 1000))
lcli1 fundchannel $ID2 $CHANNEL_SAT
# Lock them in.
$CLI generate 10
check "lcli1 getpeers info | $FGREP 'Funding tx reached depth'"
# 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 ]
lcli1 stop
lcli2 stop
all_ok
Loading…
Cancel
Save