]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc.cc
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 54 Interprocess Communication */
12 #include "comm/Connection.h"
16 #include "ip/Address.h"
19 #include "SquidConfig.h"
23 static const char *hello_string
= "hi there\n";
24 #define HELLO_BUF_SZ 32
25 static char hello_buf
[HELLO_BUF_SZ
];
28 ipcCloseAllFD(int prfd
, int pwfd
, int crfd
, int cwfd
)
53 env_str
= (char *)xcalloc((tmp_s
= strlen(Debug::debugOptions
) + 32), 1);
54 snprintf(env_str
, tmp_s
, "SQUID_DEBUG=%s", Debug::debugOptions
);
60 ipcCreate(int type
, const char *prog
, const char *const args
[], const char *name
, Ip::Address
&local_addr
, int *rfd
, int *wfd
, void **hIpc
)
65 struct addrinfo
*AI
= NULL
;
74 #if USE_POLL && _SQUID_OSF_
75 assert(type
!= IPC_FIFO
);
87 // NP: no wrapping around d and c usage since we *want* code expansion
88 #define IPC_CHECK_FAIL(f,d,c) \
90 debugs(54, DBG_CRITICAL, "ERROR: Failed to create helper " d " FD: " << c); \
91 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); \
94 if (type
== IPC_TCP_SOCKET
) {
95 crfd
= cwfd
= comm_open(SOCK_STREAM
,
100 prfd
= pwfd
= comm_open(SOCK_STREAM
,
105 IPC_CHECK_FAIL(crfd
, "child read", "TCP " << local_addr
);
106 IPC_CHECK_FAIL(prfd
, "parent read", "TCP " << local_addr
);
107 } else if (type
== IPC_UDP_SOCKET
) {
108 crfd
= cwfd
= comm_open(SOCK_DGRAM
,
113 prfd
= pwfd
= comm_open(SOCK_DGRAM
,
118 IPC_CHECK_FAIL(crfd
, "child read", "UDP" << local_addr
);
119 IPC_CHECK_FAIL(prfd
, "parent read", "UDP" << local_addr
);
120 } else if (type
== IPC_FIFO
) {
125 debugs(54, DBG_CRITICAL
, "ipcCreate: pipe: " << xstrerror());
126 return -1; // maybe ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
128 fd_open(prfd
= p2c
[0], FD_PIPE
, "IPC FIFO Parent Read");
129 fd_open(cwfd
= p2c
[1], FD_PIPE
, "IPC FIFO Child Write");
132 debugs(54, DBG_CRITICAL
, "ipcCreate: pipe: " << xstrerror());
133 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
135 fd_open(crfd
= c2p
[0], FD_PIPE
, "IPC FIFO Child Read");
136 fd_open(pwfd
= c2p
[1], FD_PIPE
, "IPC FIFO Parent Write");
138 IPC_CHECK_FAIL(crfd
, "child read", "FIFO pipe");
139 IPC_CHECK_FAIL(prfd
, "parent read", "FIFO pipe");
141 #if HAVE_SOCKETPAIR && defined(AF_UNIX)
143 } else if (type
== IPC_UNIX_STREAM
) {
147 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, fds
) < 0) {
148 debugs(54, DBG_CRITICAL
, "ipcCreate: socketpair: " << xstrerror());
152 setsockopt(fds
[0], SOL_SOCKET
, SO_SNDBUF
, (void *) &buflen
, sizeof(buflen
));
153 setsockopt(fds
[0], SOL_SOCKET
, SO_RCVBUF
, (void *) &buflen
, sizeof(buflen
));
154 setsockopt(fds
[1], SOL_SOCKET
, SO_SNDBUF
, (void *) &buflen
, sizeof(buflen
));
155 setsockopt(fds
[1], SOL_SOCKET
, SO_RCVBUF
, (void *) &buflen
, sizeof(buflen
));
156 fd_open(prfd
= pwfd
= fds
[0], FD_PIPE
, "IPC UNIX STREAM Parent");
157 fd_open(crfd
= cwfd
= fds
[1], FD_PIPE
, "IPC UNIX STREAM Parent");
158 IPC_CHECK_FAIL(crfd
, "child read", "UDS socket");
159 IPC_CHECK_FAIL(prfd
, "parent read", "UDS socket");
161 } else if (type
== IPC_UNIX_DGRAM
) {
164 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, fds
) < 0) {
165 debugs(54, DBG_CRITICAL
, "ipcCreate: socketpair: " << xstrerror());
169 fd_open(prfd
= pwfd
= fds
[0], FD_PIPE
, "IPC UNIX DGRAM Parent");
170 fd_open(crfd
= cwfd
= fds
[1], FD_PIPE
, "IPC UNIX DGRAM Parent");
172 IPC_CHECK_FAIL(crfd
, "child read", "UDS datagram");
173 IPC_CHECK_FAIL(prfd
, "parent read", "UDS datagram");
180 debugs(54, 3, "ipcCreate: prfd FD " << prfd
);
181 debugs(54, 3, "ipcCreate: pwfd FD " << pwfd
);
182 debugs(54, 3, "ipcCreate: crfd FD " << crfd
);
183 debugs(54, 3, "ipcCreate: cwfd FD " << cwfd
);
185 if (type
== IPC_TCP_SOCKET
|| type
== IPC_UDP_SOCKET
) {
186 Ip::Address::InitAddrInfo(AI
);
188 if (getsockname(pwfd
, AI
->ai_addr
, &AI
->ai_addrlen
) < 0) {
189 Ip::Address::FreeAddrInfo(AI
);
190 debugs(54, DBG_CRITICAL
, "ipcCreate: getsockname: " << xstrerror());
191 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
196 debugs(54, 3, "ipcCreate: FD " << pwfd
<< " sockaddr " << PaS
);
198 Ip::Address::FreeAddrInfo(AI
);
200 Ip::Address::InitAddrInfo(AI
);
202 if (getsockname(crfd
, AI
->ai_addr
, &AI
->ai_addrlen
) < 0) {
203 Ip::Address::FreeAddrInfo(AI
);
204 debugs(54, DBG_CRITICAL
, "ipcCreate: getsockname: " << xstrerror());
205 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
210 Ip::Address::FreeAddrInfo(AI
);
212 debugs(54, 3, "ipcCreate: FD " << crfd
<< " sockaddr " << ChS
);
216 if (type
== IPC_TCP_SOCKET
) {
217 if (listen(crfd
, 1) < 0) {
218 debugs(54, DBG_IMPORTANT
, "ipcCreate: listen FD " << crfd
<< ": " << xstrerror());
219 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
222 debugs(54, 3, "ipcCreate: FD " << crfd
<< " listening...");
225 /* flush or else we get dup data if unbuffered_logs is set */
228 if ((pid
= fork()) < 0) {
229 debugs(54, DBG_IMPORTANT
, "ipcCreate: fork: " << xstrerror());
230 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
233 if (pid
> 0) { /* parent */
234 /* close shared socket with child */
242 if (type
== IPC_TCP_SOCKET
|| type
== IPC_UDP_SOCKET
) {
243 if (comm_connect_addr(pwfd
, ChS
) == Comm::COMM_ERROR
)
244 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
247 memset(hello_buf
, '\0', HELLO_BUF_SZ
);
249 if (type
== IPC_UDP_SOCKET
)
250 x
= comm_udp_recv(prfd
, hello_buf
, HELLO_BUF_SZ
- 1, 0);
252 x
= read(prfd
, hello_buf
, HELLO_BUF_SZ
- 1);
255 debugs(54, DBG_CRITICAL
, "ipcCreate: PARENT: hello read test failed");
256 debugs(54, DBG_CRITICAL
, "--> read: " << xstrerror());
257 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
258 } else if (strcmp(hello_buf
, hello_string
)) {
259 debugs(54, DBG_CRITICAL
, "ipcCreate: PARENT: hello read test failed");
260 debugs(54, DBG_CRITICAL
, "--> read returned " << x
);
261 debugs(54, DBG_CRITICAL
, "--> got '" << rfc1738_escape(hello_buf
) << "'");
262 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
265 commUnsetFdTimeout(prfd
);
266 commSetNonBlocking(prfd
);
267 commSetNonBlocking(pwfd
);
275 fd_table
[prfd
].flags
.ipc
= 1;
277 fd_table
[pwfd
].flags
.ipc
= 1;
279 if (Config
.sleep_after_fork
) {
280 /* XXX emulation of usleep() */
283 sl
.tv_sec
= Config
.sleep_after_fork
/ 1000000;
284 sl
.tv_usec
= Config
.sleep_after_fork
% 1000000;
285 select(0, NULL
, NULL
, NULL
, &sl
);
292 TheProcessKind
= pkHelper
;
293 no_suid(); /* give up extra priviliges */
295 /* close shared socket with parent */
303 if (type
== IPC_TCP_SOCKET
) {
304 debugs(54, 3, "ipcCreate: calling accept on FD " << crfd
);
306 if ((fd
= accept(crfd
, NULL
, NULL
)) < 0) {
307 debugs(54, DBG_CRITICAL
, "ipcCreate: FD " << crfd
<< " accept: " << xstrerror());
311 debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd
);
314 } else if (type
== IPC_UDP_SOCKET
) {
315 if (comm_connect_addr(crfd
, PaS
) == Comm::COMM_ERROR
)
316 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
319 if (type
== IPC_UDP_SOCKET
) {
320 x
= comm_udp_send(cwfd
, hello_string
, strlen(hello_string
) + 1, 0);
323 debugs(54, DBG_CRITICAL
, "sendto FD " << cwfd
<< ": " << xstrerror());
324 debugs(54, DBG_CRITICAL
, "ipcCreate: CHILD: hello write test failed");
328 if (write(cwfd
, hello_string
, strlen(hello_string
) + 1) < 0) {
329 debugs(54, DBG_CRITICAL
, "write FD " << cwfd
<< ": " << xstrerror());
330 debugs(54, DBG_CRITICAL
, "ipcCreate: CHILD: hello write test failed");
337 * This double-dup stuff avoids problems when one of
338 * crfd, cwfd, or debug_log are in the rage 0-2.
342 /* First make sure 0-2 is occupied by something. Gets cleaned up later */
345 } while (x
< 3 && x
> -1);
353 t3
= dup(fileno(debug_log
));
355 assert(t1
> 2 && t2
> 2 && t3
> 2);
361 close(fileno(debug_log
));
375 /* Make sure all other filedescriptors are closed */
376 for (x
= 3; x
< SQUID_MAXFD
; ++x
)
384 execvp(prog
, (char *const *) args
);
386 debug_log
= fdopen(2, "a+");
388 debugs(54, DBG_CRITICAL
, "ipcCreate: " << prog
<< ": " << xstrerror());