]>
Commit | Line | Data |
---|---|---|
b13bbe1c | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 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; | |
aee3523a | 67 | struct addrinfo *AI = nullptr; |
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; |
b69e9ffa | 75 | int xerrno; |
b13bbe1c | 76 | |
8a09e810 | 77 | #if USE_POLL && _SQUID_OSF_ |
91ef94d6 | 78 | assert(type != IPC_FIFO); |
79 | #endif | |
80 | ||
b13bbe1c | 81 | if (rfd) |
62e76326 | 82 | *rfd = -1; |
83 | ||
b13bbe1c | 84 | if (wfd) |
62e76326 | 85 | *wfd = -1; |
86 | ||
812dc4b8 | 87 | if (hIpc) |
aee3523a | 88 | *hIpc = nullptr; |
812dc4b8 | 89 | |
23d23d7a | 90 | // NP: no wrapping around d and c usage since we *want* code expansion |
148feb19 AJ |
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 | ||
b13bbe1c | 97 | if (type == IPC_TCP_SOCKET) { |
408ea1cf | 98 | crfd = cwfd = comm_open_listener(SOCK_STREAM, |
41b10565 | 99 | 0, |
100 | local_addr, | |
101 | COMM_NOCLOEXEC, | |
102 | name); | |
62e76326 | 103 | prfd = pwfd = comm_open(SOCK_STREAM, |
f53969cc | 104 | 0, /* protocol */ |
62e76326 | 105 | local_addr, |
f53969cc | 106 | 0, /* blocking */ |
62e76326 | 107 | name); |
148feb19 AJ |
108 | IPC_CHECK_FAIL(crfd, "child read", "TCP " << local_addr); |
109 | IPC_CHECK_FAIL(prfd, "parent read", "TCP " << local_addr); | |
b13bbe1c | 110 | } else if (type == IPC_UDP_SOCKET) { |
62e76326 | 111 | crfd = cwfd = comm_open(SOCK_DGRAM, |
112 | 0, | |
113 | local_addr, | |
62e76326 | 114 | COMM_NOCLOEXEC, |
115 | name); | |
116 | prfd = pwfd = comm_open(SOCK_DGRAM, | |
117 | 0, | |
118 | local_addr, | |
119 | 0, | |
62e76326 | 120 | name); |
148feb19 AJ |
121 | IPC_CHECK_FAIL(crfd, "child read", "UDP" << local_addr); |
122 | IPC_CHECK_FAIL(prfd, "parent read", "UDP" << local_addr); | |
b13bbe1c | 123 | } else if (type == IPC_FIFO) { |
62e76326 | 124 | int p2c[2]; |
125 | int c2p[2]; | |
126 | ||
127 | if (pipe(p2c) < 0) { | |
b69e9ffa AJ |
128 | xerrno = errno; |
129 | debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerr(xerrno)); | |
bd116068 | 130 | return -1; // maybe ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
62e76326 | 131 | } |
bd116068 AJ |
132 | fd_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read"); |
133 | fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write"); | |
62e76326 | 134 | |
135 | if (pipe(c2p) < 0) { | |
b69e9ffa AJ |
136 | xerrno = errno; |
137 | debugs(54, DBG_CRITICAL, "ipcCreate: pipe: " << xstrerr(xerrno)); | |
bd116068 | 138 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
62e76326 | 139 | } |
9708d22b | 140 | fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read"); |
141 | fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write"); | |
bd116068 | 142 | |
148feb19 AJ |
143 | IPC_CHECK_FAIL(crfd, "child read", "FIFO pipe"); |
144 | IPC_CHECK_FAIL(prfd, "parent read", "FIFO pipe"); | |
145 | ||
1ccc0d40 | 146 | #if HAVE_SOCKETPAIR && defined(AF_UNIX) |
62e76326 | 147 | |
1ccc0d40 | 148 | } else if (type == IPC_UNIX_STREAM) { |
62e76326 | 149 | int fds[2]; |
150 | int buflen = 32768; | |
151 | ||
152 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { | |
b69e9ffa AJ |
153 | xerrno = errno; |
154 | debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerr(xerrno)); | |
62e76326 | 155 | return -1; |
156 | } | |
157 | ||
3c177ce1 FC |
158 | errno = 0; |
159 | if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen)) == -1) { | |
b69e9ffa | 160 | xerrno = errno; |
d816f28d | 161 | debugs(54, DBG_IMPORTANT, "ERROR: setsockopt failed: " << xstrerr(xerrno)); |
3c177ce1 FC |
162 | errno = 0; |
163 | } | |
164 | if (setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen)) == -1) { | |
b69e9ffa | 165 | xerrno = errno; |
d816f28d | 166 | debugs(54, DBG_IMPORTANT, "ERROR: setsockopt failed: " << xstrerr(xerrno)); |
3c177ce1 FC |
167 | errno = 0; |
168 | } | |
169 | if (setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen)) == -1) { | |
b69e9ffa | 170 | xerrno = errno; |
d816f28d | 171 | debugs(54, DBG_IMPORTANT, "ERROR: setsockopt failed: " << xstrerr(xerrno)); |
3c177ce1 FC |
172 | errno = 0; |
173 | } | |
174 | if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen)) == -1) { | |
b69e9ffa | 175 | xerrno = errno; |
d816f28d | 176 | debugs(54, DBG_IMPORTANT, "ERROR: setsockopt failed: " << xstrerr(xerrno)); |
3c177ce1 FC |
177 | errno = 0; |
178 | } | |
9708d22b | 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"); | |
148feb19 AJ |
181 | IPC_CHECK_FAIL(crfd, "child read", "UDS socket"); |
182 | IPC_CHECK_FAIL(prfd, "parent read", "UDS socket"); | |
183 | ||
1ccc0d40 | 184 | } else if (type == IPC_UNIX_DGRAM) { |
62e76326 | 185 | int fds[2]; |
186 | ||
187 | if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) { | |
b69e9ffa AJ |
188 | xerrno = errno; |
189 | debugs(54, DBG_CRITICAL, "ipcCreate: socketpair: " << xstrerr(xerrno)); | |
62e76326 | 190 | return -1; |
191 | } | |
192 | ||
9708d22b | 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"); | |
148feb19 AJ |
195 | |
196 | IPC_CHECK_FAIL(crfd, "child read", "UDS datagram"); | |
197 | IPC_CHECK_FAIL(prfd, "parent read", "UDS datagram"); | |
1ccc0d40 | 198 | #endif |
62e76326 | 199 | |
b13bbe1c | 200 | } else { |
62e76326 | 201 | assert(IPC_NONE); |
b13bbe1c | 202 | } |
62e76326 | 203 | |
bf8fe701 | 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); | |
b13bbe1c | 208 | |
b13bbe1c | 209 | if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) { |
851614a8 | 210 | Ip::Address::InitAddr(AI); |
62e76326 | 211 | |
cc192b50 | 212 | if (getsockname(pwfd, AI->ai_addr, &AI->ai_addrlen) < 0) { |
b69e9ffa | 213 | xerrno = errno; |
851614a8 | 214 | Ip::Address::FreeAddr(AI); |
b69e9ffa | 215 | debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerr(xerrno)); |
62e76326 | 216 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
217 | } | |
218 | ||
cc192b50 | 219 | PaS = *AI; |
bf8fe701 | 220 | |
cc192b50 | 221 | debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << PaS); |
62e76326 | 222 | |
851614a8 | 223 | Ip::Address::FreeAddr(AI); |
cc192b50 | 224 | |
851614a8 | 225 | Ip::Address::InitAddr(AI); |
cc192b50 | 226 | |
227 | if (getsockname(crfd, AI->ai_addr, &AI->ai_addrlen) < 0) { | |
b69e9ffa | 228 | xerrno = errno; |
851614a8 | 229 | Ip::Address::FreeAddr(AI); |
b69e9ffa | 230 | debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerr(xerrno)); |
62e76326 | 231 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
232 | } | |
233 | ||
cc192b50 | 234 | ChS = *AI; |
235 | ||
851614a8 | 236 | Ip::Address::FreeAddr(AI); |
cc192b50 | 237 | |
238 | debugs(54, 3, "ipcCreate: FD " << crfd << " sockaddr " << ChS ); | |
bf8fe701 | 239 | |
b13bbe1c | 240 | } |
62e76326 | 241 | |
b13bbe1c | 242 | if (type == IPC_TCP_SOCKET) { |
62e76326 | 243 | if (listen(crfd, 1) < 0) { |
b69e9ffa AJ |
244 | xerrno = errno; |
245 | debugs(54, DBG_IMPORTANT, "ipcCreate: listen FD " << crfd << ": " << xstrerr(xerrno)); | |
62e76326 | 246 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
247 | } | |
248 | ||
bf8fe701 | 249 | debugs(54, 3, "ipcCreate: FD " << crfd << " listening..."); |
b13bbe1c | 250 | } |
62e76326 | 251 | |
b13bbe1c | 252 | /* flush or else we get dup data if unbuffered_logs is set */ |
253 | logsFlush(); | |
62e76326 | 254 | |
b13bbe1c | 255 | if ((pid = fork()) < 0) { |
b69e9ffa AJ |
256 | xerrno = errno; |
257 | debugs(54, DBG_IMPORTANT, "ipcCreate: fork: " << xstrerr(xerrno)); | |
62e76326 | 258 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
b13bbe1c | 259 | } |
62e76326 | 260 | |
f53969cc | 261 | if (pid > 0) { /* parent */ |
62e76326 | 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) { | |
4ee57cbe | 271 | if (comm_connect_addr(pwfd, ChS) == Comm::COMM_ERROR) |
62e76326 | 272 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
273 | } | |
274 | ||
62e76326 | 275 | if (type == IPC_UDP_SOCKET) |
9ad18ba8 | 276 | x = comm_udp_recv(prfd, hello_buf, sizeof(hello_buf)-1, 0); |
62e76326 | 277 | else |
9ad18ba8 | 278 | x = read(prfd, hello_buf, sizeof(hello_buf)-1); |
b69e9ffa | 279 | xerrno = errno; |
9ad18ba8 | 280 | if (x >= 0) |
710171db | 281 | hello_buf[x] = '\0'; |
62e76326 | 282 | |
283 | if (x < 0) { | |
d816f28d | 284 | debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: PARENT: hello read test failed"); |
b69e9ffa | 285 | debugs(54, DBG_CRITICAL, "--> read: " << xstrerr(xerrno)); |
62e76326 | 286 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
287 | } else if (strcmp(hello_buf, hello_string)) { | |
d816f28d | 288 | debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: PARENT: hello read test failed"); |
fa84c01d FC |
289 | debugs(54, DBG_CRITICAL, "--> read returned " << x); |
290 | debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'"); | |
62e76326 | 291 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
292 | } | |
293 | ||
933dd095 | 294 | commUnsetFdTimeout(prfd); |
62e76326 | 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; | |
aee3523a | 314 | select(0, nullptr, nullptr, nullptr, &sl); |
62e76326 | 315 | } |
316 | ||
317 | return pid; | |
b13bbe1c | 318 | } |
62e76326 | 319 | |
b13bbe1c | 320 | /* child */ |
ed1a1519 | 321 | TheProcessKind = pkHelper; |
2f8abb64 | 322 | no_suid(); /* give up extra privileges */ |
62e76326 | 323 | |
b13bbe1c | 324 | /* close shared socket with parent */ |
2dde67ef | 325 | close(prfd); |
62e76326 | 326 | |
b13bbe1c | 327 | if (pwfd != prfd) |
62e76326 | 328 | close(pwfd); |
329 | ||
b13bbe1c | 330 | pwfd = prfd = -1; |
331 | ||
332 | if (type == IPC_TCP_SOCKET) { | |
bf8fe701 | 333 | debugs(54, 3, "ipcCreate: calling accept on FD " << crfd); |
62e76326 | 334 | |
aee3523a | 335 | if ((fd = accept(crfd, nullptr, nullptr)) < 0) { |
b69e9ffa AJ |
336 | xerrno = errno; |
337 | debugs(54, DBG_CRITICAL, "ipcCreate: FD " << crfd << " accept: " << xstrerr(xerrno)); | |
62e76326 | 338 | _exit(1); |
339 | } | |
340 | ||
bf8fe701 | 341 | debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd); |
62e76326 | 342 | close(crfd); |
343 | cwfd = crfd = fd; | |
b13bbe1c | 344 | } else if (type == IPC_UDP_SOCKET) { |
4ee57cbe | 345 | if (comm_connect_addr(crfd, PaS) == Comm::COMM_ERROR) |
62e76326 | 346 | return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); |
b13bbe1c | 347 | } |
62e76326 | 348 | |
b13bbe1c | 349 | if (type == IPC_UDP_SOCKET) { |
62e76326 | 350 | x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0); |
351 | ||
352 | if (x < 0) { | |
b69e9ffa AJ |
353 | xerrno = errno; |
354 | debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerr(xerrno)); | |
d816f28d | 355 | debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: hello write test failed"); |
62e76326 | 356 | _exit(1); |
357 | } | |
b13bbe1c | 358 | } else { |
62e76326 | 359 | if (write(cwfd, hello_string, strlen(hello_string) + 1) < 0) { |
b69e9ffa AJ |
360 | xerrno = errno; |
361 | debugs(54, DBG_CRITICAL, "write FD " << cwfd << ": " << xstrerr(xerrno)); | |
d816f28d | 362 | debugs(54, DBG_CRITICAL, "ERROR: ipcCreate: CHILD: hello write test failed"); |
62e76326 | 363 | _exit(1); |
364 | } | |
b13bbe1c | 365 | } |
62e76326 | 366 | |
2e4528cc | 367 | PutEnvironment(); |
b13bbe1c | 368 | /* |
26ac0430 | 369 | * This double-dup stuff avoids problems when one of |
86ed3fd2 | 370 | * crfd, cwfd, or debug_log are in the rage 0-2. |
b13bbe1c | 371 | */ |
62e76326 | 372 | |
86ed3fd2 | 373 | do { |
bed704f7 | 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); | |
62e76326 | 378 | |
bed704f7 | 379 | close(x); |
62e76326 | 380 | |
86ed3fd2 | 381 | t1 = dup(crfd); |
62e76326 | 382 | |
86ed3fd2 | 383 | t2 = dup(cwfd); |
62e76326 | 384 | |
86ed3fd2 | 385 | t3 = dup(fileno(debug_log)); |
62e76326 | 386 | |
86ed3fd2 | 387 | assert(t1 > 2 && t2 > 2 && t3 > 2); |
62e76326 | 388 | |
86ed3fd2 | 389 | close(crfd); |
62e76326 | 390 | |
86ed3fd2 | 391 | close(cwfd); |
62e76326 | 392 | |
86ed3fd2 | 393 | close(fileno(debug_log)); |
62e76326 | 394 | |
86ed3fd2 | 395 | dup2(t1, 0); |
62e76326 | 396 | |
86ed3fd2 | 397 | dup2(t2, 1); |
62e76326 | 398 | |
86ed3fd2 | 399 | dup2(t3, 2); |
62e76326 | 400 | |
86ed3fd2 | 401 | close(t1); |
62e76326 | 402 | |
86ed3fd2 | 403 | close(t2); |
62e76326 | 404 | |
86ed3fd2 | 405 | close(t3); |
62e76326 | 406 | |
3cdb7cd0 | 407 | /* Make sure all other filedescriptors are closed */ |
95dc7ff4 | 408 | for (x = 3; x < SQUID_MAXFD; ++x) |
62e76326 | 409 | close(x); |
410 | ||
62740359 | 411 | #if HAVE_SETSID |
26e75de2 | 412 | if (opt_no_daemon) |
af6a12ee | 413 | setsid(); |
62740359 | 414 | #endif |
415 | ||
a2c963ae | 416 | execvp(prog, (char *const *) args); |
b69e9ffa | 417 | xerrno = errno; |
62e76326 | 418 | |
0c7e529e | 419 | ResyncDebugLog(fdopen(2, "a+")); |
62e76326 | 420 | |
b69e9ffa | 421 | debugs(54, DBG_CRITICAL, "ipcCreate: " << prog << ": " << xstrerr(xerrno)); |
62e76326 | 422 | |
b13bbe1c | 423 | _exit(1); |
62e76326 | 424 | |
b13bbe1c | 425 | return 0; |
426 | } | |
f53969cc | 427 |