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