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