]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc.cc
2 * DEBUG: section 54 Interprocess Communication
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
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.
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.
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.
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
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "comm/Connection.h"
38 #include "ip/Address.h"
39 #include "SquidConfig.h"
44 static const char *hello_string
= "hi there\n";
45 #define HELLO_BUF_SZ 32
46 static char hello_buf
[HELLO_BUF_SZ
];
49 ipcCloseAllFD(int prfd
, int pwfd
, int crfd
, int cwfd
)
74 env_str
= (char *)xcalloc((tmp_s
= strlen(Debug::debugOptions
) + 32), 1);
75 snprintf(env_str
, tmp_s
, "SQUID_DEBUG=%s", Debug::debugOptions
);
81 ipcCreate(int type
, const char *prog
, const char *const args
[], const char *name
, Ip::Address
&local_addr
, int *rfd
, int *wfd
, void **hIpc
)
86 struct addrinfo
*AI
= NULL
;
95 #if USE_POLL && _SQUID_OSF_
96 assert(type
!= IPC_FIFO
);
108 // NP: no wrapping around d and c usage since we *want* code expansion
109 #define IPC_CHECK_FAIL(f,d,c) \
111 debugs(54, DBG_CRITICAL, "ERROR: Failed to create helper " d " FD: " << c); \
112 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd); \
115 if (type
== IPC_TCP_SOCKET
) {
116 crfd
= cwfd
= comm_open(SOCK_STREAM
,
121 prfd
= pwfd
= comm_open(SOCK_STREAM
,
126 IPC_CHECK_FAIL(crfd
, "child read", "TCP " << local_addr
);
127 IPC_CHECK_FAIL(prfd
, "parent read", "TCP " << local_addr
);
128 } else if (type
== IPC_UDP_SOCKET
) {
129 crfd
= cwfd
= comm_open(SOCK_DGRAM
,
134 prfd
= pwfd
= comm_open(SOCK_DGRAM
,
139 IPC_CHECK_FAIL(crfd
, "child read", "UDP" << local_addr
);
140 IPC_CHECK_FAIL(prfd
, "parent read", "UDP" << local_addr
);
141 } else if (type
== IPC_FIFO
) {
146 debugs(54, DBG_CRITICAL
, "ipcCreate: pipe: " << xstrerror());
147 return -1; // maybe ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
149 fd_open(prfd
= p2c
[0], FD_PIPE
, "IPC FIFO Parent Read");
150 fd_open(cwfd
= p2c
[1], FD_PIPE
, "IPC FIFO Child Write");
153 debugs(54, DBG_CRITICAL
, "ipcCreate: pipe: " << xstrerror());
154 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
156 fd_open(crfd
= c2p
[0], FD_PIPE
, "IPC FIFO Child Read");
157 fd_open(pwfd
= c2p
[1], FD_PIPE
, "IPC FIFO Parent Write");
159 IPC_CHECK_FAIL(crfd
, "child read", "FIFO pipe");
160 IPC_CHECK_FAIL(prfd
, "parent read", "FIFO pipe");
162 #if HAVE_SOCKETPAIR && defined(AF_UNIX)
164 } else if (type
== IPC_UNIX_STREAM
) {
168 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, fds
) < 0) {
169 debugs(54, DBG_CRITICAL
, "ipcCreate: socketpair: " << xstrerror());
173 setsockopt(fds
[0], SOL_SOCKET
, SO_SNDBUF
, (void *) &buflen
, sizeof(buflen
));
174 setsockopt(fds
[0], SOL_SOCKET
, SO_RCVBUF
, (void *) &buflen
, sizeof(buflen
));
175 setsockopt(fds
[1], SOL_SOCKET
, SO_SNDBUF
, (void *) &buflen
, sizeof(buflen
));
176 setsockopt(fds
[1], SOL_SOCKET
, SO_RCVBUF
, (void *) &buflen
, sizeof(buflen
));
177 fd_open(prfd
= pwfd
= fds
[0], FD_PIPE
, "IPC UNIX STREAM Parent");
178 fd_open(crfd
= cwfd
= fds
[1], FD_PIPE
, "IPC UNIX STREAM Parent");
179 IPC_CHECK_FAIL(crfd
, "child read", "UDS socket");
180 IPC_CHECK_FAIL(prfd
, "parent read", "UDS socket");
182 } else if (type
== IPC_UNIX_DGRAM
) {
185 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, fds
) < 0) {
186 debugs(54, DBG_CRITICAL
, "ipcCreate: socketpair: " << xstrerror());
190 fd_open(prfd
= pwfd
= fds
[0], FD_PIPE
, "IPC UNIX DGRAM Parent");
191 fd_open(crfd
= cwfd
= fds
[1], FD_PIPE
, "IPC UNIX DGRAM Parent");
193 IPC_CHECK_FAIL(crfd
, "child read", "UDS datagram");
194 IPC_CHECK_FAIL(prfd
, "parent read", "UDS datagram");
201 debugs(54, 3, "ipcCreate: prfd FD " << prfd
);
202 debugs(54, 3, "ipcCreate: pwfd FD " << pwfd
);
203 debugs(54, 3, "ipcCreate: crfd FD " << crfd
);
204 debugs(54, 3, "ipcCreate: cwfd FD " << cwfd
);
206 if (type
== IPC_TCP_SOCKET
|| type
== IPC_UDP_SOCKET
) {
207 PaS
.InitAddrInfo(AI
);
209 if (getsockname(pwfd
, AI
->ai_addr
, &AI
->ai_addrlen
) < 0) {
210 PaS
.FreeAddrInfo(AI
);
211 debugs(54, DBG_CRITICAL
, "ipcCreate: getsockname: " << xstrerror());
212 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
217 debugs(54, 3, "ipcCreate: FD " << pwfd
<< " sockaddr " << PaS
);
219 PaS
.FreeAddrInfo(AI
);
221 ChS
.InitAddrInfo(AI
);
223 if (getsockname(crfd
, AI
->ai_addr
, &AI
->ai_addrlen
) < 0) {
224 ChS
.FreeAddrInfo(AI
);
225 debugs(54, DBG_CRITICAL
, "ipcCreate: getsockname: " << xstrerror());
226 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
231 ChS
.FreeAddrInfo(AI
);
233 debugs(54, 3, "ipcCreate: FD " << crfd
<< " sockaddr " << ChS
);
237 if (type
== IPC_TCP_SOCKET
) {
238 if (listen(crfd
, 1) < 0) {
239 debugs(54, DBG_IMPORTANT
, "ipcCreate: listen FD " << crfd
<< ": " << xstrerror());
240 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
243 debugs(54, 3, "ipcCreate: FD " << crfd
<< " listening...");
246 /* flush or else we get dup data if unbuffered_logs is set */
249 if ((pid
= fork()) < 0) {
250 debugs(54, DBG_IMPORTANT
, "ipcCreate: fork: " << xstrerror());
251 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
254 if (pid
> 0) { /* parent */
255 /* close shared socket with child */
263 if (type
== IPC_TCP_SOCKET
|| type
== IPC_UDP_SOCKET
) {
264 if (comm_connect_addr(pwfd
, ChS
) == COMM_ERROR
)
265 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
268 memset(hello_buf
, '\0', HELLO_BUF_SZ
);
270 if (type
== IPC_UDP_SOCKET
)
271 x
= comm_udp_recv(prfd
, hello_buf
, HELLO_BUF_SZ
- 1, 0);
273 x
= read(prfd
, hello_buf
, HELLO_BUF_SZ
- 1);
276 debugs(54, DBG_CRITICAL
, "ipcCreate: PARENT: hello read test failed");
277 debugs(54, DBG_CRITICAL
, "--> read: " << xstrerror());
278 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
279 } else if (strcmp(hello_buf
, hello_string
)) {
280 debugs(54, DBG_CRITICAL
, "ipcCreate: PARENT: hello read test failed");
281 debugs(54, DBG_CRITICAL
, "--> read returned " << x
);
282 debugs(54, DBG_CRITICAL
, "--> got '" << rfc1738_escape(hello_buf
) << "'");
283 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
286 commUnsetFdTimeout(prfd
);
287 commSetNonBlocking(prfd
);
288 commSetNonBlocking(pwfd
);
296 fd_table
[prfd
].flags
.ipc
= 1;
298 fd_table
[pwfd
].flags
.ipc
= 1;
300 if (Config
.sleep_after_fork
) {
301 /* XXX emulation of usleep() */
304 sl
.tv_sec
= Config
.sleep_after_fork
/ 1000000;
305 sl
.tv_usec
= Config
.sleep_after_fork
% 1000000;
306 select(0, NULL
, NULL
, NULL
, &sl
);
313 no_suid(); /* give up extra priviliges */
315 /* close shared socket with parent */
323 if (type
== IPC_TCP_SOCKET
) {
324 debugs(54, 3, "ipcCreate: calling accept on FD " << crfd
);
326 if ((fd
= accept(crfd
, NULL
, NULL
)) < 0) {
327 debugs(54, DBG_CRITICAL
, "ipcCreate: FD " << crfd
<< " accept: " << xstrerror());
331 debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd
);
334 } else if (type
== IPC_UDP_SOCKET
) {
335 if (comm_connect_addr(crfd
, PaS
) == COMM_ERROR
)
336 return ipcCloseAllFD(prfd
, pwfd
, crfd
, cwfd
);
339 if (type
== IPC_UDP_SOCKET
) {
340 x
= comm_udp_send(cwfd
, hello_string
, strlen(hello_string
) + 1, 0);
343 debugs(54, DBG_CRITICAL
, "sendto FD " << cwfd
<< ": " << xstrerror());
344 debugs(54, DBG_CRITICAL
, "ipcCreate: CHILD: hello write test failed");
348 if (write(cwfd
, hello_string
, strlen(hello_string
) + 1) < 0) {
349 debugs(54, DBG_CRITICAL
, "write FD " << cwfd
<< ": " << xstrerror());
350 debugs(54, DBG_CRITICAL
, "ipcCreate: CHILD: hello write test failed");
357 * This double-dup stuff avoids problems when one of
358 * crfd, cwfd, or debug_log are in the rage 0-2.
362 /* First make sure 0-2 is occupied by something. Gets cleaned up later */
365 } while (x
< 3 && x
> -1);
373 t3
= dup(fileno(debug_log
));
375 assert(t1
> 2 && t2
> 2 && t3
> 2);
381 close(fileno(debug_log
));
395 /* Make sure all other filedescriptors are closed */
396 for (x
= 3; x
< SQUID_MAXFD
; ++x
)
404 execvp(prog
, (char *const *) args
);
406 debug_log
= fdopen(2, "a+");
408 debugs(54, DBG_CRITICAL
, "ipcCreate: " << prog
<< ": " << xstrerror());