varnish-cache/lib/libvmod_debug/vmod_debug.c
1
/*-
2
 * Copyright (c) 2012-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
29
#include "config.h"
30
31
#include <errno.h>
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 "vtim.h"
43
#include "vcc_if.h"
44
#include "VSC_debug.h"
45
46
struct priv_vcl {
47
        unsigned                magic;
48
#define PRIV_VCL_MAGIC          0x8E62FA9D
49
        char                    *foo;
50
        uintptr_t               obj_cb;
51
        struct vcl              *vcl;
52
        struct vclref           *vclref;
53
};
54
55
static VCL_DURATION vcl_release_delay = 0.0;
56
57
static pthread_mutex_t vsc_mtx = PTHREAD_MUTEX_INITIALIZER;
58
static struct vsc_seg *vsc_seg = NULL;
59
static struct VSC_debug *vsc = NULL;
60
61
/**********************************************************************/
62
63
static enum vfp_status v_matchproto_(vfp_pull_f)
64 4
xyzzy_rot13_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
65
    ssize_t *lp)
66
{
67
        enum vfp_status vp;
68
        char *q;
69
        ssize_t l;
70
71
        (void)vfe;
72 4
        vp = VFP_Suck(vc, p, lp);
73 4
        if (vp == VFP_ERROR)
74 0
                return (vp);
75 4
        q = p;
76 116
        for (l = 0; l < *lp; l++, q++) {
77 112
                if (*q >= 'A' && *q <= 'Z')
78 16
                        *q = (((*q - 'A') + 13) % 26) + 'A';
79 112
                if (*q >= 'a' && *q <= 'z')
80 76
                        *q = (((*q - 'a') + 13) % 26) + 'a';
81
        }
82 4
        return (vp);
83
}
84
85
static const struct vfp xyzzy_rot13 = {
86
        .name = "rot13",
87
        .pull = xyzzy_rot13_pull,
88
};
89
90
/**********************************************************************/
91
92
VCL_STRING v_matchproto_(td_debug_author)
93 20
xyzzy_author(VRT_CTX, VCL_ENUM person, VCL_ENUM someone)
94
{
95
        (void)someone;
96
97 20
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
98 20
        if (person == xyzzy_enum_phk)
99 8
                return ("Poul-Henning");
100 12
        assert(strcmp(person, "phk"));
101 12
        if (person == xyzzy_enum_des)
102 4
                return ("Dag-Erling");
103 8
        assert(strcmp(person, "des"));
104 8
        if (person == xyzzy_enum_kristian)
105 4
                return ("Kristian");
106 4
        assert(strcmp(person, "kristian"));
107 4
        if (person == xyzzy_enum_mithrandir)
108 4
                return ("Tollef");
109 0
        assert(strcmp(person, "mithrandir"));
110 0
        WRONG("Illegal VMOD enum");
111
}
112
113
VCL_VOID v_matchproto_(td_debug_test_priv_call)
114 8
xyzzy_test_priv_call(VRT_CTX, struct vmod_priv *priv)
115
{
116
117 8
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
118 8
        if (priv->priv == NULL) {
119 8
                priv->priv = strdup("BAR");
120 8
                priv->free = free;
121
        } else {
122 0
                assert(!strcmp(priv->priv, "BAR"));
123
        }
124 8
}
125
126
static void
127 52
priv_task_free(void *ptr)
128
{
129 52
        AN(ptr);
130 52
        VSL(SLT_Debug, 0, "priv_task_free(%p)", ptr);
131 52
        free(ptr);
132 52
}
133
134
VCL_STRING v_matchproto_(td_debug_test_priv_task)
135 192
xyzzy_test_priv_task(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
136
{
137
138 192
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
139 192
        if (s == NULL || *s == '\0') {
140 112
                VSL(SLT_Debug, 0, "test_priv_task(%p) = %p (exists)",
141
                    priv, priv->priv);
142 80
        } else if (priv->priv == NULL) {
143 52
                priv->priv = strdup(s);
144 52
                priv->free = priv_task_free;
145 52
                VSL(SLT_Debug, 0, "test_priv_task(%p) = %p (new)",
146
                    priv, priv->priv);
147
        } else {
148 28
                char *n = realloc(priv->priv,
149 28
                    strlen(priv->priv) + strlen(s) + 2);
150 28
                if (n == NULL)
151 0
                        return NULL;
152 28
                strcat(n, " ");
153 28
                strcat(n, s);
154 28
                priv->priv = n;
155 28
                VSL(SLT_Debug, 0, "test_priv_task(%p) = %p (update)",
156
                    priv, priv->priv);
157
        }
158 192
        if (priv->priv != NULL)
159 192
                assert(priv->free == priv_task_free);
160 192
        return (priv->priv);
161
}
162
163
VCL_STRING v_matchproto_(td_debug_test_priv_top)
164 64
xyzzy_test_priv_top(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
165
{
166
167 64
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
168 64
        if (priv->priv == NULL) {
169 8
                priv->priv = strdup(s);
170 8
                priv->free = free;
171
        }
172 64
        return (priv->priv);
173
}
174
175
VCL_VOID v_matchproto_(td_debug_test_priv_vcl)
176 8
xyzzy_test_priv_vcl(VRT_CTX, struct vmod_priv *priv)
177
{
178
        struct priv_vcl *priv_vcl;
179
180 8
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
181 8
        AN(priv);
182 8
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
183 8
        AN(priv_vcl->foo);
184 8
        assert(!strcmp(priv_vcl->foo, "FOO"));
185 8
}
186
187
VCL_VOID v_matchproto_(td_debug_rot52)
188 8
xyzzy_rot52(VRT_CTX, VCL_HTTP hp)
189
{
190
191 8
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
192 8
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
193
194 8
        http_PrintfHeader(hp, "Encrypted: ROT52");
195 8
}
196
197
VCL_STRING v_matchproto_(td_debug_argtest)
198 28
xyzzy_argtest(VRT_CTX, struct xyzzy_argtest_arg *arg)
199
{
200
        char buf[100];
201
202 28
        AN(arg);
203 28
        bprintf(buf, "%s %g %s %s %jd %d %s",
204
            arg->one, arg->two, arg->three, arg->comma, (intmax_t)arg->four,
205
            arg->valid_opt, arg->valid_opt ? arg->opt : "<undef>");
206 28
        return (WS_Copy(ctx->ws, buf, -1));
207
}
208
209
VCL_INT v_matchproto_(td_debug_vre_limit)
210 8
xyzzy_vre_limit(VRT_CTX)
211
{
212
        (void)ctx;
213 8
        return (cache_param->vre_limits.match);
214
}
215
216
static void v_matchproto_(obj_event_f)
217 8
obj_cb(struct worker *wrk, void *priv, struct objcore *oc, unsigned event)
218
{
219
        const struct priv_vcl *priv_vcl;
220
        const char *what;
221
222 8
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
223 8
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
224 8
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
225 8
        switch (event) {
226 4
        case OEV_INSERT: what = "insert"; break;
227 4
        case OEV_EXPIRE: what = "expire"; break;
228 0
        default: WRONG("Wrong object event");
229
        }
230
231
        /* We cannot trust %p to be 0x... format as expected by m00021.vtc */
232 8
        VSL(SLT_Debug, 0, "Object Event: %s 0x%jx", what,
233
            (intmax_t)(uintptr_t)oc);
234 8
}
235
236
VCL_VOID v_matchproto_(td_debug_register_obj_events)
237 4
xyzzy_register_obj_events(VRT_CTX, struct vmod_priv *priv)
238
{
239
        struct priv_vcl *priv_vcl;
240
241 4
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
242 4
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
243 4
        AZ(priv_vcl->obj_cb);
244 4
        priv_vcl->obj_cb = ObjSubscribeEvents(obj_cb, priv_vcl,
245
                OEV_INSERT|OEV_EXPIRE);
246 4
        VSL(SLT_Debug, 0, "Subscribed to Object Events");
247 4
}
248
249
VCL_VOID v_matchproto_(td_debug_fail)
250 56
xyzzy_fail(VRT_CTX)
251
{
252
253 56
        VRT_fail(ctx, "Forced failure");
254 56
}
255
256
static void v_matchproto_(vmod_priv_free_f)
257 44
priv_vcl_free(void *priv)
258
{
259
        struct priv_vcl *priv_vcl;
260
261 44
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
262 44
        AN(priv_vcl->foo);
263 44
        free(priv_vcl->foo);
264 44
        if (priv_vcl->obj_cb != 0) {
265 4
                ObjUnsubscribeEvents(&priv_vcl->obj_cb);
266 4
                VSL(SLT_Debug, 0, "Unsubscribed from Object Events");
267
        }
268 44
        AZ(priv_vcl->vcl);
269 44
        AZ(priv_vcl->vclref);
270 44
        FREE_OBJ(priv_vcl);
271 44
        AZ(priv_vcl);
272 44
}
273
274
static int
275 236
event_load(VRT_CTX, struct vmod_priv *priv)
276
{
277
        struct priv_vcl *priv_vcl;
278
279 236
        AN(ctx->msg);
280 236
        if (cache_param->nuke_limit == 42) {
281 4
                VSB_printf(ctx->msg, "nuke_limit is not the answer.");
282 4
                return (-1);
283
        }
284
285 232
        ALLOC_OBJ(priv_vcl, PRIV_VCL_MAGIC);
286 232
        AN(priv_vcl);
287 232
        priv_vcl->foo = strdup("FOO");
288 232
        AN(priv_vcl->foo);
289 232
        priv->priv = priv_vcl;
290 232
        priv->free = priv_vcl_free;
291
292
        /*
293
         * NB: This is a proof of concept, until we decide what the real
294
         * API should look like, do NOT do this anywhere else.
295
         */
296 232
        VRT_AddVFP(ctx, &xyzzy_rot13);
297 232
        return (0);
298
}
299
300
static int
301 228
event_warm(VRT_CTX, const struct vmod_priv *priv)
302
{
303
        struct priv_vcl *priv_vcl;
304
        char buf[32];
305
306 228
        VSL(SLT_Debug, 0, "%s: VCL_EVENT_WARM", VCL_Name(ctx->vcl));
307
308 228
        AN(ctx->msg);
309 228
        if (cache_param->max_esi_depth == 42) {
310 12
                VSB_printf(ctx->msg, "max_esi_depth is not the answer.");
311 12
                return (-1);
312
        }
313
314 216
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
315 216
        AZ(priv_vcl->vcl);
316 216
        AZ(priv_vcl->vclref);
317
318 216
        bprintf(buf, "vmod-debug ref on %s", VCL_Name(ctx->vcl));
319 216
        priv_vcl->vcl = ctx->vcl;
320 216
        priv_vcl->vclref = VRT_ref_vcl(ctx, buf);
321 216
        return (0);
322
}
323
324
static void*
325 4
cooldown_thread(void *priv)
326
{
327
        struct vrt_ctx ctx;
328
        struct priv_vcl *priv_vcl;
329
330 4
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
331 4
        AN(priv_vcl->vcl);
332 4
        AN(priv_vcl->vclref);
333
334 4
        INIT_OBJ(&ctx, VRT_CTX_MAGIC);
335 4
        ctx.vcl = priv_vcl->vcl;
336
337 4
        VTIM_sleep(vcl_release_delay);
338 4
        VRT_rel_vcl(&ctx, &priv_vcl->vclref);
339 4
        priv_vcl->vcl = NULL;
340 4
        return (NULL);
341
}
342
343
static int
344 36
event_cold(VRT_CTX, const struct vmod_priv *priv)
345
{
346
        pthread_t thread;
347
        struct priv_vcl *priv_vcl;
348
349 36
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
350 36
        AN(priv_vcl->vcl);
351 36
        AN(priv_vcl->vclref);
352
353 36
        VSL(SLT_Debug, 0, "%s: VCL_EVENT_COLD", VCL_Name(ctx->vcl));
354
355 36
        if (vcl_release_delay == 0.0) {
356 32
                VRT_rel_vcl(ctx, &priv_vcl->vclref);
357 32
                priv_vcl->vcl = NULL;
358 32
                return (0);
359
        }
360
361 4
        AZ(pthread_create(&thread, NULL, cooldown_thread, priv_vcl));
362 4
        AZ(pthread_detach(thread));
363 4
        return (0);
364
}
365
366
int v_matchproto_(vmod_event_f)
367 544
event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
368
{
369
370 544
        switch (e) {
371 236
        case VCL_EVENT_LOAD: return (event_load(ctx, priv));
372 228
        case VCL_EVENT_WARM: return (event_warm(ctx, priv));
373 36
        case VCL_EVENT_COLD: return (event_cold(ctx, priv));
374
        case VCL_EVENT_DISCARD:
375 44
                VRT_RemoveVFP(ctx, &xyzzy_rot13);
376 44
                if (vsc)
377 0
                        VSC_debug_Destroy(&vsc_seg);
378 44
                return (0);
379 0
        default: return (0);
380
        }
381
}
382
383
VCL_VOID v_matchproto_(td_debug_vcl_release_delay)
384 4
xyzzy_vcl_release_delay(VRT_CTX, VCL_DURATION delay)
385
{
386
387 4
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
388 4
        assert(delay > 0.0);
389 4
        vcl_release_delay = delay;
390 4
}
391
392
VCL_BOOL v_matchproto_(td_debug_match_acl)
393 8
xyzzy_match_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip)
394
{
395
396 8
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
397 8
        CHECK_OBJ_ORNULL(acl, VRT_ACL_MAGIC);
398 8
        assert(VSA_Sane(ip));
399
400 8
        return (VRT_acl_match(ctx, acl, ip));
401
}
402
403
VCL_VOID v_matchproto_(td_debug_test_probe)
404 0
xyzzy_test_probe(VRT_CTX, VCL_PROBE probe, VCL_PROBE same)
405
{
406
407 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
408 0
        CHECK_OBJ_NOTNULL(probe, VRT_BACKEND_PROBE_MAGIC);
409 0
        CHECK_OBJ_ORNULL(same, VRT_BACKEND_PROBE_MAGIC);
410 0
        AZ(same == NULL || probe == same);
411 0
}
412
413
VCL_VOID
414 4
xyzzy_vsc_new(VRT_CTX)
415
{
416
        (void)ctx;
417 4
        AZ(pthread_mutex_lock(&vsc_mtx));
418 4
        if (vsc == NULL) {
419 4
                AZ(vsc_seg);
420 4
                vsc = VSC_debug_New(NULL, &vsc_seg, "");
421
        }
422 4
        AN(vsc);
423 4
        AN(vsc_seg);
424 4
        AZ(pthread_mutex_unlock(&vsc_mtx));
425 4
}
426
427
VCL_VOID
428 4
xyzzy_vsc_count(VRT_CTX, VCL_INT cnt)
429
{
430
        (void)ctx;
431 4
        AN(vsc);
432 4
        vsc->count += cnt;
433 4
}
434
435
VCL_VOID
436 0
xyzzy_vsc_destroy(VRT_CTX)
437
{
438
        (void)ctx;
439 0
        AZ(pthread_mutex_lock(&vsc_mtx));
440 0
        if (vsc != NULL) {
441 0
                AN(vsc_seg);
442 0
                VSC_debug_Destroy(&vsc_seg);
443
        }
444 0
        AZ(vsc_seg);
445 0
        vsc = NULL;
446 0
        AZ(pthread_mutex_unlock(&vsc_mtx));
447 0
}
448
449
struct xyzzy_debug_concat {
450
        unsigned        magic;
451
#define CONCAT_MAGIC 0x6b746493
452
        VCL_STRING      s;
453
};
454
455
VCL_VOID
456 8
xyzzy_concat__init(VRT_CTX, struct xyzzy_debug_concat **concatp,
457
                   const char *vcl_name, VCL_STRANDS s)
458
{
459
        struct xyzzy_debug_concat *concat;
460 8
        size_t sz = 0;
461
        char *p;
462
463 8
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
464 8
        AN(concatp);
465 8
        AZ(*concatp);
466 8
        AN(vcl_name);
467
468 8
        ALLOC_OBJ(concat, CONCAT_MAGIC);
469 8
        AN(concat);
470 8
        *concatp = concat;
471
472 32
        for (int i = 0; i < s->n; i++)
473 24
                if (s->p[i] != NULL)
474 24
                        sz += strlen(s->p[i]);
475 8
        p = malloc(sz + 1);
476 8
        AN(p);
477 8
        (void)VRT_Strands(p, sz + 1, s);
478 8
        concat->s = p;
479 8
}
480
481
VCL_VOID
482 0
xyzzy_concat__fini(struct xyzzy_debug_concat **concatp)
483
{
484
        struct xyzzy_debug_concat *concat;
485
        void *p;
486
487 0
        if (concatp == NULL || *concatp == NULL)
488 0
                return;
489 0
        CHECK_OBJ(*concatp, CONCAT_MAGIC);
490 0
        concat = *concatp;
491 0
        *concatp = NULL;
492 0
        p = TRUST_ME(concat->s);
493 0
        free(p);
494 0
        FREE_OBJ(concat);
495
}
496
497
VCL_STRING
498 8
xyzzy_concat_get(VRT_CTX, struct xyzzy_debug_concat *concat)
499
{
500 8
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
501 8
        CHECK_OBJ_NOTNULL(concat, CONCAT_MAGIC);
502 8
        return (concat->s);
503
}
504
505
VCL_STRING
506 32
xyzzy_concatenate(VRT_CTX, VCL_STRANDS s)
507
{
508
        VCL_STRING r;
509
510 32
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
511 32
        r = VRT_StrandsWS(ctx->ws, NULL, s);
512 32
        if (r != NULL && *r != '\0')
513 24
                WS_Assert_Allocated(ctx->ws, r, strlen(r) + 1);
514 32
        return (r);
515
}
516
517
VCL_STRING
518 32
xyzzy_collect(VRT_CTX, VCL_STRANDS s)
519
{
520
        VCL_STRING r;
521
522 32
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
523 32
        r = VRT_CollectStrands(ctx, s);
524 32
        if (r != NULL && *r != '\0')
525 24
                WS_Assert_Allocated(ctx->ws, r, strlen(r) + 1);
526 32
        return (r);
527
}
528
529
/* cf. VRT_SetHdr() */
530
VCL_VOID
531 32
xyzzy_sethdr(VRT_CTX, VCL_HEADER hs, VCL_STRANDS s)
532
{
533
        struct http *hp;
534
        const char *b;
535
536 32
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
537 32
        AN(hs);
538 32
        AN(hs->what);
539 32
        hp = VRT_selecthttp(ctx, hs->where);
540 32
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
541 32
        if (s->n == 0) {
542 0
                http_Unset(hp, hs->what);
543
        } else {
544 32
                b = VRT_StrandsWS(hp->ws, hs->what + 1, s);
545 32
                if (b == NULL) {
546 0
                        VSLb(ctx->vsl, SLT_LostHeader, "%s", hs->what + 1);
547
                } else {
548 32
                        if (*b != '\0')
549 32
                                WS_Assert_Allocated(hp->ws, b, strlen(b) + 1);
550 32
                        http_Unset(hp, hs->what);
551 32
                        http_SetHeader(hp, b);
552
                }
553
        }
554 32
}