]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc_win32.cc
Prepare external_acl_type format codes for libformat upgrade
[thirdparty/squid.git] / src / ipc_win32.cc
CommitLineData
b5d712b5 1/*
b5d712b5 2 * DEBUG: section 54 Windows Interprocess Communication
1b52df9a 3 * AUTHOR: Andrey Shorin <tolsty@tushino.com>
4 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
b5d712b5 5 *
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
8 *
9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
26ac0430 22 *
b5d712b5 23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
26ac0430 27 *
b5d712b5 28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
31 *
32 */
33
582c2af2 34#include "squid.h"
8a01b99e 35#include "cache_cf.h"
b5d712b5 36#include "comm.h"
c4ad1349 37#include "fd.h"
b5d712b5 38#include "fde.h"
a13c93d1
C
39#include "ip/Address.h"
40#include "rfc1738.h"
4d5904f7 41#include "SquidConfig.h"
96097880 42#include "SquidIpc.h"
b5d712b5 43#include "SquidTime.h"
a8e49d54 44#include "tools.h"
b5d712b5 45
46#ifndef _MSWSOCK_
47#include <mswsock.h>
48#endif
49#include <process.h>
21d845b1
FC
50#if HAVE_ERRNO_H
51#include <errno.h>
52#endif
b5d712b5 53
26ac0430 54struct ipc_params {
b5d712b5 55 int type;
56 int crfd;
57 int cwfd;
b7ac5457 58 Ip::Address local_addr;
cc192b50 59 struct addrinfo PS;
b5d712b5 60 const char *prog;
61 char **args;
62};
63
26ac0430 64struct thread_params {
b5d712b5 65 int type;
66 int rfd;
67 int send_fd;
68 const char *prog;
69 pid_t pid;
70};
71
72static unsigned int __stdcall ipc_thread_1(void *params);
73static unsigned int __stdcall ipc_thread_2(void *params);
74
75static const char *ok_string = "OK\n";
76static const char *err_string = "ERR\n";
77static const char *shutdown_string = "$shutdown\n";
78
79static const char *hello_string = "hi there\n";
80#define HELLO_BUF_SZ 32
81static char hello_buf[HELLO_BUF_SZ];
82
83static int
84ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
85{
86 if (prfd >= 0)
87 comm_close(prfd);
88
89 if (prfd != pwfd)
90 if (pwfd >= 0)
91 comm_close(pwfd);
92
93 if (crfd >= 0)
94 comm_close(crfd);
95
96 if (crfd != cwfd)
97 if (cwfd >= 0)
98 comm_close(cwfd);
99
100 return -1;
101}
102
103static void
104PutEnvironment()
105{
106#if HAVE_PUTENV
107 char *env_str;
108 int tmp_s;
62493678
AJ
109 env_str = (char *)xcalloc((tmp_s = strlen(Debug::debugOptions) + 32), 1);
110 snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Debug::debugOptions);
b5d712b5 111 putenv(env_str);
112#endif
113}
114
115pid_t
b7ac5457 116ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc)
b5d712b5 117{
118 unsigned long thread;
119
120 struct ipc_params params;
121 int opt;
122 int optlen = sizeof(opt);
123 DWORD ecode = 0;
124 pid_t pid;
125
b7ac5457 126 Ip::Address tmp_addr;
cc192b50 127 struct addrinfo *aiCS = NULL;
128 struct addrinfo *aiPS = NULL;
b5d712b5 129
b5d712b5 130 int crfd = -1;
131 int prfd = -1;
132 int cwfd = -1;
133 int pwfd = -1;
b5d712b5 134 int x;
135
136 requirePathnameExists(name, prog);
137
138 if (rfd)
139 *rfd = -1;
140
141 if (wfd)
142 *wfd = -1;
143
144 if (hIpc)
145 *hIpc = NULL;
146
147 if (WIN32_OS_version != _WIN_OS_WINNT) {
148 getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
149 opt = opt & ~(SO_SYNCHRONOUS_NONALERT | SO_SYNCHRONOUS_ALERT);
150 setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, sizeof(opt));
151 }
152
153 if (type == IPC_TCP_SOCKET) {
154 crfd = cwfd = comm_open(SOCK_STREAM,
155 IPPROTO_TCP,
156 local_addr,
b5d712b5 157 COMM_NOCLOEXEC,
158 name);
159 prfd = pwfd = comm_open(SOCK_STREAM,
160 IPPROTO_TCP, /* protocol */
161 local_addr,
b5d712b5 162 0, /* blocking */
163 name);
164 } else if (type == IPC_UDP_SOCKET) {
165 crfd = cwfd = comm_open(SOCK_DGRAM,
166 IPPROTO_UDP,
167 local_addr,
b5d712b5 168 COMM_NOCLOEXEC,
169 name);
170 prfd = pwfd = comm_open(SOCK_DGRAM,
171 IPPROTO_UDP,
172 local_addr,
173 0,
b5d712b5 174 name);
175 } else if (type == IPC_FIFO) {
fa84c01d 176 debugs(54, DBG_CRITICAL, "ipcCreate: " << prog << ": use IPC_TCP_SOCKET instead of IP_FIFO on Windows");
b5d712b5 177 assert(0);
178 } else {
179 assert(IPC_NONE);
180 }
181
bf8fe701 182 debugs(54, 3, "ipcCreate: prfd FD " << prfd);
183 debugs(54, 3, "ipcCreate: pwfd FD " << pwfd);
184 debugs(54, 3, "ipcCreate: crfd FD " << crfd);
185 debugs(54, 3, "ipcCreate: cwfd FD " << cwfd);
b5d712b5 186
187 if (WIN32_OS_version != _WIN_OS_WINNT) {
188 getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
189 opt = opt | SO_SYNCHRONOUS_NONALERT;
190 setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen);
191 }
192
193 if (crfd < 0) {
fa84c01d 194 debugs(54, DBG_CRITICAL, "ipcCreate: Failed to create child FD.");
b5d712b5 195 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
196 }
197
198 if (pwfd < 0) {
fa84c01d 199 debugs(54, DBG_CRITICAL, "ipcCreate: Failed to create server FD.");
b5d712b5 200 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
201 }
202
cc192b50 203// AYJ: these flags should be neutral, but if not IPv6 version needs adding
b5d712b5 204 if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
b5d712b5 205
cc192b50 206 tmp_addr.InitAddrInfo(aiPS);
207
208 if (getsockname(pwfd, aiPS->ai_addr, &(aiPS->ai_addrlen) ) < 0) {
fa84c01d 209 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
b5d712b5 210 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
211 }
212
cc192b50 213 tmp_addr = *aiPS;
214
215 debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << tmp_addr );
b5d712b5 216
cc192b50 217 tmp_addr.InitAddrInfo(aiCS);
218
219 if (getsockname(crfd, aiCS->ai_addr, &(aiCS->ai_addrlen) ) < 0) {
fa84c01d 220 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
b5d712b5 221 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
222 }
223
cc192b50 224 tmp_addr.SetEmpty();
225 tmp_addr = *aiCS;
226
227 debugs(54, 3, "ipcCreate: FD " << crfd << " sockaddr " << tmp_addr );
b5d712b5 228 }
229
230 if (type == IPC_TCP_SOCKET) {
231 if (listen(crfd, 1) < 0) {
e0236918 232 debugs(54, DBG_IMPORTANT, "ipcCreate: listen FD " << crfd << ": " << xstrerror());
b5d712b5 233 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
234 }
235
bf8fe701 236 debugs(54, 3, "ipcCreate: FD " << crfd << " listening...");
b5d712b5 237 }
238
239 /* flush or else we get dup data if unbuffered_logs is set */
240 logsFlush();
241
242 params.type = type;
243
244 params.crfd = crfd;
245
246 params.cwfd = cwfd;
247
cc192b50 248 params.PS = *aiPS;
26ac0430 249
cc192b50 250 params.local_addr = local_addr;
b5d712b5 251
252 params.prog = prog;
253
254 params.args = (char **) args;
255
256 thread = _beginthreadex(NULL, 0, ipc_thread_1, &params, 0, NULL);
257
258 if (thread == 0) {
e0236918 259 debugs(54, DBG_IMPORTANT, "ipcCreate: _beginthread: " << xstrerror());
b5d712b5 260 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
261 }
262
b7ac5457 263 /* NP: tmp_addr was left with eiether empty or aiCS in Ip::Address format */
cc192b50 264 if (comm_connect_addr(pwfd, tmp_addr) == COMM_ERROR) {
b5d712b5 265 CloseHandle((HANDLE) thread);
266 return ipcCloseAllFD(prfd, pwfd, -1, -1);
267 }
268
269 memset(hello_buf, '\0', HELLO_BUF_SZ);
270 x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0);
271
272 if (x < 0) {
fa84c01d
FC
273 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
274 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 275 CloseHandle((HANDLE) thread);
276 return ipcCloseAllFD(prfd, pwfd, -1, -1);
277 } else if (strcmp(hello_buf, hello_string)) {
fa84c01d
FC
278 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
279 debugs(54, DBG_CRITICAL, "--> read returned " << x);
280 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
b5d712b5 281 CloseHandle((HANDLE) thread);
282 return ipcCloseAllFD(prfd, pwfd, -1, -1);
283 }
284
285 x = send(pwfd, (const void *)ok_string, strlen(ok_string), 0);
286
287 if (x < 0) {
fa84c01d
FC
288 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: OK write test failed");
289 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 290 CloseHandle((HANDLE) thread);
291 return ipcCloseAllFD(prfd, pwfd, -1, -1);
292 }
293
294 memset(hello_buf, '\0', HELLO_BUF_SZ);
295 x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0);
296
297 if (x < 0) {
fa84c01d
FC
298 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: OK read test failed");
299 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 300 CloseHandle((HANDLE) thread);
301 return ipcCloseAllFD(prfd, pwfd, -1, -1);
302 } else if (!strcmp(hello_buf, err_string)) {
fa84c01d
FC
303 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: OK read test failed");
304 debugs(54, DBG_CRITICAL, "--> read returned " << x);
305 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
b5d712b5 306 CloseHandle((HANDLE) thread);
307 return ipcCloseAllFD(prfd, pwfd, -1, -1);
308 }
309
310 hello_buf[x] = '\0';
311 pid = atol(hello_buf);
933dd095 312 commUnsetFdTimeout(prfd);
b5d712b5 313 commSetNonBlocking(prfd);
314 commSetNonBlocking(pwfd);
315 commSetCloseOnExec(prfd);
316 commSetCloseOnExec(pwfd);
317
318 if (rfd)
319 *rfd = prfd;
320
321 if (wfd)
322 *wfd = pwfd;
323
be4d35dc
FC
324 fd_table[prfd].flags.ipc = true;
325 fd_table[pwfd].flags.ipc = true;
326 fd_table[crfd].flags.ipc = true;
327 fd_table[cwfd].flags.ipc = true;
b5d712b5 328
329 if (Config.sleep_after_fork) {
330 /* XXX emulation of usleep() */
331 DWORD sl;
332 sl = Config.sleep_after_fork / 1000;
333
334 if (sl == 0)
335 sl = 1;
336
337 Sleep(sl);
338 }
339
340 if (GetExitCodeThread((HANDLE) thread, &ecode) && ecode == STILL_ACTIVE) {
341 if (hIpc)
342 *hIpc = (HANDLE) thread;
343
344 return pid;
345 } else {
346 CloseHandle((HANDLE) thread);
347 return ipcCloseAllFD(prfd, pwfd, -1, -1);
348 }
349}
350
351static int
352ipcSend(int cwfd, const char *buf, int len)
353{
354 int x;
355
356 x = send(cwfd, (const void *)buf, len, 0);
357
358 if (x < 0) {
fa84c01d
FC
359 debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerror());
360 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
b5d712b5 361 }
362
363 return x;
364}
365
366static unsigned int __stdcall
367ipc_thread_1(void *in_params)
368{
369 int t1, t2, t3, retval = -1;
26ac0430
AJ
370 int p2c[2] = {-1, -1};
371 int c2p[2] = {-1, -1};
b5d712b5 372 HANDLE hProcess = NULL, thread = NULL;
373 pid_t pid = -1;
374
375 struct thread_params thread_params;
376 ssize_t x;
cc192b50 377 int fd = -1;
b5d712b5 378 char *str;
379 STARTUPINFO si;
380 PROCESS_INFORMATION pi;
381 long F;
382 int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1;
383 char *prog = NULL, *buf1 = NULL;
384
b7ac5457
AJ
385 Ip::Address PS_ipc;
386 Ip::Address CS_ipc;
cc192b50 387 struct addrinfo *aiPS_ipc = NULL;
388 struct addrinfo *aiCS_ipc = NULL;
b5d712b5 389
390 struct ipc_params *params = (struct ipc_params *) in_params;
391 int type = params->type;
392 int crfd = params->crfd;
393 int cwfd = params->cwfd;
394 char **args = params->args;
395
b7ac5457
AJ
396 Ip::Address PS = params->PS;
397 Ip::Address local_addr = params->local_addr;
26ac0430 398
b5d712b5 399 buf1 = (char *)xcalloc(1, 8192);
400 strcpy(buf1, params->prog);
401 prog = strtok(buf1, w_space);
402
403 if ((str = strrchr(prog, '/')))
404 prog = ++str;
405
406 if ((str = strrchr(prog, '\\')))
407 prog = ++str;
408
409 prog = xstrdup(prog);
410
411 if (type == IPC_TCP_SOCKET) {
bf8fe701 412 debugs(54, 3, "ipcCreate: calling accept on FD " << crfd);
b5d712b5 413
414 if ((fd = accept(crfd, NULL, NULL)) < 0) {
fa84c01d 415 debugs(54, DBG_CRITICAL, "ipcCreate: FD " << crfd << " accept: " << xstrerror());
b5d712b5 416 goto cleanup;
417 }
418
bf8fe701 419 debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd);
b5d712b5 420 comm_close(crfd);
421 snprintf(buf1, 8191, "%s CHILD socket", prog);
422 fd_open(fd, FD_SOCKET, buf1);
423 fd_table[fd].flags.ipc = 1;
424 cwfd = crfd = fd;
425 } else if (type == IPC_UDP_SOCKET) {
cc192b50 426 if (comm_connect_addr(crfd, params->PS) == COMM_ERROR)
b5d712b5 427 goto cleanup;
428 }
429
430 x = send(cwfd, (const void *)hello_string, strlen(hello_string) + 1, 0);
431
432 if (x < 0) {
fa84c01d
FC
433 debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerror());
434 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
b5d712b5 435 goto cleanup;
436 }
437
438 PutEnvironment();
439 memset(buf1, '\0', sizeof(buf1));
440 x = recv(crfd, (void *)buf1, 8191, 0);
441
442 if (x < 0) {
fa84c01d
FC
443 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: OK read test failed");
444 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 445 goto cleanup;
446 } else if (strcmp(buf1, ok_string)) {
fa84c01d
FC
447 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: OK read test failed");
448 debugs(54, DBG_CRITICAL, "--> read returned " << x);
449 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
b5d712b5 450 goto cleanup;
451 }
452
453 /* assign file descriptors to child process */
454 if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
fa84c01d 455 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: pipe: " << xstrerror());
b5d712b5 456 ipcSend(cwfd, err_string, strlen(err_string));
457 goto cleanup;
458 }
459
460 if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
fa84c01d 461 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: pipe: " << xstrerror());
b5d712b5 462 ipcSend(cwfd, err_string, strlen(err_string));
463 goto cleanup;
464 }
465
466 if (type == IPC_UDP_SOCKET) {
467 snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L);
cc192b50 468 crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, buf1);
b5d712b5 469
470 if (crfd_ipc < 0) {
fa84c01d 471 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: Failed to create child FD for " << prog << ".");
b5d712b5 472 ipcSend(cwfd, err_string, strlen(err_string));
473 goto cleanup;
474 }
475
476 snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L);
cc192b50 477 prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, buf1);
b5d712b5 478
479 if (pwfd_ipc < 0) {
fa84c01d 480 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: Failed to create server FD for " << prog << ".");
b5d712b5 481 ipcSend(cwfd, err_string, strlen(err_string));
482 goto cleanup;
483 }
484
cc192b50 485 PS_ipc.InitAddrInfo(aiPS_ipc);
b5d712b5 486
cc192b50 487 if (getsockname(pwfd_ipc, aiPS_ipc->ai_addr, &(aiPS_ipc->ai_addrlen)) < 0) {
fa84c01d 488 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
b5d712b5 489 ipcSend(cwfd, err_string, strlen(err_string));
490 goto cleanup;
491 }
492
cc192b50 493 PS_ipc = *aiPS_ipc;
494
495 debugs(54, 3, "ipcCreate: FD " << pwfd_ipc << " sockaddr " << PS_ipc);
bf8fe701 496
cc192b50 497 CS_ipc.InitAddrInfo(aiCS_ipc);
b5d712b5 498
cc192b50 499 if (getsockname(crfd_ipc, aiCS_ipc->ai_addr, &(aiCS_ipc->ai_addrlen)) < 0) {
fa84c01d 500 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
b5d712b5 501 ipcSend(cwfd, err_string, strlen(err_string));
502 goto cleanup;
503 }
504
cc192b50 505 CS_ipc = *aiCS_ipc;
506
507 debugs(54, 3, "ipcCreate: FD " << crfd_ipc << " sockaddr " << CS_ipc);
b5d712b5 508
cc192b50 509 if (comm_connect_addr(pwfd_ipc, CS_ipc) == COMM_ERROR) {
b5d712b5 510 ipcSend(cwfd, err_string, strlen(err_string));
511 goto cleanup;
512 }
513
514 fd = crfd;
515
cc192b50 516 if (comm_connect_addr(crfd_ipc, PS_ipc) == COMM_ERROR) {
b5d712b5 517 ipcSend(cwfd, err_string, strlen(err_string));
518 goto cleanup;
519 }
520 } /* IPC_UDP_SOCKET */
521
522 t1 = dup(0);
523
524 t2 = dup(1);
525
526 t3 = dup(2);
527
528 dup2(c2p[0], 0);
529
530 dup2(p2c[1], 1);
531
532 dup2(fileno(debug_log), 2);
533
534 close(c2p[0]);
535
536 close(p2c[1]);
537
538 commUnsetNonBlocking(fd);
539
540 memset(&si, 0, sizeof(STARTUPINFO));
541
542 si.cb = sizeof(STARTUPINFO);
543
544 si.hStdInput = (HANDLE) _get_osfhandle(0);
545
546 si.hStdOutput = (HANDLE) _get_osfhandle(1);
547
548 si.hStdError = (HANDLE) _get_osfhandle(2);
549
550 si.dwFlags = STARTF_USESTDHANDLES;
551
552 /* Make sure all other valid handles are not inerithable */
95dc7ff4 553 for (x = 3; x < Squid_MaxFD; ++x) {
b5d712b5 554 if ((F = _get_osfhandle(x)) == -1)
555 continue;
556
557 SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0);
558 }
559
560 *buf1 = '\0';
561 strcpy(buf1 + 4096, params->prog);
562 str = strtok(buf1 + 4096, w_space);
563
564 do {
565 strcat(buf1, str);
566 strcat(buf1, " ");
567 } while ((str = strtok(NULL, w_space)));
568
569 x = 1;
570
571 while (args[x]) {
f412b2d6
FC
572 strcat(buf1, args[x]);
573 ++x;
b5d712b5 574 strcat(buf1, " ");
575 }
576
577 if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW,
578 NULL, NULL, &si, &pi)) {
579 pid = pi.dwProcessId;
580 hProcess = pi.hProcess;
581 } else {
582 pid = -1;
979f3ae6 583 x = GetLastError();
b5d712b5 584 }
585
586 dup2(t1, 0);
587 dup2(t2, 1);
588 dup2(t3, 2);
589 close(t1);
590 close(t2);
591 close(t3);
592
593 if (pid == -1) {
594 errno = x;
fa84c01d 595 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << params->prog << ": " << xstrerror());
bf8fe701 596
b5d712b5 597 ipcSend(cwfd, err_string, strlen(err_string));
598 goto cleanup;
599 }
600
601 if (type == IPC_UDP_SOCKET) {
602 WSAPROTOCOL_INFO wpi;
603
604 memset(&wpi, 0, sizeof(wpi));
605
606 if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
fa84c01d 607 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: WSADuplicateSocket: " << xstrerror());
bf8fe701 608
b5d712b5 609 ipcSend(cwfd, err_string, strlen(err_string));
610 goto cleanup;
611 }
612
613 x = write(c2p[1], (const char *) &wpi, sizeof(wpi));
614
615 if (x < (ssize_t)sizeof(wpi)) {
fa84c01d
FC
616 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: write FD " << c2p[1] << ": " << xstrerror());
617 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 618
b5d712b5 619 ipcSend(cwfd, err_string, strlen(err_string));
620 goto cleanup;
621 }
622
623 x = read(p2c[0], buf1, 8192);
624
625 if (x < 0) {
fa84c01d
FC
626 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: read FD " << p2c[0] << ": " << xstrerror());
627 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 628
b5d712b5 629 ipcSend(cwfd, err_string, strlen(err_string));
630 goto cleanup;
631 } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
fa84c01d
FC
632 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
633 debugs(54, DBG_CRITICAL, "--> read returned " << x);
b5d712b5 634 buf1[x] = '\0';
fa84c01d 635 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(buf1) << "'");
b5d712b5 636 ipcSend(cwfd, err_string, strlen(err_string));
637 goto cleanup;
638 }
639
640 x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
641
642 if (x < (ssize_t)sizeof(PS_ipc)) {
fa84c01d
FC
643 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: write FD " << c2p[1] << ": " << xstrerror());
644 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 645
b5d712b5 646 ipcSend(cwfd, err_string, strlen(err_string));
647 goto cleanup;
648 }
649
650 x = read(p2c[0], buf1, 8192);
651
652 if (x < 0) {
fa84c01d
FC
653 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: read FD " << p2c[0] << ": " << xstrerror());
654 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 655
b5d712b5 656 ipcSend(cwfd, err_string, strlen(err_string));
657 goto cleanup;
658 } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
fa84c01d
FC
659 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
660 debugs(54, DBG_CRITICAL, "--> read returned " << x);
b5d712b5 661 buf1[x] = '\0';
fa84c01d 662 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(buf1) << "'");
b5d712b5 663 ipcSend(cwfd, err_string, strlen(err_string));
664 goto cleanup;
665 }
666
667 x = send(pwfd_ipc, (const void *)ok_string, strlen(ok_string), 0);
668 x = recv(prfd_ipc, (void *)(buf1 + 200), 8191 - 200, 0);
669 assert((size_t) x == strlen(ok_string)
670 && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
671 } /* IPC_UDP_SOCKET */
672
673 snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid);
674
675 fd_note(fd, buf1);
676
677 if (prfd_ipc != -1) {
678 snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid);
679 fd_note(crfd_ipc, buf1);
680 snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid);
681 fd_note(prfd_ipc, buf1);
682 }
683
684 /* else { IPC_TCP_SOCKET */
685 /* commSetNoLinger(fd); */
686 /* } */
687 thread_params.prog = prog;
688
689 thread_params.send_fd = cwfd;
690
691 thread_params.pid = pid;
692
693 if ((thread_params.type = type) == IPC_TCP_SOCKET)
694 thread_params.rfd = p2c[0];
695 else
696 thread_params.rfd = prfd_ipc;
697
6ca34f6f 698 thread = (HANDLE)_beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL);
b5d712b5 699
700 if (!thread) {
fa84c01d 701 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: _beginthreadex: " << xstrerror());
b5d712b5 702 ipcSend(cwfd, err_string, strlen(err_string));
703 goto cleanup;
704 }
705
706 snprintf(buf1, 8191, "%ld\n", (long int) pid);
707
708 if (-1 == ipcSend(cwfd, buf1, strlen(buf1)))
709 goto cleanup;
710
26ac0430 711 debugs(54, 2, "ipc(" << prog << "," << pid << "): started successfully");
b5d712b5 712
713 /* cycle */
714 for (;;) {
715 x = recv(crfd, (void *)buf1, 8192, 0);
716
717 if (x <= 0) {
bf8fe701 718 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes received from parent. Exiting...");
b5d712b5 719 break;
720 }
721
722 buf1[x] = '\0';
723
724 if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
bf8fe701 725 debugs(54, 3, "ipc(" << prog << "," << pid << "): request for shutdown received from parent. Exiting...");
726
b5d712b5 727 TerminateProcess(hProcess, 0);
728 break;
729 }
730
bf8fe701 731 debugs(54, 5, "ipc(" << prog << "," << pid << "): received from parent: " << rfc1738_escape_unescaped(buf1));
b5d712b5 732
733 if (type == IPC_TCP_SOCKET)
734 x = write(c2p[1], buf1, x);
735 else
736 x = send(pwfd_ipc, (const void *)buf1, x, 0);
737
738 if (x <= 0) {
bf8fe701 739 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes written to " << prog << ". Exiting...");
740
b5d712b5 741 break;
742 }
743 }
744
745 retval = 0;
746
747cleanup:
748
749 if (c2p[1] != -1)
750 close(c2p[1]);
751
752 if (fd_table[crfd].flags.open)
753 ipcCloseAllFD(-1, -1, crfd, cwfd);
754
755 if (prfd_ipc != -1) {
756 send(crfd_ipc, (const void *)shutdown_string, strlen(shutdown_string), 0);
757 shutdown(crfd_ipc, SD_BOTH);
758 shutdown(prfd_ipc, SD_BOTH);
759 }
760
761 ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc);
762
763 if (hProcess && WAIT_OBJECT_0 !=
764 WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {
765
766 getCurrentTime();
fa84c01d 767 debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: " << prog <<
bf8fe701 768 " didn't exit in " << (type == IPC_UDP_SOCKET ? 12 : 5) << " seconds.");
769
b5d712b5 770 }
771
772 if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
773 getCurrentTime();
fa84c01d 774 debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: ipc_thread_2 didn't exit in 3 seconds.");
bf8fe701 775
b5d712b5 776 }
777
778 getCurrentTime();
779
780 if (!retval)
bf8fe701 781 debugs(54, 2, "ipc(" << prog << "," << pid << "): normal exit");
b5d712b5 782
783 if (buf1)
784 xfree(buf1);
785
786 if (prog)
787 xfree(prog);
788
789 if (thread)
790 CloseHandle(thread);
791
792 if (hProcess)
793 CloseHandle(hProcess);
794
795 if (p2c[0] != -1)
796 close(p2c[0]);
797
798 return retval;
799}
800
801static unsigned int __stdcall
802ipc_thread_2(void *in_params)
803{
804 int x;
805
806 struct thread_params *params = (struct thread_params *) in_params;
807 int type = params->type;
808 int rfd = params->rfd;
809 int send_fd = params->send_fd;
810 char *prog = xstrdup(params->prog);
811 pid_t pid = params->pid;
812 char *buf2 = (char *)xcalloc(1, 8192);
813
814 for (;;) {
815 if (type == IPC_TCP_SOCKET)
816 x = read(rfd, buf2, 8192);
817 else
818 x = recv(rfd, (void *)buf2, 8192, 0);
819
820 if ((x <= 0 && type == IPC_TCP_SOCKET) ||
821 (x < 0 && type == IPC_UDP_SOCKET)) {
bf8fe701 822 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes read from " << prog << ". Exiting...");
823
b5d712b5 824 break;
825 }
826
827 buf2[x] = '\0';
828
829 if (type == IPC_UDP_SOCKET && !strcmp(buf2, shutdown_string)) {
bf8fe701 830 debugs(54, 3, "ipc(" << prog << "," << pid << "): request for shutdown received. Exiting...");
831
b5d712b5 832 break;
833 }
834
835 if (x >= 2) {
836 if ((buf2[x - 1] == '\n') && (buf2[x - 2] == '\r')) {
837 buf2[x - 2] = '\n';
838 buf2[x - 1] = '\0';
5e263176 839 --x;
b5d712b5 840 }
841 }
842
bf8fe701 843 debugs(54, 5, "ipc(" << prog << "," << pid << "): received from child : " << rfc1738_escape_unescaped(buf2));
844
b5d712b5 845 x = send(send_fd, (const void *)buf2, x, 0);
846
847 if ((x <= 0 && type == IPC_TCP_SOCKET) ||
848 (x < 0 && type == IPC_UDP_SOCKET)) {
bf8fe701 849 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes sent to parent. Exiting...");
850
b5d712b5 851 break;
852 }
853 }
854
855 xfree(prog);
856 xfree(buf2);
857 return 0;
858}