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