--------------------- PatchSet 2127 Date: 2005/11/07 21:21:09 Author: serassio Branch: ipc Tag: (none) Log: Imported ipc changes from nt branch Members: src/Makefile.am:1.68->1.68.2.1 src/dns.cc:1.7->1.7.16.1 src/external_acl.cc:1.43->1.43.4.1 src/helper.cc:1.21->1.21.2.1 src/icmp.cc:1.9->1.9.8.1 src/ipc.cc:1.11->1.11.6.1 src/ipc.h:1.1->1.1.32.1 src/redirect.cc:1.17->1.17.4.1 src/unlinkd.cc:1.8->1.8.2.1 src/auth/basic/auth_basic.cc:1.16->1.16.2.1 src/auth/digest/auth_digest.cc:1.22->1.22.8.1 src/auth/negotiate/auth_negotiate.cc:1.4->1.4.2.1 src/auth/ntlm/auth_ntlm.cc:1.25->1.25.2.1 Index: squid3/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Makefile.am,v retrieving revision 1.68 retrieving revision 1.68.2.1 diff -u -r1.68 -r1.68.2.1 --- squid3/src/Makefile.am 5 Nov 2005 23:03:11 -0000 1.68 +++ squid3/src/Makefile.am 7 Nov 2005 21:21:09 -0000 1.68.2.1 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.68 2005/11/05 23:03:11 squidadm Exp $ +# $Id: Makefile.am,v 1.68.2.1 2005/11/07 21:21:09 serassio Exp $ # # Uncomment and customize the following to suit your needs: # @@ -431,6 +431,7 @@ int.cc \ internal.cc \ ipc.cc \ + ipc.h \ ipcache.cc \ IPInterception.cc \ IPInterception.h \ Index: squid3/src/dns.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/dns.cc,v retrieving revision 1.7 retrieving revision 1.7.16.1 diff -u -r1.7 -r1.7.16.1 --- squid3/src/dns.cc 11 Apr 2004 01:59:05 -0000 1.7 +++ squid3/src/dns.cc 7 Nov 2005 21:21:09 -0000 1.7.16.1 @@ -1,6 +1,6 @@ /* - * $Id: dns.cc,v 1.7 2004/04/11 01:59:05 squidadm Exp $ + * $Id: dns.cc,v 1.7.16.1 2005/11/07 21:21:09 serassio Exp $ * * DEBUG: section 34 Dnsserver interface * AUTHOR: Harvest Derived @@ -34,13 +34,15 @@ */ #include "squid.h" -#include "Store.h" /* MS VisualStudio Projects are monolitich, so we need the following #if to include the external DNS code in compile process when using external DNS. */ #if USE_DNSSERVERS +#include "Store.h" +#include "ipc.h" + static helper *dnsservers = NULL; static void Index: squid3/src/external_acl.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/external_acl.cc,v retrieving revision 1.43 retrieving revision 1.43.4.1 diff -u -r1.43 -r1.43.4.1 --- squid3/src/external_acl.cc 18 Sep 2005 02:12:40 -0000 1.43 +++ squid3/src/external_acl.cc 7 Nov 2005 21:21:09 -0000 1.43.4.1 @@ -1,6 +1,6 @@ /* - * $Id: external_acl.cc,v 1.43 2005/09/18 02:12:40 squidadm Exp $ + * $Id: external_acl.cc,v 1.43.4.1 2005/11/07 21:21:09 serassio Exp $ * * DEBUG: section 82 External ACL * AUTHOR: Henrik Nordstrom, MARA Systems AB @@ -45,6 +45,7 @@ #include "ExternalACLEntry.h" #include "AuthUserRequest.h" #include "Store.h" +#include "ipc.h" #include "fde.h" #include "ACLChecklist.h" #include "ACL.h" Index: squid3/src/helper.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/helper.cc,v retrieving revision 1.21 retrieving revision 1.21.2.1 diff -u -r1.21 -r1.21.2.1 --- squid3/src/helper.cc 2 Nov 2005 03:12:52 -0000 1.21 +++ squid3/src/helper.cc 7 Nov 2005 21:21:09 -0000 1.21.2.1 @@ -1,6 +1,6 @@ /* - * $Id: helper.cc,v 1.21 2005/11/02 03:12:52 squidadm Exp $ + * $Id: helper.cc,v 1.21.2.1 2005/11/07 21:21:09 serassio Exp $ * * DEBUG: section 84 Helper process maintenance * AUTHOR: Harvest Derived? @@ -38,6 +38,7 @@ #include "Store.h" #include "comm.h" #include "MemBuf.h" +#include "ipc.h" #define HELPER_MAX_ARGS 64 @@ -73,9 +74,6 @@ helper_server *srv; int nargs = 0; int k; - int x; - int rfd; - int wfd; wordlist *w; if (hlp->cmdline == NULL) @@ -106,15 +104,12 @@ for (k = 0; k < hlp->n_to_start; k++) { getCurrentTime(); - rfd = wfd = -1; - x = ipcCreate(hlp->ipc_type, - progname, - args, - shortname, - &rfd, - &wfd); + IPCResult ipcRV = ipcCreate(hlp->ipc_type, + progname, + args, + shortname); - if (x < 0) { + if (!ipcRV.success) { debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; } @@ -122,10 +117,15 @@ hlp->n_running++; hlp->n_active++; srv = cbdataAlloc(helper_server); - srv->pid = x; +#ifdef _SQUID_MSWIN_ + + srv->hIpc = ipcRV.hIpc; +#endif + + 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; @@ -133,22 +133,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); } @@ -171,9 +171,6 @@ helper_stateful_server *srv; int nargs = 0; int k; - int x; - int rfd; - int wfd; wordlist *w; if (hlp->cmdline == NULL) @@ -204,15 +201,12 @@ for (k = 0; k < hlp->n_to_start; k++) { getCurrentTime(); - rfd = wfd = -1; - x = ipcCreate(hlp->ipc_type, - progname, - args, - shortname, - &rfd, - &wfd); + IPCResult ipcRV = ipcCreate(hlp->ipc_type, + progname, + args, + shortname); - if (x < 0) { + if (!ipcRV.success) { debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; } @@ -220,7 +214,12 @@ hlp->n_running++; hlp->n_active++; srv = cbdataAlloc(helper_stateful_server); - srv->pid = x; +#ifdef _SQUID_MSWIN_ + + srv->hIpc = ipcRV.hIpc; +#endif + + srv->pid = ipcRV.pid; srv->flags.reserved = S_HELPER_FREE; srv->deferred_requests = 0; srv->stats.deferbyfunc = 0; @@ -228,8 +227,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); @@ -239,25 +238,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 =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/icmp.cc,v retrieving revision 1.9 retrieving revision 1.9.8.1 diff -u -r1.9 -r1.9.8.1 --- squid3/src/icmp.cc 19 Apr 2005 02:14:50 -0000 1.9 +++ squid3/src/icmp.cc 7 Nov 2005 21:21:09 -0000 1.9.8.1 @@ -1,6 +1,6 @@ /* - * $Id: icmp.cc,v 1.9 2005/04/19 02:14:50 squidadm Exp $ + * $Id: icmp.cc,v 1.9.8.1 2005/11/07 21:21:09 serassio Exp $ * * DEBUG: section 37 ICMP Routines * AUTHOR: Duane Wessels @@ -36,6 +36,7 @@ #include "squid.h" #include "comm.h" +#include "ipc.h" #if USE_ICMP @@ -224,24 +225,19 @@ { #if USE_ICMP const char *args[2]; - int x; - int rfd; - int wfd; args[0] = "(pinger)"; args[1] = NULL; - x = ipcCreate(IPC_DGRAM, - Config.Program.pinger, - args, - "Pinger Socket", - &rfd, - &wfd); + IPCResult ipcRV = ipcCreate(IPC_DGRAM, + Config.Program.pinger, + args, + "Pinger Socket"); - if (x < 0) + if (!ipcRV.success) return; - assert(rfd == wfd); + assert(ipcRV.rfd == ipcRV.wfd); - icmp_sock = rfd; + icmp_sock = ipcRV.rfd; fd_note(icmp_sock, "pinger"); Index: squid3/src/ipc.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ipc.cc,v retrieving revision 1.11 retrieving revision 1.11.6.1 diff -u -r1.11 -r1.11.6.1 --- squid3/src/ipc.cc 5 Jun 2005 02:13:17 -0000 1.11 +++ squid3/src/ipc.cc 7 Nov 2005 21:21:09 -0000 1.11.6.1 @@ -1,6 +1,6 @@ /* - * $Id: ipc.cc,v 1.11 2005/06/05 02:13:17 squidadm Exp $ + * $Id: ipc.cc,v 1.11.6.1 2005/11/07 21:21:09 serassio Exp $ * * DEBUG: section 54 Interprocess Communication * AUTHOR: Duane Wessels @@ -34,252 +34,1398 @@ */ #include "squid.h" +#include "ipc.h" #include "comm.h" #include "fde.h" +#ifdef _SQUID_MSWIN_ +#ifndef _MSWSOCK_ +#include +#endif +#include +#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]; -static int -ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd) +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() +{ + /* + * This double-dup stuff avoids problems when one of + * crfd, cwfd, or debug_log are in the range 0-2. + */ + int openrv; + + do { + openrv = open(_PATH_DEVNULL, 0, 0444); + + if (openrv > -1) + commSetCloseOnExec(openrv); + } while (openrv < 3); +} + +void +IPC::doExec() +{ +#ifndef _SQUID_MSWIN_ + int t1, t2, t3; + reserveFD0Thru2(); + 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 +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(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 (threadHandle != NULL) + CloseHandle(threadHandle); + + threadHandle = NULL; +} + +unsigned int __stdcall +WindowsSpawn::ThreadReflector (void *me_) +{ + WindowsSpawn *me = static_cast(me_); + assert (me->newThread != NULL); + me->childRV = me->newThread (me->data); + return me->childRV; +} + +Spawn * +WindowsSpawn::clone() const +{ + WindowsSpawn *result = new WindowsSpawn (*this); + return result; +} + +bool +WindowsSpawn::success() const +{ + return threadID != 0; +} + +void * +WindowsSpawn::getHandle() const +{ + return threadHandle; +} + +pid_t +WindowsSpawn::getPid() const +{ + assert (0); + return pid; +} + +void +WindowsSpawn::splitExecution(Spawn::Child *_newThread, void *_data) { - if (prfd >= 0) - comm_close(prfd); + newThread = _newThread; + data = _data; + HANDLE beginRv = + (HANDLE) _beginthreadex(NULL, 0, ThreadReflector, this, 0, &threadID); - if (prfd != pwfd) - if (pwfd >= 0) - comm_close(pwfd); + 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 (crfd >= 0) - comm_close(crfd); +#else +UnixSpawn::UnixSpawn() :newThread (NULL), data(NULL), + pid(-1) +{} - if (crfd != cwfd) - if (cwfd >= 0) - comm_close(cwfd); +UnixSpawn::UnixSpawn(UnixSpawn const &old) +{} - return -1; +Spawn * +UnixSpawn::clone() const +{ + UnixSpawn *result = new UnixSpawn (*this); + return result; } -static void -PutEnvironment() +bool +UnixSpawn::success() 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 pid > -1; } -int -ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd) +void * +UnixSpawn::getHandle() const { - pid_t pid; + assert (0); + return NULL; +} - struct sockaddr_in ChS; +pid_t +UnixSpawn::getPid() const +{ + return pid; +} - 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; +void +UnixSpawn::splitExecution(Spawn::Child *_newThread, void *_data) +{ + newThread = _newThread; + data = _data; -#if USE_POLL && defined(_SQUID_OSF_) + if ((pid = fork()) < 0) { + debug(50, 1) ("ipcCreate: fork: %s\n", xstrerror()); + } else if (pid > 0) { + /* parent */ + return; + } else { + /* Still checked outside here */ + child(); + } +} + +void +UnixSpawn::child() +{ + /*exit(*/newThread(data)/*)*/; +} - assert(type != IPC_FIFO); #endif - if (rfd) - *rfd = -1; +unsigned int +IPC::ForkChild(void *data) +{ + IPC *result = static_cast(data); + assert (result); +#ifndef _SQUID_MSWIN_ + /* child */ + no_suid(); /* give up extra priviliges */ + /* close shared socket with parent */ + comm_close(result->prfd); - if (wfd) - *wfd = -1; - - 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(50, 0) ("ipcCreate: pipe: %s\n", xstrerror()); - return -1; - } - - if (pipe(c2p) < 0) { - debug(50, 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) + if (result->pwfd != result->prfd) + close(result->pwfd); - } else if (type == IPC_UNIX_STREAM) { - int fds[2]; - int buflen = 32768; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - debug(50, 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(50, 0) ("ipcCreate: socketpair: %s\n", xstrerror()); - return -1; - } + result->pwfd = result->prfd = -1; - fdc_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX DGRAM Parent"); - fdc_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX DGRAM Parent"); +#else #endif - } else { - assert(IPC_NONE); - } + /* Until we are entire in this routine */ + return 0; +} - 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); +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_ - if (crfd < 0) { - debug(54, 0) ("ipcCreate: Failed to create child FD.\n"); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + 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 (pwfd < 0) { - debug(54, 0) ("ipcCreate: Failed to create server FD.\n"); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + result->prepFDsForSpawn(); + + if (!result->preppedFDsForSpawn()) { + result->cleanUp(); + return result; } - if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { - len = sizeof(PaS); - memset(&PaS, '\0', len); + /* flush or else we get dup data if unbuffered_logs is set */ + logsFlush(); - if (getsockname(pwfd, (struct sockaddr *) &PaS, &len) < 0) { - debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); - } + result->mySpawn = Spawn::GetSpawn(); - 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); + result->prog = prog; - if (getsockname(crfd, (struct sockaddr *) &ChS, &len) < 0) { - debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); - } + result->args = const_cast(args); - debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", - crfd, inet_ntoa(ChS.sin_addr), ntohs(ChS.sin_port)); - } +#ifdef _SQUID_MSWIN_ - if (type == IPC_TCP_SOCKET) { - if (listen(crfd, 1) < 0) { - debug(50, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror()); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); - } + ipc_params *params = new ipc_params (type); - debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd); - } + /* 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(); - /* flush or else we get dup data if unbuffered_logs is set */ - logsFlush(); + params->prog = prog; - if ((pid = fork()) < 0) { - debug(50, 1) ("ipcCreate: fork: %s\n", xstrerror()); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); - } + params->args = (char **) args; - if (pid > 0) { /* parent */ - /* close shared socket with child */ - comm_close(crfd); + 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); + +#endif - if (x < 0) { + if (x < 0) + { debug(50, 0) ("ipcCreate: PARENT: hello read test failed\n"); debug(50, 0) ("--> read: %s\n", xstrerror()); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); - } else if (strcmp(hello_buf, hello_string)) { + 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; } - commSetTimeout(prfd, -1, NULL, NULL); - commSetNonBlocking(prfd); - commSetNonBlocking(pwfd); +#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; + } + + 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; @@ -288,78 +1434,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; - if (pwfd != prfd) - close(pwfd); + niceprog = xstrdup(niceprog); - pwfd = prfd = -1; + assert (myIPC); - if (type == IPC_TCP_SOCKET) { - debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd); + IPC *result = myIPC; - if ((fd = accept(crfd, NULL, NULL)) < 0) { - debug(50, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror()); + /* ForkChild is called directly from non windows routines */ + IPC::ForkChild (myIPC); + +#endif + + result->childFDConnect(); + + if (!result->childFDConnected()) { +#ifdef _SQUID_MSWIN_ + freeResources(); + return 1; +#else + + result->cleanUp(); + _exit (1); +#endif + + } + + tempFD = result->childFD.rfd; + + /* 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 + + 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; + } + + /* create FDs for child */ - 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); + 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(50, 0) ("sendto FD %d: %s\n", cwfd, xstrerror()); - debug(50, 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(50, 0) ("write FD %d: %s\n", cwfd, xstrerror()); - debug(50, 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 { - x = open(_PATH_DEVNULL, 0, 0444); + 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; + } - if (x > -1) - commSetCloseOnExec(x); - } while (x < 3); + 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); - t1 = dup(crfd); + 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; + } - t2 = dup(cwfd); + debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", + crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port)); - t3 = dup(fileno(debug_log)); + if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) { + ipcSend(myIPC->childFD.wfd, err_string, strlen(err_string)); + freeResources(); + return 1; + } - assert(t1 > 2 && t2 > 2 && t3 > 2); + tempFD = myIPC->childFD.rfd; - close(crfd); + 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 */ - close(cwfd); + assert (tempFD == myIPC->childFD.rfd); - close(fileno(debug_log)); + 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(tempFD); + + SpawnResult spawnResult = ipc_spawn (prog, args); + + pid = spawnResult.pid; + + hProcess = spawnResult.hProcess; dup2(t1, 0); @@ -373,22 +1651,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 (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(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(50, 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(voidParam); + IPCInstance *newInstance = new IPCInstance(params->type, params->pid, params->prog, params->rfd, params->send_fd); + + newInstance->childToParentLoop(); + + delete newInstance; return 0; } + +#endif --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/src/ipc.h Wed Feb 14 13:35:35 2007 @@ -0,0 +1,88 @@ + +/* + * $Id: ipc.h,v 1.1.32.1 2005/11/07 21:21:09 serassio Exp $ + * + * + * 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 +#ifdef _SQUID_MSWIN_ + ,HANDLE aHandle=NULL +#endif + ) : success(aBool), pid (aPid), rfd (_rfd), wfd (_wfd) +#ifdef _SQUID_MSWIN_ + ,hIpc(aHandle) +#endif + {} + bool success; + pid_t pid; + int rfd; + int wfd; +#ifdef _SQUID_MSWIN_ + HANDLE hIpc; +#endif +}; + +IPCResult ipcCreate(int type, + const char *prog, + const char *const args[], + const char *name +); + +#endif /* SQUID_IPC_H */ Index: squid3/src/redirect.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/redirect.cc,v retrieving revision 1.17 retrieving revision 1.17.4.1 diff -u -r1.17 -r1.17.4.1 --- squid3/src/redirect.cc 10 Sep 2005 02:12:51 -0000 1.17 +++ squid3/src/redirect.cc 7 Nov 2005 21:21:09 -0000 1.17.4.1 @@ -1,6 +1,6 @@ /* - * $Id: redirect.cc,v 1.17 2005/09/10 02:12:51 squidadm Exp $ + * $Id: redirect.cc,v 1.17.4.1 2005/11/07 21:21:09 serassio Exp $ * * DEBUG: section 61 Redirector * AUTHOR: Duane Wessels @@ -36,6 +36,7 @@ #include "squid.h" #include "AuthUserRequest.h" #include "Store.h" +#include "ipc.h" #include "client_side_request.h" #include "ACLChecklist.h" #include "HttpRequest.h" Index: squid3/src/unlinkd.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/unlinkd.cc,v retrieving revision 1.8 retrieving revision 1.8.2.1 diff -u -r1.8 -r1.8.2.1 --- squid3/src/unlinkd.cc 7 Nov 2005 03:13:16 -0000 1.8 +++ squid3/src/unlinkd.cc 7 Nov 2005 21:21:09 -0000 1.8.2.1 @@ -1,6 +1,6 @@ /* - * $Id: unlinkd.cc,v 1.8 2005/11/07 03:13:16 squidadm Exp $ + * $Id: unlinkd.cc,v 1.8.2.1 2005/11/07 21:21:09 serassio Exp $ * * DEBUG: section 2 Unlink Daemon * AUTHOR: Duane Wessels @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "ipc.h" #ifdef UNLINK_DAEMON @@ -87,6 +88,11 @@ static int unlinkd_wfd = -1; static int unlinkd_rfd = -1; +#ifdef _SQUID_MSWIN_ +static HANDLE hIpc; +#endif +static pid_t pid; + #define UNLINKD_QUEUE_LIMIT 20 void @@ -173,11 +179,42 @@ void unlinkdClose(void) +#ifdef _SQUID_MSWIN_ { + + if (unlinkd_wfd > -1) + { + debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd); + shutdown(unlinkd_wfd, SD_BOTH); + comm_close(unlinkd_wfd); + + if (unlinkd_wfd != unlinkd_rfd) + comm_close(unlinkd_rfd); + + unlinkd_wfd = -1; + + unlinkd_rfd = -1; + } else + debugs(2, 0, "unlinkdClose: WARNING: unlinkd_wfd is " << unlinkd_wfd); + + if (hIpc) + { + if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) { + getCurrentTime(); + debugs(2, 1, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds"); + } + + CloseHandle(hIpc); + } +} + +#else +{ + if (unlinkd_wfd < 0) return; - debug(2, 1) ("Closing unlinkd pipe on FD %d\n", unlinkd_wfd); + debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd); file_close(unlinkd_wfd); @@ -189,37 +226,60 @@ unlinkd_rfd = -1; } +#endif /* _SQUID_MSWIN_ */ + void unlinkdInit(void) { - int x; const char *args[2]; struct timeval slp; args[0] = "(unlinkd)"; args[1] = NULL; + IPCResult ipcRV = ipcCreate( #if USE_POLL && defined(_SQUID_OSF_) - /* pipes and poll() don't get along on DUNIX -DW */ - x = ipcCreate(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, #else /* We currently need to use FIFO.. see below */ -x = ipcCreate(IPC_FIFO, +IPC_FIFO, #endif - Config.Program.unlinkd, - args, - "unlinkd", - &unlinkd_rfd, - &unlinkd_wfd); + Config.Program.unlinkd, + args, + "unlinkd"); - if (x < 0) + if (!ipcRV.success) fatal("Failed to create unlinkd subprocess"); + + pid = ipcRV.pid; + + unlinkd_rfd = ipcRV.rfd; + + unlinkd_wfd = ipcRV.wfd; + +#ifdef _SQUID_MSWIN_ + + hIpc = ipcRV.hIpc; + +#endif + slp.tv_sec = 0; + slp.tv_usec = 250000; + select(0, NULL, NULL, NULL, &slp); + fd_note(unlinkd_wfd, "squid -> unlinkd"); + fd_note(unlinkd_rfd, "unlinkd -> squid"); + commSetTimeout(unlinkd_rfd, -1, NULL, NULL); + commSetTimeout(unlinkd_wfd, -1, NULL, NULL); + /* * unlinkd_rfd should already be non-blocking because of * ipcCreate. We change unlinkd_wfd to blocking mode because @@ -228,9 +288,11 @@ * do this only for the IPC_FIFO case. */ assert(fd_table[unlinkd_rfd].flags.nonblocking); + 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); } #endif /* ndef UNLINK_DAEMON */ Index: squid3/src/auth/basic/auth_basic.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/auth/basic/auth_basic.cc,v retrieving revision 1.16 retrieving revision 1.16.2.1 diff -u -r1.16 -r1.16.2.1 --- squid3/src/auth/basic/auth_basic.cc 5 Nov 2005 23:03:12 -0000 1.16 +++ squid3/src/auth/basic/auth_basic.cc 7 Nov 2005 21:21:10 -0000 1.16.2.1 @@ -1,5 +1,5 @@ /* - * $Id: auth_basic.cc,v 1.16 2005/11/05 23:03:12 squidadm Exp $ + * $Id: auth_basic.cc,v 1.16.2.1 2005/11/07 21:21:10 serassio Exp $ * * DEBUG: section 29 Authenticator * AUTHOR: Duane Wessels @@ -43,6 +43,7 @@ #include "Store.h" #include "HttpReply.h" #include "basicScheme.h" +#include "ipc.h" static void authenticateStateFree(AuthenticateStateData * r) Index: squid3/src/auth/digest/auth_digest.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/auth/digest/auth_digest.cc,v retrieving revision 1.22 retrieving revision 1.22.8.1 diff -u -r1.22 -r1.22.8.1 --- squid3/src/auth/digest/auth_digest.cc 25 Apr 2005 02:14:35 -0000 1.22 +++ squid3/src/auth/digest/auth_digest.cc 7 Nov 2005 21:21:10 -0000 1.22.8.1 @@ -1,6 +1,6 @@ /* - * $Id: auth_digest.cc,v 1.22 2005/04/25 02:14:35 squidadm Exp $ + * $Id: auth_digest.cc,v 1.22.8.1 2005/11/07 21:21:10 serassio Exp $ * * DEBUG: section 29 Authenticator * AUTHOR: Robert Collins @@ -45,6 +45,8 @@ #include "Store.h" #include "HttpRequest.h" #include "HttpReply.h" +#include "ipc.h" + /* TODO don't include this */ #include "digestScheme.h" Index: squid3/src/auth/negotiate/auth_negotiate.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/auth/negotiate/auth_negotiate.cc,v retrieving revision 1.4 retrieving revision 1.4.2.1 diff -u -r1.4 -r1.4.2.1 --- squid3/src/auth/negotiate/auth_negotiate.cc 7 Nov 2005 03:13:16 -0000 1.4 +++ squid3/src/auth/negotiate/auth_negotiate.cc 7 Nov 2005 21:21:10 -0000 1.4.2.1 @@ -1,6 +1,6 @@ /* - * $Id: auth_negotiate.cc,v 1.4 2005/11/07 03:13:16 squidadm Exp $ + * $Id: auth_negotiate.cc,v 1.4.2.1 2005/11/07 21:21:10 serassio Exp $ * * DEBUG: section 29 Negotiate Authenticator * AUTHOR: Robert Collins, Henrik Nordstrom, Francesco Chemolli @@ -42,6 +42,7 @@ #include "auth_negotiate.h" #include "authenticate.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 =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/auth/ntlm/auth_ntlm.cc,v retrieving revision 1.25 retrieving revision 1.25.2.1 diff -u -r1.25 -r1.25.2.1 --- squid3/src/auth/ntlm/auth_ntlm.cc 7 Nov 2005 03:13:16 -0000 1.25 +++ squid3/src/auth/ntlm/auth_ntlm.cc 7 Nov 2005 21:21:10 -0000 1.25.2.1 @@ -1,6 +1,6 @@ /* - * $Id: auth_ntlm.cc,v 1.25 2005/11/07 03:13:16 squidadm Exp $ + * $Id: auth_ntlm.cc,v 1.25.2.1 2005/11/07 21:21:10 serassio Exp $ * * DEBUG: section 29 NTLM Authenticator * AUTHOR: Robert Collins, Henrik Nordstrom, Francesco Chemolli @@ -42,6 +42,7 @@ #include "auth_ntlm.h" #include "authenticate.h" #include "Store.h" +#include "ipc.h" #include "client_side.h" #include "HttpReply.h" #include "HttpRequest.h"