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 120
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 120
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
55 120
        AN(addr);
56 120
        AN(*addr);
57 120
        assert(tmo >= 0.0);
58
59 120
        VSLb(ctx->vsl, SLT_Debug, "barrier_sync(\"%s\")", addr);
60 120
        sock = VTCP_open(addr, NULL, 0., &err);
61 120
        if (sock < 0) {
62 0
                VRT_fail(ctx, "Barrier connection failed: %s", err);
63 0
                return;
64
        }
65
66 120
        sz = VTCP_read(sock, buf, sizeof buf, tmo);
67 120
        i = errno;
68 120
        closefd(&sock);
69 120
        if (sz < 0)
70 0
                VRT_fail(ctx, "Barrier read failed: %s (errno=%d)",
71 0
                    strerror(i), i);
72 120
        if (sz > 0)
73 0
                VRT_fail(ctx, "Barrier unexpected data (%zdB)", sz);
74 120
}
75
76
/*--------------------------------------------------------------------*/
77
78
VCL_BACKEND v_matchproto_(td_vtc_no_backend)
79 9
vmod_no_backend(VRT_CTX)
80
{
81
82 9
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
83 9
        return (NULL);
84
}
85
86
VCL_STEVEDORE v_matchproto_(td_vtc_no_stevedore)
87 3
vmod_no_stevedore(VRT_CTX)
88
{
89
90 3
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
91 3
        return (NULL);
92
}
93
94
VCL_IP v_matchproto_(td_vtc_no_ip)
95 3
vmod_no_ip(VRT_CTX)
96
{
97
98 3
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
99 3
        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 39
vmod_sleep(VRT_CTX, VCL_DURATION t)
119
{
120
121 39
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
122 39
        VTIM_sleep(t);
123 39
}
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 1299
vtc_ws_find(VRT_CTX, VCL_ENUM which)
132
{
133
134 1299
        if (which == VENUM(client))
135 453
                return (ctx->ws);
136 846
        if (which == VENUM(backend))
137 759
                return (ctx->bo->ws);
138 87
        if (which == VENUM(session))
139 81
                return (ctx->req->sp->ws);
140 6
        if (which == VENUM(thread))
141 6
                return (ctx->req->wrk->aws);
142 0
        WRONG("vtc_ws_find Illegal enum");
143 1299
}
144
145
VCL_VOID v_matchproto_(td_vtc_workspace_alloc)
146 1176
vmod_workspace_alloc(VRT_CTX, VCL_ENUM which, VCL_INT size)
147
{
148
        struct ws *ws;
149
        void *p;
150
151 1176
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
152
153 1176
        ws = vtc_ws_find(ctx, which);
154 1176
        if (ws == NULL)
155 0
                return;
156 1176
        WS_Assert(ws);
157
158 1176
        if (size < 0) {
159 1128
                size += WS_ReserveAll(ws);
160 1128
                WS_Release(ws, 0);
161 1128
        }
162 1176
        if (size <= 0) {
163 6
                VRT_fail(ctx, "Attempted negative WS allocation");
164 6
                return;
165
        }
166 1170
        p = WS_Alloc(ws, size);
167 1170
        if (p == NULL)
168 3
                VRT_fail(ctx, "vtc.workspace_alloc");
169
        else
170 1167
                memset(p, '\0', size);
171 1176
}
172
173
VCL_BYTES v_matchproto_(td_vtc_workspace_reserve)
174 15
vmod_workspace_reserve(VRT_CTX, VCL_ENUM which, VCL_INT size)
175
{
176
        struct ws *ws;
177
        unsigned r;
178
179 15
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
180
181 15
        ws = vtc_ws_find(ctx, which);
182 15
        if (ws == NULL)
183 0
                return (0);
184 15
        WS_Assert(ws);
185
186 15
        if (size < 0) {
187 0
                size += WS_ReserveAll(ws);
188 0
                WS_Release(ws, 0);
189 0
        }
190 15
        if (size <= 0) {
191 0
                VRT_fail(ctx, "Attempted negative WS reservation");
192 0
                return (0);
193
        }
194 15
        r = WS_ReserveSize(ws, size);
195 15
        if (r == 0)
196 3
                return (0);
197 12
        WS_Release(ws, 0);
198 12
        return (r);
199 15
}
200
201
VCL_INT v_matchproto_(td_vtc_workspace_free)
202 48
vmod_workspace_free(VRT_CTX, VCL_ENUM which)
203
{
204
        struct ws *ws;
205
        unsigned u;
206
207 48
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
208
209 48
        ws = vtc_ws_find(ctx, which);
210 48
        if (ws == NULL)
211 0
                return (-1);
212 48
        WS_Assert(ws);
213
214 48
        u = WS_ReserveAll(ws);
215 48
        WS_Release(ws, 0);
216 48
        return (u);
217 48
}
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 3
VTC_WS_OP(VOID, , snapshot, (vtc_ws_snapshot = WS_Snapshot(ws)))
235 3
VTC_WS_OP(VOID, , reset, WS_Reset(ws, vtc_ws_snapshot))
236 3
VTC_WS_OP(VOID, , overflow, WS_MarkOverflow(ws))
237 15
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 36
vmod_workspace_dump(VRT_CTX, VCL_ENUM which, VCL_ENUM where,
242
    VCL_BYTES off, VCL_BYTES len)
243
{
244
        struct ws *ws;
245 36
        VCL_BYTES l, maxlen = 1024;
246 36
        unsigned char buf[maxlen];
247
        const char *p, *err;
248
249 36
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
250 36
        AN(where);
251
252 36
        ws = vtc_ws_find(ctx, which);
253 36
        if (ws == NULL)
254 0
                return (NULL);
255 36
        WS_Assert(ws);
256
257 36
        if (len > maxlen) {
258 0
                VRT_fail(ctx, "workspace_dump: max length is %jd",
259 0
                    (intmax_t)maxlen);
260 0
                return (NULL);
261
        }
262
263 36
        l = WS_Dump(ws, *where, off, buf, len);
264
265 36
        if (l == 0) {
266 0
                switch (errno) {
267 0
                case EINVAL: WRONG(where); break;
268 0
                case EAGAIN: err = "NULL"; break;
269 0
                case EFAULT: err = "off limit"; break;
270 0
                default: err = "unknown error"; break;
271
                }
272 0
                VRT_fail(ctx, "workspace_dump: %s", err);
273 0
                return (NULL);
274
        }
275
276 36
        assert(l < maxlen);
277 36
        p = WS_Copy(ctx->ws, buf, l);
278 36
        if (p == NULL) {
279 0
                VRT_fail(ctx, "workspace_dump: copy failed");
280 0
                return (NULL);
281
        }
282 36
        return (VRT_blob(ctx, "workspace_dump", p, l, 0xd000d000));
283 36
}
284
285
/*--------------------------------------------------------------------*/
286
287
VCL_INT v_matchproto_(td_vtc_typesize)
288 75
vmod_typesize(VRT_CTX, VCL_STRING s)
289
{
290 75
        size_t i = 0, l, a, p = 0;
291
292 75
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
293 75
        AN(s);
294 75
        AN(*s);
295
296 294
        for (; *s; s++) {
297 222
                switch (*s) {
298
#define VTC_TYPESIZE(c, t) case c: l = sizeof(t); break;
299 33
                VTC_TYPESIZE('c', char)
300 9
                VTC_TYPESIZE('d', double)
301 3
                VTC_TYPESIZE('f', float)
302 9
                VTC_TYPESIZE('i', int)
303 3
                VTC_TYPESIZE('j', intmax_t)
304 3
                VTC_TYPESIZE('l', long)
305 3
                VTC_TYPESIZE('o', off_t)
306 48
                VTC_TYPESIZE('p', void *)
307 9
                VTC_TYPESIZE('s', short)
308 45
                VTC_TYPESIZE('u', unsigned)
309 54
                VTC_TYPESIZE('z', size_t)
310
#undef VTC_TYPESIZE
311 3
                default:        return (-1);
312
                }
313 219
                if (l > p)
314 126
                        p = l;
315 219
                a = i % l;
316 219
                if (a != 0)
317 57
                        i += (l - a); /* align */
318 219
                i += l;
319 219
        }
320 72
        AN(p);
321 72
        a = i % p;
322 72
        if (a != 0)
323 18
                i += (p - a); /* pad */
324 72
        return ((VCL_INT)i);
325 75
}
326
327
/*--------------------------------------------------------------------*/
328
329
#define BLOB_VMOD_PROXY_HEADER_TYPE     0xc8f34f78
330
331
VCL_BLOB v_matchproto_(td_vtc_proxy_header)
332 6
vmod_proxy_header(VRT_CTX, VCL_ENUM venum, VCL_IP client, VCL_IP server,
333
    VCL_STRING authority)
334
{
335
        struct vsb *vsb;
336
        const void *h;
337
        int version;
338
        size_t l;
339
340 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
341
342 6
        if (venum == VENUM(v1))
343 3
                version = 1;
344 3
        else if (venum == VENUM(v2))
345 3
                version = 2;
346
        else
347 0
                WRONG(venum);
348
349 6
        vsb = VSB_new_auto();
350 6
        AN(vsb);
351 6
        VRT_Format_Proxy(vsb, version, client, server, authority);
352 6
        l = VSB_len(vsb);
353 6
        h = WS_Copy(ctx->ws, VSB_data(vsb), l);
354 6
        VSB_destroy(&vsb);
355
356 6
        if (h == NULL) {
357 0
                VRT_fail(ctx, "proxy_header: out of workspace");
358 0
                return (NULL);
359
        }
360
361 6
        return (VRT_blob(ctx, "proxy_header", h, l,
362
            BLOB_VMOD_PROXY_HEADER_TYPE));
363 6
}