varnish-cache/vmod/vmod_debug.c
0
/*-
1
 * Copyright (c) 2012-2019 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <stdlib.h>
33
#include <stdio.h>
34
#include <string.h>
35
#include <sys/socket.h>
36
#include <unistd.h>
37
38
#include "cache/cache_varnishd.h"
39
#include "cache/cache_filter.h"
40
41
#include "vsa.h"
42
#include "vtim.h"
43
#include "vcc_debug_if.h"
44
#include "VSC_debug.h"
45
46
struct priv_vcl {
47
        unsigned                magic;
48
#define PRIV_VCL_MAGIC          0x8E62FA9D
49
        char                    *foo;
50
        uintptr_t               obj_cb;
51
        struct vclref           *vclref_discard;
52
        struct vclref           *vclref_cold;
53
        VCL_DURATION            vcl_discard_delay;
54
        VCL_BACKEND             be;
55
        unsigned                cold_be;
56
        unsigned                cooling_be;
57
};
58
59
60
static pthread_mutex_t vsc_mtx = PTHREAD_MUTEX_INITIALIZER;
61
static struct vsc_seg *vsc_seg = NULL;
62
static struct VSC_debug *vsc = NULL;
63
static int loads;
64
static const int store_ip_token;
65
static const int fail_task_fini_token;
66
extern void mylog(struct vsl_log *vsl, enum VSL_tag_e tag,
67
    const char *fmt, ...) v_printflike_(3,4);
68
69
/**********************************************************************/
70
71
static enum vfp_status v_matchproto_(vfp_pull_f)
72 25
xyzzy_vfp_rot13_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
73
    ssize_t *lp)
74
{
75
        enum vfp_status vp;
76
        char *q;
77
        ssize_t l;
78
79 25
        (void)vfe;
80 25
        vp = VFP_Suck(vc, p, lp);
81 25
        if (vp == VFP_ERROR)
82 0
                return (vp);
83 25
        q = p;
84 725
        for (l = 0; l < *lp; l++, q++) {
85 700
                if (*q >= 'A' && *q <= 'Z')
86 100
                        *q = (((*q - 'A') + 13) % 26) + 'A';
87 700
                if (*q >= 'a' && *q <= 'z')
88 475
                        *q = (((*q - 'a') + 13) % 26) + 'a';
89 700
        }
90 25
        return (vp);
91 25
}
92
93
static const struct vfp xyzzy_vfp_rot13 = {
94
        .name = "rot13",
95
        .pull = xyzzy_vfp_rot13_pull,
96
};
97
98
/**********************************************************************/
99
100
// deliberately fragmenting the stream to make testing more interesting
101
#define ROT13_BUFSZ 8
102
103
static int v_matchproto_(vdp_init_f)
104 200
xyzzy_vfp_rot13_init(VRT_CTX, struct vdp_ctx *vdc, void **priv, struct objcore *oc)
105
{
106 200
        (void)vdc;
107 200
        (void)oc;
108
109 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
110 200
        AN(priv);
111 200
        *priv = malloc(ROT13_BUFSZ);
112 200
        if (*priv == NULL)
113 0
                return (-1);
114 200
        return (0);
115 200
}
116
117
static int v_matchproto_(vdp_bytes_f)
118 550
xyzzy_vfp_rot13_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
119
    const void *ptr, ssize_t len)
120
{
121
        char *q;
122
        const char *pp;
123 550
        int i, j, retval = 0;
124
125 550
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
126 550
        AN(priv);
127 550
        AN(*priv);
128 550
        if (len <= 0)
129 150
                return (VDP_bytes(vdc, act, ptr, len));
130 400
        AN(ptr);
131 400
        if (act != VDP_END)
132 250
                act = VDP_FLUSH;
133 400
        q = *priv;
134 400
        pp = ptr;
135
136 10200
        for (i = 0, j = 0; j < len; i++, j++) {
137 9800
                if (pp[j] >= 'A' && pp[j] <= 'Z')
138 650
                        q[i] = (((pp[j] - 'A') + 13) % 26) + 'A';
139 9150
                else if (pp[j] >= 'a' && pp[j] <= 'z')
140 5950
                        q[i] = (((pp[j] - 'a') + 13) % 26) + 'a';
141
                else
142 3200
                        q[i] = pp[j];
143 9800
                if (i == ROT13_BUFSZ - 1 && j < len - 1) {
144 1000
                        retval = VDP_bytes(vdc, VDP_FLUSH, q, ROT13_BUFSZ);
145 1000
                        if (retval != 0)
146 0
                                return (retval);
147 1000
                        i = -1;
148 1000
                }
149 9800
        }
150 400
        if (i >= 0)
151 400
                retval = VDP_bytes(vdc, act, q, i);
152 400
        return (retval);
153 550
}
154
155
static int v_matchproto_(vdp_fini_f)
156 200
xyzzy_vfp_rot13_fini(struct vdp_ctx *vdc, void **priv)
157
{
158 200
        (void)vdc;
159 200
        AN(priv);
160 200
        free(*priv);
161 200
        *priv = NULL;
162 200
        return (0);
163
}
164
165
static const struct vdp xyzzy_vdp_rot13 = {
166
        .name  = "rot13",
167
        .init  = xyzzy_vfp_rot13_init,
168
        .bytes = xyzzy_vfp_rot13_bytes,
169
        .fini  = xyzzy_vfp_rot13_fini,
170
};
171
172
/**********************************************************************
173
 * pendantic tests of the VDP API:
174
 * - assert that we see a VDP_END
175
 * - assert that _fini gets called before the task ends
176
 *
177
 * note:
178
 * we could lookup our own vdpe in _fini and check for vdpe->end == VDP_END
179
 * yet that would cross the API
180
 */
181
182
enum vdp_state_e {
183
        VDPS_NULL = 0,
184
        VDPS_INIT,      // _init called
185
        VDPS_BYTES,     // _bytes called act != VDP_END
186
        VDPS_END,       // _bytes called act == VDP_END
187
        VDPS_FINI       // _fini called
188
};
189
190
struct vdp_state_s {
191
        unsigned                magic;
192
#define VDP_STATE_MAGIC 0x57c8d309
193
        enum vdp_state_e        state;
194
};
195
196
static void v_matchproto_(vmod_priv_fini_f)
197 3000
priv_pedantic_fini(VRT_CTX, void *priv)
198
{
199
        struct vdp_state_s *vdps;
200
201 3000
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
202 3000
        CAST_OBJ_NOTNULL(vdps, priv, VDP_STATE_MAGIC);
203
204 3000
        assert(vdps->state == VDPS_FINI);
205 3000
}
206
207
static const struct vmod_priv_methods priv_pedantic_methods[1] = {{
208
        .magic = VMOD_PRIV_METHODS_MAGIC,
209
        .type = "debug_vdp_pedantic",
210
        .fini = priv_pedantic_fini
211
}};
212
213
static int v_matchproto_(vdp_init_f)
214 4800
xyzzy_pedantic_init(VRT_CTX, struct vdp_ctx *vdc, void **priv,
215
    struct objcore *oc)
216
{
217
        struct vdp_state_s *vdps;
218
        struct vmod_priv *p;
219
220 4800
        (void)oc;
221
222 4800
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
223 9400
        WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_STATE_MAGIC);
224 4800
        if (vdps == NULL)
225 200
                return (-1);
226 4600
        assert(vdps->state == VDPS_NULL);
227
228 4600
        p = VRT_priv_task(ctx, (void *)vdc);
229 4600
        if (p == NULL)
230 1600
                return (-1);
231 3000
        p->priv = vdps;
232 3000
        p->methods = priv_pedantic_methods;
233
234 3000
        AN(priv);
235 3000
        *priv = vdps;
236
237 3000
        vdps->state = VDPS_INIT;
238
239 3000
        return (0);
240 4800
}
241
242
static int v_matchproto_(vdp_bytes_f)
243 5365
xyzzy_pedantic_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
244
    const void *ptr, ssize_t len)
245
{
246
        struct vdp_state_s *vdps;
247
248 5365
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_STATE_MAGIC);
249 5365
        assert(vdps->state >= VDPS_INIT);
250 5365
        assert(vdps->state < VDPS_END);
251
252 5365
        if (act == VDP_END)
253 1400
                vdps->state = VDPS_END;
254
        else
255 3965
                vdps->state = VDPS_BYTES;
256
257 5365
        return (VDP_bytes(vdc, act, ptr, len));
258
}
259
260
static int v_matchproto_(vdp_fini_f)
261 4800
xyzzy_pedantic_fini(struct vdp_ctx *vdc, void **priv)
262
{
263
        struct vdp_state_s *vdps;
264
265 4800
        (void) vdc;
266 4800
        AN(priv);
267 4800
        if (*priv == NULL)
268 1800
                return (0);
269 3000
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_STATE_MAGIC);
270 3000
        assert(vdps->state == VDPS_INIT || vdps->state == VDPS_END);
271 3000
        vdps->state = VDPS_FINI;
272
273 3000
        *priv = NULL;
274 3000
        return (0);
275 4800
}
276
277
static const struct vdp xyzzy_vdp_pedantic = {
278
        .name  = "debug.pedantic",
279
        .init  = xyzzy_pedantic_init,
280
        .bytes = xyzzy_pedantic_bytes,
281
        .fini  = xyzzy_pedantic_fini,
282
};
283
284
/**********************************************************************/
285
286
VCL_STRING v_matchproto_(td_debug_author)
287 125
xyzzy_author(VRT_CTX, VCL_ENUM person, VCL_ENUM someone)
288
{
289 125
        (void)someone;
290
291 125
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
292 125
        if (person == VENUM(phk))
293 50
                return ("Poul-Henning");
294 75
        assert(strcmp(person, "phk"));
295 75
        if (person == VENUM(des))
296 25
                return ("Dag-Erling");
297 50
        assert(strcmp(person, "des"));
298 50
        if (person == VENUM(kristian))
299 25
                return ("Kristian");
300 25
        assert(strcmp(person, "kristian"));
301 25
        if (person == VENUM(mithrandir))
302 25
                return ("Tollef");
303 0
        assert(strcmp(person, "mithrandir"));
304 0
        WRONG("Illegal VMOD enum");
305 125
}
306
307
#define AN0(x) (void) 0
308
#define AN1(x) AN(x)
309
#define PRIV_FINI(name, assert)                                         \
310
static void v_matchproto_(vmod_priv_fini_f)                             \
311
priv_ ## name ## _fini(VRT_CTX, void *ptr)                              \
312
{                                                                       \
313
        const char * const fmt = "priv_" #name "_fini(%p)";             \
314
                                                                        \
315
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);                          \
316
        AN ## assert (ptr);                                             \
317
        mylog(ctx->vsl, SLT_Debug, fmt, (char *)ptr);                   \
318
        free(ptr);                                                      \
319
}                                                                       \
320
                                                                        \
321
static const struct vmod_priv_methods                                   \
322
xyzzy_test_priv_ ## name ## _methods[1] = {{                            \
323
        .magic = VMOD_PRIV_METHODS_MAGIC,                               \
324
        .type = "debug_test_priv_" #name,                               \
325
        .fini = priv_ ## name ## _fini                                  \
326
}};
327 50
PRIV_FINI(call, 0)
328 375
PRIV_FINI(task, 1)
329 75
PRIV_FINI(top, 1)
330
#undef PRIV_FINI
331
#undef AN0
332
#undef AN1
333
334
VCL_VOID v_matchproto_(td_debug_test_priv_call)
335 50
xyzzy_test_priv_call(VRT_CTX, struct vmod_priv *priv)
336
{
337
338 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
339 50
        if (priv->priv == NULL) {
340 50
                priv->priv = strdup("BAR");
341 50
                priv->methods = xyzzy_test_priv_call_methods;
342 50
        } else {
343 0
                assert(priv->methods == xyzzy_test_priv_call_methods);
344 0
                assert(!strcmp(priv->priv, "BAR"));
345
        }
346 50
}
347
348
VCL_VOID v_matchproto_(td_debug_test_priv_task_get)
349 25
xyzzy_test_priv_task_get(VRT_CTX)
350
{
351
352 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
353 25
        AZ(VRT_priv_task_get(ctx, NULL));
354 25
}
355
356
VCL_STRING v_matchproto_(td_debug_test_priv_task)
357 1150
xyzzy_test_priv_task(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
358
{
359
360 1150
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
361 1150
        if (s == NULL || *s == '\0') {
362 1050
                mylog(ctx->vsl, SLT_Debug, "test_priv_task(%p) = %p (exists)",
363 525
                    priv, priv->priv);
364 1150
        } else if (priv->priv == NULL) {
365 375
                priv->priv = strdup(s);
366 375
                priv->methods = xyzzy_test_priv_task_methods;
367 750
                mylog(ctx->vsl, SLT_Debug, "test_priv_task(%p) = %p (new)",
368 375
                    priv, priv->priv);
369 375
        } else {
370 500
                char *n = realloc(priv->priv,
371 250
                    strlen(priv->priv) + strlen(s) + 2);
372 250
                if (n == NULL)
373 0
                        return (NULL);
374 250
                strcat(n, " ");
375 250
                strcat(n, s);
376 250
                priv->priv = n;
377 500
                mylog(ctx->vsl, SLT_Debug, "test_priv_task(%p) = %p (update)",
378 250
                    priv, priv->priv);
379
        }
380 1150
        if (priv->priv != NULL)
381 1125
                assert(priv->methods == xyzzy_test_priv_task_methods);
382 1150
        return (priv->priv);
383 1150
}
384
385
VCL_STRING v_matchproto_(td_debug_test_priv_top)
386 600
xyzzy_test_priv_top(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
387
{
388
389 600
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
390 600
        if (priv->priv == NULL) {
391 75
                priv->priv = strdup(s);
392 75
                priv->methods = xyzzy_test_priv_top_methods;
393 75
        } else {
394 525
                assert(priv->methods == xyzzy_test_priv_top_methods);
395
        }
396 600
        return (priv->priv);
397
}
398
399
VCL_VOID v_matchproto_(td_debug_test_priv_vcl)
400 50
xyzzy_test_priv_vcl(VRT_CTX, struct vmod_priv *priv)
401
{
402
        struct priv_vcl *priv_vcl;
403
404 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
405 50
        AN(priv);
406 50
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
407 50
        AN(priv_vcl->foo);
408 50
        assert(!strcmp(priv_vcl->foo, "FOO"));
409 50
}
410
411
VCL_VOID v_matchproto_(td_debug_rot104)
412 25
xyzzy_rot104(VRT_CTX)
413
{
414
415 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
416
        // This should fail
417 25
        AN(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13));
418 25
}
419
420
VCL_VOID v_matchproto_(td_debug_rot52)
421 50
xyzzy_rot52(VRT_CTX, VCL_HTTP hp)
422
{
423
424 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
425 50
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
426
427 50
        http_PrintfHeader(hp, "Encrypted: ROT52");
428 50
}
429
430
VCL_STRING v_matchproto_(td_debug_argtest)
431 175
xyzzy_argtest(VRT_CTX, struct VARGS(argtest) *arg)
432
{
433
        char buf[100];
434
435 175
        AN(arg);
436 175
        bprintf(buf, "%s %g %s %s %jd %d %s",
437
            arg->one, arg->two, arg->three, arg->comma, (intmax_t)arg->four,
438
            arg->valid_opt, arg->valid_opt ? arg->opt : "<undef>");
439 175
        return (WS_Copy(ctx->ws, buf, -1));
440
}
441
442
VCL_INT v_matchproto_(td_debug_vre_limit)
443 50
xyzzy_vre_limit(VRT_CTX)
444
{
445 50
        (void)ctx;
446 50
        return (cache_param->vre_limits.match);
447
}
448
449
static void v_matchproto_(obj_event_f)
450 50
obj_cb(struct worker *wrk, void *priv, struct objcore *oc, unsigned event)
451
{
452
        const struct priv_vcl *priv_vcl;
453
        const char *what;
454
455 50
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
456 50
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
457 50
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
458 50
        switch (event) {
459 25
        case OEV_INSERT: what = "insert"; break;
460 25
        case OEV_EXPIRE: what = "expire"; break;
461 0
        default: WRONG("Wrong object event");
462 0
        }
463
464
        /* We cannot trust %p to be 0x... format as expected by m00021.vtc */
465 100
        VSL(SLT_Debug, NO_VXID, "Object Event: %s 0x%jx", what,
466 50
            (intmax_t)(uintptr_t)oc);
467 50
}
468
469
VCL_VOID v_matchproto_(td_debug_register_obj_events)
470 25
xyzzy_register_obj_events(VRT_CTX, struct vmod_priv *priv)
471
{
472
        struct priv_vcl *priv_vcl;
473
474 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
475 25
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
476 25
        AZ(priv_vcl->obj_cb);
477 25
        priv_vcl->obj_cb = ObjSubscribeEvents(obj_cb, priv_vcl,
478
                OEV_INSERT|OEV_EXPIRE);
479 25
        VSL(SLT_Debug, NO_VXID, "Subscribed to Object Events");
480 25
}
481
482
VCL_VOID v_matchproto_(td_debug_fail)
483 400
xyzzy_fail(VRT_CTX)
484
{
485
486 400
        VRT_fail(ctx, "Forced failure");
487 400
}
488
489
VCL_BOOL v_matchproto_(td_debug_fail2)
490 25
xyzzy_fail2(VRT_CTX)
491
{
492
493 25
        VRT_fail(ctx, "Forced failure");
494 25
        return (1);
495
}
496
497
static void v_matchproto_(vmod_priv_fini_f)
498 575
priv_vcl_fini(VRT_CTX, void *priv)
499
{
500
        struct priv_vcl *priv_vcl;
501
502 575
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
503 575
        AN(priv_vcl->foo);
504 575
        free(priv_vcl->foo);
505 575
        if (priv_vcl->obj_cb != 0) {
506 25
                ObjUnsubscribeEvents(&priv_vcl->obj_cb);
507 25
                VSLb(ctx->vsl, SLT_Debug, "Unsubscribed from Object Events");
508 25
        }
509 575
        AZ(priv_vcl->vclref_discard);
510 575
        AZ(priv_vcl->vclref_cold);
511 575
        FREE_OBJ(priv_vcl);
512 575
}
513
514
static const struct vmod_priv_methods priv_vcl_methods[1] = {{
515
        .magic = VMOD_PRIV_METHODS_MAGIC,
516
        .type = "debug_priv_vcl_fini",
517
        .fini = priv_vcl_fini
518
}};
519
520
static int
521 2300
event_load(VRT_CTX, struct vmod_priv *priv)
522
{
523
        struct priv_vcl *priv_vcl;
524
525 2300
        AN(ctx->msg);
526
527 2300
        loads++;
528
529 2300
        if (cache_param->nuke_limit == 42) {
530 25
                VSB_cat(ctx->msg, "nuke_limit is not the answer.");
531 25
                return (-1);
532
        }
533
534 2275
        ALLOC_OBJ(priv_vcl, PRIV_VCL_MAGIC);
535 2275
        AN(priv_vcl);
536 2275
        priv_vcl->foo = strdup("FOO");
537 2275
        AN(priv_vcl->foo);
538 2275
        priv->priv = priv_vcl;
539 2275
        priv->methods = priv_vcl_methods;
540
541 2275
        AZ(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13));
542 2275
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_pedantic));
543 2275
        return (0);
544 2300
}
545
546
VCL_VOID
547 25
xyzzy_vcl_prevent_cold(VRT_CTX, struct vmod_priv *priv)
548
{
549
        struct priv_vcl *priv_vcl;
550
        char buf[32];
551
552 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
553 25
        AN(priv);
554 25
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
555 25
        AZ(priv_vcl->vclref_cold);
556
557 25
        bprintf(buf, "vmod-debug ref on %s", VCL_Name(ctx->vcl));
558 25
        priv_vcl->vclref_cold = VRT_VCL_Prevent_Cold(ctx, buf);
559 25
}
560
561
VCL_VOID
562 25
xyzzy_vcl_allow_cold(VRT_CTX, struct vmod_priv *priv)
563
{
564
        struct priv_vcl *priv_vcl;
565
566 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
567 25
        AN(priv);
568 25
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
569 25
        AN(priv_vcl->vclref_cold);
570 25
        VRT_VCL_Allow_Cold(&priv_vcl->vclref_cold);
571 25
}
572
573
VCL_VOID
574 0
xyzzy_cold_backend(VRT_CTX, struct vmod_priv *priv)
575
{
576
        struct priv_vcl *priv_vcl;
577
578 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
579 0
        AN(priv);
580 0
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
581 0
        priv_vcl->cold_be = 1;
582 0
}
583
584
VCL_VOID
585 0
xyzzy_cooling_backend(VRT_CTX, struct vmod_priv *priv)
586
{
587
        struct priv_vcl *priv_vcl;
588
589 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
590 0
        AN(priv);
591 0
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
592 0
        priv_vcl->cooling_be = 1;
593 0
}
594
595
static const struct vdi_methods empty_methods[1] = {{
596
        .magic =        VDI_METHODS_MAGIC,
597
        .type = "debug.dummy"
598
}};
599
600
static int
601 2050
event_warm(VRT_CTX, const struct vmod_priv *priv)
602
{
603
        struct priv_vcl *priv_vcl;
604
        char buf[32];
605 2050
        const char *vcl_name = VCL_Name(ctx->vcl);
606
607
        // Using VSLs for coverage
608 2050
        VSLs(SLT_Debug, NO_VXID, TOSTRANDS(2, vcl_name, ": VCL_EVENT_WARM"));
609
610 2050
        AN(ctx->msg);
611 2050
        if (cache_param->max_esi_depth == 42) {
612 75
                VSB_cat(ctx->msg, "max_esi_depth is not the answer.");
613 75
                return (-1);
614
        }
615
616 1975
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
617 1975
        AZ(priv_vcl->vclref_discard);
618
619 1975
        if (!priv_vcl->cold_be) {
620
                /* NB: set up a COOLING step unless we want a COLD backend. */
621 1975
                bprintf(buf, "vmod-debug ref on %s", VCL_Name(ctx->vcl));
622 1975
                priv_vcl->vclref_discard = VRT_VCL_Prevent_Discard(ctx, buf);
623 1975
        }
624
625 1975
        AZ(priv_vcl->be);
626 1975
        priv_vcl->be = VRT_AddDirector(ctx, empty_methods,
627
            NULL, "%s", "dir_warmcold");
628
629 1975
        return (0);
630 2050
}
631
632
static void*
633 25
cooldown_thread(void *priv)
634
{
635
        struct priv_vcl *priv_vcl;
636
637 25
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
638 25
        AN(priv_vcl->vclref_discard);
639
640 25
        VTIM_sleep(priv_vcl->vcl_discard_delay);
641 25
        VRT_VCL_Allow_Discard(&priv_vcl->vclref_discard);
642 25
        return (NULL);
643
}
644
645
static VCL_BACKEND
646 0
create_cold_backend(VRT_CTX)
647
{
648
        struct vrt_endpoint vep[1];
649
        struct vrt_backend be[1];
650
651 0
        INIT_OBJ(vep, VRT_ENDPOINT_MAGIC);
652 0
        vep->uds_path = "/";
653 0
        INIT_OBJ(be, VRT_BACKEND_MAGIC);
654 0
        be->endpoint = vep;
655 0
        be->vcl_name = "doomed";
656 0
        return (VRT_new_backend(ctx, be, NULL));
657
}
658
659
static int
660 347
event_cold(VRT_CTX, const struct vmod_priv *priv)
661
{
662
        pthread_t thread;
663
        struct priv_vcl *priv_vcl;
664
665 347
        AZ(ctx->msg);
666
667 347
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
668
669 347
        VSL(SLT_Debug, NO_VXID, "%s: VCL_EVENT_COLD", VCL_Name(ctx->vcl));
670
671 347
        VRT_DelDirector(&priv_vcl->be);
672
673 347
        if (priv_vcl->cold_be) {
674 0
                AZ(priv_vcl->vclref_discard);
675 0
                priv_vcl->be = create_cold_backend(ctx);
676 0
                WRONG("unreachable");
677 0
        }
678
679 347
        if (priv_vcl->cooling_be) {
680 0
                AN(priv_vcl->vclref_discard);
681 0
                priv_vcl->be = create_cold_backend(ctx);
682 0
                AZ(priv_vcl->be);
683 0
        }
684
685 347
        if (priv_vcl->vcl_discard_delay == 0.0) {
686 322
                AN(priv_vcl->vclref_discard);
687 322
                VRT_VCL_Allow_Discard(&priv_vcl->vclref_discard);
688 322
                return (0);
689
        }
690
691 25
        PTOK(pthread_create(&thread, NULL, cooldown_thread, priv_vcl));
692 25
        PTOK(pthread_detach(thread));
693 25
        return (0);
694 347
}
695
696
static int
697 575
event_discard(VRT_CTX, void *priv)
698
{
699
700 575
        (void)priv;
701
702 575
        AZ(ctx->msg);
703
704 575
        VRT_RemoveFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13);
705 575
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_pedantic);
706
707 575
        if (--loads)
708 375
                return (0);
709
710
        /*
711
         * The vsc and vsc_seg variables are not per-VCL, they are
712
         * the same in all VCL's which import the same binary version
713
         * of this VMOD, so we should only carry out cleanup on the
714
         * last discard event.
715
         */
716 200
        PTOK(pthread_mutex_lock(&vsc_mtx));
717 200
        if (vsc != NULL) {
718 25
                VSC_debug_Destroy(&vsc_seg);
719 25
                vsc = NULL;
720 25
        }
721 200
        PTOK(pthread_mutex_unlock(&vsc_mtx));
722
723 200
        return (0);
724 575
}
725
726
int v_matchproto_(vmod_event_f)
727 5272
xyzzy_event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
728
{
729
730 5272
        switch (e) {
731 2300
        case VCL_EVENT_LOAD:    return (event_load(ctx, priv));
732 2050
        case VCL_EVENT_WARM:    return (event_warm(ctx, priv));
733 347
        case VCL_EVENT_COLD:    return (event_cold(ctx, priv));
734 575
        case VCL_EVENT_DISCARD: return (event_discard(ctx, priv));
735 0
        default: WRONG("we should test all possible events");
736 0
        }
737 5272
}
738
739
VCL_VOID v_matchproto_(td_debug_vcl_discard_delay)
740 25
xyzzy_vcl_discard_delay(VRT_CTX, struct vmod_priv *priv, VCL_DURATION delay)
741
{
742
        struct priv_vcl *priv_vcl;
743
744 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
745 25
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
746 25
        assert(delay > 0.0);
747 25
        priv_vcl->vcl_discard_delay = delay;
748 25
}
749
750
VCL_VOID v_matchproto_(td_debug_test_probe)
751 0
xyzzy_test_probe(VRT_CTX, VCL_PROBE probe, VCL_PROBE same)
752
{
753
754 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
755 0
        CHECK_OBJ_NOTNULL(probe, VRT_BACKEND_PROBE_MAGIC);
756 0
        CHECK_OBJ_ORNULL(same, VRT_BACKEND_PROBE_MAGIC);
757 0
        AZ(same == NULL || probe == same);
758 0
}
759
760
VCL_VOID
761 25
xyzzy_vsc_new(VRT_CTX)
762
{
763 25
        (void)ctx;
764 25
        PTOK(pthread_mutex_lock(&vsc_mtx));
765 25
        if (vsc == NULL) {
766 25
                AZ(vsc_seg);
767 25
                vsc = VSC_debug_New(NULL, &vsc_seg, "");
768 25
        }
769 25
        AN(vsc);
770 25
        AN(vsc_seg);
771 25
        PTOK(pthread_mutex_unlock(&vsc_mtx));
772 25
}
773
774
VCL_VOID
775 25
xyzzy_vsc_count(VRT_CTX, VCL_INT cnt)
776
{
777 25
        (void)ctx;
778 25
        PTOK(pthread_mutex_lock(&vsc_mtx));
779 25
        AN(vsc);
780 25
        vsc->count += cnt;
781 25
        PTOK(pthread_mutex_unlock(&vsc_mtx));
782 25
}
783
784
VCL_VOID
785 0
xyzzy_vsc_destroy(VRT_CTX)
786
{
787 0
        (void)ctx;
788 0
        PTOK(pthread_mutex_lock(&vsc_mtx));
789 0
        if (vsc != NULL) {
790 0
                AN(vsc_seg);
791 0
                VSC_debug_Destroy(&vsc_seg);
792 0
        }
793 0
        AZ(vsc_seg);
794 0
        vsc = NULL;
795 0
        PTOK(pthread_mutex_unlock(&vsc_mtx));
796 0
}
797
798
struct xyzzy_debug_concat {
799
        unsigned        magic;
800
#define CONCAT_MAGIC 0x6b746493
801
        VCL_STRING      s;
802
};
803
804
VCL_VOID
805 100
xyzzy_concat__init(VRT_CTX, struct xyzzy_debug_concat **concatp,
806
                   const char *vcl_name, VCL_STRANDS s)
807
{
808
        struct xyzzy_debug_concat *concat;
809 100
        size_t sz = 0;
810
        char *p;
811
812 100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
813 100
        AN(concatp);
814 100
        AZ(*concatp);
815 100
        AN(vcl_name);
816
817 100
        ALLOC_OBJ(concat, CONCAT_MAGIC);
818 100
        AN(concat);
819 100
        *concatp = concat;
820
821 300
        for (int i = 0; i < s->n; i++)
822 400
                if (s->p[i] != NULL)
823 200
                        sz += strlen(s->p[i]);
824 100
        p = malloc(sz + 1);
825 100
        AN(p);
826 100
        (void)VRT_Strands(p, sz + 1, s);
827 100
        concat->s = p;
828 100
}
829
830
VCL_VOID
831 0
xyzzy_concat__fini(struct xyzzy_debug_concat **concatp)
832
{
833
        struct xyzzy_debug_concat *concat;
834
835
836 0
        TAKE_OBJ_NOTNULL(concat, concatp, CONCAT_MAGIC);
837 0
        free(TRUST_ME(concat->s));
838 0
        FREE_OBJ(concat);
839 0
}
840
841
VCL_STRING
842 50
xyzzy_concat_get(VRT_CTX, struct xyzzy_debug_concat *concat)
843
{
844 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
845 50
        CHECK_OBJ_NOTNULL(concat, CONCAT_MAGIC);
846 50
        return (concat->s);
847
}
848
849
VCL_STRING
850 200
xyzzy_concatenate(VRT_CTX, VCL_STRANDS s)
851
{
852
        VCL_STRING r;
853
854 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
855 200
        r = VRT_StrandsWS(ctx->ws, NULL, s);
856 200
        if (r != NULL && *r != '\0')
857 150
                AN(WS_Allocated(ctx->ws, r, strlen(r) + 1));
858 200
        return (r);
859
}
860
861
VCL_STRING
862 200
xyzzy_collect(VRT_CTX, VCL_STRANDS s)
863
{
864
        VCL_STRING r;
865
866 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
867 200
        r = VRT_STRANDS_string(ctx, s);
868 200
        if (r != NULL && *r != '\0')
869 150
                AN(WS_Allocated(ctx->ws, r, strlen(r) + 1));
870 200
        return (r);
871
}
872
873
/* cf. VRT_SetHdr() */
874
VCL_VOID
875 200
xyzzy_sethdr(VRT_CTX, VCL_HEADER hdr, VCL_STRANDS s)
876
{
877
        struct http *hp;
878
        const char *b;
879
880 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
881 200
        if (hdr == NULL) {
882 0
                VRT_fail(ctx, "debug.sethdr(): header argument is NULL");
883 0
                return;
884
        }
885 200
        hp = VRT_selecthttp(ctx, hdr->where);
886 200
        if (hp == NULL) {
887 0
                VRT_fail(ctx, "debug.sethdr(): header argument "
888
                    "can not be used here");
889 0
                return;
890
        }
891 200
        AN(hdr->what);
892 200
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
893 200
        if (s->n == 0) {
894 0
                http_Unset(hp, hdr->what);
895 0
        } else {
896 200
                b = VRT_StrandsWS(hp->ws, hdr->what + 1, s);
897 200
                if (b == NULL) {
898 0
                        VSLbs(ctx->vsl, SLT_LostHeader,
899 0
                            TOSTRAND(hdr->what + 1));
900 0
                } else {
901 200
                        if (*b != '\0')
902 200
                                AN(WS_Allocated(hp->ws, b, strlen(b) + 1));
903 200
                        http_Unset(hp, hdr->what);
904 200
                        http_SetHeader(hp, b);
905
                }
906
        }
907 200
}
908
909
void
910 3450
mylog(struct vsl_log *vsl, enum VSL_tag_e tag,  const char *fmt, ...)
911
{
912
        va_list ap;
913
914 3450
        va_start(ap, fmt);
915 3450
        if (vsl != NULL)
916 2975
                VSLbv(vsl, tag, fmt, ap);
917
        else
918 475
                VSLv(tag, NO_VXID, fmt, ap);
919 3450
        va_end(ap);
920 3450
}
921
922
VCL_DURATION
923 100
xyzzy_priv_perf(VRT_CTX, VCL_INT size, VCL_INT rounds)
924
{
925
        vtim_mono t0, t1;
926
        vtim_dur d;
927
        struct vmod_priv *p;
928
        VCL_INT s, r;
929 100
        uintptr_t check = 0;
930
931 100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
932
933 27875
        for (s = 1; s <= size; s++) {
934 27775
                p = VRT_priv_task(ctx, (void *)(uintptr_t)s);
935 27775
                if (p == NULL) {
936 0
                        VRT_fail(ctx, "no priv task - out of ws?");
937 0
                        return (-1.0);
938
                }
939 27775
                p->priv = NULL;
940 27775
        }
941
942 100
        t0 = VTIM_mono();
943 1000100
        for (r = 0; r < rounds; r++) {
944 278750000
                for (s = 1; s <= size; s++) {
945 277750000
                        p = VRT_priv_task_get(ctx, (void *)(uintptr_t)s);
946 277750000
                        AN(p);
947 277750000
                        check += (uintptr_t)p->priv;
948 277750000
                        p->priv = (void *)(uintptr_t)(s * rounds + r);
949 277750000
                }
950 1000000
        }
951 100
        t1 = VTIM_mono();
952
953 100
        d = (t1 - t0) * 1e9 / ((double)size * (double)rounds);
954
955 200
        mylog(ctx->vsl, SLT_Debug,
956
             "perf size %jd rounds %jd time %.1fns check %jd",
957 100
             (intmax_t)size, (intmax_t)rounds, d, (uintmax_t)check);
958
959 100
        return (d);
960 100
}
961
962
VCL_STRANDS
963 100
xyzzy_return_strands(VRT_CTX, VCL_STRANDS strand)
964
{
965
966 100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
967 100
        VSLbs(ctx->vsl, SLT_Debug, strand);
968 100
        return (strand);
969
}
970
971
VCL_VOID
972 50
xyzzy_vsl_flush(VRT_CTX)
973
{
974 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
975 50
        VSL_Flush(ctx->vsl, 0);
976 50
}
977
978
/*---------------------------------------------------------------------*/
979
980
static const struct vcf_return * v_matchproto_(vcf_func_f)
981 350
xyzzy_catflap_simple(struct req *req, struct objcore **oc,
982
    struct objcore **oc_exp, int state)
983
{
984
985 350
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
986 350
        CHECK_OBJ_NOTNULL(req->vcf, VCF_MAGIC);
987 350
        assert(req->vcf->func == xyzzy_catflap_simple);
988
989 350
        (void)oc;
990 350
        (void)oc_exp;
991 350
        if (state == 0) {
992 100
                if (req->vcf->priv == VENUM(first))
993 25
                        return (VCF_HIT);
994 75
                if (req->vcf->priv == VENUM(miss))
995 75
                        return (VCF_MISS);
996 0
                WRONG("Shouldn't get here");
997 0
        }
998 250
        return (VCF_DEFAULT);
999 350
}
1000
1001
static const struct vcf_return * v_matchproto_(vcf_func_f)
1002 150
xyzzy_catflap_last(struct req *req, struct objcore **oc,
1003
    struct objcore **oc_exp, int state)
1004
{
1005
1006 150
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1007 150
        CHECK_OBJ_NOTNULL(req->vcf, VCF_MAGIC);
1008 150
        assert(req->vcf->func == xyzzy_catflap_last);
1009
1010 150
        (void)oc_exp;
1011 150
        if (state == 0) {
1012 100
                AN(oc);
1013 100
                CHECK_OBJ_NOTNULL(*oc, OBJCORE_MAGIC);
1014 100
                req->vcf->priv = *oc;
1015 100
                return (VCF_CONTINUE);
1016
        }
1017 50
        if (state == 1) {
1018 25
                AN(oc);
1019 25
                if (req->vcf->priv != NULL)
1020 25
                        CAST_OBJ_NOTNULL(*oc, req->vcf->priv, OBJCORE_MAGIC);
1021 25
                return (VCF_CONTINUE);
1022
        }
1023 25
        return (VCF_DEFAULT);
1024 150
}
1025
1026
VCL_VOID
1027 200
xyzzy_catflap(VRT_CTX, VCL_ENUM type)
1028
{
1029
        struct req *req;
1030
1031 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1032 200
        req = ctx->req;
1033 200
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1034 200
        XXXAZ(req->vcf);
1035 400
        WS_TASK_ALLOC_OBJ(ctx, req->vcf, VCF_MAGIC);
1036 200
        if (req->vcf == NULL)
1037 0
                return;
1038 200
        if (type == VENUM(first) || type == VENUM(miss)) {
1039 175
                req->vcf->func = xyzzy_catflap_simple;
1040 175
                req->vcf->priv = TRUST_ME(type);
1041 200
        } else if (type == VENUM(last)) {
1042 25
                req->vcf->func = xyzzy_catflap_last;
1043 25
        } else {
1044 0
                WRONG("Wrong VENUM");
1045
        }
1046 200
}
1047
1048
VCL_BYTES
1049 0
xyzzy_stk(VRT_CTX)
1050
{
1051 0
        const VCL_BYTES max = 100 * 1024 * 1024;
1052
        const char *a, *b;
1053
        VCL_BYTES r;
1054
1055 0
        a = TRUST_ME(&b);
1056 0
        b = TRUST_ME(ctx->req->wrk);
1057 0
        b += sizeof(*ctx->req->wrk);
1058
1059 0
        if (b > a && (r = b - a) < max)
1060 0
                return (r);
1061 0
        if (a > b && (r = a - b) < max)
1062 0
                return (r);
1063
1064 0
        return (0);
1065 0
}
1066
1067
VCL_VOID
1068 200
xyzzy_sndbuf(VRT_CTX, VCL_BYTES arg)
1069
{
1070 200
        int fd = -1, oldbuf, newbuf, buflen;
1071 200
        socklen_t intlen = sizeof(int);
1072
1073 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1074
1075 200
        if (ctx->bo) {
1076 0
                CHECK_OBJ(ctx->bo, BUSYOBJ_MAGIC);
1077 0
                INCOMPL();
1078 0
        }
1079 200
        else if (ctx->req) {
1080 200
                CHECK_OBJ(ctx->req, REQ_MAGIC);
1081 200
                CHECK_OBJ(ctx->req->sp, SESS_MAGIC);
1082 200
                fd = ctx->req->sp->fd;
1083 200
        }
1084
        else {
1085 0
                VRT_fail(ctx, "debug.sndbuf() called outside a transaction.");
1086 0
                return;
1087
        }
1088
1089 200
        xxxassert(fd >= 0);
1090
1091 200
        if (arg > INT_MAX)
1092 0
                buflen = INT_MAX;
1093 200
        else if (arg <= 0)
1094 0
                buflen = 0;
1095
        else
1096 200
                buflen = (int)arg;
1097
1098 200
        oldbuf = 0;
1099 200
        AZ(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &oldbuf, &intlen));
1100
1101 200
        newbuf = buflen;
1102 200
        AZ(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &newbuf, intlen));
1103 200
        AZ(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &newbuf, &intlen));
1104
1105 200
        AN(ctx->vsl);
1106 400
        VSLb(ctx->vsl, SLT_Debug, "SO_SNDBUF fd=%d old=%d new=%d actual=%d",
1107 200
            fd, oldbuf, buflen, newbuf);
1108 200
}
1109
1110
VCL_VOID
1111 350
xyzzy_store_ip(VRT_CTX, VCL_IP ip)
1112
{
1113
        struct vmod_priv *priv;
1114
1115 350
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1116
1117 350
        priv = VRT_priv_task(ctx, &store_ip_token);
1118 350
        if (priv == NULL) {
1119 0
                VRT_fail(ctx, "no priv task - out of ws?");
1120 0
                return;
1121
        }
1122
1123 350
        AZ(priv->methods);
1124 350
        assert(VSA_Sane(ip));
1125 350
        priv->priv = TRUST_ME(ip);
1126 350
}
1127
1128
VCL_IP
1129 700
xyzzy_get_ip(VRT_CTX)
1130
{
1131
        struct vmod_priv *priv;
1132
        VCL_IP ip;
1133
1134 700
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1135
1136 700
        priv = VRT_priv_task_get(ctx, &store_ip_token);
1137 700
        AN(priv);
1138 700
        AZ(priv->methods);
1139
1140 700
        ip = priv->priv;
1141 700
        assert(VSA_Sane(ip));
1142 700
        return (ip);
1143
}
1144
1145
/*---------------------------------------------------------------------*/
1146
1147
struct VPFX(debug_director) {
1148
        unsigned                        magic;
1149
#define VMOD_DEBUG_DIRECTOR_MAGIC       0x66b9ff3d
1150
        VCL_BACKEND                     dir;
1151
};
1152
1153
/* XXX more callbacks ? */
1154
static vdi_healthy_f vmod_debug_director_healthy;
1155
static vdi_resolve_f vmod_debug_director_resolve;
1156
1157
static const struct vdi_methods vmod_debug_director_methods[1] = {{
1158
        .magic =        VDI_METHODS_MAGIC,
1159
        .type =         "debug.director",
1160
        .resolve =      vmod_debug_director_resolve,
1161
        .healthy =      vmod_debug_director_healthy
1162
}};
1163
1164
VCL_VOID v_matchproto_(td_xyzzy_debug_director__init)
1165 25
xyzzy_director__init(VRT_CTX, struct VPFX(debug_director) **dp,
1166
    const char *vcl_name)
1167
{
1168
        struct VPFX(debug_director) *d;
1169
1170 25
        AN(dp);
1171 25
        AZ(*dp);
1172 25
        ALLOC_OBJ(d, VMOD_DEBUG_DIRECTOR_MAGIC);
1173 25
        AN(d);
1174
1175 25
        *dp = d;
1176 50
        d->dir = VRT_AddDirector(ctx, vmod_debug_director_methods, d,
1177 25
            "%s", vcl_name);
1178 25
}
1179
1180
VCL_VOID v_matchproto_(td_xyzzy_debug_director__fini)
1181 0
xyzzy_director__fini(struct VPFX(debug_director) **dp)
1182
{
1183
        struct VPFX(debug_director) *d;
1184
1185 0
        TAKE_OBJ_NOTNULL(d, dp, VMOD_DEBUG_DIRECTOR_MAGIC);
1186 0
        VRT_DelDirector(&d->dir);
1187 0
        FREE_OBJ(d);
1188 0
}
1189
1190
VCL_BACKEND v_matchproto_(td_xyzzy_debug_director_fail)
1191 50
xyzzy_director_fail(VRT_CTX, struct VPFX(debug_director) *d)
1192
{
1193 50
        CHECK_OBJ_NOTNULL(d, VMOD_DEBUG_DIRECTOR_MAGIC);
1194 50
        (void) ctx;
1195
1196 50
        return (d->dir);
1197
}
1198
1199
static VCL_BOOL v_matchproto_(vdi_healthy_f)
1200 50
vmod_debug_director_healthy(VRT_CTX, VCL_BACKEND dir, VCL_TIME *changed)
1201
{
1202 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1203
1204 50
        (void) dir;
1205 50
        (void) changed;
1206
1207 50
        VRT_fail(ctx, "fail");
1208 50
        return (1);
1209
}
1210
1211
static VCL_BACKEND v_matchproto_(vdi_resolve_f)
1212 25
vmod_debug_director_resolve(VRT_CTX, VCL_BACKEND dir)
1213
{
1214 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1215
1216 25
        (void) dir;
1217
1218 25
        VRT_fail(ctx, "fail");
1219 25
        return (NULL);
1220
}
1221
1222
VCL_STRING v_matchproto_(td_xyzzy_debug_client_ip)
1223 25
xyzzy_client_ip(VRT_CTX)
1224
{
1225 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1226
1227 25
        return (SES_Get_String_Attr(ctx->sp, SA_CLIENT_IP));
1228
}
1229
1230
VCL_STRING v_matchproto_(td_xyzzy_debug_client_port)
1231 25
xyzzy_client_port(VRT_CTX)
1232
{
1233 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1234
1235 25
        return (SES_Get_String_Attr(ctx->sp, SA_CLIENT_PORT));
1236
}
1237
1238
static void * fail_magic = &fail_magic;
1239
1240
static void
1241 75
fail_f(VRT_CTX, void *priv)
1242
{
1243
1244 75
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1245 75
        assert(priv == fail_magic);
1246
1247 75
        VRT_fail(ctx, "thou shalt not fini");
1248 75
}
1249
1250
static const struct vmod_priv_methods xyzzy_fail_task_fini_methods[1] = {{
1251
        .magic = VMOD_PRIV_METHODS_MAGIC,
1252
        .type = "debug_fail_task_fini",
1253
        .fini = fail_f
1254
}};
1255
1256
VCL_VOID v_matchproto_(td_xyzzy_debug_fail_task_fini)
1257 100
xyzzy_fail_task_fini(VRT_CTX)
1258
{
1259
        struct vmod_priv *p;
1260
1261 100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1262
1263 100
        p = VRT_priv_task(ctx, &fail_task_fini_token);
1264 100
        if (p == NULL) {
1265 0
                VRT_fail(ctx, "no priv task - out of ws?");
1266 0
                return;
1267
        }
1268
1269 100
        if (p->priv != NULL) {
1270 0
                assert(p->priv == fail_magic);
1271 0
                assert(p->methods == xyzzy_fail_task_fini_methods);
1272 0
                return;
1273
        }
1274
1275 100
        p->priv = fail_magic;
1276 100
        p->methods = xyzzy_fail_task_fini_methods;
1277 100
}
1278
1279
VCL_VOID v_matchproto_(td_xyzzy_debug_ok_task_fini)
1280 25
xyzzy_ok_task_fini(VRT_CTX)
1281
{
1282
        struct vmod_priv *p;
1283
1284 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1285
1286 25
        p = VRT_priv_task(ctx, &fail_task_fini_token);
1287 25
        if (p == NULL) {
1288 0
                VRT_fail(ctx, "no priv task - out of ws?");
1289 0
                return;
1290
        }
1291
1292 25
        p->priv = NULL;
1293 25
        p->methods = NULL;
1294 25
}
1295
1296
VCL_STRING v_matchproto_(td_xyzzy_debug_re_quote)
1297 150
xyzzy_re_quote(VRT_CTX, VCL_STRING s)
1298
{
1299
        struct vsb vsb[1];
1300
        char *q;
1301
1302 150
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1303 150
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
1304 150
        WS_VSB_new(vsb, ctx->ws);
1305 150
        VRE_quote(vsb, s);
1306 150
        q = WS_VSB_finish(vsb, ctx->ws, NULL);
1307 150
        if (q == NULL)
1308 0
                WS_MarkOverflow(ctx->ws);
1309 150
        return (q);
1310
}
1311
1312
VCL_STRING v_matchproto_(td_xyzzy_priv_task_with_option)
1313 75
xyzzy_priv_task_with_option(VRT_CTX, struct VARGS(priv_task_with_option) *args)
1314
{
1315
1316 75
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1317 75
        AN(args->priv);
1318 75
        if (args->priv->priv == NULL && args->valid_opt)
1319 25
                args->priv->priv = WS_Copy(ctx->ws, args->opt, -1);
1320 75
        return (args->priv->priv);
1321
}
1322
1323
VCL_BOOL v_matchproto_(td_xyzzy_validhdr)
1324 50
xyzzy_validhdr(VRT_CTX, VCL_STRANDS s)
1325
{
1326 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1327 50
        return (VRT_ValidHdr(ctx, s));
1328
}
1329
1330
VCL_REGEX v_matchproto_(td_xyzzy_regex)
1331 150
xyzzy_just_return_regex(VRT_CTX, VCL_REGEX r)
1332
{
1333
1334 150
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1335 150
        AN(r);
1336 150
        return (r);
1337
}
1338
1339
/*---------------------------------------------------------------------*/
1340
1341
VCL_VOID v_matchproto_(td_xyzzy_call)
1342 300
xyzzy_call(VRT_CTX, VCL_SUB sub)
1343
{
1344 300
        VRT_call(ctx, sub);
1345 300
}
1346
1347
VCL_STRING v_matchproto_(td_xyzzy_check_call)
1348 25
xyzzy_check_call(VRT_CTX, VCL_SUB sub)
1349
{
1350 25
        return (VRT_check_call(ctx, sub));
1351
}
1352
1353
/* the next two are to test WRONG vmod behavior:
1354
 * holding a VCL_SUB reference across vcls
1355
 */
1356
1357
static VCL_SUB wrong = NULL;
1358
1359
VCL_VOID v_matchproto_(td_xyzzy_bad_memory)
1360 0
xyzzy_bad_memory(VRT_CTX, VCL_SUB sub)
1361
{
1362 0
        (void) ctx;
1363
1364 0
        wrong = sub;
1365 0
}
1366
1367
VCL_SUB v_matchproto_(td_xyzzy_total_recall)
1368 0
xyzzy_total_recall(VRT_CTX)
1369
{
1370 0
        (void) ctx;
1371
1372 0
        return (wrong);
1373
}
1374
1375
/*---------------------------------------------------------------------*/
1376
1377
struct VPFX(debug_caller) {
1378
       unsigned        magic;
1379
#define DEBUG_CALLER_MAGIC 0xb47f3449
1380
       VCL_SUB         sub;
1381
};
1382
1383
VCL_VOID v_matchproto_(td_xyzzy_debug_caller__init)
1384 50
xyzzy_caller__init(VRT_CTX, struct VPFX(debug_caller) **callerp,
1385
    const char *name, VCL_SUB sub)
1386
{
1387
        struct VPFX(debug_caller) *caller;
1388
1389 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1390 50
        AN(callerp);
1391 50
        AZ(*callerp);
1392 50
        AN(name);
1393 50
        AN(sub);
1394
1395 50
        ALLOC_OBJ(caller, DEBUG_CALLER_MAGIC);
1396 50
        AN(caller);
1397 50
        *callerp = caller;
1398 50
        caller->sub = sub;
1399 50
}
1400
1401
VCL_VOID v_matchproto_(td_xyzzy_debug_caller__fini)
1402 0
xyzzy_caller__fini(struct VPFX(debug_caller) **callerp)
1403
{
1404
        struct VPFX(debug_caller) *caller;
1405
1406 0
        if (callerp == NULL || *callerp == NULL)
1407 0
                return;
1408 0
        TAKE_OBJ_NOTNULL(caller, callerp, DEBUG_CALLER_MAGIC);
1409 0
        FREE_OBJ(caller);
1410 0
}
1411
1412
VCL_VOID v_matchproto_(td_xyzzy_debug_caller_call)
1413 25
xyzzy_caller_call(VRT_CTX, struct VPFX(debug_caller) *caller)
1414
{
1415 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1416 25
        CHECK_OBJ_NOTNULL(caller, DEBUG_CALLER_MAGIC);
1417 25
        AN(caller->sub);
1418
1419 25
        VRT_call(ctx, caller->sub);
1420 25
}
1421
1422
VCL_SUB v_matchproto_(td_xyzzy_debug_caller_sub)
1423 25
xyzzy_caller_xsub(VRT_CTX, struct VPFX(debug_caller) *caller)
1424
{
1425 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1426 25
        CHECK_OBJ_NOTNULL(caller, DEBUG_CALLER_MAGIC);
1427 25
        AN(caller->sub);
1428
1429 25
        return (caller->sub);
1430
}