This patch is generated from the ipc branch of HEAD in squid3
Mon May 14 18:16:43 2007 GMT
See http://devel.squid-cache.org/

Index: squid3/configure.in
diff -u squid3/configure.in:1.132 squid3/configure.in:1.85.2.12
--- squid3/configure.in:1.132	Mon Apr 16 17:56:31 2007
+++ squid3/configure.in	Sat Apr 28 09:34:46 2007
@@ -5,7 +5,7 @@
 dnl
 dnl
 dnl
-AC_INIT(Squid Web Proxy, 3.0.PRE5-CVS, http://www.squid-cache.org/bugs/, squid)
+AC_INIT(Squid Web Proxy, 3.0.PRE5-IPC-CVS, http://www.squid-cache.org/bugs/, squid)
 AC_PREREQ(2.52)
 AM_CONFIG_HEADER(include/autoconf.h)
 AC_CONFIG_AUX_DIR(cfgaux)
@@ -75,12 +75,8 @@
 		LIBS="$LIBS -lpsapi"
 	fi
 	MINGW_LIBS="-lmingwex"
-	AM_CONDITIONAL(USE_IPC_WIN32, true)
 	AC_SUBST(MINGW_LIBS)
 	;;
-*)
-	AM_CONDITIONAL(USE_IPC_WIN32, false)
-	;;
 esac
 
 if test -z "$CACHE_HTTP_PORT"; then
Index: squid3/src/Makefile.am
diff -u squid3/src/Makefile.am:1.118 squid3/src/Makefile.am:1.68.2.19
--- squid3/src/Makefile.am:1.118	Tue Apr 24 09:54:46 2007
+++ squid3/src/Makefile.am	Sat Apr 28 09:35:19 2007
@@ -151,12 +151,6 @@
 WINSVC_SOURCE =
 endif
 
-if USE_IPC_WIN32
-IPC_SOURCE = ipc_win32.cc
-else
-IPC_SOURCE = ipc.cc
-endif
-
 AIO_WIN32_ALL_SOURCES = \
 	DiskIO/AIO/aio_win32.cc \
 	DiskIO/AIO/aio_win32.h
@@ -278,8 +272,6 @@
 	dns_internal.cc \
 	htcp.cc \
 	htcp.h \
-	ipc.cc \
-	ipc_win32.cc \
 	$(IDENT_ALL_SOURCE) \
 	$(ESI_ALL_SOURCE) \
 	ProfStats.cc \
@@ -514,7 +506,8 @@
 	$(IDENT_SOURCE) \
 	int.cc \
 	internal.cc \
-	$(IPC_SOURCE) \
+	ipc.cc \
+	ipc.h \
 	ipcache.cc \
 	$(LEAKFINDERSOURCE) \
 	list.cc \
@@ -806,7 +799,7 @@
 	icp_v3.cc \
 	$(IDENT_SOURCE) \
 	internal.cc \
-	$(IPC_SOURCE) \
+	ipc.cc \
 	ipcache.cc \
 	$(LEAKFINDERSOURCE) \
         list.cc \
@@ -1297,7 +1290,7 @@
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IDENT_SOURCE) \
-	$(IPC_SOURCE) \
+	ipc.cc \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
@@ -1462,7 +1455,7 @@
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IDENT_SOURCE) \
-	$(IPC_SOURCE) \
+	ipc.cc \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
@@ -1613,7 +1606,7 @@
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IDENT_SOURCE) \
-	$(IPC_SOURCE) \
+	ipc.cc \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
@@ -1794,7 +1787,7 @@
 	$(IDENT_SOURCE) \
 	int.cc \
 	internal.cc \
-	$(IPC_SOURCE) \
+	ipc.cc \
 	ipcache.cc \
 	list.cc \
 	logfile.cc \
@@ -1945,7 +1938,7 @@
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IDENT_SOURCE) \
-	$(IPC_SOURCE) \
+	ipc.cc \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
@@ -2281,7 +2274,7 @@
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IDENT_SOURCE) \
-	$(IPC_SOURCE) \
+	ipc.cc \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
Index: squid3/src/defines.h
diff -u squid3/src/defines.h:1.15 squid3/src/defines.h:1.12.4.3
--- squid3/src/defines.h:1.15	Sun Aug 20 18:51:49 2006
+++ squid3/src/defines.h	Sun Sep  3 09:23:50 2006
@@ -180,21 +180,6 @@
 #define STORE_META_DIRTY  0x04
 #define STORE_META_BAD    0x05
 
-#define IPC_NONE 0
-#define IPC_TCP_SOCKET 1
-#define IPC_UDP_SOCKET 2
-#define IPC_FIFO 3
-#define IPC_UNIX_STREAM 4
-#define IPC_UNIX_DGRAM 5
-
-#if HAVE_SOCKETPAIR && defined (AF_UNIX)
-#define IPC_STREAM IPC_UNIX_STREAM
-#define IPC_DGRAM IPC_UNIX_DGRAM
-#else
-#define IPC_STREAM IPC_TCP_SOCKET
-#define IPC_DGRAM IPC_UDP_SOCKET
-#endif
-
 #define STORE_META_KEY STORE_META_KEY_MD5
 
 #define STORE_META_TLD_START sizeof(int)+sizeof(char)
Index: squid3/src/dns.cc
diff -u squid3/src/dns.cc:1.13 squid3/src/dns.cc:1.7.16.6
--- squid3/src/dns.cc:1.13	Thu Oct 19 22:52:15 2006
+++ squid3/src/dns.cc	Sun Oct 22 03:33:47 2006
@@ -46,6 +46,8 @@
  */
 #if USE_DNSSERVERS
 
+#include "ipc.h"
+
 static helper *dnsservers = NULL;
 
 static void
Index: squid3/src/external_acl.cc
diff -u squid3/src/external_acl.cc:1.53 squid3/src/external_acl.cc:1.43.4.9
--- squid3/src/external_acl.cc:1.53	Fri Apr 20 15:51:20 2007
+++ squid3/src/external_acl.cc	Sat Apr 28 09:35:22 2007
@@ -47,6 +47,7 @@
 #include "AuthUserRequest.h"
 #include "SquidTime.h"
 #include "Store.h"
+#include "ipc.h"
 #include "fde.h"
 #include "ACLChecklist.h"
 #include "ACL.h"
Index: squid3/src/helper.cc
diff -u squid3/src/helper.cc:1.29 squid3/src/helper.cc:1.21.2.7
--- squid3/src/helper.cc:1.29	Fri Apr  6 05:54:13 2007
+++ squid3/src/helper.cc	Sat Apr 28 09:35:23 2007
@@ -40,6 +40,7 @@
 #include "comm.h"
 #include "MemBuf.h"
 #include "wordlist.h"
+#include "ipc.h"
 
 #define HELPER_MAX_ARGS 64
 
@@ -80,10 +81,6 @@
     helper_server *srv;
     int nargs = 0;
     int k;
-    pid_t pid;
-    int rfd;
-    int wfd;
-    void * hIpc;
     wordlist *w;
 
     if (hlp->cmdline == NULL)
@@ -114,16 +111,12 @@
 
     for (k = 0; k < hlp->n_to_start; k++) {
         getCurrentTime();
-        rfd = wfd = -1;
-        pid = ipcCreate(hlp->ipc_type,
-                        progname,
-                        args,
-                        shortname,
-                        &rfd,
-                        &wfd,
-                        &hIpc);
+        IPCResult ipcRV = ipcCreate(hlp->ipc_type,
+                                    progname,
+                                    args,
+                                    shortname);
 
-        if (pid < 0) {
+        if (!ipcRV.success) {
             debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname);
             continue;
         }
@@ -132,11 +125,11 @@
         hlp->n_active++;
         CBDATA_INIT_TYPE(helper_server);
         srv = cbdataAlloc(helper_server);
-        srv->hIpc = hIpc;
-        srv->pid = pid;
+        srv->hIpc = ipcRV.hIpc;
+        srv->pid = ipcRV.pid;
         srv->index = k;
-        srv->rfd = rfd;
-        srv->wfd = wfd;
+        srv->rfd = ipcRV.rfd;
+        srv->wfd = ipcRV.wfd;
         srv->rbuf = (char *)memAllocBuf(8192, &srv->rbuf_sz);
         srv->wqueue = new MemBuf;
         srv->roffset = 0;
@@ -144,22 +137,22 @@
         srv->parent = cbdataReference(hlp);
         dlinkAddTail(srv, &srv->link, &hlp->servers);
 
-        if (rfd == wfd) {
+        if (srv->rfd == srv->wfd) {
             snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", shortname, k + 1);
-            fd_note(rfd, fd_note_buf);
+            fd_note(srv->rfd, fd_note_buf);
         } else {
             snprintf(fd_note_buf, FD_DESC_SZ, "reading %s #%d", shortname, k + 1);
-            fd_note(rfd, fd_note_buf);
+            fd_note(srv->rfd, fd_note_buf);
             snprintf(fd_note_buf, FD_DESC_SZ, "writing %s #%d", shortname, k + 1);
-            fd_note(wfd, fd_note_buf);
+            fd_note(srv->wfd, fd_note_buf);
         }
 
-        commSetNonBlocking(rfd);
+        commSetNonBlocking(srv->rfd);
 
-        if (wfd != rfd)
-            commSetNonBlocking(wfd);
+        if (srv->wfd != srv->rfd)
+            commSetNonBlocking(srv->wfd);
 
-        comm_add_close_handler(rfd, helperServerFree, srv);
+        comm_add_close_handler(srv->rfd, helperServerFree, srv);
 
         comm_read(srv->rfd, srv->rbuf, srv->rbuf_sz - 1, helperHandleRead, srv);
     }
@@ -182,10 +175,6 @@
     helper_stateful_server *srv;
     int nargs = 0;
     int k;
-    pid_t pid;
-    int rfd;
-    int wfd;
-    void * hIpc;
     wordlist *w;
 
     if (hlp->cmdline == NULL)
@@ -216,16 +205,12 @@
 
     for (k = 0; k < hlp->n_to_start; k++) {
         getCurrentTime();
-        rfd = wfd = -1;
-        pid = ipcCreate(hlp->ipc_type,
-                        progname,
-                        args,
-                        shortname,
-                        &rfd,
-                        &wfd,
-                        &hIpc);
+        IPCResult ipcRV = ipcCreate(hlp->ipc_type,
+                                    progname,
+                                    args,
+                                    shortname);
 
-        if (pid < 0) {
+        if (!ipcRV.success) {
             debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname);
             continue;
         }
@@ -234,8 +219,8 @@
         hlp->n_active++;
         CBDATA_INIT_TYPE(helper_stateful_server);
         srv = cbdataAlloc(helper_stateful_server);
-        srv->hIpc = hIpc;
-        srv->pid = pid;
+        srv->hIpc = ipcRV.hIpc;
+        srv->pid = ipcRV.pid;
         srv->flags.reserved = S_HELPER_FREE;
         srv->deferred_requests = 0;
         srv->stats.deferbyfunc = 0;
@@ -243,8 +228,8 @@
         srv->stats.submits = 0;
         srv->stats.releases = 0;
         srv->index = k;
-        srv->rfd = rfd;
-        srv->wfd = wfd;
+        srv->rfd = ipcRV.rfd;
+        srv->wfd = ipcRV.wfd;
         srv->rbuf = (char *)memAllocBuf(8192, &srv->rbuf_sz);
         srv->roffset = 0;
         srv->parent = cbdataReference(hlp);
@@ -254,25 +239,24 @@
 
         dlinkAddTail(srv, &srv->link, &hlp->servers);
 
-        if (rfd == wfd) {
+        if (srv->rfd == srv->wfd) {
             snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", shortname, k + 1);
-            fd_note(rfd, fd_note_buf);
+            fd_note(srv->rfd, fd_note_buf);
         } else {
             snprintf(fd_note_buf, FD_DESC_SZ, "reading %s #%d", shortname, k + 1);
-            fd_note(rfd, fd_note_buf);
+            fd_note(srv->rfd, fd_note_buf);
             snprintf(fd_note_buf, FD_DESC_SZ, "writing %s #%d", shortname, k + 1);
-            fd_note(wfd, fd_note_buf);
+            fd_note(srv->wfd, fd_note_buf);
         }
 
-        commSetNonBlocking(rfd);
+        commSetNonBlocking(srv->rfd);
 
-        if (wfd != rfd)
-            commSetNonBlocking(wfd);
+        if (srv->wfd != srv->rfd)
+            commSetNonBlocking(srv->wfd);
 
-        comm_add_close_handler(rfd, helperStatefulServerFree, srv);
+        comm_add_close_handler(srv->rfd, helperStatefulServerFree, srv);
 
         comm_read(srv->rfd, srv->rbuf, srv->rbuf_sz - 1, helperStatefulHandleRead, srv);
-
     }
 
     hlp->last_restart = squid_curtime;
Index: squid3/src/icmp.cc
diff -u squid3/src/icmp.cc:1.14 squid3/src/icmp.cc:1.9.8.6
--- squid3/src/icmp.cc:1.14	Thu Apr 19 14:50:22 2007
+++ squid3/src/icmp.cc	Sat Apr 28 09:35:23 2007
@@ -36,6 +36,7 @@
 
 #include "squid.h"
 #include "comm.h"
+#include "ipc.h"
 #include "SquidTime.h"
 
 #if USE_ICMP
@@ -234,29 +235,23 @@
 {
 #if USE_ICMP
     const char *args[2];
-    int rfd;
-    int wfd;
     args[0] = "(pinger)";
     args[1] = NULL;
-    /*
-     * Do NOT use IPC_DGRAM (=IPC_UNIX_DGRAM) here because you can't
-     * send() more than 4096 bytes on a socketpair() socket (at
-     * least on FreeBSD).
-     */
-    pid = ipcCreate(IPC_UDP_SOCKET,
-                    Config.Program.pinger,
-                    args,
-                    "Pinger Socket",
-                    &rfd,
-                    &wfd,
-                    &hIpc);
+    IPCResult ipcRV = ipcCreate(IPC_UDP_SOCKET,
+                                Config.Program.pinger,
+                                args,
+                                "Pinger Socket");
 
-    if (pid < 0)
+    if (!ipcRV.success)
         return;
 
-    assert(rfd == wfd);
+    hIpc = ipcRV.hIpc;
 
-    icmp_sock = rfd;
+    pid = ipcRV.pid;
+
+    assert(ipcRV.rfd == ipcRV.wfd);
+
+    icmp_sock = ipcRV.rfd;
 
     fd_note(icmp_sock, "pinger");
 
Index: squid3/src/ipc.cc
diff -u squid3/src/ipc.cc:1.14 squid3/src/ipc.cc:1.11.6.3
--- squid3/src/ipc.cc:1.14	Sun Sep  3 12:50:29 2006
+++ squid3/src/ipc.cc	Sun Sep  3 09:16:48 2006
@@ -34,255 +34,1400 @@
  */
 
 #include "squid.h"
+#include "ipc.h"
 #include "comm.h"
 #include "fde.h"
+#include "SquidTime.h"
+
+#ifdef _SQUID_MSWIN_
+#ifndef _MSWSOCK_
+#include <mswsock.h>
+#endif
+#include <process.h>
+#endif
+
+class FDPair
+{
+
+public:
+    FDPair() : rfd (-1), wfd (-1) {}
+
+    FDPair (int anFD) : rfd (anFD), wfd (anFD) {}
+
+    FDPair (int r, int w) : rfd (r), wfd (w) {}
+
+    void close();
+    int rfd;
+    int wfd;
+};
+
+
+/* XXX: The mechanics could be made into a strategy and this
+   class a parent for classes that need to spawn.
+   For now, a callforward will do. Alternatively we could
+   make this a template class and use a unary functor.
+   */
+
+class Spawn
+{
+
+public:
+    static Spawn *GetSpawn();
+    virtual ~Spawn(){}
+
+    virtual Spawn *clone() const = 0;
+    virtual bool success() const = 0;
+    /* For windows, until the spawn object is kept around */
+    virtual void * getHandle() const = 0;
+    virtual pid_t getPid() const = 0;
+    typedef unsigned int Child (void *);
+    virtual void splitExecution(Child*, void *) = 0;
+    // virtual ... startProcess(prog, args);
+
+protected:
+    Spawn (){}
+
+    Spawn (Spawn const &){}
+
+    Spawn &operator= (Spawn const &);
+
+private:
+};
+
+#ifdef _SQUID_MSWIN_
+
+class WindowsSpawn : public Spawn
+{
+
+public:
+    WindowsSpawn();
+    virtual Spawn *clone() const;
+    virtual bool success() const;
+    /* For windows, until the spawn object is kept around */
+    virtual void * getHandle() const;
+    virtual pid_t getPid() const;
+    virtual void splitExecution(Child*, void *);
+    ~WindowsSpawn();
+
+protected:
+    WindowsSpawn (WindowsSpawn const &);
+    WindowsSpawn &operator= (WindowsSpawn const &);
+
+private:
+    static unsigned int __stdcall ThreadReflector (void *);
+    Child* newThread;
+    void *data;
+    pid_t pid;
+    int error;
+    unsigned int childRV;
+    unsigned threadID;
+    void * threadHandle;
+};
+
+#else
+
+class UnixSpawn : public Spawn
+{
+
+public:
+    UnixSpawn();
+    virtual Spawn *clone() const;
+    virtual bool success() const;
+    /* For windows, until the spawn object is kept around */
+    virtual void * getHandle() const;
+    virtual pid_t getPid() const;
+    virtual void splitExecution(Child*, void *);
+
+protected:
+    UnixSpawn (UnixSpawn const &);
+    UnixSpawn &operator= (UnixSpawn const &);
+
+private:
+    void child();
+    Child* newThread;
+    void *data;
+    pid_t pid;
+};
+
+#endif
+
+Spawn *
+Spawn::GetSpawn()
+{
+#ifdef _SQUID_MSWIN_
+    return new WindowsSpawn;
+#else
+
+    return new UnixSpawn;
+#endif
+}
+
+class IPC
+{
+
+public:
+    static IPC *Create(int type, const char *prog, const char *const args[], const char *name);
+    static unsigned int ForkChild(void *);
+    IPCResult result() const { return rv;}
+
+    virtual ~IPC()
+    {
+        safe_free (name_);
+        delete mySpawn;
+    }
+
+    virtual IPC *clone() const = 0;
+
+    /* FIXME: move below again */
+
+    FDPair childFD;
+
+    virtual struct sockaddr_in & PS ();
+    Spawn *mySpawn;
+    const char *prog;
+    char * const *args;
+    virtual void childFDConnect();
+    virtual bool childFDConnected() const;
+    virtual int childWrite(char const *, size_t) = 0;
+    void doExec();
+
+protected:
+    IPC (char const *aName);
+    IPC(IPC const &);
+
+    /* not implemented, but the synthetic operator won't do */
+    IPC &operator= (IPC const &);
+
+    void result (IPCResult const& newRV)
+    {
+        rv = newRV;
+    }
+
+    char const *name() const {return name_;}
+
+    virtual void markFailed();
+    virtual void cleanUp();
+    virtual bool openedInitialFDs() const;
+
+    virtual struct sockaddr_in & CS ();
+    //  virtual struct sockaddr_in & PS ();
+    virtual void prepFDsForSpawn();
+    virtual bool preppedFDsForSpawn() const;
+    //  virtual void childFDConnect();
+    //  virtual bool childFDConnected() const;
+    int prfd;
+    int pwfd;
+    static IPC *Factory(int type, char const *name);
+
+private:
+    IPC (IPCResult aResult):rv(aResult){}
+
+    void closeAllFD();
+    IPCResult rv;
+    char const *name_;
+};
+
+#ifndef _SQUID_MSWIN_
+#if ! (HAVE_POLL && defined(_SQUID_OSF_))
+
+class IPCFIFO : public IPC
+{
+
+public:
+    virtual IPC *clone() const;
+    virtual int childWrite(char const *, size_t);
+
+private:
+    friend IPC *IPC::Factory(int, char const *);
+    IPCFIFO (char const *aName);
+};
+
+IPCFIFO::IPCFIFO (char const *aName) : IPC(aName)
+{
+    int p2c[2];
+    int c2p[2];
+
+    if (pipe(p2c) < 0) {
+        debug(50, 0) ("ipcCreate: pipe: %s\n", xstrerror());
+        return;
+    }
+
+    if (pipe(c2p) < 0) {
+        debug(50, 0) ("ipcCreate: pipe: %s\n", xstrerror());
+        return;
+    }
+
+    childFD = FDPair (c2p[0], p2c[1]);
+    fdc_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
+    fdc_open(childFD.wfd, FD_PIPE, "IPC FIFO Child Write");
+    fdc_open(childFD.rfd, FD_PIPE, "IPC FIFO Child Read");
+    fdc_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
+}
+
+IPC *
+IPCFIFO::clone() const
+{
+    IPCFIFO *rv = new IPCFIFO (*this);
+    return rv;
+}
+
+int
+IPCFIFO::childWrite(char const *buf , size_t len)
+{
+    int result = write(childFD.wfd, buf, len);
+
+    if (result < 0)
+        debug(50, 0) ("write FD %d: %s\n", childFD.wfd, xstrerror());
+
+    return result;
+}
+
+#endif
+#endif
+
+class IPCSocket : public IPC
+{
+
+public:
+    virtual IPC *clone() const = 0;
+
+protected:
+    IPCSocket (char const *aName, int socktype, int proto);
+    IPCSocket (IPCSocket const &);
+    /* not implemented */
+    IPCSocket &operator=(IPCSocket const &);
+
+    virtual struct sockaddr_in & CS ();
+
+    virtual struct sockaddr_in & PS ();
+    virtual void prepFDsForSpawn();
+    virtual bool preppedFDsForSpawn() const;
+    bool fdDetailsRetrieved;
+
+private:
+    int openASocket(int socktype, int proto, int flags) const;
+
+    struct sockaddr_in CS_;
+
+    struct sockaddr_in PS_;
+};
+
+IPCSocket::IPCSocket (char const *aName, int socktype, int proto) : IPC (aName),
+        fdDetailsRetrieved (false)
+{
+#ifdef _SQUID_MSWIN_ /* Windows IPC needs Overlapped sockets */
+    int opt = 0;
+    int optlen = sizeof(opt);
+
+    if (WIN32_OS_version !=_WIN_OS_WINNT) {
+        getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
+        opt = opt & ~(SO_SYNCHRONOUS_NONALERT | SO_SYNCHRONOUS_ALERT);
+        setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, sizeof(opt));
+    }
+
+#endif
+
+    childFD = FDPair (openASocket (socktype, proto, COMM_NOCLOEXEC));
+
+    prfd = pwfd = openASocket (socktype, proto, 0); /* blocking */
+
+#ifdef _SQUID_MSWIN_ /* Restore sockets to synchronous mode*/
+
+    if (WIN32_OS_version !=_WIN_OS_WINNT) {
+        getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
+        opt = opt | SO_SYNCHRONOUS_NONALERT;
+        setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen);
+    }
+
+#endif
+
+}
+
+IPCSocket::IPCSocket (IPCSocket const &old) : IPC(old), fdDetailsRetrieved (old.fdDetailsRetrieved),
+        CS_(old.CS_), PS_(old.PS_)
+{}
+
+struct sockaddr_in &
+            IPCSocket::CS()
+{
+    return CS_;
+}
+
+struct sockaddr_in &
+            IPCSocket::PS()
+{
+    return PS_;
+}
+
+void
+IPCSocket::prepFDsForSpawn()
+{
+    socklen_t len = sizeof(PS_);
+    memset(&PS_, '\0', len);
+
+    if (getsockname(pwfd, (struct sockaddr *) &PS_, &len) < 0) {
+        debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
+        return;
+    }
+
+    debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
+                  pwfd, inet_ntoa(PS_.sin_addr), ntohs(PS_.sin_port));
+    len = sizeof(CS_);
+    memset(&CS_, '\0', len);
+
+    if (getsockname(childFD.rfd, (struct sockaddr *) &CS_, &len) < 0) {
+        debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
+        return;
+    }
+
+    debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
+                  childFD.rfd, inet_ntoa(CS_.sin_addr), ntohs(CS_.sin_port));
+
+    fdDetailsRetrieved = true;
+}
+
+bool
+IPCSocket::preppedFDsForSpawn() const
+{
+    return fdDetailsRetrieved;
+}
+
+int
+IPCSocket::openASocket(int socktype, int proto, int flags) const
+{
+    return comm_open(socktype,
+                     proto,	/* protocol */
+                     local_addr,
+                     0,		/* port */
+                     flags,	/* blocking */
+                     name());
+}
+
+class IPCTCP : public IPCSocket
+{
+
+public:
+    virtual void prepFDsForSpawn();
+    virtual bool preppedFDsForSpawn() const;
+    virtual IPC *clone() const;
+    virtual int childWrite(char const *, size_t);
+
+protected:
+    virtual void childFDConnect();
+    virtual bool childFDConnected() const;
+
+private:
+    friend IPC *IPC::Factory(int, char const *);
+    IPCTCP (char const *aName);
+    bool childConnected;
+};
+
+IPCTCP::IPCTCP (char const *aName) :
+        IPCSocket(aName, SOCK_STREAM, IPPROTO_TCP) , childConnected(false)
+{}
+
+void
+IPCTCP::prepFDsForSpawn()
+{
+    IPCSocket::prepFDsForSpawn();
+
+    if (!IPCSocket::preppedFDsForSpawn())
+        return;
+
+    if (listen(childFD.rfd, 1) < 0) {
+        debug(50, 1) ("ipcCreate: listen FD %d: %s\n", childFD.rfd, xstrerror());
+        /* Naughty abstraction break ! */
+        fdDetailsRetrieved = false;
+        return;
+    }
+
+    debug(54, 3) ("ipcCreate: FD %d listening...\n", childFD.rfd);
+}
+
+bool
+IPCTCP::preppedFDsForSpawn() const
+{
+    /* TODO: heal the abstraction - call this if our flag is ok, otherwise
+     * return false. (See preFDsForSpawn)
+     */
+    return IPCSocket::preppedFDsForSpawn();
+}
+
+IPC *
+IPCTCP::clone() const
+{
+    IPCTCP *rv = new IPCTCP (*this);
+    return rv;
+}
+
+void
+IPCTCP::childFDConnect()
+{
+    debug(54, 3) ("ipcCreate: calling accept on FD %d\n", childFD.rfd);
+    int tempFD;
+
+    if ((tempFD = accept(childFD.rfd, NULL, NULL)) < 0) {
+        debug(50, 0) ("ipcCreate: FD %d accept: %s\n", childFD.rfd, xstrerror());
+        return;
+    }
+
+    debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", tempFD);
+
+    comm_close(childFD.rfd);
+#ifdef _SQUID_MSWIN_
+
+    char buf1[8192];
+    snprintf(buf1, 8191, "%s CHILD socket", prog);
+    fdc_open(tempFD, FD_SOCKET, buf1);
+    fd_table[tempFD].flags.ipc = 1;
+#endif
+
+    childFD = FDPair (tempFD);
+
+    childConnected = true;
+}
+
+bool
+IPCTCP::childFDConnected() const
+{
+    return childConnected;
+}
+
+int
+IPCTCP::childWrite(char const *buf , size_t len)
+{
+#ifndef _SQUID_MSWIN_
+    int result = write(childFD.wfd, buf, len);
+
+    if (result < 0)
+        debug(50, 0) ("write FD %d: %s\n", childFD.wfd, xstrerror());
+
+#else
+
+    int result = send (childFD.wfd, (const void *) buf, len, 0);
+
+    if (result < 0)
+        debug(50, 0) ("send FD %d: %s\n", childFD.wfd, xstrerror());
+
+#endif
+
+    return result;
+}
+
+
+class IPCUDP : public IPCSocket
+{
+
+public:
+    virtual IPC *clone() const;
+    virtual int childWrite(char const *, size_t);
+
+protected:
+    virtual void childFDConnect();
+    virtual bool childFDConnected() const;
+
+private:
+    friend IPC *IPC::Factory(int, char const *);
+    IPCUDP (char const *aName);
+    bool childConnected;
+};
+
+IPCUDP::IPCUDP (char const *aName) :
+        IPCSocket(aName, SOCK_DGRAM, IPPROTO_UDP), childConnected (false)
+{}
+
+IPC *
+IPCUDP::clone() const
+{
+    IPCUDP *rv = new IPCUDP (*this);
+    return rv;
+}
+
+void
+IPCUDP::childFDConnect()
+{
+    if (comm_connect_addr(childFD.rfd, &PS()) == COMM_ERROR)
+        return;
+
+    childConnected = true;
+}
+
+bool
+IPCUDP::childFDConnected() const
+{
+    return childConnected;
+}
+
+int
+IPCUDP::childWrite(char const *buf , size_t len)
+{
+    int result = comm_udp_send(childFD.wfd, buf, len, 0);
+
+    if (result < 0)
+        debug(50, 0) ("sendto FD %d: %s\n", childFD.wfd, xstrerror());
+
+    return result;
+}
+
+#if HAVE_SOCKETPAIR && defined(AF_UNIX)
+#ifndef _SQUID_MSWIN_
+
+class IPCUNIXStream : public IPC
+{
+
+public:
+    virtual IPC *clone() const;
+    virtual int childWrite(char const *, size_t);
+
+private:
+    friend IPC *IPC::Factory(int, char const *);
+    IPCUNIXStream (char const *aName);
+};
+
+IPCUNIXStream::IPCUNIXStream (char const *aName) : IPC(aName)
+{
+    int fds[2];
+    int buflen = 32768;
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
+        debug(50, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
+        return;
+    }
+
+    setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
+    setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
+    setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
+    setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
+    childFD = FDPair (fds[1]);
+    fdc_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX STREAM Parent");
+    fdc_open(childFD.rfd, FD_PIPE, "IPC UNIX STREAM Child");
+}
+
+IPC *
+IPCUNIXStream::clone() const
+{
+    IPCUNIXStream *rv = new IPCUNIXStream (*this);
+    return rv;
+}
+
+int
+IPCUNIXStream::childWrite(char const *buf , size_t len)
+{
+    int result = write(childFD.wfd, buf, len);
+
+    if (result < 0)
+        debug(50, 0) ("write FD %d: %s\n", childFD.wfd, xstrerror());
+
+    return result;
+}
+
+class IPCUNIXDGram : public IPC
+{
+
+public:
+    virtual IPC *clone() const;
+    virtual int childWrite(char const *, size_t);
+
+private:
+    friend IPC *IPC::Factory(int, char const *);
+    IPCUNIXDGram (char const *aName);
+};
+
+IPCUNIXDGram::IPCUNIXDGram (char const *aName) : IPC(aName)
+{
+    int fds[2];
+
+    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
+        debug(50, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
+        return;
+    }
+
+    childFD = FDPair (fds[1]);
+    fdc_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX DGRAM Parent");
+    fdc_open(childFD.rfd, FD_PIPE, "IPC UNIX DGRAM Child");
+}
+
+IPC *
+IPCUNIXDGram::clone() const
+{
+    IPCUNIXDGram *rv = new IPCUNIXDGram (*this);
+    return rv;
+}
+
+int
+IPCUNIXDGram::childWrite(char const *buf , size_t len)
+{
+    int result = comm_udp_send(childFD.wfd, buf, len, 0);
+
+    if (result < 0)
+        debug(50, 0) ("sendto FD %d: %s\n", childFD.wfd, xstrerror());
+
+    return result;
+}
+
+#endif
+#endif
+
+IPC *
+IPC::Factory (int type, char const *name)
+{
+    if (type == IPC_TCP_SOCKET)
+        return new IPCTCP (name);
+
+#ifndef _SQUID_MSWIN_
+#if !(USE_POLL && defined(_SQUID_OSF_))
+
+    if (type == IPC_FIFO)
+        return new IPCFIFO (name);
+
+#endif
+#endif
+
+    if (type == IPC_UDP_SOCKET)
+        return new IPCUDP (name);
+
+#if HAVE_SOCKETPAIR && defined(AF_UNIX)
+#ifndef _SQUID_MSWIN_
+
+    if (type == IPC_UNIX_STREAM)
+        return new IPCUNIXStream (name);
+
+    if (type == IPC_UNIX_DGRAM)
+        return new IPCUNIXDGram (name);
+
+#endif
+#endif
+
+    fatal ("Unexpected IPC type : check your source\n");
+
+    return NULL;
+}
+
+void
+IPC::markFailed()
+{
+    result(IPCResult(false));
+}
+
+struct sockaddr_in &
+            IPC::CS ()
+{
+    fatal("attempt to get Client Socket for non socket IPC class\n");
+
+    struct sockaddr_in *f = new struct sockaddr_in;
+    return *f;
+}
+
+struct sockaddr_in &
+            IPC::PS ()
+{
+    fatal("attempt to get Parent Socket for non socket IPC class\n");
+
+    struct sockaddr_in *f = new struct sockaddr_in;
+    return *f;
+}
+
+void
+IPC::prepFDsForSpawn()
+{}
+
+bool
+IPC::preppedFDsForSpawn() const
+{
+    return true;
+}
+
+void
+IPC::childFDConnect()
+{}
+
+bool
+IPC::childFDConnected() const
+{
+    return true;
+}
+
+class IPCInstance
+{
+
+public:
+    static char const *ShutdownMessage;
+
+    IPCInstance(int aType, pid_t aPid, char const *program, int fromChildFD, int toParentFD) : type (aType),
+            pid(aPid), prog (xstrdup(program)), prfd (fromChildFD),
+    send_fd (toParentFD){}
+
+    virtual ~IPCInstance()
+    {
+        safe_free(prog);
+    }
+
+    virtual void childToParentLoop();
+
+protected:
+    /* Not implemented */
+    IPCInstance(IPCInstance const &);
+    IPCInstance &operator= (IPCInstance const &);
+
+private:
+    /* what sort of IPC we are */
+    int const type;
+    /* if this is really IPC to another process, the process id. */
+    pid_t pid;
+    /* What program it is */
+    char *prog;
+    /* the parent uses this to read from the child */
+    int const prfd;
+    int const send_fd;
+};
+
+char const *IPCInstance::ShutdownMessage = "$shutdown\n";
+
+#ifdef _SQUID_MSWIN_
+
+struct ipc_params
+{
+    static unsigned int ThreadReflector (void *); // ipc_params *
+    ipc_params (int aType) : type(aType), prfd_ipc (-1), pwfd_ipc(-1), crfd_ipc(-1), cwfd_ipc(-1),
+            hProcess(NULL), thread(NULL), pid (-1), niceprog(NULL)
+#if HAVE_PUTENV
+            , env_str(NULL)
+#endif
+    {
+        p2c[0]=-1;
+        p2c[1]=-1;
+        c2p[0]=-1;
+        c2p[1]=-1;
+    }
+    ~ipc_params()
+    {
+        delete myIPC;
+    }
+
+    int const type;
+    const char *prog;
+    char **args;
+    IPC *myIPC;
+
+private:
+    unsigned int threadLoop();
+    void freeResources();
+    void normalExit();
+    void parentToChildLoop();
+    int p2c[2];
+    int c2p[2];
+    int prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc;
+    HANDLE hProcess;
+    HANDLE thread;
+    pid_t pid;
+    char *niceprog;
+    char buf1[8192];
+#if HAVE_PUTENV
+
+    char *env_str;
+#endif
+};
+
+struct thread_params
+{
+    int type;
+    int rfd;
+    int send_fd;
+    const char *prog;
+    pid_t pid;
+};
+
+static unsigned int __stdcall ipc_thread_2(void *); // thread_params *
+
+static const char *ok_string = "OK\n";
+static const char *err_string = "ERR\n";
+static const char *shutdown_string = "$shutdown\n";
+#endif
 
 static const char *hello_string = "hi there\n";
 #define HELLO_BUF_SZ 32
 static char hello_buf[HELLO_BUF_SZ];
 
+void
+FDPair::close()
+{
+    if (rfd >= 0)
+        comm_close(rfd);
+
+    if (rfd != wfd &&
+            wfd >= 0)
+        comm_close (wfd);
+
+    rfd = wfd = -1;
+}
+
+#ifdef _SQUID_MSWIN_
+static void
+ipcCloseAllFD(int prfd, int pwfd)
+{
+    FDPair (prfd, pwfd).close();
+}
+
+#endif
+
+static void
+PutEnvironment()
+{
+#if HAVE_PUTENV
+    char *env_str;
+    int tmp_s;
+    env_str = (char *)xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
+    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
+    putenv(env_str);
+#endif
+}
+
+void
+IPC::closeAllFD()
+{
+    FDPair (prfd, pwfd).close();
+    childFD.close();
+}
+
+void
+IPC::cleanUp()
+{
+    delete mySpawn;
+    mySpawn = NULL;
+    closeAllFD();
+}
+
+void
+reserveFD0Thru2(int crfd)
+{
+    /*
+     * This double-dup stuff avoids problems when one of 
+     *  crfd, cwfd, or debug_log are in the range 0-2.
+     */
+    int openrv;
+
+    do {
+        /* First make sure 0-2 is occupied by something. Gets cleaned up later */
+        openrv = dup(crfd);
+        assert(openrv > -1);
+    } while (openrv < 3 && openrv > -1);
+
+    close(openrv);
+}
+
+void
+IPC::doExec()
+{
+#ifndef _SQUID_MSWIN_
+    int t1, t2, t3;
+    reserveFD0Thru2(childFD.rfd);
+    t1 = dup(childFD.rfd);
+    t2 = dup(childFD.wfd);
+    t3 = dup(fileno(debug_log));
+    assert(t1 > 2 && t2 > 2 && t3 > 2);
+    close(childFD.rfd);
+    close(childFD.wfd);
+    close(fileno(debug_log));
+    dup2(t1, 0);
+    dup2(t2, 1);
+    dup2(t3, 2);
+    close(t1);
+    close(t2);
+    close(t3);
+    /* Make sure all other filedescriptors are closed */
+
+    for (int loopIndex = 3; loopIndex < SQUID_MAXFD; ++loopIndex)
+        close(loopIndex);
+
+    if (opt_no_daemon) {
+        squid_signal(SIGINT, SIG_IGN, SA_RESETHAND);
+        squid_signal(SIGHUP, SIG_IGN, SA_RESETHAND);
+    }
+
+    execvp(prog, (char *const *) args);
+
+    debug_log = fdopen(2, "a+");
+
+    debug(50, 0) ("ipcCreate: %s: %s\n", prog, xstrerror());
+
+    _exit(1);
+
+#else
+    /* NT code goes here eventually */
+#endif
+}
+
+IPCResult
+ipcCreate(int type, const char *prog, const char *const args[], const char *name)
+{
+    IPC *newIPC = IPC::Create(type, prog, args, name);
+    IPCResult result = newIPC->result();
+    delete newIPC;
+    return result;
+}
+
+IPC::IPC(char const *aName): mySpawn(NULL), prfd(-1), pwfd(-1)
+        , rv(false) , name_ (xstrdup(aName))
+{}
+
+/* yes. we have *real* remote ownership issues with prog and args */
+IPC::IPC (IPC const &old):childFD(old.childFD), mySpawn(old.mySpawn->clone()),
+        prog (old.prog), args (old.args),
+        prfd(old.prfd), pwfd (old.pwfd)
+        , rv(old.rv), name_ (xstrdup(old.name_))
+{}
+
+bool
+IPC::openedInitialFDs() const
+{
+    if (childFD.rfd < 0) {
+        debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
+        return false;
+    }
+
+    if (pwfd < 0) {
+        debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
+        return false;
+    }
+
+    return true;
+}
+
+#ifdef _SQUID_MSWIN_
 static int
-ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
+ipcSend(int cwfd, const char *buf, int len)
+{
+    int result = send(cwfd, (const void *) buf, len, 0);
+
+    if (result < 0) {
+        debug(50, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
+        debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n");
+    }
+
+    return result;
+}
+
+struct SpawnResult
+{
+    SpawnResult() : hProcess (NULL), pid (-1), error (0){}
+
+    HANDLE hProcess;
+    pid_t pid;
+    int error;
+};
+
+static
+SpawnResult
+ipc_spawn(const char *prog, char **args)
+{
+    char buf1[8192];
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+
+    memset(&si, 0, sizeof(STARTUPINFO));
+    si.cb = sizeof(STARTUPINFO);
+    si.hStdInput = (HANDLE) _get_osfhandle(0);
+    si.hStdOutput = (HANDLE) _get_osfhandle(1);
+    si.hStdError = (HANDLE) _get_osfhandle(2);
+    si.dwFlags = STARTF_USESTDHANDLES;
+
+    /* Make sure all other valid handles are not inerithable */
+
+    for (int x = 3; x < SQUID_MAXFD; x++) {
+        fde *F = &fd_table[x];
+
+        if (F->win32.handle == 0)
+            continue;
+
+        SetHandleInformation((HANDLE) F->win32.handle, HANDLE_FLAG_INHERIT, 0);
+    }
+
+    *buf1 = '\0';
+    strcpy(buf1 + 4096, prog);
+    char *str = strtok(buf1 + 4096, w_space);
+
+    do {
+        strcat(buf1, str);
+        strcat(buf1, " ");
+    } while ((str = strtok(NULL, w_space)));
+
+    int loopIndex = 1;
+
+    while (args[loopIndex]) {
+        strcat(buf1, args[loopIndex++]);
+        strcat(buf1, " ");
+    }
+
+    SpawnResult result;
+
+    if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW,
+                      NULL, NULL, &si, &pi)) {
+        result.pid = pi.dwProcessId;
+        result.hProcess = pi.hProcess;
+    } else {
+        WIN32_maperror(GetLastError());
+        result.error = errno;
+    }
+
+    return result;
+}
+
+unsigned int
+ipc_params::ThreadReflector(void *voidParam)
+{
+
+    struct ipc_params *params = static_cast<struct ipc_params *>(voidParam);
+    unsigned int result = params->threadLoop();
+    delete params;
+    return result;
+}
+
+#endif
+
+#ifdef _SQUID_MSWIN_
+
+WindowsSpawn::WindowsSpawn(): newThread (NULL), data(NULL),
+        pid(-1), error (0), childRV (0), threadID (0), threadHandle(NULL)
+{}
+
+WindowsSpawn::WindowsSpawn(WindowsSpawn const &old) : Spawn (old), newThread (old.newThread),
+        data (old.data), pid (old.pid), error (old.error), childRV (old.childRV), threadID (old.threadID)
+{
+    if (old.threadHandle)
+        DuplicateHandle (GetCurrentProcess(), old.threadHandle,GetCurrentProcess(), &threadHandle, 0,FALSE,DUPLICATE_SAME_ACCESS);
+}
+
+WindowsSpawn::~WindowsSpawn()
 {
-    if (prfd >= 0)
-        comm_close(prfd);
+    if (threadHandle != NULL)
+        CloseHandle(threadHandle);
 
-    if (prfd != pwfd)
-        if (pwfd >= 0)
-            comm_close(pwfd);
+    threadHandle = NULL;
+}
 
-    if (crfd >= 0)
-        comm_close(crfd);
+unsigned int __stdcall
+WindowsSpawn::ThreadReflector (void *me_)
+{
+    WindowsSpawn *me = static_cast<WindowsSpawn*>(me_);
+    assert (me->newThread != NULL);
+    me->childRV = me->newThread (me->data);
+    return me->childRV;
+}
 
-    if (crfd != cwfd)
-        if (cwfd >= 0)
-            comm_close(cwfd);
+Spawn *
+WindowsSpawn::clone() const
+{
+    WindowsSpawn *result = new WindowsSpawn (*this);
+    return result;
+}
 
-    return -1;
+bool
+WindowsSpawn::success() const
+{
+    return threadID != 0;
 }
 
-static void
-PutEnvironment()
+void *
+WindowsSpawn::getHandle() const
 {
-#if HAVE_PUTENV
-    char *env_str;
-    int tmp_s;
-    env_str = (char *)xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
-    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
-    putenv(env_str);
-#endif
+    return threadHandle;
 }
 
 pid_t
-ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, void **hIpc)
+WindowsSpawn::getPid() const
 {
-    pid_t pid;
+    assert (0);
+    return pid;
+}
 
-    struct sockaddr_in ChS;
+void
+WindowsSpawn::splitExecution(Spawn::Child *_newThread, void *_data)
+{
+    newThread = _newThread;
+    data = _data;
+    HANDLE beginRv =
+        (HANDLE) _beginthreadex(NULL, 0, ThreadReflector, this, 0, &threadID);
 
-    struct sockaddr_in PaS;
-    int crfd = -1;
-    int prfd = -1;
-    int cwfd = -1;
-    int pwfd = -1;
-    int fd;
-    int t1, t2, t3;
-    socklen_t len;
-    int x;
+    if (!beginRv) {
+        debug(50, 1) ("ipcCreate: _beginthreadex: %s\n", xstrerror());
+    } else {
+        assert (threadID != 0);
+        /* undocumented! */
+        threadHandle =  beginRv;
+        debug(50, 1) ("WindowsSpawn::splitExecution: Handle: 0x%x, ThreadID: %d\n", (unsigned) threadHandle,threadID);
+    }
+}
 
-#if USE_POLL && defined(_SQUID_OSF_)
+#else
+UnixSpawn::UnixSpawn() :newThread (NULL), data(NULL),
+        pid(-1)
+{}
 
-    assert(type != IPC_FIFO);
-#endif
+UnixSpawn::UnixSpawn(UnixSpawn const &old)
+{}
 
-    if (rfd)
-        *rfd = -1;
+Spawn *
+UnixSpawn::clone() const
+{
+    UnixSpawn *result = new UnixSpawn (*this);
+    return result;
+}
 
-    if (wfd)
-        *wfd = -1;
-
-    if (hIpc)
-        *hIpc = NULL;
-
-    if (type == IPC_TCP_SOCKET) {
-        crfd = cwfd = comm_open(SOCK_STREAM,
-                                0,
-                                local_addr,
-                                0,
-                                COMM_NOCLOEXEC,
-                                name);
-        prfd = pwfd = comm_open(SOCK_STREAM,
-                                0,			/* protocol */
-                                local_addr,
-                                0,			/* port */
-                                0,			/* blocking */
-                                name);
-    } else if (type == IPC_UDP_SOCKET) {
-        crfd = cwfd = comm_open(SOCK_DGRAM,
-                                0,
-                                local_addr,
-                                0,
-                                COMM_NOCLOEXEC,
-                                name);
-        prfd = pwfd = comm_open(SOCK_DGRAM,
-                                0,
-                                local_addr,
-                                0,
-                                0,
-                                name);
-    } else if (type == IPC_FIFO) {
-        int p2c[2];
-        int c2p[2];
-
-        if (pipe(p2c) < 0) {
-            debug(54, 0) ("ipcCreate: pipe: %s\n", xstrerror());
-            return -1;
-        }
-
-        if (pipe(c2p) < 0) {
-            debug(54, 0) ("ipcCreate: pipe: %s\n", xstrerror());
-            return -1;
-        }
-
-        fdc_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
-        fdc_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write");
-        fdc_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read");
-        fdc_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
-#if HAVE_SOCKETPAIR && defined(AF_UNIX)
+bool
+UnixSpawn::success() const
+{
+    return pid > -1;
+}
 
-    } else if (type == IPC_UNIX_STREAM) {
-        int fds[2];
-        int buflen = 32768;
-
-        if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
-            debug(54, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
-            return -1;
-        }
-
-        setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
-        setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
-        setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
-        setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
-        fdc_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX STREAM Parent");
-        fdc_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX STREAM Parent");
-    } else if (type == IPC_UNIX_DGRAM) {
-        int fds[2];
-
-        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
-            debug(54, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
-            return -1;
-        }
+void *
+UnixSpawn::getHandle() const
+{
+    assert (0);
+    return NULL;
+}
 
-        fdc_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX DGRAM Parent");
-        fdc_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX DGRAM Parent");
-#endif
+pid_t
+UnixSpawn::getPid() const
+{
+    return pid;
+}
 
+void
+UnixSpawn::splitExecution(Spawn::Child *_newThread, void *_data)
+{
+    newThread = _newThread;
+    data = _data;
+
+    if ((pid = fork()) < 0) {
+        debug(50, 1) ("ipcCreate: fork: %s\n", xstrerror());
+    } else if (pid > 0) {
+        /* parent */
+        return;
     } else {
-        assert(IPC_NONE);
+        /* Still checked outside here */
+        child();
     }
+}
 
-    debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd);
-    debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd);
-    debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd);
-    debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd);
+void
+UnixSpawn::child()
+{
+    /*exit(*/newThread(data)/*)*/;
+}
 
-    if (crfd < 0) {
-        debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
-        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-    }
+#endif
 
-    if (pwfd < 0) {
-        debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
-        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-    }
+unsigned int
+IPC::ForkChild(void *data)
+{
+    IPC *result = static_cast<IPC*>(data);
+    assert (result);
+#ifndef _SQUID_MSWIN_
+    /* child */
+    no_suid();			/* give up extra priviliges */
+    /* close shared socket with parent */
+    comm_close(result->prfd);
 
-    if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
-        len = sizeof(PaS);
-        memset(&PaS, '\0', len);
+    if (result->pwfd != result->prfd)
+        close(result->pwfd);
 
-        if (getsockname(pwfd, (struct sockaddr *) &PaS, &len) < 0) {
-            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        }
+    result->pwfd = result->prfd = -1;
 
-        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
-                      pwfd, inet_ntoa(PaS.sin_addr), ntohs(PaS.sin_port));
-        len = sizeof(ChS);
-        memset(&ChS, '\0', len);
-
-        if (getsockname(crfd, (struct sockaddr *) &ChS, &len) < 0) {
-            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        }
+#else
+#endif
 
-        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
-                      crfd, inet_ntoa(ChS.sin_addr), ntohs(ChS.sin_port));
+    /* Until we are entire in this routine */
+    return 0;
+}
+
+IPC *
+IPC::Create (int type, const char *prog, const char *const args[], const char *name)
+{
+    IPC *result = NULL;
+    /* get our candidate object */
+    assert (result = Factory (type, name));
+#ifndef _SQUID_MSWIN_
+
+    int tempFD;
+#endif
+
+    int x;
+
+    debug(54, 3) ("ipcCreate: prfd FD %d\n", result->prfd);
+    debug(54, 3) ("ipcCreate: pwfd FD %d\n", result->pwfd);
+    debug(54, 3) ("ipcCreate: crfd FD %d\n", result->childFD.rfd);
+    debug(54, 3) ("ipcCreate: cwfd FD %d\n", result->childFD.wfd);
+
+    if (!result->openedInitialFDs()) {
+        result->cleanUp();
+        return result;
     }
 
-    if (type == IPC_TCP_SOCKET) {
-        if (listen(crfd, 1) < 0) {
-            debug(54, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror());
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        }
+    result->prepFDsForSpawn();
 
-        debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
+    if (!result->preppedFDsForSpawn()) {
+        result->cleanUp();
+        return result;
     }
 
     /* flush or else we get dup data if unbuffered_logs is set */
     logsFlush();
 
-    if ((pid = fork()) < 0) {
-        debug(54, 1) ("ipcCreate: fork: %s\n", xstrerror());
-        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-    }
+    result->mySpawn = Spawn::GetSpawn();
 
-    if (pid > 0) {		/* parent */
-        /* close shared socket with child */
-        comm_close(crfd);
+    result->prog = prog;
+
+    result->args = const_cast<char* const*>(args);
+
+#ifdef _SQUID_MSWIN_
+
+    ipc_params *params = new ipc_params (type);
+
+    /* Note to self: we must always clone result, even if
+       we eliminate the ipc_params class, because using a single instance
+       might overlap on variable usage. Until the code is fully 
+       reorganised, cloning is safer.
+       Later on we might want to make threadsafe IPC classes ..
+       */
+    params->myIPC = result->clone();
+
+    params->prog = prog;
+
+    params->args = (char **) args;
+
+    result->mySpawn->splitExecution ((Spawn::Child *)ipc_params::ThreadReflector, params);
+
+#else
+
+    result->mySpawn->splitExecution (ForkChild, result);
+
+#endif
 
-        if (cwfd != crfd)
-            comm_close(cwfd);
+    if (!result->mySpawn->success()) {
+        result->cleanUp();
+        return result;
+    }
 
-        cwfd = crfd = -1;
+#ifndef _SQUID_MSWIN_
+    if (result->mySpawn->getPid() > 0) {		/* parent */
+        /* close shared socket with child */
+        result->childFD.close();
 
         if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
-            if (comm_connect_addr(pwfd, &ChS) == COMM_ERROR)
-                return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        }
+#else
+    {
+        {
+#endif
 
+            if (comm_connect_addr(result->pwfd, &result->CS()) == COMM_ERROR)
+            {
+                result->cleanUp();
+                return result;
+            }
+        }
         memset(hello_buf, '\0', HELLO_BUF_SZ);
+#ifdef _SQUID_MSWIN_
+
+        x = recv(result->prfd, (void *) hello_buf, HELLO_BUF_SZ - 1, 0);
+#else
 
         if (type == IPC_UDP_SOCKET)
-            x = comm_udp_recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);
+            x = comm_udp_recv(result->prfd, hello_buf, HELLO_BUF_SZ - 1, 0);
         else
-            x = read(prfd, hello_buf, HELLO_BUF_SZ - 1);
+            x = read(result->prfd, hello_buf, HELLO_BUF_SZ - 1);
 
-        if (x < 0) {
-            debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
-            debug(54, 0) ("--> read: %s\n", xstrerror());
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        } else if (strcmp(hello_buf, hello_string)) {
+#endif
+
+        if (x < 0)
+        {
+            debug(50, 0) ("ipcCreate: PARENT: hello read test failed\n");
+            debug(50, 0) ("--> read: %s\n", xstrerror());
+            result->cleanUp();
+            return result;
+        } else if (strcmp(hello_buf, hello_string))
+        {
             debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
             debug(54, 0) ("--> read returned %d\n", x);
             debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
+            result->cleanUp();
+            return result;
+        }
+
+#ifdef _SQUID_MSWIN_
+        x = send(result->pwfd, (const void *) ok_string, strlen(ok_string), 0);
+
+        if (x < 0)
+        {
+            debug(50, 0) ("ipcCreate: PARENT: OK write test failed\n");
+            debug(50, 0) ("--> read: %s\n", xstrerror());
+            result->cleanUp();
+            return result;
+        }
+
+        memset(hello_buf, '\0', HELLO_BUF_SZ);
+        x = recv(result->prfd, (void *) hello_buf, HELLO_BUF_SZ - 1, 0);
+
+        if (x < 0)
+        {
+            debug(50, 0) ("ipcCreate: PARENT: OK read test failed\n");
+            debug(50, 0) ("--> read: %s\n", xstrerror());
+            result->cleanUp();
+            return result;
+        } else if (!strcmp(hello_buf, err_string))
+        {
+            debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n");
+            debug(54, 0) ("--> read returned %d\n", x);
+            debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
+            result->cleanUp();
+            return result;
         }
 
-        commSetTimeout(prfd, -1, NULL, NULL);
-        commSetNonBlocking(prfd);
-        commSetNonBlocking(pwfd);
+        hello_buf[x] = '\0';
+        pid_t pid = atol(hello_buf);
+        HANDLE HProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
+
+#endif
+
+        commSetTimeout(result->prfd, -1, NULL, NULL);
+        commSetNonBlocking(result->prfd);
+        commSetNonBlocking(result->pwfd);
+        fd_table[result->prfd].flags.ipc = 1;
+        fd_table[result->pwfd].flags.ipc = 1;
+#ifdef _SQUID_MSWIN_
+
+        fd_table[result->childFD.rfd].flags.ipc = 1;
+        fd_table[result->childFD.wfd].flags.ipc = 1;
+
+        if (Config.sleep_after_fork)
+        {
+            /* XXX emulation of usleep() */
+            DWORD sl;
+            sl = Config.sleep_after_fork / 1000;
+
+            if (sl == 0)
+                sl = 1;
 
-        if (rfd)
-            *rfd = prfd;
+            Sleep(sl);
+        }
 
-        if (wfd)
-            *wfd = pwfd;
+        DWORD ecode = 0;
 
-        fd_table[prfd].flags.ipc = 1;
+        if (GetExitCodeThread(result->mySpawn->getHandle(), &ecode) && ecode == STILL_ACTIVE)
+        {
+            result->result (IPCResult(true, pid, result->prfd, result->pwfd, HProcess));
+            debugs(50, 1, "IPC::Create: Program: " << prog << ", PID: " << ", Handle: 0x" << HProcess);
+
+            return result;
+        } else
+        {
+            result->cleanUp();
+            return result;
+        }
 
-        fd_table[pwfd].flags.ipc = 1;
+#else
 
-        if (Config.sleep_after_fork) {
+        if (Config.sleep_after_fork)
+        {
             /* XXX emulation of usleep() */
 
             struct timeval sl;
@@ -291,79 +1436,210 @@
             select(0, NULL, NULL, NULL, &sl);
         }
 
-        return pid;
+        result->result (IPCResult (true, result->mySpawn->getPid(), result->prfd, result->pwfd));
+        return result;
+#endif
+
     }
+#ifdef _SQUID_MSWIN_
+}
 
-    /* child */
-    no_suid();			/* give up extra priviliges */
+unsigned int
+ipc_params::threadLoop() {
+    int t1, t2, t3;
 
-    /* close shared socket with parent */
-    close(prfd);
+    struct thread_params thread_params;
+    int tempFD = -1;
+    char *str;
+    int tmp_s;
+
+    struct sockaddr_in CS_ipc, PS_ipc;
+
+    strcpy(buf1, prog);
+    niceprog = strtok(buf1, w_space);
+
+    if ((str = strrchr(niceprog, '/')))
+        niceprog = ++str;
+
+    if ((str = strrchr(niceprog, '\\')))
+        niceprog = ++str;
+
+    niceprog = xstrdup(niceprog);
+
+    assert (myIPC);
+
+    IPC *result = myIPC;
+
+    /* ForkChild is called directly from non windows routines */
+    IPC::ForkChild (myIPC);
+
+#endif
+
+    result->childFDConnect();
+
+    if (!result->childFDConnected())  {
+#ifdef _SQUID_MSWIN_
+        freeResources();
+        return 1;
+#else
 
-    if (pwfd != prfd)
-        close(pwfd);
+        result->cleanUp();
+        _exit (1);
+#endif
+
+    }
 
-    pwfd = prfd = -1;
+    tempFD = result->childFD.rfd;
 
-    if (type == IPC_TCP_SOCKET) {
-        debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
+    /* XXX: candidate for extract method */
+    {
+        int sendresult = result->childWrite(hello_string, strlen(hello_string) + 1);
+
+        if (sendresult < 0)
+        {
+            debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n");
+#ifdef _SQUID_MSWIN_
+
+            freeResources();
+            return 1;
+#else
 
-        if ((fd = accept(crfd, NULL, NULL)) < 0) {
-            debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
+            result->cleanUp();
             _exit(1);
+#endif
+
         }
+    }
+    PutEnvironment();
+#ifndef _SQUID_MSWIN_
+
+    result->doExec();
+    return 0;
+#else
+
+    memset(buf1, '\0', sizeof(buf1));
+    int recvresult = recv(myIPC->childFD.rfd, (void *) buf1, 8191, 0);
+
+    if (recvresult < 0) {
+        debug(50, 0) ("ipcCreate: CHILD: OK read test failed\n");
+        debug(50, 0) ("--> read: %s\n", xstrerror());
+        freeResources();
+        return 1;
+    } else if (strcmp(buf1, ok_string)) {
+        debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
+        debug(54, 0) ("--> read returned %d\n", recvresult);
+        debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
+        freeResources();
+        return 1;
+    }
 
-        debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
-        close(crfd);
-        cwfd = crfd = fd;
-    } else if (type == IPC_UDP_SOCKET) {
-        if (comm_connect_addr(crfd, &PaS) == COMM_ERROR)
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
+    /* create FDs for child */
+
+    if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
+        debug(50, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
+        ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+        freeResources();
+        return 1;
+    }
+
+    if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
+        debug(50, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
+        ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+        freeResources();
+        return 1;
     }
 
+    /* assign file descriptors to child process */
     if (type == IPC_UDP_SOCKET) {
-        x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0);
+        snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", niceprog, -1L);
+        crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);
 
-        if (x < 0) {
-            debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
-            debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
-            _exit(1);
+        if (crfd_ipc < 0) {
+            debug(54,
+                  0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n",
+                      niceprog);
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
         }
-    } else {
-        if (write(cwfd, hello_string, strlen(hello_string) + 1) < 0) {
-            debug(54, 0) ("write FD %d: %s\n", cwfd, xstrerror());
-            debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
-            _exit(1);
+
+        snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", niceprog, -1L);
+        prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);
+
+        if (pwfd_ipc < 0) {
+            debug(54,
+                  0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n",
+                      niceprog);
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
         }
-    }
 
-    PutEnvironment();
-    /*
-     * This double-dup stuff avoids problems when one of 
-     *  crfd, cwfd, or debug_log are in the rage 0-2.
-     */
+        tmp_s = sizeof(PS_ipc);
+        memset(&PS_ipc, '\0', tmp_s);
 
-    do {
-        /* First make sure 0-2 is occupied by something. Gets cleaned up later */
-        x = dup(crfd);
-        assert(x > -1);
-    } while (x < 3 && x > -1);
+        if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) {
+            debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+
+        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
+                      pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port));
+        tmp_s = sizeof(CS_ipc);
+        memset(&CS_ipc, '\0', tmp_s);
+
+        if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) {
+            debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+
+        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
+                      crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port));
 
-    close(x);
+        if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) {
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
 
-    t1 = dup(crfd);
+        tempFD = myIPC->childFD.rfd;
 
-    t2 = dup(cwfd);
+        if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) {
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+    }		/* IPC_UDP_SOCKET */
 
-    t3 = dup(fileno(debug_log));
+    assert (tempFD == myIPC->childFD.rfd);
 
-    assert(t1 > 2 && t2 > 2 && t3 > 2);
+    t1 = dup(0);
 
-    close(crfd);
+    t2 = dup(1);
 
-    close(cwfd);
+    t3 = dup(2);
 
-    close(fileno(debug_log));
+    dup2(c2p[0], 0);
+
+    dup2(p2c[1], 1);
+
+    dup2(fileno(debug_log), 2);
+
+    close(c2p[0]);
+
+    close(p2c[1]);
+
+    commUnsetNonBlocking(tempFD);
+
+    SpawnResult spawnResult = ipc_spawn (prog, args);
+
+    pid = spawnResult.pid;
+
+    hProcess = spawnResult.hProcess;
 
     dup2(t1, 0);
 
@@ -377,22 +1653,315 @@
 
     close(t3);
 
-    /* Make sure all other filedescriptors are closed */
-    for (x = 3; x < SQUID_MAXFD; x++)
-        close(x);
+    if (pid == -1) {
+        errno = spawnResult.error;
+        debug(50, 0) ("ipcCreate: CHILD: %s: %s\n", prog, xstrerror());
+        ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+        freeResources();
+        return 1;
+    }
 
-    if (opt_no_daemon) {
-        squid_signal(SIGINT, SIG_IGN, SA_RESETHAND);
-        squid_signal(SIGHUP, SIG_IGN, SA_RESETHAND);
+    /* Ok, the child has started */
+    if (type == IPC_UDP_SOCKET) {
+        WSAPROTOCOL_INFO wpi;
+
+        memset(&wpi, 0, sizeof(wpi));
+
+        if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
+            debug(50, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n",
+                          xstrerror());
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+
+        int writeresult = write(c2p[1], (const char *) &wpi, sizeof(wpi));
+
+        if (writeresult < 0 || static_cast <size_t>(writeresult) < sizeof(wpi)) {
+            debug(50, 0)
+            ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
+             xstrerror());
+            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
+                          niceprog);
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+
+        int readresult = read(p2c[0], buf1, 8192);
+
+        if (readresult < 0) {
+            debug(50, 0)
+            ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
+             xstrerror());
+            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
+                          niceprog);
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
+            debug(54, 0)
+            ("ipcCreate: CHILD: %s: socket exchange failed\n",
+             niceprog);
+            debug(54, 0) ("--> read returned %d\n", readresult);
+            buf1[readresult] = '\0';
+            debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+
+        int write2result = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
+
+        if (write2result < 0 || static_cast<size_t>(write2result) < sizeof(PS_ipc)) {
+            debug(50, 0)
+            ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
+             xstrerror());
+            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
+                          niceprog);
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+
+        int read2result = read(p2c[0], buf1, 8192);
+
+        if (read2result < 0) {
+            debug(50, 0)
+            ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
+             xstrerror());
+            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
+                          niceprog);
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
+            debug(54, 0)
+            ("ipcCreate: CHILD: %s: socket exchange failed\n",
+             niceprog);
+            debug(54, 0) ("--> read returned %d\n", read2result);
+            buf1[read2result] = '\0';
+            debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
+            ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+            freeResources();
+            return 1;
+        }
+
+        /* We should error check this send */
+        send(pwfd_ipc, (const void *) ok_string, strlen(ok_string), 0);
+        int recvrv = recv(prfd_ipc, (void *) (buf1 + 200), 8191 - 200, 0);
+        assert((size_t) recvrv == strlen(ok_string)
+               && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
+    }	/* IPC_UDP_SOCKET */
+
+    snprintf(buf1, 8191, "%s(%ld) CHILD socket", niceprog, (long int)pid);
+
+    fd_note(tempFD, buf1);
+
+    if (prfd_ipc != -1) {
+        snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", niceprog, (long int)pid);
+        fd_note(crfd_ipc, buf1);
+        snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", niceprog, (long int)pid);
+        fd_note(prfd_ipc, buf1);
+    }				/* else {                      // IPC_TCP_SOCKET
+
+    * commSetNoLinger(fd);
+    * }
+    */
+    thread_params.prog = niceprog;
+
+    thread_params.send_fd = myIPC->childFD.wfd;
+
+    thread_params.pid = pid;
+
+    if ((thread_params.type = type) == IPC_TCP_SOCKET)
+        thread_params.rfd = p2c[0];
+    else
+        thread_params.rfd = prfd_ipc;
+
+    thread =
+        (HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL);
+
+    if (!thread) {
+        debug(50, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror());
+        ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string));
+        freeResources();
+        return 1;
     }
 
-    execvp(prog, (char *const *) args);
+    snprintf(buf1, 8191, "%ld\n", (long int)pid);
 
-    debug_log = fdopen(2, "a+");
+    if (-1 == ipcSend(myIPC->childFD.wfd, buf1, strlen(buf1))) {
+        freeResources();
+        return 1;
+    }
 
-    debug(54, 0) ("ipcCreate: %s: %s\n", prog, xstrerror());
+    debug(54, 2) ("ipc(%s,%ld): started successfully\n", niceprog, (long int)pid);
+    parentToChildLoop();
 
-    _exit(1);
+    normalExit();
+    freeResources();
+    return 0;
+}
+
+void
+ipc_params::normalExit() {
+    debug(54, 2) ("ipc(%s,%d): normal exit\n", niceprog, pid);
+}
+
+void
+ipc_params::freeResources() {
+    if (c2p[1] != -1)
+        close(c2p[1]);
+
+    if (fd_table[myIPC->childFD.rfd].flags.open)
+        myIPC->childFD.close();
+
+    if (prfd_ipc != -1) {
+        send(crfd_ipc, (const void *) shutdown_string, strlen(shutdown_string), 0);
+        shutdown(crfd_ipc, SD_BOTH);
+        shutdown(prfd_ipc, SD_BOTH);
+    }
+
+    ipcCloseAllFD(prfd_ipc, pwfd_ipc);
+    myIPC->childFD.close();
+
+    if (hProcess && WAIT_OBJECT_0 !=
+            WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {
+
+        getCurrentTime();
+        debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n",
+                      niceprog, pid, niceprog, type == IPC_UDP_SOCKET ? 12 : 5);
+    }
+
+    if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
+        getCurrentTime();
+        debug(54, 0)
+        ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n",
+         niceprog, pid);
+    }
+
+    getCurrentTime();
+    safe_free(niceprog);
+#if HAVE_PUTENV
+
+    safe_free(env_str);
+#endif
+
+    if (thread)
+        CloseHandle(thread);
+
+    if (hProcess)
+        CloseHandle(hProcess);
+
+    if (p2c[0] != -1)
+        close(p2c[0]);
+
+#endif
+}
+
+#ifdef _SQUID_MSWIN_
+void
+ipc_params::parentToChildLoop() {
+    /* cycle */
+
+    for (;;) {
+        int recvrv = recv(myIPC->childFD.rfd, (void *) buf1, 8192, 0);
+
+        if (recvrv <= 0) {
+            debug(54, 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n",
+                          niceprog, pid, recvrv);
+            return;
+        }
 
+        buf1[recvrv] = '\0';
+
+        if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
+            debug(54, 3)
+            ("ipc(%s,%d): request for shutdown received from parent. Exiting...\n",
+             niceprog, pid);
+            //            TerminateProcess(hProcess, 0);
+            return;
+        }
+
+        debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", niceprog, pid,
+                      rfc1738_escape_unescaped(buf1));
+        int writerv;
+
+        if (type == IPC_TCP_SOCKET)
+            writerv = write(c2p[1], buf1, recvrv);
+        else
+            writerv = send(pwfd_ipc, (const void *) buf1, recvrv, 0);
+
+        if (writerv <= 0) {
+            debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n",
+                          niceprog, pid, writerv, niceprog);
+            return;
+        }
+    }
+}
+
+#endif
+
+void
+IPCInstance::childToParentLoop() {
+    char buf2[8192];
+
+    for (;;) {
+        int x;
+
+        if (type == IPC_TCP_SOCKET)
+            x = read(prfd, buf2, 8192);
+        else
+            x = recv(prfd, (void *) buf2, 8192, 0);
+
+        if ((x <= 0 && type == IPC_TCP_SOCKET) ||
+                (x < 0 && type == IPC_UDP_SOCKET)) {
+            debug(54, 3) ("ipc(%s,%d): %d bytes read from %s. Exiting...\n",
+                          prog, pid, x, prog);
+            break;
+        }
+
+        buf2[x] = '\0';
+
+        if (type == IPC_UDP_SOCKET && !strcmp(buf2, ShutdownMessage)) {
+            debug(54, 3) ("ipc(%s,%d): request for shutdown received. Exiting...\n",
+                          prog, pid);
+            break;
+        }
+
+        if (x >= 2) {
+            if ((buf2[x-1] == '\n') && (buf2[x-2] == '\r')) {
+                buf2[x-2] = '\n';
+                buf2[x-1] = '\0';
+                x--;
+            }
+        }
+
+        debug(54, 5) ("ipc(%s,%d): received from child : %s\n", prog, pid,
+                      rfc1738_escape_unescaped(buf2));
+        x = send(send_fd, (const void *) buf2, x, 0);
+
+        if ((x <= 0 && type == IPC_TCP_SOCKET) ||
+                (x < 0 && type == IPC_UDP_SOCKET)) {
+            debug(54, 3) ("ipc(%s,%d): %d bytes sent to parent. Exiting...\n",
+                          prog, pid, x);
+            break;
+        }
+    }
+}
+
+#ifdef _SQUID_MSWIN_
+static unsigned int __stdcall
+ipc_thread_2(void *voidParam) {
+
+    struct thread_params *params = static_cast<struct thread_params *>(voidParam);
+    IPCInstance *newInstance = new IPCInstance(params->type, params->pid, params->prog, params->rfd, params->send_fd);
+
+    newInstance->childToParentLoop();
+
+    delete newInstance;
     return 0;
 }
+
+#endif
Index: squid3/src/ipc.h
diff -u /dev/null squid3/src/ipc.h:1.1.32.2
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid3/src/ipc.h	Sun Oct 22 05:17:08 2006
@@ -0,0 +1,79 @@
+
+/*
+ * $Id$
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_IPC_H
+#define SQUID_IPC_H
+
+
+#define IPC_NONE 0
+#define IPC_TCP_SOCKET 1
+#define IPC_UDP_SOCKET 2
+
+#ifndef _SQUID_MSWIN_
+
+#if !(USE_POLL && defined(_SQUID_OSF_))
+
+#define IPC_FIFO 3
+
+#endif
+
+#define IPC_UNIX_STREAM 4
+#define IPC_UNIX_DGRAM 5
+#endif
+
+#if HAVE_SOCKETPAIR && defined (AF_UNIX)
+#define IPC_STREAM IPC_UNIX_STREAM
+#define IPC_DGRAM IPC_UNIX_DGRAM
+#else
+#define IPC_STREAM IPC_TCP_SOCKET
+#define IPC_DGRAM IPC_UDP_SOCKET
+#endif
+
+struct IPCResult {
+    IPCResult (int causelinkfailure);
+    IPCResult (bool aBool, pid_t aPid=-1, int _rfd=-1, int _wfd = -1 ,void * aHandle=NULL) : success(aBool), pid (aPid), rfd (_rfd), wfd (_wfd), hIpc(aHandle)
+	{}
+    bool success;
+    pid_t pid;
+    int rfd;
+    int wfd;
+    void * hIpc;
+};
+
+IPCResult ipcCreate(int type,
+    const char *prog,
+    const char *const args[],
+    const char *name
+);
+
+#endif /* SQUID_IPC_H */
Index: squid3/src/ipc_win32.cc
diff -u squid3/src/ipc_win32.cc:1.3 squid3/src/ipc_win32.cc:removed
--- squid3/src/ipc_win32.cc:1.3	Sat Sep  9 08:50:33 2006
+++ squid3/src/ipc_win32.cc	Mon May 14 11:17:21 2007
@@ -1,864 +0,0 @@
-
-/*
- * $Id$
- *
- * DEBUG: section 54    Windows Interprocess Communication
- * AUTHOR: Andrey Shorin <tolsty@tushino.com>
- * AUTHOR: Guido Serassio <serassio@squid-cache.org>
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "comm.h"
-#include "fde.h"
-#include "SquidTime.h"
-
-#ifndef _MSWSOCK_
-#include <mswsock.h>
-#endif
-#include <process.h>
-
-struct ipc_params
-{
-    int type;
-    int crfd;
-    int cwfd;
-
-    struct sockaddr_in PS;
-    const char *prog;
-    char **args;
-};
-
-struct thread_params
-{
-    int type;
-    int rfd;
-    int send_fd;
-    const char *prog;
-    pid_t pid;
-};
-
-static unsigned int __stdcall ipc_thread_1(void *params);
-static unsigned int __stdcall ipc_thread_2(void *params);
-
-static const char *ok_string = "OK\n";
-static const char *err_string = "ERR\n";
-static const char *shutdown_string = "$shutdown\n";
-
-static const char *hello_string = "hi there\n";
-#define HELLO_BUF_SZ 32
-static char hello_buf[HELLO_BUF_SZ];
-
-static int
-ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
-{
-    if (prfd >= 0)
-        comm_close(prfd);
-
-    if (prfd != pwfd)
-        if (pwfd >= 0)
-            comm_close(pwfd);
-
-    if (crfd >= 0)
-        comm_close(crfd);
-
-    if (crfd != cwfd)
-        if (cwfd >= 0)
-            comm_close(cwfd);
-
-    return -1;
-}
-
-static void
-PutEnvironment()
-{
-#if HAVE_PUTENV
-    char *env_str;
-    int tmp_s;
-    env_str = (char *)xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
-    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
-    putenv(env_str);
-#endif
-}
-
-pid_t
-ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, void **hIpc)
-{
-    unsigned long thread;
-
-    struct ipc_params params;
-    int opt;
-    int optlen = sizeof(opt);
-    DWORD ecode = 0;
-    pid_t pid;
-
-    struct sockaddr_in CS;
-
-    struct sockaddr_in PS;
-    int crfd = -1;
-    int prfd = -1;
-    int cwfd = -1;
-    int pwfd = -1;
-    socklen_t len;
-    int x;
-
-    requirePathnameExists(name, prog);
-
-    if (rfd)
-        *rfd = -1;
-
-    if (wfd)
-        *wfd = -1;
-
-    if (hIpc)
-        *hIpc = NULL;
-
-    if (WIN32_OS_version != _WIN_OS_WINNT) {
-        getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
-        opt = opt & ~(SO_SYNCHRONOUS_NONALERT | SO_SYNCHRONOUS_ALERT);
-        setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, sizeof(opt));
-    }
-
-    if (type == IPC_TCP_SOCKET) {
-        crfd = cwfd = comm_open(SOCK_STREAM,
-                                IPPROTO_TCP,
-                                local_addr,
-                                0,
-                                COMM_NOCLOEXEC,
-                                name);
-        prfd = pwfd = comm_open(SOCK_STREAM,
-                                IPPROTO_TCP,	/* protocol */
-                                local_addr,
-                                0,			/* port */
-                                0,			/* blocking */
-                                name);
-    } else if (type == IPC_UDP_SOCKET) {
-        crfd = cwfd = comm_open(SOCK_DGRAM,
-                                IPPROTO_UDP,
-                                local_addr,
-                                0,
-                                COMM_NOCLOEXEC,
-                                name);
-        prfd = pwfd = comm_open(SOCK_DGRAM,
-                                IPPROTO_UDP,
-                                local_addr,
-                                0,
-                                0,
-                                name);
-    } else if (type == IPC_FIFO) {
-        debug(54, 0)
-        ("ipcCreate: %s: use IPC_TCP_SOCKET instead of IP_FIFO on Windows\n",
-         prog);
-        assert(0);
-    } else {
-        assert(IPC_NONE);
-    }
-
-    debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd);
-    debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd);
-    debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd);
-    debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd);
-
-    if (WIN32_OS_version != _WIN_OS_WINNT) {
-        getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
-        opt = opt | SO_SYNCHRONOUS_NONALERT;
-        setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen);
-    }
-
-    if (crfd < 0) {
-        debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
-        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-    }
-
-    if (pwfd < 0) {
-        debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
-        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-    }
-
-    if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
-        len = sizeof(PS);
-        memset(&PS, '\0', len);
-
-        if (getsockname(pwfd, (struct sockaddr *) &PS, &len) < 0) {
-            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        }
-
-        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
-                      pwfd, inet_ntoa(PS.sin_addr), ntohs(PS.sin_port));
-        len = sizeof(CS);
-        memset(&CS, '\0', len);
-
-        if (getsockname(crfd, (struct sockaddr *) &CS, &len) < 0) {
-            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        }
-
-        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
-                      crfd, inet_ntoa(CS.sin_addr), ntohs(CS.sin_port));
-    }
-
-    if (type == IPC_TCP_SOCKET) {
-        if (listen(crfd, 1) < 0) {
-            debug(54, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror());
-            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-        }
-
-        debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
-    }
-
-    /* flush or else we get dup data if unbuffered_logs is set */
-    logsFlush();
-
-    params.type = type;
-
-    params.crfd = crfd;
-
-    params.cwfd = cwfd;
-
-    params.PS = PS;
-
-    params.prog = prog;
-
-    params.args = (char **) args;
-
-    thread = _beginthreadex(NULL, 0, ipc_thread_1, &params, 0, NULL);
-
-    if (thread == 0) {
-        debug(54, 1) ("ipcCreate: _beginthread: %s\n", xstrerror());
-        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
-    }
-
-    if (comm_connect_addr(pwfd, &CS) == COMM_ERROR) {
-        CloseHandle((HANDLE) thread);
-        return ipcCloseAllFD(prfd, pwfd, -1, -1);
-    }
-
-    memset(hello_buf, '\0', HELLO_BUF_SZ);
-    x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0);
-
-    if (x < 0) {
-        debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
-        debug(54, 0) ("--> read: %s\n", xstrerror());
-        CloseHandle((HANDLE) thread);
-        return ipcCloseAllFD(prfd, pwfd, -1, -1);
-    } else if (strcmp(hello_buf, hello_string)) {
-        debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
-        debug(54, 0) ("--> read returned %d\n", x);
-        debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
-        CloseHandle((HANDLE) thread);
-        return ipcCloseAllFD(prfd, pwfd, -1, -1);
-    }
-
-    x = send(pwfd, (const void *)ok_string, strlen(ok_string), 0);
-
-    if (x < 0) {
-        debug(54, 0) ("ipcCreate: PARENT: OK write test failed\n");
-        debug(54, 0) ("--> read: %s\n", xstrerror());
-        CloseHandle((HANDLE) thread);
-        return ipcCloseAllFD(prfd, pwfd, -1, -1);
-    }
-
-    memset(hello_buf, '\0', HELLO_BUF_SZ);
-    x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0);
-
-    if (x < 0) {
-        debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n");
-        debug(54, 0) ("--> read: %s\n", xstrerror());
-        CloseHandle((HANDLE) thread);
-        return ipcCloseAllFD(prfd, pwfd, -1, -1);
-    } else if (!strcmp(hello_buf, err_string)) {
-        debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n");
-        debug(54, 0) ("--> read returned %d\n", x);
-        debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
-        CloseHandle((HANDLE) thread);
-        return ipcCloseAllFD(prfd, pwfd, -1, -1);
-    }
-
-    hello_buf[x] = '\0';
-    pid = atol(hello_buf);
-    commSetTimeout(prfd, -1, NULL, NULL);
-    commSetNonBlocking(prfd);
-    commSetNonBlocking(pwfd);
-    commSetCloseOnExec(prfd);
-    commSetCloseOnExec(pwfd);
-
-    if (rfd)
-        *rfd = prfd;
-
-    if (wfd)
-        *wfd = pwfd;
-
-    fd_table[prfd].flags.ipc = 1;
-
-    fd_table[pwfd].flags.ipc = 1;
-
-    fd_table[crfd].flags.ipc = 1;
-
-    fd_table[cwfd].flags.ipc = 1;
-
-    if (Config.sleep_after_fork) {
-        /* XXX emulation of usleep() */
-        DWORD sl;
-        sl = Config.sleep_after_fork / 1000;
-
-        if (sl == 0)
-            sl = 1;
-
-        Sleep(sl);
-    }
-
-    if (GetExitCodeThread((HANDLE) thread, &ecode) && ecode == STILL_ACTIVE) {
-        if (hIpc)
-            *hIpc = (HANDLE) thread;
-
-        return pid;
-    } else {
-        CloseHandle((HANDLE) thread);
-        return ipcCloseAllFD(prfd, pwfd, -1, -1);
-    }
-}
-
-static int
-ipcSend(int cwfd, const char *buf, int len)
-{
-    int x;
-
-    x = send(cwfd, (const void *)buf, len, 0);
-
-    if (x < 0) {
-        debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
-        debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
-    }
-
-    return x;
-}
-
-static unsigned int __stdcall
-ipc_thread_1(void *in_params)
-{
-    int t1, t2, t3, retval = -1;
-    int p2c[2] =
-        {-1, -1};
-    int c2p[2] =
-        {-1, -1};
-    HANDLE hProcess = NULL, thread = NULL;
-    pid_t pid = -1;
-
-    struct thread_params thread_params;
-    ssize_t x;
-    int tmp_s, fd = -1;
-    char *str;
-    STARTUPINFO si;
-    PROCESS_INFORMATION pi;
-    long F;
-    int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1;
-    char *prog = NULL, *buf1 = NULL;
-
-    struct sockaddr_in CS_ipc, PS_ipc;
-
-    struct ipc_params *params = (struct ipc_params *) in_params;
-    int type = params->type;
-    int crfd = params->crfd;
-    int cwfd = params->cwfd;
-    char **args = params->args;
-
-    struct sockaddr_in PS = params->PS;
-
-
-    buf1 = (char *)xcalloc(1, 8192);
-    strcpy(buf1, params->prog);
-    prog = strtok(buf1, w_space);
-
-    if ((str = strrchr(prog, '/')))
-        prog = ++str;
-
-    if ((str = strrchr(prog, '\\')))
-        prog = ++str;
-
-    prog = xstrdup(prog);
-
-    if (type == IPC_TCP_SOCKET) {
-        debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
-
-        if ((fd = accept(crfd, NULL, NULL)) < 0) {
-            debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
-            goto cleanup;
-        }
-
-        debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
-        comm_close(crfd);
-        snprintf(buf1, 8191, "%s CHILD socket", prog);
-        fd_open(fd, FD_SOCKET, buf1);
-        fd_table[fd].flags.ipc = 1;
-        cwfd = crfd = fd;
-    } else if (type == IPC_UDP_SOCKET) {
-        if (comm_connect_addr(crfd, &PS) == COMM_ERROR)
-            goto cleanup;
-    }
-
-    x = send(cwfd, (const void *)hello_string, strlen(hello_string) + 1, 0);
-
-    if (x < 0) {
-        debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
-        debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
-        goto cleanup;
-    }
-
-    PutEnvironment();
-    memset(buf1, '\0', sizeof(buf1));
-    x = recv(crfd, (void *)buf1, 8191, 0);
-
-    if (x < 0) {
-        debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
-        debug(54, 0) ("--> read: %s\n", xstrerror());
-        goto cleanup;
-    } else if (strcmp(buf1, ok_string)) {
-        debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
-        debug(54, 0) ("--> read returned %d\n", x);
-        debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
-        goto cleanup;
-    }
-
-    /* assign file descriptors to child process */
-    if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
-        debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
-        ipcSend(cwfd, err_string, strlen(err_string));
-        goto cleanup;
-    }
-
-    if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
-        debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
-        ipcSend(cwfd, err_string, strlen(err_string));
-        goto cleanup;
-    }
-
-    if (type == IPC_UDP_SOCKET) {
-        snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L);
-        crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);
-
-        if (crfd_ipc < 0) {
-            debug(54, 0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n",
-                          prog);
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L);
-        prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);
-
-        if (pwfd_ipc < 0) {
-            debug(54, 0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n",
-                          prog);
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        tmp_s = sizeof(PS_ipc);
-        memset(&PS_ipc, '\0', tmp_s);
-
-        if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) {
-            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
-                      pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port));
-        tmp_s = sizeof(CS_ipc);
-        memset(&CS_ipc, '\0', tmp_s);
-
-        if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) {
-            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
-                      crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port));
-
-        if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) {
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        fd = crfd;
-
-        if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) {
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-    }				/* IPC_UDP_SOCKET */
-
-    t1 = dup(0);
-
-    t2 = dup(1);
-
-    t3 = dup(2);
-
-    dup2(c2p[0], 0);
-
-    dup2(p2c[1], 1);
-
-    dup2(fileno(debug_log), 2);
-
-    close(c2p[0]);
-
-    close(p2c[1]);
-
-    commUnsetNonBlocking(fd);
-
-    memset(&si, 0, sizeof(STARTUPINFO));
-
-    si.cb = sizeof(STARTUPINFO);
-
-    si.hStdInput = (HANDLE) _get_osfhandle(0);
-
-    si.hStdOutput = (HANDLE) _get_osfhandle(1);
-
-    si.hStdError = (HANDLE) _get_osfhandle(2);
-
-    si.dwFlags = STARTF_USESTDHANDLES;
-
-    /* Make sure all other valid handles are not inerithable */
-    for (x = 3; x < Squid_MaxFD; x++) {
-        if ((F = _get_osfhandle(x)) == -1)
-            continue;
-
-        SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0);
-    }
-
-    *buf1 = '\0';
-    strcpy(buf1 + 4096, params->prog);
-    str = strtok(buf1 + 4096, w_space);
-
-    do {
-        strcat(buf1, str);
-        strcat(buf1, " ");
-    } while ((str = strtok(NULL, w_space)));
-
-    x = 1;
-
-    while (args[x]) {
-        strcat(buf1, args[x++]);
-        strcat(buf1, " ");
-    }
-
-    if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW,
-                      NULL, NULL, &si, &pi)) {
-        pid = pi.dwProcessId;
-        hProcess = pi.hProcess;
-    } else {
-        pid = -1;
-        WIN32_maperror(GetLastError());
-        x = errno;
-    }
-
-    dup2(t1, 0);
-    dup2(t2, 1);
-    dup2(t3, 2);
-    close(t1);
-    close(t2);
-    close(t3);
-
-    if (pid == -1) {
-        errno = x;
-        debug(54, 0) ("ipcCreate: CHILD: %s: %s\n", params->prog, xstrerror());
-        ipcSend(cwfd, err_string, strlen(err_string));
-        goto cleanup;
-    }
-
-    if (type == IPC_UDP_SOCKET) {
-        WSAPROTOCOL_INFO wpi;
-
-        memset(&wpi, 0, sizeof(wpi));
-
-        if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
-            debug(54, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n",
-                          xstrerror());
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        x = write(c2p[1], (const char *) &wpi, sizeof(wpi));
-
-        if (x < (ssize_t)sizeof(wpi)) {
-            debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
-                          xstrerror());
-            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
-                          prog);
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        x = read(p2c[0], buf1, 8192);
-
-        if (x < 0) {
-            debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
-                          xstrerror());
-            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
-                          prog);
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
-            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
-                          prog);
-            debug(54, 0) ("--> read returned %d\n", x);
-            buf1[x] = '\0';
-            debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
-
-        if (x < (ssize_t)sizeof(PS_ipc)) {
-            debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
-                          xstrerror());
-            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
-                          prog);
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        x = read(p2c[0], buf1, 8192);
-
-        if (x < 0) {
-            debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
-                          xstrerror());
-            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
-                          prog);
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
-            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
-                          prog);
-            debug(54, 0) ("--> read returned %d\n", x);
-            buf1[x] = '\0';
-            debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
-            ipcSend(cwfd, err_string, strlen(err_string));
-            goto cleanup;
-        }
-
-        x = send(pwfd_ipc, (const void *)ok_string, strlen(ok_string), 0);
-        x = recv(prfd_ipc, (void *)(buf1 + 200), 8191 - 200, 0);
-        assert((size_t) x == strlen(ok_string)
-               && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
-    }				/* IPC_UDP_SOCKET */
-
-    snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid);
-
-    fd_note(fd, buf1);
-
-    if (prfd_ipc != -1) {
-        snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid);
-        fd_note(crfd_ipc, buf1);
-        snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid);
-        fd_note(prfd_ipc, buf1);
-    }
-
-    /* else {                       IPC_TCP_SOCKET */
-    /*     commSetNoLinger(fd); */
-    /*  } */
-    thread_params.prog = prog;
-
-    thread_params.send_fd = cwfd;
-
-    thread_params.pid = pid;
-
-    if ((thread_params.type = type) == IPC_TCP_SOCKET)
-        thread_params.rfd = p2c[0];
-    else
-        thread_params.rfd = prfd_ipc;
-
-    thread =
-        (HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL);
-
-    if (!thread) {
-        debug(54, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror());
-        ipcSend(cwfd, err_string, strlen(err_string));
-        goto cleanup;
-    }
-
-    snprintf(buf1, 8191, "%ld\n", (long int) pid);
-
-    if (-1 == ipcSend(cwfd, buf1, strlen(buf1)))
-        goto cleanup;
-
-    debug(54, 2) ("ipc(%s,%ld): started successfully\n", prog, (long int) pid);
-
-    /* cycle */
-    for (;;) {
-        x = recv(crfd, (void *)buf1, 8192, 0);
-
-        if (x <= 0) {
-            debug(54, 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n",
-                          prog, pid, x);
-            break;
-        }
-
-        buf1[x] = '\0';
-
-        if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
-            debug(54, 3)
-            ("ipc(%s,%d): request for shutdown received from parent. Exiting...\n",
-             prog, pid);
-            TerminateProcess(hProcess, 0);
-            break;
-        }
-
-        debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", prog, pid,
-                      rfc1738_escape_unescaped(buf1));
-
-        if (type == IPC_TCP_SOCKET)
-            x = write(c2p[1], buf1, x);
-        else
-            x = send(pwfd_ipc, (const void *)buf1, x, 0);
-
-        if (x <= 0) {
-            debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n",
-                          prog, pid, x, prog);
-            break;
-        }
-    }
-
-    retval = 0;
-
-cleanup:
-
-    if (c2p[1] != -1)
-        close(c2p[1]);
-
-    if (fd_table[crfd].flags.open)
-        ipcCloseAllFD(-1, -1, crfd, cwfd);
-
-    if (prfd_ipc != -1) {
-        send(crfd_ipc, (const void *)shutdown_string, strlen(shutdown_string), 0);
-        shutdown(crfd_ipc, SD_BOTH);
-        shutdown(prfd_ipc, SD_BOTH);
-    }
-
-    ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc);
-
-    if (hProcess && WAIT_OBJECT_0 !=
-            WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {
-
-        getCurrentTime();
-        debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n",
-                      prog, pid, prog, type == IPC_UDP_SOCKET ? 12 : 5);
-    }
-
-    if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
-        getCurrentTime();
-        debug(54, 0)
-        ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n",
-         prog, pid);
-    }
-
-    getCurrentTime();
-
-    if (!retval)
-        debug(54, 2) ("ipc(%s,%d): normal exit\n", prog, pid);
-
-    if (buf1)
-        xfree(buf1);
-
-    if (prog)
-        xfree(prog);
-
-    if (thread)
-        CloseHandle(thread);
-
-    if (hProcess)
-        CloseHandle(hProcess);
-
-    if (p2c[0] != -1)
-        close(p2c[0]);
-
-    return retval;
-}
-
-static unsigned int __stdcall
-ipc_thread_2(void *in_params)
-{
-    int x;
-
-    struct thread_params *params = (struct thread_params *) in_params;
-    int type = params->type;
-    int rfd = params->rfd;
-    int send_fd = params->send_fd;
-    char *prog = xstrdup(params->prog);
-    pid_t pid = params->pid;
-    char *buf2 = (char *)xcalloc(1, 8192);
-
-    for (;;) {
-        if (type == IPC_TCP_SOCKET)
-            x = read(rfd, buf2, 8192);
-        else
-            x = recv(rfd, (void *)buf2, 8192, 0);
-
-        if ((x <= 0 && type == IPC_TCP_SOCKET) ||
-                (x < 0 && type == IPC_UDP_SOCKET)) {
-            debug(54, 3) ("ipc(%s,%d): %d bytes read from %s. Exiting...\n",
-                          prog, pid, x, prog);
-            break;
-        }
-
-        buf2[x] = '\0';
-
-        if (type == IPC_UDP_SOCKET && !strcmp(buf2, shutdown_string)) {
-            debug(54, 3) ("ipc(%s,%d): request for shutdown received. Exiting...\n",
-                          prog, pid);
-            break;
-        }
-
-        if (x >= 2) {
-            if ((buf2[x - 1] == '\n') && (buf2[x - 2] == '\r')) {
-                buf2[x - 2] = '\n';
-                buf2[x - 1] = '\0';
-                x--;
-            }
-        }
-
-        debug(54, 5) ("ipc(%s,%d): received from child : %s\n", prog, pid,
-                      rfc1738_escape_unescaped(buf2));
-        x = send(send_fd, (const void *)buf2, x, 0);
-
-        if ((x <= 0 && type == IPC_TCP_SOCKET) ||
-                (x < 0 && type == IPC_UDP_SOCKET)) {
-            debug(54, 3) ("ipc(%s,%d): %d bytes sent to parent. Exiting...\n",
-                          prog, pid, x);
-            break;
-        }
-    }
-
-    xfree(prog);
-    xfree(buf2);
-    return 0;
-}
Index: squid3/src/protos.h
diff -u squid3/src/protos.h:1.82 squid3/src/protos.h:1.60.2.13
--- squid3/src/protos.h:1.82	Fri Apr 20 17:16:10 2007
+++ squid3/src/protos.h	Sat Apr 28 09:35:24 2007
@@ -682,7 +682,6 @@
                              int *wfd,
                              void **hIpc);
 
-
 /* CacheDigest */
 SQUIDCEXTERN CacheDigest *cacheDigestCreate(int capacity, int bpe);
 SQUIDCEXTERN void cacheDigestDestroy(CacheDigest * cd);
Index: squid3/src/redirect.cc
diff -u squid3/src/redirect.cc:1.22 squid3/src/redirect.cc:1.17.4.4
--- squid3/src/redirect.cc:1.22	Fri Apr 20 15:51:20 2007
+++ squid3/src/redirect.cc	Sat Apr 28 09:35:24 2007
@@ -38,6 +38,7 @@
 #include "CacheManager.h"
 #include "Store.h"
 #include "fde.h"
+#include "ipc.h"
 #include "client_side_request.h"
 #include "ACLChecklist.h"
 #include "HttpRequest.h"
Index: squid3/src/unlinkd.cc
diff -u squid3/src/unlinkd.cc:1.14 squid3/src/unlinkd.cc:1.8.2.7
--- squid3/src/unlinkd.cc:1.14	Tue Apr 24 09:54:50 2007
+++ squid3/src/unlinkd.cc	Sat Apr 28 09:35:25 2007
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "ipc.h"
 #include "SquidTime.h"
 #include "fde.h"
 #include "xusleep.h"
@@ -189,8 +190,7 @@
 
     unlinkd_rfd = -1;
 }
-
-#endif
+#endif /* _SQUID_MSWIN_ */
 
 void
 unlinkdInit(void)
@@ -199,10 +199,10 @@
 
     args[0] = "(unlinkd)";
     args[1] = NULL;
-    pid = ipcCreate(
+    IPCResult ipcRV = ipcCreate(
 #if USE_POLL && defined(_SQUID_OSF_)
-              /* pipes and poll() don't get along on DUNIX -DW */
-              IPC_STREAM,
+                          /* pipes and poll() don't get along on DUNIX -DW */
+                          IPC_STREAM,
 #elif defined(_SQUID_MSWIN_)
 /* select() will fail on a pipe */
 IPC_TCP_SOCKET,
@@ -210,14 +210,11 @@
 /* We currently need to use FIFO.. see below */
 IPC_FIFO,
 #endif
-              Config.Program.unlinkd,
-              args,
-              "unlinkd",
-              &unlinkd_rfd,
-              &unlinkd_wfd,
-              &hIpc);
+                          Config.Program.unlinkd,
+                          args,
+                          "unlinkd");
 
-    if (pid < 0)
+    if (!ipcRV.success)
         fatal("Failed to create unlinkd subprocess");
 
     xusleep(250000);
@@ -242,7 +239,7 @@
     if (FD_PIPE == fd_table[unlinkd_wfd].type)
         commUnsetNonBlocking(unlinkd_wfd);
 
-    debug(2, 1) ("Unlinkd pipe opened on FD %d\n", unlinkd_wfd);
+    debugs(2, 1, "Unlinkd pipe opened on FD " << unlinkd_wfd);
 
 #ifdef _SQUID_MSWIN_
 
Index: squid3/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc
diff -u squid3/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc:1.8 squid3/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc:1.2.14.3
--- squid3/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc:1.8	Thu Apr 12 17:17:36 2007
+++ squid3/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc	Sat Apr 28 09:35:26 2007
@@ -47,6 +47,7 @@
 /* for statfs */
 #include "Store.h"
 #include "SquidTime.h"
+#include "ipc.h"
 
 diskd_stats_t diskd_stats;
 
@@ -150,9 +151,6 @@
 void
 DiskdIOStrategy::init()
 {
-    int pid;
-    void * hIpc;
-    int rfd;
     int ikey;
     const char *args[5];
     char skey1[32];
@@ -184,19 +182,18 @@
     args[2] = skey2;
     args[3] = skey3;
     args[4] = NULL;
-    pid = ipcCreate(IPC_STREAM,
-                    Config.Program.diskd,
-                    args,
-                    "diskd",
-                    &rfd,
-                    &wfd,
-                    &hIpc);
+    IPCResult ipcRV = ipcCreate(IPC_STREAM,
+                                Config.Program.diskd,
+                                args,
+                                "diskd");
 
-    if (pid < 0)
+    if (!ipcRV.success)
         fatalf("execl: %s", Config.Program.diskd);
 
-    if (rfd != wfd)
-        comm_close(rfd);
+    wfd = ipcRV.wfd;
+
+    if (ipcRV.rfd != wfd)
+        comm_close(ipcRV.rfd);
 
     fd_note(wfd, "squid -> diskd");
 
Index: squid3/src/auth/basic/auth_basic.cc
diff -u squid3/src/auth/basic/auth_basic.cc:1.22 squid3/src/auth/basic/auth_basic.cc:1.16.2.6
--- squid3/src/auth/basic/auth_basic.cc:1.22	Sun Apr 22 23:52:07 2007
+++ squid3/src/auth/basic/auth_basic.cc	Sat Apr 28 09:35:28 2007
@@ -46,6 +46,7 @@
 #include "basicScheme.h"
 #include "wordlist.h"
 #include "SquidTime.h"
+#include "ipc.h"
 
 static void
 authenticateStateFree(AuthenticateStateData * r)
Index: squid3/src/auth/digest/auth_digest.cc
diff -u squid3/src/auth/digest/auth_digest.cc:1.29 squid3/src/auth/digest/auth_digest.cc:1.22.8.7
--- squid3/src/auth/digest/auth_digest.cc:1.29	Sun Sep  3 14:51:50 2006
+++ squid3/src/auth/digest/auth_digest.cc	Sun Oct 22 03:33:54 2006
@@ -48,6 +48,8 @@
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "wordlist.h"
+#include "ipc.h"
+
 /* TODO don't include this */
 #include "digestScheme.h"
 
Index: squid3/src/auth/negotiate/auth_negotiate.cc
diff -u squid3/src/auth/negotiate/auth_negotiate.cc:1.11 squid3/src/auth/negotiate/auth_negotiate.cc:1.4.2.7
--- squid3/src/auth/negotiate/auth_negotiate.cc:1.11	Sat Jan 20 13:50:55 2007
+++ squid3/src/auth/negotiate/auth_negotiate.cc	Sat Apr 28 09:35:29 2007
@@ -43,6 +43,7 @@
 #include "authenticate.h"
 #include "CacheManager.h"
 #include "Store.h"
+#include "ipc.h"
 #include "client_side.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
Index: squid3/src/auth/ntlm/auth_ntlm.cc
diff -u squid3/src/auth/ntlm/auth_ntlm.cc:1.33 squid3/src/auth/ntlm/auth_ntlm.cc:1.25.2.7
--- squid3/src/auth/ntlm/auth_ntlm.cc:1.33	Sat Jan 20 13:50:56 2007
+++ squid3/src/auth/ntlm/auth_ntlm.cc	Sat Apr 28 09:35:29 2007
@@ -43,6 +43,7 @@
 #include "authenticate.h"
 #include "CacheManager.h"
 #include "Store.h"
+#include "ipc.h"
 #include "client_side.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
Index: squid3/src/tests/stub_comm.cc
diff -u squid3/src/tests/stub_comm.cc:1.4 squid3/src/tests/stub_comm.cc:1.1.16.3
--- squid3/src/tests/stub_comm.cc:1.4	Thu Sep 14 13:50:47 2006
+++ squid3/src/tests/stub_comm.cc	Sun Oct 22 03:33:55 2006
@@ -33,6 +33,7 @@
  */
 
 #include "squid.h"
+#include "ipc.h"
 #include "comm.h"
 #include "CommRead.h"
 #include "fde.h"
@@ -113,13 +114,15 @@
 
 /* bah, cheating on stub count */
 
-pid_t
-ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, void **hIpc)
+IPCResult
+ipcCreate(int type, const char *prog, const char *const args[], const char *name)
 {
     fatal ("Not implemented");
     return -1;
 }
 
+IPCResult::IPCResult(int dummy) {}
+
 void
 comm_init(void)
 {
