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