dev_disconnect: new option to stop using connection, but don't close.

This allows us to ensure a packet is read by the other end, but we
don't read anything else from them or write anything to them.

Using '+' is similar, but because it closes the connection, the peer
might notice before receiving the packet (such as if it does a write).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2021-06-15 06:37:36 +09:30
parent 0fccfc0a9a
commit 62e1e2467c
5 changed files with 33 additions and 11 deletions

View File

@@ -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
}

View File

@@ -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]);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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();
}