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