Commit f6c4379a authored by Martin Blix Grydeland's avatar Martin Blix Grydeland

On return from waitinglist, do a poll() on the socket to see if the

client has closed the connection and gone away. If so, release the
session early.

Fixes: #1252
parent f91fc4d9
......@@ -399,7 +399,7 @@ HSH_Lookup(struct req *req)
assert(oc->objhead == oh);
oc->refcnt++;
Lck_Unlock(&oh->mtx);
assert(hash->deref(oh));
assert(HSH_DerefObjHead(&wrk->stats, &oh));
o = oc_getobj(&wrk->stats, oc);
CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
if (!cache_param->obj_readonly && o->hits < INT_MAX)
......@@ -694,13 +694,30 @@ HSH_Deref(struct dstat *ds, struct objcore *oc, struct object **oo)
if (oh != NULL) {
/* Drop our ref on the objhead */
assert(oh->refcnt > 0);
if (hash->deref(oh))
return (0);
HSH_DeleteObjHead(ds, oh);
(void)HSH_DerefObjHead(ds, &oh);
}
return (0);
}
int
HSH_DerefObjHead(struct dstat *ds, struct objhead **poh)
{
struct objhead *oh;
int r;
AN(ds);
AN(poh);
oh = *poh;
*poh = NULL;
CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
assert(oh->refcnt > 0);
r = hash->deref(oh);
if (!r)
HSH_DeleteObjHead(ds, oh);
return (r);
}
void
HSH_Init(const struct hash_slinger *slinger)
{
......
......@@ -74,6 +74,7 @@
#include <stdlib.h>
#include "cache.h"
#include "hash/hash_slinger.h"
#include "vcl.h"
#include "vct.h"
......@@ -329,6 +330,19 @@ HTTP1_Session(struct worker *wrk, struct req *req)
return;
}
/*
* Return from waitinglist. Check to see if the remote has left.
*/
if (req->req_step == R_STP_LOOKUP && VTCP_check_hup(sp->fd)) {
AN(req->hash_objhead);
(void)HSH_DerefObjHead(&wrk->stats, &req->hash_objhead);
AZ(req->hash_objhead);
SES_Close(sp, SC_REM_CLOSE);
sdr = http1_cleanup(sp, wrk, req);
assert(sdr == SESS_DONE_RET_GONE);
return;
}
if (sp->sess_step == S_STP_NEWREQ) {
HTTP1_Init(req->htc, req->ws, sp->fd, req->vsl,
cache_param->http_req_size,
......
......@@ -98,6 +98,7 @@ struct objhead {
void HSH_Unbusy(struct dstat *, struct objcore *);
void HSH_Complete(struct objcore *oc);
void HSH_DeleteObjHead(struct dstat *, struct objhead *oh);
int HSH_DerefObjHead(struct dstat *, struct objhead **poh);
int HSH_Deref(struct dstat *, struct objcore *oc, struct object **o);
#endif /* VARNISH_CACHE_CHILD */
......
varnishtest "#1252 - Drop remote closed connections returning from waitinglists"
# This test case is disabled because it will only pass on platforms
# where the tcp_keepalive_* runtime arguments are available, and also
# because it requires "-t 75" argument to varnishtest (remote closed
# state will only be detected after FIN timeout has passed (60s))
server s1 {
rxreq
expect req.http.X-Client == "1"
sema r1 sync 2
delay 75
close
} -start
server s2 {
rxreq
expect req.url == "/should/not/happen"
txresp
} -start
varnish v1 -arg "-p debug=+waitinglist -p tcp_keepalive_time=1s -p tcp_keepalive_probes=1 -p tcp_keepalive_intvl=1s -p first_byte_timeout=70" -vcl+backend {
sub vcl_recv {
if (req.http.x-client == "2") {
set req.backend = s2;
}
}
} -start
client c1 {
timeout 70
txreq -hdr "X-Client: 1"
rxresp
expect resp.status == 503
} -start
client c2 {
sema r1 sync 2
txreq -hdr "X-Client: 2"
delay 1
} -start
client c1 -wait
client c2 -wait
......@@ -62,6 +62,7 @@ int VTCP_filter_http(int sock);
int VTCP_blocking(int sock);
int VTCP_nonblocking(int sock);
int VTCP_linger(int sock, int linger);
int VTCP_check_hup(int sock);
#ifdef SOL_SOCKET
int VTCP_port(const struct sockaddr_storage *addr);
......
......@@ -308,3 +308,22 @@ VTCP_linger(int sock, int linger)
VTCP_Assert(i);
return (i);
}
/*--------------------------------------------------------------------
* Do a poll to check for remote HUP
*/
int
VTCP_check_hup(int sock)
{
struct pollfd pfd;
assert(sock > 0);
pfd.fd = sock;
pfd.events = POLLOUT;
pfd.revents = 0;
if (poll(&pfd, 1, 0) == 1 && pfd.revents & POLLHUP)
return (1);
return (0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment