This patch is generated from the eventio branch of HEAD in squid
Wed Sep 29 01:32:37 2004 GMT
See http://devel.squid-cache.org/

Index: squid/configure.in
diff -u squid/configure.in:1.36 squid/configure.in:1.17.8.8
--- squid/configure.in:1.36	Wed Nov 21 15:49:04 2001
+++ squid/configure.in	Wed Nov 21 18:40:27 2001
@@ -719,16 +719,20 @@
 ])
 
 AC_ARG_ENABLE(ident-lookups,
-[  --disable-ident-lookups
-                          This allows you to remove code that performs
+[  --enable-ident-lookups
+                          This allows you to reenable code that performs
                           Ident (RFC 931) lookups.],
-[ if test "$enableval" = "no" ; then
-    echo "Disabling Ident Lookups"
-    AC_DEFINE(USE_IDENT, 0)
+[ if test "$enableval" = "yes" ; then
+    echo "Enabling Ident Lookups"
+    use_ident="yes"
   else
-    AC_DEFINE(USE_IDENT, 1)
+    echo "Disabling Ident Lookups"
+    use_ident=
   fi
 ])
+if test "$use_dnsserver" = "yes"; then
+    AC_DEFINE(USE_IDENT)
+fi
 
 AM_CONDITIONAL(USE_DNSSERVER, false)
 use_dnsserver=
Index: squid/doc/debug-sections.txt
diff -u squid/doc/debug-sections.txt:1.3 squid/doc/debug-sections.txt:1.3.14.1
--- squid/doc/debug-sections.txt:1.3	Sun Jan  7 15:53:36 2001
+++ squid/doc/debug-sections.txt	Fri Feb 16 07:01:02 2001
@@ -86,3 +86,4 @@
 section 79    HTTP Meter Header
 section 80    WCCP
 section 81    Store Removal/Replacement policy
+section 90    New comm code
Index: squid/doc/Programming-Guide/prog-guide.sgml
diff -u squid/doc/Programming-Guide/prog-guide.sgml:1.16 squid/doc/Programming-Guide/prog-guide.sgml:1.9.8.13
--- squid/doc/Programming-Guide/prog-guide.sgml:1.16	Fri Sep  7 16:55:49 2001
+++ squid/doc/Programming-Guide/prog-guide.sgml	Sat Feb 23 08:22:17 2002
@@ -3085,4 +3085,371 @@
 that pointer was last accessed.  If there is a leak, then the bug
 occurs somewhere after that point of the code.
 
+<sect>Network I/O
+
+<p>
+	The networking I/O layer is responsible for all network I/O (duh!).
+
+<p>
+	It is implemented as a set of asyncronous operations for opening /
+	acception connections and reading/writing data on those connections.
+	The asyncronous operation means that each API call will only initiate
+	the operation, and when the operation s finished a supplied callback
+	function will be called.
+
+<p>
+	Created filehandles are cbdata enabled, and any links / pointers to
+	filehandles should be properly managed as cbdata. 
+
+<p>
+	The return value of is 0 on success or -1 on error. On error, errno
+	will be set to a suitable error code.
+
+<p>
+	All data is contained in IOBuf handlers. Each IOBuf has a reference
+	count, knows the amount of data stored in the IOBuf, actual size
+	of the allocated buffer area (internal) and the buffer area itself.
+	IOBuf is not a simple pointer.
+
+<sect1>API
+
+<p>
+	This are the functions available for performing network I/O operations
+
+<sect2>ncomm_close
+
+<p><verb>
+	int
+	ncomm_close(filehandle *fh);
+</verb>
+
+<p>
+	Signals EOF on the socket. No further ncomm_write calls is allowed
+	after this.
+
+<p>
+	Any pending I/O operations will be completed.
+
+<p>
+	The socket will get fully closed when the last reference to the
+	filehandle is gone.
+
+<sect2>ncomm_closed
+
+<p><verb>
+	int
+	ncomm_closed(filehandle *fh);
+</verb>
+
+<p>
+	Returns true if a filehandle has been closed with ncomm_close()
+
+<sect2>ncomm_abort
+
+<p><em/What should we do with callbacks?/
+
+<p><verb>
+	int
+	ncomm_abort(filehandle *fh);
+</verb>
+
+<p>
+	Aborts the given network connection immediately. Any pending I/O
+	requests will be aborted. No callbacks will be done for
+	cancelled I/O requests.
+
+<sect2>ncomm_listen
+
+<p><verb>
+	filehandle *
+	ncomm_listen(int sock_type, int proto, struct sockaddr *where,
+		     int addrsize, int backlog, COMMNEWCB *callback,
+		     void *cbdata)
+</verb>
+
+<p>
+	start listening for new connections on the given address/port.
+
+<p>
+	The listening port is open until closed with ncomm_close or aborted
+	with ncomm_abort. comm_abort will cancel any pending queued incoming
+	connections not yet notified to the callback, while ncomm_close will
+	only stop listening for new connection requests.
+
+<sect2>ncomm_accept
+
+<p><verb>
+	filehandle *
+	ncomm_accept(int sock_type, int proto, struct sockaddr *where,
+		     struct sockaddr *from, int addrsize,
+		     COMMNEWCB callback, void *cbdata)
+</verb>
+
+<p>
+	Accept a single connection from the given source
+
+<p>
+	The returned filehandle is not valid for use until the callback
+	has been notified, except for comm_abort to cancel the connection
+	request.
+
+<sect2>ncomm_connect
+
+<p><verb>
+	filehandle *
+	ncomm_connect(int sock_type, int proto,
+		      const struct sockaddr *local,
+		      const struct sockaddr *remote, int addrsize,
+		      COMMNEWCB *callback, void *cbdata)
+</verb>
+
+<p>
+	Creates a new network connection to the given remote address,
+	optionally using a specified local source address.
+
+<p>
+	The returned filehandle is not valid for use until the callback
+	has been notified, except for comm_abort to cancel the connection
+	request.
+
+<sect2>ncomm_read
+
+<p><verb>
+	void
+	ncomm_read(filehandle *fh, COMMIOCB *callback, void *cbdata);
+	void
+	ncomm_read_limited(filehandle *fh, size_t max_size, COMMIOCB *callback,
+		   void *cbdata);
+</verb>
+
+<p>
+	Request to write data. The callback will be called when
+	the request has finished, or if an unrecoverable error
+	occurs.
+	
+<p>
+	ncomm_read_limited can limit the max amount of data read in
+	one request.
+
+<p>
+	Any errors will be signalled to the callback function.
+
+<sect2>ncomm_write
+
+<p><verb>
+	void
+	ncomm_write(filehandle *fh, IOBUF *buf, COMMIOCB *callback,
+		    void *cbdata);
+</verb>
+
+<p>
+	Request to write data. The callback will be called when
+	the request has finished, or if an unrecoverable error
+	occurs.
+
+<p>
+	it is allowable to queue more write requests before the first has
+	finished. The requests will be processed and completed in the order
+	requested without reordering in data or callback order.
+
+<p>
+	Any errors will be signalled to the callback function.
+
+<sect2>ncomm_write_fragment
+
+<p><verb>
+	void
+	ncomm_write_fragment(filehandle *fh, IOBUF *buf, off_t offset,
+		    size_t size, COMMIOCB *callback, void *cbdata);
+</verb>
+
+<p>
+	as ncomm_write, but only writes the indicated range of the supplied
+	IOBuf.
+
+<sect2>ncomm_write_mbuf
+
+<p><verb>
+	void
+	ncomm_write_mbuf(filehandle *fh, MemBuf mb, COMMIOCB *callback,
+			 void *cbdata);
+</verb>
+
+<p>
+	Like comm_write, but gets the data from a MemBuf instead of a IOBuf.
+
+<p>
+	The MemBuf should not be used after this. The responsibility for
+	the data area is taken over by ncomm.
+
+<sect2>ncomm_add_close_handler
+
+<p><verb>
+	int
+	ncomm_add_close_handler(filehandle *fh, COMMCLOSECB *handler,
+				void *cbdata);
+</verb>
+
+<p>
+	Registers a close handler what will be called when the socket is closed.
+	For example to clean up associated data structures or keep relations
+	proper.
+
+<sect1>callbacks
+
+<p>
+	Callbacks are used to get notifications when an network operation
+	has finished. These functions are passed as arguments to the
+	I/O operation to be performed, and will get called when the operation
+	finishes (completed or error).
+
+<sect2>COMMNEWCB
+
+<p><verb>
+	typedef void
+	COMMNEWCB(filehandle *fh, int error, struct sockaddr *local,
+		  struct sockaddr *peer, int addrsize, void *cbdata);
+</verb>
+
+<p>
+	Called when a new filehandle is created (ncomm_listen / ncomm_accept
+	/ ncomm_connect)
+
+<p>
+	On error, error is set to the appropriate errno.
+
+<sect2>COMMIOCB
+
+<p><verb>
+	typedef void
+	COMMIOCB(filehandle *fh, IOBUF *buf, int offset, int size,
+		 int errno, void *cbdata);
+</verb>
+
+<p>
+	Called when an I/O operation has finished (ncomm_read / 
+	ncomm_write).
+
+<p>
+	On error errno will be set to the error, otherwise errno will
+	be 0.
+
+<p>
+	offset is the offset in the IOBUF where the data for the operation
+	starts, and size is the amount of data processed by the operation.
+
+<p>
+	Note: On error the operation might have been partially completed. In
+	such case size >= 0 and errno != 0.
+
+<sect2>COMMCLOSECB
+
+<p><verb>
+	typedef void
+	COMMCLOSECB(filehandle *fh, void *cbdata);
+</verb>
+
+<p>
+	Called when the filehandle is closed (ncomm_close / ncomm_abort), as
+	requested (ncomm_add_close_handler)
+
+<sect1>"system" API
+
+<p>
+	These functions are part of the general framework, and are generally
+	only called once, at suitable locations in the program.
+
+<sect2>ncomm_handle_events
+
+<p><verb>
+	void
+	ncomm_handle_events(int timeout);
+</verb>
+
+<p>
+	This is the network I/O "main loop". Will execute any pending I/O
+	events, and if no events are pending optionally wait for timeout
+	milliseconds for an event to arrive.
+
+<sect2>ncomm_module_init
+
+<p><verb>
+	void
+	ncomm_module_init(void);
+</verb>
+
+<p>
+	Initializes the network I/O subsystem
+
+<sect2>ncomm_module_shutdown
+
+<p><verb>
+	void
+	ncomm_module_shutdown(void);
+</verb>
+
+<p>
+	Called on shutdown. Terminates all pending I/O operations and/or
+	connections and other related cleanups.
+
+<sect2>ncomm_abort_all_connections
+
+<p><em/Do we really need this?/
+
+<p><verb>
+	void
+	ncomm_abort_all_connections(void);
+</verb>
+
+<p>
+	Aborts all currently open network connections.
+
+<sect1>Internal "poll" API
+
+<p>
+	The "poll" API can be used on UNIX to implement event notification
+	mechanisms without having to reimplement all the read/write logics.
+	The purpose of this "event" system is to notify the generic
+	read/write logics when I/O is possible on a socket.
+
+<sect2>comm_register_for_read_event
+
+<p><verb>
+	void
+	comm_register_for_read_event(filehandle *fh, COMMEVENTREAD *handler);
+</verb>
+
+<p>
+	Ask to receive read events on the filehandle "fh". When there is a
+	read event available, "handler" will be called.
+
+<sect2>COMMEVENTREAD
+
+<p><verb>
+	typedef int COMMEVENTREAD(filehandle *fh);
+</verb>
+
+<p>
+	Callback function type for receiving read event notifications
+
+<SECT2>comm_register_for_write_event
+
+<p><verb>
+	void
+	comm_register_for_write_event(filehandle *fh, COMMEVENTWRITE *handler);
+</verb>
+
+<p>
+	Ask to receive write events on the filehandle "fh". When writing is
+	possible, "handler" will get called.
+
+<SECT2>COMMEVENTWRITE
+
+<p><verb>
+	typedef int COMMEVENTWRITE(filehandle *fh);
+</verb>
+
+<p>
+	Callback function type for receiving write event notifications
+
 </article>
Index: squid/src/HttpBody.c
diff -u squid/src/HttpBody.c:1.4 squid/src/HttpBody.c:1.4.12.1
--- squid/src/HttpBody.c:1.4	Fri Jan 12 00:20:32 2001
+++ squid/src/HttpBody.c	Sat Feb 24 04:52:42 2001
@@ -64,7 +64,7 @@
 {
     assert(body && p);
     if (body->mb.size)
-	packerAppend(p, body->mb.buf, body->mb.size);
+	packerAppend(p, *body->mb.bufp, body->mb.size);
 }
 
 #if UNUSED_CODE
Index: squid/src/HttpHeader.c
diff -u squid/src/HttpHeader.c:1.10 squid/src/HttpHeader.c:1.5.12.3
--- squid/src/HttpHeader.c:1.10	Wed Oct 24 02:42:11 2001
+++ squid/src/HttpHeader.c	Sat Nov 17 05:11:57 2001
@@ -721,7 +721,7 @@
     packerToMemInit(&p, &mb);
     httpHdrCcPackInto(cc, &p);
     /* put */
-    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_CACHE_CONTROL, NULL, mb.buf));
+    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_CACHE_CONTROL, NULL, *mb.bufp));
     /* cleanup */
     packerClean(&p);
     memBufClean(&mb);
@@ -740,7 +740,7 @@
     packerToMemInit(&p, &mb);
     httpHdrContRangePackInto(cr, &p);
     /* put */
-    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_CONTENT_RANGE, NULL, mb.buf));
+    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_CONTENT_RANGE, NULL, *mb.bufp));
     /* cleanup */
     packerClean(&p);
     memBufClean(&mb);
@@ -759,7 +759,7 @@
     packerToMemInit(&p, &mb);
     httpHdrRangePackInto(range, &p);
     /* put */
-    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_RANGE, NULL, mb.buf));
+    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_RANGE, NULL, *mb.bufp));
     /* cleanup */
     packerClean(&p);
     memBufClean(&mb);
Index: squid/src/HttpHeaderTools.c
diff -u squid/src/HttpHeaderTools.c:1.7 squid/src/HttpHeaderTools.c:1.6.8.2
--- squid/src/HttpHeaderTools.c:1.7	Thu Sep  6 14:19:46 2001
+++ squid/src/HttpHeaderTools.c	Wed Sep 12 13:34:24 2001
@@ -131,7 +131,7 @@
     MemBuf mb;
     memBufDefInit(&mb);
     memBufVPrintf(&mb, fmt, vargs);
-    httpHeaderPutStr(hdr, id, mb.buf);
+    httpHeaderPutStr(hdr, id, *mb.bufp);
     memBufClean(&mb);
 }
 
Index: squid/src/Makefile.am
diff -u squid/src/Makefile.am:1.8 squid/src/Makefile.am:1.4.4.3
--- squid/src/Makefile.am:1.8	Thu Nov 15 23:28:20 2001
+++ squid/src/Makefile.am	Sat Nov 17 05:11:57 2001
@@ -116,6 +116,7 @@
 	$(DELAY_POOL_SOURCE) \
 	disk.c \
 	$(DNSSOURCE) \
+	dlink.c \
 	enums.h \
 	errorpage.c \
 	ETag.c \
@@ -155,6 +156,8 @@
 	MemBuf.c \
 	mime.c \
 	multicast.c \
+	ncomm.c \
+	ncomm_poll.c \
 	neighbors.c \
 	net_db.c \
 	Packer.c \
@@ -195,6 +198,7 @@
 	wais.c \
 	wccp.c \
 	whois.c \
+	wordlist.c \
 	$(WIN32SOURCE)
 
 nodist_squid_SOURCES = \
@@ -205,6 +209,26 @@
 	globals.c \
 	string_arrays.c
 
+#NOBJS = \
+#       cbdata.o \
+#       client_side.o \
+#       debug.o \
+#       dlink.o \
+#       fd.o \
+#       globals.o \
+#       MemBuf.o \
+#       mem.o \
+#       MemPool.o \
+#       ncomm.o \
+#       ncomm_poll.o \
+#       ncomm_test.o \
+#       string_arrays.o \
+#       wordlist.o \
+#
+#ncomm_test: $(NOBJS)
+#       $(CC) -o $@ $(LDFLAGS) $(NOBJS) $(SQUID_LIBS)
+
+
 squid_LDADD = \
 	-L../lib \
 	@XTRA_OBJS@ \
Index: squid/src/MemBuf.c
diff -u squid/src/MemBuf.c:1.5 squid/src/MemBuf.c:1.4.12.3
--- squid/src/MemBuf.c:1.5	Fri Apr 20 14:27:11 2001
+++ squid/src/MemBuf.c	Sun Feb 25 12:45:55 2001
@@ -34,10 +34,6 @@
  */
 
 /*
- * To-Do: use memory pools for .buf recycling @?@ @?@
- */
-
-/*
  * Rationale:
  * ----------
  * 
@@ -87,15 +83,39 @@
  * memBufInit(&buf, initial-size, absolute-maximum);
  * 
  * -- "pack" (no need to handle offsets or check for overflows)
- * memBufPrintf(&buf, ...);
+ * memBufPrintf(&buf, "format", ...);
  * ...
  * 
  * -- write
- * comm_write_mbuf(fd, buf, handler, data);
+ * comm_write_mbuf(fd, &buf, handler, data);
  *
  * -- *iff* you did not give the buffer away, free it yourself
  * -- memBufClean(&buf);
  * }
+ *
+ * or alternatively using pointers and references
+ *
+ * {
+ * -- setup
+ * MemBuf *bufp = memBufCreate(initial-size, absolute-maximum);
+ * MemBuf *otherp;
+ *
+ * -- "pack" (no need to handle offsets or check for overflows)
+ * memBufPrintf(bufp, "format", ...);
+ * ...
+ * 
+ * -- write
+ * comm_write_mbuf(fd, bufp, handler, data);
+ *
+ * -- reference
+ * otherp = cbdataReference(bufp);
+ *
+ * -- destroy reference
+ * cbdataUnreference(&otherp)
+ *
+ * -- free
+ * memBufFree(&bufp)
+ * }
  */
 
 
@@ -107,10 +127,56 @@
 #define MEM_BUF_INIT_SIZE   (2*1024)
 #define MEM_BUF_MAX_SIZE    (2*1000*1024*1024)
 
-
 /* local routines */
 static void memBufGrow(MemBuf * mb, mb_size_t min_cap);
 
+/* Define data types */
+#define MEM_BUF_MIN_SIZE 64
+typedef struct {char *buf; char _buf[64];} MemBuf64; CBDATA_TYPE(MemBuf64);
+typedef struct {char *buf; char _buf[128];} MemBuf128; CBDATA_TYPE(MemBuf128);
+typedef struct {char *buf; char _buf[256];} MemBuf256; CBDATA_TYPE(MemBuf256);
+typedef struct {char *buf; char _buf[512];} MemBuf512; CBDATA_TYPE(MemBuf512);
+typedef struct {char *buf; char _buf[1024];} MemBuf1K; CBDATA_TYPE(MemBuf1K);
+typedef struct {char *buf; char _buf[2048];} MemBuf2K; CBDATA_TYPE(MemBuf2K);
+typedef struct {char *buf; char _buf[4096];} MemBuf4K; CBDATA_TYPE(MemBuf4K);
+typedef struct {char *buf; char _buf[8192];} MemBuf8K; CBDATA_TYPE(MemBuf8K);
+typedef struct {char *buf; char _buf[16384];} MemBuf16K; CBDATA_TYPE(MemBuf16K);
+typedef struct {char *buf; char _buf[32768];} MemBuf32K; CBDATA_TYPE(MemBuf32K);
+typedef struct {char *buf; char _buf[65535];} MemBuf64K; CBDATA_TYPE(MemBuf64K);
+typedef struct {char *buf; int size;} MemBufLarge; CBDATA_TYPE(MemBufLarge);
+
+static FREE memBufFreeLarge;
+
+/* initialize the membuf module */
+void
+memBuf_module_init(void)
+{
+    CBDATA_INIT_TYPE(MemBuf64);
+    CBDATA_INIT_TYPE(MemBuf128);
+    CBDATA_INIT_TYPE(MemBuf256);
+    CBDATA_INIT_TYPE(MemBuf512);
+    CBDATA_INIT_TYPE(MemBuf1K);
+    CBDATA_INIT_TYPE(MemBuf2K);
+    CBDATA_INIT_TYPE(MemBuf4K);
+    CBDATA_INIT_TYPE(MemBuf8K);
+    CBDATA_INIT_TYPE(MemBuf16K);
+    CBDATA_INIT_TYPE(MemBuf32K);
+    CBDATA_INIT_TYPE(MemBuf64K);
+    CBDATA_INIT_TYPE_FREECB(MemBufLarge, memBufFreeLarge);
+}
+
+void
+memBuf_module_shutdown(void)
+{
+}
+
+/* free functions */
+void
+memBufFreeLarge(void *data)
+{
+    char **p = data;
+    safe_free(*p);
+}
 
 /* init with defaults */
 void
@@ -127,11 +193,10 @@
     assert(mb);
     assert(szInit > 0 && szMax > 0);
 
-    mb->buf = NULL;
     mb->size = 0;
     mb->max_capacity = szMax;
     mb->capacity = 0;
-    mb->freefunc = NULL;
+    mb->bufp = NULL;
 
     memBufGrow(mb, szInit);
 }
@@ -144,12 +209,8 @@
 memBufClean(MemBuf * mb)
 {
     assert(mb);
-    assert(mb->buf);
-    assert(mb->freefunc);	/* not frozen */
 
-    (*mb->freefunc) (mb->buf);	/* free */
-    mb->freefunc = NULL;	/* freeze */
-    mb->buf = NULL;
+    cbdataFree(mb->bufp);
     mb->size = mb->capacity = 0;
 }
 
@@ -163,10 +224,16 @@
     if (memBufIsNull(mb)) {
 	memBufDefInit(mb);
     } else {
-	assert(mb->freefunc);	/* not frozen */
 	/* reset */
-	memset(mb->buf, 0, mb->capacity);
 	mb->size = 0;
+	if (cbdataLocked(mb->bufp)) {
+	    /* oops.. the buffer is in use somewhere.. create a new one */
+	    cbdataFree(mb->bufp);
+	    memBufGrow(mb, mb->capacity);
+	} else {
+	    /* reuse the existing buffer */
+	    memset(*mb->bufp, 0, mb->capacity);
+	}
     }
 }
 
@@ -175,9 +242,9 @@
 memBufIsNull(MemBuf * mb)
 {
     assert(mb);
-    if (!mb->buf && !mb->max_capacity && !mb->capacity && !mb->size)
+    if (!mb->bufp && !mb->max_capacity && !mb->capacity && !mb->size)
 	return 1;		/* is null (not initialized) */
-    assert(mb->buf && mb->max_capacity && mb->capacity);	/* paranoid */
+    assert(mb->bufp && mb->max_capacity && mb->capacity);	/* paranoid */
     return 0;
 }
 
@@ -187,14 +254,12 @@
 memBufAppend(MemBuf * mb, const char *buf, mb_size_t sz)
 {
     assert(mb && buf && sz >= 0);
-    assert(mb->buf);
-    assert(mb->freefunc);	/* not frozen */
 
     if (sz > 0) {
 	if (mb->size + sz > mb->capacity)
 	    memBufGrow(mb, mb->size + sz);
 	assert(mb->size + sz <= mb->capacity);	/* paranoid */
-	xmemcpy(mb->buf + mb->size, buf, sz);
+	xmemcpy(*mb->bufp + mb->size, buf, sz);
 	mb->size += sz;
     }
 }
@@ -230,138 +295,115 @@
 {
     int sz = 0;
     assert(mb && fmt);
-    assert(mb->buf);
-    assert(mb->freefunc);	/* not frozen */
+    assert(mb->bufp);
     /* assert in Grow should quit first, but we do not want to have a scary infinite loop */
     while (mb->capacity <= mb->max_capacity) {
 	mb_size_t free_space = mb->capacity - mb->size;
 	/* put as much as we can */
-	sz = vsnprintf(mb->buf + mb->size, free_space, fmt, vargs);
+	sz = vsnprintf(*mb->bufp + mb->size, free_space, fmt, vargs);
 	/* check for possible overflow */
-	/* snprintf on Linuz returns -1 on overflows */
-	/* snprintf on FreeBSD returns at least free_space on overflows */
-	if (sz < 0 || sz >= free_space)
+	if (sz >= free_space) {
+	    /* snprintf on FreeBSD returns at least free_space on overflows */
+	    memBufGrow(mb, mb->size + free_space + 1);
+	} else if (sz < 0) {
+	    /* snprintf on old (libc5) Linux returns -1 on overflows */
 	    memBufGrow(mb, mb->capacity + 1);
-	else
+	} else
 	    break;
     }
     mb->size += sz;
     /* on Linux and FreeBSD, '\0' is not counted in return value */
     /* on XXX it might be counted */
     /* check that '\0' is appended and not counted */
-    if (!mb->size || mb->buf[mb->size - 1]) {
-	assert(!mb->buf[mb->size]);
+    if (!mb->size || (*mb->bufp)[mb->size - 1]) {
+	assert(!(*mb->bufp)[mb->size]);
     } else {
 	mb->size--;
     }
 }
 
-/*
- * returns free() function to be used.
- * Important:
- *   calling this function "freezes" mb,
- *   do not _update_ mb after that in any way
- *   (you still can read-access .buf and .size)
- */
-FREE *
-memBufFreeFunc(MemBuf * mb)
-{
-    FREE *ff;
-    assert(mb);
-    assert(mb->buf);
-    assert(mb->freefunc);	/* not frozen */
-
-    ff = mb->freefunc;
-    mb->freefunc = NULL;	/* freeze */
-    return ff;
-}
-
 /* grows (doubles) internal buffer to satisfy required minimal capacity */
 static void
 memBufGrow(MemBuf * mb, mb_size_t min_cap)
 {
     mb_size_t new_cap;
-    MemBuf old_mb;
+    char **old_bufp;
+    mb_size_t old_size;
 
     assert(mb);
     assert(mb->capacity < min_cap);
 
+    assert(min_cap <= mb->max_capacity); /* no overflow */
+
     /* determine next capacity */
     new_cap = mb->capacity;
-    if (new_cap > 0)
-	while (new_cap < min_cap)
-	    new_cap *= 2;	/* double */
-    else
-	new_cap = min_cap;
-
-    /* last chance to fit before we assert(!overflow) */
-    if (new_cap > mb->max_capacity)
-	new_cap = mb->max_capacity;
-
-    assert(new_cap <= mb->max_capacity);	/* no overflow */
-    assert(new_cap > mb->capacity);	/* progress */
-
-    old_mb = *mb;
+    if (new_cap == 0)
+	new_cap = MEM_BUF_MIN_SIZE; /* start doubling at a nice round value */
+    while (new_cap < min_cap)
+	new_cap *= 2;	/* double */
+
+    old_size = mb->size;
+    old_bufp = cbdataReference(mb->bufp);
+    cbdataFree(mb->bufp);
 
     /* allocate new memory */
     switch (new_cap) {
+#define NEW_MEMBUFP(type) \
+	{ \
+	    type *new_bufp = cbdataAlloc(type); \
+	    new_bufp->buf = new_bufp->_buf; \
+	    mb->bufp = (char **)new_bufp; \
+	}
+    case 64:
+	NEW_MEMBUFP(MemBuf64);
+	break;
+    case 128:
+	NEW_MEMBUFP(MemBuf128);
+	break;
+    case 256:
+	NEW_MEMBUFP(MemBuf256);
+	break;
+    case 512:
+	NEW_MEMBUFP(MemBuf512);
+	break;
+    case 1024:
+	NEW_MEMBUFP(MemBuf1K);
+	break;
     case 2048:
-	mb->buf = memAllocate(MEM_2K_BUF);
-	mb->freefunc = &memFree2K;
+	NEW_MEMBUFP(MemBuf2K);
 	break;
     case 4096:
-	mb->buf = memAllocate(MEM_4K_BUF);
-	mb->freefunc = &memFree4K;
+	NEW_MEMBUFP(MemBuf4K);
 	break;
     case 8192:
-	mb->buf = memAllocate(MEM_8K_BUF);
-	mb->freefunc = &memFree8K;
+	NEW_MEMBUFP(MemBuf8K);
 	break;
     case 16384:
-	mb->buf = memAllocate(MEM_16K_BUF);
-	mb->freefunc = &memFree16K;
+	NEW_MEMBUFP(MemBuf16K);
 	break;
     case 32768:
-	mb->buf = memAllocate(MEM_32K_BUF);
-	mb->freefunc = &memFree32K;
+	NEW_MEMBUFP(MemBuf32K);
 	break;
     case 65536:
-	mb->buf = memAllocate(MEM_64K_BUF);
-	mb->freefunc = &memFree64K;
+	NEW_MEMBUFP(MemBuf64K);
 	break;
     default:
-	/* recycle if old buffer was not "pool"ed */
-	if (old_mb.freefunc == &xfree) {
-	    mb->buf = xrealloc(old_mb.buf, new_cap);
-	    old_mb.buf = NULL;
-	    old_mb.freefunc = NULL;
-	    /* init tail, just in case */
-	    memset(mb->buf + mb->size, 0, new_cap - mb->size);
-	} else {
-	    mb->buf = xcalloc(1, new_cap);
-	    mb->freefunc = &xfree;
+	{
+	    MemBufLarge *new_bufp = cbdataAlloc(MemBufLarge);
+	    new_bufp->buf = xmalloc(new_cap);
+	    mb->bufp = (char **)new_bufp; \
 	}
     }
 
-    /* copy and free old buffer if needed */
-    if (old_mb.buf && old_mb.freefunc) {
-	xmemcpy(mb->buf, old_mb.buf, old_mb.size);
-	(*old_mb.freefunc) (old_mb.buf);
-    } else {
-	assert(!old_mb.buf && !old_mb.freefunc);
+    if (old_bufp) {
+	/* copy old buffer */
+	xmemcpy(*mb->bufp, *old_bufp, mb->size);
+	cbdataUnreference(old_bufp);
     }
 
+    /* init tail, just in case */
+    memset(*mb->bufp + mb->size, 0, new_cap - mb->size);
+
     /* done */
     mb->capacity = new_cap;
 }
-
-
-/* Reports */
-
-/* puts report on MemBuf _module_ usage into mb */
-void
-memBufReport(MemBuf * mb)
-{
-    assert(mb);
-    memBufPrintf(mb, "memBufReport is not yet implemented @?@\n");
-}
Index: squid/src/MemPool.c
diff -u squid/src/MemPool.c:1.6 squid/src/MemPool.c:1.5.12.3
--- squid/src/MemPool.c:1.6	Wed Oct 24 02:42:11 2001
+++ squid/src/MemPool.c	Sat Nov 17 05:11:57 2001
@@ -159,10 +159,10 @@
 
 static void
 memPoolMeterReport(const MemPoolMeter * pm, size_t obj_size,
-    int alloc_count, int inuse_count, int idle_count, StoreEntry * e)
+    int alloc_count, int inuse_count, int idle_count, MemBuf *out)
 {
     assert(pm);
-    storeAppendPrintf(e, "%d\t %ld\t %ld\t %.2f\t %d\t %d\t %ld\t %ld\t %d\t %d\t %ld\t %ld\t %ld\t %.2f\t %.2f\t %.2f\t %ld\n",
+    memBufPrintf(out, "%d\t %ld\t %ld\t %.2f\t %d\t %d\t %ld\t %ld\t %d\t %d\t %ld\t %ld\t %ld\t %.2f\t %.2f\t %.2f\t %ld\n",
     /* alloc */
 	alloc_count,
 	(long int) toKB(obj_size * pm->alloc.level),
@@ -323,29 +323,31 @@
     return TheMeter.alloc.level;
 }
 
-void
-memPoolReport(const MemPool * pool, StoreEntry * e)
+static void
+memPoolReport(const MemPool * pool, MemBuf *out)
 {
     assert(pool);
-    storeAppendPrintf(e, "%-20s\t %4d\t ",
+    memBufPrintf(out, "%-20s\t %4d\t ",
 	pool->label, (int) pool->obj_size);
     memPoolMeterReport(&pool->meter, pool->obj_size,
 	pool->meter.alloc.level, pool->meter.inuse.level, pool->meter.idle.level,
-	e);
+	out);
 }
 
-void
-memReport(StoreEntry * e)
+IOBuf *
+memReport(void)
 {
+    IOBuf *out;
     size_t overhd_size = 0;
     int alloc_count = 0;
     int inuse_count = 0;
     int idle_count = 0;
     int i;
+    out = IOBufAlloc(8192);
     /* caption */
-    storeAppendPrintf(e, "Current memory usage:\n");
+    memBufPrintf(out, "Current memory usage:\n");
     /* heading */
-    storeAppendPrintf(e, "Pool\t Obj Size\t"
+    memBufPrintf(out, "Pool\t Obj Size\t"
 	"Allocated\t\t\t\t\t In Use\t\t\t\t Idle\t\t\t Allocations Saved\t\t\t Hit Rate\t\n"
 	" \t (bytes)\t"
 	"(#)\t (KB)\t high (KB)\t high (hrs)\t impact (%%total)\t"
@@ -359,7 +361,7 @@
     for (i = 0; i < Pools.count; i++) {
 	const MemPool *pool = Pools.items[i];
 	if (memPoolWasUsed(pool)) {
-	    memPoolReport(pool, e);
+	    memPoolReport(pool, out);
 	    alloc_count += pool->meter.alloc.level;
 	    inuse_count += pool->meter.inuse.level;
 	    idle_count += pool->meter.idle.level;
@@ -370,14 +372,53 @@
     }
     overhd_size += sizeof(Pools) + Pools.capacity * sizeof(MemPool *);
     /* totals */
-    storeAppendPrintf(e, "%-20s\t %-4s\t ", "Total", "-");
-    memPoolMeterReport(&TheMeter, 1, alloc_count, inuse_count, idle_count, e);
-    storeAppendPrintf(e, "Cumulative allocated volume: %s\n", gb_to_str(&mem_traffic_volume));
+    memBufPrintf(out, "%-20s\t %-4s\t ", "Total", "-");
+    memPoolMeterReport(&TheMeter, 1, alloc_count, inuse_count, idle_count, out);
+    memBufPrintf(out, "Cumulative allocated volume: %s\n", gb_to_str(&mem_traffic_volume));
     /* overhead */
-    storeAppendPrintf(e, "Current overhead: %ld bytes (%.3f%%)\n",
+    memBufPrintf(out, "Current overhead: %ld bytes (%.3f%%)\n",
 	(long int) overhd_size, xpercent(overhd_size, TheMeter.inuse.level));
     /* limits */
-    storeAppendPrintf(e, "Idle pool limit: %.2f MB\n", toMB(mem_idle_limit));
-    storeAppendPrintf(e, "memPoolAlloc calls: %d\n", mem_pool_alloc_calls);
-    storeAppendPrintf(e, "memPoolFree calls: %d\n", mem_pool_free_calls);
+    memBufPrintf(out, "Idle pool limit: %.2f MB\n", toMB(mem_idle_limit));
+    memBufPrintf(out, "memPoolAlloc calls: %d\n", mem_pool_alloc_calls);
+    memBufPrintf(out, "memPoolFree calls: %d\n", mem_pool_free_calls);
+    return out;
 }
+
+void
+gb_flush(gb_t * g)
+{
+    g->gb += (g->bytes >> 30);
+    g->bytes &= (1 << 30) - 1;
+}
+
+double
+gb_to_double(const gb_t * g)
+{
+    return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes);
+}
+
+const char *
+gb_to_str(const gb_t * g)
+{
+    /*
+     * it is often convenient to call gb_to_str several times for _one_ printf
+     */
+#define max_cc_calls 5
+    typedef char GbBuf[32];
+    static GbBuf bufs[max_cc_calls];
+    static int call_id = 0;
+    double value = gb_to_double(g);
+    char *buf = bufs[call_id++];
+    if (call_id >= max_cc_calls)
+	call_id = 0;
+    /* select format */
+    if (value < 1e9)
+	snprintf(buf, sizeof(GbBuf), "%.2f MB", value / 1e6);
+    else if (value < 1e12)
+	snprintf(buf, sizeof(GbBuf), "%.2f GB", value / 1e9);
+    else
+	snprintf(buf, sizeof(GbBuf), "%.2f TB", value / 1e12);
+    return buf;
+}
+
Index: squid/src/acl.c
diff -u squid/src/acl.c:1.42 squid/src/acl.c:1.21.8.7
--- squid/src/acl.c:1.42	Tue Nov 13 14:19:33 2001
+++ squid/src/acl.c	Sat Nov 17 05:11:57 2001
@@ -2287,7 +2287,7 @@
 	memBufPrintf(&mb, "-%s", inet_ntoa(ip->addr2));
     if (ip->mask.s_addr != no_addr.s_addr)
 	memBufPrintf(&mb, "/%s", inet_ntoa(ip->mask));
-    wordlistAdd(W, mb.buf);
+    wordlistAdd(W, *mb.bufp);
     memBufClean(&mb);
 }
 
Index: squid/src/asn.c
diff -u squid/src/asn.c:1.15 squid/src/asn.c:1.9.8.3
--- squid/src/asn.c:1.15	Tue Nov 13 14:19:33 2001
+++ squid/src/asn.c	Sat Nov 17 05:11:57 2001
@@ -199,7 +199,7 @@
     if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
 	e = storeCreateEntry(asres, asres, null_request_flags, METHOD_GET);
 	asState->sc = storeClientListAdd(e, asState);
-	fwdStart(-1, e, asState->request);
+	fwdStart(NULL, e, asState->request);
     } else {
 	storeLockObject(e);
 	asState->sc = storeClientListAdd(e, asState);
Index: squid/src/authenticate.c
diff -u squid/src/authenticate.c:1.22 squid/src/authenticate.c:1.12.8.4
--- squid/src/authenticate.c:1.22	Sat Oct 27 03:15:54 2001
+++ squid/src/authenticate.c	Sat Nov 17 05:11:57 2001
@@ -487,8 +487,8 @@
      * not had bungled connection oriented authentication happen on it. */
     debug(28, 9) ("authenticateAuthenticate: header %s.\n", proxy_auth);
     if (*auth_user_request == NULL) {
-	debug(28, 9) ("authenticateAuthenticate: This is a new checklist test on FD:%d\n",
-	    conn->fd);
+	debug(28, 9) ("authenticateAuthenticate: This is a new checklist test on FH:%p\n",
+	    conn->fh);
 	if ((!request->auth_user_request)
 	    && (conn->auth_type == AUTH_UNKNOWN)) {
 	    /* beginning of a new request check */
Index: squid/src/cache_cf.c
diff -u squid/src/cache_cf.c:1.38 squid/src/cache_cf.c:1.18.8.8
--- squid/src/cache_cf.c:1.38	Wed Oct 24 02:42:12 2001
+++ squid/src/cache_cf.c	Sat Nov 17 05:11:57 2001
@@ -114,70 +114,6 @@
 }
 
 void
-wordlistDestroy(wordlist ** list)
-{
-    wordlist *w = NULL;
-    while ((w = *list) != NULL) {
-	*list = w->next;
-	safe_free(w->key);
-	memFree(w, MEM_WORDLIST);
-    }
-    *list = NULL;
-}
-
-const char *
-wordlistAdd(wordlist ** list, const char *key)
-{
-    while (*list)
-	list = &(*list)->next;
-    *list = memAllocate(MEM_WORDLIST);
-    (*list)->key = xstrdup(key);
-    (*list)->next = NULL;
-    return (*list)->key;
-}
-
-void
-wordlistJoin(wordlist ** list, wordlist ** wl)
-{
-    while (*list)
-	list = &(*list)->next;
-    *list = *wl;
-    *wl = NULL;
-}
-
-void
-wordlistAddWl(wordlist ** list, wordlist * wl)
-{
-    while (*list)
-	list = &(*list)->next;
-    for (; wl; wl = wl->next, list = &(*list)->next) {
-	*list = memAllocate(MEM_WORDLIST);
-	(*list)->key = xstrdup(wl->key);
-	(*list)->next = NULL;
-    }
-}
-
-void
-wordlistCat(const wordlist * w, MemBuf * mb)
-{
-    while (NULL != w) {
-	memBufPrintf(mb, "%s\n", w->key);
-	w = w->next;
-    }
-}
-
-wordlist *
-wordlistDup(const wordlist * w)
-{
-    wordlist *D = NULL;
-    while (NULL != w) {
-	wordlistAdd(&D, w->key);
-	w = w->next;
-    }
-    return D;
-}
-
-void
 intlistDestroy(intlist ** list)
 {
     intlist *w = NULL;
@@ -285,9 +221,6 @@
     memset(&Config2, '\0', sizeof(SquidConfig2));
     /* init memory as early as possible */
     memConfigure();
-    /* Sanity checks */
-    if (Config.cacheSwap.swapDirs == NULL)
-	fatal("No cache_dir's specified in config file");
     /* calculate Config.Swap.maxSize */
     storeDirConfigure();
     if (0 == Config.Swap.maxSize)
@@ -2227,6 +2160,7 @@
 	    self_destruct();
 	}
 	s = xcalloc(1, sizeof(*s));
+	s->s.sin_family = AF_INET;
 	s->s.sin_port = htons(port);
 	if (NULL == host)
 	    s->s.sin_addr = any_addr;
Index: squid/src/cache_manager.c
diff -u squid/src/cache_manager.c:1.7 squid/src/cache_manager.c:1.6.12.2
--- squid/src/cache_manager.c:1.7	Fri Feb 23 13:03:30 2001
+++ squid/src/cache_manager.c	Wed Sep 12 14:16:47 2001
@@ -192,7 +192,7 @@
 }
 
 void
-cachemgrStart(int fd, request_t * request, StoreEntry * entry)
+cachemgrStart(request_t * request, StoreEntry * entry)
 {
     cachemgrStateData *mgr = NULL;
     ErrorState *err = NULL;
@@ -209,7 +209,7 @@
     storeLockObject(entry);
     entry->expires = squid_curtime;
     debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
-	fd_table[fd].ipaddr, mgr->action);
+	inet_ntoa(request->client_addr), mgr->action);
     /* get additional info from request headers */
     cachemgrParseHeaders(mgr, request);
     /* Check password */
@@ -222,11 +222,11 @@
 	if (mgr->passwd)
 	    debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n",
 		mgr->user_name ? mgr->user_name : "<unknown>",
-		fd_table[fd].ipaddr, mgr->action);
+		inet_ntoa(request->client_addr), mgr->action);
 	else
 	    debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n",
 		mgr->user_name ? mgr->user_name : "<unknown>",
-		fd_table[fd].ipaddr, mgr->action);
+		inet_ntoa(request->client_addr), mgr->action);
 	err->request = requestLink(request);
 	rep = errorBuildReply(err);
 	errorStateFree(err);
@@ -246,7 +246,7 @@
     }
     debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n",
 	mgr->user_name ? mgr->user_name : "<unknown>",
-	fd_table[fd].ipaddr, mgr->action);
+	inet_ntoa(request->client_addr), mgr->action);
     /* retrieve object requested */
     a = cachemgrFindAction(mgr->action);
     assert(a != NULL);
Index: squid/src/cbdata.c
diff -u squid/src/cbdata.c:1.14 squid/src/cbdata.c:1.9.8.6
--- squid/src/cbdata.c:1.14	Thu Oct 18 13:52:11 2001
+++ squid/src/cbdata.c	Sat Nov 17 05:11:58 2001
@@ -84,12 +84,10 @@
     } data;
 } cbdata;
 
-static OBJH cbdataDump;
-
 struct {
     MemPool *pool;
     FREE *free_func;
-}     *cbdata_index = NULL;
+} *cbdata_index = NULL;
 int cbdata_types = 0;
 
 #define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member)
@@ -127,9 +125,6 @@
 cbdataInit(void)
 {
     debug(45, 3) ("cbdataInit\n");
-    cachemgrRegister("cbdata",
-	"Callback Data Registry Contents",
-	cbdataDump, 0, 1);
 #define CREATE_CBDATA(type) cbdataInitType(CBDATA_##type, #type, sizeof(type), NULL)
 #define CREATE_CBDATA_FREE(type, free_func) cbdataInitType(CBDATA_##type, #type, sizeof(type), free_func)
     CREATE_CBDATA(acl_access);
@@ -274,10 +269,3 @@
     assert(c->locks > 0);
     return c->valid;
 }
-
-static void
-cbdataDump(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
-    storeAppendPrintf(sentry, "see also memory pools section\n");
-}
Index: squid/src/client_side.c
diff -u squid/src/client_side.c:1.45 squid/src/client_side.c:1.19.2.12
--- squid/src/client_side.c:1.45	Sun Nov 18 10:57:17 2001
+++ squid/src/client_side.c	Wed Nov 21 18:19:01 2001
@@ -35,38 +35,6 @@
 
 #include "squid.h"
 
-#if IPF_TRANSPARENT
-#if HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#include <netinet/tcp.h>
-#include <net/if.h>
-#if HAVE_IP_FIL_COMPAT_H
-#include <ip_fil_compat.h>
-#elif HAVE_NETINET_IP_FIL_COMPAT_H
-#include <netinet/ip_fil_compat.h>
-#elif HAVE_IP_COMPAT_H
-#include <ip_compat.h>
-#elif HAVE_NETINET_IP_COMPAT_H
-#include <netinet/ip_compat.h>
-#endif
-#if HAVE_IP_FIL_H
-#include <ip_fil.h>
-#elif HAVE_NETINET_IP_FIL_H
-#include <netinet/ip_fil.h>
-#endif
-#if HAVE_IP_NAT_H
-#include <ip_nat.h>
-#elif HAVE_NETINET_IP_NAT_H
-#include <netinet/ip_nat.h>
-#endif
-#endif
-
-#if LINUX_NETFILTER
-#include <linux/netfilter_ipv4.h>
-#endif
-
-
 #if LINGERING_CLOSE
 #define comm_close comm_lingering_close
 #endif
@@ -77,19 +45,22 @@
 
 /* Local functions */
 
-static CWCB clientWriteComplete;
-static CWCB clientWriteBodyComplete;
-static PF clientReadRequest;
+static COMMIOCB clientWriteComplete;
+static COMMIOCB clientWriteBodyComplete;
+static COMMIOCB clientReadRequest;
+static void clientReadRequest2(ConnStateData * conn);
+#if NOT_YET_PORTED
 static PF connStateFree;
 static PF requestTimeout;
 static PF clientLifetimeTimeout;
+#endif
 static int clientCheckTransferDone(clientHttpRequest *);
 static int clientGotNotEnough(clientHttpRequest *);
 static void checkFailureRatio(err_type, hier_code);
 static void clientProcessMiss(clientHttpRequest *);
 static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep);
 static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
-static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, char **, size_t *);
+static clientHttpRequest *parseHttpRequest(ConnStateData *, char **, size_t *, method_t *, int *, char **, size_t *);
 static RH clientRedirectDone;
 static void clientCheckNoCache(clientHttpRequest *);
 static void clientCheckNoCacheDone(int answer, void *data);
@@ -112,7 +83,9 @@
 static int clientCachable(clientHttpRequest * http);
 static int clientHierarchical(clientHttpRequest * http);
 static int clientCheckContentLength(request_t * r);
+#if NOT_YET_PORTED
 static DEFER httpAcceptDefer;
+#endif
 static log_type clientProcessRequest2(clientHttpRequest * http);
 static int clientReplyBodyTooLarge(HttpReply *, ssize_t clen);
 static int clientRequestBodyTooLarge(int clen);
@@ -329,7 +302,7 @@
 #if HEADERS_LOG
     headersLog(0, 1, request->method, request);
 #endif
-    fd_note(http->conn->fd, http->uri);
+    ncomm_note(http->conn->fh, http->uri);
     clientCheckNoCache(http);
 }
 
@@ -393,7 +366,7 @@
     debug(33, 5) ("clientProcessExpired: lastmod %ld\n", (long int) entry->lastmod);
     http->entry = entry;
     http->out.offset = 0;
-    fwdStart(http->conn->fd, http->entry, http->request);
+    fwdStart(http->conn->fh, http->entry, http->request);
     /* Register with storage manager to receive updates when data comes in. */
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
 	debug(33, 0) ("clientProcessExpired: found ENTRY_ABORTED object\n");
@@ -793,7 +766,7 @@
 	    httpHeaderPackInto(&request->header, &p);
 	    http->al.http.method = request->method;
 	    http->al.http.version = request->http_ver;
-	    http->al.headers.request = xstrdup(mb.buf);
+	    http->al.headers.request = xstrdup(*mb.bufp);
 	    http->al.hier = request->hier;
 	    if (request->auth_user_request) {
 		http->al.cache.authuser = xstrdup(authenticateUserRequestUsername(request->auth_user_request));
@@ -850,13 +823,14 @@
     cbdataFree(http);
 }
 
+#if NOT_YET_PORTED
 /* This is a handler normally called by comm_close() */
 static void
-connStateFree(int fd, void *data)
+connStateFree(filehandle *fh, void *data)
 {
     ConnStateData *connState = data;
     clientHttpRequest *http;
-    debug(33, 3) ("connStateFree: FD %d\n", fd);
+    debug(33, 3) ("connStateFree: FH %p\n", fh);
     assert(connState != NULL);
     clientdbEstablished(connState->peer.sin_addr, -1);	/* decrement */
     while ((http = connState->chr) != NULL) {
@@ -868,21 +842,11 @@
 	authenticateAuthUserRequestUnlock(connState->auth_user_request);
     connState->auth_user_request = NULL;
     authenticateOnCloseConnection(connState);
-    if (connState->in.size == CLIENT_REQ_BUF_SZ)
-	memFree(connState->in.buf, MEM_CLIENT_REQ_BUF);
-    else
-	safe_free(connState->in.buf);
-    /* XXX account connState->in.buf */
+    cbdataUnreference(connState->in);
     pconnHistCount(0, connState->nrequests);
     cbdataFree(connState);
-#ifdef _SQUID_LINUX_
-    /* prevent those nasty RST packets */
-    {
-	char buf[SQUID_TCP_SO_RCVBUF];
-	while (FD_READ_METHOD(fd, buf, SQUID_TCP_SO_RCVBUF) > 0);
-    }
-#endif
 }
+#endif
 
 static void
 clientInterpretRequestHeaders(clientHttpRequest * http)
@@ -1584,8 +1548,8 @@
 	     */
 	    e->timestamp = timestamp;
 	    http->entry = e;
-	    httpReplyParse(e->mem_obj->reply, mb.buf, mb.size);
-	    storeAppend(e, mb.buf, mb.size);
+	    httpReplyParse(e->mem_obj->reply, *mb.bufp, mb.size);
+	    storeAppend(e, *mb.bufp, mb.size);
 	    memBufClean(&mb);
 	    storeComplete(e);
 	}
@@ -1826,7 +1790,6 @@
     clientHttpRequest *http = data;
     StoreEntry *entry = http->entry;
     ConnStateData *conn = http->conn;
-    int fd = conn->fd;
     HttpReply *rep = NULL;
     const char *body_buf = buf;
     ssize_t body_size = size;
@@ -1837,8 +1800,8 @@
     assert(http->request != NULL);
     dlinkDelete(&http->active, &ClientActiveRequests);
     dlinkAdd(http, &http->active, &ClientActiveRequests);
-    debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%ld \n",
-	fd, storeUrl(entry), (long int) http->out.offset);
+    debug(33, 5) ("clientSendMoreData: FH %p '%s', out.offset=%ld \n",
+	conn->fh, storeUrl(entry), (long int) http->out.offset);
     if (conn->chr != http) {
 	/* there is another object in progress, defer this one */
 	debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry));
@@ -1846,17 +1809,17 @@
 	return;
     } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
 	/* call clientWriteComplete so the client socket gets closed */
-	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
+	clientWriteComplete(conn->fh, NULL, 0, 0, 0, http);
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	return;
     } else if (size < 0) {
 	/* call clientWriteComplete so the client socket gets closed */
-	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
+	clientWriteComplete(conn->fh, NULL, 0, 0, 0, http);
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	return;
     } else if (size == 0) {
 	/* call clientWriteComplete so the client socket gets closed */
-	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
+	clientWriteComplete(conn->fh, NULL, 0, 0, 0, http);
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	return;
     }
@@ -1931,11 +1894,11 @@
 	/* reset range iterator */
 	http->range_iter.pos = HttpHdrRangeInitPos;
     } else if (!http->request->range) {
-	/* Avoid copying to MemBuf for non-range requests */
 	/* Note, if we're here, then 'rep' is known to be NULL */
+	IOBuf *iob = IOBufCreate(buf, size); /* should get an IOBuf from start... */
 	http->out.offset += body_size;
-	comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL);
-	/* NULL because clientWriteBodyComplete frees it */
+	ncomm_write(conn->fh, iob, clientWriteBodyComplete, http);
+	cbdataUnreference(iob);
 	return;
     }
     if (http->request->method == METHOD_HEAD) {
@@ -1986,7 +1949,7 @@
     if (!http->request->range && http->request->method == METHOD_GET)
 	assert(check_size == size);
     /* write */
-    comm_write_mbuf(fd, mb, clientWriteComplete, http);
+    ncomm_write_mbuf(conn->fh, mb, clientWriteComplete, http);
     /* if we don't do it, who will? */
     memFree(buf, MEM_CLIENT_SOCK_BUF);
 }
@@ -1998,14 +1961,13 @@
  * the headers probably go through here.
  */
 static void
-clientWriteBodyComplete(int fd, char *buf, size_t size, int errflag, void *data)
+clientWriteBodyComplete(filehandle *fh, IOBuf *buf, int offset, int size, int error, void *cbdata)
 {
     /*
      * NOTE: clientWriteComplete doesn't currently use its "buf"
      * (second) argument, so we pass in NULL.
      */
-    clientWriteComplete(fd, NULL, size, errflag, data);
-    memFree(buf, MEM_CLIENT_SOCK_BUF);
+    clientWriteComplete(fh, NULL, offset, size, error, cbdata);
 }
 
 static void
@@ -2013,28 +1975,19 @@
 {
     ConnStateData *conn = http->conn;
     StoreEntry *entry;
-    debug(33, 3) ("clientKeepaliveNextRequest: FD %d\n", conn->fd);
-    conn->defer.until = 0;	/* Kick it to read a new request */
+    debug(33, 3) ("clientKeepaliveNextRequest: FH %p\n", conn->fh);
     httpRequestFree(http);
     if ((http = conn->chr) == NULL) {
-	debug(33, 5) ("clientKeepaliveNextRequest: FD %d reading next req\n",
-	    conn->fd);
-	fd_note(conn->fd, "Waiting for next request");
+	debug(33, 5) ("clientKeepaliveNextRequest: FH %p reading next req\n",
+	    conn->fh);
+	ncomm_note(conn->fh, "Waiting for next request");
 	/*
 	 * Set the timeout BEFORE calling clientReadRequest().
 	 */
-	commSetTimeout(conn->fd, Config.Timeout.pconn, requestTimeout, conn);
-	/*
-	 * CYGWIN has a problem and is blocking on read() requests when there
-	 * is no data present.
-	 * This hack may hit performance a little, but it's better than 
-	 * blocking!.
-	 */
-#ifdef _SQUID_CYGWIN_
-	commSetSelect(conn->fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
-#else
-	clientReadRequest(conn->fd, conn);	/* Read next request */
+#if NOT_YET_PORTED
+	commSetTimeout(conn->fh, Config.Timeout.pconn, requestTimeout, conn);
 #endif
+	clientReadRequest2(conn);	/* Read next request */
 	/*
 	 * Note, the FD may be closed at this point.
 	 */
@@ -2044,8 +1997,8 @@
 	 * execution will resume after the operation completes.
 	 */
     } else {
-	debug(33, 1) ("clientKeepaliveNextRequest: FD %d Sending next\n",
-	    conn->fd);
+	debug(33, 1) ("clientKeepaliveNextRequest: FH %p Sending next\n",
+	    conn->fh);
 	assert(entry);
 	if (0 == storeClientCopyPending(http->sc, entry, http)) {
 	    if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
@@ -2062,14 +2015,14 @@
 }
 
 static void
-clientWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
+clientWriteComplete(filehandle *fh, IOBuf *buf, int offset, int size, int errflag, void *data)
 {
     clientHttpRequest *http = data;
     StoreEntry *entry = http->entry;
     int done;
     http->out.size += size;
-    debug(33, 5) ("clientWriteComplete: FD %d, sz %ld, err %d, off %ld, len %d\n",
-	fd, (long int) size, errflag, (long int) http->out.offset, entry ? objectLen(entry) : 0);
+    debug(33, 5) ("clientWriteComplete: FH %p, sz %ld, err %d, off %ld, len %d\n",
+	fh, (long int)size, errflag, (long int) http->out.offset, entry ? objectLen(entry) : 0);
     if (size > 0) {
 	kb_incr(&statCounter.client_http.kbytes_out, size);
 	if (isTcpHit(http->log_type))
@@ -2079,31 +2032,31 @@
 	/*
 	 * just close the socket, httpRequestFree will abort if needed
 	 */
-	comm_close(fd);
+	ncomm_close(fh);
     } else if (NULL == entry) {
-	comm_close(fd);		/* yuk */
+	ncomm_close(fh);		/* yuk */
     } else if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	comm_close(fd);
+	ncomm_close(fh);
     } else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) {
-	debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd);
+	debug(33, 5) ("clientWriteComplete: FH %p transfer is DONE\n", fh);
 	/* We're finished case */
 	if (httpReplyBodySize(http->request->method, entry->mem_obj->reply) < 0) {
 	    debug(33, 5) ("clientWriteComplete: closing, content_length < 0\n");
-	    comm_close(fd);
+	    ncomm_close(fh);
 	} else if (!done) {
 	    debug(33, 5) ("clientWriteComplete: closing, !done\n");
-	    comm_close(fd);
+	    ncomm_close(fh);
 	} else if (clientGotNotEnough(http)) {
 	    debug(33, 5) ("clientWriteComplete: client didn't get all it expected\n");
-	    comm_close(fd);
+	    ncomm_close(fh);
 	} else if (http->request->flags.proxy_keepalive) {
-	    debug(33, 5) ("clientWriteComplete: FD %d Keeping Alive\n", fd);
+	    debug(33, 5) ("clientWriteComplete: FH %p Keeping Alive\n", fh);
 	    clientKeepaliveNextRequest(http);
 	} else {
-	    comm_close(fd);
+	    ncomm_close(fh);
 	}
     } else if (clientReplyBodyTooLarge(entry->mem_obj->reply, http->out.offset)) {
-	comm_close(fd);
+	ncomm_close(fh);
     } else {
 	/* More data will be coming from primary server; register with 
 	 * storage manager. */
@@ -2269,7 +2222,7 @@
 {
     char *url = http->uri;
     request_t *r = http->request;
-    int fd = http->conn->fd;
+    filehandle *fh = http->conn->fh;
     HttpReply *rep;
     http_version_t version;
     debug(33, 4) ("clientProcessRequest: %s '%s'\n",
@@ -2277,7 +2230,7 @@
 	url);
     if (r->method == METHOD_CONNECT) {
 	http->log_type = LOG_TCP_MISS;
-	sslStart(fd, url, r, &http->out.size, &http->al.http.code);
+	sslStart(fh, url, r, &http->out.size, &http->al.http.code);
 	return;
     } else if (r->method == METHOD_PURGE) {
 	clientPurgeRequest(http);
@@ -2389,7 +2342,7 @@
     }
     if (http->flags.internal)
 	r->protocol = PROTO_INTERNAL;
-    fwdStart(http->conn->fd, http->entry, r);
+    fwdStart(http->conn->fh, http->entry, r);
 }
 
 static clientHttpRequest *
@@ -2399,7 +2352,6 @@
     http = cbdataAlloc(clientHttpRequest);
     http->conn = conn;
     http->start = current_time;
-    http->req_sz = conn->in.offset;
     http->uri = xstrdup(uri);
     http->log_uri = xstrndup(uri, MAX_URL);
     http->range_iter.boundary = StringNull;
@@ -2415,10 +2367,10 @@
  *    a clientHttpRequest structure on success
  */
 static clientHttpRequest *
-parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
-    char **prefix_p, size_t * req_line_sz_p)
+parseHttpRequest(ConnStateData * conn, char ** buf_p, size_t *size_p, method_t * method_p, int *status, char **prefix_p, size_t * req_line_sz_p)
 {
-    char *inbuf = NULL;
+    char *inbuf;
+    char *buf = *buf_p;
     char *mstr = NULL;
     char *url = NULL;
     char *req_hdr = NULL;
@@ -2432,32 +2384,28 @@
     size_t req_sz;
     method_t method;
     clientHttpRequest *http = NULL;
-#if IPF_TRANSPARENT
-    struct natlookup natLookup;
-    static int natfd = -1;
-    static int siocgnatl_cmd = SIOCGNATL & 0xff;
-    int x;
-#endif
-#if LINUX_NETFILTER
-    size_t sock_sz = sizeof(conn->me);
-#endif
 
-    /* pre-set these values to make aborting simpler */
-    *prefix_p = NULL;
-    *method_p = METHOD_NONE;
-    *status = -1;
-
-    if ((req_sz = headersEnd(conn->in.buf, conn->in.offset)) == 0) {
+    if ((req_sz = headersEnd(*buf_p, *size_p)) == 0) {
 	debug(33, 5) ("Incomplete request, waiting for end of headers\n");
 	*status = 0;
 	return NULL;
     }
-    assert(req_sz <= conn->in.offset);
-    /* Use memcpy, not strdup! */
+    assert(req_sz <= *size_p);
+
+    /* Make a temporary (terminated) copy of the request line and headers */
     inbuf = xmalloc(req_sz + 1);
-    xmemcpy(inbuf, conn->in.buf, req_sz);
+    xmemcpy(inbuf, *buf_p, req_sz);
     *(inbuf + req_sz) = '\0';
 
+    /* Eat up the request line and headers from the input */
+    *buf_p += req_sz;
+    *size_p -= req_sz;
+
+    /* pre-set these values to make aborting simpler */
+    *prefix_p = inbuf;
+    *method_p = METHOD_NONE;
+    *status = -1;
+
     /* Barf on NULL characters in the headers */
     if (strlen(inbuf) != req_sz) {
 	debug(33, 1) ("parseHttpRequest: Requestheader contains NULL characters\n");
@@ -2537,7 +2485,7 @@
     *req_line_sz_p = req_hdr - inbuf;
     debug(33, 3) ("parseHttpRequest: prefix_sz = %d, req_line_sz = %d\n",
 	(int) prefix_sz, (int) *req_line_sz_p);
-    assert(prefix_sz <= conn->in.offset);
+    assert(prefix_sz == req_sz);
 
     /* Ok, all headers are received */
     http = cbdataAlloc(clientHttpRequest);
@@ -2547,7 +2495,7 @@
     http->req_sz = prefix_sz;
     http->range_iter.boundary = StringNull;
     *prefix_p = xmalloc(prefix_sz + 1);
-    xmemcpy(*prefix_p, conn->in.buf, prefix_sz);
+    xmemcpy(*prefix_p, buf, prefix_sz);
     *(*prefix_p + prefix_sz) = '\0';
     dlinkAdd(http, &http->active, &ClientActiveRequests);
 
@@ -2611,75 +2559,6 @@
 		vport = (int) ntohs(http->conn->me.sin_port);
 	    else
 		vport = (int) Config.Accel.port;
-#if IPF_TRANSPARENT
-	    natLookup.nl_inport = http->conn->me.sin_port;
-	    natLookup.nl_outport = http->conn->peer.sin_port;
-	    natLookup.nl_inip = http->conn->me.sin_addr;
-	    natLookup.nl_outip = http->conn->peer.sin_addr;
-	    natLookup.nl_flags = IPN_TCP;
-	    if (natfd < 0) {
-		int save_errno;
-		enter_suid();
-		natfd = open(IPL_NAT, O_RDONLY, 0);
-		save_errno = errno;
-		leave_suid();
-		errno = save_errno;
-	    }
-	    if (natfd < 0) {
-		debug(50, 1) ("parseHttpRequest: NAT open failed: %s\n",
-		    xstrerror());
-		dlinkDelete(&http->active, &ClientActiveRequests);
-		xfree(http->uri);
-		cbdataFree(http);
-		xfree(inbuf);
-		return parseHttpRequestAbort(conn, "error:nat-open-failed");
-	    }
-	    /*
-	     * IP-Filter changed the type for SIOCGNATL between
-	     * 3.3 and 3.4.  It also changed the cmd value for
-	     * SIOCGNATL, so at least we can detect it.  We could
-	     * put something in configure and use ifdefs here, but
-	     * this seems simpler.
-	     */
-	    if (63 == siocgnatl_cmd) {
-		struct natlookup *nlp = &natLookup;
-		x = ioctl(natfd, SIOCGNATL, &nlp);
-	    } else {
-		x = ioctl(natfd, SIOCGNATL, &natLookup);
-	    }
-	    if (x < 0) {
-		if (errno != ESRCH) {
-		    debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)\n");
-		    close(natfd);
-		    natfd = -1;
-		    dlinkDelete(&http->active, &ClientActiveRequests);
-		    xfree(http->uri);
-		    cbdataFree(http);
-		    xfree(inbuf);
-		    return parseHttpRequestAbort(conn, "error:nat-lookup-failed");
-		} else
-		    snprintf(http->uri, url_sz, "http://%s:%d%s",
-			inet_ntoa(http->conn->me.sin_addr),
-			vport, url);
-	    } else {
-		if (vport_mode)
-		    vport = natLookup.nl_realport;
-		snprintf(http->uri, url_sz, "http://%s:%d%s",
-		    inet_ntoa(natLookup.nl_realip),
-		    vport, url);
-	    }
-#else
-#if LINUX_NETFILTER
-	    /* If the call fails the address structure will be unchanged */
-	    getsockopt(conn->fd, SOL_IP, SO_ORIGINAL_DST, &conn->me, &sock_sz);
-	    debug(33, 5) ("parseHttpRequest: addr = %s", inet_ntoa(conn->me.sin_addr));
-	    if (vport_mode)
-		vport = (int) ntohs(http->conn->me.sin_port);
-#endif
-	    snprintf(http->uri, url_sz, "http://%s:%d%s",
-		inet_ntoa(http->conn->me.sin_addr),
-		vport, url);
-#endif
 	    debug(33, 5) ("VHOST REWRITE: '%s'\n", http->uri);
 	} else {
 	    url_sz = strlen(Config2.Accel.prefix) + strlen(url) +
@@ -2705,6 +2584,7 @@
     return http;
 }
 
+#if OLD_COMM_CODE
 static int
 clientReadDefer(int fdnotused, void *data)
 {
@@ -2714,8 +2594,220 @@
     else
 	return conn->defer.until > squid_curtime;
 }
+#endif
 
 static void
+clientReadRequest2(ConnStateData * conn)
+{
+    filehandle *fh = conn->fh;
+    request_t *request;
+
+    /* Process request body if any */
+    if (conn->body.callback != NULL)
+	clientProcessBody(conn);
+    
+    while (conn->in && conn->body.size_left == 0) {
+	clientHttpRequest **H, *http;
+	int nrequests;
+	method_t method;
+	char *prefix;
+	int parser_return_code;
+	char *buf = IOBufP(conn->in);
+	size_t size = IOBufSize(conn->in);
+	size_t req_line_sz;
+	/* Skip leading (and trailing) whitespace */
+	while (size > 0 && xisspace(*buf)) {
+	    buf++;
+	    size--;
+	}
+	if (size == 0)
+	    break;
+	/* Limit the number of concurrent requests to 2 */
+	for (H = &conn->chr, nrequests = 0; *H; H = &(*H)->next, nrequests++);
+	if (nrequests >= (Config.onoff.pipeline_prefetch ? 2 : 1)) {
+	    debug(33, 3) ("clientReadRequest: FH %p max concurrent requests reached\n", fh);
+	    debug(33, 5) ("clientReadRequest: FH %p defering new request until one is done\n", fh);
+	    return;
+	}
+	if (nrequests == 0)
+	    ncomm_note(conn->fh, "Reading next request");
+	/* Process request */
+	http = parseHttpRequest(conn,
+	    &buf,
+	    &size,
+	    &method,
+	    &parser_return_code,
+	    &prefix,
+	    &req_line_sz);
+	if (!http)
+	    safe_free(prefix);
+	if (http) {
+	    IOBuf *newbuf = NULL;
+	    assert(http->req_sz > 0);
+	    assert(size >= 0);
+	    /*
+	     * If we read past the end of this request, move the remaining
+	     * data to the beginning
+	     */
+	    if (size > 0)
+		newbuf = IOBufCreate(buf, size);
+	    cbdataUnreference(conn->in);
+	    conn->in = cbdataReference(newbuf);
+	    cbdataUnreference(newbuf);
+
+	    /* add to the client request queue */
+	    for (H = &conn->chr; *H; H = &(*H)->next);
+	    *H = http;
+	    conn->nrequests++;
+	    /*
+	     * I wanted to lock 'http' here since its callback data for 
+	     * clientLifetimeTimeout(), but there's no logical place to
+	     * cbdataUnlock if the timeout never happens.  Maybe its safe
+	     * enough to assume that if the FD is open, and the timeout
+	     * triggers, that 'http' is valid.
+	     */
+#if NOT_YET_PORTED
+	    commSetTimeout(fh, Config.Timeout.lifetime, clientLifetimeTimeout, http);
+#endif
+	    if (parser_return_code < 0) {
+		ErrorState *err;
+		debug(33, 1) ("clientReadRequest: FH %p Invalid Request\n", fh);
+		err = errorCon(ERR_INVALID_REQ, HTTP_BAD_REQUEST);
+		err->request_hdrs = xstrdup(buf); /* XXX NULL termination! */
+		http->entry = clientCreateStoreEntry(http, method, null_request_flags);
+		errorAppendEntry(http->entry, err);
+		safe_free(prefix);
+		break;
+	    }
+	    if ((request = urlParse(method, http->uri)) == NULL) {
+		ErrorState *err;
+		debug(33, 5) ("Invalid URL: %s\n", http->uri);
+		err = errorCon(ERR_INVALID_URL, HTTP_BAD_REQUEST);
+		err->src_addr = conn->peer.sin_addr;
+		err->url = xstrdup(http->uri);
+		http->al.http.code = err->http_status;
+		http->entry = clientCreateStoreEntry(http, method, null_request_flags);
+		errorAppendEntry(http->entry, err);
+		safe_free(prefix);
+		break;
+	    } else {
+		/* compile headers */
+		/* we should skip request line! */
+		if (!httpRequestParseHeader(request, prefix + req_line_sz))
+		    debug(33, 1) ("Failed to parse request headers: %s\n%s\n",
+			http->uri, prefix);
+		/* continue anyway? */
+	    }
+	    request->flags.accelerated = http->flags.accel;
+	    if (!http->flags.internal) {
+		if (internalCheck(strBuf(request->urlpath))) {
+		    if (internalHostnameIs(request->host) &&
+			request->port == ntohs(Config.Sockaddr.http->s.sin_port)) {
+			http->flags.internal = 1;
+		    } else if (internalStaticCheck(strBuf(request->urlpath))) {
+			xstrncpy(request->host, internalHostname(), SQUIDHOSTNAMELEN);
+			request->port = ntohs(Config.Sockaddr.http->s.sin_port);
+			http->flags.internal = 1;
+		    }
+		}
+	    }
+	    /*
+	     * cache the Content-length value in request_t.
+	     */
+	    request->content_length = httpHeaderGetInt(&request->header,
+		HDR_CONTENT_LENGTH);
+	    request->flags.internal = http->flags.internal;
+	    safe_free(prefix);
+	    safe_free(http->log_uri);
+	    http->log_uri = xstrdup(urlCanonicalClean(request));
+	    request->client_addr = conn->peer.sin_addr;
+	    request->my_addr = conn->me.sin_addr;
+	    request->my_port = ntohs(conn->me.sin_port);
+	    request->http_ver = http->http_ver;
+	    if (!urlCheckRequest(request)) {
+		ErrorState *err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
+		err->src_addr = conn->peer.sin_addr;
+		err->request = requestLink(request);
+		request->flags.proxy_keepalive = 0;
+		http->al.http.code = err->http_status;
+		http->entry = clientCreateStoreEntry(http, request->method, null_request_flags);
+		errorAppendEntry(http->entry, err);
+		break;
+	    }
+	    if (!clientCheckContentLength(request)) {
+		ErrorState *err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
+		err->src_addr = conn->peer.sin_addr;
+		err->request = requestLink(request);
+		http->al.http.code = err->http_status;
+		http->entry = clientCreateStoreEntry(http, request->method, null_request_flags);
+		errorAppendEntry(http->entry, err);
+		break;
+	    }
+	    http->request = requestLink(request);
+	    clientSetKeepaliveFlag(http);
+	    /* Do we expect a request-body? */
+	    if (request->content_length > 0) {
+		conn->body.size_left = request->content_length;
+		request->body_connection = conn;
+		/* Is it too large? */
+		if (clientRequestBodyTooLarge(request->content_length)) {
+		    ErrorState *err = errorCon(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE);
+		    err->request = requestLink(request);
+		    http->entry = clientCreateStoreEntry(http,
+			METHOD_NONE, null_request_flags);
+		    errorAppendEntry(http->entry, err);
+		    break;
+		}
+	    }
+	    clientAccessCheck(http);
+	    continue;		/* while offset > 0 && body.size_left == 0 */
+	} else if (parser_return_code == 0) {
+	    /*
+	     *    Partial request received; reschedule until parseHttpRequest()
+	     *    is happy with the input
+	     */
+	    if (size >= Config.maxRequestHeaderSize) {
+		ErrorState *err;
+		/* The request is too large to handle */
+		debug(33, 1) ("Request header is too large (%d bytes)\n",
+		    (int) size);
+		debug(33, 1) ("Config 'request_header_max_size'= %d bytes.\n",
+		    Config.maxRequestHeaderSize);
+		err = errorCon(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE);
+		http = parseHttpRequestAbort(conn, "error:request-too-large");
+		/* add to the client request queue */
+		for (H = &conn->chr; *H; H = &(*H)->next);
+		*H = http;
+		http->entry = clientCreateStoreEntry(http, METHOD_NONE, null_request_flags);
+		errorAppendEntry(http->entry, err);
+		return;
+	    }
+	    break;
+	}
+    }				/* while offset > 0 && conn->body.size_left == 0 */
+    ncomm_read(fh, clientReadRequest, conn);
+}
+
+static void
+clientReadRequest(filehandle *fh, IOBuf *in, int offset, int size, int error, void *cbdata)
+{
+    ConnStateData *conn = cbdata;
+
+    kb_incr(&statCounter.client_http.kbytes_in, size);
+
+    /* TODO: error, EOF (size == 0) */
+
+    if (conn->in)
+	IOBufAppend(conn->in, IOBufP(in), size);
+    else
+	conn->in = cbdataReference(in);
+
+    clientReadRequest2(conn);
+}
+
+
+#if OLD_VERSION
+static void
 clientReadRequest(int fd, void *data)
 {
     ConnStateData *conn = data;
@@ -2821,7 +2913,7 @@
 	}
 	conn->in.buf[conn->in.offset] = '\0';	/* Terminate the string */
 	if (nrequests == 0)
-	    fd_note(conn->fd, "Reading next request");
+	    fd_note(conn->fh, "Reading next request");
 	/* Process request */
 	http = parseHttpRequest(conn,
 	    &method,
@@ -2976,6 +3068,7 @@
 	}
     }
 }
+#endif /* OLD_VERSION */
 
 /* file_read like function, for reading body content */
 void
@@ -2987,7 +3080,7 @@
 	callback(buf, 0, cbdata);	/* Signal end of body */
 	return;
     }
-    debug(33, 2) ("clientReadBody: start fd=%d body_size=%lu in.offset=%ld cb=%p req=%p\n", conn->fd, (unsigned long int) conn->body.size_left, (long int) conn->in.offset, callback, request);
+    debug(33, 2) ("clientReadBody: start fh=%p body_size=%lu size=%ld cb=%p req=%p\n", conn->fh, (unsigned long int) conn->body.size_left, (long int)IOBufSize(conn->in), callback, request);
     conn->body.callback = callback;
     conn->body.cbdata = cbdata;
     conn->body.buf = buf;
@@ -3000,31 +3093,37 @@
 static void
 clientProcessBody(ConnStateData * conn)
 {
-    int size;
+    int size, remaining;
     char *buf = conn->body.buf;
     void *cbdata = conn->body.cbdata;
     CBCB *callback = conn->body.callback;
     request_t *request = conn->body.request;
     /* Note: request is null while eating "aborted" transfers */
-    debug(33, 2) ("clientProcessBody: start fd=%d body_size=%lu in.offset=%ld cb=%p req=%p\n", conn->fd, (unsigned long int) conn->body.size_left, (long int) conn->in.offset, callback, request);
-    if (conn->in.offset) {
+    debug(33, 2) ("clientProcessBody: start fh=%p body_size=%ld size=%ld cb=%p req=%p\n", conn->fh, (unsigned long int)conn->body.size_left, (long int)IOBufSize(conn->in), callback, request);
+    if (conn->in) {
 	/* Some sanity checks... */
 	assert(conn->body.size_left > 0);
-	assert(conn->in.offset > 0);
+	assert(conn->in);
 	assert(callback != NULL);
 	assert(buf != NULL);
 	/* How much do we have to process? */
-	size = conn->in.offset;
+	size = IOBufSize(conn->in);
 	if (size > conn->body.size_left)	/* only process the body part */
 	    size = conn->body.size_left;
 	if (size > conn->body.bufsize)	/* don't copy more than requested */
 	    size = conn->body.bufsize;
-	xmemcpy(buf, conn->in.buf, size);
+	xmemcpy(buf, IOBufP(conn->in), size);
 	conn->body.size_left -= size;
 	/* Move any remaining data */
-	conn->in.offset -= size;
-	if (conn->in.offset > 0)
-	    xmemmove(conn->in.buf, conn->in.buf + size, conn->in.offset);
+	remaining = IOBufSize(conn->in) - size;
+	if (remaining) {
+	    IOBuf *newbuf = IOBufCreate(IOBufP(conn->in)+size, remaining);
+	    cbdataUnreference(conn->in);
+	    conn->in = cbdataReference(newbuf);
+	    cbdataUnreference(newbuf);
+	} else {
+	    cbdataUnreference(conn->in);
+	}
 	/* Remove request link if this is the last part of the body, as
 	 * clientReadRequest automatically continues to process next request */
 	if (conn->body.size_left <= 0 && request != NULL)
@@ -3041,7 +3140,7 @@
 	callback(buf, size, cbdata);
 	if (request != NULL)
 	    requestUnlink(request);	/* Linked in clientReadBody */
-	debug(33, 2) ("clientProcessBody: end fd=%d size=%d body_size=%lu in.offset=%ld cb=%p req=%p\n", conn->fd, size, (unsigned long int) conn->body.size_left, (long int) conn->in.offset, callback, request);
+	debug(33, 2) ("clientProcessBody: end fh=%p size=%d body_size=%ld remaining=%ld cb=%p req=%p\n", conn->fh, size, (unsigned long int) conn->body.size_left, (long int)IOBufSize(conn->in), callback, request);
     }
 }
 
@@ -3051,9 +3150,9 @@
 clientReadBodyAbortHandler(char *buf, size_t size, void *data)
 {
     ConnStateData *conn = (ConnStateData *) data;
-    debug(33, 2) ("clientReadBodyAbortHandler: fd=%d body_size=%lu in.offset=%ld\n", conn->fd, (unsigned long int) conn->body.size_left, (long int) conn->in.offset);
+    debug(33, 2) ("clientReadBodyAbortHandler: fh=%p body_size=%lu size=%ld\n", conn->fh, (unsigned long int) conn->body.size_left, (long int) IOBufSize(conn->in));
     if (size != 0 && conn->body.size_left != 0) {
-	debug(33, 3) ("clientReadBodyAbortHandler: fd=%d shedule next read\n", conn->fd);
+	debug(33, 3) ("clientReadBodyAbortHandler: fh=%p shedule next read\n", conn->fh);
 	conn->body.callback = clientReadBodyAbortHandler;
 	conn->body.buf = bodyAbortBuf;
 	conn->body.bufsize = sizeof(bodyAbortBuf);
@@ -3089,6 +3188,7 @@
     return 1;			/* Aborted */
 }
 
+#if NOT_YET_PORTED
 /* general lifetime handler for HTTP requests */
 static void
 requestTimeout(int fd, void *data)
@@ -3096,7 +3196,7 @@
 #if THIS_CONFUSES_PERSISTENT_CONNECTION_AWARE_BROWSERS_AND_USERS
     ConnStateData *conn = data;
     ErrorState *err;
-    debug(33, 3) ("requestTimeout: FD %d: lifetime is expired.\n", fd);
+    debug(33, 3) ("requestTimeout: FH %p: lifetime is expired.\n", fd);
     if (fd_table[fd].rwstate) {
 	/*
 	 * Some data has been sent to the client, just close the FD
@@ -3139,7 +3239,7 @@
      * the open has already been completed on another
      * connection)
      */
-    debug(33, 3) ("requestTimeout: FD %d: lifetime is expired.\n", fd);
+    debug(33, 3) ("requestTimeout: FH %p: lifetime is expired.\n", fd);
     comm_close(fd);
 #endif
 }
@@ -3167,57 +3267,40 @@
     }
     return 1;
 }
+#endif /* NOT_YET_PORTED */
+
 
 /* Handle a new connection on HTTP socket. */
-void
-httpAccept(int sock, void *data)
+static void
+clientNewHttpConnection(filehandle *fh, int error, struct sockaddr *local, struct sockaddr *peer, int addrlen, void *cbdata)
 {
-    int *N = &incoming_sockets_accepted;
     int fd = -1;
-    ConnStateData *connState = NULL;
-    struct sockaddr_in peer;
-    struct sockaddr_in me;
-    int max = INCOMING_HTTP_MAX;
+    ConnStateData *conn = NULL;
 #if USE_IDENT
     static aclCheck_t identChecklist;
 #endif
-    commSetSelect(sock, COMM_SELECT_READ, httpAccept, NULL, 0);
-    while (max-- && !httpAcceptDefer(sock, NULL)) {
-	memset(&peer, '\0', sizeof(struct sockaddr_in));
-	memset(&me, '\0', sizeof(struct sockaddr_in));
-	if ((fd = comm_accept(sock, &peer, &me)) < 0) {
-	    if (!ignoreErrno(errno))
-		debug(50, 1) ("httpAccept: FD %d: accept failure: %s\n",
-		    sock, xstrerror());
-	    break;
-	}
-	debug(33, 4) ("httpAccept: FD %d: accepted\n", fd);
-	connState = cbdataAlloc(ConnStateData);
-	connState->peer = peer;
-	connState->log_addr = peer.sin_addr;
-	connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
-	connState->me = me;
-	connState->fd = fd;
-	connState->in.size = CLIENT_REQ_BUF_SZ;
-	connState->in.buf = memAllocate(MEM_CLIENT_REQ_BUF);
-	/* XXX account connState->in.buf */
-	comm_add_close_handler(fd, connStateFree, connState);
-	if (Config.onoff.log_fqdn)
-	    fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS);
-	commSetTimeout(fd, Config.Timeout.request, requestTimeout, connState);
+    debug(33, 4) ("httpAccept: FH %p: accepted\n", fd);
+    conn = cbdataAlloc(ConnStateData);
+    conn->fh = cbdataReference(fh);
+    memcpy(&conn->peer, peer, sizeof(conn->peer)); /* addrsize? */
+    conn->log_addr = ((struct sockaddr_in *)peer)->sin_addr;
+    conn->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
+    memcpy(&conn->me, local, sizeof(conn->me)); /* addrsize? */
+#if NOT_YET_PORTED
+    comm_add_close_handler(fd, connFree, conn);
+    if (Config.onoff.log_fqdn)
+	fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS);
+    commSetTimeout(fd, Config.Timeout.request, requestTimeout, conn);
+#endif
 #if USE_IDENT
-	identChecklist.src_addr = peer.sin_addr;
-	identChecklist.my_addr = me.sin_addr;
-	identChecklist.my_port = ntohs(me.sin_port);
-	if (aclCheckFast(Config.accessList.identLookup, &identChecklist))
-	    identStart(&me, &peer, clientIdentDone, connState);
+    identChecklist.src_addr = ((struct sockaddr_in *)peer)->sin_addr;
+    identChecklist.my_addr = ((struct sockaddr_in *)local)->sin_addr;
+    identChecklist.my_port = ntohs(((struct sockaddr_in *)local)->sin_port);
+    if (aclCheckFast(Config.accessList.identLookup, &identChecklist))
+	identStart(local, peer, clientIdentDone, conn);
 #endif
-	commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, connState, 0);
-	commSetDefer(fd, clientReadDefer, connState);
-	clientdbEstablished(peer.sin_addr, 1);
-	assert(N);
-	(*N)++;
-    }
+    clientdbEstablished(((struct sockaddr_in *)peer)->sin_addr, 1);
+    ncomm_read(fh, clientReadRequest, conn);
 }
 
 #if USE_SSL
@@ -3464,35 +3547,13 @@
 clientHttpConnectionsOpen(void)
 {
     sockaddr_in_list *s;
-    int fd;
+    filehandle *fh;
     for (s = Config.Sockaddr.http; s; s = s->next) {
-	if (MAXHTTPPORTS == NHttpSockets) {
-	    debug(1, 1) ("WARNING: You have too many 'http_port' lines.\n");
-	    debug(1, 1) ("         The limit is %d\n", MAXHTTPPORTS);
-	    continue;
-	}
 	enter_suid();
-	fd = comm_open(SOCK_STREAM,
-	    0,
-	    s->s.sin_addr,
-	    ntohs(s->s.sin_port),
-	    COMM_NONBLOCKING,
-	    "HTTP Socket");
+	fh = ncomm_listen_transparent(SOCK_STREAM, 0, (struct sockaddr *)&s->s, sizeof(s->s), 8192, clientNewHttpConnection, NULL);
 	leave_suid();
-	if (fd < 0)
-	    continue;
-	comm_listen(fd);
-	commSetSelect(fd, COMM_SELECT_READ, httpAccept, NULL, 0);
-	/*
-	 * We need to set a defer handler here so that we don't
-	 * peg the CPU with select() when we hit the FD limit.
-	 */
-	commSetDefer(fd, httpAcceptDefer, NULL);
-	debug(1, 1) ("Accepting HTTP connections at %s, port %d, FD %d.\n",
-	    inet_ntoa(s->s.sin_addr),
-	    (int) ntohs(s->s.sin_port),
-	    fd);
-	HttpSockets[NHttpSockets++] = fd;
+	if (fh == NULL)
+	    fatal("Cannot open HTTP Port");
     }
 }
 
@@ -3546,7 +3607,7 @@
     int i;
     for (i = 0; i < NHttpSockets; i++) {
 	if (HttpSockets[i] >= 0) {
-	    debug(1, 1) ("FD %d Closing HTTP connection\n", HttpSockets[i]);
+	    debug(1, 1) ("FH %p Closing HTTP connection\n", HttpSockets[i]);
 	    comm_close(HttpSockets[i]);
 	    HttpSockets[i] = -1;
 	}
Index: squid/src/comm.c
diff -u squid/src/comm.c:1.18 squid/src/comm.c:1.7.12.9
--- squid/src/comm.c:1.18	Wed Oct 24 02:42:12 2001
+++ squid/src/comm.c	Sat Nov 17 05:11:58 2001
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
@@ -942,10 +941,31 @@
 }
 
 /* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
+typedef struct {
+    char **bufp;
+    CWCB *handler;
+    void *handler_data;
+} comm_write_mbuf_handle;
+CBDATA_TYPE(comm_write_mbuf_handle);
+static void comm_write_mbuf_handler(int fd, char *buf, size_t size, int flag, void *data)
+{
+    comm_write_mbuf_handle *handle = data;
+    cbdataUnreference(handle->bufp);
+    if (cbdataValid(handle->handler_data))
+	handle->handler(fd, NULL, size, flag, handle->handler_data);
+    cbdataUnreference(handle->handler_data);
+    cbdataFree(handle);
+}
 void
 comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
 {
-    comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
+    comm_write_mbuf_handle *handle;
+    CBDATA_INIT_TYPE(comm_write_mbuf_handle);
+    handle = cbdataAlloc(comm_write_mbuf_handle);
+    handle->bufp = cbdataReference(mb.bufp);
+    handle->handler = handler;
+    handle->handler_data = handler_data;
+    comm_write(fd, *handle->bufp, mb.size, comm_write_mbuf_handler, handle, NULL);
 }
 
 /*
Index: squid/src/comm_select.c
diff -u squid/src/comm_select.c:1.8 squid/src/comm_select.c:1.4.12.4
--- squid/src/comm_select.c:1.8	Wed Oct 24 02:42:12 2001
+++ squid/src/comm_select.c	Sat Nov 17 05:11:58 2001
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
Index: squid/src/defines.h
diff -u squid/src/defines.h:1.15 squid/src/defines.h:1.8.12.6
--- squid/src/defines.h:1.15	Sat Nov 17 17:15:42 2001
+++ squid/src/defines.h	Wed Nov 21 18:19:01 2001
@@ -234,7 +234,7 @@
 #define countof(arr) (sizeof(arr)/sizeof(*arr))
 
 /* to initialize static variables (see also MemBufNull) */
-#define MemBufNULL { NULL, 0, 0, 0, NULL }
+#define MemBufNULL { NULL, 0, 0, 0 }
 
 /*
  * Max number of ICP messages to receive per call to icpHandleUdp
@@ -296,4 +296,9 @@
 #define O_BINARY 0
 #endif
 
+/* IOBuf macros */
+#define IOBufP(iobuf)	(*(iobuf)->bufp)
+#define IOBufSize(iobuf) ((iobuf) ? (iobuf)->size : 0)
+#define IOBufAppend(iobuf, buf, size) memBufAppend(iobuf, buf, size)
+
 #endif /* SQUID_DEFINES_H */
Index: squid/src/disk.c
diff -u squid/src/disk.c:1.8 squid/src/disk.c:1.5.12.6
--- squid/src/disk.c:1.8	Thu Aug 16 00:39:03 2001
+++ squid/src/disk.c	Wed Sep 12 13:34:25 2001
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
@@ -331,10 +330,31 @@
  * a wrapper around file_write to allow for MemBuf to be file_written
  * in a snap
  */
+typedef struct {
+    char **bufp;
+    DWCB *handler;
+    void *handler_data;
+} file_write_mbuf_handle;
+CBDATA_TYPE(file_write_mbuf_handle);
+static void file_write_mbuf_handler(int fd, int errflag, size_t len, void *data)
+{
+    file_write_mbuf_handle *handle = data;
+    cbdataUnreference(handle->bufp);
+    if (cbdataValid(handle->handler_data))
+	handle->handler(fd, errflag, len, handle->handler_data);
+    cbdataUnreference(handle->handler_data);
+    cbdataFree(handle);
+}
 void
 file_write_mbuf(int fd, off_t off, MemBuf mb, DWCB * handler, void *handler_data)
 {
-    file_write(fd, off, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
+    file_write_mbuf_handle *handle;
+    CBDATA_INIT_TYPE(file_write_mbuf_handle);
+    handle = cbdataAlloc(file_write_mbuf_handle);
+    handle->bufp = cbdataReference(mb.bufp);
+    handle->handler = handler;
+    handle->handler_data = handler_data;
+    file_write(fd, off, *handle->bufp, mb.size, file_write_mbuf_handler, handle, NULL);
 }
 
 /* Read from FD */
Index: squid/src/dlink.c
diff -u /dev/null squid/src/dlink.c:1.1.2.1
--- /dev/null	Tue Sep 28 18:37:31 2004
+++ squid/src/dlink.c	Sat Feb 24 15:48:43 2001
@@ -0,0 +1,71 @@
+#include "squid.h"
+
+MemPool *dlink_node_pool = NULL;
+
+dlink_node *
+dlinkNodeNew()
+{
+    if (dlink_node_pool == NULL)
+	dlink_node_pool = memPoolCreate("Dlink list nodes", sizeof(dlink_node));
+    /* where should we call memPoolDestroy(dlink_node_pool); */
+    return memPoolAlloc(dlink_node_pool);
+}
+
+/* the node needs to be unlinked FIRST */
+void
+dlinkNodeDelete(dlink_node * m)
+{
+    if (m == NULL)
+	return;
+    memPoolFree(dlink_node_pool, m);
+}
+
+void
+dlinkAdd(void *data, dlink_node * m, dlink_list * list)
+{
+    m->data = data;
+    m->prev = NULL;
+    m->next = list->head;
+    if (list->head)
+	list->head->prev = m;
+    list->head = m;
+    if (list->tail == NULL)
+	list->tail = m;
+}
+
+void
+dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
+{
+    m->data = data;
+    m->next = NULL;
+    m->prev = list->tail;
+    if (list->tail)
+	list->tail->next = m;
+    list->tail = m;
+    if (list->head == NULL)
+	list->head = m;
+}
+
+void
+dlinkDelete(dlink_node * m, dlink_list * list)
+{
+    if (m->next)
+	m->next->prev = m->prev;
+    if (m->prev)
+	m->prev->next = m->next;
+    if (m == list->head)
+	list->head = m->next;
+    if (m == list->tail)
+	list->tail = m->prev;
+    m->next = m->prev = NULL;
+}
+
+void *
+dlinkGetFirst(dlink_list * list)
+{
+    dlink_node * m = list->head;
+    if (!m)
+	return NULL;
+    dlinkDelete(m, list);
+    return m->data;
+}
Index: squid/src/enums.h
diff -u squid/src/enums.h:1.27 squid/src/enums.h:1.14.8.9
--- squid/src/enums.h:1.27	Sat Nov 17 17:15:42 2001
+++ squid/src/enums.h	Wed Nov 21 18:19:01 2001
@@ -720,6 +720,15 @@
 } cbdata_type;
 
 /*
+ * comm_server stuff
+ */
+enum comm_event_type {
+    EVENT_NONE,
+    EVENT_READ,
+    EVENT_WRITE
+};
+
+/*
  * Return codes from checkVary(request)
  */
 enum {
Index: squid/src/errorpage.c
diff -u squid/src/errorpage.c:1.15 squid/src/errorpage.c:1.10.12.4
--- squid/src/errorpage.c:1.15	Wed Oct 24 02:42:12 2001
+++ squid/src/errorpage.c	Sat Nov 17 05:11:58 2001
@@ -515,7 +515,7 @@
 	    MemBuf sign_mb;
 	    err->page_id = ERR_SQUID_SIGNATURE;
 	    sign_mb = errorBuildContent(err);
-	    memBufPrintf(&mb, "%s", sign_mb.buf);
+	    memBufPrintf(&mb, "%s", *sign_mb.bufp);
 	    memBufClean(&sign_mb);
 	    err->page_id = saved_id;
 	    do_quote = 0;
@@ -553,7 +553,7 @@
 	break;
     }
     if (!p)
-	p = mb.buf;		/* do not use mb after this assignment! */
+	p = *mb.bufp;		/* do not use mb after this assignment! */
     assert(p);
     debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p);
     if (do_quote)
@@ -606,6 +606,6 @@
     }
     if (*m)
 	memBufPrintf(&content, "%s", m);	/* copy tail */
-    assert(content.size == strlen(content.buf));
+    assert(content.size == strlen(*content.bufp));
     return content;
 }
Index: squid/src/fd.c
diff -u squid/src/fd.c:1.7 squid/src/fd.c:1.5.12.4
--- squid/src/fd.c:1.7	Sun Aug 26 15:26:29 2001
+++ squid/src/fd.c	Wed Sep 12 13:49:10 2001
@@ -84,13 +84,9 @@
 	assert(F->write_handler == NULL);
     }
     debug(51, 3) ("fd_close FD %d %s\n", fd, F->desc);
-    F->flags.open = 0;
+    memset(F, '\0', sizeof(fde));
     fdUpdateBiggest(fd, 0);
     Number_FD--;
-    commUpdateReadBits(fd, NULL);
-    commUpdateWriteBits(fd, NULL);
-    memset(F, '\0', sizeof(fde));
-    F->timeout = 0;
 }
 
 int
Index: squid/src/forward.c
diff -u squid/src/forward.c:1.13 squid/src/forward.c:1.9.12.3
--- squid/src/forward.c:1.13	Wed Oct 10 11:07:43 2001
+++ squid/src/forward.c	Sat Nov 17 05:11:58 2001
@@ -431,8 +431,8 @@
     request_t *request = fwdState->request;
     StoreEntry *entry = fwdState->entry;
     ErrorState *err;
-    debug(17, 3) ("fwdDispatch: FD %d: Fetching '%s %s'\n",
-	fwdState->client_fd,
+    debug(17, 3) ("fwdDispatch: FH %p: Fetching '%s %s'\n",
+	fwdState->client_fh,
 	RequestMethodStr[request->method],
 	storeUrl(entry));
     /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
@@ -546,7 +546,7 @@
 }
 
 void
-fwdStart(int fd, StoreEntry * e, request_t * r)
+fwdStart(filehandle *fh, StoreEntry * e, request_t * r)
 {
     FwdState *fwdState;
     aclCheck_t ch;
@@ -577,7 +577,6 @@
     }
     debug(17, 3) ("fwdStart: '%s'\n", storeUrl(e));
     e->mem_obj->request = requestLink(r);
-    e->mem_obj->fd = fd;
 #if URL_CHECKSUM_DEBUG
     assert(e->mem_obj->chksum == url_checksum(e->mem_obj->url));
 #endif
@@ -596,7 +595,7 @@
 	internalStart(r, e);
 	return;
     case PROTO_CACHEOBJ:
-	cachemgrStart(fd, r, e);
+	cachemgrStart(r, e);
 	return;
     case PROTO_URN:
 	urnStart(r, e);
@@ -606,7 +605,7 @@
     }
     fwdState = cbdataAlloc(FwdState);
     fwdState->entry = e;
-    fwdState->client_fd = fd;
+    fwdState->client_fh = fh;
     fwdState->server_fd = -1;
     fwdState->request = requestLink(r);
     fwdState->start = squid_curtime;
Index: squid/src/gopher.c
diff -u squid/src/gopher.c:1.10 squid/src/gopher.c:1.7.12.3
--- squid/src/gopher.c:1.10	Wed Oct 24 02:42:13 2001
+++ squid/src/gopher.c	Sat Nov 17 05:11:58 2001
@@ -187,7 +187,7 @@
     }
     memBufPrintf(&mb, "\r\n");
     EBIT_CLR(gopherState->entry->flags, ENTRY_FWD_HDR_WAIT);
-    storeAppend(gopherState->entry, mb.buf, mb.size);
+    storeAppend(gopherState->entry, *mb.bufp, mb.size);
     memBufClean(&mb);
 }
 
Index: squid/src/http.c
diff -u squid/src/http.c:1.17 squid/src/http.c:1.11.12.6
--- squid/src/http.c:1.17	Wed Oct 24 02:42:13 2001
+++ squid/src/http.c	Sat Nov 17 05:11:58 2001
@@ -964,12 +964,16 @@
     else
 	sendHeaderDone = httpSendComplete;
 
+#if NOT_YET_PORTED
     if (!opt_forwarded_for)
 	cfd = -1;
     else if (entry->mem_obj == NULL)
 	cfd = -1;
     else
 	cfd = entry->mem_obj->fd;
+#else
+    cfd = -1;
+#endif
     assert(-1 == cfd || FD_SOCKET == fd_table[cfd].type);
     if (p != NULL)
 	httpState->flags.proxying = 1;
@@ -997,7 +1001,7 @@
 	&mb,
 	cfd,
 	httpState->flags);
-    debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", httpState->fd, mb.buf);
+    debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", httpState->fd, *mb.bufp);
     comm_write_mbuf(httpState->fd, mb, sendHeaderDone, httpState);
 }
 
Index: squid/src/ident.c
diff -u squid/src/ident.c:1.8 squid/src/ident.c:1.6.12.3
--- squid/src/ident.c:1.8	Fri Apr 13 17:31:02 2001
+++ squid/src/ident.c	Sat Apr 14 06:43:18 2001
@@ -186,8 +186,10 @@
  * start a TCP connection to the peer host on port 113
  */
 void
-identStart(struct sockaddr_in *me, struct sockaddr_in *my_peer, IDCB * callback, void *data)
+identStart(struct sockaddr *local, struct sockaddr *remote, IDCB * callback, void *data)
 {
+    struct sockaddr_in *me = (struct sockaddr_in *)local;
+    struct sockaddr_in *my_peer = (struct sockaddr_in *)remote;
     IdentStateData *state;
     int fd;
     char key1[IDENT_KEY_SZ];
Index: squid/src/internal.c
diff -u squid/src/internal.c:1.7 squid/src/internal.c:1.7.12.1
--- squid/src/internal.c:1.7	Fri Jan 12 00:20:33 2001
+++ squid/src/internal.c	Sat Feb 24 04:52:42 2001
@@ -117,7 +117,7 @@
 	memBufPrintf(&mb, "%s", dir);
     memBufPrintf(&mb, "%s", name);
     /* return a pointer to a local static buffer */
-    return mb.buf;
+    return *mb.bufp;
 }
 
 /*
Index: squid/src/main.c
diff -u squid/src/main.c:1.28 squid/src/main.c:1.19.8.8
--- squid/src/main.c:1.28	Wed Oct 24 02:42:13 2001
+++ squid/src/main.c	Sat Nov 17 05:11:58 2001
@@ -645,8 +645,11 @@
 	if (checkRunningPid())
 	    exit(1);
 
+    memBuf_module_init();
+
 #if TEST_ACCESS
     comm_init();
+    ncomm_module_init();
     comm_select_init();
     mainInitialize();
     test_access();
@@ -682,6 +685,7 @@
 
     /* init comm module */
     comm_init();
+    ncomm_module_init();
     comm_select_init();
 
     if (opt_no_daemon) {
@@ -720,6 +724,7 @@
 	eventRun();
 	if ((loop_delay = eventNextTime()) < 0)
 	    loop_delay = 0;
+        ncomm_handle_events(0);
 #if HAVE_POLL
 	switch (comm_poll(loop_delay)) {
 #else
Index: squid/src/mem.c
diff -u squid/src/mem.c:1.13 squid/src/mem.c:1.8.12.4
--- squid/src/mem.c:1.13	Fri Sep  7 16:55:49 2001
+++ squid/src/mem.c	Wed Sep 12 13:34:25 2001
@@ -65,6 +65,7 @@
 
 /* local routines */
 
+#if 0
 static void
 memStringStats(StoreEntry * sentry)
 {
@@ -102,7 +103,7 @@
     memStringStats(sentry);
     storeBufferFlush(sentry);
 }
-
+#endif
 
 /*
  * public routines
@@ -247,9 +248,11 @@
     for (i = 0; i < mem_str_pool_count; i++) {
 	StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
     }
+#if 0
     cachemgrRegister("mem",
 	"Memory Utilization",
 	memStats, 0, 1);
+#endif
 }
 
 /*
Index: squid/src/mime.c
diff -u squid/src/mime.c:1.11 squid/src/mime.c:1.8.12.4
--- squid/src/mime.c:1.11	Tue Nov 13 14:19:33 2001
+++ squid/src/mime.c	Sat Nov 17 05:11:58 2001
@@ -409,7 +409,7 @@
     if (storeGetPublic(url, METHOD_GET))
 	return;
     snprintf(path, MAXPATHLEN, "%s/%s", Config.icons.directory, icon);
-    fd = file_open(path, O_RDONLY | O_BINARY);
+    fd = open(path, O_RDONLY | O_BINARY, 0);
     if (fd < 0) {
 	debug(25, 0) ("mimeLoadIconFile: %s: %s\n", path, xstrerror());
 	return;
@@ -443,7 +443,7 @@
     buf = memAllocate(MEM_4K_BUF);
     while ((n = FD_READ_METHOD(fd, buf, 4096)) > 0)
 	storeAppend(e, buf, n);
-    file_close(fd);
+    close(fd);
     storeBufferFlush(e);
     storeComplete(e);
     storeTimestampsSet(e);
Index: squid/src/ncomm.c
diff -u /dev/null squid/src/ncomm.c:1.1.2.17
--- /dev/null	Tue Sep 28 18:37:31 2004
+++ squid/src/ncomm.c	Wed Nov 21 18:32:12 2001
@@ -0,0 +1,804 @@
+#include "squid.h"
+#include "ncomm_internals.h"
+
+/* transparent proxying requires some extra headers... */
+
+#if IPF_TRANSPARENT
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <netinet/tcp.h>
+#include <net/if.h>
+#if HAVE_IP_FIL_COMPAT_H
+#include <ip_fil_compat.h>
+#elif HAVE_NETINET_IP_FIL_COMPAT_H
+#include <netinet/ip_fil_compat.h>
+#elif HAVE_IP_COMPAT_H
+#include <ip_compat.h>
+#elif HAVE_NETINET_IP_COMPAT_H
+#include <netinet/ip_compat.h>
+#endif
+#if HAVE_IP_FIL_H
+#include <ip_fil.h>
+#elif HAVE_NETINET_IP_FIL_H
+#include <netinet/ip_fil.h>
+#endif
+#if HAVE_IP_NAT_H
+#include <ip_nat.h>
+#elif HAVE_NETINET_IP_NAT_H
+#include <netinet/ip_nat.h>
+#endif
+#endif
+
+#if LINUX_NETFILTER
+#include <linux/netfilter_ipv4.h>
+#endif
+
+/* end of headers for transparent proxying */
+
+
+#define UNUSED __attribute__((unused))
+
+typedef enum cbent_type {
+    COMMCB_none,
+    COMMCB_io,
+    COMMCB_new,
+    COMMCB_close
+} cbent_type_t;
+
+typedef struct {
+    dlink_node node;
+    cbent_type_t type;
+    filehandle *fh;
+    void *cbdata;
+    int error;
+    union {
+	struct {
+	    COMMIOCB *callback;
+	    IOBuf *buf;
+	    size_t offset;
+	    ssize_t len;
+	} io;
+	struct {
+	    COMMNEWCB *callback;
+	} new;
+	struct {
+	    COMMCLOSECB *callback;
+	} close;
+    } cb;
+} comm_callback_entry_t;
+
+dlink_list callbacklist;
+CBDATA_TYPE(comm_callback_entry_t);
+CBDATA_TYPE(filehandle);
+CBDATA_TYPE(IOBuf);
+CBDATA_TYPE(fh_write_t);
+
+static void
+IOBufIsFreed(void *data)
+{
+    IOBuf *buf = data;
+    memBufClean(buf);
+}
+
+IOBuf *
+IOBufAlloc(size_t size)
+{
+    IOBuf *buf, *bufp;
+    buf = cbdataAlloc(IOBuf);
+    memBufInit(buf, size, 1024*1024); /* max 1MB per IOBuf */
+    bufp = cbdataReference(buf);
+    cbdataFree(buf);
+    return bufp;
+}
+
+IOBuf *
+IOBufCreate(void *data, size_t size)
+{
+    IOBuf *buf = IOBufAlloc(size);
+    memBufAppend(buf, data, size);
+    return buf;
+}
+
+IOBuf *
+IOBufCreateFromMemBuf(MemBuf *mb)
+{
+    IOBuf *buf;
+    buf = cbdataAlloc(IOBuf);
+    *buf = *mb;
+    mb->bufp = NULL;
+    return buf;
+}
+
+static int
+ncommIgnoreErrno(int error)
+{
+    switch (error) {
+    case EINPROGRESS:
+    case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+    case EAGAIN:
+#endif
+    case EALREADY:
+    case EINTR:
+#ifdef ERESTART
+    case ERESTART:
+#endif
+	return 1;
+    default:
+	return 0;
+    }
+}
+
+static comm_callback_entry_t *
+newCbent(filehandle *fh, int error, void *cbdata, cbent_type_t type)
+{
+    comm_callback_entry_t *cbent = cbdataAlloc(comm_callback_entry_t);
+    cbent->fh = cbdataReference(fh);
+    cbent->type = type;
+    cbent->error = error;
+    cbent->cbdata = cbdataReference(cbdata);
+    return cbent;
+}
+
+static void
+comm_new_callback(filehandle *fh, int error, COMMNEWCB *callback, void *cbdata)
+{
+    comm_callback_entry_t *cbent = newCbent(fh, error, cbdata, COMMCB_new);
+    cbent->cb.new.callback = callback;
+
+    dlinkAddTail(cbent, &cbent->node, &callbacklist);
+}
+
+static void
+comm_io_callback(filehandle *fh, IOBuf *buf, size_t offset, ssize_t len, int error, COMMIOCB *callback, void *cbdata)
+{
+    comm_callback_entry_t *cbent = newCbent(fh, error, cbdata, COMMCB_io);
+    cbent->cb.io.callback = callback;
+    cbent->cb.io.buf = cbdataReference(buf);
+    cbent->cb.io.offset = offset;
+    cbent->cb.io.len = len;
+
+    dlinkAddTail(cbent, &cbent->node, &callbacklist);
+}
+
+#if NOT_YET_USED
+static void
+comm_close_callback(filehandle *fh, int error, COMMNEWCB *callback, void *cbdata)
+{
+    comm_callback_entry_t *cbent = newCbent(fh, error, cbdata, COMMCB_new);
+    cbent->cb.new.callback = callback;
+
+    dlinkAddTail(cbent, &cbent->node, &callbacklist);
+}
+#endif
+
+void
+ncomm_call_callbacks(void)
+{
+    /* Do callbacks */
+    comm_callback_entry_t *cb;
+    while((cb = dlinkGetFirst(&callbacklist)) != NULL) {
+	int valid = cbdataValid(cb->cbdata);
+	filehandle *fh = cb->fh;
+	switch(cb->type) {
+	case COMMCB_io:
+	    if (valid && cb->cb.io.callback)
+		cb->cb.io.callback(fh, cb->cb.io.buf, cb->cb.io.offset, cb->cb.io.len, cb->error, cb->cbdata);
+	    cbdataUnreference(cb->cb.io.buf);
+	    break;
+	case COMMCB_new:
+	    if (valid && cb->cb.new.callback) {
+		if (fh)
+		    cb->cb.new.callback(fh, cb->error, &fh->local, &fh->peer, fh->addrsize, cb->cbdata);
+		else
+		    cb->cb.new.callback(NULL, cb->error, NULL, NULL, 0, cb->cbdata);
+	    }
+	    break;
+	case COMMCB_close:
+	    /* NOT YET DONE */
+	    break;
+	default:
+	    fatal("Unknown ncomm callback type");
+	    break;
+	}
+	cbdataUnreference(cb->cbdata);
+	cbdataUnreference(cb->fh);
+	cbdataFree(cb);
+    }
+}
+
+static void
+comm_read_callback(filehandle *fh, fh_read_t *fhr, void *data, int len, int error)
+{
+    COMMIOCB *callback = fhr->callback;
+    void *cbdata;
+    IOBuf *buf = NULL;
+    fhr->callback = NULL;
+    if (len > 0)
+	buf = IOBufCreate(data, len);
+    cbdata = cbdataEatReference(fhr->cbdata);
+    comm_io_callback(fh, buf, 0, len, error, callback, cbdata);
+    cbdataUnreference(cbdata);
+    cbdataUnreference(buf);
+}
+
+static void
+fh_bytes(filehandle *fh, ssize_t len, unsigned int type)
+{
+}
+
+static void
+fh_open(filehandle *fh, const char *descr)
+{
+}
+
+static void
+comm_do_close(filehandle *fh)
+{
+    if (!fh->shutdown_write) {
+	shutdown(fh->fd, 1);
+	fh->shutdown_write = 1;
+    }
+    if (fh->shutdown_read) {
+	close(fh->fd);
+	fh->fd = -1;
+    }
+}
+
+static int
+comm_do_read(filehandle *fh)
+{
+    static char inbuf[65536];
+    int fd = fh->fd;
+    fh_read_t *fhr = &fh->read;
+    /* Read in some data */
+    const ssize_t len = read(fd, inbuf, fhr->size);
+    statCounter.syscalls.sock.reads++;
+    fh_bytes(fh, len, FD_READ);
+    if (len > 0) {
+	/* We got some data to deliver to the application */
+	comm_read_callback(fh, fhr, inbuf, len, 0);
+	return 1;
+    } else if (len == 0 || (len == -1 && !ncommIgnoreErrno(errno))) {
+	int saved_errno = errno;
+	/* EOF or error, shut down the read channel */
+	fh->shutdown_read = 1;
+	if (fh->shutdown_write) {
+	    close(fh->fd);
+	    fh->fd = -1;
+	} else {
+	    shutdown(fh->fd, 0);
+	}
+	comm_read_callback(fh, fhr, NULL, len, len ? saved_errno : 0);
+	return 1;
+    }
+    /* Try again */
+    return 0;
+}
+
+void
+ncomm_read_limited(filehandle *fh, size_t size, COMMIOCB *callback, void *cbdata)
+{
+    fh_read_t *fhr = &fh->read;
+    int done;
+
+    if (size > 65536)
+	size = 65536; /* Do not overflow buffer in comm_do_read */
+
+    /* Read in some data */
+    fhr->size = size;
+    fhr->callback = callback;
+    fhr->cbdata = cbdataReference(cbdata);
+    done = comm_do_read(fh);
+    if (!done) {
+	/* Oops.. we could not get any data. Register for read event */
+	comm_register_for_read_event(fh, comm_do_read);
+    }
+}
+
+void
+ncomm_read(filehandle *fh, COMMIOCB *callback, void *cbdata)
+{
+    ncomm_read_limited(fh, 65536, callback, cbdata);
+}
+
+static void
+comm_write_callback(filehandle *fh, fh_write_t *fhw, int len, int error)
+{
+    COMMIOCB *callback = fhw->callback;
+    void *cbdata;
+    IOBuf *buf;
+    fhw->callback = NULL;
+    cbdata = cbdataEatReference(fhw->cbdata);
+    buf = cbdataEatReference(fhw->buf);
+    comm_io_callback(fh, buf, fhw->offset, len, error, callback, cbdata);
+    cbdataUnreference(cbdata);
+    cbdataUnreference(buf);
+}
+
+static int
+comm_do_write(filehandle *fh)
+{
+    fh_write_t *fhw;
+    int fd = fh->fd;
+    /* Write out some more data */
+    const void *buf;
+    size_t size = fhw->size - fhw->done;
+    ssize_t len;
+writemore:
+    fhw = fh->write;
+    buf = (void *)(*fhw->buf->bufp + fhw->done);
+    size = fhw->size - fhw->done;
+    assert(size > 0);
+    len = write(fd, buf, size);
+    statCounter.syscalls.sock.writes++;
+    fh_bytes(fh, len, FD_WRITE);
+    if ((size_t)len == size) {
+	/* finished */
+	fh->write = fhw->next;
+	comm_write_callback(fh, fhw, (ssize_t)fhw->size, 0);
+	cbdataFree(fhw);
+	if (fh->write)
+	    goto writemore;
+	/* OK. No more data. We are done */
+	if (fh->closed)
+	    comm_do_close(fh);
+	return 1;
+    }
+    if (len == -1 && !ncommIgnoreErrno(errno)) {
+	/* error */
+	comm_write_callback(fh, fhw, fhw->done, errno);
+	if (fh->closed)
+	    comm_do_close(fh);
+	return 1;
+    }
+    /* try again */
+    if (len > 0)
+	fhw->done += len;
+    return 0;
+}
+
+void
+ncomm_write_fragment(filehandle *fh, IOBuf *buf, size_t offset, size_t size, COMMIOCB *callback, void *cbdata)
+{
+    int done;
+    int first = 1;
+    fh_write_t **fhwp;
+    fh_write_t *fhw = cbdataAlloc(fh_write_t);
+    fhw->buf = cbdataReference(buf);
+    fhw->offset = offset;
+    fhw->size = size;
+    fhw->done = 0;
+    fhw->callback = callback;
+    fhw->cbdata = cbdataReference(cbdata);
+    for (fhwp = &fh->write; *fhwp; fhwp = &(*fhwp)->next)
+	first = 0;
+    *fhwp = fhw;
+    if (first)
+	done = comm_do_write(fh);
+    else
+	done = 0; /* there is pending writes ahead of this one... */
+    if (!done)
+	comm_register_for_write_event(fh, comm_do_write);
+}
+
+void
+ncomm_write(filehandle *fh, IOBuf *buf, COMMIOCB *callback, void *cbdata)
+{
+    ncomm_write_fragment(fh, buf, 0, buf->size, callback, cbdata);
+}
+
+/* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap
+*/
+void
+ncomm_write_mbuf(filehandle *fh, MemBuf mb, COMMIOCB * callback, void *cbdata)
+{
+    IOBuf *buf = IOBufCreateFromMemBuf(&mb);
+    ncomm_write(fh, buf, callback, cbdata);
+}
+
+static int
+ncommSetNonBlocking(int fd)
+{
+    int flags;
+    int dummy = 0;
+    if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
+	debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
+	return COMM_ERROR;
+    }
+    if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
+	debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror());
+	return COMM_ERROR;
+    }
+    return 0;
+}
+
+static void
+ncommSetCloseOnExec(int fd)
+{
+#ifdef FD_CLOEXEC
+    int flags;
+    int dummy = 0;
+    if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
+	debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
+	return;
+    }
+    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
+	debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());
+#endif
+}
+
+static int
+comm_do_listen(filehandle *fh)
+{
+    int fd = fh->fd;
+    while(1) {
+	filehandle *nfh;
+	int nfd;
+	struct sockaddr saddr;
+	socklen_t addrsize = sizeof(saddr);
+        nfd = accept(fd, &saddr, &addrsize);
+        statCounter.syscalls.sock.accepts++;
+        if (nfd < 0)
+            break;
+
+	nfh = cbdataAlloc(filehandle);
+	nfh->fd = nfd;
+
+        /* Update the FD state */
+        fh_open(nfh, "Incoming connection");
+
+	/* Update the socket information */
+	memcpy(&nfh->peer, &saddr, addrsize);
+	nfh->addrsize = addrsize;
+
+        addrsize = sizeof(nfh->local);
+        getsockname(nfd, (struct sockaddr *) &nfh->local, &addrsize);
+	if (addrsize < nfh->addrsize)
+	    nfh->addrsize = addrsize;
+
+#if IPF_TRANSPARENT
+	if (fh->transparent && fh->local.sa_family == AF_INET) {
+	    struct natlookup natLookup;
+	    static int natfd = -1;
+	    static const int siocgnatl_cmd = SIOCGNATL & 0xff;
+	    int x;
+	    struct sockaddr_in *local = (struct sockaddr_in *)&fh->local;
+	    struct sockaddr_in *peer = (struct sockaddr_in *)&fh->peer;
+
+	    natLookup.nl_inport = local->sin_port;
+	    natLookup.nl_outport = peer->sin_port;
+	    natLookup.nl_inip = local->sin_addr;
+	    natLookup.nl_outip = peer->sin_addr;
+	    natLookup.nl_flags = IPN_TCP;
+	    if (natfd < 0)
+		natfd = open(IPL_NAT, O_RDONLY, 0);
+	    if (natfd < 0) {
+		debug(50, 1) ("WARNING: NAT open failed: %s\n", xstrerror());
+	    } else {
+		/*
+		 * IP-Filter changed the type for SIOCGNATL between
+		 * 3.3 and 3.4.  It also changed the cmd value for
+		 * SIOCGNATL, so at least we can detect it.  We could
+		 * put something in configure and use ifdefs here, but
+		 * this seems simpler.
+		 */
+		if (63 == siocgnatl_cmd) {
+		    struct natlookup *nlp = &natLookup;
+		    x = ioctl(natfd, SIOCGNATL, &nlp);
+		} else {
+		    x = ioctl(natfd, SIOCGNATL, &natLookup);
+		}
+		if (x < 0) {
+		    if (errno != ESRCH) {
+			debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)\n");
+			close(natfd);
+			natfd = -1;
+		    }
+		} else {
+		    local->sin_port = natLookup.nl_realport;
+		    local->sin_addr = natLookup.nl_realip;
+		    nfh->transparent = 1;
+		}
+	    }
+	}
+#elsif LINUX_NETFILTER
+	if (fh->transparent) {
+	    int x;
+	    addrsize = sizeof(fh->local);
+	    x = getsockopt(fh->fd, SOL_IP, SO_ORIGINAL_DST, &fh->local, &addrsize);
+	    if (x == 0)
+		nfh->transparent = 1;
+	}
+#endif
+
+	/* Set the flags */
+        ncommSetCloseOnExec(nfd);
+        ncommSetNonBlocking(nfd); 
+        
+        /* Finally, hand over the socket */
+	comm_new_callback(nfh, 0, fh->connect.callback, fh->connect.cbdata);
+	cbdataUnreference(fh->connect.cbdata);
+    }
+    if (!ncommIgnoreErrno(errno)) {
+	comm_new_callback(NULL, errno, fh->connect.callback, fh->connect.cbdata);
+	cbdataUnreference(fh->connect.cbdata);
+    }
+    /* continue listening */
+    return 0;
+}
+
+filehandle *
+ncomm_listen(int sock_type, int proto, struct sockaddr *where,
+	     int addrsize, int backlog, COMMNEWCB *callback, void *cbdata)
+{
+    filehandle *fh;
+    int fd, rc;
+    int on = 1;
+
+    fd = socket(where->sa_family, sock_type, proto);
+    statCounter.syscalls.sock.sockets++;
+    if (fd < 0)
+	return NULL;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
+    ncommSetCloseOnExec(fd);
+    ncommSetNonBlocking(fd); 
+    rc = bind(fd, where, addrsize);
+    statCounter.syscalls.sock.binds++;
+    if (rc < 0) {
+	int saved_errno = errno;
+	close(fd);
+	statCounter.syscalls.sock.closes++;
+	errno = saved_errno;
+	return NULL;
+    }
+    rc = listen(fd, backlog);
+    if (rc < 0) {
+	int saved_errno = errno;
+	close(fd);
+	statCounter.syscalls.sock.closes++;
+	errno = saved_errno;
+	return NULL;
+    }
+    fh = cbdataAlloc(filehandle);
+    fh->fd = fd;
+    fh->local = *where;
+    fh->connect.callback = callback;
+    fh->connect.cbdata = cbdataReference(cbdata);
+    fh_open(fh, "Listening socket");
+    comm_register_for_read_event(fh, comm_do_listen);
+    return fh;
+}
+
+filehandle *
+ncomm_listen_transparent(int sock_type, int proto, struct sockaddr *where,
+	     int addrsize, int backlog, COMMNEWCB *callback, void *cbdata)
+{
+    filehandle *fh = ncomm_listen(sock_type, proto, where, addrsize,
+				  backlog, callback, cbdata);
+    if (fh)
+	fh->transparent = 1;
+    
+    return fh;
+}
+
+static void
+destroy_filehandle(void *data)
+{
+    filehandle *fh = data;
+    if (fh->fd != -1) {
+	close(fh->fd);
+	fh->fd = -1;
+    }
+}
+
+static void
+destroy_fh_write(void *data)
+{
+    fh_write_t *fhw = data;
+    cbdataUnreference(fhw->buf);
+}
+
+void
+ncomm_module_init(void)
+{
+    CBDATA_INIT_TYPE(comm_callback_entry_t);
+    CBDATA_INIT_TYPE_FREECB(filehandle, destroy_filehandle);
+    CBDATA_INIT_TYPE_FREECB(IOBuf, IOBufIsFreed);
+    CBDATA_INIT_TYPE_FREECB(fh_write_t, destroy_fh_write);
+}
+
+void ncomm_module_shutdown(void)
+{
+}
+
+
+void
+ncomm_close(filehandle *fh)
+{
+    fh->closed = 1;
+    if (!fh->write && fh->fd != -1)
+	comm_do_close(fh);
+    cbdataFree(fh);
+}
+
+int
+ncomm_closed(filehandle *fh)
+{
+    return fh->closed;
+}
+
+void
+ncomm_abort(filehandle *fh)
+{
+    /* NOT YET IMPLEMENTED */
+}
+
+filehandle *
+ncomm_accept(int sock_type, int proto, struct sockaddr *where,
+	     struct sockaddr *from, int addrsize,
+	     COMMNEWCB callback, void *cbdata)
+{
+    /* NOT YET IMPLEMENTED */
+    return NULL;
+}
+
+static int
+comm_do_connect(filehandle *fh)
+{
+    int x;
+    int done = 0;
+    int err;
+    int errlen = sizeof(err);
+    x = connect(fh->fd, &fh->peer, sizeof(fh->peer));
+    statCounter.syscalls.sock.connects++;
+    if (x == 0) {
+	errno = 0;
+    } else if (x < 0) {
+	    debug(5, 9) ("connect FD %d: %s\n", fh->fd, xstrerror());
+    } else {
+#if defined(_SQUID_NEWSOS6_)
+	/* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
+	x = connect(fh->fd, &fh->peer, sizeof(fh->peer));
+	if (errno == EINVAL) {
+	    errlen = sizeof(err);
+	    x = getsockopt(fh->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
+	    if (x >= 0)
+		errno = x;
+	}
+#else
+	errlen = sizeof(err);
+	x = getsockopt(fh->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
+	if (x == 0)
+	    errno = err;
+#if defined(_SQUID_SOLARIS_)
+	/*
+	 * Solaris 2.4's socket emulation doesn't allow you
+	 * to determine the error from a failed non-blocking
+	 * connect and just returns EPIPE.  Create a fake
+	 * error message for connect.   -- fenner@parc.xerox.com
+	 */
+	if (x < 0 && errno == EPIPE)
+	    errno = ENOTCONN;
+#endif
+#endif
+    }
+    if (errno == 0 || errno == EISCONN) {
+	errno = 0;
+	done = 1;
+    } else if (!ncommIgnoreErrno(errno)) {
+	done = 1;
+    }
+    if (done) {
+	socklen_t addrsize = sizeof(fh->local);
+	err = errno; /* just in case */
+	getsockname(fh->fd, &fh->local, &addrsize);
+	if (addrsize < fh->addrsize)
+	    fh->addrsize = addrsize;
+	if (err) {
+	    comm_new_callback(fh, err, fh->connect.callback, fh->connect.cbdata);
+	    cbdataUnreference(fh->connect.cbdata);
+	    cbdataFree(fh);
+	} else {
+	    comm_new_callback(fh, 0, fh->connect.callback, fh->connect.cbdata);
+	    cbdataUnreference(fh->connect.cbdata);
+	}
+    }
+    return done;
+}
+
+/*
+ * Open a new socket to a given service
+ */
+filehandle *
+ncomm_connect(int sock_type, int proto, const struct sockaddr *local, const struct sockaddr *remote, int addrsize, COMMNEWCB *callback, void *cbdata)
+{
+    filehandle *fh;
+    int sock;
+    int x;
+    int done;
+    assert(remote);
+    sock = socket(remote->sa_family, sock_type, proto);
+    statCounter.syscalls.sock.sockets++;
+    if (sock == -1) {
+	debug(5, 1) ("comm_connet: Cannot create new socket: %s\n", xstrerror());
+	return NULL;
+    }
+    ncommSetCloseOnExec(sock);
+    ncommSetNonBlocking(sock); 
+    /* Bind to local endpoint */
+    if (local) {
+	int on = 1;
+	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
+	x = bind(sock, local, addrsize);
+	statCounter.syscalls.sock.binds++;
+	if (x != 0)
+	    debug(5, 1) ("comm_connect: WARNING: Failed to bind local endpoint: %s\n", xstrerror());
+    }
+    /* set up filehandle */
+    fh = cbdataAlloc(filehandle);
+    fh->fd = sock;
+    if (local)
+	memcpy(&fh->local, local, addrsize);
+    memcpy(&fh->peer, remote, addrsize);
+    fh->addrsize = addrsize;
+    fh->peer = *remote;
+    fh->connect.callback = callback;
+    fh->connect.cbdata = cbdataReference(cbdata);
+
+    /* Establish connection. */
+    cbdataLock(fh);
+    done = comm_do_connect(fh);
+
+    if (done) {
+	/* Ouch.. an error occurred while setting up the connection */
+	cbdataUnlock(fh);
+	return NULL;
+    }
+
+    if (!done) {
+	comm_register_for_write_event(fh, comm_do_connect);
+    } else if (!cbdataValid(fh)) {
+	/* Ouch.. an error occurred */
+	cbdataUnlock(fh);
+	return NULL;
+    }
+    cbdataUnlock(fh);
+    return fh;
+}
+
+int
+ncomm_add_close_handler(filehandle *fh, COMMCLOSECB *handler, void *cbdata)
+{
+    /* NOT YET IMPLEMENTED */
+    return 1;
+}
+
+void
+ncomm_note(filehandle *fh, const char *note)
+{
+    fd_note(fh->fd, note);
+}
+
+int
+ncomm_sendto(filehandle *fh, const struct sockaddr *to_addr, int addr_len, const void *msg, int msglen)
+{
+    int error = 0;
+    int x;
+
+    x = sendto(fh->fd, msg, msglen, 0, to_addr, addr_len);
+    if (x < 0) {
+	error = errno;
+#ifdef _SQUID_LINUX
+	if (errno != ECONNREFUSED)
+#endif
+	    debug(50, 1) ("ncomm_sendto: FH %p, %s, port %d: %s\n",
+			    fh,
+			    inet_ntoa(((struct sockaddr_in *)to_addr)->sin_addr),
+			    (int) htons(((struct sockaddr_in *)to_addr)->sin_port),
+			    xstrerror());
+	return error;
+    }
+    return x;
+}
Index: squid/src/ncomm_internals.h
diff -u /dev/null squid/src/ncomm_internals.h:1.1.2.6
--- /dev/null	Tue Sep 28 18:37:31 2004
+++ squid/src/ncomm_internals.h	Wed Nov 21 18:16:29 2001
@@ -0,0 +1,52 @@
+/*
+ * ncomm.c <-> ncomm_poll.c only
+ */
+
+/* Execute queued callbacks */
+extern void ncomm_call_callbacks(void);
+
+/* event callbacks */
+typedef int COMMEVENTREAD(filehandle *fh);
+typedef int COMMEVENTWRITE(filehandle *fh);
+
+/* event registration */
+void comm_register_for_read_event(filehandle *fh, COMMEVENTREAD *handler);
+void comm_register_for_write_event(filehandle *fh, COMMEVENTWRITE *handler);
+
+/* internal filehandle structure */
+typedef struct {
+    size_t size;
+    COMMIOCB *callback;
+    void *cbdata;
+} fh_read_t;
+typedef struct _fh_write fh_write_t;
+struct _fh_write {
+    fh_write_t *next;
+    IOBuf *buf;
+    size_t offset;
+    size_t size;
+    size_t done;
+    COMMIOCB *callback;
+    void *cbdata;
+};
+typedef struct {
+    void *cbdata;
+    COMMNEWCB *callback;
+} fh_connect_t;
+struct _file_handle {
+    int fd;
+    fh_read_t read;
+    fh_write_t *write;
+    fh_connect_t connect;
+    void *eventdata;
+    socklen_t addrsize;
+    struct sockaddr peer;
+    struct sockaddr local;
+    COMMEVENTREAD *read_handler;
+    COMMEVENTWRITE *write_handler;
+    unsigned int closed:1;
+    unsigned int shutdown_read:1;
+    unsigned int shutdown_write:1;
+    unsigned int transparent:1;	/* look up the real destination in NAT */
+};
+
Index: squid/src/ncomm_poll.c
diff -u /dev/null squid/src/ncomm_poll.c:1.1.2.3
--- /dev/null	Tue Sep 28 18:37:31 2004
+++ squid/src/ncomm_poll.c	Sat Feb 24 17:15:32 2001
@@ -0,0 +1,139 @@
+#include "squid.h"
+#include "ncomm_internals.h"
+
+/*
+ * Magics for poll(2)
+ */
+static struct pollfd pollfds[FD_SETSIZE];
+static filehandle *pollfh[FD_SETSIZE];
+static unsigned int pollnfds = 0;
+static unsigned int pollfirstfree = 1; /* 0 is skipped to simplify logics */
+
+static inline void
+cleanup_poll(int fd, unsigned int poll_index)
+{
+    if (!pollfds[poll_index].events) {
+	pollfh[poll_index]->eventdata = NULL;
+	cbdataUnreference(pollfh[poll_index]);
+	pollfds[poll_index].fd = -1;
+	if (poll_index < pollfirstfree)
+	    pollfirstfree = poll_index;
+	if (poll_index == pollnfds) {
+	    /* Shrink the active set */
+	    while(pollnfds > 0 && pollfds[pollnfds].fd == -1)
+		pollnfds--;
+	}
+    }
+}
+
+static inline void
+comm_read_event(filehandle *fh, int fd, int poll_index)
+{
+    int done = fh->read_handler(fh);
+
+    if (done) {
+	pollfds[poll_index].events &= ~POLLIN;
+	fh->read_handler = NULL;
+	cleanup_poll(fd, (unsigned int)poll_index);
+    }
+}
+
+
+static inline void
+comm_write_event(filehandle *fh, int fd, int poll_index)
+{
+    int done = fh->write_handler(fh);
+
+    if (done) {
+	pollfds[poll_index].events &= ~POLLOUT;
+	fh->write_handler = NULL;
+	cleanup_poll(fd, (unsigned int)poll_index);
+    }
+}
+
+#define CALLBACK_MAGIC 16
+void
+ncomm_handle_events(int timeout)
+{
+    int poll_index;
+    struct pollfd *pollfd;
+    int fds = poll(pollfds+1 /* skip position 0 */, pollnfds, timeout);
+    int callback_limit = CALLBACK_MAGIC;
+    for (poll_index=1, pollfd = pollfds+1; poll_index <= (int)pollnfds && fds > 0; poll_index++, pollfd++) {
+	short revents = pollfd->revents;
+	if(revents) {
+	    int fd = pollfd->fd;
+	    filehandle *fh = pollfh[poll_index];
+	    assert(fh->fd == fd);
+	    assert(fh->eventdata == &pollfds[poll_index]);
+	    fds--;
+	    if (revents & POLLIN) {
+		comm_read_event(fh, fd, poll_index);
+	    } else if (revents & POLLOUT) {
+		comm_write_event(fh, fd, poll_index);
+	    } else if (revents & (POLLHUP | POLLERR | POLLNVAL)) {
+		short events = pollfds[poll_index].events;
+		/* I am pretty sure there is better ways to handle errors.. */
+		if (events & POLLOUT)
+		    comm_write_event(fh, fd, poll_index);
+		else if (events & POLLIN)
+		    comm_read_event(fh, fd, poll_index);
+	    }
+	    if (--callback_limit == 0) {
+		ncomm_call_callbacks();
+		callback_limit = CALLBACK_MAGIC;
+	    }
+	}
+    }
+    if (callback_limit != CALLBACK_MAGIC)
+	ncomm_call_callbacks();
+}
+
+static void
+comm_register_for_event(filehandle *fh, enum comm_event_type event)
+{
+    struct pollfd *pollfd = fh->eventdata;
+    int fd = fh->fd;
+    short events = 0;
+    switch (event) {
+    case EVENT_READ:
+	events = POLLIN;
+	break;
+    case EVENT_WRITE:
+	events = POLLOUT;
+	break;
+    default:
+	/* ERROR! */
+	return;
+    }
+    if (!pollfd) {
+	int poll_index = pollfirstfree;
+	while (pollfds[poll_index].fd >= 0 && poll_index < (int)pollnfds)
+	    poll_index++;
+	if (poll_index > (int)pollnfds)
+	    pollnfds = (unsigned int)poll_index;
+	pollfirstfree = poll_index + 1;
+	pollfd = &pollfds[poll_index];
+	pollfd->fd = fd;
+	pollfh[poll_index] = cbdataReference(fh);
+	fh->eventdata = pollfd;
+    }
+    assert(pollfd->fd == fd);
+    pollfd->events |= events;
+}
+
+void
+comm_register_for_read_event(filehandle *fh, COMMEVENTREAD *handler)
+{
+    assert(!fh->read_handler);
+    fh->read_handler = handler;
+    comm_register_for_event(fh, EVENT_READ);
+}
+
+void
+comm_register_for_write_event(filehandle *fh, COMMEVENTWRITE *handler)
+{
+    assert(!fh->write_handler);
+    fh->write_handler = handler;
+    comm_register_for_event(fh, EVENT_WRITE);
+}
Index: squid/src/ncomm_test.c
diff -u /dev/null squid/src/ncomm_test.c:1.1.2.9
--- /dev/null	Tue Sep 28 18:37:31 2004
+++ squid/src/ncomm_test.c	Tue Mar  6 23:22:24 2001
@@ -0,0 +1,199 @@
+#include "squid.h"
+
+typedef struct {
+    filehandle *client;
+    filehandle *server;
+} connection;
+
+CBDATA_TYPE(connection);
+
+void fatalf(const char *fmt,...)
+{
+    fatal(fmt);
+}
+
+void fatal(const char *message)
+{
+    fprintf(stderr, "FATAL: %s (%s)\n", message, strerror(errno));
+    abort();
+}
+
+static void
+got_server_data(filehandle *fh, IOBuf *buf, int offset, int len, int error, void *cbdata)
+{
+    connection *conn = cbdata;
+    printf("Got %d server bytes\n", len);
+    if (len > 0) {
+	ncomm_write(conn->client, buf, NULL, NULL);
+	ncomm_read(fh, got_server_data, conn);
+    } else {
+	ncomm_close(conn->client);
+	if (ncomm_closed(fh))
+	    cbdataFree(conn);
+    }
+}
+
+static void
+got_client_data(filehandle *fh, IOBuf *buf, int offset, int len, int error, void *cbdata)
+{
+    connection *conn = cbdata;
+    printf("Got %d client bytes\n", len);
+    if (len > 0) {
+	ncomm_write(conn->server, buf, NULL, NULL);
+	ncomm_read(fh, got_client_data, conn);
+    } else {
+	ncomm_close(conn->server);
+	if (ncomm_closed(fh))
+	    cbdataFree(conn);
+    }
+}
+
+static void
+new_server_connection(filehandle *fh, int error, struct sockaddr *local, struct sockaddr *remote, int addrsize, void *cbdata)
+{
+    connection *conn = cbdata;
+    if (error) {
+	errno = error;
+	fatal("server connect failed");
+    }
+    conn->server = cbdataReference(fh);
+    ncomm_read(conn->client, got_client_data, conn);
+    ncomm_read(conn->server, got_server_data, conn);
+}
+
+static void
+new_client_connection(filehandle *fh, int error, struct sockaddr *local, struct sockaddr *remote_client, int addrsize, void *cbdata)
+{
+    connection *conn;
+    struct sockaddr_in remote;
+    printf("New connection!\n");
+    conn = cbdataAlloc(connection);
+    conn->client = cbdataReference(fh);
+    memset(&remote, 0, sizeof remote);
+    remote.sin_family = AF_INET;
+    remote.sin_port = htons(80);
+    inet_aton("127.0.0.1", &remote.sin_addr);
+    ncomm_connect(SOCK_STREAM, 0, NULL, (struct sockaddr *)&remote, sizeof remote, new_server_connection, conn);
+}
+
+static void
+new_debug_connection(filehandle *fh, int error, struct sockaddr *local, struct sockaddr *remote_client, int addrsize, void *cbdata)
+{
+    if (fh) {
+	IOBuf *buf = memReport();
+	ncomm_write(fh, buf, NULL, NULL);
+	cbdataUnreference(buf);
+	ncomm_close(fh);
+    }
+}
+
+static void destroy_connection(void *cbdata)
+{
+    connection *conn = cbdata;
+
+    cbdataUnreference(conn->server);
+    cbdataUnreference(conn->client);
+}
+
+int main(int argc, char **argv)
+{
+    struct sockaddr_in me;
+    filehandle *lfh, *debugfh;
+    cbdataInit();
+    memInit();
+    memBuf_module_init();
+    ncomm_module_init();
+
+    ConfigFile = xstrdup(DefaultConfigFile);
+
+    memInitModule();
+
+    parseConfigFile(ConfigFile);
+
+
+    clientHttpConnectionsOpen();
+
+    CBDATA_INIT_TYPE_FREECB(connection, destroy_connection);
+
+    memset(&me, 0, sizeof(me));
+    me.sin_family = AF_INET;
+    me.sin_port = htons(45678);
+    lfh = ncomm_listen(SOCK_STREAM, 0, (struct sockaddr *)&me, sizeof(me), 8192, new_client_connection, NULL);
+    me.sin_port = htons(55555);
+    debugfh = ncomm_listen(SOCK_STREAM, 0, (struct sockaddr *)&me, sizeof(me), 8192, new_debug_connection, NULL);
+
+    while(1)
+	ncomm_handle_events(1000);
+
+    return 0;
+}
+
+
+
+
+/* DUMMY while testing */
+
+void peerDestroy(void *data) { }
+int authenticateSchemeCount(void) { return 0; }
+int authenticateActiveSchemeCount(void) { return 0; }
+const ipcache_addrs *ipcache_gethostbyname(const char *host, int flags) { return NULL; }
+void ipcache_nbgethostbyname(const char *name, IPH *handler, void *cbdata) { handler(NULL, cbdata); }
+ipcache_addrs *ipcacheCheckNumeric(const char *name) { return NULL; }
+const char *fqdncache_gethostbyaddr(struct in_addr saddr, int flags) { return NULL; }
+void fqdncache_nbgethostbyaddr(struct in_addr saddr, FQDNH *handler, void *cbdata) { handler(NULL, cbdata); }
+int clientdbEstablished(struct in_addr saddr, int something) { return 0; }
+int asnMatchIp(void *data, struct in_addr saddr) { return 0; }
+void enter_suid(void) { }
+void leave_suid(void) { }
+void cachemgrRegister(const char *a, const char *b, OBJH *c, int d, int e) { }
+void storeDirConfigure(void) { }
+void storeConfigure(void) { }
+const char *uniqueHostname(void) { return "henrik"; }
+void storeAppend(StoreEntry *a, const char *b, int c) { }
+void storeAppendPrintf(StoreEntry *a, const char *b,...) { }
+struct in_addr inaddrFromHostent(const struct hostent *hp) { struct in_addr addr = { s_addr : INADDR_ANY }; return addr; }
+int authenticateAuthSchemeId(const char *typestr) { return -1; }
+char *neighborTypeStr(const peer * e) { return NULL; }
+void dump_peer_options(StoreEntry *a, peer *b) { }
+PeerDigest *peerDigestCreate(peer * p) { return NULL; }
+void peerClearRR(void *a) { }
+peer *peerFindByName(const char *a) { return NULL; }
+int internalCheck(const char *urlpath) { return 0; }
+char *internalLocalUri(const char *dir, const char *name) { return "http://UNKNOWN/"; };
+int errorReservePageId(const char *page_name) { return 0; }
+auth_user_request_t *authenticateGetAuthUser(const char *proxy_auth) { return NULL; }
+int authenticateValidateUser(auth_user_request_t *a) { return 0; }
+char *authenticateUserRequestUsername(auth_user_request_t *a) { return NULL; }
+void authenticateAuthUserRequestLock(auth_user_request_t *a) { }
+void authenticateAuthUserRequestSetIp(auth_user_request_t *a, struct in_addr b) { }
+int authenticateUserAuthenticated(auth_user_request_t *a) { return 0; }
+void authenticateAuthenticateUser(auth_user_request_t *a, request_t *b, ConnStateData *c, http_hdr_type d) { }
+int authenticateDirection(auth_user_request_t *a) { return 0; }
+void authenticateAuthUserRequestUnlock(auth_user_request_t *a) { }
+int authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user) { return 0; }
+void authenticateStart(auth_user_request_t *a, RH *b, void *c) { }
+void identStart(struct sockaddr_in *me, struct sockaddr_in *peer, IDCB * callback, void *cbdata) { }
+void requestUnlink(request_t *a) { }
+request_t *requestLink(request_t *)
+
+void
+kb_incr(kb_t * k, size_t v)
+{
+    k->bytes += v;
+    k->kb += (k->bytes >> 10);
+    k->bytes &= 0x3FF;
+}
+
+int
+stringHasCntl(const char *s)
+{
+    unsigned char c;
+    while ((c = (unsigned char) *s++) != '\0') {
+	if (c <= 0x1f)
+	    return 1;
+	if (c >= 0x7f && c <= 0x9f)
+	    return 1;
+    }
+    return 0;
+}
+
Index: squid/src/peer_digest.c
diff -u squid/src/peer_digest.c:1.10 squid/src/peer_digest.c:1.6.8.5
--- squid/src/peer_digest.c:1.10	Wed Oct 24 02:42:13 2001
+++ squid/src/peer_digest.c	Sat Nov 17 05:11:58 2001
@@ -327,7 +327,7 @@
 
     /* push towards peer cache */
     debug(72, 3) ("peerDigestRequest: forwarding to fwdStart...\n");
-    fwdStart(-1, e, req);
+    fwdStart(NULL, e, req);
     cbdataLock(fetch);
     cbdataLock(fetch->pd);
     storeClientCopy(fetch->sc, e, 0, 0, 4096, memAllocate(MEM_4K_BUF),
Index: squid/src/protos.h
diff -u squid/src/protos.h:1.41 squid/src/protos.h:1.18.8.17
--- squid/src/protos.h:1.41	Tue Nov 13 14:19:33 2001
+++ squid/src/protos.h	Sat Nov 17 05:11:58 2001
@@ -145,6 +145,7 @@
 extern int commSetNonBlocking(int fd);
 extern int commUnsetNonBlocking(int fd);
 extern void commSetCloseOnExec(int fd);
+
 extern int comm_accept(int fd, struct sockaddr_in *, struct sockaddr_in *);
 extern void comm_close(int fd);
 #if LINGERING_CLOSE
@@ -157,7 +158,6 @@
 extern int comm_open(int, int, struct in_addr, u_short port, int, const char *note);
 extern int comm_openex(int, int, struct in_addr, u_short, int, unsigned char TOS, const char *);
 extern u_short comm_local_port(int fd);
-
 extern void commSetSelect(int, unsigned int, PF *, void *, time_t);
 extern void comm_add_close_handler(int fd, PF *, void *);
 extern void comm_remove_close_handler(int fd, PF *, void *);
@@ -595,6 +595,8 @@
 extern int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr);
 
 /* MemBuf */
+extern void memBuf_module_init(void);
+extern void memBuf_module_shutdown(void);
 /* init with specific sizes */
 extern void memBufInit(MemBuf * mb, mb_size_t szInit, mb_size_t szMax);
 /* init with defaults */
@@ -698,7 +700,7 @@
 extern peer *netdbClosestParent(request_t *);
 extern void netdbHostData(const char *host, int *samp, int *rtt, int *hops);
 
-extern void cachemgrStart(int fd, request_t * request, StoreEntry * entry);
+extern void cachemgrStart(request_t * request, StoreEntry * entry);
 extern void cachemgrRegister(const char *, const char *, OBJH *, int, int);
 extern void cachemgrInit(void);
 
@@ -712,7 +714,7 @@
 extern void peerDigestStatsReport(const PeerDigest * pd, StoreEntry * e);
 
 /* forward.c */
-extern void fwdStart(int, StoreEntry *, request_t *);
+extern void fwdStart(filehandle *fh, StoreEntry *, request_t *);
 extern DEFER fwdCheckDeferRead;
 extern void fwdFail(FwdState *, ErrorState *);
 extern void fwdUnregister(int fd, FwdState *);
@@ -789,13 +791,12 @@
 
 
 extern void start_announce(void *unused);
-extern void sslStart(int fd, const char *, request_t *, size_t *, int *);
+extern void sslStart(filehandle *client_fh, const char *, request_t *, size_t *, int *);
 extern void waisStart(FwdState *);
 
 /* ident.c */
 #if USE_IDENT
-extern void identStart(struct sockaddr_in *me, struct sockaddr_in *my_peer,
-    IDCB * callback, void *cbdata);
+extern void identStart(struct sockaddr *local, struct sockaddr *remote, IDCB * callback, void *cbdata);
 extern void identInit(void);
 #endif
 
@@ -865,10 +866,7 @@
 extern int memPoolInUseCount(const MemPool * pool);
 extern size_t memPoolInUseSize(const MemPool * pool);
 extern int memPoolUsedCount(const MemPool * pool);
-extern void memPoolReport(const MemPool * pool, StoreEntry * e);
-
-/* Mem */
-extern void memReport(StoreEntry * e);
+extern IOBuf *memReport(void);
 
 extern int stmemFreeDataUpto(mem_hdr *, int);
 extern void stmemAppend(mem_hdr *, const char *, int);
@@ -1151,6 +1149,7 @@
 extern void dlinkDelete(dlink_node * m, dlink_list * list);
 extern void dlinkNodeDelete(dlink_node * m);
 extern dlink_node *dlinkNodeNew(void);
+extern void *dlinkGetFirst(dlink_list *);
 
 extern void kb_incr(kb_t *, size_t);
 extern double gb_to_double(const gb_t *);
@@ -1317,6 +1316,31 @@
  */
 extern StatCounters *snmpStatGet(int);
 
+/*
+ * ncomm.c
+ */
+void ncomm_module_init(void);
+void ncomm_module_shutdown(void);
+void ncomm_handle_events(int timeout);
+void ncomm_close(filehandle *fh);
+int ncomm_closed(filehandle *fh);
+void ncomm_abort(filehandle *fh);
+filehandle * ncomm_listen(int sock_type, int proto, struct sockaddr *where, int addrsize, int backlog, COMMNEWCB *callback, void *cbdata);
+filehandle * ncomm_listen_transparent(int sock_type, int proto, struct sockaddr *where, int addrsize, int backlog, COMMNEWCB *callback, void *cbdata);
+filehandle * ncomm_accept(int sock_type, int proto, struct sockaddr *where, struct sockaddr *from, int addrsize, COMMNEWCB callback, void *cbdata);
+filehandle * ncomm_connect(int sock_type, int proto, const struct sockaddr *local, const struct sockaddr *remote, int addrsize, COMMNEWCB *callback, void *cbdata);
+void ncomm_read(filehandle *fh, COMMIOCB *callback, void *cbdata);
+void ncomm_read_limited(filehandle *fh, size_t max_size, COMMIOCB *callback, void *cbdata);
+void ncomm_write(filehandle *fh, IOBuf *buf, COMMIOCB *callback, void *cbdata);
+void ncomm_write_fragment(filehandle *fh, IOBuf *buf, size_t offset, size_t len, COMMIOCB *callback, void *cbdata);
+void ncomm_write_mbuf(filehandle *fh, MemBuf mb, COMMIOCB *callback, void *cbdata);
+int ncomm_sendto(filehandle *fh, const struct sockaddr *to_addr, int addr_len, const void *msg, int msglen);
+int ncomm_add_close_handler(filehandle *fh, COMMCLOSECB *handler, void *cbdata);
+IOBuf *IOBufAlloc(size_t size);
+IOBuf *IOBufCreate(void *data, size_t size);
+IOBuf *IOBufCreateFromMemBuf(MemBuf *mb);
+extern void ncomm_note(filehandle *fh, const char *);
+
 /* Vary support functions */
 int varyEvaluateMatch(StoreEntry * entry, request_t * req);
 
Index: squid/src/squid.h
diff -u squid/src/squid.h:1.13 squid/src/squid.h:1.9.10.7
--- squid/src/squid.h:1.13	Tue Nov 13 14:19:33 2001
+++ squid/src/squid.h	Sat Nov 17 05:11:58 2001
@@ -463,6 +463,17 @@
  */
 #define INDEXSD(i)   (&Config.cacheSwap.swapDirs[(i)])
 
+/*
+ * macros to simplify cbdata operations
+ * Usage:
+ *    pointer = cbdataReference(cbdata);
+ *    pointer = cbdataEatReference(cbdata);
+ *    cbdataUnreference(&cbdata);
+ */
+#define cbdataReference(data) (cbdataLock(data), data)
+#define cbdataUnreference(data) data = (cbdataUnlock(data), NULL)
+#define cbdataEatReference(data) data; data = NULL
+
 #define FD_READ_METHOD(fd, buf, len) (*fd_table[fd].read_method)(fd, buf, len)
 #define FD_WRITE_METHOD(fd, buf, len) (*fd_table[fd].write_method)(fd, buf, len)
 
Index: squid/src/ssl.c
diff -u squid/src/ssl.c:1.13 squid/src/ssl.c:1.6.12.5
--- squid/src/ssl.c:1.13	Tue Oct 30 05:32:08 2001
+++ squid/src/ssl.c	Sat Nov 17 05:11:58 2001
@@ -35,6 +35,7 @@
 
 #include "squid.h"
 
+#if NOT_YET_PORTED
 typedef struct {
     char *url;
     char *host;			/* either request->host or proxy host */
@@ -431,7 +432,7 @@
 
 CBDATA_TYPE(SslStateData);
 void
-sslStart(int fd, const char *url, request_t * request, size_t * size_ptr, int *status_ptr)
+sslStart(filehandle *fh, const char *url, request_t * request, size_t * size_ptr, int *status_ptr)
 {
     /* Create state structure. */
     SslStateData *sslState = NULL;
@@ -547,7 +548,7 @@
     httpHeaderClean(&hdr_out);
     packerClean(&p);
     memBufAppend(&mb, "\r\n", 2);
-    xstrncpy(sslState->client.buf, mb.buf, SQUID_TCP_SO_RCVBUF);
+    xstrncpy(sslState->client.buf, *mb.bufp, SQUID_TCP_SO_RCVBUF);
     debug(26, 3) ("sslProxyConnected: Sending {%s}\n", sslState->client.buf);
     sslState->client.len = mb.size;
     memBufClean(&mb);
@@ -605,3 +606,9 @@
 	sslConnectDone,
 	sslState);
 }
+#else
+void
+sslStart(filehandle *fh, const char *url, request_t * request, size_t * size_ptr, int *status_ptr)
+{
+}
+#endif /* NOT_YET_PORTED */
Index: squid/src/stat.c
diff -u squid/src/stat.c:1.13 squid/src/stat.c:1.8.8.4
--- squid/src/stat.c:1.13	Wed Oct 24 02:42:13 2001
+++ squid/src/stat.c	Sat Nov 17 05:11:58 2001
@@ -1398,19 +1398,21 @@
     clientHttpRequest *http;
     ConnStateData *conn;
     StoreEntry *e;
-    int fd;
+    filehandle *fh;
     for (i = ClientActiveRequests.head; i; i = i->next) {
 	http = i->data;
 	assert(http);
 	conn = http->conn;
 	storeAppendPrintf(s, "Connection: %p\n", conn);
 	if (conn) {
-	    fd = conn->fd;
-	    storeAppendPrintf(s, "\tFD %d, read %d, wrote %d\n", fd,
+	    fh = conn->fh;
+#if NOT_YET_PORTED
+	    storeAppendPrintf(s, "\tFH %p, read %d, wrote %d\n", fh,
 		fd_table[fd].bytes_read, fd_table[fd].bytes_written);
-	    storeAppendPrintf(s, "\tFD desc: %s\n", fd_table[fd].desc);
-	    storeAppendPrintf(s, "\tin: buf %p, offset %ld, size %ld\n",
-		conn->in.buf, (long int) conn->in.offset, (long int) conn->in.size);
+	    storeAppendPrintf(s, "\tFH desc: %s\n", ncomm_get_note(fh));
+#endif
+	    storeAppendPrintf(s, "\tin: buf %p, size %ld\n",
+		conn->in, (long int)IOBufSize(conn->in));
 	    storeAppendPrintf(s, "\tpeer: %s:%d\n",
 		inet_ntoa(conn->peer.sin_addr),
 		ntohs(conn->peer.sin_port));
Index: squid/src/store.c
diff -u squid/src/store.c:1.16 squid/src/store.c:1.9.12.6
--- squid/src/store.c:1.16	Wed Oct 24 02:42:13 2001
+++ squid/src/store.c	Sat Nov 17 05:11:58 2001
@@ -121,7 +121,6 @@
 #endif
     mem->log_url = xstrdup(log_url);
     mem->object_sz = -1;
-    mem->fd = -1;
     /* XXX account log_url */
     debug(20, 3) ("new_MemObject: returning %p\n", mem);
     return mem;
@@ -159,7 +158,7 @@
      * There is no way to abort FD-less clients, so they might
      * still have mem->clients set if mem->fd == -1
      */
-    assert(mem->fd == -1 || mem->clients.head == NULL);
+    assert(mem->clients.head == NULL);
     httpReplyDestroy(mem->reply);
     requestUnlink(mem->request);
     mem->request = NULL;
Index: squid/src/store_client.c
diff -u squid/src/store_client.c:1.9 squid/src/store_client.c:1.6.12.4
--- squid/src/store_client.c:1.9	Wed Oct 24 02:42:13 2001
+++ squid/src/store_client.c	Sat Nov 17 05:11:58 2001
@@ -512,13 +512,6 @@
 	return 0;
     if (mem->clients.head == NULL)
 	return 0;
-    if (sc == mem->clients.head->data) {
-	/*
-	 * If we are unregistering the _first_ client for this
-	 * entry, then we have to reset the client FD to -1.
-	 */
-	mem->fd = -1;
-    }
     dlinkDelete(&sc->node, &mem->clients);
     mem->nclients--;
     if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
Index: squid/src/store_dir.c
diff -u squid/src/store_dir.c:1.19 squid/src/store_dir.c:1.12.8.5
--- squid/src/store_dir.c:1.19	Wed Oct 24 02:42:14 2001
+++ squid/src/store_dir.c	Sat Nov 17 05:11:59 2001
@@ -321,6 +321,8 @@
 {
     SwapDir *SD;
     int i;
+    if (Config.cacheSwap.swapDirs == NULL)
+	fatal("No cache_dir's specified in config file");
     Config.Swap.maxSize = 0;
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
 	SD = &Config.cacheSwap.swapDirs[i];
Index: squid/src/store_key_md5.c
diff -u squid/src/store_key_md5.c:1.6 squid/src/store_key_md5.c:1.5.12.2
--- squid/src/store_key_md5.c:1.6	Fri Apr 13 17:31:02 2001
+++ squid/src/store_key_md5.c	Sat Apr 14 06:43:18 2001
@@ -45,7 +45,7 @@
     memBufReset(&mb);
     for (i = 0; i < MD5_DIGEST_CHARS; i++)
 	memBufPrintf(&mb, "%02X", *(key + i));
-    return mb.buf;
+    return *mb.bufp;
 }
 
 const cache_key *
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.47 squid/src/structs.h:1.24.8.16
--- squid/src/structs.h:1.47	Wed Oct 24 02:42:14 2001
+++ squid/src/structs.h	Sat Nov 17 05:11:59 2001
@@ -743,6 +743,9 @@
     int weak;			/* true if it is a weak validator */
 };
 
+/*
+ * old comm.c data
+ */
 struct _fde {
     unsigned int type;
     u_short local_port;
@@ -787,6 +790,8 @@
     DEFER *defer_check;		/* check if we should defer read */
     void *defer_data;
     CommWriteStateData *rwstate;	/* State data for comm_write */
+    /* ncomm stuff */
+    filehandle *fh;
     READ_HANDLER *read_method;
     WRITE_HANDLER *write_method;
 #if USE_SSL
@@ -807,13 +812,12 @@
 /* note: when updating this struct, update MemBufNULL #define */
 struct _MemBuf {
     /* public, read-only */
-    char *buf;
+    char **bufp;
     mb_size_t size;		/* used space, does not count 0-terminator */
 
     /* private, stay away; use interface function instead */
     mb_size_t max_capacity;	/* when grows: assert(new_capacity <= max_capacity) */
     mb_size_t capacity;		/* allocated space */
-    FREE *freefunc;		/* what to use to free the buffer, NULL after memBufFreeFunc() is called */
 };
 
 /* see Packer.c for description */
@@ -1078,12 +1082,9 @@
 };
 
 struct _ConnStateData {
-    int fd;
-    struct {
-	char *buf;
-	off_t offset;
-	size_t size;
-    } in;
+    filehandle *fh;
+    MemBuf *in;
+    off_t in_offset;
     struct {
 	size_t size_left;	/* How much body left to process */
 	request_t *request;	/* Parameters passed to clientReadBody */
@@ -1484,7 +1485,6 @@
     struct timeval start_ping;
     IRCB *ping_reply_callback;
     void *ircb_data;
-    int fd;			/* FD of client creating this entry */
     struct {
 	STABH *callback;
 	void *data;
@@ -1943,7 +1943,7 @@
 };
 
 struct _FwdState {
-    int client_fd;
+    filehandle *client_fh;
     StoreEntry *entry;
     request_t *request;
     FwdServer *servers;
Index: squid/src/tools.c
diff -u squid/src/tools.c:1.19 squid/src/tools.c:1.10.12.8
--- squid/src/tools.c:1.19	Sat Nov 17 17:15:42 2001
+++ squid/src/tools.c	Wed Nov 21 18:19:02 2001
@@ -62,8 +62,6 @@
 
 extern void (*failure_notify) (const char *);
 
-MemPool *dlink_node_pool = NULL;
-
 void
 releaseServerSockets(void)
 {
@@ -767,64 +765,6 @@
     return p ? p : "(NULL)";
 }
 
-dlink_node *
-dlinkNodeNew()
-{
-    if (dlink_node_pool == NULL)
-	dlink_node_pool = memPoolCreate("Dlink list nodes", sizeof(dlink_node));
-    /* where should we call memPoolDestroy(dlink_node_pool); */
-    return memPoolAlloc(dlink_node_pool);
-}
-
-/* the node needs to be unlinked FIRST */
-void
-dlinkNodeDelete(dlink_node * m)
-{
-    if (m == NULL)
-	return;
-    memPoolFree(dlink_node_pool, m);
-}
-
-void
-dlinkAdd(void *data, dlink_node * m, dlink_list * list)
-{
-    m->data = data;
-    m->prev = NULL;
-    m->next = list->head;
-    if (list->head)
-	list->head->prev = m;
-    list->head = m;
-    if (list->tail == NULL)
-	list->tail = m;
-}
-
-void
-dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
-{
-    m->data = data;
-    m->next = NULL;
-    m->prev = list->tail;
-    if (list->tail)
-	list->tail->next = m;
-    list->tail = m;
-    if (list->head == NULL)
-	list->head = m;
-}
-
-void
-dlinkDelete(dlink_node * m, dlink_list * list)
-{
-    if (m->next)
-	m->next->prev = m->prev;
-    if (m->prev)
-	m->prev->next = m->next;
-    if (m == list->head)
-	list->head = m->next;
-    if (m == list->tail)
-	list->tail = m->prev;
-    m->next = m->prev = NULL;
-}
-
 void
 kb_incr(kb_t * k, size_t v)
 {
@@ -834,43 +774,6 @@
 }
 
 void
-gb_flush(gb_t * g)
-{
-    g->gb += (g->bytes >> 30);
-    g->bytes &= (1 << 30) - 1;
-}
-
-double
-gb_to_double(const gb_t * g)
-{
-    return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes);
-}
-
-const char *
-gb_to_str(const gb_t * g)
-{
-    /*
-     * it is often convenient to call gb_to_str several times for _one_ printf
-     */
-#define max_cc_calls 5
-    typedef char GbBuf[32];
-    static GbBuf bufs[max_cc_calls];
-    static int call_id = 0;
-    double value = gb_to_double(g);
-    char *buf = bufs[call_id++];
-    if (call_id >= max_cc_calls)
-	call_id = 0;
-    /* select format */
-    if (value < 1e9)
-	snprintf(buf, sizeof(GbBuf), "%.2f MB", value / 1e6);
-    else if (value < 1e12)
-	snprintf(buf, sizeof(GbBuf), "%.2f GB", value / 1e9);
-    else
-	snprintf(buf, sizeof(GbBuf), "%.2f TB", value / 1e12);
-    return buf;
-}
-
-void
 debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
 {
     MemBuf mb;
@@ -879,7 +782,7 @@
     memBufDefInit(&mb);
     packerToMemInit(&p, &mb);
     (*pm) (obj, &p);
-    debug(section, level) ("%s%s", label, mb.buf);
+    debug(section, level) ("%s%s", label, *mb.bufp);
     packerClean(&p);
     memBufClean(&mb);
 }
Index: squid/src/typedefs.h
diff -u squid/src/typedefs.h:1.25 squid/src/typedefs.h:1.15.8.11
--- squid/src/typedefs.h:1.25	Wed Oct 10 11:07:43 2001
+++ squid/src/typedefs.h	Sat Nov 17 05:11:59 2001
@@ -92,6 +92,7 @@
 typedef struct _dnsserver_t dnsserver_t;
 typedef struct _dwrite_q dwrite_q;
 typedef struct _ETag ETag;
+typedef struct _file_handle filehandle;
 typedef struct _fde fde;
 typedef struct _fileMap fileMap;
 typedef struct _HttpReply http_reply;
@@ -360,4 +361,12 @@
 
 typedef int STDIRSELECT(const StoreEntry *);
 
+/*
+ * ncomm.c 
+ */
+typedef MemBuf IOBuf;
+typedef void COMMNEWCB(filehandle *fh, int error, struct sockaddr *local, struct sockaddr *peer, int addrsize, void *cbdata);
+typedef void COMMIOCB(filehandle *fh, IOBuf *buf, int offset, int size, int error, void *cbdata);
+typedef void COMMCLOSECB(filehandle *fh, void *cbdata);
+
 #endif /* SQUID_TYPEDEFS_H */
Index: squid/src/urn.c
diff -u squid/src/urn.c:1.11 squid/src/urn.c:1.8.8.4
--- squid/src/urn.c:1.11	Wed Oct 24 02:42:14 2001
+++ squid/src/urn.c	Sat Nov 17 05:11:59 2001
@@ -139,7 +139,7 @@
     if ((urlres_e = storeGetPublic(urlres, METHOD_GET)) == NULL) {
 	urlres_e = storeCreateEntry(urlres, urlres, null_request_flags, METHOD_GET);
 	urnState->sc = storeClientListAdd(urlres_e, urnState);
-	fwdStart(-1, urlres_e, urlres_r);
+	fwdStart(NULL, urlres_e, urlres_r);
     } else {
 	storeLockObject(urlres_e);
 	urnState->sc = storeClientListAdd(urlres_e, urnState);
Index: squid/src/wais.c
diff -u squid/src/wais.c:1.8 squid/src/wais.c:1.5.12.3
--- squid/src/wais.c:1.8	Wed Oct 24 02:42:14 2001
+++ squid/src/wais.c	Sat Nov 17 05:11:59 2001
@@ -209,7 +209,7 @@
 	packerClean(&p);
     }
     memBufPrintf(&mb, "\r\n");
-    debug(24, 6) ("waisSendRequest: buf: %s\n", mb.buf);
+    debug(24, 6) ("waisSendRequest: buf: %s\n", *mb.bufp);
     comm_write_mbuf(fd, mb, waisSendComplete, waisState);
     if (EBIT_TEST(waisState->entry->flags, ENTRY_CACHABLE))
 	storeSetPublicKey(waisState->entry);	/* Make it public */
Index: squid/src/wordlist.c
diff -u /dev/null squid/src/wordlist.c:1.1.2.1
--- /dev/null	Tue Sep 28 18:37:32 2004
+++ squid/src/wordlist.c	Sat Feb 24 15:48:43 2001
@@ -0,0 +1,66 @@
+#include "squid.h"
+
+void
+wordlistDestroy(wordlist ** list)
+{
+    wordlist *w = NULL;
+    while ((w = *list) != NULL) {
+	*list = w->next;
+	safe_free(w->key);
+	memFree(w, MEM_WORDLIST);
+    }
+    *list = NULL;
+}
+
+const char *
+wordlistAdd(wordlist ** list, const char *key)
+{
+    while (*list)
+	list = &(*list)->next;
+    *list = memAllocate(MEM_WORDLIST);
+    (*list)->key = xstrdup(key);
+    (*list)->next = NULL;
+    return (*list)->key;
+}
+
+void
+wordlistJoin(wordlist ** list, wordlist ** wl)
+{
+    while (*list)
+	list = &(*list)->next;
+    *list = *wl;
+    *wl = NULL;
+}
+
+void
+wordlistAddWl(wordlist ** list, wordlist * wl)
+{
+    while (*list)
+	list = &(*list)->next;
+    for (; wl; wl = wl->next, list = &(*list)->next) {
+	*list = memAllocate(MEM_WORDLIST);
+	(*list)->key = xstrdup(wl->key);
+	(*list)->next = NULL;
+    }
+}
+
+void
+wordlistCat(const wordlist * w, MemBuf * mb)
+{
+    while (NULL != w) {
+	memBufPrintf(mb, "%s\n", w->key);
+	w = w->next;
+    }
+}
+
+wordlist *
+wordlistDup(const wordlist * w)
+{
+    wordlist *D = NULL;
+    while (NULL != w) {
+	wordlistAdd(&D, w->key);
+	w = w->next;
+    }
+    return D;
+}
+