mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
lightningd: add dev_ping command for channeld.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
d5be8d26f2
commit
8f358b7a91
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
|
91
lightningd/dev_ping.c
Normal file
91
lightningd/dev_ping.c
Normal file
@ -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);
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
Executable file
56
lightningd/test/test-ping
Executable file
@ -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…
Reference in New Issue
Block a user