varnish-cache/vmod/vmod_vtc.c
1
/*-
2
 * Copyright (c) 2012-2017 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
6
 * Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
7
 *
8
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include "config.h"
33
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 714
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 714
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
55 714
        AN(addr);
56 714
        AN(*addr);
57 714
        assert(tmo >= 0.0);
58
59 714
        VSLb(ctx->vsl, SLT_Debug, "barrier_sync(\"%s\")", addr);
60 714
        sock = VTCP_open(addr, NULL, 0., &err);
61 714
        if (sock < 0) {
62 0
                VRT_fail(ctx, "Barrier connection failed: %s", err);
63 0
                return;
64
        }
65
66 714
        sz = VTCP_read(sock, buf, sizeof buf, tmo);
67 714
        i = errno;
68 714
        closefd(&sock);
69 714
        if (sz < 0)
70 0
                VRT_fail(ctx, "Barrier read failed: %s (errno=%d)",
71 0
                    strerror(i), i);
72 714
        if (sz > 0)
73 0
                VRT_fail(ctx, "Barrier unexpected data (%zdB)", sz);
74 714
}
75
76
/*--------------------------------------------------------------------*/
77
78
VCL_BACKEND v_matchproto_(td_vtc_no_backend)
79 63
vmod_no_backend(VRT_CTX)
80
{
81
82 63
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
83 63
        return (NULL);
84
}
85
86
VCL_STEVEDORE v_matchproto_(td_vtc_no_stevedore)
87 21
vmod_no_stevedore(VRT_CTX)
88
{
89
90 21
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
91 21
        return (NULL);
92
}
93
94
VCL_IP v_matchproto_(td_vtc_no_ip)
95 21
vmod_no_ip(VRT_CTX)
96
{
97
98 21
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
99 21
        return (NULL);
100
}
101
102
/*--------------------------------------------------------------------*/
103
104
VCL_VOID v_noreturn_ v_matchproto_(td_vtc_panic)
105 0
vmod_panic(VRT_CTX, VCL_STRANDS str)
106
{
107
        const char *b;
108
109 0
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
110
111 0
        b = VRT_StrandsWS(ctx->ws, "PANIC:", str);
112 0
        VAS_Fail("VCL", "", 0, b, VAS_VCL);
113
}
114
115
/*--------------------------------------------------------------------*/
116
117
VCL_VOID v_matchproto_(td_vtc_sleep)
118 147
vmod_sleep(VRT_CTX, VCL_DURATION t)
119
{
120
121 147
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
122 147
        VTIM_sleep(t);
123 147
}
124
125
/*--------------------------------------------------------------------*/
126
127
// XXX this really should be PRIV_TASK state
128
static uintptr_t vtc_ws_snapshot;
129
130
static struct ws *
131 9176
vtc_ws_find(VRT_CTX, VCL_ENUM which)
132
{
133
134 9176
        if (which == VENUM(client))
135 3150
                return (ctx->ws);
136 6027
        if (which == VENUM(backend))
137 5313
                return (ctx->bo->ws);
138 714
        if (which == VENUM(session))
139 672
                return (ctx->req->sp->ws);
140 42
        if (which == VENUM(thread))
141 42
                return (ctx->req->wrk->aws);
142 0
        WRONG("vtc_ws_find Illegal enum");
143 9177
}
144
145
VCL_VOID v_matchproto_(td_vtc_workspace_alloc)
146 8211
vmod_workspace_alloc(VRT_CTX, VCL_ENUM which, VCL_INT size)
147
{
148
        struct ws *ws;
149
        void *p;
150
151 8211
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
152
153 8211
        ws = vtc_ws_find(ctx, which);
154 8211
        if (ws == NULL)
155 0
                return;
156 8211
        WS_Assert(ws);
157
158 8211
        if (size < 0) {
159 7875
                size += WS_ReserveAll(ws);
160 7875
                WS_Release(ws, 0);
161 7875
        }
162 8211
        if (size <= 0) {
163 42
                VRT_fail(ctx, "Attempted negative WS allocation");
164 42
                return;
165
        }
166 8169
        p = WS_Alloc(ws, size);
167 8169
        if (p == NULL)
168 21
                VRT_fail(ctx, "vtc.workspace_alloc");
169
        else
170 8148
                memset(p, '\0', size);
171 8211
}
172
173
VCL_BYTES v_matchproto_(td_vtc_workspace_reserve)
174 105
vmod_workspace_reserve(VRT_CTX, VCL_ENUM which, VCL_INT size)
175
{
176
        struct ws *ws;
177
        unsigned r;
178
179 105
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
180
181 105
        ws = vtc_ws_find(ctx, which);
182 105
        if (ws == NULL)
183 0
                return (0);
184 105
        WS_Assert(ws);
185
186 105
        if (size < 0) {
187 0
                size += WS_ReserveAll(ws);
188 0
                WS_Release(ws, 0);
189 0
        }
190 105
        if (size <= 0) {
191 0
                VRT_fail(ctx, "Attempted negative WS reservation");
192 0
                return (0);
193
        }
194 105
        r = WS_ReserveSize(ws, size);
195 105
        if (r == 0)
196 21
                return (0);
197 84
        WS_Release(ws, 0);
198 84
        return (r);
199 105
}
200
201
VCL_INT v_matchproto_(td_vtc_workspace_free)
202 441
vmod_workspace_free(VRT_CTX, VCL_ENUM which)
203
{
204
        struct ws *ws;
205
        unsigned u;
206
207 441
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
208
209 441
        ws = vtc_ws_find(ctx, which);
210 441
        if (ws == NULL)
211 0
                return (-1);
212 441
        WS_Assert(ws);
213
214 441
        u = WS_ReserveAll(ws);
215 441
        WS_Release(ws, 0);
216 441
        return (u);
217 440
}
218
219
#define VTC_WS_OP(type, def, name, op)                  \
220
VCL_##type v_matchproto_(td_vtc_workspace_##name)       \
221
vmod_workspace_##name(VRT_CTX, VCL_ENUM which)          \
222
{                                                       \
223
        struct ws *ws;                                  \
224
                                                        \
225
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);          \
226
                                                        \
227
        ws = vtc_ws_find(ctx, which);                   \
228
        if (ws == NULL)                                 \
229
                return def ;                            \
230
        WS_Assert(ws);                                  \
231
                                                        \
232
        op;                                             \
233
}
234 21
VTC_WS_OP(VOID, , snapshot, (vtc_ws_snapshot = WS_Snapshot(ws)))
235 21
VTC_WS_OP(VOID, , reset, WS_Reset(ws, vtc_ws_snapshot))
236 21
VTC_WS_OP(VOID, , overflow, WS_MarkOverflow(ws))
237 105
VTC_WS_OP(BOOL, (0), overflowed, return (WS_Overflowed(ws)))
238
#undef VTC_WS_OP
239
240
VCL_BLOB v_matchproto_(td_vtc_workspace_dump)
241 252
vmod_workspace_dump(VRT_CTX, VCL_ENUM which, VCL_ENUM where,
242
    VCL_BYTES off, VCL_BYTES len)
243
{
244
        struct ws *ws;
245 252
        VCL_BYTES l, maxlen = 1024;
246 252
        unsigned char buf[maxlen];
247
        const char *p;
248
249 252
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
250
251 252
        ws = vtc_ws_find(ctx, which);
252 252
        if (ws == NULL)
253 0
                return (NULL);
254 252
        WS_Assert(ws);
255
256 252
        if (len > maxlen) {
257 0
                VRT_fail(ctx, "workspace_dump: max length is %jd",
258 0
                    (intmax_t)maxlen);
259 0
                return (NULL);
260
        }
261
262 252
        if (where == VENUM(s))
263 0
                p = ws->s;
264 252
        else if (where == VENUM(f))
265 252
                p = ws->f;
266 0
        else if (where == VENUM(r))
267 0
                p = ws->r;
268
        else
269 0
                INCOMPL();
270
271 252
        if (p == NULL) {
272 0
                VSLb(ctx->vsl, SLT_Error, "workspace_dump: NULL");
273 0
                return (NULL);
274
        }
275
276 252
        p += off;
277 252
        if (p >= ws->e) {
278 0
                VSLb(ctx->vsl, SLT_Error, "workspace_dump: off limit");
279 0
                return (NULL);
280
        }
281
282 252
        l = pdiff(p, ws->e);
283 252
        if (len < l)
284 251
                l = len;
285
286 251
        assert(l < maxlen);
287 251
        memcpy(buf, p, l);
288 251
        p = WS_Copy(ctx->ws, buf, l);
289 251
        if (p == NULL) {
290 0
                VRT_fail(ctx, "workspace_dump: copy failed");
291 0
                return (NULL);
292
        }
293 252
        return (VRT_blob(ctx, "workspace_dump", p, l, 0xd000d000));
294 252
}
295
296
/*--------------------------------------------------------------------*/
297
298
VCL_INT v_matchproto_(td_vtc_typesize)
299 525
vmod_typesize(VRT_CTX, VCL_STRING s)
300
{
301 525
        size_t i = 0, l, a, p = 0;
302
303 525
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
304 525
        AN(s);
305 525
        AN(*s);
306
307 2058
        for (; *s; s++) {
308 1554
                switch (*s) {
309
#define VTC_TYPESIZE(c, t) case c: l = sizeof(t); break;
310 231
                VTC_TYPESIZE('c', char)
311 63
                VTC_TYPESIZE('d', double)
312 21
                VTC_TYPESIZE('f', float)
313 63
                VTC_TYPESIZE('i', int)
314 21
                VTC_TYPESIZE('j', intmax_t)
315 21
                VTC_TYPESIZE('l', long)
316 21
                VTC_TYPESIZE('o', off_t)
317 336
                VTC_TYPESIZE('p', void *)
318 63
                VTC_TYPESIZE('s', short)
319 315
                VTC_TYPESIZE('u', unsigned)
320 378
                VTC_TYPESIZE('z', size_t)
321
#undef VTC_TYPESIZE
322 21
                default:        return (-1);
323
                }
324 1533
                if (l > p)
325 882
                        p = l;
326 1533
                a = i % l;
327 1533
                if (a != 0)
328 399
                        i += (l - a); /* align */
329 1533
                i += l;
330 1533
        }
331 504
        AN(p);
332 504
        a = i % p;
333 504
        if (a != 0)
334 126
                i += (p - a); /* pad */
335 504
        return ((VCL_INT)i);
336 525
}
337
338
/*--------------------------------------------------------------------*/
339
340
#define BLOB_VMOD_PROXY_HEADER_TYPE     0xc8f34f78
341
342
VCL_BLOB v_matchproto_(td_vtc_proxy_header)
343 42
vmod_proxy_header(VRT_CTX, VCL_ENUM venum, VCL_IP client, VCL_IP server,
344
    VCL_STRING authority)
345
{
346
        struct vsb *vsb;
347
        const void *h;
348
        int version;
349
        size_t l;
350
351 42
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
352
353 42
        if (venum == VENUM(v1))
354 21
                version = 1;
355 21
        else if (venum == VENUM(v2))
356 21
                version = 2;
357
        else
358 0
                WRONG(venum);
359
360 42
        vsb = VSB_new_auto();
361 42
        AN(vsb);
362 42
        VRT_Format_Proxy(vsb, version, client, server, authority);
363 42
        l = VSB_len(vsb);
364 42
        h = WS_Copy(ctx->ws, VSB_data(vsb), l);
365 42
        VSB_destroy(&vsb);
366
367 42
        if (h == NULL) {
368 0
                VRT_fail(ctx, "proxy_header: out of workspace");
369 0
                return (NULL);
370
        }
371
372 42
        return (VRT_blob(ctx, "proxy_header", h, l,
373
            BLOB_VMOD_PROXY_HEADER_TYPE));
374 42
}