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 1645
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 1645
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
55 1645
        AN(addr);
56 1645
        AN(*addr);
57 1645
        assert(tmo >= 0.0);
58
59 1645
        if (ctx->vsl != NULL)
60 1645
                VSLb(ctx->vsl, SLT_Debug, "barrier_sync(\"%s\")", addr);
61
        else
62 0
                VSL(SLT_Debug, NO_VXID, "barrier_sync(\"%s\")", addr);
63
64 1645
        sock = VTCP_open(addr, NULL, 0., &err);
65 1645
        if (sock < 0) {
66 0
                VRT_fail(ctx, "Barrier connection failed: %s", err);
67 0
                return;
68
        }
69
70 1645
        sz = VTCP_read(sock, buf, sizeof buf, tmo);
71 1645
        i = errno;
72 1645
        closefd(&sock);
73 1645
        if (sz < 0)
74 0
                VRT_fail(ctx, "Barrier read failed: %s (errno=%d)",
75 0
                    strerror(i), i);
76 1645
        if (sz > 0)
77 0
                VRT_fail(ctx, "Barrier unexpected data (%zdB)", sz);
78 1645
}
79
80
/*--------------------------------------------------------------------*/
81
82
VCL_BACKEND v_matchproto_(td_vtc_no_backend)
83 44
vmod_no_backend(VRT_CTX)
84
{
85
86 44
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
87 44
        return (NULL);
88
}
89
90
VCL_STEVEDORE v_matchproto_(td_vtc_no_stevedore)
91 22
vmod_no_stevedore(VRT_CTX)
92
{
93
94 22
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
95 22
        return (NULL);
96
}
97
98
VCL_IP v_matchproto_(td_vtc_no_ip)
99 22
vmod_no_ip(VRT_CTX)
100
{
101
102 22
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
103 22
        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 550
vmod_sleep(VRT_CTX, VCL_DURATION t)
123
{
124
125 550
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
126 550
        VTIM_sleep(t);
127 550
}
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 11858
vtc_ws_find(VRT_CTX, VCL_ENUM which)
136
{
137
138 11858
        if (which == VENUM(client))
139 5676
                return (ctx->ws);
140 6182
        if (which == VENUM(backend))
141 5544
                return (ctx->bo->ws);
142 638
        if (which == VENUM(session))
143 594
                return (ctx->req->sp->ws);
144 44
        if (which == VENUM(thread) && ctx->req != NULL)
145 44
                return (ctx->req->wrk->aws);
146 0
        if (which == VENUM(thread) && ctx->bo != NULL)
147 0
                return (ctx->bo->wrk->aws);
148 0
        WRONG("vtc_ws_find Illegal enum");
149 11858
}
150
151
VCL_VOID v_matchproto_(td_vtc_workspace_alloc)
152 10802
vmod_workspace_alloc(VRT_CTX, VCL_ENUM which, VCL_INT size)
153
{
154
        struct ws *ws;
155
        void *p;
156
157 10802
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
158
159 10802
        ws = vtc_ws_find(ctx, which);
160 10802
        if (ws == NULL)
161 0
                return;
162 10802
        WS_Assert(ws);
163
164 10802
        if (size < 0) {
165 10450
                size += WS_ReserveAll(ws);
166 10450
                WS_Release(ws, 0);
167 10450
        }
168 10802
        if (size <= 0) {
169 44
                VRT_fail(ctx, "Attempted negative WS allocation");
170 44
                return;
171
        }
172 10758
        p = WS_Alloc(ws, size);
173 10758
        if (p == NULL)
174 22
                VRT_fail(ctx, "vtc.workspace_alloc");
175
        else
176 10736
                memset(p, '\0', size);
177 10802
}
178
179
VCL_BYTES v_matchproto_(td_vtc_workspace_reserve)
180 264
vmod_workspace_reserve(VRT_CTX, VCL_ENUM which, VCL_INT size)
181
{
182
        struct ws *ws;
183
        unsigned r;
184
185 264
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
186
187 264
        ws = vtc_ws_find(ctx, which);
188 264
        if (ws == NULL)
189 0
                return (0);
190 264
        WS_Assert(ws);
191
192 264
        if (size < 0) {
193 154
                size += WS_ReserveAll(ws);
194 154
                WS_Release(ws, 0);
195 154
        }
196 264
        if (size <= 0) {
197 0
                VRT_fail(ctx, "Attempted negative WS reservation");
198 0
                return (0);
199
        }
200 264
        r = WS_ReserveSize(ws, size);
201 264
        if (r == 0)
202 22
                return (0);
203 242
        memset(WS_Reservation(ws), 0, r);
204 242
        WS_Release(ws, 0);
205 242
        return (r);
206 264
}
207
208
VCL_INT v_matchproto_(td_vtc_workspace_free)
209 352
vmod_workspace_free(VRT_CTX, VCL_ENUM which)
210
{
211
        struct ws *ws;
212
        unsigned u;
213
214 352
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
215
216 352
        ws = vtc_ws_find(ctx, which);
217 352
        if (ws == NULL)
218 0
                return (-1);
219 352
        WS_Assert(ws);
220
221 352
        u = WS_ReserveAll(ws);
222 352
        WS_Release(ws, 0);
223 352
        return (u);
224 352
}
225
226
#define VTC_WS_OP(type, def, name, op)                  \
227
VCL_##type v_matchproto_(td_vtc_workspace_##name)       \
228
vmod_workspace_##name(VRT_CTX, VCL_ENUM which)          \
229
{                                                       \
230
        struct ws *ws;                                  \
231
                                                        \
232
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);          \
233
                                                        \
234
        ws = vtc_ws_find(ctx, which);                   \
235
        if (ws == NULL)                                 \
236
                return def ;                            \
237
        WS_Assert(ws);                                  \
238
                                                        \
239
        op;                                             \
240
}
241 22
VTC_WS_OP(VOID, , snapshot, (vtc_ws_snapshot = WS_Snapshot(ws)))
242 22
VTC_WS_OP(VOID, , reset, WS_Reset(ws, vtc_ws_snapshot))
243 22
VTC_WS_OP(VOID, , overflow, WS_MarkOverflow(ws))
244 110
VTC_WS_OP(BOOL, (0), overflowed, return (WS_Overflowed(ws)))
245
#undef VTC_WS_OP
246
247
VCL_BLOB v_matchproto_(td_vtc_workspace_dump)
248 261
vmod_workspace_dump(VRT_CTX, VCL_ENUM which, VCL_ENUM where,
249
    VCL_BYTES off, VCL_BYTES len)
250
{
251
        struct ws *ws;
252
        unsigned l;
253 261
        const unsigned maxlen = 1024;
254 261
        unsigned char buf[maxlen];
255
        const char *p, *err;
256
257 261
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
258 261
        AN(where);
259
260 261
        ws = vtc_ws_find(ctx, which);
261 261
        if (ws == NULL)
262 0
                return (NULL);
263 261
        WS_Assert(ws);
264
265 261
        if (len > maxlen) {
266 0
                VRT_fail(ctx, "workspace_dump: max length is %jd",
267
                    (intmax_t)maxlen);
268 0
                return (NULL);
269
        }
270
271 261
        l = WS_Dump(ws, *where, off, buf, len);
272 261
        assert(l <= maxlen);
273
274 261
        if (l == 0) {
275 0
                switch (errno) {
276 0
                case EINVAL: WRONG(where); break;
277 0
                case EAGAIN: err = "NULL"; break;
278 0
                case EFAULT: err = "off limit"; break;
279 0
                default: err = "unknown error"; break;
280
                }
281 0
                VRT_fail(ctx, "workspace_dump: %s", err);
282 0
                return (NULL);
283
        }
284
285 261
        p = WS_Copy(ctx->ws, buf, (int)l);
286 261
        if (p == NULL) {
287 0
                VRT_fail(ctx, "workspace_dump: copy failed");
288 0
                return (NULL);
289
        }
290 261
        return (VRT_blob(ctx, "workspace_dump", p, l, 0xd000d000));
291 261
}
292
293
/*--------------------------------------------------------------------*/
294
295
VCL_INT v_matchproto_(td_vtc_typesize)
296 550
vmod_typesize(VRT_CTX, VCL_STRING s)
297
{
298 550
        size_t i = 0, l, a, p = 0;
299
300 550
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
301 550
        AN(s);
302 550
        AN(*s);
303
304 2464
        for (; *s; s++) {
305 1936
                switch (*s) {
306
#define VTC_TYPESIZE(c, t) case c: l = sizeof(t); break;
307 242
                VTC_TYPESIZE('c', char)
308 66
                VTC_TYPESIZE('d', double)
309 22
                VTC_TYPESIZE('f', float)
310 66
                VTC_TYPESIZE('i', int)
311 22
                VTC_TYPESIZE('j', intmax_t)
312 22
                VTC_TYPESIZE('l', long)
313 22
                VTC_TYPESIZE('o', off_t)
314 352
                VTC_TYPESIZE('p', void *)
315 66
                VTC_TYPESIZE('s', short)
316 638
                VTC_TYPESIZE('u', unsigned)
317 396
                VTC_TYPESIZE('z', size_t)
318
#undef VTC_TYPESIZE
319 22
                default:        return (-1);
320
                }
321 1914
                if (l > p)
322 924
                        p = l;
323 1914
                a = i % l;
324 1914
                if (a != 0)
325 110
                        i += (l - a); /* align */
326 1914
                i += l;
327 1914
        }
328 528
        AN(p);
329 528
        a = i % p;
330 528
        if (a != 0)
331 132
                i += (p - a); /* pad */
332 528
        return ((VCL_INT)i);
333 550
}
334
335
/*--------------------------------------------------------------------*/
336
337
#define BLOB_VMOD_PROXY_HEADER_TYPE     0xc8f34f78
338
339
VCL_BLOB v_matchproto_(td_vtc_proxy_header)
340 44
vmod_proxy_header(VRT_CTX, VCL_ENUM venum, VCL_IP client, VCL_IP server,
341
    VCL_STRING authority)
342
{
343
        struct vsb *vsb;
344
        const void *h;
345
        int version;
346
        size_t l;
347
348 44
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
349
350 44
        if (venum == VENUM(v1))
351 22
                version = 1;
352 22
        else if (venum == VENUM(v2))
353 22
                version = 2;
354
        else
355 0
                WRONG(venum);
356
357 44
        vsb = VSB_new_auto();
358 44
        AN(vsb);
359 44
        VRT_Format_Proxy(vsb, version, client, server, authority);
360 44
        l = VSB_len(vsb);
361 44
        h = WS_Copy(ctx->ws, VSB_data(vsb), l);
362 44
        VSB_destroy(&vsb);
363
364 44
        if (h == NULL) {
365 0
                VRT_fail(ctx, "proxy_header: out of workspace");
366 0
                return (NULL);
367
        }
368
369 44
        return (VRT_blob(ctx, "proxy_header", h, l,
370
            BLOB_VMOD_PROXY_HEADER_TYPE));
371 44
}
372
373
// ref vsl.c
374
struct vsl_tag2enum {
375
        const char      *string;
376
        enum VSL_tag_e  tag;
377
};
378
379
static struct vsl_tag2enum vsl_tag2enum[SLT__MAX] = {
380
#define SLTM(name,flags,sdesc,ldesc) [SLT_ ## name] = { \
381
                .string = #name,                                \
382
                .tag = SLT_ ## name                             \
383
        },
384
#include "tbl/vsl_tags.h"
385
};
386
387
static int
388 1399178
vsl_tagcmp(const void *aa, const void *bb)
389
{
390 1399178
        const struct vsl_tag2enum *a = aa, *b = bb;
391
392
        // ref vsl2rst.c ptag_cmp
393 1399178
        if (a->string == NULL && b->string != NULL)
394 3168
                return (1);
395 1396010
        else if (a->string != NULL && b->string == NULL)
396 152482
                return (-1);
397 1243528
        else if (a->string == NULL && b->string == NULL)
398 267696
                return (0);
399 975832
        return (strcmp(a->string, b->string));
400 1399178
}
401
402
/*lint -esym(528, init_vsl_tag2enum) */
403
static void __attribute__((constructor))
404 1584
init_vsl_tag2enum(void)
405
{
406 1584
        qsort(vsl_tag2enum, SLT__MAX, sizeof *vsl_tag2enum, vsl_tagcmp);
407 1584
}
408
409
410
VCL_VOID
411 1342
vmod_vsl(VRT_CTX, VCL_INT id, VCL_STRING tag_s, VCL_ENUM side, VCL_STRANDS s)
412
{
413
        struct vsl_tag2enum *te, key;
414
        vxid_t vxid;
415
416 1342
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
417
418 1342
        key.string = tag_s;
419 1342
        te = bsearch(&key, vsl_tag2enum, SLT__MAX,
420
            sizeof *vsl_tag2enum, vsl_tagcmp);
421
422 1342
        if (te == NULL) {
423 0
                VRT_fail(ctx, "No such tag: %s", tag_s);
424 0
                return;
425
        }
426
427 1342
        if (id < 0 || id > VRT_INTEGER_MAX) {
428 0
                VRT_fail(ctx, "id out of bounds");
429 0
                return;
430
        }
431
432 1342
        vxid.vxid = id & VSL_IDENTMASK;
433 1342
        if (side == VENUM(c))
434 1298
                vxid.vxid |= VSL_CLIENTMARKER;
435 44
        else if (side == VENUM(b))
436 44
                vxid.vxid |= VSL_BACKENDMARKER;
437
        else
438 0
                WRONG("side");
439
440 1342
        VSLs(te->tag, vxid, s);
441 1342
}
442
443
static void
444 1298
vsl_line(VRT_CTX, char *str)
445
{
446
        VCL_INT id;
447
        VCL_ENUM side;
448
        VCL_STRANDS s;
449 1298
        const char *tag, *delim = " \t\r\n";
450
        char *e, *save;
451
452 1298
        if (*str == '*') {
453
                // varnishtest
454 1210
                str = strstr(str, "vsl|");
455 1210
                if (str == NULL)
456 0
                        return;
457 1210
                str += 4;
458 1210
        }
459 1298
        if ((str = strtok_r(str, delim, &save)) == NULL)
460 88
                return;
461 1210
        id = strtoll(str, &e, 10);
462 1210
        if (e == str)
463 0
                return;
464
465 1210
        if ((str = strtok_r(NULL, delim, &save)) == NULL)
466 0
                return;
467 1210
        tag = str;
468
469 1210
        if ((str = strtok_r(NULL, delim, &save)) == NULL)
470 0
                return;
471 1210
        if (*str == 'c')
472 1166
                side = VENUM(c);
473 44
        else if (*str == 'b')
474 44
                side = VENUM(b);
475
        else
476 0
                return;
477
478 1210
        str = strtok_r(NULL, "\r\n", &save);
479
        // needs to be assigned here because of the compound literal lifetime
480 1210
        s = TOSTRAND(str);
481 1210
        if (str == NULL)
482 176
                s = vrt_null_strands;
483
484 1210
        vmod_vsl(ctx, id, tag, side, s);
485 1298
}
486
487
VCL_VOID
488 44
vmod_vsl_replay(VRT_CTX, VCL_STRANDS s)
489
{
490
        struct vsb cp[1];
491
        const char *p, *pp;
492
        size_t l;
493 44
        int i, err = 0;
494
495 44
        CHECK_OBJ_ORNULL(s, STRANDS_MAGIC);
496 44
        if (s == NULL || s->n == 0)
497 0
                return;
498
499 44
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
500 44
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
501 44
        WS_VSB_new(cp, ctx->ws);
502
503 88
        for (i = 0; i < s->n; i++) {
504 44
                p = s->p[i];
505 44
                if (p == NULL || *p == '\0')
506 0
                        continue;
507 44
                pp = strpbrk(p, "\r\n");
508 1298
                while (pp != NULL) {
509 1254
                        l = pp - p;
510 1254
                        if (VSB_bcat(cp, p, l) || VSB_finish(cp)) {
511 0
                                err = 1;
512 0
                                break;
513
                        }
514 1254
                        vsl_line(ctx, VSB_data(cp));
515 1254
                        VSB_clear(cp);
516 1254
                        p = pp + 1;
517 1254
                        pp = strpbrk(p, "\r\n");
518
                }
519 44
                if (err || VSB_cat(cp, p)) {
520 0
                        err = 1;
521 0
                        break;
522
                }
523 44
        }
524 44
        if (err || VSB_finish(cp)) {
525 0
                AZ(WS_VSB_finish(cp, ctx->ws, NULL));
526 0
                VRT_fail(ctx, "out of workspace");
527 0
                return;
528
        }
529 44
        vsl_line(ctx, VSB_data(cp));
530 44
        VSB_clear(cp);
531 44
        AN(WS_VSB_finish(cp, ctx->ws, NULL));
532 44
}