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 double 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 4500
vca_periodic(double t0)
141
{
142
        double now;
143
144 4500
        now = VTIM_real();
145 4500
        VSC_C_main->uptime = (uint64_t)(now - t0);
146
147 4500
        VTIM_postel = FEATURE(FEATURE_HTTP_DATE_POSTEL);
148 4500
}
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 4500
vca_tcp_opt_init(void)
158
{
159
        int n;
160 4500
        int one = 1;
161
        struct tcp_opt *to;
162
        struct timeval tv;
163 4500
        int chg = 0;
164
        int x;
165
166 4500
        memset(&tv, 0, sizeof tv);
167 4500
        memset(&x, 0, sizeof x);
168
169 40500
        for (n = 0; n < n_tcp_opts; n++) {
170 36000
                to = &tcp_opts[n];
171 36000
                if (to->ptr == NULL)
172 10928
                        to->ptr = calloc(1, to->sz);
173 36000
                AN(to->ptr);
174 36000
                if (!strcmp(to->strname, "SO_LINGER")) {
175 4500
                        assert(to->sz == sizeof linger);
176 4500
                        memcpy(to->ptr, &linger, sizeof linger);
177 4500
                        to->need = 1;
178 31500
                } else if (!strcmp(to->strname, "TCP_NODELAY")) {
179 4500
                        assert(to->sz == sizeof one);
180 4500
                        memcpy(to->ptr, &one, sizeof one);
181 4500
                        to->need = 1;
182 27000
                } else if (!strcmp(to->strname, "SO_KEEPALIVE")) {
183 4500
                        assert(to->sz == sizeof one);
184 4500
                        memcpy(to->ptr, &one, sizeof one);
185 4500
                        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 22500
                } else if (!strcmp(to->strname, "SO_SNDTIMEO")) {
199 4500
                        tv = VTIM_timeval(cache_param->idle_send_timeout);
200 4500
                        NEW_VAL(to, tv);
201
#endif
202
#ifdef SO_RCVTIMEO_WORKS
203 18000
                } else if (!strcmp(to->strname, "SO_RCVTIMEO")) {
204 4500
                        tv = VTIM_timeval(cache_param->timeout_idle);
205 4500
                        NEW_VAL(to, tv);
206
#endif
207
#ifdef HAVE_TCP_KEEP
208 13500
                } else if (!strcmp(to->strname, "TCP_KEEPIDLE")) {
209 4500
                        x = (int)(cache_param->tcp_keepalive_time);
210 4500
                        NEW_VAL(to, x);
211 9000
                } else if (!strcmp(to->strname, "TCP_KEEPCNT")) {
212 4500
                        x = (int)(cache_param->tcp_keepalive_probes);
213 4500
                        NEW_VAL(to, x);
214 4500
                } else if (!strcmp(to->strname, "TCP_KEEPINTVL")) {
215 4500
                        x = (int)(cache_param->tcp_keepalive_intvl);
216 4500
                        NEW_VAL(to, x);
217
#endif
218
                }
219
        }
220 4500
        return (chg);
221
}
222
223
static void
224 1283
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 11546
        for (n = 0; n < n_tcp_opts; n++) {
232 10263
                to = &tcp_opts[n];
233 10263
                if (to->iponly && uds)
234 140
                        continue;
235 10123
                to->need = 1;
236 10123
                ptr = calloc(1, to->sz);
237 10123
                AN(ptr);
238 10124
                l = to->sz;
239 10124
                i = getsockopt(sock, to->level, to->optname, ptr, &l);
240 10123
                if (i == 0 && !memcmp(ptr, to->ptr, to->sz))
241 7592
                        to->need = 0;
242 10123
                free(ptr);
243 10123
                if (i && errno != ENOPROTOOPT)
244 0
                        VTCP_Assert(i);
245
        }
246 1283
}
247
248
static void
249 4264
vca_tcp_opt_set(const int sock, const unsigned uds, const int force)
250
{
251
        int n;
252
        struct tcp_opt *to;
253
254 38381
        for (n = 0; n < n_tcp_opts; n++) {
255 34115
                to = &tcp_opts[n];
256 34115
                if (to->iponly && uds)
257 391
                        continue;
258 33724
                if (to->need || force) {
259 17186
                        VTCP_Assert(setsockopt(sock,
260
                            to->level, to->optname, to->ptr, to->sz));
261
                }
262
        }
263 4266
}
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 5612
vca_pace_check(void)
272
{
273
        double p;
274
275 5612
        if (vca_pace == 0.0)
276 5612
                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 2896
vca_pace_good(void)
297
{
298
299 2896
        if (vca_pace == 0.0)
300 2896
                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 2836
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 2836
        SES_Reserve_remote_addr(sp, &sa);
323 2836
        AN(VSA_Build(sa, &wa->acceptaddr, wa->acceptaddrlen));
324 2835
        sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR];
325
326 2835
        VTCP_name(sa, raddr, VTCP_ADDRBUFSIZE, rport, VTCP_PORTBUFSIZE);
327 2836
        SES_Set_String_Attr(sp, SA_CLIENT_IP, raddr);
328 2836
        SES_Set_String_Attr(sp, SA_CLIENT_PORT, rport);
329
330 2836
        sl = sizeof ss;
331 2836
        AZ(getsockname(sp->fd, (void*)&ss, &sl));
332 2836
        SES_Reserve_local_addr(sp, &sa);
333 2836
        AN(VSA_Build(sa, &ss, sl));
334 2836
        sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_LOCAL_ADDR];
335 2836
        VTCP_name(sa, laddr, VTCP_ADDRBUFSIZE, lport, VTCP_PORTBUFSIZE);
336 2836
}
337
338
static void
339 60
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 60
        SES_Reserve_remote_addr(sp, &sa);
346 60
        AZ(SES_Set_remote_addr(sp, bogo_ip));
347 60
        sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR];
348 60
        sp->sattr[SA_LOCAL_ADDR] = sp->sattr[SA_REMOTE_ADDR];
349 60
        sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_REMOTE_ADDR];
350 60
        SES_Set_String_Attr(sp, SA_CLIENT_IP, "0.0.0.0");
351 60
        SES_Set_String_Attr(sp, SA_CLIENT_PORT, "0");
352
353 60
        strcpy(laddr, "0.0.0.0");
354 60
        strcpy(raddr, "0.0.0.0");
355 60
        strcpy(lport, "0");
356 60
        strcpy(rport, "0");
357 60
}
358
359
static void v_matchproto_(task_func_t)
360 2896
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 2896
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
371 2896
        CAST_OBJ_NOTNULL(wa, arg, WRK_ACCEPT_MAGIC);
372
373 2896
        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 2896
        AN(wrk->aws->r);
382 2896
        sp = SES_New(wrk->pool);
383 2896
        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 2896
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
397 2896
        wrk->stats->s_sess++;
398
399 2896
        sp->t_open = VTIM_real();
400 2896
        sp->t_idle = sp->t_open;
401 2896
        sp->vxid = VXID_Get(wrk, VSL_CLIENTMARKER);
402
403 2896
        sp->fd = wa->acceptsock;
404 2896
        wa->acceptsock = -1;
405 2896
        sp->listen_sock = wa->acceptlsock;
406
407 2896
        assert(wa->acceptaddrlen <= vsa_suckaddr_len);
408
409 2896
        if (wa->acceptlsock->uds)
410 60
                vca_mk_uds(wa, sp, laddr, lport, raddr, rport);
411
        else
412 2836
                vca_mk_tcp(wa, sp, laddr, lport, raddr, rport);
413
414 2896
        AN(wa->acceptlsock->name);
415 2896
        VSL(SLT_Begin, sp->vxid, "sess 0 %s",
416 2896
            wa->acceptlsock->transport->name);
417 5792
        VSL(SLT_SessOpen, sp->vxid, "%s %s %s %s %s %.6f %d",
418 2896
            raddr, rport, wa->acceptlsock->name, laddr, lport,
419
            sp->t_open, sp->fd);
420
421 2896
        WS_Release(wrk->aws, 0);
422
423 2896
        vca_pace_good();
424 2896
        wrk->stats->sess_conn++;
425
426 2896
        if (need_test) {
427 1283
                vca_tcp_opt_test(sp->fd, wa->acceptlsock->uds);
428 1283
                need_test = 0;
429
        }
430 2896
        vca_tcp_opt_set(sp->fd, wa->acceptlsock->uds, 0);
431
432 2896
        req = Req_New(wrk, sp);
433 2896
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
434 2896
        req->htc->rfd = &sp->fd;
435
436 2896
        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 2724
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
455 2724
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
456 2724
        CAST_OBJ_NOTNULL(ps, arg, POOLSOCK_MAGIC);
457 2724
        ls = ps->lsock;
458 2724
        CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
459
460 8136
        while (!pool_accepting)
461 2692
                VTIM_sleep(.1);
462
463 8332
        while (!ps->pool->die) {
464 5612
                INIT_OBJ(&wa, WRK_ACCEPT_MAGIC);
465 5612
                wa.acceptlsock = ls;
466
467 5612
                vca_pace_check();
468
469 5612
                wa.acceptaddrlen = sizeof wa.acceptaddr;
470
                do {
471 5612
                        i = accept(ls->sock, (void*)&wa.acceptaddr,
472
                                   &wa.acceptaddrlen);
473 2897
                } while (i < 0 && errno == EAGAIN);
474
475 2897
                if (i < 0 && ps->pool->die) {
476 0
                        VSL(SLT_Debug, 0, "XXX Accept thread dies %p", ps);
477 0
                        FREE_OBJ(ps);
478 4
                        return;
479
                }
480
481 2897
                if (i < 0 && ls->sock == -2) {
482
                        /* Shut down in progress */
483 1
                        sleep(2);
484 0
                        continue;
485
                }
486
487 2896
                if (i < 0) {
488 0
                        switch (errno) {
489
                        case ECONNABORTED:
490 0
                                wrk->stats->sess_fail_econnaborted++;
491 0
                                break;
492
                        case EINTR:
493 0
                                wrk->stats->sess_fail_eintr++;
494 0
                                break;
495
                        case EMFILE:
496 0
                                wrk->stats->sess_fail_emfile++;
497 0
                                vca_pace_bad();
498 0
                                break;
499
                        case EBADF:
500 0
                                wrk->stats->sess_fail_ebadf++;
501 0
                                vca_pace_bad();
502 0
                                break;
503
                        case ENOBUFS:
504
                        case ENOMEM:
505 0
                                wrk->stats->sess_fail_enomem++;
506 0
                                vca_pace_bad();
507 0
                                break;
508
                        default:
509 0
                                wrk->stats->sess_fail_other++;
510 0
                                vca_pace_bad();
511 0
                                break;
512
                        }
513 0
                        wrk->stats->sess_fail++;
514 0
                        VSL(SLT_Debug, ls->sock, "Accept failed: %s",
515 0
                            strerror(errno));
516 0
                        (void)Pool_TrySumstat(wrk);
517 0
                        continue;
518
                }
519
520 2896
                wa.acceptsock = i;
521
522 2896
                if (!Pool_Task_Arg(wrk, TASK_QUEUE_VCA,
523
                    vca_make_session, &wa, sizeof wa)) {
524
                        /*
525
                         * We couldn't get another thread, so we will handle
526
                         * the request in this worker thread, but first we
527
                         * must reschedule the listening task so it will be
528
                         * taken up by another thread again.
529
                         */
530 4
                        if (!ps->pool->die)
531 0
                                AZ(Pool_Task(wrk->pool, &ps->task,
532
                                    TASK_QUEUE_VCA));
533 4
                        return;
534
                }
535 2892
                if (!ps->pool->die && DO_DEBUG(DBG_SLOW_ACCEPTOR))
536 12
                        VTIM_sleep(2.0);
537
538
                /*
539
                 * We were able to hand off, so release this threads VCL
540
                 * reference (if any) so we don't hold on to discarded VCLs.
541
                 */
542 2892
                if (wrk->vcl != NULL)
543 0
                        VCL_Rel(&wrk->vcl);
544
        }
545
}
546
547
/*--------------------------------------------------------------------
548
 * Called when a worker and attached thread pool is created, to
549
 * allocate the tasks which will listen to sockets for that pool.
550
 */
551
552
void
553 2720
VCA_NewPool(struct pool *pp)
554
{
555
        struct listen_sock *ls;
556
        struct poolsock *ps;
557
558 5444
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
559 2724
                ALLOC_OBJ(ps, POOLSOCK_MAGIC);
560 2724
                AN(ps);
561 2724
                ps->lsock = ls;
562 2724
                ps->task.func = vca_accept_task;
563 2724
                ps->task.priv = ps;
564 2724
                ps->pool = pp;
565 2724
                VTAILQ_INSERT_TAIL(&pp->poolsocks, ps, list);
566 2724
                AZ(Pool_Task(pp, &ps->task, TASK_QUEUE_VCA));
567
        }
568 2720
}
569
570
void
571 4
VCA_DestroyPool(struct pool *pp)
572
{
573
        struct poolsock *ps;
574
575 12
        while (!VTAILQ_EMPTY(&pp->poolsocks)) {
576 4
                ps = VTAILQ_FIRST(&pp->poolsocks);
577 4
                VTAILQ_REMOVE(&pp->poolsocks, ps, list);
578
        }
579 4
}
580
581
/*--------------------------------------------------------------------*/
582
583
static void * v_matchproto_()
584 1366
vca_acct(void *arg)
585
{
586
        struct listen_sock *ls;
587
        double t0;
588
589
        // XXX Actually a mis-nomer now because the accept happens in a pool
590
        // thread. Rename to accept-nanny or so?
591 1366
        THR_SetName("cache-acceptor");
592 1366
        THR_Init();
593
        (void)arg;
594
595 1366
        t0 = VTIM_real();
596 1366
        vca_periodic(t0);
597
598 1366
        pool_accepting = 1;
599
600
        while (1) {
601 7634
                (void)sleep(1);
602 3134
                if (vca_tcp_opt_init()) {
603 2
                        AZ(pthread_mutex_lock(&shut_mtx));
604 4
                        VTAILQ_FOREACH(ls, &heritage.socks, list) {
605 2
                                if (ls->sock == -2)
606 0
                                        continue;       // VCA_Shutdown
607 2
                                assert (ls->sock > 0);
608 2
                                vca_tcp_opt_set(ls->sock, ls->uds, 1);
609
                        }
610 2
                        AZ(pthread_mutex_unlock(&shut_mtx));
611
                }
612 3134
                vca_periodic(t0);
613
        }
614
        NEEDLESS(return NULL);
615
}
616
617
/*--------------------------------------------------------------------*/
618
619
static void v_matchproto_(cli_func_t)
620 1366
ccf_start(struct cli *cli, const char * const *av, void *priv)
621
{
622
        struct listen_sock *ls;
623
624
        (void)cli;
625
        (void)av;
626
        (void)priv;
627
628 1366
        (void)vca_tcp_opt_init();
629
630 2734
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
631 1368
                CHECK_OBJ_NOTNULL(ls->transport, TRANSPORT_MAGIC);
632 1368
                assert (ls->sock > 0);  // We know where stdin is
633 1368
                if (cache_param->tcp_fastopen) {
634
                        int i;
635 0
                        i = VTCP_fastopen(ls->sock, cache_param->listen_depth);
636 0
                        if (i)
637 0
                                VSL(SLT_Error, 0,
638
                                    "Kernel TCP Fast Open: sock=%d, ret=%d %s",
639 0
                                    ls->sock, i, strerror(errno));
640
                }
641 1368
                if (listen(ls->sock, cache_param->listen_depth)) {
642 0
                        VCLI_SetResult(cli, CLIS_CANT);
643 0
                        VCLI_Out(cli, "Listen failed on socket '%s': %s",
644 0
                            ls->endpoint, strerror(errno));
645 0
                        return;
646
                }
647 1368
                vca_tcp_opt_set(ls->sock, ls->uds, 1);
648 1368
                if (cache_param->accept_filter) {
649
                        int i;
650 1364
                        i = VTCP_filter_http(ls->sock);
651 1364
                        if (i)
652 1364
                                VSL(SLT_Error, 0,
653
                                    "Kernel filtering: sock=%d, ret=%d %s",
654 1364
                                    ls->sock, i, strerror(errno));
655
                }
656
        }
657
658 1366
        need_test = 1;
659
660 1366
        AZ(pthread_create(&VCA_thread, NULL, vca_acct, NULL));
661
}
662
663
/*--------------------------------------------------------------------*/
664
665
static void v_matchproto_(cli_func_t)
666 2718
ccf_listen_address(struct cli *cli, const char * const *av, void *priv)
667
{
668
        struct listen_sock *ls;
669
        char h[32], p[32];
670
671
        (void)cli;
672
        (void)av;
673
        (void)priv;
674
675
        /*
676
         * This CLI command is primarily used by varnishtest.  Don't
677
         * respond until listen(2) has been called, in order to avoid
678
         * a race where varnishtest::client would attempt to connect(2)
679
         * before listen(2) has been called.
680
         */
681 5436
        while (!pool_accepting)
682 0
                VTIM_sleep(.1);
683
684 2718
        AZ(pthread_mutex_lock(&shut_mtx));
685 5440
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
686 2722
                if (!ls->uds) {
687 2646
                        VTCP_myname(ls->sock, h, sizeof h, p, sizeof p);
688 2646
                        VCLI_Out(cli, "%s %s\n", h, p);
689
                }
690
                else
691 76
                        VCLI_Out(cli, "%s -\n", ls->endpoint);
692
        }
693 2718
        AZ(pthread_mutex_unlock(&shut_mtx));
694 2718
}
695
696
/*--------------------------------------------------------------------*/
697
698
static struct cli_proto vca_cmds[] = {
699
        { CLICMD_SERVER_START,          "", ccf_start },
700
        { CLICMD_DEBUG_LISTEN_ADDRESS,  "d", ccf_listen_address },
701
        { NULL }
702
};
703
704
void
705 1368
VCA_Init(void)
706
{
707
708 1368
        CLI_AddFuncs(vca_cmds);
709 1368
        Lck_New(&pace_mtx, lck_vcapace);
710 1368
}
711
712
void
713 1356
VCA_Shutdown(void)
714
{
715
        struct listen_sock *ls;
716
        int i;
717
718 1356
        AZ(pthread_mutex_lock(&shut_mtx));
719 2714
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
720 1358
                i = ls->sock;
721 1358
                ls->sock = -2;
722 1358
                (void)close(i);
723
        }
724 1356
        AZ(pthread_mutex_unlock(&shut_mtx));
725 1356
}
726
727
/*--------------------------------------------------------------------
728
 * Transport protocol registration
729
 *
730
 */
731
732
static VTAILQ_HEAD(,transport)  transports =
733
    VTAILQ_HEAD_INITIALIZER(transports);
734
735
void
736 1542
XPORT_Init(void)
737
{
738
        uint16_t n;
739
        struct transport *xp;
740
741 1542
        ASSERT_MGT();
742
743 1542
        VTAILQ_INSERT_TAIL(&transports, &PROXY_transport, list);
744 1542
        VTAILQ_INSERT_TAIL(&transports, &HTTP1_transport, list);
745 1542
        VTAILQ_INSERT_TAIL(&transports, &H2_transport, list);
746
747 1542
        n = 0;
748 6168
        VTAILQ_FOREACH(xp, &transports, list)
749 4626
                xp->number = ++n;
750 1542
}
751
752
const struct transport *
753 1470
XPORT_Find(const char *name)
754
{
755
        const struct transport *xp;
756
757 1470
        ASSERT_MGT();
758
759 2926
        VTAILQ_FOREACH(xp, &transports, list)
760 5840
                if (xp->proto_ident != NULL &&
761 2918
                    !strcasecmp(xp->proto_ident, name))
762 1466
                        return (xp);
763 4
        return (NULL);
764
}
765
766
const struct transport *
767 8
XPORT_ByNumber(uint16_t no)
768
{
769
        const struct transport *xp;
770
771 18
        VTAILQ_FOREACH(xp, &transports, list)
772 18
                if (xp->number == no)
773 8
                        return (xp);
774 0
        return (NULL);
775
}