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  (void)setenv("SQUID_DEBUG", Debug::debugOptions, 1);
88 }
89 
90 pid_t
91 ipcCreate(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 {
154  assert(IPC_NONE);
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 
181  Ip::Address::InitAddr(aiPS);
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));
186  Ip::Address::FreeAddr(aiPS);
187  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
188  }
189 
190  tmp_addr = *aiPS;
191  Ip::Address::FreeAddr(aiPS);
192 
193  debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << tmp_addr );
194 
195  Ip::Address::InitAddr(aiCS);
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));
200  Ip::Address::FreeAddr(aiCS);
201  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
202  }
203 
204  tmp_addr.setEmpty();
205  tmp_addr = *aiCS;
206  Ip::Address::FreeAddr(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 
329 static int
330 ipcSend(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 
343 static unsigned int __stdcall
344 ipc_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);
399  comm_close(crfd);
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 
418  PutEnvironment();
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));
438  ipcSend(cwfd, err_string, strlen(err_string));
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));
445  ipcSend(cwfd, err_string, strlen(err_string));
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 << ".");
455  ipcSend(cwfd, err_string, strlen(err_string));
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 << ".");
464  ipcSend(cwfd, err_string, strlen(err_string));
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));
473  ipcSend(cwfd, err_string, strlen(err_string));
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));
488  ipcSend(cwfd, err_string, strlen(err_string));
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) {
499  ipcSend(cwfd, err_string, strlen(err_string));
500  goto cleanup;
501  }
502 
503  fd = crfd;
504 
505  if (comm_connect_addr(crfd_ipc, PS_ipc) == Comm::COMM_ERROR) {
506  ipcSend(cwfd, err_string, strlen(err_string));
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 
586  ipcSend(cwfd, err_string, strlen(err_string));
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));
598  ipcSend(cwfd, err_string, strlen(err_string));
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");
608  ipcSend(cwfd, err_string, strlen(err_string));
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");
618  ipcSend(cwfd, err_string, strlen(err_string));
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) << "'");
625  ipcSend(cwfd, err_string, strlen(err_string));
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");
635  ipcSend(cwfd, err_string, strlen(err_string));
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");
645  ipcSend(cwfd, err_string, strlen(err_string));
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) << "'");
652  ipcSend(cwfd, err_string, strlen(err_string));
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));
692  ipcSend(cwfd, err_string, strlen(err_string));
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 
737 cleanup:
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 
756  getCurrentTime();
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)) {
763  getCurrentTime();
764  debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: ipc_thread_2 didn't exit in 3 seconds.");
765 
766  }
767 
768  getCurrentTime();
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 
788 static unsigned int __stdcall
789 ipc_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 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:789
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:344
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:3914
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:330
#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:91
@ 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