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