? HttpRequest.h ? ipc.h Index: helper.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/helper.cc,v retrieving revision 1.54 diff -u -p -r1.54 helper.cc --- helper.cc 23 Oct 2002 09:15:00 -0000 1.54 +++ helper.cc 2 Dec 2002 12:37:28 -0000 @@ -36,6 +36,7 @@ #include "squid.h" #include "Store.h" #include "comm.h" +#include "ipc.h" #define HELPER_MAX_ARGS 64 @@ -71,9 +72,6 @@ helperOpenServers(helper * hlp) helper_server *srv; int nargs = 0; int k; - int x; - int rfd; - int wfd; wordlist *w; if (hlp->cmdline == NULL) return; @@ -93,42 +91,39 @@ helperOpenServers(helper * hlp) assert(nargs <= HELPER_MAX_ARGS); for (k = 0; k < hlp->n_to_start; k++) { getCurrentTime(); - rfd = wfd = -1; - x = ipcCreate(hlp->ipc_type, + IPCResult ipcRV = ipcCreate(hlp->ipc_type, progname, args, - shortname, - &rfd, - &wfd); - if (x < 0) { + shortname); + if (!ipcRV.success) { debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; } hlp->n_running++; srv = cbdataAlloc(helper_server); - srv->pid = x; + srv->pid = ipcRV.pid; srv->flags.alive = 1; srv->index = k; - srv->rfd = rfd; - srv->wfd = wfd; + srv->rfd = ipcRV.rfd; + srv->wfd = ipcRV.wfd; srv->buf = (char *)memAllocate(MEM_8K_BUF); srv->buf_sz = 8192; srv->offset = 0; 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); - if (wfd != rfd) - commSetNonBlocking(wfd); - comm_add_close_handler(rfd, helperServerFree, srv); + commSetNonBlocking(srv->rfd); + if (srv->wfd != srv->rfd) + commSetNonBlocking(srv->wfd); + comm_add_close_handler(srv->rfd, helperServerFree, srv); } safe_free(shortname); safe_free(procname); @@ -147,10 +142,8 @@ helperStatefulOpenServers(statefulhelper helper_stateful_server *srv; int nargs = 0; int k; - int x; - int rfd; - int wfd; wordlist *w; + if (hlp->cmdline == NULL) return; progname = hlp->cmdline->key; @@ -169,20 +162,17 @@ helperStatefulOpenServers(statefulhelper assert(nargs <= HELPER_MAX_ARGS); for (k = 0; k < hlp->n_to_start; k++) { getCurrentTime(); - rfd = wfd = -1; - x = ipcCreate(hlp->ipc_type, + IPCResult ipcRV = ipcCreate(hlp->ipc_type, progname, args, - shortname, - &rfd, - &wfd); - if (x < 0) { + shortname); + if (!ipcRV.success) { debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; } hlp->n_running++; srv = cbdataAlloc(helper_stateful_server); - srv->pid = x; + srv->pid = ipcRV.pid; srv->flags.alive = 1; srv->flags.reserved = S_HELPER_FREE; srv->deferred_requests = 0; @@ -191,8 +181,8 @@ helperStatefulOpenServers(statefulhelper 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->buf = (char *)memAllocate(MEM_8K_BUF); srv->buf_sz = 8192; srv->offset = 0; @@ -200,19 +190,19 @@ helperStatefulOpenServers(statefulhelper if (hlp->datapool != NULL) srv->data = memPoolAlloc(hlp->datapool); 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); - if (wfd != rfd) - commSetNonBlocking(wfd); - comm_add_close_handler(rfd, helperStatefulServerFree, srv); + commSetNonBlocking(srv->rfd); + if (srv->wfd != srv->rfd) + commSetNonBlocking(srv->wfd); + comm_add_close_handler(srv->rfd, helperStatefulServerFree, srv); } safe_free(shortname); safe_free(procname); Index: icmp.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/icmp.cc,v retrieving revision 1.80 diff -u -p -r1.80 icmp.cc --- icmp.cc 22 Oct 2002 21:12:51 -0000 1.80 +++ icmp.cc 2 Dec 2002 12:37:28 -0000 @@ -36,6 +36,7 @@ #include "squid.h" #include "comm.h" +#include "ipc.h" #if USE_ICMP @@ -72,6 +73,8 @@ icmpRecv(int unused1, void *unused2) static int fail_count = 0; pingerReplyData preply; static struct sockaddr_in F; + if (icmp_sock < 0) + return; commSetSelect(icmp_sock, COMM_SELECT_READ, icmpRecv, NULL, 0); memset(&preply, '\0', sizeof(pingerReplyData)); n = comm_udp_recv(icmp_sock, @@ -151,6 +154,8 @@ void icmpPing(struct in_addr to) { #if USE_ICMP + if (icmp_sock < 0) + return; icmpSendEcho(to, S_ICMP_ECHO, NULL, 0); #endif } @@ -163,6 +168,8 @@ icmpSourcePing(struct in_addr to, const char *payload; int len; int ulen; + if (icmp_sock < 0) + return; debug(37, 3) ("icmpSourcePing: '%s'\n", url); if ((ulen = strlen(url)) > MAX_URL) return; @@ -181,6 +188,8 @@ void icmpDomainPing(struct in_addr to, const char *domain) { #if USE_ICMP + if (icmp_sock < 0) + return; debug(37, 3) ("icmpDomainPing: '%s'\n", domain); icmpSendEcho(to, S_ICMP_DOM, domain, 0); #endif @@ -191,21 +200,20 @@ icmpOpen(void) { #if USE_ICMP const char *args[2]; - int x; - int rfd; - int wfd; + if (strcmp(Config.Program.pinger, "none") == 0) { + debug(37, 1) ("Pinger disabled\n"); + return; + } args[0] = "(pinger)"; args[1] = NULL; - x = ipcCreate(IPC_DGRAM, + IPCResult ipcRV = ipcCreate(IPC_DGRAM, Config.Program.pinger, args, - "Pinger Socket", - &rfd, - &wfd); - if (x < 0) + "Pinger Socket"); + if (!ipcRV.success) return; - assert(rfd == wfd); - icmp_sock = rfd; + assert(ipcRV.rfd == ipcRV.wfd); + icmp_sock = ipcRV.rfd; fd_note(icmp_sock, "pinger"); commSetSelect(icmp_sock, COMM_SELECT_READ, icmpRecv, NULL, 0); commSetTimeout(icmp_sock, -1, NULL, NULL); Index: ipc.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/ipc.cc,v retrieving revision 1.34 diff -u -p -r1.34 ipc.cc --- ipc.cc 28 Nov 2002 12:21:46 -0000 1.34 +++ ipc.cc 2 Dec 2002 12:37:28 -0000 @@ -34,208 +34,845 @@ */ #include "squid.h" +#include "ipc.h" #include "comm.h" -static const char *hello_string = "hi there\n"; -#define HELLO_BUF_SZ 32 -static char hello_buf[HELLO_BUF_SZ]; +static void +PutEnvironment(); +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; +}; -static int -ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd) + +/* 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; + 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: +}; + +class UnixSpawn : public Spawn { - 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; -} +public: + UnixSpawn(); + virtual Spawn *clone() const; + virtual bool success() 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; +}; -static void -PutEnvironment() +Spawn * +Spawn::GetSpawn() { -#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 new UnixSpawn; } -int -ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd) +class IPC { - pid_t pid; - struct sockaddr_in CS; - struct sockaddr_in PS; - int crfd = -1; - int prfd = -1; - int cwfd = -1; - int pwfd = -1; - int fd; - int t1, t2, t3; - socklen_t len; - int x; +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; -#if USE_POLL && defined(_SQUID_OSF_) - assert(type != IPC_FIFO); -#endif +/* 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; + +private: + static IPC *Factory(int type, char const *name); + IPC (IPCResult aResult):rv(aResult){} + void closeAllFD(); + IPCResult rv; + char const *name_; +}; - if (rfd) - *rfd = -1; - 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) { +#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 -1; + return; } if (pipe(c2p) < 0) { debug(50, 0) ("ipcCreate: pipe: %s\n", xstrerror()); - return -1; + return; } + childFD = FDPair (c2p[0], p2c[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(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 + +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) +{ + childFD = FDPair (openASocket (socktype, proto, COMM_NOCLOEXEC)); + prfd = pwfd = openASocket (socktype, proto, 0); /* blocking */ +} + +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); + childFD = FDPair (tempFD); + + childConnected = true; +} + +bool +IPCTCP::childFDConnected() const +{ + return childConnected; +} + +int +IPCTCP::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 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) - } else if (type == IPC_UNIX_STREAM) { +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 -1; + 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(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; - } - 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 - } else { - assert(IPC_NONE); + 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; } - 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); + 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 - if (crfd < 0) { +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 +} +IPC * +IPC::Factory (int type, char const *name) +{ + if (type == IPC_TCP_SOCKET) + return new IPCTCP (name); +#if !(USE_POLL && defined(_SQUID_OSF_)) + + if (type == IPC_FIFO) + return new IPCFIFO (name); +#endif + if (type == IPC_UDP_SOCKET) + return new IPCUDP (name); +#if HAVE_SOCKETPAIR && defined(AF_UNIX) + if (type == IPC_UNIX_STREAM) + return new IPCUNIXStream (name); + if (type == IPC_UNIX_DGRAM) + return new IPCUNIXDGram (name); +#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); + } + +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"; + +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; +} + +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() +{ + 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 HAVE_SETSID + setsid(); +#endif + execvp(prog, (char *const *) args); + debug_log = fdopen(2, "a+"); + debug(50, 0) ("ipcCreate: %s: %s\n", prog, xstrerror()); + _exit(1); +} + +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 ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + return false; } if (pwfd < 0) { debug(54, 0) ("ipcCreate: Failed to create server FD.\n"); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + return false; } - 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(50, 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(50, 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)); + return true; +} + +UnixSpawn::UnixSpawn() :newThread (NULL), data(NULL), + pid(-1) +{ +} + +UnixSpawn::UnixSpawn(UnixSpawn const &old) +{ +} + +Spawn * +UnixSpawn::clone() const +{ + UnixSpawn *result = new UnixSpawn (*this); + return result; +} + +bool +UnixSpawn::success() const +{ + return pid > -1; +} + +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 { + /* Still checked outside here */ + child(); + } +} + +void +UnixSpawn::child() +{ + /*exit(*/newThread(data)/*)*/; +} + +unsigned int +IPC::ForkChild(void *data) +{ + IPC *result = static_cast(data); + assert (result); + /* child */ + no_suid(); /* give up extra priviliges */ + /* close shared socket with parent */ + comm_close(result->prfd); + if (result->pwfd != result->prfd) + close(result->pwfd); + result->pwfd = result->prfd = -1; + + result->childFDConnect(); + if (!result->childFDConnected()) { + result->cleanUp(); + _exit (1); } - 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); + + /* 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"); + result->cleanUp(); + _exit(1); } - debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd); } + PutEnvironment(); + result->doExec(); + /* Until we are entirely 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)); + int tempFD; + + 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; + } + + result->prepFDsForSpawn(); + 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(50, 1) ("ipcCreate: fork: %s\n", xstrerror()); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + result->mySpawn = Spawn::GetSpawn(); + result->prog = prog; + result->args = const_cast(args); + result->mySpawn->splitExecution (ForkChild, result); + + if (!result->mySpawn->success()) { + result->cleanUp(); + return result; } - if (pid > 0) { /* parent */ + if (result->mySpawn->getPid() > 0) { /* parent */ /* close shared socket with child */ - comm_close(crfd); - if (cwfd != crfd) - comm_close(cwfd); - cwfd = crfd = -1; + result->childFD.close(); if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { - if (comm_connect_addr(pwfd, &CS) == COMM_ERROR) - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + if (comm_connect_addr(result->pwfd, &result->CS()) == COMM_ERROR) { + result->cleanUp(); + return result; + } } memset(hello_buf, '\0', HELLO_BUF_SZ); 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(50, 0) ("ipcCreate: PARENT: hello read test failed\n"); debug(50, 0) ("--> read: %s\n", xstrerror()); - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + 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); - if (rfd) - *rfd = prfd; - if (wfd) - *wfd = pwfd; - fd_table[prfd].flags.ipc = 1; - fd_table[pwfd].flags.ipc = 1; + 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; if (Config.sleep_after_fork) { /* XXX emulation of usleep() */ struct timeval sl; @@ -243,75 +880,27 @@ ipcCreate(int type, const char *prog, co sl.tv_usec = Config.sleep_after_fork % 1000000; select(0, NULL, NULL, NULL, &sl); } - return pid; + result->result (IPCResult (true, result->mySpawn->getPid(), result->prfd, result->pwfd)); + return result; } - /* child */ - no_suid(); /* give up extra priviliges */ - /* close shared socket with parent */ - close(prfd); - if (pwfd != prfd) - close(pwfd); - pwfd = prfd = -1; - - if (type == IPC_TCP_SOCKET) { - debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd); - if ((fd = accept(crfd, NULL, NULL)) < 0) { - debug(50, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror()); - _exit(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, &PS) == COMM_ERROR) - return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + + result->childFDConnect(); + if (!result->childFDConnected()) { + result->cleanUp(); + _exit (1); } - if (type == IPC_UDP_SOCKET) { - x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0); - 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); - } - } else { - if (write(cwfd, hello_string, strlen(hello_string) + 1) < 0) { - debug(50, 0) ("write FD %d: %s\n", cwfd, xstrerror()); + 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"); + result->cleanUp(); _exit(1); } } PutEnvironment(); - /* - * This double-dup stuff avoids problems when one of - * crfd, cwfd, or debug_log are in the rage 0-2. - */ - do { - x = open(_PATH_DEVNULL, 0, 0444); - if (x > -1) - commSetCloseOnExec(x); - } while (x < 3); - t1 = dup(crfd); - t2 = dup(cwfd); - t3 = dup(fileno(debug_log)); - assert(t1 > 2 && t2 > 2 && t3 > 2); - close(crfd); - close(cwfd); - 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 (x = 3; x < SQUID_MAXFD; x++) - close(x); -#if HAVE_SETSID - setsid(); -#endif - execvp(prog, (char *const *) args); - debug_log = fdopen(2, "a+"); - debug(50, 0) ("ipcCreate: %s: %s\n", prog, xstrerror()); - _exit(1); - return 0; + result->doExec(); + return 0; } Index: protos.h =================================================================== RCS file: /cvsroot/squid/squid3/src/protos.h,v retrieving revision 1.457 diff -u -p -r1.457 protos.h --- protos.h 15 Nov 2002 13:29:20 -0000 1.457 +++ protos.h 2 Dec 2002 12:37:30 -0000 @@ -1101,16 +1101,6 @@ SQUIDCEXTERN void stringReset(String * s SQUIDCEXTERN void stringAppend(String * s, const char *buf, int len); /* SQUIDCEXTERN void stringAppendf(String *s, const char *fmt, ...) PRINTF_FORMAT_ARG2; */ -/* - * ipc.c - */ -SQUIDCEXTERN int ipcCreate(int type, - const char *prog, - const char *const args[], - const char *name, - int *rfd, - int *wfd); - /* CacheDigest */ SQUIDCEXTERN CacheDigest *cacheDigestCreate(int capacity, int bpe); SQUIDCEXTERN void cacheDigestDestroy(CacheDigest * cd); Index: unlinkd.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/unlinkd.cc,v retrieving revision 1.48 diff -u -p -r1.48 unlinkd.cc --- unlinkd.cc 21 Jul 2002 00:25:44 -0000 1.48 +++ unlinkd.cc 2 Dec 2002 12:37:30 -0000 @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "ipc.h" #ifdef UNLINK_DAEMON @@ -74,6 +75,8 @@ main(int argc, char *argv[]) static int unlinkd_wfd = -1; static int unlinkd_rfd = -1; +static pid_t pid; + #define UNLINKD_QUEUE_LIMIT 20 void @@ -158,25 +161,27 @@ unlinkdClose(void) void unlinkdInit(void) { - int x; +#ifdef USE_UNLINKD 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, + IPC_STREAM, #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); - if (x < 0) + "unlinkd"); + if (!ipcRV.success) fatal("Failed to create unlinkd subprocess"); + pid = ipcRV.pid; + unlinkd_rfd = ipcRV.rfd; + unlinkd_wfd = ipcRV.wfd; slp.tv_sec = 0; slp.tv_usec = 250000; select(0, NULL, NULL, NULL, &slp); @@ -195,6 +200,9 @@ unlinkdInit(void) if (FD_PIPE == fd_table[unlinkd_wfd].type) commUnsetNonBlocking(unlinkd_wfd); debug(2, 1) ("Unlinkd pipe opened on FD %d\n", unlinkd_wfd); +#else + debug(2, 1) ("Unlinkd is disabled\n"); +#endif } #endif /* ndef UNLINK_DAEMON */ Index: auth/basic/auth_basic.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/auth/basic/auth_basic.cc,v retrieving revision 1.20 diff -u -p -r1.20 auth_basic.cc --- auth/basic/auth_basic.cc 15 Oct 2002 09:25:34 -0000 1.20 +++ auth/basic/auth_basic.cc 2 Dec 2002 12:37:30 -0000 @@ -42,6 +42,9 @@ #include "authenticate.h" #include "Store.h" +/* For the IPC type defines */ +#include "ipc.h" + static void authenticateStateFree(AuthenticateStateData * r) { Index: auth/digest/auth_digest.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/auth/digest/auth_digest.cc,v retrieving revision 1.17 diff -u -p -r1.17 auth_digest.cc --- auth/digest/auth_digest.cc 15 Oct 2002 09:25:34 -0000 1.17 +++ auth/digest/auth_digest.cc 2 Dec 2002 12:37:31 -0000 @@ -43,6 +43,7 @@ #include "auth_digest.h" #include "authenticate.h" #include "Store.h" +#include "ipc.h" extern AUTHSSETUP authSchemeSetup_digest; @@ -739,7 +740,7 @@ authenticateDigestDirection(auth_user_re static void authDigestAddHeader(auth_user_request_t * auth_user_request, HttpReply * rep, int accel) { - enum http_hdr_type type; + http_hdr_type type; digest_request_h *digest_request; if (!auth_user_request) return; Index: auth/ntlm/auth_ntlm.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/auth/ntlm/auth_ntlm.cc,v retrieving revision 1.24 diff -u -p -r1.24 auth_ntlm.cc --- auth/ntlm/auth_ntlm.cc 15 Oct 2002 09:25:35 -0000 1.24 +++ auth/ntlm/auth_ntlm.cc 2 Dec 2002 12:37:32 -0000 @@ -42,6 +42,7 @@ #include "auth_ntlm.h" #include "authenticate.h" #include "Store.h" +#include "ipc.h" extern AUTHSSETUP authSchemeSetup_ntlm; Index: fs/diskd/store_dir_diskd.cc =================================================================== RCS file: /cvsroot/squid/squid3/src/fs/diskd/store_dir_diskd.cc,v retrieving revision 1.73 diff -u -p -r1.73 store_dir_diskd.cc --- fs/diskd/store_dir_diskd.cc 28 Oct 2002 08:53:37 -0000 1.73 +++ fs/diskd/store_dir_diskd.cc 2 Dec 2002 12:37:33 -0000 @@ -44,6 +44,8 @@ #include "ufscommon.h" +#include "ipc.h" + diskd_stats_t diskd_stats; MemPool *diskd_state_pool = NULL; @@ -63,9 +65,7 @@ STSETUP storeFsSetup_diskd; static void storeDiskdDirInit(SwapDir * sd) { - int x; int i; - int rfd; int ikey; const char *args[5]; char skey1[32]; @@ -111,16 +111,15 @@ storeDiskdDirInit(SwapDir * sd) args[2] = skey2; args[3] = skey3; args[4] = NULL; - x = ipcCreate(IPC_STREAM, + IPCResult ipcRV = ipcCreate(IPC_STREAM, Config.Program.diskd, args, - "diskd", - &rfd, - &diskdinfo->wfd); - if (x < 0) + "diskd"); + if (!ipcRV.success) fatalf("execl: %s", Config.Program.diskd); - if (rfd != diskdinfo->wfd) - comm_close(rfd); + diskdinfo->wfd = ipcRV.wfd; + if (ipcRV.rfd != diskdinfo->wfd) + comm_close(ipcRV.rfd); fd_note(diskdinfo->wfd, "squid -> diskd"); commSetTimeout(diskdinfo->wfd, -1, NULL, NULL); commSetNonBlocking(diskdinfo->wfd);