Show
Ignore:
Timestamp:
03/16/10 09:52:37 (5 months ago)
Author:
phk
Message:

Move the utility parser functions into their own file

Location:
trunk/varnish-cache/lib/libvcl
Files:
2 modified
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/varnish-cache/lib/libvcl/Makefile.am

    r4188 r4611  
    1515        vcc_action.c \ 
    1616        vcc_backend.c \ 
     17        vcc_backend_util.c \ 
    1718        vcc_compile.c \ 
    1819        vcc_dir_random.c \ 
  • trunk/varnish-cache/lib/libvcl/vcc_backend.c

    r4556 r4611  
    219219 
    220220/*-------------------------------------------------------------------- 
    221  * Helper functions to complain about duplicate and missing fields 
    222  * 
    223  * XXX: idea: add groups to check for exclusivity, such that 
    224  * XXX:    ("!foo", "?bar", "!{", "this", "that", "}", NULL) 
    225  * XXX: means exactly one of "this" or "that", and 
    226  * XXX:    ("!foo", "?bar", "?{", "this", "that", "}", NULL) 
    227  * XXX: means at most one of "this" or "that". 
    228  */ 
    229  
    230 struct fld_spec { 
    231         const char      *name; 
    232         struct token    *found; 
    233 }; 
    234  
    235 void 
    236 vcc_ResetFldSpec(struct fld_spec *f) 
    237 { 
    238  
    239         for (; f->name != NULL; f++) 
    240                 f->found = NULL; 
    241 } 
    242  
    243 struct fld_spec * 
    244 vcc_FldSpec(struct tokenlist *tl, const char *first, ...) 
    245 { 
    246         struct fld_spec f[100], *r; 
    247         int n = 0; 
    248         va_list ap; 
    249         const char *p; 
    250  
    251         f[n++].name = first; 
    252         va_start(ap, first); 
    253         while (1) { 
    254                 p = va_arg(ap, const char *); 
    255                 if (p == NULL) 
    256                         break; 
    257                 f[n++].name = p; 
    258                 assert(n < 100); 
    259         } 
    260         va_end(ap); 
    261         f[n++].name = NULL; 
    262  
    263         vcc_ResetFldSpec(f); 
    264  
    265         r = TlAlloc(tl, sizeof *r * n); 
    266         memcpy(r, f, n * sizeof *r); 
    267         return (r); 
    268 } 
    269  
    270 void 
    271 vcc_IsField(struct tokenlist *tl, struct token **t, struct fld_spec *fs) 
    272 { 
    273         struct token *t_field; 
    274  
    275         ExpectErr(tl, '.'); 
    276         vcc_NextToken(tl); 
    277         ExpectErr(tl, ID); 
    278         t_field = tl->t; 
    279         *t = t_field; 
    280         vcc_NextToken(tl); 
    281         ExpectErr(tl, '='); 
    282         vcc_NextToken(tl); 
    283  
    284         for (; fs->name != NULL; fs++) { 
    285                 if (!vcc_IdIs(t_field, fs->name + 1)) 
    286                         continue; 
    287                 if (fs->found == NULL) { 
    288                         fs->found = t_field; 
    289                         return; 
    290                 } 
    291                 vsb_printf(tl->sb, "Field "); 
    292                 vcc_ErrToken(tl, t_field); 
    293                 vsb_printf(tl->sb, " redefined at:\n"); 
    294                 vcc_ErrWhere(tl, t_field); 
    295                 vsb_printf(tl->sb, "\nFirst defined at:\n"); 
    296                 vcc_ErrWhere(tl, fs->found); 
    297                 return; 
    298         } 
    299         vsb_printf(tl->sb, "Unknown field: "); 
    300         vcc_ErrToken(tl, t_field); 
    301         vsb_printf(tl->sb, " at\n"); 
    302         vcc_ErrWhere(tl, t_field); 
    303         return; 
    304 } 
    305  
    306 void 
    307 vcc_FieldsOk(struct tokenlist *tl, const struct fld_spec *fs) 
    308 { 
    309  
    310         for (; fs->name != NULL; fs++) { 
    311                 if (*fs->name == '!' && fs->found == NULL) { 
    312                         vsb_printf(tl->sb, 
    313                             "Mandatory field '%s' missing.\n", fs->name + 1); 
    314                         tl->err = 1; 
    315                 } 
    316         } 
    317 } 
    318  
    319 /*-------------------------------------------------------------------- 
    320221 * Parse a backend probe specification 
    321222 */ 
  • trunk/varnish-cache/lib/libvcl/vcc_backend_util.c

    r4556 r4611  
    2727 * SUCH DAMAGE. 
    2828 * 
    29  * A necessary explanation of a convoluted policy: 
    30  * 
    31  * In VCL we have backends and directors. 
    32  * 
    33  * In VRT we have directors which reference (a number of) backend hosts. 
    34  * 
    35  * A VCL backend therefore has an implicit director of type "simple" created 
    36  * by the compiler, but not visible in VCL. 
    37  * 
    38  * A VCL backend is a "named host", these can be referenced by name from 
    39  * VCL directors, but not from VCL backends. 
    40  * 
    41  * The reason for this quasimadness is that we want to collect statistics 
    42  * for each actual kickable hardware backend machine, but we want to be 
    43  * able to refer to them multiple times in different directors. 
    44  * 
    45  * At the same time, we do not want to force users to declare each backend 
    46  * host with a name, if all they want to do is put it into a director, so 
    47  * backend hosts can be declared inline in the director, in which case 
    48  * its identity is the director and its numerical index therein. 
    4929 */ 
    5030 
     
    5434SVNID("$Id$") 
    5535 
    56 #include <sys/types.h> 
    57 #include <sys/socket.h> 
    58  
    59 #include <limits.h> 
    60 #include <netdb.h> 
    6136#include <stdio.h> 
    6237#include <stdarg.h> 
     
    6843#include "vcc_compile.h" 
    6944#include "libvarnish.h" 
    70  
    71 struct host { 
    72         VTAILQ_ENTRY(host)      list; 
    73         struct token            *name; 
    74         char                    *vgcname; 
    75 }; 
    76  
    77 static const char * 
    78 CheckHostPort(const char *host, const char *port) 
    79 { 
    80         struct addrinfo *res, hint; 
    81         int error; 
    82  
    83         memset(&hint, 0, sizeof hint); 
    84         hint.ai_family = PF_UNSPEC; 
    85         hint.ai_socktype = SOCK_STREAM; 
    86         error = getaddrinfo(host, port, &hint, &res); 
    87         if (error) 
    88                 return (gai_strerror(error)); 
    89         freeaddrinfo(res); 
    90         return (NULL); 
    91 } 
    92  
    93 /*-------------------------------------------------------------------- 
    94  * Struct sockaddr is not really designed to be a compile time 
    95  * initialized data structure, so we encode it as a byte-string 
    96  * and put it in an official sockaddr when we load the VCL. 
    97  */ 
    98  
    99 static void 
    100 Emit_Sockaddr(struct tokenlist *tl, const struct token *t_host, 
    101     const char *port) 
    102 { 
    103         struct addrinfo *res, *res0, *res1, hint; 
    104         int n4, n6, len, error, retval; 
    105         const char *emit, *multiple; 
    106         unsigned char *u; 
    107         char hbuf[NI_MAXHOST]; 
    108  
    109         AN(t_host->dec); 
    110         retval = 0; 
    111         memset(&hint, 0, sizeof hint); 
    112         hint.ai_family = PF_UNSPEC; 
    113         hint.ai_socktype = SOCK_STREAM; 
    114         error = getaddrinfo(t_host->dec, port, &hint, &res0); 
    115         AZ(error); 
    116         n4 = n6 = 0; 
    117         multiple = NULL; 
    118         for (res = res0; res; res = res->ai_next) { 
    119                 emit = NULL; 
    120                 if (res->ai_family == PF_INET) { 
    121                         if (n4++ == 0) 
    122                                 emit = "ipv4_sockaddr"; 
    123                         else 
    124                                 multiple = "IPv4"; 
    125                 } else if (res->ai_family == PF_INET6) { 
    126                         if (n6++ == 0) 
    127                                 emit = "ipv6_sockaddr"; 
    128                         else 
    129                                 multiple = "IPv6"; 
    130                 } else 
    131                         continue; 
    132  
    133                 if (multiple != NULL) { 
    134                         vsb_printf(tl->sb, 
    135                             "Backend host %.*s: resolves to " 
    136                             "multiple %s addresses.\n" 
    137                             "Only one address is allowed.\n" 
    138                             "Please specify which exact address " 
    139                             "you want to use, we found these:\n", 
    140                             PF(t_host), multiple); 
    141                         for (res1 = res0; res1 != NULL; res1 = res1->ai_next) { 
    142                                 error = getnameinfo(res1->ai_addr, 
    143                                     res1->ai_addrlen, hbuf, sizeof hbuf, 
    144                                     NULL, 0, NI_NUMERICHOST); 
    145                                 AZ(error); 
    146                                 vsb_printf(tl->sb, "\t%s\n", hbuf); 
    147                         } 
    148                         vcc_ErrWhere(tl, t_host); 
    149                         return; 
    150                 } 
    151                 AN(emit); 
    152                 AN(res->ai_addr); 
    153                 AN(res->ai_addrlen); 
    154                 assert(res->ai_addrlen < 256); 
    155                 Fh(tl, 0, "\nstatic const unsigned char sockaddr%u[%d] = {\n", 
    156                     tl->nsockaddr, res->ai_addrlen + 1); 
    157                 Fh(tl, 0, "    %3u, /* Length */\n",  res->ai_addrlen); 
    158                 u = (void*)res->ai_addr; 
    159                 for (len = 0; len < res->ai_addrlen; len++) { 
    160                         if ((len % 8) == 0) 
    161                                 Fh(tl, 0, "   "); 
    162                         Fh(tl, 0, " %3u", u[len]); 
    163                         if (len + 1 < res->ai_addrlen) 
    164                                 Fh(tl, 0, ","); 
    165                         if ((len % 8) == 7) 
    166                                 Fh(tl, 0, "\n"); 
    167                 } 
    168                 Fh(tl, 0, "\n};\n"); 
    169                 Fb(tl, 0, "\t.%s = sockaddr%u,\n", emit, tl->nsockaddr++); 
    170                 retval++; 
    171         } 
    172         freeaddrinfo(res0); 
    173         if (retval == 0) { 
    174                 vsb_printf(tl->sb, 
    175                     "Backend host '%.*s': resolves to " 
    176                     "neither IPv4 nor IPv6 addresses.\n", 
    177                     PF(t_host) ); 
    178                 vcc_ErrWhere(tl, t_host); 
    179         } 
    180 } 
    181  
    182 /*-------------------------------------------------------------------- 
    183  * When a new VCL is loaded, it is likely to contain backend declarations 
    184  * identical to other loaded VCL programs, and we want to reuse the state 
    185  * of those in order to not have to relearn statistics, DNS etc. 
    186  * 
    187  * This function emits a space separated text-string of the tokens which 
    188  * define a given backend which can be used to determine "identical backend" 
    189  * in that context. 
    190  */ 
    191  
    192 static void 
    193 vcc_EmitBeIdent(const struct tokenlist *tl, struct vsb *v, 
    194     int serial, const struct token *first, const struct token *last) 
    195 { 
    196  
    197         assert(first != last); 
    198         vsb_printf(v, "\t.ident ="); 
    199         if (serial >= 0) { 
    200                 vsb_printf(v, "\n\t    \"%.*s %.*s [%d] \"", 
    201                     PF(tl->t_policy), PF(tl->t_dir), serial); 
    202         } else { 
    203                 vsb_printf(v, "\n\t    \"%.*s %.*s \"", 
    204                     PF(tl->t_policy), PF(tl->t_dir)); 
    205         } 
    206         while (1) { 
    207                 if (first->dec != NULL) 
    208                         vsb_printf(v, "\n\t    \"\\\"\" %.*s \"\\\" \"", 
    209                             PF(first)); 
    210                 else 
    211                         vsb_printf(v, "\n\t    \"%.*s \"", PF(first)); 
    212                 if (first == last) 
    213                         break; 
    214                 first = VTAILQ_NEXT(first, list); 
    215                 AN(first); 
    216         } 
    217         vsb_printf(v, ",\n"); 
    218 } 
    21945 
    22046/*-------------------------------------------------------------------- 
     
    316142        } 
    317143} 
    318  
    319 /*-------------------------------------------------------------------- 
    320  * Parse a backend probe specification 
    321  */ 
    322  
    323 static void 
    324 vcc_ProbeRedef(struct tokenlist *tl, struct token **t_did, 
    325     struct token *t_field) 
    326 { 
    327         /* .url and .request are mutually exclusive */ 
    328  
    329         if (*t_did != NULL) { 
    330                 vsb_printf(tl->sb, 
    331                     "Probe request redefinition at:\n"); 
    332                 vcc_ErrWhere(tl, t_field); 
    333                 vsb_printf(tl->sb, 
    334                     "Previous definition:\n"); 
    335                 vcc_ErrWhere(tl, *t_did); 
    336                 return; 
    337         } 
    338         *t_did = t_field; 
    339 } 
    340  
    341 static void 
    342 vcc_ParseProbe(struct tokenlist *tl) 
    343 { 
    344         struct fld_spec *fs; 
    345         struct token *t_field; 
    346         struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL; 
    347         struct token *t_initial = NULL; 
    348         unsigned window, threshold, initial, status; 
    349  
    350         fs = vcc_FldSpec(tl, 
    351             "?url", 
    352             "?request", 
    353             "?expected_response", 
    354             "?timeout", 
    355             "?interval", 
    356             "?window", 
    357             "?threshold", 
    358             "?initial", 
    359             NULL); 
    360  
    361         ExpectErr(tl, '{'); 
    362         vcc_NextToken(tl); 
    363  
    364         window = 0; 
    365         threshold = 0; 
    366         initial = 0; 
    367         status = 0; 
    368         Fb(tl, 0, "\t.probe = {\n"); 
    369         while (tl->t->tok != '}') { 
    370  
    371                 vcc_IsField(tl, &t_field, fs); 
    372                 ERRCHK(tl); 
    373                 if (vcc_IdIs(t_field, "url")) { 
    374                         vcc_ProbeRedef(tl, &t_did, t_field); 
    375                         ERRCHK(tl); 
    376                         ExpectErr(tl, CSTR); 
    377                         Fb(tl, 0, "\t\t.url = "); 
    378                         EncToken(tl->fb, tl->t); 
    379                         Fb(tl, 0, ",\n"); 
    380                         vcc_NextToken(tl); 
    381                 } else if (vcc_IdIs(t_field, "request")) { 
    382                         vcc_ProbeRedef(tl, &t_did, t_field); 
    383                         ERRCHK(tl); 
    384                         ExpectErr(tl, CSTR); 
    385                         Fb(tl, 0, "\t\t.request =\n"); 
    386                         while (tl->t->tok == CSTR) { 
    387                                 Fb(tl, 0, "\t\t\t"); 
    388                                 EncToken(tl->fb, tl->t); 
    389                                 Fb(tl, 0, " \"\\r\\n\"\n"); 
    390                                 vcc_NextToken(tl); 
    391                         } 
    392                         Fb(tl, 0, "\t\t\t\"\\r\\n\",\n"); 
    393                 } else if (vcc_IdIs(t_field, "timeout")) { 
    394                         Fb(tl, 0, "\t\t.timeout = "); 
    395                         vcc_TimeVal(tl); 
    396                         ERRCHK(tl); 
    397                         Fb(tl, 0, ",\n"); 
    398                 } else if (vcc_IdIs(t_field, "interval")) { 
    399                         Fb(tl, 0, "\t\t.interval = "); 
    400                         vcc_TimeVal(tl); 
    401                         ERRCHK(tl); 
    402                         Fb(tl, 0, ",\n"); 
    403                 } else if (vcc_IdIs(t_field, "window")) { 
    404                         t_window = tl->t; 
    405                         window = vcc_UintVal(tl); 
    406                         vcc_NextToken(tl); 
    407                         ERRCHK(tl); 
    408                 } else if (vcc_IdIs(t_field, "initial")) { 
    409                         t_initial = tl->t; 
    410                         initial = vcc_UintVal(tl); 
    411                         vcc_NextToken(tl); 
    412                         ERRCHK(tl); 
    413                 } else if (vcc_IdIs(t_field, "expected_response")) { 
    414                         status = vcc_UintVal(tl); 
    415                         if (status < 100 || status > 999) { 
    416                                 vsb_printf(tl->sb, 
    417                                     "Must specify .status with exactly three " 
    418                                     " digits (100 <= x <= 999)\n"); 
    419                                 vcc_ErrWhere(tl, tl->t); 
    420                                 return; 
    421                         } 
    422                         vcc_NextToken(tl); 
    423                         ERRCHK(tl); 
    424                 } else if (vcc_IdIs(t_field, "threshold")) { 
    425                         t_threshold = tl->t; 
    426                         threshold = vcc_UintVal(tl); 
    427                         vcc_NextToken(tl); 
    428                         ERRCHK(tl); 
    429                 } else { 
    430                         vcc_ErrToken(tl, t_field); 
    431                         vcc_ErrWhere(tl, t_field); 
    432                         ErrInternal(tl); 
    433                         return; 
    434                 } 
    435  
    436                 ExpectErr(tl, ';'); 
    437                 vcc_NextToken(tl); 
    438         } 
    439  
    440         if (t_threshold != NULL || t_window != NULL) { 
    441                 if (t_threshold == NULL && t_window != NULL) { 
    442                         vsb_printf(tl->sb, 
    443                             "Must specify .threshold with .window\n"); 
    444                         vcc_ErrWhere(tl, t_window); 
    445                         return; 
    446                 } else if (t_threshold != NULL && t_window == NULL) { 
    447                         if (threshold > 64) { 
    448                                 vsb_printf(tl->sb, 
    449                                     "Threshold must be 64 or less.\n"); 
    450                                 vcc_ErrWhere(tl, t_threshold); 
    451                                 return; 
    452                         } 
    453                         window = threshold + 1; 
    454                 } else if (window > 64) { 
    455                         AN(t_window); 
    456                         vsb_printf(tl->sb, "Window must be 64 or less.\n"); 
    457                         vcc_ErrWhere(tl, t_window); 
    458                         return; 
    459                 } 
    460                 if (threshold > window ) { 
    461                         vsb_printf(tl->sb, 
    462                             "Threshold can not be greater than window.\n"); 
    463                         AN(t_threshold); 
    464                         vcc_ErrWhere(tl, t_threshold); 
    465                         AN(t_window); 
    466                         vcc_ErrWhere(tl, t_window); 
    467                 } 
    468                 Fb(tl, 0, "\t\t.window = %u,\n", window); 
    469                 Fb(tl, 0, "\t\t.threshold = %u,\n", threshold); 
    470         } 
    471         if (t_initial != NULL) 
    472                 Fb(tl, 0, "\t\t.initial = %u,\n", initial); 
    473         else 
    474                 Fb(tl, 0, "\t\t.initial = ~0U,\n", initial); 
    475         if (status > 0) 
    476                 Fb(tl, 0, "\t\t.exp_status = %u,\n", status); 
    477         Fb(tl, 0, "\t},\n"); 
    478         ExpectErr(tl, '}'); 
    479         vcc_NextToken(tl); 
    480 } 
    481  
    482 /*-------------------------------------------------------------------- 
    483  * Parse and emit a backend host definition 
    484  * 
    485  * The struct vrt_backend is emitted to Fh(). 
    486  */ 
    487  
    488 static void 
    489 vcc_ParseHostDef(struct tokenlist *tl, int serial, const char *vgcname) 
    490 { 
    491         struct token *t_field; 
    492         struct token *t_first; 
    493         struct token *t_host = NULL; 
    494         struct token *t_port = NULL; 
    495         struct token *t_hosthdr = NULL; 
    496         unsigned saint = UINT_MAX; 
    497         const char *ep; 
    498         struct fld_spec *fs; 
    499         struct vsb *vsb; 
    500         unsigned u; 
    501  
    502         Fh(tl, 1, "\n#define VGC_backend_%s %d\n", vgcname, tl->ndirector); 
    503  
    504         fs = vcc_FldSpec(tl, 
    505             "!host", 
    506             "?port", 
    507             "?host_header", 
    508             "?connect_timeout", 
    509             "?first_byte_timeout", 
    510             "?between_bytes_timeout", 
    511             "?probe", 
    512             "?max_connections", 
    513             "?saintmode_threshold", 
    514             NULL); 
    515         t_first = tl->t; 
    516  
    517         ExpectErr(tl, '{'); 
    518         vcc_NextToken(tl); 
    519  
    520         vsb = vsb_newauto(); 
    521         AN(vsb); 
    522         tl->fb = vsb; 
    523  
    524         Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n", 
    525             vgcname); 
    526  
    527         Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(tl->t_dir)); 
    528         if (serial >= 0) 
    529                 Fb(tl, 0, "[%d]", serial); 
    530         Fb(tl, 0, "\",\n"); 
    531  
    532         /* Check for old syntax */ 
    533         if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) { 
    534                 vsb_printf(tl->sb, 
    535                     "NB: Backend Syntax has changed:\n" 
    536                     "Remove \"set\" and \"backend\" in front" 
    537                     " of backend fields.\n" ); 
    538                 vcc_ErrToken(tl, tl->t); 
    539                 vsb_printf(tl->sb, " at "); 
    540                 vcc_ErrWhere(tl, tl->t); 
    541                 return; 
    542         } 
    543  
    544         while (tl->t->tok != '}') { 
    545  
    546                 vcc_IsField(tl, &t_field, fs); 
    547                 ERRCHK(tl); 
    548                 if (vcc_IdIs(t_field, "host")) { 
    549                         ExpectErr(tl, CSTR); 
    550                         assert(tl->t->dec != NULL); 
    551                         t_host = tl->t; 
    552                         vcc_NextToken(tl); 
    553                         ExpectErr(tl, ';'); 
    554                         vcc_NextToken(tl); 
    555                 } else if (vcc_IdIs(t_field, "port")) { 
    556                         ExpectErr(tl, CSTR); 
    557                         assert(tl->t->dec != NULL); 
    558                         t_port = tl->t; 
    559                         vcc_NextToken(tl); 
    560                         ExpectErr(tl, ';'); 
    561                         vcc_NextToken(tl); 
    562                 } else if (vcc_IdIs(t_field, "host_header")) { 
    563                         ExpectErr(tl, CSTR); 
    564                         assert(tl->t->dec != NULL); 
    565                         t_hosthdr = tl->t; 
    566                         vcc_NextToken(tl); 
    567                         ExpectErr(tl, ';'); 
    568                         vcc_NextToken(tl); 
    569                 } else if (vcc_IdIs(t_field, "connect_timeout")) { 
    570                         Fb(tl, 0, "\t.connect_timeout = "); 
    571                         vcc_TimeVal(tl); 
    572                         ERRCHK(tl); 
    573                         Fb(tl, 0, ",\n"); 
    574                         ExpectErr(tl, ';'); 
    575                         vcc_NextToken(tl); 
    576                 } else if (vcc_IdIs(t_field, "first_byte_timeout")) { 
    577                         Fb(tl, 0, "\t.first_byte_timeout = "); 
    578                         vcc_TimeVal(tl); 
    579                         ERRCHK(tl); 
    580                         Fb(tl, 0, ",\n"); 
    581                         ExpectErr(tl, ';'); 
    582                         vcc_NextToken(tl); 
    583                 } else if (vcc_IdIs(t_field, "between_bytes_timeout")) { 
    584                         Fb(tl, 0, "\t.between_bytes_timeout = "); 
    585                         vcc_TimeVal(tl); 
    586                         ERRCHK(tl); 
    587                         Fb(tl, 0, ",\n"); 
    588                         ExpectErr(tl, ';'); 
    589                         vcc_NextToken(tl); 
    590                 } else if (vcc_IdIs(t_field, "max_connections")) { 
    591                         u = vcc_UintVal(tl); 
    592                         vcc_NextToken(tl); 
    593                         ERRCHK(tl); 
    594                         ExpectErr(tl, ';'); 
    595                         vcc_NextToken(tl); 
    596                         Fb(tl, 0, "\t.max_connections = %u,\n", u); 
    597                 } else if (vcc_IdIs(t_field, "saintmode_threshold")) { 
    598                         u = vcc_UintVal(tl); 
    599                         /* UINT_MAX == magic number to mark as unset, so 
    600                          * not allowed here. 
    601                          */ 
    602                         if (u == UINT_MAX) { 
    603                                 vsb_printf(tl->sb, 
    604                                     "Value outside allowed range: "); 
    605                                 vcc_ErrToken(tl, tl->t); 
    606                                 vsb_printf(tl->sb, " at\n"); 
    607                                 vcc_ErrWhere(tl, tl->t); 
    608                         } 
    609                         vcc_NextToken(tl); 
    610                         ERRCHK(tl); 
    611                         saint = u; 
    612                         ExpectErr(tl, ';'); 
    613                         vcc_NextToken(tl); 
    614                 } else if (vcc_IdIs(t_field, "probe")) { 
    615                         vcc_ParseProbe(tl); 
    616                         ERRCHK(tl); 
    617                 } else { 
    618                         ErrInternal(tl); 
    619                         return; 
    620                 } 
    621  
    622         } 
    623  
    624         vcc_FieldsOk(tl, fs); 
    625         ERRCHK(tl); 
    626  
    627         /* Check that the hostname makes sense */ 
    628         assert(t_host != NULL); 
    629         ep = CheckHostPort(t_host->dec, "80"); 
    630         if (ep != NULL) { 
    631                 vsb_printf(tl->sb, "Backend host '%.*s': %s\n", PF(t_host), ep); 
    632                 vcc_ErrWhere(tl, t_host); 
    633                 return; 
    634         } 
    635  
    636         /* Check that the portname makes sense */ 
    637         if (t_port != NULL) { 
    638                 ep = CheckHostPort("127.0.0.1", t_port->dec); 
    639                 if (ep != NULL) { 
    640                         vsb_printf(tl->sb, 
    641                             "Backend port '%.*s': %s\n", PF(t_port), ep); 
    642                         vcc_ErrWhere(tl, t_port); 
    643                         return; 
    644                 } 
    645                 Emit_Sockaddr(tl, t_host, t_port->dec); 
    646         } else { 
    647                 Emit_Sockaddr(tl, t_host, "80"); 
    648         } 
    649         ERRCHK(tl); 
    650  
    651         ExpectErr(tl, '}'); 
    652  
    653         /* We have parsed it all, emit the ident string */ 
    654         vcc_EmitBeIdent(tl, tl->fb, serial, t_first, tl->t); 
    655  
    656         /* Emit the hosthdr field, fall back to .host if not specified */ 
    657         Fb(tl, 0, "\t.hosthdr = "); 
    658         if (t_hosthdr != NULL) 
    659                 EncToken(tl->fb, t_hosthdr); 
    660         else 
    661                 EncToken(tl->fb, t_host); 
    662         Fb(tl, 0, ",\n"); 
    663  
    664         Fb(tl, 0, "\t.saintmode_threshold = %d,\n",saint); 
    665  
    666         /* Close the struct */ 
    667         Fb(tl, 0, "};\n"); 
    668  
    669         vcc_NextToken(tl); 
    670  
    671         tl->fb = NULL; 
    672         vsb_finish(vsb); 
    673         AZ(vsb_overflowed(vsb)); 
    674         Fh(tl, 0, "%s", vsb_data(vsb)); 
    675         vsb_delete(vsb); 
    676  
    677         Fi(tl, 0, "\tVRT_init_dir(cli, VCL_conf.director, \"simple\",\n" 
    678             "\t    VGC_backend_%s, &vgc_dir_priv_%s);\n", vgcname, vgcname); 
    679         Ff(tl, 0, "\tVRT_fini_dir(cli, VGCDIR(%s));\n", vgcname); 
    680         tl->ndirector++; 
    681 } 
    682  
    683 /*-------------------------------------------------------------------- 
    684  * Parse and emit a backend host specification. 
    685  * 
    686  * The syntax is the following: 
    687  * 
    688  * backend_spec: 
    689  *      name_of_backend         # by reference 
    690  *      '{' be_elements '}'     # by specification 
    691  * 
    692  * The struct vrt_backend is emitted to Fh(). 
    693  */ 
    694  
    695 void 
    696 vcc_ParseBackendHost(struct tokenlist *tl, int serial, char **nm) 
    697 { 
    698         struct host *h; 
    699         struct token *t; 
    700         char vgcname[BUFSIZ]; 
    701  
    702         AN(nm); 
    703         *nm = NULL; 
    704         if (tl->t->tok == ID) { 
    705                 VTAILQ_FOREACH(h, &tl->hosts, list) { 
    706                         if (vcc_Teq(h->name, tl->t)) 
    707                                 break; 
    708                 } 
    709                 if (h == NULL) { 
    710                         vsb_printf(tl->sb, "Reference to unknown backend "); 
    711                         vcc_ErrToken(tl, tl->t); 
    712                         vsb_printf(tl->sb, " at\n"); 
    713                         vcc_ErrWhere(tl, tl->t); 
    714                         return; 
    715                 } 
    716                 vcc_AddRef(tl, h->name, R_BACKEND); 
    717                 vcc_NextToken(tl); 
    718                 ExpectErr(tl, ';'); 
    719                 vcc_NextToken(tl); 
    720                 *nm = h->vgcname; 
    721         } else if (tl->t->tok == '{') { 
    722                 t = tl->t; 
    723  
    724                 sprintf(vgcname, "%.*s_%d", PF(tl->t_dir), serial); 
    725  
    726                 Ff(tl, 0, "\tVRT_fini_dir(cli, VGCDIR(_%.*s));\n", 
    727                     PF(tl->t_dir)); 
    728                 vcc_ParseHostDef(tl, serial, vgcname); 
    729                 if (tl->err) { 
    730                         vsb_printf(tl->sb, 
    731                             "\nIn backend host specification starting at:\n"); 
    732                         vcc_ErrWhere(tl, t); 
    733                 } 
    734                 *nm = strdup(vgcname);   /* XXX */ 
    735  
    736                 return; 
    737         } else { 
    738                 vsb_printf(tl->sb, 
    739                     "Expected a backend host specification here, " 
    740                     "either by name or by {...}\n"); 
    741                 vcc_ErrToken(tl, tl->t); 
    742                 vsb_printf(tl->sb, " at\n"); 
    743                 vcc_ErrWhere(tl, tl->t); 
    744                 return; 
    745         } 
    746 } 
    747  
    748 /*-------------------------------------------------------------------- 
    749  * Parse a plain backend aka a simple director 
    750  */ 
    751  
    752 static void 
    753 vcc_ParseSimpleDirector(struct tokenlist *tl) 
    754 { 
    755         struct host *h; 
    756         char vgcname[BUFSIZ]; 
    757  
    758         h = TlAlloc(tl, sizeof *h); 
    759         h->name = tl->t_dir; 
    760         vcc_AddDef(tl, tl->t_dir, R_BACKEND); 
    761         sprintf(vgcname, "_%.*s", PF(h->name)); 
    762         h->vgcname = TlAlloc(tl, strlen(vgcname) + 1); 
    763         strcpy(h->vgcname, vgcname); 
    764  
    765         vcc_ParseHostDef(tl, -1, vgcname); 
    766         ERRCHK(tl); 
    767  
    768         VTAILQ_INSERT_TAIL(&tl->hosts, h, list); 
    769 } 
    770  
    771 /*-------------------------------------------------------------------- 
    772  * Parse directors and backends 
    773  */ 
    774  
    775 static const struct dirlist { 
    776         const char      *name; 
    777         parsedirector_f *func; 
    778 } dirlist[] = { 
    779         { "hash",               vcc_ParseRandomDirector }, 
    780         { "random",             vcc_ParseRandomDirector }, 
    781         { "client",             vcc_ParseRandomDirector }, 
    782         { "round-robin",        vcc_ParseRoundRobinDirector }, 
    783         { NULL,         NULL } 
    784 }; 
    785  
    786 void 
    787 vcc_ParseDirector(struct tokenlist *tl) 
    788 { 
    789         struct token *t_first; 
    790         struct dirlist const *dl; 
    791  
    792         t_first = tl->t; 
    793         vcc_NextToken(tl);              /* ID: director | backend */ 
    794  
    795         vcc_ExpectCid(tl);              /* ID: name */ 
    796         ERRCHK(tl); 
    797         tl->t_dir = tl->t; 
    798         vcc_NextToken(tl); 
    799  
    800  
    801         if (vcc_IdIs(t_first, "backend")) { 
    802                 tl->t_policy = t_first; 
    803                 vcc_ParseSimpleDirector(tl); 
    804         } else { 
    805                 Fh(tl, 1, "\n#define VGC_backend__%.*s %d\n", 
    806                     PF(tl->t_dir), tl->ndirector); 
    807                 vcc_AddDef(tl, tl->t_dir, R_BACKEND); 
    808                 tl->ndirector++; 
    809                 ExpectErr(tl, ID);              /* ID: policy */ 
    810                 tl->t_policy = tl->t; 
    811                 vcc_NextToken(tl); 
    812  
    813                 for (dl = dirlist; dl->name != NULL; dl++) 
    814                         if (vcc_IdIs(tl->t_policy, dl->name)) 
    815                                 break; 
    816                 if (dl->name == NULL) { 
    817                         vsb_printf(tl->sb, "Unknown director policy: "); 
    818                         vcc_ErrToken(tl, tl->t_policy); 
    819                         vsb_printf(tl->sb, " at\n"); 
    820                         vcc_ErrWhere(tl, tl->t_policy); 
    821                         return; 
    822                 } 
    823                 ExpectErr(tl, '{'); 
    824                 vcc_NextToken(tl); 
    825                 dl->func(tl); 
    826                 if (!tl->err) { 
    827                         ExpectErr(tl, '}'); 
    828                         vcc_NextToken(tl); 
    829                 } 
    830                 Fi(tl, 0, 
    831                     "\tVRT_init_dir(cli, VCL_conf.director, \"%.*s\",\n", 
    832                     PF(tl->t_policy)); 
    833                 Fi(tl, 0, "\t    VGC_backend__%.*s, &vgc_dir_priv_%.*s);\n", 
    834                     PF(tl->t_dir), PF(tl->t_dir)); 
    835  
    836  
    837         } 
    838         if (tl->err) { 
    839                 vsb_printf(tl->sb, 
    840                     "\nIn %.*s specification starting at:\n", PF(t_first)); 
    841                 vcc_ErrWhere(tl, t_first); 
    842                 return; 
    843         } 
    844         tl->t_policy = NULL; 
    845         tl->t_dir = NULL; 
    846 }