From: Amos Jeffries Date: Fri, 16 Jul 2010 12:10:38 +0000 (+1200) Subject: Improved Async implementation. X-Git-Tag: take08~55^2~124^2~120 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=294775b5ac63022a3297456c22ec0e93b936faba;p=thirdparty%2Fsquid.git Improved Async implementation. * use AsyncJob::AsyncStart instead of start() * implements doneAll() * handle timeouts on INPROGRESS states --- diff --git a/src/adaptation/icap/Xaction.cc b/src/adaptation/icap/Xaction.cc index 8f7d7bec40..74eb3b22b0 100644 --- a/src/adaptation/icap/Xaction.cc +++ b/src/adaptation/icap/Xaction.cc @@ -132,7 +132,7 @@ void Adaptation::Icap::Xaction::openConnection() ConnOpener *cs = new ConnOpener(connection, connector); cs->setHost(s.cfg().host.termedBuf()); cs->connect_timeout = TheConfig.connect_timeout(service().cfg().bypass); - cs->start(); + AsyncJob::AsyncStart(cs); } /* diff --git a/src/comm/ConnOpener.cc b/src/comm/ConnOpener.cc index 62b82e6b85..4a4659ebd5 100644 --- a/src/comm/ConnOpener.cc +++ b/src/comm/ConnOpener.cc @@ -26,6 +26,20 @@ ConnOpener::~ConnOpener() solo = NULL; } +bool +ConnOpener::doneAll() const +{ + // is the conn to be opened still waiting? + if (solo != NULL) + return false; + + // is the callback still to be called? + if (callback != NULL) + return false; + + return true; +} + void ConnOpener::setHost(const char * new_host) { @@ -47,19 +61,24 @@ ConnOpener::getHost() const void ConnOpener::callCallback(comm_err_t status, int xerrno) { - /* remove handlers we don't want to happen now */ - comm_remove_close_handler(solo->fd, ConnOpener::EarlyAbort, this); - commSetTimeout(solo->fd, -1, NULL, NULL); - - typedef CommConnectCbParams Params; - Params ¶ms = GetCommParams(callback); - params.conn = solo; - params.flag = status; - params.xerrno = xerrno; - ScheduleCallHere(callback); - - callback = NULL; - delete this; + /* remove handlers we don't want to happen anymore */ + if (solo != NULL && solo->fd > 0) { + comm_remove_close_handler(solo->fd, ConnOpener::EarlyAbort, this); + commSetTimeout(solo->fd, -1, NULL, NULL); + } + + if (callback != NULL) { + typedef CommConnectCbParams Params; + Params ¶ms = GetCommParams(callback); + params.conn = solo; + params.flag = status; + params.xerrno = xerrno; + ScheduleCallHere(callback); + callback = NULL; + } + + /* ensure cleared local state, we are done. */ + solo = NULL; } void @@ -74,7 +93,7 @@ ConnOpener::start() } #endif solo->fd = comm_openex(SOCK_STREAM, IPPROTO_TCP, solo->local, solo->flags, solo->tos, host); - if (solo->fd <= 0) { + if (solo->fd < 0) { callCallback(COMM_ERR_CONNECT, 0); return; } @@ -98,8 +117,15 @@ ConnOpener::start() switch (comm_connect_addr(solo->fd, solo->remote) ) { case COMM_INPROGRESS: - debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_INPROGRESS"); - commSetSelect(solo->fd, COMM_SELECT_WRITE, ConnOpener::ConnectRetry, this, 0); + // check for timeout FIRST. + if(squid_curtime - connstart > connect_timeout) { + debugs(5, 5, HERE << "FD " << solo->fd << ": * - ERR took too long already."); + callCallback(COMM_TIMEOUT, errno); + return; + } else { + debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_INPROGRESS"); + commSetSelect(solo->fd, COMM_SELECT_WRITE, ConnOpener::ConnectRetry, this, 0); + } break; case COMM_OK: @@ -155,12 +181,6 @@ ConnOpener::EarlyAbort(int fd, void *data) ConnOpener *cs = static_cast(data); debugs(5, 3, HERE << "FD " << fd); cs->callCallback(COMM_ERR_CLOSING, errno); // NP: is closing or shutdown better? - - /* TODO split cases: - * remote end rejecting the connection is normal and one of the other paths may be taken. - * squid shutting down or forcing abort on the connection attempt(s) are the only real fatal cases. - * we may need separate error codes to send back for these two. - */ } void @@ -183,4 +203,3 @@ ConnOpener::ConnectTimeout(int fd, void *data) ConnOpener *cs = static_cast(data); cs->start(); } - diff --git a/src/comm/ConnOpener.h b/src/comm/ConnOpener.h index 9c4e2a6cc7..b8632be161 100644 --- a/src/comm/ConnOpener.h +++ b/src/comm/ConnOpener.h @@ -21,6 +21,7 @@ public: /** Actual start opening a TCP connection. */ void start(); + virtual bool doneAll() const; private: /* These objects may NOT be created without connections to act on. Do not define this operator. */ ConnOpener(const ConnOpener &); diff --git a/src/dns_internal.cc b/src/dns_internal.cc index 92f677c3c0..c7263fed18 100644 --- a/src/dns_internal.cc +++ b/src/dns_internal.cc @@ -751,7 +751,7 @@ idnsInitVC(int ns) ConnOpener *cs = new ConnOpener(conn, call); cs->setHost("DNS TCP Socket"); - cs->start(); + AsyncJob::AsyncStart(cs); } static void diff --git a/src/forward.cc b/src/forward.cc index 7e531a420a..1cc2c240d8 100644 --- a/src/forward.cc +++ b/src/forward.cc @@ -812,7 +812,7 @@ FwdState::connectStart() ConnOpener *cs = new ConnOpener(paths[0], call); cs->setHost(host); cs->connect_timeout = ctimeout; - cs->start(); + AsyncJob::AsyncStart(cs); } void diff --git a/src/ftp.cc b/src/ftp.cc index 7d500db11e..51559b2c02 100644 --- a/src/ftp.cc +++ b/src/ftp.cc @@ -2420,7 +2420,7 @@ ftpReadEPSV(FtpStateData* ftpState) AsyncCall::Pointer call = commCbCall(9,3, "FtpStateData::ftpPasvCallback", CommConnectCbPtrFun(FtpStateData::ftpPasvCallback, ftpState)); ConnOpener *cs = new ConnOpener(conn, call); cs->setHost(ftpState->data.host); - cs->start(); + AsyncJob::AsyncStart(cs); } /** \ingroup ServerProtocolFTPInternal @@ -2705,7 +2705,7 @@ ftpReadPasv(FtpStateData * ftpState) ConnOpener *cs = new ConnOpener(conn, call); cs->setHost(ftpState->data.host); cs->connect_timeout = Config.Timeout.connect; - cs->start(); + AsyncJob::AsyncStart(cs); } void diff --git a/src/ident/Ident.cc b/src/ident/Ident.cc index e56476460d..15ed8e3cb1 100644 --- a/src/ident/Ident.cc +++ b/src/ident/Ident.cc @@ -252,7 +252,7 @@ Ident::Start(Comm::ConnectionPointer &conn, IDCB * callback, void *data) AsyncCall::Pointer call = commCbCall(30,3, "Ident::ConnectDone", CommConnectCbPtrFun(Ident::ConnectDone, state)); ConnOpener *cs = new ConnOpener(state->conn, call); cs->connect_timeout = Ident::TheConfig.timeout; - cs->start(); + AsyncJob::AsyncStart(cs); } void diff --git a/src/neighbors.cc b/src/neighbors.cc index 81859e30f1..805d0524d7 100644 --- a/src/neighbors.cc +++ b/src/neighbors.cc @@ -1372,7 +1372,7 @@ peerProbeConnect(peer * p) ConnOpener *cs = new ConnOpener(conn, call); cs->connect_timeout = ctimeout; cs->setHost(p->host); - cs->start(); + AsyncJob::AsyncStart(cs); } p->stats.last_connect_probe = squid_curtime; diff --git a/src/tunnel.cc b/src/tunnel.cc index 88b7144006..163f24e25a 100644 --- a/src/tunnel.cc +++ b/src/tunnel.cc @@ -550,7 +550,7 @@ tunnelConnectDone(Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, ConnOpener *cs = new ConnOpener(tunnelState->paths[0], call); cs->setHost(tunnelState->url); cs->connect_timeout = Config.Timeout.connect; - cs->start(); + AsyncJob::AsyncStart(cs); } else { err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE; @@ -704,7 +704,7 @@ tunnelPeerSelectComplete(Comm::Paths *peer_paths, void *data) ConnOpener *cs = new ConnOpener(tunnelState->paths[0], call); cs->setHost(tunnelState->url); cs->connect_timeout = Config.Timeout.connect; - cs->start(); + AsyncJob::AsyncStart(cs); } CBDATA_CLASS_INIT(TunnelStateData);