]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc.cc
merge changes from SQUID_2_3 branch
[thirdparty/squid.git] / src / ipc.cc
CommitLineData
b13bbe1c 1
2/*
7e3ce7b9 3 * $Id: ipc.cc,v 1.17 1999/12/30 17:36:39 wessels Exp $
b13bbe1c 4 *
5 * DEBUG: section 54 Interprocess Communication
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
b13bbe1c 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
b13bbe1c 19 *
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.
24 *
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.
29 *
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
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
b13bbe1c 34 */
35
36#include "squid.h"
37
38static const char *hello_string = "hi there\n";
39#define HELLO_BUF_SZ 32
40static char hello_buf[HELLO_BUF_SZ];
41
42static int
43ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
44{
45 if (prfd >= 0)
46 comm_close(prfd);
47 if (prfd != pwfd)
48 if (pwfd >= 0)
49 comm_close(pwfd);
50 if (crfd >= 0)
51 comm_close(crfd);
52 if (crfd != cwfd)
53 if (cwfd >= 0)
54 comm_close(cwfd);
55 return -1;
56}
57
58int
59ipcCreate(int type, const char *prog, char *const args[], const char *name, int *rfd, int *wfd)
60{
61 pid_t pid;
62 struct sockaddr_in CS;
63 struct sockaddr_in PS;
64 int crfd = -1;
65 int prfd = -1;
66 int cwfd = -1;
67 int pwfd = -1;
68 int fd;
86ed3fd2 69 int t1, t2, t3;
6637e3a5 70 socklen_t len;
b13bbe1c 71 int tmp_s;
c68e9c6b 72#if HAVE_PUTENV
b13bbe1c 73 char *env_str;
c68e9c6b 74#endif
b13bbe1c 75 int x;
76
91ef94d6 77#if HAVE_POLL && defined(_SQUID_OSF_)
78 assert(type != IPC_FIFO);
79#endif
80
b13bbe1c 81 if (rfd)
82 *rfd = -1;
83 if (wfd)
84 *wfd = -1;
85 if (type == IPC_TCP_SOCKET) {
86 crfd = cwfd = comm_open(SOCK_STREAM,
87 0,
88 local_addr,
89 0,
90 COMM_NOCLOEXEC,
91 name);
92 prfd = pwfd = comm_open(SOCK_STREAM,
93 0, /* protocol */
94 local_addr,
95 0, /* port */
96 0, /* blocking */
97 name);
98 } else if (type == IPC_UDP_SOCKET) {
99 crfd = cwfd = comm_open(SOCK_DGRAM,
100 0,
101 local_addr,
102 0,
103 COMM_NOCLOEXEC,
104 name);
105 prfd = pwfd = comm_open(SOCK_DGRAM,
106 0,
107 local_addr,
108 0,
109 0,
110 name);
111 } else if (type == IPC_FIFO) {
112 int p2c[2];
113 int c2p[2];
114 if (pipe(p2c) < 0) {
115 debug(50, 0) ("ipcCreate: pipe: %s\n", xstrerror());
116 return -1;
117 }
118 if (pipe(c2p) < 0) {
119 debug(50, 0) ("ipcCreate: pipe: %s\n", xstrerror());
120 return -1;
121 }
122 fd_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
123 fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write");
124 fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read");
125 fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
126 } else {
127 assert(IPC_NONE);
128 }
129 debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd);
130 debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd);
131 debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd);
132 debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd);
133
134 if (crfd < 0) {
135 debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
136 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
137 }
138 if (pwfd < 0) {
139 debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
140 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
141 }
142 if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
143 len = sizeof(PS);
144 memset(&PS, '\0', len);
145 if (getsockname(pwfd, (struct sockaddr *) &PS, &len) < 0) {
146 debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
147 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
148 }
149 debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
150 pwfd, inet_ntoa(PS.sin_addr), ntohs(PS.sin_port));
151 len = sizeof(CS);
152 memset(&CS, '\0', len);
153 if (getsockname(crfd, (struct sockaddr *) &CS, &len) < 0) {
154 debug(50, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
155 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
156 }
157 debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
158 crfd, inet_ntoa(CS.sin_addr), ntohs(CS.sin_port));
159 }
160 if (type == IPC_TCP_SOCKET) {
161 if (listen(crfd, 1) < 0) {
0e473d70 162 debug(50, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror());
b13bbe1c 163 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
164 }
165 debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
166 }
b13bbe1c 167 /* flush or else we get dup data if unbuffered_logs is set */
168 logsFlush();
169 if ((pid = fork()) < 0) {
a60f7062 170 debug(50, 1) ("ipcCreate: fork: %s\n", xstrerror());
b13bbe1c 171 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
172 }
173 if (pid > 0) { /* parent */
174 /* close shared socket with child */
175 comm_close(crfd);
176 if (cwfd != crfd)
177 comm_close(cwfd);
178 cwfd = crfd = -1;
179 if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
180 if (comm_connect_addr(pwfd, &CS) == COMM_ERROR)
181 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
182 }
183 memset(hello_buf, '\0', HELLO_BUF_SZ);
184 if (type == IPC_UDP_SOCKET)
9bc73deb 185 x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);
b13bbe1c 186 else
9bc73deb 187 x = read(prfd, hello_buf, HELLO_BUF_SZ - 1);
b13bbe1c 188 if (x < 0) {
189 debug(50, 0) ("ipcCreate: PARENT: hello read test failed\n");
190 debug(50, 0) ("--> read: %s\n", xstrerror());
191 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
192 } else if (strcmp(hello_buf, hello_string)) {
6f6f0853 193 debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
9bc73deb 194 debug(54, 0) ("--> read returned %d\n", x);
6f6f0853 195 debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
b13bbe1c 196 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
197 }
198 commSetTimeout(prfd, -1, NULL, NULL);
199 commSetNonBlocking(prfd);
200 commSetNonBlocking(pwfd);
201 if (rfd)
202 *rfd = prfd;
203 if (wfd)
204 *wfd = pwfd;
de718ec4 205 fd_table[prfd].flags.ipc = 1;
206 fd_table[pwfd].flags.ipc = 1;
b13bbe1c 207 return pwfd;
208 }
209 /* child */
210 no_suid(); /* give up extra priviliges */
211 /* close shared socket with parent */
2dde67ef 212 close(prfd);
b13bbe1c 213 if (pwfd != prfd)
2dde67ef 214 close(pwfd);
b13bbe1c 215 pwfd = prfd = -1;
216
217 if (type == IPC_TCP_SOCKET) {
218 debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
219 if ((fd = accept(crfd, NULL, NULL)) < 0) {
220 debug(50, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
221 _exit(1);
222 }
54f742e7 223 debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
b13bbe1c 224 close(crfd);
225 cwfd = crfd = fd;
226 } else if (type == IPC_UDP_SOCKET) {
0e473d70 227 if (comm_connect_addr(crfd, &PS) == COMM_ERROR)
228 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
b13bbe1c 229 }
b13bbe1c 230 if (type == IPC_UDP_SOCKET) {
231 x = send(cwfd, hello_string, strlen(hello_string), 0);
232 if (x < 0) {
233 debug(50, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
234 debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n");
235 _exit(1);
236 }
237 } else {
238 if (write(cwfd, hello_string, strlen(hello_string)) < 0) {
239 debug(50, 0) ("write FD %d: %s\n", cwfd, xstrerror());
240 debug(50, 0) ("ipcCreate: CHILD: hello write test failed\n");
241 _exit(1);
242 }
243 }
c68e9c6b 244#if HAVE_PUTENV
b13bbe1c 245 env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
246 snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
247 putenv(env_str);
c68e9c6b 248#endif
b13bbe1c 249 /*
86ed3fd2 250 * This double-dup stuff avoids problems when one of
251 * crfd, cwfd, or debug_log are in the rage 0-2.
b13bbe1c 252 */
86ed3fd2 253 do {
254 x = open(_PATH_DEVNULL, 0, 0444);
7e3ce7b9 255 if (x > -1)
256 commSetCloseOnExec(x);
86ed3fd2 257 } while (x < 3);
258 t1 = dup(crfd);
259 t2 = dup(cwfd);
260 t3 = dup(fileno(debug_log));
261 assert(t1 > 2 && t2 > 2 && t3 > 2);
262 close(crfd);
263 close(cwfd);
264 close(fileno(debug_log));
265 dup2(t1, 0);
266 dup2(t2, 1);
267 dup2(t3, 2);
268 close(t1);
269 close(t2);
270 close(t3);
c1f0aa2e 271#if HAVE_SETSID
272 setsid();
273#endif
b13bbe1c 274 execvp(prog, args);
275 debug(50, 0) ("ipcCreate: %s: %s\n", prog, xstrerror());
276 _exit(1);
277 return 0;
278}