Obtained from: ftp://ftp.linux.org.uk/pub/linux/rmk/ijb20.rmk.diff

--- bind.c.orig	Fri Nov 30 11:25:23 2001
+++ bind.c	Fri Nov 30 11:33:46 2001
@@ -45,6 +45,242 @@
 long  remote_ip_long;
 char *remote_ip_str;
 
+#ifdef HAVE_IPV6
+#ifdef HAVE_POLL
+/*
+ * Do we have the superiour poll() interface?
+ */
+#include <sys/poll.h>
+
+static struct pollfd	*b_pfd;
+static int		nr_fds;
+#else
+/*
+ * Argh, we've only got the select() interface.
+ */
+#include <sys/select.h>
+
+static fd_set		sfd;
+static int		max_fd;
+#endif
+
+static int add_fd(fd)
+	int fd;
+{
+#ifdef HAVE_POLL
+	struct pollfd *n;
+	int nr = nr_fds + 1;
+
+	n = realloc(b_pfd, nr * sizeof(*n));
+	if (!n)
+		return -3;
+
+	n[nr_fds].fd     = fd;
+	n[nr_fds].events = POLLIN;
+
+	b_pfd  = n;
+	nr_fds = nr;
+
+	return 0;
+#else
+	if (fd >= max_fd)
+		max_fd = fd + 1;
+	FD_SET(fd, &sfd);
+	return 0;
+#endif
+}
+
+/*
+ * Bind one port of an address family, specified by `ai'
+ */
+static int bind_one(ai)
+	struct addrinfo *ai;
+{
+	int fd, one = 1;
+
+	fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+	if (fd == -1) {
+		/*
+		 * Is it an unsupported family or protocol?
+		 * Move along please.
+		 */
+		if (errno == EINVAL || errno == EPROTONOSUPPORT)
+			return -1;
+
+		/*
+		 * Ok, something else went wrong - fatal error.
+		 */
+		return -3;
+	}
+
+	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+		   (char *)&one, sizeof(one));
+
+	/*
+	 * Now bind the socket.  This may fail on Linux.
+	 */
+	if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) {
+		close(fd);
+
+		if (errno == EADDRINUSE)
+			return -2;
+		else
+			return -1;
+	}
+
+	/*
+	 * and ensure that it is listening.
+	 */
+	while (listen(fd, 5) == -1) {
+		if (errno != EINTR) {
+			close(fd);
+			return -1;
+		}
+	}
+
+	return add_fd(fd);
+}
+
+/*
+ * BIND-PORT (portnum)
+ *  if success, return file descriptor
+ *  if failure, returns -2 if address is in use, otherwise -1
+ */
+int 	bind_port (hostnam, portnum)
+char	*hostnam;
+int	 portnum;
+{
+	struct addrinfo *ai, *aip, aihint;
+	int rc, nr = 0;
+	char serv[NI_MAXSERV];
+
+	if (snprintf(serv, NI_MAXSERV, "%d", portnum) >= NI_MAXSERV)
+		return -1;
+
+	memset(&aihint, 0, sizeof(aihint));
+
+	aihint.ai_flags = AI_PASSIVE;
+	aihint.ai_family = PF_UNSPEC;
+	aihint.ai_socktype = SOCK_STREAM;
+
+	rc = getaddrinfo(hostnam, serv, &aihint, &ai);
+	if (rc)
+		return -1;
+
+	/*
+	 * Go through each entry creating a socket and trying
+	 * to bind it.  Note that on Linux, if we bind to an
+	 * IPv6 address, we can't bind to it's corresponding
+	 * IPv4 address, so we bind IPv6 first, then IPv4.
+	 * 
+	 * We classify success as being able to establish at
+	 * least one listening socket.
+	 */
+	for (aip = ai; aip; aip = aip->ai_next) {
+		if (aip->ai_family == PF_INET6) {
+			rc = bind_one(aip);
+			if (rc == 0)
+				nr++;
+		}
+	}
+
+	for (aip = ai; aip; aip = aip->ai_next) {
+		if (aip->ai_family == PF_INET) {
+			rc = bind_one(aip);
+			if (rc == 0)
+				nr++;
+		}
+	}
+
+	freeaddrinfo(ai);
+
+	if (nr != 0)
+		rc = 0;
+
+	return rc;
+}
+
+/* 
+ * ACCEPT-CONNECTION
+ * the argument, fd, is the value returned from bind_port
+ *
+ * when a connection is accepted, it returns the file descriptor
+ * for the connected port
+ */
+int	accept_connection (_fd)
+int	_fd;
+{
+	struct sockaddr_storage sa;
+	int afd, alen = sizeof(sa);
+	char host[NI_MAXHOST];
+	int rc, fd;
+
+#ifdef HAVE_POLL
+	int i;
+
+	do {
+		rc = poll(b_pfd, nr_fds, -1);
+	} while (rc == 0 || (rc == -1 && errno == EINTR));
+
+	/*
+	 * I wish we could spawn the handler here.  Alas, without
+	 * rewriting more of ijb...
+	 */
+	for (i = 0; i < nr_fds; i++)
+		if (b_pfd[i].revents)
+			break;
+
+	/*
+	 * hmm, if we ran out of fds to check, someone lied to us.
+	 */
+	if (i >= nr_fds)
+		return -1;
+
+	fd = b_pfd[i].fd;
+#else
+	fd_set rfds;
+
+	rfds = sfd;
+	do {
+		rc = select(max_fd, &rfds, NULL, NULL, NULL);
+	} while (rc == 0 || (rc == -1 && errno == EINTR));
+
+	/*
+	 * Find the first fd.  Same comment as above.
+	 */
+	for (fd = 0; fd < max_fd; fd++)
+		if (FD_ISSET(fd, &rfds))
+			break;
+
+	/*
+	 * If we found no fds, someone lied to us.
+	 */
+	if (fd >= max_fd)
+		return -1;
+
+#endif
+	afd = accept(fd, (struct sockaddr *)&sa, &alen);
+	if (afd < 0)
+		return -1;
+
+	if (getnameinfo((struct sockaddr *)&sa, alen,
+			host, NI_MAXHOST,
+			NULL, 0, NI_NUMERICHOST))
+		strcpy(host, "unknown");
+
+	remote_ip_str = strdup(host);
+	remote_ip_long = 0;
+
+	return afd;
+}
+#else
+/*
+ * -------------------------------- IPv4 ----------------------------
+ */
+
+extern int atoip();
+
+
 /*
  * BIND-PORT (portnum)
  *  if success, return file descriptor
@@ -100,7 +336,6 @@
 	return fd;
 }
 
-
 /* 
  * ACCEPT-CONNECTION
  * the argument, fd, is the value returned from bind_port
@@ -128,3 +363,5 @@
 
 	return afd;
 }
+#endif
+
--- conn.c.orig	Fri Nov 30 11:25:23 2001
+++ conn.c	Fri Nov 30 11:30:30 2001
@@ -41,6 +41,10 @@
 #include "gnuregex.h"
 #endif
 
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif
+
 #include "jcc.h"
 
 int
@@ -82,14 +86,127 @@
 	return(inaddr.sin_addr.s_addr);
 }
 
+#ifdef HAVE_IPV6
+int connect_to(char *host, int portnum, struct client_state *csp)
+{
+	struct addrinfo *ai, *aip, aihint;
+	int fd = -1, rc;
+	char serv[NI_MAXSERV];
+
+	if (snprintf(serv, NI_MAXSERV, "%d", portnum) >= NI_MAXSERV) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+
+	memset(&aihint, 0, sizeof(aihint));
+
+	aihint.ai_family = PF_UNSPEC;
+	aihint.ai_socktype = SOCK_STREAM;
+
+	rc = getaddrinfo(host, serv, &aihint, &ai);
+	if (rc)
+		return -1;
+
+	/*
+	 * Go through each entry trying to connect to the host.
+	 */
+	for (aip = ai; aip; aip = aip->ai_next) {
+		int flags;
+
+		fd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
+		if (fd == -1)
+			continue;
+
+#ifdef TCP_NODELAY	/* turn off TCP coalescence */
+		{
+			int mi = 1;
+			setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&mi, sizeof(mi));
+		}
+#endif
+#if !defined(_WIN32) && !defined(__BEOS__)
+		flags = fcntl(fd, F_GETFL, 0);
+		if (flags != -1)
+			fcntl(fd, F_SETFL, flags | O_NDELAY);
+#endif
+		do {
+			rc = connect(fd, aip->ai_addr, aip->ai_addrlen);
+		} while (rc == -1 && errno == EINTR);
+
+		if (rc == -1 && errno != EINPROGRESS) {
+			close(fd);
+			fd = -1;
+			continue;
+		}
+
+		/*
+		 * Ok, the connection is in progress.
+		 */
+#if !defined(_WIN32) && !defined(__BEOS__)
+		if (flags != -1)
+			fcntl(fd, F_SETFL, flags);
+#endif
+		{
+#ifdef HAVE_POLL
+			struct pollfd pfd;
+
+			pfd.fd = fd;
+			pfd.events = POLLOUT | POLLERR | POLLHUP;
+
+			if (poll(&pfd, 1, 30000) <= 0) {
+				close(fd);
+				fd = -1;
+				continue;
+			}
+
+			if (pfd.revents & (POLLERR|POLLHUP)) {
+				close(fd);
+				fd = -1;
+				continue;
+			}
+#else
+			fd_set rfds, wfds;
+			struct timeval tv[1];
+
+			FD_ZERO(&rfds);
+			FD_ZERO(&wfds);
+			FD_SET(fd, &rfds);
+			FD_SET(fd, &wfds);
+
+			tv->tv_sec  = 30;
+			tv->tv_usec = 0;
+
+			if (select(fd + 1, &rfds, &wfds, NULL, tv) <= 0) {
+				(void) close(fd);
+				fd = -1;
+				continue;
+			}
+
+			if (FD_ISSET(fd, &rfds) && FD_ISSET(fd, &wfds)) {
+				int r = 0, l = sizeof(r);
+
+				if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &l)
+				    || r) {
+					(void) close(fd);
+					fd = -1;
+					continue;
+				}
+			}
+#endif
+		}
+		break;
+	}
+
+	freeaddrinfo(ai);
 
+	return fd;
+}
+
+#else
 int
 connect_to(char *host, int portnum, struct client_state *csp)
 {
 	struct sockaddr_in inaddr;
 	int	fd, addr;
-	fd_set wfds;
-	struct timeval tv[1];
 	int	flags;
 	struct access_control_addr src[1], dst[1];
 
@@ -122,23 +239,19 @@
 	}
 
 #ifdef TCP_NODELAY
-{	/* turn off TCP coalescence */
-	int	mi = 1;
-	setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char * ) &mi, sizeof (int));
-}
+	{	/* turn off TCP coalescence */
+		int	mi = 1;
+		setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char * ) &mi, sizeof (int));
+	}
 #endif
-
-#ifndef _WIN32
-#ifndef __BEOS__
+#if !defined(_WIN32) && !defined(__BEOS__)
 	if ((flags = fcntl(fd, F_GETFL, 0)) != -1) {
 		flags |= O_NDELAY;
 		fcntl(fd, F_SETFL, flags);
 	}
 #endif
-#endif
 
 	while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == -1) {
-
 #ifdef _WIN32
 		if (errno == WSAEINPROGRESS)
 #else
@@ -154,25 +267,59 @@
 		}
 	}
 
-#ifndef _WIN32
-#ifndef __BEOS__
+#if !defined(_WIN32) && !defined(__BEOS__)
 	if (flags != -1) {
 		flags &= ~O_NDELAY;
 		fcntl(fd, F_SETFL, flags);
 	}
 #endif
-#endif
 
-	/* wait for connection to complete */
-	FD_ZERO(&wfds);
-	FD_SET(fd, &wfds);
+	{
+#ifdef HAVE_POLL
+		struct pollfd pfd;
+
+		pfd.fd = fd;
+		pfd.events = POLLOUT | POLLERR | POLLHUP;
+
+		if (poll(&pfd, 1, 30000) <= 0) {
+			close(fd);
+			return -1;
+		}
 
-	tv->tv_sec  = 30;
-	tv->tv_usec = 0;
+		if (pfd.revents & (POLLERR|POLLHUP)) {
+			close(fd);
+			return -1;
+		}
+#else
+		fd_set rfds, wfds;
+		struct timeval tv[1];
 
-	if (select(fd + 1, NULL, &wfds, NULL, tv) <= 0) {
-		(void) close(fd);
-		return(-1);
+		/* wait for connection to complete */
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+		FD_SET(fd, &rfds);
+		FD_SET(fd, &wfds);
+
+		tv->tv_sec  = 30;
+		tv->tv_usec = 0;
+
+		if (select(fd + 1, &rfds, &wfds, NULL, tv) <= 0) {
+			(void) close(fd);
+			return(-1);
+		}
+
+		if (FD_ISSET(fd, &rfds) && FD_ISSET(fd, &wfds)) {
+			int r = 0, l = sizeof(r);
+
+			if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &l)
+			    || r) {
+				(void) close(fd);
+				fd = -1;
+			}
+		}
+#endif
 	}
+
 	return(fd);
 }
+#endif
--- jcc.c.orig	Fri Nov 30 11:25:24 2001
+++ jcc.c	Fri Nov 30 11:30:30 2001
@@ -32,9 +32,13 @@
 #include <OS.h>		/* declarations for threads and stuff. */
 #endif
 
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#else
 #ifndef FD_ZERO
 #include <select.h>
 #endif
+#endif
 
 #endif
 
@@ -640,7 +644,26 @@
 
 	server_body = 0;
 
+#ifdef HAVE_POLL
+	fds[0].fd = csp->cfd;
+	fds[0].events = POLLIN|POLLHUP;
+	fds[1].fd = csp->sfd;
+	fds[1].events = POLLIN|POLLHUP;
+#endif
+
 	for(;;) {
+#ifdef HAVE_POLL
+		n = poll(fds, 2, -1);
+
+		if (n < 0) {
+			fprintf(logfp, "%s: poll() failed!: ", prog);
+			fperror(logfp, "");
+			return;
+		}
+
+#define IS_CLIENT()	(fds[0].revents & POLLIN)
+#define IS_SERVER()	(fds[1].revents & POLLIN)
+#else
 		FD_ZERO(&rfds);
 
 		FD_SET(csp->cfd, &rfds);
@@ -653,12 +676,14 @@
 			fperror(logfp, "");
 			return;
 		}
-
+#define IS_CLIENT()	FD_ISSET(csp->cfd, &rfds)
+#define IS_SERVER()	FD_ISSET(csp->sfd, &rfds)
+#endif
 		/* this is the body of the browser's request
 		 * just read it and write it.
 		 */
 
-		if(FD_ISSET(csp->cfd, &rfds)) {
+		if(IS_CLIENT()) {
 
 			n = read_socket(csp->cfd, buf, sizeof(buf));
 
@@ -679,7 +704,7 @@
 		 * otherwise it's the body
 		 */
 
-		if(FD_ISSET(csp->sfd, &rfds)) {
+		if(IS_SERVER()) {
 
 			n = read_socket(csp->sfd, buf, sizeof(buf));
 
--- jcc.h.orig	Fri Nov 30 11:25:24 2001
+++ jcc.h	Fri Nov 30 11:37:12 2001
@@ -339,6 +339,7 @@
 extern void client_cookie_adder(struct client_state *csp);
 extern void client_xtra_adder(struct client_state *csp);
 extern void client_x_forwarded_adder(struct client_state *csp);
+extern void server_conn_close_adder(struct client_state *csp);
 
 /* interceptors from filters.c
 */
--- parsers.c.orig	Fri Nov 30 11:25:24 2001
+++ parsers.c	Fri Nov 30 11:30:30 2001
@@ -32,6 +32,7 @@
 	{ "cookie:",		 7,	client_send_cookie	},
 	{ "x-forwarded-for:",	16,	client_x_forwarded	},
 	{ "proxy-connection:",	17,	crumble			},
+	{ "keep-alive:",	11,	crumble			},
 /*	{ "if-modified-since:", 18,	crumble			}, */
 	{ NULL,			 0,	NULL			}
 };
@@ -57,6 +58,7 @@
 };
 
 void (*add_server_headers[])() = {
+	server_conn_close_adder,	/* for http/1.1 */
 	NULL
 };
 
@@ -608,6 +610,12 @@
 	if(csp->accept_server_cookie == 0) return(crumble(v, s, csp));
 
 	return(strdup(s));
+}
+
+void server_conn_close_adder(struct client_state *csp)
+{
+	char *p = strsav(NULL, "Connection: close");
+	enlist(csp->headers, p);
 }
 
 /* case insensitive string comparison */
--- socks4.c.orig	Fri Nov 30 11:25:25 2001
+++ socks4.c	Fri Nov 30 11:30:31 2001
@@ -11,6 +11,7 @@
 
 
 #include <stdio.h>
+#include <string.h>
 #include <sys/types.h>
 #include <errno.h>
 
@@ -112,6 +113,8 @@
 		strcpy(((char *)cbuf) + csiz, http->host);
 		csiz = n;
 		break;
+	default:
+		return -1; /* oops */
 	}
 
 	c->vn         = 4;
