varnish-cache/bin/varnishd/cache/cache_tcp_pool.c
1
/*-
2
 * Copyright (c) 2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * TCP connection pools.
29
 *
30
 */
31
32
#include "config.h"
33
34
#include <errno.h>
35
#include <stdlib.h>
36
37
#include "cache_varnishd.h"
38
39
#include "vsa.h"
40
#include "vtcp.h"
41
#include "vus.h"
42
#include "vtim.h"
43
#include "waiter/waiter.h"
44
45
#include "cache_tcp_pool.h"
46
#include "cache_pool.h"
47
48
struct conn_pool;
49
50
/*--------------------------------------------------------------------
51
 */
52
53
struct pfd {
54
        unsigned                magic;
55
#define PFD_MAGIC               0x0c5e6593
56
        int                     fd;
57
        VTAILQ_ENTRY(pfd)       list;
58
        const void              *priv;
59
        uint8_t                 state;
60
        struct waited           waited[1];
61
        struct conn_pool        *conn_pool;
62
63
        pthread_cond_t          *cond;
64
};
65
66
/*--------------------------------------------------------------------
67
 */
68
69
typedef int cp_open_f(const struct conn_pool *, double tmo, const void **privp);
70
typedef void cp_close_f(struct pfd *);
71
typedef int cp_cmp_f(const struct conn_pool *, const void *priv);
72
typedef void cp_name_f(const struct pfd *, char *, unsigned, char *, unsigned);
73
74
struct cp_methods {
75
        cp_open_f                               *open;
76
        cp_close_f                              *close;
77
        cp_cmp_f                                *cmp;
78
        cp_name_f                               *local_name;
79
        cp_name_f                               *remote_name;
80
};
81
82
struct conn_pool {
83
        unsigned                                magic;
84
#define CONN_POOL_MAGIC                         0x85099bc3
85
86
        const struct cp_methods                 *methods;
87
88
        const void                              *id;
89
        void                                    *priv;
90
91
        VTAILQ_ENTRY(conn_pool)                 list;
92
        int                                     refcnt;
93
        struct lock                             mtx;
94
95
        VTAILQ_HEAD(, pfd)                      connlist;
96
        int                                     n_conn;
97
98
        VTAILQ_HEAD(, pfd)                      killlist;
99
        int                                     n_kill;
100
101
        int                                     n_used;
102
103
        double                                  holddown;
104
        int                                     holddown_errno;
105
};
106
107
struct tcp_pool {
108
        unsigned                                magic;
109
#define TCP_POOL_MAGIC                          0x28b0e42a
110
111
        struct suckaddr                         *ip4;
112
        struct suckaddr                         *ip6;
113
        char                                    *uds;
114
        struct conn_pool                        cp[1];
115
};
116
117
static struct lock              conn_pools_mtx;
118
static VTAILQ_HEAD(, conn_pool) conn_pools =
119
    VTAILQ_HEAD_INITIALIZER(conn_pools);
120
121
/*--------------------------------------------------------------------
122
 */
123
124
unsigned
125 31516
PFD_State(const struct pfd *p)
126
{
127 31516
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
128 31516
        return (p->state);
129
}
130
131
int *
132 13048
PFD_Fd(struct pfd *p)
133
{
134 13048
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
135 13048
        return (&(p->fd));
136
}
137
138
void
139 6504
PFD_LocalName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
140
              unsigned plen)
141
{
142 6504
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
143 6504
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
144 6504
        p->conn_pool->methods->local_name(p, abuf, alen, pbuf, plen);
145 6504
}
146
147
void
148 13008
PFD_RemoteName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
149
               unsigned plen)
150
{
151 13008
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
152 13008
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
153 13008
        p->conn_pool->methods->remote_name(p, abuf, alen, pbuf, plen);
154 13008
}
155
156
/*--------------------------------------------------------------------
157
 * Waiter-handler
158
 */
159
160
static void  v_matchproto_(waiter_handle_f)
161 5605
vcp_handle(struct waited *w, enum wait_event ev, double now)
162
{
163
        struct pfd *pfd;
164
        struct conn_pool *cp;
165
166 5605
        CAST_OBJ_NOTNULL(pfd, w->priv1, PFD_MAGIC);
167
        (void)ev;
168
        (void)now;
169 5605
        CHECK_OBJ_NOTNULL(pfd->conn_pool, CONN_POOL_MAGIC);
170 5605
        cp = pfd->conn_pool;
171
172 5605
        Lck_Lock(&cp->mtx);
173
174 5605
        switch (pfd->state) {
175
        case PFD_STATE_STOLEN:
176 2578
                pfd->state = PFD_STATE_USED;
177 2578
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
178 2578
                AN(pfd->cond);
179 2578
                AZ(pthread_cond_signal(pfd->cond));
180 2578
                break;
181
        case PFD_STATE_AVAIL:
182 3023
                cp->methods->close(pfd);
183 3023
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
184 3023
                cp->n_conn--;
185 3023
                FREE_OBJ(pfd);
186 3023
                break;
187
        case PFD_STATE_CLEANUP:
188 4
                cp->methods->close(pfd);
189 4
                cp->n_kill--;
190 4
                VTAILQ_REMOVE(&cp->killlist, pfd, list);
191 4
                memset(pfd, 0x11, sizeof *pfd);
192 4
                free(pfd);
193 4
                break;
194
        default:
195 0
                WRONG("Wrong pfd state");
196
        }
197 5605
        Lck_Unlock(&cp->mtx);
198 5605
}
199
200
/*--------------------------------------------------------------------
201
 */
202
203
static struct conn_pool *
204 4244
VCP_Ref(const void *id, const void *priv)
205
{
206
        struct conn_pool *cp;
207
208 4244
        Lck_Lock(&conn_pools_mtx);
209 5088
        VTAILQ_FOREACH(cp, &conn_pools, list) {
210 1788
                assert(cp->refcnt > 0);
211 1788
                if (cp->id != id)
212 0
                        continue;
213 1788
                if (cp->methods->cmp(cp, priv))
214 844
                        continue;
215 944
                cp->refcnt++;
216 944
                Lck_Unlock(&conn_pools_mtx);
217 944
                return (cp);
218
        }
219 3300
        Lck_Unlock(&conn_pools_mtx);
220 3300
        return (NULL);
221
}
222
223
/*--------------------------------------------------------------------
224
 */
225
226
static void *
227 3300
VCP_New(struct conn_pool *cp, const void *id, void *priv,
228
    const struct cp_methods *cm)
229
{
230
231 3300
        AN(cp);
232 3300
        AN(cm);
233 3300
        AN(cm->open);
234 3300
        AN(cm->close);
235 3300
        AN(cm->cmp);
236
237 3300
        INIT_OBJ(cp, CONN_POOL_MAGIC);
238 3300
        cp->id = id;
239 3300
        cp->priv = priv;
240 3300
        cp->methods = cm;
241 3300
        cp->refcnt = 1;
242 3300
        cp->holddown = 0;
243 3300
        Lck_New(&cp->mtx, lck_tcp_pool);
244 3300
        VTAILQ_INIT(&cp->connlist);
245 3300
        VTAILQ_INIT(&cp->killlist);
246
247 3300
        Lck_Lock(&conn_pools_mtx);
248 3300
        VTAILQ_INSERT_HEAD(&conn_pools, cp, list);
249 3300
        Lck_Unlock(&conn_pools_mtx);
250
251 3300
        return (priv);
252
}
253
254
255
/*--------------------------------------------------------------------
256
 */
257
258
static void
259 88
VCP_AddRef(struct conn_pool *cp)
260
{
261 88
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
262
263 88
        Lck_Lock(&conn_pools_mtx);
264 88
        assert(cp->refcnt > 0);
265 88
        cp->refcnt++;
266 88
        Lck_Unlock(&conn_pools_mtx);
267 88
}
268
269
/*--------------------------------------------------------------------
270
 * Release Conn pool, destroy if last reference.
271
 */
272
273
static int
274 276
VCP_Rel(struct conn_pool *cp)
275
{
276
        struct pfd *pfd, *pfd2;
277
278 276
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
279
280 276
        Lck_Lock(&conn_pools_mtx);
281 276
        assert(cp->refcnt > 0);
282 276
        if (--cp->refcnt > 0) {
283 224
                Lck_Unlock(&conn_pools_mtx);
284 224
                return (1);
285
        }
286 52
        AZ(cp->n_used);
287 52
        VTAILQ_REMOVE(&conn_pools, cp, list);
288 52
        Lck_Unlock(&conn_pools_mtx);
289
290 52
        Lck_Lock(&cp->mtx);
291 52
        VTAILQ_FOREACH_SAFE(pfd, &cp->connlist, list, pfd2) {
292 0
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
293 0
                cp->n_conn--;
294 0
                assert(pfd->state == PFD_STATE_AVAIL);
295 0
                pfd->state = PFD_STATE_CLEANUP;
296 0
                (void)shutdown(pfd->fd, SHUT_WR);
297 0
                VTAILQ_INSERT_TAIL(&cp->killlist, pfd, list);
298 0
                cp->n_kill++;
299
        }
300 104
        while (cp->n_kill) {
301 0
                Lck_Unlock(&cp->mtx);
302 0
                (void)usleep(20000);
303 0
                Lck_Lock(&cp->mtx);
304
        }
305 52
        Lck_Unlock(&cp->mtx);
306 52
        Lck_Delete(&cp->mtx);
307 52
        AZ(cp->n_conn);
308 52
        AZ(cp->n_kill);
309 52
        return (0);
310
}
311
312
/*--------------------------------------------------------------------
313
 * Recycle a connection.
314
 */
315
316
static void
317 5676
VCP_Recycle(const struct worker *wrk, struct pfd **pfdp)
318
{
319
        struct pfd *pfd;
320
        struct conn_pool *cp;
321 5676
        int i = 0;
322
323 5676
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
324 5676
        pfd = *pfdp;
325 5676
        *pfdp = NULL;
326 5676
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
327 5676
        cp = pfd->conn_pool;
328 5676
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
329
330 5676
        assert(pfd->state == PFD_STATE_USED);
331 5676
        assert(pfd->fd > 0);
332
333 5676
        Lck_Lock(&cp->mtx);
334 5676
        cp->n_used--;
335
336 5676
        pfd->waited->priv1 = pfd;
337 5676
        pfd->waited->fd = pfd->fd;
338 5676
        pfd->waited->idle = VTIM_real();
339 5676
        pfd->state = PFD_STATE_AVAIL;
340 5676
        pfd->waited->func = vcp_handle;
341 5676
        pfd->waited->tmo = &cache_param->backend_idle_timeout;
342 5676
        if (Wait_Enter(wrk->pool->waiter, pfd->waited)) {
343 0
                cp->methods->close(pfd);
344 0
                memset(pfd, 0x33, sizeof *pfd);
345 0
                free(pfd);
346
                // XXX: stats
347 0
                pfd = NULL;
348
        } else {
349 5676
                VTAILQ_INSERT_HEAD(&cp->connlist, pfd, list);
350 5676
                i++;
351
        }
352
353 5676
        if (pfd != NULL)
354 5676
                cp->n_conn++;
355 5676
        Lck_Unlock(&cp->mtx);
356
357 5676
        if (i && DO_DEBUG(DBG_VTC_MODE)) {
358
                /*
359
                 * In varnishtest we do not have the luxury of using
360
                 * multiple backend connections, so whenever we end up
361
                 * in the "pending" case, take a short nap to let the
362
                 * waiter catch up and put the pfd back into circulations.
363
                 *
364
                 * In particular ESI:include related tests suffer random
365
                 * failures without this.
366
                 *
367
                 * In normal operation, the only effect is that we will
368
                 * have N+1 backend connections rather than N, which is
369
                 * entirely harmless.
370
                 */
371 5676
                (void)usleep(10000);
372
        }
373 5676
}
374
375
/*--------------------------------------------------------------------
376
 * Open a new connection from pool.
377
 */
378
379
static int
380 4956
VCP_Open(struct conn_pool *cp, double tmo, const void **privp, int *err)
381
{
382
        int r;
383
        double h;
384
385 4956
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
386 4956
        AN(err);
387
388 9912
        while (cp->holddown > 0) {
389 286
                Lck_Lock(&cp->mtx);
390 286
                if (cp->holddown == 0) {
391 0
                        Lck_Unlock(&cp->mtx);
392 0
                        break;
393
                }
394
395 286
                if (VTIM_mono() >= cp->holddown) {
396 215
                        cp->holddown = 0;
397 215
                        Lck_Unlock(&cp->mtx);
398 215
                        break;
399
                }
400
401 71
                *err = 0;
402 71
                errno = cp->holddown_errno;
403 71
                Lck_Unlock(&cp->mtx);
404 71
                return (-1);
405
        }
406
407 4885
        r = cp->methods->open(cp, tmo, privp);
408
409 4886
        *err = errno;
410
411 4886
        if (r >= 0)
412 4599
                return (r);
413
414 287
        h = 0;
415
416
        /* stats access unprotected */
417 287
        switch (errno) {
418
        case EACCES:
419
        case EPERM:
420 0
                h = cache_param->backend_local_error_holddown;
421 0
                break;
422
        case EADDRNOTAVAIL:
423 0
                h = cache_param->backend_local_error_holddown;
424 0
                break;
425
        case ECONNREFUSED:
426 287
                h = cache_param->backend_remote_error_holddown;
427 287
                break;
428
        case ENETUNREACH:
429 0
                h = cache_param->backend_remote_error_holddown;
430 0
                break;
431
        default:
432 0
                break;
433
        }
434
435 287
        if (h == 0)
436 0
                return (r);
437
438 287
        Lck_Lock(&cp->mtx);
439 287
        h += VTIM_mono();
440 287
        if (cp->holddown == 0 || h < cp->holddown) {
441 287
                cp->holddown = h;
442 287
                cp->holddown_errno = errno;
443
        }
444
445 287
        Lck_Unlock(&cp->mtx);
446
447 287
        return (r);
448
}
449
450
/*--------------------------------------------------------------------
451
 * Close a connection.
452
 */
453
454
static void
455 824
VCP_Close(struct pfd **pfdp)
456
{
457
        struct pfd *pfd;
458
        struct conn_pool *cp;
459
460 824
        pfd = *pfdp;
461 824
        *pfdp = NULL;
462 824
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
463 824
        cp = pfd->conn_pool;
464 824
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
465
466 824
        assert(pfd->fd > 0);
467
468 824
        Lck_Lock(&cp->mtx);
469 824
        assert(pfd->state == PFD_STATE_USED || pfd->state == PFD_STATE_STOLEN);
470 824
        cp->n_used--;
471 824
        if (pfd->state == PFD_STATE_STOLEN) {
472 4
                (void)shutdown(pfd->fd, SHUT_RDWR);
473 4
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
474 4
                pfd->state = PFD_STATE_CLEANUP;
475 4
                VTAILQ_INSERT_HEAD(&cp->killlist, pfd, list);
476 4
                cp->n_kill++;
477
        } else {
478 820
                assert(pfd->state == PFD_STATE_USED);
479 820
                cp->methods->close(pfd);
480 820
                memset(pfd, 0x44, sizeof *pfd);
481 820
                free(pfd);
482
        }
483 824
        Lck_Unlock(&cp->mtx);
484 824
}
485
486
/*--------------------------------------------------------------------
487
 * Get a connection, possibly recycled
488
 */
489
490
static struct pfd *
491 6564
VCP_Get(struct conn_pool *cp, double tmo, struct worker *wrk,
492
    unsigned force_fresh, int *err)
493
{
494
        struct pfd *pfd;
495
496 6564
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
497 6564
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
498 6564
        AN(err);
499
500 6564
        *err = 0;
501 6564
        Lck_Lock(&cp->mtx);
502 6564
        pfd = VTAILQ_FIRST(&cp->connlist);
503 6564
        CHECK_OBJ_ORNULL(pfd, PFD_MAGIC);
504 6564
        if (force_fresh || pfd == NULL || pfd->state == PFD_STATE_STOLEN)
505 3982
                pfd = NULL;
506
        else {
507 2582
                assert(pfd->conn_pool == cp);
508 2582
                assert(pfd->state == PFD_STATE_AVAIL);
509 2582
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
510 2582
                VTAILQ_INSERT_TAIL(&cp->connlist, pfd, list);
511 2582
                cp->n_conn--;
512 2582
                VSC_C_main->backend_reuse++;
513 2582
                pfd->state = PFD_STATE_STOLEN;
514 2582
                pfd->cond = &wrk->cond;
515
        }
516 6564
        cp->n_used++;                   // Opening mostly works
517 6564
        Lck_Unlock(&cp->mtx);
518
519 6564
        if (pfd != NULL)
520 2582
                return (pfd);
521
522 3982
        ALLOC_OBJ(pfd, PFD_MAGIC);
523 3982
        AN(pfd);
524 3982
        INIT_OBJ(pfd->waited, WAITED_MAGIC);
525 3982
        pfd->state = PFD_STATE_USED;
526 3982
        pfd->conn_pool = cp;
527 3982
        pfd->fd = VCP_Open(cp, tmo, &pfd->priv, err);
528 3982
        if (pfd->fd < 0) {
529 60
                FREE_OBJ(pfd);
530 60
                Lck_Lock(&cp->mtx);
531 60
                cp->n_used--;           // Nope, didn't work after all.
532 60
                Lck_Unlock(&cp->mtx);
533
        } else
534 3922
                VSC_C_main->backend_conn++;
535
536 3982
        return (pfd);
537
}
538
539
/*--------------------------------------------------------------------
540
 */
541
542
static int
543 2466
VCP_Wait(struct worker *wrk, struct pfd *pfd, vtim_real tmo)
544
{
545
        struct conn_pool *cp;
546
        int r;
547
548 2466
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
549 2466
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
550 2466
        cp = pfd->conn_pool;
551 2466
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
552 2466
        assert(pfd->cond == &wrk->cond);
553 2466
        Lck_Lock(&cp->mtx);
554 2466
        while (pfd->state == PFD_STATE_STOLEN) {
555 2456
                r = Lck_CondWait(&wrk->cond, &cp->mtx, tmo);
556 2456
                if (r != 0) {
557 4
                        if (r == EINTR)
558 0
                                continue;
559 4
                        assert(r == ETIMEDOUT);
560 4
                        Lck_Unlock(&cp->mtx);
561 4
                        return (1);
562
                }
563
        }
564 2462
        assert(pfd->state == PFD_STATE_USED);
565 2462
        pfd->cond = NULL;
566 2462
        Lck_Unlock(&cp->mtx);
567
568 2462
        return (0);
569
}
570
571
/*--------------------------------------------------------------------
572
 */
573
574
struct vtp_cs {
575
        unsigned                        magic;
576
#define VTP_CS_MAGIC                    0xc1e40447
577
        const struct suckaddr           *ip4;
578
        const struct suckaddr           *ip6;
579
        const char                      *uds;
580
};
581
582
static inline int
583 4886
tmo2msec(double tmo)
584
{
585 4886
        return ( (int)floor(tmo * 1000.0) );
586
}
587
588
static int v_matchproto_(cp_open_f)
589 4369
vtp_open(const struct conn_pool *cp, double tmo, const void **privp)
590
{
591
        int s;
592
        int msec;
593
        struct tcp_pool *tp;
594
595 4369
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
596 4369
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
597
598 4369
        msec = tmo2msec(tmo);
599 4369
        if (cache_param->prefer_ipv6) {
600 0
                *privp = tp->ip6;
601 0
                s = VTCP_connect(tp->ip6, msec);
602 0
                if (s >= 0)
603 0
                        return (s);
604
        }
605 4369
        *privp = tp->ip4;
606 4369
        s = VTCP_connect(tp->ip4, msec);
607 4369
        if (s >= 0)
608 4102
                return (s);
609 267
        if (!cache_param->prefer_ipv6) {
610 267
                *privp = tp->ip6;
611 267
                s = VTCP_connect(tp->ip6, msec);
612
        }
613 267
        return (s);
614
}
615
616
static void v_matchproto_(cp_close_f)
617 3847
vtp_close(struct pfd *pfd)
618
{
619
620 3847
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
621 3847
        VTCP_close(&pfd->fd);
622 3847
}
623
624
static int v_matchproto_(cp_cmp_f)
625 1704
vtp_cmp(const struct conn_pool *cp, const void *priv)
626
{
627
        const struct vtp_cs *vcs;
628
        const struct tcp_pool *tp;
629
630 1704
        CAST_OBJ_NOTNULL(vcs, priv, VTP_CS_MAGIC);
631 1704
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
632 1704
        if (tp->ip4 == NULL && vcs->ip4 != NULL)
633 0
                return (1);
634 1704
        if (tp->ip4 != NULL && vcs->ip4 == NULL)
635 56
                return (1);
636 1648
        if (tp->ip6 == NULL && vcs->ip6 != NULL)
637 4
                return (1);
638 1644
        if (tp->ip6 != NULL && vcs->ip6 == NULL)
639 0
                return (1);
640 3288
        if (tp->ip4 != NULL && vcs->ip4 != NULL &&
641 1644
            VSA_Compare(tp->ip4, vcs->ip4))
642 708
                return (1);
643 936
        if (tp->ip6 != NULL && vcs->ip6 != NULL &&
644 0
            VSA_Compare(tp->ip6, vcs->ip6))
645 0
                return (1);
646 936
        return (0);
647
}
648
649
static void v_matchproto_(cp_name_f)
650 6088
vtp_local_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
651
               unsigned plen)
652
{
653 6088
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
654 6088
        VTCP_myname(pfd->fd, addr, alen, pbuf, plen);
655 6088
}
656
657
static void v_matchproto_(cp_name_f)
658 12176
vtp_remote_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
659
                unsigned plen)
660
{
661 12176
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
662 12176
        VTCP_hisname(pfd->fd, addr, alen, pbuf, plen);
663 12176
}
664
665
static const struct cp_methods vtp_methods = {
666
        .open = vtp_open,
667
        .close = vtp_close,
668
        .cmp = vtp_cmp,
669
        .local_name = vtp_local_name,
670
        .remote_name = vtp_remote_name,
671
};
672
673
/*--------------------------------------------------------------------
674
 */
675
676
static int v_matchproto_(cp_open_f)
677 517
vus_open(const struct conn_pool *cp, double tmo, const void **privp)
678
{
679
        int s;
680
        int msec;
681
        struct tcp_pool *tp;
682
683 517
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
684 517
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
685 517
        AN(tp->uds);
686
687 517
        msec = tmo2msec(tmo);
688 517
        *privp = bogo_ip;
689 517
        s = VUS_connect(tp->uds, msec);
690 517
        return (s);
691
}
692
693
static int v_matchproto_(cp_cmp_f)
694 84
vus_cmp(const struct conn_pool *cp, const void *priv)
695
{
696
        const struct vtp_cs *vcs;
697
        const struct tcp_pool *tp;
698
699 84
        CAST_OBJ_NOTNULL(vcs, priv, VTP_CS_MAGIC);
700 84
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
701 84
        if (tp->uds != NULL && vcs->uds != NULL)
702 60
                return (strcmp(tp->uds, vcs->uds));
703 24
        return (1);
704
}
705
706
static void v_matchproto_(cp_name_f)
707 1248
vus_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
708
         unsigned plen)
709
{
710
        (void) pfd;
711 1248
        assert(alen > strlen("0.0.0.0"));
712 1248
        assert(plen > 1);
713 1248
        strcpy(addr, "0.0.0.0");
714 1248
        strcpy(pbuf, "0");
715 1248
}
716
717
static const struct cp_methods vus_methods = {
718
        .open = vus_open,
719
        .close = vtp_close,
720
        .cmp = vus_cmp,
721
        .local_name = vus_name,
722
        .remote_name = vus_name,
723
};
724
725
/*--------------------------------------------------------------------
726
 * Reference a TCP pool given by {ip4, ip6} pair or a UDS.  Create if
727
 * it doesn't exist already.
728
 */
729
730
struct tcp_pool *
731 4244
VTP_Ref(const struct suckaddr *ip4, const struct suckaddr *ip6, const char *uds,
732
        const void *id)
733
{
734
        struct tcp_pool *tp;
735
        struct conn_pool *cp;
736
        struct vtp_cs vcs;
737
        const struct cp_methods *methods;
738
739 4244
        assert((uds != NULL && ip4 == NULL && ip6 == NULL) ||
740
            (uds == NULL && (ip4 != NULL || ip6 != NULL)));
741 4244
        INIT_OBJ(&vcs, VTP_CS_MAGIC);
742 4244
        vcs.ip4 = ip4;
743 4244
        vcs.ip6 = ip6;
744 4244
        vcs.uds = uds;
745
746 4244
        cp = VCP_Ref(id, &vcs);
747 4244
        if (cp != NULL)
748 944
                return (cp->priv);
749
750
        /*
751
         * this is racy - we could end up with additional pools on the same id /
752
         * destination address with just a single connection
753
         */
754 3300
        ALLOC_OBJ(tp, TCP_POOL_MAGIC);
755 3300
        AN(tp);
756 3300
        if (uds != NULL) {
757 152
                methods = &vus_methods;
758 152
                tp->uds = strdup(uds);
759
        }
760
        else {
761 3148
                methods = &vtp_methods;
762 3148
                if (ip4 != NULL)
763 3148
                        tp->ip4 = VSA_Clone(ip4);
764 3148
                if (ip6 != NULL)
765 4
                        tp->ip6 = VSA_Clone(ip6);
766
        }
767 3300
        return(VCP_New(tp->cp, id, tp, methods));
768
}
769
770
/*--------------------------------------------------------------------
771
 * Add a reference to a tcp_pool
772
 */
773
774
void
775 88
VTP_AddRef(struct tcp_pool *tp)
776
{
777 88
        CHECK_OBJ_NOTNULL(tp, TCP_POOL_MAGIC);
778 88
        VCP_AddRef(tp->cp);
779 88
}
780
781
/*--------------------------------------------------------------------
782
 * Release TCP pool, destroy if last reference.
783
 */
784
785
void
786 276
VTP_Rel(struct tcp_pool **tpp)
787
{
788
        struct tcp_pool *tp;
789
790 276
        TAKE_OBJ_NOTNULL(tp, tpp, TCP_POOL_MAGIC);
791 276
        if (VCP_Rel(tp->cp))
792 224
                return;
793
794 52
        free(tp->ip4);
795 52
        free(tp->ip6);
796 52
        free(tp->uds);
797 52
        FREE_OBJ(tp);
798
}
799
800
/*--------------------------------------------------------------------
801
 * Open a new connection from pool.
802
 */
803
804
int
805 975
VTP_Open(struct tcp_pool *tp, double tmo, const void **privp, int *err)
806
{
807 975
        return (VCP_Open(tp->cp, tmo, privp, err));
808
}
809
810
/*--------------------------------------------------------------------
811
 * Recycle a connection.
812
 */
813
814
void
815 5676
VTP_Recycle(const struct worker *wrk, struct pfd **pfdp)
816
{
817
818 5676
        VCP_Recycle(wrk, pfdp);
819 5676
}
820
821
/*--------------------------------------------------------------------
822
 * Close a connection.
823
 */
824
825
void
826 824
VTP_Close(struct pfd **pfdp)
827
{
828
829 824
        VCP_Close(pfdp);
830 824
}
831
832
/*--------------------------------------------------------------------
833
 * Get a connection
834
 */
835
836
struct pfd *
837 6564
VTP_Get(struct tcp_pool *tp, vtim_dur tmo, struct worker *wrk,
838
        unsigned force_fresh, int *err)
839
{
840
841 6564
        return VCP_Get(tp->cp, tmo, wrk, force_fresh, err);
842
}
843
844
/*--------------------------------------------------------------------
845
 */
846
847
int
848 2466
VTP_Wait(struct worker *wrk, struct pfd *pfd, vtim_real tmo)
849
{
850 2466
        return (VCP_Wait(wrk, pfd, tmo));
851
}
852
853
/*--------------------------------------------------------------------
854
 */
855
856
const struct suckaddr *
857 4
VTP_getip(struct pfd *pfd)
858
{
859
        struct tcp_pool *tp;
860
861 4
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
862 4
        CAST_OBJ_NOTNULL(tp, pfd->conn_pool->priv, TCP_POOL_MAGIC);
863 4
        return (pfd->priv);
864
}
865
866
/*--------------------------------------------------------------------*/
867
868
void
869 2752
VTP_Init(void)
870
{
871 2752
        Lck_New(&conn_pools_mtx, lck_tcp_pool);
872 2752
}