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