]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc.cc
protos.h refactoring, part one.
[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"
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
42static const char *hello_string = "hi there\n";
43#define HELLO_BUF_SZ 32
44static char hello_buf[HELLO_BUF_SZ];
45
46static int
47ipcCloseAllFD(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 66static void
67PutEnvironment()
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 78pid_t
b7ac5457 79ipcCreate(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}