mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
lightningd: --dev-disconnect support.
We use a file descriptor, so when we consume an entry, we move past it (and everyone shares a file offset, so this works). The file contains packet names prefixed by - (treat fd as closed when we try to write this packet), + (write the packet then ensure the file descriptor fails), or @ ("lose" the packet then ensure the file descriptor fails). The sync and async peer-write functions hook this in automatically. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Header from folded patch 'test-run-cryptomsg__fix_compilation.patch': test/run-cryptomsg: fix compilation. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
8f190c673c
commit
9b1d240c1f
@ -44,6 +44,7 @@ LIGHTNINGD_LIB_SRC := \
|
|||||||
lightningd/debug.c \
|
lightningd/debug.c \
|
||||||
lightningd/daemon_conn.c \
|
lightningd/daemon_conn.c \
|
||||||
lightningd/derive_basepoints.c \
|
lightningd/derive_basepoints.c \
|
||||||
|
lightningd/dev_disconnect.c \
|
||||||
lightningd/funding_tx.c \
|
lightningd/funding_tx.c \
|
||||||
lightningd/gossip_msg.c \
|
lightningd/gossip_msg.c \
|
||||||
lightningd/htlc_tx.c \
|
lightningd/htlc_tx.c \
|
||||||
|
@ -3,19 +3,38 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <lightningd/crypto_sync.h>
|
#include <lightningd/crypto_sync.h>
|
||||||
#include <lightningd/cryptomsg.h>
|
#include <lightningd/cryptomsg.h>
|
||||||
|
#include <lightningd/dev_disconnect.h>
|
||||||
#include <lightningd/status.h>
|
#include <lightningd/status.h>
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
|
#include <wire/wire.h>
|
||||||
#include <wire/wire_sync.h>
|
#include <wire/wire_sync.h>
|
||||||
|
|
||||||
bool sync_crypto_write(struct crypto_state *cs, int fd, const void *msg)
|
bool sync_crypto_write(struct crypto_state *cs, int fd, const void *msg)
|
||||||
{
|
{
|
||||||
u8 *enc = cryptomsg_encrypt_msg(msg, cs, msg);
|
u8 *enc = cryptomsg_encrypt_msg(msg, cs, msg);
|
||||||
bool ret;
|
bool ret;
|
||||||
|
bool post_sabotage = false;
|
||||||
|
|
||||||
status_trace("Writing crypto with sn=%"PRIu64" msg=%s",
|
status_trace("Writing crypto with sn=%"PRIu64" msg=%s",
|
||||||
cs->sn-2, tal_hex(trc, msg));
|
cs->sn-2, tal_hex(trc, msg));
|
||||||
|
|
||||||
|
switch (dev_disconnect(fromwire_peektype(msg))) {
|
||||||
|
case DEV_DISCONNECT_BEFORE:
|
||||||
|
dev_sabotage_fd(fd);
|
||||||
|
return false;
|
||||||
|
case DEV_DISCONNECT_DROPPKT:
|
||||||
|
enc = tal_free(enc); /* FALL THRU */
|
||||||
|
case DEV_DISCONNECT_AFTER:
|
||||||
|
post_sabotage = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
ret = write_all(fd, enc, tal_len(enc));
|
ret = write_all(fd, enc, tal_len(enc));
|
||||||
tal_free(enc);
|
tal_free(enc);
|
||||||
|
|
||||||
|
if (post_sabotage)
|
||||||
|
dev_sabotage_fd(fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <ccan/short_types/short_types.h>
|
#include <ccan/short_types/short_types.h>
|
||||||
#include <ccan/take/take.h>
|
#include <ccan/take/take.h>
|
||||||
#include <lightningd/cryptomsg.h>
|
#include <lightningd/cryptomsg.h>
|
||||||
|
#include <lightningd/dev_disconnect.h>
|
||||||
#include <lightningd/status.h>
|
#include <lightningd/status.h>
|
||||||
#include <sodium/crypto_aead_chacha20poly1305.h>
|
#include <sodium/crypto_aead_chacha20poly1305.h>
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
@ -316,12 +317,21 @@ u8 *cryptomsg_encrypt_msg(const tal_t *ctx,
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct io_plan *peer_write_postclose(struct io_conn *conn,
|
||||||
|
struct peer_crypto_state *pcs)
|
||||||
|
{
|
||||||
|
pcs->out = tal_free(pcs->out);
|
||||||
|
dev_sabotage_fd(io_conn_fd(conn));
|
||||||
|
return pcs->next_out(conn, pcs->peer);
|
||||||
|
}
|
||||||
|
|
||||||
struct io_plan *peer_write_message(struct io_conn *conn,
|
struct io_plan *peer_write_message(struct io_conn *conn,
|
||||||
struct peer_crypto_state *pcs,
|
struct peer_crypto_state *pcs,
|
||||||
const u8 *msg,
|
const u8 *msg,
|
||||||
struct io_plan *(*next)(struct io_conn *,
|
struct io_plan *(*next)(struct io_conn *,
|
||||||
struct peer *))
|
struct peer *))
|
||||||
{
|
{
|
||||||
|
struct io_plan *(*post)(struct io_conn *, struct peer_crypto_state *);
|
||||||
assert(!pcs->out);
|
assert(!pcs->out);
|
||||||
|
|
||||||
pcs->out = cryptomsg_encrypt_msg(conn, &pcs->cs, msg);
|
pcs->out = cryptomsg_encrypt_msg(conn, &pcs->cs, msg);
|
||||||
@ -329,11 +339,24 @@ struct io_plan *peer_write_message(struct io_conn *conn,
|
|||||||
tal_free(msg);
|
tal_free(msg);
|
||||||
pcs->next_out = next;
|
pcs->next_out = next;
|
||||||
|
|
||||||
|
post = peer_write_done;
|
||||||
|
|
||||||
|
switch (dev_disconnect(fromwire_peektype(msg))) {
|
||||||
|
case DEV_DISCONNECT_BEFORE:
|
||||||
|
return io_close(conn);
|
||||||
|
case DEV_DISCONNECT_DROPPKT:
|
||||||
|
pcs->out = NULL; /* FALL THRU */
|
||||||
|
case DEV_DISCONNECT_AFTER:
|
||||||
|
post = peer_write_postclose;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* BOLT #8:
|
/* BOLT #8:
|
||||||
* * Send `lc || c` over the network buffer.
|
* * Send `lc || c` over the network buffer.
|
||||||
*/
|
*/
|
||||||
return io_write(conn, pcs->out, tal_count(pcs->out),
|
return io_write(conn, pcs->out, tal_count(pcs->out), post, pcs);
|
||||||
peer_write_done, pcs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_peer_crypto_state(struct peer *peer, struct peer_crypto_state *pcs)
|
void init_peer_crypto_state(struct peer *peer, struct peer_crypto_state *pcs)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include <ccan/str/str.h>
|
#include <ccan/str/str.h>
|
||||||
#include <lightningd/debug.h>
|
#include <lightningd/debug.h>
|
||||||
|
#include <lightningd/dev_disconnect.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -9,6 +11,13 @@ void subdaemon_debug(int argc, char *argv[])
|
|||||||
int i;
|
int i;
|
||||||
bool printed = false;
|
bool printed = false;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (strstarts(argv[i], "--dev-disconnect=")) {
|
||||||
|
dev_disconnect_init(atoi(argv[i]
|
||||||
|
+ strlen("--dev-disconnect=")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* From debugger, tell gdb "return". */
|
/* From debugger, tell gdb "return". */
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
while (streq(argv[i], "--debugger")) {
|
while (streq(argv[i], "--debugger")) {
|
||||||
|
55
lightningd/dev_disconnect.c
Normal file
55
lightningd/dev_disconnect.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <ccan/err/err.h>
|
||||||
|
#include <ccan/str/str.h>
|
||||||
|
#include <lightningd/dev_disconnect.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wire/gen_peer_wire.h>
|
||||||
|
|
||||||
|
/* We move the fd IFF we do a disconnect. */
|
||||||
|
static int dev_disconnect_fd = -1;
|
||||||
|
static char dev_disconnect_line[200];
|
||||||
|
|
||||||
|
void dev_disconnect_init(int fd)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = read(fd, dev_disconnect_line, sizeof(dev_disconnect_line)-1);
|
||||||
|
if (r < 0)
|
||||||
|
err(1, "Reading dev_disconnect file");
|
||||||
|
lseek(fd, -r, SEEK_CUR);
|
||||||
|
|
||||||
|
/* Get first line */
|
||||||
|
dev_disconnect_line[r] = '\n';
|
||||||
|
*strchr(dev_disconnect_line, '\n') = '\0';
|
||||||
|
|
||||||
|
/* So we can move forward if we do use the line. */
|
||||||
|
dev_disconnect_fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
char dev_disconnect(int pkt_type)
|
||||||
|
{
|
||||||
|
if (!streq(wire_type_name(pkt_type), dev_disconnect_line+1))
|
||||||
|
return DEV_DISCONNECT_NORMAL;
|
||||||
|
|
||||||
|
assert(dev_disconnect_fd != -1);
|
||||||
|
lseek(dev_disconnect_fd, strlen(dev_disconnect_line)+1, SEEK_CUR);
|
||||||
|
|
||||||
|
return dev_disconnect_line[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_sabotage_fd(int fd)
|
||||||
|
{
|
||||||
|
int fds[2];
|
||||||
|
|
||||||
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0)
|
||||||
|
errx(1, "dev_sabotage_fd: creating socketpair");
|
||||||
|
|
||||||
|
/* Close one. */
|
||||||
|
close(fds[0]);
|
||||||
|
/* Move other over to the fd we want to sabotage. */
|
||||||
|
dup2(fds[1], fd);
|
||||||
|
close(fds[1]);
|
||||||
|
}
|
20
lightningd/dev_disconnect.h
Normal file
20
lightningd/dev_disconnect.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef LIGHTNING_LIGHTNINGD_DEV_DISCONNECT_H
|
||||||
|
#define LIGHTNING_LIGHTNINGD_DEV_DISCONNECT_H
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define DEV_DISCONNECT_BEFORE '-'
|
||||||
|
#define DEV_DISCONNECT_AFTER '+'
|
||||||
|
#define DEV_DISCONNECT_DROPPKT '@'
|
||||||
|
#define DEV_DISCONNECT_NORMAL 0
|
||||||
|
|
||||||
|
/* Force a close fd before or after a certain packet type */
|
||||||
|
char dev_disconnect(int pkt_type);
|
||||||
|
|
||||||
|
/* Make next write on fd fail as if they'd disconnected. */
|
||||||
|
void dev_sabotage_fd(int fd);
|
||||||
|
|
||||||
|
/* For debug code to set in daemon. */
|
||||||
|
void dev_disconnect_init(int fd);
|
||||||
|
|
||||||
|
#endif /* LIGHTNING_LIGHTNINGD_DEV_DISCONNECT_H */
|
@ -111,6 +111,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
|
|||||||
ld->dev_debug_subdaemon = NULL;
|
ld->dev_debug_subdaemon = NULL;
|
||||||
list_head_init(&ld->utxos);
|
list_head_init(&ld->utxos);
|
||||||
htlc_end_map_init(&ld->htlc_ends);
|
htlc_end_map_init(&ld->htlc_ends);
|
||||||
|
ld->dev_disconnect_fd = -1;
|
||||||
ld->dstate.log_book = new_log_book(&ld->dstate, 20*1024*1024,LOG_INFORM);
|
ld->dstate.log_book = new_log_book(&ld->dstate, 20*1024*1024,LOG_INFORM);
|
||||||
ld->log = ld->dstate.base_log = new_log(&ld->dstate,
|
ld->log = ld->dstate.base_log = new_log(&ld->dstate,
|
||||||
ld->dstate.log_book,
|
ld->dstate.log_book,
|
||||||
@ -233,6 +234,9 @@ int main(int argc, char *argv[])
|
|||||||
opt_show_uintval, &ld->broadcast_interval,
|
opt_show_uintval, &ld->broadcast_interval,
|
||||||
"Time between gossip broadcasts in milliseconds (default: 30000)");
|
"Time between gossip broadcasts in milliseconds (default: 30000)");
|
||||||
|
|
||||||
|
opt_register_arg("--dev-disconnect=<filename>", opt_subd_dev_disconnect,
|
||||||
|
NULL, ld, "File containing disconnection points");
|
||||||
|
|
||||||
/* FIXME: move to option initialization once we drop the
|
/* FIXME: move to option initialization once we drop the
|
||||||
* legacy daemon */
|
* legacy daemon */
|
||||||
ld->broadcast_interval = 30000;
|
ld->broadcast_interval = 30000;
|
||||||
|
@ -50,6 +50,9 @@ struct lightningd {
|
|||||||
/* If we want to debug a subdaemon. */
|
/* If we want to debug a subdaemon. */
|
||||||
const char *dev_debug_subdaemon;
|
const char *dev_debug_subdaemon;
|
||||||
|
|
||||||
|
/* If we have a --dev-disconnect file */
|
||||||
|
int dev_disconnect_fd;
|
||||||
|
|
||||||
/* UTXOs we have available to spend. */
|
/* UTXOs we have available to spend. */
|
||||||
struct list_head utxos;
|
struct list_head utxos;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <ccan/noerr/noerr.h>
|
#include <ccan/noerr/noerr.h>
|
||||||
#include <ccan/take/take.h>
|
#include <ccan/take/take.h>
|
||||||
#include <ccan/tal/path/path.h>
|
#include <ccan/tal/path/path.h>
|
||||||
|
#include <ccan/tal/str/str.h>
|
||||||
#include <daemon/log.h>
|
#include <daemon/log.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -120,7 +121,7 @@ static struct subd_req *get_req(struct subd *sd, int reply_type)
|
|||||||
|
|
||||||
/* We use sockets, not pipes, because fds are bidir. */
|
/* We use sockets, not pipes, because fds are bidir. */
|
||||||
static int subd(const char *dir, const char *name, bool debug,
|
static int subd(const char *dir, const char *name, bool debug,
|
||||||
int *msgfd, va_list ap)
|
int *msgfd, int dev_disconnect_fd, va_list ap)
|
||||||
{
|
{
|
||||||
int childmsg[2], execfail[2];
|
int childmsg[2], execfail[2];
|
||||||
pid_t childpid;
|
pid_t childpid;
|
||||||
@ -143,7 +144,7 @@ static int subd(const char *dir, const char *name, bool debug,
|
|||||||
if (childpid == 0) {
|
if (childpid == 0) {
|
||||||
int fdnum = 3, i;
|
int fdnum = 3, i;
|
||||||
long max;
|
long max;
|
||||||
const char *debug_arg = NULL;
|
const char *debug_arg[2] = { NULL, NULL };
|
||||||
|
|
||||||
close(childmsg[0]);
|
close(childmsg[0]);
|
||||||
close(execfail[0]);
|
close(execfail[0]);
|
||||||
@ -154,6 +155,13 @@ static int subd(const char *dir, const char *name, bool debug,
|
|||||||
goto child_errno_fail;
|
goto child_errno_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move dev_disconnect_fd out the way.
|
||||||
|
if (dev_disconnect_fd != -1) {
|
||||||
|
if (!move_fd(dev_disconnect_fd, 101))
|
||||||
|
goto child_errno_fail;
|
||||||
|
dev_disconnect_fd = 101;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dup any extra fds up first. */
|
/* Dup any extra fds up first. */
|
||||||
while ((fd = va_arg(ap, int *)) != NULL) {
|
while ((fd = va_arg(ap, int *)) != NULL) {
|
||||||
/* If this were stdin, dup2 closed! */
|
/* If this were stdin, dup2 closed! */
|
||||||
@ -166,11 +174,14 @@ static int subd(const char *dir, const char *name, bool debug,
|
|||||||
/* Make (fairly!) sure all other fds are closed. */
|
/* Make (fairly!) sure all other fds are closed. */
|
||||||
max = sysconf(_SC_OPEN_MAX);
|
max = sysconf(_SC_OPEN_MAX);
|
||||||
for (i = fdnum; i < max; i++)
|
for (i = fdnum; i < max; i++)
|
||||||
close(i);
|
if (i != dev_disconnect_fd)
|
||||||
|
close(i);
|
||||||
|
|
||||||
|
if (dev_disconnect_fd != -1)
|
||||||
|
debug_arg[0] = tal_fmt(NULL, "--dev-disconnect=%i", dev_disconnect_fd);
|
||||||
if (debug)
|
if (debug)
|
||||||
debug_arg = "--debugger";
|
debug_arg[debug_arg[0] ? 1 : 0] = "--debugger";
|
||||||
execl(path_join(NULL, dir, name), name, debug_arg, NULL);
|
execl(path_join(NULL, dir, name), name, debug_arg[0], debug_arg[1], NULL);
|
||||||
|
|
||||||
child_errno_fail:
|
child_errno_fail:
|
||||||
err = errno;
|
err = errno;
|
||||||
@ -381,7 +392,8 @@ struct subd *new_subd(const tal_t *ctx,
|
|||||||
debug = ld->dev_debug_subdaemon
|
debug = ld->dev_debug_subdaemon
|
||||||
&& strends(name, ld->dev_debug_subdaemon);
|
&& strends(name, ld->dev_debug_subdaemon);
|
||||||
va_start(ap, finished);
|
va_start(ap, finished);
|
||||||
sd->pid = subd(ld->daemon_dir, name, debug, &msg_fd, ap);
|
sd->pid = subd(ld->daemon_dir, name, debug, &msg_fd,
|
||||||
|
ld->dev_disconnect_fd, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (sd->pid == (pid_t)-1) {
|
if (sd->pid == (pid_t)-1) {
|
||||||
log_unusual(ld->log, "subd %s failed: %s",
|
log_unusual(ld->log, "subd %s failed: %s",
|
||||||
@ -467,3 +479,12 @@ char *opt_subd_debug(const char *optarg, struct lightningd *ld)
|
|||||||
ld->dev_debug_subdaemon = optarg;
|
ld->dev_debug_subdaemon = optarg;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld)
|
||||||
|
{
|
||||||
|
ld->dev_disconnect_fd = open(optarg, O_RDONLY);
|
||||||
|
if (ld->dev_disconnect_fd < 0)
|
||||||
|
return tal_fmt(ld, "Could not open --dev-disconnect=%s: %s",
|
||||||
|
optarg, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -122,5 +122,5 @@ void subd_req_(const tal_t *ctx,
|
|||||||
void subd_shutdown(struct subd *subd, unsigned int seconds);
|
void subd_shutdown(struct subd *subd, unsigned int seconds);
|
||||||
|
|
||||||
char *opt_subd_debug(const char *optarg, struct lightningd *ld);
|
char *opt_subd_debug(const char *optarg, struct lightningd *ld);
|
||||||
|
char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld);
|
||||||
#endif /* LIGHTNING_LIGHTNINGD_SUBD_H */
|
#endif /* LIGHTNING_LIGHTNINGD_SUBD_H */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ccan/str/hex/hex.h>
|
#include <ccan/str/hex/hex.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
|
#include <lightningd/dev_disconnect.h>
|
||||||
#include <lightningd/status.h>
|
#include <lightningd/status.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <wire/peer_wire.h>
|
#include <wire/peer_wire.h>
|
||||||
@ -38,6 +39,16 @@ static void do_write(const void *buf, size_t len)
|
|||||||
#define status_trace(fmt, ...) \
|
#define status_trace(fmt, ...) \
|
||||||
printf(fmt "\n", __VA_ARGS__)
|
printf(fmt "\n", __VA_ARGS__)
|
||||||
|
|
||||||
|
void dev_sabotage_fd(int fd)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
char dev_disconnect(int pkt_type)
|
||||||
|
{
|
||||||
|
return DEV_DISCONNECT_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* We test what look like unknown messages. */
|
/* We test what look like unknown messages. */
|
||||||
#define unknown_msg_discardable(x) 0
|
#define unknown_msg_discardable(x) 0
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user