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

 

Introduction

Documentation

Support

Miscellaneous