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 40
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 40
        (void)vfe;
80 40
        vp = VFP_Suck(vc, p, lp);
81 40
        if (vp == VFP_ERROR)
82 0
                return (vp);
83 40
        q = p;
84 1160
        for (l = 0; l < *lp; l++, q++) {
85 1120
                if (*q >= 'A' && *q <= 'Z')
86 160
                        *q = (((*q - 'A') + 13) % 26) + 'A';
87 1120
                if (*q >= 'a' && *q <= 'z')
88 760
                        *q = (((*q - 'a') + 13) % 26) + 'a';
89 1120
        }
90 40
        return (vp);
91 40
}
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 320
xyzzy_vfp_rot13_init(VRT_CTX, struct vdp_ctx *vdc, void **priv, struct objcore *oc)
105
{
106 320
        (void)vdc;
107 320
        (void)oc;
108
109 320
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
110 320
        AN(priv);
111 320
        *priv = malloc(ROT13_BUFSZ);
112 320
        if (*priv == NULL)
113 0
                return (-1);
114 320
        return (0);
115 320
}
116
117
static int v_matchproto_(vdp_bytes_f)
118 880
xyzzy_vfp_rot13_bytes(struct vdp_ctx *vdx, enum vdp_action act, void **priv,
119
    const void *ptr, ssize_t len)
120
{
121
        char *q;
122
        const char *pp;
123 880
        int i, j, retval = 0;
124
125 880
        CHECK_OBJ_NOTNULL(vdx, VDP_CTX_MAGIC);
126 880
        AN(priv);
127 880
        AN(*priv);
128 880
        if (len <= 0)
129 240
                return (VDP_bytes(vdx, act, ptr, len));
130 640
        AN(ptr);
131 640
        if (act != VDP_END)
132 400
                act = VDP_FLUSH;
133 640
        q = *priv;
134 640
        pp = ptr;
135
136 16320
        for (i = 0, j = 0; j < len; i++, j++) {
137 15680
                if (pp[j] >= 'A' && pp[j] <= 'Z')
138 1040
                        q[i] = (((pp[j] - 'A') + 13) % 26) + 'A';
139 14640
                else if (pp[j] >= 'a' && pp[j] <= 'z')
140 9520
                        q[i] = (((pp[j] - 'a') + 13) % 26) + 'a';
141
                else
142 5120
                        q[i] = pp[j];
143 15680
                if (i == ROT13_BUFSZ - 1 && j < len - 1) {
144 1600
                        retval = VDP_bytes(vdx, VDP_FLUSH, q, ROT13_BUFSZ);
145 1600
                        if (retval != 0)
146 0
                                return (retval);
147 1600
                        i = -1;
148 1600
                }
149 15680
        }
150 640
        if (i >= 0)
151 640
                retval = VDP_bytes(vdx, act, q, i);
152 640
        return (retval);
153 880
}
154
155
static int v_matchproto_(vdp_fini_f)
156 320
xyzzy_vfp_rot13_fini(struct vdp_ctx *vdc, void **priv)
157
{
158 320
        (void)vdc;
159 320
        AN(priv);
160 320
        free(*priv);
161 320
        *priv = NULL;
162 320
        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 4800
priv_pedantic_fini(VRT_CTX, void *priv)
198
{
199
        struct vdp_state_s *vdps;
200
201 4800
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
202 4800
        CAST_OBJ_NOTNULL(vdps, priv, VDP_STATE_MAGIC);
203
204 4800
        assert(vdps->state == VDPS_FINI);
205 4800
}
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 7680
xyzzy_pedantic_init(VRT_CTX, struct vdp_ctx *vdx, void **priv,
215
    struct objcore *oc)
216
{
217
        struct vdp_state_s *vdps;
218
        struct vmod_priv *p;
219
220 7680
        (void)oc;
221
222 7680
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
223 15040
        WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_STATE_MAGIC);
224 7680
        if (vdps == NULL)
225 320
                return (-1);
226 7360
        assert(vdps->state == VDPS_NULL);
227
228 7360
        p = VRT_priv_task(ctx, (void *)vdx);
229 7360
        if (p == NULL)
230 2560
                return (-1);
231 4800
        p->priv = vdps;
232 4800
        p->methods = priv_pedantic_methods;
233
234 4800
        AN(priv);
235 4800
        *priv = vdps;
236
237 4800
        vdps->state = VDPS_INIT;
238
239 4800
        return (0);
240 7680
}
241
242
static int v_matchproto_(vdp_bytes_f)
243 8598
xyzzy_pedantic_bytes(struct vdp_ctx *vdx, enum vdp_action act, void **priv,
244
    const void *ptr, ssize_t len)
245
{
246
        struct vdp_state_s *vdps;
247
248 8598
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_STATE_MAGIC);
249 8598
        assert(vdps->state >= VDPS_INIT);
250 8598
        assert(vdps->state < VDPS_END);
251
252 8598
        if (act == VDP_END)
253 2240
                vdps->state = VDPS_END;
254
        else
255 6358
                vdps->state = VDPS_BYTES;
256
257 8598
        return (VDP_bytes(vdx, act, ptr, len));
258
}
259
260
static int v_matchproto_(vdp_fini_f)
261 7680
xyzzy_pedantic_fini(struct vdp_ctx *vdx, void **priv)
262
{
263
        struct vdp_state_s *vdps;
264
265 7680
        (void) vdx;
266 7680
        AN(priv);
267 7680
        if (*priv == NULL)
268 2880
                return (0);
269 4800
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_STATE_MAGIC);
270 4800
        assert(vdps->state == VDPS_INIT || vdps->state == VDPS_END);
271 4800
        vdps->state = VDPS_FINI;
272
273 4800
        *priv = NULL;
274 4800
        return (0);
275 7680
}
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 200
xyzzy_author(VRT_CTX, VCL_ENUM person, VCL_ENUM someone)
288
{
289 200
        (void)someone;
290
291 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
292 200
        if (person == VENUM(phk))
293 80
                return ("Poul-Henning");
294 120
        assert(strcmp(person, "phk"));
295 120
        if (person == VENUM(des))
296 40
                return ("Dag-Erling");
297 80
        assert(strcmp(person, "des"));
298 80
        if (person == VENUM(kristian))
299 40
                return ("Kristian");
300 40
        assert(strcmp(person, "kristian"));
301 40
        if (person == VENUM(mithrandir))
302 40
                return ("Tollef");
303 0
        assert(strcmp(person, "mithrandir"));
304 0
        WRONG("Illegal VMOD enum");
305 200
}
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 80
PRIV_FINI(call, 0)
328 600
PRIV_FINI(task, 1)
329 120
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 80
xyzzy_test_priv_call(VRT_CTX, struct vmod_priv *priv)
336
{
337
338 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
339 80
        if (priv->priv == NULL) {
340 80
                priv->priv = strdup("BAR");
341 80
                priv->methods = xyzzy_test_priv_call_methods;
342 80
        } else {
343 0
                assert(priv->methods == xyzzy_test_priv_call_methods);
344 0
                assert(!strcmp(priv->priv, "BAR"));
345
        }
346 80
}
347
348
VCL_VOID v_matchproto_(td_debug_test_priv_task_get)
349 40
xyzzy_test_priv_task_get(VRT_CTX)
350
{
351
352 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
353 40
        AZ(VRT_priv_task_get(ctx, NULL));
354 40
}
355
356
VCL_STRING v_matchproto_(td_debug_test_priv_task)
357 1840
xyzzy_test_priv_task(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
358
{
359
360 1840
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
361 1840
        if (s == NULL || *s == '\0') {
362 1680
                mylog(ctx->vsl, SLT_Debug, "test_priv_task(%p) = %p (exists)",
363 840
                    priv, priv->priv);
364 1840
        } else if (priv->priv == NULL) {
365 600
                priv->priv = strdup(s);
366 600
                priv->methods = xyzzy_test_priv_task_methods;
367 1200
                mylog(ctx->vsl, SLT_Debug, "test_priv_task(%p) = %p (new)",
368 600
                    priv, priv->priv);
369 600
        } else {
370 800
                char *n = realloc(priv->priv,
371 400
                    strlen(priv->priv) + strlen(s) + 2);
372 400
                if (n == NULL)
373 0
                        return (NULL);
374 400
                strcat(n, " ");
375 400
                strcat(n, s);
376 400
                priv->priv = n;
377 800
                mylog(ctx->vsl, SLT_Debug, "test_priv_task(%p) = %p (update)",
378 400
                    priv, priv->priv);
379
        }
380 1840
        if (priv->priv != NULL)
381 1800
                assert(priv->methods == xyzzy_test_priv_task_methods);
382 1840
        return (priv->priv);
383 1840
}
384
385
VCL_STRING v_matchproto_(td_debug_test_priv_top)
386 960
xyzzy_test_priv_top(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
387
{
388
389 960
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
390 960
        if (priv->priv == NULL) {
391 120
                priv->priv = strdup(s);
392 120
                priv->methods = xyzzy_test_priv_top_methods;
393 120
        } else {
394 840
                assert(priv->methods == xyzzy_test_priv_top_methods);
395
        }
396 960
        return (priv->priv);
397
}
398
399
VCL_VOID v_matchproto_(td_debug_test_priv_vcl)
400 80
xyzzy_test_priv_vcl(VRT_CTX, struct vmod_priv *priv)
401
{
402
        struct priv_vcl *priv_vcl;
403
404 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
405 80
        AN(priv);
406 80
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
407 80
        AN(priv_vcl->foo);
408 80
        assert(!strcmp(priv_vcl->foo, "FOO"));
409 80
}
410
411
VCL_VOID v_matchproto_(td_debug_rot104)
412 40
xyzzy_rot104(VRT_CTX)
413
{
414
415 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
416
        // This should fail
417 40
        AN(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13));
418 40
}
419
420
VCL_VOID v_matchproto_(td_debug_rot52)
421 80
xyzzy_rot52(VRT_CTX, VCL_HTTP hp)
422
{
423
424 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
425 80
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
426
427 80
        http_PrintfHeader(hp, "Encrypted: ROT52");
428 80
}
429
430
VCL_STRING v_matchproto_(td_debug_argtest)
431 280
xyzzy_argtest(VRT_CTX, struct VARGS(argtest) *arg)
432
{
433
        char buf[100];
434
435 280
        AN(arg);
436 280
        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 280
        return (WS_Copy(ctx->ws, buf, -1));
440
}
441
442
VCL_INT v_matchproto_(td_debug_vre_limit)
443 80
xyzzy_vre_limit(VRT_CTX)
444
{
445 80
        (void)ctx;
446 80
        return (cache_param->vre_limits.match);
447
}
448
449
static void v_matchproto_(obj_event_f)
450 80
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 80
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
456 80
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
457 80
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
458 80
        switch (event) {
459 40
        case OEV_INSERT: what = "insert"; break;
460 40
        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 160
        VSL(SLT_Debug, NO_VXID, "Object Event: %s 0x%jx", what,
466 80
            (intmax_t)(uintptr_t)oc);
467 80
}
468
469
VCL_VOID v_matchproto_(td_debug_register_obj_events)
470 40
xyzzy_register_obj_events(VRT_CTX, struct vmod_priv *priv)
471
{
472
        struct priv_vcl *priv_vcl;
473
474 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
475 40
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
476 40
        AZ(priv_vcl->obj_cb);
477 40
        priv_vcl->obj_cb = ObjSubscribeEvents(obj_cb, priv_vcl,
478
                OEV_INSERT|OEV_EXPIRE);
479 40
        VSL(SLT_Debug, NO_VXID, "Subscribed to Object Events");
480 40
}
481
482
VCL_VOID v_matchproto_(td_debug_fail)
483 640
xyzzy_fail(VRT_CTX)
484
{
485
486 640
        VRT_fail(ctx, "Forced failure");
487 640
}
488
489
VCL_BOOL v_matchproto_(td_debug_fail2)
490 40
xyzzy_fail2(VRT_CTX)
491
{
492
493 40
        VRT_fail(ctx, "Forced failure");
494 40
        return (1);
495
}
496
497
static void v_matchproto_(vmod_priv_fini_f)
498 920
priv_vcl_fini(VRT_CTX, void *priv)
499
{
500
        struct priv_vcl *priv_vcl;
501
502 920
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
503 920
        AN(priv_vcl->foo);
504 920
        free(priv_vcl->foo);
505 920
        if (priv_vcl->obj_cb != 0) {
506 40
                ObjUnsubscribeEvents(&priv_vcl->obj_cb);
507 40
                VSLb(ctx->vsl, SLT_Debug, "Unsubscribed from Object Events");
508 40
        }
509 920
        AZ(priv_vcl->vclref_discard);
510 920
        AZ(priv_vcl->vclref_cold);
511 920
        FREE_OBJ(priv_vcl);
512 920
}
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 3680
event_load(VRT_CTX, struct vmod_priv *priv)
522
{
523
        struct priv_vcl *priv_vcl;
524
525 3680
        AN(ctx->msg);
526
527 3680
        loads++;
528
529 3680
        if (cache_param->nuke_limit == 42) {
530 40
                VSB_cat(ctx->msg, "nuke_limit is not the answer.");
531 40
                return (-1);
532
        }
533
534 3640
        ALLOC_OBJ(priv_vcl, PRIV_VCL_MAGIC);
535 3640
        AN(priv_vcl);
536 3640
        priv_vcl->foo = strdup("FOO");
537 3640
        AN(priv_vcl->foo);
538 3640
        priv->priv = priv_vcl;
539 3640
        priv->methods = priv_vcl_methods;
540
541 3640
        AZ(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13));
542 3640
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_pedantic));
543 3640
        return (0);
544 3680
}
545
546
VCL_VOID
547 40
xyzzy_vcl_prevent_cold(VRT_CTX, struct vmod_priv *priv)
548
{
549
        struct priv_vcl *priv_vcl;
550
        char buf[32];
551
552 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
553 40
        AN(priv);
554 40
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
555 40
        AZ(priv_vcl->vclref_cold);
556
557 40
        bprintf(buf, "vmod-debug ref on %s", VCL_Name(ctx->vcl));
558 40
        priv_vcl->vclref_cold = VRT_VCL_Prevent_Cold(ctx, buf);
559 40
}
560
561
VCL_VOID
562 40
xyzzy_vcl_allow_cold(VRT_CTX, struct vmod_priv *priv)
563
{
564
        struct priv_vcl *priv_vcl;
565
566 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
567 40
        AN(priv);
568 40
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
569 40
        AN(priv_vcl->vclref_cold);
570 40
        VRT_VCL_Allow_Cold(&priv_vcl->vclref_cold);
571 40
}
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 3280
event_warm(VRT_CTX, const struct vmod_priv *priv)
602
{
603
        struct priv_vcl *priv_vcl;
604
        char buf[32];
605 3280
        const char *vcl_name = VCL_Name(ctx->vcl);
606
607
        // Using VSLs for coverage
608 3280
        VSLs(SLT_Debug, NO_VXID, TOSTRANDS(2, vcl_name, ": VCL_EVENT_WARM"));
609
610 3280
        AN(ctx->msg);
611 3280
        if (cache_param->max_esi_depth == 42) {
612 120
                VSB_cat(ctx->msg, "max_esi_depth is not the answer.");
613 120
                return (-1);
614
        }
615
616 3160
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
617 3160
        AZ(priv_vcl->vclref_discard);
618
619 3160
        if (!priv_vcl->cold_be) {
620
                /* NB: set up a COOLING step unless we want a COLD backend. */
621 3160
                bprintf(buf, "vmod-debug ref on %s", VCL_Name(ctx->vcl));
622 3160
                priv_vcl->vclref_discard = VRT_VCL_Prevent_Discard(ctx, buf);
623 3160
        }
624
625 3160
        AZ(priv_vcl->be);
626 3160
        priv_vcl->be = VRT_AddDirector(ctx, empty_methods,
627
            NULL, "%s", "dir_warmcold");
628
629 3160
        return (0);
630 3280
}
631
632
static void*
633 40
cooldown_thread(void *priv)
634
{
635
        struct priv_vcl *priv_vcl;
636
637 40
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
638 40
        AN(priv_vcl->vclref_discard);
639
640 40
        VTIM_sleep(priv_vcl->vcl_discard_delay);
641 40
        VRT_VCL_Allow_Discard(&priv_vcl->vclref_discard);
642 40
        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 553
event_cold(VRT_CTX, const struct vmod_priv *priv)
661
{
662
        pthread_t thread;
663
        struct priv_vcl *priv_vcl;
664
665 553
        AZ(ctx->msg);
666
667 553
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
668
669 553
        VSL(SLT_Debug, NO_VXID, "%s: VCL_EVENT_COLD", VCL_Name(ctx->vcl));
670
671 553
        VRT_DelDirector(&priv_vcl->be);
672
673 553
        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 553
        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 553
        if (priv_vcl->vcl_discard_delay == 0.0) {
686 513
                AN(priv_vcl->vclref_discard);
687 513
                VRT_VCL_Allow_Discard(&priv_vcl->vclref_discard);
688 513
                return (0);
689
        }
690
691 40
        PTOK(pthread_create(&thread, NULL, cooldown_thread, priv_vcl));
692 40
        PTOK(pthread_detach(thread));
693 40
        return (0);
694 553
}
695
696
static int
697 920
event_discard(VRT_CTX, void *priv)
698
{
699
700 920
        (void)priv;
701
702 920
        AZ(ctx->msg);
703
704 920
        VRT_RemoveFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13);
705 920
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_pedantic);
706
707 920
        if (--loads)
708 600
                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 320
        if (vsc)
717 40
                VSC_debug_Destroy(&vsc_seg);
718
719 320
        return (0);
720 920
}
721
722
int v_matchproto_(vmod_event_f)
723 8433
xyzzy_event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
724
{
725
726 8433
        switch (e) {
727 3680
        case VCL_EVENT_LOAD:    return (event_load(ctx, priv));
728 3280
        case VCL_EVENT_WARM:    return (event_warm(ctx, priv));
729 553
        case VCL_EVENT_COLD:    return (event_cold(ctx, priv));
730 920
        case VCL_EVENT_DISCARD: return (event_discard(ctx, priv));
731 0
        default: WRONG("we should test all possible events");
732 0
        }
733 8433
}
734
735
VCL_VOID v_matchproto_(td_debug_vcl_discard_delay)
736 40
xyzzy_vcl_discard_delay(VRT_CTX, struct vmod_priv *priv, VCL_DURATION delay)
737
{
738
        struct priv_vcl *priv_vcl;
739
740 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
741 40
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
742 40
        assert(delay > 0.0);
743 40
        priv_vcl->vcl_discard_delay = delay;
744 40
}
745
746
VCL_VOID v_matchproto_(td_debug_test_probe)
747 0
xyzzy_test_probe(VRT_CTX, VCL_PROBE probe, VCL_PROBE same)
748
{
749
750 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
751 0
        CHECK_OBJ_NOTNULL(probe, VRT_BACKEND_PROBE_MAGIC);
752 0
        CHECK_OBJ_ORNULL(same, VRT_BACKEND_PROBE_MAGIC);
753 0
        AZ(same == NULL || probe == same);
754 0
}
755
756
VCL_VOID
757 40
xyzzy_vsc_new(VRT_CTX)
758
{
759 40
        (void)ctx;
760 40
        PTOK(pthread_mutex_lock(&vsc_mtx));
761 40
        if (vsc == NULL) {
762 40
                AZ(vsc_seg);
763 40
                vsc = VSC_debug_New(NULL, &vsc_seg, "");
764 40
        }
765 40
        AN(vsc);
766 40
        AN(vsc_seg);
767 40
        PTOK(pthread_mutex_unlock(&vsc_mtx));
768 40
}
769
770
VCL_VOID
771 40
xyzzy_vsc_count(VRT_CTX, VCL_INT cnt)
772
{
773 40
        (void)ctx;
774 40
        AN(vsc);
775 40
        vsc->count += cnt;
776 40
}
777
778
VCL_VOID
779 0
xyzzy_vsc_destroy(VRT_CTX)
780
{
781 0
        (void)ctx;
782 0
        PTOK(pthread_mutex_lock(&vsc_mtx));
783 0
        if (vsc != NULL) {
784 0
                AN(vsc_seg);
785 0
                VSC_debug_Destroy(&vsc_seg);
786 0
        }
787 0
        AZ(vsc_seg);
788 0
        vsc = NULL;
789 0
        PTOK(pthread_mutex_unlock(&vsc_mtx));
790 0
}
791
792
struct xyzzy_debug_concat {
793
        unsigned        magic;
794
#define CONCAT_MAGIC 0x6b746493
795
        VCL_STRING      s;
796
};
797
798
VCL_VOID
799 160
xyzzy_concat__init(VRT_CTX, struct xyzzy_debug_concat **concatp,
800
                   const char *vcl_name, VCL_STRANDS s)
801
{
802
        struct xyzzy_debug_concat *concat;
803 160
        size_t sz = 0;
804
        char *p;
805
806 160
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
807 160
        AN(concatp);
808 160
        AZ(*concatp);
809 160
        AN(vcl_name);
810
811 160
        ALLOC_OBJ(concat, CONCAT_MAGIC);
812 160
        AN(concat);
813 160
        *concatp = concat;
814
815 480
        for (int i = 0; i < s->n; i++)
816 640
                if (s->p[i] != NULL)
817 320
                        sz += strlen(s->p[i]);
818 160
        p = malloc(sz + 1);
819 160
        AN(p);
820 160
        (void)VRT_Strands(p, sz + 1, s);
821 160
        concat->s = p;
822 160
}
823
824
VCL_VOID
825 0
xyzzy_concat__fini(struct xyzzy_debug_concat **concatp)
826
{
827
        struct xyzzy_debug_concat *concat;
828
829
830 0
        TAKE_OBJ_NOTNULL(concat, concatp, CONCAT_MAGIC);
831 0
        free(TRUST_ME(concat->s));
832 0
        FREE_OBJ(concat);
833 0
}
834
835
VCL_STRING
836 80
xyzzy_concat_get(VRT_CTX, struct xyzzy_debug_concat *concat)
837
{
838 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
839 80
        CHECK_OBJ_NOTNULL(concat, CONCAT_MAGIC);
840 80
        return (concat->s);
841
}
842
843
VCL_STRING
844 320
xyzzy_concatenate(VRT_CTX, VCL_STRANDS s)
845
{
846
        VCL_STRING r;
847
848 320
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
849 320
        r = VRT_StrandsWS(ctx->ws, NULL, s);
850 320
        if (r != NULL && *r != '\0')
851 240
                AN(WS_Allocated(ctx->ws, r, strlen(r) + 1));
852 320
        return (r);
853
}
854
855
VCL_STRING
856 320
xyzzy_collect(VRT_CTX, VCL_STRANDS s)
857
{
858
        VCL_STRING r;
859
860 320
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
861 320
        r = VRT_STRANDS_string(ctx, s);
862 320
        if (r != NULL && *r != '\0')
863 240
                AN(WS_Allocated(ctx->ws, r, strlen(r) + 1));
864 320
        return (r);
865
}
866
867
/* cf. VRT_SetHdr() */
868
VCL_VOID
869 320
xyzzy_sethdr(VRT_CTX, VCL_HEADER hdr, VCL_STRANDS s)
870
{
871
        struct http *hp;
872
        const char *b;
873
874 320
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
875 320
        if (hdr == NULL) {
876 0
                VRT_fail(ctx, "debug.sethdr(): header argument is NULL");
877 0
                return;
878
        }
879 320
        hp = VRT_selecthttp(ctx, hdr->where);
880 320
        if (hp == NULL) {
881 0
                VRT_fail(ctx, "debug.sethdr(): header argument "
882
                    "can not be used here");
883 0
                return;
884
        }
885 320
        AN(hdr->what);
886 320
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
887 320
        if (s->n == 0) {
888 0
                http_Unset(hp, hdr->what);
889 0
        } else {
890 320
                b = VRT_StrandsWS(hp->ws, hdr->what + 1, s);
891 320
                if (b == NULL) {
892 0
                        VSLbs(ctx->vsl, SLT_LostHeader,
893 0
                            TOSTRAND(hdr->what + 1));
894 0
                } else {
895 320
                        if (*b != '\0')
896 320
                                AN(WS_Allocated(hp->ws, b, strlen(b) + 1));
897 320
                        http_Unset(hp, hdr->what);
898 320
                        http_SetHeader(hp, b);
899
                }
900
        }
901 320
}
902
903
void
904 5520
mylog(struct vsl_log *vsl, enum VSL_tag_e tag,  const char *fmt, ...)
905
{
906
        va_list ap;
907
908 5520
        va_start(ap, fmt);
909 5520
        if (vsl != NULL)
910 4760
                VSLbv(vsl, tag, fmt, ap);
911
        else
912 760
                VSLv(tag, NO_VXID, fmt, ap);
913 5520
        va_end(ap);
914 5520
}
915
916
VCL_DURATION
917 160
xyzzy_priv_perf(VRT_CTX, VCL_INT size, VCL_INT rounds)
918
{
919
        vtim_mono t0, t1;
920
        vtim_dur d;
921
        struct vmod_priv *p;
922
        VCL_INT s, r;
923 160
        uintptr_t check = 0;
924
925 160
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
926
927 44600
        for (s = 1; s <= size; s++) {
928 44440
                p = VRT_priv_task(ctx, (void *)(uintptr_t)s);
929 44440
                if (p == NULL) {
930 0
                        VRT_fail(ctx, "no priv task - out of ws?");
931 0
                        return (-1.0);
932
                }
933 44440
                p->priv = NULL;
934 44440
        }
935
936 160
        t0 = VTIM_mono();
937 1600160
        for (r = 0; r < rounds; r++) {
938 446000000
                for (s = 1; s <= size; s++) {
939 444400000
                        p = VRT_priv_task_get(ctx, (void *)(uintptr_t)s);
940 444400000
                        AN(p);
941 444400000
                        check += (uintptr_t)p->priv;
942 444400000
                        p->priv = (void *)(uintptr_t)(s * rounds + r);
943 444400000
                }
944 1600000
        }
945 160
        t1 = VTIM_mono();
946
947 160
        d = (t1 - t0) * 1e9 / ((double)size * (double)rounds);
948
949 320
        mylog(ctx->vsl, SLT_Debug,
950
             "perf size %jd rounds %jd time %.1fns check %jd",
951 160
             (intmax_t)size, (intmax_t)rounds, d, (uintmax_t)check);
952
953 160
        return (d);
954 160
}
955
956
VCL_STRANDS
957 160
xyzzy_return_strands(VRT_CTX, VCL_STRANDS strand)
958
{
959
960 160
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
961 160
        VSLbs(ctx->vsl, SLT_Debug, strand);
962 160
        return (strand);
963
}
964
965
VCL_VOID
966 80
xyzzy_vsl_flush(VRT_CTX)
967
{
968 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
969 80
        VSL_Flush(ctx->vsl, 0);
970 80
}
971
972
/*---------------------------------------------------------------------*/
973
974
static const struct vcf_return * v_matchproto_(vcf_func_f)
975 560
xyzzy_catflap_simple(struct req *req, struct objcore **oc,
976
    struct objcore **oc_exp, int state)
977
{
978
979 560
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
980 560
        CHECK_OBJ_NOTNULL(req->vcf, VCF_MAGIC);
981 560
        assert(req->vcf->func == xyzzy_catflap_simple);
982
983 560
        (void)oc;
984 560
        (void)oc_exp;
985 560
        if (state == 0) {
986 160
                if (req->vcf->priv == VENUM(first))
987 40
                        return (VCF_HIT);
988 120
                if (req->vcf->priv == VENUM(miss))
989 120
                        return (VCF_MISS);
990 0
                WRONG("Shouldn't get here");
991 0
        }
992 400
        return (VCF_DEFAULT);
993 560
}
994
995
static const struct vcf_return * v_matchproto_(vcf_func_f)
996 240
xyzzy_catflap_last(struct req *req, struct objcore **oc,
997
    struct objcore **oc_exp, int state)
998
{
999
1000 240
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1001 240
        CHECK_OBJ_NOTNULL(req->vcf, VCF_MAGIC);
1002 240
        assert(req->vcf->func == xyzzy_catflap_last);
1003
1004 240
        (void)oc_exp;
1005 240
        if (state == 0) {
1006 160
                AN(oc);
1007 160
                CHECK_OBJ_NOTNULL(*oc, OBJCORE_MAGIC);
1008 160
                req->vcf->priv = *oc;
1009 160
                return (VCF_CONTINUE);
1010
        }
1011 80
        if (state == 1) {
1012 40
                AN(oc);
1013 40
                if (req->vcf->priv != NULL)
1014 40
                        CAST_OBJ_NOTNULL(*oc, req->vcf->priv, OBJCORE_MAGIC);
1015 40
                return (VCF_CONTINUE);
1016
        }
1017 40
        return (VCF_DEFAULT);
1018 240
}
1019
1020
VCL_VOID
1021 320
xyzzy_catflap(VRT_CTX, VCL_ENUM type)
1022
{
1023
        struct req *req;
1024
1025 320
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1026 320
        req = ctx->req;
1027 320
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
1028 320
        XXXAZ(req->vcf);
1029 640
        WS_TASK_ALLOC_OBJ(ctx, req->vcf, VCF_MAGIC);
1030 320
        if (req->vcf == NULL)
1031 0
                return;
1032 320
        if (type == VENUM(first) || type == VENUM(miss)) {
1033 280
                req->vcf->func = xyzzy_catflap_simple;
1034 280
                req->vcf->priv = TRUST_ME(type);
1035 320
        } else if (type == VENUM(last)) {
1036 40
                req->vcf->func = xyzzy_catflap_last;
1037 40
        } else {
1038 0
                WRONG("Wrong VENUM");
1039
        }
1040 320
}
1041
1042
VCL_BYTES
1043 0
xyzzy_stk(VRT_CTX)
1044
{
1045 0
        const VCL_BYTES max = 100 * 1024 * 1024;
1046
        const char *a, *b;
1047
        VCL_BYTES r;
1048
1049 0
        a = TRUST_ME(&b);
1050 0
        b = TRUST_ME(ctx->req->wrk);
1051 0
        b += sizeof(*ctx->req->wrk);
1052
1053 0
        if (b > a && (r = b - a) < max)
1054 0
                return (r);
1055 0
        if (a > b && (r = a - b) < max)
1056 0
                return (r);
1057
1058 0
        return (0);
1059 0
}
1060
1061
VCL_VOID
1062 320
xyzzy_sndbuf(VRT_CTX, VCL_BYTES arg)
1063
{
1064 320
        int fd = -1, oldbuf, newbuf, buflen;
1065 320
        socklen_t intlen = sizeof(int);
1066
1067 320
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1068
1069 320
        if (ctx->bo) {
1070 0
                CHECK_OBJ(ctx->bo, BUSYOBJ_MAGIC);
1071 0
                INCOMPL();
1072 0
        }
1073 320
        else if (ctx->req) {
1074 320
                CHECK_OBJ(ctx->req, REQ_MAGIC);
1075 320
                CHECK_OBJ(ctx->req->sp, SESS_MAGIC);
1076 320
                fd = ctx->req->sp->fd;
1077 320
        }
1078
        else {
1079 0
                VRT_fail(ctx, "debug.sndbuf() called outside a transaction.");
1080 0
                return;
1081
        }
1082
1083 320
        xxxassert(fd >= 0);
1084
1085 320
        if (arg > INT_MAX)
1086 0
                buflen = INT_MAX;
1087 320
        else if (arg <= 0)
1088 0
                buflen = 0;
1089
        else
1090 320
                buflen = (int)arg;
1091
1092 320
        oldbuf = 0;
1093 320
        AZ(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &oldbuf, &intlen));
1094
1095 320
        newbuf = buflen;
1096 320
        AZ(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &newbuf, intlen));
1097 320
        AZ(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &newbuf, &intlen));
1098
1099 320
        AN(ctx->vsl);
1100 640
        VSLb(ctx->vsl, SLT_Debug, "SO_SNDBUF fd=%d old=%d new=%d actual=%d",
1101 320
            fd, oldbuf, buflen, newbuf);
1102 320
}
1103
1104
VCL_VOID
1105 560
xyzzy_store_ip(VRT_CTX, VCL_IP ip)
1106
{
1107
        struct vmod_priv *priv;
1108
1109 560
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1110
1111 560
        priv = VRT_priv_task(ctx, &store_ip_token);
1112 560
        if (priv == NULL) {
1113 0
                VRT_fail(ctx, "no priv task - out of ws?");
1114 0
                return;
1115
        }
1116
1117 560
        AZ(priv->methods);
1118 560
        assert(VSA_Sane(ip));
1119 560
        priv->priv = TRUST_ME(ip);
1120 560
}
1121
1122
VCL_IP
1123 1120
xyzzy_get_ip(VRT_CTX)
1124
{
1125
        struct vmod_priv *priv;
1126
        VCL_IP ip;
1127
1128 1120
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1129
1130 1120
        priv = VRT_priv_task_get(ctx, &store_ip_token);
1131 1120
        AN(priv);
1132 1120
        AZ(priv->methods);
1133
1134 1120
        ip = priv->priv;
1135 1120
        assert(VSA_Sane(ip));
1136 1120
        return (ip);
1137
}
1138
1139
/*---------------------------------------------------------------------*/
1140
1141
struct VPFX(debug_director) {
1142
        unsigned                        magic;
1143
#define VMOD_DEBUG_DIRECTOR_MAGIC       0x66b9ff3d
1144
        VCL_BACKEND                     dir;
1145
};
1146
1147
/* XXX more callbacks ? */
1148
static vdi_healthy_f vmod_debug_director_healthy;
1149
static vdi_resolve_f vmod_debug_director_resolve;
1150
1151
static const struct vdi_methods vmod_debug_director_methods[1] = {{
1152
        .magic =        VDI_METHODS_MAGIC,
1153
        .type =         "debug.director",
1154
        .resolve =      vmod_debug_director_resolve,
1155
        .healthy =      vmod_debug_director_healthy
1156
}};
1157
1158
VCL_VOID v_matchproto_(td_xyzzy_debug_director__init)
1159 40
xyzzy_director__init(VRT_CTX, struct VPFX(debug_director) **dp,
1160
    const char *vcl_name)
1161
{
1162
        struct VPFX(debug_director) *d;
1163
1164 40
        AN(dp);
1165 40
        AZ(*dp);
1166 40
        ALLOC_OBJ(d, VMOD_DEBUG_DIRECTOR_MAGIC);
1167 40
        AN(d);
1168
1169 40
        *dp = d;
1170 80
        d->dir = VRT_AddDirector(ctx, vmod_debug_director_methods, d,
1171 40
            "%s", vcl_name);
1172 40
}
1173
1174
VCL_VOID v_matchproto_(td_xyzzy_debug_director__fini)
1175 0
xyzzy_director__fini(struct VPFX(debug_director) **dp)
1176
{
1177
        struct VPFX(debug_director) *d;
1178
1179 0
        TAKE_OBJ_NOTNULL(d, dp, VMOD_DEBUG_DIRECTOR_MAGIC);
1180 0
        VRT_DelDirector(&d->dir);
1181 0
        FREE_OBJ(d);
1182 0
}
1183
1184
VCL_BACKEND v_matchproto_(td_xyzzy_debug_director_fail)
1185 80
xyzzy_director_fail(VRT_CTX, struct VPFX(debug_director) *d)
1186
{
1187 80
        CHECK_OBJ_NOTNULL(d, VMOD_DEBUG_DIRECTOR_MAGIC);
1188 80
        (void) ctx;
1189
1190 80
        return (d->dir);
1191
}
1192
1193
static VCL_BOOL v_matchproto_(vdi_healthy_f)
1194 80
vmod_debug_director_healthy(VRT_CTX, VCL_BACKEND dir, VCL_TIME *changed)
1195
{
1196 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1197
1198 80
        (void) dir;
1199 80
        (void) changed;
1200
1201 80
        VRT_fail(ctx, "fail");
1202 80
        return (1);
1203
}
1204
1205
static VCL_BACKEND v_matchproto_(vdi_resolve_f)
1206 40
vmod_debug_director_resolve(VRT_CTX, VCL_BACKEND dir)
1207
{
1208 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1209
1210 40
        (void) dir;
1211
1212 40
        VRT_fail(ctx, "fail");
1213 40
        return (NULL);
1214
}
1215
1216
VCL_STRING v_matchproto_(td_xyzzy_debug_client_ip)
1217 40
xyzzy_client_ip(VRT_CTX)
1218
{
1219 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1220
1221 40
        return (SES_Get_String_Attr(ctx->sp, SA_CLIENT_IP));
1222
}
1223
1224
VCL_STRING v_matchproto_(td_xyzzy_debug_client_port)
1225 40
xyzzy_client_port(VRT_CTX)
1226
{
1227 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1228
1229 40
        return (SES_Get_String_Attr(ctx->sp, SA_CLIENT_PORT));
1230
}
1231
1232
static void * fail_magic = &fail_magic;
1233
1234
static void
1235 120
fail_f(VRT_CTX, void *priv)
1236
{
1237
1238 120
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1239 120
        assert(priv == fail_magic);
1240
1241 120
        VRT_fail(ctx, "thou shalt not fini");
1242 120
}
1243
1244
static const struct vmod_priv_methods xyzzy_fail_task_fini_methods[1] = {{
1245
        .magic = VMOD_PRIV_METHODS_MAGIC,
1246
        .type = "debug_fail_task_fini",
1247
        .fini = fail_f
1248
}};
1249
1250
VCL_VOID v_matchproto_(td_xyzzy_debug_fail_task_fini)
1251 160
xyzzy_fail_task_fini(VRT_CTX)
1252
{
1253
        struct vmod_priv *p;
1254
1255 160
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1256
1257 160
        p = VRT_priv_task(ctx, &fail_task_fini_token);
1258 160
        if (p == NULL) {
1259 0
                VRT_fail(ctx, "no priv task - out of ws?");
1260 0
                return;
1261
        }
1262
1263 160
        if (p->priv != NULL) {
1264 0
                assert(p->priv == fail_magic);
1265 0
                assert(p->methods == xyzzy_fail_task_fini_methods);
1266 0
                return;
1267
        }
1268
1269 160
        p->priv = fail_magic;
1270 160
        p->methods = xyzzy_fail_task_fini_methods;
1271 160
}
1272
1273
VCL_VOID v_matchproto_(td_xyzzy_debug_ok_task_fini)
1274 40
xyzzy_ok_task_fini(VRT_CTX)
1275
{
1276
        struct vmod_priv *p;
1277
1278 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1279
1280 40
        p = VRT_priv_task(ctx, &fail_task_fini_token);
1281 40
        if (p == NULL) {
1282 0
                VRT_fail(ctx, "no priv task - out of ws?");
1283 0
                return;
1284
        }
1285
1286 40
        p->priv = NULL;
1287 40
        p->methods = NULL;
1288 40
}
1289
1290
VCL_STRING v_matchproto_(td_xyzzy_debug_re_quote)
1291 240
xyzzy_re_quote(VRT_CTX, VCL_STRING s)
1292
{
1293
        struct vsb vsb[1];
1294
        char *q;
1295
1296 240
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1297 240
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
1298 240
        WS_VSB_new(vsb, ctx->ws);
1299 240
        VRE_quote(vsb, s);
1300 240
        q = WS_VSB_finish(vsb, ctx->ws, NULL);
1301 240
        if (q == NULL)
1302 0
                WS_MarkOverflow(ctx->ws);
1303 240
        return (q);
1304
}
1305
1306
VCL_STRING v_matchproto_(td_xyzzy_priv_task_with_option)
1307 120
xyzzy_priv_task_with_option(VRT_CTX, struct VARGS(priv_task_with_option) *args)
1308
{
1309
1310 120
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1311 120
        AN(args->priv);
1312 120
        if (args->priv->priv == NULL && args->valid_opt)
1313 40
                args->priv->priv = WS_Copy(ctx->ws, args->opt, -1);
1314 120
        return (args->priv->priv);
1315
}
1316
1317
VCL_BOOL v_matchproto_(td_xyzzy_validhdr)
1318 80
xyzzy_validhdr(VRT_CTX, VCL_STRANDS s)
1319
{
1320 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1321 80
        return (VRT_ValidHdr(ctx, s));
1322
}
1323
1324
VCL_REGEX v_matchproto_(td_xyzzy_regex)
1325 240
xyzzy_just_return_regex(VRT_CTX, VCL_REGEX r)
1326
{
1327
1328 240
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1329 240
        AN(r);
1330 240
        return (r);
1331
}
1332
1333
/*---------------------------------------------------------------------*/
1334
1335
VCL_VOID v_matchproto_(td_xyzzy_call)
1336 480
xyzzy_call(VRT_CTX, VCL_SUB sub)
1337
{
1338 480
        VRT_call(ctx, sub);
1339 480
}
1340
1341
VCL_STRING v_matchproto_(td_xyzzy_check_call)
1342 40
xyzzy_check_call(VRT_CTX, VCL_SUB sub)
1343
{
1344 40
        return (VRT_check_call(ctx, sub));
1345
}
1346
1347
/* the next two are to test WRONG vmod behavior:
1348
 * holding a VCL_SUB reference across vcls
1349
 */
1350
1351
static VCL_SUB wrong = NULL;
1352
1353
VCL_VOID v_matchproto_(td_xyzzy_bad_memory)
1354 0
xyzzy_bad_memory(VRT_CTX, VCL_SUB sub)
1355
{
1356 0
        (void) ctx;
1357
1358 0
        wrong = sub;
1359 0
}
1360
1361
VCL_SUB v_matchproto_(td_xyzzy_total_recall)
1362 0
xyzzy_total_recall(VRT_CTX)
1363
{
1364 0
        (void) ctx;
1365
1366 0
        return (wrong);
1367
}
1368
1369
/*---------------------------------------------------------------------*/
1370
1371
struct VPFX(debug_caller) {
1372
       unsigned        magic;
1373
#define DEBUG_CALLER_MAGIC 0xb47f3449
1374
       VCL_SUB         sub;
1375
};
1376
1377
VCL_VOID v_matchproto_(td_xyzzy_debug_caller__init)
1378 80
xyzzy_caller__init(VRT_CTX, struct VPFX(debug_caller) **callerp,
1379
    const char *name, VCL_SUB sub)
1380
{
1381
        struct VPFX(debug_caller) *caller;
1382
1383 80
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1384 80
        AN(callerp);
1385 80
        AZ(*callerp);
1386 80
        AN(name);
1387 80
        AN(sub);
1388
1389 80
        ALLOC_OBJ(caller, DEBUG_CALLER_MAGIC);
1390 80
        AN(caller);
1391 80
        *callerp = caller;
1392 80
        caller->sub = sub;
1393 80
}
1394
1395
VCL_VOID v_matchproto_(td_xyzzy_debug_caller__fini)
1396 0
xyzzy_caller__fini(struct VPFX(debug_caller) **callerp)
1397
{
1398
        struct VPFX(debug_caller) *caller;
1399
1400 0
        if (callerp == NULL || *callerp == NULL)
1401 0
                return;
1402 0
        TAKE_OBJ_NOTNULL(caller, callerp, DEBUG_CALLER_MAGIC);
1403 0
        FREE_OBJ(caller);
1404 0
}
1405
1406
VCL_VOID v_matchproto_(td_xyzzy_debug_caller_call)
1407 40
xyzzy_caller_call(VRT_CTX, struct VPFX(debug_caller) *caller)
1408
{
1409 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1410 40
        CHECK_OBJ_NOTNULL(caller, DEBUG_CALLER_MAGIC);
1411 40
        AN(caller->sub);
1412
1413 40
        VRT_call(ctx, caller->sub);
1414 40
}
1415
1416
VCL_SUB v_matchproto_(td_xyzzy_debug_caller_sub)
1417 40
xyzzy_caller_xsub(VRT_CTX, struct VPFX(debug_caller) *caller)
1418
{
1419 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1420 40
        CHECK_OBJ_NOTNULL(caller, DEBUG_CALLER_MAGIC);
1421 40
        AN(caller->sub);
1422
1423 40
        return (caller->sub);
1424
}