diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2008-04-22 08:52:47 +0000 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2008-04-22 08:52:47 +0000 |
| commit | 5f55bc197ff9aa8b8bbcd030f2c32995661aac07 (patch) | |
| tree | 5cf208048aa83658798fd7658ac67c1ec7551d60 /src | |
| parent | 1c7c6f989800b10d3820614123dcfc7d90677c85 (diff) | |
2008-04-22 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Reuse socket if the origin server supports HTTP keep-alive and
--enable-http-keep-alive or --enable-http-pipelining is given.
The current implementation doesn't reuse the connections
established
against proxy server.
* src/AbstractCommand.cc
* src/DownloadEngine.cc
* src/DownloadEngine.h
* src/HttpDownloadCommand.cc
* src/HttpInitiateConnectionCommand.cc
* src/HttpResponseCommand.cc
Diffstat (limited to 'src')
| -rw-r--r-- | src/AbstractCommand.cc | 1 | ||||
| -rw-r--r-- | src/DownloadEngine.cc | 27 | ||||
| -rw-r--r-- | src/DownloadEngine.h | 10 | ||||
| -rw-r--r-- | src/HttpDownloadCommand.cc | 13 | ||||
| -rw-r--r-- | src/HttpInitiateConnectionCommand.cc | 13 | ||||
| -rw-r--r-- | src/HttpResponseCommand.cc | 8 |
6 files changed, 68 insertions, 4 deletions
diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index 4bd8d388..9745cf8a 100644 --- a/src/AbstractCommand.cc +++ b/src/AbstractCommand.cc @@ -133,6 +133,7 @@ bool AbstractCommand::execute() { _segments.push_back(segment); } if(_segments.empty()) { + // TODO socket could be pooled here if pipelining is enabled... logger->info(MSG_NO_SEGMENT_AVAILABLE, cuid); return prepareForRetry(1); } diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index 46844246..6378300b 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -46,6 +46,7 @@ #include "TimeA2.h" #include "a2time.h" #include "Socket.h" +#include "Util.h" #include <signal.h> #include <cstring> #include <algorithm> @@ -361,4 +362,30 @@ void DownloadEngine::addRoutineCommand(Command* command) _routineCommands.push_back(command); } +void DownloadEngine::poolSocket(const std::string& ipaddr, uint16_t port, + const SharedHandle<SocketCore>& sock) +{ + std::string addr = ipaddr+":"+Util::uitos(port); + logger->info("Pool socket for %s", addr.c_str()); + std::multimap<std::string, SharedHandle<SocketCore> >::value_type newPair + (addr, sock); + _socketPool.insert(newPair); +} + +SharedHandle<SocketCore> +DownloadEngine::popPooledSocket(const std::string& ipaddr, uint16_t port) +{ + std::string addr = ipaddr+":"+Util::uitos(port); + std::multimap<std::string, SharedHandle<SocketCore> >::iterator i = + _socketPool.find(addr); + if(i == _socketPool.end()) { + return SharedHandle<SocketCore>(); + } else { + logger->info("Reuse socket for %s", addr.c_str()); + SharedHandle<SocketCore> s = (*i).second; + _socketPool.erase(i); + return s; + } +} + } // namespace aria2 diff --git a/src/DownloadEngine.h b/src/DownloadEngine.h index f134299a..039a1246 100644 --- a/src/DownloadEngine.h +++ b/src/DownloadEngine.h @@ -39,6 +39,7 @@ #include "SharedHandle.h" #include "Command.h" #include <deque> +#include <map> #include "a2netcompat.h" namespace aria2 { @@ -104,6 +105,9 @@ private: bool _haltRequested; + // key = IP address:port, value = Socket + std::multimap<std::string, SharedHandle<SocketCore> > _socketPool; + void shortSleep() const; bool addSocket(const SocketEntry& socketEntry); bool deleteSocket(const SocketEntry& socketEntry); @@ -170,6 +174,12 @@ public: void setNoWait(bool b); void addRoutineCommand(Command* command); + + void poolSocket(const std::string& ipaddr, uint16_t port, + const SharedHandle<SocketCore>& sock); + + SharedHandle<SocketCore> popPooledSocket(const std::string& ipaddr, + uint16_t port); }; typedef SharedHandle<DownloadEngine> DownloadEngineHandle; diff --git a/src/HttpDownloadCommand.cc b/src/HttpDownloadCommand.cc index 104d0ae1..13fcfffc 100644 --- a/src/HttpDownloadCommand.cc +++ b/src/HttpDownloadCommand.cc @@ -41,6 +41,8 @@ #include "HttpRequest.h" #include "Segment.h" #include "Socket.h" +#include "prefs.h" +#include "Option.h" namespace aria2 { @@ -61,6 +63,17 @@ bool HttpDownloadCommand::prepareForNextSegment() { e->commands.push_back(command); return true; } else { + if(!e->option->getAsBool(PREF_HTTP_PROXY_ENABLED)) { + if(req->isPipeliningEnabled() || + (req->isKeepAliveEnabled() && + ((!transferDecoder.isNull() && _requestGroup->downloadFinished()) || + (uint64_t)_segments.front()->getPositionToWrite() == _requestGroup->getTotalLength()))) { + std::pair<std::string, uint16_t> peerInfo; + socket->getPeerInfo(peerInfo); + e->poolSocket(peerInfo.first, peerInfo.second, socket); + } + } + return DownloadCommand::prepareForNextSegment(); } } diff --git a/src/HttpInitiateConnectionCommand.cc b/src/HttpInitiateConnectionCommand.cc index f0e6c6d2..6e904116 100644 --- a/src/HttpInitiateConnectionCommand.cc +++ b/src/HttpInitiateConnectionCommand.cc @@ -103,9 +103,16 @@ bool HttpInitiateConnectionCommand::executeInternal() { throw new DlAbortEx("ERROR"); } } else { - logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(), - req->getPort()); - socket->establishConnection(hostname, req->getPort()); + SharedHandle<SocketCore> pooledSocket = + e->popPooledSocket(hostname, req->getPort()); + + if(pooledSocket.isNull()) { + logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(), + req->getPort()); + socket->establishConnection(hostname, req->getPort()); + } else { + socket = pooledSocket; + } SharedHandle<HttpConnection> httpConnection(new HttpConnection(cuid, socket, e->option)); command = new HttpRequestCommand(cuid, req, _requestGroup, httpConnection, e, socket); diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 997b17fc..97ab2a79 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -145,7 +145,13 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpRe File file(_requestGroup->getFilePath()); SegmentHandle segment = _requestGroup->getSegmentMan()->getSegment(cuid, 0); - if(!segment.isNull() && segment->getPositionToWrite() == 0) { + // pipelining requires implicit range specified. But the request for + // this response most likely dones't contains range header. This means + // we can't continue to use this socket because server sends all entity + // body instead of a segment. + // Therefore, we shutdown the socket here if pipelining is enabled. + if(!segment.isNull() && segment->getPositionToWrite() == 0 && + !req->isPipeliningEnabled()) { command = createHttpDownloadCommand(httpResponse); } else { _requestGroup->getSegmentMan()->cancelSegment(cuid); |
