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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors