varnish-cache/bin/varnishd/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_varnishd.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 133
VRBT_GENERATE_REMOVE_COLOR(vrb, conn_pool, entry, static)
117 332
VRBT_GENERATE_REMOVE(vrb, conn_pool, entry, static)
118 1731
VRBT_GENERATE_INSERT_COLOR(vrb, conn_pool, entry, static)
119 8330
VRBT_GENERATE_INSERT_FINISH(vrb, conn_pool, entry, static)
120 12641
VRBT_GENERATE_INSERT(vrb, conn_pool, entry, vcp_cmp, static)
121 18
VRBT_GENERATE_NEXT(vrb, conn_pool, entry, static)
122 36
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 82892
PFD_State(const struct pfd *p)
132
{
133 82892
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
134 82892
        return (p->state);
135
}
136
137
int *
138 35040
PFD_Fd(struct pfd *p)
139
{
140 35040
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
141 35040
        return (&(p->fd));
142
}
143
144
vtim_dur
145 6518
PFD_Age(const struct pfd *p)
146
{
147
        vtim_mono t_mono;
148
149 6518
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
150 6518
        t_mono = VTIM_mono();
151 6518
        assert(t_mono >= p->created);
152
153 6518
        return (t_mono - p->created);
154
}
155
156
uint64_t
157 6518
PFD_Reused(const struct pfd *p)
158
{
159 6518
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
160 6518
        return (p->reused);
161
}
162
163
void
164 17432
PFD_LocalName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
165
              unsigned plen)
166
{
167 17432
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
168 17432
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
169 17432
        p->conn_pool->methods->local_name(p, abuf, alen, pbuf, plen);
170 17432
}
171
172
void
173 17432
PFD_RemoteName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
174
               unsigned plen)
175
{
176 17432
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
177 17432
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
178 17432
        p->conn_pool->methods->remote_name(p, abuf, alen, pbuf, plen);
179 17432
}
180
181
/*--------------------------------------------------------------------
182
 */
183
184
static inline int
185 4311
vcp_cmp(const struct conn_pool *a, const struct conn_pool *b)
186
{
187 4311
        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 14079
vcp_handle(struct waited *w, enum wait_event ev, vtim_real now)
196
{
197
        struct pfd *pfd;
198
        struct conn_pool *cp;
199
200 14079
        CHECK_OBJ_NOTNULL(w, WAITED_MAGIC);
201 14079
        CAST_OBJ_NOTNULL(pfd, w->priv1, PFD_MAGIC);
202 14079
        (void)ev;
203 14079
        (void)now;
204 14079
        CHECK_OBJ_NOTNULL(pfd->conn_pool, CONN_POOL_MAGIC);
205 14079
        cp = pfd->conn_pool;
206
207 14079
        Lck_Lock(&cp->mtx);
208
209 14079
        switch (pfd->state) {
210
        case PFD_STATE_STOLEN:
211 6502
                pfd->state = PFD_STATE_USED;
212 6502
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
213 6502
                AN(pfd->cond);
214 6502
                PTOK(pthread_cond_signal(pfd->cond));
215 6502
                break;
216
        case PFD_STATE_AVAIL:
217 7545
                cp->methods->close(pfd);
218 7545
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
219 7545
                cp->n_conn--;
220 7545
                FREE_OBJ(pfd);
221 7545
                break;
222
        case PFD_STATE_CLEANUP:
223 32
                cp->methods->close(pfd);
224 32
                cp->n_kill--;
225 32
                memset(pfd, 0x11, sizeof *pfd);
226 32
                free(pfd);
227 32
                break;
228
        default:
229 0
                WRONG("Wrong pfd state");
230 0
        }
231 14079
        Lck_Unlock(&cp->mtx);
232 14079
}
233
234
235
/*--------------------------------------------------------------------
236
 */
237
238
void
239 296
VCP_AddRef(struct conn_pool *cp)
240
{
241 296
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
242
243 296
        Lck_Lock(&conn_pools_mtx);
244 296
        assert(cp->refcnt > 0);
245 296
        cp->refcnt++;
246 296
        Lck_Unlock(&conn_pools_mtx);
247 296
}
248
249
/*--------------------------------------------------------------------
250
 */
251
252
static void
253 2672
vcp_destroy(struct conn_pool **cpp)
254
{
255
        struct conn_pool *cp;
256
257 2672
        TAKE_OBJ_NOTNULL(cp, cpp, CONN_POOL_MAGIC);
258 2672
        AZ(cp->n_conn);
259 2672
        AZ(cp->n_kill);
260 2672
        Lck_Delete(&cp->mtx);
261 2672
        FREE_OBJ(cp->endpoint);
262 2672
        FREE_OBJ(cp);
263 2672
}
264
265
/*--------------------------------------------------------------------
266
 * Release Conn pool, destroy or stash for future destruction if last
267
 * reference.
268
 */
269
270
void
271 691
VCP_Rel(struct conn_pool **cpp)
272
{
273
        struct conn_pool *cp;
274
        struct pfd *pfd, *pfd2;
275
        int n_kill;
276
277 691
        TAKE_OBJ_NOTNULL(cp, cpp, CONN_POOL_MAGIC);
278
279 691
        Lck_Lock(&conn_pools_mtx);
280 691
        assert(cp->refcnt > 0);
281 691
        if (--cp->refcnt > 0) {
282 475
                Lck_Unlock(&conn_pools_mtx);
283 475
                return;
284
        }
285 216
        AZ(cp->n_used);
286 216
        VRBT_REMOVE(vrb, &conn_pools, cp);
287 216
        Lck_Unlock(&conn_pools_mtx);
288
289 216
        Lck_Lock(&cp->mtx);
290 232
        VTAILQ_FOREACH_SAFE(pfd, &cp->connlist, list, pfd2) {
291 16
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
292 16
                cp->n_conn--;
293 16
                assert(pfd->state == PFD_STATE_AVAIL);
294 16
                pfd->state = PFD_STATE_CLEANUP;
295 16
                (void)shutdown(pfd->fd, SHUT_RDWR);
296 16
                cp->n_kill++;
297 16
        }
298 216
        n_kill = cp->n_kill;
299 216
        Lck_Unlock(&cp->mtx);
300 216
        if (n_kill == 0) {
301 200
                vcp_destroy(&cp);
302 200
                return;
303
        }
304 16
        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 16
        VRBT_INSERT(vrb, &dead_pools, cp);
310 16
        Lck_Unlock(&dead_pools_mtx);
311 691
}
312
313
void
314 62160
VCP_RelPoll(void)
315
{
316
        struct vrb dead;
317
        struct conn_pool *cp, *cp2;
318
        int n_kill;
319
320 62160
        ASSERT_CLI();
321
322 62160
        Lck_Lock(&dead_pools_mtx);
323 62160
        if (VRBT_EMPTY(&dead_pools)) {
324 62142
                Lck_Unlock(&dead_pools_mtx);
325 62142
                return;
326
        }
327 18
        dead = dead_pools;
328 18
        VRBT_INIT(&dead_pools);
329 18
        Lck_Unlock(&dead_pools_mtx);
330
331 36
        VRBT_FOREACH_SAFE(cp, vrb, &dead, cp2) {
332 18
                CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
333 18
                Lck_Lock(&cp->mtx);
334 18
                n_kill = cp->n_kill;
335 18
                Lck_Unlock(&cp->mtx);
336 18
                if (n_kill > 0)
337 2
                        continue;
338 16
                VRBT_REMOVE(vrb, &dead, cp);
339 16
                vcp_destroy(&cp);
340 16
        }
341
342 18
        if (VRBT_EMPTY(&dead))
343 16
                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 62160
}
355
356
/*--------------------------------------------------------------------
357
 * Recycle a connection.
358
 */
359
360
void
361 14255
VCP_Recycle(const struct worker *wrk, struct pfd **pfdp)
362
{
363
        struct pfd *pfd;
364
        struct conn_pool *cp;
365 14255
        int i = 0;
366
367 14255
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
368 14255
        TAKE_OBJ_NOTNULL(pfd, pfdp, PFD_MAGIC);
369 14255
        cp = pfd->conn_pool;
370 14255
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
371
372 14255
        assert(pfd->state == PFD_STATE_USED);
373 14255
        assert(pfd->fd > 0);
374
375 14255
        Lck_Lock(&cp->mtx);
376 14255
        cp->n_used--;
377
378 14255
        pfd->waited->priv1 = pfd;
379 14255
        pfd->waited->fd = pfd->fd;
380 14255
        pfd->waited->idle = VTIM_real();
381 14255
        pfd->state = PFD_STATE_AVAIL;
382 14255
        pfd->waited->func = vcp_handle;
383 14255
        pfd->waited->tmo = cache_param->backend_idle_timeout;
384 14255
        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 14255
                VTAILQ_INSERT_HEAD(&cp->connlist, pfd, list);
392 14255
                i++;
393
        }
394
395 14255
        if (pfd != NULL)
396 14255
                cp->n_conn++;
397 14255
        Lck_Unlock(&cp->mtx);
398
399 14255
        if (i && DO_DEBUG(DBG_VTC_MODE)) {
400
                /*
401
                 * In varnishtest 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 14255
                VTIM_sleep(0.01);
414 14255
        }
415 14255
}
416
417
/*--------------------------------------------------------------------
418
 * Open a new connection from pool.
419
 */
420
421
int
422 12753
VCP_Open(struct conn_pool *cp, vtim_dur tmo, VCL_IP *ap, int *err)
423
{
424
        int r;
425
        vtim_mono h;
426
427 12753
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
428 12753
        AN(err);
429
430 12753
        while (cp->holddown > 0) {
431 184
                Lck_Lock(&cp->mtx);
432 184
                if (cp->holddown == 0) {
433 0
                        Lck_Unlock(&cp->mtx);
434 0
                        break;
435
                }
436
437 184
                if (VTIM_mono() >= cp->holddown) {
438 24
                        cp->holddown = 0;
439 24
                        Lck_Unlock(&cp->mtx);
440 24
                        break;
441
                }
442
443 160
                *err = 0;
444 160
                errno = cp->holddown_errno;
445 160
                Lck_Unlock(&cp->mtx);
446 160
                return (-1);
447
        }
448
449 12593
        *err = errno = 0;
450 12593
        r = cp->methods->open(cp, tmo, ap);
451
452 12593
        if (r >= 0 && errno == 0 && cp->endpoint->preamble != NULL &&
453 72
             cp->endpoint->preamble->len > 0) {
454 72
                CHECK_OBJ(cp->endpoint->preamble, VRT_BLOB_MAGIC);
455 216
                if (write(r, cp->endpoint->preamble->blob,
456 144
                    cp->endpoint->preamble->len) !=
457 72
                    cp->endpoint->preamble->len) {
458 0
                        *err = errno;
459 0
                        closefd(&r);
460 0
                }
461 72
        } else {
462 12521
                *err = errno;
463
        }
464
465 12593
        if (r >= 0)
466 12379
                return (r);
467
468 214
        h = 0;
469
470 214
        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 214
                h = cache_param->backend_remote_error_holddown;
480 214
                break;
481
        case ENETUNREACH:
482 0
                h = cache_param->backend_remote_error_holddown;
483 0
                break;
484
        default:
485 0
                break;
486
        }
487
488 214
        if (h == 0)
489 0
                return (r);
490
491 214
        Lck_Lock(&cp->mtx);
492 214
        h += VTIM_mono();
493 214
        if (cp->holddown == 0 || h < cp->holddown) {
494 192
                cp->holddown = h;
495 192
                cp->holddown_errno = errno;
496 192
        }
497
498 214
        Lck_Unlock(&cp->mtx);
499
500 214
        return (r);
501 12753
}
502
503
/*--------------------------------------------------------------------
504
 * Close a connection.
505
 */
506
507
void
508 3169
VCP_Close(struct pfd **pfdp)
509
{
510
        struct pfd *pfd;
511
        struct conn_pool *cp;
512
513 3169
        TAKE_OBJ_NOTNULL(pfd, pfdp, PFD_MAGIC);
514 3169
        cp = pfd->conn_pool;
515 3169
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
516
517 3169
        assert(pfd->fd > 0);
518
519 3169
        Lck_Lock(&cp->mtx);
520 3169
        assert(pfd->state == PFD_STATE_USED || pfd->state == PFD_STATE_STOLEN);
521 3169
        cp->n_used--;
522 3169
        if (pfd->state == PFD_STATE_STOLEN) {
523 16
                (void)shutdown(pfd->fd, SHUT_RDWR);
524 16
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
525 16
                pfd->state = PFD_STATE_CLEANUP;
526 16
                cp->n_kill++;
527 16
        } else {
528 3153
                assert(pfd->state == PFD_STATE_USED);
529 3153
                cp->methods->close(pfd);
530 3153
                memset(pfd, 0x44, sizeof *pfd);
531 3153
                free(pfd);
532
        }
533 3169
        Lck_Unlock(&cp->mtx);
534 3169
}
535
536
/*--------------------------------------------------------------------
537
 * Get a connection, possibly recycled
538
 */
539
540
struct pfd *
541 17680
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 17680
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
547 17680
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
548 17680
        AN(err);
549
550 17680
        *err = 0;
551 17680
        Lck_Lock(&cp->mtx);
552 17680
        pfd = VTAILQ_FIRST(&cp->connlist);
553 17680
        CHECK_OBJ_ORNULL(pfd, PFD_MAGIC);
554 17680
        if (force_fresh || pfd == NULL || pfd->state == PFD_STATE_STOLEN) {
555 11162
                pfd = NULL;
556 11162
        } else {
557 6518
                assert(pfd->conn_pool == cp);
558 6518
                assert(pfd->state == PFD_STATE_AVAIL);
559 6518
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
560 6518
                VTAILQ_INSERT_TAIL(&cp->connlist, pfd, list);
561 6518
                cp->n_conn--;
562 6518
                VSC_C_main->backend_reuse++;
563 6518
                pfd->state = PFD_STATE_STOLEN;
564 6518
                pfd->cond = &wrk->cond;
565 6518
                pfd->reused++;
566
        }
567 17680
        cp->n_used++;                   // Opening mostly works
568 17680
        Lck_Unlock(&cp->mtx);
569
570 17680
        if (pfd != NULL)
571 6518
                return (pfd);
572
573 11162
        ALLOC_OBJ(pfd, PFD_MAGIC);
574 11162
        AN(pfd);
575 11162
        INIT_OBJ(pfd->waited, WAITED_MAGIC);
576 11162
        pfd->state = PFD_STATE_USED;
577 11162
        pfd->conn_pool = cp;
578 11162
        pfd->fd = VCP_Open(cp, tmo, &pfd->addr, err);
579 11162
        if (pfd->fd < 0) {
580 248
                FREE_OBJ(pfd);
581 248
                Lck_Lock(&cp->mtx);
582 248
                cp->n_used--;           // Nope, didn't work after all.
583 248
                Lck_Unlock(&cp->mtx);
584 248
        } else {
585 10914
                pfd->created = VTIM_mono();
586 10914
                VSC_C_main->backend_conn++;
587
        }
588
589 11162
        return (pfd);
590 17680
}
591
592
/*--------------------------------------------------------------------
593
 */
594
595
int
596 6494
VCP_Wait(struct worker *wrk, struct pfd *pfd, vtim_real when)
597
{
598
        struct conn_pool *cp;
599
        int r;
600
601 6494
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
602 6494
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
603 6494
        cp = pfd->conn_pool;
604 6494
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
605 6494
        assert(pfd->cond == &wrk->cond);
606 6494
        Lck_Lock(&cp->mtx);
607 12980
        while (pfd->state == PFD_STATE_STOLEN) {
608 6494
                r = Lck_CondWaitUntil(&wrk->cond, &cp->mtx, when);
609 6494
                if (r != 0) {
610 8
                        if (r == EINTR)
611 0
                                continue;
612 8
                        assert(r == ETIMEDOUT);
613 8
                        Lck_Unlock(&cp->mtx);
614 8
                        return (1);
615
                }
616
        }
617 6486
        assert(pfd->state == PFD_STATE_USED);
618 6486
        pfd->cond = NULL;
619 6486
        Lck_Unlock(&cp->mtx);
620
621 6486
        return (0);
622 6494
}
623
624
/*--------------------------------------------------------------------
625
 */
626
627
VCL_IP
628 8
VCP_GetIp(struct pfd *pfd)
629
{
630
631 8
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
632 8
        return (pfd->addr);
633
}
634
635
/*--------------------------------------------------------------------*/
636
637
static void
638 48
vcp_panic_endpoint(struct vsb *vsb, const struct vrt_endpoint *vep)
639
{
640
        char h[VTCP_ADDRBUFSIZE];
641
        char p[VTCP_PORTBUFSIZE];
642
643 48
        if (PAN_dump_struct(vsb, vep, VRT_ENDPOINT_MAGIC, "vrt_endpoint"))
644 0
                return;
645 48
        if (vep->uds_path)
646 0
                VSB_printf(vsb, "uds_path = %s,\n", vep->uds_path);
647 48
        if (vep->ipv4 && VSA_Sane(vep->ipv4)) {
648 48
                VTCP_name(vep->ipv4, h, sizeof h, p, sizeof p);
649 48
                VSB_printf(vsb, "ipv4 = %s, ", h);
650 48
                VSB_printf(vsb, "port = %s,\n", p);
651 48
        }
652 48
        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 48
        VSB_indent(vsb, -2);
658 48
        VSB_cat(vsb, "},\n");
659 48
}
660
661
void
662 48
VCP_Panic(struct vsb *vsb, struct conn_pool *cp)
663
{
664
665 48
        if (PAN_dump_struct(vsb, cp, CONN_POOL_MAGIC, "conn_pool"))
666 0
                return;
667 48
        VSB_cat(vsb, "ident = ");
668 48
        VSB_quote(vsb, cp->ident, VSHA256_DIGEST_LENGTH, VSB_QUOTE_HEX);
669 48
        VSB_cat(vsb, ",\n");
670 48
        vcp_panic_endpoint(vsb, cp->endpoint);
671 48
        VSB_indent(vsb, -2);
672 48
        VSB_cat(vsb, "},\n");
673 48
}
674
675
/*--------------------------------------------------------------------*/
676
677
void
678 7631
VCP_Init(void)
679
{
680 7631
        Lck_New(&conn_pools_mtx, lck_conn_pool);
681 7631
        Lck_New(&dead_pools_mtx, lck_dead_pool);
682
683 7631
        AZ(vsc);
684 7631
        vsc = VSC_vcp_New(NULL, NULL, "");
685 7631
        AN(vsc);
686 7631
}
687
688
/**********************************************************************/
689
690
static inline int
691 12601
tmo2msec(vtim_dur tmo)
692
{
693 12601
        return ((int)floor(tmo * 1000.0));
694
}
695
696
static int v_matchproto_(cp_open_f)
697 11629
vtp_open(const struct conn_pool *cp, vtim_dur tmo, VCL_IP *ap)
698
{
699
        int s;
700
        int msec;
701
702 11629
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
703
704 11629
        msec = tmo2msec(tmo);
705 11629
        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 11629
        *ap = cp->endpoint->ipv4;
712 11629
        s = VTCP_connect(*ap, msec);
713 11629
        if (s >= 0)
714 11403
                return (s);
715 226
        if (!cache_param->prefer_ipv6) {
716 226
                *ap = cp->endpoint->ipv6;
717 226
                s = VTCP_connect(*ap, msec);
718 226
        }
719 226
        return (s);
720 11629
}
721
722
723
/*--------------------------------------------------------------------*/
724
725
static void v_matchproto_(cp_close_f)
726 10729
vtp_close(struct pfd *pfd)
727
{
728
729 10729
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
730 10729
        VTCP_close(&pfd->fd);
731 10729
}
732
733
static void v_matchproto_(cp_name_f)
734 16544
vtp_local_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
735
               unsigned plen)
736
{
737 16544
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
738 16544
        VTCP_myname(pfd->fd, addr, alen, pbuf, plen);
739 16544
}
740
741
static void v_matchproto_(cp_name_f)
742 16544
vtp_remote_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
743
                unsigned plen)
744
{
745 16544
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
746 16544
        VTCP_hisname(pfd->fd, addr, alen, pbuf, plen);
747 16544
}
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 964
vus_open(const struct conn_pool *cp, vtim_dur tmo, VCL_IP *ap)
761
{
762
        int s;
763
        int msec;
764
765 964
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
766 964
        AN(cp->endpoint->uds_path);
767
768 964
        msec = tmo2msec(tmo);
769 964
        *ap = bogo_ip;
770 964
        s = VUS_connect(cp->endpoint->uds_path, msec);
771 964
        return (s);
772
}
773
774
static void v_matchproto_(cp_name_f)
775 1776
vus_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
776
         unsigned plen)
777
{
778 1776
        (void) pfd;
779 1776
        assert(alen > strlen("0.0.0.0"));
780 1776
        assert(plen > 1);
781 1776
        strcpy(addr, "0.0.0.0");
782 1776
        strcpy(pbuf, "0");
783 1776
}
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 10768
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 10768
        CHECK_OBJ_NOTNULL(vep, VRT_ENDPOINT_MAGIC);
805 10768
        AN(ident);
806 10768
        AN(vsc);
807
808 10768
        VSHA256_Init(cx);
809 10768
        VSHA256_Update(cx, ident, strlen(ident) + 1); // include \0
810 10768
        if (vep->uds_path != NULL) {
811 368
                AZ(vep->ipv4);
812 368
                AZ(vep->ipv6);
813 368
                VSHA256_Update(cx, "UDS", 4); // include \0
814 368
                VSHA256_Update(cx, vep->uds_path, strlen(vep->uds_path));
815 368
        } else {
816 10400
                assert(vep->ipv4 != NULL || vep->ipv6 != NULL);
817 10400
                if (vep->ipv4 != NULL) {
818 10376
                        assert(VSA_Sane(vep->ipv4));
819 10376
                        VSHA256_Update(cx, "IP4", 4); // include \0
820 10376
                        VSHA256_Update(cx, vep->ipv4, vsa_suckaddr_len);
821 10376
                }
822 10400
                if (vep->ipv6 != NULL) {
823 32
                        assert(VSA_Sane(vep->ipv6));
824 32
                        VSHA256_Update(cx, "IP6", 4); // include \0
825 32
                        VSHA256_Update(cx, vep->ipv6, vsa_suckaddr_len);
826 32
                }
827
        }
828 10768
        CHECK_OBJ_ORNULL(vep->preamble, VRT_BLOB_MAGIC);
829 10768
        if (vep->preamble != NULL && vep->preamble->len > 0) {
830 72
                VSHA256_Update(cx, "PRE", 4); // include \0
831 72
                VSHA256_Update(cx, vep->preamble->blob, vep->preamble->len);
832 72
        }
833 10768
        VSHA256_Final(digest, cx);
834
835 10768
        ALLOC_OBJ(cp, CONN_POOL_MAGIC);
836 10768
        AN(cp);
837 10768
        cp->refcnt = 1;
838 10768
        cp->holddown = 0;
839 10768
        cp->endpoint = VRT_Endpoint_Clone(vep);
840 10768
        CHECK_OBJ_NOTNULL(cp->endpoint, VRT_ENDPOINT_MAGIC);
841 10768
        memcpy(cp->ident, digest, sizeof cp->ident);
842 10768
        if (vep->uds_path != NULL)
843 368
                cp->methods = &vus_methods;
844
        else
845 10400
                cp->methods = &vtp_methods;
846 10768
        Lck_New(&cp->mtx, lck_conn_pool);
847 10768
        VTAILQ_INIT(&cp->connlist);
848
849 10768
        Lck_Lock(&conn_pools_mtx);
850 10768
        cp2 = VRBT_INSERT(vrb, &conn_pools, cp);
851 10768
        if (cp2 == NULL) {
852 8312
                vsc->ref_miss++;
853 8312
                Lck_Unlock(&conn_pools_mtx);
854 8312
                return (cp);
855
        }
856
857 2456
        CHECK_OBJ(cp2, CONN_POOL_MAGIC);
858 2456
        assert(cp2->refcnt > 0);
859 2456
        cp2->refcnt++;
860 2456
        vsc->ref_hit++;
861 2456
        Lck_Unlock(&conn_pools_mtx);
862
863 2456
        vcp_destroy(&cp);
864 2456
        return (cp2);
865 10768
}