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