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