~ubuntu-branches/ubuntu/karmic/dante/karmic

« back to all changes in this revision

Viewing changes to sockd/sockd_child.c

  • Committer: Bazaar Package Importer
  • Author(s): Adrian Bridgett
  • Date: 2002-04-07 12:45:55 UTC
  • Revision ID: james.westby@ubuntu.com-20020407124555-qke8rt2tdor0naz2
Tags: upstream-1.1.11.12p1
ImportĀ upstreamĀ versionĀ 1.1.11.12p1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1997, 1998, 1999, 2000, 2001
 
3
 *      Inferno Nettverk A/S, Norway.  All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. The above copyright notice, this list of conditions and the following
 
9
 *    disclaimer must appear in all copies of the software, derivative works
 
10
 *    or modified versions, and any portions thereof, aswell as in all
 
11
 *    supporting documentation.
 
12
 * 2. All advertising materials mentioning features or use of this software
 
13
 *    must display the following acknowledgement:
 
14
 *      This product includes software developed by
 
15
 *      Inferno Nettverk A/S, Norway.
 
16
 * 3. The name of the author may not be used to endorse or promote products
 
17
 *    derived from this software without specific prior written permission.
 
18
 *
 
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
20
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
22
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
24
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 *
 
30
 * Inferno Nettverk A/S requests users of this software to return to
 
31
 *
 
32
 *  Software Distribution Coordinator  or  sdc@inet.no
 
33
 *  Inferno Nettverk A/S
 
34
 *  Oslo Research Park
 
35
 *  Gaustadallļæ½en 21
 
36
 *  NO-0349 Oslo
 
37
 *  Norway
 
38
 *
 
39
 * any improvements or extensions that they make and grant Inferno Nettverk A/S
 
40
 * the rights to redistribute these changes.
 
41
 *
 
42
 */
 
43
 
 
44
#include "common.h"
 
45
 
 
46
static const char rcsid[] =
 
47
"$Id: sockd_child.c,v 1.134 2001/12/18 12:38:51 karls Exp $";
 
48
 
 
49
#define MOTHER  0       /* descriptor mother reads/writes on.   */
 
50
#define CHILD   1       /* descriptor child reads/writes on.    */
 
51
 
 
52
__BEGIN_DECLS
 
53
 
 
54
static int
 
55
setchildtype __P((int type, struct sockd_child_t ***childv, int **childc,
 
56
                                                void (**function)(struct sockd_mother_t *mother)));
 
57
/*
 
58
 * Sets "childv", "childc" and "function" to the correct value depending
 
59
 * on "type".
 
60
 */
 
61
 
 
62
 
 
63
static int
 
64
findchild __P((pid_t pid, int childc, const struct sockd_child_t *childv));
 
65
/*
 
66
 * Finds the child with pid "pid" in the array "childv".  Searching
 
67
 * Elements in "childv" is given by "childc".
 
68
 * Returns:
 
69
 *              On success: the index of the child in "childv".
 
70
 *              On failure: -1.
 
71
 */
 
72
 
 
73
__END_DECLS
 
74
 
 
75
 
 
76
static struct sockd_child_t *iochildv;                          /* all our iochildren                   */
 
77
static int iochildc;
 
78
 
 
79
static struct sockd_child_t *negchildv;                 /* all our negotiatorchildren */
 
80
static int negchildc;
 
81
 
 
82
static struct sockd_child_t *reqchildv;                 /* all our requestchildren              */
 
83
static int reqchildc;
 
84
 
 
85
 
 
86
struct sockd_child_t *
 
87
addchild(type)
 
88
        int type;
 
89
{
 
90
        const char *function = "addchild()";
 
91
        /*
 
92
         * It is better to reserve some descriptors for temporary use
 
93
         * than to get errors when passing them and thus lose clients.
 
94
         */
 
95
        const int reserved = FDPASS_MAX /* max descriptors we pass.                     */
 
96
                                                         + 1                            /* need a descriptor for accept().      */
 
97
                                                         + 2;                           /* for each new child.                                  */
 
98
        struct sockd_mother_t mother;
 
99
        struct sockd_child_t **childv;
 
100
        int *childc;
 
101
        void (*childfunction)(struct sockd_mother_t *mother);
 
102
        pid_t pid;
 
103
        int optval, flags;
 
104
        int pipev[] = { -1, -1 };
 
105
        int ackpipev[] = { -1, -1 };
 
106
 
 
107
        /*
 
108
         * XXX This is a expensive test which shouldn't be hard to optimize
 
109
         * away.  It only happens when we are running low on slots though,
 
110
         * so assume it's "good enough" until I get the time to fix it.
 
111
         */
 
112
        if (freedescriptors(NULL) < reserved) {
 
113
                errno = EMFILE;
 
114
                swarn(function);
 
115
                return NULL;
 
116
        }
 
117
 
 
118
        /* create datapipe. */
 
119
        if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) {
 
120
                swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function);
 
121
                return NULL;
 
122
        }
 
123
 
 
124
        /* and ackpipe. */
 
125
        if (pipe(ackpipev) != 0) {
 
126
                swarn("%s: pipe()", function);
 
127
                closev(pipev, ELEMENTS(pipev));
 
128
                return NULL;
 
129
        }
 
130
 
 
131
        /*
 
132
         * Try to set socketbuffer and watermarks to a optimal size.
 
133
         */
 
134
        switch (type = setchildtype(type, &childv, &childc, &childfunction)) {
 
135
                case CHILD_NEGOTIATE:
 
136
                        /*
 
137
                         * A negotiator child receives only descriptors, so mothers
 
138
                         * send buffer can be small, and so can the child's receive buffer.
 
139
                         * The child sends a sockd_request_t struct back to mother, so
 
140
                         * mothers recv buffer has to be considerably bigger, as does
 
141
                         * childs send buffer.
 
142
                         */
 
143
 
 
144
                        /* negotiator shouldn't block on sending to mother. */
 
145
                        if ((flags = fcntl(pipev[CHILD], F_GETFL, 0)) == -1
 
146
                        ||  fcntl(pipev[CHILD], F_SETFL, flags | O_NONBLOCK) == -1)
 
147
                                swarn("%s: fcntl()", function);
 
148
 
 
149
#if HAVE_SENDMSG_DEADLOCK
 
150
                        if ((mother.lock = socks_mklock(SOCKS_LOCKFILE)) == -1) {
 
151
                                swarn("%s: socks_mklock()", function);
 
152
                                closev(pipev, ELEMENTS(pipev));
 
153
                                closev(ackpipev, ELEMENTS(ackpipev));
 
154
                                return NULL;
 
155
                        }
 
156
#endif /* HAVE_SENDMSG_DEADLOCK */
 
157
 
 
158
                        optval = sizeof(struct sockd_request_t) * (SOCKD_NEGOTIATEMAX + 1);
 
159
                        if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,
 
160
                        sizeof(optval)) != 0
 
161
                        ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,
 
162
                        sizeof(optval)) != 0)
 
163
                                swarn("%s: setsockopt(SO_RCVBUF/SO_SNDBUF)", function);
 
164
 
 
165
#if HAVE_SO_SNDLOWAT
 
166
                        optval = sizeof(struct sockd_request_t) * LOWATSKEW;
 
167
                        if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDLOWAT, &optval,
 
168
                        sizeof(optval)) != 0
 
169
                        || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVLOWAT, &optval,
 
170
                        sizeof(optval)) != 0)
 
171
                                swarn("%s: setsockopt(SO_SNDLOWAT/SO_RCVLOWAT)", function);
 
172
#endif
 
173
                        break;
 
174
 
 
175
                case CHILD_REQUEST:
 
176
                        /*
 
177
                         * A request child receives a sockd_request_t structure,
 
178
                         * it sends back a sockd_io_t structure.
 
179
                         */
 
180
 
 
181
#if HAVE_SENDMSG_DEADLOCK
 
182
                        mother.lock = -1;       /* doesn't need lock. */
 
183
#endif /* HAVE_SENDMSG_DEADLOCK */
 
184
 
 
185
                        optval = sizeof(struct sockd_request_t) * (SOCKD_REQUESTMAX + 1);
 
186
                        if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDBUF, &optval,
 
187
                        sizeof(optval)) != 0
 
188
                        ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVBUF, &optval,
 
189
                        sizeof(optval)) != 0)
 
190
                                swarn("%s: setsockopt()", function);
 
191
 
 
192
                        optval = sizeof(struct sockd_io_t) * (SOCKD_REQUESTMAX + 1);
 
193
                        if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,
 
194
                        sizeof(optval)) != 0
 
195
                        ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,
 
196
                        sizeof(optval)) != 0)
 
197
                                swarn("%s: setsockopt()", function);
 
198
 
 
199
#if HAVE_SO_SNDLOWAT
 
200
                        optval = sizeof(struct sockd_request_t) * LOWATSKEW;
 
201
                        if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVLOWAT, &optval,
 
202
                        sizeof(optval)) != 0
 
203
                        || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDLOWAT, &optval,
 
204
                        sizeof(optval)) != 0)
 
205
                                swarn("%s: setsockopt(SO_RCVLOWAT)", function);
 
206
 
 
207
                        optval = sizeof(struct sockd_io_t) * LOWATSKEW;
 
208
                        if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDLOWAT, &optval,
 
209
                        sizeof(optval)) != 0
 
210
                        || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVLOWAT, &optval,
 
211
                        sizeof(optval)) != 0)
 
212
                                swarn("%s: setsockopt(SO_RCVLOWAT/SO_SNDLOWAT)", function);
 
213
#endif
 
214
                        break;
 
215
 
 
216
                case CHILD_IO:
 
217
                        /*
 
218
                         * A io child receives a sockd_io_t structure,
 
219
                         * it sends back only a ack.
 
220
                         */
 
221
 
 
222
#if HAVE_SENDMSG_DEADLOCK
 
223
                        mother.lock = -1;       /* doesn't need lock. */
 
224
#endif /* HAVE_SENDMSG_DEADLOCK */
 
225
 
 
226
                        optval = sizeof(struct sockd_io_t) * (SOCKD_IOMAX + 1);
 
227
                        if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDBUF, &optval,
 
228
                        sizeof(optval)) != 0
 
229
                        ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVBUF, &optval,
 
230
                        sizeof(optval)) != 0)
 
231
                                swarn("%s: setsockopt(SO_SNDBUF/SO_RCVBUF)", function);
 
232
 
 
233
                        optval = sizeof(int) * (SOCKD_IOMAX + 1);
 
234
                        if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,
 
235
                        sizeof(optval)) != 0
 
236
                        ||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,
 
237
                        sizeof(optval)) != 0)
 
238
                                swarn("%s: setsockopt(SO_RCVBUF/SO_SNDBUF)", function);
 
239
 
 
240
#if HAVE_SO_SNDLOWAT
 
241
                        optval = sizeof(struct sockd_io_t) * LOWATSKEW;
 
242
                        if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVLOWAT, &optval,
 
243
                        sizeof(optval)) != 0
 
244
                        || setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDLOWAT, &optval,
 
245
                        sizeof(optval)) != 0)
 
246
                                swarn("%s: setsockopt(SO_RCVLOWAT)", function);
 
247
#endif
 
248
                        break;
 
249
 
 
250
                default:
 
251
                        SERRX(type);
 
252
        }
 
253
 
 
254
        switch ((pid = fork())) {
 
255
                case -1:
 
256
                        swarn("%s: fork()", function);
 
257
                        closev(pipev, ELEMENTS(pipev));
 
258
                        closev(ackpipev, ELEMENTS(ackpipev));
 
259
 
 
260
#if HAVE_SENDMSG_DEADLOCK
 
261
                        if (mother.lock != -1)
 
262
                                close(mother.lock);
 
263
#endif /* HAVE_SENDMSG_DEADLOCK */
 
264
 
 
265
                        return NULL;
 
266
 
 
267
                case 0: {
 
268
                        size_t i, maxfd;
 
269
                        struct sigaction sigact;
 
270
 
 
271
                        sockscf.state.type      = type;
 
272
 
 
273
                        sockscf.state.pid       = getpid(); /* for logmessage. */
 
274
                        slog(LOG_INFO, "created new %schild", childtype2string(type));
 
275
#if 0
 
276
                        slog(LOG_DEBUG, "sleeping...");
 
277
                        sleep(20);
 
278
#endif
 
279
 
 
280
                        mother.s                = pipev[CHILD];
 
281
                        mother.ack      = ackpipev[CHILD];
 
282
 
 
283
                        /*
 
284
                         * It would be nice to be able to lose all privileges here
 
285
                         * but unfortunately we can't, yet.
 
286
                         *
 
287
                         * negotiation children:
 
288
                         *              could need privileges to check password.
 
289
                         *
 
290
                         * request children:
 
291
                         *              could need privileges to bind port.
 
292
                         *
 
293
                         * io children:
 
294
                         *              could need privileges to bind port if using redirect()
 
295
                         *              module, also SIGHUP performs misc. seteuid() tests that
 
296
                         *    could fail if we lose privileges.
 
297
                         */
 
298
 
 
299
                        switch (type) {
 
300
                                case CHILD_NEGOTIATE:
 
301
#if HAVE_LIBWRAP
 
302
#if SOCKD_NEGOTIATEMAX > 1
 
303
                                        resident = 1;
 
304
#endif /* SOCKD_NEGOTIATEMAX > 1 */
 
305
#endif  /* HAVE_LIBWRAP */
 
306
                                        break;
 
307
 
 
308
                                case CHILD_REQUEST:
 
309
#if HAVE_LIBWRAP
 
310
#if SOCKD_REQUESTMAX > 1
 
311
                                        resident = 1;
 
312
#endif /* SOCKD_REQUESTMAX > 1 */
 
313
#endif  /* HAVE_LIBWRAP */
 
314
                                        break;
 
315
 
 
316
                                case CHILD_IO:
 
317
#if HAVE_LIBWRAP
 
318
#if SOCKD_IOMAX > 1
 
319
                                        resident = 1;
 
320
#endif /* SOCKD_IOMAX > 1 */
 
321
#endif  /* HAVE_LIBWRAP */
 
322
                                        break;
 
323
 
 
324
                                default:
 
325
                                        SERRX(type);
 
326
                        }
 
327
 
 
328
                        sigemptyset(&sigact.sa_mask);
 
329
                        sigact.sa_flags = 0;
 
330
 
 
331
                        /* signals mother has set up but which we ignore at this point. */
 
332
                        sigact.sa_handler = SIG_IGN;
 
333
 
 
334
#if HAVE_SIGNAL_SIGINFO
 
335
                        if (sigaction(SIGINFO, &sigact, NULL) != 0)
 
336
                                swarn("%s: sigaction(SIGINFO)", function);
 
337
#endif  /* HAVE_SIGNAL_SIGINFO */
 
338
 
 
339
                        if (sigaction(SIGUSR1, &sigact, NULL) != 0)
 
340
                                swarn("%s: sigaction(USR1)", function);
 
341
 
 
342
                        /* delete everything we got from parent. */
 
343
                        for (i = 0, maxfd = getdtablesize(); i < maxfd; ++i) {
 
344
                                /* exceptions */
 
345
                                if (i == (size_t)mother.s
 
346
#if HAVE_SENDMSG_DEADLOCK
 
347
                                ||      i == (size_t)mother.lock
 
348
#endif /* HAVE_SENDMSG_DEADLOCK */
 
349
                                ||      i == (size_t)mother.ack)
 
350
                                        continue;
 
351
 
 
352
                                if (descriptorisreserved(i))
 
353
                                        continue;
 
354
 
 
355
                                close((int)i);
 
356
                        }
 
357
                        newprocinit();
 
358
 
 
359
                        childfunction(&mother);
 
360
                        /* NOTREACHED */
 
361
                }
 
362
 
 
363
                default: {
 
364
                        struct sockd_child_t *newchildv;
 
365
 
 
366
                        if ((newchildv = (struct sockd_child_t *)realloc(*childv,
 
367
                        sizeof(**childv) * (*childc + 1))) == NULL) {
 
368
                                slog(LOG_WARNING, "%s: %s", function, NOMEM);
 
369
                                closev(pipev, ELEMENTS(pipev));
 
370
                                closev(ackpipev, ELEMENTS(ackpipev));
 
371
                                return NULL;
 
372
                        }
 
373
                        *childv = newchildv;
 
374
 
 
375
                        (*childv)[*childc].type = type;
 
376
                        (*childv)[*childc].pid  = pid;
 
377
                        (*childv)[*childc].s            = pipev[MOTHER];
 
378
#if HAVE_SENDMSG_DEADLOCK
 
379
                        (*childv)[*childc].lock = mother.lock;
 
380
#endif /* HAVE_SENDMSG_DEADLOCK */
 
381
                        (*childv)[*childc].ack  = ackpipev[MOTHER];
 
382
 
 
383
                        close(pipev[CHILD]);
 
384
                        close(ackpipev[CHILD]);
 
385
 
 
386
                        switch ((*childv)[*childc].type) {
 
387
                                case CHILD_NEGOTIATE:
 
388
                                        (*childv)[*childc].freec = SOCKD_NEGOTIATEMAX;
 
389
                                        break;
 
390
 
 
391
                                case CHILD_REQUEST:
 
392
                                        (*childv)[*childc].freec = SOCKD_REQUESTMAX;
 
393
                                        break;
 
394
 
 
395
                                case CHILD_IO:
 
396
                                        (*childv)[*childc].freec = SOCKD_IOMAX;
 
397
                                        break;
 
398
 
 
399
                                default:
 
400
                                        SERRX((*childv)[*childc].type);
 
401
                        }
 
402
 
 
403
                        return &(*childv)[(*childc)++];
 
404
                }
 
405
        }
 
406
}
 
407
 
 
408
int
 
409
childcheck(type)
 
410
        int type;
 
411
{
 
412
        int child, proxyc;
 
413
        int min, max;
 
414
        struct sockd_child_t **childv;
 
415
        int *childc;
 
416
 
 
417
        switch (type) {
 
418
                case -CHILD_NEGOTIATE:
 
419
                case CHILD_NEGOTIATE:
 
420
                        childc  = &negchildc;
 
421
                        childv  = &negchildv;
 
422
                        min             = SOCKD_FREESLOTS;
 
423
                        max             = SOCKD_NEGOTIATEMAX;
 
424
                        break;
 
425
 
 
426
                case -CHILD_REQUEST:
 
427
                case CHILD_REQUEST:
 
428
                        childc  = &reqchildc;
 
429
                        childv  = &reqchildv;
 
430
                        min             = SOCKD_FREESLOTS;
 
431
                        max             = SOCKD_REQUESTMAX;
 
432
                        break;
 
433
 
 
434
                case -CHILD_IO:
 
435
                case CHILD_IO:
 
436
                        childc  = &iochildc;
 
437
                        childv  = &iochildv;
 
438
                        /* attempt to keep in a state where we can accept all requests. */
 
439
                        min             = MAX(SOCKD_FREESLOTS, childcheck(-CHILD_REQUEST));
 
440
                        max             = SOCKD_IOMAX;
 
441
                        break;
 
442
 
 
443
                default:
 
444
                        SERRX(type);
 
445
        }
 
446
 
 
447
        /*
 
448
         * get a estimate over how many (new) clients our children are able to
 
449
         * accept in total.
 
450
    */
 
451
        for (child = 0, proxyc = 0; child < *childc; ++child) {
 
452
                SASSERTX((*childv)[child].freec <= max);
 
453
                proxyc += type < 0 ? max : (*childv)[child].freec;
 
454
        }
 
455
 
 
456
        if (type >= 0)
 
457
                if (proxyc < min && sockscf.state.addchild)
 
458
                        if (addchild(type) != NULL)
 
459
                                return childcheck(type);
 
460
                        else
 
461
                                sockscf.state.addchild = 0;     /* don't retry until a child dies. */
 
462
 
 
463
        return proxyc;
 
464
}
 
465
 
 
466
int
 
467
fillset(set)
 
468
        fd_set *set;
 
469
{
 
470
        const char *function = "fillset()";
 
471
        int negc, reqc, ioc;
 
472
        int i, dbits;
 
473
 
 
474
        /*
 
475
         * There is no point in setting data descriptor of child N unless
 
476
         * child N+1 is able to accept the data from child N.  So find
 
477
         * out if we have slots of the various types available .
 
478
         */
 
479
 
 
480
        ioc     = childcheck(CHILD_IO);
 
481
        reqc    = childcheck(CHILD_REQUEST);
 
482
        negc    = childcheck(CHILD_NEGOTIATE);
 
483
 
 
484
        FD_ZERO(set);
 
485
        dbits = -1;
 
486
 
 
487
        /* new clients we accept. */
 
488
        if (negc > 0)
 
489
                for (i = 0; i < sockscf.internalc; ++i) {
 
490
                        SASSERTX(sockscf.internalv[i].s >= 0);
 
491
                        FD_SET(sockscf.internalv[i].s, set);
 
492
                        dbits = MAX(dbits, sockscf.internalv[i].s);
 
493
                }
 
494
 
 
495
        /* negotiator children. */
 
496
        for (i = 0; i < negchildc; ++i) {
 
497
                if (reqc > 0) {
 
498
                        SASSERTX(negchildv[i].s >= 0);
 
499
                        FD_SET(negchildv[i].s, set);
 
500
                        dbits = MAX(dbits, negchildv[i].s);
 
501
                }
 
502
 
 
503
                /* we can always accept a ack ofcourse. */
 
504
                SASSERTX(negchildv[i].ack >= 0);
 
505
                FD_SET(negchildv[i].ack, set);
 
506
                dbits = MAX(dbits, negchildv[i].ack);
 
507
        }
 
508
 
 
509
        /* request children. */
 
510
        for (i = 0; i < reqchildc; ++i) {
 
511
                if (ioc > 0) {
 
512
                        SASSERTX(reqchildv[i].s >= 0);
 
513
                        FD_SET(reqchildv[i].s, set);
 
514
                        dbits = MAX(dbits, reqchildv[i].s);
 
515
                }
 
516
 
 
517
                /* we can always accept a ack ofcourse. */
 
518
                SASSERTX(reqchildv[i].ack >= 0);
 
519
                FD_SET(reqchildv[i].ack, set);
 
520
                dbits = MAX(dbits, reqchildv[i].ack);
 
521
        }
 
522
 
 
523
        /* io children, last in chain. */
 
524
        for (i = 0; i < iochildc; ++i) {
 
525
                SASSERTX(iochildv[i].s >= 0);
 
526
                FD_SET(iochildv[i].s, set);
 
527
                dbits = MAX(dbits, iochildv[i].s);
 
528
 
 
529
                SASSERTX(iochildv[i].ack >= 0);
 
530
                FD_SET(iochildv[i].ack, set);
 
531
                dbits = MAX(dbits, iochildv[i].ack);
 
532
        }
 
533
 
 
534
        return dbits;
 
535
}
 
536
 
 
537
void
 
538
clearset(type, child, set)
 
539
        int type;
 
540
        const struct sockd_child_t *child;
 
541
        fd_set *set;
 
542
{
 
543
 
 
544
        switch (type) {
 
545
                case SOCKD_FREESLOT:
 
546
                        FD_CLR(child->ack, set);
 
547
                        break;
 
548
 
 
549
                case SOCKD_NEWREQUEST:
 
550
                        FD_CLR(child->s, set);
 
551
                        break;
 
552
 
 
553
                default:
 
554
                        SERRX(type);
 
555
        }
 
556
}
 
557
 
 
558
 
 
559
struct sockd_child_t *
 
560
getset(type, set)
 
561
        int type;
 
562
        fd_set *set;
 
563
{
 
564
        int i;
 
565
 
 
566
        /* check negotiator children for match. */
 
567
        for (i = 0; i < negchildc; ++i)
 
568
                switch (type) {
 
569
                        case SOCKD_NEWREQUEST:
 
570
                                if (FD_ISSET(negchildv[i].s, set))
 
571
                                        return &negchildv[i];
 
572
                                break;
 
573
 
 
574
                        case SOCKD_FREESLOT:
 
575
                                if (FD_ISSET(negchildv[i].ack, set))
 
576
                                        return &negchildv[i];
 
577
                                break;
 
578
                }
 
579
 
 
580
        /* check request children for match. */
 
581
        for (i = 0; i < reqchildc; ++i)
 
582
                switch (type) {
 
583
                        case SOCKD_NEWREQUEST:
 
584
                                if (FD_ISSET(reqchildv[i].s, set))
 
585
                                        return &reqchildv[i];
 
586
                                break;
 
587
 
 
588
                        case SOCKD_FREESLOT:
 
589
                                if (FD_ISSET(reqchildv[i].ack, set))
 
590
                                        return &reqchildv[i];
 
591
                                break;
 
592
                }
 
593
 
 
594
        /* check io children for match. */
 
595
        for (i = 0; i < iochildc; ++i)
 
596
                switch (type) {
 
597
                        case SOCKD_NEWREQUEST:
 
598
                                if (FD_ISSET(iochildv[i].s, set))
 
599
                                        return &iochildv[i];
 
600
                                break;
 
601
 
 
602
                        case SOCKD_FREESLOT:
 
603
                                if (FD_ISSET(iochildv[i].ack, set))
 
604
                                        return &iochildv[i];
 
605
                                break;
 
606
                }
 
607
 
 
608
        return NULL;
 
609
}
 
610
 
 
611
 
 
612
int
 
613
removechild(pid)
 
614
        pid_t pid;
 
615
{
 
616
        const char *function = "removechild()";
 
617
        struct sockd_child_t **childv;
 
618
        struct sockd_child_t *newchildv;
 
619
        int *childc;
 
620
        int child;
 
621
 
 
622
        slog(LOG_DEBUG, "%s: %d", function, (int)pid);
 
623
 
 
624
        setchildtype(childtype(pid), &childv, &childc, NULL);
 
625
 
 
626
        child = findchild(pid, *childc, *childv);
 
627
        SASSERTX(child >= 0);
 
628
 
 
629
        close((*childv)[child].s);
 
630
        close((*childv)[child].ack);
 
631
 
 
632
        /* shift all following one down */
 
633
        while (child < *childc - 1) {
 
634
                (*childv)[child] = (*childv)[child + 1];
 
635
                ++child;
 
636
        }
 
637
        --*childc;
 
638
 
 
639
        if ((newchildv = (struct sockd_child_t *)realloc(*childv,
 
640
        sizeof(**childv) * (*childc + 1))) == NULL) {
 
641
                slog(LOG_WARNING, NOMEM);
 
642
                return -1;
 
643
        }
 
644
        *childv = newchildv;
 
645
 
 
646
        return 0;
 
647
}
 
648
 
 
649
struct sockd_child_t *
 
650
nextchild(type)
 
651
        int type;
 
652
{
 
653
        const char *function = "nextchild()";
 
654
        struct timeval timeout;
 
655
        struct sockd_child_t **childv;
 
656
        int *childc;
 
657
        int i, maxd;
 
658
        fd_set wset;
 
659
 
 
660
        setchildtype(type, &childv, &childc, NULL);
 
661
 
 
662
        FD_ZERO(&wset);
 
663
        for (i = 0, maxd = -1; i < *childc; ++i)
 
664
                if ((*childv)[i].freec > 0) {
 
665
                        FD_SET((*childv)[i].s, &wset);
 
666
                        maxd = MAX(maxd, (*childv)[i].s);
 
667
                }
 
668
 
 
669
        if (maxd < 0)
 
670
                return NULL;
 
671
        ++maxd;
 
672
 
 
673
        timeout.tv_sec          = 0;
 
674
        timeout.tv_usec = 0;
 
675
 
 
676
        switch (selectn(maxd, NULL, &wset, NULL, &timeout)) {
 
677
                case -1:
 
678
                        SERR(-1);
 
679
                        /* NOTREACHED */
 
680
 
 
681
                case 0:
 
682
                        slog(LOG_DEBUG, "%s: no child writable", function);
 
683
                        return NULL;
 
684
        }
 
685
 
 
686
        return getset(SOCKD_NEWREQUEST, &wset);
 
687
}
 
688
 
 
689
 
 
690
static int
 
691
setchildtype(type, childv, childc, function)
 
692
        int type;
 
693
        struct sockd_child_t ***childv;
 
694
        int **childc;
 
695
        void (**function)(struct sockd_mother_t *mother);
 
696
{
 
697
 
 
698
        switch (type) {
 
699
                case CHILD_IO:
 
700
                        if (childv != NULL)
 
701
                                *childv = &iochildv;
 
702
 
 
703
                        if (childc != NULL)
 
704
                                *childc = &iochildc;
 
705
 
 
706
                        if (function != NULL)
 
707
                                *function = &run_io;
 
708
 
 
709
                        break;
 
710
 
 
711
                case CHILD_NEGOTIATE:
 
712
                        if (childv != NULL)
 
713
                                *childv = &negchildv;
 
714
 
 
715
                        if (childc != NULL)
 
716
                                *childc = &negchildc;
 
717
 
 
718
                        if (function != NULL)
 
719
                                *function = &run_negotiate;
 
720
 
 
721
                        break;
 
722
 
 
723
                case CHILD_REQUEST:
 
724
                        if (childv != NULL)
 
725
                                *childv = &reqchildv;
 
726
 
 
727
                        if (childc != NULL)
 
728
                                *childc = &reqchildc;
 
729
 
 
730
                        if (function != NULL)
 
731
                                *function = &run_request;
 
732
 
 
733
                        break;
 
734
 
 
735
                default:
 
736
                        SASSERTX(type);
 
737
        }
 
738
 
 
739
        return type;
 
740
}
 
741
 
 
742
int
 
743
childtype(pid)
 
744
        pid_t pid;
 
745
{
 
746
 
 
747
        if (findchild(pid, iochildc, iochildv) != -1)
 
748
                return CHILD_IO;
 
749
 
 
750
        if (findchild(pid, negchildc, negchildv) != -1)
 
751
                return CHILD_NEGOTIATE;
 
752
 
 
753
        if (findchild(pid, reqchildc, reqchildv) != -1)
 
754
                return CHILD_REQUEST;
 
755
 
 
756
        if (pidismother(pid))
 
757
                return CHILD_MOTHER;
 
758
 
 
759
        SERRX(pid);
 
760
        /* NOTREACHED */
 
761
}
 
762
 
 
763
static int
 
764
findchild(pid, childc, childv)
 
765
        pid_t pid;
 
766
        int childc;
 
767
        const struct sockd_child_t *childv;
 
768
{
 
769
        int i;
 
770
 
 
771
        for (i = 0; i < childc; ++i)
 
772
                if (childv[i].pid == pid)
 
773
                        return i;
 
774
 
 
775
        return -1;
 
776
}
 
777
 
 
778
struct sockd_child_t *
 
779
getchild(pid)
 
780
        pid_t pid;
 
781
{
 
782
        int child, type;
 
783
        int *childc;
 
784
        struct sockd_child_t **childv;
 
785
 
 
786
        switch (type = childtype(pid)) {
 
787
                case CHILD_IO:
 
788
                case CHILD_NEGOTIATE:
 
789
                case CHILD_REQUEST:
 
790
                        break;
 
791
 
 
792
                case CHILD_MOTHER:
 
793
                        return NULL;
 
794
 
 
795
                default:
 
796
                        SERRX(type);
 
797
        }
 
798
 
 
799
        setchildtype(type, &childv, &childc, NULL);
 
800
 
 
801
        if ((child = findchild(pid, *childc, *childv)) != -1)
 
802
                return &(*childv)[child];
 
803
        return NULL;
 
804
}
 
805
 
 
806
int
 
807
send_io(s, io)
 
808
        int s;
 
809
        const struct sockd_io_t *io;
 
810
{
 
811
        const char *function = "send_io()";
 
812
        struct iovec iovec[1];
 
813
        struct msghdr msg;
 
814
        int w, fdsent, length;
 
815
        CMSG_AALLOC(cmsg, sizeof(int) * FDPASS_MAX);
 
816
 
 
817
 
 
818
        length = 0;
 
819
        /* LINTED operands have incompatible pointer types */
 
820
        iovec[0].iov_base               = (const void *)io;
 
821
        iovec[0].iov_len                = sizeof(*io);
 
822
        length                            += iovec[0].iov_len;
 
823
 
 
824
        fdsent = 0;
 
825
        CMSG_ADDOBJECT(io->src.s, cmsg, sizeof(io->src.s) * fdsent++);
 
826
        CMSG_ADDOBJECT(io->dst.s, cmsg, sizeof(io->dst.s) * fdsent++);
 
827
 
 
828
        switch (io->state.command) {
 
829
                case SOCKS_BIND:
 
830
                case SOCKS_BINDREPLY:
 
831
                        if (!io->state.extension.bind)
 
832
                                break;
 
833
                        /* else: */ /* FALLTHROUGH */
 
834
 
 
835
                case SOCKS_UDPASSOCIATE:
 
836
                        CMSG_ADDOBJECT(io->control.s, cmsg, sizeof(io->control.s) * fdsent++);
 
837
                        break;
 
838
 
 
839
                case SOCKS_CONNECT:
 
840
                        break;
 
841
 
 
842
                default:
 
843
                        SERRX(io->state.command);
 
844
        }
 
845
 
 
846
        msg.msg_iov                             = iovec;
 
847
        msg.msg_iovlen                  = ELEMENTS(iovec);
 
848
        msg.msg_name                    = NULL;
 
849
        msg.msg_namelen         = 0;
 
850
 
 
851
        CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdsent);
 
852
 
 
853
        if ((w = sendmsg(s, &msg, 0)) != length)        {
 
854
                swarn("%s: sendmsg(): %d of %d", function, w, length);
 
855
                return -1;
 
856
        }
 
857
 
 
858
#if HARDCORE_DEBUG
 
859
        printfd(io, "sent");
 
860
#endif
 
861
 
 
862
        return 0;
 
863
}
 
864
 
 
865
 
 
866
int
 
867
send_client(s, client)
 
868
        int s;
 
869
        int client;
 
870
{
 
871
        const char *function = "send_client()";
 
872
        const char command = SOCKD_NEWREQUEST;
 
873
        struct iovec iovec[1];
 
874
        struct msghdr msg;
 
875
        CMSG_AALLOC(cmsg, sizeof(int));
 
876
        int fdsent;
 
877
 
 
878
        /* LINTED operands have incompatible pointer types */
 
879
        iovec[0].iov_base               = (const void *)&command;
 
880
        iovec[0].iov_len                = sizeof(command);
 
881
 
 
882
        fdsent = 0;
 
883
        CMSG_ADDOBJECT(client, cmsg, sizeof(client) * fdsent++);
 
884
 
 
885
        msg.msg_iov                             = iovec;
 
886
        msg.msg_iovlen                  = ELEMENTS(iovec);
 
887
        msg.msg_name                    = NULL;
 
888
        msg.msg_namelen         = 0;
 
889
 
 
890
        CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdsent);
 
891
 
 
892
        if (sendmsg(s, &msg, 0) != sizeof(command))     {
 
893
                swarn("%s: sendmsg()", function);
 
894
                return -1;
 
895
        }
 
896
 
 
897
        return 0;
 
898
}
 
899
 
 
900
int
 
901
send_req(s, req)
 
902
        int s;
 
903
        const struct sockd_request_t *req;
 
904
{
 
905
        const char *function = "send_req()";
 
906
        struct iovec iovec[1];
 
907
        struct msghdr msg;
 
908
        int fdsent;
 
909
        CMSG_AALLOC(cmsg, sizeof(int));
 
910
 
 
911
        /* LINTED operands have incompatible pointer types */
 
912
        iovec[0].iov_base               = (const void *)req;
 
913
        iovec[0].iov_len                = sizeof(*req);
 
914
 
 
915
        fdsent = 0;
 
916
        CMSG_ADDOBJECT(req->s, cmsg, sizeof(req->s) * fdsent++);
 
917
 
 
918
        msg.msg_iov                             = iovec;
 
919
        msg.msg_iovlen                  = ELEMENTS(iovec);
 
920
        msg.msg_name                    = NULL;
 
921
        msg.msg_namelen         = 0;
 
922
 
 
923
        CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdsent);
 
924
 
 
925
        if (sendmsg(s, &msg, 0) != sizeof(*req))        {
 
926
                swarn("%s: sendmsg()", function);
 
927
                return -1;
 
928
        }
 
929
 
 
930
        return 0;
 
931
}
 
932
 
 
933
void
 
934
sigchildbroadcast(sig, childtype)
 
935
        int sig;
 
936
        int childtype;
 
937
{
 
938
        int i;
 
939
 
 
940
        if (childtype & CHILD_NEGOTIATE)
 
941
                for (i = 0; i < negchildc; ++i)
 
942
                        kill(negchildv[i].pid, sig);
 
943
 
 
944
        if (childtype & CHILD_REQUEST)
 
945
                for (i = 0; i < reqchildc; ++i)
 
946
                        kill(reqchildv[i].pid, sig);
 
947
 
 
948
        if (childtype & CHILD_IO)
 
949
                for (i = 0; i < iochildc; ++i)
 
950
                        kill(iochildv[i].pid, sig);
 
951
}
 
952
 
 
953
#if DEBUG
 
954
void
 
955
printfd(io, prefix)
 
956
        const struct sockd_io_t *io;
 
957
        const char *prefix;
 
958
{
 
959
        const char *function = "printfd()";
 
960
        struct sockaddr name;
 
961
        socklen_t namelen;
 
962
        char namestring[MAXSOCKADDRSTRING];
 
963
 
 
964
        bzero(&name, sizeof(name));
 
965
        namelen = sizeof(name);
 
966
        /* LINTED pointer casts may be troublesome */
 
967
        if (getsockname(io->src.s, &name, &namelen) != 0)
 
968
                swarn("%s: getsockname(io->src)", function);
 
969
        else
 
970
                slog(LOG_DEBUG, "%s: io->src (%d), name: %s", prefix,
 
971
                io->src.s, sockaddr2string(&name, namestring, sizeof(namestring)));
 
972
 
 
973
        bzero(&name, sizeof(name));
 
974
        namelen = sizeof(name);
 
975
        /* LINTED pointer casts may be troublesome */
 
976
        if (getsockname(io->dst.s, &name, &namelen) != 0)
 
977
                swarn("%s: getsockname(io->dst)", function);
 
978
        else
 
979
                slog(LOG_DEBUG, "%s: io->dst (%d), name: %s", prefix, io->dst.s,
 
980
                sockaddr2string(&name, namestring, sizeof(namestring)));
 
981
 
 
982
        switch (io->state.command) {
 
983
                case SOCKS_BIND:
 
984
                case SOCKS_BINDREPLY:
 
985
                        if (!io->state.extension.bind)
 
986
                                break;
 
987
                        /* else: */ /* FALLTHROUGH */
 
988
 
 
989
                case SOCKS_UDPASSOCIATE:
 
990
                        bzero(&name, sizeof(name));
 
991
                        namelen = sizeof(name);
 
992
                        /* LINTED pointer casts may be troublesome */
 
993
                        if (getpeername(io->control.s, &name, &namelen)
 
994
                        != 0)
 
995
                                swarn("%s: getpeername(io->control)", function);
 
996
                        else  {
 
997
                                if (namelen == 0)
 
998
                                        slog(LOG_DEBUG, "%s: io->control (%d), name: <none>",
 
999
                                        prefix, io->control.s);
 
1000
                                else
 
1001
                                        slog(LOG_DEBUG, "%s: io->control (%d), name: %s",
 
1002
                                        prefix, io->control.s,
 
1003
                                        sockaddr2string(&name, namestring, sizeof(namestring)));
 
1004
                        }
 
1005
                        break;
 
1006
 
 
1007
                case SOCKS_CONNECT:
 
1008
                        break;
 
1009
 
 
1010
                default:
 
1011
                        SERRX(io->state.command);
 
1012
        }
 
1013
}
 
1014
#endif