*
* $Id$
*
- *
- * XXX: When we switch VCL we can have vbe_conn's dangling from
- * XXX: the backends no longer used. When the VCL's refcount
- * XXX: drops to zero we should zap them.
*/
#include <sys/types.h>
TAILQ_HEAD(, vbe_conn) connlist;
};
-/*--------------------------------------------------------------------*/
-
+/*--------------------------------------------------------------------
+ * Try to get a socket connected to one of the addresses on the list.
+ * We start from the cached "last good" address and try all items on
+ * the list exactly once.
+ * If a new DNS lookup is made while we try, we start over and try the
+ * new list exactly once.
+ */
static int
bes_conn_try_list(struct sess *sp, struct bes *bes)
{
struct addrinfo *ai, *from;
- struct sockaddr_storage ss;
- int fam, sockt, proto;
- socklen_t alen;
int s, loops;
- char abuf1[TCP_ADDRBUFSIZE], abuf2[TCP_ADDRBUFSIZE];
- char pbuf1[TCP_PORTBUFSIZE], pbuf2[TCP_PORTBUFSIZE];
unsigned myseq;
+ CHECK_OBJ_NOTNULL(bes, BES_MAGIC);
+ if (bes->addr == NULL)
+ return (-1);
+ AN(bes->last_addr);
+
/* Called with lock held */
myseq = bes->dnsseq;
loops = 0;
- from = bes->last_addr;
- for (ai = from; ai != NULL && (loops != 1 || ai != from);) {
- fam = ai->ai_family;
- sockt = ai->ai_socktype;
- proto = ai->ai_protocol;
- alen = ai->ai_addrlen;
- assert(alen <= sizeof ss);
- memcpy(&ss, ai->ai_addr, alen);
- UNLOCK(&sp->backend->mtx);
- s = socket(fam, sockt, proto);
- if (s >= 0 && connect(s, (void *)&ss, alen)) {
- AZ(close(s));
- s = -1;
- }
- if (s >= 0) {
- TCP_myname(s, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1);
- TCP_name((void*)&ss, alen,
- abuf2, sizeof abuf2, pbuf2, sizeof pbuf2);
- WSL(sp->wrk, SLT_BackendOpen, s, "%s %s %s %s %s",
- sp->backend->vcl_name, abuf1, pbuf1, abuf2, pbuf2);
- }
- LOCK(&sp->backend->mtx);
- if (s >= 0) {
+ ai = from = bes->last_addr;
+ while (1) {
+
+ /* NB: releases/acquires lock */
+ s = VBE_TryConnect(sp, ai);
+
+ if (s >= 0) {
+ /* Update cached "last good" if still valid */
if (myseq == bes->dnsseq)
bes->last_addr = ai;
return (s);
}
+
if (myseq != bes->dnsseq) {
+ /* A DNS-lookup happended, try again from start */
loops = 0;
from = bes->last_addr;
ai = from;
} else {
+ /* Try next one */
ai = ai->ai_next;
if (ai == NULL) {
loops++;
ai = bes->addr;
}
}
+ if (loops == 1 && ai == from)
+ return (-1);
}
- return (-1);
+}
+
+/*--------------------------------------------------------------------*/
+
+static const char *
+bes_dns_lookup(struct backend *bp)
+{
+ struct addrinfo *res, hint, *old;
+ struct bes *bes;
+ int error;
+
+ CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
+ CAST_OBJ_NOTNULL(bes, bp->priv, BES_MAGIC);
+
+ bes->dnstime = TIM_mono();
+
+ /* Let go of lock while we do sleepable stuff */
+ UNLOCK(&bp->mtx);
+
+ memset(&hint, 0, sizeof hint);
+ hint.ai_family = PF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+ res = NULL;
+ error = getaddrinfo(bes->hostname,
+ bes->portname == NULL ? "http" : bes->portname,
+ &hint, &res);
+ LOCK(&bp->mtx);
+ if (error) {
+ if (res != NULL)
+ freeaddrinfo(res);
+ return(gai_strerror(error));
+ }
+ bes->dnsseq++;
+ old = bes->addr;
+ bes->last_addr = res;
+ bes->addr = res;
+ if (old != NULL)
+ freeaddrinfo(old);
+ return (NULL);
}
/*--------------------------------------------------------------------*/
{
int s;
struct bes *bes;
- struct addrinfo *res, hint, *old;
- int error;
CAST_OBJ_NOTNULL(bes, bp->priv, BES_MAGIC);
return (-1);
}
- /* Then do another lookup to catch DNS changes */
- bes->dnstime = TIM_mono();
- UNLOCK(&bp->mtx);
-
- memset(&hint, 0, sizeof hint);
- hint.ai_family = PF_UNSPEC;
- hint.ai_socktype = SOCK_STREAM;
- res = NULL;
- error = getaddrinfo(bes->hostname,
- bes->portname == NULL ? "http" : bes->portname,
- &hint, &res);
- if (error) {
- if (res != NULL)
- freeaddrinfo(res);
- printf("getaddrinfo: %s\n", gai_strerror(error)); /* XXX */
- LOCK(&bp->mtx);
- } else {
- LOCK(&bp->mtx);
- bes->dnsseq++;
- old = bes->addr;
- bes->last_addr = res;
- bes->addr = res;
- if (old != NULL)
- freeaddrinfo(old);
- }
+ (void)bes_dns_lookup(bp);
/* And try the entire list */
s = bes_conn_try_list(sp, bes);
{
struct backend *b;
struct bes *bes;
+ const char *p;
/*
* Scan existing backends to see if we can recycle one of them.
AN(t->host);
REPLACE(bes->hostname, t->host);
+ /*
+ * The VCL compiler already did a lookup, but we'll do another one
+ * here, just in case...
+ */
+ LOCK(&b->mtx);
+ p = bes_dns_lookup(b);
+ UNLOCK(&b->mtx);
+ if (p != NULL)
+ printf("Warning: could not lookup backend %s (%s:%s): %s",
+ t->name, t->host, t->port, p);
+
*bp = b;
}