varnish-cache/lib/libvcc/vcc_backend.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 */
30
31
#include "config.h"
32
33
#include <stdlib.h>
34
#include <string.h>
35
36
#include "vcc_compile.h"
37
38
/*--------------------------------------------------------------------
39
 * Struct sockaddr is not really designed to be a compile time
40
 * initialized data structure, so we encode it as a byte-string
41
 * and put it in an official sockaddr when we load the VCL.
42
 */
43
44
static void
45 916
Emit_Sockaddr(struct vcc *tl, const struct token *t_host,
46
    const struct token *t_port)
47
{
48
        const char *ipv4, *ipv4a, *ipv6, *ipv6a, *pa;
49
        char buf[256];
50
51 916
        AN(t_host->dec);
52
53 916
        if (t_port != NULL)
54 719
                bprintf(buf, "%s %s", t_host->dec, t_port->dec);
55
        else
56 197
                bprintf(buf, "%s", t_host->dec);
57 916
        Resolve_Sockaddr(tl, buf, "80",
58
            &ipv4, &ipv4a, &ipv6, &ipv6a, &pa, 2, t_host, "Backend host");
59 1832
        ERRCHK(tl);
60 914
        if (ipv4 != NULL) {
61 913
                Fb(tl, 0, "\t.ipv4_suckaddr = (const struct suckaddr *)%s,\n",
62
                    ipv4);
63 913
                Fb(tl, 0, "\t.ipv4_addr = \"%s\",\n", ipv4a);
64
        }
65 914
        if (ipv6 != NULL) {
66 2
                Fb(tl, 0, "\t.ipv6_suckaddr = (const struct suckaddr *)%s,\n",
67
                    ipv6);
68 2
                Fb(tl, 0, "\t.ipv6_addr = \"%s\",\n", ipv6a);
69
        }
70 914
        Fb(tl, 0, "\t.port = \"%s\",\n", pa);
71
}
72
73
/*--------------------------------------------------------------------
74
 * Parse a backend probe specification
75
 */
76
77
static void
78 8
vcc_ProbeRedef(struct vcc *tl, struct token **t_did,
79
    struct token *t_field)
80
{
81
        /* .url and .request are mutually exclusive */
82
83 8
        if (*t_did != NULL) {
84 2
                VSB_printf(tl->sb, "Probe request redefinition at:\n");
85 2
                vcc_ErrWhere(tl, t_field);
86 2
                VSB_printf(tl->sb, "Previous definition:\n");
87 2
                vcc_ErrWhere(tl, *t_did);
88 10
                return;
89
        }
90 6
        *t_did = t_field;
91
}
92
93
static void
94 24
vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **name)
95
{
96
        struct fld_spec *fs;
97
        struct token *t_field;
98 24
        struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL;
99 24
        struct token *t_initial = NULL;
100
        struct vsb *vsb;
101
        char *retval;
102
        unsigned window, threshold, initial, status;
103
        double t;
104
105 24
        fs = vcc_FldSpec(tl,
106
            "?url",
107
            "?request",
108
            "?expected_response",
109
            "?timeout",
110
            "?interval",
111
            "?window",
112
            "?threshold",
113
            "?initial",
114
            NULL);
115
116 31
        SkipToken(tl, '{');
117
118 24
        vsb = VSB_new_auto();
119 24
        AN(vsb);
120 24
        if (sym != NULL)
121 8
                VSB_cat(vsb, sym->rname);
122
        else
123 16
                VSB_printf(vsb, "vgc_probe__%d", tl->nprobe++);
124 24
        AZ(VSB_finish(vsb));
125 24
        retval = TlDup(tl, VSB_data(vsb));
126 24
        AN(retval);
127 24
        VSB_destroy(&vsb);
128 24
        if (name != NULL)
129 24
                *name = retval;
130
131 24
        window = 0;
132 24
        threshold = 0;
133 24
        initial = 0;
134 24
        status = 0;
135 24
        Fh(tl, 0, "static const struct vrt_backend_probe %s[] = {{\n", retval);
136 24
        Fh(tl, 0, "\t.magic = VRT_BACKEND_PROBE_MAGIC,\n");
137 94
        while (tl->t->tok != '}') {
138
139 49
                vcc_IsField(tl, &t_field, fs);
140 49
                ERRCHK(tl);
141 49
                if (vcc_IdIs(t_field, "url")) {
142 5
                        vcc_ProbeRedef(tl, &t_did, t_field);
143 5
                        ERRCHK(tl);
144 4
                        ExpectErr(tl, CSTR);
145 4
                        Fh(tl, 0, "\t.url = ");
146 4
                        EncToken(tl->fh, tl->t);
147 4
                        Fh(tl, 0, ",\n");
148 4
                        vcc_NextToken(tl);
149 44
                } else if (vcc_IdIs(t_field, "request")) {
150 3
                        vcc_ProbeRedef(tl, &t_did, t_field);
151 3
                        ERRCHK(tl);
152 2
                        ExpectErr(tl, CSTR);
153 2
                        Fh(tl, 0, "\t.request =\n");
154 8
                        while (tl->t->tok == CSTR) {
155 4
                                Fh(tl, 0, "\t\t");
156 4
                                EncToken(tl->fh, tl->t);
157 4
                                Fh(tl, 0, " \"\\r\\n\"\n");
158 4
                                vcc_NextToken(tl);
159
                        }
160 2
                        Fh(tl, 0, "\t\t\"\\r\\n\",\n");
161 41
                } else if (vcc_IdIs(t_field, "timeout")) {
162 3
                        Fh(tl, 0, "\t.timeout = ");
163 3
                        vcc_Duration(tl, &t);
164 3
                        ERRCHK(tl);
165 3
                        Fh(tl, 0, "%g,\n", t);
166 38
                } else if (vcc_IdIs(t_field, "interval")) {
167 9
                        Fh(tl, 0, "\t.interval = ");
168 9
                        vcc_Duration(tl, &t);
169 9
                        ERRCHK(tl);
170 9
                        Fh(tl, 0, "%g,\n", t);
171 29
                } else if (vcc_IdIs(t_field, "window")) {
172 9
                        t_window = tl->t;
173 9
                        window = vcc_UintVal(tl);
174 9
                        ERRCHK(tl);
175 20
                } else if (vcc_IdIs(t_field, "initial")) {
176 9
                        t_initial = tl->t;
177 9
                        initial = vcc_UintVal(tl);
178 9
                        ERRCHK(tl);
179 11
                } else if (vcc_IdIs(t_field, "expected_response")) {
180 2
                        status = vcc_UintVal(tl);
181 2
                        if (status < 100 || status > 999) {
182 1
                                VSB_printf(tl->sb,
183
                                    "Must specify .expected_response with "
184
                                    "exactly three digits "
185
                                    "(100 <= x <= 999)\n");
186 1
                                vcc_ErrWhere(tl, tl->t);
187 1
                                return;
188
                        }
189 1
                        ERRCHK(tl);
190 9
                } else if (vcc_IdIs(t_field, "threshold")) {
191 9
                        t_threshold = tl->t;
192 9
                        threshold = vcc_UintVal(tl);
193 9
                        ERRCHK(tl);
194
                } else {
195 0
                        vcc_ErrToken(tl, t_field);
196 0
                        vcc_ErrWhere(tl, t_field);
197 0
                        ErrInternal(tl);
198 0
                        return;
199
                }
200
201 46
                SkipToken(tl, ';');
202
        }
203
204 21
        if (t_threshold != NULL || t_window != NULL) {
205 10
                if (t_threshold == NULL && t_window != NULL) {
206 1
                        VSB_printf(tl->sb,
207
                            "Must specify .threshold with .window\n");
208 1
                        vcc_ErrWhere(tl, t_window);
209 1
                        return;
210 9
                } else if (t_threshold != NULL && t_window == NULL) {
211 1
                        if (threshold > 64) {
212 1
                                VSB_printf(tl->sb,
213
                                    "Threshold must be 64 or less.\n");
214 1
                                vcc_ErrWhere(tl, t_threshold);
215 1
                                return;
216
                        }
217 0
                        window = threshold + 1;
218 8
                } else if (window > 64) {
219 1
                        AN(t_window);
220 1
                        VSB_printf(tl->sb, "Window must be 64 or less.\n");
221 1
                        vcc_ErrWhere(tl, t_window);
222 1
                        return;
223
                }
224 7
                if (threshold > window ) {
225 1
                        VSB_printf(tl->sb,
226
                            "Threshold can not be greater than window.\n");
227 1
                        AN(t_threshold);
228 1
                        vcc_ErrWhere(tl, t_threshold);
229 1
                        AN(t_window);
230 1
                        vcc_ErrWhere(tl, t_window);
231
                }
232 7
                Fh(tl, 0, "\t.window = %u,\n", window);
233 7
                Fh(tl, 0, "\t.threshold = %u,\n", threshold);
234
        }
235 18
        if (t_initial != NULL)
236 9
                Fh(tl, 0, "\t.initial = %u,\n", initial);
237
        else
238 9
                Fh(tl, 0, "\t.initial = ~0U,\n");
239 18
        if (status > 0)
240 1
                Fh(tl, 0, "\t.exp_status = %u,\n", status);
241 18
        Fh(tl, 0, "}};\n");
242 18
        SkipToken(tl, '}');
243
}
244
245
/*--------------------------------------------------------------------
246
 * Parse and emit a probe definition
247
 */
248
249
void
250 9
vcc_ParseProbe(struct vcc *tl)
251
{
252
        struct token *t_probe;
253
        struct symbol *sym;
254
        char *p;
255
256 9
        vcc_NextToken(tl);                      /* ID: probe */
257
258 9
        vcc_ExpectVid(tl, "backend probe");     /* ID: name */
259 10
        ERRCHK(tl);
260 9
        t_probe = tl->t;
261 9
        vcc_NextToken(tl);
262
263 9
        sym = VCC_HandleSymbol(tl, t_probe, PROBE, "vgc_probe");
264 9
        ERRCHK(tl);
265 8
        AN(sym);
266
267 8
        vcc_ParseProbeSpec(tl, sym, &p);
268 8
        if (vcc_IdIs(t_probe, "default")) {
269 2
                (void)vcc_AddRef(tl, t_probe, SYM_PROBE);
270 2
                tl->default_probe = p;
271
        }
272
}
273
274
/*--------------------------------------------------------------------
275
 * Parse and emit a backend host definition
276
 *
277
 * The struct vrt_backend is emitted to Fh().
278
 */
279
280
static void
281 929
vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
282
{
283
        struct token *t_field;
284
        struct token *t_val;
285 929
        struct token *t_host = NULL;
286 929
        struct token *t_port = NULL;
287 929
        struct token *t_hosthdr = NULL;
288
        struct symbol *pb;
289
        struct fld_spec *fs;
290
        struct inifin *ifp;
291
        struct vsb *vsb;
292
        char *p;
293
        unsigned u;
294
        double t;
295
296 929
        fs = vcc_FldSpec(tl,
297
            "!host",
298
            "?port",
299
            "?host_header",
300
            "?connect_timeout",
301
            "?first_byte_timeout",
302
            "?between_bytes_timeout",
303
            "?probe",
304
            "?max_connections",
305
            "?proxy_header",
306
            NULL);
307
308 944
        SkipToken(tl, '{');
309
310 929
        vsb = VSB_new_auto();
311 929
        AN(vsb);
312 929
        tl->fb = vsb;
313
314 929
        Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n",
315
            vgcname);
316
317 929
        Fb(tl, 0, "\t.magic = VRT_BACKEND_MAGIC,\n");
318 929
        Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be));
319 929
        Fb(tl, 0, "\",\n");
320
321
        /* Check for old syntax */
322 929
        if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
323 1
                VSB_printf(tl->sb,
324
                    "NB: Backend Syntax has changed:\n"
325
                    "Remove \"set\" and \"backend\" in front"
326
                    " of backend fields.\n" );
327 1
                vcc_ErrToken(tl, tl->t);
328 1
                VSB_printf(tl->sb, " at ");
329 1
                vcc_ErrWhere(tl, tl->t);
330 1
                return;
331
        }
332
333 3529
        while (tl->t->tok != '}') {
334
335 1684
                vcc_IsField(tl, &t_field, fs);
336 1684
                ERRCHK(tl);
337 1682
                if (vcc_IdIs(t_field, "host")) {
338 927
                        ExpectErr(tl, CSTR);
339 927
                        assert(tl->t->dec != NULL);
340 927
                        t_host = tl->t;
341 927
                        vcc_NextToken(tl);
342 927
                        SkipToken(tl, ';');
343 755
                } else if (vcc_IdIs(t_field, "port")) {
344 721
                        ExpectErr(tl, CSTR);
345 721
                        assert(tl->t->dec != NULL);
346 721
                        t_port = tl->t;
347 721
                        vcc_NextToken(tl);
348 721
                        SkipToken(tl, ';');
349 34
                } else if (vcc_IdIs(t_field, "host_header")) {
350 1
                        ExpectErr(tl, CSTR);
351 1
                        assert(tl->t->dec != NULL);
352 1
                        t_hosthdr = tl->t;
353 1
                        vcc_NextToken(tl);
354 1
                        SkipToken(tl, ';');
355 33
                } else if (vcc_IdIs(t_field, "connect_timeout")) {
356 0
                        Fb(tl, 0, "\t.connect_timeout = ");
357 0
                        vcc_Duration(tl, &t);
358 0
                        ERRCHK(tl);
359 0
                        Fb(tl, 0, "%g,\n", t);
360 0
                        SkipToken(tl, ';');
361 33
                } else if (vcc_IdIs(t_field, "first_byte_timeout")) {
362 3
                        Fb(tl, 0, "\t.first_byte_timeout = ");
363 3
                        vcc_Duration(tl, &t);
364 3
                        ERRCHK(tl);
365 3
                        Fb(tl, 0, "%g,\n", t);
366 3
                        SkipToken(tl, ';');
367 30
                } else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
368 1
                        Fb(tl, 0, "\t.between_bytes_timeout = ");
369 1
                        vcc_Duration(tl, &t);
370 1
                        ERRCHK(tl);
371 1
                        Fb(tl, 0, "%g,\n", t);
372 1
                        SkipToken(tl, ';');
373 29
                } else if (vcc_IdIs(t_field, "max_connections")) {
374 3
                        u = vcc_UintVal(tl);
375 3
                        ERRCHK(tl);
376 3
                        SkipToken(tl, ';');
377 3
                        Fb(tl, 0, "\t.max_connections = %u,\n", u);
378 26
                } else if (vcc_IdIs(t_field, "proxy_header")) {
379 4
                        t_val = tl->t;
380 4
                        u = vcc_UintVal(tl);
381 4
                        ERRCHK(tl);
382 4
                        if (u != 1 && u != 2) {
383 0
                                VSB_printf(tl->sb,
384
                                    ".proxy_header must be 1 or 2\n");
385 0
                                vcc_ErrWhere(tl, t_val);
386 0
                                return;
387
                        }
388 4
                        SkipToken(tl, ';');
389 4
                        Fb(tl, 0, "\t.proxy_header = %u,\n", u);
390 22
                } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
391 16
                        vcc_ParseProbeSpec(tl, NULL, &p);
392 16
                        Fb(tl, 0, "\t.probe = %s,\n", p);
393 16
                        ERRCHK(tl);
394 6
                } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) {
395 5
                        pb = VCC_SymbolTok(tl, NULL, tl->t, SYM_PROBE, 0);
396 5
                        if (pb == NULL) {
397 2
                                VSB_printf(tl->sb, "Probe %.*s not found\n",
398 2
                                    PF(tl->t));
399 1
                                vcc_ErrWhere(tl, tl->t);
400 1
                                return;
401
                        }
402 4
                        Fb(tl, 0, "\t.probe = %s,\n", pb->rname);
403 4
                        (void)vcc_AddRef(tl, tl->t, SYM_PROBE);
404 4
                        vcc_NextToken(tl);
405 4
                        SkipToken(tl, ';');
406 1
                } else if (vcc_IdIs(t_field, "probe")) {
407 1
                        VSB_printf(tl->sb,
408
                            "Expected '{' or name of probe, got ");
409 1
                        vcc_ErrToken(tl, tl->t);
410 1
                        VSB_printf(tl->sb, " at\n");
411 1
                        vcc_ErrWhere(tl, tl->t);
412 1
                        return;
413
                } else {
414 0
                        ErrInternal(tl);
415 0
                        return;
416
                }
417
418
        }
419
420 917
        vcc_FieldsOk(tl, fs);
421 917
        ERRCHK(tl);
422
423
        /* Check that the hostname makes sense */
424 916
        assert(t_host != NULL);
425 916
        Emit_Sockaddr(tl, t_host, t_port);
426 916
        ERRCHK(tl);
427
428 914
        ExpectErr(tl, '}');
429
430
        /* We have parsed it all, emit the ident string */
431
432
        /* Emit the hosthdr field, fall back to .host if not specified */
433 914
        Fb(tl, 0, "\t.hosthdr = ");
434 914
        if (t_hosthdr != NULL)
435 1
                EncToken(tl->fb, t_hosthdr);
436
        else
437 913
                EncToken(tl->fb, t_host);
438 914
        Fb(tl, 0, ",\n");
439
440
        /* Close the struct */
441 914
        Fb(tl, 0, "};\n");
442
443 914
        vcc_NextToken(tl);
444
445 914
        tl->fb = NULL;
446 914
        AZ(VSB_finish(vsb));
447 914
        Fh(tl, 0, "%s", VSB_data(vsb));
448 914
        VSB_destroy(&vsb);
449
450 914
        ifp = New_IniFin(tl);
451 914
        VSB_printf(ifp->ini,
452
            "\t%s =\n\t    VRT_new_backend(ctx, &vgc_dir_priv_%s);",
453
            vgcname, vgcname);
454
}
455
456
/*--------------------------------------------------------------------
457
 * Parse directors and backends
458
 */
459
460
void
461 933
vcc_ParseBackend(struct vcc *tl)
462
{
463
        struct token *t_first, *t_be;
464
        struct symbol *sym;
465
466 933
        t_first = tl->t;
467 933
        vcc_NextToken(tl);              /* ID: backend */
468
469 933
        vcc_ExpectVid(tl, "backend");   /* ID: name */
470 933
        ERRCHK(tl);
471
472 932
        t_be = tl->t;
473 932
        vcc_NextToken(tl);
474
475 932
        sym = VCC_HandleSymbol(tl, t_be, BACKEND, "vgc_backend");
476 932
        ERRCHK(tl);
477
478 929
        Fh(tl, 0, "\nstatic struct director *%s;\n", sym->rname);
479
480 929
        vcc_ParseHostDef(tl, t_be, sym->rname);
481 929
        ERRCHK(tl);
482
483 914
        if (tl->err) {
484 0
                VSB_printf(tl->sb,
485 0
                    "\nIn %.*s specification starting at:\n", PF(t_first));
486 0
                vcc_ErrWhere(tl, t_first);
487 0
                return;
488
        }
489
490 914
        if (tl->default_director == NULL || vcc_IdIs(t_be, "default")) {
491 834
                tl->default_director = sym->rname;
492 834
                tl->t_default_director = t_be;
493
        }
494
}