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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors