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