diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2016-01-30 00:17:54 +0900 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2016-01-30 00:17:54 +0900 |
| commit | cf2fa33fe0d73f7001d262beee5e8aba03544126 (patch) | |
| tree | 338c442bac72e4ea7920970de6bc122b3485ad68 | |
| parent | 96247475315f6373c31f53bb658c7d59f48e8171 (diff) | |
WinTLS: Fix hang because of buffered received data
WinTLSSession buffers received decrypted data into its own buffer. If
read is requested, it copies the data from its buffer. But if
requested buffer size is less than decrypted buffer, some of the data
is left in the buffer. Previously, we had no facility to check the
existence of this pending data. If this data is the last requested
data from remote server, we may end up waiting for read event even if
we have already data in our buffer, which may cause hang. This commit
fixes this issue by introducing function to return the buffered length
in TLSSession. SocketCore also provides the same function, which
delegates to TLSSession object.
| -rw-r--r-- | src/AbstractCommand.cc | 7 | ||||
| -rw-r--r-- | src/AppleTLSSession.h | 2 | ||||
| -rw-r--r-- | src/HttpServerBodyCommand.cc | 4 | ||||
| -rw-r--r-- | src/HttpServerCommand.cc | 10 | ||||
| -rw-r--r-- | src/LibgnutlsTLSSession.h | 1 | ||||
| -rw-r--r-- | src/LibsslTLSSession.h | 1 | ||||
| -rw-r--r-- | src/SocketCore.cc | 9 | ||||
| -rw-r--r-- | src/SocketCore.h | 5 | ||||
| -rw-r--r-- | src/TLSSession.h | 4 | ||||
| -rw-r--r-- | src/WinTLSSession.cc | 2 | ||||
| -rw-r--r-- | src/WinTLSSession.h | 2 |
11 files changed, 42 insertions, 5 deletions
diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index 27762cc8..c2ead096 100644 --- a/src/AbstractCommand.cc +++ b/src/AbstractCommand.cc @@ -148,6 +148,10 @@ bool AbstractCommand::shouldProcess() const if (socketRecvBuffer_ && !socketRecvBuffer_->bufferEmpty()) { return true; } + + if (socket_ && socket_->getRecvBufferedLength()) { + return true; + } } if (checkSocketIsWritable_ && writeEventEnabled()) { @@ -916,7 +920,8 @@ const std::shared_ptr<PieceStorage>& AbstractCommand::getPieceStorage() const void AbstractCommand::checkSocketRecvBuffer() { - if (socketRecvBuffer_->bufferEmpty()) { + if (socketRecvBuffer_->bufferEmpty() && + socket_->getRecvBufferedLength() == 0) { return; } diff --git a/src/AppleTLSSession.h b/src/AppleTLSSession.h index 33641591..5213b7b7 100644 --- a/src/AppleTLSSession.h +++ b/src/AppleTLSSession.h @@ -105,6 +105,8 @@ public: // Returns last error string virtual std::string getLastErrorString() CXX11_OVERRIDE; + virtual size_t getRecvBufferedLength() CXX11_OVERRIDE { return 0; } + private: static OSStatus SocketWrite(SSLConnectionRef conn, const void* data, size_t* len) diff --git a/src/HttpServerBodyCommand.cc b/src/HttpServerBodyCommand.cc index 2bb9d6d2..3665181e 100644 --- a/src/HttpServerBodyCommand.cc +++ b/src/HttpServerBodyCommand.cc @@ -79,7 +79,8 @@ HttpServerBodyCommand::HttpServerBodyCommand( // To handle Content-Length == 0 case setStatus(Command::STATUS_ONESHOT_REALTIME); e_->addSocketForReadCheck(socket_, this); - if (!httpServer_->getSocketRecvBuffer()->bufferEmpty()) { + if (!httpServer_->getSocketRecvBuffer()->bufferEmpty() || + socket_->getRecvBufferedLength()) { e_->setNoWait(true); } } @@ -178,6 +179,7 @@ bool HttpServerBodyCommand::execute() } try { if (socket_->isReadable(0) || (writeCheck_ && socket_->isWritable(0)) || + socket_->getRecvBufferedLength() || !httpServer_->getSocketRecvBuffer()->bufferEmpty() || httpServer_->getContentLength() == 0) { timeoutTimer_ = global::wallclock(); diff --git a/src/HttpServerCommand.cc b/src/HttpServerCommand.cc index 8ce196df..f39d2fab 100644 --- a/src/HttpServerCommand.cc +++ b/src/HttpServerCommand.cc @@ -107,10 +107,13 @@ HttpServerCommand::~HttpServerCommand() void HttpServerCommand::checkSocketRecvBuffer() { - if (!httpServer_->getSocketRecvBuffer()->bufferEmpty()) { - setStatus(Command::STATUS_ONESHOT_REALTIME); - e_->setNoWait(true); + if (httpServer_->getSocketRecvBuffer()->bufferEmpty() && + socket_->getRecvBufferedLength() == 0) { + return; } + + setStatus(Command::STATUS_ONESHOT_REALTIME); + e_->setNoWait(true); } #ifdef ENABLE_WEBSOCKET @@ -172,6 +175,7 @@ bool HttpServerCommand::execute() } try { if (socket_->isReadable(0) || (writeCheck_ && socket_->isWritable(0)) || + socket_->getRecvBufferedLength() || !httpServer_->getSocketRecvBuffer()->bufferEmpty()) { timeoutTimer_ = global::wallclock(); diff --git a/src/LibgnutlsTLSSession.h b/src/LibgnutlsTLSSession.h index 6d3010dc..a9146988 100644 --- a/src/LibgnutlsTLSSession.h +++ b/src/LibgnutlsTLSSession.h @@ -59,6 +59,7 @@ public: std::string& handshakeErr) CXX11_OVERRIDE; virtual int tlsAccept(TLSVersion& version) CXX11_OVERRIDE; virtual std::string getLastErrorString() CXX11_OVERRIDE; + virtual size_t getRecvBufferedLength() CXX11_OVERRIDE { return 0; } private: gnutls_session_t sslSession_; diff --git a/src/LibsslTLSSession.h b/src/LibsslTLSSession.h index ccb1c2e2..5964aa21 100644 --- a/src/LibsslTLSSession.h +++ b/src/LibsslTLSSession.h @@ -59,6 +59,7 @@ public: std::string& handshakeErr) CXX11_OVERRIDE; virtual int tlsAccept(TLSVersion& version) CXX11_OVERRIDE; virtual std::string getLastErrorString() CXX11_OVERRIDE; + virtual size_t getRecvBufferedLength() CXX11_OVERRIDE { return 0; } private: int handshake(TLSVersion& version); diff --git a/src/SocketCore.cc b/src/SocketCore.cc index 50e974f5..3f04ee54 100644 --- a/src/SocketCore.cc +++ b/src/SocketCore.cc @@ -1324,6 +1324,15 @@ void SocketCore::setSocketRecvBufferSize(int size) int SocketCore::getSocketRecvBufferSize() { return socketRecvBufferSize_; } +size_t SocketCore::getRecvBufferedLength() const +{ + if (!tlsSession_) { + return 0; + } + + return tlsSession_->getRecvBufferedLength(); +} + std::vector<SockAddr> SocketCore::getInterfaceAddress(const std::string& iface, int family, int aiFlags) { diff --git a/src/SocketCore.h b/src/SocketCore.h index 48c9c7d2..7fdcf6e3 100644 --- a/src/SocketCore.h +++ b/src/SocketCore.h @@ -337,6 +337,11 @@ public: */ bool wantWrite() const; + // Returns buffered data which are already received. This data was + // already read from socket, and ready to read without reading + // socket. + size_t getRecvBufferedLength() const; + #ifdef ENABLE_SSL static void setClientTLSContext(const std::shared_ptr<TLSContext>& tlsContext); diff --git a/src/TLSSession.h b/src/TLSSession.h index 80e3dd75..4b430d13 100644 --- a/src/TLSSession.h +++ b/src/TLSSession.h @@ -107,6 +107,10 @@ public: // Returns last error string virtual std::string getLastErrorString() = 0; + // Returns buffered length, which can be read immediately without + // contacting network. + virtual size_t getRecvBufferedLength() = 0; + protected: TLSSession() {} diff --git a/src/WinTLSSession.cc b/src/WinTLSSession.cc index 45e61a8d..8f916657 100644 --- a/src/WinTLSSession.cc +++ b/src/WinTLSSession.cc @@ -832,4 +832,6 @@ std::string WinTLSSession::getLastErrorString() return ss.str(); } +size_t WinTLSSession::getRecvBufferedLength() { return decBuf_.size(); } + } // namespace aria2 diff --git a/src/WinTLSSession.h b/src/WinTLSSession.h index 1d4fe70d..2db9cb21 100644 --- a/src/WinTLSSession.h +++ b/src/WinTLSSession.h @@ -169,6 +169,8 @@ public: // Returns last error string virtual std::string getLastErrorString() CXX11_OVERRIDE; + virtual size_t getRecvBufferedLength() CXX11_OVERRIDE; + private: std::string hostname_; sock_t sockfd_; |
