varnish-cache/bin/varnishd/cache/cache_acceptor.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * This source file has the various trickery surrounding the accept/listen
30
 * sockets.
31
 *
32
 */
33
34
#include "config.h"
35
36
#include <errno.h>
37
#include <stdlib.h>
38
#include <netinet/in.h>
39
#include <netinet/tcp.h>
40
#include <sys/socket.h>
41
#include <sys/un.h>
42
43
#include "cache_varnishd.h"
44
45
#include "cache_transport.h"
46
#include "cache_pool.h"
47
#include "common/heritage.h"
48
49
#include "vcli_serve.h"
50
#include "vsa.h"
51
#include "vtcp.h"
52
#include "vtim.h"
53
54
static pthread_t        VCA_thread;
55
static vtim_dur vca_pace = 0.0;
56
static struct lock pace_mtx;
57
static unsigned pool_accepting;
58
static pthread_mutex_t shut_mtx = PTHREAD_MUTEX_INITIALIZER;
59
60
struct wrk_accept {
61
        unsigned                magic;
62
#define WRK_ACCEPT_MAGIC        0x8c4b4d59
63
64
        /* Accept stuff */
65
        struct sockaddr_storage acceptaddr;
66
        socklen_t               acceptaddrlen;
67
        int                     acceptsock;
68
        struct listen_sock      *acceptlsock;
69
};
70
71
struct poolsock {
72
        unsigned                        magic;
73
#define POOLSOCK_MAGIC                  0x1b0a2d38
74
        VTAILQ_ENTRY(poolsock)          list;
75
        struct listen_sock              *lsock;
76
        struct pool_task                task;
77
        struct pool                     *pool;
78
};
79
80
/*--------------------------------------------------------------------
81
 * TCP options we want to control
82
 */
83
84
static struct tcp_opt {
85
        int             level;
86
        int             optname;
87
        const char      *strname;
88
        socklen_t       sz;
89
        void            *ptr;
90
        int             need;
91
        int             iponly;
92
} tcp_opts[] = {
93
#define TCPO(lvl, nam, sz, ip) { lvl, nam, #nam, sizeof(sz), 0, 0, ip},
94
95
        TCPO(SOL_SOCKET, SO_LINGER, struct linger, 0)
96
        TCPO(SOL_SOCKET, SO_KEEPALIVE, int, 0)
97
        TCPO(IPPROTO_TCP, TCP_NODELAY, int, 1)
98
99
#ifdef SO_SNDTIMEO_WORKS
100
        TCPO(SOL_SOCKET, SO_SNDTIMEO, struct timeval, 0)
101
#endif
102
103
#ifdef SO_RCVTIMEO_WORKS
104
        TCPO(SOL_SOCKET, SO_RCVTIMEO, struct timeval, 0)
105
#endif
106
107
#ifdef HAVE_TCP_KEEP
108
        TCPO(IPPROTO_TCP, TCP_KEEPIDLE, int, 1)
109
        TCPO(IPPROTO_TCP, TCP_KEEPCNT, int, 1)
110
        TCPO(IPPROTO_TCP, TCP_KEEPINTVL, int, 1)
111
#endif
112
113
#undef TCPO
114
};
115
116
static const int n_tcp_opts = sizeof tcp_opts / sizeof tcp_opts[0];
117
118
/*--------------------------------------------------------------------
119
 * We want to get out of any kind of trouble-hit TCP connections as fast
120
 * as absolutely possible, so we set them LINGER enabled with zero timeout,
121
 * so that even if there are outstanding write data on the socket, a close(2)
122
 * will return immediately.
123
 */
124
static const struct linger linger = {
125
        .l_onoff        =       0,
126
};
127
128
/*
129
 * We turn on keepalives by default to assist in detecting clients that have
130
 * hung up on connections returning from waitinglists
131
 */
132
133
static unsigned         need_test;
134
135
/*--------------------------------------------------------------------
136
 * lacking a better place, we put some generic periodic updates
137
 * into the vca_acct() loop which we are running anyway
138
 */
139
static void
140 2344
vca_periodic(vtim_real t0)
141
{
142
        vtim_real now;
143
144 2344
        now = VTIM_real();
145 2344
        VSC_C_main->uptime = (uint64_t)(now - t0);
146
147 2344
        VTIM_postel = FEATURE(FEATURE_HTTP_DATE_POSTEL);
148 2344
}
149
150
/*--------------------------------------------------------------------
151
 * Some kernels have bugs/limitations with respect to which options are
152
 * inherited from the accept/listen socket, so we have to keep track of
153
 * which, if any, sockopts we have to set on the accepted socket.
154
 */
155
156
static int
157 2344
vca_tcp_opt_init(void)
158
{
159
        int n;
160 2344
        int one = 1;
161
        struct tcp_opt *to;
162
        struct timeval tv;
163 2344
        int chg = 0;
164
        int x;
165
166 2344
        memset(&tv, 0, sizeof tv);
167 2344
        memset(&x, 0, sizeof x);
168
169 21096
        for (n = 0; n < n_tcp_opts; n++) {
170 18752
                to = &tcp_opts[n];
171 18752
                if (to->ptr == NULL)
172 5496
                        to->ptr = calloc(1, to->sz);
173 18752
                AN(to->ptr);
174 18752
                if (!strcmp(to->strname, "SO_LINGER")) {
175 2344
                        assert(to->sz == sizeof linger);
176 2344
                        memcpy(to->ptr, &linger, sizeof linger);
177 2344
                        to->need = 1;
178 16408
                } else if (!strcmp(to->strname, "TCP_NODELAY")) {
179 2344
                        assert(to->sz == sizeof one);
180 2344
                        memcpy(to->ptr, &one, sizeof one);
181 2344
                        to->need = 1;
182 14064
                } else if (!strcmp(to->strname, "SO_KEEPALIVE")) {
183 2344
                        assert(to->sz == sizeof one);
184 2344
                        memcpy(to->ptr, &one, sizeof one);
185 2344
                        to->need = 1;
186
#define NEW_VAL(to, xx)                                         \
187
        do {                                                    \
188
                assert(to->sz == sizeof xx);                    \
189
                if (memcmp(to->ptr, &(xx), sizeof xx)) {        \
190
                        memcpy(to->ptr, &(xx), sizeof xx);      \
191
                        to->need = 1;                           \
192
                        chg = 1;                                \
193
                        need_test = 1;                          \
194
                }                                               \
195
        } while (0)
196
197
#ifdef SO_SNDTIMEO_WORKS
198 11720
                } else if (!strcmp(to->strname, "SO_SNDTIMEO")) {
199 2344
                        tv = VTIM_timeval(cache_param->idle_send_timeout);
200 2344
                        NEW_VAL(to, tv);
201
#endif
202
#ifdef SO_RCVTIMEO_WORKS
203 9376
                } else if (!strcmp(to->strname, "SO_RCVTIMEO")) {
204 2344
                        tv = VTIM_timeval(cache_param->timeout_idle);
205 2344
                        NEW_VAL(to, tv);
206
#endif
207
#ifdef HAVE_TCP_KEEP
208 7032
                } else if (!strcmp(to->strname, "TCP_KEEPIDLE")) {
209 2344
                        x = (int)(cache_param->tcp_keepalive_time);
210 2344
                        NEW_VAL(to, x);
211 4688
                } else if (!strcmp(to->strname, "TCP_KEEPCNT")) {
212 2344
                        x = (int)(cache_param->tcp_keepalive_probes);
213 2344
                        NEW_VAL(to, x);
214 2344
                } else if (!strcmp(to->strname, "TCP_KEEPINTVL")) {
215 2344
                        x = (int)(cache_param->tcp_keepalive_intvl);
216 2344
                        NEW_VAL(to, x);
217
#endif
218
                }
219
        }
220 2344
        return (chg);
221
}
222
223
static void
224 644
vca_tcp_opt_test(const int sock, const unsigned uds)
225
{
226
        int i, n;
227
        struct tcp_opt *to;
228
        socklen_t l;
229
        void *ptr;
230
231 5796
        for (n = 0; n < n_tcp_opts; n++) {
232 5152
                to = &tcp_opts[n];
233 5152
                if (to->iponly && uds)
234 65
                        continue;
235 5087
                to->need = 1;
236 5087
                ptr = calloc(1, to->sz);
237 5087
                AN(ptr);
238 5087
                l = to->sz;
239 5087
                i = getsockopt(sock, to->level, to->optname, ptr, &l);
240 5087
                if (i == 0 && !memcmp(ptr, to->ptr, to->sz))
241 3816
                        to->need = 0;
242 5087
                free(ptr);
243 5087
                if (i && errno != ENOPROTOOPT)
244 0
                        VTCP_Assert(i);
245
        }
246 644
}
247
248
static void
249 2094
vca_tcp_opt_set(const int sock, const unsigned uds, const int force)
250
{
251
        int n;
252
        struct tcp_opt *to;
253
254 18846
        for (n = 0; n < n_tcp_opts; n++) {
255 16752
                to = &tcp_opts[n];
256 16752
                if (to->iponly && uds)
257 196
                        continue;
258 16556
                if (to->need || force) {
259 8536
                        VTCP_Assert(setsockopt(sock,
260
                            to->level, to->optname, to->ptr, to->sz));
261
                }
262
        }
263 2094
}
264
265
/*--------------------------------------------------------------------
266
 * If accept(2)'ing fails, we pace ourselves to relive any resource
267
 * shortage if possible.
268
 */
269
270
static void
271 2769
vca_pace_check(void)
272
{
273
        vtim_dur p;
274
275 2769
        if (vca_pace == 0.0)
276 2769
                return;
277 0
        Lck_Lock(&pace_mtx);
278 0
        p = vca_pace;
279 0
        Lck_Unlock(&pace_mtx);
280 0
        if (p > 0.0)
281 0
                VTIM_sleep(p);
282
}
283
284
static void
285 0
vca_pace_bad(void)
286
{
287
288 0
        Lck_Lock(&pace_mtx);
289 0
        vca_pace += cache_param->acceptor_sleep_incr;
290 0
        if (vca_pace > cache_param->acceptor_sleep_max)
291 0
                vca_pace = cache_param->acceptor_sleep_max;
292 0
        Lck_Unlock(&pace_mtx);
293 0
}
294
295
static void
296 1405
vca_pace_good(void)
297
{
298
299 1405
        if (vca_pace == 0.0)
300 1405
                return;
301 0
        Lck_Lock(&pace_mtx);
302 0
        vca_pace *= cache_param->acceptor_sleep_decay;
303 0
        if (vca_pace < cache_param->acceptor_sleep_incr)
304 0
                vca_pace = 0.0;
305 0
        Lck_Unlock(&pace_mtx);
306
}
307
308
/*--------------------------------------------------------------------
309
 * The pool-task for a newly accepted session
310
 *
311
 * Called from assigned worker thread
312
 */
313
314
static void
315 1375
vca_mk_tcp(const struct wrk_accept *wa,
316
    struct sess *sp, char *laddr, char *lport, char *raddr, char *rport)
317
{
318
        struct suckaddr *sa;
319
        struct sockaddr_storage ss;
320
        socklen_t sl;
321
322 1375
        SES_Reserve_remote_addr(sp, &sa);
323 1375
        AN(VSA_Build(sa, &wa->acceptaddr, wa->acceptaddrlen));
324 1375
        sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR];
325
326 1375
        VTCP_name(sa, raddr, VTCP_ADDRBUFSIZE, rport, VTCP_PORTBUFSIZE);
327 1375
        SES_Set_String_Attr(sp, SA_CLIENT_IP, raddr);
328 1375
        SES_Set_String_Attr(sp, SA_CLIENT_PORT, rport);
329
330 1375
        sl = sizeof ss;
331 1375
        AZ(getsockname(sp->fd, (void*)&ss, &sl));
332 1375
        SES_Reserve_local_addr(sp, &sa);
333 1375
        AN(VSA_Build(sa, &ss, sl));
334 1375
        sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_LOCAL_ADDR];
335 1375
        VTCP_name(sa, laddr, VTCP_ADDRBUFSIZE, lport, VTCP_PORTBUFSIZE);
336 1375
}
337
338
static void
339 30
vca_mk_uds(struct wrk_accept *wa, struct sess *sp, char *laddr, char *lport,
340
           char *raddr, char *rport)
341
{
342
        struct suckaddr *sa;
343
344
        (void) wa;
345 30
        SES_Reserve_remote_addr(sp, &sa);
346 30
        AZ(SES_Set_remote_addr(sp, bogo_ip));
347 30
        sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR];
348 30
        sp->sattr[SA_LOCAL_ADDR] = sp->sattr[SA_REMOTE_ADDR];
349 30
        sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_REMOTE_ADDR];
350 30
        SES_Set_String_Attr(sp, SA_CLIENT_IP, "0.0.0.0");
351 30
        SES_Set_String_Attr(sp, SA_CLIENT_PORT, "0");
352
353 30
        strcpy(laddr, "0.0.0.0");
354 30
        strcpy(raddr, "0.0.0.0");
355 30
        strcpy(lport, "0");
356 30
        strcpy(rport, "0");
357 30
}
358
359
static void v_matchproto_(task_func_t)
360 1405
vca_make_session(struct worker *wrk, void *arg)
361
{
362
        struct sess *sp;
363
        struct req *req;
364
        struct wrk_accept *wa;
365
        char laddr[VTCP_ADDRBUFSIZE];
366
        char lport[VTCP_PORTBUFSIZE];
367
        char raddr[VTCP_ADDRBUFSIZE];
368
        char rport[VTCP_PORTBUFSIZE];
369
370 1405
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
371 1405
        CAST_OBJ_NOTNULL(wa, arg, WRK_ACCEPT_MAGIC);
372
373 1405
        if (VTCP_blocking(wa->acceptsock)) {
374 0
                closefd(&wa->acceptsock);
375 0
                wrk->stats->sess_drop++;        // XXX Better counter ?
376 0
                WS_Release(wrk->aws, 0);
377 0
                return;
378
        }
379
380
        /* Turn accepted socket into a session */
381 1405
        AN(wrk->aws->r);
382 1405
        sp = SES_New(wrk->pool);
383 1405
        if (sp == NULL) {
384
                /*
385
                 * We consider this a DoS situation and silently close the
386
                 * connection with minimum effort and fuzz, rather than try
387
                 * to send an intelligent message back.
388
                 */
389 0
                vca_pace_bad();
390 0
                (void)VTCP_nonblocking(wa->acceptsock);
391 0
                closefd(&wa->acceptsock);
392 0
                wrk->stats->sess_drop++;
393 0
                WS_Release(wrk->aws, 0);
394 0
                return;
395
        }
396 1405
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
397 1405
        wrk->stats->s_sess++;
398
399 1405
        sp->t_open = VTIM_real();
400 1405
        sp->t_idle = sp->t_open;
401 1405
        sp->vxid = VXID_Get(wrk, VSL_CLIENTMARKER);
402
403 1405
        sp->fd = wa->acceptsock;
404 1405
        wa->acceptsock = -1;
405 1405
        sp->listen_sock = wa->acceptlsock;
406
407 1405
        assert(wa->acceptaddrlen <= vsa_suckaddr_len);
408
409 1405
        if (wa->acceptlsock->uds)
410 30
                vca_mk_uds(wa, sp, laddr, lport, raddr, rport);
411
        else
412 1375
                vca_mk_tcp(wa, sp, laddr, lport, raddr, rport);
413
414 1405
        AN(wa->acceptlsock->name);
415 1405
        VSL(SLT_Begin, sp->vxid, "sess 0 %s",
416 1405
            wa->acceptlsock->transport->name);
417 2810
        VSL(SLT_SessOpen, sp->vxid, "%s %s %s %s %s %.6f %d",
418 1405
            raddr, rport, wa->acceptlsock->name, laddr, lport,
419
            sp->t_open, sp->fd);
420
421 1405
        WS_Release(wrk->aws, 0);
422
423 1405
        vca_pace_good();
424 1405
        wrk->stats->sess_conn++;
425
426 1405
        if (need_test) {
427 644
                vca_tcp_opt_test(sp->fd, wa->acceptlsock->uds);
428 644
                need_test = 0;
429
        }
430 1405
        vca_tcp_opt_set(sp->fd, wa->acceptlsock->uds, 0);
431
432 1405
        req = Req_New(wrk, sp);
433 1405
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
434 1405
        req->htc->rfd = &sp->fd;
435
436 1405
        SES_SetTransport(wrk, sp, req, wa->acceptlsock->transport);
437
}
438
439
/*--------------------------------------------------------------------
440
 * This function accepts on a single socket for a single thread pool.
441
 *
442
 * As long as we can stick the accepted connection to another thread
443
 * we do so, otherwise we put the socket back on the "BACK" pool
444
 * and handle the new connection ourselves.
445
 */
446
447
static void v_matchproto_(task_func_t)
448 1369
vca_accept_task(struct worker *wrk, void *arg)
449
{
450
        struct wrk_accept wa;
451
        struct poolsock *ps;
452
        struct listen_sock *ls;
453
        int i;
454
        char laddr[VTCP_ADDRBUFSIZE];
455
        char lport[VTCP_PORTBUFSIZE];
456
457 1369
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
458 1369
        CAST_OBJ_NOTNULL(ps, arg, POOLSOCK_MAGIC);
459 1369
        ls = ps->lsock;
460 1369
        CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
461
462 4107
        while (!pool_accepting)
463 1371
                VTIM_sleep(.1);
464
465 4136
        while (!ps->pool->die) {
466 2769
                INIT_OBJ(&wa, WRK_ACCEPT_MAGIC);
467 2769
                wa.acceptlsock = ls;
468
469 2769
                vca_pace_check();
470
471 2769
                wa.acceptaddrlen = sizeof wa.acceptaddr;
472
                do {
473 2769
                        i = accept(ls->sock, (void*)&wa.acceptaddr,
474
                                   &wa.acceptaddrlen);
475 1405
                } while (i < 0 && errno == EAGAIN);
476
477 1405
                if (i < 0 && ps->pool->die) {
478 0
                        VSL(SLT_Debug, 0, "XXX Accept thread dies %p", ps);
479 0
                        FREE_OBJ(ps);
480 3
                        return;
481
                }
482
483 1405
                if (i < 0 && ls->sock == -2) {
484
                        /* Shut down in progress */
485 0
                        sleep(2);
486 0
                        continue;
487
                }
488
489 1405
                if (i < 0) {
490 0
                        switch (errno) {
491
                        case ECONNABORTED:
492 0
                                wrk->stats->sess_fail_econnaborted++;
493 0
                                break;
494
                        case EINTR:
495 0
                                wrk->stats->sess_fail_eintr++;
496 0
                                break;
497
                        case EMFILE:
498 0
                                wrk->stats->sess_fail_emfile++;
499 0
                                vca_pace_bad();
500 0
                                break;
501
                        case EBADF:
502 0
                                wrk->stats->sess_fail_ebadf++;
503 0
                                vca_pace_bad();
504 0
                                break;
505
                        case ENOBUFS:
506
                        case ENOMEM:
507 0
                                wrk->stats->sess_fail_enomem++;
508 0
                                vca_pace_bad();
509 0
                                break;
510
                        default:
511 0
                                wrk->stats->sess_fail_other++;
512 0
                                vca_pace_bad();
513 0
                                break;
514
                        }
515
516 0
                        i = errno;
517 0
                        wrk->stats->sess_fail++;
518
519 0
                        if (wa.acceptlsock->uds) {
520 0
                                strcpy(laddr, "0.0.0.0");
521 0
                                strcpy(lport, "0");
522
                        } else {
523 0
                                VTCP_myname(ls->sock, laddr, VTCP_ADDRBUFSIZE,
524
                                    lport, VTCP_ADDRBUFSIZE);
525
                        }
526
527 0
                        VSL(SLT_SessError, 0, "%s %s %s %d %d %s",
528 0
                            wa.acceptlsock->name, laddr, lport,
529
                            ls->sock, i, strerror(i));
530 0
                        (void)Pool_TrySumstat(wrk);
531 0
                        continue;
532
                }
533
534 1405
                wa.acceptsock = i;
535
536 1405
                if (!Pool_Task_Arg(wrk, TASK_QUEUE_VCA,
537
                    vca_make_session, &wa, sizeof wa)) {
538
                        /*
539
                         * We couldn't get another thread, so we will handle
540
                         * the request in this worker thread, but first we
541
                         * must reschedule the listening task so it will be
542
                         * taken up by another thread again.
543
                         */
544 3
                        if (!ps->pool->die)
545 1
                                AZ(Pool_Task(wrk->pool, &ps->task,
546
                                    TASK_QUEUE_VCA));
547 3
                        return;
548
                }
549 1402
                if (!ps->pool->die && DO_DEBUG(DBG_SLOW_ACCEPTOR))
550 6
                        VTIM_sleep(2.0);
551
552
                /*
553
                 * We were able to hand off, so release this threads VCL
554
                 * reference (if any) so we don't hold on to discarded VCLs.
555
                 */
556 1402
                if (wrk->vcl != NULL)
557 0
                        VCL_Rel(&wrk->vcl);
558
        }
559
}
560
561
/*--------------------------------------------------------------------
562
 * Called when a worker and attached thread pool is created, to
563
 * allocate the tasks which will listen to sockets for that pool.
564
 */
565
566
void
567 1367
VCA_NewPool(struct pool *pp)
568
{
569
        struct listen_sock *ls;
570
        struct poolsock *ps;
571
572 2736
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
573 1369
                ALLOC_OBJ(ps, POOLSOCK_MAGIC);
574 1369
                AN(ps);
575 1369
                ps->lsock = ls;
576 1369
                ps->task.func = vca_accept_task;
577 1369
                ps->task.priv = ps;
578 1369
                ps->pool = pp;
579 1369
                VTAILQ_INSERT_TAIL(&pp->poolsocks, ps, list);
580 1369
                AZ(Pool_Task(pp, &ps->task, TASK_QUEUE_VCA));
581
        }
582 1367
}
583
584
void
585 2
VCA_DestroyPool(struct pool *pp)
586
{
587
        struct poolsock *ps;
588
589 6
        while (!VTAILQ_EMPTY(&pp->poolsocks)) {
590 2
                ps = VTAILQ_FIRST(&pp->poolsocks);
591 2
                VTAILQ_REMOVE(&pp->poolsocks, ps, list);
592
        }
593 2
}
594
595
/*--------------------------------------------------------------------*/
596
597
static void * v_matchproto_()
598 687
vca_acct(void *arg)
599
{
600
        struct listen_sock *ls;
601
        vtim_real t0;
602
603
        // XXX Actually a mis-nomer now because the accept happens in a pool
604
        // thread. Rename to accept-nanny or so?
605 687
        THR_SetName("cache-acceptor");
606 687
        THR_Init();
607
        (void)arg;
608
609 687
        t0 = VTIM_real();
610 687
        vca_periodic(t0);
611
612 687
        pool_accepting = 1;
613
614
        while (1) {
615 4001
                (void)sleep(1);
616 1657
                if (vca_tcp_opt_init()) {
617 1
                        AZ(pthread_mutex_lock(&shut_mtx));
618 2
                        VTAILQ_FOREACH(ls, &heritage.socks, list) {
619 1
                                if (ls->sock == -2)
620 0
                                        continue;       // VCA_Shutdown
621 1
                                assert (ls->sock > 0);
622 1
                                vca_tcp_opt_set(ls->sock, ls->uds, 1);
623
                        }
624 1
                        AZ(pthread_mutex_unlock(&shut_mtx));
625
                }
626 1657
                vca_periodic(t0);
627
        }
628
        NEEDLESS(return NULL);
629
}
630
631
/*--------------------------------------------------------------------*/
632
633
static void v_matchproto_(cli_func_t)
634 687
ccf_start(struct cli *cli, const char * const *av, void *priv)
635
{
636
        struct listen_sock *ls;
637
638
        (void)cli;
639
        (void)av;
640
        (void)priv;
641
642 687
        (void)vca_tcp_opt_init();
643
644 1375
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
645 688
                CHECK_OBJ_NOTNULL(ls->transport, TRANSPORT_MAGIC);
646 688
                assert (ls->sock > 0);  // We know where stdin is
647 688
                if (cache_param->tcp_fastopen) {
648
                        int i;
649 0
                        i = VTCP_fastopen(ls->sock, cache_param->listen_depth);
650 0
                        if (i)
651 0
                                VSL(SLT_Error, 0,
652
                                    "Kernel TCP Fast Open: sock=%d, ret=%d %s",
653 0
                                    ls->sock, i, strerror(errno));
654
                }
655 688
                if (listen(ls->sock, cache_param->listen_depth)) {
656 0
                        VCLI_SetResult(cli, CLIS_CANT);
657 0
                        VCLI_Out(cli, "Listen failed on socket '%s': %s",
658 0
                            ls->endpoint, strerror(errno));
659 0
                        return;
660
                }
661 688
                vca_tcp_opt_set(ls->sock, ls->uds, 1);
662 688
                if (cache_param->accept_filter) {
663
                        int i;
664 686
                        i = VTCP_filter_http(ls->sock);
665 686
                        if (i)
666 686
                                VSL(SLT_Error, 0,
667
                                    "Kernel filtering: sock=%d, ret=%d %s",
668 686
                                    ls->sock, i, strerror(errno));
669
                }
670
        }
671
672 687
        need_test = 1;
673
674 687
        AZ(pthread_create(&VCA_thread, NULL, vca_acct, NULL));
675
}
676
677
/*--------------------------------------------------------------------*/
678
679
static void v_matchproto_(cli_func_t)
680 1367
ccf_listen_address(struct cli *cli, const char * const *av, void *priv)
681
{
682
        struct listen_sock *ls;
683
        char h[32], p[32];
684
685
        (void)cli;
686
        (void)av;
687
        (void)priv;
688
689
        /*
690
         * This CLI command is primarily used by varnishtest.  Don't
691
         * respond until listen(2) has been called, in order to avoid
692
         * a race where varnishtest::client would attempt to connect(2)
693
         * before listen(2) has been called.
694
         */
695 2734
        while (!pool_accepting)
696 0
                VTIM_sleep(.1);
697
698 1367
        AZ(pthread_mutex_lock(&shut_mtx));
699 2736
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
700 1369
                if (!ls->uds) {
701 1331
                        VTCP_myname(ls->sock, h, sizeof h, p, sizeof p);
702 1331
                        VCLI_Out(cli, "%s %s\n", h, p);
703
                }
704
                else
705 38
                        VCLI_Out(cli, "%s -\n", ls->endpoint);
706
        }
707 1367
        AZ(pthread_mutex_unlock(&shut_mtx));
708 1367
}
709
710
/*--------------------------------------------------------------------*/
711
712
static struct cli_proto vca_cmds[] = {
713
        { CLICMD_SERVER_START,          "", ccf_start },
714
        { CLICMD_DEBUG_LISTEN_ADDRESS,  "d", ccf_listen_address },
715
        { NULL }
716
};
717
718
void
719 688
VCA_Init(void)
720
{
721
722 688
        CLI_AddFuncs(vca_cmds);
723 688
        Lck_New(&pace_mtx, lck_vcapace);
724 688
}
725
726
void
727 681
VCA_Shutdown(void)
728
{
729
        struct listen_sock *ls;
730
        int i;
731
732 681
        AZ(pthread_mutex_lock(&shut_mtx));
733 1363
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
734 682
                i = ls->sock;
735 682
                ls->sock = -2;
736 682
                (void)close(i);
737
        }
738 681
        AZ(pthread_mutex_unlock(&shut_mtx));
739 681
}
740
741
/*--------------------------------------------------------------------
742
 * Transport protocol registration
743
 *
744
 */
745
746
static VTAILQ_HEAD(,transport)  transports =
747
    VTAILQ_HEAD_INITIALIZER(transports);
748
749
void
750 768
XPORT_Init(void)
751
{
752
        uint16_t n;
753
        struct transport *xp;
754
755 768
        ASSERT_MGT();
756
757 768
        VTAILQ_INSERT_TAIL(&transports, &PROXY_transport, list);
758 768
        VTAILQ_INSERT_TAIL(&transports, &HTTP1_transport, list);
759 768
        VTAILQ_INSERT_TAIL(&transports, &H2_transport, list);
760
761 768
        n = 0;
762 3072
        VTAILQ_FOREACH(xp, &transports, list)
763 2304
                xp->number = ++n;
764 768
}
765
766
const struct transport *
767 739
XPORT_Find(const char *name)
768
{
769
        const struct transport *xp;
770
771 739
        ASSERT_MGT();
772
773 1471
        VTAILQ_FOREACH(xp, &transports, list)
774 2936
                if (xp->proto_ident != NULL &&
775 1467
                    !strcasecmp(xp->proto_ident, name))
776 737
                        return (xp);
777 2
        return (NULL);
778
}
779
780
const struct transport *
781 4
XPORT_ByNumber(uint16_t no)
782
{
783
        const struct transport *xp;
784
785 9
        VTAILQ_FOREACH(xp, &transports, list)
786 9
                if (xp->number == no)
787 4
                        return (xp);
788 0
        return (NULL);
789
}