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  * SPDX-License-Identifier: BSD-2-Clause
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  */
32 
33 #include "config.h"
34 
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 
39 #include "vcc_compile.h"
40 
41 const char *
vcc_default_probe(struct vcc * tl)42 vcc_default_probe(struct vcc *tl)
43 {
44 
45 	if (tl->default_probe != NULL)
46 		return (tl->default_probe);
47 	VSB_cat(tl->sb, "No default probe defined\n");
48 	vcc_ErrToken(tl, tl->t);
49 	VSB_cat(tl->sb, " at\n");
50 	vcc_ErrWhere(tl, tl->t);
51 	return ("");
52 }
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
Emit_Sockaddr(struct vcc * tl,struct vsb * vsb1,const struct token * t_host,const struct token * t_port)61 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 	AN(t_host->dec);
68 
69 	if (t_port != NULL)
70 		bprintf(buf, "%s %s", t_host->dec, t_port->dec);
71 	else
72 		bprintf(buf, "%s", t_host->dec);
73 	Resolve_Sockaddr(tl, buf, "80",
74 	    &ipv4, &ipv4a, &ipv6, &ipv6a, &pa, 2, t_host, "Backend host");
75 	ERRCHK(tl);
76 	if (ipv4 != NULL) {
77 		VSB_printf(vsb1,
78 		    "\t.ipv4 = (const struct suckaddr *)%s,\n",
79 		    ipv4);
80 	}
81 	if (ipv6 != NULL) {
82 		VSB_printf(vsb1,
83 		    "\t.ipv6 = (const struct suckaddr *)%s,\n",
84 		    ipv6);
85 	}
86 	VSB_cat(vsb1, "\t.uds_path = (void *) 0,\n");
87 }
88 
89 /*
90  * For UDS, we do not create a VSA. Check if it's an absolute path, can
91  * be accessed, and is a socket. If so, just emit the path field and set
92  * the IP suckaddrs to NULL.
93  */
94 static void
Emit_UDS_Path(struct vcc * tl,struct vsb * vsb1,const struct token * t_path,const char * errid)95 Emit_UDS_Path(struct vcc *tl, struct vsb *vsb1,
96     const struct token *t_path, const char *errid)
97 {
98 	struct stat st;
99 
100 	AN(t_path);
101 	AN(t_path->dec);
102 
103 	if (*t_path->dec != '/') {
104 		VSB_printf(tl->sb,
105 			   "%s: Must be an absolute path:\n", errid);
106 		vcc_ErrWhere(tl, t_path);
107 		return;
108 	}
109 	errno = 0;
110 	if (stat(t_path->dec, &st) != 0) {
111 		int err = errno;
112 		VSB_printf(tl->sb, "%s: Cannot stat: %s\n", errid,
113 			   strerror(errno));
114 		vcc_ErrWhere(tl, t_path);
115 		if (err == ENOENT || err == EACCES)
116 			vcc_Warn(tl);
117 		else
118 			return;
119 	} else if (!S_ISSOCK(st.st_mode)) {
120 		VSB_printf(tl->sb, "%s: Not a socket:\n", errid);
121 		vcc_ErrWhere(tl, t_path);
122 		return;
123 	}
124 	VSB_printf(vsb1, "\t.uds_path = \"%s\",\n", t_path->dec);
125 	VSB_cat(vsb1, "\t.ipv4 = (void *) 0,\n");
126 	VSB_cat(vsb1, "\t.ipv6 = (void *) 0,\n");
127 }
128 
129 /*--------------------------------------------------------------------
130  * Disallow mutually exclusive field definitions
131  */
132 
133 static void
vcc_Redef(struct vcc * tl,const char * redef,const struct token ** t_did,const struct token * t_field)134 vcc_Redef(struct vcc *tl, const char *redef, const struct token **t_did,
135     const struct token *t_field)
136 {
137 	if (*t_did != NULL) {
138 		VSB_printf(tl->sb, "%s redefinition at:\n", redef);
139 		vcc_ErrWhere(tl, t_field);
140 		VSB_cat(tl->sb, "Previous definition:\n");
141 		vcc_ErrWhere(tl, *t_did);
142 		return;
143 	}
144 	*t_did = t_field;
145 }
146 
147 /*--------------------------------------------------------------------
148  * Parse a backend probe specification
149  */
150 
151 static void
vcc_ParseProbeSpec(struct vcc * tl,const struct symbol * sym,char ** namep)152 vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **namep)
153 {
154 	struct fld_spec *fs;
155 	const struct token *t_field;
156 	const struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL;
157 	struct token *t_initial = NULL;
158 	unsigned window, threshold, initial, status;
159 	char buf[32];
160 	const char *name;
161 	double t;
162 
163 	fs = vcc_FldSpec(tl,
164 	    "?url",
165 	    "?request",
166 	    "?expected_response",
167 	    "?timeout",
168 	    "?interval",
169 	    "?window",
170 	    "?threshold",
171 	    "?initial",
172 	    NULL);
173 
174 	SkipToken(tl, '{');
175 
176 	if (sym != NULL) {
177 		name = sym->rname;
178 	} else {
179 		bprintf(buf, "vgc_probe__%d", tl->nprobe++);
180 		name = buf;
181 	}
182 	Fh(tl, 0, "static const struct vrt_backend_probe %s[] = {{\n", name);
183 	Fh(tl, 0, "\t.magic = VRT_BACKEND_PROBE_MAGIC,\n");
184 	if (namep != NULL)
185 		*namep = TlDup(tl, name);
186 
187 	window = 0;
188 	threshold = 0;
189 	initial = 0;
190 	status = 0;
191 	while (tl->t->tok != '}') {
192 
193 		vcc_IsField(tl, &t_field, fs);
194 		ERRCHK(tl);
195 		if (vcc_IdIs(t_field, "url")) {
196 			vcc_Redef(tl, "Probe request", &t_did, t_field);
197 			ERRCHK(tl);
198 			ExpectErr(tl, CSTR);
199 			Fh(tl, 0, "\t.url = ");
200 			EncToken(tl->fh, tl->t);
201 			Fh(tl, 0, ",\n");
202 			vcc_NextToken(tl);
203 		} else if (vcc_IdIs(t_field, "request")) {
204 			vcc_Redef(tl, "Probe request", &t_did, t_field);
205 			ERRCHK(tl);
206 			ExpectErr(tl, CSTR);
207 			Fh(tl, 0, "\t.request =\n");
208 			while (tl->t->tok == CSTR) {
209 				Fh(tl, 0, "\t\t");
210 				EncToken(tl->fh, tl->t);
211 				Fh(tl, 0, " \"\\r\\n\"\n");
212 				vcc_NextToken(tl);
213 			}
214 			Fh(tl, 0, "\t\t\"\\r\\n\",\n");
215 		} else if (vcc_IdIs(t_field, "timeout")) {
216 			Fh(tl, 0, "\t.timeout = ");
217 			vcc_Duration(tl, &t);
218 			ERRCHK(tl);
219 			Fh(tl, 0, "%g,\n", t);
220 		} else if (vcc_IdIs(t_field, "interval")) {
221 			Fh(tl, 0, "\t.interval = ");
222 			vcc_Duration(tl, &t);
223 			ERRCHK(tl);
224 			Fh(tl, 0, "%g,\n", t);
225 		} else if (vcc_IdIs(t_field, "window")) {
226 			t_window = tl->t;
227 			window = vcc_UintVal(tl);
228 			ERRCHK(tl);
229 		} else if (vcc_IdIs(t_field, "initial")) {
230 			t_initial = tl->t;
231 			initial = vcc_UintVal(tl);
232 			ERRCHK(tl);
233 		} else if (vcc_IdIs(t_field, "expected_response")) {
234 			status = vcc_UintVal(tl);
235 			if (status < 100 || status > 999) {
236 				VSB_cat(tl->sb,
237 				    "Must specify .expected_response with "
238 				    "exactly three digits "
239 				    "(100 <= x <= 999)\n");
240 				vcc_ErrWhere(tl, tl->t);
241 				return;
242 			}
243 			ERRCHK(tl);
244 		} else if (vcc_IdIs(t_field, "threshold")) {
245 			t_threshold = tl->t;
246 			threshold = vcc_UintVal(tl);
247 			ERRCHK(tl);
248 		} else {
249 			vcc_ErrToken(tl, t_field);
250 			vcc_ErrWhere(tl, t_field);
251 			ErrInternal(tl);
252 			return;
253 		}
254 
255 		SkipToken(tl, ';');
256 	}
257 	free(fs);
258 
259 	if (t_threshold != NULL || t_window != NULL) {
260 		if (t_threshold == NULL && t_window != NULL) {
261 			VSB_cat(tl->sb,
262 			    "Must specify .threshold with .window\n");
263 			vcc_ErrWhere(tl, t_window);
264 			return;
265 		} else if (t_threshold != NULL && t_window == NULL) {
266 			if (threshold > 64) {
267 				VSB_cat(tl->sb,
268 				    "Threshold must be 64 or less.\n");
269 				vcc_ErrWhere(tl, t_threshold);
270 				return;
271 			}
272 			window = threshold + 1;
273 		} else if (window > 64) {
274 			AN(t_window);
275 			VSB_cat(tl->sb, "Window must be 64 or less.\n");
276 			vcc_ErrWhere(tl, t_window);
277 			return;
278 		}
279 		if (threshold > window ) {
280 			VSB_cat(tl->sb,
281 			    "Threshold can not be greater than window.\n");
282 			AN(t_threshold);
283 			vcc_ErrWhere(tl, t_threshold);
284 			AN(t_window);
285 			vcc_ErrWhere(tl, t_window);
286 		}
287 		Fh(tl, 0, "\t.window = %u,\n", window);
288 		Fh(tl, 0, "\t.threshold = %u,\n", threshold);
289 	}
290 	if (t_initial != NULL)
291 		Fh(tl, 0, "\t.initial = %u,\n", initial);
292 	else
293 		Fh(tl, 0, "\t.initial = ~0U,\n");
294 	if (status > 0)
295 		Fh(tl, 0, "\t.exp_status = %u,\n", status);
296 	Fh(tl, 0, "}};\n");
297 	SkipToken(tl, '}');
298 }
299 
300 /*--------------------------------------------------------------------
301  * Parse and emit a probe definition
302  */
303 
304 void
vcc_ParseProbe(struct vcc * tl)305 vcc_ParseProbe(struct vcc *tl)
306 {
307 	struct symbol *sym;
308 	char *p;
309 
310 	vcc_NextToken(tl);			/* ID: probe */
311 
312 	vcc_ExpectVid(tl, "backend probe");	/* ID: name */
313 	ERRCHK(tl);
314 	if (vcc_IdIs(tl->t, "default")) {
315 		vcc_NextToken(tl);
316 		vcc_ParseProbeSpec(tl, NULL, &p);
317 		tl->default_probe = p;
318 	} else {
319 		sym = VCC_HandleSymbol(tl, PROBE, "vgc_probe");
320 		ERRCHK(tl);
321 		AN(sym);
322 		vcc_ParseProbeSpec(tl, sym, NULL);
323 	}
324 }
325 
326 /*--------------------------------------------------------------------
327  * Parse and emit a backend host definition
328  *
329  * The struct vrt_backend is emitted to Fh().
330  */
331 
332 static void
vcc_ParseHostDef(struct vcc * tl,const struct token * t_be,const char * vgcname)333 vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
334 {
335 	const struct token *t_field;
336 	const struct token *t_val;
337 	const struct token *t_host = NULL;
338 	const struct token *t_port = NULL;
339 	const struct token *t_path = NULL;
340 	const struct token *t_hosthdr = NULL;
341 	const struct token *t_did = NULL;
342 	const struct token *t_preamble = NULL;
343 	struct symbol *pb;
344 	struct fld_spec *fs;
345 	struct inifin *ifp;
346 	struct vsb *vsb1;
347 	char *p;
348 	unsigned u;
349 	double t;
350 
351 	if (tl->t->tok == ID &&
352 	    (vcc_IdIs(tl->t, "none") || vcc_IdIs(tl->t, "None"))) {
353 		vcc_NextToken(tl);
354 		SkipToken(tl, ';');
355 		ifp = New_IniFin(tl);
356 		VSB_printf(ifp->ini, "\t(void)%s;\n", vgcname);
357 		VSB_printf(ifp->fin, "\t\t(void)%s;\n", vgcname);
358 		return;
359 	}
360 
361 	SkipToken(tl, '{');
362 
363 	/* Check for old syntax */
364 	if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
365 		VSB_cat(tl->sb,
366 		    "NB: Backend Syntax has changed:\n"
367 		    "Remove \"set\" and \"backend\" in front"
368 		    " of backend fields.\n" );
369 		vcc_ErrToken(tl, tl->t);
370 		VSB_cat(tl->sb, " at ");
371 		vcc_ErrWhere(tl, tl->t);
372 		return;
373 	}
374 
375 	fs = vcc_FldSpec(tl,
376 	    "?host",
377 	    "?port",
378 	    "?path",
379 	    "?host_header",
380 	    "?connect_timeout",
381 	    "?first_byte_timeout",
382 	    "?between_bytes_timeout",
383 	    "?probe",
384 	    "?max_connections",
385 	    "?proxy_header",
386 	    "?preamble",
387 	    NULL);
388 
389 	tl->fb = VSB_new_auto();
390 	AN(tl->fb);
391 
392 	Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n",
393 	    vgcname);
394 
395 	Fb(tl, 0, "\t.magic = VRT_BACKEND_MAGIC,\n");
396 	Fb(tl, 0, "\t.endpoint = &vgc_dir_ep_%s,\n", vgcname);
397 	Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be));
398 	Fb(tl, 0, "\",\n");
399 
400 	while (tl->t->tok != '}') {
401 
402 		vcc_IsField(tl, &t_field, fs);
403 		ERRCHK(tl);
404 		if (vcc_IdIs(t_field, "host")) {
405 			vcc_Redef(tl, "Address", &t_did, t_field);
406 			ERRCHK(tl);
407 			ExpectErr(tl, CSTR);
408 			assert(tl->t->dec != NULL);
409 			t_host = tl->t;
410 			vcc_NextToken(tl);
411 			SkipToken(tl, ';');
412 		} else if (vcc_IdIs(t_field, "port")) {
413 			ExpectErr(tl, CSTR);
414 			assert(tl->t->dec != NULL);
415 			t_port = tl->t;
416 			vcc_NextToken(tl);
417 			SkipToken(tl, ';');
418 		} else if (vcc_IdIs(t_field, "path")) {
419 			if (tl->syntax < VCL_41) {
420 				VSB_cat(tl->sb,
421 				    "Unix socket backends only supported"
422 				    " in VCL4.1 and higher.\n");
423 				vcc_ErrToken(tl, tl->t);
424 				VSB_cat(tl->sb, " at ");
425 				vcc_ErrWhere(tl, tl->t);
426 				VSB_destroy(&tl->fb);
427 				return;
428 			}
429 			vcc_Redef(tl, "Address", &t_did, t_field);
430 			ERRCHK(tl);
431 			ExpectErr(tl, CSTR);
432 			assert(tl->t->dec != NULL);
433 			t_path = tl->t;
434 			vcc_NextToken(tl);
435 			SkipToken(tl, ';');
436 		} else if (vcc_IdIs(t_field, "host_header")) {
437 			ExpectErr(tl, CSTR);
438 			assert(tl->t->dec != NULL);
439 			t_hosthdr = tl->t;
440 			vcc_NextToken(tl);
441 			SkipToken(tl, ';');
442 		} else if (vcc_IdIs(t_field, "connect_timeout")) {
443 			Fb(tl, 0, "\t.connect_timeout = ");
444 			vcc_Duration(tl, &t);
445 			ERRCHK(tl);
446 			Fb(tl, 0, "%g,\n", t);
447 			SkipToken(tl, ';');
448 		} else if (vcc_IdIs(t_field, "first_byte_timeout")) {
449 			Fb(tl, 0, "\t.first_byte_timeout = ");
450 			vcc_Duration(tl, &t);
451 			ERRCHK(tl);
452 			Fb(tl, 0, "%g,\n", t);
453 			SkipToken(tl, ';');
454 		} else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
455 			Fb(tl, 0, "\t.between_bytes_timeout = ");
456 			vcc_Duration(tl, &t);
457 			ERRCHK(tl);
458 			Fb(tl, 0, "%g,\n", t);
459 			SkipToken(tl, ';');
460 		} else if (vcc_IdIs(t_field, "max_connections")) {
461 			u = vcc_UintVal(tl);
462 			ERRCHK(tl);
463 			SkipToken(tl, ';');
464 			Fb(tl, 0, "\t.max_connections = %u,\n", u);
465 		} else if (vcc_IdIs(t_field, "proxy_header")) {
466 			t_val = tl->t;
467 			u = vcc_UintVal(tl);
468 			ERRCHK(tl);
469 			if (u != 1 && u != 2) {
470 				VSB_cat(tl->sb,
471 				    ".proxy_header must be 1 or 2\n");
472 				vcc_ErrWhere(tl, t_val);
473 				VSB_destroy(&tl->fb);
474 				return;
475 			}
476 			SkipToken(tl, ';');
477 			Fb(tl, 0, "\t.proxy_header = %u,\n", u);
478 		} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
479 			vcc_ParseProbeSpec(tl, NULL, &p);
480 			Fb(tl, 0, "\t.probe = %s,\n", p);
481 			free(p);
482 			ERRCHK(tl);
483 		} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) {
484 			if (vcc_IdIs(tl->t, "default")) {
485 				vcc_NextToken(tl);
486 				(void)vcc_default_probe(tl);
487 			} else {
488 				pb = VCC_SymbolGet(tl, SYM_MAIN, SYM_PROBE,
489 				    SYMTAB_EXISTING, XREF_REF);
490 				ERRCHK(tl);
491 				AN(pb);
492 				Fb(tl, 0, "\t.probe = %s,\n", pb->rname);
493 			}
494 			SkipToken(tl, ';');
495 		} else if (vcc_IdIs(t_field, "probe")) {
496 			VSB_cat(tl->sb, "Expected '{' or name of probe, got ");
497 			vcc_ErrToken(tl, tl->t);
498 			VSB_cat(tl->sb, " at\n");
499 			vcc_ErrWhere(tl, tl->t);
500 			VSB_destroy(&tl->fb);
501 			return;
502 		} else if (vcc_IdIs(t_field, "preamble")) {
503 			ExpectErr(tl, CBLOB);
504 			t_preamble = tl->t;
505 			vcc_NextToken(tl);
506 			SkipToken(tl, ';');
507 		} else {
508 			ErrInternal(tl);
509 			VSB_destroy(&tl->fb);
510 			return;
511 		}
512 
513 	}
514 
515 	vcc_FieldsOk(tl, fs);
516 	free(fs);
517 	ERRCHK(tl);
518 
519 	ExpectErr(tl, '}');
520 
521 	if (t_host == NULL && t_path == NULL) {
522 		VSB_cat(tl->sb, "Expected .host or .path.\n");
523 		vcc_ErrWhere(tl, t_be);
524 		VSB_destroy(&tl->fb);
525 		return;
526 	}
527 
528 	vsb1 = VSB_new_auto();
529 	AN(vsb1);
530 	VSB_printf(vsb1,
531 	    "\nstatic const struct vrt_endpoint vgc_dir_ep_%s = {\n",
532 	    vgcname);
533 	VSB_cat(vsb1, "\t.magic = VRT_ENDPOINT_MAGIC,\n");
534 
535 	assert(t_host != NULL || t_path != NULL);
536 	if (t_host != NULL)
537 		/* Check that the hostname makes sense */
538 		Emit_Sockaddr(tl, vsb1, t_host, t_port);
539 	else
540 		/* Check that the path can be a legal UDS */
541 		Emit_UDS_Path(tl, vsb1, t_path, "Backend path");
542 	ERRCHK(tl);
543 
544 	if (t_preamble != NULL)
545 		VSB_printf(vsb1, "\t.preamble = %s,\n", t_preamble->dec);
546 
547 	VSB_cat(vsb1, "};\n");
548 	AZ(VSB_finish(vsb1));
549 	Fh(tl, 0, "%s", VSB_data(vsb1));
550 	VSB_destroy(&vsb1);
551 
552 	/* Emit the hosthdr field, fall back to .host if not specified */
553 	/* If .path is specified, set "0.0.0.0". */
554 	Fb(tl, 0, "\t.hosthdr = ");
555 	if (t_hosthdr != NULL)
556 		EncToken(tl->fb, t_hosthdr);
557 	else if (t_host != NULL)
558 		EncToken(tl->fb, t_host);
559 	else
560 		Fb(tl, 0, "\"0.0.0.0\"");
561 	Fb(tl, 0, ",\n");
562 
563 	/* Close the struct */
564 	Fb(tl, 0, "};\n");
565 
566 	vcc_NextToken(tl);
567 
568 	AZ(VSB_finish(tl->fb));
569 	Fh(tl, 0, "%s", VSB_data(tl->fb));
570 	VSB_destroy(&tl->fb);
571 
572 	ifp = New_IniFin(tl);
573 	VSB_printf(ifp->ini,
574 	    "\t%s =\n\t    VRT_new_backend_clustered(ctx, vsc_cluster,\n"
575 	    "\t\t&vgc_dir_priv_%s);",
576 	    vgcname, vgcname);
577 	VSB_printf(ifp->fin, "\t\tVRT_delete_backend(ctx, &%s);", vgcname);
578 }
579 
580 /*--------------------------------------------------------------------
581  * Parse directors and backends
582  */
583 
584 void
vcc_ParseBackend(struct vcc * tl)585 vcc_ParseBackend(struct vcc *tl)
586 {
587 	struct token *t_first, *t_be;
588 	struct symbol *sym;
589 	const char *dn;
590 
591 	tl->ndirector++;
592 	t_first = tl->t;
593 	SkipToken(tl, ID);		/* ID: backend */
594 
595 	vcc_ExpectVid(tl, "backend");	/* ID: name */
596 	ERRCHK(tl);
597 
598 	t_be = tl->t;
599 	if (vcc_IdIs(tl->t, "default")) {
600 		if (tl->first_director != NULL) {
601 			tl->first_director->noref = 0;
602 			tl->first_director = NULL;
603 			tl->default_director = NULL;
604 		}
605 		if (tl->default_director != NULL) {
606 			VSB_cat(tl->sb,
607 			    "Only one default director possible.\n");
608 			vcc_ErrWhere(tl, t_first);
609 			return;
610 		}
611 		vcc_NextToken(tl);
612 		dn = "vgc_backend_default";
613 		tl->default_director = dn;
614 	} else {
615 		sym = VCC_HandleSymbol(tl, BACKEND, "vgc_backend");
616 		ERRCHK(tl);
617 		AN(sym);
618 		dn = sym->rname;
619 		if (tl->default_director == NULL) {
620 			tl->first_director = sym;
621 			tl->default_director = dn;
622 			sym->noref = 1;
623 		}
624 	}
625 	Fh(tl, 0, "\nstatic VCL_BACKEND %s;\n", dn);
626 	vcc_ParseHostDef(tl, t_be, dn);
627 	if (tl->err) {
628 		VSB_printf(tl->sb,
629 		    "\nIn %.*s specification starting at:\n", PF(t_first));
630 		vcc_ErrWhere(tl, t_first);
631 		return;
632 	}
633 }
634 
635 void
vcc_Backend_Init(struct vcc * tl)636 vcc_Backend_Init(struct vcc *tl)
637 {
638 	struct inifin *ifp;
639 
640 	Fh(tl, 0, "\nstatic struct vsmw_cluster *vsc_cluster;\n");
641 	ifp = New_IniFin(tl);
642 	VSB_cat(ifp->ini, "\tvsc_cluster = VRT_VSM_Cluster_New(ctx,\n"
643 	    "\t    ndirector * VRT_backend_vsm_need(ctx));\n");
644 	VSB_cat(ifp->ini, "\tif (vsc_cluster == 0)\n\t\treturn(1);");
645 	VSB_cat(ifp->fin, "\t\tVRT_VSM_Cluster_Destroy(ctx, &vsc_cluster);");
646 }
647