[master] 5c0b833 Support Unix domain sockets as addresses in backend definitions.
Geoff Simmons
geoff at uplex.de
Mon Mar 12 09:45:10 UTC 2018
commit 5c0b833a0170f0f91631f852abdf6c7bf2aa7cbd
Author: Geoff Simmons <geoff at uplex.de>
Date: Mon Feb 19 02:39:53 2018 +0100
Support Unix domain sockets as addresses in backend definitions.
diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c
index 11a35c9..74b29d6 100644
--- a/bin/varnishd/cache/cache_backend.c
+++ b/bin/varnishd/cache/cache_backend.c
@@ -212,6 +212,7 @@ vbe_dir_gethdrs(const struct director *d, struct worker *wrk,
int i, extrachance = 1;
struct backend *bp;
struct pfd *pfd;
+ char abuf[VTCP_ADDRBUFSIZE], pbuf[VTCP_PORTBUFSIZE];
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
@@ -234,8 +235,9 @@ vbe_dir_gethdrs(const struct director *d, struct worker *wrk,
if (PFD_State(pfd) != PFD_STATE_STOLEN)
extrachance = 0;
+ PFD_RemoteName(pfd, abuf, sizeof abuf, pbuf, sizeof pbuf);
i = V1F_SendReq(wrk, bo, &bo->acct.bereq_hdrbytes,
- &bo->acct.bereq_bodybytes, 0);
+ &bo->acct.bereq_bodybytes, 0, abuf, pbuf);
if (PFD_State(pfd) != PFD_STATE_USED) {
if (VTP_Wait(wrk, pfd, VTIM_real() +
@@ -300,6 +302,7 @@ vbe_dir_http1pipe(const struct director *d, struct req *req, struct busyobj *bo)
struct backend *bp;
struct v1p_acct v1a;
struct pfd *pfd;
+ char abuf[VTCP_ADDRBUFSIZE], pbuf[VTCP_PORTBUFSIZE];
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
@@ -320,7 +323,9 @@ vbe_dir_http1pipe(const struct director *d, struct req *req, struct busyobj *bo)
retval = SC_TX_ERROR;
} else {
CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC);
- i = V1F_SendReq(req->wrk, bo, &v1a.bereq, &v1a.out, 1);
+ PFD_RemoteName(pfd, abuf, sizeof abuf, pbuf, sizeof pbuf);
+ i = V1F_SendReq(req->wrk, bo, &v1a.bereq, &v1a.out, 1, abuf,
+ pbuf);
VSLb_ts_req(req, "Pipe", W_TIM_real(req->wrk));
if (i == 0)
V1P_Process(req, *PFD_Fd(pfd), &v1a);
@@ -437,7 +442,12 @@ VRT_new_backend_clustered(VRT_CTX, struct vsmw_cluster *vc,
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(vrt, VRT_BACKEND_MAGIC);
- assert(vrt->ipv4_suckaddr != NULL || vrt->ipv6_suckaddr != NULL);
+ if (vrt->path == NULL)
+ assert(vrt->ipv4_suckaddr != NULL
+ || vrt->ipv6_suckaddr != NULL);
+ else
+ assert(vrt->ipv4_suckaddr == NULL
+ && vrt->ipv6_suckaddr == NULL);
vcl = ctx->vcl;
AN(vcl);
@@ -480,7 +490,7 @@ VRT_new_backend_clustered(VRT_CTX, struct vsmw_cluster *vc,
VTAILQ_INSERT_TAIL(&backends, be, list);
VSC_C_main->n_backend++;
be->tcp_pool = VTP_Ref(vrt->ipv4_suckaddr, vrt->ipv6_suckaddr,
- vbe_proto_ident);
+ vrt->path, vbe_proto_ident);
Lck_Unlock(&backends_mtx);
if (vbp != NULL) {
diff --git a/bin/varnishd/cache/cache_backend_probe.c b/bin/varnishd/cache/cache_backend_probe.c
index b5522dc..478ad18 100644
--- a/bin/varnishd/cache/cache_backend_probe.c
+++ b/bin/varnishd/cache/cache_backend_probe.c
@@ -283,7 +283,9 @@ vbp_poke(struct vbp_target *vt)
}
i = VSA_Get_Proto(sa);
- if (i == AF_INET)
+ if (VSA_Compare(sa, bogo_ip) == 0)
+ vt->good_unix |= 1;
+ else if (i == AF_INET)
vt->good_ipv4 |= 1;
else if (i == AF_INET6)
vt->good_ipv6 |= 1;
diff --git a/bin/varnishd/cache/cache_tcp_pool.c b/bin/varnishd/cache/cache_tcp_pool.c
index c63ad64..e9fa812 100644
--- a/bin/varnishd/cache/cache_tcp_pool.c
+++ b/bin/varnishd/cache/cache_tcp_pool.c
@@ -38,6 +38,7 @@
#include "vsa.h"
#include "vtcp.h"
+#include "vus.h"
#include "vtim.h"
#include "waiter/waiter.h"
@@ -106,6 +107,7 @@ struct tcp_pool {
struct suckaddr *ip4;
struct suckaddr *ip6;
+ char *uds;
struct conn_pool cp[1];
};
@@ -489,6 +491,20 @@ VCP_Wait(struct worker *wrk, struct pfd *pfd, double tmo)
/*--------------------------------------------------------------------
*/
+struct vtp_cs {
+ unsigned magic;
+#define VTP_CS_MAGIC 0xc1e40447
+ const struct suckaddr *ip4;
+ const struct suckaddr *ip6;
+ const char *uds;
+};
+
+static inline int
+tmo2msec(double tmo)
+{
+ return ( (int)floor(tmo * 1000.0) );
+}
+
static int v_matchproto_(cp_open_f)
vtp_open(const struct conn_pool *cp, double tmo, const void **privp)
{
@@ -499,7 +515,7 @@ vtp_open(const struct conn_pool *cp, double tmo, const void **privp)
CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
- msec = (int)floor(tmo * 1000.0);
+ msec = tmo2msec(tmo);
if (cache_param->prefer_ipv6) {
*privp = tp->ip6;
s = VTCP_connect(tp->ip6, msec);
@@ -525,13 +541,6 @@ vtp_close(struct pfd *pfd)
VTCP_close(&pfd->fd);
}
-struct vtp_cs {
- unsigned magic;
-#define VTP_CS_MAGIC 0xc1e40447
- const struct suckaddr *ip4;
- const struct suckaddr *ip6;
-};
-
static int v_matchproto_(cp_cmp_f)
vtp_cmp(const struct conn_pool *cp, const void *priv)
{
@@ -581,23 +590,78 @@ static const struct cp_methods vtp_methods = {
.remote_name = vtp_remote_name,
};
+/*--------------------------------------------------------------------
+ */
+
+static int v_matchproto_(cp_open_f)
+vus_open(const struct conn_pool *cp, double tmo, const void **privp)
+{
+ int s;
+ int msec;
+ struct tcp_pool *tp;
+
+ CHECK_OBJ_NOTNULL(cp, CONN_POOL_MAGIC);
+ CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
+ AN(tp->uds);
+
+ msec = tmo2msec(tmo);
+ *privp = bogo_ip;
+ s = VUS_connect(tp->uds, msec);
+ return (s);
+}
+
+static int v_matchproto_(cp_cmp_f)
+vus_cmp(const struct conn_pool *cp, const void *priv)
+{
+ const struct vtp_cs *vcs;
+ const struct tcp_pool *tp;
+
+ CAST_OBJ_NOTNULL(vcs, priv, VTP_CS_MAGIC);
+ CAST_OBJ_NOTNULL(tp, cp->priv, TCP_POOL_MAGIC);
+ if (tp->uds != NULL && vcs->uds != NULL)
+ return (strcmp(tp->uds, vcs->uds));
+ return (1);
+}
+
+static void v_matchproto_(cp_name_f)
+vus_name(const struct pfd *pfd, char *addr, unsigned alen, char *pbuf,
+ unsigned plen)
+{
+ (void) pfd;
+ assert(alen > strlen("0.0.0.0"));
+ assert(plen > 1);
+ strcpy(addr, "0.0.0.0");
+ strcpy(pbuf, "0");
+}
+
+static const struct cp_methods vus_methods = {
+ .open = vus_open,
+ .close = vtp_close,
+ .cmp = vus_cmp,
+ .local_name = vus_name,
+ .remote_name = vus_name,
+};
/*--------------------------------------------------------------------
- * Reference a TCP pool given by {ip4, ip6} pair. Create if it
- * doesn't exist already.
+ * Reference a TCP pool given by {ip4, ip6} pair or a UDS. Create if
+ * it doesn't exist already.
*/
struct tcp_pool *
-VTP_Ref(const struct suckaddr *ip4, const struct suckaddr *ip6, const void *id)
+VTP_Ref(const struct suckaddr *ip4, const struct suckaddr *ip6, const char *uds,
+ const void *id)
{
struct tcp_pool *tp;
struct conn_pool *cp;
struct vtp_cs vcs;
+ const struct cp_methods *methods;
- assert(ip4 != NULL || ip6 != NULL);
+ assert((uds != NULL && ip4 == NULL && ip6 == NULL)
+ || (uds == NULL && (ip4 != NULL || ip6 != NULL)));
INIT_OBJ(&vcs, VTP_CS_MAGIC);
vcs.ip4 = ip4;
vcs.ip6 = ip6;
+ vcs.uds = uds;
cp = VCP_Ref(id, &vcs);
if (cp != NULL)
@@ -605,11 +669,18 @@ VTP_Ref(const struct suckaddr *ip4, const struct suckaddr *ip6, const void *id)
ALLOC_OBJ(tp, TCP_POOL_MAGIC);
AN(tp);
- if (ip4 != NULL)
- tp->ip4 = VSA_Clone(ip4);
- if (ip6 != NULL)
- tp->ip6 = VSA_Clone(ip6);
- return(VCP_New(tp->cp, id, tp, &vtp_methods));
+ if (uds != NULL) {
+ methods = &vus_methods;
+ tp->uds = strdup(uds);
+ }
+ else {
+ methods = &vtp_methods;
+ if (ip4 != NULL)
+ tp->ip4 = VSA_Clone(ip4);
+ if (ip6 != NULL)
+ tp->ip6 = VSA_Clone(ip6);
+ }
+ return(VCP_New(tp->cp, id, tp, methods));
}
/*--------------------------------------------------------------------
@@ -638,6 +709,7 @@ VTP_Rel(struct tcp_pool **tpp)
free(tp->ip4);
free(tp->ip6);
+ free(tp->uds);
FREE_OBJ(tp);
}
@@ -650,6 +722,8 @@ int
VTP_Open(const struct tcp_pool *tp, double tmo, const void **privp)
{
+ if (tp->uds != NULL)
+ return (vus_open(tp->cp, tmo, privp));
return (vtp_open(tp->cp, tmo, privp));
}
diff --git a/bin/varnishd/cache/cache_tcp_pool.h b/bin/varnishd/cache/cache_tcp_pool.h
index 6c792c1..d554a36 100644
--- a/bin/varnishd/cache/cache_tcp_pool.h
+++ b/bin/varnishd/cache/cache_tcp_pool.h
@@ -51,11 +51,12 @@ void PFD_RemoteName(const struct pfd *, char *, unsigned, char *, unsigned);
*/
struct tcp_pool *VTP_Ref(const struct suckaddr *ip4, const struct suckaddr *ip6,
- const void *id);
+ const char *uds, const void *id);
/*
- * Get a reference to a TCP pool. Either ip4 or ip6 arg must be
- * non-NULL. If recycling is to be used, the id pointer distinguishes
- * the pool per protocol.
+ * Get a reference to a TCP pool. Either one or both of ip4 or
+ * ip6 arg must be non-NULL, or uds must be non-NULL. If recycling
+ * is to be used, the id pointer distinguishes the pool per
+ * protocol.
*/
void VTP_AddRef(struct tcp_pool *);
diff --git a/bin/varnishd/http1/cache_http1.h b/bin/varnishd/http1/cache_http1.h
index f3b3ed2..7dd0c62 100644
--- a/bin/varnishd/http1/cache_http1.h
+++ b/bin/varnishd/http1/cache_http1.h
@@ -31,7 +31,7 @@ struct VSC_vbe;
/* cache_http1_fetch.c [V1F] */
int V1F_SendReq(struct worker *, struct busyobj *, uint64_t *ctr_hdrbytes,
- uint64_t *ctr_bodybytes, int onlycached);
+ uint64_t *ctr_bodybytes, int onlycached, char *addr, char *port);
int V1F_FetchRespHdr(struct busyobj *);
int V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc);
diff --git a/bin/varnishd/http1/cache_http1_fetch.c b/bin/varnishd/http1/cache_http1_fetch.c
index a3b7b4f..1a77021 100644
--- a/bin/varnishd/http1/cache_http1_fetch.c
+++ b/bin/varnishd/http1/cache_http1_fetch.c
@@ -70,7 +70,7 @@ vbf_iter_req_body(void *priv, int flush, const void *ptr, ssize_t l)
int
V1F_SendReq(struct worker *wrk, struct busyobj *bo, uint64_t *ctr_hdrbytes,
- uint64_t *ctr_bodybytes, int onlycached)
+ uint64_t *ctr_bodybytes, int onlycached, char *abuf, char *pbuf)
{
struct http *hp;
int j;
@@ -78,8 +78,6 @@ V1F_SendReq(struct worker *wrk, struct busyobj *bo, uint64_t *ctr_hdrbytes,
uint64_t bytes, hdrbytes;
struct http_conn *htc;
int do_chunked = 0;
- char abuf[VTCP_ADDRBUFSIZE];
- char pbuf[VTCP_PORTBUFSIZE];
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
@@ -98,7 +96,6 @@ V1F_SendReq(struct worker *wrk, struct busyobj *bo, uint64_t *ctr_hdrbytes,
do_chunked = 1;
}
- VTCP_hisname(*htc->rfd, abuf, sizeof abuf, pbuf, sizeof pbuf);
VSLb(bo->vsl, SLT_BackendStart, "%s %s", abuf, pbuf);
(void)VTCP_blocking(*htc->rfd); /* XXX: we should timeout instead */
diff --git a/bin/varnishtest/tests/b00053.vtc b/bin/varnishtest/tests/b00053.vtc
index 09e3d20..0acb9da 100644
--- a/bin/varnishtest/tests/b00053.vtc
+++ b/bin/varnishtest/tests/b00053.vtc
@@ -1,6 +1,6 @@
varnishtest "Does anything get through Unix domain sockets at all ?"
-server s1 {
+server s1 -listen "${tmpdir}/s1.sock" {
rxreq
txresp -body "012345\n"
} -start
diff --git a/bin/varnishtest/tests/b00057.vtc b/bin/varnishtest/tests/b00057.vtc
index 74c73cc..9f75edb 100644
--- a/bin/varnishtest/tests/b00057.vtc
+++ b/bin/varnishtest/tests/b00057.vtc
@@ -1,7 +1,7 @@
varnishtest "Test orderly connection closure of a UDS listen socket"
-server s1 {
+server s1 -listen "${tmpdir}/s1.sock" {
rxreq
txresp -nolen -hdr "Transfer-encoding: chunked"
delay .2
diff --git a/bin/varnishtest/tests/b00059.vtc b/bin/varnishtest/tests/b00059.vtc
index 00ce94f..c529a5f 100644
--- a/bin/varnishtest/tests/b00059.vtc
+++ b/bin/varnishtest/tests/b00059.vtc
@@ -1,6 +1,6 @@
varnishtest "Run a lot of transactions through Unix domain sockets"
-server s0 {
+server s0 -listen "${tmpdir}/s1.sock" {
loop 10 {
rxreq
txresp -body "foo1"
diff --git a/bin/varnishtest/tests/b00060.vtc b/bin/varnishtest/tests/b00060.vtc
index 9e2750a..cdbb2d4 100644
--- a/bin/varnishtest/tests/b00060.vtc
+++ b/bin/varnishtest/tests/b00060.vtc
@@ -1,12 +1,13 @@
varnishtest "VSL tags affected by the use of UDS addresses"
-varnish v1 -arg "-a foo=${tmpdir}/foo.sock -a bar=${tmpdir}/bar.sock" -vcl {
- backend b { .host = "${bad_ip}"; }
-
- sub vcl_recv { return(synth(200)); }
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ txresp
} -start
-client c1 -connect "${tmpdir}/foo.sock" {
+varnish v1 -arg "-a foo=${tmpdir}/v1.sock" -vcl+backend {} -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
txreq
rxresp
} -run
@@ -16,45 +17,12 @@ logexpect l1 -v v1 -d 1 -g session {
expect 0 = SessOpen "^0.0.0.0 0 foo 0.0.0.0 0"
} -run
-logexpect l2 -v v1 -d 1 -g vxid {
+logexpect l2 -v v1 -d 1 -g vxid -c {
expect 0 1001 Begin
- expect * = ReqStart "^0.0.0.0 0 foo$"
-} -run
-
-logexpect l1 -v v1 -d 0 -g session {
- expect 0 * Begin
- expect 0 = SessOpen "^0.0.0.0 0 bar 0.0.0.0 0"
-} -start
-
-logexpect l2 -v v1 -d 0 -g vxid {
- expect 0 * Begin
- expect * = ReqStart "^0.0.0.0 0 bar"
-} -start
-
-client c1 -connect "${tmpdir}/bar.sock" {
- txreq
- rxresp
+ expect * = ReqStart "^0.0.0.0 0$"
} -run
-logexpect l1 -wait
-logexpect l2 -wait
-
-varnish v1 -stop
-
-# For completeness, also test the endpoint name field in ReqStart when
-# Varnish listens at an IP address.
-varnish v2 -vcl {
- backend b { .host = "${bad_ip}"; }
-
- sub vcl_recv { return(synth(200)); }
-} -start
-
-client c2 -connect ${v2_sock} {
- txreq
- rxresp
-} -run
-
-logexpect l3 -v v2 -d 1 -g vxid {
- expect 0 1001 Begin
- expect * = ReqStart "^${v2_addr} [0-9]+ a0$"
+logexpect l2 -v v1 -d 1 -g vxid -b {
+ expect 0 1002 Begin
+ expect * = BackendOpen "${s1_sock} - - -$"
} -run
diff --git a/bin/varnishtest/tests/c00087.vtc b/bin/varnishtest/tests/c00087.vtc
index 5f55cdf..761ba0d 100644
--- a/bin/varnishtest/tests/c00087.vtc
+++ b/bin/varnishtest/tests/c00087.vtc
@@ -1,6 +1,6 @@
varnishtest "VCL *.ip vars as bogo-IPs when -a is UDS, and test ACL matches"
-server s1 {
+server s1 -listen "${tmpdir}/s1.sock" {
rxreq
txresp
} -start
diff --git a/bin/varnishtest/tests/c00088.vtc b/bin/varnishtest/tests/c00088.vtc
new file mode 100644
index 0000000..b39171f
--- /dev/null
+++ b/bin/varnishtest/tests/c00088.vtc
@@ -0,0 +1,44 @@
+varnishtest "Dropping polling of a backend that listens at UDS"
+
+server s1 -listen "${tmpdir}/s1.sock" -repeat 40 {
+ rxreq
+ txresp
+} -start
+
+varnish v1 -vcl {
+ probe default {
+ .window = 8;
+ .initial = 7;
+ .threshold = 8;
+ .interval = 0.1s;
+ }
+ backend s1 {
+ .path = "${s1_sock}";
+ }
+} -start
+
+delay 1
+
+varnish v1 -vcl+backend { } -cliok "vcl.use vcl2" -cliok "vcl.discard vcl1"
+
+delay 1
+
+varnish v1 -cliok "vcl.list"
+varnish v1 -cliok "backend.list -p"
+
+server s1 -break {
+ rxreq
+ expect req.url == /foo
+ txresp -bodylen 4
+} -start
+
+delay 1
+
+client c1 {
+ txreq -url /foo
+ rxresp
+ txreq -url /foo
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 4
+} -run
diff --git a/bin/varnishtest/tests/c00089.vtc b/bin/varnishtest/tests/c00089.vtc
new file mode 100644
index 0000000..960741b
--- /dev/null
+++ b/bin/varnishtest/tests/c00089.vtc
@@ -0,0 +1,33 @@
+varnishtest "Backend close retry with a UDS"
+
+server s1 -listen "${tmpdir}/s1.sock" -repeat 1 {
+ rxreq
+ txresp -bodylen 5
+
+ rxreq
+ accept
+
+ rxreq
+ txresp -bodylen 6
+
+} -start
+
+varnish v1 -vcl+backend {
+ sub vcl_recv {
+ return(pass);
+ }
+} -start
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 5
+
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 6
+} -run
+
+varnish v1 -expect backend_retry == 1
diff --git a/bin/varnishtest/tests/c00090.vtc b/bin/varnishtest/tests/c00090.vtc
new file mode 100644
index 0000000..189748b
--- /dev/null
+++ b/bin/varnishtest/tests/c00090.vtc
@@ -0,0 +1,65 @@
+varnishtest "Forcing health of backends listening at UDS"
+
+server s1 -listen "${tmpdir}/s1.sock" -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+varnish v1 -vcl {
+ backend s1 {
+ .path = "${s1_sock}";
+ .probe = {
+ .window = 8;
+ .initial = 7;
+ .threshold = 8;
+ .interval = 10s;
+ }
+ }
+
+ sub vcl_recv {
+ return(pass);
+ }
+
+} -start
+
+delay 1
+
+varnish v1 -cliok "vcl.list"
+varnish v1 -cliok "backend.list -p"
+varnish v1 -cliok "backend.set_health s1 auto"
+varnish v1 -cliok "backend.list -p"
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+varnish v1 -cliok "backend.list"
+varnish v1 -cliok "backend.set_health s1 sick"
+varnish v1 -cliok "backend.list"
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+varnish v1 -cliok "backend.list"
+varnish v1 -cliok "backend.set_health s1 healthy"
+varnish v1 -cliok "backend.list"
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+varnish v1 -clierr 106 "backend.set_health s1 foo"
+varnish v1 -clierr 106 "backend.set_health s2 foo"
+varnish v1 -clierr 106 "backend.set_health s2 auto"
+varnish v1 -cliok "vcl.list"
+varnish v1 -cliok "backend.list *"
+varnish v1 -cliok "backend.list *.foo"
+varnish v1 -cliok "backend.list vcl1.*"
+
diff --git a/bin/varnishtest/tests/c00091.vtc b/bin/varnishtest/tests/c00091.vtc
new file mode 100644
index 0000000..59c63d1
--- /dev/null
+++ b/bin/varnishtest/tests/c00091.vtc
@@ -0,0 +1,50 @@
+varnishtest "vcl_backend_response{} retry with a UDS backend"
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ txresp -hdr "foo: 1"
+ accept
+ rxreq
+ txresp -hdr "foo: 2"
+} -start
+
+varnish v1 -vcl+backend {
+ sub vcl_recv { return (pass); }
+ sub vcl_backend_response {
+ set beresp.http.bar = bereq.retries;
+ if (beresp.http.foo != bereq.http.stop) {
+ return (retry);
+ }
+ }
+} -start
+
+varnish v1 -cliok "param.set debug +syncvsl"
+
+client c1 {
+ txreq -hdr "stop: 2"
+ rxresp
+ expect resp.http.foo == 2
+} -run
+
+delay .1
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ txresp -hdr "foo: 1"
+ accept
+ rxreq
+ txresp -hdr "foo: 2"
+ accept
+ rxreq
+ txresp -hdr "foo: 3"
+} -start
+
+varnish v1 -cliok "param.set max_retries 2"
+
+client c1 {
+ txreq -hdr "stop: 3"
+ rxresp
+ expect resp.http.foo == 3
+} -run
+
+# XXX: Add a test which exceeds max_retries and gets 503 back
diff --git a/bin/varnishtest/tests/c00092.vtc b/bin/varnishtest/tests/c00092.vtc
new file mode 100644
index 0000000..df85d19
--- /dev/null
+++ b/bin/varnishtest/tests/c00092.vtc
@@ -0,0 +1,32 @@
+varnishtest "Check aborted backend body with a backend listening at UDS"
+
+barrier b1 cond 2
+barrier b2 cond 2
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ txresp -nolen -hdr "Transfer-encoding: chunked"
+ chunked {<HTML>}
+ barrier b1 sync
+ chunked {<HTML>}
+ barrier b2 sync
+} -start
+
+varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend {
+
+} -start
+
+
+client c1 {
+ txreq
+ rxresphdrs
+ expect resp.status == 200
+ rxchunk
+ barrier b1 sync
+ rxchunk
+ barrier b2 sync
+ expect_close
+} -run
+
+
+
diff --git a/bin/varnishtest/tests/c00093.vtc b/bin/varnishtest/tests/c00093.vtc
new file mode 100644
index 0000000..625dc3d
--- /dev/null
+++ b/bin/varnishtest/tests/c00093.vtc
@@ -0,0 +1,39 @@
+varnishtest "Test resp.is_streaming with a UDS backend"
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ txresp -nolen -hdr "Content-Length: 10"
+ delay 1
+ send "1234567890"
+} -start
+
+varnish v1 -vcl+backend {
+ sub vcl_recv {
+ if (req.url == "/synth") {
+ return(synth(200, "OK"));
+ }
+ }
+ sub vcl_synth {
+ set resp.http.streaming = resp.is_streaming;
+ }
+ sub vcl_deliver {
+ set resp.http.streaming = resp.is_streaming;
+ }
+} -start
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.http.streaming == "true"
+
+ delay 0.1
+
+ txreq
+ rxresp
+ expect resp.http.streaming == "false"
+
+ txreq -url /synth
+ rxresp
+ expect resp.http.streaming == "false"
+} -run
+
diff --git a/bin/varnishtest/tests/c00094.vtc b/bin/varnishtest/tests/c00094.vtc
new file mode 100644
index 0000000..546efb0
--- /dev/null
+++ b/bin/varnishtest/tests/c00094.vtc
@@ -0,0 +1,51 @@
+varnishtest "Test Backend Polling with a backend listening at a UDS"
+
+barrier b1 cond 2
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ # Probes
+ loop 8 {
+ rxreq
+ expect req.url == "/"
+ txresp -hdr "Bar: foo" -body "foobar"
+ accept
+ }
+
+ loop 3 {
+ rxreq
+ expect req.url == "/"
+ txresp -status 404 -hdr "Bar: foo" -body "foobar"
+ accept
+ }
+ loop 2 {
+ rxreq
+ expect req.url == "/"
+ txresp -proto "FROBOZ" -status 200 -hdr "Bar: foo" -body "foobar"
+ accept
+ }
+ loop 2 {
+ rxreq
+ expect req.url == "/"
+ send "HTTP/1.1 200 \r\n"
+ accept
+ }
+
+ barrier b1 sync
+} -start
+
+varnish v1 -vcl {
+
+ backend foo {
+ .path = "${s1_sock}";
+ .probe = {
+ .timeout = 1 s;
+ .interval = 0.1 s;
+ }
+ }
+
+} -start
+
+barrier b1 sync
+
+varnish v1 -cliexpect "^CLI RX| -+U+ Good UNIX" "backend.list -p"
+varnish v1 -cliexpect "^CLI RX| -+H{10}-{5}H{2}-{0,5} Happy" "backend.list -p"
diff --git a/bin/varnishtest/tests/d00031.vtc b/bin/varnishtest/tests/d00031.vtc
new file mode 100644
index 0000000..fa11ee3
--- /dev/null
+++ b/bin/varnishtest/tests/d00031.vtc
@@ -0,0 +1,86 @@
+varnishtest "Test round robin director with UDS backends"
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ txresp -body "1"
+} -start
+
+server s2 -listen "${tmpdir}/s2.sock" {
+ rxreq
+ txresp -body "22"
+} -start
+
+server s3 -listen "${tmpdir}/s3.sock" {
+ rxreq
+ txresp -body "333"
+} -start
+
+server s4 -listen "${tmpdir}/s4.sock" {
+ rxreq
+ txresp -body "4444"
+} -start
+
+varnish v1 -vcl+backend {
+ import directors;
+
+ sub vcl_init {
+ new rr = directors.round_robin();
+ rr.add_backend(s1);
+ rr.add_backend(s2);
+ rr.add_backend(s3);
+ rr.add_backend(s4);
+ }
+
+ sub vcl_recv {
+ if (req.method == "DELETE") {
+ rr.remove_backend(s1);
+ rr.remove_backend(s2);
+ rr.remove_backend(s3);
+ return(synth(204));
+ }
+ }
+
+ sub vcl_backend_fetch {
+ set bereq.backend = rr.backend();
+ }
+} -start
+
+client c1 {
+ timeout 3
+ txreq -url "/foo1"
+ rxresp
+ expect resp.bodylen == 1
+ txreq -url "/foo2"
+ rxresp
+ expect resp.bodylen == 2
+ txreq -url "/foo3"
+ rxresp
+ expect resp.bodylen == 3
+ txreq -url "/foo4"
+ rxresp
+ expect resp.bodylen == 4
+} -run
+
+server s1 -start
+server s2 -start
+
+client c2 {
+ timeout 3
+ txreq -url "/foo11"
+ rxresp
+ expect resp.bodylen == 1
+ txreq -url "/foo22"
+ rxresp
+ expect resp.bodylen == 2
+} -run
+
+server s4 -start
+
+client c3 {
+ txreq -req "DELETE"
+ rxresp
+ expect resp.status == 204
+ txreq -url "/foo31"
+ rxresp
+ expect resp.bodylen == 4
+} -run
diff --git a/bin/varnishtest/tests/m00046.vtc b/bin/varnishtest/tests/m00046.vtc
index a5de275..dca4fba 100644
--- a/bin/varnishtest/tests/m00046.vtc
+++ b/bin/varnishtest/tests/m00046.vtc
@@ -21,7 +21,7 @@ client c1 -connect "${tmpdir}/v2.sock" {
expect resp.http.v1_addr == "0.0.0.0"
} -run
-varnish v2 -errvcl {IP constant '"${v1_addr}"'} {
+varnish v2 -errvcl {Cannot convert to an IP address: '"${v1_addr}"'} {
import std;
sub vcl_recv {
diff --git a/bin/varnishtest/tests/t02013.vtc b/bin/varnishtest/tests/t02013.vtc
index 47a226c..3711111 100644
--- a/bin/varnishtest/tests/t02013.vtc
+++ b/bin/varnishtest/tests/t02013.vtc
@@ -1,6 +1,6 @@
varnishtest "Direct H2 start over Unix domain sockets"
-server s1 {
+server s1 -listen "${tmpdir}/s1.sock" {
rxreq
expect req.http.host == foo.bar
txresp \
diff --git a/bin/varnishtest/tests/v00038.vtc b/bin/varnishtest/tests/v00038.vtc
index f4a8c88..d93d4d5 100644
--- a/bin/varnishtest/tests/v00038.vtc
+++ b/bin/varnishtest/tests/v00038.vtc
@@ -87,7 +87,7 @@ varnish v1 -errvcl "Unknown field:" {
}
}
-varnish v1 -errvcl "Mandatory field 'host' missing." {
+varnish v1 -errvcl "Expected .host or .path." {
backend b1 {
.port = "NONE";
}
@@ -109,3 +109,30 @@ varnish v1 -errvcl "Unused backend b1, defined:" {
backend b1 { .host = "127.0.0.1"; }
backend default { .host = "127.0.0.1"; }
}
+
+varnish v1 -errvcl "Address redefinition at:" {
+ backend b1 {
+ .host = "127.0.0.1";
+ .path = "/path/to/uds";
+ }
+}
+
+varnish v1 -errvcl "Must be an absolute path:" {
+ backend b1 {
+ .path = "server.sock";
+ }
+}
+
+shell { rm -f ${tmpdir}/foo }
+
+varnish v1 -errvcl "Cannot stat:" {
+ backend b1 {
+ .path = "${tmpdir}/foo";
+ }
+}
+
+varnish v1 -errvcl "Not a socket:" {
+ backend b1 {
+ .path = "${tmpdir}";
+ }
+}
diff --git a/bin/varnishtest/tests/v00055.vtc b/bin/varnishtest/tests/v00055.vtc
new file mode 100644
index 0000000..4584f1b
--- /dev/null
+++ b/bin/varnishtest/tests/v00055.vtc
@@ -0,0 +1,41 @@
+varnishtest "Check backend connection limit with UDS backends"
+
+barrier b1 cond 2
+barrier b2 cond 2
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ barrier b1 sync
+ barrier b2 sync
+ txresp
+} -start
+
+varnish v1 -vcl {
+
+ backend default {
+ .path = "${s1_sock}";
+ .max_connections = 1;
+ }
+ sub vcl_recv {
+ return(pass);
+ }
+} -start
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -start
+
+
+client c2 {
+ barrier b1 sync
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+barrier b2 sync
+client c1 -wait
+
+varnish v1 -expect backend_busy == 1
diff --git a/bin/varnishtest/tests/v00056.vtc b/bin/varnishtest/tests/v00056.vtc
new file mode 100644
index 0000000..7d3d507
--- /dev/null
+++ b/bin/varnishtest/tests/v00056.vtc
@@ -0,0 +1,70 @@
+varnishtest "Check req.backend.healthy with UDS backends"
+
+barrier b1 cond 2
+barrier b2 cond 2
+barrier b3 cond 2
+barrier b4 cond 2
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ barrier b1 sync
+ expect req.url == "/"
+ txresp -body "slash"
+ accept
+ rxreq
+ barrier b2 sync
+ barrier b3 sync
+ expect req.url == "/"
+ txresp -body "slash"
+ accept
+ barrier b4 sync
+} -start
+
+varnish v1 -vcl {
+
+ import std;
+
+ probe foo {
+ .url = "/";
+ .timeout = 1s;
+ .interval = 1s;
+ .window = 3;
+ .threshold = 2;
+ .initial = 0;
+ }
+
+ backend default {
+ .path = "${s1_sock}";
+ .max_connections = 1;
+ .probe = foo;
+ }
+
+ sub vcl_recv {
+ if (std.healthy(default)) {
+ return(synth(200,"Backend healthy"));
+ } else {
+ return(synth(500,"Backend sick"));
+ }
+ }
+} -start
+
+varnish v1 -cliok "backend.list -p"
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 500
+
+ barrier b1 sync
+
+ barrier b2 sync
+ txreq
+ rxresp
+ expect resp.status == 500
+
+ barrier b3 sync
+ barrier b4 sync
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/bin/varnishtest/tests/v00057.vtc b/bin/varnishtest/tests/v00057.vtc
new file mode 100644
index 0000000..58d8de3
--- /dev/null
+++ b/bin/varnishtest/tests/v00057.vtc
@@ -0,0 +1,41 @@
+varnishtest "Test backend .hosthdr with UDS backends"
+
+server s1 -listen "${tmpdir}/s1.sock" {
+ rxreq
+ expect req.url == "/foo"
+ expect req.http.host == "snafu"
+ txresp -body "foo1"
+
+ rxreq
+ expect req.url == "/bar"
+ expect req.http.host == "0.0.0.0"
+ txresp -body "foo1"
+} -start
+
+varnish v1 -vcl+backend { } -start
+
+client c1 {
+ txreq -url "/foo" -hdr "Host: snafu"
+ rxresp
+ txreq -url "/bar"
+ rxresp
+} -run
+
+server s2 -listen "${tmpdir}/s2.sock" {
+ rxreq
+ expect req.url == "/barf"
+ expect req.http.host == "FOObar"
+ txresp -body "foo1"
+} -start
+
+varnish v1 -vcl {
+ backend b1 {
+ .path = "${s2_sock}";
+ .host_header = "FOObar";
+ }
+}
+
+client c1 {
+ txreq -url "/barf"
+ rxresp
+} -run
diff --git a/bin/varnishtest/vtc_server.c b/bin/varnishtest/vtc_server.c
index 9c084ba..9496046 100644
--- a/bin/varnishtest/vtc_server.c
+++ b/bin/varnishtest/vtc_server.c
@@ -392,9 +392,15 @@ cmd_server_genvcl(struct vsb *vsb)
AZ(pthread_mutex_lock(&server_mtx));
VTAILQ_FOREACH(s, &servers, list) {
- VSB_printf(vsb,
- "backend %s { .host = \"%s\"; .port = \"%s\"; }\n",
- s->name, s->aaddr, s->aport);
+ if (*s->listen != '/')
+ VSB_printf(vsb,
+ "backend %s { .host = \"%s\"; "
+ ".port = \"%s\"; }\n",
+ s->name, s->aaddr, s->aport);
+ else
+ VSB_printf(vsb,
+ "backend %s { .path = \"%s\"; }\n",
+ s->name, s->listen);
}
AZ(pthread_mutex_unlock(&server_mtx));
}
diff --git a/include/tbl/backend_poll.h b/include/tbl/backend_poll.h
index a6fa339..5c1e207 100644
--- a/include/tbl/backend_poll.h
+++ b/include/tbl/backend_poll.h
@@ -31,6 +31,7 @@
BITMAP(good_ipv4, '4', "Good IPv4", 0)
BITMAP(good_ipv6, '6', "Good IPv6", 0)
+BITMAP(good_unix, 'U', "Good UNIX", 0)
BITMAP( err_xmit, 'x', "Error Xmit", 0)
BITMAP(good_xmit, 'X', "Good Xmit", 0)
BITMAP( err_recv, 'r', "Error Recv", 0)
diff --git a/include/vrt.h b/include/vrt.h
index c29f8d4..5a25e6b 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -53,6 +53,7 @@
*
*
* 6.2 (scheduled for: 2018-03-15)
+ * path field added to struct vrt_backend
* VRT_Healthy() added
* VRT_VSC_Alloc() added
* VRT_VSC_Destroy() added
@@ -253,6 +254,7 @@ extern const void * const vrt_magic_string_unset;
rigid char *ipv4_addr; \
rigid char *ipv6_addr; \
rigid char *port; \
+ rigid char *path; \
rigid char *hosthdr; \
double connect_timeout; \
double first_byte_timeout; \
@@ -266,6 +268,7 @@ extern const void * const vrt_magic_string_unset;
DA(ipv4_addr); \
DA(ipv6_addr); \
DA(port); \
+ DA(path); \
DA(hosthdr); \
DN(connect_timeout); \
DN(first_byte_timeout); \
diff --git a/include/vus.h b/include/vus.h
index 3747d92..ddaf331 100644
--- a/include/vus.h
+++ b/include/vus.h
@@ -33,3 +33,4 @@ typedef int vus_resolved_f(void *priv, const struct sockaddr_un *);
int VUS_resolver(const char *path, vus_resolved_f *func, void *priv,
const char **err);
int VUS_bind(const struct sockaddr_un *uds, const char **errp);
+int VUS_connect(const char *path, int msec);
diff --git a/lib/libvarnish/vus.c b/lib/libvarnish/vus.c
index 8471d15..69a223d 100644
--- a/lib/libvarnish/vus.c
+++ b/lib/libvarnish/vus.c
@@ -32,10 +32,12 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
+#include <poll.h>
#include "vdef.h"
#include "vas.h"
#include "vus.h"
+#include "vtcp.h"
int
VUS_resolver(const char *path, vus_resolved_f *func, void *priv,
@@ -95,3 +97,60 @@ VUS_bind(const struct sockaddr_un *uds, const char **errp)
}
return (sd);
}
+
+int
+VUS_connect(const char *path, int msec)
+{
+ int s, i;
+ struct pollfd fds[1];
+ struct sockaddr_un uds;
+ socklen_t sl = (socklen_t) sizeof(uds);
+
+ if (path == NULL)
+ return (-1);
+ /* Attempt the connect */
+ assert(strlen(path) + 1 <= sizeof(uds.sun_path));
+ uds.sun_family = PF_UNIX;
+ strcpy(uds.sun_path, path);
+ AN(sl);
+
+ s = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (s < 0)
+ return (s);
+
+ /* Set the socket non-blocking */
+ if (msec != 0)
+ (void)VTCP_nonblocking(s);
+
+ i = connect(s, (const struct sockaddr *)&uds, sl);
+ if (i == 0)
+ return (s);
+ if (errno != EINPROGRESS) {
+ closefd(&s);
+ return (-1);
+ }
+
+ if (msec < 0) {
+ /*
+ * Caller is responsible for waiting and
+ * calling VTCP_connected
+ */
+ return (s);
+ }
+
+ assert(msec > 0);
+ /* Exercise our patience, polling for write */
+ fds[0].fd = s;
+ fds[0].events = POLLWRNORM;
+ fds[0].revents = 0;
+ i = poll(fds, 1, msec);
+
+ if (i == 0) {
+ /* Timeout, close and give up */
+ closefd(&s);
+ errno = ETIMEDOUT;
+ return (-1);
+ }
+
+ return (VTCP_connected(s));
+}
diff --git a/lib/libvcc/vcc_backend.c b/lib/libvcc/vcc_backend.c
index db5ce71..640481d 100644
--- a/lib/libvcc/vcc_backend.c
+++ b/lib/libvcc/vcc_backend.c
@@ -81,20 +81,19 @@ Emit_Sockaddr(struct vcc *tl, const struct token *t_host,
Fb(tl, 0, "\t.ipv6_addr = \"%s\",\n", ipv6a);
}
Fb(tl, 0, "\t.port = \"%s\",\n", pa);
+ Fb(tl, 0, "\t.path = (void *) 0,\n");
}
/*--------------------------------------------------------------------
- * Parse a backend probe specification
+ * Disallow mutually exclusive field definitions
*/
static void
-vcc_ProbeRedef(struct vcc *tl, struct token **t_did,
+vcc_Redef(struct vcc *tl, const char *redef, struct token **t_did,
struct token *t_field)
{
- /* .url and .request are mutually exclusive */
-
if (*t_did != NULL) {
- VSB_printf(tl->sb, "Probe request redefinition at:\n");
+ VSB_printf(tl->sb, "%s redefinition at:\n", redef);
vcc_ErrWhere(tl, t_field);
VSB_printf(tl->sb, "Previous definition:\n");
vcc_ErrWhere(tl, *t_did);
@@ -103,6 +102,10 @@ vcc_ProbeRedef(struct vcc *tl, struct token **t_did,
*t_did = t_field;
}
+/*--------------------------------------------------------------------
+ * Parse a backend probe specification
+ */
+
static void
vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **name)
{
@@ -152,7 +155,7 @@ vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **name)
vcc_IsField(tl, &t_field, fs);
ERRCHK(tl);
if (vcc_IdIs(t_field, "url")) {
- vcc_ProbeRedef(tl, &t_did, t_field);
+ vcc_Redef(tl, "Probe request", &t_did, t_field);
ERRCHK(tl);
ExpectErr(tl, CSTR);
Fh(tl, 0, "\t.url = ");
@@ -160,7 +163,7 @@ vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **name)
Fh(tl, 0, ",\n");
vcc_NextToken(tl);
} else if (vcc_IdIs(t_field, "request")) {
- vcc_ProbeRedef(tl, &t_did, t_field);
+ vcc_Redef(tl, "Probe request", &t_did, t_field);
ERRCHK(tl);
ExpectErr(tl, CSTR);
Fh(tl, 0, "\t.request =\n");
@@ -294,8 +297,10 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
struct token *t_val;
struct token *t_host = NULL;
struct token *t_port = NULL;
+ struct token *t_path = NULL;
struct token *t_hosthdr = NULL;
struct symbol *pb;
+ struct token *t_did = NULL;
struct fld_spec *fs;
struct inifin *ifp;
struct vsb *vsb;
@@ -304,8 +309,9 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
double t;
fs = vcc_FldSpec(tl,
- "!host",
+ "?host",
"?port",
+ "?path",
"?host_header",
"?connect_timeout",
"?first_byte_timeout",
@@ -345,6 +351,8 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
vcc_IsField(tl, &t_field, fs);
ERRCHK(tl);
if (vcc_IdIs(t_field, "host")) {
+ vcc_Redef(tl, "Address", &t_did, t_field);
+ ERRCHK(tl);
ExpectErr(tl, CSTR);
assert(tl->t->dec != NULL);
t_host = tl->t;
@@ -356,6 +364,14 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
t_port = tl->t;
vcc_NextToken(tl);
SkipToken(tl, ';');
+ } else if (vcc_IdIs(t_field, "path")) {
+ vcc_Redef(tl, "Address", &t_did, t_field);
+ ERRCHK(tl);
+ ExpectErr(tl, CSTR);
+ assert(tl->t->dec != NULL);
+ t_path = tl->t;
+ vcc_NextToken(tl);
+ SkipToken(tl, ';');
} else if (vcc_IdIs(t_field, "host_header")) {
ExpectErr(tl, CSTR);
assert(tl->t->dec != NULL);
@@ -430,9 +446,19 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
vcc_FieldsOk(tl, fs);
ERRCHK(tl);
- /* Check that the hostname makes sense */
- assert(t_host != NULL);
- Emit_Sockaddr(tl, t_host, t_port);
+ if (t_host == NULL && t_path == NULL) {
+ VSB_printf(tl->sb, "Expected .host or .path.\n");
+ vcc_ErrWhere(tl, t_be);
+ return;
+ }
+
+ assert(t_host != NULL || t_path != NULL);
+ if (t_host != NULL)
+ /* Check that the hostname makes sense */
+ Emit_Sockaddr(tl, t_host, t_port);
+ else
+ /* Check that the path can be a legal UDS */
+ Emit_UDS_Path(tl, t_path, "Backend path");
ERRCHK(tl);
ExpectErr(tl, '}');
@@ -440,11 +466,14 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
/* We have parsed it all, emit the ident string */
/* Emit the hosthdr field, fall back to .host if not specified */
+ /* If .path is specified, set "0.0.0.0". */
Fb(tl, 0, "\t.hosthdr = ");
if (t_hosthdr != NULL)
EncToken(tl->fb, t_hosthdr);
- else
+ else if (t_host != NULL)
EncToken(tl->fb, t_host);
+ else
+ Fb(tl, 0, "\"0.0.0.0\"");
Fb(tl, 0, ",\n");
/* Close the struct */
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
index 2d9478b..f530095 100644
--- a/lib/libvcc/vcc_compile.h
+++ b/lib/libvcc/vcc_compile.h
@@ -327,6 +327,8 @@ void Resolve_Sockaddr(struct vcc *tl, const char *host, const char *defport,
const char **ipv4, const char **ipv4_ascii, const char **ipv6,
const char **ipv6_ascii, const char **p_ascii, int maxips,
const struct token *t_err, const char *errid);
+void Emit_UDS_Path(struct vcc *tl, const struct token *t_path,
+ const char *errid);
double vcc_TimeUnit(struct vcc *);
void vcc_ByteVal(struct vcc *, double *);
void vcc_NumVal(struct vcc *, double *, int *);
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index f67b141..17209dc 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -729,6 +729,19 @@ vcc_expr4(struct vcc *tl, struct expr **e, vcc_type_t fmt)
case CSTR:
assert(fmt != VOID);
if (fmt == IP) {
+ if (*tl->t->dec == '/') {
+ /*
+ * On some platforms (e.g. FreeBSD),
+ * getaddrinfo(3) may resolve a path to a
+ * sockaddr_un if it happens to exist and
+ * is a socket. So don't let that happen.
+ */
+ VSB_printf(tl->sb,
+ "Cannot convert to an IP address: ");
+ vcc_ErrToken(tl, tl->t);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
Resolve_Sockaddr(tl, tl->t->dec, "80",
&ip, NULL, &ip, NULL, NULL, 1,
tl->t, "IP constant");
diff --git a/lib/libvcc/vcc_utils.c b/lib/libvcc/vcc_utils.c
index a2ae14d..987eb98 100644
--- a/lib/libvcc/vcc_utils.c
+++ b/lib/libvcc/vcc_utils.c
@@ -33,6 +33,10 @@
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
#include "vcc_compile.h"
@@ -161,6 +165,7 @@ rs_callback(void *priv, const struct suckaddr *vsa)
assert(VSA_Sane(vsa));
v = VSA_Get_Proto(vsa);
+ assert(v != AF_UNIX);
VTCP_name(vsa, a, sizeof a, p, sizeof p);
VSB_printf(rss->vsb, "\t%s:%s\n", a, p);
if (v == AF_INET) {
@@ -252,6 +257,42 @@ Resolve_Sockaddr(struct vcc *tl,
FREE_OBJ(rss);
}
+/*
+ * For UDS, we do not create a VSA. Check if it's an absolute path, can
+ * be accessed, and is a socket. If so, just emit the path field and set
+ * the IP suckaddrs to NULL.
+ */
+void
+Emit_UDS_Path(struct vcc *tl, const struct token *t_path, const char *errid)
+{
+ struct stat st;
+
+ AN(t_path);
+ AN(t_path->dec);
+
+ if (*t_path->dec != '/') {
+ VSB_printf(tl->sb,
+ "%s: Must be an absolute path:\n", errid);
+ vcc_ErrWhere(tl, t_path);
+ return;
+ }
+ errno = 0;
+ if (stat(t_path->dec, &st) != 0) {
+ VSB_printf(tl->sb, "%s: Cannot stat: %s\n", errid,
+ strerror(errno));
+ vcc_ErrWhere(tl, t_path);
+ return;
+ }
+ if (! S_ISSOCK(st.st_mode)) {
+ VSB_printf(tl->sb, "%s: Not a socket:\n", errid);
+ vcc_ErrWhere(tl, t_path);
+ return;
+ }
+ Fb(tl, 0, "\t.path = \"%s\",\n", t_path->dec);
+ Fb(tl, 0, "\t.ipv4_suckaddr = (void *) 0,\n");
+ Fb(tl, 0, "\t.ipv6_suckaddr = (void *) 0,\n");
+}
+
/*--------------------------------------------------------------------
* Recognize and convert units of time, return seconds.
*/
More information about the varnish-commit
mailing list