varnish-cache/bin/varnishd/cache/cache_vcl.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2016 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 */
30
31
#include "config.h"
32
33
#include <errno.h>
34
#include <dlfcn.h>
35
#include <fnmatch.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
39
#include "cache_varnishd.h"
40
#include "common/heritage.h"
41
42
#include "vcl.h"
43
44
#include "cache_director.h"
45
#include "cache_backend.h"
46
#include "vcli_serve.h"
47
48
static const char * const VCL_TEMP_INIT = "init";
49
static const char * const VCL_TEMP_COLD = "cold";
50
static const char * const VCL_TEMP_WARM = "warm";
51
static const char * const VCL_TEMP_BUSY = "busy";
52
static const char * const VCL_TEMP_COOLING = "cooling";
53
static const char * const VCL_TEMP_LABEL = "label";
54
55
/*
56
 * NB: The COOLING temperature is neither COLD nor WARM.
57
 * And LABEL is not a temperature, it's a different kind of VCL.
58
 */
59
#define VCL_WARM(v) ((v)->temp == VCL_TEMP_WARM || (v)->temp == VCL_TEMP_BUSY)
60
#define VCL_COLD(v) ((v)->temp == VCL_TEMP_INIT || (v)->temp == VCL_TEMP_COLD)
61
62
struct vcl {
63
        unsigned                magic;
64
#define VCL_MAGIC               0x214188f2
65
        VTAILQ_ENTRY(vcl)       list;
66
        void                    *dlh;
67
        const struct VCL_conf   *conf;
68
        char                    state[8];
69
        char                    *loaded_name;
70
        unsigned                busy;
71
        unsigned                discard;
72
        const char              *temp;
73
        pthread_rwlock_t        temp_rwl;
74
        VTAILQ_HEAD(,director)  director_list;
75
        VTAILQ_HEAD(,vclref)    ref_list;
76
        int                     nrefs;
77
        struct vcl              *label;
78
        int                     nlabels;
79
};
80
81
struct vclref {
82
        unsigned                magic;
83
#define VCLREF_MAGIC            0x47fb6848
84
        const struct vcl        *vcl;
85
        VTAILQ_ENTRY(vclref)    list;
86
        char                    desc[32];
87
};
88
89
/*
90
 * XXX: Presently all modifications to this list happen from the
91
 * CLI event-engine, so no locking is necessary
92
 */
93
static VTAILQ_HEAD(, vcl)       vcl_head =
94
    VTAILQ_HEAD_INITIALIZER(vcl_head);
95
96
static struct lock              vcl_mtx;
97
static struct vcl               *vcl_active; /* protected by vcl_mtx */
98
99
static struct vrt_ctx ctx_cli;
100
static unsigned handling_cli;
101
static struct ws ws_cli;
102
static uintptr_t ws_snapshot_cli;
103
104
/*--------------------------------------------------------------------*/
105
106
static struct vrt_ctx *
107 11556
vcl_get_ctx(unsigned method, int msg)
108
{
109 11556
        AZ(ctx_cli.handling);
110 11556
        INIT_OBJ(&ctx_cli, VRT_CTX_MAGIC);
111 11556
        handling_cli = 0;
112 11556
        ctx_cli.handling = &handling_cli;
113 11556
        ctx_cli.method = method;
114 11556
        if (msg) {
115 1550
                ctx_cli.msg = VSB_new_auto();
116 1550
                AN(ctx_cli.msg);
117
        }
118 11556
        ctx_cli.ws = &ws_cli;
119 11556
        WS_Assert(ctx_cli.ws);
120 11556
        VRTPRIV_init(cli_task_privs);
121 11556
        return (&ctx_cli);
122
}
123
124
static void
125 11556
vcl_rel_ctx(struct vrt_ctx **ctx)
126
{
127 11556
        assert(*ctx == &ctx_cli);
128 11556
        AN((*ctx)->handling);
129 11556
        if (ctx_cli.msg)
130 1550
                VSB_destroy(&ctx_cli.msg);
131 11556
        WS_Assert(ctx_cli.ws);
132 11556
        WS_Reset(&ws_cli, ws_snapshot_cli);
133 11556
        INIT_OBJ(*ctx, VRT_CTX_MAGIC);
134 11556
        *ctx = NULL;
135 11556
        VRTPRIV_dynamic_kill(cli_task_privs, (uintptr_t)cli_task_privs);
136 11556
}
137
138
/*--------------------------------------------------------------------*/
139
140
static int
141 3024
vcl_send_event(VRT_CTX, enum vcl_event_e ev)
142
{
143
        int r;
144
145 3024
        ASSERT_CLI();
146 3024
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
147 3024
        CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
148 3024
        CHECK_OBJ_NOTNULL(ctx->vcl->conf, VCL_CONF_MAGIC);
149 3024
        assert(ev == VCL_EVENT_LOAD ||
150
               ev == VCL_EVENT_WARM ||
151
               ev == VCL_EVENT_COLD ||
152
               ev == VCL_EVENT_DISCARD);
153 3024
        AN(ctx->handling);
154 3024
        *ctx->handling = 0;
155 3024
        AN(ctx->ws);
156
157 3024
        if (ev == VCL_EVENT_LOAD || ev == VCL_EVENT_WARM)
158 2934
                AN(ctx->msg);
159
160 3024
        r = ctx->vcl->conf->event_vcl(ctx, ev);
161
162 3024
        if (r && (ev == VCL_EVENT_COLD || ev == VCL_EVENT_DISCARD))
163 0
                WRONG("A VMOD cannot fail COLD or DISCARD events");
164
165 3024
        return (r);
166
}
167
168
/*--------------------------------------------------------------------*/
169
170
static struct vcl *
171 3166
vcl_find(const char *name)
172
{
173
        struct vcl *vcl;
174
175 3166
        ASSERT_CLI();
176 4648
        VTAILQ_FOREACH(vcl, &vcl_head, list) {
177 3130
                if (vcl->discard)
178 32
                        continue;
179 3098
                if (!strcmp(vcl->loaded_name, name))
180 1648
                        return (vcl);
181
        }
182 1518
        return (NULL);
183
}
184
185
/*--------------------------------------------------------------------*/
186
187
void
188 8
VCL_Panic(struct vsb *vsb, const struct vcl *vcl)
189
{
190
        int i;
191
192 8
        AN(vsb);
193 8
        if (vcl == NULL)
194 8
                return;
195 8
        VSB_printf(vsb, "vcl = {\n");
196 8
        VSB_indent(vsb, 2);
197 8
        PAN_CheckMagic(vsb, vcl, VCL_MAGIC);
198 8
        VSB_printf(vsb, "name = \"%s\",\n", vcl->loaded_name);
199 8
        VSB_printf(vsb, "busy = %u,\n", vcl->busy);
200 8
        VSB_printf(vsb, "discard = %u,\n", vcl->discard);
201 8
        VSB_printf(vsb, "state = %s,\n", vcl->state);
202 8
        VSB_printf(vsb, "temp = %s,\n", (const volatile char *)vcl->temp);
203 8
        VSB_printf(vsb, "conf = {\n");
204 8
        VSB_indent(vsb, 2);
205 8
        if (vcl->conf == NULL) {
206 0
                VSB_printf(vsb, "conf = NULL\n");
207
        } else {
208 8
                PAN_CheckMagic(vsb, vcl->conf, VCL_CONF_MAGIC);
209 8
                VSB_printf(vsb, "srcname = {\n");
210 8
                VSB_indent(vsb, 2);
211 24
                for (i = 0; i < vcl->conf->nsrc; ++i)
212 16
                        VSB_printf(vsb, "\"%s\",\n", vcl->conf->srcname[i]);
213 8
                VSB_indent(vsb, -2);
214 8
                VSB_printf(vsb, "},\n");
215
        }
216 8
        VSB_indent(vsb, -2);
217 8
        VSB_printf(vsb, "},\n");
218 8
        VSB_indent(vsb, -2);
219 8
        VSB_printf(vsb, "},\n");
220
}
221
222
/*--------------------------------------------------------------------*/
223
224
const char *
225 20974
VCL_Return_Name(unsigned r)
226
{
227
228 20974
        switch (r) {
229
#define VCL_RET_MAC(l, U, B)    \
230
        case VCL_RET_##U:       \
231
                return(#l);
232
#include "tbl/vcl_returns.h"
233
        default:
234 6
                return (NULL);
235
        }
236
}
237
238
const char *
239 20992
VCL_Method_Name(unsigned m)
240
{
241
242 20992
        switch (m) {
243
#define VCL_MET_MAC(func, upper, typ, bitmap)   \
244
        case VCL_MET_##upper:                   \
245
                return (#upper);
246
#include "tbl/vcl_returns.h"
247
        default:
248 0
                return (NULL);
249
        }
250
}
251
252
/*--------------------------------------------------------------------*/
253
254
static void
255 1605
vcl_get(struct vcl **vcc, struct vcl *vcl)
256
{
257 1605
        AN(vcc);
258
259 1605
        Lck_Lock(&vcl_mtx);
260 1605
        if (vcl == NULL)
261 1585
                vcl = vcl_active; /* Sample vcl_active under lock to avoid
262
                                   * race */
263 1605
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
264 1605
        if (vcl->label == NULL) {
265 1579
                AN(strcmp(vcl->state, VCL_TEMP_LABEL));
266 1579
                *vcc = vcl;
267
        } else {
268 26
                AZ(strcmp(vcl->state, VCL_TEMP_LABEL));
269 26
                *vcc = vcl->label;
270
        }
271 1605
        CHECK_OBJ_NOTNULL(*vcc, VCL_MAGIC);
272 1605
        AZ((*vcc)->discard);
273 1605
        (*vcc)->busy++;
274 1605
        Lck_Unlock(&vcl_mtx);
275 1605
        AZ(errno=pthread_rwlock_rdlock(&(*vcc)->temp_rwl));
276 1605
        assert(VCL_WARM(*vcc));
277 1605
        AZ(errno=pthread_rwlock_unlock(&(*vcc)->temp_rwl));
278 1605
}
279
280
void
281 3428
VCL_Refresh(struct vcl **vcc)
282
{
283 3428
        if (*vcc == vcl_active)
284 5271
                return;
285 1585
        if (*vcc != NULL)
286 86
                VCL_Rel(vcc);   /* XXX: optimize locking */
287
288 3170
        while (vcl_active == NULL)
289 0
                (void)usleep(100000);
290
291 1585
        vcl_get(vcc, NULL);
292
}
293
294
void
295 2684
VCL_Ref(struct vcl *vcl)
296
{
297
298 2684
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
299 2684
        AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
300 2684
        assert(!VCL_COLD(vcl));
301 2684
        AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
302 2684
        Lck_Lock(&vcl_mtx);
303 2684
        assert(vcl->busy > 0);
304 2684
        vcl->busy++;
305 2684
        Lck_Unlock(&vcl_mtx);
306 2684
}
307
308
void
309 2812
VCL_Rel(struct vcl **vcc)
310
{
311
        struct vcl *vcl;
312
313 2812
        AN(*vcc);
314 2812
        vcl = *vcc;
315 2812
        *vcc = NULL;
316
317 2812
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
318 2812
        Lck_Lock(&vcl_mtx);
319 2812
        assert(vcl->busy > 0);
320 2812
        vcl->busy--;
321
        /*
322
         * We do not garbage collect discarded VCL's here, that happens
323
         * in VCL_Poll() which is called from the CLI thread.
324
         */
325 2812
        Lck_Unlock(&vcl_mtx);
326 2812
}
327
328
/*--------------------------------------------------------------------*/
329
330
int
331 1656
VCL_AddDirector(struct vcl *vcl, struct director *d, const char *vcl_name)
332
{
333
        struct vsb *vsb;
334
335 1656
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
336 1656
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
337 1656
        AN(d->destroy);
338
339 1656
        vsb = VSB_new_auto();
340 1656
        AN(vsb);
341 1656
        VSB_printf(vsb, "%s.%s", VCL_Name(vcl), vcl_name);
342 1656
        AZ(VSB_finish(vsb));
343 1656
        REPLACE((d->display_name), VSB_data(vsb));
344 1656
        VSB_destroy(&vsb);
345
346 1656
        AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
347 1656
        if (vcl->temp == VCL_TEMP_COOLING) {
348 0
                AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
349 0
                return (1);
350
        }
351
352 1656
        Lck_Lock(&vcl_mtx);
353 1656
        VTAILQ_INSERT_TAIL(&vcl->director_list, d, vcl_list);
354 1656
        d->vcl = vcl;
355 1656
        Lck_Unlock(&vcl_mtx);
356
357 1656
        if (VCL_WARM(vcl))
358
                /* Only when adding backend to already warm VCL */
359 10
                VDI_Event(d, VCL_EVENT_WARM);
360 1646
        else if (vcl->temp != VCL_TEMP_INIT)
361 0
                WRONG("Dynamic Backends can only be added to warm VCLs");
362 1656
        AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
363
364 1656
        return (0);
365
}
366
367
void
368 0
VCL_DelDirector(struct director *d)
369
{
370
        struct vcl *vcl;
371
372 0
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
373 0
        vcl = d->vcl;
374 0
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
375 0
        Lck_Lock(&vcl_mtx);
376 0
        VTAILQ_REMOVE(&vcl->director_list, d, vcl_list);
377 0
        Lck_Unlock(&vcl_mtx);
378
379 0
        AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
380 0
        if (VCL_WARM(vcl))
381 0
                VDI_Event(d, VCL_EVENT_COLD);
382 0
        AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
383 0
        AN(d->destroy);
384 0
        REPLACE(d->display_name, NULL);
385 0
        d->destroy(d);
386 0
}
387
388
static int
389 1248
vcl_iterdir(struct cli *cli, const char *pat, const struct vcl *vcl,
390
    vcl_be_func *func, void *priv)
391
{
392 1248
        int i, found = 0;
393
        struct director *d;
394
395 2826
        VTAILQ_FOREACH(d, &vcl->director_list, vcl_list) {
396 1578
                if (fnmatch(pat, d->display_name, 0))
397 134
                        continue;
398 1444
                found++;
399 1444
                i = func(cli, d, priv);
400 1444
                if (i < 0)
401 0
                        return (i);
402 1444
                found += i;
403
        }
404 1248
        return (found);
405
}
406
407
int
408 1248
VCL_IterDirector(struct cli *cli, const char *pat,
409
    vcl_be_func *func, void *priv)
410
{
411 1248
        int i, found = 0;
412
        struct vsb *vsb;
413
        struct vcl *vcl;
414
415 1248
        ASSERT_CLI();
416 1248
        vsb = VSB_new_auto();
417 1248
        AN(vsb);
418 1248
        if (pat == NULL || *pat == '\0' || !strcmp(pat, "*")) {
419
                // all backends in active VCL
420 1180
                VSB_printf(vsb, "%s.*", VCL_Name(vcl_active));
421 1180
                vcl = vcl_active;
422 68
        } else if (strchr(pat, '.') == NULL) {
423
                // pattern applies to active vcl
424 60
                VSB_printf(vsb, "%s.%s", VCL_Name(vcl_active), pat);
425 60
                vcl = vcl_active;
426
        } else {
427
                // use pattern as is
428 8
                VSB_cat(vsb, pat);
429 8
                vcl = NULL;
430
        }
431 1248
        AZ(VSB_finish(vsb));
432 1248
        Lck_Lock(&vcl_mtx);
433 1248
        if (vcl != NULL) {
434 1240
                found = vcl_iterdir(cli, VSB_data(vsb), vcl, func, priv);
435
        } else {
436 16
                VTAILQ_FOREACH(vcl, &vcl_head, list) {
437 8
                        i = vcl_iterdir(cli, VSB_data(vsb), vcl, func, priv);
438 8
                        if (i < 0) {
439 0
                                found = i;
440 0
                                break;
441
                        } else {
442 8
                                found += i;
443
                        }
444
                }
445
        }
446 1248
        Lck_Unlock(&vcl_mtx);
447 1248
        VSB_destroy(&vsb);
448 1248
        return (found);
449
}
450
451
static void
452 1502
vcl_BackendEvent(const struct vcl *vcl, enum vcl_event_e e)
453
{
454
        struct director *d;
455
456 1502
        ASSERT_CLI();
457 1502
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
458 1502
        AZ(vcl->busy);
459
460 3180
        VTAILQ_FOREACH(d, &vcl->director_list, vcl_list)
461 1678
                VDI_Event(d, e);
462 1502
}
463
464
static void
465 72
vcl_KillBackends(struct vcl *vcl)
466
{
467
        struct director *d;
468
469 72
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
470 72
        AZ(vcl->busy);
471 72
        assert(VTAILQ_EMPTY(&vcl->ref_list));
472
        while (1) {
473 148
                d = VTAILQ_FIRST(&vcl->director_list);
474 148
                if (d == NULL)
475 72
                        break;
476 76
                VTAILQ_REMOVE(&vcl->director_list, d, vcl_list);
477 76
                AN(d->destroy);
478 76
                d->destroy(d);
479 76
        }
480 72
}
481
482
/*--------------------------------------------------------------------*/
483
484
static struct vcl *
485 2988
VCL_Open(const char *fn, struct vsb *msg)
486
{
487
        struct vcl *vcl;
488
        void *dlh;
489
        struct VCL_conf const *cnf;
490
491 2988
        AN(fn);
492 2988
        AN(msg);
493
494
#ifdef RTLD_NOLOAD
495
        /* Detect bogus caching by dlopen(3) */
496 2988
        dlh = dlopen(fn, RTLD_NOW | RTLD_NOLOAD);
497 2988
        AZ(dlh);
498
#endif
499 2988
        dlh = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
500 2988
        if (dlh == NULL) {
501 0
                VSB_printf(msg, "Could not load compiled VCL.\n");
502 0
                VSB_printf(msg, "\tdlopen() = %s\n", dlerror());
503 0
                return (NULL);
504
        }
505 2988
        cnf = dlsym(dlh, "VCL_conf");
506 2988
        if (cnf == NULL) {
507 0
                VSB_printf(msg, "Compiled VCL lacks metadata.\n");
508 0
                (void)dlclose(dlh);
509 0
                return (NULL);
510
        }
511 2988
        if (cnf->magic != VCL_CONF_MAGIC) {
512 0
                VSB_printf(msg, "Compiled VCL has mangled metadata.\n");
513 0
                (void)dlclose(dlh);
514 0
                return (NULL);
515
        }
516 2988
        ALLOC_OBJ(vcl, VCL_MAGIC);
517 2988
        AN(vcl);
518 2988
        AZ(errno=pthread_rwlock_init(&vcl->temp_rwl, NULL));
519 2988
        vcl->dlh = dlh;
520 2988
        vcl->conf = cnf;
521 2988
        return (vcl);
522
}
523
524
static void
525 1582
VCL_Close(struct vcl **vclp)
526
{
527
        struct vcl *vcl;
528
529 1582
        CHECK_OBJ_NOTNULL(*vclp, VCL_MAGIC);
530 1582
        vcl = *vclp;
531 1582
        *vclp = NULL;
532 1582
        AZ(dlclose(vcl->dlh));
533 1582
        AZ(errno=pthread_rwlock_destroy(&vcl->temp_rwl));
534 1582
        FREE_OBJ(vcl);
535 1582
}
536
537
/*--------------------------------------------------------------------
538
 * NB: This function is called from the test-load subprocess.
539
 */
540
541
int
542 1510
VCL_TestLoad(const char *fn)
543
{
544
        struct vsb *vsb;
545
        struct vcl *vcl;
546 1510
        int retval = 0;
547
548 1510
        AN(fn);
549 1510
        vsb = VSB_new_auto();
550 1510
        AN(vsb);
551 1510
        vcl = VCL_Open(fn, vsb);
552 1510
        if (vcl == NULL) {
553 0
                AZ(VSB_finish(vsb));
554 0
                fprintf(stderr, "%s", VSB_data(vsb));
555 0
                retval = -1;
556
        } else
557 1510
                VCL_Close(&vcl);
558 1510
        VSB_destroy(&vsb);
559 1510
        return (retval);
560
}
561
562
/*--------------------------------------------------------------------*/
563
564
struct director *
565 3845
VCL_DefaultDirector(const struct vcl *vcl)
566
{
567
568 3845
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
569 3845
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
570 3845
        return (*vcl->conf->default_director);
571
}
572
573
const char *
574 3078
VCL_Name(const struct vcl *vcl)
575
{
576
577 3078
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
578 3078
        return (vcl->loaded_name);
579
}
580
581
const struct vrt_backend_probe *
582 1634
VCL_DefaultProbe(const struct vcl *vcl)
583
{
584
585 1634
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
586 1634
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
587 1634
        return (vcl->conf->default_probe);
588
}
589
590
/*--------------------------------------------------------------------
591
 * VRT apis relating to VCL's as VCLS.
592
 */
593
594
void
595 53212
VRT_count(VRT_CTX, unsigned u)
596
{
597
598 53212
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
599 53212
        CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
600 53212
        CHECK_OBJ_NOTNULL(ctx->vcl->conf, VCL_CONF_MAGIC);
601 53212
        assert(u < ctx->vcl->conf->nref);
602 53212
        if (ctx->vsl != NULL)
603 205888
                VSLb(ctx->vsl, SLT_VCL_trace, "%s %u %u.%u.%u",
604 102944
                    ctx->vcl->loaded_name, u, ctx->vcl->conf->ref[u].source,
605 102944
                    ctx->vcl->conf->ref[u].line, ctx->vcl->conf->ref[u].pos);
606
        else
607 6960
                VSL(SLT_VCL_trace, 0, "%s %u %u.%u.%u",
608 3480
                    ctx->vcl->loaded_name, u, ctx->vcl->conf->ref[u].source,
609 3480
                    ctx->vcl->conf->ref[u].line, ctx->vcl->conf->ref[u].pos);
610 53215
}
611
612
VCL_VCL
613 32
VRT_vcl_get(VRT_CTX, const char *name)
614
{
615
        VCL_VCL vcl;
616
617 32
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
618 32
        vcl = vcl_find(name);
619 32
        AN(vcl);
620 32
        Lck_Lock(&vcl_mtx);
621 32
        vcl->nrefs++;
622 32
        Lck_Unlock(&vcl_mtx);
623 32
        return (vcl);
624
}
625
626
void
627 12
VRT_vcl_rel(VRT_CTX, VCL_VCL vcl)
628
{
629 12
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
630 12
        AN(vcl);
631 12
        Lck_Lock(&vcl_mtx);
632 12
        vcl->nrefs--;
633 12
        Lck_Unlock(&vcl_mtx);
634 12
}
635
636
void
637 20
VRT_vcl_select(VRT_CTX, VCL_VCL vcl)
638
{
639 20
        struct req *req = ctx->req;
640
641 20
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
642 20
        VCL_Rel(&req->vcl);
643 20
        vcl_get(&req->vcl, vcl);
644
        /* XXX: better logging */
645 20
        VSLb(ctx->req->vsl, SLT_Debug, "Now using %s VCL", vcl->loaded_name);
646 20
}
647
648
struct vclref *
649 80
VRT_ref_vcl(VRT_CTX, const char *desc)
650
{
651
        struct vcl *vcl;
652
        struct vclref* ref;
653
654 80
        ASSERT_CLI();
655 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
656 80
        AN(desc);
657 80
        AN(*desc);
658
659 80
        vcl = ctx->vcl;
660 80
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
661 80
        assert(VCL_WARM(vcl));
662
663 80
        ALLOC_OBJ(ref, VCLREF_MAGIC);
664 80
        AN(ref);
665 80
        ref->vcl = vcl;
666 80
        bprintf(ref->desc, "%s", desc);
667
668 80
        Lck_Lock(&vcl_mtx);
669 80
        VTAILQ_INSERT_TAIL(&vcl->ref_list, ref, list);
670 80
        vcl->nrefs++;
671 80
        Lck_Unlock(&vcl_mtx);
672
673 80
        return (ref);
674
}
675
676
void
677 16
VRT_rel_vcl(VRT_CTX, struct vclref **refp)
678
{
679
        struct vcl *vcl;
680
        struct vclref *ref;
681
682 16
        AN(refp);
683 16
        ref = *refp;
684 16
        *refp = NULL;
685
686 16
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
687 16
        CHECK_OBJ_NOTNULL(ref, VCLREF_MAGIC);
688
689 16
        vcl = ctx->vcl;
690 16
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
691 16
        assert(vcl == ref->vcl);
692
693
        /* NB: A VCL may be released by a VMOD at any time, but it must happen
694
         * after a warmup and before the end of a cooldown. The release may or
695
         * may not happen while the same thread holds the temperature lock, so
696
         * instead we check that all references are gone in VCL_Nuke.
697
         */
698
699 16
        Lck_Lock(&vcl_mtx);
700 16
        assert(!VTAILQ_EMPTY(&vcl->ref_list));
701 16
        VTAILQ_REMOVE(&vcl->ref_list, ref, list);
702 16
        vcl->nrefs--;
703
        /* No garbage collection here, for the same reasons as in VCL_Rel. */
704 16
        Lck_Unlock(&vcl_mtx);
705
706 16
        FREE_OBJ(ref);
707 16
}
708
709
/*--------------------------------------------------------------------*/
710
711
static void
712 2
vcl_print_refs(VRT_CTX)
713
{
714
        struct vcl *vcl;
715
        struct vclref *ref;
716
717 2
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
718 2
        CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
719 2
        AN(ctx->msg);
720 2
        vcl = ctx->vcl;
721 2
        VSB_printf(ctx->msg, "VCL %s is waiting for:", vcl->loaded_name);
722 2
        Lck_Lock(&vcl_mtx);
723 4
        VTAILQ_FOREACH(ref, &ctx->vcl->ref_list, list)
724 2
                VSB_printf(ctx->msg, "\n\t- %s", ref->desc);
725 2
        Lck_Unlock(&vcl_mtx);
726 2
}
727
728
static int
729 1613
vcl_set_state(VRT_CTX, const char *state)
730
{
731
        struct vcl *vcl;
732 1613
        int i = 0;
733
734 1613
        ASSERT_CLI();
735 1613
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
736 1613
        CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
737 1613
        CHECK_OBJ_NOTNULL(ctx->vcl->conf, VCL_CONF_MAGIC);
738 1613
        AN(ctx->handling);
739 1613
        AN(ctx->vcl);
740 1613
        AN(state);
741 1613
        assert(ctx->msg != NULL || *state == '0');
742
743 1613
        vcl = ctx->vcl;
744 1613
        AZ(errno=pthread_rwlock_wrlock(&vcl->temp_rwl));
745 1613
        AN(vcl->temp);
746
747 1613
        switch (state[0]) {
748
        case '0':
749 155
                assert(vcl->temp != VCL_TEMP_COLD);
750 155
                if (vcl->busy == 0 && VCL_WARM(vcl)) {
751
752 104
                        vcl->temp = VTAILQ_EMPTY(&vcl->ref_list) ?
753 52
                            VCL_TEMP_COLD : VCL_TEMP_COOLING;
754 52
                        AZ(vcl_send_event(ctx, VCL_EVENT_COLD));
755 52
                        vcl_BackendEvent(vcl, VCL_EVENT_COLD);
756
                }
757 103
                else if (vcl->busy)
758 79
                        vcl->temp = VCL_TEMP_BUSY;
759 24
                else if (VTAILQ_EMPTY(&vcl->ref_list))
760 18
                        vcl->temp = VCL_TEMP_COLD;
761
                else
762 6
                        vcl->temp = VCL_TEMP_COOLING;
763 155
                break;
764
        case '1':
765 1458
                assert(vcl->temp != VCL_TEMP_WARM);
766
                /* The warm VCL hasn't seen a cold event yet */
767 1458
                if (vcl->temp == VCL_TEMP_BUSY)
768 0
                        vcl->temp = VCL_TEMP_WARM;
769
                /* The VCL must first reach a stable cold state */
770 1458
                else if (vcl->temp == VCL_TEMP_COOLING) {
771 2
                        vcl_print_refs(ctx);
772 2
                        i = -1;
773
                }
774
                else {
775 1456
                        vcl->temp = VCL_TEMP_WARM;
776 1456
                        i = vcl_send_event(ctx, VCL_EVENT_WARM);
777 1456
                        if (i == 0)
778 1450
                                vcl_BackendEvent(vcl, VCL_EVENT_WARM);
779
                        else
780 6
                                AZ(vcl->conf->event_vcl(ctx, VCL_EVENT_COLD));
781
                }
782 1458
                break;
783
        default:
784 0
                WRONG("Wrong enum state");
785
        }
786 1613
        AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
787
788 1613
        return (i);
789
}
790
791
static void
792 34
vcl_cancel_load(VRT_CTX, struct cli *cli, const char *name, const char *step)
793
{
794 34
        struct vcl *vcl = ctx->vcl;
795
796 34
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
797 34
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
798
799 34
        AZ(VSB_finish(ctx->msg));
800 34
        VCLI_SetResult(cli, CLIS_CANT);
801 34
        VCLI_Out(cli, "VCL \"%s\" Failed %s", name, step);
802 34
        if (VSB_len(ctx->msg))
803 32
                VCLI_Out(cli, "\nMessage:\n\t%s", VSB_data(ctx->msg));
804 34
        *ctx->handling = 0;
805 34
        AZ(vcl->conf->event_vcl(ctx, VCL_EVENT_DISCARD));
806 34
        vcl_KillBackends(vcl);
807 34
        free(vcl->loaded_name);
808 34
        VCL_Close(&vcl);
809 34
}
810
811
static void
812 1478
vcl_load(struct cli *cli, struct vrt_ctx *ctx,
813
    const char *name, const char *fn, const char *state)
814
{
815
        struct vcl *vcl;
816
        int i;
817
818 1478
        ASSERT_CLI();
819
820 1478
        vcl = vcl_find(name);
821 1478
        AZ(vcl);
822
823 1478
        vcl = VCL_Open(fn, ctx->msg);
824 1478
        if (vcl == NULL) {
825 0
                AZ(VSB_finish(ctx->msg));
826 0
                VCLI_SetResult(cli, CLIS_PARAM);
827 0
                VCLI_Out(cli, "%s", VSB_data(ctx->msg));
828 0
                return;
829
        }
830
831 1478
        vcl->loaded_name = strdup(name);
832 1478
        XXXAN(vcl->loaded_name);
833 1478
        VTAILQ_INIT(&vcl->director_list);
834 1478
        VTAILQ_INIT(&vcl->ref_list);
835
836 1478
        vcl->temp = VCL_TEMP_INIT;
837
838 1478
        ctx->vcl = vcl;
839
840 1478
        VSB_clear(ctx->msg);
841 1478
        i = vcl_send_event(ctx, VCL_EVENT_LOAD);
842 1478
        if (i || *ctx->handling != VCL_RET_OK) {
843 32
                vcl_cancel_load(ctx, cli, name, "initialization");
844 32
                return;
845
        }
846 1446
        assert(*ctx->handling == VCL_RET_OK);
847 1446
        VSB_clear(ctx->msg);
848 1446
        i = vcl_set_state(ctx, state);
849 1446
        if (i) {
850 2
                assert(*state == '1');
851 2
                vcl_cancel_load(ctx, cli, name, "warmup");
852 2
                return;
853
        }
854 1444
        bprintf(vcl->state, "%s", state + 1);
855 1444
        VCLI_Out(cli, "Loaded \"%s\" as \"%s\"", fn , name);
856 1444
        VTAILQ_INSERT_TAIL(&vcl_head, vcl, list);
857 1444
        Lck_Lock(&vcl_mtx);
858 1444
        if (vcl_active == NULL)
859 1226
                vcl_active = vcl;
860 1444
        Lck_Unlock(&vcl_mtx);
861 1444
        VSC_C_main->n_vcl++;
862 1444
        VSC_C_main->n_vcl_avail++;
863
}
864
865
/*--------------------------------------------------------------------*/
866
867
void
868 10006
VCL_Poll(void)
869
{
870
        struct vrt_ctx *ctx;
871
        struct vcl *vcl, *vcl2;
872
873 10006
        ASSERT_CLI();
874 10006
        ctx = vcl_get_ctx(0, 0);
875 21168
        VTAILQ_FOREACH_SAFE(vcl, &vcl_head, list, vcl2) {
876 22251
                if (vcl->temp == VCL_TEMP_BUSY ||
877 11089
                    vcl->temp == VCL_TEMP_COOLING) {
878 95
                        ctx->vcl = vcl;
879 95
                        ctx->method = 0;
880 95
                        (void)vcl_set_state(ctx, "0");
881
                }
882 11162
                if (vcl->discard && vcl->temp == VCL_TEMP_COLD) {
883 38
                        AZ(vcl->busy);
884 38
                        assert(vcl != vcl_active);
885 38
                        assert(VTAILQ_EMPTY(&vcl->ref_list));
886 38
                        VTAILQ_REMOVE(&vcl_head, vcl, list);
887 38
                        ctx->method = VCL_MET_FINI;
888 38
                        ctx->vcl = vcl;
889 38
                        AZ(vcl_send_event(ctx, VCL_EVENT_DISCARD));
890 38
                        vcl_KillBackends(vcl);
891 38
                        free(vcl->loaded_name);
892 38
                        VCL_Close(&vcl);
893 38
                        VSC_C_main->n_vcl--;
894 38
                        VSC_C_main->n_vcl_discard--;
895
                }
896
        }
897 10006
        vcl_rel_ctx(&ctx);
898 10006
}
899
900
/*--------------------------------------------------------------------*/
901
902
static void v_matchproto_(cli_func_t)
903 78
vcl_cli_list(struct cli *cli, const char * const *av, void *priv)
904
{
905
        struct vcl *vcl;
906
        const char *flg;
907
908
        /* NB: Shall generate same output as mcf_vcl_list() */
909
910
        (void)av;
911
        (void)priv;
912 78
        ASSERT_CLI();
913 250
        VTAILQ_FOREACH(vcl, &vcl_head, list) {
914 172
                if (vcl == vcl_active) {
915 78
                        flg = "active";
916 94
                } else if (vcl->discard) {
917 6
                        flg = "discarded";
918
                } else
919 88
                        flg = "available";
920 344
                VCLI_Out(cli, "%-10s %5s/%-8s %6u %s",
921 172
                    flg, vcl->state, vcl->temp, vcl->busy, vcl->loaded_name);
922 172
                if (vcl->label != NULL) {
923 36
                        VCLI_Out(cli, " -> %s", vcl->label->loaded_name);
924 36
                        if (vcl->nrefs)
925 8
                                VCLI_Out(cli, " (%d return(vcl)%s)",
926 8
                                    vcl->nrefs, vcl->nrefs > 1 ? "'s" : "");
927 136
                } else if (vcl->nlabels > 0) {
928 24
                        VCLI_Out(cli, " (%d label%s)",
929 24
                            vcl->nlabels, vcl->nlabels > 1 ? "s" : "");
930
                }
931 172
                VCLI_Out(cli, "\n");
932
        }
933 78
}
934
935
static void v_matchproto_(cli_func_t)
936 1478
vcl_cli_load(struct cli *cli, const char * const *av, void *priv)
937
{
938
        struct vrt_ctx *ctx;
939
940 1478
        AZ(priv);
941 1478
        ASSERT_CLI();
942 1478
        ctx = vcl_get_ctx(VCL_MET_INIT, 1);
943 1478
        vcl_load(cli, ctx, av[2], av[3], av[4]);
944 1478
        vcl_rel_ctx(&ctx);
945 1478
}
946
947
static void v_matchproto_(cli_func_t)
948 72
vcl_cli_state(struct cli *cli, const char * const *av, void *priv)
949
{
950
        struct vrt_ctx *ctx;
951
952 72
        AZ(priv);
953 72
        ASSERT_CLI();
954 72
        AN(av[2]);
955 72
        AN(av[3]);
956 72
        ctx = vcl_get_ctx(0, 1);
957 72
        ctx->vcl = vcl_find(av[2]);
958 72
        AN(ctx->vcl);                   // MGT ensures this
959 72
        if (vcl_set_state(ctx, av[3]) == 0) {
960 66
                bprintf(ctx->vcl->state, "%s", av[3] + 1);
961
        } else {
962 6
                AZ(VSB_finish(ctx->msg));
963 6
                VCLI_SetResult(cli, CLIS_CANT);
964 6
                VCLI_Out(cli, "Failed <vcl.state %s %s>", ctx->vcl->loaded_name,
965 6
                    av[3] + 1);
966 6
                if (VSB_len(ctx->msg))
967 6
                        VCLI_Out(cli, "\nMessage:\n\t%s", VSB_data(ctx->msg));
968
        }
969 72
        vcl_rel_ctx(&ctx);
970 72
}
971
972
static void v_matchproto_(cli_func_t)
973 52
vcl_cli_discard(struct cli *cli, const char * const *av, void *priv)
974
{
975
        struct vcl *vcl;
976
977 52
        ASSERT_CLI();
978
        (void)cli;
979 52
        AZ(priv);
980 52
        vcl = vcl_find(av[2]);
981 52
        AN(vcl);                        // MGT ensures this
982 52
        Lck_Lock(&vcl_mtx);
983 52
        assert (vcl != vcl_active);     // MGT ensures this
984 52
        AZ(vcl->nlabels);               // MGT ensures this
985 52
        VSC_C_main->n_vcl_discard++;
986 52
        VSC_C_main->n_vcl_avail--;
987 52
        vcl->discard = 1;
988 52
        if (vcl->label != NULL) {
989 8
                AZ(strcmp(vcl->state, VCL_TEMP_LABEL));
990 8
                vcl->label->nlabels--;
991 8
                vcl->label= NULL;
992
        }
993 52
        Lck_Unlock(&vcl_mtx);
994
995 52
        if (!strcmp(vcl->state, VCL_TEMP_LABEL)) {
996 8
                VTAILQ_REMOVE(&vcl_head, vcl, list);
997 8
                free(vcl->loaded_name);
998 8
                AZ(errno=pthread_rwlock_destroy(&vcl->temp_rwl));
999 8
                FREE_OBJ(vcl);
1000 44
        } else if (vcl->temp == VCL_TEMP_COLD) {
1001 34
                VCL_Poll();
1002
        }
1003 52
}
1004
1005
static void v_matchproto_(cli_func_t)
1006 42
vcl_cli_label(struct cli *cli, const char * const *av, void *priv)
1007
{
1008
        struct vcl *lbl;
1009
        struct vcl *vcl;
1010
1011 42
        ASSERT_CLI();
1012
        (void)cli;
1013
        (void)priv;
1014 42
        vcl = vcl_find(av[3]);
1015 42
        AN(vcl);                                // MGT ensures this
1016 42
        lbl = vcl_find(av[2]);
1017 42
        if (lbl == NULL) {
1018 38
                ALLOC_OBJ(lbl, VCL_MAGIC);
1019 38
                AN(lbl);
1020 38
                bprintf(lbl->state, "%s", VCL_TEMP_LABEL);
1021 38
                lbl->temp = VCL_TEMP_WARM;
1022 38
                REPLACE(lbl->loaded_name, av[2]);
1023 38
                AZ(errno=pthread_rwlock_init(&lbl->temp_rwl, NULL));
1024 38
                VTAILQ_INSERT_TAIL(&vcl_head, lbl, list);
1025
        }
1026 42
        if (lbl->label != NULL)
1027 4
                lbl->label->nlabels--;
1028 42
        lbl->label = vcl;
1029 42
        vcl->nlabels++;
1030 42
}
1031
1032
static void v_matchproto_(cli_func_t)
1033 1436
vcl_cli_use(struct cli *cli, const char * const *av, void *priv)
1034
{
1035
        struct vcl *vcl;
1036
1037 1436
        ASSERT_CLI();
1038 1436
        AN(cli);
1039 1436
        AZ(priv);
1040 1436
        vcl = vcl_find(av[2]);
1041 1436
        AN(vcl);                                // MGT ensures this
1042 1436
        assert(vcl->temp == VCL_TEMP_WARM);     // MGT ensures this
1043 1436
        Lck_Lock(&vcl_mtx);
1044 1436
        vcl_active = vcl;
1045 1436
        Lck_Unlock(&vcl_mtx);
1046 1436
}
1047
1048
static void v_matchproto_(cli_func_t)
1049 16
vcl_cli_show(struct cli *cli, const char * const *av, void *priv)
1050
{
1051
        struct vcl *vcl;
1052 16
        int verbose = 0;
1053
        int i;
1054
1055 16
        ASSERT_CLI();
1056 16
        AZ(priv);
1057 16
        if (!strcmp(av[2], "-v") && av[3] == NULL) {
1058 2
                VCLI_Out(cli, "Too few parameters");
1059 2
                VCLI_SetResult(cli, CLIS_TOOFEW);
1060 2
                return;
1061 14
        } else if (strcmp(av[2], "-v") && av[3] != NULL) {
1062 2
                VCLI_Out(cli, "Unknown options '%s'", av[2]);
1063 2
                VCLI_SetResult(cli, CLIS_PARAM);
1064 2
                return;
1065 12
        } else if (av[3] != NULL) {
1066 4
                verbose = 1;
1067 4
                vcl = vcl_find(av[3]);
1068
        } else
1069 8
                vcl = vcl_find(av[2]);
1070
1071 12
        if (vcl == NULL) {
1072 2
                VCLI_Out(cli, "No VCL named '%s'",
1073 2
                    av[3] == NULL ? av[2] : av[3]);
1074 2
                VCLI_SetResult(cli, CLIS_PARAM);
1075 2
                return;
1076
        }
1077 10
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
1078 10
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
1079 10
        if (verbose) {
1080 12
                for (i = 0; i < vcl->conf->nsrc; i++)
1081 24
                        VCLI_Out(cli, "// VCL.SHOW %d %zd %s\n%s\n",
1082 8
                            i, strlen(vcl->conf->srcbody[i]),
1083 8
                            vcl->conf->srcname[i],
1084 8
                            vcl->conf->srcbody[i]);
1085
        } else {
1086 6
                VCLI_Out(cli, "%s", vcl->conf->srcbody[0]);
1087
        }
1088
}
1089
1090
/*--------------------------------------------------------------------
1091
 * Method functions to call into VCL programs.
1092
 *
1093
 * Either the request or busyobject must be specified, but not both.
1094
 * The workspace argument is where random VCL stuff gets space from.
1095
 */
1096
1097
static void
1098 20975
vcl_call_method(struct worker *wrk, struct req *req, struct busyobj *bo,
1099
    void *specific, unsigned method, vcl_func_f *func)
1100
{
1101
        uintptr_t aws;
1102 20975
        struct vsl_log *vsl = NULL;
1103
        struct vrt_ctx ctx;
1104
1105 20975
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1106 20975
        INIT_OBJ(&ctx, VRT_CTX_MAGIC);
1107 20975
        if (req != NULL) {
1108 15526
                CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1109 15526
                CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC);
1110 15526
                CHECK_OBJ_NOTNULL(req->vcl, VCL_MAGIC);
1111 15526
                vsl = req->vsl;
1112 15526
                ctx.vcl = req->vcl;
1113 15526
                ctx.http_req = req->http;
1114 15526
                ctx.http_req_top = req->top->http;
1115 15526
                ctx.http_resp = req->resp;
1116 15526
                ctx.req = req;
1117 15526
                ctx.sp = req->sp;
1118 15526
                ctx.now = req->t_prev;
1119 15526
                ctx.ws = req->ws;
1120
        }
1121 20975
        if (bo != NULL) {
1122 5475
                CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
1123 5475
                CHECK_OBJ_NOTNULL(bo->vcl, VCL_MAGIC);
1124 5475
                vsl = bo->vsl;
1125 5475
                ctx.vcl = bo->vcl;
1126 5475
                ctx.http_bereq = bo->bereq;
1127 5475
                ctx.http_beresp = bo->beresp;
1128 5475
                ctx.bo = bo;
1129 5475
                ctx.sp = bo->sp;
1130 5475
                ctx.now = bo->t_prev;
1131 5475
                ctx.ws = bo->ws;
1132
        }
1133 20975
        assert(ctx.now != 0);
1134 20975
        ctx.vsl = vsl;
1135 20975
        ctx.specific = specific;
1136 20975
        ctx.method = method;
1137 20975
        wrk->handling = 0;
1138 20975
        ctx.handling = &wrk->handling;
1139 20975
        aws = WS_Snapshot(wrk->aws);
1140 20977
        wrk->cur_method = method;
1141 20977
        wrk->seen_methods |= method;
1142 20977
        AN(vsl);
1143 20977
        VSLb(vsl, SLT_VCL_call, "%s", VCL_Method_Name(method));
1144 20976
        func(&ctx);
1145 20971
        VSLb(vsl, SLT_VCL_return, "%s", VCL_Return_Name(wrk->handling));
1146 20971
        wrk->cur_method |= 1;           // Magic marker
1147 20971
        if (wrk->handling == VCL_RET_FAIL)
1148 168
                wrk->stats->vcl_fail++;
1149
1150
        /*
1151
         * VCL/Vmods are not allowed to make permanent allocations from
1152
         * wrk->aws, but they can reserve and return from it.
1153
         */
1154 20971
        assert(aws == WS_Snapshot(wrk->aws));
1155 20969
}
1156
1157
#define VCL_MET_MAC(func, upper, typ, bitmap)                           \
1158
void                                                                    \
1159
VCL_##func##_method(struct vcl *vcl, struct worker *wrk,                \
1160
     struct req *req, struct busyobj *bo, void *specific)               \
1161
{                                                                       \
1162
                                                                        \
1163
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);                              \
1164
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);                   \
1165
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);                           \
1166
        vcl_call_method(wrk, req, bo, specific,                         \
1167
            VCL_MET_ ## upper, vcl->conf->func##_func);                 \
1168
        AN((1U << wrk->handling) & bitmap);                             \
1169
}
1170
1171
#include "tbl/vcl_returns.h"
1172
1173
/*--------------------------------------------------------------------*/
1174
1175
static struct cli_proto vcl_cmds[] = {
1176
        { CLICMD_VCL_LOAD,              "", vcl_cli_load },
1177
        { CLICMD_VCL_LIST,              "", vcl_cli_list },
1178
        { CLICMD_VCL_STATE,             "", vcl_cli_state },
1179
        { CLICMD_VCL_DISCARD,           "", vcl_cli_discard },
1180
        { CLICMD_VCL_USE,               "", vcl_cli_use },
1181
        { CLICMD_VCL_SHOW,              "", vcl_cli_show },
1182
        { CLICMD_VCL_LABEL,             "", vcl_cli_label },
1183
        { NULL }
1184
};
1185
1186
void
1187 1228
VCL_Init(void)
1188
{
1189
1190 1228
        assert(cache_param->workspace_client > 0);
1191 1228
        WS_Init(&ws_cli, "cli", malloc(cache_param->workspace_client),
1192 1228
            cache_param->workspace_client);
1193 1228
        ws_snapshot_cli = WS_Snapshot(&ws_cli);
1194 1228
        CLI_AddFuncs(vcl_cmds);
1195 1228
        Lck_New(&vcl_mtx, lck_vcl);
1196 1228
}