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