diff --git a/src/FwdState.cc b/src/FwdState.cc
index d0c1b09..424e87f 100644
--- a/src/FwdState.cc
+++ b/src/FwdState.cc
@@ -119,7 +119,8 @@ void
FwdState::closeServerConnection(const char *reason)
{
debugs(17, 3, "because " << reason << "; " << serverConn);
- comm_remove_close_handler(serverConn->fd, fwdServerClosedWrapper, this);
+ comm_remove_close_handler(serverConn->fd, closeHandler);
+ closeHandler = NULL;
fwdPconnPool->noteUses(fd_table[serverConn->fd].pconn.uses);
serverConn->close();
}
@@ -443,7 +444,8 @@ FwdState::unregister(Comm::ConnectionPointer &conn)
debugs(17, 3, HERE << entry->url() );
assert(serverConnection() == conn);
assert(Comm::IsConnOpen(conn));
- comm_remove_close_handler(conn->fd, fwdServerClosedWrapper, this);
+ comm_remove_close_handler(serverConn->fd, closeHandler);
+ closeHandler = NULL;
serverConn = NULL;
}
@@ -676,7 +678,7 @@ FwdState::connectDone(const Comm::ConnectionPointer &conn, Comm::Flag status, in
debugs(17, 3, HERE << serverConnection() << ": '" << entry->url() << "'" );
- comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
+ closeHandler = comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
if (serverConnection()->getPeer())
peerConnectSucceded(serverConnection()->getPeer());
@@ -815,7 +817,8 @@ FwdState::connectStart()
request->hier.note(serverConn, pinned_connection->pinning.host);
if (pinned_connection->pinnedAuth())
request->flags.auth = true;
- comm_add_close_handler(serverConn->fd, fwdServerClosedWrapper, this);
+
+ closeHandler = comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
/* Update server side TOS and Netfilter mark on the connection. */
if (Ip::Qos::TheConfig.isAclTosActive()) {
@@ -865,7 +868,7 @@ FwdState::connectStart()
debugs(17, 3, HERE << "reusing pconn " << serverConnection());
++n_tries;
- comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
+ closeHandler = comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
/* Update server side TOS and Netfilter mark on the connection. */
if (Ip::Qos::TheConfig.isAclTosActive()) {
diff --git a/src/clients/Client.h b/src/clients/Client.h
index 0347408..10dc49e 100644
--- a/src/clients/Client.h
+++ b/src/clients/Client.h
@@ -99,7 +99,9 @@ protected:
virtual void sentRequestBody(const CommIoCbParams &io) = 0;
virtual void doneSendingRequestBody() = 0;
- virtual void closeServer() = 0; /**< end communication with the server */
+ /// Use this to end communication with the server. The call cancels our
+ /// closure handler and tells FwdState to forget about the connection.
+ virtual void closeServer() = 0;
virtual bool doneWithServer() const = 0; /**< did we end communication? */
/// whether we may receive more virgin response body bytes
virtual bool mayReadVirginReplyBody() const = 0;
diff --git a/src/comm.cc b/src/comm.cc
index 54a1344..700fe9a 100644
--- a/src/comm.cc
+++ b/src/comm.cc
@@ -976,7 +976,7 @@ comm_udp_sendto(int fd,
return Comm::COMM_ERROR;
}
-void
+AsyncCall::Pointer
comm_add_close_handler(int fd, CLCB * handler, void *data)
{
debugs(5, 5, "comm_add_close_handler: FD " << fd << ", handler=" <<
@@ -985,6 +985,7 @@ comm_add_close_handler(int fd, CLCB * handler, void *data)
AsyncCall::Pointer call=commCbCall(5,4, "SomeCloseHandler",
CommCloseCbPtrFun(handler, data));
comm_add_close_handler(fd, call);
+ return call;
}
void
diff --git a/src/comm.h b/src/comm.h
index 6647d09..02afb45 100644
--- a/src/comm.h
+++ b/src/comm.h
@@ -79,7 +79,7 @@ int ignoreErrno(int);
void commCloseAllSockets(void);
void checkTimeouts(void);
-void comm_add_close_handler(int fd, CLCB *, void *);
+AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *, void *);
void comm_add_close_handler(int fd, AsyncCall::Pointer &);
void comm_remove_close_handler(int fd, CLCB *, void *);
void comm_remove_close_handler(int fd, AsyncCall::Pointer &);
diff --git a/src/http.cc b/src/http.cc
index bdd4596..65b452e 100644
--- a/src/http.cc
+++ b/src/http.cc
@@ -165,7 +165,8 @@ HttpStateData::httpTimeout(const CommTimeoutCbParams ¶ms)
fwd->fail(new ErrorState(ERR_READ_TIMEOUT, Http::scGatewayTimeout, fwd->request));
}
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::httpTimeout");
}
/// Remove an existing public store entry if the incoming response (to be
@@ -1150,7 +1151,8 @@ HttpStateData::readReply(const CommIoCbParams &io)
err->xerrno = io.xerrno;
fwd->fail(err);
flags.do_next_read = false;
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::readReply");
}
return;
@@ -1306,7 +1308,8 @@ HttpStateData::continueAfterParsingHeader()
entry->reset();
fwd->fail(new ErrorState(error, Http::scBadGateway, fwd->request));
flags.do_next_read = false;
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::continueAfterParsingHeader");
return false; // quit on error
}
@@ -1540,7 +1543,8 @@ HttpStateData::wroteLast(const CommIoCbParams &io)
ErrorState *err = new ErrorState(ERR_WRITE_ERROR, Http::scBadGateway, fwd->request);
err->xerrno = io.xerrno;
fwd->fail(err);
- serverConnection->close();
+ closeServer();
+ mustStop("HttpStateData::wroteLast");
return;
}
@@ -1568,7 +1572,6 @@ HttpStateData::sendComplete()
request->hier.peer_http_request_sent = current_time;
}
-// Close the HTTP server connection. Used by serverComplete().
void
HttpStateData::closeServer()
{
@@ -2371,8 +2374,9 @@ HttpStateData::handleMoreRequestBodyAvailable()
debugs(11, DBG_IMPORTANT, "http handleMoreRequestBodyAvailable: Likely proxy abuse detected '" << request->client_addr << "' -> '" << entry->url() << "'" );
if (virginReply()->sline.status() == Http::scInvalidHeader) {
- serverConnection->close();
- return;
+ closeServer();
+ mustStop("HttpStateData::handleMoreRequestBodyAvailable");
+ return;
}
}
}
diff --git a/src/FwdState.h b/src/FwdState.h
index 56dad30..b724b13 100644
--- a/src/FwdState.h
+++ b/src/FwdState.h
@@ -150,6 +150,8 @@ private:
Comm::ConnectionPointer serverConn; ///< a successfully opened connection to a server.
+ AsyncCall::Pointer closeHandler; ///< The serverConn close handler
+
/// possible pconn race states
typedef enum { raceImpossible, racePossible, raceHappened } PconnRace;
PconnRace pconnRace; ///< current pconn race state
diff --git a/src/tests/stub_comm.cc b/src/tests/stub_comm.cc
index abd3a6b..746ec92 100644
--- a/src/tests/stub_comm.cc
+++ b/src/tests/stub_comm.cc
@@ -57,7 +57,7 @@ int commUnsetConnTimeout(const Comm::ConnectionPointer &conn) STUB_RETVAL(-1)
int ignoreErrno(int ierrno) STUB_RETVAL(-1)
void commCloseAllSockets(void) STUB
void checkTimeouts(void) STUB
-void comm_add_close_handler(int fd, CLCB *, void *) STUB
+AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *, void *) STUB
void comm_add_close_handler(int fd, AsyncCall::Pointer &) STUB
void comm_remove_close_handler(int fd, CLCB *, void *) STUB
void comm_remove_close_handler(int fd, AsyncCall::Pointer &)STUB