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