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