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