diff --git a/common/crypto_sync.c b/common/crypto_sync.c index e8f5f8321..c529de687 100644 --- a/common/crypto_sync.c +++ b/common/crypto_sync.c @@ -17,7 +17,7 @@ void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) { #if DEVELOPER - bool post_sabotage = false; + bool post_sabotage = false, post_close; int type = fromwire_peektype(msg); #endif u8 *enc; @@ -28,18 +28,23 @@ void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) #if DEVELOPER switch (dev_disconnect(type)) { case DEV_DISCONNECT_BEFORE: - dev_sabotage_fd(pps->peer_fd); + dev_sabotage_fd(pps->peer_fd, true); peer_failed_connection_lost(); case DEV_DISCONNECT_DROPPKT: enc = tal_free(enc); /* FALL THRU */ case DEV_DISCONNECT_AFTER: post_sabotage = true; + post_close = true; break; case DEV_DISCONNECT_BLACKHOLE: dev_blackhole_fd(pps->peer_fd); break; case DEV_DISCONNECT_NORMAL: break; + case DEV_DISCONNECT_DISABLE_AFTER: + post_sabotage = true; + post_close = false; + break; } #endif if (!write_all(pps->peer_fd, enc, tal_count(enc))) @@ -48,7 +53,7 @@ void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) #if DEVELOPER if (post_sabotage) - dev_sabotage_fd(pps->peer_fd); + dev_sabotage_fd(pps->peer_fd, post_close); #endif } diff --git a/common/dev_disconnect.c b/common/dev_disconnect.c index d55c7f029..e5a1a6f96 100644 --- a/common/dev_disconnect.c +++ b/common/dev_disconnect.c @@ -90,16 +90,13 @@ enum dev_disconnect dev_disconnect(int pkt_type) return dev_disconnect_line[0]; } -void dev_sabotage_fd(int fd) +void dev_sabotage_fd(int fd, bool close_fd) { int fds[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) err(1, "dev_sabotage_fd: creating socketpair"); - /* Close one. */ - close(fds[0]); - #if defined(TCP_NODELAY) /* On Linux, at least, this flushes. */ int opt = TCP_NODELAY; @@ -108,6 +105,14 @@ void dev_sabotage_fd(int fd) #else #error No TCP_NODELAY? #endif + + /* Move fd out the way if we don't want to close it. */ + if (!close_fd) + dup(fd); + else + /* Close other end of socket. */ + close(fds[0]); + /* Move other over to the fd we want to sabotage. */ dup2(fds[1], fd); close(fds[1]); diff --git a/common/dev_disconnect.h b/common/dev_disconnect.h index 8760f35ee..3c0f4b897 100644 --- a/common/dev_disconnect.h +++ b/common/dev_disconnect.h @@ -15,13 +15,15 @@ enum dev_disconnect { DEV_DISCONNECT_DROPPKT = '@', /* Swallow all writes from now on, and do no more reads. */ DEV_DISCONNECT_BLACKHOLE = '0', + /* Don't use connection after sending packet, but don't close. */ + DEV_DISCONNECT_DISABLE_AFTER = 'x', }; /* Force a close fd before or after a certain packet type */ enum dev_disconnect dev_disconnect(int pkt_type); /* Make next write on fd fail as if they'd disconnected. */ -void dev_sabotage_fd(int fd); +void dev_sabotage_fd(int fd, bool close_fd); /* No more data to arrive, what's written is swallowed. */ void dev_blackhole_fd(int fd); diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index f5e2dc24d..f4aecacaf 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -132,7 +132,14 @@ static struct io_plan *read_init(struct io_conn *conn, struct peer *peer) static struct io_plan *peer_write_postclose(struct io_conn *conn, struct peer *peer) { - dev_sabotage_fd(io_conn_fd(conn)); + dev_sabotage_fd(io_conn_fd(conn), true); + return read_init(conn, peer); +} + +static struct io_plan *peer_write_post_sabotage(struct io_conn *conn, + struct peer *peer) +{ + dev_sabotage_fd(io_conn_fd(conn), false); return read_init(conn, peer); } #endif @@ -197,7 +204,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, #if DEVELOPER switch (dev_disconnect(WIRE_INIT)) { case DEV_DISCONNECT_BEFORE: - dev_sabotage_fd(io_conn_fd(conn)); + dev_sabotage_fd(io_conn_fd(conn), true); break; case DEV_DISCONNECT_DROPPKT: peer->msg = tal_free(peer->msg); /* FALL THRU */ @@ -209,6 +216,9 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, break; case DEV_DISCONNECT_NORMAL: break; + case DEV_DISCONNECT_DISABLE_AFTER: + next = peer_write_post_sabotage; + break; } #endif /* DEVELOPER */ diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 92983bf92..9f0a715f3 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -67,7 +67,7 @@ void status_fmt(enum log_level level, } #if DEVELOPER -void dev_sabotage_fd(int fd) +void dev_sabotage_fd(int fd, bool close_fd) { abort(); }