ipc.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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 Interprocess Communication */
10 
11 #include "squid.h"
12 #include "comm/Connection.h"
13 #include "fd.h"
14 #include "fde.h"
15 #include "globals.h"
16 #include "ip/Address.h"
17 #include "ipc/Kid.h"
18 #include "rfc1738.h"
19 #include "SquidConfig.h"
20 #include "SquidIpc.h"
21 #include "tools.h"
22 
23 static const char *hello_string = "hi there\n";
24 #ifndef HELLO_BUF_SZ
25 #define HELLO_BUF_SZ 32
26 #endif
27 static char hello_buf[HELLO_BUF_SZ];
28 
29 static int
30 ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
31 {
32  if (prfd >= 0)
33  comm_close(prfd);
34 
35  if (prfd != pwfd)
36  if (pwfd >= 0)
37  comm_close(pwfd);
38 
39  if (crfd >= 0)
40  comm_close(crfd);
41 
42  if (crfd != cwfd)
43  if (cwfd >= 0)
44  comm_close(cwfd);
45 
46  return -1;
47 }
48 
49 static void
51 {
52 #if HAVE_PUTENV
53  char *env_str;
54  int tmp_s;
55  env_str = (char *)xcalloc((tmp_s = strlen(Debug::debugOptions) + 32), 1);
56  snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Debug::debugOptions);
57  putenv(env_str);
58 #endif
59 }
60 
61 pid_t
62 ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc)
63 {
64  pid_t pid;
65  Ip::Address ChS;
66  Ip::Address PaS;
67  struct addrinfo *AI = NULL;
68  int crfd = -1;
69  int prfd = -1;
70  int cwfd = -1;
71  int pwfd = -1;
72  int fd;
73  int t1, t2, t3;
74  int x;
75  int xerrno;
76 
77 #if USE_POLL && _SQUID_OSF_
78  assert(type != IPC_FIFO);
79 #endif
80 
81  if (rfd)
82  *rfd = -1;
83 
84  if (wfd)
85  *wfd = -1;
86 
87  if (hIpc)
88  *hIpc = NULL;
89 
90 // NP: no wrapping around d and c usage since we *want* code expansion
91 #define IPC_CHECK_FAIL(f,d,c) \
92  if ((f) < 0) { \
93  debugs(54, DBG_CRITICAL, "ERROR: Failed to create helper " d " FD: " << c); \
94  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); \
95  } else void(0)
96 
97  if (type == IPC_TCP_SOCKET) {
98  crfd = cwfd = comm_open(SOCK_STREAM,
99  0,
100  local_addr,
102  name);
103  prfd = pwfd = comm_open(SOCK_STREAM,
104  0, /* protocol */
105  local_addr,
106  0, /* blocking */
107  name);
108  IPC_CHECK_FAIL(crfd, "child read", "TCP " << local_addr);
109  IPC_CHECK_FAIL(prfd, "parent read", "TCP " << local_addr);
110  } else if (type == IPC_UDP_SOCKET) {
111  crfd = cwfd = comm_open(SOCK_DGRAM,
112  0,
113  local_addr,
115  name);
116  prfd = pwfd = comm_open(SOCK_DGRAM,
117  0,
118  local_addr,
119  0,
120  name);
121  IPC_CHECK_FAIL(crfd, "child read", "UDP" << local_addr);
122  IPC_CHECK_FAIL(prfd, "parent read", "UDP" << local_addr);
123  } else if (type == IPC_FIFO) {
124  int p2c[2];
125  int c2p[2];
126 
127  if (pipe(p2c) < 0) {
128  xerrno = errno;
129  debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerr(xerrno));
130  return -1; // maybe ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
131  }
132  fd_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
133  fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write");
134 
135  if (pipe(c2p) < 0) {
136  xerrno = errno;
137  debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerr(xerrno));
138  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
139  }
140  fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read");
141  fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
142 
143  IPC_CHECK_FAIL(crfd, "child read", "FIFO pipe");
144  IPC_CHECK_FAIL(prfd, "parent read", "FIFO pipe");
145 
146 #if HAVE_SOCKETPAIR && defined(AF_UNIX)
147 
148  } else if (type == IPC_UNIX_STREAM) {
149  int fds[2];
150  int buflen = 32768;
151 
152  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
153  xerrno = errno;
154  debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerr(xerrno));
155  return -1;
156  }
157 
158  errno = 0;
159  if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen)) == -1) {
160  xerrno = errno;
161  debugs(54, DBG_IMPORTANT, "setsockopt failed: " << xstrerr(xerrno));
162  errno = 0;
163  }
164  if (setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen)) == -1) {
165  xerrno = errno;
166  debugs(54, DBG_IMPORTANT, "setsockopt failed: " << xstrerr(xerrno));
167  errno = 0;
168  }
169  if (setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen)) == -1) {
170  xerrno = errno;
171  debugs(54, DBG_IMPORTANT, "setsockopt failed: " << xstrerr(xerrno));
172  errno = 0;
173  }
174  if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen)) == -1) {
175  xerrno = errno;
176  debugs(54, DBG_IMPORTANT, "setsockopt failed: " << xstrerr(xerrno));
177  errno = 0;
178  }
179  fd_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX STREAM Parent");
180  fd_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX STREAM Parent");
181  IPC_CHECK_FAIL(crfd, "child read", "UDS socket");
182  IPC_CHECK_FAIL(prfd, "parent read", "UDS socket");
183 
184  } else if (type == IPC_UNIX_DGRAM) {
185  int fds[2];
186 
187  if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
188  xerrno = errno;
189  debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerr(xerrno));
190  return -1;
191  }
192 
193  fd_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX DGRAM Parent");
194  fd_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX DGRAM Parent");
195 
196  IPC_CHECK_FAIL(crfd, "child read", "UDS datagram");
197  IPC_CHECK_FAIL(prfd, "parent read", "UDS datagram");
198 #endif
199 
200  } else {
201  assert(IPC_NONE);
202  }
203 
204  debugs(54, 3, "ipcCreate: prfd FD " << prfd);
205  debugs(54, 3, "ipcCreate: pwfd FD " << pwfd);
206  debugs(54, 3, "ipcCreate: crfd FD " << crfd);
207  debugs(54, 3, "ipcCreate: cwfd FD " << cwfd);
208 
209  if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
211 
212  if (getsockname(pwfd, AI->ai_addr, &AI->ai_addrlen) < 0) {
213  xerrno = errno;
215  debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerr(xerrno));
216  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
217  }
218 
219  PaS = *AI;
220 
221  debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << PaS);
222 
224 
226 
227  if (getsockname(crfd, AI->ai_addr, &AI->ai_addrlen) < 0) {
228  xerrno = errno;
230  debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerr(xerrno));
231  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
232  }
233 
234  ChS = *AI;
235 
237 
238  debugs(54, 3, "ipcCreate: FD " << crfd << " sockaddr " << ChS );
239 
240  }
241 
242  if (type == IPC_TCP_SOCKET) {
243  if (listen(crfd, 1) < 0) {
244  xerrno = errno;
245  debugs(54, DBG_IMPORTANT, "ipcCreate: listen FD " << crfd << ": " << xstrerr(xerrno));
246  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
247  }
248 
249  debugs(54, 3, "ipcCreate: FD " << crfd << " listening...");
250  }
251 
252  /* flush or else we get dup data if unbuffered_logs is set */
253  logsFlush();
254 
255  if ((pid = fork()) < 0) {
256  xerrno = errno;
257  debugs(54, DBG_IMPORTANT, "ipcCreate: fork: " << xstrerr(xerrno));
258  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
259  }
260 
261  if (pid > 0) { /* parent */
262  /* close shared socket with child */
263  comm_close(crfd);
264 
265  if (cwfd != crfd)
266  comm_close(cwfd);
267 
268  cwfd = crfd = -1;
269 
270  if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
271  if (comm_connect_addr(pwfd, ChS) == Comm::COMM_ERROR)
272  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
273  }
274 
275  if (type == IPC_UDP_SOCKET)
276  x = comm_udp_recv(prfd, hello_buf, sizeof(hello_buf)-1, 0);
277  else
278  x = read(prfd, hello_buf, sizeof(hello_buf)-1);
279  xerrno = errno;
280  if (x >= 0)
281  hello_buf[x] = '\0';
282 
283  if (x < 0) {
284  debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
285  debugs(54, DBG_CRITICAL, "--> read: " << xstrerr(xerrno));
286  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
287  } else if (strcmp(hello_buf, hello_string)) {
288  debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
289  debugs(54, DBG_CRITICAL, "--> read returned " << x);
290  debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
291  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
292  }
293 
294  commUnsetFdTimeout(prfd);
295  commSetNonBlocking(prfd);
296  commSetNonBlocking(pwfd);
297 
298  if (rfd)
299  *rfd = prfd;
300 
301  if (wfd)
302  *wfd = pwfd;
303 
304  fd_table[prfd].flags.ipc = 1;
305 
306  fd_table[pwfd].flags.ipc = 1;
307 
308  if (Config.sleep_after_fork) {
309  /* XXX emulation of usleep() */
310 
311  struct timeval sl;
312  sl.tv_sec = Config.sleep_after_fork / 1000000;
313  sl.tv_usec = Config.sleep_after_fork % 1000000;
314  select(0, NULL, NULL, NULL, &sl);
315  }
316 
317  return pid;
318  }
319 
320  /* child */
322  no_suid(); /* give up extra priviliges */
323 
324  /* close shared socket with parent */
325  close(prfd);
326 
327  if (pwfd != prfd)
328  close(pwfd);
329 
330  pwfd = prfd = -1;
331 
332  if (type == IPC_TCP_SOCKET) {
333  debugs(54, 3, "ipcCreate: calling accept on FD " << crfd);
334 
335  if ((fd = accept(crfd, NULL, NULL)) < 0) {
336  xerrno = errno;
337  debugs(54, DBG_CRITICAL, "ipcCreate: FD " << crfd << " accept: " << xstrerr(xerrno));
338  _exit(1);
339  }
340 
341  debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd);
342  close(crfd);
343  cwfd = crfd = fd;
344  } else if (type == IPC_UDP_SOCKET) {
345  if (comm_connect_addr(crfd, PaS) == Comm::COMM_ERROR)
346  return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
347  }
348 
349  if (type == IPC_UDP_SOCKET) {
350  x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0);
351 
352  if (x < 0) {
353  xerrno = errno;
354  debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerr(xerrno));
355  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
356  _exit(1);
357  }
358  } else {
359  if (write(cwfd, hello_string, strlen(hello_string) + 1) < 0) {
360  xerrno = errno;
361  debugs(54, DBG_CRITICAL, "write FD " << cwfd << ": " << xstrerr(xerrno));
362  debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
363  _exit(1);
364  }
365  }
366 
367  PutEnvironment();
368  /*
369  * This double-dup stuff avoids problems when one of
370  * crfd, cwfd, or debug_log are in the rage 0-2.
371  */
372 
373  do {
374  /* First make sure 0-2 is occupied by something. Gets cleaned up later */
375  x = dup(crfd);
376  assert(x > -1);
377  } while (x < 3 && x > -1);
378 
379  close(x);
380 
381  t1 = dup(crfd);
382 
383  t2 = dup(cwfd);
384 
385  t3 = dup(fileno(debug_log));
386 
387  assert(t1 > 2 && t2 > 2 && t3 > 2);
388 
389  close(crfd);
390 
391  close(cwfd);
392 
393  close(fileno(debug_log));
394 
395  dup2(t1, 0);
396 
397  dup2(t2, 1);
398 
399  dup2(t3, 2);
400 
401  close(t1);
402 
403  close(t2);
404 
405  close(t3);
406 
407  /* Make sure all other filedescriptors are closed */
408  for (x = 3; x < SQUID_MAXFD; ++x)
409  close(x);
410 
411 #if HAVE_SETSID
412  if (opt_no_daemon)
413  setsid();
414 #endif
415 
416  execvp(prog, (char *const *) args);
417  xerrno = errno;
418 
419  ResyncDebugLog(fdopen(2, "a+"));
420 
421  debugs(54, DBG_CRITICAL, "ipcCreate: " << prog << ": " << xstrerr(xerrno));
422 
423  _exit(1);
424 
425  return 0;
426 }
427 
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Debug.h:106
#define fd_table
Definition: fde.h:157
int comm_udp_recv(int fd, void *buf, size_t len, int flags)
Definition: comm.cc:134
#define assert(EX)
Definition: assert.h:17
general-purpose helper child
Definition: Kid.h:103
#define IPC_UNIX_DGRAM
Definition: defines.h:150
int comm_connect_addr(int sock, const Ip::Address &address)
Definition: comm.cc:591
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:694
int type
Definition: errorpage.cc:79
#define xcalloc
Definition: membanger.c:57
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
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.cc:62
void fd_open(int fd, unsigned int type, const char *desc)
Definition: fd.cc:187
#define rfc1738_escape(x)
Definition: rfc1738.h:52
#define IPC_UNIX_STREAM
Definition: defines.h:149
#define DBG_CRITICAL
Definition: Debug.h:44
static void * hIpc
Definition: IcmpSquid.cc:34
#define IPC_CHECK_FAIL(f, d, c)
const char * xstrerr(int error)
Definition: xstrerror.cc:83
ssize_t comm_udp_send(int s, const void *buf, size_t len, int flags)
Definition: comm.cc:141
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define DBG_IMPORTANT
Definition: Debug.h:45
static char * debugOptions
Definition: Debug.h:78
#define COMM_NOCLOEXEC
Definition: Connection.h:45
static void InitAddr(struct addrinfo *&ai)
Definition: Address.cc:676
#define IPC_UDP_SOCKET
Definition: defines.h:147
int commSetNonBlocking(int fd)
Definition: comm.cc:1076
#define IPC_TCP_SOCKET
Definition: defines.h:146
int sleep_after_fork
Definition: SquidConfig.h:504
static void PutEnvironment()
Definition: ipc.cc:50
static pid_t pid
Definition: IcmpSquid.cc:35
bool SIGHDLR int STUB void logsFlush(void) STUB void debugObj(int
static const char * hello_string
Definition: ipc.cc:23
Definition: enums.h:17
socklen_t ai_addrlen
void ResyncDebugLog(FILE *newFile)
a hack for low-level file descriptor manipulations in ipcCreate()
Definition: debug.cc:88
struct sockaddr * ai_addr
int TheProcessKind
ProcessKind for the current process.
Definition: Kid.cc:21
static int ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
Definition: ipc.cc:30
void commUnsetFdTimeout(int fd)
clear a timeout handler by FD number
Definition: comm.cc:539
#define IPC_FIFO
Definition: defines.h:148
int opt_no_daemon
class SquidConfig Config
Definition: SquidConfig.cc:12
#define comm_close(x)
Definition: comm.h:28
#define NULL
Definition: types.h:166
void no_suid(void)
Definition: tools.cc:601
#define HELLO_BUF_SZ
Definition: ipc.cc:25
static char hello_buf[HELLO_BUF_SZ]
Definition: ipc.cc:27

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors