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 12
vcc_default_probe(struct vcc *tl)
40
{
41
42 12
        if (tl->default_probe != NULL)
43 0
                return (tl->default_probe);
44 12
        VSB_printf(tl->sb, "No default probe defined\n");
45 12
        vcc_ErrToken(tl, tl->t);
46 12
        VSB_printf(tl->sb, " at\n");
47 12
        vcc_ErrWhere(tl, tl->t);
48 12
        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 13476
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 13476
        AN(t_host->dec);
65
66 13476
        if (t_port != NULL)
67 9300
                bprintf(buf, "%s %s", t_host->dec, t_port->dec);
68
        else
69 4176
                bprintf(buf, "%s", t_host->dec);
70 13476
        Resolve_Sockaddr(tl, buf, "80",
71
            &ipv4, &ipv4a, &ipv6, &ipv6a, &pa, 2, t_host, "Backend host");
72 13476
        ERRCHK(tl);
73 13452
        if (ipv4 != NULL) {
74 13440
                Fb(tl, 0, "\t.ipv4_suckaddr = (const struct suckaddr *)%s,\n",
75
                    ipv4);
76 13440
                Fb(tl, 0, "\t.ipv4_addr = \"%s\",\n", ipv4a);
77
        }
78 13452
        if (ipv6 != NULL) {
79 24
                Fb(tl, 0, "\t.ipv6_suckaddr = (const struct suckaddr *)%s,\n",
80
                    ipv6);
81 24
                Fb(tl, 0, "\t.ipv6_addr = \"%s\",\n", ipv6a);
82
        }
83 13452
        Fb(tl, 0, "\t.port = \"%s\",\n", pa);
84 13452
        Fb(tl, 0, "\t.path = (void *) 0,\n");
85
}
86
87
/*--------------------------------------------------------------------
88
 * Disallow mutually exclusive field definitions
89
 */
90
91
static void
92 14112
vcc_Redef(struct vcc *tl, const char *redef, struct token **t_did,
93
    struct token *t_field)
94
{
95 14112
        if (*t_did != NULL) {
96 36
                VSB_printf(tl->sb, "%s redefinition at:\n", redef);
97 36
                vcc_ErrWhere(tl, t_field);
98 36
                VSB_printf(tl->sb, "Previous definition:\n");
99 36
                vcc_ErrWhere(tl, *t_did);
100 36
                return;
101
        }
102 14076
        *t_did = t_field;
103
}
104
105
/*--------------------------------------------------------------------
106
 * Parse a backend probe specification
107
 */
108
109
static void
110 372
vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **name)
111
{
112
        struct fld_spec *fs;
113
        struct token *t_field;
114 372
        struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL;
115 372
        struct token *t_initial = NULL;
116
        struct vsb *vsb;
117
        char *retval;
118
        unsigned window, threshold, initial, status;
119
        double t;
120
121 372
        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 456
        SkipToken(tl, '{');
133
134 372
        vsb = VSB_new_auto();
135 372
        AN(vsb);
136 372
        if (sym != NULL)
137 84
                VSB_cat(vsb, sym->rname);
138
        else
139 288
                VSB_printf(vsb, "vgc_probe__%d", tl->nprobe++);
140 372
        AZ(VSB_finish(vsb));
141 372
        retval = TlDup(tl, VSB_data(vsb));
142 372
        AN(retval);
143 372
        VSB_destroy(&vsb);
144 372
        if (name != NULL)
145 372
                *name = retval;
146
147 372
        window = 0;
148 372
        threshold = 0;
149 372
        initial = 0;
150 372
        status = 0;
151 372
        Fh(tl, 0, "static const struct vrt_backend_probe %s[] = {{\n", retval);
152 372
        Fh(tl, 0, "\t.magic = VRT_BACKEND_PROBE_MAGIC,\n");
153 1572
        while (tl->t->tok != '}') {
154
155 864
                vcc_IsField(tl, &t_field, fs);
156 864
                ERRCHK(tl);
157 864
                if (vcc_IdIs(t_field, "url")) {
158 84
                        vcc_Redef(tl, "Probe request", &t_did, t_field);
159 84
                        ERRCHK(tl);
160 72
                        ExpectErr(tl, CSTR);
161 72
                        Fh(tl, 0, "\t.url = ");
162 72
                        EncToken(tl->fh, tl->t);
163 72
                        Fh(tl, 0, ",\n");
164 72
                        vcc_NextToken(tl);
165 780
                } else if (vcc_IdIs(t_field, "request")) {
166 36
                        vcc_Redef(tl, "Probe request", &t_did, t_field);
167 36
                        ERRCHK(tl);
168 24
                        ExpectErr(tl, CSTR);
169 24
                        Fh(tl, 0, "\t.request =\n");
170 96
                        while (tl->t->tok == CSTR) {
171 48
                                Fh(tl, 0, "\t\t");
172 48
                                EncToken(tl->fh, tl->t);
173 48
                                Fh(tl, 0, " \"\\r\\n\"\n");
174 48
                                vcc_NextToken(tl);
175
                        }
176 24
                        Fh(tl, 0, "\t\t\"\\r\\n\",\n");
177 744
                } else if (vcc_IdIs(t_field, "timeout")) {
178 60
                        Fh(tl, 0, "\t.timeout = ");
179 60
                        vcc_Duration(tl, &t);
180 60
                        ERRCHK(tl);
181 60
                        Fh(tl, 0, "%g,\n", t);
182 684
                } else if (vcc_IdIs(t_field, "interval")) {
183 180
                        Fh(tl, 0, "\t.interval = ");
184 180
                        vcc_Duration(tl, &t);
185 180
                        ERRCHK(tl);
186 180
                        Fh(tl, 0, "%g,\n", t);
187 504
                } else if (vcc_IdIs(t_field, "window")) {
188 168
                        t_window = tl->t;
189 168
                        window = vcc_UintVal(tl);
190 168
                        ERRCHK(tl);
191 336
                } else if (vcc_IdIs(t_field, "initial")) {
192 144
                        t_initial = tl->t;
193 144
                        initial = vcc_UintVal(tl);
194 144
                        ERRCHK(tl);
195 192
                } else if (vcc_IdIs(t_field, "expected_response")) {
196 24
                        status = vcc_UintVal(tl);
197 24
                        if (status < 100 || status > 999) {
198 12
                                VSB_printf(tl->sb,
199
                                    "Must specify .expected_response with "
200
                                    "exactly three digits "
201
                                    "(100 <= x <= 999)\n");
202 12
                                vcc_ErrWhere(tl, tl->t);
203 12
                                return;
204
                        }
205 12
                        ERRCHK(tl);
206 168
                } else if (vcc_IdIs(t_field, "threshold")) {
207 168
                        t_threshold = tl->t;
208 168
                        threshold = vcc_UintVal(tl);
209 168
                        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 828
                SkipToken(tl, ';');
218
        }
219
220 336
        if (t_threshold != NULL || t_window != NULL) {
221 180
                if (t_threshold == NULL && t_window != NULL) {
222 12
                        VSB_printf(tl->sb,
223
                            "Must specify .threshold with .window\n");
224 12
                        vcc_ErrWhere(tl, t_window);
225 12
                        return;
226 168
                } else if (t_threshold != NULL && t_window == NULL) {
227 12
                        if (threshold > 64) {
228 12
                                VSB_printf(tl->sb,
229
                                    "Threshold must be 64 or less.\n");
230 12
                                vcc_ErrWhere(tl, t_threshold);
231 12
                                return;
232
                        }
233 0
                        window = threshold + 1;
234 156
                } else if (window > 64) {
235 12
                        AN(t_window);
236 12
                        VSB_printf(tl->sb, "Window must be 64 or less.\n");
237 12
                        vcc_ErrWhere(tl, t_window);
238 12
                        return;
239
                }
240 144
                if (threshold > window ) {
241 12
                        VSB_printf(tl->sb,
242
                            "Threshold can not be greater than window.\n");
243 12
                        AN(t_threshold);
244 12
                        vcc_ErrWhere(tl, t_threshold);
245 12
                        AN(t_window);
246 12
                        vcc_ErrWhere(tl, t_window);
247
                }
248 144
                Fh(tl, 0, "\t.window = %u,\n", window);
249 144
                Fh(tl, 0, "\t.threshold = %u,\n", threshold);
250
        }
251 300
        if (t_initial != NULL)
252 144
                Fh(tl, 0, "\t.initial = %u,\n", initial);
253
        else
254 156
                Fh(tl, 0, "\t.initial = ~0U,\n");
255 300
        if (status > 0)
256 12
                Fh(tl, 0, "\t.exp_status = %u,\n", status);
257 300
        Fh(tl, 0, "}};\n");
258 300
        SkipToken(tl, '}');
259
}
260
261
/*--------------------------------------------------------------------
262
 * Parse and emit a probe definition
263
 */
264
265
void
266 144
vcc_ParseProbe(struct vcc *tl)
267
{
268
        struct symbol *sym;
269
        char *p;
270
271 144
        vcc_NextToken(tl);                      /* ID: probe */
272
273 144
        vcc_ExpectVid(tl, "backend probe");     /* ID: name */
274 156
        ERRCHK(tl);
275 144
        if (vcc_IdIs(tl->t, "default")) {
276 48
                vcc_NextToken(tl);
277 48
                vcc_ParseProbeSpec(tl, NULL, &p);
278 48
                tl->default_probe = p;
279
        } else {
280 96
                sym = VCC_HandleSymbol(tl, PROBE, "vgc_probe");
281 96
                ERRCHK(tl);
282 84
                AN(sym);
283 84
                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 14028
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 14028
        struct token *t_host = NULL;
299 14028
        struct token *t_port = NULL;
300 14028
        struct token *t_path = NULL;
301 14028
        struct token *t_hosthdr = NULL;
302
        struct symbol *pb;
303 14028
        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 14028
        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 14280
        SkipToken(tl, '{');
325
326 14028
        vsb = VSB_new_auto();
327 14028
        AN(vsb);
328 14028
        tl->fb = vsb;
329
330 14028
        Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n",
331
            vgcname);
332
333 14028
        Fb(tl, 0, "\t.magic = VRT_BACKEND_MAGIC,\n");
334 14028
        Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be));
335 14028
        Fb(tl, 0, "\",\n");
336
337
        /* Check for old syntax */
338 14028
        if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
339 12
                VSB_printf(tl->sb,
340
                    "NB: Backend Syntax has changed:\n"
341
                    "Remove \"set\" and \"backend\" in front"
342
                    " of backend fields.\n" );
343 12
                vcc_ErrToken(tl, tl->t);
344 12
                VSB_printf(tl->sb, " at ");
345 12
                vcc_ErrWhere(tl, tl->t);
346 12
                return;
347
        }
348
349 51768
        while (tl->t->tok != '}') {
350
351 23904
                vcc_IsField(tl, &t_field, fs);
352 23904
                ERRCHK(tl);
353 23880
                if (vcc_IdIs(t_field, "host")) {
354 13620
                        vcc_Redef(tl, "Address", &t_did, t_field);
355 13620
                        ERRCHK(tl);
356 13620
                        ExpectErr(tl, CSTR);
357 13620
                        assert(tl->t->dec != NULL);
358 13620
                        t_host = tl->t;
359 13620
                        vcc_NextToken(tl);
360 13620
                        SkipToken(tl, ';');
361 10260
                } else if (vcc_IdIs(t_field, "port")) {
362 9324
                        ExpectErr(tl, CSTR);
363 9324
                        assert(tl->t->dec != NULL);
364 9324
                        t_port = tl->t;
365 9324
                        vcc_NextToken(tl);
366 9324
                        SkipToken(tl, ';');
367 936
                } else if (vcc_IdIs(t_field, "path")) {
368 384
                        if (tl->syntax < VCL_41) {
369 12
                                VSB_printf(tl->sb,
370
                                    "Unix socket backends only supported"
371
                                    " in VCL4.1 and higher.\n");
372 12
                                vcc_ErrToken(tl, tl->t);
373 12
                                VSB_printf(tl->sb, " at ");
374 12
                                vcc_ErrWhere(tl, tl->t);
375 12
                                return;
376
                        }
377 372
                        vcc_Redef(tl, "Address", &t_did, t_field);
378 372
                        ERRCHK(tl);
379 360
                        ExpectErr(tl, CSTR);
380 360
                        assert(tl->t->dec != NULL);
381 360
                        t_path = tl->t;
382 360
                        vcc_NextToken(tl);
383 360
                        SkipToken(tl, ';');
384 552
                } else if (vcc_IdIs(t_field, "host_header")) {
385 36
                        ExpectErr(tl, CSTR);
386 36
                        assert(tl->t->dec != NULL);
387 36
                        t_hosthdr = tl->t;
388 36
                        vcc_NextToken(tl);
389 36
                        SkipToken(tl, ';');
390 516
                } 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 516
                } else if (vcc_IdIs(t_field, "first_byte_timeout")) {
397 36
                        Fb(tl, 0, "\t.first_byte_timeout = ");
398 36
                        vcc_Duration(tl, &t);
399 36
                        ERRCHK(tl);
400 36
                        Fb(tl, 0, "%g,\n", t);
401 36
                        SkipToken(tl, ';');
402 480
                } else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
403 12
                        Fb(tl, 0, "\t.between_bytes_timeout = ");
404 12
                        vcc_Duration(tl, &t);
405 12
                        ERRCHK(tl);
406 12
                        Fb(tl, 0, "%g,\n", t);
407 12
                        SkipToken(tl, ';');
408 468
                } else if (vcc_IdIs(t_field, "max_connections")) {
409 60
                        u = vcc_UintVal(tl);
410 60
                        ERRCHK(tl);
411 60
                        SkipToken(tl, ';');
412 60
                        Fb(tl, 0, "\t.max_connections = %u,\n", u);
413 408
                } else if (vcc_IdIs(t_field, "proxy_header")) {
414 72
                        t_val = tl->t;
415 72
                        u = vcc_UintVal(tl);
416 72
                        ERRCHK(tl);
417 72
                        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 72
                        SkipToken(tl, ';');
424 72
                        Fb(tl, 0, "\t.proxy_header = %u,\n", u);
425 336
                } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
426 240
                        vcc_ParseProbeSpec(tl, NULL, &p);
427 240
                        Fb(tl, 0, "\t.probe = %s,\n", p);
428 240
                        ERRCHK(tl);
429 96
                } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) {
430 84
                        if (vcc_IdIs(tl->t, "default")) {
431 12
                                vcc_NextToken(tl);
432 12
                                (void)vcc_default_probe(tl);
433
                        } else {
434 72
                                pb = VCC_SymbolGet(tl, SYM_PROBE,
435
                                    "Probe not found", XREF_REF);
436 72
                                ERRCHK(tl);
437 60
                                AN(pb);
438 60
                                Fb(tl, 0, "\t.probe = %s,\n", pb->rname);
439
                        }
440 72
                        SkipToken(tl, ';');
441 12
                } else if (vcc_IdIs(t_field, "probe")) {
442 12
                        VSB_printf(tl->sb,
443
                            "Expected '{' or name of probe, got ");
444 12
                        vcc_ErrToken(tl, tl->t);
445 12
                        VSB_printf(tl->sb, " at\n");
446 12
                        vcc_ErrWhere(tl, tl->t);
447 12
                        return;
448
                } else {
449 0
                        ErrInternal(tl);
450 0
                        return;
451
                }
452
453
        }
454
455 13848
        vcc_FieldsOk(tl, fs);
456 13848
        ERRCHK(tl);
457
458 13848
        if (t_host == NULL && t_path == NULL) {
459 12
                VSB_printf(tl->sb, "Expected .host or .path.\n");
460 12
                vcc_ErrWhere(tl, t_be);
461 12
                return;
462
        }
463
464 13836
        assert(t_host != NULL || t_path != NULL);
465 13836
        if (t_host != NULL)
466
                /* Check that the hostname makes sense */
467 13476
                Emit_Sockaddr(tl, t_host, t_port);
468
        else
469
                /* Check that the path can be a legal UDS */
470 360
                Emit_UDS_Path(tl, t_path, "Backend path");
471 13836
        ERRCHK(tl);
472
473 13776
        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 13776
        Fb(tl, 0, "\t.hosthdr = ");
480 13776
        if (t_hosthdr != NULL)
481 36
                EncToken(tl->fb, t_hosthdr);
482 13740
        else if (t_host != NULL)
483 13440
                EncToken(tl->fb, t_host);
484
        else
485 300
                Fb(tl, 0, "\"0.0.0.0\"");
486 13776
        Fb(tl, 0, ",\n");
487
488
        /* Close the struct */
489 13776
        Fb(tl, 0, "};\n");
490
491 13776
        vcc_NextToken(tl);
492
493 13776
        tl->fb = NULL;
494 13776
        AZ(VSB_finish(vsb));
495 13776
        Fh(tl, 0, "%s", VSB_data(vsb));
496 13776
        VSB_destroy(&vsb);
497
498 13776
        ifp = New_IniFin(tl);
499 13776
        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 13776
        VSB_printf(ifp->fin, "\t\tVRT_delete_backend(ctx, &%s);", vgcname);
504
}
505
506
/*--------------------------------------------------------------------
507
 * Parse directors and backends
508
 */
509
510
void
511 14088
vcc_ParseBackend(struct vcc *tl)
512
{
513
        struct token *t_first, *t_be;
514
        struct symbol *sym;
515
        const char *dn;
516
517 14088
        tl->ndirector++;
518 14088
        t_first = tl->t;
519 14088
        SkipToken(tl, ID);              /* ID: backend */
520
521 14088
        vcc_ExpectVid(tl, "backend");   /* ID: name */
522 14088
        ERRCHK(tl);
523
524 14076
        t_be = tl->t;
525 14076
        if (vcc_IdIs(tl->t, "default")) {
526 432
                if (tl->first_director != NULL) {
527 36
                        tl->first_director->noref = 0;
528 36
                        tl->first_director = NULL;
529 36
                        tl->default_director = NULL;
530
                }
531 432
                if (tl->default_director != NULL) {
532 12
                        VSB_printf(tl->sb,
533
                            "Only one default director possible.\n");
534 12
                        vcc_ErrWhere(tl, t_first);
535 12
                        return;
536
                }
537 420
                vcc_NextToken(tl);
538 420
                dn = "vgc_backend_default";
539 420
                tl->default_director = dn;
540
        } else {
541 13644
                sym = VCC_HandleSymbol(tl, BACKEND, "vgc_backend");
542 13644
                ERRCHK(tl);
543 13608
                dn = sym->rname;
544 13608
                if (tl->default_director == NULL) {
545 11412
                        tl->first_director = sym;
546 11412
                        tl->default_director = dn;
547 11412
                        sym->noref = 1;
548
                }
549
        }
550 14028
        Fh(tl, 0, "\nstatic VCL_BACKEND %s;\n", dn);
551 14028
        vcc_ParseHostDef(tl, t_be, dn);
552 14028
        if (tl->err) {
553 504
                VSB_printf(tl->sb,
554 252
                    "\nIn %.*s specification starting at:\n", PF(t_first));
555 252
                vcc_ErrWhere(tl, t_first);
556 252
                return;
557
        }
558
}
559
560
void
561 12756
vcc_Backend_Init(struct vcc *tl)
562
{
563
        struct inifin *ifp;
564
565 12756
        Fh(tl, 0, "\nstatic struct vsmw_cluster *vsc_cluster;\n");
566 12756
        ifp = New_IniFin(tl);
567 12756
        VSB_printf(ifp->ini, "\tvsc_cluster = VRT_VSM_Cluster_New(ctx,\n"
568
            "\t    ndirector * VRT_backend_vsm_need(ctx));\n");
569 12756
        VSB_printf(ifp->ini, "\tif (vsc_cluster == 0)\n\t\treturn(1);");
570 12756
        VSB_printf(ifp->fin, "\t\tVRT_VSM_Cluster_Destroy(ctx, &vsc_cluster);");
571 12756
}