From: serassio <> Date: Mon, 4 Sep 2006 00:47:17 +0000 (+0000) Subject: Windows port: merged Windows native IPC support X-Git-Tag: SQUID_3_0_PRE5~120 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5d712b5ca5894753dce408bd12e038897fac12d;p=thirdparty%2Fsquid.git Windows port: merged Windows native IPC support --- diff --git a/CONTRIBUTORS b/CONTRIBUTORS index db881bf09e..ee72abfe57 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -82,7 +82,8 @@ and ideas to make this software available. Sergio Rabellino Ian Turner Moez Mahfoudh - Guido Serassio + Guido Serassio + Andrey Shorin Miquel van Smoorenburg Brian Ian Castle diff --git a/configure.in b/configure.in index ba94fd4a75..ba4d0e3fe2 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl Configuration input file for Squid dnl -dnl $Id: configure.in,v 1.433 2006/09/03 04:09:35 hno Exp $ +dnl $Id: configure.in,v 1.434 2006/09/03 18:47:17 serassio Exp $ dnl dnl dnl @@ -11,7 +11,7 @@ AM_CONFIG_HEADER(include/autoconf.h) AC_CONFIG_AUX_DIR(cfgaux) AC_CONFIG_SRCDIR([src/main.cc]) AM_INIT_AUTOMAKE([tar-ustar]) -AC_REVISION($Revision: 1.433 $)dnl +AC_REVISION($Revision: 1.434 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -75,8 +75,12 @@ mingw|mingw32) LIBS="$LIBS -lpsapi" fi MINGW_LIBS="-lmingwex" + AM_CONDITIONAL(USE_IPC_WIN32, true) AC_SUBST(MINGW_LIBS) ;; +*) + AM_CONDITIONAL(USE_IPC_WIN32, false) + ;; esac if test -z "$CACHE_HTTP_PORT"; then diff --git a/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc b/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc index 5c6c306209..a1030db404 100644 --- a/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc +++ b/src/DiskIO/DiskDaemon/DiskdIOStrategy.cc @@ -1,6 +1,6 @@ /* - * $Id: DiskdIOStrategy.cc,v 1.4 2006/05/08 23:38:34 robertc Exp $ + * $Id: DiskdIOStrategy.cc,v 1.5 2006/09/03 18:47:18 serassio Exp $ * * DEBUG: section 79 Squid-side DISKD I/O functions. * AUTHOR: Duane Wessels @@ -153,7 +153,8 @@ DiskdIOStrategy::unlinkFile(char const *path) void DiskdIOStrategy::init() { - int x; + int pid; + void * hIpc; int rfd; int ikey; const char *args[5]; @@ -186,14 +187,15 @@ DiskdIOStrategy::init() args[2] = skey2; args[3] = skey3; args[4] = NULL; - x = ipcCreate(IPC_STREAM, - Config.Program.diskd, - args, - "diskd", - &rfd, - &wfd); - - if (x < 0) + pid = ipcCreate(IPC_STREAM, + Config.Program.diskd, + args, + "diskd", + &rfd, + &wfd, + &hIpc); + + if (pid < 0) fatalf("execl: %s", Config.Program.diskd); if (rfd != wfd) diff --git a/src/Makefile.am b/src/Makefile.am index cb3fcc1baf..c4c231cc26 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.162 2006/09/02 19:42:11 hno Exp $ +# $Id: Makefile.am,v 1.163 2006/09/03 18:47:18 serassio Exp $ # # Uncomment and customize the following to suit your needs: # @@ -147,6 +147,12 @@ else WIN32_SOURCE = endif +if USE_IPC_WIN32 +IPC_SOURCE = ipc_win32.cc +else +IPC_SOURCE = ipc.cc +endif + IDENT_ALL_SOURCE = ACLIdent.cc ACLIdent.h ident.cc if ENABLE_IDENT IDENT_SOURCE = $(IDENT_ALL_SOURCE) @@ -252,6 +258,8 @@ EXTRA_squid_SOURCES = \ dns_internal.cc \ htcp.cc \ htcp.h \ + ipc.cc \ + ipc_win32.cc \ $(IDENT_ALL_SOURCE) \ $(ESI_ALL_SOURCE) \ ProfStats.cc \ @@ -482,7 +490,7 @@ squid_SOURCES = \ $(IDENT_SOURCE) \ int.cc \ internal.cc \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ $(LEAKFINDERSOURCE) \ list.cc \ @@ -778,7 +786,7 @@ ufsdump_SOURCES = \ icp_v3.cc \ $(IDENT_SOURCE) \ internal.cc \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ $(LEAKFINDERSOURCE) \ list.cc \ @@ -1265,7 +1273,7 @@ tests_testCacheManager_SOURCES = \ icp_v2.cc \ icp_v3.cc \ $(IDENT_SOURCE) \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ int.cc \ internal.cc \ @@ -1416,7 +1424,7 @@ tests_testEvent_SOURCES = \ icp_v2.cc \ icp_v3.cc \ $(IDENT_SOURCE) \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ int.cc \ internal.cc \ @@ -1566,7 +1574,7 @@ tests_testEventLoop_SOURCES = \ icp_v2.cc \ icp_v3.cc \ $(IDENT_SOURCE) \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ int.cc \ internal.cc \ @@ -1746,7 +1754,7 @@ tests_test_http_range_SOURCES = \ $(IDENT_SOURCE) \ int.cc \ internal.cc \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ list.cc \ logfile.cc \ @@ -1894,7 +1902,7 @@ tests_testHttpRequest_SOURCES = \ icp_v2.cc \ icp_v3.cc \ $(IDENT_SOURCE) \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ int.cc \ internal.cc \ @@ -2227,7 +2235,7 @@ tests_testURL_SOURCES = \ icp_v2.cc \ icp_v3.cc \ $(IDENT_SOURCE) \ - ipc.cc \ + $(IPC_SOURCE) \ ipcache.cc \ int.cc \ internal.cc \ diff --git a/src/cf.data.pre b/src/cf.data.pre index 2a60870146..02aae2bc07 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.422 2006/08/25 18:53:35 serassio Exp $ +# $Id: cf.data.pre,v 1.423 2006/09/03 18:47:18 serassio Exp $ # # # SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -4902,6 +4902,8 @@ DOC_START processes, these sleep delays will add up and your Squid will not service requests for some amount of time until all the child processes have been started. + On Windows value less then 1000 (1 millisencond) are + rounded to 1000. DOC_END NAME: minimum_expiry_time diff --git a/src/dns.cc b/src/dns.cc index d088997590..c00cf38724 100644 --- a/src/dns.cc +++ b/src/dns.cc @@ -1,6 +1,6 @@ /* - * $Id: dns.cc,v 1.97 2006/05/31 17:29:00 wessels Exp $ + * $Id: dns.cc,v 1.98 2006/09/03 18:47:18 serassio Exp $ * * DEBUG: section 34 Dnsserver interface * AUTHOR: Harvest Derived @@ -44,6 +44,7 @@ using external DNS. */ #if USE_DNSSERVERS + static helper *dnsservers = NULL; static void diff --git a/src/helper.cc b/src/helper.cc index 622089f514..fc814d943a 100644 --- a/src/helper.cc +++ b/src/helper.cc @@ -1,6 +1,6 @@ /* - * $Id: helper.cc,v 1.76 2006/09/02 15:24:08 serassio Exp $ + * $Id: helper.cc,v 1.77 2006/09/03 18:47:18 serassio Exp $ * * DEBUG: section 84 Helper process maintenance * AUTHOR: Harvest Derived? @@ -80,9 +80,10 @@ helperOpenServers(helper * hlp) helper_server *srv; int nargs = 0; int k; - int x; + pid_t pid; int rfd; int wfd; + void * hIpc; wordlist *w; if (hlp->cmdline == NULL) @@ -114,23 +115,25 @@ helperOpenServers(helper * hlp) for (k = 0; k < hlp->n_to_start; k++) { getCurrentTime(); rfd = wfd = -1; - x = ipcCreate(hlp->ipc_type, - progname, - args, - shortname, - &rfd, - &wfd); - - if (x < 0) { + pid = ipcCreate(hlp->ipc_type, + progname, + args, + shortname, + &rfd, + &wfd, + &hIpc); + + if (pid < 0) { debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; } hlp->n_running++; hlp->n_active++; - CBDATA_INIT_TYPE(helper_server); + CBDATA_INIT_TYPE(helper_server); srv = cbdataAlloc(helper_server); - srv->pid = x; + srv->hIpc = hIpc; + srv->pid = pid; srv->index = k; srv->rfd = rfd; srv->wfd = wfd; @@ -179,9 +182,10 @@ helperStatefulOpenServers(statefulhelper * hlp) helper_stateful_server *srv; int nargs = 0; int k; - int x; + pid_t pid; int rfd; int wfd; + void * hIpc; wordlist *w; if (hlp->cmdline == NULL) @@ -213,23 +217,25 @@ helperStatefulOpenServers(statefulhelper * hlp) for (k = 0; k < hlp->n_to_start; k++) { getCurrentTime(); rfd = wfd = -1; - x = ipcCreate(hlp->ipc_type, - progname, - args, - shortname, - &rfd, - &wfd); - - if (x < 0) { + pid = ipcCreate(hlp->ipc_type, + progname, + args, + shortname, + &rfd, + &wfd, + &hIpc); + + if (pid < 0) { debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname); continue; } hlp->n_running++; hlp->n_active++; - CBDATA_INIT_TYPE(helper_stateful_server); + CBDATA_INIT_TYPE(helper_stateful_server); srv = cbdataAlloc(helper_stateful_server); - srv->pid = x; + srv->hIpc = hIpc; + srv->pid = pid; srv->flags.reserved = S_HELPER_FREE; srv->deferred_requests = 0; srv->stats.deferbyfunc = 0; diff --git a/src/icmp.cc b/src/icmp.cc index 4d8c813e41..0fd6f60eed 100644 --- a/src/icmp.cc +++ b/src/icmp.cc @@ -1,6 +1,6 @@ /* - * $Id: icmp.cc,v 1.87 2006/09/02 15:31:30 serassio Exp $ + * $Id: icmp.cc,v 1.88 2006/09/03 18:47:18 serassio Exp $ * * DEBUG: section 37 ICMP Routines * AUTHOR: Duane Wessels @@ -52,9 +52,7 @@ static void icmpSend(pingerEchoData * pkt, int len); static void icmpHandleSourcePing(const struct sockaddr_in *from, const char *buf); #endif -#ifdef _SQUID_MSWIN_ -static HANDLE hIpc; -#endif +static void * hIpc; static pid_t pid; static void @@ -240,11 +238,12 @@ icmpOpen(void) args[0] = "(pinger)"; args[1] = NULL; pid = ipcCreate(IPC_DGRAM, - Config.Program.pinger, - args, - "Pinger Socket", - &rfd, - &wfd); + Config.Program.pinger, + args, + "Pinger Socket", + &rfd, + &wfd, + &hIpc); if (pid < 0) return; diff --git a/src/ipc_win32.cc b/src/ipc_win32.cc new file mode 100755 index 0000000000..b38f4fd810 --- /dev/null +++ b/src/ipc_win32.cc @@ -0,0 +1,863 @@ + +/* + * $Id: ipc_win32.cc,v 1.1 2006/09/03 18:47:18 serassio Exp $ + * + * DEBUG: section 54 Windows Interprocess Communication + * AUTHOR: Andrey Shorin & Guido Serassio + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "comm.h" +#include "fde.h" +#include "SquidTime.h" + +#ifndef _MSWSOCK_ +#include +#endif +#include + +struct ipc_params +{ + int type; + int crfd; + int cwfd; + + struct sockaddr_in PS; + const char *prog; + char **args; +}; + +struct thread_params +{ + int type; + int rfd; + int send_fd; + const char *prog; + pid_t pid; +}; + +static unsigned int __stdcall ipc_thread_1(void *params); +static unsigned int __stdcall ipc_thread_2(void *params); + +static const char *ok_string = "OK\n"; +static const char *err_string = "ERR\n"; +static const char *shutdown_string = "$shutdown\n"; + +static const char *hello_string = "hi there\n"; +#define HELLO_BUF_SZ 32 +static char hello_buf[HELLO_BUF_SZ]; + +static int +ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd) +{ + if (prfd >= 0) + comm_close(prfd); + + if (prfd != pwfd) + if (pwfd >= 0) + comm_close(pwfd); + + if (crfd >= 0) + comm_close(crfd); + + if (crfd != cwfd) + if (cwfd >= 0) + comm_close(cwfd); + + return -1; +} + +static void +PutEnvironment() +{ +#if HAVE_PUTENV + char *env_str; + int tmp_s; + env_str = (char *)xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1); + snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions); + putenv(env_str); +#endif +} + +pid_t +ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, void **hIpc) +{ + unsigned long thread; + + struct ipc_params params; + int opt; + int optlen = sizeof(opt); + DWORD ecode = 0; + pid_t pid; + + struct sockaddr_in CS; + + struct sockaddr_in PS; + int crfd = -1; + int prfd = -1; + int cwfd = -1; + int pwfd = -1; + socklen_t len; + int x; + + requirePathnameExists(name, prog); + + if (rfd) + *rfd = -1; + + if (wfd) + *wfd = -1; + + if (hIpc) + *hIpc = NULL; + + if (WIN32_OS_version != _WIN_OS_WINNT) { + getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen); + opt = opt & ~(SO_SYNCHRONOUS_NONALERT | SO_SYNCHRONOUS_ALERT); + setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, sizeof(opt)); + } + + if (type == IPC_TCP_SOCKET) { + crfd = cwfd = comm_open(SOCK_STREAM, + IPPROTO_TCP, + local_addr, + 0, + COMM_NOCLOEXEC, + name); + prfd = pwfd = comm_open(SOCK_STREAM, + IPPROTO_TCP, /* protocol */ + local_addr, + 0, /* port */ + 0, /* blocking */ + name); + } else if (type == IPC_UDP_SOCKET) { + crfd = cwfd = comm_open(SOCK_DGRAM, + IPPROTO_UDP, + local_addr, + 0, + COMM_NOCLOEXEC, + name); + prfd = pwfd = comm_open(SOCK_DGRAM, + IPPROTO_UDP, + local_addr, + 0, + 0, + name); + } else if (type == IPC_FIFO) { + debug(54, 0) + ("ipcCreate: %s: use IPC_TCP_SOCKET instead of IP_FIFO on Windows\n", + prog); + assert(0); + } else { + assert(IPC_NONE); + } + + debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd); + debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd); + debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd); + debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd); + + if (WIN32_OS_version != _WIN_OS_WINNT) { + getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen); + opt = opt | SO_SYNCHRONOUS_NONALERT; + setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen); + } + + if (crfd < 0) { + debug(54, 0) ("ipcCreate: Failed to create child FD.\n"); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + + if (pwfd < 0) { + debug(54, 0) ("ipcCreate: Failed to create server FD.\n"); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + + if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { + len = sizeof(PS); + memset(&PS, '\0', len); + + if (getsockname(pwfd, (struct sockaddr *) &PS, &len) < 0) { + debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + + debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", + pwfd, inet_ntoa(PS.sin_addr), ntohs(PS.sin_port)); + len = sizeof(CS); + memset(&CS, '\0', len); + + if (getsockname(crfd, (struct sockaddr *) &CS, &len) < 0) { + debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + + debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", + crfd, inet_ntoa(CS.sin_addr), ntohs(CS.sin_port)); + } + + if (type == IPC_TCP_SOCKET) { + if (listen(crfd, 1) < 0) { + debug(54, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror()); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + + debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd); + } + + /* flush or else we get dup data if unbuffered_logs is set */ + logsFlush(); + + params.type = type; + + params.crfd = crfd; + + params.cwfd = cwfd; + + params.PS = PS; + + params.prog = prog; + + params.args = (char **) args; + + thread = _beginthreadex(NULL, 0, ipc_thread_1, ¶ms, 0, NULL); + + if (thread == 0) { + debug(54, 1) ("ipcCreate: _beginthread: %s\n", xstrerror()); + return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); + } + + if (comm_connect_addr(pwfd, &CS) == COMM_ERROR) { + CloseHandle((HANDLE) thread); + return ipcCloseAllFD(prfd, pwfd, -1, -1); + } + + memset(hello_buf, '\0', HELLO_BUF_SZ); + x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0); + + if (x < 0) { + debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n"); + debug(54, 0) ("--> read: %s\n", xstrerror()); + CloseHandle((HANDLE) thread); + return ipcCloseAllFD(prfd, pwfd, -1, -1); + } else if (strcmp(hello_buf, hello_string)) { + debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n"); + debug(54, 0) ("--> read returned %d\n", x); + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf)); + CloseHandle((HANDLE) thread); + return ipcCloseAllFD(prfd, pwfd, -1, -1); + } + + x = send(pwfd, (const void *)ok_string, strlen(ok_string), 0); + + if (x < 0) { + debug(54, 0) ("ipcCreate: PARENT: OK write test failed\n"); + debug(54, 0) ("--> read: %s\n", xstrerror()); + CloseHandle((HANDLE) thread); + return ipcCloseAllFD(prfd, pwfd, -1, -1); + } + + memset(hello_buf, '\0', HELLO_BUF_SZ); + x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0); + + if (x < 0) { + debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n"); + debug(54, 0) ("--> read: %s\n", xstrerror()); + CloseHandle((HANDLE) thread); + return ipcCloseAllFD(prfd, pwfd, -1, -1); + } else if (!strcmp(hello_buf, err_string)) { + debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n"); + debug(54, 0) ("--> read returned %d\n", x); + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf)); + CloseHandle((HANDLE) thread); + return ipcCloseAllFD(prfd, pwfd, -1, -1); + } + + hello_buf[x] = '\0'; + pid = atol(hello_buf); + commSetTimeout(prfd, -1, NULL, NULL); + commSetNonBlocking(prfd); + commSetNonBlocking(pwfd); + commSetCloseOnExec(prfd); + commSetCloseOnExec(pwfd); + + if (rfd) + *rfd = prfd; + + if (wfd) + *wfd = pwfd; + + fd_table[prfd].flags.ipc = 1; + + fd_table[pwfd].flags.ipc = 1; + + fd_table[crfd].flags.ipc = 1; + + fd_table[cwfd].flags.ipc = 1; + + if (Config.sleep_after_fork) { + /* XXX emulation of usleep() */ + DWORD sl; + sl = Config.sleep_after_fork / 1000; + + if (sl == 0) + sl = 1; + + Sleep(sl); + } + + if (GetExitCodeThread((HANDLE) thread, &ecode) && ecode == STILL_ACTIVE) { + if (hIpc) + *hIpc = (HANDLE) thread; + + return pid; + } else { + CloseHandle((HANDLE) thread); + return ipcCloseAllFD(prfd, pwfd, -1, -1); + } +} + +static int +ipcSend(int cwfd, const char *buf, int len) +{ + int x; + + x = send(cwfd, (const void *)buf, len, 0); + + if (x < 0) { + debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n"); + } + + return x; +} + +static unsigned int __stdcall +ipc_thread_1(void *in_params) +{ + int t1, t2, t3, retval = -1; + int p2c[2] = + {-1, -1}; + int c2p[2] = + {-1, -1}; + HANDLE hProcess = NULL, thread = NULL; + pid_t pid = -1; + + struct thread_params thread_params; + ssize_t x; + int tmp_s, fd = -1; + char *str; + STARTUPINFO si; + PROCESS_INFORMATION pi; + long F; + int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1; + char *prog = NULL, *buf1 = NULL; + + struct sockaddr_in CS_ipc, PS_ipc; + + struct ipc_params *params = (struct ipc_params *) in_params; + int type = params->type; + int crfd = params->crfd; + int cwfd = params->cwfd; + char **args = params->args; + + struct sockaddr_in PS = params->PS; + + + buf1 = (char *)xcalloc(1, 8192); + strcpy(buf1, params->prog); + prog = strtok(buf1, w_space); + + if ((str = strrchr(prog, '/'))) + prog = ++str; + + if ((str = strrchr(prog, '\\'))) + prog = ++str; + + prog = xstrdup(prog); + + if (type == IPC_TCP_SOCKET) { + debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd); + + if ((fd = accept(crfd, NULL, NULL)) < 0) { + debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror()); + goto cleanup; + } + + debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd); + comm_close(crfd); + snprintf(buf1, 8191, "%s CHILD socket", prog); + fd_open(fd, FD_SOCKET, buf1); + fd_table[fd].flags.ipc = 1; + cwfd = crfd = fd; + } else if (type == IPC_UDP_SOCKET) { + if (comm_connect_addr(crfd, &PS) == COMM_ERROR) + goto cleanup; + } + + x = send(cwfd, (const void *)hello_string, strlen(hello_string) + 1, 0); + + if (x < 0) { + debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n"); + goto cleanup; + } + + PutEnvironment(); + memset(buf1, '\0', sizeof(buf1)); + x = recv(crfd, (void *)buf1, 8191, 0); + + if (x < 0) { + debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n"); + debug(54, 0) ("--> read: %s\n", xstrerror()); + goto cleanup; + } else if (strcmp(buf1, ok_string)) { + debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n"); + debug(54, 0) ("--> read returned %d\n", x); + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf)); + goto cleanup; + } + + /* assign file descriptors to child process */ + if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) { + debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) { + debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + if (type == IPC_UDP_SOCKET) { + snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L); + crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1); + + if (crfd_ipc < 0) { + debug(54, 0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L); + prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1); + + if (pwfd_ipc < 0) { + debug(54, 0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + tmp_s = sizeof(PS_ipc); + memset(&PS_ipc, '\0', tmp_s); + + if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) { + debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", + pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port)); + tmp_s = sizeof(CS_ipc); + memset(&CS_ipc, '\0', tmp_s); + + if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) { + debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n", + crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port)); + + if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) { + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + fd = crfd; + + if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) { + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + } /* IPC_UDP_SOCKET */ + + t1 = dup(0); + + t2 = dup(1); + + t3 = dup(2); + + dup2(c2p[0], 0); + + dup2(p2c[1], 1); + + dup2(fileno(debug_log), 2); + + close(c2p[0]); + + close(p2c[1]); + + commUnsetNonBlocking(fd); + + memset(&si, 0, sizeof(STARTUPINFO)); + + si.cb = sizeof(STARTUPINFO); + + si.hStdInput = (HANDLE) _get_osfhandle(0); + + si.hStdOutput = (HANDLE) _get_osfhandle(1); + + si.hStdError = (HANDLE) _get_osfhandle(2); + + si.dwFlags = STARTF_USESTDHANDLES; + + /* Make sure all other valid handles are not inerithable */ + for (x = 3; x < Squid_MaxFD; x++) { + if ((F = _get_osfhandle(x)) == -1) + continue; + + SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0); + } + + *buf1 = '\0'; + strcpy(buf1 + 4096, params->prog); + str = strtok(buf1 + 4096, w_space); + + do { + strcat(buf1, str); + strcat(buf1, " "); + } while ((str = strtok(NULL, w_space))); + + x = 1; + + while (args[x]) { + strcat(buf1, args[x++]); + strcat(buf1, " "); + } + + if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW, + NULL, NULL, &si, &pi)) { + pid = pi.dwProcessId; + hProcess = pi.hProcess; + } else { + pid = -1; + WIN32_maperror(GetLastError()); + x = errno; + } + + dup2(t1, 0); + dup2(t2, 1); + dup2(t3, 2); + close(t1); + close(t2); + close(t3); + + if (pid == -1) { + errno = x; + debug(54, 0) ("ipcCreate: CHILD: %s: %s\n", params->prog, xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + if (type == IPC_UDP_SOCKET) { + WSAPROTOCOL_INFO wpi; + + memset(&wpi, 0, sizeof(wpi)); + + if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) { + debug(54, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n", + xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + x = write(c2p[1], (const char *) &wpi, sizeof(wpi)); + + if (x < (ssize_t)sizeof(wpi)) { + debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + x = read(p2c[0], buf1, 8192); + + if (x < 0) { + debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } else if (strncmp(buf1, ok_string, strlen(ok_string))) { + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + debug(54, 0) ("--> read returned %d\n", x); + buf1[x] = '\0'; + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1)); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc)); + + if (x < (ssize_t)sizeof(PS_ipc)) { + debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + x = read(p2c[0], buf1, 8192); + + if (x < 0) { + debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0], + xstrerror()); + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } else if (strncmp(buf1, ok_string, strlen(ok_string))) { + debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n", + prog); + debug(54, 0) ("--> read returned %d\n", x); + buf1[x] = '\0'; + debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1)); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + x = send(pwfd_ipc, (const void *)ok_string, strlen(ok_string), 0); + x = recv(prfd_ipc, (void *)(buf1 + 200), 8191 - 200, 0); + assert((size_t) x == strlen(ok_string) + && !strncmp(ok_string, buf1 + 200, strlen(ok_string))); + } /* IPC_UDP_SOCKET */ + + snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid); + + fd_note(fd, buf1); + + if (prfd_ipc != -1) { + snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid); + fd_note(crfd_ipc, buf1); + snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid); + fd_note(prfd_ipc, buf1); + } + + /* else { IPC_TCP_SOCKET */ + /* commSetNoLinger(fd); */ + /* } */ + thread_params.prog = prog; + + thread_params.send_fd = cwfd; + + thread_params.pid = pid; + + if ((thread_params.type = type) == IPC_TCP_SOCKET) + thread_params.rfd = p2c[0]; + else + thread_params.rfd = prfd_ipc; + + thread = + (HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL); + + if (!thread) { + debug(54, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror()); + ipcSend(cwfd, err_string, strlen(err_string)); + goto cleanup; + } + + snprintf(buf1, 8191, "%ld\n", (long int) pid); + + if (-1 == ipcSend(cwfd, buf1, strlen(buf1))) + goto cleanup; + + debug(54, 2) ("ipc(%s,%ld): started successfully\n", prog, (long int) pid); + + /* cycle */ + for (;;) { + x = recv(crfd, (void *)buf1, 8192, 0); + + if (x <= 0) { + debug(54, 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n", + prog, pid, x); + break; + } + + buf1[x] = '\0'; + + if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) { + debug(54, 3) + ("ipc(%s,%d): request for shutdown received from parent. Exiting...\n", + prog, pid); + TerminateProcess(hProcess, 0); + break; + } + + debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", prog, pid, + rfc1738_escape_unescaped(buf1)); + + if (type == IPC_TCP_SOCKET) + x = write(c2p[1], buf1, x); + else + x = send(pwfd_ipc, (const void *)buf1, x, 0); + + if (x <= 0) { + debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n", + prog, pid, x, prog); + break; + } + } + + retval = 0; + +cleanup: + + if (c2p[1] != -1) + close(c2p[1]); + + if (fd_table[crfd].flags.open) + ipcCloseAllFD(-1, -1, crfd, cwfd); + + if (prfd_ipc != -1) { + send(crfd_ipc, (const void *)shutdown_string, strlen(shutdown_string), 0); + shutdown(crfd_ipc, SD_BOTH); + shutdown(prfd_ipc, SD_BOTH); + } + + ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc); + + if (hProcess && WAIT_OBJECT_0 != + WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) { + + getCurrentTime(); + debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n", + prog, pid, prog, type == IPC_UDP_SOCKET ? 12 : 5); + } + + if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) { + getCurrentTime(); + debug(54, 0) + ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n", + prog, pid); + } + + getCurrentTime(); + + if (!retval) + debug(54, 2) ("ipc(%s,%d): normal exit\n", prog, pid); + + if (buf1) + xfree(buf1); + + if (prog) + xfree(prog); + + if (thread) + CloseHandle(thread); + + if (hProcess) + CloseHandle(hProcess); + + if (p2c[0] != -1) + close(p2c[0]); + + return retval; +} + +static unsigned int __stdcall +ipc_thread_2(void *in_params) +{ + int x; + + struct thread_params *params = (struct thread_params *) in_params; + int type = params->type; + int rfd = params->rfd; + int send_fd = params->send_fd; + char *prog = xstrdup(params->prog); + pid_t pid = params->pid; + char *buf2 = (char *)xcalloc(1, 8192); + + for (;;) { + if (type == IPC_TCP_SOCKET) + x = read(rfd, buf2, 8192); + else + x = recv(rfd, (void *)buf2, 8192, 0); + + if ((x <= 0 && type == IPC_TCP_SOCKET) || + (x < 0 && type == IPC_UDP_SOCKET)) { + debug(54, 3) ("ipc(%s,%d): %d bytes read from %s. Exiting...\n", + prog, pid, x, prog); + break; + } + + buf2[x] = '\0'; + + if (type == IPC_UDP_SOCKET && !strcmp(buf2, shutdown_string)) { + debug(54, 3) ("ipc(%s,%d): request for shutdown received. Exiting...\n", + prog, pid); + break; + } + + if (x >= 2) { + if ((buf2[x - 1] == '\n') && (buf2[x - 2] == '\r')) { + buf2[x - 2] = '\n'; + buf2[x - 1] = '\0'; + x--; + } + } + + debug(54, 5) ("ipc(%s,%d): received from child : %s\n", prog, pid, + rfc1738_escape_unescaped(buf2)); + x = send(send_fd, (const void *)buf2, x, 0); + + if ((x <= 0 && type == IPC_TCP_SOCKET) || + (x < 0 && type == IPC_UDP_SOCKET)) { + debug(54, 3) ("ipc(%s,%d): %d bytes sent to parent. Exiting...\n", + prog, pid, x); + break; + } + } + + xfree(prog); + xfree(buf2); + return 0; +} diff --git a/src/protos.h b/src/protos.h index 0a3ff3f541..769aa4b008 100644 --- a/src/protos.h +++ b/src/protos.h @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.536 2006/08/21 00:50:41 robertc Exp $ + * $Id: protos.h,v 1.537 2006/09/03 18:47:18 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -676,16 +676,17 @@ SQUIDCEXTERN char *strwordtok(char *buf, char **t); SQUIDCEXTERN void strwordquote(MemBuf * mb, const char *str); - /* * ipc.c */ -SQUIDCEXTERN int ipcCreate(int type, - const char *prog, - const char *const args[], - const char *name, - int *rfd, - int *wfd); +SQUIDCEXTERN pid_t ipcCreate(int type, + const char *prog, + const char *const args[], + const char *name, + int *rfd, + int *wfd, + void **hIpc); + /* CacheDigest */ SQUIDCEXTERN CacheDigest *cacheDigestCreate(int capacity, int bpe); diff --git a/src/unlinkd.cc b/src/unlinkd.cc index 74e1f3e2a2..931dc010a2 100644 --- a/src/unlinkd.cc +++ b/src/unlinkd.cc @@ -1,6 +1,6 @@ /* - * $Id: unlinkd.cc,v 1.55 2006/09/02 14:59:49 serassio Exp $ + * $Id: unlinkd.cc,v 1.56 2006/09/03 18:47:18 serassio Exp $ * * DEBUG: section 2 Unlink Daemon * AUTHOR: Duane Wessels @@ -85,9 +85,7 @@ main(int argc, char *argv[]) static int unlinkd_wfd = -1; static int unlinkd_rfd = -1; -#ifdef _SQUID_MSWIN_ -static HANDLE hIpc; -#endif +static void * hIpc; static pid_t pid; #define UNLINKD_QUEUE_LIMIT 20 @@ -232,28 +230,41 @@ unlinkdInit(void) struct timeval slp; args[0] = "(unlinkd)"; args[1] = NULL; + pid = ipcCreate( #if USE_POLL && defined(_SQUID_OSF_) - /* pipes and poll() don't get along on DUNIX -DW */ - pid = 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 */ -pid = ipcCreate(IPC_FIFO, +IPC_FIFO, #endif - Config.Program.unlinkd, - args, - "unlinkd", - &unlinkd_rfd, - &unlinkd_wfd); + Config.Program.unlinkd, + args, + "unlinkd", + &unlinkd_rfd, + &unlinkd_wfd, + &hIpc); if (pid < 0) fatal("Failed to create unlinkd subprocess"); + 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 @@ -262,8 +273,10 @@ pid = ipcCreate(IPC_FIFO, * 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); #ifdef _SQUID_MSWIN_ diff --git a/src/win32.cc b/src/win32.cc index 2a8a73ab02..08374321fb 100644 --- a/src/win32.cc +++ b/src/win32.cc @@ -1,6 +1,6 @@ /* - * $Id: win32.cc,v 1.22 2006/09/02 13:21:00 serassio Exp $ + * $Id: win32.cc,v 1.23 2006/09/03 18:47:18 serassio Exp $ * * * * * * * * * Legal stuff * * * * * * * * @@ -907,6 +907,12 @@ int main(int argc, char **argv) } } else { WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE; +#ifdef _SQUID_MSWIN_ + + opt_no_daemon = 1; + +#endif + return SquidMain(argc, argv); }