mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
connectd: handle pings and pongs.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Changed: JSON_RPC: `ping` now works with connected peers, even without a channel.
This commit is contained in:
parent
0ac5c4f8df
commit
50eccb6a12
@ -29,7 +29,6 @@
|
|||||||
#include <common/peer_failed.h>
|
#include <common/peer_failed.h>
|
||||||
#include <common/peer_io.h>
|
#include <common/peer_io.h>
|
||||||
#include <common/per_peer_state.h>
|
#include <common/per_peer_state.h>
|
||||||
#include <common/ping.h>
|
|
||||||
#include <common/private_channel_announcement.h>
|
#include <common/private_channel_announcement.h>
|
||||||
#include <common/read_peer_msg.h>
|
#include <common/read_peer_msg.h>
|
||||||
#include <common/status.h>
|
#include <common/status.h>
|
||||||
@ -50,15 +49,6 @@
|
|||||||
#define MASTER_FD STDIN_FILENO
|
#define MASTER_FD STDIN_FILENO
|
||||||
#define HSM_FD 5
|
#define HSM_FD 5
|
||||||
|
|
||||||
enum pong_expect_type {
|
|
||||||
/* We weren't expecting a ping reply */
|
|
||||||
PONG_UNEXPECTED = 0,
|
|
||||||
/* We were expecting a ping reply due to ping command */
|
|
||||||
PONG_EXPECTED_COMMAND = 1,
|
|
||||||
/* We were expecting a ping reply due to ping timer */
|
|
||||||
PONG_EXPECTED_PROBING = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct peer {
|
struct peer {
|
||||||
struct per_peer_state *pps;
|
struct per_peer_state *pps;
|
||||||
bool funding_locked[NUM_SIDES];
|
bool funding_locked[NUM_SIDES];
|
||||||
@ -110,12 +100,6 @@ struct peer {
|
|||||||
u64 commit_timer_attempts;
|
u64 commit_timer_attempts;
|
||||||
u32 commit_msec;
|
u32 commit_msec;
|
||||||
|
|
||||||
/* Random ping timer, to detect dead connections. */
|
|
||||||
struct oneshot *ping_timer;
|
|
||||||
|
|
||||||
/* Are we expecting a pong? */
|
|
||||||
enum pong_expect_type expecting_pong;
|
|
||||||
|
|
||||||
/* The feerate we want. */
|
/* The feerate we want. */
|
||||||
u32 desired_feerate;
|
u32 desired_feerate;
|
||||||
|
|
||||||
@ -1095,29 +1079,6 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx,
|
|||||||
return htlc_sigs;
|
return htlc_sigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mutual recursion */
|
|
||||||
static void send_ping(struct peer *peer);
|
|
||||||
|
|
||||||
static void set_ping_timer(struct peer *peer)
|
|
||||||
{
|
|
||||||
peer->ping_timer = new_reltimer(&peer->timers, peer,
|
|
||||||
time_from_sec(15 + pseudorand(30)),
|
|
||||||
send_ping, peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_ping(struct peer *peer)
|
|
||||||
{
|
|
||||||
/* Already have a ping in flight? */
|
|
||||||
if (peer->expecting_pong != PONG_UNEXPECTED) {
|
|
||||||
status_debug("Last ping unreturned: hanging up");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
peer_write(peer->pps, take(make_ping(NULL, 1, 0)));
|
|
||||||
peer->expecting_pong = PONG_EXPECTED_PROBING;
|
|
||||||
set_ping_timer(peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Peer protocol doesn't want sighash flags. */
|
/* Peer protocol doesn't want sighash flags. */
|
||||||
static secp256k1_ecdsa_signature *raw_sigs(const tal_t *ctx,
|
static secp256k1_ecdsa_signature *raw_sigs(const tal_t *ctx,
|
||||||
const struct bitcoin_signature *sigs)
|
const struct bitcoin_signature *sigs)
|
||||||
@ -2190,29 +2151,6 @@ static void handle_unexpected_reestablish(struct peer *peer, const u8 *msg)
|
|||||||
&channel_id));
|
&channel_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_ping_reply(struct peer *peer, const u8 *msg)
|
|
||||||
{
|
|
||||||
u8 *ignored;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* We print this out because we asked for pong, so can't spam us... */
|
|
||||||
if (!fromwire_pong(msg, msg, &ignored))
|
|
||||||
status_unusual("Got malformed ping reply %s",
|
|
||||||
tal_hex(tmpctx, msg));
|
|
||||||
|
|
||||||
/* We print this because dev versions of c-lightning embed
|
|
||||||
* version here: see check_ping_make_pong! */
|
|
||||||
for (i = 0; i < tal_count(ignored); i++) {
|
|
||||||
if (ignored[i] < ' ' || ignored[i] == 127)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
status_debug("Got pong %zu bytes (%.*s...)",
|
|
||||||
tal_count(ignored), (int)i, (char *)ignored);
|
|
||||||
wire_sync_write(MASTER_FD,
|
|
||||||
take(towire_channeld_ping_reply(NULL, true,
|
|
||||||
tal_bytelen(msg))));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void peer_in(struct peer *peer, const u8 *msg)
|
static void peer_in(struct peer *peer, const u8 *msg)
|
||||||
{
|
{
|
||||||
enum peer_wire type = fromwire_peektype(msg);
|
enum peer_wire type = fromwire_peektype(msg);
|
||||||
@ -2298,19 +2236,6 @@ static void peer_in(struct peer *peer, const u8 *msg)
|
|||||||
case WIRE_INIT_RBF:
|
case WIRE_INIT_RBF:
|
||||||
case WIRE_ACK_RBF:
|
case WIRE_ACK_RBF:
|
||||||
break;
|
break;
|
||||||
case WIRE_PONG:
|
|
||||||
switch (peer->expecting_pong) {
|
|
||||||
case PONG_EXPECTED_COMMAND:
|
|
||||||
handle_ping_reply(peer, msg);
|
|
||||||
/* fall thru */
|
|
||||||
case PONG_EXPECTED_PROBING:
|
|
||||||
peer->expecting_pong = PONG_UNEXPECTED;
|
|
||||||
return;
|
|
||||||
case PONG_UNEXPECTED:
|
|
||||||
status_debug("Unexpected pong?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
|
|
||||||
case WIRE_CHANNEL_REESTABLISH:
|
case WIRE_CHANNEL_REESTABLISH:
|
||||||
handle_unexpected_reestablish(peer, msg);
|
handle_unexpected_reestablish(peer, msg);
|
||||||
@ -2326,6 +2251,7 @@ static void peer_in(struct peer *peer, const u8 *msg)
|
|||||||
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
||||||
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
||||||
case WIRE_PING:
|
case WIRE_PING:
|
||||||
|
case WIRE_PONG:
|
||||||
case WIRE_WARNING:
|
case WIRE_WARNING:
|
||||||
case WIRE_ERROR:
|
case WIRE_ERROR:
|
||||||
case WIRE_OBS2_ONION_MESSAGE:
|
case WIRE_OBS2_ONION_MESSAGE:
|
||||||
@ -3608,57 +3534,6 @@ static void handle_send_error(struct peer *peer, const u8 *msg)
|
|||||||
take(towire_channeld_send_error_reply(NULL)));
|
take(towire_channeld_send_error_reply(NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_send_ping(struct peer *peer, const u8 *msg)
|
|
||||||
{
|
|
||||||
u8 *ping;
|
|
||||||
u16 len, num_pong_bytes;
|
|
||||||
|
|
||||||
if (!fromwire_channeld_ping(msg, &num_pong_bytes, &len))
|
|
||||||
master_badmsg(WIRE_CHANNELD_PING, msg);
|
|
||||||
|
|
||||||
/* We're not supposed to send another ping until previous replied */
|
|
||||||
if (peer->expecting_pong != PONG_UNEXPECTED) {
|
|
||||||
wire_sync_write(MASTER_FD,
|
|
||||||
take(towire_channeld_ping_reply(NULL, false, 0)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* It should never ask for an oversize ping. */
|
|
||||||
ping = make_ping(NULL, num_pong_bytes, len);
|
|
||||||
if (tal_count(ping) > 65535)
|
|
||||||
status_failed(STATUS_FAIL_MASTER_IO, "Oversize ping");
|
|
||||||
|
|
||||||
peer_write(peer->pps, take(ping));
|
|
||||||
|
|
||||||
/* Since we're doing this manually, kill and restart timer. */
|
|
||||||
status_debug("sending ping expecting %sresponse",
|
|
||||||
num_pong_bytes >= 65532 ? "no " : "");
|
|
||||||
|
|
||||||
/* BOLT #1:
|
|
||||||
*
|
|
||||||
* A node receiving a `ping` message:
|
|
||||||
*...
|
|
||||||
* - if `num_pong_bytes` is less than 65532:
|
|
||||||
* - MUST respond by sending a `pong` message, with `byteslen` equal
|
|
||||||
* to `num_pong_bytes`.
|
|
||||||
* - otherwise (`num_pong_bytes` is **not** less than 65532):
|
|
||||||
* - MUST ignore the `ping`.
|
|
||||||
*/
|
|
||||||
if (num_pong_bytes >= 65532) {
|
|
||||||
wire_sync_write(MASTER_FD,
|
|
||||||
take(towire_channeld_ping_reply(NULL,
|
|
||||||
true, 0)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We'll respond to lightningd once the pong comes in */
|
|
||||||
peer->expecting_pong = PONG_EXPECTED_COMMAND;
|
|
||||||
|
|
||||||
/* Restart our timed pings now. */
|
|
||||||
tal_free(peer->ping_timer);
|
|
||||||
set_ping_timer(peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
static void handle_dev_reenable_commit(struct peer *peer)
|
static void handle_dev_reenable_commit(struct peer *peer)
|
||||||
{
|
{
|
||||||
@ -3757,9 +3632,6 @@ static void req_in(struct peer *peer, const u8 *msg)
|
|||||||
case WIRE_CHANNELD_SEND_ERROR:
|
case WIRE_CHANNELD_SEND_ERROR:
|
||||||
handle_send_error(peer, msg);
|
handle_send_error(peer, msg);
|
||||||
return;
|
return;
|
||||||
case WIRE_CHANNELD_PING:
|
|
||||||
handle_send_ping(peer, msg);
|
|
||||||
return;
|
|
||||||
case WIRE_CHANNELD_CHANNEL_UPDATE:
|
case WIRE_CHANNELD_CHANNEL_UPDATE:
|
||||||
handle_channel_update(peer, msg);
|
handle_channel_update(peer, msg);
|
||||||
return;
|
return;
|
||||||
@ -3798,7 +3670,6 @@ static void req_in(struct peer *peer, const u8 *msg)
|
|||||||
case WIRE_CHANNELD_SEND_ERROR_REPLY:
|
case WIRE_CHANNELD_SEND_ERROR_REPLY:
|
||||||
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:
|
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:
|
||||||
case WIRE_CHANNELD_UPGRADED:
|
case WIRE_CHANNELD_UPGRADED:
|
||||||
case WIRE_CHANNELD_PING_REPLY:
|
|
||||||
case WIRE_CHANNELD_USED_CHANNEL_UPDATE:
|
case WIRE_CHANNELD_USED_CHANNEL_UPDATE:
|
||||||
case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE:
|
case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE:
|
||||||
case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT:
|
case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT:
|
||||||
@ -4039,10 +3910,8 @@ int main(int argc, char *argv[])
|
|||||||
status_setup_sync(MASTER_FD);
|
status_setup_sync(MASTER_FD);
|
||||||
|
|
||||||
peer = tal(NULL, struct peer);
|
peer = tal(NULL, struct peer);
|
||||||
peer->expecting_pong = PONG_UNEXPECTED;
|
|
||||||
timers_init(&peer->timers, time_mono());
|
timers_init(&peer->timers, time_mono());
|
||||||
peer->commit_timer = NULL;
|
peer->commit_timer = NULL;
|
||||||
set_ping_timer(peer);
|
|
||||||
peer->have_sigs[LOCAL] = peer->have_sigs[REMOTE] = false;
|
peer->have_sigs[LOCAL] = peer->have_sigs[REMOTE] = false;
|
||||||
peer->announce_depth_reached = false;
|
peer->announce_depth_reached = false;
|
||||||
peer->channel_local_active = false;
|
peer->channel_local_active = false;
|
||||||
|
@ -266,14 +266,3 @@ msgdata,channeld_upgraded,new_type,channel_type,
|
|||||||
# Tell peer about our latest and greatest blockheight.
|
# Tell peer about our latest and greatest blockheight.
|
||||||
msgtype,channeld_blockheight,1012
|
msgtype,channeld_blockheight,1012
|
||||||
msgdata,channeld_blockheight,blockheight,u32,
|
msgdata,channeld_blockheight,blockheight,u32,
|
||||||
|
|
||||||
# Ping/pong test. Waits for a reply if it expects one.
|
|
||||||
msgtype,channeld_ping,1030
|
|
||||||
msgdata,channeld_ping,num_pong_bytes,u16,
|
|
||||||
msgdata,channeld_ping,len,u16,
|
|
||||||
|
|
||||||
msgtype,channeld_ping_reply,1130
|
|
||||||
# False if we there was already a ping in progress.
|
|
||||||
msgdata,channeld_ping_reply,sent,bool,
|
|
||||||
# 0 == no pong expected, otherwise length of pong.
|
|
||||||
msgdata,channeld_ping_reply,totlen,u16,
|
|
||||||
|
Can't render this file because it has a wrong number of fields in line 13.
|
@ -57,6 +57,7 @@ CONNECTD_COMMON_OBJS := \
|
|||||||
common/msg_queue.o \
|
common/msg_queue.o \
|
||||||
common/node_id.o \
|
common/node_id.o \
|
||||||
common/onionreply.o \
|
common/onionreply.o \
|
||||||
|
common/ping.o \
|
||||||
common/per_peer_state.o \
|
common/per_peer_state.o \
|
||||||
common/psbt_open.o \
|
common/psbt_open.o \
|
||||||
common/pseudorand.o \
|
common/pseudorand.o \
|
||||||
|
@ -1966,6 +1966,10 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
|||||||
peer_final_msg(conn, daemon, msg);
|
peer_final_msg(conn, daemon, msg);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
case WIRE_CONNECTD_PING:
|
||||||
|
send_manual_ping(daemon, msg);
|
||||||
|
goto out;
|
||||||
|
|
||||||
case WIRE_CONNECTD_DEV_MEMLEAK:
|
case WIRE_CONNECTD_DEV_MEMLEAK:
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
dev_connect_memleak(daemon, msg);
|
dev_connect_memleak(daemon, msg);
|
||||||
@ -1978,6 +1982,7 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
|||||||
case WIRE_CONNECTD_RECONNECTED:
|
case WIRE_CONNECTD_RECONNECTED:
|
||||||
case WIRE_CONNECTD_CONNECT_FAILED:
|
case WIRE_CONNECTD_CONNECT_FAILED:
|
||||||
case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:
|
case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:
|
||||||
|
case WIRE_CONNECTD_PING_REPLY:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,16 @@ struct gossip_state {
|
|||||||
size_t off;
|
size_t off;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*~ We need to know if we were expecting a pong, and why */
|
||||||
|
enum pong_expect_type {
|
||||||
|
/* We weren't expecting a ping reply */
|
||||||
|
PONG_UNEXPECTED = 0,
|
||||||
|
/* We were expecting a ping reply due to ping command */
|
||||||
|
PONG_EXPECTED_COMMAND = 1,
|
||||||
|
/* We were expecting a ping reply due to ping timer */
|
||||||
|
PONG_EXPECTED_PROBING = 2,
|
||||||
|
};
|
||||||
|
|
||||||
/*~ We keep a hash table (ccan/htable) of peers, which tells us what peers are
|
/*~ We keep a hash table (ccan/htable) of peers, which tells us what peers are
|
||||||
* already connected (by peer->id). */
|
* already connected (by peer->id). */
|
||||||
struct peer {
|
struct peer {
|
||||||
@ -65,6 +75,12 @@ struct peer {
|
|||||||
/* We stream from the gossip_store for them, when idle */
|
/* We stream from the gossip_store for them, when idle */
|
||||||
struct gossip_state gs;
|
struct gossip_state gs;
|
||||||
|
|
||||||
|
/* Are we expecting a pong? */
|
||||||
|
enum pong_expect_type expecting_pong;
|
||||||
|
|
||||||
|
/* Random ping timer, to detect dead connections. */
|
||||||
|
struct oneshot *ping_timer;
|
||||||
|
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
bool dev_read_enabled;
|
bool dev_read_enabled;
|
||||||
/* If non-NULL, this counts down; 0 means disable */
|
/* If non-NULL, this counts down; 0 means disable */
|
||||||
|
@ -82,3 +82,15 @@ msgtype,connectd_dev_memleak,2033
|
|||||||
|
|
||||||
msgtype,connectd_dev_memleak_reply,2133
|
msgtype,connectd_dev_memleak_reply,2133
|
||||||
msgdata,connectd_dev_memleak_reply,leak,bool,
|
msgdata,connectd_dev_memleak_reply,leak,bool,
|
||||||
|
|
||||||
|
# Ping/pong test. Waits for a reply if it expects one.
|
||||||
|
msgtype,connectd_ping,2030
|
||||||
|
msgdata,connectd_ping,id,node_id,
|
||||||
|
msgdata,connectd_ping,num_pong_bytes,u16,
|
||||||
|
msgdata,connectd_ping,len,u16,
|
||||||
|
|
||||||
|
msgtype,connectd_ping_reply,2130
|
||||||
|
# False if we there was already a ping in progress.
|
||||||
|
msgdata,connectd_ping_reply,sent,bool,
|
||||||
|
# 0 == no pong expected, otherwise length of pong.
|
||||||
|
msgdata,connectd_ping_reply,totlen,u16,
|
||||||
|
|
@ -14,12 +14,14 @@
|
|||||||
#include <common/gossip_store.h>
|
#include <common/gossip_store.h>
|
||||||
#include <common/memleak.h>
|
#include <common/memleak.h>
|
||||||
#include <common/per_peer_state.h>
|
#include <common/per_peer_state.h>
|
||||||
|
#include <common/ping.h>
|
||||||
#include <common/status.h>
|
#include <common/status.h>
|
||||||
#include <common/timeout.h>
|
#include <common/timeout.h>
|
||||||
#include <common/utils.h>
|
#include <common/utils.h>
|
||||||
#include <common/wire_error.h>
|
#include <common/wire_error.h>
|
||||||
#include <connectd/connectd.h>
|
#include <connectd/connectd.h>
|
||||||
#include <connectd/connectd_gossipd_wiregen.h>
|
#include <connectd/connectd_gossipd_wiregen.h>
|
||||||
|
#include <connectd/connectd_wiregen.h>
|
||||||
#include <connectd/multiplex.h>
|
#include <connectd/multiplex.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -337,32 +339,110 @@ again:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We handle gossip_timestamp_filter, and divert other gossip msgs to gossipd */
|
/* Mutual recursion */
|
||||||
static bool handle_message_locally(struct peer *peer, const u8 *msg)
|
static void send_ping(struct peer *peer);
|
||||||
|
|
||||||
|
static void set_ping_timer(struct peer *peer)
|
||||||
|
{
|
||||||
|
peer->ping_timer = new_reltimer(&peer->daemon->timers, peer,
|
||||||
|
time_from_sec(15 + pseudorand(30)),
|
||||||
|
send_ping, peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_ping(struct peer *peer)
|
||||||
|
{
|
||||||
|
/* Already have a ping in flight? */
|
||||||
|
if (peer->expecting_pong != PONG_UNEXPECTED) {
|
||||||
|
status_peer_debug(&peer->id, "Last ping unreturned: hanging up");
|
||||||
|
if (peer->to_peer)
|
||||||
|
io_close(peer->to_peer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_peer_msg(peer, take(make_ping(NULL, 1, 0)));
|
||||||
|
peer->expecting_pong = PONG_EXPECTED_PROBING;
|
||||||
|
set_ping_timer(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ping_in(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
u8 *pong;
|
||||||
|
|
||||||
|
/* gossipd doesn't log IO, so we log it here. */
|
||||||
|
status_peer_io(LOG_IO_IN, &peer->id, msg);
|
||||||
|
|
||||||
|
if (!check_ping_make_pong(NULL, msg, &pong)) {
|
||||||
|
send_warning(peer, "Invalid ping %s", tal_hex(msg, msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pong)
|
||||||
|
queue_peer_msg(peer, take(pong));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ping_reply(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
u8 *ignored;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* We print this out because we asked for pong, so can't spam us... */
|
||||||
|
if (!fromwire_pong(msg, msg, &ignored))
|
||||||
|
status_peer_unusual(&peer->id, "Got malformed ping reply %s",
|
||||||
|
tal_hex(tmpctx, msg));
|
||||||
|
|
||||||
|
/* We print this because dev versions of c-lightning embed
|
||||||
|
* version here: see check_ping_make_pong! */
|
||||||
|
for (i = 0; i < tal_count(ignored); i++) {
|
||||||
|
if (ignored[i] < ' ' || ignored[i] == 127)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
status_debug("Got pong %zu bytes (%.*s...)",
|
||||||
|
tal_count(ignored), (int)i, (char *)ignored);
|
||||||
|
daemon_conn_send(peer->daemon->master,
|
||||||
|
take(towire_connectd_ping_reply(NULL, true,
|
||||||
|
tal_bytelen(msg))));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pong_in(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
/* gossipd doesn't log IO, so we log it here. */
|
||||||
|
status_peer_io(LOG_IO_IN, &peer->id, msg);
|
||||||
|
|
||||||
|
switch (peer->expecting_pong) {
|
||||||
|
case PONG_EXPECTED_COMMAND:
|
||||||
|
handle_ping_reply(peer, msg);
|
||||||
|
/* fall thru */
|
||||||
|
case PONG_EXPECTED_PROBING:
|
||||||
|
peer->expecting_pong = PONG_UNEXPECTED;
|
||||||
|
return;
|
||||||
|
case PONG_UNEXPECTED:
|
||||||
|
status_debug("Unexpected pong?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forward to gossipd */
|
||||||
|
static void handle_gossip_in(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
u8 *gmsg = towire_gossipd_recv_gossip(NULL, &peer->id, msg);
|
||||||
|
|
||||||
|
/* gossipd doesn't log IO, so we log it here. */
|
||||||
|
status_peer_io(LOG_IO_IN, &peer->id, msg);
|
||||||
|
daemon_conn_send(peer->daemon->gossipd, take(gmsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_gossip_timetamp_filter_in(struct peer *peer, const u8 *msg)
|
||||||
{
|
{
|
||||||
struct bitcoin_blkid chain_hash;
|
struct bitcoin_blkid chain_hash;
|
||||||
u32 first_timestamp, timestamp_range;
|
u32 first_timestamp, timestamp_range;
|
||||||
|
|
||||||
/* We remember these so we don't rexmit them */
|
|
||||||
if (is_msg_gossip_broadcast(msg))
|
|
||||||
gossip_rcvd_filter_add(peer->gs.grf, msg);
|
|
||||||
|
|
||||||
if (!fromwire_gossip_timestamp_filter(msg, &chain_hash,
|
if (!fromwire_gossip_timestamp_filter(msg, &chain_hash,
|
||||||
&first_timestamp,
|
&first_timestamp,
|
||||||
×tamp_range)) {
|
×tamp_range)) {
|
||||||
/* Do we want to divert to gossipd? */
|
send_warning(peer, "gossip_timestamp_filter invalid: %s",
|
||||||
if (is_msg_for_gossipd(msg)) {
|
tal_hex(tmpctx, msg));
|
||||||
u8 *gmsg = towire_gossipd_recv_gossip(NULL,
|
return;
|
||||||
&peer->id, msg);
|
|
||||||
|
|
||||||
/* gossipd doesn't log IO, so we log it here. */
|
|
||||||
status_peer_io(LOG_IO_IN, &peer->id, msg);
|
|
||||||
|
|
||||||
daemon_conn_send(peer->daemon->gossipd, take(gmsg));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gossipd doesn't log IO, so we log it here. */
|
/* gossipd doesn't log IO, so we log it here. */
|
||||||
@ -371,7 +451,7 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg)
|
|||||||
if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) {
|
if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) {
|
||||||
send_warning(peer, "gossip_timestamp_filter for bad chain: %s",
|
send_warning(peer, "gossip_timestamp_filter for bad chain: %s",
|
||||||
tal_hex(tmpctx, msg));
|
tal_hex(tmpctx, msg));
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
peer->gs.timestamp_min = first_timestamp;
|
peer->gs.timestamp_min = first_timestamp;
|
||||||
@ -388,8 +468,35 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg)
|
|||||||
/* We send immediately the first time, after that we wait. */
|
/* We send immediately the first time, after that we wait. */
|
||||||
if (!peer->gs.gossip_timer)
|
if (!peer->gs.gossip_timer)
|
||||||
wake_gossip(peer);
|
wake_gossip(peer);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
/* We handle pings and gossip messages. */
|
||||||
|
static bool handle_message_locally(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
enum peer_wire type = fromwire_peektype(msg);
|
||||||
|
|
||||||
|
/* We remember these so we don't rexmit them */
|
||||||
|
if (is_msg_gossip_broadcast(msg))
|
||||||
|
gossip_rcvd_filter_add(peer->gs.grf, msg);
|
||||||
|
|
||||||
|
if (type == WIRE_GOSSIP_TIMESTAMP_FILTER) {
|
||||||
|
handle_gossip_timetamp_filter_in(peer, msg);
|
||||||
|
return true;
|
||||||
|
} else if (type == WIRE_PING) {
|
||||||
|
handle_ping_in(peer, msg);
|
||||||
|
return true;
|
||||||
|
} else if (type == WIRE_PONG) {
|
||||||
|
handle_pong_in(peer, msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do we want to divert to gossipd? */
|
||||||
|
if (is_msg_for_gossipd(msg)) {
|
||||||
|
handle_gossip_in(peer, msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_timeout(struct peer *peer)
|
static void close_timeout(struct peer *peer)
|
||||||
@ -665,6 +772,10 @@ struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn,
|
|||||||
* lightningd to tell us to close with the peer */
|
* lightningd to tell us to close with the peer */
|
||||||
tal_add_destructor2(peer_conn, destroy_peer_conn, peer);
|
tal_add_destructor2(peer_conn, destroy_peer_conn, peer);
|
||||||
|
|
||||||
|
/* Start keepalives */
|
||||||
|
peer->expecting_pong = PONG_UNEXPECTED;
|
||||||
|
set_ping_timer(peer);
|
||||||
|
|
||||||
return io_duplex(peer_conn,
|
return io_duplex(peer_conn,
|
||||||
read_hdr_from_peer(peer_conn, peer),
|
read_hdr_from_peer(peer_conn, peer),
|
||||||
write_to_peer(peer_conn, peer));
|
write_to_peer(peer_conn, peer));
|
||||||
@ -677,3 +788,65 @@ void multiplex_final_msg(struct peer *peer, const u8 *final_msg TAKES)
|
|||||||
if (!peer->to_subd)
|
if (!peer->to_subd)
|
||||||
io_wake(peer->peer_outq);
|
io_wake(peer->peer_outq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Lightningd says to send a ping */
|
||||||
|
void send_manual_ping(struct daemon *daemon, const u8 *msg)
|
||||||
|
{
|
||||||
|
u8 *ping;
|
||||||
|
struct node_id id;
|
||||||
|
u16 len, num_pong_bytes;
|
||||||
|
struct peer *peer;
|
||||||
|
|
||||||
|
if (!fromwire_connectd_ping(msg, &id, &num_pong_bytes, &len))
|
||||||
|
master_badmsg(WIRE_CONNECTD_PING, msg);
|
||||||
|
|
||||||
|
peer = peer_htable_get(&daemon->peers, &id);
|
||||||
|
if (!peer) {
|
||||||
|
daemon_conn_send(daemon->master,
|
||||||
|
take(towire_connectd_ping_reply(NULL,
|
||||||
|
false, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're not supposed to send another ping until previous replied */
|
||||||
|
if (peer->expecting_pong != PONG_UNEXPECTED) {
|
||||||
|
daemon_conn_send(daemon->master,
|
||||||
|
take(towire_connectd_ping_reply(NULL,
|
||||||
|
false, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It should never ask for an oversize ping. */
|
||||||
|
ping = make_ping(NULL, num_pong_bytes, len);
|
||||||
|
if (tal_count(ping) > 65535)
|
||||||
|
status_failed(STATUS_FAIL_MASTER_IO, "Oversize ping");
|
||||||
|
|
||||||
|
queue_peer_msg(peer, take(ping));
|
||||||
|
|
||||||
|
status_debug("sending ping expecting %sresponse",
|
||||||
|
num_pong_bytes >= 65532 ? "no " : "");
|
||||||
|
|
||||||
|
/* BOLT #1:
|
||||||
|
*
|
||||||
|
* A node receiving a `ping` message:
|
||||||
|
*...
|
||||||
|
* - if `num_pong_bytes` is less than 65532:
|
||||||
|
* - MUST respond by sending a `pong` message, with `byteslen` equal
|
||||||
|
* to `num_pong_bytes`.
|
||||||
|
* - otherwise (`num_pong_bytes` is **not** less than 65532):
|
||||||
|
* - MUST ignore the `ping`.
|
||||||
|
*/
|
||||||
|
if (num_pong_bytes >= 65532) {
|
||||||
|
daemon_conn_send(daemon->master,
|
||||||
|
take(towire_connectd_ping_reply(NULL,
|
||||||
|
true, 0)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We'll respond to lightningd once the pong comes in */
|
||||||
|
peer->expecting_pong = PONG_EXPECTED_COMMAND;
|
||||||
|
|
||||||
|
/* Since we're doing this manually, kill and restart timer. */
|
||||||
|
tal_free(peer->ping_timer);
|
||||||
|
set_ping_timer(peer);
|
||||||
|
}
|
||||||
|
@ -30,4 +30,7 @@ void setup_peer_gossip_store(struct peer *peer,
|
|||||||
|
|
||||||
/* Start the process of flushing and closing the peer_conn */
|
/* Start the process of flushing and closing the peer_conn */
|
||||||
void close_peer_conn(struct peer *peer);
|
void close_peer_conn(struct peer *peer);
|
||||||
|
|
||||||
|
/* When lightningd says to send a ping */
|
||||||
|
void send_manual_ping(struct daemon *daemon, const u8 *msg);
|
||||||
#endif /* LIGHTNING_CONNECTD_MULTIPLEX_H */
|
#endif /* LIGHTNING_CONNECTD_MULTIPLEX_H */
|
||||||
|
@ -31,7 +31,6 @@ LIGHTNINGD_SRC := \
|
|||||||
lightningd/peer_control.c \
|
lightningd/peer_control.c \
|
||||||
lightningd/peer_fd.c \
|
lightningd/peer_fd.c \
|
||||||
lightningd/peer_htlcs.c \
|
lightningd/peer_htlcs.c \
|
||||||
lightningd/ping.c \
|
|
||||||
lightningd/plugin.c \
|
lightningd/plugin.c \
|
||||||
lightningd/plugin_control.c \
|
lightningd/plugin_control.c \
|
||||||
lightningd/plugin_hook.c \
|
lightningd/plugin_hook.c \
|
||||||
@ -42,6 +41,7 @@ LIGHTNINGD_SRC := \
|
|||||||
|
|
||||||
LIGHTNINGD_SRC_NOHDR := \
|
LIGHTNINGD_SRC_NOHDR := \
|
||||||
lightningd/datastore.c \
|
lightningd/datastore.c \
|
||||||
|
lightningd/ping.c \
|
||||||
lightningd/offer.c \
|
lightningd/offer.c \
|
||||||
lightningd/signmessage.c
|
lightningd/signmessage.c
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include <lightningd/notification.h>
|
#include <lightningd/notification.h>
|
||||||
#include <lightningd/peer_control.h>
|
#include <lightningd/peer_control.h>
|
||||||
#include <lightningd/peer_fd.h>
|
#include <lightningd/peer_fd.h>
|
||||||
#include <lightningd/ping.h>
|
|
||||||
#include <wire/common_wiregen.h>
|
#include <wire/common_wiregen.h>
|
||||||
|
|
||||||
static void update_feerates(struct lightningd *ld, struct channel *channel)
|
static void update_feerates(struct lightningd *ld, struct channel *channel)
|
||||||
@ -519,9 +518,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
|
|||||||
case WIRE_CHANNELD_SEND_ERROR_REPLY:
|
case WIRE_CHANNELD_SEND_ERROR_REPLY:
|
||||||
handle_error_channel(sd->channel, msg);
|
handle_error_channel(sd->channel, msg);
|
||||||
break;
|
break;
|
||||||
case WIRE_CHANNELD_PING_REPLY:
|
|
||||||
ping_reply(sd, msg);
|
|
||||||
break;
|
|
||||||
case WIRE_CHANNELD_USED_CHANNEL_UPDATE:
|
case WIRE_CHANNELD_USED_CHANNEL_UPDATE:
|
||||||
/* This tells gossipd we used it. */
|
/* This tells gossipd we used it. */
|
||||||
get_channel_update(sd->channel);
|
get_channel_update(sd->channel);
|
||||||
@ -565,7 +561,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
|
|||||||
case WIRE_CHANNELD_DEV_MEMLEAK_REPLY:
|
case WIRE_CHANNELD_DEV_MEMLEAK_REPLY:
|
||||||
case WIRE_CHANNELD_SEND_ERROR:
|
case WIRE_CHANNELD_SEND_ERROR:
|
||||||
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:
|
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:
|
||||||
case WIRE_CHANNELD_PING:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,10 +363,12 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd
|
|||||||
case WIRE_CONNECTD_PEER_DISCONNECTED:
|
case WIRE_CONNECTD_PEER_DISCONNECTED:
|
||||||
case WIRE_CONNECTD_DEV_MEMLEAK:
|
case WIRE_CONNECTD_DEV_MEMLEAK:
|
||||||
case WIRE_CONNECTD_PEER_FINAL_MSG:
|
case WIRE_CONNECTD_PEER_FINAL_MSG:
|
||||||
|
case WIRE_CONNECTD_PING:
|
||||||
/* This is a reply, so never gets through to here. */
|
/* This is a reply, so never gets through to here. */
|
||||||
case WIRE_CONNECTD_INIT_REPLY:
|
case WIRE_CONNECTD_INIT_REPLY:
|
||||||
case WIRE_CONNECTD_ACTIVATE_REPLY:
|
case WIRE_CONNECTD_ACTIVATE_REPLY:
|
||||||
case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:
|
case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:
|
||||||
|
case WIRE_CONNECTD_PING_REPLY:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WIRE_CONNECTD_RECONNECTED:
|
case WIRE_CONNECTD_RECONNECTED:
|
||||||
|
@ -1,83 +1,39 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <channeld/channeld_wiregen.h>
|
|
||||||
#include <common/json_command.h>
|
#include <common/json_command.h>
|
||||||
#include <common/json_tok.h>
|
#include <common/json_tok.h>
|
||||||
#include <common/param.h>
|
#include <common/param.h>
|
||||||
|
#include <connectd/connectd_wiregen.h>
|
||||||
#include <lightningd/channel.h>
|
#include <lightningd/channel.h>
|
||||||
#include <lightningd/jsonrpc.h>
|
#include <lightningd/jsonrpc.h>
|
||||||
#include <lightningd/lightningd.h>
|
#include <lightningd/lightningd.h>
|
||||||
#include <lightningd/peer_control.h>
|
#include <lightningd/peer_control.h>
|
||||||
#include <lightningd/ping.h>
|
|
||||||
#include <lightningd/subd.h>
|
#include <lightningd/subd.h>
|
||||||
|
|
||||||
struct ping_command {
|
static void ping_reply(struct subd *connectd,
|
||||||
struct list_node list;
|
const u8 *msg, const int *fds,
|
||||||
struct node_id id;
|
struct command *cmd)
|
||||||
struct command *cmd;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ping_command *find_ping_cmd(struct lightningd *ld,
|
|
||||||
const struct node_id *id)
|
|
||||||
{
|
|
||||||
struct ping_command *i;
|
|
||||||
|
|
||||||
list_for_each(&ld->ping_commands, i, list) {
|
|
||||||
if (node_id_eq(id, &i->id))
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroy_ping_command(struct ping_command *pc)
|
|
||||||
{
|
|
||||||
list_del(&pc->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ping_command *new_ping_command(const tal_t *ctx,
|
|
||||||
struct lightningd *ld,
|
|
||||||
const struct node_id *peer_id,
|
|
||||||
struct command *cmd)
|
|
||||||
{
|
|
||||||
struct ping_command *pc = tal(ctx, struct ping_command);
|
|
||||||
|
|
||||||
pc->id = *peer_id;
|
|
||||||
pc->cmd = cmd;
|
|
||||||
list_add_tail(&ld->ping_commands, &pc->list);
|
|
||||||
tal_add_destructor(pc, destroy_ping_command);
|
|
||||||
|
|
||||||
return pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ping_reply(struct subd *channeld, const u8 *msg)
|
|
||||||
{
|
{
|
||||||
u16 totlen;
|
u16 totlen;
|
||||||
bool sent;
|
bool sent;
|
||||||
struct ping_command *pc;
|
|
||||||
struct channel *c = channeld->channel;
|
|
||||||
|
|
||||||
log_debug(channeld->log, "Got ping reply!");
|
log_debug(connectd->log, "Got ping reply!");
|
||||||
pc = find_ping_cmd(channeld->ld, &c->peer->id);
|
|
||||||
if (!pc) {
|
|
||||||
log_broken(channeld->log, "Unexpected ping reply?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fromwire_channeld_ping_reply(msg, &sent, &totlen)) {
|
if (!fromwire_connectd_ping_reply(msg, &sent, &totlen)) {
|
||||||
log_broken(channeld->log, "Malformed ping reply %s",
|
log_broken(connectd->log, "Malformed ping reply %s",
|
||||||
tal_hex(tmpctx, msg));
|
tal_hex(tmpctx, msg));
|
||||||
was_pending(command_fail(pc->cmd, LIGHTNINGD,
|
was_pending(command_fail(cmd, LIGHTNINGD,
|
||||||
"Bad reply message"));
|
"Bad reply message"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sent)
|
if (!sent)
|
||||||
was_pending(command_fail(pc->cmd, LIGHTNINGD,
|
was_pending(command_fail(cmd, LIGHTNINGD,
|
||||||
"Ping already pending"));
|
"Ping already pending"));
|
||||||
else {
|
else {
|
||||||
struct json_stream *response = json_stream_success(pc->cmd);
|
struct json_stream *response = json_stream_success(cmd);
|
||||||
|
|
||||||
json_add_num(response, "totlen", totlen);
|
json_add_num(response, "totlen", totlen);
|
||||||
was_pending(command_success(pc->cmd, response));
|
was_pending(command_success(cmd, response));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +44,6 @@ static struct command_result *json_ping(struct command *cmd,
|
|||||||
{
|
{
|
||||||
unsigned int *len, *pongbytes;
|
unsigned int *len, *pongbytes;
|
||||||
struct node_id *id;
|
struct node_id *id;
|
||||||
struct peer *peer;
|
|
||||||
struct channel *channel;
|
|
||||||
u8 *msg;
|
u8 *msg;
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
if (!param(cmd, buffer, params,
|
||||||
@ -124,19 +78,11 @@ static struct command_result *json_ping(struct command *cmd,
|
|||||||
"pongbytes %u > 65535", *pongbytes);
|
"pongbytes %u > 65535", *pongbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
peer = peer_by_id(cmd->ld, id);
|
if (!peer_by_id(cmd->ld, id))
|
||||||
if (!peer)
|
|
||||||
return command_fail(cmd, LIGHTNINGD, "Peer not connected");
|
return command_fail(cmd, LIGHTNINGD, "Peer not connected");
|
||||||
|
|
||||||
channel = peer_active_channel(peer);
|
msg = towire_connectd_ping(NULL, id, *pongbytes, *len);
|
||||||
if (!channel || !channel->owner || channel->state != CHANNELD_NORMAL)
|
subd_req(cmd, cmd->ld->connectd, take(msg), -1, 0, ping_reply, cmd);
|
||||||
return command_fail(cmd, LIGHTNINGD, "Peer bad state");
|
|
||||||
|
|
||||||
/* parent is cmd, so when we complete cmd, we free this. */
|
|
||||||
new_ping_command(cmd, cmd->ld, id, cmd);
|
|
||||||
|
|
||||||
msg = towire_channeld_ping(NULL, *pongbytes, *len);
|
|
||||||
subd_send_msg(channel->owner, take(msg));
|
|
||||||
|
|
||||||
return command_still_pending(cmd);
|
return command_still_pending(cmd);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#ifndef LIGHTNING_LIGHTNINGD_PING_H
|
|
||||||
#define LIGHTNING_LIGHTNINGD_PING_H
|
|
||||||
#include "config.h"
|
|
||||||
#include <ccan/short_types/short_types.h>
|
|
||||||
|
|
||||||
struct subd;
|
|
||||||
void ping_reply(struct subd *subd, const u8 *msg);
|
|
||||||
|
|
||||||
#endif /* LIGHTNING_LIGHTNINGD_PING_H */
|
|
Loading…
Reference in New Issue
Block a user