From phk at projects.linpro.no Tue Mar 6 22:40:07 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Tue, 6 Mar 2007 23:40:07 +0100 (CET) Subject: r1277 - in trunk/varnish-cache: bin/varnishd include lib/libvcl Message-ID: <20070306224007.8B4451EC45D@projects.linpro.no> Author: phk Date: 2007-03-06 23:40:06 +0100 (Tue, 06 Mar 2007) New Revision: 1277 Removed: trunk/varnish-cache/bin/varnishd/cache_pass.c Modified: trunk/varnish-cache/bin/varnishd/Makefile.am trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_center.c trunk/varnish-cache/bin/varnishd/cache_fetch.c trunk/varnish-cache/bin/varnishd/cache_hash.c trunk/varnish-cache/bin/varnishd/cache_vrt.c trunk/varnish-cache/bin/varnishd/mgt_vcc.c trunk/varnish-cache/bin/varnishd/steps.h trunk/varnish-cache/include/vcl.h trunk/varnish-cache/include/vcl_returns.h trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcc_token_defs.h Log: Having thought long and hard about this, commit what I think is the new and simpler flow for version2. Pass is now handled like a miss where the object will not be cached. The main result of this is that we drag the entire object, header and body, from the backend before transmitting it to the client, thus isolating the backend from slow clients. >From a software engineering point of view it is a big improvement, because it eliminates the need for all of cache_pass.c and we therefore end up with less HTTP protocol implementations. A side effect of this is that ticket #56 should be fixed now. If the object is pass'ed before vcl_fetch{} that is, in vcl_recv{}, vcl_hit{} or vcl_miss{}, no "pass this" object is inserted in the cache. The confusion between "pass", "insert" and "insert_pass" has been cleaned up, by the removal of the latter. Pipe and Pass calls vcl_pipe{} and vcl_pass{} respectively, before contacting the backend. I havn't quite decided if they should operate on the request header from the client or the one to the backend, or both. One possible use is to inject a "Connection: close" header to limit pipe to one transaction. A new vcl_hash{} has been added, it will allow customization of which fields we hash on, instead of the default "url + Host:" but this is not yet implemented. vcl_fetch{} is now called after both the headers and body have been picked up from the backend. This will allow us to do more comprehensive handling of backend errors later on. A disadvantage to this is that if the object ends up as a "pass this" object in the cache, we could possibly have released any queued requests already after the headers were received. If this is transpires as a real-world problem, we can add a vcl_fetchhdr{} which can do an early release (ie: "pass"). Modified: trunk/varnish-cache/bin/varnishd/Makefile.am =================================================================== --- trunk/varnish-cache/bin/varnishd/Makefile.am 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/Makefile.am 2007-03-06 22:40:06 UTC (rev 1277) @@ -21,7 +21,6 @@ cache_http.c \ cache_main.c \ cache_pool.c \ - cache_pass.c \ cache_pipe.c \ cache_response.c \ cache_session.c \ Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/cache.h 2007-03-06 22:40:06 UTC (rev 1277) @@ -279,7 +279,6 @@ TAILQ_ENTRY(sess) list; - struct vbe_conn *vbc; struct backend *backend; struct object *obj; struct VCL_conf *vcl; @@ -348,10 +347,10 @@ void EXP_TTLchange(struct object *o); /* cache_fetch.c */ -int FetchBody(struct sess *sp); -int FetchHeaders(struct sess *sp); +int Fetch(struct sess *sp); /* cache_hash.c */ +void HSH_Prealloc(struct sess *sp); struct object *HSH_Lookup(struct sess *sp); void HSH_Unbusy(struct object *o); void HSH_Ref(struct object *o); @@ -390,10 +389,6 @@ #include "http_headers.h" #undef HTTPH -/* cache_pass.c */ -int PassSession(struct sess *sp); -void PassBody(struct sess *sp); - /* cache_pipe.c */ void PipeSession(struct sess *sp); Modified: trunk/varnish-cache/bin/varnishd/cache_center.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_center.c 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/cache_center.c 2007-03-06 22:40:06 UTC (rev 1277) @@ -44,14 +44,24 @@ /* DOT digraph vcl_center { -DOT page="8.2,11.7" -DOT size="6.3,9.7" -DOT margin="1.0" +xDOT page="8.2,11.5" +DOT size="7.2,10.5" +DOT margin="0.5" +DOT center="1" DOT start [ DOT shape=hexagon -DOT label="Start" +DOT label="Request received" DOT ] -DOT start -> RECV +DOT RECV [shape=plaintext] +DOT PIPE [shape=plaintext] +DOT LOOKUP [shape=plaintext] +DOT HIT [shape=plaintext] +DOT MISS [shape=plaintext] +DOT PASS [shape=plaintext] +DOT FETCH [shape=plaintext] +DOT DELIVER [shape=plaintext] +DOT ERROR [shape=plaintext] +DOT start -> RECV [style=bold,color=green,weight=4] */ #include @@ -71,8 +81,13 @@ static unsigned xids; /*-------------------------------------------------------------------- - * The very first request + * AGAIN + * We come here when we just completed a request and already have + * received (part of) the next one. Instead taking the detour + * around the acceptor and then back to a worker, just stay in this + * worker and do what it takes. */ + static int cnt_again(struct sess *sp) { @@ -101,19 +116,19 @@ /*-------------------------------------------------------------------- * We have a refcounted object on the session, now deliver it. * -DOT subgraph cluster_deliver { +DOT subgraph xcluster_deliver { DOT deliver [ DOT shape=ellipse DOT label="Build & send header" DOT ] -DOT DELIVER -> deliver [style=bold] +DOT DELIVER -> deliver [style=bold,color=green,weight=4] DOT deliver2 [ DOT shape=ellipse DOT label="Send object" DOT ] -DOT deliver -> deliver2 [style=bold] +DOT deliver -> deliver2 [style=bold,color=green,weight=4] DOT } -DOT deliver2 -> DONE [style=bold] +DOT deliver2 -> DONE [style=bold,color=green,weight=4] */ static int @@ -154,7 +169,6 @@ double dh, dp, da; AZ(sp->obj); - AZ(sp->vbc); sp->backend = NULL; if (sp->vcl != NULL) { if (sp->wrk->vcl != NULL) @@ -211,7 +225,7 @@ /*-------------------------------------------------------------------- * Emit an error * -DOT subgraph cluster_error { +DOT subgraph xcluster_error { DOT error [ DOT shape=ellipse DOT label="Issue HTTP error" @@ -237,99 +251,61 @@ * We have fetched the headers from the backend, ask the VCL code what * to do next, then head off in that direction. * -DOT subgraph cluster_fetch { +DOT subgraph xcluster_fetch { DOT fetch [ DOT shape=ellipse -DOT label="find obj.ttl\nobj.cacheable" +DOT label="fetch from backend\n(find obj.ttl)" DOT ] -DOT FETCH -> fetch [style=bold] +DOT FETCH -> fetch [style=bold,color=blue,weight=2] DOT vcl_fetch [ DOT shape=box DOT label="vcl_fetch()" DOT ] -DOT fetch -> vcl_fetch [style=bold] -DOT fetch_lookup [ -DOT shape=ellipse -DOT label="obj.cacheable=false\nunbusy obj\ndiscard body\n" -DOT ] -DOT vcl_fetch -> fetch_lookup [label="lookup", style=dotted, weight=0] +DOT fetch -> vcl_fetch [style=bold,color=blue,weight=2] DOT fetch_pass [ DOT shape=ellipse -DOT label="obj.cacheable=false\nunbusy obj" +DOT label="obj.pass=true" DOT ] DOT vcl_fetch -> fetch_pass [label="pass"] -DOT fetch_ipass [ -DOT shape=ellipse -DOT label="obj.cacheable=true\nobj.pass=true\nunbusy obj" -DOT ] -DOT vcl_fetch -> fetch_ipass [label="insert_pass"] -DOT fetch_insert [ -DOT shape=ellipse -DOT label="rcv body\nobj.cacheable=true\nunbusy" -DOT ] -DOT vcl_fetch -> fetch_insert [label="insert", style=bold] -DOT fetch_error [ -DOT shape=ellipse -DOT label="disc body\nobj.cacheable=false\nunbusy" -DOT ] -DOT vcl_fetch -> fetch_error [label="error"] DOT } -DOT fetch_lookup -> LOOKUP [style=dotted, weight=0] -DOT fetch_pass -> PASSBODY -DOT fetch_ipass -> PASSBODY -DOT fetch_insert -> DELIVER [style=bold] -DOT fetch_error -> ERROR +DOT fetch_pass -> DELIVER +DOT vcl_fetch -> DELIVER [label="insert",style=bold,color=blue,weight=2] +DOT vcl_fetch -> errfetch [label="error"] +DOT errfetch [label="ERROR",shape=plaintext] */ static int cnt_fetch(struct sess *sp) { - CHECK_OBJ_NOTNULL(sp->vbc, VBE_CONN_MAGIC); - RFC2616_cache_policy(sp, sp->vbc->http); - VCL_fetch_method(sp); - - if (sp->handling == VCL_RET_LOOKUP) - INCOMPL(); - if (sp->handling == VCL_RET_PASS) { + if (Fetch(sp)) { sp->obj->cacheable = 0; HSH_Unbusy(sp->obj); HSH_Deref(sp->obj); sp->obj = NULL; - sp->step = STP_PASSBODY; + sp->step = STP_DONE; + RES_Error(sp, 503, NULL); return (0); } - if (sp->handling == VCL_RET_INSERT_PASS) { - sp->obj->pass = 1; - sp->obj->cacheable = 1; - HSH_Unbusy(sp->obj); - /* Don't HSH_Deref(sp->obj); we need the ref for storage */ - sp->obj = NULL; - sp->step = STP_PASSBODY; - return (0); - } - if (sp->handling == VCL_RET_INSERT) { - if (FetchBody(sp)) { - sp->obj->cacheable = 0; - HSH_Unbusy(sp->obj); - HSH_Deref(sp->obj); - sp->obj = NULL; - RES_Error(sp, 503, NULL); - sp->step = STP_DONE; - return (0); - } - sp->obj->cacheable = 1; - AZ(sp->vbc); - HSH_Ref(sp->obj); /* get another, STP_DELIVER will deref */ - HSH_Unbusy(sp->obj); - sp->wrk->acct.fetch++; - sp->step = STP_DELIVER; - return (0); - } + + RFC2616_cache_policy(sp, &sp->obj->http); /* XXX -> VCL */ + + VCL_fetch_method(sp); + if (sp->handling == VCL_RET_ERROR) INCOMPL(); - INCOMPL(); + + if (sp->handling == VCL_RET_PASS) + sp->obj->pass = 1; + + sp->obj->cacheable = 1; + HSH_Ref(sp->obj); /* get another, STP_DELIVER will deref */ + if (sp->obj->objhead != NULL) + HSH_Unbusy(sp->obj); + sp->wrk->acct.fetch++; + sp->step = STP_DELIVER; + return (0); } /*-------------------------------------------------------------------- @@ -370,120 +346,96 @@ } /*-------------------------------------------------------------------- + * HIT * We had a cache hit. Ask VCL, then march off as instructed. * -DOT subgraph cluster_hit { +DOT subgraph xcluster_hit { DOT hit [ DOT shape=box DOT label="vcl_hit()" DOT ] -DOT HIT -> hit [style=bold] -DOT hit2 [ -DOT shape=diamond -DOT label="obj.pass ?" -DOT ] -DOT hit -> hit2 [label=deliver, style=bold] -DOT hit_lookup [ -DOT shape=ellipse -DOT label="unbusy" -DOT ] -DOT hit -> hit_lookup [label="lookup", style=dotted, weight=0] -DOT hit_error [ -DOT shape=ellipse -DOT label="unbusy" -DOT ] -DOT hit -> hit_error [label="error", weight=0] -DOT hit_pass [ -DOT shape=ellipse -DOT label="unbusy" -DOT ] -DOT hit -> hit_pass [label=pass] -DOT hit2 -> hit_pass +DOT HIT -> hit [style=bold,color=green,weight=4] DOT } -DOT hit_error -> ERROR -DOT hit_pass -> PASS -DOT hit_lookup -> LOOKUP [style=dotted, weight=0] -DOT hit2 -> DELIVER [style=bold] +DOT hit -> err_hit [label="error"] +DOT err_hit [label="ERROR",shape=plaintext] +DOT hit -> PASS [label=pass] +DOT hit -> DELIVER [label="deliver",style=bold,color=green,weight=4] */ static int cnt_hit(struct sess *sp) { + assert(!sp->obj->pass); + VCL_hit_method(sp); - if (sp->handling == VCL_RET_DELIVER && sp->obj->pass) - sp->handling = VCL_RET_PASS; - if (sp->handling == VCL_RET_DELIVER) { sp->step = STP_DELIVER; return (0); } + + /* Drop our object, we won't need it */ + HSH_Deref(sp->obj); + sp->obj = NULL; + if (sp->handling == VCL_RET_PASS) { - HSH_Deref(sp->obj); - sp->obj = NULL; sp->step = STP_PASS; return (0); } if (sp->handling == VCL_RET_ERROR) { - HSH_Deref(sp->obj); - sp->obj = NULL; sp->step = STP_ERROR; return (0); } - if (sp->handling == VCL_RET_LOOKUP) - INCOMPL(); INCOMPL(); } /*-------------------------------------------------------------------- - * Look up request in hash table + * LOOKUP + * Hash things together and look object up in hash-table. * * LOOKUP consists of two substates so that we can reenter if we * encounter a busy object. * -DOT subgraph cluster_lookup { +DOT subgraph xcluster_lookup { +DOT hash [ +DOT shape=box +DOT label="vcl_hash()" +DOT ] DOT lookup [ DOT shape=ellipse -DOT label="find obj in cache" +DOT label="obj in cache ?" DOT ] -DOT LOOKUP -> lookup [style=bold] -DOT lookup3 [ +DOT lookup2 [ DOT shape=ellipse -DOT label="Insert new busy object" +DOT label="obj.pass ?" DOT ] -DOT lookup -> lookup3 [style=bold] +DOT LOOKUP -> hash [style=bold,color=green,weight=4] +DOT hash -> lookup [label="hash",style=bold,color=green,weight=4] +DOT lookup -> lookup2 [label="yes",style=bold,color=green,weight=4] DOT } -DOT lookup -> HIT [label="hit", style=bold] -DOT lookup3 -> MISS [label="miss", style=bold] +DOT lookup2 -> HIT [label="no", style=bold,color=green,weight=4] +DOT lookup2 -> PASS [label="yes"] +DOT lookup -> MISS [label="no",style=bold,color=blue,weight=2] */ static int cnt_lookup(struct sess *sp) { - - AZ(sp->obj); - sp->step = STP_LOOKUP2; - return (0); -} - -static int -cnt_lookup2(struct sess *sp) -{ struct object *o; - /* - * We don't assign to sp->obj directly because it is used - * to cache state when we encounter a busy object. - */ - o = HSH_Lookup(sp); + VCL_hash_method(sp); /* XXX: no-op for now */ - /* If we encountered busy-object, disembark worker thread */ + o = HSH_Lookup(sp); if (o == NULL) { + /* + * We hit a busy object, disembark worker thread and expect + * hash code to restart us, still in STP_LOOKUP, later. + */ WSL(sp->wrk, SLT_Debug, sp->fd, "on waiting list on obj %u", sp->obj->xid); SES_Charge(sp); @@ -499,14 +451,17 @@ return (0); } - /* Account separately for pass and cache objects */ if (sp->obj->pass) { VSL_stats->cache_hitpass++; WSL(sp->wrk, SLT_HitPass, sp->fd, "%u", sp->obj->xid); - } else { - VSL_stats->cache_hit++; - WSL(sp->wrk, SLT_Hit, sp->fd, "%u", sp->obj->xid); - } + HSH_Deref(sp->obj); + sp->obj = NULL; + sp->step = STP_PASS; + return (0); + } + + VSL_stats->cache_hit++; + WSL(sp->wrk, SLT_Hit, sp->fd, "%u", sp->obj->xid); sp->step = STP_HIT; return (0); } @@ -515,37 +470,21 @@ /*-------------------------------------------------------------------- * We had a miss, ask VCL, proceed as instructed * -DOT subgraph cluster_miss { +DOT subgraph xcluster_miss { DOT miss [ DOT shape=box DOT label="vcl_miss()" DOT ] -DOT MISS -> miss [style=bold] -DOT miss_error [ -DOT shape=ellipse -DOT label="obj.cacheable=false\nunbusy" +DOT MISS -> miss [style=bold,color=blue,weight=2] +DOT miss_ins [ +DOT label="insert new object" DOT ] -DOT miss -> miss_error [label="error"] -DOT miss_pass [ -DOT shape=ellipse -DOT label="obj.cacheable=false\nunbusy" -DOT ] -DOT miss -> miss_pass [label="pass"] -DOT miss_lookup [ -DOT shape=ellipse -DOT label="obj.cacheable=false\nunbusy" -DOT ] -DOT miss -> miss_lookup [label="lookup", style=dotted, weight=0] -DOT miss_fetch [ -DOT shape=ellipse -DOT label="fetch obj headers\nfrom backend" -DOT ] -DOT miss -> miss_fetch [label="fetch", style=bold] +DOT miss -> miss_ins [label="fetch",style=bold,color=blue,weight=2] DOT } -DOT miss_error -> ERROR -DOT miss_pass -> PASS -DOT miss_fetch -> FETCH [style=bold] -DOT miss_lookup -> LOOKUP [style=dotted, weight=0] +DOT miss -> err_miss [label="error"] +DOT err_miss [label="ERROR",shape=plaintext] +DOT miss_ins -> FETCH [style=bold,color=blue,weight=2] +DOT miss -> PASS [label="pass"] DOT */ @@ -570,21 +509,8 @@ sp->step = STP_PASS; return (0); } - if (sp->handling == VCL_RET_LOOKUP) - INCOMPL(); if (sp->handling == VCL_RET_FETCH) { - AZ(sp->vbc); - if (FetchHeaders(sp)) { - sp->obj->cacheable = 0; - HSH_Unbusy(sp->obj); - HSH_Deref(sp->obj); - sp->obj = NULL; - sp->step = STP_DONE; - RES_Error(sp, 503, NULL); - return (0); - } sp->step = STP_FETCH; - AN(sp->vbc); return (0); } INCOMPL(); @@ -595,69 +521,61 @@ * Start pass processing by getting headers from backend, then * continue in passbody. * -DOT subgraph cluster_pass { +DOT subgraph xcluster_pass { DOT pass [ +DOT shape=box +DOT label="vcl_pass()" +DOT ] +DOT pass_do [ DOT shape=ellipse -DOT label="send to bke\nrx bkehdr" +DOT label="create new object\n" DOT ] DOT PASS -> pass +DOT pass -> pass_do [label="pass"] DOT } -DOT pass -> PASSBODY +DOT pass_do -> FETCH +DOT pass -> err_pass [label="error"] +DOT err_pass [label="ERROR",shape=plaintext] */ static int cnt_pass(struct sess *sp) { - AZ(sp->vbc); - if (!PassSession(sp)) { - AN(sp->vbc); - sp->step = STP_PASSBODY; - } else - sp->step = STP_DONE; - return (0); -} + AZ(sp->obj); - -/*-------------------------------------------------------------------- - * We get here when we have the backends headers, send them to client - * and pass any body the backend may have on as well. - * -DOT subgraph cluster_passbody { -DOT passbody [ -DOT shape=ellipse -DOT label="send hdrs\npass body\n" -DOT ] -DOT PASSBODY -> passbody -DOT } -DOT passbody -> DONE - */ - -static int -cnt_passbody(struct sess *sp) -{ - - sp->wrk->acct.pass++; - AN(sp->vbc); - PassBody(sp); - AZ(sp->vbc); - sp->step = STP_DONE; + VCL_pass_method(sp); + if (sp->handling == VCL_RET_ERROR) { + sp->step = STP_ERROR; + return (0); + } + HSH_Prealloc(sp); + sp->obj = sp->wrk->nobj; + sp->wrk->nobj = NULL; + sp->obj->busy = 1; + sp->step = STP_FETCH; return (0); } - /*-------------------------------------------------------------------- * Ship the request header to the backend unchanged, then pipe * until one of the ends close the connection. * -DOT subgraph cluster_pipe { +DOT subgraph xcluster_pipe { DOT pipe [ +DOT shape=box +DOT label="vcl_pipe()" +DOT ] +DOT pipe_do [ DOT shape=ellipse DOT label="build&send hdr\npipe until close" DOT ] DOT PIPE -> pipe +DOT pipe -> pipe_do [label="pipe"] DOT } -DOT pipe -> DONE +DOT pipe_do -> DONE +DOT pipe -> err_pipe [label="error"] +DOT err_pipe [label="ERROR",shape=plaintext] */ static int @@ -672,29 +590,22 @@ /*-------------------------------------------------------------------- - * Dispatch the request as instructed by VCL + * RECV + * We have a complete request, get a VCL reference and dispatch it + * as instructed by vcl_recv{} * -DOT subgraph cluster_recv { +DOT subgraph xcluster_recv { DOT recv [ DOT shape=box DOT label="vcl_recv()" DOT ] -DOT RECV -> recv -DOT recv_lookup [ -DOT shape=ellipse -DOT label="discard any body" -DOT ] -DOT recv -> recv_lookup [label="lookup"] -DOT recv_error [ -DOT shape=ellipse -DOT label="discard any body" -DOT ] -DOT recv -> recv_error [label="error"] +DOT RECV -> recv [style=bold,color=green,weight=4] DOT } DOT recv -> PIPE [label="pipe"] DOT recv -> PASS [label="pass"] -DOT recv_lookup -> LOOKUP -DOT recv_error -> ERROR +DOT recv -> err_recv [label="error"] +DOT err_recv [label="ERROR",shape=plaintext] +DOT recv -> LOOKUP [label="lookup",style=bold,color=green,weight=4] */ static int @@ -702,43 +613,45 @@ { int done; - VSL_stats->client_req++; + AZ(sp->vcl); + AZ(sp->obj); + + /* Update stats of various sorts */ + VSL_stats->client_req++; /* XXX not locked */ clock_gettime(CLOCK_REALTIME, &sp->t_req); sp->wrk->idle = sp->t_req.tv_sec; - sp->xid = ++xids; + sp->wrk->acct.req++; + + /* Assign XID and log */ + sp->xid = ++xids; /* XXX not locked */ WSL(sp->wrk, SLT_ReqStart, sp->fd, "%s %s %u", sp->addr, sp->port, sp->xid); - AZ(sp->vcl); + /* Borrow VCL reference from worker thread */ VCL_Refresh(&sp->wrk->vcl); sp->vcl = sp->wrk->vcl; sp->wrk->vcl = NULL; - AZ(sp->obj); - AZ(sp->vbc); - - sp->wrk->acct.req++; done = http_DissectRequest(sp->wrk, sp->http, sp->fd); if (done != 0) { - RES_Error(sp, done, NULL); + RES_Error(sp, done, NULL); /* XXX: STP_ERROR ? */ sp->step = STP_DONE; return (0); } http_DoConnection(sp); + /* By default we use the first backend */ sp->backend = sp->vcl->backend[0]; /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */ - /* XXX: determine if request comes with body */ - VCL_recv_method(sp); + sp->wantbody = !strcmp(sp->http->hd[HTTP_HDR_REQ].b, "GET"); switch(sp->handling) { case VCL_RET_LOOKUP: /* XXX: discard req body, if any */ - sp->wantbody = !strcmp(sp->http->hd[HTTP_HDR_REQ].b, "GET"); sp->step = STP_LOOKUP; return (0); case VCL_RET_PIPE: @@ -760,8 +673,7 @@ /*-------------------------------------------------------------------- * Central state engine dispatcher. * - * We grab a VCL reference, and keeps kicking the session around until - * it has had enough. + * Kick the session around until it has had enough. * */ @@ -776,6 +688,10 @@ CHECK_OBJ_NOTNULL(w, WORKER_MAGIC); for (done = 0; !done; ) { + /* + * This is a good place to be paranoid about the various + * pointers still pointing to the things we expect. + */ CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); if (sp->obj != NULL) CHECK_OBJ(sp->obj, OBJECT_MAGIC); @@ -784,11 +700,9 @@ CHECK_OBJ(w->nobj, OBJECT_MAGIC); if (w->nobjhead != NULL) CHECK_OBJ(w->nobjhead, OBJHEAD_MAGIC); + switch (sp->step) { -#define STEP(l,u) \ - case STP_##u: \ - done = cnt_##l(sp); \ - break; +#define STEP(l,u) case STP_##u: done = cnt_##l(sp); break; #include "steps.h" #undef STEP default: INCOMPL(); Modified: trunk/varnish-cache/bin/varnishd/cache_fetch.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_fetch.c 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/cache_fetch.c 2007-03-06 22:40:06 UTC (rev 1277) @@ -243,11 +243,12 @@ /*--------------------------------------------------------------------*/ int -FetchBody(struct sess *sp) +Fetch(struct sess *sp) { - int cls; struct vbe_conn *vc; + struct worker *w; char *b; + int cls; int body = 1; /* XXX */ struct http *hp; struct storage *st; @@ -256,10 +257,54 @@ CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); assert(sp->obj->busy != 0); + w = sp->wrk; - vc = sp->vbc; - sp->vbc = NULL; + sp->obj->xid = sp->xid; + vc = VBE_GetFd(sp); + if (vc == NULL) + return (1); + + http_ClrHeader(vc->http); + vc->http->logtag = HTTP_Tx; + http_GetReq(w, vc->fd, vc->http, sp->http); + http_FilterHeader(w, vc->fd, vc->http, sp->http, HTTPH_R_FETCH); + http_PrintfHeader(w, vc->fd, vc->http, "X-Varnish: %u", sp->xid); + http_PrintfHeader(w, vc->fd, vc->http, + "X-Forwarded-for: %s", sp->addr); + if (!http_GetHdr(vc->http, H_Host, &b)) { + http_PrintfHeader(w, vc->fd, vc->http, "Host: %s", + sp->backend->hostname); + } + + WRK_Reset(w, &vc->fd); + http_Write(w, vc->http, 0); + if (WRK_Flush(w)) { + /* XXX: cleanup */ + return (1); + } + + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); + CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); + + if (http_RecvHead(vc->http, vc->fd)) { + /* XXX: cleanup */ + return (1); + } + if (http_DissectResponse(sp->wrk, vc->http, vc->fd)) { + /* XXX: cleanup */ + return (1); + } + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); + CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); + + sp->obj->entered = time(NULL); + + + assert(sp->obj->busy != 0); + if (http_GetHdr(vc->http, H_Last_Modified, &b)) sp->obj->last_modified = TIM_parse(b); @@ -314,66 +359,3 @@ return (0); } - -/*--------------------------------------------------------------------*/ - -int -FetchHeaders(struct sess *sp) -{ - struct vbe_conn *vc; - struct worker *w; - char *b; - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); - CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); - assert(sp->obj->busy != 0); - w = sp->wrk; - - sp->obj->xid = sp->xid; - - vc = VBE_GetFd(sp); - if (vc == NULL) - return (1); - - http_ClrHeader(vc->http); - vc->http->logtag = HTTP_Tx; - http_GetReq(w, vc->fd, vc->http, sp->http); - http_FilterHeader(w, vc->fd, vc->http, sp->http, HTTPH_R_FETCH); - http_PrintfHeader(w, vc->fd, vc->http, "X-Varnish: %u", sp->xid); - http_PrintfHeader(w, vc->fd, vc->http, - "X-Forwarded-for: %s", sp->addr); - if (!http_GetHdr(vc->http, H_Host, &b)) { - http_PrintfHeader(w, vc->fd, vc->http, "Host: %s", - sp->backend->hostname); - } - - WRK_Reset(w, &vc->fd); - http_Write(w, vc->http, 0); - if (WRK_Flush(w)) { - /* XXX: cleanup */ - return (1); - } - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); - CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); - - if (http_RecvHead(vc->http, vc->fd)) { - /* XXX: cleanup */ - return (1); - } - if (http_DissectResponse(sp->wrk, vc->http, vc->fd)) { - /* XXX: cleanup */ - return (1); - } - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); - CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); - AZ(sp->vbc); - sp->vbc = vc; - - sp->obj->entered = time(NULL); - - return (0); -} Modified: trunk/varnish-cache/bin/varnishd/cache_hash.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_hash.c 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/cache_hash.c 2007-03-06 22:40:06 UTC (rev 1277) @@ -64,23 +64,15 @@ static struct hash_slinger *hash; -struct object * -HSH_Lookup(struct sess *sp) +/* Precreate an objhead and object for later use */ +void +HSH_Prealloc(struct sess *sp) { struct worker *w; - struct http *h; - struct objhead *oh; - struct object *o; - char *url, *host; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); - CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC); - AN(hash); w = sp->wrk; - h = sp->http; - /* Precreate an objhead and object in case we need them */ if (w->nobjhead == NULL) { w->nobjhead = calloc(sizeof *w->nobjhead, 1); XXXAN(w->nobjhead); @@ -102,7 +94,25 @@ VSL_stats->n_object++; } else CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC); +} +struct object * +HSH_Lookup(struct sess *sp) +{ + struct worker *w; + struct http *h; + struct objhead *oh; + struct object *o; + char *url, *host; + + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); + CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC); + AN(hash); + w = sp->wrk; + h = sp->http; + + HSH_Prealloc(sp); url = h->hd[HTTP_HDR_URL].b; if (!http_GetHdr(h, H_Host, &host)) host = url; @@ -189,11 +199,14 @@ CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); oh = o->objhead; - CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); - LOCK(&oh->mtx); + if (oh != NULL) { + CHECK_OBJ(oh, OBJHEAD_MAGIC); + LOCK(&oh->mtx); + } assert(o->refcnt > 0); o->refcnt++; - UNLOCK(&oh->mtx); + if (oh != NULL) + UNLOCK(&oh->mtx); } void @@ -205,8 +218,14 @@ CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); oh = o->objhead; - CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); + if (oh == NULL) { + /* Pass object, not referenced anywhere */ + free(o); + return; + } + CHECK_OBJ(oh, OBJHEAD_MAGIC); + /* drop ref on object */ LOCK(&oh->mtx); assert(o->refcnt > 0); Deleted: trunk/varnish-cache/bin/varnishd/cache_pass.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_pass.c 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/cache_pass.c 2007-03-06 22:40:06 UTC (rev 1277) @@ -1,269 +0,0 @@ -/*- - * Copyright (c) 2006 Verdens Gang AS - * Copyright (c) 2006 Linpro AS - * All rights reserved. - * - * Author: Poul-Henning Kamp - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - * - * XXX: charge bytes to srcaddr - * XXX: buffer to relieve backed ASAP. - * XXX: Check if response has any body - * XXX: Don't pass chunked to HTTP/1.0 client - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef HAVE_CLOCK_GETTIME -#include "compat/clock_gettime.h" -#endif - -#include "shmlog.h" -#include "cache.h" - -#define PASS_BUFSIZ 8192 - -/*--------------------------------------------------------------------*/ - -static int -pass_straight(struct sess *sp, int fd, struct http *hp, char *bi) -{ - int i; - off_t cl; - unsigned c; - char buf[PASS_BUFSIZ]; - - if (bi != NULL) - cl = strtoumax(bi, NULL, 0); - else - cl = (1 << 30); - - i = fcntl(fd, F_GETFL); /* XXX ? */ - i &= ~O_NONBLOCK; - i = fcntl(fd, F_SETFL, i); - - while (cl != 0) { - c = cl; - if (c > sizeof buf) - c = sizeof buf; - i = http_Read(hp, fd, buf, c); - if (i == 0 && bi == NULL) - return (1); - if (i <= 0) { - vca_close_session(sp, "backend closed"); - return (1); - } - sp->wrk->acct.bodybytes += WRK_Write(sp->wrk, buf, i); - if (WRK_Flush(sp->wrk)) - vca_close_session(sp, "remote closed"); - cl -= i; - } - return (0); -} - - -/*--------------------------------------------------------------------*/ - -static int -pass_chunked(struct sess *sp, int fd, struct http *hp) -{ - int i, j; - char *p, *q; - unsigned u; - char buf[PASS_BUFSIZ]; - char *bp, *be; - - i = fcntl(fd, F_GETFL); /* XXX ? */ - i &= ~O_NONBLOCK; - i = fcntl(fd, F_SETFL, i); - - bp = buf; - be = buf + sizeof buf; - p = buf; - while (1) { - i = http_Read(hp, fd, bp, be - bp); - xxxassert(i >= 0); - if (i == 0 && p == bp) - break; - bp += i; - /* buffer valid from p to bp */ - assert(bp >= p); - - /* chunk starts with f("%x\r\n", len) */ - u = strtoul(p, &q, 16); - while (q && q < bp && *q == ' ') - /* shouldn't happen - but sometimes it does */ - q++; - if (q == NULL || q > bp - 2 /* want \r\n in same buffer */) { - /* short - move to start of buffer and extend */ - memmove(buf, p, bp - p); - bp -= p - buf; - p = buf; - continue; - } - assert(*q == '\r'); - q++; - assert(*q == '\n'); - q++; - - /* we just received the final zero-length chunk */ - if (u == 0) { - sp->wrk->acct.bodybytes += WRK_Write(sp->wrk, p, q - p); - break; - } - - /* include chunk header */ - u += q - p; - - /* include trailing \r\n with chunk */ - u += 2; - - for (;;) { - j = u; - if (bp - p < j) - j = bp - p; - sp->wrk->acct.bodybytes += WRK_Write(sp->wrk, p, j); - WRK_Flush(sp->wrk); - p += j; - assert(u >= j); - u -= j; - if (u == 0) - break; - p = bp = buf; - j = u; - if (j > be - bp) - j = be - bp; - i = http_Read(hp, fd, bp, j); - xxxassert(i > 0); - bp += i; - } - } - if (WRK_Flush(sp->wrk)) - vca_close_session(sp, "remote closed"); - return (0); -} - - -/*--------------------------------------------------------------------*/ - -void -PassBody(struct sess *sp) -{ - struct vbe_conn *vc; - char *b; - int cls; - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->vbc, VBE_CONN_MAGIC); - vc = sp->vbc; - sp->vbc = NULL; - - clock_gettime(CLOCK_REALTIME, &sp->t_resp); - - http_ClrHeader(sp->http); - http_CopyResp(sp->wrk, sp->fd, sp->http, vc->http); - http_FilterHeader(sp->wrk, sp->fd, sp->http, vc->http, HTTPH_A_PASS); - http_PrintfHeader(sp->wrk, sp->fd, sp->http, "X-Varnish: %u", sp->xid); - http_PrintfHeader(sp->wrk, sp->fd, sp->http, - "X-Forwarded-for: %s", sp->addr); - /* XXX */ - if (http_HdrIs(vc->http, H_Transfer_Encoding, "chunked")) - http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Transfer-Encoding: chunked"); - WRK_Reset(sp->wrk, &sp->fd); - sp->wrk->acct.hdrbytes += http_Write(sp->wrk, sp->http, 1); - - if (http_GetHdr(vc->http, H_Content_Length, &b)) - cls = pass_straight(sp, vc->fd, vc->http, b); - else if (http_HdrIs(vc->http, H_Connection, "close")) - cls = pass_straight(sp, vc->fd, vc->http, NULL); - else if (http_HdrIs(vc->http, H_Transfer_Encoding, "chunked")) - cls = pass_chunked(sp, vc->fd, vc->http); - else if (http_IsBodyless(vc->http)) - cls = 0; - else { - cls = pass_straight(sp, vc->fd, vc->http, NULL); - } - - if (WRK_Flush(sp->wrk)) - vca_close_session(sp, "remote closed"); - - if (http_GetHdr(vc->http, H_Connection, &b) && !strcasecmp(b, "close")) - cls = 1; - - if (cls) - VBE_ClosedFd(sp->wrk, vc, 0); - else - VBE_RecycleFd(sp->wrk, vc); -} - - -/*--------------------------------------------------------------------*/ - -int -PassSession(struct sess *sp) -{ - int i; - struct vbe_conn *vc; - struct worker *w; - char *b; - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); - w = sp->wrk; - - vc = VBE_GetFd(sp); - if (vc == NULL) - return (1); - - http_CopyReq(w, vc->fd, vc->http, sp->http); - http_FilterHeader(w, vc->fd, vc->http, sp->http, HTTPH_R_PASS); - http_PrintfHeader(w, vc->fd, vc->http, "X-Varnish: %u", sp->xid); - if (!http_GetHdr(vc->http, H_Host, &b)) { - http_PrintfHeader(w, vc->fd, vc->http, "Host: %s", - sp->backend->hostname); - } - WRK_Reset(w, &vc->fd); - http_Write(w, vc->http, 0); - i = WRK_Flush(w); - xxxassert(i == 0); - - /* XXX: copy any contents */ - - i = http_RecvHead(vc->http, vc->fd); - xxxassert(i == 0); - http_DissectResponse(w, vc->http, vc->fd); - - assert(sp->vbc == NULL); - sp->vbc = vc; - return (0); -} Modified: trunk/varnish-cache/bin/varnishd/cache_vrt.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_vrt.c 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/cache_vrt.c 2007-03-06 22:40:06 UTC (rev 1277) @@ -82,7 +82,7 @@ hp = sp->http; break; case 2: - hp = sp->vbc->http; + hp = &sp->obj->http; break; default: INCOMPL(); Modified: trunk/varnish-cache/bin/varnishd/mgt_vcc.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_vcc.c 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/mgt_vcc.c 2007-03-06 22:40:06 UTC (rev 1277) @@ -79,6 +79,18 @@ " lookup;\n" "}\n" "\n" + "sub default_vcl_pipe {\n" + " pipe;\n" + "}\n" + "\n" + "sub default_vcl_pass {\n" + " pass;\n" + "}\n" + "\n" + "sub default_vcl_hash {\n" + " hash;\n" + "}\n" + "\n" "sub default_vcl_hit {\n" " if (!obj.cacheable) {\n" " pass;\n" @@ -95,10 +107,10 @@ " error;\n" " }\n" " if (!obj.cacheable) {\n" - " insert_pass;\n" + " pass;\n" " }\n" " if (resp.http.Set-Cookie) {\n" - " insert_pass;\n" + " pass;\n" " }\n" " insert;\n" "}\n" Modified: trunk/varnish-cache/bin/varnishd/steps.h =================================================================== --- trunk/varnish-cache/bin/varnishd/steps.h 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/bin/varnishd/steps.h 2007-03-06 22:40:06 UTC (rev 1277) @@ -34,9 +34,7 @@ STEP(recv, RECV) STEP(pipe, PIPE) STEP(pass, PASS) -STEP(passbody, PASSBODY) STEP(lookup, LOOKUP) -STEP(lookup2, LOOKUP2) STEP(miss, MISS) STEP(hit, HIT) STEP(fetch, FETCH) Modified: trunk/varnish-cache/include/vcl.h =================================================================== --- trunk/varnish-cache/include/vcl.h 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/include/vcl.h 2007-03-06 22:40:06 UTC (rev 1277) @@ -28,6 +28,9 @@ vcl_fini_f *fini_func; vcl_func_f *recv_func; + vcl_func_f *pipe_func; + vcl_func_f *pass_func; + vcl_func_f *hash_func; vcl_func_f *miss_func; vcl_func_f *hit_func; vcl_func_f *fetch_func; Modified: trunk/varnish-cache/include/vcl_returns.h =================================================================== --- trunk/varnish-cache/include/vcl_returns.h 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/include/vcl_returns.h 2007-03-06 22:40:06 UTC (rev 1277) @@ -11,9 +11,9 @@ VCL_RET_MAC_E(error, ERROR, (1 << 0), 0) #endif VCL_RET_MAC(lookup, LOOKUP, (1 << 1), 1) -VCL_RET_MAC(pipe, PIPE, (1 << 2), 2) -VCL_RET_MAC(pass, PASS, (1 << 3), 3) -VCL_RET_MAC(insert_pass, INSERT_PASS, (1 << 4), 4) +VCL_RET_MAC(hash, HASH, (1 << 2), 2) +VCL_RET_MAC(pipe, PIPE, (1 << 3), 3) +VCL_RET_MAC(pass, PASS, (1 << 4), 4) VCL_RET_MAC(fetch, FETCH, (1 << 5), 5) VCL_RET_MAC(insert, INSERT, (1 << 6), 6) VCL_RET_MAC(deliver, DELIVER, (1 << 7), 7) @@ -21,9 +21,9 @@ #else #define VCL_RET_ERROR (1 << 0) #define VCL_RET_LOOKUP (1 << 1) -#define VCL_RET_PIPE (1 << 2) -#define VCL_RET_PASS (1 << 3) -#define VCL_RET_INSERT_PASS (1 << 4) +#define VCL_RET_HASH (1 << 2) +#define VCL_RET_PIPE (1 << 3) +#define VCL_RET_PASS (1 << 4) #define VCL_RET_FETCH (1 << 5) #define VCL_RET_INSERT (1 << 6) #define VCL_RET_DELIVER (1 << 7) @@ -33,8 +33,11 @@ #ifdef VCL_MET_MAC VCL_MET_MAC(recv,RECV,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_LOOKUP)) -VCL_MET_MAC(miss,MISS,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_FETCH)) -VCL_MET_MAC(hit,HIT,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_DELIVER)) -VCL_MET_MAC(fetch,FETCH,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_INSERT|VCL_RET_INSERT_PASS)) +VCL_MET_MAC(pipe,PIPE,(VCL_RET_ERROR|VCL_RET_PIPE)) +VCL_MET_MAC(pass,PASS,(VCL_RET_ERROR|VCL_RET_PASS)) +VCL_MET_MAC(hash,HASH,(VCL_RET_HASH)) +VCL_MET_MAC(miss,MISS,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_FETCH)) +VCL_MET_MAC(hit,HIT,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_DELIVER)) +VCL_MET_MAC(fetch,FETCH,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_INSERT)) VCL_MET_MAC(timeout,TIMEOUT,(VCL_RET_FETCH|VCL_RET_DISCARD)) #endif Modified: trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-03-06 22:40:06 UTC (rev 1277) @@ -228,15 +228,15 @@ return (T_FETCH); } return (0); + case 'h': + if (p[0] == 'h' && p[1] == 'a' && p[2] == 's' && + p[3] == 'h' && !isvar(p[4])) { + *q = p + 4; + return (T_HASH); + } + return (0); case 'i': if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' && - p[3] == 'e' && p[4] == 'r' && p[5] == 't' && - p[6] == '_' && p[7] == 'p' && p[8] == 'a' && - p[9] == 's' && p[10] == 's' && !isvar(p[11])) { - *q = p + 11; - return (T_INSERT_PASS); - } - if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' && p[3] == 'e' && p[4] == 'r' && p[5] == 't' && !isvar(p[6])) { *q = p + 6; @@ -396,11 +396,11 @@ vcl_tnames[T_FETCH] = "fetch"; vcl_tnames[T_FUNC] = "func"; vcl_tnames[T_GEQ] = ">="; + vcl_tnames[T_HASH] = "hash"; vcl_tnames[T_IF] = "if"; vcl_tnames[T_INC] = "++"; vcl_tnames[T_INCR] = "+="; vcl_tnames[T_INSERT] = "insert"; - vcl_tnames[T_INSERT_PASS] = "insert_pass"; vcl_tnames[T_LEQ] = "<="; vcl_tnames[T_LOOKUP] = "lookup"; vcl_tnames[T_MUL] = "*="; @@ -424,9 +424,9 @@ { fputs("#define VCL_RET_ERROR (1 << 0)\n", f); fputs("#define VCL_RET_LOOKUP (1 << 1)\n", f); - fputs("#define VCL_RET_PIPE (1 << 2)\n", f); - fputs("#define VCL_RET_PASS (1 << 3)\n", f); - fputs("#define VCL_RET_INSERT_PASS (1 << 4)\n", f); + fputs("#define VCL_RET_HASH (1 << 2)\n", f); + fputs("#define VCL_RET_PIPE (1 << 3)\n", f); + fputs("#define VCL_RET_PASS (1 << 4)\n", f); fputs("#define VCL_RET_FETCH (1 << 5)\n", f); fputs("#define VCL_RET_INSERT (1 << 6)\n", f); fputs("#define VCL_RET_DELIVER (1 << 7)\n", f); @@ -461,6 +461,9 @@ fputs(" vcl_fini_f *fini_func;\n", f); fputs("\n", f); fputs(" vcl_func_f *recv_func;\n", f); + fputs(" vcl_func_f *pipe_func;\n", f); + fputs(" vcl_func_f *pass_func;\n", f); + fputs(" vcl_func_f *hash_func;\n", f); fputs(" vcl_func_f *miss_func;\n", f); fputs(" vcl_func_f *hit_func;\n", f); fputs(" vcl_func_f *fetch_func;\n", f); Modified: trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-06 22:40:06 UTC (rev 1277) @@ -35,9 +35,12 @@ # set methods { {recv {error pass pipe lookup}} - {miss {error pass pipe fetch}} - {hit {error pass pipe deliver}} - {fetch {error pass pipe insert insert_pass}} + {pipe {error pipe}} + {pass {error pass}} + {hash {hash}} + {miss {error pass fetch}} + {hit {error pass deliver}} + {fetch {error pass insert}} {timeout {fetch discard}} } @@ -46,9 +49,9 @@ set returns { error lookup + hash pipe pass - insert_pass fetch insert deliver Modified: trunk/varnish-cache/lib/libvcl/vcc_token_defs.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_token_defs.h 2007-02-27 20:33:42 UTC (rev 1276) +++ trunk/varnish-cache/lib/libvcl/vcc_token_defs.h 2007-03-06 22:40:06 UTC (rev 1277) @@ -24,9 +24,9 @@ #define T_SWITCH_CONFIG 142 #define T_ERROR 143 #define T_LOOKUP 144 -#define T_PIPE 145 -#define T_PASS 146 -#define T_INSERT_PASS 147 +#define T_HASH 145 +#define T_PIPE 146 +#define T_PASS 147 #define T_FETCH 148 #define T_INSERT 149 #define T_DELIVER 150 From phk at projects.linpro.no Wed Mar 7 10:38:20 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Wed, 7 Mar 2007 11:38:20 +0100 (CET) Subject: r1278 - trunk/varnish-cache/bin/varnishd Message-ID: <20070307103820.EC6CB1EC2B4@projects.linpro.no> Author: phk Date: 2007-03-07 11:38:20 +0100 (Wed, 07 Mar 2007) New Revision: 1278 Modified: trunk/varnish-cache/bin/varnishd/cache.h trunk/varnish-cache/bin/varnishd/cache_center.c trunk/varnish-cache/bin/varnishd/cache_hash.c Log: Add a bit of garbage collection to yesterdays change: Passed objects need to have their storage properly reclaimed, including the actual content of a obj.pass=1 cache entry, once we have sent the content to the original requestor. Modified: trunk/varnish-cache/bin/varnishd/cache.h =================================================================== --- trunk/varnish-cache/bin/varnishd/cache.h 2007-03-06 22:40:06 UTC (rev 1277) +++ trunk/varnish-cache/bin/varnishd/cache.h 2007-03-07 10:38:20 UTC (rev 1278) @@ -351,6 +351,7 @@ /* cache_hash.c */ void HSH_Prealloc(struct sess *sp); +void HSH_Freestore(struct object *o); struct object *HSH_Lookup(struct sess *sp); void HSH_Unbusy(struct object *o); void HSH_Ref(struct object *o); Modified: trunk/varnish-cache/bin/varnishd/cache_center.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_center.c 2007-03-06 22:40:06 UTC (rev 1277) +++ trunk/varnish-cache/bin/varnishd/cache_center.c 2007-03-07 10:38:20 UTC (rev 1278) @@ -136,6 +136,10 @@ { RES_WriteObj(sp); + if (sp->obj->objhead != NULL && sp->obj->pass) { + /* we will no longer need the storage */ + HSH_Freestore(sp->obj); + } HSH_Deref(sp->obj); sp->obj = NULL; sp->step = STP_DONE; @@ -300,9 +304,10 @@ sp->obj->pass = 1; sp->obj->cacheable = 1; - HSH_Ref(sp->obj); /* get another, STP_DELIVER will deref */ - if (sp->obj->objhead != NULL) + if (sp->obj->objhead != NULL) { + HSH_Ref(sp->obj); /* get another, STP_DELIVER will deref */ HSH_Unbusy(sp->obj); + } sp->wrk->acct.fetch++; sp->step = STP_DELIVER; return (0); Modified: trunk/varnish-cache/bin/varnishd/cache_hash.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_hash.c 2007-03-06 22:40:06 UTC (rev 1277) +++ trunk/varnish-cache/bin/varnishd/cache_hash.c 2007-03-07 10:38:20 UTC (rev 1278) @@ -96,6 +96,18 @@ CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC); } +void +HSH_Freestore(struct object *o) +{ + struct storage *st, *stn; + + TAILQ_FOREACH_SAFE(st, &o->store, list, stn) { + CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC); + TAILQ_REMOVE(&o->store, st, list); + st->stevedore->free(st); + } +} + struct object * HSH_Lookup(struct sess *sp) { @@ -213,43 +225,37 @@ HSH_Deref(struct object *o) { struct objhead *oh; - struct storage *st, *stn; unsigned r; CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); oh = o->objhead; - if (oh == NULL) { - /* Pass object, not referenced anywhere */ - free(o); - return; + if (oh != NULL) { + CHECK_OBJ(oh, OBJHEAD_MAGIC); + + /* drop ref on object */ + LOCK(&oh->mtx); } - - CHECK_OBJ(oh, OBJHEAD_MAGIC); - - /* drop ref on object */ - LOCK(&oh->mtx); assert(o->refcnt > 0); r = --o->refcnt; - if (!r) - TAILQ_REMOVE(&oh->objects, o, list); - UNLOCK(&oh->mtx); + if (oh != NULL) { + if (!r) + TAILQ_REMOVE(&oh->objects, o, list); + UNLOCK(&oh->mtx); + } /* If still referenced, done */ if (r != 0) return; - if (o->http.s != NULL) { + if (o->http.s != NULL) free(o->http.s); - } - TAILQ_FOREACH_SAFE(st, &o->store, list, stn) { - CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC); - TAILQ_REMOVE(&o->store, st, list); - st->stevedore->free(st); - } + HSH_Freestore(o); free(o); VSL_stats->n_object--; + if (oh == NULL) + return; /* Drop our ref on the objhead */ if (hash->deref(oh)) return; From phk at projects.linpro.no Thu Mar 8 09:07:21 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 8 Mar 2007 10:07:21 +0100 (CET) Subject: r1279 - trunk/varnish-cache/bin/varnishd Message-ID: <20070308090721.E73E71EC425@projects.linpro.no> Author: phk Date: 2007-03-08 10:07:21 +0100 (Thu, 08 Mar 2007) New Revision: 1279 Modified: trunk/varnish-cache/bin/varnishd/mgt_param.c Log: Add missing "volatile" qualifiers on generic tweakers. Modified: trunk/varnish-cache/bin/varnishd/mgt_param.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_param.c 2007-03-07 10:38:20 UTC (rev 1278) +++ trunk/varnish-cache/bin/varnishd/mgt_param.c 2007-03-08 09:07:21 UTC (rev 1279) @@ -58,7 +58,7 @@ /*--------------------------------------------------------------------*/ static void -tweak_generic_timeout(struct cli *cli, unsigned *dst, const char *arg) +tweak_generic_timeout(struct cli *cli, volatile unsigned *dst, const char *arg) { unsigned u; @@ -77,7 +77,7 @@ /*--------------------------------------------------------------------*/ static void -tweak_generic_bool(struct cli *cli, unsigned *dest, const char *arg) +tweak_generic_bool(struct cli *cli, volatile unsigned *dest, const char *arg) { if (arg != NULL) { if (!strcasecmp(arg, "off")) @@ -104,7 +104,7 @@ /*--------------------------------------------------------------------*/ static void -tweak_generic_uint(struct cli *cli, unsigned *dest, const char *arg, unsigned min, unsigned max) +tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg, unsigned min, unsigned max) { unsigned u; From phk at projects.linpro.no Thu Mar 8 10:09:18 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Thu, 8 Mar 2007 11:09:18 +0100 (CET) Subject: r1280 - trunk/varnish-cache/bin/varnishd Message-ID: <20070308100918.707291EC1E7@projects.linpro.no> Author: phk Date: 2007-03-08 11:09:18 +0100 (Thu, 08 Mar 2007) New Revision: 1280 Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c trunk/varnish-cache/bin/varnishd/heritage.h trunk/varnish-cache/bin/varnishd/mgt_child.c trunk/varnish-cache/bin/varnishd/mgt_param.c trunk/varnish-cache/bin/varnishd/varnishd.c Log: Make Varnish able to accept connections from multiple sockets by specifying a whitespace separated list of addresses to -a (or param.set listen_address). I'm not sure about the error handling, for instance, what is the desirable behaviour if one of multiple sockets fail to open ? Suggested by: Modified: trunk/varnish-cache/bin/varnishd/cache_acceptor.c =================================================================== --- trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2007-03-08 09:07:21 UTC (rev 1279) +++ trunk/varnish-cache/bin/varnishd/cache_acceptor.c 2007-03-08 10:09:18 UTC (rev 1280) @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -137,47 +138,65 @@ struct sess *sp; socklen_t l; struct sockaddr addr[2]; /* XXX: IPv6 hack */ - int i; + int i, j; + struct pollfd *pfd; + struct listen_sock *ls; (void)arg; + + /* Set up the poll argument */ + pfd = calloc(sizeof *pfd, heritage.nsocks); + AN(pfd); + i = 0; + TAILQ_FOREACH(ls, &heritage.socks, list) { + AZ(setsockopt(ls->sock, SOL_SOCKET, SO_LINGER, + &linger, sizeof linger)); + pfd[i].events = POLLIN; + pfd[i++].fd = ls->sock; + } + need_test = 1; - AZ(setsockopt(heritage.socket, SOL_SOCKET, SO_LINGER, - &linger, sizeof linger)); while (1) { if (params->send_timeout != tv_sndtimeo.tv_sec) { need_test = 1; tv_sndtimeo.tv_sec = params->send_timeout; - AZ(setsockopt(heritage.socket, SOL_SOCKET, - SO_SNDTIMEO, &tv_sndtimeo, sizeof tv_sndtimeo)); + TAILQ_FOREACH(ls, &heritage.socks, list) + AZ(setsockopt(ls->sock, SOL_SOCKET, + SO_SNDTIMEO, &tv_sndtimeo, sizeof tv_sndtimeo)); } if (params->sess_timeout != tv_rcvtimeo.tv_sec) { need_test = 1; tv_rcvtimeo.tv_sec = params->sess_timeout; - AZ(setsockopt(heritage.socket, SOL_SOCKET, - SO_RCVTIMEO, &tv_rcvtimeo, sizeof tv_rcvtimeo)); + TAILQ_FOREACH(ls, &heritage.socks, list) + AZ(setsockopt(ls->sock, SOL_SOCKET, + SO_RCVTIMEO, &tv_rcvtimeo, sizeof tv_rcvtimeo)); } - VSL_stats->client_conn++; - - l = sizeof addr; - i = accept(heritage.socket, addr, &l); - if (i < 0) { - if (errno != EAGAIN) { - VSL(SLT_Debug, heritage.socket, - "Accept failed errno=%d", errno); - /* XXX: stats ? */ + i = poll(pfd, heritage.nsocks, 1000); + for (j = 0; j < heritage.nsocks; j++) { + if (pfd[j].revents == 0) + continue; + VSL_stats->client_conn++; + l = sizeof addr; + i = accept(pfd[j].fd, addr, &l); + if (i < 0) { + if (errno != EAGAIN) { + VSL(SLT_Debug, pfd[j].fd, + "Accept failed errno=%d", errno); + /* XXX: stats ? */ + } + continue; } - continue; - } - sp = SES_New(addr, l); - XXXAN(sp); + sp = SES_New(addr, l); + XXXAN(sp); - sp->fd = i; - sp->id = i; - (void)clock_gettime(CLOCK_REALTIME, &sp->t_open); + sp->fd = i; + sp->id = i; + (void)clock_gettime(CLOCK_REALTIME, &sp->t_open); - http_RecvPrep(sp->http); - sp->step = STP_FIRST; - WRK_QueueSession(sp); + http_RecvPrep(sp->http); + sp->step = STP_FIRST; + WRK_QueueSession(sp); + } } } Modified: trunk/varnish-cache/bin/varnishd/heritage.h =================================================================== --- trunk/varnish-cache/bin/varnishd/heritage.h 2007-03-08 09:07:21 UTC (rev 1279) +++ trunk/varnish-cache/bin/varnishd/heritage.h 2007-03-08 10:09:18 UTC (rev 1280) @@ -31,27 +31,38 @@ * This file contains the heritage passed when mgt forks cache */ +#include "queue.h" + +struct listen_sock { + TAILQ_ENTRY(listen_sock) list; + int sock; + char *host; + char *port; +}; + +TAILQ_HEAD(listen_sock_head, listen_sock); + struct heritage { /* * Two pipe(2)'s for CLI connection between cache and mgt. * cache reads [2] and writes [1]. Mgt reads [0] and writes [3]. */ - int fds[4]; + int fds[4]; - /* Socket from which to accept connections */ - int socket; + /* Sockets from which to accept connections */ + struct listen_sock_head socks; + int nsocks; /* Share memory log fd and size (incl header) */ - int vsl_fd; - unsigned vsl_size; + int vsl_fd; + unsigned vsl_size; /* Storage method */ - struct stevedore *stevedore; + struct stevedore *stevedore; /* Hash method */ - struct hash_slinger *hash; - + struct hash_slinger *hash; }; struct params { @@ -89,8 +100,6 @@ /* Listen address */ char *listen_address; - char *listen_host; - char *listen_port; /* Listen depth */ unsigned listen_depth; Modified: trunk/varnish-cache/bin/varnishd/mgt_child.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_child.c 2007-03-08 09:07:21 UTC (rev 1279) +++ trunk/varnish-cache/bin/varnishd/mgt_child.c 2007-03-08 10:09:18 UTC (rev 1280) @@ -122,7 +122,39 @@ /*--------------------------------------------------------------------*/ +static int +open_sockets(void) +{ + struct listen_sock *ls; + + TAILQ_FOREACH(ls, &heritage.socks, list) { + if (ls->sock >= 0) + continue; + ls->sock = TCP_open(ls->host, ls->port, 1); + if (ls->sock < 0) + return (1); + } + return (0); +} + +/*--------------------------------------------------------------------*/ + static void +close_sockets(void) +{ + struct listen_sock *ls; + + TAILQ_FOREACH(ls, &heritage.socks, list) { + if (ls->sock < 0) + continue; + close(ls->sock); + ls->sock = -1; + } +} + +/*--------------------------------------------------------------------*/ + +static void start_child(void) { int i; @@ -133,12 +165,8 @@ if (child_state != CH_STOPPED && child_state != CH_DIED) return; - if (heritage.socket < 0) { - heritage.socket = - TCP_open(params->listen_host, params->listen_port, 1); - if (heritage.socket < 0) - return; - } + if (open_sockets()) + return; /* XXX ?? */ child_state = CH_STARTING; @@ -219,8 +247,7 @@ if (child_state != CH_RUNNING) return; - close(heritage.socket); - heritage.socket = -1; + close_sockets(); child_state = CH_STOPPING; if (ev_poker != NULL) { @@ -295,8 +322,7 @@ if (child_state == CH_DIED && params->auto_restart) start_child(); else if (child_state == CH_DIED) { - close(heritage.socket); - heritage.socket = -1; + close_sockets(); child_state = CH_STOPPED; } else if (child_state == CH_STOPPING) Modified: trunk/varnish-cache/bin/varnishd/mgt_param.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_param.c 2007-03-08 09:07:21 UTC (rev 1279) +++ trunk/varnish-cache/bin/varnishd/mgt_param.c 2007-03-08 10:09:18 UTC (rev 1280) @@ -278,33 +278,86 @@ /*--------------------------------------------------------------------*/ static void +clean_listen_sock_head(struct listen_sock_head *lsh) +{ + struct listen_sock *ls, *ls2; + + TAILQ_FOREACH_SAFE(ls, lsh, list, ls2) { + TAILQ_REMOVE(lsh, ls, list); + free(ls->host); + free(ls->port); + free(ls); + } +} + +static void tweak_listen_address(struct cli *cli, struct parspec *par, const char *arg) { - char *a, *p; + char **av; + int i; + struct listen_sock *ls; + struct listen_sock_head lsh; (void)par; - if (arg != NULL) { - if (TCP_parse(arg, &a, &p) != 0) { - cli_out(cli, "Invalid listen address"); + if (arg == NULL) { + /* Quote the string if we have more than one socket */ + if (heritage.nsocks > 1) + cli_out(cli, "\"%s\"", params->listen_address); + else + cli_out(cli, "%s", params->listen_address); + return; + } + + av = ParseArgv(arg, 0); + if (av[0] != NULL) { + cli_out(cli, "Parse error: %s", av[0]); + cli_result(cli, CLIS_PARAM); + FreeArgv(av); + return; + } + if (av[1] == NULL) { + cli_out(cli, "Empty listen address"); + cli_result(cli, CLIS_PARAM); + FreeArgv(av); + return; + } + TAILQ_INIT(&lsh); + for (i = 1; av[i] != NULL; i++) { + ls = calloc(sizeof *ls, 1); + AN(ls); + ls->sock = -1; + TAILQ_INSERT_TAIL(&lsh, ls, list); + if (TCP_parse(av[i], &ls->host, &ls->port) != 0) { + cli_out(cli, "Invalid listen address \"%s\"", av[i]); cli_result(cli, CLIS_PARAM); - return; + break; } - if (p == NULL) { - p = strdup("http"); - AN(p); - } - TCP_check(cli, a, p); + if (ls->port == NULL) + ls->port = strdup("http"); + AN(ls->port); + TCP_check(cli, ls->host, ls->port); if (cli->result != CLIS_OK) - return; - free(params->listen_address); - free(params->listen_host); - free(params->listen_port); - params->listen_address = strdup(arg); - AN(params->listen_address); - params->listen_host = a; - params->listen_port = p; - } else - cli_out(cli, "%s", params->listen_address); + break; + } + FreeArgv(av); + if (cli->result != CLIS_OK) { + clean_listen_sock_head(&lsh); + return; + } + + free(params->listen_address); + params->listen_address = strdup(arg); + AN(params->listen_address); + + clean_listen_sock_head(&heritage.socks); + heritage.nsocks = 0; + + while (!TAILQ_EMPTY(&lsh)) { + ls = TAILQ_FIRST(&lsh); + TAILQ_REMOVE(&lsh, ls, list); + TAILQ_INSERT_TAIL(&heritage.socks, ls, list); + heritage.nsocks++; + } } /*--------------------------------------------------------------------*/ @@ -477,9 +530,11 @@ "default. ", "off", "bool" }, { "listen_address", tweak_listen_address, - "The network address/port where Varnish services requests.\n" + "Whitespace separated list of network endpoints where " + "Varnish will accept requests.\n" + "Possible formats: host, host:port, :port\n" MUST_RESTART, - "0.0.0.0:80" }, + ":80" }, { "listen_depth", tweak_listen_depth, "Listen(2) queue depth.\n" #if defined(__FreeBSD__) Modified: trunk/varnish-cache/bin/varnishd/varnishd.c =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.c 2007-03-08 09:07:21 UTC (rev 1279) +++ trunk/varnish-cache/bin/varnishd/varnishd.c 2007-03-08 10:09:18 UTC (rev 1280) @@ -410,8 +410,6 @@ XXXAN(cli[0].sb); cli[0].result = CLIS_OK; - heritage.socket = -1; - /* * Set up a temporary param block until VSL_MgtInit() can * replace with shmem backed structure version. @@ -426,6 +424,7 @@ * XXX: 'param' to static */ + TAILQ_INIT(&heritage.socks); memset(¶m, 0, sizeof param); params = ¶m; mgt_vcc_init(); From phk at projects.linpro.no Fri Mar 9 10:31:29 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 9 Mar 2007 11:31:29 +0100 (CET) Subject: r1281 - in trunk/varnish-cache: include lib/libvcl Message-ID: <20070309103129.AC2401EC405@projects.linpro.no> Author: phk Date: 2007-03-09 11:31:29 +0100 (Fri, 09 Mar 2007) New Revision: 1281 Modified: trunk/varnish-cache/include/vcl.h trunk/varnish-cache/include/vrt.h trunk/varnish-cache/lib/libvcl/vcc_acl.c trunk/varnish-cache/lib/libvcl/vcc_compile.c trunk/varnish-cache/lib/libvcl/vcc_compile.h trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcc_token.c trunk/varnish-cache/lib/libvcl/vcc_token_defs.h Log: Implement a facility for source file modularization in the VCL compiler. The syntax is: include "filename" ; Unlike the C preprocessors #include directive, a VCL include can appear anywhere in the sourcefile: if {req.Cookie == include "cookie.vcl" ; || !req.Host } { } and have cookie.vcl contain just: "8435398475983275293759843" Technically this results in a change to how we account for source code references in the counter/profile table as well, and as a result the entire source code of the VCL program is now compiled into the shared library for easy reference. Modified: trunk/varnish-cache/include/vcl.h =================================================================== --- trunk/varnish-cache/include/vcl.h 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/include/vcl.h 2007-03-09 10:31:29 UTC (rev 1281) @@ -22,6 +22,10 @@ unsigned nref; unsigned busy; + unsigned nsrc; + const char **srcname; + const char **srcbody; + void *priv; vcl_init_f *init_func; Modified: trunk/varnish-cache/include/vrt.h =================================================================== --- trunk/varnish-cache/include/vrt.h 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/include/vrt.h 2007-03-09 10:31:29 UTC (rev 1281) @@ -40,7 +40,8 @@ struct VCL_conf; struct vrt_ref { - unsigned file; + unsigned source; + unsigned offset; unsigned line; unsigned pos; unsigned count; Modified: trunk/varnish-cache/lib/libvcl/vcc_acl.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_acl.c 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/lib/libvcl/vcc_acl.c 2007-03-09 10:31:29 UTC (rev 1281) @@ -120,14 +120,14 @@ mask = UintVal(tl); } Fc(tl, 1, "{ %u, %u, %u, ", not, mask, para); - EncString(tl->fc, t); + EncToken(tl->fc, t); Fc(tl, 0, ", \""); if (para) Fc(tl, 0, "("); if (not) Fc(tl, 0, "!"); Fc(tl, 0, "\\\"\" "); - EncString(tl->fc, t); + EncToken(tl->fc, t); Fc(tl, 0, " \"\\\""); if (mask) Fc(tl, 0, "/%u", mask); Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-09 10:31:29 UTC (rev 1281) @@ -86,8 +86,8 @@ #include "libvcl.h" static struct method method_tab[] = { -#define VCL_RET_MAC(a,b,c,d) -#define VCL_MET_MAC(a,b,c) { "vcl_"#a, "default_vcl_"#a, c }, +#define VCL_RET_MAC(l,U,b,n) +#define VCL_MET_MAC(l,U,m) { "vcl_"#l, "default_vcl_"#l, m }, #include "vcl_returns.h" #undef VCL_MET_MAC #undef VCL_RET_MAC @@ -170,23 +170,42 @@ /*--------------------------------------------------------------------*/ void -EncString(struct vsb *sb, struct token *t) +EncString(struct vsb *sb, const char *b, const char *e) { - const char *p; - assert(t->tok == CSTR); + if (e == NULL) + e = strchr(b, '\0'); + vsb_cat(sb, "\""); - for (p = t->dec; *p != '\0'; p++) { - if (*p == '\\' || *p == '"') - vsb_printf(sb, "\\%c", *p); - else if (isgraph(*p)) - vsb_printf(sb, "%c", *p); - else - vsb_printf(sb, "\\%03o", *p); + for (; b < e; b++) { + switch (*b) { + case '\\': + case '"': + vsb_printf(sb, "\\%c", *b); + break; + case '\n': vsb_printf(sb, "\\n"); break; + case '\t': vsb_printf(sb, "\\t"); break; + case '\r': vsb_printf(sb, "\\r"); break; + case ' ': vsb_printf(sb, " "); break; + default: + if (isgraph(*b)) + vsb_printf(sb, "%c", *b); + else + vsb_printf(sb, "\\%03o", *b); + break; + } } vsb_cat(sb, "\""); } +void +EncToken(struct vsb *sb, struct token *t) +{ + + assert(t->tok == CSTR); + EncString(sb, t->dec, NULL); +} + /*--------------------------------------------------------------------*/ static int @@ -505,7 +524,7 @@ Fc(tl, 1, "VRT_re_match(%s, %s)\n", str, buf); Fh(tl, 0, "void *%s;\n", buf); Fi(tl, 0, "\tVRT_re_init(&%s, ",buf); - EncString(tl->fi, re); + EncToken(tl->fi, re); Fi(tl, 0, ");\n"); Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf); } @@ -530,7 +549,7 @@ tl->t->tok == T_EQ ? "!" : "", vp->rname); vcc_NextToken(tl); ExpectErr(tl, CSTR); - EncString(tl->fc, tl->t); + EncToken(tl->fc, tl->t); Fc(tl, 0, ")\n"); vcc_NextToken(tl); break; @@ -974,7 +993,7 @@ ExpectErr(tl, CSTR); t_host = tl->t; Fc(tl, 1, "\t%s ", vp->lname); - EncString(tl->fc, t_host); + EncToken(tl->fc, t_host); Fc(tl, 0, ");\n"); vcc_NextToken(tl); break; @@ -982,7 +1001,7 @@ ExpectErr(tl, CSTR); t_port = tl->t; Fc(tl, 1, "\t%s ", vp->lname); - EncString(tl->fc, t_port); + EncToken(tl->fc, t_port); Fc(tl, 0, ");\n"); vcc_NextToken(tl); break; @@ -1282,32 +1301,39 @@ return (nerr); } -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * Output the location/profiling table. For each counted token, we + * record source+line+charpos for the first character in the token. + */ static void LocTable(struct tokenlist *tl) { struct token *t; - unsigned fil, lin, pos; + unsigned lin, pos; + struct source *sp; const char *p; Fh(tl, 0, "#define VGC_NREFS %u\n", tl->cnt + 1); Fh(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS];\n"); Fc(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS] = {\n"); - fil = 0; lin = 1; pos = 0; - p = vcc_default_vcl_b; + sp = 0; + p = NULL; TAILQ_FOREACH(t, &tl->tokens, list) { if (t->cnt == 0) continue; + assert(t->src != NULL); + if (t->src != sp) { + lin = 1; + pos = 0; + sp = t->src; + p = sp->b; + } + assert(sp != NULL); + assert(p != NULL); for (;p < t->b; p++) { - if (p == vcc_default_vcl_e) { - p = tl->b; - fil = 1; - lin = 1; - pos = 0; - } if (*p == '\n') { lin++; pos = 0; @@ -1318,13 +1344,12 @@ pos++; } - Fc(tl, 0, " [%3u] = { %d, %4u, %3u, 0, \"%.*s\" },\n", - t->cnt, fil, lin, pos + 1, PF(t)); + Fc(tl, 0, " [%3u] = { %d, %8u, %4u, %3u, 0, \"%.*s\" },\n", + t->cnt, sp->idx, t->b - sp->b, lin, pos + 1, PF(t)); } Fc(tl, 0, "};\n"); } - /*--------------------------------------------------------------------*/ static void @@ -1352,7 +1377,24 @@ static void EmitStruct(struct tokenlist *tl) { + struct source *sp; + Fc(tl, 0, "\nconst char *srcname[%u] = {\n", tl->nsources); + TAILQ_FOREACH(sp, &tl->sources, list) { + Fc(tl, 0, "\t"); + EncString(tl->fc, sp->name, NULL); + Fc(tl, 0, ",\n"); + } + Fc(tl, 0, "};\n"); + + Fc(tl, 0, "\nconst char *srcbody[%u] = {\n", tl->nsources); + TAILQ_FOREACH(sp, &tl->sources, list) { + Fc(tl, 0, "\t"); + EncString(tl->fc, sp->b, sp->e); + Fc(tl, 0, ",\n"); + } + Fc(tl, 0, "};\n"); + Fc(tl, 0, "\nstruct VCL_conf VCL_conf = {\n"); Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n"); Fc(tl, 0, "\t.init_func = VGC_Init,\n"); @@ -1360,6 +1402,9 @@ Fc(tl, 0, "\t.nbackend = %d,\n", tl->nbackend); Fc(tl, 0, "\t.ref = VGC_ref,\n"); Fc(tl, 0, "\t.nref = VGC_NREFS,\n"); + Fc(tl, 0, "\t.nsrc = %u,\n", tl->nsources); + Fc(tl, 0, "\t.srcname = srcname,\n"); + Fc(tl, 0, "\t.srcbody = srcbody,\n"); #define VCL_RET_MAC(l,u,b,n) #define VCL_MET_MAC(l,u,b) \ if (FindRefStr(tl, "vcl_" #l, R_FUNC)) { \ @@ -1377,10 +1422,112 @@ /*--------------------------------------------------------------------*/ -char * -VCC_Compile(struct vsb *sb, const char *b, const char *e) +static struct source * +vcc_new_source(const char *b, const char *e, const char *name) { - struct tokenlist tokens; + struct source *sp; + + if (e == NULL) + e = strchr(b, '\0'); + sp = calloc(sizeof *sp, 1); + assert(sp != NULL); + sp->name = strdup(name); + sp->b = b; + sp->e = e; + return (sp); +} + +static void +vcc_destroy_source(struct source *sp) +{ + + free(sp->name); + free(sp); +} + +/*--------------------------------------------------------------------*/ + +static struct source * +vcc_file_source(struct vsb *sb, const char *fn) +{ + char *f; + int fd, i; + struct stat st; + + fd = open(fn, O_RDONLY); + if (fd < 0) { + vsb_printf(sb, "Cannot open file '%s': %s\n", + fn, strerror(errno)); + return (NULL); + } + assert(0 == fstat(fd, &st)); + f = malloc(st.st_size + 1); + assert(f != NULL); + i = read(fd, f, st.st_size); + assert(i == st.st_size); + close(fd); + f[i] = '\0'; + return (vcc_new_source(f, f + i, fn)); +} + +/*--------------------------------------------------------------------*/ + +static void +vcc_resolve_includes(struct tokenlist *tl) +{ + struct token *t, *t1, *t2; + struct source *sp; + + TAILQ_FOREACH(t, &tl->tokens, list) { + if (t->tok != T_INCLUDE) + continue; + + t1 = TAILQ_NEXT(t, list); + assert(t1 != NULL); /* There's always an EOI */ + if (t1->tok != CSTR) { + vsb_printf(tl->sb, + "include not followed by string constant.\n"); + vcc_ErrWhere(tl, t1); + return; + } + t2 = TAILQ_NEXT(t1, list); + assert(t2 != NULL); /* There's always an EOI */ + if (t2->tok != ';') { + vsb_printf(tl->sb, + "include not followed by semicolon.\n"); + vcc_ErrWhere(tl, t1); + return; + } + assert(t2 != NULL); + + sp = vcc_file_source(tl->sb, t1->dec); + if (sp == NULL) { + vcc_ErrWhere(tl, t1); + return; + } + TAILQ_INSERT_TAIL(&tl->sources, sp, list); + sp->idx = tl->nsources++; + tl->t = t2; + vcc_Lexer(tl, sp); + + TAILQ_REMOVE(&tl->tokens, t, list); + TAILQ_REMOVE(&tl->tokens, t1, list); + TAILQ_REMOVE(&tl->tokens, t2, list); + vcc_FreeToken(t); + vcc_FreeToken(t1); + vcc_FreeToken(t2); + if (!tl->err) + vcc_resolve_includes(tl); + return; + } +} + +/*--------------------------------------------------------------------*/ + +static char * +vcc_CompileSource(struct vsb *sb, struct source *sp) +{ + struct tokenlist tokens, *tl; struct ref *r; struct token *t; FILE *fo; @@ -1389,11 +1536,15 @@ int i; memset(&tokens, 0, sizeof tokens); - TAILQ_INIT(&tokens.tokens); - TAILQ_INIT(&tokens.refs); - TAILQ_INIT(&tokens.procs); + tl = &tokens; + TAILQ_INIT(&tl->tokens); + TAILQ_INIT(&tl->refs); + TAILQ_INIT(&tl->procs); + TAILQ_INIT(&tl->sources); tokens.sb = sb; + tl->nsources = 0; + tokens.fc = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tokens.fc != NULL); @@ -1406,38 +1557,52 @@ tokens.ff = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tokens.ff != NULL); - Fh(&tokens, 0, "extern struct VCL_conf VCL_conf;\n"); +#define VCL_MET_MAC(l,U,m) \ + tokens.fm_##l = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ + assert(tokens.fm_##l != NULL); +#include "vcl_returns.h" +#undef VCL_MET_MAC - Fi(&tokens, 0, "\tVRT_alloc_backends(&VCL_conf);\n"); + Fh(tl, 0, "extern struct VCL_conf VCL_conf;\n"); - tokens.b = b; - if (e == NULL) - e = strchr(b, '\0'); - assert(e != NULL); - tokens.e = e; - vcc_Lexer(&tokens, vcc_default_vcl_b, vcc_default_vcl_e); - vcc_Lexer(&tokens, b, e); - vcc_AddToken(&tokens, EOI, e, e); + Fi(tl, 0, "\tVRT_alloc_backends(&VCL_conf);\n"); + + TAILQ_INSERT_TAIL(&tl->sources, sp, list); + sp->idx = tl->nsources++; + vcc_Lexer(tl, sp); if (tokens.err) goto done; - tokens.t = TAILQ_FIRST(&tokens.tokens); - Parse(&tokens); + + sp = vcc_new_source(vcc_default_vcl_b, vcc_default_vcl_e, "Default"); + TAILQ_INSERT_TAIL(&tl->sources, sp, list); + sp->idx = tl->nsources++; + vcc_Lexer(tl, sp); + vcc_AddToken(tl, EOI, sp->e, sp->e); if (tokens.err) goto done; - Consistency(&tokens); + + vcc_resolve_includes(tl); if (tokens.err) goto done; - LocTable(&tokens); - Ff(&tokens, 0, "\tVRT_free_backends(&VCL_conf);\n"); + tokens.t = TAILQ_FIRST(&tl->tokens); + Parse(tl); + if (tokens.err) + goto done; + Consistency(tl); + if (tokens.err) + goto done; + LocTable(tl); - EmitInitFunc(&tokens); + Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n"); - EmitFiniFunc(&tokens); + EmitInitFunc(tl); - EmitStruct(&tokens); + EmitFiniFunc(tl); - if (CheckRefs(&tokens)) + EmitStruct(tl); + + if (CheckRefs(tl)) goto done; of = strdup("/tmp/vcl.XXXXXXXX"); @@ -1472,18 +1637,22 @@ } done: +#define VCL_MET_MAC(l,U,m) vsb_delete(tokens.fm_##l); +#include "vcl_returns.h" +#undef VCL_MET_MAC + /* Free References */ - while (!TAILQ_EMPTY(&tokens.refs)) { - r = TAILQ_FIRST(&tokens.refs); - TAILQ_REMOVE(&tokens.refs, r, list); + while (!TAILQ_EMPTY(&tl->refs)) { + r = TAILQ_FIRST(&tl->refs); + TAILQ_REMOVE(&tl->refs, r, list); free(r); } /* Free Tokens */ - while (!TAILQ_EMPTY(&tokens.tokens)) { - t = TAILQ_FIRST(&tokens.tokens); - TAILQ_REMOVE(&tokens.tokens, t, list); - free(t); + while (!TAILQ_EMPTY(&tl->tokens)) { + t = TAILQ_FIRST(&tl->tokens); + TAILQ_REMOVE(&tl->tokens, t, list); + vcc_FreeToken(t); } return (of); } @@ -1491,26 +1660,32 @@ /*--------------------------------------------------------------------*/ char * +VCC_Compile(struct vsb *sb, const char *b, const char *e) +{ + struct source *sp; + char *r; + + sp = vcc_new_source(b, e, "input"); + if (sp == NULL) + return (NULL); + r = vcc_CompileSource(sb, sp); + vcc_destroy_source(sp); + return (r); +} + +/*--------------------------------------------------------------------*/ + +char * VCC_CompileFile(struct vsb *sb, const char *fn) { - char *f, *r; - int fd, i; - struct stat st; + struct source *sp; + char *r; - fd = open(fn, O_RDONLY); - if (fd < 0) { - vsb_printf(sb, "Cannot open file '%s': %s", - fn, strerror(errno)); + sp = vcc_file_source(sb, fn); + if (sp == NULL) return (NULL); - } - assert(0 == fstat(fd, &st)); - f = malloc(st.st_size + 1); - assert(f != NULL); - i = read(fd, f, st.st_size); - assert(i == st.st_size); - f[i] = '\0'; - r = VCC_Compile(sb, f, NULL); - free(f); + r = vcc_CompileSource(sb, sp); + vcc_destroy_source(sp); return (r); } Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-09 10:31:29 UTC (rev 1281) @@ -34,23 +34,38 @@ #define INDENT 2 +struct source { + TAILQ_ENTRY(source) list; + char *name; + const char *b; + const char *e; + unsigned idx; +}; + struct token { unsigned tok; const char *b; const char *e; + struct source *src; TAILQ_ENTRY(token) list; unsigned cnt; char *dec; }; +TAILQ_HEAD(tokenhead, token); + struct tokenlist { - TAILQ_HEAD(, token) tokens; - const char *b; - const char *e; + struct tokenhead tokens; + TAILQ_HEAD(, source) sources; + unsigned nsources; + struct source *src; struct token *t; int indent; unsigned cnt; struct vsb *fc, *fh, *fi, *ff; +#define VCL_MET_MAC(l,U,m) struct vsb *fm_##l; +#include "vcl_returns.h" +#undef VCL_MET_MAC TAILQ_HEAD(, ref) refs; struct vsb *sb; int err; @@ -138,7 +153,8 @@ unsigned UintVal(struct tokenlist *tl); void AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); -void EncString(struct vsb *sb, struct token *t); +void EncToken(struct vsb *sb, struct token *t); +void EncString(struct vsb *sb, const char *b, const char *e); /* vcc_obj.c */ @@ -153,10 +169,11 @@ void vcc__Expect(struct tokenlist *tl, unsigned tok, int line); int vcc_Teq(struct token *t1, struct token *t2); int vcc_IdIs(struct token *t, const char *p); -void vcc_Lexer(struct tokenlist *tl, const char *b, const char *e); +void vcc_Lexer(struct tokenlist *tl, struct source *sp); void vcc_NextToken(struct tokenlist *tl); void vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line); void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e); +void vcc_FreeToken(struct token *t); #define ERRCHK(tl) do { if ((tl)->err) return; } while (0) #define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__) Modified: trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-03-09 10:31:29 UTC (rev 1281) @@ -242,6 +242,12 @@ *q = p + 6; return (T_INSERT); } + if (p[0] == 'i' && p[1] == 'n' && p[2] == 'c' && + p[3] == 'l' && p[4] == 'u' && p[5] == 'd' && + p[6] == 'e' && !isvar(p[7])) { + *q = p + 7; + return (T_INCLUDE); + } if (p[0] == 'i' && p[1] == 'f' && !isvar(p[2])) { *q = p + 2; return (T_IF); @@ -399,6 +405,7 @@ vcl_tnames[T_HASH] = "hash"; vcl_tnames[T_IF] = "if"; vcl_tnames[T_INC] = "++"; + vcl_tnames[T_INCLUDE] = "include"; vcl_tnames[T_INCR] = "+="; vcl_tnames[T_INSERT] = "insert"; vcl_tnames[T_LEQ] = "<="; @@ -455,6 +462,10 @@ fputs(" unsigned nref;\n", f); fputs(" unsigned busy;\n", f); fputs("\n", f); + fputs(" unsigned nsrc;\n", f); + fputs(" const char **srcname;\n", f); + fputs(" const char **srcbody;\n", f); + fputs("\n", f); fputs(" void *priv;\n", f); fputs("\n", f); fputs(" vcl_init_f *init_func;\n", f); @@ -511,7 +522,8 @@ fputs("struct VCL_conf;\n", f); fputs("\n", f); fputs("struct vrt_ref {\n", f); - fputs(" unsigned file;\n", f); + fputs(" unsigned source;\n", f); + fputs(" unsigned offset;\n", f); fputs(" unsigned line;\n", f); fputs(" unsigned pos;\n", f); fputs(" unsigned count;\n", f); Modified: trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-09 10:31:29 UTC (rev 1281) @@ -61,6 +61,8 @@ # Language keywords # set keywords { + include + if else elseif elsif func proc sub @@ -140,6 +142,10 @@ unsigned nref; unsigned busy; + unsigned nsrc; + const char **srcname; + const char **srcbody; + void *priv; vcl_init_f *init_func; Modified: trunk/varnish-cache/lib/libvcl/vcc_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_token.c 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/lib/libvcl/vcc_token.c 2007-03-09 10:31:29 UTC (rev 1281) @@ -70,20 +70,16 @@ { unsigned lin, pos, x, y; const char *p, *l, *f, *b, *e; + struct source *sp; lin = 1; pos = 0; if (t->tok == METHOD) return; - if (t->b >= vcc_default_vcl_b && t->b < vcc_default_vcl_e) { - f = "Default VCL code (compiled in)"; - b = vcc_default_vcl_b; - e = vcc_default_vcl_e; - } else { - f = "VCL code"; - b = tl->b; - e = tl->e; - } + sp = t->src; + f = sp->name; + b = sp->b; + e = sp->e; for (l = p = b; p < t->b; p++) { if (*p == '\n') { lin++; @@ -266,27 +262,44 @@ t->tok = tok; t->b = b; t->e = e; - TAILQ_INSERT_TAIL(&tl->tokens, t, list); + t->src = tl->src; + if (tl->t != NULL) + TAILQ_INSERT_AFTER(&tl->tokens, tl->t, t, list); + else + TAILQ_INSERT_TAIL(&tl->tokens, t, list); tl->t = t; if (0) { fprintf(stderr, "[%s %.*s] ", - vcl_tnames[tok],(int)(e - b), b); + vcl_tnames[tok], PF(t)); if (tok == EOI) fprintf(stderr, "\n"); } } /*-------------------------------------------------------------------- + * Free a token + */ + +void +vcc_FreeToken(struct token *t) +{ + + /* XXX: more */ + free(t); +} + +/*-------------------------------------------------------------------- * Lexical analysis and token generation */ void -vcc_Lexer(struct tokenlist *tl, const char *b, const char *e) +vcc_Lexer(struct tokenlist *tl, struct source *sp) { const char *p, *q; unsigned u; - for (p = b; p < e; ) { + tl->src = sp; + for (p = sp->b; p < sp->e; ) { /* Skip any whitespace */ if (isspace(*p)) { @@ -296,7 +309,7 @@ /* Skip '#.*\n' comments */ if (*p == '#') { - while (p < e && *p != '\n') + while (p < sp->e && *p != '\n') p++; continue; } @@ -304,7 +317,7 @@ /* Skip C-style comments */ if (*p == '/' && p[1] == '*') { p += 2; - for (p += 2; p < e; p++) { + for (p += 2; p < sp->e; p++) { if (*p == '*' && p[1] == '/') { p += 2; break; @@ -315,7 +328,7 @@ /* Skip C++-style comments */ if (*p == '/' && p[1] == '/') { - while (p < e && *p != '\n') + while (p < sp->e && *p != '\n') p++; continue; } @@ -330,7 +343,7 @@ /* Match strings, with \\ and \" escapes */ if (*p == '"') { - for (q = p + 1; q < e; q++) { + for (q = p + 1; q < sp->e; q++) { if (*q == '"') { q++; break; @@ -352,11 +365,11 @@ /* Match Identifiers */ if (isident1(*p)) { - for (q = p; q < e; q++) + for (q = p; q < sp->e; q++) if (!isident(*q)) break; if (isvar(*q)) { - for (; q < e; q++) + for (; q < sp->e; q++) if (!isvar(*q)) break; vcc_AddToken(tl, VAR, p, q); @@ -369,7 +382,7 @@ /* Match numbers { [0-9]+ } */ if (isdigit(*p)) { - for (q = p; q < e; q++) + for (q = p; q < sp->e; q++) if (!isdigit(*q)) break; vcc_AddToken(tl, CNUM, p, q); Modified: trunk/varnish-cache/lib/libvcl/vcc_token_defs.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_token_defs.h 2007-03-08 10:09:18 UTC (rev 1280) +++ trunk/varnish-cache/lib/libvcl/vcc_token_defs.h 2007-03-09 10:31:29 UTC (rev 1281) @@ -7,47 +7,48 @@ */ #define LOW_TOKEN 128 -#define T_IF 128 -#define T_ELSE 129 -#define T_ELSEIF 130 -#define T_ELSIF 131 -#define T_FUNC 132 -#define T_PROC 133 -#define T_SUB 134 -#define T_ACL 135 -#define T_BACKEND 136 -#define T_CALL 137 -#define T_NO_CACHE 138 -#define T_NO_NEW_CACHE 139 -#define T_SET 140 -#define T_REWRITE 141 -#define T_SWITCH_CONFIG 142 -#define T_ERROR 143 -#define T_LOOKUP 144 -#define T_HASH 145 -#define T_PIPE 146 -#define T_PASS 147 -#define T_FETCH 148 -#define T_INSERT 149 -#define T_DELIVER 150 -#define T_DISCARD 151 -#define T_INC 152 -#define T_DEC 153 -#define T_CAND 154 -#define T_COR 155 -#define T_LEQ 156 -#define T_EQ 157 -#define T_NEQ 158 -#define T_GEQ 159 -#define T_SHR 160 -#define T_SHL 161 -#define T_INCR 162 -#define T_DECR 163 -#define T_MUL 164 -#define T_DIV 165 -#define ID 166 -#define VAR 167 -#define CNUM 168 -#define CSTR 169 -#define EOI 170 -#define METHOD 171 +#define T_INCLUDE 128 +#define T_IF 129 +#define T_ELSE 130 +#define T_ELSEIF 131 +#define T_ELSIF 132 +#define T_FUNC 133 +#define T_PROC 134 +#define T_SUB 135 +#define T_ACL 136 +#define T_BACKEND 137 +#define T_CALL 138 +#define T_NO_CACHE 139 +#define T_NO_NEW_CACHE 140 +#define T_SET 141 +#define T_REWRITE 142 +#define T_SWITCH_CONFIG 143 +#define T_ERROR 144 +#define T_LOOKUP 145 +#define T_HASH 146 +#define T_PIPE 147 +#define T_PASS 148 +#define T_FETCH 149 +#define T_INSERT 150 +#define T_DELIVER 151 +#define T_DISCARD 152 +#define T_INC 153 +#define T_DEC 154 +#define T_CAND 155 +#define T_COR 156 +#define T_LEQ 157 +#define T_EQ 158 +#define T_NEQ 159 +#define T_GEQ 160 +#define T_SHR 161 +#define T_SHL 162 +#define T_INCR 163 +#define T_DECR 164 +#define T_MUL 165 +#define T_DIV 166 +#define ID 167 +#define VAR 168 +#define CNUM 169 +#define CSTR 170 +#define EOI 171 +#define METHOD 172 From phk at projects.linpro.no Sat Mar 24 20:33:40 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 24 Mar 2007 21:33:40 +0100 (CET) Subject: r1282 - trunk/varnish-cache/lib/libvcl Message-ID: <20070324203340.AD2791EC2F5@projects.linpro.no> Author: phk Date: 2007-03-24 21:33:40 +0100 (Sat, 24 Mar 2007) New Revision: 1282 Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c Log: use tl-> consistently Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-09 10:31:29 UTC (rev 1281) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-24 20:33:40 UTC (rev 1282) @@ -110,9 +110,9 @@ tl->indent -= INDENT; \ } while (0) -#define C(tl, sep) do { \ +#define C(tl, sep) do { \ Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \ - tl->t->cnt = tl->cnt; \ + tl->t->cnt = tl->cnt; \ } while (0) /*-------------------------------------------------------------------- @@ -1527,7 +1527,7 @@ static char * vcc_CompileSource(struct vsb *sb, struct source *sp) { - struct tokenlist tokens, *tl; + struct tokenlist tokenlist, *tl; struct ref *r; struct token *t; FILE *fo; @@ -1535,31 +1535,31 @@ char buf[BUFSIZ]; int i; - memset(&tokens, 0, sizeof tokens); - tl = &tokens; + memset(&tokenlist, 0, sizeof tokenlist); + tl = &tokenlist; TAILQ_INIT(&tl->tokens); TAILQ_INIT(&tl->refs); TAILQ_INIT(&tl->procs); TAILQ_INIT(&tl->sources); - tokens.sb = sb; + tl->sb = sb; tl->nsources = 0; - tokens.fc = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); - assert(tokens.fc != NULL); + tl->fc = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); + assert(tl->fc != NULL); - tokens.fh = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); - assert(tokens.fh != NULL); + tl->fh = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); + assert(tl->fh != NULL); - tokens.fi = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); - assert(tokens.fi != NULL); + tl->fi = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); + assert(tl->fi != NULL); - tokens.ff = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); - assert(tokens.ff != NULL); + tl->ff = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); + assert(tl->ff != NULL); #define VCL_MET_MAC(l,U,m) \ - tokens.fm_##l = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ - assert(tokens.fm_##l != NULL); + tl->fm_##l = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ + assert(tl->fm_##l != NULL); #include "vcl_returns.h" #undef VCL_MET_MAC @@ -1570,7 +1570,7 @@ TAILQ_INSERT_TAIL(&tl->sources, sp, list); sp->idx = tl->nsources++; vcc_Lexer(tl, sp); - if (tokens.err) + if (tl->err) goto done; sp = vcc_new_source(vcc_default_vcl_b, vcc_default_vcl_e, "Default"); @@ -1578,19 +1578,19 @@ sp->idx = tl->nsources++; vcc_Lexer(tl, sp); vcc_AddToken(tl, EOI, sp->e, sp->e); - if (tokens.err) + if (tl->err) goto done; vcc_resolve_includes(tl); - if (tokens.err) + if (tl->err) goto done; - tokens.t = TAILQ_FIRST(&tl->tokens); + tl->t = TAILQ_FIRST(&tl->tokens); Parse(tl); - if (tokens.err) + if (tl->err) goto done; Consistency(tl); - if (tokens.err) + if (tl->err) goto done; LocTable(tl); @@ -1619,13 +1619,13 @@ vcl_output_lang_h(fo); fputs(vrt_obj_h, fo); - vsb_finish(tokens.fh); - fputs(vsb_data(tokens.fh), fo); - vsb_delete(tokens.fh); + vsb_finish(tl->fh); + fputs(vsb_data(tl->fh), fo); + vsb_delete(tl->fh); - vsb_finish(tokens.fc); - fputs(vsb_data(tokens.fc), fo); - vsb_delete(tokens.fc); + vsb_finish(tl->fc); + fputs(vsb_data(tl->fc), fo); + vsb_delete(tl->fc); i = pclose(fo); fprintf(stderr, "pclose=%d\n", i); @@ -1637,7 +1637,7 @@ } done: -#define VCL_MET_MAC(l,U,m) vsb_delete(tokens.fm_##l); +#define VCL_MET_MAC(l,U,m) vsb_delete(tl->fm_##l); #include "vcl_returns.h" #undef VCL_MET_MAC From phk at projects.linpro.no Sat Mar 24 21:01:43 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 24 Mar 2007 22:01:43 +0100 (CET) Subject: r1283 - trunk/varnish-cache/lib/libvcl Message-ID: <20070324210143.9F9061EC2F3@projects.linpro.no> Author: phk Date: 2007-03-24 22:01:43 +0100 (Sat, 24 Mar 2007) New Revision: 1283 Added: trunk/varnish-cache/lib/libvcl/vcc_parse.c Modified: trunk/varnish-cache/lib/libvcl/Makefile.am trunk/varnish-cache/lib/libvcl/vcc_compile.c trunk/varnish-cache/lib/libvcl/vcc_compile.h Log: Split off the parsing from vcc_compile.c into vcc_parse.c Modified: trunk/varnish-cache/lib/libvcl/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libvcl/Makefile.am 2007-03-24 20:33:40 UTC (rev 1282) +++ trunk/varnish-cache/lib/libvcl/Makefile.am 2007-03-24 21:01:43 UTC (rev 1283) @@ -11,6 +11,7 @@ \ vcc_acl.c \ vcc_compile.c \ + vcc_parse.c \ vcc_fixed_token.c \ vcc_obj.c \ vcc_token.c Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-24 20:33:40 UTC (rev 1282) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-24 21:01:43 UTC (rev 1283) @@ -96,25 +96,8 @@ /*--------------------------------------------------------------------*/ -static void Compound(struct tokenlist *tl); -static void Cond_0(struct tokenlist *tl); -static struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); -static void AddCall(struct tokenlist *tl, struct token *t); const char *vcc_default_vcl_b, *vcc_default_vcl_e; -/*--------------------------------------------------------------------*/ - -#define L(tl, foo) do { \ - tl->indent += INDENT; \ - foo; \ - tl->indent -= INDENT; \ -} while (0) - -#define C(tl, sep) do { \ - Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \ - tl->t->cnt = tl->cnt; \ -} while (0) - /*-------------------------------------------------------------------- * Printf output to the two vsbs, possibly indented */ @@ -206,22 +189,6 @@ EncString(sb, t->dec, NULL); } -/*--------------------------------------------------------------------*/ - -static int -IsMethod(struct token *t) -{ - struct method *m; - - for(m = method_tab; m->name != NULL; m++) { - if (vcc_IdIs(t, m->defname)) - return (2); - if (vcc_IdIs(t, m->name)) - return (1); - } - return (0); -} - /*-------------------------------------------------------------------- * Keep track of definitions and references */ @@ -290,131 +257,6 @@ r->name = t; } -/*-------------------------------------------------------------------- - * Recognize and convert units of time, return seconds. - */ - -static double -TimeUnit(struct tokenlist *tl) -{ - double sc = 1.0; - - assert(tl->t->tok == ID); - if (vcc_IdIs(tl->t, "ms")) - sc = 1e-3; - else if (vcc_IdIs(tl->t, "s")) - sc = 1.0; - else if (vcc_IdIs(tl->t, "m")) - sc = 60.0; - else if (vcc_IdIs(tl->t, "h")) - sc = 60.0 * 60.0; - else if (vcc_IdIs(tl->t, "d")) - sc = 60.0 * 60.0 * 24.0; - else { - vsb_printf(tl->sb, "Unknown time unit "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n"); - vcc_ErrWhere(tl, tl->t); - return (1.0); - } - vcc_NextToken(tl); - return (sc); -} - -/*-------------------------------------------------------------------- - * Recognize and convert units of size, return bytes. - */ - -static double -SizeUnit(struct tokenlist *tl) -{ - double sc = 1.0; - - assert(tl->t->tok == ID); - if (vcc_IdIs(tl->t, "b")) - sc = 1.0; - else if (vcc_IdIs(tl->t, "kb")) - sc = 1024.0; - else if (vcc_IdIs(tl->t, "mb") || vcc_IdIs(tl->t, "Mb")) - sc = 1024.0 * 1024.0; - else if (vcc_IdIs(tl->t, "gb") || vcc_IdIs(tl->t, "Gb")) - sc = 1024.0 * 1024.0 * 1024.0; - else { - vsb_printf(tl->sb, "Unknown size unit "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, ". Legal are 'kb', 'mb' and 'gb'\n"); - vcc_ErrWhere(tl, tl->t); - return (1.0); - } - vcc_NextToken(tl); - return (sc); -} - -/*-------------------------------------------------------------------- - * Recognize and convert units of rate as { space '/' time } - */ - -static double -RateUnit(struct tokenlist *tl) -{ - double sc = 1.0; - - assert(tl->t->tok == ID); - sc = SizeUnit(tl); - Expect(tl, '/'); - vcc_NextToken(tl); - sc /= TimeUnit(tl); - return (sc); -} - -/*-------------------------------------------------------------------- - * Recognize and convert { CNUM } to unsigned value - */ - -unsigned -UintVal(struct tokenlist *tl) -{ - unsigned d = 0; - const char *p; - - Expect(tl, CNUM); - for (p = tl->t->b; p < tl->t->e; p++) { - d *= 10; - d += *p - '0'; - } - vcc_NextToken(tl); - return (d); -} - -/*-------------------------------------------------------------------- - * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value - */ - -static double -DoubleVal(struct tokenlist *tl) -{ - double d = 0.0, e = 0.1; - const char *p; - - Expect(tl, CNUM); - for (p = tl->t->b; p < tl->t->e; p++) { - d *= 10; - d += *p - '0'; - } - vcc_NextToken(tl); - if (tl->t->tok != '.') - return (d); - vcc_NextToken(tl); - if (tl->t->tok != CNUM) - return (d); - for (p = tl->t->b; p < tl->t->e; p++) { - d += (*p - '0') * e; - e *= 0.1; - } - vcc_NextToken(tl); - return (d); -} - /*--------------------------------------------------------------------*/ static struct var * @@ -448,7 +290,7 @@ /*--------------------------------------------------------------------*/ -static struct var * +struct var * FindVar(struct tokenlist *tl, struct token *t, struct var *vl) { struct var *v; @@ -471,671 +313,11 @@ return (NULL); } - -/*--------------------------------------------------------------------*/ - -static void -TimeVal(struct tokenlist *tl) -{ - double v, sc; - - v = DoubleVal(tl); - ExpectErr(tl, ID); - sc = TimeUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); -} - -static void -SizeVal(struct tokenlist *tl) -{ - double v, sc; - - v = DoubleVal(tl); - ExpectErr(tl, ID); - sc = SizeUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); -} - -static void -RateVal(struct tokenlist *tl) -{ - double v, sc; - - v = DoubleVal(tl); - ExpectErr(tl, ID); - sc = RateUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); -} - -/*--------------------------------------------------------------------*/ - -static void -vcc_re(struct tokenlist *tl, const char *str, struct token *re) -{ - char buf[32]; - - assert(re->tok == CSTR); - if (VRT_re_test(tl->sb, re->dec)) { - vcc_ErrWhere(tl, re); - return; - } - sprintf(buf, "VGC_re_%u", tl->recnt++); - - Fc(tl, 1, "VRT_re_match(%s, %s)\n", str, buf); - Fh(tl, 0, "void *%s;\n", buf); - Fi(tl, 0, "\tVRT_re_init(&%s, ",buf); - EncToken(tl->fi, re); - Fi(tl, 0, ");\n"); - Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf); -} - - -/*--------------------------------------------------------------------*/ - -static void -Cond_String(struct var *vp, struct tokenlist *tl) -{ - - switch (tl->t->tok) { - case '~': - vcc_NextToken(tl); - ExpectErr(tl, CSTR); - vcc_re(tl, vp->rname, tl->t); - vcc_NextToken(tl); - break; - case T_EQ: - case T_NEQ: - Fc(tl, 1, "%sstrcmp(%s, ", - tl->t->tok == T_EQ ? "!" : "", vp->rname); - vcc_NextToken(tl); - ExpectErr(tl, CSTR); - EncToken(tl->fc, tl->t); - Fc(tl, 0, ")\n"); - vcc_NextToken(tl); - break; - default: - Fc(tl, 1, "%s != (void*)0", vp->rname); - break; - } -} - -static void -Cond_Int(struct var *vp, struct tokenlist *tl) -{ - - Fc(tl, 1, "%s ", vp->rname); - switch (tl->t->tok) { - case T_EQ: - case T_NEQ: - case T_LEQ: - case T_GEQ: - case '>': - case '<': - Fc(tl, 0, "%.*s ", PF(tl->t)); - vcc_NextToken(tl); - switch(vp->fmt) { - case TIME: - TimeVal(tl); - break; - case INT: - ExpectErr(tl, CNUM); - Fc(tl, 0, "%.*s ", PF(tl->t)); - vcc_NextToken(tl); - break; - case SIZE: - SizeVal(tl); - break; - default: - vsb_printf(tl->sb, - "No conditions available for variable '%s'\n", - vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - Fc(tl, 0, "\n"); - break; - default: - vsb_printf(tl->sb, "Illegal condition "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, " on integer variable\n"); - vsb_printf(tl->sb, - " only '==', '!=', '<', '>', '<=' and '>=' are legal\n"); - vcc_ErrWhere(tl, tl->t); - break; - } -} - -static void -Cond_Bool(struct var *vp, struct tokenlist *tl) -{ - - Fc(tl, 1, "%s\n", vp->rname); -} - -static void -Cond_Backend(struct var *vp, struct tokenlist *tl) -{ - - Fc(tl, 1, "%s\n", vp->rname); -} - -static void -Cond_2(struct tokenlist *tl) -{ - struct var *vp; - - C(tl, ","); - if (tl->t->tok == '!') { - Fc(tl, 1, "!(\n"); - vcc_NextToken(tl); - } else { - Fc(tl, 1, "(\n"); - } - if (tl->t->tok == '(') { - vcc_NextToken(tl); - Cond_0(tl); - ExpectErr(tl, ')'); - vcc_NextToken(tl); - } else if (tl->t->tok == VAR) { - vp = FindVar(tl, tl->t, vcc_vars); - ERRCHK(tl); - assert(vp != NULL); - vcc_NextToken(tl); - switch (vp->fmt) { - case INT: L(tl, Cond_Int(vp, tl)); break; - case SIZE: L(tl, Cond_Int(vp, tl)); break; - case BOOL: L(tl, Cond_Bool(vp, tl)); break; - case IP: L(tl, vcc_Cond_Ip(vp, tl)); break; - case STRING: L(tl, Cond_String(vp, tl)); break; - case TIME: L(tl, Cond_Int(vp, tl)); break; - case BACKEND: L(tl, Cond_Backend(vp, tl)); break; - default: - vsb_printf(tl->sb, - "Variable '%s'" - " has no conditions that can be checked\n", - vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - } else { - vsb_printf(tl->sb, - "Syntax error in condition, expected '(', '!' or" - " variable name, found "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, "\n"); - vcc_ErrWhere(tl, tl->t); - return; - } - Fc(tl, 1, ")\n"); -} - -static void -Cond_1(struct tokenlist *tl) -{ - - Fc(tl, 1, "(\n"); - L(tl, Cond_2(tl)); - while (tl->t->tok == T_CAND) { - vcc_NextToken(tl); - Fc(tl, 1, ") && (\n"); - L(tl, Cond_2(tl)); - } - Fc(tl, 1, ")\n"); -} - -static void -Cond_0(struct tokenlist *tl) -{ - - Fc(tl, 1, "(\n"); - L(tl, Cond_1(tl)); - while (tl->t->tok == T_COR) { - vcc_NextToken(tl); - Fc(tl, 1, ") || (\n"); - L(tl, Cond_1(tl)); - } - Fc(tl, 1, ")\n"); -} - -static void -Conditional(struct tokenlist *tl) -{ - - ExpectErr(tl, '('); - vcc_NextToken(tl); - Fc(tl, 1, "(\n"); - L(tl, Cond_0(tl)); - ERRCHK(tl); - Fc(tl, 1, ")\n"); - ExpectErr(tl, ')'); - vcc_NextToken(tl); -} - -/*--------------------------------------------------------------------*/ - -static void -IfStmt(struct tokenlist *tl) -{ - - ExpectErr(tl, T_IF); - Fc(tl, 1, "if \n"); - vcc_NextToken(tl); - L(tl, Conditional(tl)); - ERRCHK(tl); - L(tl, Compound(tl)); - ERRCHK(tl); - while (1) { - switch (tl->t->tok) { - case T_ELSE: - vcc_NextToken(tl); - if (tl->t->tok != T_IF) { - Fc(tl, 1, "else \n"); - L(tl, Compound(tl)); - ERRCHK(tl); - return; - } - /* FALLTHROUGH */ - case T_ELSEIF: - case T_ELSIF: - Fc(tl, 1, "else if \n"); - vcc_NextToken(tl); - L(tl, Conditional(tl)); - ERRCHK(tl); - L(tl, Compound(tl)); - ERRCHK(tl); - break; - default: - C(tl, ";"); - return; - } - } -} - -/*--------------------------------------------------------------------*/ - -static void -Action(struct tokenlist *tl) -{ - unsigned a; - struct var *vp; - struct token *at; - - at = tl->t; - vcc_NextToken(tl); - switch (at->tok) { - case T_NO_NEW_CACHE: - Fc(tl, 1, "VCL_no_new_cache(sp);\n"); - return; - case T_NO_CACHE: - Fc(tl, 1, "VCL_no_cache(sp);\n"); - return; -#define VCL_RET_MAC(a,b,c,d) case T_##b: \ - Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ - tl->curproc->returns |= VCL_RET_##b; \ - tl->curproc->returnt[d] = at; \ - return; -#include "vcl_returns.h" -#undef VCL_RET_MAC - case T_ERROR: - if (tl->t->tok == CNUM) - a = UintVal(tl); - else - a = 0; - Fc(tl, 1, "VRT_error(sp, %u", a); - if (tl->t->tok == CSTR) { - Fc(tl, 0, ", %.*s", PF(tl->t)); - vcc_NextToken(tl); - } else { - Fc(tl, 0, ", (const char *)0"); - } - Fc(tl, 0, ");\n"); - Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n"); - return; - case T_SWITCH_CONFIG: - ExpectErr(tl, ID); - Fc(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t)); - vcc_NextToken(tl); - return; - case T_CALL: - ExpectErr(tl, ID); - AddCall(tl, tl->t); - AddRef(tl, tl->t, R_FUNC); - Fc(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); - Fc(tl, 1, "\treturn (1);\n"); - vcc_NextToken(tl); - return; - case T_REWRITE: - ExpectErr(tl, CSTR); - Fc(tl, 1, "VCL_rewrite(%.*s", PF(tl->t)); - vcc_NextToken(tl); - ExpectErr(tl, CSTR); - Fc(tl, 0, ", %.*s);\n", PF(tl->t)); - vcc_NextToken(tl); - return; - case T_SET: - ExpectErr(tl, VAR); - vp = FindVar(tl, tl->t, vcc_vars); - ERRCHK(tl); - assert(vp != NULL); - Fc(tl, 1, "%s", vp->lname); - vcc_NextToken(tl); - switch (vp->fmt) { - case INT: - case SIZE: - case RATE: - case TIME: - case FLOAT: - if (tl->t->tok != '=') - Fc(tl, 0, "%s %c ", vp->rname, *tl->t->b); - a = tl->t->tok; - vcc_NextToken(tl); - if (a == T_MUL || a == T_DIV) - Fc(tl, 0, "%g", DoubleVal(tl)); - else if (vp->fmt == TIME) - TimeVal(tl); - else if (vp->fmt == SIZE) - SizeVal(tl); - else if (vp->fmt == RATE) - RateVal(tl); - else - Fc(tl, 0, "%g", DoubleVal(tl)); - Fc(tl, 0, ");\n"); - break; -#if 0 /* XXX: enable if we find a legit use */ - case IP: - if (tl->t->tok == '=') { - vcc_NextToken(tl); - u = vcc_IpVal(tl); - Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n", - u, - (u >> 24) & 0xff, - (u >> 16) & 0xff, - (u >> 8) & 0xff, - u & 0xff); - break; - } - vsb_printf(tl->sb, "Illegal assignment operator "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, - " only '=' is legal for IP numbers\n"); - vcc_ErrWhere(tl, tl->t); - return; -#endif - case BACKEND: - if (tl->t->tok == '=') { - vcc_NextToken(tl); - AddRef(tl, tl->t, R_BACKEND); - Fc(tl, 0, "VGC_backend_%.*s", PF(tl->t)); - vcc_NextToken(tl); - Fc(tl, 0, ");\n"); - break; - } - vsb_printf(tl->sb, "Illegal assignment operator "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, - " only '=' is legal for backend\n"); - vcc_ErrWhere(tl, tl->t); - return; - default: - vsb_printf(tl->sb, - "Assignments not possible for '%s'\n", vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - return; - default: - vsb_printf(tl->sb, "Expected action, 'if' or '}'\n"); - vcc_ErrWhere(tl, at); - return; - } -} - -/*--------------------------------------------------------------------*/ - -static void -Compound(struct tokenlist *tl) -{ - - ExpectErr(tl, '{'); - Fc(tl, 1, "{\n"); - tl->indent += INDENT; - C(tl, ";"); - vcc_NextToken(tl); - while (1) { - ERRCHK(tl); - switch (tl->t->tok) { - case '{': - Compound(tl); - break; - case T_IF: - IfStmt(tl); - break; - case '}': - vcc_NextToken(tl); - tl->indent -= INDENT; - Fc(tl, 1, "}\n"); - return; - case EOI: - vsb_printf(tl->sb, - "End of input while in compound statement\n"); - tl->err = 1; - return; - default: - Action(tl); - ERRCHK(tl); - ExpectErr(tl, ';'); - vcc_NextToken(tl); - break; - } - } -} - -/*--------------------------------------------------------------------*/ - -static const char * -CheckHostPort(const char *host, const char *port) -{ - struct addrinfo *res, hint; - int error; - - memset(&hint, 0, sizeof hint); - hint.ai_family = PF_UNSPEC; - hint.ai_socktype = SOCK_STREAM; - error = getaddrinfo(host, port, &hint, &res); - if (error) - return (gai_strerror(error)); - freeaddrinfo(res); - return (NULL); -} - -static void -Backend(struct tokenlist *tl) -{ - unsigned a; - struct var *vp; - struct token *t_be = NULL; - struct token *t_host = NULL; - struct token *t_port = NULL; - const char *ep; - - vcc_NextToken(tl); - ExpectErr(tl, ID); - t_be = tl->t; - AddDef(tl, tl->t, R_BACKEND); - if (tl->nbackend == 0) - AddRef(tl, tl->t, R_BACKEND); - Fh(tl, 1, "#define VGC_backend_%.*s (VCL_conf.backend[%d])\n", - PF(tl->t), tl->nbackend); - Fc(tl, 0, "\n"); - Fc(tl, 0, "static void\n"); - Fc(tl, 1, "VGC_init_backend_%.*s (void)\n", PF(tl->t)); - Fc(tl, 1, "{\n"); - Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%.*s;\n", PF(tl->t)); - Fc(tl, 1, "\n"); - Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%.*s\");\n", PF(tl->t)); - vcc_NextToken(tl); - ExpectErr(tl, '{'); - vcc_NextToken(tl); - while (1) { - if (tl->t->tok == '}') - break; - ExpectErr(tl, T_SET); - vcc_NextToken(tl); - ExpectErr(tl, VAR); - vp = FindVar(tl, tl->t, vcc_be_vars); - ERRCHK(tl); - assert(vp != NULL); - vcc_NextToken(tl); - ExpectErr(tl, '='); - vcc_NextToken(tl); - switch (vp->fmt) { - case HOSTNAME: - ExpectErr(tl, CSTR); - t_host = tl->t; - Fc(tl, 1, "\t%s ", vp->lname); - EncToken(tl->fc, t_host); - Fc(tl, 0, ");\n"); - vcc_NextToken(tl); - break; - case PORTNAME: - ExpectErr(tl, CSTR); - t_port = tl->t; - Fc(tl, 1, "\t%s ", vp->lname); - EncToken(tl->fc, t_port); - Fc(tl, 0, ");\n"); - vcc_NextToken(tl); - break; -#if 0 - case INT: - case SIZE: - case RATE: - case FLOAT: -#endif - case TIME: - Fc(tl, 1, "\t%s ", vp->lname); - a = tl->t->tok; - if (a == T_MUL || a == T_DIV) - Fc(tl, 0, "%g", DoubleVal(tl)); - else if (vp->fmt == TIME) - TimeVal(tl); - else if (vp->fmt == SIZE) - SizeVal(tl); - else if (vp->fmt == RATE) - RateVal(tl); - else - Fc(tl, 0, "%g", DoubleVal(tl)); - Fc(tl, 0, ");\n"); - break; - default: - vsb_printf(tl->sb, - "Assignments not possible for '%s'\n", vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - ExpectErr(tl, ';'); - vcc_NextToken(tl); - } - ExpectErr(tl, '}'); - if (t_host == NULL) { - vsb_printf(tl->sb, "Backend '%.*s' has no hostname\n", - PF(t_be)); - vcc_ErrWhere(tl, tl->t); - return; - } - ep = CheckHostPort(t_host->dec, "80"); - if (ep != NULL) { - vsb_printf(tl->sb, "Backend '%.*s': %s\n", PF(t_be), ep); - vcc_ErrWhere(tl, t_host); - return; - } - if (t_port != NULL) { - ep = CheckHostPort(t_host->dec, t_port->dec); - if (ep != NULL) { - vsb_printf(tl->sb, - "Backend '%.*s': %s\n", PF(t_be), ep); - vcc_ErrWhere(tl, t_port); - return; - } - } - - vcc_NextToken(tl); - Fc(tl, 1, "}\n"); - Fc(tl, 0, "\n"); - Fi(tl, 0, "\tVGC_init_backend_%.*s();\n", PF(t_be)); - Ff(tl, 0, "\tVRT_fini_backend(VGC_backend_%.*s);\n", PF(t_be)); - tl->nbackend++; -} - -/*--------------------------------------------------------------------*/ - -static void -Function(struct tokenlist *tl) -{ - struct token *tn; - - vcc_NextToken(tl); - ExpectErr(tl, ID); - tl->curproc = AddProc(tl, tl->t, 1); - tl->curproc->exists++; - tn = tl->t; - AddDef(tl, tl->t, R_FUNC); - Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", - PF(tl->t)); - Fc(tl, 1, "static int\n"); - Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t)); - vcc_NextToken(tl); - tl->indent += INDENT; - Fc(tl, 1, "{\n"); - L(tl, Compound(tl)); - if (IsMethod(tn) == 1) { - Fc(tl, 1, "VGC_function_default_%.*s(sp);\n", PF(tn)); - } - Fc(tl, 1, "}\n"); - tl->indent -= INDENT; - Fc(tl, 0, "\n"); -} - /*-------------------------------------------------------------------- - * Top level of parser, recognize: - * Function definitions - * Backend definitions - * End of input - */ - -static void -Parse(struct tokenlist *tl) -{ - - while (tl->t->tok != EOI) { - ERRCHK(tl); - switch (tl->t->tok) { - case T_ACL: - vcc_Acl(tl); - break; - case T_SUB: - Function(tl); - break; - case T_BACKEND: - Backend(tl); - break; - case EOI: - break; - default: - vsb_printf(tl->sb, - "Expected 'acl', 'sub' or 'backend', found "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, " at\n"); - vcc_ErrWhere(tl, tl->t); - return; - } - } -} - -/*-------------------------------------------------------------------- * Consistency check */ -static struct proc * +struct proc * AddProc(struct tokenlist *tl, struct token *t, int def) { struct proc *p; @@ -1155,7 +337,7 @@ return (p); } -static void +void AddCall(struct tokenlist *tl, struct token *t) { struct proccall *pc; @@ -1545,18 +727,23 @@ tl->nsources = 0; + /* General C code */ tl->fc = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->fc != NULL); + /* Forward decls (.h like) */ tl->fh = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->fh != NULL); + /* Init C code */ tl->fi = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->fi != NULL); + /* Finish C code */ tl->ff = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->ff != NULL); + /* body code of methods */ #define VCL_MET_MAC(l,U,m) \ tl->fm_##l = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ assert(tl->fm_##l != NULL); @@ -1586,7 +773,7 @@ goto done; tl->t = TAILQ_FIRST(&tl->tokens); - Parse(tl); + vcc_Parse(tl); if (tl->err) goto done; Consistency(tl); Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-24 20:33:40 UTC (rev 1282) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-24 21:01:43 UTC (rev 1283) @@ -155,13 +155,17 @@ void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); void EncToken(struct vsb *sb, struct token *t); void EncString(struct vsb *sb, const char *b, const char *e); +struct var *FindVar(struct tokenlist *tl, struct token *t, struct var *vl); +void AddCall(struct tokenlist *tl, struct token *t); +struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); - /* vcc_obj.c */ extern struct var vcc_be_vars[]; extern struct var vcc_vars[]; extern const char *vrt_obj_h; +/* vcc_parse.c */ +void vcc_Parse(struct tokenlist *tl); /* vcc_token.c */ void vcc_ErrToken(struct tokenlist *tl, struct token *t); Copied: trunk/varnish-cache/lib/libvcl/vcc_parse.c (from rev 1282, trunk/varnish-cache/lib/libvcl/vcc_compile.c) =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-24 20:33:40 UTC (rev 1282) +++ trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-03-24 21:01:43 UTC (rev 1283) @@ -0,0 +1,914 @@ +/*- + * Copyright (c) 2006 Verdens Gang AS + * Copyright (c) 2006 Linpro AS + * All rights reserved. + * + * Author: Poul-Henning Kamp + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +/* + * XXX: + * generate interface structure + * + * XXX: + * Better error messages, throughout. + * >It also accured to me that we could link the errors to the error + * >documentation. + * > + * >Unreferenced function 'request_policy', first mention is + * > Line 8 Pos 4 + * > sub request_policy { + * > ----##############-- + * >Read more about this type of error: + * >http://varnish/doc/error.html#Unreferenced%20function + * > + * > + * > Unknown variable 'obj.bandwidth' + * > At: Line 88 Pos 12 + * > if (obj.bandwidth < 1 kb/h) { + * > ------------#############------------ + * >Read more about this type of error: + * >http://varnish/doc/error.html#Unknown%20variable + * + * XXX: + * Create proper tmp filenames for .h, .c and .o + * + * XXX: + * and all the rest... + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat/asprintf.h" +#include "vsb.h" + +#include "vcc_priv.h" +#include "vcc_compile.h" + +#include "vrt.h" +#include "libvcl.h" + +static struct method method_tab[] = { +#define VCL_RET_MAC(l,U,b,n) +#define VCL_MET_MAC(l,U,m) { "vcl_"#l, "default_vcl_"#l, m }, +#include "vcl_returns.h" +#undef VCL_MET_MAC +#undef VCL_RET_MAC + { NULL, 0U } +}; + +/*--------------------------------------------------------------------*/ + +static void Compound(struct tokenlist *tl); +static void Cond_0(struct tokenlist *tl); +const char *vcc_default_vcl_b, *vcc_default_vcl_e; + +/*--------------------------------------------------------------------*/ + +#define L(tl, foo) do { \ + tl->indent += INDENT; \ + foo; \ + tl->indent -= INDENT; \ +} while (0) + +#define C(tl, sep) do { \ + Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \ + tl->t->cnt = tl->cnt; \ +} while (0) + +/*--------------------------------------------------------------------*/ + +static int +IsMethod(struct token *t) +{ + struct method *m; + + for(m = method_tab; m->name != NULL; m++) { + if (vcc_IdIs(t, m->defname)) + return (2); + if (vcc_IdIs(t, m->name)) + return (1); + } + return (0); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of time, return seconds. + */ + +static double +TimeUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + if (vcc_IdIs(tl->t, "ms")) + sc = 1e-3; + else if (vcc_IdIs(tl->t, "s")) + sc = 1.0; + else if (vcc_IdIs(tl->t, "m")) + sc = 60.0; + else if (vcc_IdIs(tl->t, "h")) + sc = 60.0 * 60.0; + else if (vcc_IdIs(tl->t, "d")) + sc = 60.0 * 60.0 * 24.0; + else { + vsb_printf(tl->sb, "Unknown time unit "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n"); + vcc_ErrWhere(tl, tl->t); + return (1.0); + } + vcc_NextToken(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of size, return bytes. + */ + +static double +SizeUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + if (vcc_IdIs(tl->t, "b")) + sc = 1.0; + else if (vcc_IdIs(tl->t, "kb")) + sc = 1024.0; + else if (vcc_IdIs(tl->t, "mb") || vcc_IdIs(tl->t, "Mb")) + sc = 1024.0 * 1024.0; + else if (vcc_IdIs(tl->t, "gb") || vcc_IdIs(tl->t, "Gb")) + sc = 1024.0 * 1024.0 * 1024.0; + else { + vsb_printf(tl->sb, "Unknown size unit "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, ". Legal are 'kb', 'mb' and 'gb'\n"); + vcc_ErrWhere(tl, tl->t); + return (1.0); + } + vcc_NextToken(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of rate as { space '/' time } + */ + +static double +RateUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + sc = SizeUnit(tl); + Expect(tl, '/'); + vcc_NextToken(tl); + sc /= TimeUnit(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert { CNUM } to unsigned value + */ + +unsigned +UintVal(struct tokenlist *tl) +{ + unsigned d = 0; + const char *p; + + Expect(tl, CNUM); + for (p = tl->t->b; p < tl->t->e; p++) { + d *= 10; + d += *p - '0'; + } + vcc_NextToken(tl); + return (d); +} + +/*-------------------------------------------------------------------- + * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value + */ + +static double +DoubleVal(struct tokenlist *tl) +{ + double d = 0.0, e = 0.1; + const char *p; + + Expect(tl, CNUM); + for (p = tl->t->b; p < tl->t->e; p++) { + d *= 10; + d += *p - '0'; + } + vcc_NextToken(tl); + if (tl->t->tok != '.') + return (d); + vcc_NextToken(tl); + if (tl->t->tok != CNUM) + return (d); + for (p = tl->t->b; p < tl->t->e; p++) { + d += (*p - '0') * e; + e *= 0.1; + } + vcc_NextToken(tl); + return (d); +} + +/*--------------------------------------------------------------------*/ + +static void +TimeVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = TimeUnit(tl); + Fc(tl, 0, "(%g * %g)", v, sc); +} + +static void +SizeVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = SizeUnit(tl); + Fc(tl, 0, "(%g * %g)", v, sc); +} + +static void +RateVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = RateUnit(tl); + Fc(tl, 0, "(%g * %g)", v, sc); +} + +/*--------------------------------------------------------------------*/ + +static void +vcc_re(struct tokenlist *tl, const char *str, struct token *re) +{ + char buf[32]; + + assert(re->tok == CSTR); + if (VRT_re_test(tl->sb, re->dec)) { + vcc_ErrWhere(tl, re); + return; + } + sprintf(buf, "VGC_re_%u", tl->recnt++); + + Fc(tl, 1, "VRT_re_match(%s, %s)\n", str, buf); + Fh(tl, 0, "void *%s;\n", buf); + Fi(tl, 0, "\tVRT_re_init(&%s, ",buf); + EncToken(tl->fi, re); + Fi(tl, 0, ");\n"); + Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf); +} + + +/*--------------------------------------------------------------------*/ + +static void +Cond_String(struct var *vp, struct tokenlist *tl) +{ + + switch (tl->t->tok) { + case '~': + vcc_NextToken(tl); + ExpectErr(tl, CSTR); + vcc_re(tl, vp->rname, tl->t); + vcc_NextToken(tl); + break; + case T_EQ: + case T_NEQ: + Fc(tl, 1, "%sstrcmp(%s, ", + tl->t->tok == T_EQ ? "!" : "", vp->rname); + vcc_NextToken(tl); + ExpectErr(tl, CSTR); + EncToken(tl->fc, tl->t); + Fc(tl, 0, ")\n"); + vcc_NextToken(tl); + break; + default: + Fc(tl, 1, "%s != (void*)0", vp->rname); + break; + } +} + +static void +Cond_Int(struct var *vp, struct tokenlist *tl) +{ + + Fc(tl, 1, "%s ", vp->rname); + switch (tl->t->tok) { + case T_EQ: + case T_NEQ: + case T_LEQ: + case T_GEQ: + case '>': + case '<': + Fc(tl, 0, "%.*s ", PF(tl->t)); + vcc_NextToken(tl); + switch(vp->fmt) { + case TIME: + TimeVal(tl); + break; + case INT: + ExpectErr(tl, CNUM); + Fc(tl, 0, "%.*s ", PF(tl->t)); + vcc_NextToken(tl); + break; + case SIZE: + SizeVal(tl); + break; + default: + vsb_printf(tl->sb, + "No conditions available for variable '%s'\n", + vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + Fc(tl, 0, "\n"); + break; + default: + vsb_printf(tl->sb, "Illegal condition "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, " on integer variable\n"); + vsb_printf(tl->sb, + " only '==', '!=', '<', '>', '<=' and '>=' are legal\n"); + vcc_ErrWhere(tl, tl->t); + break; + } +} + +static void +Cond_Bool(struct var *vp, struct tokenlist *tl) +{ + + Fc(tl, 1, "%s\n", vp->rname); +} + +static void +Cond_Backend(struct var *vp, struct tokenlist *tl) +{ + + Fc(tl, 1, "%s\n", vp->rname); +} + +static void +Cond_2(struct tokenlist *tl) +{ + struct var *vp; + + C(tl, ","); + if (tl->t->tok == '!') { + Fc(tl, 1, "!(\n"); + vcc_NextToken(tl); + } else { + Fc(tl, 1, "(\n"); + } + if (tl->t->tok == '(') { + vcc_NextToken(tl); + Cond_0(tl); + ExpectErr(tl, ')'); + vcc_NextToken(tl); + } else if (tl->t->tok == VAR) { + vp = FindVar(tl, tl->t, vcc_vars); + ERRCHK(tl); + assert(vp != NULL); + vcc_NextToken(tl); + switch (vp->fmt) { + case INT: L(tl, Cond_Int(vp, tl)); break; + case SIZE: L(tl, Cond_Int(vp, tl)); break; + case BOOL: L(tl, Cond_Bool(vp, tl)); break; + case IP: L(tl, vcc_Cond_Ip(vp, tl)); break; + case STRING: L(tl, Cond_String(vp, tl)); break; + case TIME: L(tl, Cond_Int(vp, tl)); break; + case BACKEND: L(tl, Cond_Backend(vp, tl)); break; + default: + vsb_printf(tl->sb, + "Variable '%s'" + " has no conditions that can be checked\n", + vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + } else { + vsb_printf(tl->sb, + "Syntax error in condition, expected '(', '!' or" + " variable name, found "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, "\n"); + vcc_ErrWhere(tl, tl->t); + return; + } + Fc(tl, 1, ")\n"); +} + +static void +Cond_1(struct tokenlist *tl) +{ + + Fc(tl, 1, "(\n"); + L(tl, Cond_2(tl)); + while (tl->t->tok == T_CAND) { + vcc_NextToken(tl); + Fc(tl, 1, ") && (\n"); + L(tl, Cond_2(tl)); + } + Fc(tl, 1, ")\n"); +} + +static void +Cond_0(struct tokenlist *tl) +{ + + Fc(tl, 1, "(\n"); + L(tl, Cond_1(tl)); + while (tl->t->tok == T_COR) { + vcc_NextToken(tl); + Fc(tl, 1, ") || (\n"); + L(tl, Cond_1(tl)); + } + Fc(tl, 1, ")\n"); +} + +static void +Conditional(struct tokenlist *tl) +{ + + ExpectErr(tl, '('); + vcc_NextToken(tl); + Fc(tl, 1, "(\n"); + L(tl, Cond_0(tl)); + ERRCHK(tl); + Fc(tl, 1, ")\n"); + ExpectErr(tl, ')'); + vcc_NextToken(tl); +} + +/*--------------------------------------------------------------------*/ + +static void +IfStmt(struct tokenlist *tl) +{ + + ExpectErr(tl, T_IF); + Fc(tl, 1, "if \n"); + vcc_NextToken(tl); + L(tl, Conditional(tl)); + ERRCHK(tl); + L(tl, Compound(tl)); + ERRCHK(tl); + while (1) { + switch (tl->t->tok) { + case T_ELSE: + vcc_NextToken(tl); + if (tl->t->tok != T_IF) { + Fc(tl, 1, "else \n"); + L(tl, Compound(tl)); + ERRCHK(tl); + return; + } + /* FALLTHROUGH */ + case T_ELSEIF: + case T_ELSIF: + Fc(tl, 1, "else if \n"); + vcc_NextToken(tl); + L(tl, Conditional(tl)); + ERRCHK(tl); + L(tl, Compound(tl)); + ERRCHK(tl); + break; + default: + C(tl, ";"); + return; + } + } +} + +/*--------------------------------------------------------------------*/ + +static void +Action(struct tokenlist *tl) +{ + unsigned a; + struct var *vp; + struct token *at; + + at = tl->t; + vcc_NextToken(tl); + switch (at->tok) { + case T_NO_NEW_CACHE: + Fc(tl, 1, "VCL_no_new_cache(sp);\n"); + return; + case T_NO_CACHE: + Fc(tl, 1, "VCL_no_cache(sp);\n"); + return; +#define VCL_RET_MAC(a,b,c,d) case T_##b: \ + Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ + tl->curproc->returns |= VCL_RET_##b; \ + tl->curproc->returnt[d] = at; \ + return; +#include "vcl_returns.h" +#undef VCL_RET_MAC + case T_ERROR: + if (tl->t->tok == CNUM) + a = UintVal(tl); + else + a = 0; + Fc(tl, 1, "VRT_error(sp, %u", a); + if (tl->t->tok == CSTR) { + Fc(tl, 0, ", %.*s", PF(tl->t)); + vcc_NextToken(tl); + } else { + Fc(tl, 0, ", (const char *)0"); + } + Fc(tl, 0, ");\n"); + Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n"); + return; + case T_SWITCH_CONFIG: + ExpectErr(tl, ID); + Fc(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t)); + vcc_NextToken(tl); + return; + case T_CALL: + ExpectErr(tl, ID); + AddCall(tl, tl->t); + AddRef(tl, tl->t, R_FUNC); + Fc(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); + Fc(tl, 1, "\treturn (1);\n"); + vcc_NextToken(tl); + return; + case T_REWRITE: + ExpectErr(tl, CSTR); + Fc(tl, 1, "VCL_rewrite(%.*s", PF(tl->t)); + vcc_NextToken(tl); + ExpectErr(tl, CSTR); + Fc(tl, 0, ", %.*s);\n", PF(tl->t)); + vcc_NextToken(tl); + return; + case T_SET: + ExpectErr(tl, VAR); + vp = FindVar(tl, tl->t, vcc_vars); + ERRCHK(tl); + assert(vp != NULL); + Fc(tl, 1, "%s", vp->lname); + vcc_NextToken(tl); + switch (vp->fmt) { + case INT: + case SIZE: + case RATE: + case TIME: + case FLOAT: + if (tl->t->tok != '=') + Fc(tl, 0, "%s %c ", vp->rname, *tl->t->b); + a = tl->t->tok; + vcc_NextToken(tl); + if (a == T_MUL || a == T_DIV) + Fc(tl, 0, "%g", DoubleVal(tl)); + else if (vp->fmt == TIME) + TimeVal(tl); + else if (vp->fmt == SIZE) + SizeVal(tl); + else if (vp->fmt == RATE) + RateVal(tl); + else + Fc(tl, 0, "%g", DoubleVal(tl)); + Fc(tl, 0, ");\n"); + break; +#if 0 /* XXX: enable if we find a legit use */ + case IP: + if (tl->t->tok == '=') { + vcc_NextToken(tl); + u = vcc_IpVal(tl); + Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n", + u, + (u >> 24) & 0xff, + (u >> 16) & 0xff, + (u >> 8) & 0xff, + u & 0xff); + break; + } + vsb_printf(tl->sb, "Illegal assignment operator "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, + " only '=' is legal for IP numbers\n"); + vcc_ErrWhere(tl, tl->t); + return; +#endif + case BACKEND: + if (tl->t->tok == '=') { + vcc_NextToken(tl); + AddRef(tl, tl->t, R_BACKEND); + Fc(tl, 0, "VGC_backend_%.*s", PF(tl->t)); + vcc_NextToken(tl); + Fc(tl, 0, ");\n"); + break; + } + vsb_printf(tl->sb, "Illegal assignment operator "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, + " only '=' is legal for backend\n"); + vcc_ErrWhere(tl, tl->t); + return; + default: + vsb_printf(tl->sb, + "Assignments not possible for '%s'\n", vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + return; + default: + vsb_printf(tl->sb, "Expected action, 'if' or '}'\n"); + vcc_ErrWhere(tl, at); + return; + } +} + +/*--------------------------------------------------------------------*/ + +static void +Compound(struct tokenlist *tl) +{ + + ExpectErr(tl, '{'); + Fc(tl, 1, "{\n"); + tl->indent += INDENT; + C(tl, ";"); + vcc_NextToken(tl); + while (1) { + ERRCHK(tl); + switch (tl->t->tok) { + case '{': + Compound(tl); + break; + case T_IF: + IfStmt(tl); + break; + case '}': + vcc_NextToken(tl); + tl->indent -= INDENT; + Fc(tl, 1, "}\n"); + return; + case EOI: + vsb_printf(tl->sb, + "End of input while in compound statement\n"); + tl->err = 1; + return; + default: + Action(tl); + ERRCHK(tl); + ExpectErr(tl, ';'); + vcc_NextToken(tl); + break; + } + } +} + +/*--------------------------------------------------------------------*/ + +static const char * +CheckHostPort(const char *host, const char *port) +{ + struct addrinfo *res, hint; + int error; + + memset(&hint, 0, sizeof hint); + hint.ai_family = PF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, port, &hint, &res); + if (error) + return (gai_strerror(error)); + freeaddrinfo(res); + return (NULL); +} + +static void +Backend(struct tokenlist *tl) +{ + unsigned a; + struct var *vp; + struct token *t_be = NULL; + struct token *t_host = NULL; + struct token *t_port = NULL; + const char *ep; + + vcc_NextToken(tl); + ExpectErr(tl, ID); + t_be = tl->t; + AddDef(tl, tl->t, R_BACKEND); + if (tl->nbackend == 0) + AddRef(tl, tl->t, R_BACKEND); + Fh(tl, 1, "#define VGC_backend_%.*s (VCL_conf.backend[%d])\n", + PF(tl->t), tl->nbackend); + Fc(tl, 0, "\n"); + Fc(tl, 0, "static void\n"); + Fc(tl, 1, "VGC_init_backend_%.*s (void)\n", PF(tl->t)); + Fc(tl, 1, "{\n"); + Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%.*s;\n", PF(tl->t)); + Fc(tl, 1, "\n"); + Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%.*s\");\n", PF(tl->t)); + vcc_NextToken(tl); + ExpectErr(tl, '{'); + vcc_NextToken(tl); + while (1) { + if (tl->t->tok == '}') + break; + ExpectErr(tl, T_SET); + vcc_NextToken(tl); + ExpectErr(tl, VAR); + vp = FindVar(tl, tl->t, vcc_be_vars); + ERRCHK(tl); + assert(vp != NULL); + vcc_NextToken(tl); + ExpectErr(tl, '='); + vcc_NextToken(tl); + switch (vp->fmt) { + case HOSTNAME: + ExpectErr(tl, CSTR); + t_host = tl->t; + Fc(tl, 1, "\t%s ", vp->lname); + EncToken(tl->fc, t_host); + Fc(tl, 0, ");\n"); + vcc_NextToken(tl); + break; + case PORTNAME: + ExpectErr(tl, CSTR); + t_port = tl->t; + Fc(tl, 1, "\t%s ", vp->lname); + EncToken(tl->fc, t_port); + Fc(tl, 0, ");\n"); + vcc_NextToken(tl); + break; +#if 0 + case INT: + case SIZE: + case RATE: + case FLOAT: +#endif + case TIME: + Fc(tl, 1, "\t%s ", vp->lname); + a = tl->t->tok; + if (a == T_MUL || a == T_DIV) + Fc(tl, 0, "%g", DoubleVal(tl)); + else if (vp->fmt == TIME) + TimeVal(tl); + else if (vp->fmt == SIZE) + SizeVal(tl); + else if (vp->fmt == RATE) + RateVal(tl); + else + Fc(tl, 0, "%g", DoubleVal(tl)); + Fc(tl, 0, ");\n"); + break; + default: + vsb_printf(tl->sb, + "Assignments not possible for '%s'\n", vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + ExpectErr(tl, ';'); + vcc_NextToken(tl); + } + ExpectErr(tl, '}'); + if (t_host == NULL) { + vsb_printf(tl->sb, "Backend '%.*s' has no hostname\n", + PF(t_be)); + vcc_ErrWhere(tl, tl->t); + return; + } + ep = CheckHostPort(t_host->dec, "80"); + if (ep != NULL) { + vsb_printf(tl->sb, "Backend '%.*s': %s\n", PF(t_be), ep); + vcc_ErrWhere(tl, t_host); + return; + } + if (t_port != NULL) { + ep = CheckHostPort(t_host->dec, t_port->dec); + if (ep != NULL) { + vsb_printf(tl->sb, + "Backend '%.*s': %s\n", PF(t_be), ep); + vcc_ErrWhere(tl, t_port); + return; + } + } + + vcc_NextToken(tl); + Fc(tl, 1, "}\n"); + Fc(tl, 0, "\n"); + Fi(tl, 0, "\tVGC_init_backend_%.*s();\n", PF(t_be)); + Ff(tl, 0, "\tVRT_fini_backend(VGC_backend_%.*s);\n", PF(t_be)); + tl->nbackend++; +} + +/*--------------------------------------------------------------------*/ + +static void +Function(struct tokenlist *tl) +{ + struct token *tn; + + vcc_NextToken(tl); + ExpectErr(tl, ID); + tl->curproc = AddProc(tl, tl->t, 1); + tl->curproc->exists++; + tn = tl->t; + AddDef(tl, tl->t, R_FUNC); + Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", + PF(tl->t)); + Fc(tl, 1, "static int\n"); + Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t)); + vcc_NextToken(tl); + tl->indent += INDENT; + Fc(tl, 1, "{\n"); + L(tl, Compound(tl)); + if (IsMethod(tn) == 1) { + Fc(tl, 1, "VGC_function_default_%.*s(sp);\n", PF(tn)); + } + Fc(tl, 1, "}\n"); + tl->indent -= INDENT; + Fc(tl, 0, "\n"); +} + +/*-------------------------------------------------------------------- + * Top level of parser, recognize: + * Function definitions + * Backend definitions + * End of input + */ + +void +vcc_Parse(struct tokenlist *tl) +{ + + while (tl->t->tok != EOI) { + ERRCHK(tl); + switch (tl->t->tok) { + case T_ACL: + vcc_Acl(tl); + break; + case T_SUB: + Function(tl); + break; + case T_BACKEND: + Backend(tl); + break; + case EOI: + break; + default: + vsb_printf(tl->sb, + "Expected 'acl', 'sub' or 'backend', found "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, " at\n"); + vcc_ErrWhere(tl, tl->t); + return; + } + } +} From phk at projects.linpro.no Sat Mar 24 22:09:53 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 24 Mar 2007 23:09:53 +0100 (CET) Subject: r1284 - in trunk/varnish-cache: bin/varnishd include lib/libvcl Message-ID: <20070324220953.EC0741EC2B1@projects.linpro.no> Author: phk Date: 2007-03-24 23:09:53 +0100 (Sat, 24 Mar 2007) New Revision: 1284 Modified: trunk/varnish-cache/bin/varnishd/mgt_vcc.c trunk/varnish-cache/include/vcl_returns.h trunk/varnish-cache/lib/libvcl/vcc_compile.c trunk/varnish-cache/lib/libvcl/vcc_compile.h trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcc_parse.c Log: Twist the compiler logic around a bit. Concatenate all definitions of the method functions into one instance of the function: sub vcl_pipe { foo; } sub vcl_pipe { bar; } is now the same as sub vcl_pipe { foo; bar; } This avoids all the magic related to the default functions and hopefully makes the newly introduced "include" facility much more useful. Modified: trunk/varnish-cache/bin/varnishd/mgt_vcc.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_vcc.c 2007-03-24 21:01:43 UTC (rev 1283) +++ trunk/varnish-cache/bin/varnishd/mgt_vcc.c 2007-03-24 22:09:53 UTC (rev 1284) @@ -66,7 +66,7 @@ /* keep this in synch with man/vcl.7 */ static const char *default_vcl = - "sub default_vcl_recv {\n" + "sub vcl_recv {\n" " if (req.request != \"GET\" && req.request != \"HEAD\") {\n" " pipe;\n" " }\n" @@ -79,30 +79,30 @@ " lookup;\n" "}\n" "\n" - "sub default_vcl_pipe {\n" + "sub vcl_pipe {\n" " pipe;\n" "}\n" "\n" - "sub default_vcl_pass {\n" + "sub vcl_pass {\n" " pass;\n" "}\n" "\n" - "sub default_vcl_hash {\n" + "sub vcl_hash {\n" " hash;\n" "}\n" "\n" - "sub default_vcl_hit {\n" + "sub vcl_hit {\n" " if (!obj.cacheable) {\n" " pass;\n" " }\n" " deliver;\n" "}\n" "\n" - "sub default_vcl_miss {\n" + "sub vcl_miss {\n" " fetch;\n" "}\n" "\n" - "sub default_vcl_fetch {\n" + "sub vcl_fetch {\n" " if (!obj.valid) {\n" " error;\n" " }\n" @@ -114,7 +114,7 @@ " }\n" " insert;\n" "}\n" - "sub default_vcl_timeout {\n" + "sub vcl_timeout {\n" " discard;\n" "}\n"; Modified: trunk/varnish-cache/include/vcl_returns.h =================================================================== --- trunk/varnish-cache/include/vcl_returns.h 2007-03-24 21:01:43 UTC (rev 1283) +++ trunk/varnish-cache/include/vcl_returns.h 2007-03-24 22:09:53 UTC (rev 1284) @@ -41,3 +41,4 @@ VCL_MET_MAC(fetch,FETCH,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_INSERT)) VCL_MET_MAC(timeout,TIMEOUT,(VCL_RET_FETCH|VCL_RET_DISCARD)) #endif +#define N_METHODS 8 Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-24 21:01:43 UTC (rev 1283) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-24 22:09:53 UTC (rev 1284) @@ -87,7 +87,7 @@ static struct method method_tab[] = { #define VCL_RET_MAC(l,U,b,n) -#define VCL_MET_MAC(l,U,m) { "vcl_"#l, "default_vcl_"#l, m }, +#define VCL_MET_MAC(l,U,m) { "vcl_"#l, m }, #include "vcl_returns.h" #undef VCL_MET_MAC #undef VCL_RET_MAC @@ -96,8 +96,22 @@ /*--------------------------------------------------------------------*/ -const char *vcc_default_vcl_b, *vcc_default_vcl_e; +static const char *vcc_default_vcl_b, *vcc_default_vcl_e; +/*--------------------------------------------------------------------*/ + +int +IsMethod(struct token *t) +{ + struct method *m; + + for(m = method_tab; m->name != NULL; m++) { + if (vcc_IdIs(t, m->name)) + return (m - method_tab); + } + return (-1); +} + /*-------------------------------------------------------------------- * Printf output to the two vsbs, possibly indented */ @@ -115,6 +129,19 @@ } void +Fb(struct tokenlist *tl, int indent, const char *fmt, ...) +{ + va_list ap; + + assert(tl->fb != NULL); + if (indent) + vsb_printf(tl->fb, "%*.*s", tl->indent, tl->indent, ""); + va_start(ap, fmt); + vsb_vprintf(tl->fb, fmt, ap); + va_end(ap); +} + +void Fc(struct tokenlist *tl, int indent, const char *fmt, ...) { va_list ap; @@ -152,8 +179,8 @@ /*--------------------------------------------------------------------*/ -void -EncString(struct vsb *sb, const char *b, const char *e) +static void +EncString(struct vsb *sb, const char *b, const char *e, int mode) { if (e == NULL) @@ -166,7 +193,11 @@ case '"': vsb_printf(sb, "\\%c", *b); break; - case '\n': vsb_printf(sb, "\\n"); break; + case '\n': + vsb_printf(sb, "\\n"); + if (mode) + vsb_printf(sb, "\"\n\t\""); + break; case '\t': vsb_printf(sb, "\\t"); break; case '\r': vsb_printf(sb, "\\r"); break; case ' ': vsb_printf(sb, " "); break; @@ -186,7 +217,7 @@ { assert(t->tok == CSTR); - EncString(sb, t->dec, NULL); + EncString(sb, t->dec, NULL, 0); } /*-------------------------------------------------------------------- @@ -212,20 +243,6 @@ return (r); } -static int -FindRefStr(struct tokenlist *tl, const char *s, enum ref_type type) -{ - struct ref *r; - - TAILQ_FOREACH(r, &tl->refs, list) { - if (r->type != type) - continue; - if (vcc_IdIs(r->name, s)) - return (1); - } - return (0); -} - void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type) { @@ -233,20 +250,6 @@ FindRef(tl, t, type)->refcnt++; } -static void -AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type) -{ - struct token *t; - - t = calloc(sizeof *t, 1); - assert(t != NULL); - t->b = s; - t->e = strchr(s, '\0'); - t->tok = METHOD; - AddRef(tl, t, type); - /* XXX: possibly leaking t */ -} - void AddDef(struct tokenlist *tl, struct token *t, enum ref_type type) { @@ -407,8 +410,6 @@ TAILQ_FOREACH(p, &tl->procs, list) { for(m = method_tab; m->name != NULL; m++) { - if (vcc_IdIs(p->name, m->defname)) - p->called = 1; if (vcc_IdIs(p->name, m->name)) break; } @@ -564,15 +565,18 @@ Fc(tl, 0, "\nconst char *srcname[%u] = {\n", tl->nsources); TAILQ_FOREACH(sp, &tl->sources, list) { Fc(tl, 0, "\t"); - EncString(tl->fc, sp->name, NULL); + EncString(tl->fc, sp->name, NULL, 0); Fc(tl, 0, ",\n"); } Fc(tl, 0, "};\n"); Fc(tl, 0, "\nconst char *srcbody[%u] = {\n", tl->nsources); TAILQ_FOREACH(sp, &tl->sources, list) { + Fc(tl, 0, " /* "); + EncString(tl->fc, sp->name, NULL, 0); + Fc(tl, 0, "*/\n"); Fc(tl, 0, "\t"); - EncString(tl->fc, sp->b, sp->e); + EncString(tl->fc, sp->b, sp->e, 1); Fc(tl, 0, ",\n"); } Fc(tl, 0, "};\n"); @@ -589,13 +593,7 @@ Fc(tl, 0, "\t.srcbody = srcbody,\n"); #define VCL_RET_MAC(l,u,b,n) #define VCL_MET_MAC(l,u,b) \ - if (FindRefStr(tl, "vcl_" #l, R_FUNC)) { \ - Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); \ - AddRefStr(tl, "vcl_" #l, R_FUNC); \ - } else { \ - Fc(tl, 0, "\t." #l "_func = VGC_function_default_vcl_" #l ",\n"); \ - } \ - AddRefStr(tl, "default_vcl_" #l, R_FUNC); + Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); #include "vcl_returns.h" #undef VCL_MET_MAC #undef VCL_RET_MAC @@ -744,11 +742,10 @@ assert(tl->ff != NULL); /* body code of methods */ -#define VCL_MET_MAC(l,U,m) \ - tl->fm_##l = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ - assert(tl->fm_##l != NULL); -#include "vcl_returns.h" -#undef VCL_MET_MAC + for (i = 0; i < N_METHODS; i++) { + tl->fm[i] = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ + assert(tl->fm[i] != NULL); + } Fh(tl, 0, "extern struct VCL_conf VCL_conf;\n"); @@ -779,6 +776,18 @@ Consistency(tl); if (tl->err) goto done; + + /* Emit method functions */ + for (i = 0; i < N_METHODS; i++) { + Fc(tl, 1, "static int\n"); + Fc(tl, 1, "VGC_function_%s (struct sess *sp)\n", + method_tab[i].name); + vsb_finish(tl->fm[i]); + Fc(tl, 1, "{\n"); + Fc(tl, 1, "%s", vsb_data(tl->fm[i])); + Fc(tl, 1, "}\n\n"); + } + LocTable(tl); Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n"); @@ -824,9 +833,8 @@ } done: -#define VCL_MET_MAC(l,U,m) vsb_delete(tl->fm_##l); -#include "vcl_returns.h" -#undef VCL_MET_MAC + for (i = 0; i < N_METHODS; i++) + vsb_delete(tl->fm[i]); /* Free References */ while (!TAILQ_EMPTY(&tl->refs)) { Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-24 21:01:43 UTC (rev 1283) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-24 22:09:53 UTC (rev 1284) @@ -62,16 +62,15 @@ struct token *t; int indent; unsigned cnt; - struct vsb *fc, *fh, *fi, *ff; -#define VCL_MET_MAC(l,U,m) struct vsb *fm_##l; -#include "vcl_returns.h" -#undef VCL_MET_MAC + struct vsb *fc, *fh, *fi, *ff, *fb; + struct vsb *fm[N_METHODS]; TAILQ_HEAD(, ref) refs; struct vsb *sb; int err; int nbackend; TAILQ_HEAD(, proc) procs; struct proc *curproc; + struct proc *mprocs[N_METHODS]; unsigned recnt; }; @@ -115,7 +114,6 @@ struct method { const char *name; - const char *defname; unsigned returns; }; @@ -145,19 +143,19 @@ void vcc_Cond_Ip(struct var *vp, struct tokenlist *tl); /* vcc_compile.c */ -extern const char *vcc_default_vcl_b, *vcc_default_vcl_e; void Fh(struct tokenlist *tl, int indent, const char *fmt, ...); void Fc(struct tokenlist *tl, int indent, const char *fmt, ...); +void Fb(struct tokenlist *tl, int indent, const char *fmt, ...); void Fi(struct tokenlist *tl, int indent, const char *fmt, ...); void Ff(struct tokenlist *tl, int indent, const char *fmt, ...); unsigned UintVal(struct tokenlist *tl); void AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); void EncToken(struct vsb *sb, struct token *t); -void EncString(struct vsb *sb, const char *b, const char *e); struct var *FindVar(struct tokenlist *tl, struct token *t, struct var *vl); void AddCall(struct tokenlist *tl, struct token *t); struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); +int IsMethod(struct token *t); /* vcc_obj.c */ extern struct var vcc_be_vars[]; Modified: trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-24 21:01:43 UTC (rev 1283) +++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-24 22:09:53 UTC (rev 1284) @@ -185,6 +185,7 @@ puts $for "#endif" puts $for "" puts $for "#ifdef VCL_MET_MAC" +set u 0 foreach m $methods { puts -nonewline $for "VCL_MET_MAC([lindex $m 0]" puts -nonewline $for ",[string toupper [lindex $m 0]]" @@ -195,8 +196,10 @@ } puts -nonewline $for ")" puts $for ")" + incr u } puts $for "#endif" +puts $for "#define N_METHODS $u" close $for #---------------------------------------------------------------------- Modified: trunk/varnish-cache/lib/libvcl/vcc_parse.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-03-24 21:01:43 UTC (rev 1283) +++ trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-03-24 22:09:53 UTC (rev 1284) @@ -85,20 +85,10 @@ #include "vrt.h" #include "libvcl.h" -static struct method method_tab[] = { -#define VCL_RET_MAC(l,U,b,n) -#define VCL_MET_MAC(l,U,m) { "vcl_"#l, "default_vcl_"#l, m }, -#include "vcl_returns.h" -#undef VCL_MET_MAC -#undef VCL_RET_MAC - { NULL, 0U } -}; - /*--------------------------------------------------------------------*/ static void Compound(struct tokenlist *tl); static void Cond_0(struct tokenlist *tl); -const char *vcc_default_vcl_b, *vcc_default_vcl_e; /*--------------------------------------------------------------------*/ @@ -109,26 +99,10 @@ } while (0) #define C(tl, sep) do { \ - Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \ + Fb(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \ tl->t->cnt = tl->cnt; \ } while (0) -/*--------------------------------------------------------------------*/ - -static int -IsMethod(struct token *t) -{ - struct method *m; - - for(m = method_tab; m->name != NULL; m++) { - if (vcc_IdIs(t, m->defname)) - return (2); - if (vcc_IdIs(t, m->name)) - return (1); - } - return (0); -} - /*-------------------------------------------------------------------- * Recognize and convert units of time, return seconds. */ @@ -264,7 +238,7 @@ v = DoubleVal(tl); ExpectErr(tl, ID); sc = TimeUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); + Fb(tl, 0, "(%g * %g)", v, sc); } static void @@ -275,7 +249,7 @@ v = DoubleVal(tl); ExpectErr(tl, ID); sc = SizeUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); + Fb(tl, 0, "(%g * %g)", v, sc); } static void @@ -286,7 +260,7 @@ v = DoubleVal(tl); ExpectErr(tl, ID); sc = RateUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); + Fb(tl, 0, "(%g * %g)", v, sc); } /*--------------------------------------------------------------------*/ @@ -303,7 +277,7 @@ } sprintf(buf, "VGC_re_%u", tl->recnt++); - Fc(tl, 1, "VRT_re_match(%s, %s)\n", str, buf); + Fb(tl, 1, "VRT_re_match(%s, %s)\n", str, buf); Fh(tl, 0, "void *%s;\n", buf); Fi(tl, 0, "\tVRT_re_init(&%s, ",buf); EncToken(tl->fi, re); @@ -327,16 +301,16 @@ break; case T_EQ: case T_NEQ: - Fc(tl, 1, "%sstrcmp(%s, ", + Fb(tl, 1, "%sstrcmp(%s, ", tl->t->tok == T_EQ ? "!" : "", vp->rname); vcc_NextToken(tl); ExpectErr(tl, CSTR); - EncToken(tl->fc, tl->t); - Fc(tl, 0, ")\n"); + EncToken(tl->fb, tl->t); + Fb(tl, 0, ")\n"); vcc_NextToken(tl); break; default: - Fc(tl, 1, "%s != (void*)0", vp->rname); + Fb(tl, 1, "%s != (void*)0\n", vp->rname); break; } } @@ -345,7 +319,7 @@ Cond_Int(struct var *vp, struct tokenlist *tl) { - Fc(tl, 1, "%s ", vp->rname); + Fb(tl, 1, "%s ", vp->rname); switch (tl->t->tok) { case T_EQ: case T_NEQ: @@ -353,7 +327,7 @@ case T_GEQ: case '>': case '<': - Fc(tl, 0, "%.*s ", PF(tl->t)); + Fb(tl, 0, "%.*s ", PF(tl->t)); vcc_NextToken(tl); switch(vp->fmt) { case TIME: @@ -361,7 +335,7 @@ break; case INT: ExpectErr(tl, CNUM); - Fc(tl, 0, "%.*s ", PF(tl->t)); + Fb(tl, 0, "%.*s ", PF(tl->t)); vcc_NextToken(tl); break; case SIZE: @@ -374,7 +348,7 @@ vcc_ErrWhere(tl, tl->t); return; } - Fc(tl, 0, "\n"); + Fb(tl, 0, "\n"); break; default: vsb_printf(tl->sb, "Illegal condition "); @@ -391,14 +365,14 @@ Cond_Bool(struct var *vp, struct tokenlist *tl) { - Fc(tl, 1, "%s\n", vp->rname); + Fb(tl, 1, "%s\n", vp->rname); } static void Cond_Backend(struct var *vp, struct tokenlist *tl) { - Fc(tl, 1, "%s\n", vp->rname); + Fb(tl, 1, "%s\n", vp->rname); } static void @@ -408,10 +382,10 @@ C(tl, ","); if (tl->t->tok == '!') { - Fc(tl, 1, "!(\n"); + Fb(tl, 1, "!(\n"); vcc_NextToken(tl); } else { - Fc(tl, 1, "(\n"); + Fb(tl, 1, "(\n"); } if (tl->t->tok == '(') { vcc_NextToken(tl); @@ -448,35 +422,35 @@ vcc_ErrWhere(tl, tl->t); return; } - Fc(tl, 1, ")\n"); + Fb(tl, 1, ")\n"); } static void Cond_1(struct tokenlist *tl) { - Fc(tl, 1, "(\n"); + Fb(tl, 1, "(\n"); L(tl, Cond_2(tl)); while (tl->t->tok == T_CAND) { vcc_NextToken(tl); - Fc(tl, 1, ") && (\n"); + Fb(tl, 1, ") && (\n"); L(tl, Cond_2(tl)); } - Fc(tl, 1, ")\n"); + Fb(tl, 1, ")\n"); } static void Cond_0(struct tokenlist *tl) { - Fc(tl, 1, "(\n"); + Fb(tl, 1, "(\n"); L(tl, Cond_1(tl)); while (tl->t->tok == T_COR) { vcc_NextToken(tl); - Fc(tl, 1, ") || (\n"); + Fb(tl, 1, ") || (\n"); L(tl, Cond_1(tl)); } - Fc(tl, 1, ")\n"); + Fb(tl, 1, ")\n"); } static void @@ -485,10 +459,10 @@ ExpectErr(tl, '('); vcc_NextToken(tl); - Fc(tl, 1, "(\n"); + Fb(tl, 1, "(\n"); L(tl, Cond_0(tl)); ERRCHK(tl); - Fc(tl, 1, ")\n"); + Fb(tl, 1, ")\n"); ExpectErr(tl, ')'); vcc_NextToken(tl); } @@ -500,7 +474,7 @@ { ExpectErr(tl, T_IF); - Fc(tl, 1, "if \n"); + Fb(tl, 1, "if \n"); vcc_NextToken(tl); L(tl, Conditional(tl)); ERRCHK(tl); @@ -511,7 +485,7 @@ case T_ELSE: vcc_NextToken(tl); if (tl->t->tok != T_IF) { - Fc(tl, 1, "else \n"); + Fb(tl, 1, "else \n"); L(tl, Compound(tl)); ERRCHK(tl); return; @@ -519,7 +493,7 @@ /* FALLTHROUGH */ case T_ELSEIF: case T_ELSIF: - Fc(tl, 1, "else if \n"); + Fb(tl, 1, "else if \n"); vcc_NextToken(tl); L(tl, Conditional(tl)); ERRCHK(tl); @@ -546,13 +520,13 @@ vcc_NextToken(tl); switch (at->tok) { case T_NO_NEW_CACHE: - Fc(tl, 1, "VCL_no_new_cache(sp);\n"); + Fb(tl, 1, "VCL_no_new_cache(sp);\n"); return; case T_NO_CACHE: - Fc(tl, 1, "VCL_no_cache(sp);\n"); + Fb(tl, 1, "VCL_no_cache(sp);\n"); return; #define VCL_RET_MAC(a,b,c,d) case T_##b: \ - Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ + Fb(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ tl->curproc->returns |= VCL_RET_##b; \ tl->curproc->returnt[d] = at; \ return; @@ -563,35 +537,35 @@ a = UintVal(tl); else a = 0; - Fc(tl, 1, "VRT_error(sp, %u", a); + Fb(tl, 1, "VRT_error(sp, %u", a); if (tl->t->tok == CSTR) { - Fc(tl, 0, ", %.*s", PF(tl->t)); + Fb(tl, 0, ", %.*s", PF(tl->t)); vcc_NextToken(tl); } else { - Fc(tl, 0, ", (const char *)0"); + Fb(tl, 0, ", (const char *)0"); } - Fc(tl, 0, ");\n"); - Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n"); + Fb(tl, 0, ");\n"); + Fb(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n"); return; case T_SWITCH_CONFIG: ExpectErr(tl, ID); - Fc(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t)); + Fb(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t)); vcc_NextToken(tl); return; case T_CALL: ExpectErr(tl, ID); AddCall(tl, tl->t); AddRef(tl, tl->t, R_FUNC); - Fc(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); - Fc(tl, 1, "\treturn (1);\n"); + Fb(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); + Fb(tl, 1, "\treturn (1);\n"); vcc_NextToken(tl); return; case T_REWRITE: ExpectErr(tl, CSTR); - Fc(tl, 1, "VCL_rewrite(%.*s", PF(tl->t)); + Fb(tl, 1, "VCL_rewrite(%.*s", PF(tl->t)); vcc_NextToken(tl); ExpectErr(tl, CSTR); - Fc(tl, 0, ", %.*s);\n", PF(tl->t)); + Fb(tl, 0, ", %.*s);\n", PF(tl->t)); vcc_NextToken(tl); return; case T_SET: @@ -599,7 +573,7 @@ vp = FindVar(tl, tl->t, vcc_vars); ERRCHK(tl); assert(vp != NULL); - Fc(tl, 1, "%s", vp->lname); + Fb(tl, 1, "%s", vp->lname); vcc_NextToken(tl); switch (vp->fmt) { case INT: @@ -608,11 +582,11 @@ case TIME: case FLOAT: if (tl->t->tok != '=') - Fc(tl, 0, "%s %c ", vp->rname, *tl->t->b); + Fb(tl, 0, "%s %c ", vp->rname, *tl->t->b); a = tl->t->tok; vcc_NextToken(tl); if (a == T_MUL || a == T_DIV) - Fc(tl, 0, "%g", DoubleVal(tl)); + Fb(tl, 0, "%g", DoubleVal(tl)); else if (vp->fmt == TIME) TimeVal(tl); else if (vp->fmt == SIZE) @@ -620,15 +594,15 @@ else if (vp->fmt == RATE) RateVal(tl); else - Fc(tl, 0, "%g", DoubleVal(tl)); - Fc(tl, 0, ");\n"); + Fb(tl, 0, "%g", DoubleVal(tl)); + Fb(tl, 0, ");\n"); break; #if 0 /* XXX: enable if we find a legit use */ case IP: if (tl->t->tok == '=') { vcc_NextToken(tl); u = vcc_IpVal(tl); - Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n", + Fb(tl, 0, "= %uU; /* %u.%u.%u.%u */\n", u, (u >> 24) & 0xff, (u >> 16) & 0xff, @@ -647,9 +621,9 @@ if (tl->t->tok == '=') { vcc_NextToken(tl); AddRef(tl, tl->t, R_BACKEND); - Fc(tl, 0, "VGC_backend_%.*s", PF(tl->t)); + Fb(tl, 0, "VGC_backend_%.*s", PF(tl->t)); vcc_NextToken(tl); - Fc(tl, 0, ");\n"); + Fb(tl, 0, ");\n"); break; } vsb_printf(tl->sb, "Illegal assignment operator "); @@ -679,7 +653,7 @@ { ExpectErr(tl, '{'); - Fc(tl, 1, "{\n"); + Fb(tl, 1, "{\n"); tl->indent += INDENT; C(tl, ";"); vcc_NextToken(tl); @@ -695,7 +669,7 @@ case '}': vcc_NextToken(tl); tl->indent -= INDENT; - Fc(tl, 1, "}\n"); + Fb(tl, 1, "}\n"); return; case EOI: vsb_printf(tl->sb, @@ -853,28 +827,40 @@ static void Function(struct tokenlist *tl) { - struct token *tn; + int m; vcc_NextToken(tl); ExpectErr(tl, ID); - tl->curproc = AddProc(tl, tl->t, 1); - tl->curproc->exists++; - tn = tl->t; - AddDef(tl, tl->t, R_FUNC); - Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", - PF(tl->t)); - Fc(tl, 1, "static int\n"); - Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t)); + + m = IsMethod(tl->t); + if (m != -1) { + assert(m < N_METHODS); + tl->fb = tl->fm[m]; + if (tl->mprocs[m] == NULL) { + tl->mprocs[m] = AddProc(tl, tl->t, 1); + tl->mprocs[m]->exists++; + AddDef(tl, tl->t, R_FUNC); + AddRef(tl, tl->t, R_FUNC); + } + tl->curproc = tl->mprocs[m]; + } else { + tl->fb = tl->fc; + tl->curproc = AddProc(tl, tl->t, 1); + tl->curproc->exists++; + AddDef(tl, tl->t, R_FUNC); + Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", + PF(tl->t)); + Fc(tl, 1, "static int\n"); + Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t)); + } vcc_NextToken(tl); tl->indent += INDENT; - Fc(tl, 1, "{\n"); + Fb(tl, 1, "{\n"); L(tl, Compound(tl)); - if (IsMethod(tn) == 1) { - Fc(tl, 1, "VGC_function_default_%.*s(sp);\n", PF(tn)); - } - Fc(tl, 1, "}\n"); + Fb(tl, 1, "}\n"); tl->indent -= INDENT; - Fc(tl, 0, "\n"); + Fb(tl, 0, "\n"); + tl->fb = NULL; } /*-------------------------------------------------------------------- From des at projects.linpro.no Wed Mar 28 08:11:28 2007 From: des at projects.linpro.no (des at projects.linpro.no) Date: Wed, 28 Mar 2007 10:11:28 +0200 (CEST) Subject: r1285 - trunk/varnish-cache/bin/varnishd Message-ID: <20070328081128.046F81EC2F5@projects.linpro.no> Author: des Date: 2007-03-28 10:11:27 +0200 (Wed, 28 Mar 2007) New Revision: 1285 Modified: trunk/varnish-cache/bin/varnishd/varnishd.1 Log: Actual default max is 1000, not infinity. Modified: trunk/varnish-cache/bin/varnishd/varnishd.1 =================================================================== --- trunk/varnish-cache/bin/varnishd/varnishd.1 2007-03-24 22:09:53 UTC (rev 1284) +++ trunk/varnish-cache/bin/varnishd/varnishd.1 2007-03-28 08:11:27 UTC (rev 1285) @@ -163,7 +163,7 @@ .Pp The default values are 1 for .Ar min , -infinity for +1000 for .Ar max , and 10 for .Ar timeout . From des at linpro.no Wed Mar 28 08:17:20 2007 From: des at linpro.no (Dag-Erling =?iso-8859-1?Q?Sm=F8rgrav?=) Date: Wed, 28 Mar 2007 10:17:20 +0200 Subject: r1280 - trunk/varnish-cache/bin/varnishd In-Reply-To: <20070308100918.707291EC1E7@projects.linpro.no> (phk@projects.linpro.no's message of "Thu, 8 Mar 2007 11:09:18 +0100 (CET)") References: <20070308100918.707291EC1E7@projects.linpro.no> Message-ID: phk at projects.linpro.no writes: > Log: > Make Varnish able to accept connections from multiple sockets by > specifying a whitespace separated list of addresses to -a (or > param.set listen_address). I'd like to change this to a comma-separated list, to avoid quoting on the command line (or perhaps accept both whitespace and commas?) DES -- Dag-Erling Sm?rgrav Senior Software Developer Linpro AS - www.linpro.no From des at linpro.no Wed Mar 28 08:27:37 2007 From: des at linpro.no (Dag-Erling =?iso-8859-1?Q?Sm=F8rgrav?=) Date: Wed, 28 Mar 2007 10:27:37 +0200 Subject: r1277 - in trunk/varnish-cache: bin/varnishd include lib/libvcl In-Reply-To: <20070306224007.8B4451EC45D@projects.linpro.no> (phk@projects.linpro.no's message of "Tue, 6 Mar 2007 23:40:07 +0100 (CET)") References: <20070306224007.8B4451EC45D@projects.linpro.no> Message-ID: phk at projects.linpro.no writes: > Pipe and Pass calls vcl_pipe{} and vcl_pass{} respectively, before > contacting the backend. I havn't quite decided if they should > operate on the request header from the client or the one to the > backend, or both. I'm working on the documentation, and have a couple of questions regarding these. 1) VCL_pipe_method() is never called 2) The return value from VCL_pass_method() is ignored unless it is VCL_RET_ERROR: > -static int > -cnt_passbody(struct sess *sp) > -{ > - > - sp->wrk->acct.pass++; > - AN(sp->vbc); > - PassBody(sp); > - AZ(sp->vbc); > - sp->step = STP_DONE; > + VCL_pass_method(sp); > + if (sp->handling == VCL_RET_ERROR) { > + sp->step = STP_ERROR; > + return (0); > + } > + HSH_Prealloc(sp); > + sp->obj = sp->wrk->nobj; > + sp->wrk->nobj = NULL; > + sp->obj->busy = 1; > + sp->step = STP_FETCH; > return (0); > } 3) The default implementations of vcl_pipe() and vcl_pass() end with "pipe" and "pass", respectively, which one would expect to result in infinite recursion (though we know from 2) that it doesn't) > + "sub default_vcl_pipe {\n" > + " pipe;\n" > + "}\n" > + "\n" > + "sub default_vcl_pass {\n" > + " pass;\n" > + "}\n" 4) What is the "hash" keyword supposed to mean? > + "sub default_vcl_hash {\n" > + " hash;\n" > + "}\n" DES -- Dag-Erling Sm?rgrav Senior Software Developer Linpro AS - www.linpro.no From phk at phk.freebsd.dk Wed Mar 28 08:35:17 2007 From: phk at phk.freebsd.dk (Poul-Henning Kamp) Date: Wed, 28 Mar 2007 08:35:17 +0000 Subject: r1280 - trunk/varnish-cache/bin/varnishd In-Reply-To: Your message of "Wed, 28 Mar 2007 10:17:20 +0200." Message-ID: <1514.1175070917@critter.freebsd.dk> In message , Dag-Erling =?iso-8859-1?Q?Sm=F8rgra v?= writes: >phk at projects.linpro.no writes: >> Log: >> Make Varnish able to accept connections from multiple sockets by >> specifying a whitespace separated list of addresses to -a (or >> param.set listen_address). > >I'd like to change this to a comma-separated list, to avoid quoting on >the command line (or perhaps accept both whitespace and commas?) Let me think about this. I hate to have too many parsing functions around, but we already do commas for storage and hash, so maybe a generic comma parsing function is the solution. -- Poul-Henning Kamp | UNIX since Zilog Zeus 3.20 phk at FreeBSD.ORG | TCP/IP since RFC 956 FreeBSD committer | BSD since 4.3-tahoe Never attribute to malice what can adequately be explained by incompetence. From phk at phk.freebsd.dk Wed Mar 28 08:41:27 2007 From: phk at phk.freebsd.dk (Poul-Henning Kamp) Date: Wed, 28 Mar 2007 08:41:27 +0000 Subject: r1277 - in trunk/varnish-cache: bin/varnishd include lib/libvcl In-Reply-To: Your message of "Wed, 28 Mar 2007 10:27:37 +0200." Message-ID: <1541.1175071287@critter.freebsd.dk> In message , Dag-Erling =?iso-8859-1?Q?Sm=F8rgra v?= writes: >phk at projects.linpro.no writes: >> Pipe and Pass calls vcl_pipe{} and vcl_pass{} respectively, before >> contacting the backend. I havn't quite decided if they should >> operate on the request header from the client or the one to the >> backend, or both. > >I'm working on the documentation, and have a couple of questions >regarding these. > >1) VCL_pipe_method() is never called Not yet, havn't gotten to that yet. Same for the vcl_hash {} as far as I recall. >2) The return value from VCL_pass_method() is ignored unless it is > VCL_RET_ERROR: Only error and pass are valid (see include/vcl_returns.h) The pass and pipe methods are for twapping headers and stuff before hitting the backend. They can only error or continue. >3) The default implementations of vcl_pipe() and vcl_pass() end with > "pipe" and "pass", respectively, which one would expect to result > in infinite recursion (though we know from 2) that it doesn't) No risk. The return action, for instance "pass", is interpreted in context (of the state engine), and as you saw, in this case it really means "go on". >4) What is the "hash" keyword supposed to mean? > >> + "sub default_vcl_hash {\n" >> + " hash;\n" >> + "}\n" Same basic semantics. I don't expect to see the "hash" anywhere but in the default code. The idea for the vcl_hash{} method is to make it possible to control which fields to hash. The default vcl_hash will end up looking somewhat like: sub vcl_hash { hashkey += req.url; hashkey += req.http.Host; hash; } (not sure about syntax yet) -- Poul-Henning Kamp | UNIX since Zilog Zeus 3.20 phk at FreeBSD.ORG | TCP/IP since RFC 956 FreeBSD committer | BSD since 4.3-tahoe Never attribute to malice what can adequately be explained by incompetence. From des at projects.linpro.no Wed Mar 28 09:26:18 2007 From: des at projects.linpro.no (des at projects.linpro.no) Date: Wed, 28 Mar 2007 11:26:18 +0200 (CEST) Subject: r1286 - trunk/varnish-cache/man Message-ID: <20070328092618.6E9E71EC29C@projects.linpro.no> Author: des Date: 2007-03-28 11:26:18 +0200 (Wed, 28 Mar 2007) New Revision: 1286 Modified: trunk/varnish-cache/man/vcl.7 Log: Expand and track recent changes. Modified: trunk/varnish-cache/man/vcl.7 =================================================================== --- trunk/varnish-cache/man/vcl.7 2007-03-28 08:11:27 UTC (rev 1285) +++ trunk/varnish-cache/man/vcl.7 2007-03-28 09:26:18 UTC (rev 1286) @@ -28,7 +28,7 @@ .\" .\" $Id$ .\" -.Dd October 5, 2006 +.Dd March 28, 2007 .Dt VCL 7 .Os .Sh NAME @@ -71,6 +71,11 @@ VCL has .Cm if tests, but no loops. +.Pp +The contents of another VCL file may be inserted at any point in the +code by using the +.Cm include +keyword followed by the name of the other file as a quoted string. .Ss Backend declarations A backend declaration creates and initializes a named backend object: .Bd -literal -offset 4n @@ -123,6 +128,9 @@ .Pp Subroutines in VCL do not take arguments, nor do they return values. .Pp +If multiple subroutines with the same name are defined, they are +concatenated in the order in which the appear in the source. +.Pp To call a subroutine, use the .Cm call keyword followed by the subroutine's name: @@ -130,34 +138,166 @@ call pipe_if_local; .Ed .Pp -There are five special subroutines which hook into the Varnish -workflow: +There are a number of special subroutines which hook into the Varnish +workflow. +These subroutines may inspect and manipulate HTTP headers and various +other aspects of each request, and to a certain extent decide how the +request should be handled. +Each subroutine terminates by calling one of a small number of +keywords which indicates the desired outcome. .Bl -tag -width "vcl_timeout" +.\" vcl_recv .It Cm vcl_recv Called at the beginning of a request, after the complete request has been received and parsed. Its purpose is to decide whether or not to serve the request, how to -do it, and, if applicanle, which backend to use. -.\" If the document is to be served from cache, however, backend selection -.\" can be postponed until -.\" .Cm vcl_miss . +do it, and, if applicable, which backend to use. +.Pp +The +.Cm vcl_recv +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm error Ar code Op Ar reason +Return the specified error code to the client and abandon the +request. +.It Cm pass +Switch to pass mode. +Control will eventually pass to +.Cm vcl_pass . +.It Cm pipe +Switch to pipe mode. +Control will eventually pass to +.Cm vcl_pipe . +.It Cm lookup +Look up the requested object in the cache. +Control will eventually pass to +.Cm vcl_hit +or +.Cm vcl_miss , +depending on whether the object is in the cache. +.El +.\" vcl_pipe +.It Cm vcl_pipe +Called upon entering pipe mode. +In this mode, the request is passed on to the backend, and any further +data from either client or backend is passed on unaltered until either +end closes the connection. +.Pp +The +.Cm vcl_pipe +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm error Ar code Op Ar reason +Return the specified error code to the client and abandon the +request. +.It Cm pipe +Proceed with pipe mode. +.El +.\" vcl_pass +.It Cm vcl_pass +Called upon entering pass mode. +In this mode, the request is passed on to the backend, and the +backend's response is passed on to the client, but is not entered into +the cache. +Subsequent requests submitted over the same client connection are +handled normally. +.Pp +The +.Cm vcl_pass +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm error Ar code Op Ar reason +Return the specified error code to the client and abandon the +request. +.It Cm pass +Proceed with pass mode. +.El +.\" vcl_hash +.It Cm vcl_hash +Currently not used. +The +.Cm vcl_hash +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm hash +Proceed. +.El +.\" vcl_hit .It Cm vcl_hit Called after a cache lookup if the requested document was found in the cache. -.\" Its purpose... +.Pp +The +.Cm vcl_hit +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm error Ar code Op Ar reason +Return the specified error code to the client and abandon the +request. +.It Cm pass +Switch to pass mode. +Control will eventually pass to +.Cm vcl_pass . +.It Cm deliver +Deliver the cached object to the client. +.El +.\" vcl_miss .It Cm vcl_miss Called after a cache lookup if the requested document was not found in the cache. Its purpose is to decide whether or not to attempt to retrieve the document from the backend, and which backend to use. +.Pp +The +.Cm vcl_miss +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm error Ar code Op Ar reason +Return the specified error code to the client and abandon the +request. +.It Cm pass +Switch to pass mode. +Control will eventually pass to +.Cm vcl_pass . +.It Cm fetch +Retrieve the requested object from the backend. +Control will eventually pass to +.Cm vcl_fetch . +.El +.\" vcl_fetch .It Cm vcl_fetch -Called after a document has been retrieved from the backend, before it -is inserted into the cache. +Called after a document has been successfully retrieved from the +backend. +.Pp +The +.Cm vcl_fetch +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm error Ar code Op Ar reason +Return the specified error code to the client and abandon the +request. +.It Cm pass +Switch to pass mode. +Control will eventually pass to +.Cm vcl_pass . +.It Cm insert +Insert the object into the cache, then deliver it to the client. +.El +.\" vcl_timeout .It Cm vcl_timeout Called by the reaper thread when a cached document has reached its expiry time. -.\" Its purpose... +.Pp +The +.Cm vcl_timeout +subroutine may terminate with one of the following keywords: +.Bl -tag -width "discard" +.It Cm fetch +Request a fresh copy of the object from the backend. +.It Cm discard +Discard the object. .El +.El .Pp If one of these subroutines is left undefined or terminates without reaching a handling decision, control will be handed over to the @@ -232,6 +372,18 @@ lookup; } +sub vcl_pipe { + pipe; +} + +sub vcl_pass { + pass; +} + +sub vcl_hash { + hash; +} + sub vcl_hit { if (!obj.cacheable) { pass; From des at projects.linpro.no Thu Mar 29 10:49:58 2007 From: des at projects.linpro.no (des at projects.linpro.no) Date: Thu, 29 Mar 2007 12:49:58 +0200 (CEST) Subject: r1287 - trunk/varnish-cache/bin/varnishd Message-ID: <20070329104958.664F21EC055@projects.linpro.no> Author: des Date: 2007-03-29 12:49:58 +0200 (Thu, 29 Mar 2007) New Revision: 1287 Modified: trunk/varnish-cache/bin/varnishd/mgt_cli.c Log: The argv length calculation was not only off by one, but failed to take into account the extra space required by expanded quotes, backslashes and newlines. Instead of pre-allocating a (possibly too short) buffer, start with a 64-byte buffer and double it every time we come close to filling it up. Also, avoid appending a trailing space before the final newline. This issue was uncovered by Kristoffer Gleditsch , who also helped test this patch. Modified: trunk/varnish-cache/bin/varnishd/mgt_cli.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_cli.c 2007-03-28 09:26:18 UTC (rev 1286) +++ trunk/varnish-cache/bin/varnishd/mgt_cli.c 2007-03-29 10:49:58 UTC (rev 1287) @@ -95,14 +95,23 @@ cli_out(cli, "Cache process not running"); return; } - v = 0; - for (u = 1; av[u] != NULL; u++) - v += strlen(av[u]) + 3; + v = 64; p = malloc(v); XXXAN(p); q = p; for (u = 1; av[u] != NULL; u++) { + if (v < (q - p) + 8) { + r = realloc(p, v + v); + XXXAN(r); + v += v; + q += r - p; + p = r; + } + /* v >= (q - p) + 8 */ + if (u > 1) + *q++ = ' '; *q++ = '"'; + /* v >= (q - p) + 6 */ for (r = av[u]; *r; r++) { switch (*r) { case '\\': *q++ = '\\'; *q++ = '\\'; break; @@ -111,9 +120,10 @@ default: *q++ = *r; break; } } + /* v >= (q - p) + 4 */ *q++ = '"'; - *q++ = ' '; } + /* v >= (q - p) + 3 */ *q++ = '\n'; v = q - p; i = write(cli_o, p, v); From phk at phk.freebsd.dk Thu Mar 29 21:48:31 2007 From: phk at phk.freebsd.dk (Poul-Henning Kamp) Date: Thu, 29 Mar 2007 21:48:31 +0000 Subject: r1287 - trunk/varnish-cache/bin/varnishd In-Reply-To: Your message of "Thu, 29 Mar 2007 12:49:58 +0200." <20070329104958.664F21EC055@projects.linpro.no> Message-ID: <15466.1175204911@critter.freebsd.dk> >Modified: > trunk/varnish-cache/bin/varnishd/mgt_cli.c >Log: >The argv length calculation was not only off by one, but failed to take >into account the extra space required by expanded quotes, backslashes and >newlines. Instead of pre-allocating a (possibly too short) buffer, start >with a 64-byte buffer and double it every time we come close to filling >it up. Also, avoid appending a trailing space before the final newline. > >This issue was uncovered by Kristoffer Gleditsch , >who also helped test this patch. use of vsb might be in order ? -- Poul-Henning Kamp | UNIX since Zilog Zeus 3.20 phk at FreeBSD.ORG | TCP/IP since RFC 956 FreeBSD committer | BSD since 4.3-tahoe Never attribute to malice what can adequately be explained by incompetence. From des at linpro.no Fri Mar 30 06:59:01 2007 From: des at linpro.no (Dag-Erling =?iso-8859-1?Q?Sm=F8rgrav?=) Date: Fri, 30 Mar 2007 08:59:01 +0200 Subject: r1287 - trunk/varnish-cache/bin/varnishd In-Reply-To: <15466.1175204911@critter.freebsd.dk> (Poul-Henning Kamp's message of "Thu, 29 Mar 2007 21:48:31 +0000") References: <15466.1175204911@critter.freebsd.dk> Message-ID: "Poul-Henning Kamp" writes: > use of vsb might be in order ? Yeah, I didn't think of that. DES -- Dag-Erling Sm?rgrav Senior Software Developer Linpro AS - www.linpro.no From des at projects.linpro.no Fri Mar 30 07:10:41 2007 From: des at projects.linpro.no (des at projects.linpro.no) Date: Fri, 30 Mar 2007 09:10:41 +0200 (CEST) Subject: r1288 - trunk/varnish-cache/bin/varnishd Message-ID: <20070330071041.C99801EC413@projects.linpro.no> Author: des Date: 2007-03-30 09:10:41 +0200 (Fri, 30 Mar 2007) New Revision: 1288 Modified: trunk/varnish-cache/bin/varnishd/mgt_cli.c Log: Rewrite using sbufs. Modified: trunk/varnish-cache/bin/varnishd/mgt_cli.c =================================================================== --- trunk/varnish-cache/bin/varnishd/mgt_cli.c 2007-03-29 10:49:58 UTC (rev 1287) +++ trunk/varnish-cache/bin/varnishd/mgt_cli.c 2007-03-30 07:10:41 UTC (rev 1288) @@ -83,8 +83,9 @@ static void mcf_passthru(struct cli *cli, char **av, void *priv) { - char *p, *q, *r; - unsigned u, v; + struct vsb *sb; + char *p; + unsigned u; int i; (void)priv; @@ -95,40 +96,35 @@ cli_out(cli, "Cache process not running"); return; } - v = 64; - p = malloc(v); - XXXAN(p); - q = p; + sb = vsb_new(NULL, NULL, 64, VSB_AUTOEXTEND); + XXXAN(sb); for (u = 1; av[u] != NULL; u++) { - if (v < (q - p) + 8) { - r = realloc(p, v + v); - XXXAN(r); - v += v; - q += r - p; - p = r; - } - /* v >= (q - p) + 8 */ if (u > 1) - *q++ = ' '; - *q++ = '"'; - /* v >= (q - p) + 6 */ - for (r = av[u]; *r; r++) { - switch (*r) { - case '\\': *q++ = '\\'; *q++ = '\\'; break; - case '\n': *q++ = '\\'; *q++ = 'n'; break; - case '"': *q++ = '\\'; *q++ = '"'; break; - default: *q++ = *r; break; + vsb_putc(sb, ' '); + vsb_putc(sb, '"'); + for (p = av[u]; *p; p++) { + switch (*p) { + case '\\': + vsb_cat(sb, "\\\\"); + break; + case '\n': + vsb_cat(sb, "\\n"); + break; + case '"': + vsb_cat(sb, "\\\""); + break; + default: + vsb_putc(sb, *p); } } - /* v >= (q - p) + 4 */ - *q++ = '"'; + vsb_putc(sb, '"'); } - /* v >= (q - p) + 3 */ - *q++ = '\n'; - v = q - p; - i = write(cli_o, p, v); - xxxassert(i == v); - free(p); + vsb_putc(sb, '\n'); + xxxassert(!vsb_overflowed(sb)); + vsb_finish(sb); + i = write(cli_o, vsb_data(sb), vsb_len(sb)); + xxxassert(i == vsb_len(sb)); + vsb_delete(sb); i = cli_readres(cli_i, &u, &p, 3.0); cli_result(cli, u); From phk at projects.linpro.no Fri Mar 30 21:11:16 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Fri, 30 Mar 2007 23:11:16 +0200 (CEST) Subject: r1289 - trunk/varnish-cache/lib/libvcl Message-ID: <20070330211116.CAC561EC2F5@projects.linpro.no> Author: phk Date: 2007-03-30 23:11:15 +0200 (Fri, 30 Mar 2007) New Revision: 1289 Modified: trunk/varnish-cache/lib/libvcl/flint.lnt trunk/varnish-cache/lib/libvcl/vcc_compile.c trunk/varnish-cache/lib/libvcl/vcc_compile.h trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl trunk/varnish-cache/lib/libvcl/vcc_gen_obj.tcl trunk/varnish-cache/lib/libvcl/vcc_obj.c trunk/varnish-cache/lib/libvcl/vcc_priv.h trunk/varnish-cache/lib/libvcl/vcc_token.c Log: Overhaul compiler to get rid of memory leaks and other bogons. Add a memlist to the tokenlist and a function which allocates with malloc(3) and hangs the piece on the memlist of tokenlist. At the end of compilation, we ditch everything on the list. Handle vrt_obj.h like the other #includes, and stuff these into a vsb instead of directly to a file. Free decoded token string, if any. Pull creation and destruction of tokenlist into separate functions for code clarity. Remember to destry everything in the tokenlist. Pull invocation of cc(1) into a separate function and change the way we do it, so we get any cc(1) groans and whines back in the vsb so a CLI user will see them. More errorchecks than before. More comments throughout. Modified: trunk/varnish-cache/lib/libvcl/flint.lnt =================================================================== --- trunk/varnish-cache/lib/libvcl/flint.lnt 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/flint.lnt 2007-03-30 21:11:15 UTC (rev 1289) @@ -10,6 +10,7 @@ -header(../../config.h) -sem(lbv_assert, r_no) -sem(strchr, 1p, type(1), 2n == 0 ? (@p < 1p) : (@p < 1p || @p == 0 )) +-sem(vcc_new_source, custodial(1)) -ffc // No automatic custody Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-30 21:11:15 UTC (rev 1289) @@ -100,6 +100,23 @@ /*--------------------------------------------------------------------*/ +void * +TlAlloc(struct tokenlist *tl, unsigned len) +{ + struct membit *mb; + void *p; + + p = calloc(len, 1); + assert(p != NULL); + mb = calloc(sizeof *mb, 1); + assert(mb != NULL); + mb->ptr = p; + TAILQ_INSERT_TAIL(&tl->membits, mb, list); + return (p); +} + +/*--------------------------------------------------------------------*/ + int IsMethod(struct token *t) { @@ -235,7 +252,7 @@ if (vcc_Teq(r->name, t)) return (r); } - r = calloc(sizeof *r, 1); + r = TlAlloc(tl, sizeof *r); assert(r != NULL); r->name = t; r->type = type; @@ -271,10 +288,10 @@ (void)tl; - v = calloc(sizeof *v, 1); + v = TlAlloc(tl, sizeof *v); assert(v != NULL); i = t->e - t->b; - p = malloc(i + 1); + p = TlAlloc(tl, i + 1); assert(p != NULL); memcpy(p, t->b, i); p[i] = '\0'; @@ -332,7 +349,7 @@ p->name = t; return (p); } - p = calloc(sizeof *p, 1); + p = TlAlloc(tl, sizeof *p); assert(p != NULL); p->name = t; TAILQ_INIT(&p->calls); @@ -351,7 +368,7 @@ if (pc->p == p) return; } - pc = calloc(sizeof *pc, 1); + pc = TlAlloc(tl, sizeof *pc); assert(pc != NULL); pc->p = p; pc->t = t; @@ -541,6 +558,7 @@ Fc(tl, 0, "\nstatic void\nVGC_Init(void)\n{\n\n"); vsb_finish(tl->fi); + /* XXX: check vsb_overflowed ? */ vsb_cat(tl->fc, vsb_data(tl->fi)); Fc(tl, 0, "}\n"); } @@ -551,6 +569,7 @@ Fc(tl, 0, "\nstatic void\nVGC_Fini(void)\n{\n\n"); vsb_finish(tl->ff); + /* XXX: check vsb_overflowed ? */ vsb_cat(tl->fc, vsb_data(tl->ff)); Fc(tl, 0, "}\n"); } @@ -704,24 +723,19 @@ /*--------------------------------------------------------------------*/ -static char * -vcc_CompileSource(struct vsb *sb, struct source *sp) +static struct tokenlist * +vcc_NewTokenList(void) { - struct tokenlist tokenlist, *tl; - struct ref *r; - struct token *t; - FILE *fo; - char *of = NULL; - char buf[BUFSIZ]; + struct tokenlist *tl; int i; - memset(&tokenlist, 0, sizeof tokenlist); - tl = &tokenlist; + tl = calloc(sizeof *tl, 1); + assert(tl != NULL); + TAILQ_INIT(&tl->membits); TAILQ_INIT(&tl->tokens); TAILQ_INIT(&tl->refs); TAILQ_INIT(&tl->procs); TAILQ_INIT(&tl->sources); - tl->sb = sb; tl->nsources = 0; @@ -746,43 +760,195 @@ tl->fm[i] = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ assert(tl->fm[i] != NULL); } + return (tl); +} +/*--------------------------------------------------------------------*/ + +static char * +vcc_DestroyTokenList(struct tokenlist *tl, char *ret) +{ + struct membit *mb; + int i; + + while (!TAILQ_EMPTY(&tl->membits)) { + mb = TAILQ_FIRST(&tl->membits); + TAILQ_REMOVE(&tl->membits, mb, list); + free(mb->ptr); + free(mb); + } + + vsb_delete(tl->fh); + vsb_delete(tl->fc); + vsb_delete(tl->fi); + vsb_delete(tl->ff); + for (i = 0; i < N_METHODS; i++) + vsb_delete(tl->fm[i]); + + free(tl); + return (ret); +} + +/*-------------------------------------------------------------------- + * Invoke system C compiler on source and return resulting dlfile. + * Errors goes in sb; + */ + +static char * +vcc_CallCc(char *source, struct vsb *sb) +{ + FILE *fo, *fs; + char *of, *sf, buf[BUFSIZ]; + int i, j, sfd; + + /* Create temporary C source file */ + sf = strdup("/tmp/vcl.XXXXXXXX"); + assert(sf != NULL); + sfd = mkstemp(sf); + if (sfd < 0) { + vsb_printf(sb, + "Cannot open temporary source file \"%s\": %s\n", + sf, strerror(errno)); + free(sf); + return (NULL); + } + fs = fdopen(sfd, "r+"); + assert(fs != NULL); + + if (fputs(source, fs) || fflush(fs)) { + vsb_printf(sb, + "Write error to C source file: %s\n", + strerror(errno)); + unlink(sf); + fclose(fs); + return (NULL); + } + rewind(fs); + + /* Name the output shared library */ + of = strdup("/tmp/vcl.XXXXXXXX"); + assert(of != NULL); + of = mktemp(of); + assert(of != NULL); + + /* Attempt to open a pipe to the system C-compiler */ + sprintf(buf, + "ln -f %s /tmp/_.c ;" /* XXX: for debugging */ + "exec cc -fpic -shared -Wl,-x -o %s -x c - < %s 2>&1", + sf, of, sf); + + fo = popen(buf, "r"); + if (fo == NULL) { + vsb_printf(sb, + "Internal error: Cannot execute cc(1): %s\n", + strerror(errno)); + free(of); + unlink(sf); + fclose(fs); + return (NULL); + } + + /* If we get any output, it's bad */ + j = 0; + while (1) { + if (fgets(buf, sizeof buf, fo) == NULL) + break; + if (!j) { + vsb_printf(sb, "Internal error: cc(1) complained:\n"); + j++; + } + vsb_cat(sb, buf); + } + + i = pclose(fo); + if (j == 0 && i != 0) + vsb_printf(sb, + "Internal error: cc(1) exit status 0x%04x\n", i); + + /* If the compiler complained, or exited non-zero, fail */ + if (i || j) { + unlink(of); + free(of); + of = NULL; + } + + /* clean up and return */ + unlink(sf); + free(sf); + fclose(fs); + return (of); +} + +/*-------------------------------------------------------------------- + * Compile the VCL code from the given source and return the filename + * of the resulting shared library. + */ + +static char * +vcc_CompileSource(struct vsb *sb, struct source *sp) +{ + struct tokenlist *tl; + char *of; + int i; + + tl = vcc_NewTokenList(); + tl->sb = sb; + + vcl_output_lang_h(tl->fh); Fh(tl, 0, "extern struct VCL_conf VCL_conf;\n"); Fi(tl, 0, "\tVRT_alloc_backends(&VCL_conf);\n"); + /* Register and lex the main source */ TAILQ_INSERT_TAIL(&tl->sources, sp, list); sp->idx = tl->nsources++; vcc_Lexer(tl, sp); if (tl->err) - goto done; + return (vcc_DestroyTokenList(tl, NULL)); + /* Register and lex the default VCL */ sp = vcc_new_source(vcc_default_vcl_b, vcc_default_vcl_e, "Default"); + assert(sp != NULL); TAILQ_INSERT_TAIL(&tl->sources, sp, list); sp->idx = tl->nsources++; vcc_Lexer(tl, sp); + if (tl->err) + return (vcc_DestroyTokenList(tl, NULL)); + + /* Add "END OF INPUT" token */ vcc_AddToken(tl, EOI, sp->e, sp->e); if (tl->err) - goto done; + return (vcc_DestroyTokenList(tl, NULL)); + /* Expand and lex any includes in the token string */ vcc_resolve_includes(tl); if (tl->err) - goto done; + return (vcc_DestroyTokenList(tl, NULL)); + /* Parse the token string */ tl->t = TAILQ_FIRST(&tl->tokens); vcc_Parse(tl); if (tl->err) - goto done; + return (vcc_DestroyTokenList(tl, NULL)); + + /* Perform consistency checks */ Consistency(tl); if (tl->err) - goto done; + return (vcc_DestroyTokenList(tl, NULL)); + /* Check for orphans */ + if (CheckRefs(tl)) + return (vcc_DestroyTokenList(tl, NULL)); + + Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n"); + /* Emit method functions */ for (i = 0; i < N_METHODS; i++) { Fc(tl, 1, "static int\n"); Fc(tl, 1, "VGC_function_%s (struct sess *sp)\n", method_tab[i].name); vsb_finish(tl->fm[i]); + /* XXX: check vsb_overflowed ? */ Fc(tl, 1, "{\n"); Fc(tl, 1, "%s", vsb_data(tl->fm[i])); Fc(tl, 1, "}\n\n"); @@ -790,69 +956,29 @@ LocTable(tl); - Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n"); - EmitInitFunc(tl); EmitFiniFunc(tl); EmitStruct(tl); - if (CheckRefs(tl)) - goto done; - - of = strdup("/tmp/vcl.XXXXXXXX"); - assert(of != NULL); - mktemp(of); - - sprintf(buf, - "tee /tmp/_.c |" - "cc -fpic -shared -Wl,-x -o %s -x c - ", of); - - fo = popen(buf, "w"); - assert(fo != NULL); - - vcl_output_lang_h(fo); - fputs(vrt_obj_h, fo); - + /* Combine it all in the fh vsb */ + vsb_finish(tl->fc); + /* XXX: check vsb_overflowed ? */ + vsb_cat(tl->fh, vsb_data(tl->fc)); vsb_finish(tl->fh); - fputs(vsb_data(tl->fh), fo); - vsb_delete(tl->fh); - vsb_finish(tl->fc); - fputs(vsb_data(tl->fc), fo); - vsb_delete(tl->fc); + /* Grind it through cc(1) */ + of = vcc_CallCc(vsb_data(tl->fh), sb); - i = pclose(fo); - fprintf(stderr, "pclose=%d\n", i); - if (i) { - vsb_printf(sb, "Internal error: GCC returned 0x%04x\n", i); - unlink(of); - free(of); - return (NULL); - } -done: - - for (i = 0; i < N_METHODS; i++) - vsb_delete(tl->fm[i]); - - /* Free References */ - while (!TAILQ_EMPTY(&tl->refs)) { - r = TAILQ_FIRST(&tl->refs); - TAILQ_REMOVE(&tl->refs, r, list); - free(r); - } - - /* Free Tokens */ - while (!TAILQ_EMPTY(&tl->tokens)) { - t = TAILQ_FIRST(&tl->tokens); - TAILQ_REMOVE(&tl->tokens, t, list); - vcc_FreeToken(t); - } - return (of); + /* done */ + return (vcc_DestroyTokenList(tl, of)); } -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * Compile the VCL code in the argument. Error messages, if any are + * formatted into the vsb. + */ char * VCC_Compile(struct vsb *sb, const char *b, const char *e) @@ -868,7 +994,10 @@ return (r); } -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * Compile the VCL code from the file named. Error messages, if any + * are formatted into the vsb. + */ char * VCC_CompileFile(struct vsb *sb, const char *fn) @@ -884,7 +1013,10 @@ return (r); } -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * Initialize the compiler and register the default VCL code for later + * compilation runs. + */ void VCC_InitCompile(const char *default_vcl) Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-30 21:11:15 UTC (rev 1289) @@ -34,6 +34,11 @@ #define INDENT 2 +struct membit { + TAILQ_ENTRY(membit) list; + void *ptr; +}; + struct source { TAILQ_ENTRY(source) list; char *name; @@ -57,6 +62,7 @@ struct tokenlist { struct tokenhead tokens; TAILQ_HEAD(, source) sources; + TAILQ_HEAD(, membit) membits; unsigned nsources; struct source *src; struct token *t; @@ -156,11 +162,11 @@ void AddCall(struct tokenlist *tl, struct token *t); struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); int IsMethod(struct token *t); +void *TlAlloc(struct tokenlist *tl, unsigned len); /* vcc_obj.c */ extern struct var vcc_be_vars[]; extern struct var vcc_vars[]; -extern const char *vrt_obj_h; /* vcc_parse.c */ void vcc_Parse(struct tokenlist *tl); Modified: trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-03-30 21:11:15 UTC (rev 1289) @@ -9,6 +9,7 @@ #include #include #include "vcc_priv.h" +#include "vsb.h" unsigned vcl_fixed_token(const char *p, const char **q) @@ -427,147 +428,183 @@ } void -vcl_output_lang_h(FILE *f) +vcl_output_lang_h(struct vsb *sb) { - fputs("#define VCL_RET_ERROR (1 << 0)\n", f); - fputs("#define VCL_RET_LOOKUP (1 << 1)\n", f); - fputs("#define VCL_RET_HASH (1 << 2)\n", f); - fputs("#define VCL_RET_PIPE (1 << 3)\n", f); - fputs("#define VCL_RET_PASS (1 << 4)\n", f); - fputs("#define VCL_RET_FETCH (1 << 5)\n", f); - fputs("#define VCL_RET_INSERT (1 << 6)\n", f); - fputs("#define VCL_RET_DELIVER (1 << 7)\n", f); - fputs("#define VCL_RET_DISCARD (1 << 8)\n", f); - fputs("/*\n", f); - fputs(" * $Id$\n", f); - fputs(" *\n", f); - fputs(" * NB: This file is machine generated, DO NOT EDIT!\n", f); - fputs(" *\n", f); - fputs(" * Edit vcc_gen_fixed_token.tcl instead\n", f); - fputs(" */\n", f); - fputs("\n", f); - fputs("struct sess;\n", f); - fputs("\n", f); - fputs("typedef void vcl_init_f(void);\n", f); - fputs("typedef void vcl_fini_f(void);\n", f); - fputs("typedef int vcl_func_f(struct sess *sp);\n", f); - fputs("\n", f); - fputs("struct VCL_conf {\n", f); - fputs(" unsigned magic;\n", f); - fputs("#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */\n", f); - fputs("\n", f); - fputs(" struct backend **backend;\n", f); - fputs(" unsigned nbackend;\n", f); - fputs(" struct vrt_ref *ref;\n", f); - fputs(" unsigned nref;\n", f); - fputs(" unsigned busy;\n", f); - fputs("\n", f); - fputs(" unsigned nsrc;\n", f); - fputs(" const char **srcname;\n", f); - fputs(" const char **srcbody;\n", f); - fputs("\n", f); - fputs(" void *priv;\n", f); - fputs("\n", f); - fputs(" vcl_init_f *init_func;\n", f); - fputs(" vcl_fini_f *fini_func;\n", f); - fputs("\n", f); - fputs(" vcl_func_f *recv_func;\n", f); - fputs(" vcl_func_f *pipe_func;\n", f); - fputs(" vcl_func_f *pass_func;\n", f); - fputs(" vcl_func_f *hash_func;\n", f); - fputs(" vcl_func_f *miss_func;\n", f); - fputs(" vcl_func_f *hit_func;\n", f); - fputs(" vcl_func_f *fetch_func;\n", f); - fputs(" vcl_func_f *timeout_func;\n", f); - fputs("};\n", f); - fputs("/*-\n", f); - fputs(" * Copyright (c) 2006 Verdens Gang AS\n", f); - fputs(" * Copyright (c) 2006 Linpro AS\n", f); - fputs(" * All rights reserved.\n", f); - fputs(" *\n", f); - fputs(" * Author: Poul-Henning Kamp \n", f); - fputs(" *\n", f); - fputs(" * Redistribution and use in source and binary forms, with or without\n", f); - fputs(" * modification, are permitted provided that the following conditions\n", f); - fputs(" * are met:\n", f); - fputs(" * 1. Redistributions of source code must retain the above copyright\n", f); - fputs(" * notice, this list of conditions and the following disclaimer.\n", f); - fputs(" * 2. Redistributions in binary form must reproduce the above copyright\n", f); - fputs(" * notice, this list of conditions and the following disclaimer in the\n", f); - fputs(" * documentation and/or other materials provided with the distribution.\n", f); - fputs(" *\n", f); - fputs(" * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n", f); - fputs(" * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n", f); - fputs(" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n", f); - fputs(" * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE\n", f); - fputs(" * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n", f); - fputs(" * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n", f); - fputs(" * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n", f); - fputs(" * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n", f); - fputs(" * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n", f); - fputs(" * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n", f); - fputs(" * SUCH DAMAGE.\n", f); - fputs(" *\n", f); - fputs(" * $Id$\n", f); - fputs(" *\n", f); - fputs(" * Runtime support for compiled VCL programs.\n", f); - fputs(" *\n", f); - fputs(" * XXX: When this file is changed, lib/libvcl/vcc_gen_fixed_token.tcl\n", f); - fputs(" * XXX: *MUST* be rerun.\n", f); - fputs(" */\n", f); - fputs("\n", f); - fputs("struct sess;\n", f); - fputs("struct vsb;\n", f); - fputs("struct backend;\n", f); - fputs("struct VCL_conf;\n", f); - fputs("\n", f); - fputs("struct vrt_ref {\n", f); - fputs(" unsigned source;\n", f); - fputs(" unsigned offset;\n", f); - fputs(" unsigned line;\n", f); - fputs(" unsigned pos;\n", f); - fputs(" unsigned count;\n", f); - fputs(" const char *token;\n", f); - fputs("};\n", f); - fputs("\n", f); - fputs("struct vrt_acl {\n", f); - fputs(" unsigned char not;\n", f); - fputs(" unsigned char mask;\n", f); - fputs(" unsigned char paren;\n", f); - fputs(" const char *name;\n", f); - fputs(" const char *desc;\n", f); - fputs(" void *priv;\n", f); - fputs("};\n", f); - fputs("\n", f); - fputs("/* ACL related */\n", f); - fputs("int VRT_acl_match(struct sess *, const char *, struct vrt_acl *);\n", f); - fputs("void VRT_acl_init(struct vrt_acl *);\n", f); - fputs("void VRT_acl_fini(struct vrt_acl *);\n", f); - fputs("\n", f); - fputs("/* Regexp related */\n", f); - fputs("void VRT_re_init(void **, const char *);\n", f); - fputs("void VRT_re_fini(void *);\n", f); - fputs("int VRT_re_match(const char *, void *re);\n", f); - fputs("int VRT_re_test(struct vsb *, const char *);\n", f); - fputs("\n", f); - fputs("void VRT_count(struct sess *, unsigned);\n", f); - fputs("int VRT_rewrite(const char *, const char *);\n", f); - fputs("void VRT_error(struct sess *, unsigned, const char *);\n", f); - fputs("int VRT_switch_config(const char *);\n", f); - fputs("\n", f); - fputs("char *VRT_GetHdr(struct sess *, int where, const char *);\n", f); - fputs("void VRT_handling(struct sess *sp, unsigned hand);\n", f); - fputs("\n", f); - fputs("/* Backend related */\n", f); - fputs("void VRT_set_backend_name(struct backend *, const char *);\n", f); - fputs("void VRT_alloc_backends(struct VCL_conf *cp);\n", f); - fputs("void VRT_free_backends(struct VCL_conf *cp);\n", f); - fputs("void VRT_fini_backend(struct backend *be);\n", f); - fputs("\n", f); - fputs("\n", f); - fputs("#define VRT_done(sp, hand) \\\n", f); - fputs(" do { \\\n", f); - fputs(" VRT_handling(sp, hand); \\\n", f); - fputs(" return (1); \\\n", f); - fputs(" } while (0)\n", f); + vsb_cat(sb, "#define VCL_RET_ERROR (1 << 0)\n"); + vsb_cat(sb, "#define VCL_RET_LOOKUP (1 << 1)\n"); + vsb_cat(sb, "#define VCL_RET_HASH (1 << 2)\n"); + vsb_cat(sb, "#define VCL_RET_PIPE (1 << 3)\n"); + vsb_cat(sb, "#define VCL_RET_PASS (1 << 4)\n"); + vsb_cat(sb, "#define VCL_RET_FETCH (1 << 5)\n"); + vsb_cat(sb, "#define VCL_RET_INSERT (1 << 6)\n"); + vsb_cat(sb, "#define VCL_RET_DELIVER (1 << 7)\n"); + vsb_cat(sb, "#define VCL_RET_DISCARD (1 << 8)\n"); + vsb_cat(sb, "/*\n"); + vsb_cat(sb, " * $Id$\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * NB: This file is machine generated, DO NOT EDIT!\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * Edit vcc_gen_fixed_token.tcl instead\n"); + vsb_cat(sb, " */\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "struct sess;\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "typedef void vcl_init_f(void);\n"); + vsb_cat(sb, "typedef void vcl_fini_f(void);\n"); + vsb_cat(sb, "typedef int vcl_func_f(struct sess *sp);\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "struct VCL_conf {\n"); + vsb_cat(sb, " unsigned magic;\n"); + vsb_cat(sb, "#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, " struct backend **backend;\n"); + vsb_cat(sb, " unsigned nbackend;\n"); + vsb_cat(sb, " struct vrt_ref *ref;\n"); + vsb_cat(sb, " unsigned nref;\n"); + vsb_cat(sb, " unsigned busy;\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, " unsigned nsrc;\n"); + vsb_cat(sb, " const char **srcname;\n"); + vsb_cat(sb, " const char **srcbody;\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, " void *priv;\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, " vcl_init_f *init_func;\n"); + vsb_cat(sb, " vcl_fini_f *fini_func;\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, " vcl_func_f *recv_func;\n"); + vsb_cat(sb, " vcl_func_f *pipe_func;\n"); + vsb_cat(sb, " vcl_func_f *pass_func;\n"); + vsb_cat(sb, " vcl_func_f *hash_func;\n"); + vsb_cat(sb, " vcl_func_f *miss_func;\n"); + vsb_cat(sb, " vcl_func_f *hit_func;\n"); + vsb_cat(sb, " vcl_func_f *fetch_func;\n"); + vsb_cat(sb, " vcl_func_f *timeout_func;\n"); + vsb_cat(sb, "};\n"); + vsb_cat(sb, "/*-\n"); + vsb_cat(sb, " * Copyright (c) 2006 Verdens Gang AS\n"); + vsb_cat(sb, " * Copyright (c) 2006 Linpro AS\n"); + vsb_cat(sb, " * All rights reserved.\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * Author: Poul-Henning Kamp \n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * Redistribution and use in source and binary forms, with or without\n"); + vsb_cat(sb, " * modification, are permitted provided that the following conditions\n"); + vsb_cat(sb, " * are met:\n"); + vsb_cat(sb, " * 1. Redistributions of source code must retain the above copyright\n"); + vsb_cat(sb, " * notice, this list of conditions and the following disclaimer.\n"); + vsb_cat(sb, " * 2. Redistributions in binary form must reproduce the above copyright\n"); + vsb_cat(sb, " * notice, this list of conditions and the following disclaimer in the\n"); + vsb_cat(sb, " * documentation and/or other materials provided with the distribution.\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n"); + vsb_cat(sb, " * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"); + vsb_cat(sb, " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"); + vsb_cat(sb, " * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE\n"); + vsb_cat(sb, " * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"); + vsb_cat(sb, " * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"); + vsb_cat(sb, " * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"); + vsb_cat(sb, " * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n"); + vsb_cat(sb, " * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n"); + vsb_cat(sb, " * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n"); + vsb_cat(sb, " * SUCH DAMAGE.\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * $Id$\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * Runtime support for compiled VCL programs.\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * XXX: When this file is changed, lib/libvcl/vcc_gen_fixed_token.tcl\n"); + vsb_cat(sb, " * XXX: *MUST* be rerun.\n"); + vsb_cat(sb, " */\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "struct sess;\n"); + vsb_cat(sb, "struct vsb;\n"); + vsb_cat(sb, "struct backend;\n"); + vsb_cat(sb, "struct VCL_conf;\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "struct vrt_ref {\n"); + vsb_cat(sb, " unsigned source;\n"); + vsb_cat(sb, " unsigned offset;\n"); + vsb_cat(sb, " unsigned line;\n"); + vsb_cat(sb, " unsigned pos;\n"); + vsb_cat(sb, " unsigned count;\n"); + vsb_cat(sb, " const char *token;\n"); + vsb_cat(sb, "};\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "struct vrt_acl {\n"); + vsb_cat(sb, " unsigned char not;\n"); + vsb_cat(sb, " unsigned char mask;\n"); + vsb_cat(sb, " unsigned char paren;\n"); + vsb_cat(sb, " const char *name;\n"); + vsb_cat(sb, " const char *desc;\n"); + vsb_cat(sb, " void *priv;\n"); + vsb_cat(sb, "};\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "/* ACL related */\n"); + vsb_cat(sb, "int VRT_acl_match(struct sess *, const char *, struct vrt_acl *);\n"); + vsb_cat(sb, "void VRT_acl_init(struct vrt_acl *);\n"); + vsb_cat(sb, "void VRT_acl_fini(struct vrt_acl *);\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "/* Regexp related */\n"); + vsb_cat(sb, "void VRT_re_init(void **, const char *);\n"); + vsb_cat(sb, "void VRT_re_fini(void *);\n"); + vsb_cat(sb, "int VRT_re_match(const char *, void *re);\n"); + vsb_cat(sb, "int VRT_re_test(struct vsb *, const char *);\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "void VRT_count(struct sess *, unsigned);\n"); + vsb_cat(sb, "int VRT_rewrite(const char *, const char *);\n"); + vsb_cat(sb, "void VRT_error(struct sess *, unsigned, const char *);\n"); + vsb_cat(sb, "int VRT_switch_config(const char *);\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "char *VRT_GetHdr(struct sess *, int where, const char *);\n"); + vsb_cat(sb, "void VRT_handling(struct sess *sp, unsigned hand);\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "/* Backend related */\n"); + vsb_cat(sb, "void VRT_set_backend_name(struct backend *, const char *);\n"); + vsb_cat(sb, "void VRT_alloc_backends(struct VCL_conf *cp);\n"); + vsb_cat(sb, "void VRT_free_backends(struct VCL_conf *cp);\n"); + vsb_cat(sb, "void VRT_fini_backend(struct backend *be);\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "#define VRT_done(sp, hand) \\\n"); + vsb_cat(sb, " do { \\\n"); + vsb_cat(sb, " VRT_handling(sp, hand); \\\n"); + vsb_cat(sb, " return (1); \\\n"); + vsb_cat(sb, " } while (0)\n"); + vsb_cat(sb, "/*\n"); + vsb_cat(sb, " * $Id$\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * NB: This file is machine generated, DO NOT EDIT!\n"); + vsb_cat(sb, " *\n"); + vsb_cat(sb, " * Edit vcc_gen_obj.tcl instead\n"); + vsb_cat(sb, " */\n"); + vsb_cat(sb, "\n"); + vsb_cat(sb, "const char * VRT_r_backend_host(struct backend *);\n"); + vsb_cat(sb, "void VRT_l_backend_host(struct backend *, const char *);\n"); + vsb_cat(sb, "const char * VRT_r_backend_port(struct backend *);\n"); + vsb_cat(sb, "void VRT_l_backend_port(struct backend *, const char *);\n"); + vsb_cat(sb, "double VRT_r_backend_dnsttl(struct backend *);\n"); + vsb_cat(sb, "void VRT_l_backend_dnsttl(struct backend *, double);\n"); + vsb_cat(sb, "const unsigned char * VRT_r_client_ip(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_client_ip(struct sess *, const unsigned char *);\n"); + vsb_cat(sb, "const char * VRT_r_req_request(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_req_request(struct sess *, const char *);\n"); + vsb_cat(sb, "const char * VRT_r_req_host(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_req_host(struct sess *, const char *);\n"); + vsb_cat(sb, "const char * VRT_r_req_url(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_req_url(struct sess *, const char *);\n"); + vsb_cat(sb, "const char * VRT_r_req_proto(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_req_proto(struct sess *, const char *);\n"); + vsb_cat(sb, "struct backend * VRT_r_req_backend(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_req_backend(struct sess *, struct backend *);\n"); + vsb_cat(sb, "double VRT_r_obj_valid(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_obj_valid(struct sess *, double);\n"); + vsb_cat(sb, "double VRT_r_obj_cacheable(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_obj_cacheable(struct sess *, double);\n"); + vsb_cat(sb, "double VRT_r_obj_ttl(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_obj_ttl(struct sess *, double);\n"); + vsb_cat(sb, "const char * VRT_r_req_http_(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_req_http_(struct sess *, const char *);\n"); + vsb_cat(sb, "const char * VRT_r_resp_http_(struct sess *);\n"); + vsb_cat(sb, "void VRT_l_resp_http_(struct sess *, const char *);\n"); } Modified: trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-30 21:11:15 UTC (rev 1289) @@ -214,6 +214,7 @@ puts $fo "#include " puts $fo "#include " puts $fo "#include \"vcc_priv.h\"" +puts $fo "#include \"vsb.h\"" set tn 128 puts $foh "#define LOW_TOKEN $tn" @@ -338,23 +339,24 @@ set fi [open $n] while {[gets $fi a] >= 0} { regsub -all {\\} $a {\\\\} a - puts $fo "\tfputs(\"$a\\n\", f);" + puts $fo "\tvsb_cat(sb, \"$a\\n\");" } close $fi } puts $fo "" puts $fo "void" -puts $fo "vcl_output_lang_h(FILE *f)" +puts $fo "vcl_output_lang_h(struct vsb *sb)" puts $fo "{" set i 0 foreach k $returns { - puts $fo "\tfputs(\"#define VCL_RET_[string toupper $k] (1 << $i)\\n\", f);" + puts $fo "\tvsb_cat(sb, \"#define VCL_RET_[string toupper $k] (1 << $i)\\n\");" incr i } copy_include ../../include/vcl.h copy_include ../../include/vrt.h +copy_include ../../include/vrt_obj.h puts $fo "}" Modified: trunk/varnish-cache/lib/libvcl/vcc_gen_obj.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_gen_obj.tcl 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_gen_obj.tcl 2007-03-30 21:11:15 UTC (rev 1289) @@ -115,14 +115,3 @@ puts $fo "};" close $fp -set fp [open ../../include/vrt_obj.h] - -puts $fo "" -puts $fo "const char *vrt_obj_h = " -while {[gets $fp a] >= 0} { - puts $fo "\t\"$a\\n\"" -} -puts $fo ";" - -close $fo -close $fp Modified: trunk/varnish-cache/lib/libvcl/vcc_obj.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_obj.c 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_obj.c 2007-03-30 21:11:15 UTC (rev 1289) @@ -72,42 +72,3 @@ }, { NULL } }; - -const char *vrt_obj_h = - "/*\n" - " * $Id$\n" - " *\n" - " * NB: This file is machine generated, DO NOT EDIT!\n" - " *\n" - " * Edit vcc_gen_obj.tcl instead\n" - " */\n" - "\n" - "const char * VRT_r_backend_host(struct backend *);\n" - "void VRT_l_backend_host(struct backend *, const char *);\n" - "const char * VRT_r_backend_port(struct backend *);\n" - "void VRT_l_backend_port(struct backend *, const char *);\n" - "double VRT_r_backend_dnsttl(struct backend *);\n" - "void VRT_l_backend_dnsttl(struct backend *, double);\n" - "const unsigned char * VRT_r_client_ip(struct sess *);\n" - "void VRT_l_client_ip(struct sess *, const unsigned char *);\n" - "const char * VRT_r_req_request(struct sess *);\n" - "void VRT_l_req_request(struct sess *, const char *);\n" - "const char * VRT_r_req_host(struct sess *);\n" - "void VRT_l_req_host(struct sess *, const char *);\n" - "const char * VRT_r_req_url(struct sess *);\n" - "void VRT_l_req_url(struct sess *, const char *);\n" - "const char * VRT_r_req_proto(struct sess *);\n" - "void VRT_l_req_proto(struct sess *, const char *);\n" - "struct backend * VRT_r_req_backend(struct sess *);\n" - "void VRT_l_req_backend(struct sess *, struct backend *);\n" - "double VRT_r_obj_valid(struct sess *);\n" - "void VRT_l_obj_valid(struct sess *, double);\n" - "double VRT_r_obj_cacheable(struct sess *);\n" - "void VRT_l_obj_cacheable(struct sess *, double);\n" - "double VRT_r_obj_ttl(struct sess *);\n" - "void VRT_l_obj_ttl(struct sess *, double);\n" - "const char * VRT_r_req_http_(struct sess *);\n" - "void VRT_l_req_http_(struct sess *, const char *);\n" - "const char * VRT_r_resp_http_(struct sess *);\n" - "void VRT_l_resp_http_(struct sess *, const char *);\n" -; Modified: trunk/varnish-cache/lib/libvcl/vcc_priv.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_priv.h 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_priv.h 2007-03-30 21:11:15 UTC (rev 1289) @@ -33,12 +33,14 @@ #include "vcc_token_defs.h" +struct vsb; + #define isident1(c) (isalpha(c)) #define isident(c) (isalpha(c) || isdigit(c) || (c) == '_' || (c) == '-') #define isvar(c) (isident(c) || (c) == '.') unsigned vcl_fixed_token(const char *p, const char **q); extern const char *vcl_tnames[256]; void vcl_init_tnames(void); -void vcl_output_lang_h(FILE *f); +void vcl_output_lang_h(struct vsb *sb); #define PF(t) ((t)->e - (t)->b), (t)->b Modified: trunk/varnish-cache/lib/libvcl/vcc_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_token.c 2007-03-30 07:10:41 UTC (rev 1288) +++ trunk/varnish-cache/lib/libvcl/vcc_token.c 2007-03-30 21:11:15 UTC (rev 1289) @@ -285,6 +285,8 @@ { /* XXX: more */ + if (t->dec != NULL) + free(t->dec); free(t); } From phk at projects.linpro.no Sat Mar 31 07:43:05 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 31 Mar 2007 09:43:05 +0200 (CEST) Subject: r1290 - trunk/varnish-cache/lib/libvcl Message-ID: <20070331074305.D23CD1EC523@projects.linpro.no> Author: phk Date: 2007-03-31 09:43:05 +0200 (Sat, 31 Mar 2007) New Revision: 1290 Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c trunk/varnish-cache/lib/libvcl/vcc_token.c Log: Improve error message layout and information. Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-30 21:11:15 UTC (rev 1289) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-31 07:43:05 UTC (rev 1290) @@ -395,21 +395,20 @@ if (u) { #define VCL_RET_MAC(a, b, c, d) \ if (u & VCL_RET_##b) { \ - vsb_printf(tl->sb, "Illegal return for method\n"); \ + vsb_printf(tl->sb, "Illegal action \"%s\"\n", #a); \ vcc_ErrWhere(tl, p->returnt[d]); \ } #include "vcl_returns.h" #undef VCL_RET_MAC - vsb_printf(tl->sb, "In function\n"); + vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", PF(p->name)); vcc_ErrWhere(tl, p->name); return (1); } p->active = 1; TAILQ_FOREACH(pc, &p->calls, list) { if (Consist_Decend(tl, pc->p, returns)) { - vsb_printf(tl->sb, "\nCalled from\n"); - vcc_ErrWhere(tl, p->name); - vsb_printf(tl->sb, "at\n"); + vsb_printf(tl->sb, "\n...called from \"%.*s\"\n", + PF(p->name)); vcc_ErrWhere(tl, pc->t); return (1); } @@ -434,7 +433,16 @@ continue; if (Consist_Decend(tl, p, m->returns)) { vsb_printf(tl->sb, - "\nwhich is a %s method\n", m->name); + "\n...which is the \"%s\" method\n", m->name); + vsb_printf(tl->sb, "Legal actions are:"); +#define VCL_RET_MAC(a, b, c, d) \ + if (m->returns & c) \ + vsb_printf(tl->sb, " \"%s\"", #a); +#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d) +#include "vcl_returns.h" +#undef VCL_RET_MAC +#undef VCL_RET_MAC_E + vsb_printf(tl->sb, "\n"); return (1); } } Modified: trunk/varnish-cache/lib/libvcl/vcc_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_token.c 2007-03-30 21:11:15 UTC (rev 1289) +++ trunk/varnish-cache/lib/libvcl/vcc_token.c 2007-03-31 07:43:05 UTC (rev 1290) @@ -91,7 +91,7 @@ } else pos++; } - vsb_printf(tl->sb, "In %s Line %d Pos %d\n", f, lin, pos); + vsb_printf(tl->sb, "(%s Line %d Pos %d)\n", f, lin, pos); x = y = 0; for (p = l; p < e && *p != '\n'; p++) { if (*p == '\t') { From phk at projects.linpro.no Sat Mar 31 08:36:32 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 31 Mar 2007 10:36:32 +0200 (CEST) Subject: r1291 - trunk/varnish-cache/lib/libvcl Message-ID: <20070331083632.1E7781EC52C@projects.linpro.no> Author: phk Date: 2007-03-31 10:36:31 +0200 (Sat, 31 Mar 2007) New Revision: 1291 Added: trunk/varnish-cache/lib/libvcl/vcc_xref.c Modified: trunk/varnish-cache/lib/libvcl/Makefile.am trunk/varnish-cache/lib/libvcl/flint.lnt trunk/varnish-cache/lib/libvcl/vcc_acl.c trunk/varnish-cache/lib/libvcl/vcc_compile.c trunk/varnish-cache/lib/libvcl/vcc_compile.h trunk/varnish-cache/lib/libvcl/vcc_parse.c Log: Overhaul cross reference checks in vcc compiler Move and isolate cross reference stuff to it's own source file (vcc_xref.c) and use vcc_ prefix as originally intended. Also warn about multiple definitions of objects. Modified: trunk/varnish-cache/lib/libvcl/Makefile.am =================================================================== --- trunk/varnish-cache/lib/libvcl/Makefile.am 2007-03-31 07:43:05 UTC (rev 1290) +++ trunk/varnish-cache/lib/libvcl/Makefile.am 2007-03-31 08:36:31 UTC (rev 1291) @@ -14,6 +14,7 @@ vcc_parse.c \ vcc_fixed_token.c \ vcc_obj.c \ - vcc_token.c + vcc_token.c \ + vcc_xref.c libvcl_la_CFLAGS = -include config.h Modified: trunk/varnish-cache/lib/libvcl/flint.lnt =================================================================== --- trunk/varnish-cache/lib/libvcl/flint.lnt 2007-03-31 07:43:05 UTC (rev 1290) +++ trunk/varnish-cache/lib/libvcl/flint.lnt 2007-03-31 08:36:31 UTC (rev 1291) @@ -18,7 +18,7 @@ -e763 // Redundant declaration for symbol '...' previously declared --e737 // Loss of sign in promotion from int to unsigned int +-e737 // Loss of sign in promotion from int to unsigned int -e715 // Symbol 'arg' (line 43) not referenced -e818 // Pointer parameter '...' could be declared as pointing to const Modified: trunk/varnish-cache/lib/libvcl/vcc_acl.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_acl.c 2007-03-31 07:43:05 UTC (rev 1290) +++ trunk/varnish-cache/lib/libvcl/vcc_acl.c 2007-03-31 08:36:31 UTC (rev 1291) @@ -60,7 +60,7 @@ case '~': vcc_NextToken(tl); ExpectErr(tl, ID); - AddRef(tl, tl->t, R_ACL); + vcc_AddRef(tl, tl->t, R_ACL); Fc(tl, 1, "VRT_acl_match(sp, \"%.*s\", acl_%.*s)\n", PF(tl->t), PF(tl->t)); vcc_NextToken(tl); @@ -87,7 +87,7 @@ an = tl->t; vcc_NextToken(tl); - AddDef(tl, an, R_ACL); + vcc_AddDef(tl, an, R_ACL); Fh(tl, 0, "static struct vrt_acl acl_%.*s[];\n", PF(an)); Fc(tl, 1, "static struct vrt_acl acl_%.*s[] = {\n", PF(an)); Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-31 07:43:05 UTC (rev 1290) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-31 08:36:31 UTC (rev 1291) @@ -85,7 +85,7 @@ #include "vrt.h" #include "libvcl.h" -static struct method method_tab[] = { +struct method method_tab[] = { #define VCL_RET_MAC(l,U,b,n) #define VCL_MET_MAC(l,U,m) { "vcl_"#l, m }, #include "vcl_returns.h" @@ -237,46 +237,6 @@ EncString(sb, t->dec, NULL, 0); } -/*-------------------------------------------------------------------- - * Keep track of definitions and references - */ - -static struct ref * -FindRef(struct tokenlist *tl, struct token *t, enum ref_type type) -{ - struct ref *r; - - TAILQ_FOREACH(r, &tl->refs, list) { - if (r->type != type) - continue; - if (vcc_Teq(r->name, t)) - return (r); - } - r = TlAlloc(tl, sizeof *r); - assert(r != NULL); - r->name = t; - r->type = type; - TAILQ_INSERT_TAIL(&tl->refs, r, list); - return (r); -} - -void -AddRef(struct tokenlist *tl, struct token *t, enum ref_type type) -{ - - FindRef(tl, t, type)->refcnt++; -} - -void -AddDef(struct tokenlist *tl, struct token *t, enum ref_type type) -{ - struct ref *r; - - r = FindRef(tl, t, type); - r->defcnt++; - r->name = t; -} - /*--------------------------------------------------------------------*/ static struct var * @@ -334,182 +294,6 @@ } /*-------------------------------------------------------------------- - * Consistency check - */ - -struct proc * -AddProc(struct tokenlist *tl, struct token *t, int def) -{ - struct proc *p; - - TAILQ_FOREACH(p, &tl->procs, list) { - if (!vcc_Teq(p->name, t)) - continue; - if (def) - p->name = t; - return (p); - } - p = TlAlloc(tl, sizeof *p); - assert(p != NULL); - p->name = t; - TAILQ_INIT(&p->calls); - TAILQ_INSERT_TAIL(&tl->procs, p, list); - return (p); -} - -void -AddCall(struct tokenlist *tl, struct token *t) -{ - struct proccall *pc; - struct proc *p; - - p = AddProc(tl, t, 0); - TAILQ_FOREACH(pc, &tl->curproc->calls, list) { - if (pc->p == p) - return; - } - pc = TlAlloc(tl, sizeof *pc); - assert(pc != NULL); - pc->p = p; - pc->t = t; - TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list); -} - -static int -Consist_Decend(struct tokenlist *tl, struct proc *p, unsigned returns) -{ - unsigned u; - struct proccall *pc; - - if (!p->exists) { - vsb_printf(tl->sb, "Function %.*s does not exist\n", - PF(p->name)); - return (1); - } - if (p->active) { - vsb_printf(tl->sb, "Function recurses on\n"); - vcc_ErrWhere(tl, p->name); - return (1); - } - u = p->returns & ~returns; - if (u) { -#define VCL_RET_MAC(a, b, c, d) \ - if (u & VCL_RET_##b) { \ - vsb_printf(tl->sb, "Illegal action \"%s\"\n", #a); \ - vcc_ErrWhere(tl, p->returnt[d]); \ - } -#include "vcl_returns.h" -#undef VCL_RET_MAC - vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", PF(p->name)); - vcc_ErrWhere(tl, p->name); - return (1); - } - p->active = 1; - TAILQ_FOREACH(pc, &p->calls, list) { - if (Consist_Decend(tl, pc->p, returns)) { - vsb_printf(tl->sb, "\n...called from \"%.*s\"\n", - PF(p->name)); - vcc_ErrWhere(tl, pc->t); - return (1); - } - } - p->active = 0; - p->called++; - return (0); -} - -static int -Consistency(struct tokenlist *tl) -{ - struct proc *p; - struct method *m; - - TAILQ_FOREACH(p, &tl->procs, list) { - for(m = method_tab; m->name != NULL; m++) { - if (vcc_IdIs(p->name, m->name)) - break; - } - if (m->name == NULL) - continue; - if (Consist_Decend(tl, p, m->returns)) { - vsb_printf(tl->sb, - "\n...which is the \"%s\" method\n", m->name); - vsb_printf(tl->sb, "Legal actions are:"); -#define VCL_RET_MAC(a, b, c, d) \ - if (m->returns & c) \ - vsb_printf(tl->sb, " \"%s\"", #a); -#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d) -#include "vcl_returns.h" -#undef VCL_RET_MAC -#undef VCL_RET_MAC_E - vsb_printf(tl->sb, "\n"); - return (1); - } - } - TAILQ_FOREACH(p, &tl->procs, list) { - if (p->called) - continue; - vsb_printf(tl->sb, "Function unused\n"); - vcc_ErrWhere(tl, p->name); - return (1); - } - return (0); -} - -/*--------------------------------------------------------------------*/ - -static int -CheckRefs(struct tokenlist *tl) -{ - struct ref *r; - const char *type; - int nerr = 0; - - TAILQ_FOREACH(r, &tl->refs, list) { - if (r->defcnt != 0 && r->refcnt != 0) - continue; - nerr++; - - switch(r->type) { - case R_FUNC: - type = "function"; - break; - case R_ACL: - type = "acl"; - break; - case R_BACKEND: - type = "backend"; - break; - default: - ErrInternal(tl); - vsb_printf(tl->sb, "Ref "); - vcc_ErrToken(tl, r->name); - vsb_printf(tl->sb, " has unknown type %d\n", - r->type); - continue; - } - if (r->defcnt == 0 && r->name->tok == METHOD) { - vsb_printf(tl->sb, - "No definition for method %.*s\n", PF(r->name)); - continue; - } - - if (r->defcnt == 0) { - vsb_printf(tl->sb, - "Undefined %s %.*s, first reference:\n", - type, PF(r->name)); - vcc_ErrWhere(tl, r->name); - continue; - } - - vsb_printf(tl->sb, "Unused %s %.*s, defined:\n", - type, PF(r->name)); - vcc_ErrWhere(tl, r->name); - } - return (nerr); -} - -/*-------------------------------------------------------------------- * Output the location/profiling table. For each counted token, we * record source+line+charpos for the first character in the token. */ @@ -939,13 +723,13 @@ if (tl->err) return (vcc_DestroyTokenList(tl, NULL)); - /* Perform consistency checks */ - Consistency(tl); - if (tl->err) + /* Check for orphans */ + if (vcc_CheckReferences(tl)) return (vcc_DestroyTokenList(tl, NULL)); - /* Check for orphans */ - if (CheckRefs(tl)) + /* Check that all action returns are legal */ + vcc_CheckAction(tl); + if (tl->err) return (vcc_DestroyTokenList(tl, NULL)); Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n"); Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.h =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-31 07:43:05 UTC (rev 1290) +++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2007-03-31 08:36:31 UTC (rev 1291) @@ -120,27 +120,11 @@ struct method { const char *name; - unsigned returns; + unsigned actions; }; -struct proccall { - TAILQ_ENTRY(proccall) list; - struct proc *p; - struct token *t; -}; +struct proc; -struct proc { - TAILQ_ENTRY(proc) list; - TAILQ_HEAD(,proccall) calls; - struct token *name; - unsigned returns; - unsigned exists; - unsigned called; - unsigned active; - struct token *returnt[VCL_RET_MAX]; -}; - - /*--------------------------------------------------------------------*/ /* vcc_acl.c */ @@ -149,18 +133,15 @@ void vcc_Cond_Ip(struct var *vp, struct tokenlist *tl); /* vcc_compile.c */ +extern struct method method_tab[]; void Fh(struct tokenlist *tl, int indent, const char *fmt, ...); void Fc(struct tokenlist *tl, int indent, const char *fmt, ...); void Fb(struct tokenlist *tl, int indent, const char *fmt, ...); void Fi(struct tokenlist *tl, int indent, const char *fmt, ...); void Ff(struct tokenlist *tl, int indent, const char *fmt, ...); unsigned UintVal(struct tokenlist *tl); -void AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); -void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); void EncToken(struct vsb *sb, struct token *t); struct var *FindVar(struct tokenlist *tl, struct token *t, struct var *vl); -void AddCall(struct tokenlist *tl, struct token *t); -struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); int IsMethod(struct token *t); void *TlAlloc(struct tokenlist *tl, unsigned len); @@ -183,6 +164,16 @@ void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e); void vcc_FreeToken(struct token *t); +/* vcc_expr.c */ +void vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); +void vcc_AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); +int vcc_CheckReferences(struct tokenlist *tl); + +void vcc_AddCall(struct tokenlist *tl, struct token *t); +struct proc *vcc_AddProc(struct tokenlist *tl, struct token *t); +void vcc_ProcAction(struct proc *p, unsigned action, struct token *t); +int vcc_CheckAction(struct tokenlist *tl); + #define ERRCHK(tl) do { if ((tl)->err) return; } while (0) #define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__) #define Expect(a, b) vcc__Expect(a, b, __LINE__) Modified: trunk/varnish-cache/lib/libvcl/vcc_parse.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-03-31 07:43:05 UTC (rev 1290) +++ trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-03-31 08:36:31 UTC (rev 1291) @@ -527,8 +527,7 @@ return; #define VCL_RET_MAC(a,b,c,d) case T_##b: \ Fb(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ - tl->curproc->returns |= VCL_RET_##b; \ - tl->curproc->returnt[d] = at; \ + vcc_ProcAction(tl->curproc, d, at); \ return; #include "vcl_returns.h" #undef VCL_RET_MAC @@ -554,8 +553,8 @@ return; case T_CALL: ExpectErr(tl, ID); - AddCall(tl, tl->t); - AddRef(tl, tl->t, R_FUNC); + vcc_AddCall(tl, tl->t); + vcc_AddRef(tl, tl->t, R_FUNC); Fb(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); Fb(tl, 1, "\treturn (1);\n"); vcc_NextToken(tl); @@ -620,7 +619,7 @@ case BACKEND: if (tl->t->tok == '=') { vcc_NextToken(tl); - AddRef(tl, tl->t, R_BACKEND); + vcc_AddRef(tl, tl->t, R_BACKEND); Fb(tl, 0, "VGC_backend_%.*s", PF(tl->t)); vcc_NextToken(tl); Fb(tl, 0, ");\n"); @@ -717,9 +716,9 @@ vcc_NextToken(tl); ExpectErr(tl, ID); t_be = tl->t; - AddDef(tl, tl->t, R_BACKEND); + vcc_AddDef(tl, tl->t, R_BACKEND); if (tl->nbackend == 0) - AddRef(tl, tl->t, R_BACKEND); + vcc_AddRef(tl, tl->t, R_BACKEND); Fh(tl, 1, "#define VGC_backend_%.*s (VCL_conf.backend[%d])\n", PF(tl->t), tl->nbackend); Fc(tl, 0, "\n"); @@ -837,17 +836,15 @@ assert(m < N_METHODS); tl->fb = tl->fm[m]; if (tl->mprocs[m] == NULL) { - tl->mprocs[m] = AddProc(tl, tl->t, 1); - tl->mprocs[m]->exists++; - AddDef(tl, tl->t, R_FUNC); - AddRef(tl, tl->t, R_FUNC); + tl->mprocs[m] = vcc_AddProc(tl, tl->t); + vcc_AddDef(tl, tl->t, R_FUNC); + vcc_AddRef(tl, tl->t, R_FUNC); } tl->curproc = tl->mprocs[m]; } else { tl->fb = tl->fc; - tl->curproc = AddProc(tl, tl->t, 1); - tl->curproc->exists++; - AddDef(tl, tl->t, R_FUNC); + tl->curproc = vcc_AddProc(tl, tl->t); + vcc_AddDef(tl, tl->t, R_FUNC); Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", PF(tl->t)); Fc(tl, 1, "static int\n"); Copied: trunk/varnish-cache/lib/libvcl/vcc_xref.c (from rev 1290, trunk/varnish-cache/lib/libvcl/vcc_compile.c) =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2007-03-31 07:43:05 UTC (rev 1290) +++ trunk/varnish-cache/lib/libvcl/vcc_xref.c 2007-03-31 08:36:31 UTC (rev 1291) @@ -0,0 +1,307 @@ +/*- + * Copyright (c) 2006 Verdens Gang AS + * Copyright (c) 2006 Linpro AS + * All rights reserved. + * + * Author: Poul-Henning Kamp + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + * + * This fine contains code for two cross-reference or consistency checks. + * + * The first check is simply that all functions, acls and backends are + * both defined and referenced. Complaints about referenced but undefined + * or defined but unreferenced objects will be emitted. + * + * The second check recursively decends through function calls to make + * sure that action actions are correct for the methods through which + * they are called. + */ + +#include +#include + +#include "vsb.h" + +#include "vcc_priv.h" +#include "vcc_compile.h" + +/*--------------------------------------------------------------------*/ + +struct proccall { + TAILQ_ENTRY(proccall) list; + struct proc *p; + struct token *t; +}; + +struct proc { + TAILQ_ENTRY(proc) list; + TAILQ_HEAD(,proccall) calls; + struct token *name; + unsigned actions; + unsigned exists; + unsigned called; + unsigned active; + struct token *action_tok[VCL_RET_MAX]; +}; + +/*--------------------------------------------------------------------*/ + +static const char * +vcc_typename(struct tokenlist *tl, const struct ref *r) +{ + switch (r->type) { + case R_FUNC: return ("function"); + case R_ACL: return ("acl"); + case R_BACKEND: return ("backend"); + default: + ErrInternal(tl); + vsb_printf(tl->sb, "Ref "); + vcc_ErrToken(tl, r->name); + vsb_printf(tl->sb, " has unknown type %d\n", + r->type); + return "???"; + } +} + +/*-------------------------------------------------------------------- + * Keep track of definitions and references + */ + +static struct ref * +vcc_findref(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + struct ref *r; + + TAILQ_FOREACH(r, &tl->refs, list) { + if (r->type != type) + continue; + if (vcc_Teq(r->name, t)) + return (r); + } + r = TlAlloc(tl, sizeof *r); + assert(r != NULL); + r->name = t; + r->type = type; + TAILQ_INSERT_TAIL(&tl->refs, r, list); + return (r); +} + +void +vcc_AddRef(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + + vcc_findref(tl, t, type)->refcnt++; +} + +void +vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + struct ref *r; + const char *tp; + + r = vcc_findref(tl, t, type); + if (r->defcnt > 0) { + tp = vcc_typename(tl, r); + vsb_printf(tl->sb, "Multiple definitions of %s \"%.*s\"\n", + tp, PF(t)); + vcc_ErrWhere(tl, r->name); + vsb_printf(tl->sb, "...and\n"); + vcc_ErrWhere(tl, t); + } + r->defcnt++; + r->name = t; +} + +/*--------------------------------------------------------------------*/ + +int +vcc_CheckReferences(struct tokenlist *tl) +{ + struct ref *r; + const char *type; + int nerr = 0; + + TAILQ_FOREACH(r, &tl->refs, list) { + if (r->defcnt != 0 && r->refcnt != 0) + continue; + nerr++; + + type = vcc_typename(tl, r); + if (r->defcnt == 0 && r->name->tok == METHOD) { + vsb_printf(tl->sb, + "No definition for method %.*s\n", PF(r->name)); + continue; + } + + if (r->defcnt == 0) { + vsb_printf(tl->sb, + "Undefined %s %.*s, first reference:\n", + type, PF(r->name)); + vcc_ErrWhere(tl, r->name); + continue; + } + + vsb_printf(tl->sb, "Unused %s %.*s, defined:\n", + type, PF(r->name)); + vcc_ErrWhere(tl, r->name); + } + return (nerr); +} + +/*-------------------------------------------------------------------- + * Returned action checks + */ + +static struct proc * +vcc_findproc(struct tokenlist *tl, struct token *t) +{ + struct proc *p; + + TAILQ_FOREACH(p, &tl->procs, list) + if (vcc_Teq(p->name, t)) + return (p); + p = TlAlloc(tl, sizeof *p); + assert(p != NULL); + TAILQ_INIT(&p->calls); + TAILQ_INSERT_TAIL(&tl->procs, p, list); + p->name = t; + return (p); +} + +struct proc * +vcc_AddProc(struct tokenlist *tl, struct token *t) +{ + struct proc *p; + + p = vcc_findproc(tl, t); + p->name = t; /* make sure the name matches the definition */ + p->exists++; + return (p); +} + +void +vcc_AddCall(struct tokenlist *tl, struct token *t) +{ + struct proccall *pc; + struct proc *p; + + p = vcc_findproc(tl, t); + pc = TlAlloc(tl, sizeof *pc); + assert(pc != NULL); + pc->p = p; + pc->t = t; + TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list); +} + +void +vcc_ProcAction(struct proc *p, unsigned action, struct token *t) +{ + + p->actions |= (1 << action); + /* Record the first instance of this action */ + if (p->action_tok[action] == NULL) + p->action_tok[action] = t; +} + +static int +vcc_CheckActionRecurse(struct tokenlist *tl, struct proc *p, unsigned actions) +{ + unsigned u; + struct proccall *pc; + + if (!p->exists) { + vsb_printf(tl->sb, "Function %.*s does not exist\n", + PF(p->name)); + return (1); + } + if (p->active) { + vsb_printf(tl->sb, "Function recurses on\n"); + vcc_ErrWhere(tl, p->name); + return (1); + } + u = p->actions & ~actions; + if (u) { +#define VCL_RET_MAC(a, b, c, d) \ + if (u & VCL_RET_##b) { \ + vsb_printf(tl->sb, "Illegal action \"%s\"\n", #a); \ + vcc_ErrWhere(tl, p->action_tok[d]); \ + } +#include "vcl_returns.h" +#undef VCL_RET_MAC + vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", PF(p->name)); + vcc_ErrWhere(tl, p->name); + return (1); + } + p->active = 1; + TAILQ_FOREACH(pc, &p->calls, list) { + if (vcc_CheckActionRecurse(tl, pc->p, actions)) { + vsb_printf(tl->sb, "\n...called from \"%.*s\"\n", + PF(p->name)); + vcc_ErrWhere(tl, pc->t); + return (1); + } + } + p->active = 0; + p->called++; + return (0); +} + +int +vcc_CheckAction(struct tokenlist *tl) +{ + struct proc *p; + struct method *m; + int i; + + TAILQ_FOREACH(p, &tl->procs, list) { + i = IsMethod(p->name); + if (i < 0) + continue; + m = method_tab + i; + if (vcc_CheckActionRecurse(tl, p, m->actions)) { + vsb_printf(tl->sb, + "\n...which is the \"%s\" method\n", m->name); + vsb_printf(tl->sb, "Legal actions are:"); +#define VCL_RET_MAC(a, b, c, d) \ + if (m->actions & c) \ + vsb_printf(tl->sb, " \"%s\"", #a); +#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d) +#include "vcl_returns.h" +#undef VCL_RET_MAC +#undef VCL_RET_MAC_E + vsb_printf(tl->sb, "\n"); + return (1); + } + } + TAILQ_FOREACH(p, &tl->procs, list) { + if (p->called) + continue; + vsb_printf(tl->sb, "Function unused\n"); + vcc_ErrWhere(tl, p->name); + return (1); + } + return (0); +} + From phk at projects.linpro.no Sat Mar 31 18:19:07 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 31 Mar 2007 20:19:07 +0200 (CEST) Subject: r1292 - trunk/varnish-cache/lib/libvcl Message-ID: <20070331181907.DD3491EC1E8@projects.linpro.no> Author: phk Date: 2007-03-31 20:19:07 +0200 (Sat, 31 Mar 2007) New Revision: 1292 Added: trunk/varnish-cache/lib/libvcl/syntax.txt Log: Pidgin BNF syntax of VCL Added: trunk/varnish-cache/lib/libvcl/syntax.txt =================================================================== --- trunk/varnish-cache/lib/libvcl/syntax.txt 2007-03-31 08:36:31 UTC (rev 1291) +++ trunk/varnish-cache/lib/libvcl/syntax.txt 2007-03-31 18:19:07 UTC (rev 1292) @@ -0,0 +1,192 @@ +# Manually maintained syntax description of VCL +# +# $Id$ +# + +vcl_program: + prog_element + vcl_program prog_element + +prog_element: + acl + function + backend + +function: + 'sub' ident compound + +compound: + '{' statements '}' + +statements: + statement + statements statement + +statement: + compound + if_stmt + action + +if_stmt: + 'if' conditional compound elseifparts elsepart + +elseifparts: + + elseifpart + elseifparts elseifpart + +elseifpart: + 'elseif' conditional compound + +elsepart: + + 'else' compound + +conditional: + '(' cond_0 ')' + +cond_0: + cond_1 + cond_0 '||' cond_1 + +cond_1: + cond_2 + cond_1 '&&' cond_2 + +cond_2: + cond_3 + '!' cond_3 + +cond_3: + '(' cond_0 ')' + var_int cond_int + var_size cond_size + var_bool + var_ip cond_ip + var_string cond_string + var_time cond_time + var_backend + +cond_int: + '==' cnum + '!=' cnum + '<=' cnum + '>=' cnum + '<' cnum + '>' cnum + +cond_size: + cond_int size_unit + +conf_time: + cond_int time_unit + +time_unit: + 's' + 'm' + 'h' + 'd' + +size_unit: + 'kb' + 'mb' + 'Mb' + 'gb' + 'Gb' + +cond_string: + '~' regexp + '==' cstr + '!=' cstr + +cond_ip: + +regexp: + cstr + +backend: + 'backend' ident '{' be_decls '}' + +be_decls: + be_decl + be_decls be_decl + +be_decl: + 'set' be_string '=' cstr ';' + 'set' be_time '=' cnum time_unit ';' + +action: + 'no_new_cache' ';' + 'no_cache' ';' + return_action ';' + 'error' cnum cstr ';' + 'error' cstr ';' + 'error' cnum ';' + 'error' ';' + 'switch_config' ident ';' + 'call' ident ';' + 'rewrite' cstr cstr ';' + 'set' assignment ';' + +# see variable 'returns' in vcc_gen_fixed_token.tcl +return_action: + 'lookup' + 'hash' + 'pipe' + 'pass' + 'fetch' + 'insert' + 'deliver' + 'discard' + +assignment: + var_int ratio + var_int assign_int + var_size ratio + var_size assign_int size_unit + var_rate ratio + var_rate assign_int size_unit '/' time_unit + var_time ratio + var_time assign_int time_unit + var_float ratio + var_float '+=' double + var_float '-=' double + var_float '=' double + var_backend '=' ident + +assign_int: + '+=' cnum + '-=' cnum + '=' cnum + +ratio: + '*=' double + '/=' double + +acl: + 'acl' ident '{' rules '}' + +rules: + rule + rules rule + +rule: + '(' not rule0 ')' ';' + not rule0 ';' + +not: + + '!' + +rule0: + cstr + cstr '/' cnum + '!' cstr + +cstr: (string constant) + +cnum: (numeric constant) + +double: (floating point constant) + +ident: (identifier) From phk at projects.linpro.no Sat Mar 31 18:20:33 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 31 Mar 2007 20:20:33 +0200 (CEST) Subject: r1293 - trunk/varnish-cache/lib/libvcl Message-ID: <20070331182033.720651EC41C@projects.linpro.no> Author: phk Date: 2007-03-31 20:20:33 +0200 (Sat, 31 Mar 2007) New Revision: 1293 Modified: trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl Log: Fix typo, so we correctly recognize '-=' as T_DECR token. Modified: trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-03-31 18:19:07 UTC (rev 1292) +++ trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2007-03-31 18:20:33 UTC (rev 1293) @@ -85,6 +85,10 @@ } return (0); case '-': + if (p[0] == '-' && p[1] == '=') { + *q = p + 2; + return (T_DECR); + } if (p[0] == '-' && p[1] == '-') { *q = p + 2; return (T_DEC); @@ -103,10 +107,6 @@ case '/': if (p[0] == '/' && p[1] == '=') { *q = p + 2; - return (T_DECR); - } - if (p[0] == '/' && p[1] == '=') { - *q = p + 2; return (T_DIV); } if (p[0] == '/') { @@ -391,7 +391,7 @@ vcl_tnames[T_CAND] = "&&"; vcl_tnames[T_COR] = "||"; vcl_tnames[T_DEC] = "--"; - vcl_tnames[T_DECR] = "/="; + vcl_tnames[T_DECR] = "-="; vcl_tnames[T_DELIVER] = "deliver"; vcl_tnames[T_DISCARD] = "discard"; vcl_tnames[T_DIV] = "/="; Modified: trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-31 18:19:07 UTC (rev 1292) +++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2007-03-31 18:20:33 UTC (rev 1293) @@ -93,7 +93,7 @@ {">>" SHR} {"<<" SHL} {"+=" INCR} - {"/=" DECR} + {"-=" DECR} {"*=" MUL} {"/=" DIV} } From phk at projects.linpro.no Sat Mar 31 18:21:14 2007 From: phk at projects.linpro.no (phk at projects.linpro.no) Date: Sat, 31 Mar 2007 20:21:14 +0200 (CEST) Subject: r1294 - trunk/varnish-cache/lib/libvcl Message-ID: <20070331182114.7B6291EC3ED@projects.linpro.no> Author: phk Date: 2007-03-31 20:21:14 +0200 (Sat, 31 Mar 2007) New Revision: 1294 Modified: trunk/varnish-cache/lib/libvcl/vcc_parse.c Log: Better syntax checking of "set" statements. Remove inapplicable comment. Modified: trunk/varnish-cache/lib/libvcl/vcc_parse.c =================================================================== --- trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-03-31 18:20:33 UTC (rev 1293) +++ trunk/varnish-cache/lib/libvcl/vcc_parse.c 2007-03-31 18:21:14 UTC (rev 1294) @@ -29,37 +29,6 @@ * $Id$ */ -/* - * XXX: - * generate interface structure - * - * XXX: - * Better error messages, throughout. - * >It also accured to me that we could link the errors to the error - * >documentation. - * > - * >Unreferenced function 'request_policy', first mention is - * > Line 8 Pos 4 - * > sub request_policy { - * > ----##############-- - * >Read more about this type of error: - * >http://varnish/doc/error.html#Unreferenced%20function - * > - * > - * > Unknown variable 'obj.bandwidth' - * > At: Line 88 Pos 12 - * > if (obj.bandwidth < 1 kb/h) { - * > ------------#############------------ - * >Read more about this type of error: - * >http://varnish/doc/error.html#Unknown%20variable - * - * XXX: - * Create proper tmp filenames for .h, .c and .o - * - * XXX: - * and all the rest... - */ - #include #include #include @@ -514,7 +483,7 @@ { unsigned a; struct var *vp; - struct token *at; + struct token *at, *vt; at = tl->t; vcc_NextToken(tl); @@ -569,6 +538,7 @@ return; case T_SET: ExpectErr(tl, VAR); + vt = tl->t; vp = FindVar(tl, tl->t, vcc_vars); ERRCHK(tl); assert(vp != NULL); @@ -582,18 +552,35 @@ case FLOAT: if (tl->t->tok != '=') Fb(tl, 0, "%s %c ", vp->rname, *tl->t->b); - a = tl->t->tok; + at = tl->t; vcc_NextToken(tl); - if (a == T_MUL || a == T_DIV) + switch (at->tok) { + case T_MUL: + case T_DIV: Fb(tl, 0, "%g", DoubleVal(tl)); - else if (vp->fmt == TIME) - TimeVal(tl); - else if (vp->fmt == SIZE) - SizeVal(tl); - else if (vp->fmt == RATE) - RateVal(tl); - else - Fb(tl, 0, "%g", DoubleVal(tl)); + break; + case T_INCR: + case T_DECR: + case '=': + if (vp->fmt == TIME) + TimeVal(tl); + else if (vp->fmt == SIZE) + SizeVal(tl); + else if (vp->fmt == RATE) + RateVal(tl); + else if (vp->fmt == FLOAT) + Fb(tl, 0, "%g", DoubleVal(tl)); + else { + vsb_printf(tl->sb, "Cannot assign this variable type.\n"); + vcc_ErrWhere(tl, vt); + return; + } + break; + default: + vsb_printf(tl->sb, "Illegal assignment operator.\n"); + vcc_ErrWhere(tl, at); + return; + } Fb(tl, 0, ");\n"); break; #if 0 /* XXX: enable if we find a legit use */