From ef9b16399c3627ee786f46ada773d9839d6b382f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 31 Jan 2018 13:23:35 +1030 Subject: [PATCH] common: read_peer_msg helpers for per-peer subds. It's a bit ugly because each caller has slightly different needs, but we have three hooks and standard helpers. Signed-off-by: Rusty Russell --- common/Makefile | 1 + common/read_peer_msg.c | 134 +++++++++++++++++++++++++++++++++++++++++ common/read_peer_msg.h | 57 ++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 common/read_peer_msg.c create mode 100644 common/read_peer_msg.h diff --git a/common/Makefile b/common/Makefile index 70eefc16c..e549c227d 100644 --- a/common/Makefile +++ b/common/Makefile @@ -29,6 +29,7 @@ COMMON_SRC := \ common/permute_tx.c \ common/ping.c \ common/pseudorand.c \ + common/read_peer_msg.c \ common/sphinx.c \ common/status.c \ common/subdaemon.c \ diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c new file mode 100644 index 000000000..3e4d6903b --- /dev/null +++ b/common/read_peer_msg.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void handle_ping(const u8 *msg, + int peer_fd, + struct crypto_state *cs, + const struct channel_id *channel, + bool (*send_reply)(struct crypto_state *, int, + const u8 *, void *), + void (*io_error)(const char *, void *), + void *arg) +{ + u8 *pong; + + if (!check_ping_make_pong(msg, msg, &pong)) { + send_reply(cs, peer_fd, + take(towire_errorfmt(msg, channel, + "Bad ping %s", + tal_hex(msg, msg))), arg); + io_error("Bad ping received", arg); + } + + status_trace("Got ping, sending %s", pong ? + wire_type_name(fromwire_peektype(pong)) + : "nothing"); + + if (pong && !send_reply(cs, peer_fd, pong, arg)) + io_error("Failed writing pong", arg); +} + +u8 *read_peer_msg_(const tal_t *ctx, + int peer_fd, int gossip_fd, + struct crypto_state *cs, + const struct channel_id *channel, + bool (*send_reply)(struct crypto_state *, int, const u8 *, + void *), + void (*io_error)(const char *what_i_was_doing, void *arg), + void (*err_pkt)(const char *desc, bool this_channel_only, + void *arg), + void *arg) +{ + u8 *msg; + struct channel_id chanid; + + msg = sync_crypto_read(ctx, cs, peer_fd); + if (!msg) + io_error("reading from peer", arg); + + status_trace("peer_in %s", wire_type_name(fromwire_peektype(msg))); + + if (is_gossip_msg(msg)) { + /* Forward to gossip daemon */ + wire_sync_write(gossip_fd, take(msg)); + return NULL; + } + + if (fromwire_peektype(msg) == WIRE_PING) { + handle_ping(msg, peer_fd, cs, channel, + send_reply, io_error, arg); + return tal_free(msg); + } + + if (fromwire_peektype(msg) == WIRE_ERROR) { + char *err = sanitize_error(msg, msg, &chanid); + + /* BOLT #1: + * + * The channel is referred to by `channel_id`, unless + * `channel_id` is 0 (i.e. all bytes are 0), in which + * case it refers to all channels. + * ... + + * The receiving node: + * - upon receiving `error`: + * - MUST fail the channel referred to by the error + * message. + * - if no existing channel is referred to by the + * message: + * - MUST ignore the message. + */ + if (channel_id_is_all(&chanid)) + err_pkt(err, false, arg); + else if (structeq(&chanid, channel)) + err_pkt(err, true, arg); + + return tal_free(msg); + } + + /* They're talking about a different channel? */ + if (extract_channel_id(msg, &chanid) + && !structeq(&chanid, channel)) { + status_trace("Rejecting %s for unknown channel_id %s", + wire_type_name(fromwire_peektype(msg)), + type_to_string(msg, struct channel_id, &chanid)); + if (!send_reply(cs, peer_fd, + take(towire_errorfmt(msg, &chanid, + "Multiple channels" + " unsupported")), + arg)) + io_error("Sending error for other channel ", arg); + return tal_free(msg); + } + + return msg; +} + +/* Helper: sync_crypto_write, with extra args it ignores */ +bool sync_crypto_write_arg(struct crypto_state *cs, int fd, const u8 *msg, + void *unused) +{ + return sync_crypto_write(cs, fd, msg); +} + +/* Helper: calls status_failed(STATUS_FAIL_PEER_IO) */ +void status_fail_io(const char *what_i_was_doing, void *unused) +{ + status_failed(STATUS_FAIL_PEER_IO, + "%s:%s", what_i_was_doing, strerror(errno)); +} + +/* Helper: calls status_failed(STATUS_FAIL_PEER_BAD, ) */ +void status_fail_errpkt(const char *desc, bool this_channel_only, void *unused) +{ + status_failed(STATUS_FAIL_PEER_BAD, "Peer sent ERROR: %s", desc); +} diff --git a/common/read_peer_msg.h b/common/read_peer_msg.h new file mode 100644 index 000000000..be2f84efc --- /dev/null +++ b/common/read_peer_msg.h @@ -0,0 +1,57 @@ +#ifndef LIGHTNING_COMMON_READ_PEER_MSG_H +#define LIGHTNING_COMMON_READ_PEER_MSG_H +#include "config.h" +#include +#include +#include + +struct crypto_state; +struct channel_id; + +/** + * read_peer_msg - read & decode in a peer message, handling common ones. + * @ctx: context to allocate return packet from. + * @cs: the cryptostate (updated) + * @channel_id: the channel id (for identifying errors) + * @send_reply: the way to send a reply packet (eg. sync_crypto_write_arg) + * @io_error: what to do if there's an IO error (eg. status_fail_io) + * (MUST NOT RETURN!) + * @err_pkt: what to do if there's an error packet (eg. status_fail_errorpkt) + * (MUST NOT RETURN!) + * + * This returns NULL if it handled the message, so it's normally called in + * a loop. + */ +#define read_peer_msg(ctx, cs, channel_id, send_reply, io_error, err_pkt, arg) \ + read_peer_msg_((ctx), PEER_FD, GOSSIP_FD, (cs), (channel_id), \ + typesafe_cb_preargs(bool, void *, (send_reply), (arg), \ + struct crypto_state *, int, \ + const u8 *), \ + typesafe_cb_preargs(void, void *, (io_error), (arg), \ + const char *), \ + typesafe_cb_preargs(void, void *, (err_pkt), (arg), \ + const char *, bool), \ + arg) + +/* Helper: sync_crypto_write, with extra args it ignores */ +bool sync_crypto_write_arg(struct crypto_state *cs, int fd, const u8 *TAKES, + void *unused); + +/* Helper: calls status_failed(STATUS_FAIL_PEER_IO) */ +void status_fail_io(const char *what_i_was_doing, void *unused); + +/* Helper: calls status_failed(STATUS_FAIL_PEER_BAD, ) */ +void status_fail_errpkt(const char *desc, bool this_channel_only, void *unused); + +u8 *read_peer_msg_(const tal_t *ctx, + int peer_fd, int gossip_fd, + struct crypto_state *cs, + const struct channel_id *channel, + bool (*send_reply)(struct crypto_state *cs, int fd, + const u8 *TAKES, void *arg), + void (*io_error)(const char *what_i_was_doing, void *arg), + void (*err_pkt)(const char *desc, bool this_channel_only, + void *arg), + void *arg); + +#endif /* LIGHTNING_COMMON_READ_PEER_MSG_H */