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