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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors