changeset 376:4f2dbd1c3685 channel-fix

Add some code for testing whether a writefd is closed (by read()ing from it)
author Matt Johnston <matt@ucc.asn.au>
date Tue, 05 Dec 2006 15:23:06 +0000
parents 8d149b812669
children a5bca950120d c53a26c430e5
files common-channel.c
diffstat 1 files changed, 43 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/common-channel.c	Tue Dec 05 14:42:03 2006 +0000
+++ b/common-channel.c	Tue Dec 05 15:23:06 2006 +0000
@@ -186,6 +186,29 @@
 	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 @@
 			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 @@
 				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