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