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 
33 struct ipc_params {
34  int type;
35  int crfd;
36  int cwfd;
38  struct addrinfo PS;
39  const char *prog;
40  char **args;
41 };
42 
43 struct thread_params {
44  int type;
45  int rfd;
46  int send_fd;
47  const char *prog;
48  pid_t pid;
49 };
50 
51 static unsigned int __stdcall ipc_thread_1(void *params);
52 static unsigned int __stdcall ipc_thread_2(void *params);
53 
54 static const char *ok_string = "OK\n";
55 static const char *err_string = "ERR\n";
56 static const char *shutdown_string = "$shutdown\n";
57 
58 static const char *hello_string = "hi there\n";
59 #define HELLO_BUF_SZ 32
60 static char hello_buf[HELLO_BUF_SZ];
61 
62 static int
63 ipcCloseAllFD(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 
82 static 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 
94 pid_t
95 ipcCreate(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 {
158  assert(IPC_NONE);
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 
185  Ip::Address::InitAddr(aiPS);
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));
190  Ip::Address::FreeAddr(aiPS);
191  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
192  }
193 
194  tmp_addr = *aiPS;
195  Ip::Address::FreeAddr(aiPS);
196 
197  debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << tmp_addr );
198 
199  Ip::Address::InitAddr(aiCS);
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));
204  Ip::Address::FreeAddr(aiCS);
205  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
206  }
207 
208  tmp_addr.setEmpty();
209  tmp_addr = *aiCS;
210  Ip::Address::FreeAddr(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 
333 static int
334 ipcSend(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 
347 static unsigned int __stdcall
348 ipc_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);
403  comm_close(crfd);
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 
422  PutEnvironment();
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));
442  ipcSend(cwfd, err_string, strlen(err_string));
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));
449  ipcSend(cwfd, err_string, strlen(err_string));
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 << ".");
459  ipcSend(cwfd, err_string, strlen(err_string));
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 << ".");
468  ipcSend(cwfd, err_string, strlen(err_string));
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));
477  ipcSend(cwfd, err_string, strlen(err_string));
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));
492  ipcSend(cwfd, err_string, strlen(err_string));
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) {
503  ipcSend(cwfd, err_string, strlen(err_string));
504  goto cleanup;
505  }
506 
507  fd = crfd;
508 
509  if (comm_connect_addr(crfd_ipc, PS_ipc) == Comm::COMM_ERROR) {
510  ipcSend(cwfd, err_string, strlen(err_string));
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(DebugStream()), 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 
589  ipcSend(cwfd, err_string, strlen(err_string));
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));
601  ipcSend(cwfd, err_string, strlen(err_string));
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");
611  ipcSend(cwfd, err_string, strlen(err_string));
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");
621  ipcSend(cwfd, err_string, strlen(err_string));
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) << "'");
628  ipcSend(cwfd, err_string, strlen(err_string));
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");
638  ipcSend(cwfd, err_string, strlen(err_string));
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");
648  ipcSend(cwfd, err_string, strlen(err_string));
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) << "'");
655  ipcSend(cwfd, err_string, strlen(err_string));
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  /* commConfigureLinger(fd, OnOff::off); */
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));
695  ipcSend(cwfd, err_string, strlen(err_string));
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 
740 cleanup:
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 
759  getCurrentTime();
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)) {
766  getCurrentTime();
767  debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: ipc_thread_2 didn't exit in 3 seconds.");
768 
769  }
770 
771  getCurrentTime();
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 
791 static unsigned int __stdcall
792 ipc_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 HELLO_BUF_SZ
Definition: ipc_win32.cc:59
static char * debugOptions
Definition: Stream.h:80
const char * xstrerr(int error)
Definition: xstrerror.cc:83
static void PutEnvironment()
Definition: ipc_win32.cc:83
#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
void fd_note(int fd, const char *s)
Definition: fd.cc:216
void commSetCloseOnExec(int)
Definition: minimal.cc:27
static const char * ok_string
Definition: ipc_win32.cc:54
static unsigned int __stdcall ipc_thread_2(void *params)
Definition: ipc_win32.cc:792
int comm_connect_addr(int sock, const Ip::Address &address)
Definition: comm.cc:629
const char * prog
Definition: ipc_win32.cc:39
@ FD_SOCKET
Definition: enums.h:16
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
#define xstrdup
int commSetNonBlocking(int fd)
Definition: comm.cc:1054
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:348
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:56
void requirePathnameExists(const char *name, const char *path)
Definition: cache_cf.cc:3926
static void * hIpc
Definition: IcmpSquid.cc:33
static pid_t pid
Definition: IcmpSquid.cc:34
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
Definition: comm.cc:257
int commUnsetNonBlocking(int fd)
Definition: comm.cc:1087
char ** args
Definition: ipc_win32.cc:40
#define IPC_FIFO
Definition: defines.h:91
void commUnsetFdTimeout(int fd)
clear a timeout handler by FD number
Definition: comm.cc:579
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:334
#define assert(EX)
Definition: assert.h:17
static const char * err_string
Definition: ipc_win32.cc:55
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
@ 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:243
static int ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
Definition: ipc_win32.cc:63
static const char * hello_string
Definition: ipc_win32.cc:58
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:37
#define TRUE
Definition: std-includes.h:55
#define fd_table
Definition: fde.h:189
#define rfc1738_escape_unescaped(x)
Definition: rfc1738.h:59
#define DBG_IMPORTANT
Definition: Stream.h:38
const char * prog
Definition: ipc_win32.cc:47
struct addrinfo PS
Definition: ipc_win32.cc:38
#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
static char hello_buf[HELLO_BUF_SZ]
Definition: ipc_win32.cc:60

 

Introduction

Documentation

Support

Miscellaneous