]>
Commit | Line | Data |
---|---|---|
b13bbe1c | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 The Squid Software Foundation and contributors |
e25c139f | 3 | * |
bbc27441 AJ |
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. | |
b13bbe1c | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 54 Interprocess Communication */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
f9b72e0c | 12 | #include "comm/Connection.h" |
c4ad1349 | 13 | #include "fd.h" |
528b2c61 | 14 | #include "fde.h" |
582c2af2 | 15 | #include "globals.h" |
96d89ea0 | 16 | #include "ip/Address.h" |
ed1a1519 | 17 | #include "ipc/Kid.h" |
602d9612 | 18 | #include "rfc1738.h" |
4d5904f7 | 19 | #include "SquidConfig.h" |
96097880 | 20 | #include "SquidIpc.h" |
561076e2 | 21 | #include "tools.h" |
b13bbe1c | 22 | |
23 | static const char *hello_string = "hi there\n"; | |
9ad18ba8 | 24 | #ifndef HELLO_BUF_SZ |
b13bbe1c | 25 | #define HELLO_BUF_SZ 32 |
9ad18ba8 | 26 | #endif |
b13bbe1c | 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) | |
62e76326 | 33 | comm_close(prfd); |
34 | ||
b13bbe1c | 35 | if (prfd != pwfd) |
62e76326 | 36 | if (pwfd >= 0) |
37 | comm_close(pwfd); | |
38 | ||
b13bbe1c | 39 | if (crfd >= 0) |
62e76326 | 40 | comm_close(crfd); |
41 | ||
b13bbe1c | 42 | if (crfd != cwfd) |
62e76326 | 43 | if (cwfd >= 0) |
44 | comm_close(cwfd); | |
45 | ||
b13bbe1c | 46 | return -1; |
47 | } | |
48 | ||
2e4528cc | 49 | static void |
50 | PutEnvironment() | |
51 | { | |
62e76326 | 52 | #if HAVE_PUTENV |
2e4528cc | 53 | char *env_str; |
54 | int tmp_s; | |
62493678 AJ |
55 | env_str = (char *)xcalloc((tmp_s = strlen(Debug::debugOptions) + 32), 1); |
56 | snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Debug::debugOptions); | |
2e4528cc | 57 | putenv(env_str); |
58 | #endif | |
59 | } | |
60 | ||
812dc4b8 | 61 | pid_t |
b7ac5457 | 62 | ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc) |
b13bbe1c | 63 | { |
64 | pid_t pid; | |
b7ac5457 AJ |
65 | Ip::Address ChS; |
66 | Ip::Address PaS; | |
cc192b50 | 67 | struct addrinfo *AI = NULL; |
b13bbe1c | 68 | int crfd = -1; |
69 | int prfd = -1; | |
70 | int cwfd = -1; | |
71 | int pwfd = -1; | |
72 | int fd; | |
86ed3fd2 | 73 | int t1, t2, t3; |
b13bbe1c | 74 | int x; |
75 | ||
8a09e810 | 76 | #if USE_POLL && _SQUID_OSF_ |
91ef94d6 | 77 | assert(type != IPC_FIFO); |
78 | #endif | |
79 | ||
b13bbe1c | 80 | if (rfd) |
62e76326 | 81 | *rfd = -1; |
82 | ||
b13bbe1c | 83 | if (wfd) |
62e76326 | 84 | *wfd = -1; |
85 | ||
812dc4b8 | 86 | if (hIpc) |
87 | *hIpc = NULL; | |
88 | ||
23d23d7a | 89 | // NP: no wrapping around d and c usage since we *want* code expansion |
148feb19 AJ |
90 | #define IPC_CHECK_FAIL(f,d,c) \ |
91 | if ((f) < 0) { \ | |
92 | debugs(54, DBG_CRITICAL, "ERROR: Failed to create helper " d " FD: " << c); \ | |
93 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); \ | |
94 | } else void(0) | |
95 | ||
b13bbe1c | 96 | if (type == IPC_TCP_SOCKET) { |
62e76326 | 97 | crfd = cwfd = comm_open(SOCK_STREAM, |
98 | 0, | |
99 | local_addr, | |
62e76326 | 100 | COMM_NOCLOEXEC, |
101 | name); | |
102 | prfd = pwfd = comm_open(SOCK_STREAM, | |
f53969cc | 103 | 0, /* protocol */ |
62e76326 | 104 | local_addr, |
f53969cc | 105 | 0, /* blocking */ |
62e76326 | 106 | name); |
148feb19 AJ |
107 | IPC_CHECK_FAIL(crfd, "child read", "TCP " << local_addr); |
108 | IPC_CHECK_FAIL(prfd, "parent read", "TCP " << local_addr); | |
b13bbe1c | 109 | } else if (type == IPC_UDP_SOCKET) { |
62e76326 | 110 | crfd = cwfd = comm_open(SOCK_DGRAM, |
111 | 0, | |
112 | local_addr, | |
62e76326 | 113 | COMM_NOCLOEXEC, |
114 | name); | |
115 | prfd = pwfd = comm_open(SOCK_DGRAM, | |
116 | 0, | |
117 | local_addr, | |
118 | 0, | |
62e76326 | 119 | name); |
148feb19 AJ |
120 | IPC_CHECK_FAIL(crfd, "child read", "UDP" << local_addr); |
121 | IPC_CHECK_FAIL(prfd, "parent read", "UDP" << local_addr); | |
b13bbe1c | 122 | } else if (type == IPC_FIFO) { |
62e76326 | 123 | int p2c[2]; |
124 | int c2p[2]; | |
125 | ||
126 | if (pipe(p2c) < 0) { | |
fa84c01d | 127 | debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerror()); |
bd116068 | 128 | return -1; // maybe ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
62e76326 | 129 | } |
bd116068 AJ |
130 | fd_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read"); |
131 | fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write"); | |
62e76326 | 132 | |
133 | if (pipe(c2p) < 0) { | |
fa84c01d | 134 | debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerror()); |
bd116068 | 135 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
62e76326 | 136 | } |
9708d22b | 137 | fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read"); |
138 | fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write"); | |
bd116068 | 139 | |
148feb19 AJ |
140 | IPC_CHECK_FAIL(crfd, "child read", "FIFO pipe"); |
141 | IPC_CHECK_FAIL(prfd, "parent read", "FIFO pipe"); | |
142 | ||
1ccc0d40 | 143 | #if HAVE_SOCKETPAIR && defined(AF_UNIX) |
62e76326 | 144 | |
1ccc0d40 | 145 | } else if (type == IPC_UNIX_STREAM) { |
62e76326 | 146 | int fds[2]; |
147 | int buflen = 32768; | |
148 | ||
149 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { | |
fa84c01d | 150 | debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerror()); |
62e76326 | 151 | return -1; |
152 | } | |
153 | ||
154 | setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen)); | |
155 | setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen)); | |
156 | setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen)); | |
157 | setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen)); | |
9708d22b | 158 | fd_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX STREAM Parent"); |
159 | fd_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX STREAM Parent"); | |
148feb19 AJ |
160 | IPC_CHECK_FAIL(crfd, "child read", "UDS socket"); |
161 | IPC_CHECK_FAIL(prfd, "parent read", "UDS socket"); | |
162 | ||
1ccc0d40 | 163 | } else if (type == IPC_UNIX_DGRAM) { |
62e76326 | 164 | int fds[2]; |
165 | ||
166 | if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) { | |
fa84c01d | 167 | debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerror()); |
62e76326 | 168 | return -1; |
169 | } | |
170 | ||
9708d22b | 171 | fd_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX DGRAM Parent"); |
172 | fd_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX DGRAM Parent"); | |
148feb19 AJ |
173 | |
174 | IPC_CHECK_FAIL(crfd, "child read", "UDS datagram"); | |
175 | IPC_CHECK_FAIL(prfd, "parent read", "UDS datagram"); | |
1ccc0d40 | 176 | #endif |
62e76326 | 177 | |
b13bbe1c | 178 | } else { |
62e76326 | 179 | assert(IPC_NONE); |
b13bbe1c | 180 | } |
62e76326 | 181 | |
bf8fe701 | 182 | debugs(54, 3, "ipcCreate: prfd FD " << prfd); |
183 | debugs(54, 3, "ipcCreate: pwfd FD " << pwfd); | |
184 | debugs(54, 3, "ipcCreate: crfd FD " << crfd); | |
185 | debugs(54, 3, "ipcCreate: cwfd FD " << cwfd); | |
b13bbe1c | 186 | |
b13bbe1c | 187 | if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { |
851614a8 | 188 | Ip::Address::InitAddr(AI); |
62e76326 | 189 | |
cc192b50 | 190 | if (getsockname(pwfd, AI->ai_addr, &AI->ai_addrlen) < 0) { |
851614a8 | 191 | Ip::Address::FreeAddr(AI); |
fa84c01d | 192 | debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror()); |
62e76326 | 193 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
194 | } | |
195 | ||
cc192b50 | 196 | PaS = *AI; |
bf8fe701 | 197 | |
cc192b50 | 198 | debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << PaS); |
62e76326 | 199 | |
851614a8 | 200 | Ip::Address::FreeAddr(AI); |
cc192b50 | 201 | |
851614a8 | 202 | Ip::Address::InitAddr(AI); |
cc192b50 | 203 | |
204 | if (getsockname(crfd, AI->ai_addr, &AI->ai_addrlen) < 0) { | |
851614a8 | 205 | Ip::Address::FreeAddr(AI); |
fa84c01d | 206 | debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror()); |
62e76326 | 207 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
208 | } | |
209 | ||
cc192b50 | 210 | ChS = *AI; |
211 | ||
851614a8 | 212 | Ip::Address::FreeAddr(AI); |
cc192b50 | 213 | |
214 | debugs(54, 3, "ipcCreate: FD " << crfd << " sockaddr " << ChS ); | |
bf8fe701 | 215 | |
b13bbe1c | 216 | } |
62e76326 | 217 | |
b13bbe1c | 218 | if (type == IPC_TCP_SOCKET) { |
62e76326 | 219 | if (listen(crfd, 1) < 0) { |
e0236918 | 220 | debugs(54, DBG_IMPORTANT, "ipcCreate: listen FD " << crfd << ": " << xstrerror()); |
62e76326 | 221 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
222 | } | |
223 | ||
bf8fe701 | 224 | debugs(54, 3, "ipcCreate: FD " << crfd << " listening..."); |
b13bbe1c | 225 | } |
62e76326 | 226 | |
b13bbe1c | 227 | /* flush or else we get dup data if unbuffered_logs is set */ |
228 | logsFlush(); | |
62e76326 | 229 | |
b13bbe1c | 230 | if ((pid = fork()) < 0) { |
e0236918 | 231 | debugs(54, DBG_IMPORTANT, "ipcCreate: fork: " << xstrerror()); |
62e76326 | 232 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
b13bbe1c | 233 | } |
62e76326 | 234 | |
f53969cc | 235 | if (pid > 0) { /* parent */ |
62e76326 | 236 | /* close shared socket with child */ |
237 | comm_close(crfd); | |
238 | ||
239 | if (cwfd != crfd) | |
240 | comm_close(cwfd); | |
241 | ||
242 | cwfd = crfd = -1; | |
243 | ||
244 | if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { | |
4ee57cbe | 245 | if (comm_connect_addr(pwfd, ChS) == Comm::COMM_ERROR) |
62e76326 | 246 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
247 | } | |
248 | ||
62e76326 | 249 | if (type == IPC_UDP_SOCKET) |
9ad18ba8 | 250 | x = comm_udp_recv(prfd, hello_buf, sizeof(hello_buf)-1, 0); |
62e76326 | 251 | else |
9ad18ba8 AJ |
252 | x = read(prfd, hello_buf, sizeof(hello_buf)-1); |
253 | if (x >= 0) | |
254 | hello_buf[x+1] = '\0'; | |
62e76326 | 255 | |
256 | if (x < 0) { | |
fa84c01d FC |
257 | debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed"); |
258 | debugs(54, DBG_CRITICAL, "--> read: " << xstrerror()); | |
62e76326 | 259 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
260 | } else if (strcmp(hello_buf, hello_string)) { | |
fa84c01d FC |
261 | debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed"); |
262 | debugs(54, DBG_CRITICAL, "--> read returned " << x); | |
263 | debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'"); | |
62e76326 | 264 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
265 | } | |
266 | ||
933dd095 | 267 | commUnsetFdTimeout(prfd); |
62e76326 | 268 | commSetNonBlocking(prfd); |
269 | commSetNonBlocking(pwfd); | |
270 | ||
271 | if (rfd) | |
272 | *rfd = prfd; | |
273 | ||
274 | if (wfd) | |
275 | *wfd = pwfd; | |
276 | ||
277 | fd_table[prfd].flags.ipc = 1; | |
278 | ||
279 | fd_table[pwfd].flags.ipc = 1; | |
280 | ||
281 | if (Config.sleep_after_fork) { | |
282 | /* XXX emulation of usleep() */ | |
283 | ||
284 | struct timeval sl; | |
285 | sl.tv_sec = Config.sleep_after_fork / 1000000; | |
286 | sl.tv_usec = Config.sleep_after_fork % 1000000; | |
287 | select(0, NULL, NULL, NULL, &sl); | |
288 | } | |
289 | ||
290 | return pid; | |
b13bbe1c | 291 | } |
62e76326 | 292 | |
b13bbe1c | 293 | /* child */ |
ed1a1519 | 294 | TheProcessKind = pkHelper; |
f53969cc | 295 | no_suid(); /* give up extra priviliges */ |
62e76326 | 296 | |
b13bbe1c | 297 | /* close shared socket with parent */ |
2dde67ef | 298 | close(prfd); |
62e76326 | 299 | |
b13bbe1c | 300 | if (pwfd != prfd) |
62e76326 | 301 | close(pwfd); |
302 | ||
b13bbe1c | 303 | pwfd = prfd = -1; |
304 | ||
305 | if (type == IPC_TCP_SOCKET) { | |
bf8fe701 | 306 | debugs(54, 3, "ipcCreate: calling accept on FD " << crfd); |
62e76326 | 307 | |
308 | if ((fd = accept(crfd, NULL, NULL)) < 0) { | |
fa84c01d | 309 | debugs(54, DBG_CRITICAL, "ipcCreate: FD " << crfd << " accept: " << xstrerror()); |
62e76326 | 310 | _exit(1); |
311 | } | |
312 | ||
bf8fe701 | 313 | debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd); |
62e76326 | 314 | close(crfd); |
315 | cwfd = crfd = fd; | |
b13bbe1c | 316 | } else if (type == IPC_UDP_SOCKET) { |
4ee57cbe | 317 | if (comm_connect_addr(crfd, PaS) == Comm::COMM_ERROR) |
62e76326 | 318 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
b13bbe1c | 319 | } |
62e76326 | 320 | |
b13bbe1c | 321 | if (type == IPC_UDP_SOCKET) { |
62e76326 | 322 | x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0); |
323 | ||
324 | if (x < 0) { | |
fa84c01d FC |
325 | debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerror()); |
326 | debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed"); | |
62e76326 | 327 | _exit(1); |
328 | } | |
b13bbe1c | 329 | } else { |
62e76326 | 330 | if (write(cwfd, hello_string, strlen(hello_string) + 1) < 0) { |
fa84c01d FC |
331 | debugs(54, DBG_CRITICAL, "write FD " << cwfd << ": " << xstrerror()); |
332 | debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed"); | |
62e76326 | 333 | _exit(1); |
334 | } | |
b13bbe1c | 335 | } |
62e76326 | 336 | |
2e4528cc | 337 | PutEnvironment(); |
b13bbe1c | 338 | /* |
26ac0430 | 339 | * This double-dup stuff avoids problems when one of |
86ed3fd2 | 340 | * crfd, cwfd, or debug_log are in the rage 0-2. |
b13bbe1c | 341 | */ |
62e76326 | 342 | |
86ed3fd2 | 343 | do { |
bed704f7 | 344 | /* First make sure 0-2 is occupied by something. Gets cleaned up later */ |
345 | x = dup(crfd); | |
346 | assert(x > -1); | |
347 | } while (x < 3 && x > -1); | |
62e76326 | 348 | |
bed704f7 | 349 | close(x); |
62e76326 | 350 | |
86ed3fd2 | 351 | t1 = dup(crfd); |
62e76326 | 352 | |
86ed3fd2 | 353 | t2 = dup(cwfd); |
62e76326 | 354 | |
86ed3fd2 | 355 | t3 = dup(fileno(debug_log)); |
62e76326 | 356 | |
86ed3fd2 | 357 | assert(t1 > 2 && t2 > 2 && t3 > 2); |
62e76326 | 358 | |
86ed3fd2 | 359 | close(crfd); |
62e76326 | 360 | |
86ed3fd2 | 361 | close(cwfd); |
62e76326 | 362 | |
86ed3fd2 | 363 | close(fileno(debug_log)); |
62e76326 | 364 | |
86ed3fd2 | 365 | dup2(t1, 0); |
62e76326 | 366 | |
86ed3fd2 | 367 | dup2(t2, 1); |
62e76326 | 368 | |
86ed3fd2 | 369 | dup2(t3, 2); |
62e76326 | 370 | |
86ed3fd2 | 371 | close(t1); |
62e76326 | 372 | |
86ed3fd2 | 373 | close(t2); |
62e76326 | 374 | |
86ed3fd2 | 375 | close(t3); |
62e76326 | 376 | |
3cdb7cd0 | 377 | /* Make sure all other filedescriptors are closed */ |
95dc7ff4 | 378 | for (x = 3; x < SQUID_MAXFD; ++x) |
62e76326 | 379 | close(x); |
380 | ||
62740359 | 381 | #if HAVE_SETSID |
26e75de2 | 382 | if (opt_no_daemon) |
af6a12ee | 383 | setsid(); |
62740359 | 384 | #endif |
385 | ||
a2c963ae | 386 | execvp(prog, (char *const *) args); |
62e76326 | 387 | |
3cdb7cd0 | 388 | debug_log = fdopen(2, "a+"); |
62e76326 | 389 | |
fa84c01d | 390 | debugs(54, DBG_CRITICAL, "ipcCreate: " << prog << ": " << xstrerror()); |
62e76326 | 391 | |
b13bbe1c | 392 | _exit(1); |
62e76326 | 393 | |
b13bbe1c | 394 | return 0; |
395 | } | |
f53969cc | 396 |