connectd: implement @ correctly.

dev_blackhole_fd was a hack, and doesn't work well now we are async
(it worked for sync comms in per-peer daemons, but now we could sneak
through a read before we get to the next write).

So, make explicit flags and use them.  This is much easier now we
have all peer comms in one place.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2022-01-11 11:46:10 +10:30
parent bb5beeddd7
commit a93c49ca65
5 changed files with 37 additions and 71 deletions

View File

@@ -105,56 +105,4 @@ void dev_sabotage_fd(int fd, bool close_fd)
dup2(fds[1], fd);
close(fds[1]);
}
/* Replace fd with blackhole until dev_disconnect file is truncated. */
void dev_blackhole_fd(int fd)
{
int fds[2];
int i;
struct stat st;
int maxfd;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0)
err(1, "dev_blackhole_fd: creating socketpair");
switch (fork()) {
case -1:
err(1, "dev_blackhole_fd: forking");
case 0:
/* Close everything but the dev_disconnect_fd, the socket
* which is pretending to be the peer, and stderr.
* The "correct" way to do this would be to move the
* fds we want to preserve to the low end (0, 1, 2...)
* of the fd space and then just do a single closefrom
* call, but dup2 could fail with ENFILE (which is a
* *system*-level error, i.e. the entire system has too
* many processes with open files) and we have no
* convenient way to inform the parent of the error.
* So loop until we reach whichever is higher of fds[0]
* or dev_disconnect_fd, and *then* closefrom after that.
*/
maxfd = (fds[0] > dev_disconnect_fd) ? fds[0] :
dev_disconnect_fd ;
for (i = 0; i < maxfd; i++)
if (i != fds[0]
&& i != dev_disconnect_fd
&& i != STDERR_FILENO)
close(i);
closefrom(maxfd + 1);
/* Close once dev_disconnect file is truncated. */
for (;;) {
if (fstat(dev_disconnect_fd, &st) != 0)
err(1, "fstat of dev_disconnect_fd failed");
if (st.st_size == 0)
_exit(0);
sleep(1);
}
}
close(fds[0]);
dup2(fds[1], fd);
close(fds[1]);
}
#endif