--------------------- PatchSet 8583 Date: 2006/09/01 19:21:07 Author: serassio Branch: nt Tag: (none) Log: Split Windows IPC code into ipc_win32.c Members: src/Makefile.am:1.34.2.11->1.34.2.12 src/ipc.c:1.11.2.6->1.11.2.7 src/ipc_win32.c:1.1->1.1.2.1 Index: squid/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v retrieving revision 1.34.2.11 retrieving revision 1.34.2.12 diff -u -r1.34.2.11 -r1.34.2.12 --- squid/src/Makefile.am 19 Aug 2006 08:43:38 -0000 1.34.2.11 +++ squid/src/Makefile.am 1 Sep 2006 19:21:07 -0000 1.34.2.12 @@ -66,8 +66,10 @@ if ENABLE_MINGW32SPECIFIC MINGWEXLIB = -lmingwex +IPC_SOURCE = ipc_win32.c else MINGWEXLIB = +IPC_SOURCE = ipc.c endif if USE_POLL @@ -181,7 +183,7 @@ icp_v3.c \ ident.c \ internal.c \ - ipc.c \ + $(IPC_SOURCE) \ ipcache.c \ $(LEAKFINDERSOURCE) \ locrewrite.c \ Index: squid/src/ipc.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/ipc.c,v retrieving revision 1.11.2.6 retrieving revision 1.11.2.7 diff -u -r1.11.2.6 -r1.11.2.7 --- squid/src/ipc.c 31 Jul 2006 10:21:59 -0000 1.11.2.6 +++ squid/src/ipc.c 1 Sep 2006 19:21:07 -0000 1.11.2.7 @@ -1,6 +1,6 @@ /* - * $Id: ipc.c,v 1.11.2.6 2006/07/31 10:21:59 serassio Exp $ + * $Id: ipc.c,v 1.11.2.7 2006/09/01 19:21:07 serassio Exp $ * * DEBUG: section 54 Interprocess Communication * AUTHOR: Duane Wessels @@ -35,39 +35,6 @@ #include "squid.h" -#ifdef _SQUID_MSWIN_ -#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 int __stdcall ipc_thread_1(struct ipc_params *params); -static int __stdcall ipc_thread_2(struct thread_params *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]; @@ -89,19 +56,8 @@ } int -#ifdef _SQUID_MSWIN_ -ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, HANDLE * hIpc, pid_t * ppid) -#else ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd) -#endif { -#ifdef _SQUID_MSWIN_ - unsigned long thread; - struct ipc_params params; - int opt; - int optlen = sizeof(opt); - DWORD ecode = 0; -#endif pid_t pid; struct sockaddr_in CS; struct sockaddr_in PS; @@ -109,15 +65,13 @@ int prfd = -1; int cwfd = -1; int pwfd = -1; - socklen_t len; -#ifndef _SQUID_MSWIN_ int fd; int t1, t2, t3; + socklen_t len; int tmp_s; #if HAVE_PUTENV char *env_str; #endif -#endif int x; #if HAVE_POLL && defined(_SQUID_OSF_) @@ -130,18 +84,6 @@ *rfd = -1; if (wfd) *wfd = -1; -#ifdef _SQUID_MSWIN_ - if (hIpc) - *hIpc = NULL; - if (ppid) - *ppid = -1; - - 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 if (type == IPC_TCP_SOCKET) { crfd = cwfd = comm_open(SOCK_STREAM, IPPROTO_TCP, @@ -169,12 +111,6 @@ 0, name); } else if (type == IPC_FIFO) { -#ifdef _SQUID_MSWIN_ - debug(54, 0) - ("ipcCreate: %s: use IPC_TCP_SOCKET instead of IP_FIFO on Windows\n", - prog); - assert(0); -#else int p2c[2]; int c2p[2]; if (pipe(p2c) < 0) { @@ -189,7 +125,6 @@ fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write"); fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read"); fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write"); -#endif #if HAVE_SOCKETPAIR && defined(AF_UNIX) } else if (type == IPC_UNIX_STREAM) { int fds[2]; @@ -221,14 +156,6 @@ debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd); debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd); -#ifdef _SQUID_MSWIN_ - 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 - if (crfd < 0) { debug(54, 0) ("ipcCreate: Failed to create child FD.\n"); return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); @@ -264,25 +191,10 @@ } /* flush or else we get dup data if unbuffered_logs is set */ logsFlush(); -#ifdef _SQUID_MSWIN_ - 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()); -#else if ((pid = fork()) < 0) { debug(54, 1) ("ipcCreate: fork: %s\n", xstrerror()); -#endif return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); } -#ifndef _SQUID_MSWIN_ if (pid > 0) { /* parent */ /* close shared socket with child */ comm_close(crfd); @@ -290,74 +202,24 @@ comm_close(cwfd); cwfd = crfd = -1; if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { -#else - { - { -#endif if (comm_connect_addr(pwfd, &CS) == COMM_ERROR) -#ifdef _SQUID_MSWIN_ - { - CloseHandle((HANDLE)thread); - return ipcCloseAllFD(prfd, pwfd, -1, -1); - } -#else return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); -#endif } memset(hello_buf, '\0', HELLO_BUF_SZ); -#ifdef _SQUID_MSWIN_ - x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0); -#else if (type == IPC_UDP_SOCKET) x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0); else x = read(prfd, hello_buf, HELLO_BUF_SZ - 1); -#endif if (x < 0) { debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n"); debug(54, 0) ("--> read: %s\n", xstrerror()); -#ifdef _SQUID_MSWIN_ - CloseHandle((HANDLE)thread); - return ipcCloseAllFD(prfd, pwfd, -1, -1); -#else return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); -#endif } 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)); -#ifdef _SQUID_MSWIN_ - CloseHandle((HANDLE)thread); - return ipcCloseAllFD(prfd, pwfd, -1, -1); -#else return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); -#endif } -#ifdef _SQUID_MSWIN_ - x = send(pwfd, 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, 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); -#endif commSetTimeout(prfd, -1, NULL, NULL); commSetNonBlocking(prfd); commSetNonBlocking(pwfd); @@ -367,90 +229,12 @@ *rfd = prfd; if (wfd) *wfd = pwfd; -#ifdef _SQUID_MSWIN_ - 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; - if (ppid) - *ppid = pid; - return pwfd; - } else { - CloseHandle((HANDLE)thread); - return ipcCloseAllFD(prfd, pwfd, -1, -1); - } -#else fd_table[prfd].flags.ipc = 1; fd_table[pwfd].flags.ipc = 1; if (Config.sleep_after_fork) xusleep(Config.sleep_after_fork); return pid; -#endif - } -#ifdef _SQUID_MSWIN_ -} - -static int -ipcSend(int cwfd, const char *buf, int len) -{ - int x; - - x = send(cwfd, 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 int __stdcall -ipc_thread_1(struct ipc_params *params) -{ - int retval = -1; - int t1, t2, t3; - int p2c[2] = { -1, -1 }; - int c2p[2] = { -1, -1 }; - HANDLE hProcess = NULL; - pid_t pid; - HANDLE thread = NULL; - struct thread_params thread_params; - int fd; - char *str; - int tmp_s; -#if HAVE_PUTENV - char *env_str = NULL; -#endif - int x; - int type = params->type; - int crfd = params->crfd; - int cwfd = params->cwfd; - int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1; - char *prog = NULL; - char **args = params->args; - struct sockaddr_in PS = params->PS; - struct sockaddr_in CS_ipc, PS_ipc; - char *buf1 = NULL; - - buf1 = 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); -#else /* child */ no_suid(); /* give up extra priviliges */ /* close shared socket with parent */ @@ -458,49 +242,25 @@ if (pwfd != prfd) close(pwfd); pwfd = prfd = -1; -#endif 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()); -#ifdef _SQUID_MSWIN_ - goto cleanup; -#else _exit(1); -#endif } debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd); -#ifdef _SQUID_MSWIN_ - comm_close(crfd); - snprintf(buf1, 8191, "%s CHILD socket", prog); - fd_open(fd, FD_SOCKET, buf1); - fd_table[fd].flags.ipc = 1; -#else - close(crfd); -#endif + close(crfd); cwfd = crfd = fd; } else if (type == IPC_UDP_SOCKET) { if (comm_connect_addr(crfd, &PS) == COMM_ERROR) -#ifdef _SQUID_MSWIN_ - goto cleanup; -#else return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); -#endif } -#ifndef _SQUID_MSWIN_ - if (type == IPC_UDP_SOCKET) -#endif - { + if (type == IPC_UDP_SOCKET) { x = send(cwfd, 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"); -#ifdef _SQUID_MSWIN_ - goto cleanup; - } - } -#else _exit(1); } } else { @@ -510,13 +270,11 @@ _exit(1); } } -#endif #if HAVE_PUTENV env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1); snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions); putenv(env_str); #endif -#ifndef _SQUID_MSWIN_ /* * This double-dup stuff avoids problems when one of * crfd, cwfd, or debug_log are in the rage 0-2. @@ -553,371 +311,4 @@ debug(54, 0) ("ipcCreate: %s: %s\n", prog, xstrerror()); _exit(1); return 0; -#else - memset(buf1, '\0', sizeof(buf1)); - x = recv(crfd, 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); - - { - STARTUPINFO si; - PROCESS_INFORMATION pi; - long F; - - 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 < 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 < 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, ok_string, strlen(ok_string), 0); - x = recv(prfd_ipc, 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, 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, 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, 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 (env_str) - xfree(env_str); - if (thread) - CloseHandle(thread); - if (hProcess) - CloseHandle(hProcess); - if (p2c[0] != -1) - close(p2c[0]); - return retval; -#endif } - -#ifdef _SQUID_MSWIN_ -static int __stdcall -ipc_thread_2(struct thread_params *params) -{ - int type = params->type; - int rfd = params->rfd; - int send_fd = params->send_fd; - int x; - char *prog = xstrdup(params->prog); - pid_t pid = params->pid; - char *buf2 = xcalloc(1, 8192); - - for (;;) { - if (type == IPC_TCP_SOCKET) - x = read(rfd, buf2, 8192); - else - x = recv(rfd, 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, 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; -} -#endif --- /dev/null Wed Feb 14 01:16:58 2007 +++ squid/src/ipc_win32.c Wed Feb 14 01:17:02 2007 @@ -0,0 +1,750 @@ + +/* + * $Id: ipc_win32.c,v 1.1.2.1 2006/09/01 19:21:08 serassio Exp $ + * + * DEBUG: section 54 Interprocess Communication + * AUTHOR: Duane Wessels + * + * 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" + +#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; +} + +int +ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, HANDLE * hIpc, pid_t * ppid) +{ + 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 (ppid) + *ppid = -1; + + 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, 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, 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, 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; + if (ppid) + *ppid = pid; + return pwfd; + } 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, 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; + int x, tmp_s, fd = -1; + char *str; +#if HAVE_PUTENV + char *env_str = NULL; +#endif + 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 = 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, 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; + } +#if HAVE_PUTENV + env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1); + snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions); + putenv(env_str); +#endif + memset(buf1, '\0', sizeof(buf1)); + x = recv(crfd, 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 < 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 < 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, ok_string, strlen(ok_string), 0); + x = recv(prfd_ipc, 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, 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, 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, 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 (env_str) + xfree(env_str); + + 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 = xcalloc(1, 8192); + + for (;;) { + if (type == IPC_TCP_SOCKET) + x = read(rfd, buf2, 8192); + else + x = recv(rfd, 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, 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; +}