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