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 23531
PFD_State(const struct pfd *p)
126
{
127 23531
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
128 23531
        return (p->state);
129
}
130
131
int *
132 9744
PFD_Fd(struct pfd *p)
133
{
134 9744
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
135 9744
        return (&(p->fd));
136
}
137
138
void
139 4857
PFD_LocalName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
140
              unsigned plen)
141
{
142 4857
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
143 4857
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
144 4857
        p->conn_pool->methods->local_name(p, abuf, alen, pbuf, plen);
145 4857
}
146
147
void
148 9714
PFD_RemoteName(const struct pfd *p, char *abuf, unsigned alen, char *pbuf,
149
               unsigned plen)
150
{
151 9714
        CHECK_OBJ_NOTNULL(p, PFD_MAGIC);
152 9714
        CHECK_OBJ_NOTNULL(p->conn_pool, CONN_POOL_MAGIC);
153 9714
        p->conn_pool->methods->remote_name(p, abuf, alen, pbuf, plen);
154 9714
}
155
156
/*--------------------------------------------------------------------
157
 * Waiter-handler
158
 */
159
160
static void  v_matchproto_(waiter_handle_f)
161 4185
vcp_handle(struct waited *w, enum wait_event ev, double now)
162
{
163
        struct pfd *pfd;
164
        struct conn_pool *cp;
165
166 4185
        CAST_OBJ_NOTNULL(pfd, w->priv1, PFD_MAGIC);
167
        (void)ev;
168
        (void)now;
169 4185
        CHECK_OBJ_NOTNULL(pfd->conn_pool, CONN_POOL_MAGIC);
170 4185
        cp = pfd->conn_pool;
171
172 4185
        Lck_Lock(&cp->mtx);
173
174 4185
        switch (pfd->state) {
175
        case PFD_STATE_STOLEN:
176 1653
                pfd->state = PFD_STATE_USED;
177 1653
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
178 1653
                AN(pfd->cond);
179 1653
                AZ(pthread_cond_signal(pfd->cond));
180 1653
                break;
181
        case PFD_STATE_AVAIL:
182 2529
                cp->methods->close(pfd);
183 2529
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
184 2529
                cp->n_conn--;
185 2529
                FREE_OBJ(pfd);
186 2529
                break;
187
        case PFD_STATE_CLEANUP:
188 3
                cp->methods->close(pfd);
189 3
                cp->n_kill--;
190 3
                VTAILQ_REMOVE(&cp->killlist, pfd, list);
191 3
                memset(pfd, 0x11, sizeof *pfd);
192 3
                free(pfd);
193 3
                break;
194
        default:
195 0
                WRONG("Wrong pfd state");
196
        }
197 4185
        Lck_Unlock(&cp->mtx);
198 4185
}
199
200
/*--------------------------------------------------------------------
201
 */
202
203
static struct conn_pool *
204 3150
VCP_Ref(const void *id, const void *priv)
205
{
206
        struct conn_pool *cp;
207
208 3150
        Lck_Lock(&conn_pools_mtx);
209 3762
        VTAILQ_FOREACH(cp, &conn_pools, list) {
210 1308
                assert(cp->refcnt > 0);
211 1308
                if (cp->id != id)
212 0
                        continue;
213 1308
                if (cp->methods->cmp(cp, priv))
214 612
                        continue;
215 696
                cp->refcnt++;
216 696
                Lck_Unlock(&conn_pools_mtx);
217 696
                return (cp);
218
        }
219 2454
        Lck_Unlock(&conn_pools_mtx);
220 2454
        return (NULL);
221
}
222
223
/*--------------------------------------------------------------------
224
 */
225
226
static void *
227 2454
VCP_New(struct conn_pool *cp, const void *id, void *priv,
228
    const struct cp_methods *cm)
229
{
230
231 2454
        AN(cp);
232 2454
        AN(cm);
233 2454
        AN(cm->open);
234 2454
        AN(cm->close);
235 2454
        AN(cm->cmp);
236
237 2454
        INIT_OBJ(cp, CONN_POOL_MAGIC);
238 2454
        cp->id = id;
239 2454
        cp->priv = priv;
240 2454
        cp->methods = cm;
241 2454
        cp->refcnt = 1;
242 2454
        cp->holddown = 0;
243 2454
        Lck_New(&cp->mtx, lck_tcp_pool);
244 2454
        VTAILQ_INIT(&cp->connlist);
245 2454
        VTAILQ_INIT(&cp->killlist);
246
247 2454
        Lck_Lock(&conn_pools_mtx);
248 2454
        VTAILQ_INSERT_HEAD(&conn_pools, cp, list);
249 2454
        Lck_Unlock(&conn_pools_mtx);
250
251 2454
        return (priv);
252
}
253
254
255
/*--------------------------------------------------------------------
256
 */
257
258
static void
259 63
VCP_AddRef(struct conn_pool *cp)
260
{
261 63
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
262
263 63
        Lck_Lock(&conn_pools_mtx);
264 63
        assert(cp->refcnt > 0);
265 63
        cp->refcnt++;
266 63
        Lck_Unlock(&conn_pools_mtx);
267 63
}
268
269
/*--------------------------------------------------------------------
270
 * Release Conn pool, destroy if last reference.
271
 */
272
273
static int
274 195
VCP_Rel(struct conn_pool *cp)
275
{
276
        struct pfd *pfd, *pfd2;
277
278 195
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
279
280 195
        Lck_Lock(&conn_pools_mtx);
281 195
        assert(cp->refcnt > 0);
282 195
        if (--cp->refcnt > 0) {
283 159
                Lck_Unlock(&conn_pools_mtx);
284 159
                return (1);
285
        }
286 36
        AZ(cp->n_used);
287 36
        VTAILQ_REMOVE(&conn_pools, cp, list);
288 36
        Lck_Unlock(&conn_pools_mtx);
289
290 36
        Lck_Lock(&cp->mtx);
291 36
        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 72
        while (cp->n_kill) {
301 0
                Lck_Unlock(&cp->mtx);
302 0
                (void)usleep(20000);
303 0
                Lck_Lock(&cp->mtx);
304
        }
305 36
        Lck_Unlock(&cp->mtx);
306 36
        Lck_Delete(&cp->mtx);
307 36
        AZ(cp->n_conn);
308 36
        AZ(cp->n_kill);
309 36
        return (0);
310
}
311
312
/*--------------------------------------------------------------------
313
 * Recycle a connection.
314
 */
315
316
static void
317 4235
VCP_Recycle(const struct worker *wrk, struct pfd **pfdp)
318
{
319
        struct pfd *pfd;
320
        struct conn_pool *cp;
321 4235
        int i = 0;
322
323 4235
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
324 4235
        pfd = *pfdp;
325 4235
        *pfdp = NULL;
326 4235
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
327 4235
        cp = pfd->conn_pool;
328 4235
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
329
330 4235
        assert(pfd->state == PFD_STATE_USED);
331 4235
        assert(pfd->fd > 0);
332
333 4235
        Lck_Lock(&cp->mtx);
334 4235
        cp->n_used--;
335
336 4235
        pfd->waited->priv1 = pfd;
337 4235
        pfd->waited->fd = pfd->fd;
338 4235
        pfd->waited->idle = VTIM_real();
339 4235
        pfd->state = PFD_STATE_AVAIL;
340 4235
        pfd->waited->func = vcp_handle;
341 4235
        pfd->waited->tmo = &cache_param->backend_idle_timeout;
342 4235
        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 4235
                VTAILQ_INSERT_HEAD(&cp->connlist, pfd, list);
350 4235
                i++;
351
        }
352
353 4235
        if (pfd != NULL)
354 4235
                cp->n_conn++;
355 4235
        Lck_Unlock(&cp->mtx);
356
357 4235
        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 4235
                (void)usleep(10000);
372
        }
373 4235
}
374
375
/*--------------------------------------------------------------------
376
 * Open a new connection from pool.
377
 */
378
379
static int
380 3968
VCP_Open(struct conn_pool *cp, double tmo, const void **privp, int *err)
381
{
382
        int r;
383
        double h;
384
385 3968
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
386 3968
        AN(err);
387
388 7936
        while (cp->holddown > 0) {
389 209
                Lck_Lock(&cp->mtx);
390 209
                if (cp->holddown == 0) {
391 0
                        Lck_Unlock(&cp->mtx);
392 0
                        break;
393
                }
394
395 209
                if (VTIM_mono() >= cp->holddown) {
396 162
                        cp->holddown = 0;
397 162
                        Lck_Unlock(&cp->mtx);
398 162
                        break;
399
                }
400
401 47
                *err = 0;
402 47
                errno = cp->holddown_errno;
403 47
                Lck_Unlock(&cp->mtx);
404 47
                return (-1);
405
        }
406
407 3921
        r = cp->methods->open(cp, tmo, privp);
408
409 3921
        *err = errno;
410
411 3921
        if (r >= 0)
412 3705
                return (r);
413
414 216
        h = 0;
415
416
        /* stats access unprotected */
417 216
        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 216
                h = cache_param->backend_remote_error_holddown;
427 216
                break;
428
        case ENETUNREACH:
429 0
                h = cache_param->backend_remote_error_holddown;
430 0
                break;
431
        default:
432 0
                break;
433
        }
434
435 216
        if (h == 0)
436 0
                return (r);
437
438 216
        Lck_Lock(&cp->mtx);
439 216
        h += VTIM_mono();
440 216
        if (cp->holddown == 0 || h < cp->holddown) {
441 216
                cp->holddown = h;
442 216
                cp->holddown_errno = errno;
443
        }
444
445 216
        Lck_Unlock(&cp->mtx);
446
447 216
        return (r);
448
}
449
450
/*--------------------------------------------------------------------
451
 * Close a connection.
452
 */
453
454
static void
455 619
VCP_Close(struct pfd **pfdp)
456
{
457
        struct pfd *pfd;
458
        struct conn_pool *cp;
459
460 619
        pfd = *pfdp;
461 619
        *pfdp = NULL;
462 619
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
463 619
        cp = pfd->conn_pool;
464 619
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
465
466 619
        assert(pfd->fd > 0);
467
468 619
        Lck_Lock(&cp->mtx);
469 619
        assert(pfd->state == PFD_STATE_USED || pfd->state == PFD_STATE_STOLEN);
470 619
        cp->n_used--;
471 619
        if (pfd->state == PFD_STATE_STOLEN) {
472 3
                (void)shutdown(pfd->fd, SHUT_RDWR);
473 3
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
474 3
                pfd->state = PFD_STATE_CLEANUP;
475 3
                VTAILQ_INSERT_HEAD(&cp->killlist, pfd, list);
476 3
                cp->n_kill++;
477
        } else {
478 616
                assert(pfd->state == PFD_STATE_USED);
479 616
                cp->methods->close(pfd);
480 616
                memset(pfd, 0x44, sizeof *pfd);
481 616
                free(pfd);
482
        }
483 619
        Lck_Unlock(&cp->mtx);
484 619
}
485
486
/*--------------------------------------------------------------------
487
 * Get a connection, possibly recycled
488
 */
489
490
static struct pfd *
491 4902
VCP_Get(struct conn_pool *cp, double tmo, struct worker *wrk,
492
    unsigned force_fresh, int *err)
493
{
494
        struct pfd *pfd;
495
496 4902
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
497 4902
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
498 4902
        AN(err);
499
500 4902
        *err = 0;
501 4902
        Lck_Lock(&cp->mtx);
502 4902
        pfd = VTAILQ_FIRST(&cp->connlist);
503 4902
        CHECK_OBJ_ORNULL(pfd, PFD_MAGIC);
504 4902
        if (force_fresh || pfd == NULL || pfd->state == PFD_STATE_STOLEN)
505 3246
                pfd = NULL;
506
        else {
507 1656
                assert(pfd->conn_pool == cp);
508 1656
                assert(pfd->state == PFD_STATE_AVAIL);
509 1656
                VTAILQ_REMOVE(&cp->connlist, pfd, list);
510 1656
                VTAILQ_INSERT_TAIL(&cp->connlist, pfd, list);
511 1656
                cp->n_conn--;
512 1656
                VSC_C_main->backend_reuse++;
513 1656
                pfd->state = PFD_STATE_STOLEN;
514 1656
                pfd->cond = &wrk->cond;
515
        }
516 4902
        cp->n_used++;                   // Opening mostly works
517 4902
        Lck_Unlock(&cp->mtx);
518
519 4902
        if (pfd != NULL)
520 1656
                return (pfd);
521
522 3246
        ALLOC_OBJ(pfd, PFD_MAGIC);
523 3246
        AN(pfd);
524 3246
        INIT_OBJ(pfd->waited, WAITED_MAGIC);
525 3246
        pfd->state = PFD_STATE_USED;
526 3246
        pfd->conn_pool = cp;
527 3246
        pfd->fd = VCP_Open(cp, tmo, &pfd->priv, err);
528 3246
        if (pfd->fd < 0) {
529 45
                FREE_OBJ(pfd);
530 45
                Lck_Lock(&cp->mtx);
531 45
                cp->n_used--;           // Nope, didn't work after all.
532 45
                Lck_Unlock(&cp->mtx);
533
        } else
534 3201
                VSC_C_main->backend_conn++;
535
536 3246
        return (pfd);
537
}
538
539
/*--------------------------------------------------------------------
540
 */
541
542
static int
543 1572
VCP_Wait(struct worker *wrk, struct pfd *pfd, double tmo)
544
{
545
        struct conn_pool *cp;
546
        int r;
547
548 1572
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
549 1572
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
550 1572
        cp = pfd->conn_pool;
551 1572
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
552 1572
        assert(pfd->cond == &wrk->cond);
553 1572
        Lck_Lock(&cp->mtx);
554 1572
        while (pfd->state == PFD_STATE_STOLEN) {
555 1570
                r = Lck_CondWait(&wrk->cond, &cp->mtx, tmo);
556 1570
                if (r != 0) {
557 3
                        if (r == EINTR)
558 0
                                continue;
559 3
                        assert(r == ETIMEDOUT);
560 3
                        Lck_Unlock(&cp->mtx);
561 3
                        return (1);
562
                }
563
        }
564 1569
        assert(pfd->state == PFD_STATE_USED);
565 1569
        pfd->cond = NULL;
566 1569
        Lck_Unlock(&cp->mtx);
567
568 1569
        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 3921
tmo2msec(double tmo)
584
{
585 3921
        return ( (int)floor(tmo * 1000.0) );
586
}
587
588
static int v_matchproto_(cp_open_f)
589 3534
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 3534
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
596 3534
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
597
598 3534
        msec = tmo2msec(tmo);
599 3534
        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 3534
        *privp = tp->ip4;
606 3534
        s = VTCP_connect(tp->ip4, msec);
607 3534
        if (s >= 0)
608 3333
                return (s);
609 201
        if (!cache_param->prefer_ipv6) {
610 201
                *privp = tp->ip6;
611 201
                s = VTCP_connect(tp->ip6, msec);
612
        }
613 201
        return (s);
614
}
615
616
static void v_matchproto_(cp_close_f)
617 3148
vtp_close(struct pfd *pfd)
618
{
619
620 3148
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
621 3148
        VTCP_close(&pfd->fd);
622 3148
}
623
624
static int v_matchproto_(cp_cmp_f)
625 1245
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 1245
        CAST_OBJ_NOTNULL(vcs, priv, VTP_CS_MAGIC);
631 1245
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
632 1245
        if (tp->ip4 == NULL && vcs->ip4 != NULL)
633 0
                return (1);
634 1245
        if (tp->ip4 != NULL && vcs->ip4 == NULL)
635 42
                return (1);
636 1203
        if (tp->ip6 == NULL && vcs->ip6 != NULL)
637 3
                return (1);
638 1200
        if (tp->ip6 != NULL && vcs->ip6 == NULL)
639 0
                return (1);
640 2400
        if (tp->ip4 != NULL && vcs->ip4 != NULL &&
641 1200
            VSA_Compare(tp->ip4, vcs->ip4))
642 510
                return (1);
643 690
        if (tp->ip6 != NULL && vcs->ip6 != NULL &&
644 0
            VSA_Compare(tp->ip6, vcs->ip6))
645 0
                return (1);
646 690
        return (0);
647
}
648
649
static void v_matchproto_(cp_name_f)
650 4545
vtp_local_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
651
               unsigned plen)
652
{
653 4545
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
654 4545
        VTCP_myname(pfd->fd, addr, alen, pbuf, plen);
655 4545
}
656
657
static void v_matchproto_(cp_name_f)
658 9090
vtp_remote_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
659
                unsigned plen)
660
{
661 9090
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
662 9090
        VTCP_hisname(pfd->fd, addr, alen, pbuf, plen);
663 9090
}
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 387
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 387
        CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
684 387
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
685 387
        AN(tp->uds);
686
687 387
        msec = tmo2msec(tmo);
688 387
        *privp = bogo_ip;
689 387
        s = VUS_connect(tp->uds, msec);
690 387
        return (s);
691
}
692
693
static int v_matchproto_(cp_cmp_f)
694 63
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 63
        CAST_OBJ_NOTNULL(vcs, priv, VTP_CS_MAGIC);
700 63
        CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
701 63
        if (tp->uds != NULL && vcs->uds != NULL)
702 45
                return (strcmp(tp->uds, vcs->uds));
703 18
        return (1);
704
}
705
706
static void v_matchproto_(cp_name_f)
707 936
vus_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
708
         unsigned plen)
709
{
710
        (void) pfd;
711 936
        assert(alen > strlen("0.0.0.0"));
712 936
        assert(plen > 1);
713 936
        strcpy(addr, "0.0.0.0");
714 936
        strcpy(pbuf, "0");
715 936
}
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 3150
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 3150
        assert((uds != NULL && ip4 == NULL && ip6 == NULL) ||
740
            (uds == NULL && (ip4 != NULL || ip6 != NULL)));
741 3150
        INIT_OBJ(&vcs, VTP_CS_MAGIC);
742 3150
        vcs.ip4 = ip4;
743 3150
        vcs.ip6 = ip6;
744 3150
        vcs.uds = uds;
745
746 3150
        cp = VCP_Ref(id, &vcs);
747 3150
        if (cp != NULL)
748 696
                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 2454
        ALLOC_OBJ(tp, TCP_POOL_MAGIC);
755 2454
        AN(tp);
756 2454
        if (uds != NULL) {
757 114
                methods = &vus_methods;
758 114
                tp->uds = strdup(uds);
759
        }
760
        else {
761 2340
                methods = &vtp_methods;
762 2340
                if (ip4 != NULL)
763 2340
                        tp->ip4 = VSA_Clone(ip4);
764 2340
                if (ip6 != NULL)
765 3
                        tp->ip6 = VSA_Clone(ip6);
766
        }
767 2454
        return(VCP_New(tp->cp, id, tp, methods));
768
}
769
770
/*--------------------------------------------------------------------
771
 * Add a reference to a tcp_pool
772
 */
773
774
void
775 63
VTP_AddRef(struct tcp_pool *tp)
776
{
777 63
        CHECK_OBJ_NOTNULL(tp, TCP_POOL_MAGIC);
778 63
        VCP_AddRef(tp->cp);
779 63
}
780
781
/*--------------------------------------------------------------------
782
 * Release TCP pool, destroy if last reference.
783
 */
784
785
void
786 195
VTP_Rel(struct tcp_pool **tpp)
787
{
788
        struct tcp_pool *tp;
789
790 195
        TAKE_OBJ_NOTNULL(tp, tpp, TCP_POOL_MAGIC);
791 195
        if (VCP_Rel(tp->cp))
792 159
                return;
793
794 36
        free(tp->ip4);
795 36
        free(tp->ip6);
796 36
        free(tp->uds);
797 36
        FREE_OBJ(tp);
798
}
799
800
/*--------------------------------------------------------------------
801
 * Open a new connection from pool.
802
 */
803
804
int
805 722
VTP_Open(struct tcp_pool *tp, double tmo, const void **privp, int *err)
806
{
807 722
        return (VCP_Open(tp->cp, tmo, privp, err));
808
}
809
810
/*--------------------------------------------------------------------
811
 * Recycle a connection.
812
 */
813
814
void
815 4235
VTP_Recycle(const struct worker *wrk, struct pfd **pfdp)
816
{
817
818 4235
        VCP_Recycle(wrk, pfdp);
819 4235
}
820
821
/*--------------------------------------------------------------------
822
 * Close a connection.
823
 */
824
825
void
826 619
VTP_Close(struct pfd **pfdp)
827
{
828
829 619
        VCP_Close(pfdp);
830 619
}
831
832
/*--------------------------------------------------------------------
833
 * Get a connection
834
 */
835
836
struct pfd *
837 4902
VTP_Get(struct tcp_pool *tp, double tmo, struct worker *wrk,
838
        unsigned force_fresh, int *err)
839
{
840
841 4902
        return VCP_Get(tp->cp, tmo, wrk, force_fresh, err);
842
}
843
844
/*--------------------------------------------------------------------
845
 */
846
847
int
848 1572
VTP_Wait(struct worker *wrk, struct pfd *pfd, double tmo)
849
{
850 1572
        return (VCP_Wait(wrk, pfd, tmo));
851
}
852
853
/*--------------------------------------------------------------------
854
 */
855
856
const struct suckaddr *
857 3
VTP_getip(struct pfd *pfd)
858
{
859
        struct tcp_pool *tp;
860
861 3
        CHECK_OBJ_NOTNULL(pfd, PFD_MAGIC);
862 3
        CAST_OBJ_NOTNULL(tp, pfd->conn_pool->priv, TCP_POOL_MAGIC);
863 3
        return (pfd->priv);
864
}
865
866
/*--------------------------------------------------------------------*/
867
868
void
869 2055
VTP_Init(void)
870
{
871 2055
        Lck_New(&conn_pools_mtx, lck_tcp_pool);
872 2055
}