]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc.cc
Import IPv6 support from squid3-ipv6 branch to 3-HEAD.
[thirdparty/squid.git] / src / ipc.cc
CommitLineData
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
41static const char *hello_string = "hi there\n";
42#define HELLO_BUF_SZ 32
43static char hello_buf[HELLO_BUF_SZ];
44
45static int
46ipcCloseAllFD(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 65static void
66PutEnvironment()
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 77pid_t
cc192b50 78ipcCreate(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}