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