| | varnish-cache/lib/libvcc/vcc_backend.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
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 |
|
|
32 |
|
#include "config.h" |
33 |
|
|
34 |
|
#include <stdlib.h> |
35 |
|
#include <string.h> |
36 |
|
#include <sys/stat.h> |
37 |
|
|
38 |
|
#include "vcc_compile.h" |
39 |
|
#include "vus.h" |
40 |
|
|
41 |
|
const char * |
42 |
25 |
vcc_default_probe(struct vcc *tl) |
43 |
|
{ |
44 |
|
|
45 |
25 |
if (tl->default_probe != NULL) |
46 |
0 |
return (tl->default_probe); |
47 |
25 |
VSB_cat(tl->sb, "No default probe defined\n"); |
48 |
25 |
vcc_ErrToken(tl, tl->t); |
49 |
25 |
VSB_cat(tl->sb, " at\n"); |
50 |
25 |
vcc_ErrWhere(tl, tl->t); |
51 |
25 |
return (""); |
52 |
25 |
} |
53 |
|
|
54 |
|
/*-------------------------------------------------------------------- |
55 |
|
* Struct sockaddr is not really designed to be a compile time |
56 |
|
* initialized data structure, so we encode it as a byte-string |
57 |
|
* and put it in an official sockaddr when we load the VCL. |
58 |
|
*/ |
59 |
|
|
60 |
|
static void |
61 |
32700 |
Emit_Sockaddr(struct vcc *tl, struct vsb *vsb1, const struct token *t_host, |
62 |
|
const struct token *t_port) |
63 |
|
{ |
64 |
|
const char *ipv4, *ipv4a, *ipv6, *ipv6a, *pa; |
65 |
|
char buf[BUFSIZ]; |
66 |
|
|
67 |
32700 |
AN(t_host->dec); |
68 |
|
|
69 |
32700 |
if (t_port != NULL) |
70 |
24750 |
bprintf(buf, "%s %s", t_host->dec, t_port->dec); |
71 |
|
else |
72 |
7950 |
bprintf(buf, "%s", t_host->dec); |
73 |
65400 |
Resolve_Sockaddr(tl, buf, "80", |
74 |
32700 |
&ipv4, &ipv4a, &ipv6, &ipv6a, &pa, 2, t_host, "Backend host"); |
75 |
32700 |
ERRCHK(tl); |
76 |
32650 |
if (ipv4 != NULL) { |
77 |
65000 |
VSB_printf(vsb1, |
78 |
|
"\t.ipv4 = (const struct suckaddr *)%s,\n", |
79 |
32500 |
ipv4); |
80 |
32500 |
} |
81 |
32650 |
if (ipv6 != NULL) { |
82 |
650 |
VSB_printf(vsb1, |
83 |
|
"\t.ipv6 = (const struct suckaddr *)%s,\n", |
84 |
325 |
ipv6); |
85 |
325 |
} |
86 |
32650 |
VSB_cat(vsb1, "\t.uds_path = (void *) 0,\n"); |
87 |
32700 |
} |
88 |
|
|
89 |
|
/* |
90 |
|
* For UDS, we do not create a VSA. We run the VUS_resolver() checks and, if |
91 |
|
* it's a path, can be accessed, and is a socket. If so, just emit the path |
92 |
|
* field and set the IP suckaddrs to NULL. |
93 |
|
*/ |
94 |
|
|
95 |
|
static int |
96 |
800 |
uds_resolved(void *priv, const struct sockaddr_un *uds) |
97 |
|
{ |
98 |
800 |
(void) priv; |
99 |
800 |
(void) uds; |
100 |
800 |
return (42); |
101 |
|
} |
102 |
|
|
103 |
|
static void |
104 |
775 |
emit_path(struct vsb *vsb1, char *path) |
105 |
|
{ |
106 |
775 |
VSB_printf(vsb1, "\t.uds_path = \"%s\",\n", path); |
107 |
775 |
VSB_cat(vsb1, "\t.ipv4 = (void *) 0,\n"); |
108 |
775 |
VSB_cat(vsb1, "\t.ipv6 = (void *) 0,\n"); |
109 |
775 |
} |
110 |
|
|
111 |
|
static void |
112 |
850 |
Emit_UDS_Path(struct vcc *tl, struct vsb *vsb1, |
113 |
|
const struct token *t_path, const char *errid) |
114 |
|
{ |
115 |
|
struct stat st; |
116 |
|
const char *vus_err; |
117 |
|
|
118 |
850 |
AN(t_path); |
119 |
850 |
AN(t_path->dec); |
120 |
|
|
121 |
850 |
if (! VUS_is(t_path->dec)) { |
122 |
50 |
VSB_printf(tl->sb, |
123 |
|
"%s: Must be a valid path or abstract socket:\n", |
124 |
25 |
errid); |
125 |
25 |
vcc_ErrWhere(tl, t_path); |
126 |
25 |
return; |
127 |
|
} |
128 |
825 |
if (VUS_resolver(t_path->dec, uds_resolved, NULL, &vus_err) != 42) { |
129 |
25 |
VSB_printf(tl->sb, "%s: %s\n", errid, vus_err); |
130 |
25 |
vcc_ErrWhere(tl, t_path); |
131 |
25 |
return; |
132 |
|
} |
133 |
800 |
if (*t_path->dec == '@') { |
134 |
0 |
emit_path(vsb1, t_path->dec); |
135 |
0 |
return; |
136 |
|
} |
137 |
800 |
assert(*t_path->dec == '/'); |
138 |
800 |
errno = 0; |
139 |
800 |
if (stat(t_path->dec, &st) != 0) { |
140 |
25 |
int err = errno; |
141 |
50 |
VSB_printf(tl->sb, "%s: Cannot stat: %s\n", errid, |
142 |
25 |
strerror(errno)); |
143 |
25 |
vcc_ErrWhere(tl, t_path); |
144 |
25 |
if (err == ENOENT || err == EACCES) |
145 |
25 |
vcc_Warn(tl); |
146 |
|
else |
147 |
0 |
return; |
148 |
800 |
} else if (!S_ISSOCK(st.st_mode)) { |
149 |
25 |
VSB_printf(tl->sb, "%s: Not a socket:\n", errid); |
150 |
25 |
vcc_ErrWhere(tl, t_path); |
151 |
25 |
return; |
152 |
|
} |
153 |
775 |
emit_path(vsb1, t_path->dec); |
154 |
850 |
} |
155 |
|
|
156 |
|
/*-------------------------------------------------------------------- |
157 |
|
* Disallow mutually exclusive field definitions |
158 |
|
*/ |
159 |
|
|
160 |
|
static void |
161 |
34375 |
vcc_Redef(struct vcc *tl, const char *redef, const struct token **t_did, |
162 |
|
const struct token *t_field) |
163 |
|
{ |
164 |
34375 |
if (*t_did != NULL) { |
165 |
75 |
VSB_printf(tl->sb, "%s redefinition at:\n", redef); |
166 |
75 |
vcc_ErrWhere(tl, t_field); |
167 |
75 |
VSB_cat(tl->sb, "Previous definition:\n"); |
168 |
75 |
vcc_ErrWhere(tl, *t_did); |
169 |
75 |
return; |
170 |
|
} |
171 |
34300 |
*t_did = t_field; |
172 |
34375 |
} |
173 |
|
|
174 |
|
/*-------------------------------------------------------------------- |
175 |
|
* Parse a backend probe specification |
176 |
|
*/ |
177 |
|
|
178 |
|
static void |
179 |
1125 |
vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **namep) |
180 |
|
{ |
181 |
|
struct fld_spec *fs; |
182 |
|
const struct token *t_field; |
183 |
1125 |
const struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL; |
184 |
1125 |
struct token *t_initial = NULL; |
185 |
|
unsigned window, threshold, initial, status, exp_close; |
186 |
|
char buf[32]; |
187 |
|
const char *name; |
188 |
|
double t; |
189 |
|
|
190 |
1125 |
fs = vcc_FldSpec(tl, |
191 |
|
"?url", |
192 |
|
"?request", |
193 |
|
"?expected_response", |
194 |
|
"?timeout", |
195 |
|
"?interval", |
196 |
|
"?window", |
197 |
|
"?threshold", |
198 |
|
"?initial", |
199 |
|
"?expect_close", |
200 |
|
NULL); |
201 |
|
|
202 |
1125 |
SkipToken(tl, '{'); |
203 |
|
|
204 |
1125 |
if (sym != NULL) { |
205 |
275 |
name = sym->rname; |
206 |
275 |
} else { |
207 |
850 |
bprintf(buf, "vgc_probe__%d", tl->nprobe++); |
208 |
850 |
name = buf; |
209 |
|
} |
210 |
1125 |
Fh(tl, 0, "static const struct vrt_backend_probe %s[] = {{\n", name); |
211 |
1125 |
Fh(tl, 0, "\t.magic = VRT_BACKEND_PROBE_MAGIC,\n"); |
212 |
1125 |
if (namep != NULL) |
213 |
850 |
*namep = TlDup(tl, name); |
214 |
|
|
215 |
1125 |
window = 0; |
216 |
1125 |
threshold = 0; |
217 |
1125 |
initial = 0; |
218 |
1125 |
status = 0; |
219 |
1125 |
exp_close = 1; |
220 |
3625 |
while (tl->t->tok != '}') { |
221 |
|
|
222 |
2650 |
vcc_IsField(tl, &t_field, fs); |
223 |
2650 |
ERRCHK(tl); |
224 |
2650 |
if (vcc_IdIs(t_field, "url")) { |
225 |
275 |
vcc_Redef(tl, "Probe request", &t_did, t_field); |
226 |
275 |
ERRCHK(tl); |
227 |
250 |
ExpectErr(tl, CSTR); |
228 |
250 |
Fh(tl, 0, "\t.url = "); |
229 |
250 |
EncToken(tl->fh, tl->t); |
230 |
250 |
Fh(tl, 0, ",\n"); |
231 |
250 |
vcc_NextToken(tl); |
232 |
2625 |
} else if (vcc_IdIs(t_field, "request")) { |
233 |
125 |
vcc_Redef(tl, "Probe request", &t_did, t_field); |
234 |
125 |
ERRCHK(tl); |
235 |
100 |
ExpectErr(tl, CSTR); |
236 |
100 |
Fh(tl, 0, "\t.request =\n"); |
237 |
400 |
while (tl->t->tok == CSTR) { |
238 |
300 |
Fh(tl, 0, "\t\t"); |
239 |
300 |
EncToken(tl->fh, tl->t); |
240 |
300 |
Fh(tl, 0, " \"\\r\\n\"\n"); |
241 |
300 |
vcc_NextToken(tl); |
242 |
|
} |
243 |
100 |
Fh(tl, 0, "\t\t\"\\r\\n\",\n"); |
244 |
2350 |
} else if (vcc_IdIs(t_field, "timeout")) { |
245 |
225 |
Fh(tl, 0, "\t.timeout = "); |
246 |
225 |
vcc_Duration(tl, &t); |
247 |
225 |
ERRCHK(tl); |
248 |
200 |
Fh(tl, 0, "%g,\n", t); |
249 |
2225 |
} else if (vcc_IdIs(t_field, "interval")) { |
250 |
600 |
Fh(tl, 0, "\t.interval = "); |
251 |
600 |
vcc_Duration(tl, &t); |
252 |
600 |
ERRCHK(tl); |
253 |
600 |
Fh(tl, 0, "%g,\n", t); |
254 |
2025 |
} else if (vcc_IdIs(t_field, "window")) { |
255 |
450 |
t_window = tl->t; |
256 |
450 |
window = vcc_UintVal(tl); |
257 |
450 |
ERRCHK(tl); |
258 |
1425 |
} else if (vcc_IdIs(t_field, "initial")) { |
259 |
325 |
t_initial = tl->t; |
260 |
325 |
initial = vcc_UintVal(tl); |
261 |
325 |
ERRCHK(tl); |
262 |
975 |
} else if (vcc_IdIs(t_field, "expected_response")) { |
263 |
50 |
status = vcc_UintVal(tl); |
264 |
50 |
if (status < 100 || status > 999) { |
265 |
25 |
VSB_cat(tl->sb, |
266 |
|
"Must specify .expected_response with " |
267 |
|
"exactly three digits " |
268 |
|
"(100 <= x <= 999)\n"); |
269 |
25 |
vcc_ErrWhere(tl, tl->t); |
270 |
25 |
return; |
271 |
|
} |
272 |
25 |
ERRCHK(tl); |
273 |
625 |
} else if (vcc_IdIs(t_field, "threshold")) { |
274 |
500 |
t_threshold = tl->t; |
275 |
500 |
threshold = vcc_UintVal(tl); |
276 |
500 |
ERRCHK(tl); |
277 |
600 |
} else if (vcc_IdIs(t_field, "expect_close")) { |
278 |
100 |
exp_close = vcc_BoolVal(tl); |
279 |
100 |
ERRCHK(tl); |
280 |
50 |
} else { |
281 |
0 |
vcc_ErrToken(tl, t_field); |
282 |
0 |
vcc_ErrWhere(tl, t_field); |
283 |
0 |
ErrInternal(tl); |
284 |
0 |
return; |
285 |
|
} |
286 |
|
|
287 |
2500 |
SkipToken(tl, ';'); |
288 |
|
} |
289 |
975 |
free(fs); |
290 |
|
|
291 |
975 |
if (t_threshold != NULL || t_window != NULL) { |
292 |
525 |
if (t_threshold == NULL && t_window != NULL) { |
293 |
25 |
VSB_cat(tl->sb, |
294 |
|
"Must specify .threshold with .window\n"); |
295 |
25 |
vcc_ErrWhere(tl, t_window); |
296 |
25 |
return; |
297 |
500 |
} else if (t_threshold != NULL && t_window == NULL) { |
298 |
75 |
if (threshold > 64) { |
299 |
25 |
VSB_cat(tl->sb, |
300 |
|
"Threshold must be 64 or less.\n"); |
301 |
25 |
vcc_ErrWhere(tl, t_threshold); |
302 |
25 |
return; |
303 |
|
} |
304 |
50 |
window = threshold + 1; |
305 |
475 |
} else if (window > 64) { |
306 |
25 |
AN(t_window); |
307 |
25 |
VSB_cat(tl->sb, "Window must be 64 or less.\n"); |
308 |
25 |
vcc_ErrWhere(tl, t_window); |
309 |
25 |
return; |
310 |
|
} |
311 |
450 |
if (threshold > window ) { |
312 |
25 |
VSB_cat(tl->sb, |
313 |
|
"Threshold can not be greater than window.\n"); |
314 |
25 |
AN(t_threshold); |
315 |
25 |
vcc_ErrWhere(tl, t_threshold); |
316 |
25 |
AN(t_window); |
317 |
25 |
vcc_ErrWhere(tl, t_window); |
318 |
25 |
} |
319 |
450 |
Fh(tl, 0, "\t.window = %u,\n", window); |
320 |
450 |
Fh(tl, 0, "\t.threshold = %u,\n", threshold); |
321 |
450 |
} |
322 |
900 |
if (t_initial != NULL) |
323 |
325 |
Fh(tl, 0, "\t.initial = %u,\n", initial); |
324 |
|
else |
325 |
575 |
Fh(tl, 0, "\t.initial = ~0U,\n"); |
326 |
900 |
if (status > 0) |
327 |
25 |
Fh(tl, 0, "\t.exp_status = %u,\n", status); |
328 |
900 |
Fh(tl, 0, "\t.exp_close = %u,\n", exp_close); |
329 |
900 |
Fh(tl, 0, "}};\n"); |
330 |
900 |
SkipToken(tl, '}'); |
331 |
1125 |
} |
332 |
|
|
333 |
|
/*-------------------------------------------------------------------- |
334 |
|
* Parse and emit a probe definition |
335 |
|
*/ |
336 |
|
|
337 |
|
void |
338 |
500 |
vcc_ParseProbe(struct vcc *tl) |
339 |
|
{ |
340 |
|
struct symbol *sym; |
341 |
|
char *p; |
342 |
|
|
343 |
500 |
vcc_NextToken(tl); /* ID: probe */ |
344 |
|
|
345 |
500 |
vcc_ExpectVid(tl, "backend probe"); /* ID: name */ |
346 |
500 |
ERRCHK(tl); |
347 |
500 |
if (vcc_IdIs(tl->t, "default")) { |
348 |
200 |
vcc_NextToken(tl); |
349 |
200 |
vcc_ParseProbeSpec(tl, NULL, &p); |
350 |
200 |
tl->default_probe = p; |
351 |
200 |
} else { |
352 |
300 |
sym = VCC_HandleSymbol(tl, PROBE); |
353 |
300 |
ERRCHK(tl); |
354 |
275 |
AN(sym); |
355 |
275 |
vcc_ParseProbeSpec(tl, sym, NULL); |
356 |
|
} |
357 |
500 |
} |
358 |
|
|
359 |
|
/*-------------------------------------------------------------------- |
360 |
|
* Parse and emit a backend host definition |
361 |
|
* |
362 |
|
* The struct vrt_backend is emitted to Fh(). |
363 |
|
*/ |
364 |
|
|
365 |
|
static void |
366 |
39625 |
vcc_ParseHostDef(struct vcc *tl, struct symbol *sym, |
367 |
|
const struct token *t_be, const char *vgcname) |
368 |
|
{ |
369 |
|
const struct token *t_field; |
370 |
|
const struct token *t_val; |
371 |
39625 |
const struct token *t_host = NULL; |
372 |
39625 |
const struct token *t_port = NULL; |
373 |
39625 |
const struct token *t_path = NULL; |
374 |
39625 |
const struct token *t_hosthdr = NULL; |
375 |
39625 |
const struct token *t_authority = NULL; |
376 |
39625 |
const struct token *t_did = NULL; |
377 |
39625 |
const struct token *t_preamble = NULL; |
378 |
|
struct symbol *pb; |
379 |
|
struct fld_spec *fs; |
380 |
|
struct inifin *ifp; |
381 |
|
struct vsb *vsb1; |
382 |
39625 |
struct symbol *via = NULL; |
383 |
|
char *p; |
384 |
|
unsigned u; |
385 |
|
double t; |
386 |
|
|
387 |
42225 |
if (tl->t->tok == ID && |
388 |
5550 |
(vcc_IdIs(tl->t, "none") || vcc_IdIs(tl->t, "None"))) { |
389 |
5550 |
vcc_NextToken(tl); |
390 |
5550 |
SkipToken(tl, ';'); |
391 |
5550 |
ifp = New_IniFin(tl); |
392 |
5550 |
VSB_printf(ifp->ini, "\t(void)%s;", vgcname); |
393 |
5550 |
VSB_printf(ifp->fin, "\t\t(void)%s;", vgcname); |
394 |
5550 |
return; |
395 |
|
} |
396 |
|
|
397 |
34075 |
SkipToken(tl, '{'); |
398 |
|
|
399 |
|
/* Check for old syntax */ |
400 |
34075 |
if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) { |
401 |
25 |
VSB_cat(tl->sb, |
402 |
|
"NB: Backend Syntax has changed:\n" |
403 |
|
"Remove \"set\" and \"backend\" in front" |
404 |
|
" of backend fields.\n" ); |
405 |
25 |
vcc_ErrToken(tl, tl->t); |
406 |
25 |
VSB_cat(tl->sb, " at "); |
407 |
25 |
vcc_ErrWhere(tl, tl->t); |
408 |
25 |
return; |
409 |
|
} |
410 |
|
|
411 |
34050 |
fs = vcc_FldSpec(tl, |
412 |
|
"?host", |
413 |
|
"?port", |
414 |
|
"?path", |
415 |
|
"?host_header", |
416 |
|
"?connect_timeout", |
417 |
|
"?first_byte_timeout", |
418 |
|
"?between_bytes_timeout", |
419 |
|
"?probe", |
420 |
|
"?max_connections", |
421 |
|
"?proxy_header", |
422 |
|
"?preamble", |
423 |
|
"?via", |
424 |
|
"?authority", |
425 |
|
NULL); |
426 |
|
|
427 |
34050 |
tl->fb = VSB_new_auto(); |
428 |
34050 |
AN(tl->fb); |
429 |
|
|
430 |
68100 |
Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n", |
431 |
34050 |
vgcname); |
432 |
|
|
433 |
34050 |
Fb(tl, 0, "\t.magic = VRT_BACKEND_MAGIC,\n"); |
434 |
34050 |
Fb(tl, 0, "\t.endpoint = &vgc_dir_ep_%s,\n", vgcname); |
435 |
34050 |
Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be)); |
436 |
34050 |
Fb(tl, 0, "\",\n"); |
437 |
|
|
438 |
94200 |
while (tl->t->tok != '}') { |
439 |
|
|
440 |
60600 |
vcc_IsField(tl, &t_field, fs); |
441 |
60600 |
ERRCHK(tl); |
442 |
60550 |
if (vcc_IdIs(t_field, "host")) { |
443 |
33075 |
vcc_Redef(tl, "Address", &t_did, t_field); |
444 |
33075 |
ERRCHK(tl); |
445 |
33075 |
ExpectErr(tl, CSTR); |
446 |
33075 |
assert(tl->t->dec != NULL); |
447 |
33075 |
t_host = tl->t; |
448 |
33075 |
vcc_NextToken(tl); |
449 |
33075 |
SkipToken(tl, ';'); |
450 |
60550 |
} else if (vcc_IdIs(t_field, "port")) { |
451 |
24800 |
ExpectErr(tl, CSTR); |
452 |
24800 |
assert(tl->t->dec != NULL); |
453 |
24800 |
t_port = tl->t; |
454 |
24800 |
vcc_NextToken(tl); |
455 |
24800 |
SkipToken(tl, ';'); |
456 |
27475 |
} else if (vcc_IdIs(t_field, "path")) { |
457 |
925 |
if (tl->syntax < VCL_41) { |
458 |
25 |
VSB_cat(tl->sb, |
459 |
|
"Unix socket backends only supported" |
460 |
|
" in VCL4.1 and higher.\n"); |
461 |
25 |
vcc_ErrToken(tl, tl->t); |
462 |
25 |
VSB_cat(tl->sb, " at "); |
463 |
25 |
vcc_ErrWhere(tl, tl->t); |
464 |
25 |
VSB_destroy(&tl->fb); |
465 |
25 |
return; |
466 |
|
} |
467 |
900 |
vcc_Redef(tl, "Address", &t_did, t_field); |
468 |
900 |
ERRCHK(tl); |
469 |
875 |
ExpectErr(tl, CSTR); |
470 |
875 |
assert(tl->t->dec != NULL); |
471 |
875 |
t_path = tl->t; |
472 |
875 |
vcc_NextToken(tl); |
473 |
875 |
SkipToken(tl, ';'); |
474 |
2625 |
} else if (vcc_IdIs(t_field, "host_header")) { |
475 |
100 |
ExpectErr(tl, CSTR); |
476 |
100 |
assert(tl->t->dec != NULL); |
477 |
100 |
t_hosthdr = tl->t; |
478 |
100 |
vcc_NextToken(tl); |
479 |
100 |
SkipToken(tl, ';'); |
480 |
1750 |
} else if (vcc_IdIs(t_field, "connect_timeout")) { |
481 |
0 |
Fb(tl, 0, "\t.connect_timeout = "); |
482 |
0 |
vcc_Duration(tl, &t); |
483 |
0 |
ERRCHK(tl); |
484 |
0 |
Fb(tl, 0, "%g,\n", t); |
485 |
0 |
SkipToken(tl, ';'); |
486 |
1650 |
} else if (vcc_IdIs(t_field, "first_byte_timeout")) { |
487 |
75 |
Fb(tl, 0, "\t.first_byte_timeout = "); |
488 |
75 |
vcc_Duration(tl, &t); |
489 |
75 |
ERRCHK(tl); |
490 |
75 |
Fb(tl, 0, "%g,\n", t); |
491 |
75 |
SkipToken(tl, ';'); |
492 |
1650 |
} else if (vcc_IdIs(t_field, "between_bytes_timeout")) { |
493 |
25 |
Fb(tl, 0, "\t.between_bytes_timeout = "); |
494 |
25 |
vcc_Duration(tl, &t); |
495 |
25 |
ERRCHK(tl); |
496 |
25 |
Fb(tl, 0, "%g,\n", t); |
497 |
25 |
SkipToken(tl, ';'); |
498 |
1575 |
} else if (vcc_IdIs(t_field, "max_connections")) { |
499 |
125 |
u = vcc_UintVal(tl); |
500 |
125 |
ERRCHK(tl); |
501 |
125 |
SkipToken(tl, ';'); |
502 |
125 |
Fb(tl, 0, "\t.max_connections = %u,\n", u); |
503 |
1550 |
} else if (vcc_IdIs(t_field, "proxy_header")) { |
504 |
150 |
t_val = tl->t; |
505 |
150 |
u = vcc_UintVal(tl); |
506 |
150 |
ERRCHK(tl); |
507 |
150 |
if (u != 1 && u != 2) { |
508 |
0 |
VSB_cat(tl->sb, |
509 |
|
".proxy_header must be 1 or 2\n"); |
510 |
0 |
vcc_ErrWhere(tl, t_val); |
511 |
0 |
VSB_destroy(&tl->fb); |
512 |
0 |
return; |
513 |
|
} |
514 |
150 |
SkipToken(tl, ';'); |
515 |
150 |
Fb(tl, 0, "\t.proxy_header = %u,\n", u); |
516 |
1425 |
} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') { |
517 |
650 |
vcc_ParseProbeSpec(tl, NULL, &p); |
518 |
650 |
Fb(tl, 0, "\t.probe = %s,\n", p); |
519 |
650 |
free(p); |
520 |
650 |
ERRCHK(tl); |
521 |
1025 |
} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) { |
522 |
275 |
if (vcc_IdIs(tl->t, "default")) { |
523 |
25 |
vcc_NextToken(tl); |
524 |
25 |
(void)vcc_default_probe(tl); |
525 |
25 |
} else { |
526 |
250 |
pb = VCC_SymbolGet(tl, SYM_MAIN, SYM_PROBE, |
527 |
|
SYMTAB_EXISTING, XREF_REF); |
528 |
250 |
ERRCHK(tl); |
529 |
225 |
AN(pb); |
530 |
225 |
Fb(tl, 0, "\t.probe = %s,\n", pb->rname); |
531 |
|
} |
532 |
250 |
SkipToken(tl, ';'); |
533 |
575 |
} else if (vcc_IdIs(t_field, "probe")) { |
534 |
25 |
VSB_cat(tl->sb, "Expected '{' or name of probe, got "); |
535 |
25 |
vcc_ErrToken(tl, tl->t); |
536 |
25 |
VSB_cat(tl->sb, " at\n"); |
537 |
25 |
vcc_ErrWhere(tl, tl->t); |
538 |
25 |
VSB_destroy(&tl->fb); |
539 |
25 |
return; |
540 |
325 |
} else if (vcc_IdIs(t_field, "preamble")) { |
541 |
25 |
ExpectErr(tl, CBLOB); |
542 |
25 |
t_preamble = tl->t; |
543 |
25 |
vcc_NextToken(tl); |
544 |
25 |
SkipToken(tl, ';'); |
545 |
325 |
} else if (vcc_IdIs(t_field, "via")) { |
546 |
225 |
via = VCC_SymbolGet(tl, SYM_MAIN, SYM_BACKEND, |
547 |
|
SYMTAB_EXISTING, XREF_REF); |
548 |
225 |
ERRCHK(tl); |
549 |
225 |
AN(via); |
550 |
225 |
AN(via->rname); |
551 |
|
|
552 |
225 |
if (via->extra != NULL) { |
553 |
25 |
AZ(strcmp(via->extra, "via")); |
554 |
25 |
VSB_cat(tl->sb, |
555 |
|
"Can not stack .via backends at\n"); |
556 |
25 |
vcc_ErrWhere(tl, tl->t); |
557 |
25 |
VSB_destroy(&tl->fb); |
558 |
25 |
return; |
559 |
|
} |
560 |
|
|
561 |
200 |
AN(sym); |
562 |
200 |
AZ(sym->extra); |
563 |
200 |
sym->extra = "via"; |
564 |
200 |
SkipToken(tl, ';'); |
565 |
275 |
} else if (vcc_IdIs(t_field, "authority")) { |
566 |
75 |
ExpectErr(tl, CSTR); |
567 |
75 |
assert(tl->t->dec != NULL); |
568 |
75 |
t_authority = tl->t; |
569 |
75 |
vcc_NextToken(tl); |
570 |
75 |
SkipToken(tl, ';'); |
571 |
75 |
} else { |
572 |
0 |
ErrInternal(tl); |
573 |
0 |
VSB_destroy(&tl->fb); |
574 |
0 |
return; |
575 |
|
} |
576 |
|
|
577 |
|
} |
578 |
|
|
579 |
33600 |
vcc_FieldsOk(tl, fs); |
580 |
33600 |
free(fs); |
581 |
33600 |
ERRCHK(tl); |
582 |
|
|
583 |
33600 |
ExpectErr(tl, '}'); |
584 |
|
|
585 |
33600 |
if (t_host == NULL && t_path == NULL) { |
586 |
25 |
VSB_cat(tl->sb, "Expected .host or .path.\n"); |
587 |
25 |
vcc_ErrWhere(tl, t_be); |
588 |
25 |
VSB_destroy(&tl->fb); |
589 |
25 |
return; |
590 |
|
} |
591 |
|
|
592 |
33575 |
if (via != NULL && t_path != NULL) { |
593 |
25 |
VSB_cat(tl->sb, "Cannot set both .via and .path.\n"); |
594 |
25 |
vcc_ErrWhere(tl, t_be); |
595 |
25 |
return; |
596 |
|
} |
597 |
|
|
598 |
33550 |
if (via != NULL) |
599 |
175 |
AZ(via->extra); |
600 |
|
|
601 |
33550 |
vsb1 = VSB_new_auto(); |
602 |
33550 |
AN(vsb1); |
603 |
67100 |
VSB_printf(vsb1, |
604 |
|
"\nstatic const struct vrt_endpoint vgc_dir_ep_%s = {\n", |
605 |
33550 |
vgcname); |
606 |
33550 |
VSB_cat(vsb1, "\t.magic = VRT_ENDPOINT_MAGIC,\n"); |
607 |
|
|
608 |
33550 |
assert(t_host != NULL || t_path != NULL); |
609 |
33550 |
if (t_host != NULL) |
610 |
|
/* Check that the hostname makes sense */ |
611 |
32700 |
Emit_Sockaddr(tl, vsb1, t_host, t_port); |
612 |
|
else |
613 |
|
/* Check that the path can be a legal UDS */ |
614 |
850 |
Emit_UDS_Path(tl, vsb1, t_path, "Backend path"); |
615 |
33550 |
ERRCHK(tl); |
616 |
|
|
617 |
33425 |
if (t_preamble != NULL) |
618 |
25 |
VSB_printf(vsb1, "\t.preamble = %s,\n", t_preamble->dec); |
619 |
|
|
620 |
33425 |
VSB_cat(vsb1, "};\n"); |
621 |
33425 |
AZ(VSB_finish(vsb1)); |
622 |
33425 |
Fh(tl, 0, "%s", VSB_data(vsb1)); |
623 |
33425 |
VSB_destroy(&vsb1); |
624 |
|
|
625 |
|
/* Emit the hosthdr field, fall back to .host if not specified */ |
626 |
|
/* If .path is specified, set "0.0.0.0". */ |
627 |
33425 |
Fb(tl, 0, "\t.hosthdr = "); |
628 |
33425 |
if (t_hosthdr != NULL) |
629 |
100 |
EncToken(tl->fb, t_hosthdr); |
630 |
33325 |
else if (t_host != NULL) |
631 |
32600 |
EncToken(tl->fb, t_host); |
632 |
|
else |
633 |
725 |
Fb(tl, 0, "\"0.0.0.0\""); |
634 |
33425 |
Fb(tl, 0, ",\n"); |
635 |
|
|
636 |
|
/* |
637 |
|
* Emit the authority field, falling back to hosthdr, then host. |
638 |
|
* |
639 |
|
* When authority is "", sending the TLV is disabled. |
640 |
|
* |
641 |
|
* Falling back to host may result in an IP address in authority, |
642 |
|
* which is an illegal SNI HostName (RFC 4366 ch. 3.1). But we |
643 |
|
* document the potential error, rather than try to find out |
644 |
|
* whether or not Emit_Sockaddr() had to look up a name. |
645 |
|
*/ |
646 |
33425 |
if (via != NULL) { |
647 |
175 |
AN(t_host); |
648 |
175 |
Fb(tl, 0, "\t.authority = "); |
649 |
175 |
if (t_authority != NULL) |
650 |
75 |
EncToken(tl->fb, t_authority); |
651 |
100 |
else if (t_hosthdr != NULL) |
652 |
25 |
EncToken(tl->fb, t_hosthdr); |
653 |
|
else |
654 |
75 |
EncToken(tl->fb, t_host); |
655 |
175 |
Fb(tl, 0, ",\n"); |
656 |
175 |
} |
657 |
|
|
658 |
|
/* Close the struct */ |
659 |
33425 |
Fb(tl, 0, "};\n"); |
660 |
|
|
661 |
33425 |
vcc_NextToken(tl); |
662 |
|
|
663 |
33425 |
AZ(VSB_finish(tl->fb)); |
664 |
33425 |
Fh(tl, 0, "%s", VSB_data(tl->fb)); |
665 |
33425 |
VSB_destroy(&tl->fb); |
666 |
|
|
667 |
33425 |
ifp = New_IniFin(tl); |
668 |
66850 |
VSB_printf(ifp->ini, |
669 |
|
"\t%s =\n\t VRT_new_backend_clustered(ctx, vsc_cluster,\n" |
670 |
|
"\t\t&vgc_dir_priv_%s, %s);\n", |
671 |
33425 |
vgcname, vgcname, via ? via->rname : "NULL"); |
672 |
66850 |
VSB_printf(ifp->ini, |
673 |
33425 |
"\tif (%s)\n\t\tVRT_StaticDirector(%s);", vgcname, vgcname); |
674 |
33425 |
VSB_printf(ifp->fin, "\t\tVRT_delete_backend(ctx, &%s);", vgcname); |
675 |
39625 |
} |
676 |
|
|
677 |
|
/*-------------------------------------------------------------------- |
678 |
|
* Parse directors and backends |
679 |
|
*/ |
680 |
|
|
681 |
|
void |
682 |
39750 |
vcc_ParseBackend(struct vcc *tl) |
683 |
|
{ |
684 |
|
struct token *t_first, *t_be; |
685 |
39750 |
struct symbol *sym = NULL; |
686 |
|
const char *dn; |
687 |
|
|
688 |
39750 |
tl->ndirector++; |
689 |
39750 |
t_first = tl->t; |
690 |
39750 |
SkipToken(tl, ID); /* ID: backend */ |
691 |
|
|
692 |
39750 |
vcc_ExpectVid(tl, "backend"); /* ID: name */ |
693 |
39750 |
ERRCHK(tl); |
694 |
|
|
695 |
39725 |
t_be = tl->t; |
696 |
39725 |
if (vcc_IdIs(tl->t, "default")) { |
697 |
1625 |
if (tl->first_director != NULL) { |
698 |
75 |
tl->first_director->noref = 0; |
699 |
75 |
tl->first_director = NULL; |
700 |
75 |
tl->default_director = NULL; |
701 |
75 |
} |
702 |
1625 |
if (tl->default_director != NULL) { |
703 |
25 |
VSB_cat(tl->sb, |
704 |
|
"Only one default director possible.\n"); |
705 |
25 |
vcc_ErrWhere(tl, t_first); |
706 |
25 |
return; |
707 |
|
} |
708 |
1600 |
vcc_NextToken(tl); |
709 |
1600 |
dn = "vgc_backend_default"; |
710 |
1600 |
tl->default_director = dn; |
711 |
1600 |
} else { |
712 |
38100 |
sym = VCC_HandleSymbol(tl, BACKEND); |
713 |
38100 |
ERRCHK(tl); |
714 |
38025 |
AN(sym); |
715 |
38025 |
dn = sym->rname; |
716 |
38025 |
if (tl->default_director == NULL) { |
717 |
31475 |
tl->first_director = sym; |
718 |
31475 |
tl->default_director = dn; |
719 |
31475 |
sym->noref = 1; |
720 |
31475 |
} |
721 |
|
} |
722 |
39625 |
Fh(tl, 0, "\nstatic VCL_BACKEND %s;\n", dn); |
723 |
39625 |
vcc_ParseHostDef(tl, sym, t_be, dn); |
724 |
39625 |
if (tl->err) { |
725 |
1300 |
VSB_printf(tl->sb, |
726 |
650 |
"\nIn %.*s specification starting at:\n", PF(t_first)); |
727 |
650 |
vcc_ErrWhere(tl, t_first); |
728 |
650 |
return; |
729 |
|
} |
730 |
39750 |
} |
731 |
|
|
732 |
|
void |
733 |
72975 |
vcc_Backend_Init(struct vcc *tl) |
734 |
|
{ |
735 |
|
struct inifin *ifp; |
736 |
|
|
737 |
72975 |
Fh(tl, 0, "\nstatic struct vsmw_cluster *vsc_cluster;\n"); |
738 |
72975 |
ifp = New_IniFin(tl); |
739 |
72975 |
VSB_cat(ifp->ini, "\tvsc_cluster = VRT_VSM_Cluster_New(ctx,\n" |
740 |
|
"\t ndirector * VRT_backend_vsm_need(ctx));\n"); |
741 |
72975 |
VSB_cat(ifp->ini, "\tif (vsc_cluster == 0)\n\t\treturn(1);"); |
742 |
72975 |
VSB_cat(ifp->fin, "\t\tVRT_VSM_Cluster_Destroy(ctx, &vsc_cluster);"); |
743 |
72975 |
} |