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