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