~clint-fewbar/ubuntu/precise/squid3/ignore-sighup-early

« back to all changes in this revision

Viewing changes to src/ipc.cc

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2006-11-11 10:32:06 UTC
  • Revision ID: james.westby@ubuntu.com-20061111103206-f3p0r9g0vq44rp3r
Tags: upstream-3.0.PRE5
ImportĀ upstreamĀ versionĀ 3.0.PRE5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * $Id: ipc.cc,v 1.44 2006/09/03 19:28:10 serassio Exp $
 
4
 *
 
5
 * DEBUG: section 54    Interprocess Communication
 
6
 * AUTHOR: Duane Wessels
 
7
 *
 
8
 * SQUID Web Proxy Cache          http://www.squid-cache.org/
 
9
 * ----------------------------------------------------------
 
10
 *
 
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.
 
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
 
32
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 
33
 *
 
34
 */
 
35
 
 
36
#include "squid.h"
 
37
#include "comm.h"
 
38
#include "fde.h"
 
39
 
 
40
static const char *hello_string = "hi there\n";
 
41
#define HELLO_BUF_SZ 32
 
42
static char hello_buf[HELLO_BUF_SZ];
 
43
 
 
44
static int
 
45
ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
 
46
{
 
47
    if (prfd >= 0)
 
48
        comm_close(prfd);
 
49
 
 
50
    if (prfd != pwfd)
 
51
        if (pwfd >= 0)
 
52
            comm_close(pwfd);
 
53
 
 
54
    if (crfd >= 0)
 
55
        comm_close(crfd);
 
56
 
 
57
    if (crfd != cwfd)
 
58
        if (cwfd >= 0)
 
59
            comm_close(cwfd);
 
60
 
 
61
    return -1;
 
62
}
 
63
 
 
64
static void
 
65
PutEnvironment()
 
66
{
 
67
#if HAVE_PUTENV
 
68
    char *env_str;
 
69
    int tmp_s;
 
70
    env_str = (char *)xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
 
71
    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
 
72
    putenv(env_str);
 
73
#endif
 
74
}
 
75
 
 
76
pid_t
 
77
ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, void **hIpc)
 
78
{
 
79
    pid_t pid;
 
80
 
 
81
    struct sockaddr_in ChS;
 
82
 
 
83
    struct sockaddr_in PaS;
 
84
    int crfd = -1;
 
85
    int prfd = -1;
 
86
    int cwfd = -1;
 
87
    int pwfd = -1;
 
88
    int fd;
 
89
    int t1, t2, t3;
 
90
    socklen_t len;
 
91
    int x;
 
92
 
 
93
#if USE_POLL && defined(_SQUID_OSF_)
 
94
 
 
95
    assert(type != IPC_FIFO);
 
96
#endif
 
97
 
 
98
    if (rfd)
 
99
        *rfd = -1;
 
100
 
 
101
    if (wfd)
 
102
        *wfd = -1;
 
103
 
 
104
    if (hIpc)
 
105
        *hIpc = NULL;
 
106
 
 
107
    if (type == IPC_TCP_SOCKET) {
 
108
        crfd = cwfd = comm_open(SOCK_STREAM,
 
109
                                0,
 
110
                                local_addr,
 
111
                                0,
 
112
                                COMM_NOCLOEXEC,
 
113
                                name);
 
114
        prfd = pwfd = comm_open(SOCK_STREAM,
 
115
                                0,                      /* protocol */
 
116
                                local_addr,
 
117
                                0,                      /* port */
 
118
                                0,                      /* blocking */
 
119
                                name);
 
120
    } else if (type == IPC_UDP_SOCKET) {
 
121
        crfd = cwfd = comm_open(SOCK_DGRAM,
 
122
                                0,
 
123
                                local_addr,
 
124
                                0,
 
125
                                COMM_NOCLOEXEC,
 
126
                                name);
 
127
        prfd = pwfd = comm_open(SOCK_DGRAM,
 
128
                                0,
 
129
                                local_addr,
 
130
                                0,
 
131
                                0,
 
132
                                name);
 
133
    } else if (type == IPC_FIFO) {
 
134
        int p2c[2];
 
135
        int c2p[2];
 
136
 
 
137
        if (pipe(p2c) < 0) {
 
138
            debug(54, 0) ("ipcCreate: pipe: %s\n", xstrerror());
 
139
            return -1;
 
140
        }
 
141
 
 
142
        if (pipe(c2p) < 0) {
 
143
            debug(54, 0) ("ipcCreate: pipe: %s\n", xstrerror());
 
144
            return -1;
 
145
        }
 
146
 
 
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)
 
152
 
 
153
    } else if (type == IPC_UNIX_STREAM) {
 
154
        int fds[2];
 
155
        int buflen = 32768;
 
156
 
 
157
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
 
158
            debug(54, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
 
159
            return -1;
 
160
        }
 
161
 
 
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) {
 
169
        int fds[2];
 
170
 
 
171
        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
 
172
            debug(54, 0) ("ipcCreate: socketpair: %s\n", xstrerror());
 
173
            return -1;
 
174
        }
 
175
 
 
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");
 
178
#endif
 
179
 
 
180
    } else {
 
181
        assert(IPC_NONE);
 
182
    }
 
183
 
 
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);
 
188
 
 
189
    if (crfd < 0) {
 
190
        debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
 
191
        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
 
192
    }
 
193
 
 
194
    if (pwfd < 0) {
 
195
        debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
 
196
        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
 
197
    }
 
198
 
 
199
    if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
 
200
        len = sizeof(PaS);
 
201
        memset(&PaS, '\0', len);
 
202
 
 
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);
 
206
        }
 
207
 
 
208
        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
 
209
                      pwfd, inet_ntoa(PaS.sin_addr), ntohs(PaS.sin_port));
 
210
        len = sizeof(ChS);
 
211
        memset(&ChS, '\0', len);
 
212
 
 
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);
 
216
        }
 
217
 
 
218
        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
 
219
                      crfd, inet_ntoa(ChS.sin_addr), ntohs(ChS.sin_port));
 
220
    }
 
221
 
 
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);
 
226
        }
 
227
 
 
228
        debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
 
229
    }
 
230
 
 
231
    /* flush or else we get dup data if unbuffered_logs is set */
 
232
    logsFlush();
 
233
 
 
234
    if ((pid = fork()) < 0) {
 
235
        debug(54, 1) ("ipcCreate: fork: %s\n", xstrerror());
 
236
        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
 
237
    }
 
238
 
 
239
    if (pid > 0) {              /* parent */
 
240
        /* close shared socket with child */
 
241
        comm_close(crfd);
 
242
 
 
243
        if (cwfd != crfd)
 
244
            comm_close(cwfd);
 
245
 
 
246
        cwfd = crfd = -1;
 
247
 
 
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);
 
251
        }
 
252
 
 
253
        memset(hello_buf, '\0', HELLO_BUF_SZ);
 
254
 
 
255
        if (type == IPC_UDP_SOCKET)
 
256
            x = comm_udp_recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);
 
257
        else
 
258
            x = read(prfd, hello_buf, HELLO_BUF_SZ - 1);
 
259
 
 
260
        if (x < 0) {
 
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);
 
269
        }
 
270
 
 
271
        commSetTimeout(prfd, -1, NULL, NULL);
 
272
        commSetNonBlocking(prfd);
 
273
        commSetNonBlocking(pwfd);
 
274
 
 
275
        if (rfd)
 
276
            *rfd = prfd;
 
277
 
 
278
        if (wfd)
 
279
            *wfd = pwfd;
 
280
 
 
281
        fd_table[prfd].flags.ipc = 1;
 
282
 
 
283
        fd_table[pwfd].flags.ipc = 1;
 
284
 
 
285
        if (Config.sleep_after_fork) {
 
286
            /* XXX emulation of usleep() */
 
287
 
 
288
            struct timeval sl;
 
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);
 
292
        }
 
293
 
 
294
        return pid;
 
295
    }
 
296
 
 
297
    /* child */
 
298
    no_suid();                  /* give up extra priviliges */
 
299
 
 
300
    /* close shared socket with parent */
 
301
    close(prfd);
 
302
 
 
303
    if (pwfd != prfd)
 
304
        close(pwfd);
 
305
 
 
306
    pwfd = prfd = -1;
 
307
 
 
308
    if (type == IPC_TCP_SOCKET) {
 
309
        debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
 
310
 
 
311
        if ((fd = accept(crfd, NULL, NULL)) < 0) {
 
312
            debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
 
313
            _exit(1);
 
314
        }
 
315
 
 
316
        debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
 
317
        close(crfd);
 
318
        cwfd = crfd = fd;
 
319
    } else if (type == IPC_UDP_SOCKET) {
 
320
        if (comm_connect_addr(crfd, &PaS) == COMM_ERROR)
 
321
            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
 
322
    }
 
323
 
 
324
    if (type == IPC_UDP_SOCKET) {
 
325
        x = comm_udp_send(cwfd, hello_string, strlen(hello_string) + 1, 0);
 
326
 
 
327
        if (x < 0) {
 
328
            debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
 
329
            debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
 
330
            _exit(1);
 
331
        }
 
332
    } else {
 
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");
 
336
            _exit(1);
 
337
        }
 
338
    }
 
339
 
 
340
    PutEnvironment();
 
341
    /*
 
342
     * This double-dup stuff avoids problems when one of 
 
343
     *  crfd, cwfd, or debug_log are in the rage 0-2.
 
344
     */
 
345
 
 
346
    do {
 
347
        /* First make sure 0-2 is occupied by something. Gets cleaned up later */
 
348
        x = dup(crfd);
 
349
        assert(x > -1);
 
350
    } while (x < 3 && x > -1);
 
351
 
 
352
    close(x);
 
353
 
 
354
    t1 = dup(crfd);
 
355
 
 
356
    t2 = dup(cwfd);
 
357
 
 
358
    t3 = dup(fileno(debug_log));
 
359
 
 
360
    assert(t1 > 2 && t2 > 2 && t3 > 2);
 
361
 
 
362
    close(crfd);
 
363
 
 
364
    close(cwfd);
 
365
 
 
366
    close(fileno(debug_log));
 
367
 
 
368
    dup2(t1, 0);
 
369
 
 
370
    dup2(t2, 1);
 
371
 
 
372
    dup2(t3, 2);
 
373
 
 
374
    close(t1);
 
375
 
 
376
    close(t2);
 
377
 
 
378
    close(t3);
 
379
 
 
380
    /* Make sure all other filedescriptors are closed */
 
381
    for (x = 3; x < SQUID_MAXFD; x++)
 
382
        close(x);
 
383
 
 
384
    if (opt_no_daemon) {
 
385
        squid_signal(SIGINT, SIG_IGN, SA_RESETHAND);
 
386
        squid_signal(SIGHUP, SIG_IGN, SA_RESETHAND);
 
387
    }
 
388
 
 
389
    execvp(prog, (char *const *) args);
 
390
 
 
391
    debug_log = fdopen(2, "a+");
 
392
 
 
393
    debug(54, 0) ("ipcCreate: %s: %s\n", prog, xstrerror());
 
394
 
 
395
    _exit(1);
 
396
 
 
397
    return 0;
 
398
}