diff options
author | Matt Johnston <matt@ucc.asn.au> | 2006-12-05 15:23:06 +0000 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2006-12-05 15:23:06 +0000 |
commit | 4e09d27c6f8e59631becb422a055ede15833af89 (patch) | |
tree | cd790c57e003c9851725ea5a0af5e48fbc274350 | |
parent | e1d3a8a6e9481b9fd53e5e8aa505ffc9b4536660 (diff) |
Add some code for testing whether a writefd is closed (by read()ing from it)
--HG--
branch : channel-fix
extra : convert_revision : 1dfbc5ef92391d01b576c8506061927869a89887
-rw-r--r-- | common-channel.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/common-channel.c b/common-channel.c index 19b807f..8159477 100644 --- a/common-channel.c +++ b/common-channel.c @@ -186,6 +186,29 @@ struct Channel* getchannel() { return getchannel_msg(NULL); } +/* In order to tell if a writefd is closed, we put it in the readfd FD_SET. + We then just try reading a single byte from it. It'll give EAGAIN or something + if the socket is still alive (but the FD probably shouldn't be set anyway?)*/ +static void check_closed_writefd(struct Channel* channel, int fd) { + char c; + int ret; + TRACE(("enter check_closed_writefd fd %d", fd)) + if (fd < 0) { + TRACE(("leave check_closed_writefd.")) + return; + } + + /* Read something. doing read(fd,x,0) seems to become a NOP on some platforms */ + ret = read(fd, &c, 1); + TRACE(("ret %d errno %d", ret, errno)) + if (ret > 0 || (ret < 0 && (errno == EINTR || errno == EAGAIN))) { + TRACE(("leave check_closed_writefd")) + return; + } + close_chan_fd(channel, fd, SHUT_WR); + TRACE(("leave check_closed_writefd after closing %d", fd)) +} + /* Iterate through the channels, performing IO if available */ void channelio(fd_set *readfds, fd_set *writefds) { @@ -229,6 +252,16 @@ void channelio(fd_set *readfds, fd_set *writefds) { writechannel(channel, channel->errfd, channel->extrabuf); } + /* Check writefds for close, even if we don't have anything + to write into them. */ + if (channel->writefd >= 0) { + check_closed_writefd(channel, channel->writefd); + } + if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { + check_closed_writefd(channel, channel->errfd); + } + + /* handle any channel closing etc */ check_close(channel); @@ -439,6 +472,16 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) { FD_SET(channel->errfd, writefds); } + /* We also set the writefds for reading, so that we will be notified of close */ + if (channel->writefd >= 0) { + FD_SET(channel->writefd, readfds); + } + if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { + FD_SET(channel->errfd, readfds); + } + + + } /* foreach channel */ #ifdef USING_LISTENERS |