vinyl-cache/bin/vinyld/cache/cache_conn_pool.c
0
/*-
1
 * Copyright (c) 2015 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
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
 * (TCP|UDS) connection pools.
30
 *
31
 */
32
33
#include "config.h"
34
35
#include <stdlib.h>
36
37
#include "cache_int.h"
38
39
#include "vsa.h"
40
#include "vsha256.h"
41
#include "vtcp.h"
42
#include "vus.h"
43
#include "vtim.h"
44
#include "waiter/waiter.h"
45
46
#include "cache_conn_pool.h"
47
#include "cache_pool.h"
48
49
#include "VSC_vcp.h"
50
51
struct conn_pool;
52
static inline int vcp_cmp(const struct conn_pool *a, const struct conn_pool *b);
53
54
/*--------------------------------------------------------------------
55
 */
56
57
struct pfd {
58
        unsigned                magic;
59
#define PFD_MAGIC               0x0c5e6593
60
        int                     fd;
61
        VTAILQ_ENTRY(pfd)       list;
62
        VCL_IP                  addr;
63
        uint8_t                 state;
64
        struct waited           waited[1];
65
        struct conn_pool        *conn_pool;
66
67
        pthread_cond_t          *cond;
68
69
        vtim_mono               created;
70
        uint64_t                reused;
71
};
72
73
/*--------------------------------------------------------------------
74
 */
75
76
typedef int cp_open_f(const struct conn_pool *, vtim_dur tmo, VCL_IP *ap);
77
typedef void cp_close_f(struct pfd *);
78
typedef void cp_name_f(const struct pfd *, char *, unsigned, char *, unsigned);
79
80
struct cp_methods {
81
        cp_open_f                               *open;
82
        cp_close_f                              *close;
83
        cp_name_f                               *local_name;
84
        cp_name_f                               *remote_name;
85
};
86
87
struct conn_pool {
88
        unsigned                                magic;
89
#define CONN_POOL_MAGIC                         0x85099bc3
90
91
        const struct cp_methods                 *methods;
92
93
        struct vrt_endpoint                     *endpoint;
94
        char                                    ident[VSHA256_DIGEST_LENGTH];
95
96
        VRBT_ENTRY(conn_pool)                   entry;
97
        int                                     refcnt;
98
        struct lock                             mtx;
99
100
        VTAILQ_HEAD(, pfd)                      connlist;
101
        int                                     n_conn;
102
103
        int                                     n_kill;
104
105
        int                                     n_used;
106
107
        vtim_mono                               holddown;
108
        int                                     holddown_errno;
109
};
110
111
static struct lock conn_pools_mtx;
112
static struct lock dead_pools_mtx;
113
static struct VSC_vcp *vsc;
114
115
VRBT_HEAD(vrb, conn_pool);
116 64
VRBT_GENERATE_REMOVE_COLOR(vrb, conn_pool, entry, static)
117 167
VRBT_GENERATE_REMOVE(vrb, conn_pool, entry, static)
118 883
VRBT_GENERATE_INSERT_COLOR(vrb, conn_pool, entry, static)
119 4238
VRBT_GENERATE_INSERT_FINISH(vrb, conn_pool, entry, static)
120 6421
VRBT_GENERATE_INSERT(vrb, conn_pool, entry, vcp_cmp, static)
121 10
VRBT_GENERATE_NEXT(vrb, conn_pool, entry, static)
122 20
VRBT_GENERATE_MINMAX(vrb, conn_pool, entry, static)
123
124
static struct vrb conn_pools = VRBT_INITIALIZER(&conn_pools);
125
static struct vrb dead_pools = VRBT_INITIALIZER(&dying_cps);
126
127
/*--------------------------------------------------------------------
128
 */
129
130
unsigned
131 42691
PFD_State(const struct pfd *p)
132
{
133 42691
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
134 42691
        return (p->state);
135
}
136
137
int *
138 18030
PFD_Fd(struct pfd *p)
139
{
140 18030
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
141 18030
        return (&(p->fd));
142
}
143
144
vtim_dur
145 3292
PFD_Age(const struct pfd *p)
146
{
147
        vtim_mono t_mono;
148
149 3292
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
150 3292
        t_mono = VTIM_mono();
151 3292
        assert(t_mono >= p->created);
152
153 3292
        return (t_mono - p->created);
154
}
155
156
uint64_t
157 3292
PFD_Reused(const struct pfd *p)
158
{
159 3292
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
160 3292
        return (p->reused);
161
}
162
163
void
164 8968
PFD_LocalName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
165
              unsigned plen)
166
{
167 8968
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
168 8968
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
169 8968
        p->conn_pool->methods->local_name(p, abuf, alen, pbuf, plen);
170 8968
}
171
172
void
173 8968
PFD_RemoteName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
174
               unsigned plen)
175
{
176 8968
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
177 8968
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
178 8968
        p->conn_pool->methods->remote_name(p, abuf, alen, pbuf, plen);
179 8968
}
180
181
/*--------------------------------------------------------------------
182
 */
183
184
static inline int
185 2183
vcp_cmp(const struct conn_pool *a, const struct conn_pool *b)
186
{
187 2183
        return (memcmp(a->ident, b->ident, sizeof b->ident));
188
}
189
190
/*--------------------------------------------------------------------
191
 * Waiter-handler
192
 */
193
194
static void  v_matchproto_(waiter_handle_f)
195 7252
vcp_handle(struct waited *w, enum wait_event ev, vtim_real now)
196
{
197
        struct pfd *pfd;
198
        struct conn_pool *cp;
199
200 7252
        CHECK_OBJ_NOTNULL(w, WAITED_MAGIC);
201 7252
        CAST_OBJ_NOTNULL(pfd, w->priv1, PFD_MAGIC);
202 7252
        (void)ev;
203 7252
        (void)now;
204 7252
        CHECK_OBJ_NOTNULL(pfd->conn_pool, CONN_POOL_MAGIC);
205 7252
        cp = pfd->conn_pool;
206
207 7252
        Lck_Lock(&cp->mtx);
208
209 7252
        switch (pfd->state) {
210
        case PFD_STATE_STOLEN:
211 3284
                pfd->state = PFD_STATE_USED;
212 3284
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
213 3284
                AN(pfd->cond);
214 3284
                PTOK(pthread_cond_signal(pfd->cond));
215 3284
                break;
216
        case PFD_STATE_AVAIL:
217 3952
                cp->methods->close(pfd);
218 3952
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
219 3952
                cp->n_conn--;
220 3952
                FREE_OBJ(pfd);
221 3952
                break;
222
        case PFD_STATE_CLEANUP:
223 16
                cp->methods->close(pfd);
224 16
                cp->n_kill--;
225 16
                memset(pfd, 0x11, sizeof *pfd);
226 16
                free(pfd);
227 16
                break;
228
        default:
229 0
                WRONG("Wrong pfd state");
230 0
        }
231 7252
        Lck_Unlock(&cp->mtx);
232 7252
}
233
234
235
/*--------------------------------------------------------------------
236
 */
237
238
void
239 152
VCP_AddRef(struct conn_pool *cp)
240
{
241 152
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
242
243 152
        Lck_Lock(&conn_pools_mtx);
244 152
        assert(cp->refcnt > 0);
245 152
        cp->refcnt++;
246 152
        Lck_Unlock(&conn_pools_mtx);
247 152
}
248
249
/*--------------------------------------------------------------------
250
 */
251
252
static void
253 1340
vcp_destroy(struct conn_pool **cpp)
254
{
255
        struct conn_pool *cp;
256
257 1340
        TAKE_OBJ_NOTNULL(cp, cpp, CONN_POOL_MAGIC);
258 1340
        AZ(cp->n_conn);
259 1340
        AZ(cp->n_kill);
260 1340
        Lck_Delete(&cp->mtx);
261 1340
        FREE_OBJ(cp->endpoint);
262 1340
        FREE_OBJ(cp);
263 1340
}
264
265
/*--------------------------------------------------------------------
266
 * Release Conn pool, destroy or stash for future destruction if last
267
 * reference.
268
 */
269
270
void
271 348
VCP_Rel(struct conn_pool **cpp)
272
{
273
        struct conn_pool *cp;
274
        struct pfd *pfd, *pfd2;
275
        int n_kill;
276
277 348
        TAKE_OBJ_NOTNULL(cp, cpp, CONN_POOL_MAGIC);
278
279 348
        Lck_Lock(&conn_pools_mtx);
280 348
        assert(cp->refcnt > 0);
281 348
        if (--cp->refcnt > 0) {
282 240
                Lck_Unlock(&conn_pools_mtx);
283 240
                return;
284
        }
285 108
        AZ(cp->n_used);
286 108
        VRBT_REMOVE(vrb, &conn_pools, cp);
287 108
        Lck_Unlock(&conn_pools_mtx);
288
289 108
        Lck_Lock(&cp->mtx);
290 116
        VTAILQ_FOREACH_SAFE(pfd, &cp->connlist, list, pfd2) {
291 8
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
292 8
                cp->n_conn--;
293 8
                assert(pfd->state == PFD_STATE_AVAIL);
294 8
                pfd->state = PFD_STATE_CLEANUP;
295 8
                (void)shutdown(pfd->fd, SHUT_RDWR);
296 8
                cp->n_kill++;
297 8
        }
298 108
        n_kill = cp->n_kill;
299 108
        Lck_Unlock(&cp->mtx);
300 108
        if (n_kill == 0) {
301 100
                vcp_destroy(&cp);
302 100
                return;
303
        }
304 8
        Lck_Lock(&dead_pools_mtx);
305
        /*
306
         * Here we reuse cp's entry but it will probably not be correctly
307
         * indexed because of the hack in VCP_RelPoll
308
         */
309 8
        VRBT_INSERT(vrb, &dead_pools, cp);
310 8
        Lck_Unlock(&dead_pools_mtx);
311 348
}
312
313
void
314 31828
VCP_RelPoll(void)
315
{
316
        struct vrb dead;
317
        struct conn_pool *cp, *cp2;
318
        int n_kill;
319
320 31828
        ASSERT_CLI();
321
322 31828
        Lck_Lock(&dead_pools_mtx);
323 31828
        if (VRBT_EMPTY(&dead_pools)) {
324 31818
                Lck_Unlock(&dead_pools_mtx);
325 31818
                return;
326
        }
327 10
        dead = dead_pools;
328 10
        VRBT_INIT(&dead_pools);
329 10
        Lck_Unlock(&dead_pools_mtx);
330
331 20
        VRBT_FOREACH_SAFE(cp, vrb, &dead, cp2) {
332 10
                CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
333 10
                Lck_Lock(&cp->mtx);
334 10
                n_kill = cp->n_kill;
335 10
                Lck_Unlock(&cp->mtx);
336 10
                if (n_kill > 0)
337 2
                        continue;
338 8
                VRBT_REMOVE(vrb, &dead, cp);
339 8
                vcp_destroy(&cp);
340 8
        }
341
342 10
        if (VRBT_EMPTY(&dead))
343 8
                return;
344
345 2
        Lck_Lock(&dead_pools_mtx);
346
        /*
347
         * The following insertion will most likely result in an
348
         * unordered tree, but in this case it does not matter
349
         * as we just want to iterate over all the elements
350
         * in the tree in order to delete them.
351
         */
352 2
        VRBT_INSERT(vrb, &dead_pools, dead.rbh_root);
353 2
        Lck_Unlock(&dead_pools_mtx);
354 31828
}
355
356
/*--------------------------------------------------------------------
357
 * Recycle a connection.
358
 */
359
360
void
361 7348
VCP_Recycle(const struct worker *wrk, struct pfd **pfdp)
362
{
363
        struct pfd *pfd;
364
        struct conn_pool *cp;
365 7348
        int i = 0;
366
367 7348
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
368 7348
        TAKE_OBJ_NOTNULL(pfd, pfdp, PFD_MAGIC);
369 7348
        cp = pfd->conn_pool;
370 7348
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
371
372 7348
        assert(pfd->state == PFD_STATE_USED);
373 7348
        assert(pfd->fd > 0);
374
375 7348
        Lck_Lock(&cp->mtx);
376 7348
        cp->n_used--;
377
378 7348
        pfd->waited->priv1 = pfd;
379 7348
        pfd->waited->fd = pfd->fd;
380 7348
        pfd->waited->idle = VTIM_real();
381 7348
        pfd->state = PFD_STATE_AVAIL;
382 7348
        pfd->waited->func = vcp_handle;
383 7348
        pfd->waited->tmo = cache_param->backend_idle_timeout;
384 7348
        if (Wait_Enter(wrk->pool->waiter, pfd->waited)) {
385 0
                cp->methods->close(pfd);
386 0
                memset(pfd, 0x33, sizeof *pfd);
387 0
                free(pfd);
388
                // XXX: stats
389 0
                pfd = NULL;
390 0
        } else {
391 7348
                VTAILQ_INSERT_HEAD(&cp->connlist, pfd, list);
392 7348
                i++;
393
        }
394
395 7348
        if (pfd != NULL)
396 7348
                cp->n_conn++;
397 7348
        Lck_Unlock(&cp->mtx);
398
399 7348
        if (i && DO_DEBUG(DBG_VTC_MODE)) {
400
                /*
401
                 * In vinyltest we do not have the luxury of using
402
                 * multiple backend connections, so whenever we end up
403
                 * in the "pending" case, take a short nap to let the
404
                 * waiter catch up and put the pfd back into circulations.
405
                 *
406
                 * In particular ESI:include related tests suffer random
407
                 * failures without this.
408
                 *
409
                 * In normal operation, the only effect is that we will
410
                 * have N+1 backend connections rather than N, which is
411
                 * entirely harmless.
412
                 */
413 7348
                VTIM_sleep(0.01);
414 7348
        }
415 7348
}
416
417
/*--------------------------------------------------------------------
418
 * Open a new connection from pool.
419
 */
420
421
int
422 6599
VCP_Open(struct conn_pool *cp, vtim_dur tmo, VCL_IP *ap, int *err)
423
{
424
        int r;
425
        vtim_mono h;
426
427 6599
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
428 6599
        AN(err);
429
430 6599
        while (cp->holddown > 0) {
431 89
                Lck_Lock(&cp->mtx);
432 89
                if (cp->holddown == 0) {
433 0
                        Lck_Unlock(&cp->mtx);
434 0
                        break;
435
                }
436
437 89
                if (VTIM_mono() >= cp->holddown) {
438 10
                        cp->holddown = 0;
439 10
                        Lck_Unlock(&cp->mtx);
440 10
                        break;
441
                }
442
443 79
                *err = 0;
444 79
                errno = cp->holddown_errno;
445 79
                Lck_Unlock(&cp->mtx);
446 79
                return (-1);
447
        }
448
449 6520
        *err = errno = 0;
450 6520
        r = cp->methods->open(cp, tmo, ap);
451
452 6520
        if (r >= 0 && errno == 0 && cp->endpoint->preamble != NULL &&
453 36
             cp->endpoint->preamble->len > 0) {
454 36
                CHECK_OBJ(cp->endpoint->preamble, VRT_BLOB_MAGIC);
455 108
                if (write(r, cp->endpoint->preamble->blob,
456 72
                    cp->endpoint->preamble->len) !=
457 36
                    cp->endpoint->preamble->len) {
458 0
                        *err = errno;
459 0
                        closefd(&r);
460 0
                }
461 36
        } else {
462 6484
                *err = errno;
463
        }
464
465 6520
        if (r >= 0)
466 6413
                return (r);
467
468 107
        h = 0;
469
470 107
        switch (errno) {
471
        case EACCES:
472
        case EPERM:
473 0
                h = cache_param->backend_local_error_holddown;
474 0
                break;
475
        case EADDRNOTAVAIL:
476 0
                h = cache_param->backend_local_error_holddown;
477 0
                break;
478
        case ECONNREFUSED:
479 107
                h = cache_param->backend_remote_error_holddown;
480 107
                break;
481
        case ENETUNREACH:
482 0
                h = cache_param->backend_remote_error_holddown;
483 0
                break;
484
        default:
485 0
                break;
486
        }
487
488 107
        if (h == 0)
489 0
                return (r);
490
491 107
        Lck_Lock(&cp->mtx);
492 107
        h += VTIM_mono();
493 107
        if (cp->holddown == 0 || h < cp->holddown) {
494 98
                cp->holddown = h;
495 98
                cp->holddown_errno = errno;
496 98
        }
497
498 107
        Lck_Unlock(&cp->mtx);
499
500 107
        return (r);
501 6599
}
502
503
/*--------------------------------------------------------------------
504
 * Close a connection.
505
 */
506
507
void
508 1620
VCP_Close(struct pfd **pfdp)
509
{
510
        struct pfd *pfd;
511
        struct conn_pool *cp;
512
513 1620
        TAKE_OBJ_NOTNULL(pfd, pfdp, PFD_MAGIC);
514 1620
        cp = pfd->conn_pool;
515 1620
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
516
517 1620
        assert(pfd->fd > 0);
518
519 1620
        Lck_Lock(&cp->mtx);
520 1620
        assert(pfd->state == PFD_STATE_USED || pfd->state == PFD_STATE_STOLEN);
521 1620
        cp->n_used--;
522 1620
        if (pfd->state == PFD_STATE_STOLEN) {
523 8
                (void)shutdown(pfd->fd, SHUT_RDWR);
524 8
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
525 8
                pfd->state = PFD_STATE_CLEANUP;
526 8
                cp->n_kill++;
527 8
        } else {
528 1612
                assert(pfd->state == PFD_STATE_USED);
529 1612
                cp->methods->close(pfd);
530 1612
                memset(pfd, 0x44, sizeof *pfd);
531 1612
                free(pfd);
532
        }
533 1620
        Lck_Unlock(&cp->mtx);
534 1620
}
535
536
/*--------------------------------------------------------------------
537
 * Get a connection, possibly recycled
538
 */
539
540
struct pfd *
541 9096
VCP_Get(struct conn_pool *cp, vtim_dur tmo, struct worker *wrk,
542
    unsigned force_fresh, int *err)
543
{
544
        struct pfd *pfd;
545
546 9096
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
547 9096
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
548 9096
        AN(err);
549
550 9096
        *err = 0;
551 9096
        Lck_Lock(&cp->mtx);
552 9096
        pfd = VTAILQ_FIRST(&cp->connlist);
553 9096
        CHECK_OBJ_ORNULL(pfd, PFD_MAGIC);
554 9096
        if (force_fresh || pfd == NULL || pfd->state == PFD_STATE_STOLEN) {
555 5804
                pfd = NULL;
556 5804
        } else {
557 3292
                assert(pfd->conn_pool == cp);
558 3292
                assert(pfd->state == PFD_STATE_AVAIL);
559 3292
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
560 3292
                VTAILQ_INSERT_TAIL(&cp->connlist, pfd, list);
561 3292
                cp->n_conn--;
562 3292
                VSC_C_main->backend_reuse++;
563 3292
                pfd->state = PFD_STATE_STOLEN;
564 3292
                pfd->cond = &wrk->cond;
565 3292
                pfd->reused++;
566
        }
567 9096
        cp->n_used++;                   // Opening mostly works
568 9096
        Lck_Unlock(&cp->mtx);
569
570 9096
        if (pfd != NULL)
571 3292
                return (pfd);
572
573 5804
        ALLOC_OBJ(pfd, PFD_MAGIC);
574 5804
        AN(pfd);
575 5804
        INIT_OBJ(pfd->waited, WAITED_MAGIC);
576 5804
        pfd->state = PFD_STATE_USED;
577 5804
        pfd->conn_pool = cp;
578 5804
        pfd->fd = VCP_Open(cp, tmo, &pfd->addr, err);
579 5804
        if (pfd->fd < 0) {
580 124
                FREE_OBJ(pfd);
581 124
                Lck_Lock(&cp->mtx);
582 124
                cp->n_used--;           // Nope, didn't work after all.
583 124
                Lck_Unlock(&cp->mtx);
584 124
        } else {
585 5680
                pfd->created = VTIM_mono();
586 5680
                VSC_C_main->backend_conn++;
587
        }
588
589 5804
        return (pfd);
590 9096
}
591
592
/*--------------------------------------------------------------------
593
 */
594
595
int
596 3280
VCP_Wait(struct worker *wrk, struct pfd *pfd, vtim_real when)
597
{
598
        struct conn_pool *cp;
599
        int r;
600
601 3280
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
602 3280
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
603 3280
        cp = pfd->conn_pool;
604 3280
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
605 3280
        assert(pfd->cond == &wrk->cond);
606 3280
        Lck_Lock(&cp->mtx);
607 6556
        while (pfd->state == PFD_STATE_STOLEN) {
608 3280
                r = Lck_CondWaitUntil(&wrk->cond, &cp->mtx, when);
609 3280
                if (r != 0) {
610 4
                        if (r == EINTR)
611 0
                                continue;
612 4
                        assert(r == ETIMEDOUT);
613 4
                        Lck_Unlock(&cp->mtx);
614 4
                        return (1);
615
                }
616
        }
617 3276
        assert(pfd->state == PFD_STATE_USED);
618 3276
        pfd->cond = NULL;
619 3276
        Lck_Unlock(&cp->mtx);
620
621 3276
        return (0);
622 3280
}
623
624
/*--------------------------------------------------------------------
625
 */
626
627
VCL_IP
628 4
VCP_GetIp(struct pfd *pfd)
629
{
630
631 4
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
632 4
        return (pfd->addr);
633
}
634
635
/*--------------------------------------------------------------------*/
636
637
static void
638 24
vcp_panic_endpoint(struct vsb *vsb, const struct vrt_endpoint *vep)
639
{
640
        char h[VTCP_ADDRBUFSIZE];
641
        char p[VTCP_PORTBUFSIZE];
642
643 24
        if (PAN_dump_struct(vsb, vep, VRT_ENDPOINT_MAGIC, "vrt_endpoint"))
644 0
                return;
645 24
        if (vep->uds_path)
646 0
                VSB_printf(vsb, "uds_path = %s,\n", vep->uds_path);
647 24
        if (vep->ipv4 && VSA_Sane(vep->ipv4)) {
648 24
                VTCP_name(vep->ipv4, h, sizeof h, p, sizeof p);
649 24
                VSB_printf(vsb, "ipv4 = %s, ", h);
650 24
                VSB_printf(vsb, "port = %s,\n", p);
651 24
        }
652 24
        if (vep->ipv6 && VSA_Sane(vep->ipv6)) {
653 0
                VTCP_name(vep->ipv6, h, sizeof h, p, sizeof p);
654 0
                VSB_printf(vsb, "ipv6 = %s, ", h);
655 0
                VSB_printf(vsb, "port = %s,\n", p);
656 0
        }
657 24
        VSB_indent(vsb, -2);
658 24
        VSB_cat(vsb, "},\n");
659 24
}
660
661
void
662 24
VCP_Panic(struct vsb *vsb, struct conn_pool *cp)
663
{
664
665 24
        if (PAN_dump_struct(vsb, cp, CONN_POOL_MAGIC, "conn_pool"))
666 0
                return;
667 24
        VSB_cat(vsb, "ident = ");
668 24
        VSB_quote(vsb, cp->ident, VSHA256_DIGEST_LENGTH, VSB_QUOTE_HEX);
669 24
        VSB_cat(vsb, ",\n");
670 24
        vcp_panic_endpoint(vsb, cp->endpoint);
671 24
        VSB_indent(vsb, -2);
672 24
        VSB_cat(vsb, "},\n");
673 24
}
674
675
/*--------------------------------------------------------------------*/
676
677
void
678 3892
VCP_Init(void)
679
{
680 3892
        Lck_New(&conn_pools_mtx, lck_conn_pool);
681 3892
        Lck_New(&dead_pools_mtx, lck_dead_pool);
682
683 3892
        AZ(vsc);
684 3892
        vsc = VSC_vcp_New(NULL, NULL, "");
685 3892
        AN(vsc);
686 3892
}
687
688
/**********************************************************************/
689
690
static inline int
691 6524
tmo2msec(vtim_dur tmo)
692
{
693 6524
        return ((int)floor(tmo * 1000.0));
694
}
695
696
static int v_matchproto_(cp_open_f)
697 6042
vtp_open(const struct conn_pool *cp, vtim_dur tmo, VCL_IP *ap)
698
{
699
        int s;
700
        int msec;
701
702 6042
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
703
704 6042
        msec = tmo2msec(tmo);
705 6042
        if (cache_param->prefer_ipv6) {
706 0
                *ap = cp->endpoint->ipv6;
707 0
                s = VTCP_connect(*ap, msec);
708 0
                if (s >= 0)
709 0
                        return (s);
710 0
        }
711 6042
        *ap = cp->endpoint->ipv4;
712 6042
        s = VTCP_connect(*ap, msec);
713 6042
        if (s >= 0)
714 5928
                return (s);
715 114
        if (!cache_param->prefer_ipv6) {
716 114
                *ap = cp->endpoint->ipv6;
717 114
                s = VTCP_connect(*ap, msec);
718 114
        }
719 114
        return (s);
720 6042
}
721
722
723
/*--------------------------------------------------------------------*/
724
725
static void v_matchproto_(cp_close_f)
726 5580
vtp_close(struct pfd *pfd)
727
{
728
729 5580
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
730 5580
        VTCP_close(&pfd->fd);
731 5580
}
732
733
static void v_matchproto_(cp_name_f)
734 8524
vtp_local_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
735
               unsigned plen)
736
{
737 8524
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
738 8524
        VTCP_myname(pfd->fd, addr, alen, pbuf, plen);
739 8524
}
740
741
static void v_matchproto_(cp_name_f)
742 8524
vtp_remote_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
743
                unsigned plen)
744
{
745 8524
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
746 8524
        VTCP_hisname(pfd->fd, addr, alen, pbuf, plen);
747 8524
}
748
749
static const struct cp_methods vtp_methods = {
750
        .open = vtp_open,
751
        .close = vtp_close,
752
        .local_name = vtp_local_name,
753
        .remote_name = vtp_remote_name,
754
};
755
756
/*--------------------------------------------------------------------
757
 */
758
759
static int v_matchproto_(cp_open_f)
760 478
vus_open(const struct conn_pool *cp, vtim_dur tmo, VCL_IP *ap)
761
{
762
        int s;
763
        int msec;
764
765 478
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
766 478
        AN(cp->endpoint->uds_path);
767
768 478
        msec = tmo2msec(tmo);
769 478
        *ap = bogo_ip;
770 478
        s = VUS_connect(cp->endpoint->uds_path, msec);
771 478
        return (s);
772
}
773
774
static void v_matchproto_(cp_name_f)
775 888
vus_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
776
         unsigned plen)
777
{
778 888
        (void) pfd;
779 888
        assert(alen > vstrlen("0.0.0.0"));
780 888
        assert(plen > 1);
781 888
        strcpy(addr, "0.0.0.0");
782 888
        strcpy(pbuf, "0");
783 888
}
784
785
static const struct cp_methods vus_methods = {
786
        .open = vus_open,
787
        .close = vtp_close,
788
        .local_name = vus_name,
789
        .remote_name = vus_name,
790
};
791
792
/*--------------------------------------------------------------------
793
 * Reference a TCP pool given by {ip4, ip6} pair or a UDS.  Create if
794
 * it doesn't exist already.
795
 */
796
797
struct conn_pool *
798 5460
VCP_Ref(const struct vrt_endpoint *vep, const char *ident)
799
{
800
        struct conn_pool *cp, *cp2;
801
        struct VSHA256Context cx[1];
802
        unsigned char digest[VSHA256_DIGEST_LENGTH];
803
804 5460
        CHECK_OBJ_NOTNULL(vep, VRT_ENDPOINT_MAGIC);
805 5460
        AN(ident);
806 5460
        AN(vsc);
807
808 5460
        VSHA256_Init(cx);
809 5460
        VSHA256_Update(cx, ident, vstrlen(ident) + 1); // include \0
810 5460
        if (vep->uds_path != NULL) {
811 184
                AZ(vep->ipv4);
812 184
                AZ(vep->ipv6);
813 184
                VSHA256_Update(cx, "UDS", 4); // include \0
814 184
                VSHA256_Update(cx, vep->uds_path, vstrlen(vep->uds_path));
815 184
        } else {
816 5276
                assert(vep->ipv4 != NULL || vep->ipv6 != NULL);
817 5276
                if (vep->ipv4 != NULL) {
818 5260
                        assert(VSA_Sane(vep->ipv4));
819 5260
                        VSHA256_Update(cx, "IP4", 4); // include \0
820 5260
                        VSHA256_Update(cx, vep->ipv4, vsa_suckaddr_len);
821 5260
                }
822 5276
                if (vep->ipv6 != NULL) {
823 24
                        assert(VSA_Sane(vep->ipv6));
824 24
                        VSHA256_Update(cx, "IP6", 4); // include \0
825 24
                        VSHA256_Update(cx, vep->ipv6, vsa_suckaddr_len);
826 24
                }
827
        }
828 5460
        CHECK_OBJ_ORNULL(vep->preamble, VRT_BLOB_MAGIC);
829 5460
        if (vep->preamble != NULL && vep->preamble->len > 0) {
830 36
                VSHA256_Update(cx, "PRE", 4); // include \0
831 36
                VSHA256_Update(cx, vep->preamble->blob, vep->preamble->len);
832 36
        }
833 5460
        VSHA256_Final(digest, cx);
834
835 5460
        ALLOC_OBJ(cp, CONN_POOL_MAGIC);
836 5460
        AN(cp);
837 5460
        cp->refcnt = 1;
838 5460
        cp->holddown = 0;
839 5460
        cp->endpoint = VRT_Endpoint_Clone(vep);
840 5460
        CHECK_OBJ_NOTNULL(cp->endpoint, VRT_ENDPOINT_MAGIC);
841 5460
        memcpy(cp->ident, digest, sizeof cp->ident);
842 5460
        if (vep->uds_path != NULL)
843 184
                cp->methods = &vus_methods;
844
        else
845 5276
                cp->methods = &vtp_methods;
846 5460
        Lck_New(&cp->mtx, lck_conn_pool);
847 5460
        VTAILQ_INIT(&cp->connlist);
848
849 5460
        Lck_Lock(&conn_pools_mtx);
850 5460
        cp2 = VRBT_INSERT(vrb, &conn_pools, cp);
851 5460
        if (cp2 == NULL) {
852 4228
                vsc->ref_miss++;
853 4228
                Lck_Unlock(&conn_pools_mtx);
854 4228
                return (cp);
855
        }
856
857 1232
        CHECK_OBJ(cp2, CONN_POOL_MAGIC);
858 1232
        assert(cp2->refcnt > 0);
859 1232
        cp2->refcnt++;
860 1232
        vsc->ref_hit++;
861 1232
        Lck_Unlock(&conn_pools_mtx);
862
863 1232
        vcp_destroy(&cp);
864 1232
        return (cp2);
865 5460
}