varnish-cache/vmod/vmod_vtc.c
0
/*-
1
 * Copyright (c) 2012-2017 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
5
 * Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
33
#include <stdlib.h>
34
#include <stdio.h>
35
#include <string.h>
36
#include <unistd.h>
37
38
#include "cache/cache.h"
39
40
#include "vsb.h"
41
#include "vtcp.h"
42
#include "vtim.h"
43
44
#include "vcc_vtc_if.h"
45
46
VCL_VOID v_matchproto_(td_vtc_barrier_sync)
47 1348
vmod_barrier_sync(VRT_CTX, VCL_STRING addr, VCL_DURATION tmo)
48
{
49
        const char *err;
50
        char buf[32];
51
        int sock, i;
52
        ssize_t sz;
53
54 1348
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
55 1348
        AN(addr);
56 1348
        AN(*addr);
57 1348
        assert(tmo >= 0.0);
58
59 1348
        if (ctx->vsl != NULL)
60 1348
                VSLb(ctx->vsl, SLT_Debug, "barrier_sync(\"%s\")", addr);
61
        else
62 0
                VSL(SLT_Debug, NO_VXID, "barrier_sync(\"%s\")", addr);
63
64 1348
        sock = VTCP_open(addr, NULL, 0., &err);
65 1348
        if (sock < 0) {
66 0
                VRT_fail(ctx, "Barrier connection failed: %s", err);
67 0
                return;
68
        }
69
70 1348
        sz = VTCP_read(sock, buf, sizeof buf, tmo);
71 1348
        i = errno;
72 1348
        closefd(&sock);
73 1348
        if (sz < 0)
74 0
                VRT_fail(ctx, "Barrier read failed: %s (errno=%d)",
75 0
                    strerror(i), i);
76 1348
        if (sz > 0)
77 0
                VRT_fail(ctx, "Barrier unexpected data (%zdB)", sz);
78 1348
}
79
80
/*--------------------------------------------------------------------*/
81
82
VCL_BACKEND v_matchproto_(td_vtc_no_backend)
83 50
vmod_no_backend(VRT_CTX)
84
{
85
86 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
87 50
        return (NULL);
88
}
89
90
VCL_STEVEDORE v_matchproto_(td_vtc_no_stevedore)
91 25
vmod_no_stevedore(VRT_CTX)
92
{
93
94 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
95 25
        return (NULL);
96
}
97
98
VCL_IP v_matchproto_(td_vtc_no_ip)
99 25
vmod_no_ip(VRT_CTX)
100
{
101
102 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
103 25
        return (NULL);
104
}
105
106
/*--------------------------------------------------------------------*/
107
108
VCL_VOID v_noreturn_ v_matchproto_(td_vtc_panic)
109 0
vmod_panic(VRT_CTX, VCL_STRANDS str)
110
{
111
        const char *b;
112
113 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
114
115 0
        b = VRT_StrandsWS(ctx->ws, "PANIC:", str);
116 0
        VAS_Fail("VCL", "", 0, b, VAS_VCL);
117
}
118
119
/*--------------------------------------------------------------------*/
120
121
VCL_VOID v_matchproto_(td_vtc_sleep)
122 625
vmod_sleep(VRT_CTX, VCL_DURATION t)
123
{
124
125 625
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
126 625
        VTIM_sleep(t);
127 625
}
128
129
/*--------------------------------------------------------------------*/
130
131
// XXX this really should be PRIV_TASK state
132
static uintptr_t vtc_ws_snapshot;
133
134
static struct ws *
135 13500
vtc_ws_find(VRT_CTX, VCL_ENUM which)
136
{
137
138 13500
        if (which == VENUM(client))
139 6450
                return (ctx->ws);
140 7050
        if (which == VENUM(backend))
141 6325
                return (ctx->bo->ws);
142 725
        if (which == VENUM(session))
143 675
                return (ctx->req->sp->ws);
144 50
        if (which == VENUM(thread))
145 50
                return (ctx->req->wrk->aws);
146 0
        WRONG("vtc_ws_find Illegal enum");
147 13500
}
148
149
VCL_VOID v_matchproto_(td_vtc_workspace_alloc)
150 12300
vmod_workspace_alloc(VRT_CTX, VCL_ENUM which, VCL_INT size)
151
{
152
        struct ws *ws;
153
        void *p;
154
155 12300
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
156
157 12300
        ws = vtc_ws_find(ctx, which);
158 12300
        if (ws == NULL)
159 0
                return;
160 12300
        WS_Assert(ws);
161
162 12300
        if (size < 0) {
163 11875
                size += WS_ReserveAll(ws);
164 11875
                WS_Release(ws, 0);
165 11875
        }
166 12300
        if (size <= 0) {
167 75
                VRT_fail(ctx, "Attempted negative WS allocation");
168 75
                return;
169
        }
170 12225
        p = WS_Alloc(ws, size);
171 12225
        if (p == NULL)
172 25
                VRT_fail(ctx, "vtc.workspace_alloc");
173
        else
174 12200
                memset(p, '\0', size);
175 12300
}
176
177
VCL_BYTES v_matchproto_(td_vtc_workspace_reserve)
178 300
vmod_workspace_reserve(VRT_CTX, VCL_ENUM which, VCL_INT size)
179
{
180
        struct ws *ws;
181
        unsigned r;
182
183 300
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
184
185 300
        ws = vtc_ws_find(ctx, which);
186 300
        if (ws == NULL)
187 0
                return (0);
188 300
        WS_Assert(ws);
189
190 300
        if (size < 0) {
191 175
                size += WS_ReserveAll(ws);
192 175
                WS_Release(ws, 0);
193 175
        }
194 300
        if (size <= 0) {
195 0
                VRT_fail(ctx, "Attempted negative WS reservation");
196 0
                return (0);
197
        }
198 300
        r = WS_ReserveSize(ws, size);
199 300
        if (r == 0)
200 25
                return (0);
201 275
        memset(WS_Reservation(ws), 0, r);
202 275
        WS_Release(ws, 0);
203 275
        return (r);
204 300
}
205
206
VCL_INT v_matchproto_(td_vtc_workspace_free)
207 400
vmod_workspace_free(VRT_CTX, VCL_ENUM which)
208
{
209
        struct ws *ws;
210
        unsigned u;
211
212 400
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
213
214 400
        ws = vtc_ws_find(ctx, which);
215 400
        if (ws == NULL)
216 0
                return (-1);
217 400
        WS_Assert(ws);
218
219 400
        u = WS_ReserveAll(ws);
220 400
        WS_Release(ws, 0);
221 400
        return (u);
222 400
}
223
224
#define VTC_WS_OP(type, def, name, op)                  \
225
VCL_##type v_matchproto_(td_vtc_workspace_##name)       \
226
vmod_workspace_##name(VRT_CTX, VCL_ENUM which)          \
227
{                                                       \
228
        struct ws *ws;                                  \
229
                                                        \
230
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);          \
231
                                                        \
232
        ws = vtc_ws_find(ctx, which);                   \
233
        if (ws == NULL)                                 \
234
                return def ;                            \
235
        WS_Assert(ws);                                  \
236
                                                        \
237
        op;                                             \
238
}
239 25
VTC_WS_OP(VOID, , snapshot, (vtc_ws_snapshot = WS_Snapshot(ws)))
240 25
VTC_WS_OP(VOID, , reset, WS_Reset(ws, vtc_ws_snapshot))
241 25
VTC_WS_OP(VOID, , overflow, WS_MarkOverflow(ws))
242 125
VTC_WS_OP(BOOL, (0), overflowed, return (WS_Overflowed(ws)))
243
#undef VTC_WS_OP
244
245
VCL_BLOB v_matchproto_(td_vtc_workspace_dump)
246 299
vmod_workspace_dump(VRT_CTX, VCL_ENUM which, VCL_ENUM where,
247
    VCL_BYTES off, VCL_BYTES len)
248
{
249
        struct ws *ws;
250 299
        VCL_BYTES l, maxlen = 1024;
251 299
        unsigned char buf[maxlen];
252
        const char *p, *err;
253
254 299
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
255 299
        AN(where);
256
257 299
        ws = vtc_ws_find(ctx, which);
258 299
        if (ws == NULL)
259 0
                return (NULL);
260 299
        WS_Assert(ws);
261
262 299
        if (len > maxlen) {
263 0
                VRT_fail(ctx, "workspace_dump: max length is %jd",
264 0
                    (intmax_t)maxlen);
265 0
                return (NULL);
266
        }
267
268 299
        l = WS_Dump(ws, *where, off, buf, len);
269
270 299
        if (l == 0) {
271 0
                switch (errno) {
272 0
                case EINVAL: WRONG(where); break;
273 0
                case EAGAIN: err = "NULL"; break;
274 0
                case EFAULT: err = "off limit"; break;
275 0
                default: err = "unknown error"; break;
276
                }
277 0
                VRT_fail(ctx, "workspace_dump: %s", err);
278 0
                return (NULL);
279
        }
280
281 299
        assert(l < maxlen);
282 299
        p = WS_Copy(ctx->ws, buf, l);
283 299
        if (p == NULL) {
284 0
                VRT_fail(ctx, "workspace_dump: copy failed");
285 0
                return (NULL);
286
        }
287 299
        return (VRT_blob(ctx, "workspace_dump", p, l, 0xd000d000));
288 299
}
289
290
/*--------------------------------------------------------------------*/
291
292
VCL_INT v_matchproto_(td_vtc_typesize)
293 625
vmod_typesize(VRT_CTX, VCL_STRING s)
294
{
295 625
        size_t i = 0, l, a, p = 0;
296
297 625
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
298 625
        AN(s);
299 625
        AN(*s);
300
301 2450
        for (; *s; s++) {
302 1850
                switch (*s) {
303
#define VTC_TYPESIZE(c, t) case c: l = sizeof(t); break;
304 275
                VTC_TYPESIZE('c', char)
305 75
                VTC_TYPESIZE('d', double)
306 25
                VTC_TYPESIZE('f', float)
307 75
                VTC_TYPESIZE('i', int)
308 25
                VTC_TYPESIZE('j', intmax_t)
309 25
                VTC_TYPESIZE('l', long)
310 25
                VTC_TYPESIZE('o', off_t)
311 400
                VTC_TYPESIZE('p', void *)
312 75
                VTC_TYPESIZE('s', short)
313 375
                VTC_TYPESIZE('u', unsigned)
314 450
                VTC_TYPESIZE('z', size_t)
315
#undef VTC_TYPESIZE
316 25
                default:        return (-1);
317
                }
318 1825
                if (l > p)
319 1050
                        p = l;
320 1825
                a = i % l;
321 1825
                if (a != 0)
322 475
                        i += (l - a); /* align */
323 1825
                i += l;
324 1825
        }
325 600
        AN(p);
326 600
        a = i % p;
327 600
        if (a != 0)
328 150
                i += (p - a); /* pad */
329 600
        return ((VCL_INT)i);
330 625
}
331
332
/*--------------------------------------------------------------------*/
333
334
#define BLOB_VMOD_PROXY_HEADER_TYPE     0xc8f34f78
335
336
VCL_BLOB v_matchproto_(td_vtc_proxy_header)
337 50
vmod_proxy_header(VRT_CTX, VCL_ENUM venum, VCL_IP client, VCL_IP server,
338
    VCL_STRING authority)
339
{
340
        struct vsb *vsb;
341
        const void *h;
342
        int version;
343
        size_t l;
344
345 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
346
347 50
        if (venum == VENUM(v1))
348 25
                version = 1;
349 25
        else if (venum == VENUM(v2))
350 25
                version = 2;
351
        else
352 0
                WRONG(venum);
353
354 50
        vsb = VSB_new_auto();
355 50
        AN(vsb);
356 50
        VRT_Format_Proxy(vsb, version, client, server, authority);
357 50
        l = VSB_len(vsb);
358 50
        h = WS_Copy(ctx->ws, VSB_data(vsb), l);
359 50
        VSB_destroy(&vsb);
360
361 50
        if (h == NULL) {
362 0
                VRT_fail(ctx, "proxy_header: out of workspace");
363 0
                return (NULL);
364
        }
365
366 50
        return (VRT_blob(ctx, "proxy_header", h, l,
367
            BLOB_VMOD_PROXY_HEADER_TYPE));
368 50
}
369
370
// ref vsl.c
371
struct vsl_tag2enum {
372
        const char      *string;
373
        enum VSL_tag_e  tag;
374
};
375
376
static struct vsl_tag2enum vsl_tag2enum[SLT__MAX] = {
377
#define SLTM(name,flags,sdesc,ldesc) [SLT_ ## name] = { \
378
                .string = #name,                                \
379
                .tag = SLT_ ## name                             \
380
        },
381
#include "tbl/vsl_tags.h"
382
};
383
384
static int
385 1458425
vsl_tagcmp(const void *aa, const void *bb)
386
{
387 1458425
        const struct vsl_tag2enum *a = aa, *b = bb;
388
389
        // ref vsl2rst.c ptag_cmp
390 1458425
        if (a->string == NULL && b->string != NULL)
391 3300
                return (1);
392 1455125
        else if (a->string != NULL && b->string == NULL)
393 159025
                return (-1);
394 1296100
        else if (a->string == NULL && b->string == NULL)
395 278850
                return (0);
396 1017250
        return (strcmp(a->string, b->string));
397 1458425
}
398
399
/*lint -esym(528, init_vsl_tag2enum) */
400
static void __attribute__((constructor))
401 1650
init_vsl_tag2enum(void)
402
{
403 1650
        qsort(vsl_tag2enum, SLT__MAX, sizeof *vsl_tag2enum, vsl_tagcmp);
404 1650
}
405
406
407
VCL_VOID
408 1525
vmod_vsl(VRT_CTX, VCL_INT id, VCL_STRING tag_s, VCL_ENUM side, VCL_STRANDS s)
409
{
410
        struct vsl_tag2enum *te, key;
411
        vxid_t vxid;
412
413 1525
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
414
415 1525
        key.string = tag_s;
416 1525
        te = bsearch(&key, vsl_tag2enum, SLT__MAX,
417
            sizeof *vsl_tag2enum, vsl_tagcmp);
418
419 1525
        if (te == NULL) {
420 0
                VRT_fail(ctx, "No such tag: %s", tag_s);
421 0
                return;
422
        }
423
424 1525
        if (id < 0 || id > VRT_INTEGER_MAX) {
425 0
                VRT_fail(ctx, "id out of bounds");
426 0
                return;
427
        }
428
429 1525
        vxid.vxid = id & VSL_IDENTMASK;
430 1525
        if (side == VENUM(c))
431 1475
                vxid.vxid |= VSL_CLIENTMARKER;
432 50
        else if (side == VENUM(b))
433 50
                vxid.vxid |= VSL_BACKENDMARKER;
434
        else
435 0
                WRONG("side");
436
437 1525
        VSLs(te->tag, vxid, s);
438 1525
}
439
440
static void
441 1475
vsl_line(VRT_CTX, char *str)
442
{
443
        VCL_INT id;
444
        VCL_ENUM side;
445
        VCL_STRANDS s;
446 1475
        const char *tag, *delim = " \t\r\n";
447
        char *e, *save;
448
449 1475
        if (*str == '*') {
450
                // varnishtest
451 1375
                str = strstr(str, "vsl|");
452 1375
                if (str == NULL)
453 0
                        return;
454 1375
                str += 4;
455 1375
        }
456 1475
        if ((str = strtok_r(str, delim, &save)) == NULL)
457 100
                return;
458 1375
        id = strtoll(str, &e, 10);
459 1375
        if (e == str)
460 0
                return;
461
462 1375
        if ((str = strtok_r(NULL, delim, &save)) == NULL)
463 0
                return;
464 1375
        tag = str;
465
466 1375
        if ((str = strtok_r(NULL, delim, &save)) == NULL)
467 0
                return;
468 1375
        if (*str == 'c')
469 1325
                side = VENUM(c);
470 50
        else if (*str == 'b')
471 50
                side = VENUM(b);
472
        else
473 0
                return;
474
475 1375
        str = strtok_r(NULL, "\r\n", &save);
476 1375
        s = TOSTRAND(str);
477 1375
        if (str == NULL)
478 200
                s = vrt_null_strands;
479
480 1375
        vmod_vsl(ctx, id, tag, side, s);
481 1475
}
482
483
VCL_VOID
484 50
vmod_vsl_replay(VRT_CTX, VCL_STRANDS s)
485
{
486
        struct vsb cp[1];
487
        const char *p, *pp;
488
        size_t l;
489 50
        int i, err = 0;
490
491 50
        if (s == NULL || s->n == 0)
492 0
                return;
493
494 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
495 50
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
496 50
        WS_VSB_new(cp, ctx->ws);
497
498 100
        for (i = 0; i < s->n; i++) {
499 50
                p = s->p[i];
500 50
                if (p == NULL || *p == '\0')
501 0
                        continue;
502 50
                pp = strpbrk(p, "\r\n");
503 1475
                while (pp != NULL) {
504 1425
                        l = pp - p;
505 1425
                        if (VSB_bcat(cp, p, l) || VSB_finish(cp)) {
506 0
                                err = 1;
507 0
                                break;
508
                        }
509 1425
                        vsl_line(ctx, VSB_data(cp));
510 1425
                        VSB_clear(cp);
511 1425
                        p = pp + 1;
512 1425
                        pp = strpbrk(p, "\r\n");
513
                }
514 50
                if (err || VSB_cat(cp, p)) {
515 0
                        err = 1;
516 0
                        break;
517
                }
518 50
        }
519 50
        if (err || VSB_finish(cp)) {
520 0
                AZ(WS_VSB_finish(cp, ctx->ws, NULL));
521 0
                VRT_fail(ctx, "out of workspace");
522 0
                return;
523
        }
524 50
        vsl_line(ctx, VSB_data(cp));
525 50
        VSB_clear(cp);
526 50
        AN(WS_VSB_finish(cp, ctx->ws, NULL));
527 50
}