3
* $Id: ipc.cc,v 1.44 2006/09/03 19:28:10 serassio Exp $
5
* DEBUG: section 54 Interprocess Communication
6
* AUTHOR: Duane Wessels
8
* SQUID Web Proxy Cache http://www.squid-cache.org/
9
* ----------------------------------------------------------
11
* Squid is the result of efforts by numerous individuals from
12
* the Internet community; see the CONTRIBUTORS file for full
13
* details. Many organizations have provided support for Squid's
14
* development; see the SPONSORS file for full details. Squid is
15
* Copyrighted (C) 2001 by the Regents of the University of
16
* California; see the COPYRIGHT file for full details. Squid
17
* incorporates software developed and/or copyrighted by other
18
* sources; see the CREDITS file for full details.
20
* This program is free software; you can redistribute it and/or modify
21
* it under the terms of the GNU General Public License as published by
22
* the Free Software Foundation; either version 2 of the License, or
23
* (at your option) any later version.
25
* This program is distributed in the hope that it will be useful,
26
* but WITHOUT ANY WARRANTY; without even the implied warranty of
27
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
* GNU General Public License for more details.
30
* You should have received a copy of the GNU General Public License
31
* along with this program; if not, write to the Free Software
32
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
40
static const char *hello_string = "hi there\n";
41
#define HELLO_BUF_SZ 32
42
static char hello_buf[HELLO_BUF_SZ];
45
ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
70
env_str = (char *)xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
71
snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
77
ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, void **hIpc)
81
struct sockaddr_in ChS;
83
struct sockaddr_in PaS;
93
#if USE_POLL && defined(_SQUID_OSF_)
95
assert(type != IPC_FIFO);
107
if (type == IPC_TCP_SOCKET) {
108
crfd = cwfd = comm_open(SOCK_STREAM,
114
prfd = pwfd = comm_open(SOCK_STREAM,
120
} else if (type == IPC_UDP_SOCKET) {
121
crfd = cwfd = comm_open(SOCK_DGRAM,
127
prfd = pwfd = comm_open(SOCK_DGRAM,
133
} else if (type == IPC_FIFO) {
138
debug(54, 0) ("ipcCreate: pipe: %s\n", xstrerror());
143
debug(54, 0) ("ipcCreate: pipe: %s\n", xstrerror());
147
fdc_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
148
fdc_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write");
149
fdc_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read");
150
fdc_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
151
#if HAVE_SOCKETPAIR && defined(AF_UNIX)
153
} else if (type == IPC_UNIX_STREAM) {
157
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
158
debug(54, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
162
setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
163
setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
164
setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (void *) &buflen, sizeof(buflen));
165
setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, (void *) &buflen, sizeof(buflen));
166
fdc_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX STREAM Parent");
167
fdc_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX STREAM Parent");
168
} else if (type == IPC_UNIX_DGRAM) {
171
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
172
debug(54, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
176
fdc_open(prfd = pwfd = fds[0], FD_PIPE, "IPC UNIX DGRAM Parent");
177
fdc_open(crfd = cwfd = fds[1], FD_PIPE, "IPC UNIX DGRAM Parent");
184
debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd);
185
debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd);
186
debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd);
187
debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd);
190
debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
191
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
195
debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
196
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
199
if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
201
memset(&PaS, '\0', len);
203
if (getsockname(pwfd, (struct sockaddr *) &PaS, &len) < 0) {
204
debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
205
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
208
debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
209
pwfd, inet_ntoa(PaS.sin_addr), ntohs(PaS.sin_port));
211
memset(&ChS, '\0', len);
213
if (getsockname(crfd, (struct sockaddr *) &ChS, &len) < 0) {
214
debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
215
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
218
debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
219
crfd, inet_ntoa(ChS.sin_addr), ntohs(ChS.sin_port));
222
if (type == IPC_TCP_SOCKET) {
223
if (listen(crfd, 1) < 0) {
224
debug(54, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror());
225
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
228
debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
231
/* flush or else we get dup data if unbuffered_logs is set */
234
if ((pid = fork()) < 0) {
235
debug(54, 1) ("ipcCreate: fork: %s\n", xstrerror());
236
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
239
if (pid > 0) { /* parent */
240
/* close shared socket with child */
248
if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
249
if (comm_connect_addr(pwfd, &ChS) == COMM_ERROR)
250
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
253
memset(hello_buf, '\0', HELLO_BUF_SZ);
255
if (type == IPC_UDP_SOCKET)
256
x = comm_udp_recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);
258
x = read(prfd, hello_buf, HELLO_BUF_SZ - 1);
261
debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
262
debug(54, 0) ("--> read: %s\n", xstrerror());
263
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
264
} else if (strcmp(hello_buf, hello_string)) {
265
debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
266
debug(54, 0) ("--> read returned %d\n", x);
267
debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
268
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
271
commSetTimeout(prfd, -1, NULL, NULL);
272
commSetNonBlocking(prfd);
273
commSetNonBlocking(pwfd);
281
fd_table[prfd].flags.ipc = 1;
283
fd_table[pwfd].flags.ipc = 1;
285
if (Config.sleep_after_fork) {
286
/* XXX emulation of usleep() */
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);
298
no_suid(); /* give up extra priviliges */
300
/* close shared socket with parent */
308
if (type == IPC_TCP_SOCKET) {
309
debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
311
if ((fd = accept(crfd, NULL, NULL)) < 0) {
312
debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
316
debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
319
} else if (type == IPC_UDP_SOCKET) {
320
if (comm_connect_addr(crfd, &PaS) == COMM_ERROR)
321
return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
324
if (type == IPC_UDP_SOCKET) {
325
x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0);
328
debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
329
debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
333
if (write(cwfd, hello_string, strlen(hello_string) + 1) < 0) {
334
debug(54, 0) ("write FD %d: %s\n", cwfd, xstrerror());
335
debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
342
* This double-dup stuff avoids problems when one of
343
* crfd, cwfd, or debug_log are in the rage 0-2.
347
/* First make sure 0-2 is occupied by something. Gets cleaned up later */
350
} while (x < 3 && x > -1);
358
t3 = dup(fileno(debug_log));
360
assert(t1 > 2 && t2 > 2 && t3 > 2);
366
close(fileno(debug_log));
380
/* Make sure all other filedescriptors are closed */
381
for (x = 3; x < SQUID_MAXFD; x++)
385
squid_signal(SIGINT, SIG_IGN, SA_RESETHAND);
386
squid_signal(SIGHUP, SIG_IGN, SA_RESETHAND);
389
execvp(prog, (char *const *) args);
391
debug_log = fdopen(2, "a+");
393
debug(54, 0) ("ipcCreate: %s: %s\n", prog, xstrerror());