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