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 3
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 3
        vp = VFP_Suck(vc, p, lp);
73 3
        if (vp == VFP_ERROR)
74 0
                return (vp);
75 3
        q = p;
76 87
        for (l = 0; l < *lp; l++, q++) {
77 84
                if (*q >= 'A' && *q <= 'Z')
78 12
                        *q = (((*q - 'A') + 13) % 26) + 'A';
79 84
                if (*q >= 'a' && *q <= 'z')
80 57
                        *q = (((*q - 'a') + 13) % 26) + 'a';
81
        }
82 3
        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 15
xyzzy_author(VRT_CTX, VCL_ENUM person, VCL_ENUM someone)
94
{
95
        (void)someone;
96
97 15
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
98 15
        if (person == xyzzy_enum_phk)
99 6
                return ("Poul-Henning");
100 9
        assert(strcmp(person, "phk"));
101 9
        if (person == xyzzy_enum_des)
102 3
                return ("Dag-Erling");
103 6
        assert(strcmp(person, "des"));
104 6
        if (person == xyzzy_enum_kristian)
105 3
                return ("Kristian");
106 3
        assert(strcmp(person, "kristian"));
107 3
        if (person == xyzzy_enum_mithrandir)
108 3
                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 6
xyzzy_test_priv_call(VRT_CTX, struct vmod_priv *priv)
115
{
116
117 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
118 6
        if (priv->priv == NULL) {
119 6
                priv->priv = strdup("BAR");
120 6
                priv->free = free;
121
        } else {
122 0
                assert(!strcmp(priv->priv, "BAR"));
123
        }
124 6
}
125
126
VCL_STRING v_matchproto_(td_debug_test_priv_task)
127 141
xyzzy_test_priv_task(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
128
{
129
130 141
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
131 141
        if (s == NULL || *s == '\0') {
132 84
                return priv->priv;
133 57
        } else if (priv->priv == NULL) {
134 36
                priv->priv = strdup(s);
135 36
                priv->free = free;
136
        } else {
137 21
                char *n = realloc(priv->priv,
138 21
                    strlen(priv->priv) + strlen(s) + 2);
139 21
                if (n == NULL)
140 0
                        return NULL;
141 21
                strcat(n, " ");
142 21
                strcat(n, s);
143 21
                priv->priv = n;
144
        }
145 57
        return (priv->priv);
146
}
147
148
VCL_STRING v_matchproto_(td_debug_test_priv_top)
149 48
xyzzy_test_priv_top(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
150
{
151
152 48
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
153 48
        if (priv->priv == NULL) {
154 6
                priv->priv = strdup(s);
155 6
                priv->free = free;
156
        }
157 48
        return (priv->priv);
158
}
159
160
VCL_VOID v_matchproto_(td_debug_test_priv_vcl)
161 6
xyzzy_test_priv_vcl(VRT_CTX, struct vmod_priv *priv)
162
{
163
        struct priv_vcl *priv_vcl;
164
165 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
166 6
        AN(priv);
167 6
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
168 6
        AN(priv_vcl->foo);
169 6
        assert(!strcmp(priv_vcl->foo, "FOO"));
170 6
}
171
172
VCL_VOID v_matchproto_(td_debug_rot52)
173 6
xyzzy_rot52(VRT_CTX, VCL_HTTP hp)
174
{
175
176 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
177 6
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
178
179 6
        http_PrintfHeader(hp, "Encrypted: ROT52");
180 6
}
181
182
VCL_STRING v_matchproto_(td_debug_argtest)
183 21
xyzzy_argtest(VRT_CTX, struct xyzzy_argtest_arg *arg)
184
{
185
        char buf[100];
186
187 21
        AN(arg);
188 21
        bprintf(buf, "%s %g %s %s %jd %d %s",
189
            arg->one, arg->two, arg->three, arg->comma, (intmax_t)arg->four,
190
            arg->valid_opt, arg->valid_opt ? arg->opt : "<undef>");
191 21
        return (WS_Copy(ctx->ws, buf, -1));
192
}
193
194
VCL_INT v_matchproto_(td_debug_vre_limit)
195 6
xyzzy_vre_limit(VRT_CTX)
196
{
197
        (void)ctx;
198 6
        return (cache_param->vre_limits.match);
199
}
200
201
static void v_matchproto_(obj_event_f)
202 6
obj_cb(struct worker *wrk, void *priv, struct objcore *oc, unsigned event)
203
{
204
        const struct priv_vcl *priv_vcl;
205
        const char *what;
206
207 6
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
208 6
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
209 6
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
210 6
        switch (event) {
211 3
        case OEV_INSERT: what = "insert"; break;
212 3
        case OEV_EXPIRE: what = "expire"; break;
213 0
        default: WRONG("Wrong object event");
214
        }
215
216
        /* We cannot trust %p to be 0x... format as expected by m00021.vtc */
217 6
        VSL(SLT_Debug, 0, "Object Event: %s 0x%jx", what,
218
            (intmax_t)(uintptr_t)oc);
219 6
}
220
221
VCL_VOID v_matchproto_(td_debug_register_obj_events)
222 3
xyzzy_register_obj_events(VRT_CTX, struct vmod_priv *priv)
223
{
224
        struct priv_vcl *priv_vcl;
225
226 3
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
227 3
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
228 3
        AZ(priv_vcl->obj_cb);
229 3
        priv_vcl->obj_cb = ObjSubscribeEvents(obj_cb, priv_vcl,
230
                OEV_INSERT|OEV_EXPIRE);
231 3
        VSL(SLT_Debug, 0, "Subscribed to Object Events");
232 3
}
233
234
VCL_VOID v_matchproto_(td_debug_fail)
235 42
xyzzy_fail(VRT_CTX)
236
{
237
238 42
        VRT_fail(ctx, "Forced failure");
239 42
}
240
241
static void v_matchproto_(vmod_priv_free_f)
242 33
priv_vcl_free(void *priv)
243
{
244
        struct priv_vcl *priv_vcl;
245
246 33
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
247 33
        AN(priv_vcl->foo);
248 33
        free(priv_vcl->foo);
249 33
        if (priv_vcl->obj_cb != 0) {
250 3
                ObjUnsubscribeEvents(&priv_vcl->obj_cb);
251 3
                VSL(SLT_Debug, 0, "Unsubscribed from Object Events");
252
        }
253 33
        AZ(priv_vcl->vcl);
254 33
        AZ(priv_vcl->vclref);
255 33
        FREE_OBJ(priv_vcl);
256 33
        AZ(priv_vcl);
257 33
}
258
259
static int
260 162
event_load(VRT_CTX, struct vmod_priv *priv)
261
{
262
        struct priv_vcl *priv_vcl;
263
264 162
        AN(ctx->msg);
265 162
        if (cache_param->nuke_limit == 42) {
266 3
                VSB_printf(ctx->msg, "nuke_limit is not the answer.");
267 3
                return (-1);
268
        }
269
270 159
        ALLOC_OBJ(priv_vcl, PRIV_VCL_MAGIC);
271 159
        AN(priv_vcl);
272 159
        priv_vcl->foo = strdup("FOO");
273 159
        AN(priv_vcl->foo);
274 159
        priv->priv = priv_vcl;
275 159
        priv->free = priv_vcl_free;
276
277
        /*
278
         * NB: This is a proof of concept, until we decide what the real
279
         * API should look like, do NOT do this anywhere else.
280
         */
281 159
        VRT_AddVFP(ctx, &xyzzy_rot13);
282 159
        return (0);
283
}
284
285
static int
286 156
event_warm(VRT_CTX, const struct vmod_priv *priv)
287
{
288
        struct priv_vcl *priv_vcl;
289
        char buf[32];
290
291 156
        VSL(SLT_Debug, 0, "%s: VCL_EVENT_WARM", VCL_Name(ctx->vcl));
292
293 156
        AN(ctx->msg);
294 156
        if (cache_param->max_esi_depth == 42) {
295 9
                VSB_printf(ctx->msg, "max_esi_depth is not the answer.");
296 9
                return (-1);
297
        }
298
299 147
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
300 147
        AZ(priv_vcl->vcl);
301 147
        AZ(priv_vcl->vclref);
302
303 147
        bprintf(buf, "vmod-debug ref on %s", VCL_Name(ctx->vcl));
304 147
        priv_vcl->vcl = ctx->vcl;
305 147
        priv_vcl->vclref = VRT_ref_vcl(ctx, buf);
306 147
        return (0);
307
}
308
309
static void*
310 3
cooldown_thread(void *priv)
311
{
312
        struct vrt_ctx ctx;
313
        struct priv_vcl *priv_vcl;
314
315 3
        CAST_OBJ_NOTNULL(priv_vcl, priv, PRIV_VCL_MAGIC);
316 3
        AN(priv_vcl->vcl);
317 3
        AN(priv_vcl->vclref);
318
319 3
        INIT_OBJ(&ctx, VRT_CTX_MAGIC);
320 3
        ctx.vcl = priv_vcl->vcl;
321
322 3
        VTIM_sleep(vcl_release_delay);
323 3
        VRT_rel_vcl(&ctx, &priv_vcl->vclref);
324 3
        priv_vcl->vcl = NULL;
325 3
        return (NULL);
326
}
327
328
static int
329 27
event_cold(VRT_CTX, const struct vmod_priv *priv)
330
{
331
        pthread_t thread;
332
        struct priv_vcl *priv_vcl;
333
334 27
        CAST_OBJ_NOTNULL(priv_vcl, priv->priv, PRIV_VCL_MAGIC);
335 27
        AN(priv_vcl->vcl);
336 27
        AN(priv_vcl->vclref);
337
338 27
        VSL(SLT_Debug, 0, "%s: VCL_EVENT_COLD", VCL_Name(ctx->vcl));
339
340 27
        if (vcl_release_delay == 0.0) {
341 24
                VRT_rel_vcl(ctx, &priv_vcl->vclref);
342 24
                priv_vcl->vcl = NULL;
343 24
                return (0);
344
        }
345
346 3
        AZ(pthread_create(&thread, NULL, cooldown_thread, priv_vcl));
347 3
        AZ(pthread_detach(thread));
348 3
        return (0);
349
}
350
351
int v_matchproto_(vmod_event_f)
352 378
event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
353
{
354
355 378
        switch (e) {
356 162
        case VCL_EVENT_LOAD: return (event_load(ctx, priv));
357 156
        case VCL_EVENT_WARM: return (event_warm(ctx, priv));
358 27
        case VCL_EVENT_COLD: return (event_cold(ctx, priv));
359
        case VCL_EVENT_DISCARD:
360 33
                VRT_RemoveVFP(ctx, &xyzzy_rot13);
361 33
                if (vsc)
362 0
                        VSC_debug_Destroy(&vsc_seg);
363 33
                return (0);
364 0
        default: return (0);
365
        }
366
}
367
368
VCL_VOID v_matchproto_(td_debug_vcl_release_delay)
369 3
xyzzy_vcl_release_delay(VRT_CTX, VCL_DURATION delay)
370
{
371
372 3
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
373 3
        assert(delay > 0.0);
374 3
        vcl_release_delay = delay;
375 3
}
376
377
VCL_BOOL v_matchproto_(td_debug_match_acl)
378 6
xyzzy_match_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip)
379
{
380
381 6
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
382 6
        CHECK_OBJ_ORNULL(acl, VRT_ACL_MAGIC);
383 6
        assert(VSA_Sane(ip));
384
385 6
        return (VRT_acl_match(ctx, acl, ip));
386
}
387
388
VCL_VOID v_matchproto_(td_debug_test_probe)
389 0
xyzzy_test_probe(VRT_CTX, VCL_PROBE probe, VCL_PROBE same)
390
{
391
392 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
393 0
        CHECK_OBJ_NOTNULL(probe, VRT_BACKEND_PROBE_MAGIC);
394 0
        CHECK_OBJ_ORNULL(same, VRT_BACKEND_PROBE_MAGIC);
395 0
        AZ(same == NULL || probe == same);
396 0
}
397
398
VCL_VOID
399 3
xyzzy_vsc_new(VRT_CTX)
400
{
401
        (void)ctx;
402 3
        AZ(pthread_mutex_lock(&vsc_mtx));
403 3
        if (vsc == NULL) {
404 3
                AZ(vsc_seg);
405 3
                vsc = VSC_debug_New(NULL, &vsc_seg, "");
406
        }
407 3
        AN(vsc);
408 3
        AN(vsc_seg);
409 3
        AZ(pthread_mutex_unlock(&vsc_mtx));
410 3
}
411
412
VCL_VOID
413 3
xyzzy_vsc_count(VRT_CTX, VCL_INT cnt)
414
{
415
        (void)ctx;
416 3
        AN(vsc);
417 3
        vsc->count += cnt;
418 3
}
419
420
VCL_VOID
421 0
xyzzy_vsc_destroy(VRT_CTX)
422
{
423
        (void)ctx;
424 0
        AZ(pthread_mutex_lock(&vsc_mtx));
425 0
        if (vsc != NULL) {
426 0
                AN(vsc_seg);
427 0
                VSC_debug_Destroy(&vsc_seg);
428
        }
429 0
        AZ(vsc_seg);
430 0
        vsc = NULL;
431 0
        AZ(pthread_mutex_unlock(&vsc_mtx));
432 0
}