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