summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2006-12-05 15:23:06 +0000
committerMatt Johnston <matt@ucc.asn.au>2006-12-05 15:23:06 +0000
commit4e09d27c6f8e59631becb422a055ede15833af89 (patch)
treecd790c57e003c9851725ea5a0af5e48fbc274350
parente1d3a8a6e9481b9fd53e5e8aa505ffc9b4536660 (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.c43
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