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