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