forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathping.c
136 lines (117 loc) · 3.43 KB
/
ping.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <channeld/gen_channel_wire.h>
#include <common/sphinx.h>
#include <common/utils.h>
#include <gossipd/gen_gossip_wire.h>
#include <lightningd/htlc_end.h>
#include <lightningd/json.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/jsonrpc_errors.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/param.h>
#include <lightningd/peer_control.h>
#include <lightningd/ping.h>
#include <lightningd/subd.h>
struct ping_command {
struct list_node list;
struct pubkey id;
struct command *cmd;
};
static struct ping_command *find_ping_cmd(struct lightningd *ld,
const struct pubkey *id)
{
struct ping_command *i;
list_for_each(&ld->ping_commands, i, list) {
if (pubkey_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 pubkey *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 *subd, const u8 *msg)
{
u16 totlen;
bool ok, sent = true;
struct pubkey id;
struct ping_command *pc;
log_debug(subd->ld->log, "Got ping reply!");
ok = fromwire_gossip_ping_reply(msg, &id, &sent, &totlen);
pc = find_ping_cmd(subd->ld, &id);
assert(pc);
if (!ok)
command_fail(pc->cmd, LIGHTNINGD, "Bad reply message");
else if (!sent)
command_fail(pc->cmd, LIGHTNINGD, "Unknown peer");
else {
struct json_stream *response = json_stream_success(pc->cmd);
json_object_start(response, NULL);
json_add_num(response, "totlen", totlen);
json_object_end(response);
command_success(pc->cmd, response);
}
}
static void json_ping(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
u8 *msg;
unsigned int *len, *pongbytes;
struct pubkey *id;
if (!param(cmd, buffer, params,
p_req("id", json_tok_pubkey, &id),
p_opt_def("len", json_tok_number, &len, 128),
p_opt_def("pongbytes", json_tok_number, &pongbytes, 128),
NULL))
return;
/* BOLT #1:
*
* 1. `type`: a 2-byte big-endian field indicating the type of message
* 2. `payload`: ...
* The size of the message is required by the transport layer to fit
* into a 2-byte unsigned int; therefore, the maximum possible size is
* 65535 bytes.
*...
* 1. type: 18 (`ping`)
* 2. data:
* * [`2`:`num_pong_bytes`]
* * [`2`:`byteslen`]
* * [`byteslen`:`ignored`]
*/
if (*len > 65535 - 2 - 2 - 2) {
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%u would result in oversize ping", *len);
return;
}
/* Note that > 65531 is valid: it means "no pong reply" */
if (*pongbytes > 65535) {
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"pongbytes %u > 65535", *pongbytes);
return;
}
/* parent is cmd, so when we complete cmd, we free this. */
new_ping_command(cmd, cmd->ld, id, cmd);
/* gossipd handles all pinging, even if it's in another daemon. */
msg = towire_gossip_ping(NULL, id, *pongbytes, *len);
subd_send_msg(cmd->ld->gossip, take(msg));
command_still_pending(cmd);
}
static const struct json_command ping_command = {
"ping",
json_ping,
"Send peer {id} a ping of length {len} (default 128) asking for {pongbytes} (default 128)"
};
AUTODATA(json_command, &ping_command);