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  } else {
577  pid = -1;
578  x = GetLastError();
579  }
580 
581  dup2(t1, 0);
582  dup2(t2, 1);
583  dup2(t3, 2);
584  close(t1);
585  close(t2);
586  close(t3);
587 
588  if (pid == -1) {
589  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << params->prog << ": " << xstrerr(x));
590 
591  ipcSend(cwfd, err_string, strlen(err_string));
592  goto cleanup;
593  }
594 
595  if (type == IPC_UDP_SOCKET) {
596  WSAPROTOCOL_INFO wpi;
597 
598  memset(&wpi, 0, sizeof(wpi));
599 
600  if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
601  int xerrno = errno;
602  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: WSADuplicateSocket: " << xstrerr(xerrno));
603  ipcSend(cwfd, err_string, strlen(err_string));
604  goto cleanup;
605  }
606 
607  x = xwrite(c2p[1], (const char *) &wpi, sizeof(wpi));
608 
609  if (x < (ssize_t)sizeof(wpi)) {
610  int xerrno = errno;
611  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: write FD " << c2p[1] << ": " << xstrerr(xerrno));
612  debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: " << prog << ": socket exchange failed");
613  ipcSend(cwfd, err_string, strlen(err_string));
614  goto cleanup;
615  }
616 
617  x = xread(p2c[0], buf1, bufSz-1);
618 
619  if (x < 0) {
620  int xerrno = errno;
621  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: read FD " << p2c[0] << ": " << xstrerr(xerrno));
622  debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: " << prog << ": socket exchange failed");
623  ipcSend(cwfd, err_string, strlen(err_string));
624  goto cleanup;
625  } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
626  debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: " << prog << ": socket exchange failed");
627  debugs(54, DBG_CRITICAL, "--> read returned " << x);
628  buf1[x] = '\0';
629  debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(buf1) << "'");
630  ipcSend(cwfd, err_string, strlen(err_string));
631  goto cleanup;
632  }
633 
634  x = xwrite(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
635 
636  if (x < (ssize_t)sizeof(PS_ipc)) {
637  int xerrno = errno;
638  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: write FD " << c2p[1] << ": " << xstrerr(xerrno));
639  debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: " << prog << ": socket exchange failed");
640  ipcSend(cwfd, err_string, strlen(err_string));
641  goto cleanup;
642  }
643 
644  x = xread(p2c[0], buf1, bufSz-1);
645 
646  if (x < 0) {
647  int xerrno = errno;
648  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: read FD " << p2c[0] << ": " << xstrerr(xerrno));
649  debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: " << prog << ": socket exchange failed");
650  ipcSend(cwfd, err_string, strlen(err_string));
651  goto cleanup;
652  } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
653  debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: " << prog << ": socket exchange failed");
654  debugs(54, DBG_CRITICAL, "--> read returned " << x);
655  buf1[x] = '\0';
656  debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(buf1) << "'");
657  ipcSend(cwfd, err_string, strlen(err_string));
658  goto cleanup;
659  }
660 
661  x = xsend(pwfd_ipc, ok_string, strlen(ok_string), 0);
662  x = xrecv(prfd_ipc, (void *)(buf1 + 200), bufSz -1 - 200, 0);
663  assert((size_t) x == strlen(ok_string)
664  && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
665  } /* IPC_UDP_SOCKET */
666 
667  snprintf(buf1, bufSz-1, "%s(%ld) CHILD socket", prog, (long int) pid);
668 
669  fd_note(fd, buf1);
670 
671  if (prfd_ipc != -1) {
672  snprintf(buf1, bufSz-1, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid);
673  fd_note(crfd_ipc, buf1);
674  snprintf(buf1, bufSz-1, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid);
675  fd_note(prfd_ipc, buf1);
676  }
677 
678  /* else { IPC_TCP_SOCKET */
679  /* commConfigureLinger(fd, OnOff::off); */
680  /* } */
682 
684 
686 
688  thread_params.rfd = p2c[0];
689  else
690  thread_params.rfd = prfd_ipc;
691 
692  thread = (HANDLE)_beginthreadex(nullptr, 0, ipc_thread_2, &thread_params, 0, nullptr);
693 
694  if (!thread) {
695  int xerrno = errno;
696  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: _beginthreadex: " << xstrerr(xerrno));
697  ipcSend(cwfd, err_string, strlen(err_string));
698  goto cleanup;
699  }
700 
701  snprintf(buf1, bufSz-1, "%ld\n", (long int) pid);
702 
703  if (-1 == ipcSend(cwfd, buf1, strlen(buf1)))
704  goto cleanup;
705 
706  debugs(54, 2, "ipc(" << prog << "," << pid << "): started successfully");
707 
708  /* cycle */
709  for (;;) {
710  x = xrecv(crfd, (void *)buf1, bufSz-1, 0);
711 
712  if (x <= 0) {
713  debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes received from parent. Exiting...");
714  break;
715  }
716 
717  buf1[x] = '\0';
718 
719  if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
720  debugs(54, 3, "ipc(" << prog << "," << pid << "): request for shutdown received from parent. Exiting...");
721 
722  TerminateProcess(hProcess, 0);
723  break;
724  }
725 
726  debugs(54, 5, "ipc(" << prog << "," << pid << "): received from parent: " << rfc1738_escape_unescaped(buf1));
727 
728  if (type == IPC_TCP_SOCKET)
729  x = xwrite(c2p[1], buf1, x);
730  else
731  x = xsend(pwfd_ipc, buf1, x, 0);
732 
733  if (x <= 0) {
734  debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes written to " << prog << ". Exiting...");
735 
736  break;
737  }
738  }
739 
740  retval = 0;
741 
742 cleanup:
743 
744  if (c2p[1] != -1)
745  close(c2p[1]);
746 
747  if (fd_table[crfd].flags.open)
748  ipcCloseAllFD(-1, -1, crfd, cwfd);
749 
750  if (prfd_ipc != -1) {
751  xsend(crfd_ipc, shutdown_string, strlen(shutdown_string), 0);
752  shutdown(crfd_ipc, SD_BOTH);
753  shutdown(prfd_ipc, SD_BOTH);
754  }
755 
756  ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc);
757 
758  if (hProcess && WAIT_OBJECT_0 !=
759  WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {
760 
761  getCurrentTime();
762  debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: " << prog <<
763  " didn't exit in " << (type == IPC_UDP_SOCKET ? 12 : 5) << " seconds.");
764 
765  }
766 
767  if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
768  getCurrentTime();
769  debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: ipc_thread_2 didn't exit in 3 seconds.");
770 
771  }
772 
773  getCurrentTime();
774 
775  if (!retval)
776  debugs(54, 2, "ipc(" << prog << "," << pid << "): normal exit");
777 
778  xfree(buf1);
779  xfree(prog);
780 
781  if (thread)
782  CloseHandle(thread);
783 
784  if (hProcess)
785  CloseHandle(hProcess);
786 
787  if (p2c[0] != -1)
788  close(p2c[0]);
789 
790  return retval;
791 }
792 
793 static unsigned int __stdcall
794 ipc_thread_2(void *in_params)
795 {
796  int x;
797 
798  struct thread_params *params = (struct thread_params *) in_params;
799  int type = params->type;
800  int rfd = params->rfd;
801  int send_fd = params->send_fd;
802  char *prog = xstrdup(params->prog);
803  pid_t pid = params->pid;
804  const size_t bufSz = 8192;
805  char *buf2 = (char *)xcalloc(1, bufSz);
806 
807  for (;;) {
808  if (type == IPC_TCP_SOCKET)
809  x = xread(rfd, buf2, bufSz-1);
810  else
811  x = xrecv(rfd, (void *)buf2, bufSz-1, 0);
812 
813  if ((x <= 0 && type == IPC_TCP_SOCKET) ||
814  (x < 0 && type == IPC_UDP_SOCKET)) {
815  debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes read from " << prog << ". Exiting...");
816 
817  break;
818  }
819 
820  buf2[x] = '\0';
821 
822  if (type == IPC_UDP_SOCKET && !strcmp(buf2, shutdown_string)) {
823  debugs(54, 3, "ipc(" << prog << "," << pid << "): request for shutdown received. Exiting...");
824  break;
825  }
826 
827  if (x >= 2) {
828  if ((buf2[x - 1] == '\n') && (buf2[x - 2] == '\r')) {
829  buf2[x - 2] = '\n';
830  buf2[x - 1] = '\0';
831  --x;
832  }
833  }
834 
835  debugs(54, 5, "ipc(" << prog << "," << pid << "): received from child : " << rfc1738_escape_unescaped(buf2));
836 
837  x = xsend(send_fd, buf2, x, 0);
838 
839  if ((x <= 0 && type == IPC_TCP_SOCKET) ||
840  (x < 0 && type == IPC_UDP_SOCKET)) {
841  debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes sent to parent. Exiting...");
842 
843  break;
844  }
845  }
846 
847  xfree(prog);
848  xfree(buf2);
849  return 0;
850 }
851 
#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:794
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
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
#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:706
#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 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 TRUE
Definition: std-includes.h:55
#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:688
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