From 4458bf17916973aeb9e99e9166070f645fb3295e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 15 Aug 2014 22:47:44 +0000 Subject: Fix deadlock waiting for read or write on closed connection. If the system is suspended then it may not realise that a TCP connection has been closed, while waiting for data to arrive on it. We didn't used to apply a timeout to this read operation. Now we use the connection's default timeout on all read and write operations. Network operations that don't pass a timeout will be logged with a backtrace, so that they can be fixed. --- lib/backupstore/BackupStoreFile.cpp | 3 +- lib/backupstore/BackupStoreFile.h | 3 +- lib/backupstore/BackupStoreFileCmbIdx.cpp | 6 +- lib/backupstore/BackupStoreFileEncodeStream.cpp | 3 +- lib/backupstore/BackupStoreFileEncodeStream.h | 3 +- lib/common/BufferedStream.cpp | 2 +- lib/common/BufferedStream.h | 3 +- lib/common/BufferedWriteStream.cpp | 2 +- lib/common/BufferedWriteStream.h | 3 +- lib/common/CollectInBufferStream.cpp | 2 +- lib/common/CollectInBufferStream.h | 3 +- lib/common/FileStream.cpp | 2 +- lib/common/FileStream.h | 3 +- lib/common/IOStream.h | 3 +- lib/common/MemBlockStream.cpp | 2 +- lib/common/MemBlockStream.h | 3 +- lib/common/PartialReadStream.cpp | 2 +- lib/common/PartialReadStream.h | 3 +- lib/common/RateLimitingStream.h | 5 +- lib/common/ReadGatherStream.cpp | 2 +- lib/common/ReadGatherStream.h | 3 +- lib/common/ReadLoggingStream.cpp | 2 +- lib/common/ReadLoggingStream.h | 3 +- lib/common/SelfFlushingStream.h | 5 +- lib/common/StreamableMemBlock.cpp | 8 ++- lib/common/ZeroStream.cpp | 2 +- lib/common/ZeroStream.h | 3 +- lib/raidfile/RaidFileRead.cpp | 2 +- lib/raidfile/RaidFileRead.h | 3 +- lib/raidfile/RaidFileWrite.cpp | 2 +- lib/raidfile/RaidFileWrite.h | 3 +- lib/server/ProtocolUncertainStream.cpp | 2 +- lib/server/ProtocolUncertainStream.h | 3 +- lib/server/SocketStream.cpp | 82 +++++++++++++++++++------ lib/server/SocketStream.h | 24 +++++++- lib/server/SocketStreamTLS.cpp | 51 +++------------ lib/server/SocketStreamTLS.h | 3 +- 37 files changed, 157 insertions(+), 102 deletions(-) (limited to 'lib') diff --git a/lib/backupstore/BackupStoreFile.cpp b/lib/backupstore/BackupStoreFile.cpp index d4c73f8b..07ea1637 100644 --- a/lib/backupstore/BackupStoreFile.cpp +++ b/lib/backupstore/BackupStoreFile.cpp @@ -838,7 +838,8 @@ bool BackupStoreFile::DecodedStream::IsSymLink() // Created: 9/12/03 // // -------------------------------------------------------------------------- -void BackupStoreFile::DecodedStream::Write(const void *pBuffer, int NBytes) +void BackupStoreFile::DecodedStream::Write(const void *pBuffer, int NBytes, + int Timeout) { THROW_EXCEPTION(BackupStoreException, CantWriteToDecodedFileStream) } diff --git a/lib/backupstore/BackupStoreFile.h b/lib/backupstore/BackupStoreFile.h index 776e6d22..854470df 100644 --- a/lib/backupstore/BackupStoreFile.h +++ b/lib/backupstore/BackupStoreFile.h @@ -87,7 +87,8 @@ public: // Stream functions virtual int Read(void *pBuffer, int NBytes, int Timeout); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual bool StreamDataLeft(); virtual bool StreamClosed(); diff --git a/lib/backupstore/BackupStoreFileCmbIdx.cpp b/lib/backupstore/BackupStoreFileCmbIdx.cpp index c8bcc3b9..0eec3872 100644 --- a/lib/backupstore/BackupStoreFileCmbIdx.cpp +++ b/lib/backupstore/BackupStoreFileCmbIdx.cpp @@ -32,7 +32,8 @@ public: ~BSFCombinedIndexStream(); virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual bool StreamDataLeft(); virtual bool StreamClosed(); virtual void Initialise(IOStream &rFrom); @@ -289,7 +290,8 @@ int BSFCombinedIndexStream::Read(void *pBuffer, int NBytes, int Timeout) // Created: 8/7/04 // // -------------------------------------------------------------------------- -void BSFCombinedIndexStream::Write(const void *pBuffer, int NBytes) +void BSFCombinedIndexStream::Write(const void *pBuffer, int NBytes, + int Timeout) { THROW_EXCEPTION(BackupStoreException, StreamDoesntHaveRequiredFeatures) } diff --git a/lib/backupstore/BackupStoreFileEncodeStream.cpp b/lib/backupstore/BackupStoreFileEncodeStream.cpp index b40bcd08..ccab8074 100644 --- a/lib/backupstore/BackupStoreFileEncodeStream.cpp +++ b/lib/backupstore/BackupStoreFileEncodeStream.cpp @@ -667,7 +667,8 @@ void BackupStoreFileEncodeStream::StoreBlockIndexEntry(int64_t EncSizeOrBlkIndex // Created: 8/12/03 // // -------------------------------------------------------------------------- -void BackupStoreFileEncodeStream::Write(const void *pBuffer, int NBytes) +void BackupStoreFileEncodeStream::Write(const void *pBuffer, int NBytes, + int Timeout) { THROW_EXCEPTION(BackupStoreException, CantWriteToEncodedFileStream) } diff --git a/lib/backupstore/BackupStoreFileEncodeStream.h b/lib/backupstore/BackupStoreFileEncodeStream.h index 80bdff58..13648d47 100644 --- a/lib/backupstore/BackupStoreFileEncodeStream.h +++ b/lib/backupstore/BackupStoreFileEncodeStream.h @@ -83,7 +83,8 @@ public: BackgroundTask* pBackgroundTask = NULL); virtual int Read(void *pBuffer, int NBytes, int Timeout); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual bool StreamDataLeft(); virtual bool StreamClosed(); int64_t GetTotalBytesSent() { return mTotalBytesSent; } diff --git a/lib/common/BufferedStream.cpp b/lib/common/BufferedStream.cpp index b58253f3..cef0a73f 100644 --- a/lib/common/BufferedStream.cpp +++ b/lib/common/BufferedStream.cpp @@ -96,7 +96,7 @@ IOStream::pos_type BufferedStream::BytesLeftToRead() // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void BufferedStream::Write(const void *pBuffer, int NBytes) +void BufferedStream::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(CommonException, NotSupported); } diff --git a/lib/common/BufferedStream.h b/lib/common/BufferedStream.h index 4987e37b..3984aceb 100644 --- a/lib/common/BufferedStream.h +++ b/lib/common/BufferedStream.h @@ -25,7 +25,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(IOStream::pos_type Offset, int SeekType); virtual void Close(); diff --git a/lib/common/BufferedWriteStream.cpp b/lib/common/BufferedWriteStream.cpp index 797be00d..8fbabe9b 100644 --- a/lib/common/BufferedWriteStream.cpp +++ b/lib/common/BufferedWriteStream.cpp @@ -64,7 +64,7 @@ IOStream::pos_type BufferedWriteStream::BytesLeftToRead() // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void BufferedWriteStream::Write(const void *pBuffer, int NBytes) +void BufferedWriteStream::Write(const void *pBuffer, int NBytes, int Timeout) { int numBytesRemain = NBytes; diff --git a/lib/common/BufferedWriteStream.h b/lib/common/BufferedWriteStream.h index 7a1c8c17..5f6d5f19 100644 --- a/lib/common/BufferedWriteStream.h +++ b/lib/common/BufferedWriteStream.h @@ -25,7 +25,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(IOStream::pos_type Offset, int SeekType); virtual void Flush(int Timeout = IOStream::TimeOutInfinite); diff --git a/lib/common/CollectInBufferStream.cpp b/lib/common/CollectInBufferStream.cpp index 90e2e7bc..47b271f0 100644 --- a/lib/common/CollectInBufferStream.cpp +++ b/lib/common/CollectInBufferStream.cpp @@ -98,7 +98,7 @@ IOStream::pos_type CollectInBufferStream::BytesLeftToRead() // Created: 2003/08/26 // // -------------------------------------------------------------------------- -void CollectInBufferStream::Write(const void *pBuffer, int NBytes) +void CollectInBufferStream::Write(const void *pBuffer, int NBytes, int Timeout) { if(mInWritePhase != true) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) } diff --git a/lib/common/CollectInBufferStream.h b/lib/common/CollectInBufferStream.h index d73af8db..03cb5da8 100644 --- a/lib/common/CollectInBufferStream.h +++ b/lib/common/CollectInBufferStream.h @@ -34,7 +34,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(pos_type Offset, int SeekType); virtual bool StreamDataLeft(); diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp index 62fa05f4..6d5810dc 100644 --- a/lib/common/FileStream.cpp +++ b/lib/common/FileStream.cpp @@ -246,7 +246,7 @@ IOStream::pos_type FileStream::BytesLeftToRead() // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void FileStream::Write(const void *pBuffer, int NBytes) +void FileStream::Write(const void *pBuffer, int NBytes, int Timeout) { if(mOSFileHandle == INVALID_FILE) { diff --git a/lib/common/FileStream.h b/lib/common/FileStream.h index 8489188c..f528b8bc 100644 --- a/lib/common/FileStream.h +++ b/lib/common/FileStream.h @@ -40,7 +40,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(IOStream::pos_type Offset, int SeekType); virtual void Close(); diff --git a/lib/common/IOStream.h b/lib/common/IOStream.h index 81f1cfa6..a4eb3db1 100644 --- a/lib/common/IOStream.h +++ b/lib/common/IOStream.h @@ -47,7 +47,8 @@ public: typedef int64_t pos_type; virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite) = 0; virtual pos_type BytesLeftToRead(); // may return IOStream::SizeOfStreamUnknown (and will for most stream types) - virtual void Write(const void *pBuffer, int NBytes) = 0; + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite) = 0; virtual void Write(const char *pBuffer); virtual void WriteAllBuffered(); virtual pos_type GetPosition() const; diff --git a/lib/common/MemBlockStream.cpp b/lib/common/MemBlockStream.cpp index 90c0eaf6..f49ac96f 100644 --- a/lib/common/MemBlockStream.cpp +++ b/lib/common/MemBlockStream.cpp @@ -179,7 +179,7 @@ IOStream::pos_type MemBlockStream::BytesLeftToRead() // Created: 2003/09/05 // // -------------------------------------------------------------------------- -void MemBlockStream::Write(const void *pBuffer, int NBytes) +void MemBlockStream::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(CommonException, MemBlockStreamNotSupported) } diff --git a/lib/common/MemBlockStream.h b/lib/common/MemBlockStream.h index 98398121..1ba4b0a6 100644 --- a/lib/common/MemBlockStream.h +++ b/lib/common/MemBlockStream.h @@ -38,7 +38,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(pos_type Offset, int SeekType); virtual bool StreamDataLeft(); diff --git a/lib/common/PartialReadStream.cpp b/lib/common/PartialReadStream.cpp index f2f79715..b5f99bb5 100644 --- a/lib/common/PartialReadStream.cpp +++ b/lib/common/PartialReadStream.cpp @@ -104,7 +104,7 @@ IOStream::pos_type PartialReadStream::BytesLeftToRead() // Created: 2003/08/26 // // -------------------------------------------------------------------------- -void PartialReadStream::Write(const void *pBuffer, int NBytes) +void PartialReadStream::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(CommonException, CantWriteToPartialReadStream) } diff --git a/lib/common/PartialReadStream.h b/lib/common/PartialReadStream.h index 1b46b0bd..61bdd7d1 100644 --- a/lib/common/PartialReadStream.h +++ b/lib/common/PartialReadStream.h @@ -33,7 +33,8 @@ private: public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual bool StreamDataLeft(); virtual bool StreamClosed(); diff --git a/lib/common/RateLimitingStream.h b/lib/common/RateLimitingStream.h index a322b99b..cd9d8271 100644 --- a/lib/common/RateLimitingStream.h +++ b/lib/common/RateLimitingStream.h @@ -30,9 +30,10 @@ public: int Timeout = IOStream::TimeOutInfinite); // Everything else is delegated to the sink - virtual void Write(const void *pBuffer, int NBytes) + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite) { - Write(pBuffer, NBytes); + Write(pBuffer, NBytes, Timeout); } virtual pos_type BytesLeftToRead() { diff --git a/lib/common/ReadGatherStream.cpp b/lib/common/ReadGatherStream.cpp index f50e6664..ae252832 100644 --- a/lib/common/ReadGatherStream.cpp +++ b/lib/common/ReadGatherStream.cpp @@ -213,7 +213,7 @@ IOStream::pos_type ReadGatherStream::BytesLeftToRead() // Created: 10/12/03 // // -------------------------------------------------------------------------- -void ReadGatherStream::Write(const void *pBuffer, int NBytes) +void ReadGatherStream::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(CommonException, CannotWriteToReadGatherStream); } diff --git a/lib/common/ReadGatherStream.h b/lib/common/ReadGatherStream.h index 613ede3e..9a44480b 100644 --- a/lib/common/ReadGatherStream.h +++ b/lib/common/ReadGatherStream.h @@ -37,7 +37,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual bool StreamDataLeft(); virtual bool StreamClosed(); virtual pos_type GetPosition() const; diff --git a/lib/common/ReadLoggingStream.cpp b/lib/common/ReadLoggingStream.cpp index 54c99c95..df493344 100644 --- a/lib/common/ReadLoggingStream.cpp +++ b/lib/common/ReadLoggingStream.cpp @@ -96,7 +96,7 @@ IOStream::pos_type ReadLoggingStream::BytesLeftToRead() // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void ReadLoggingStream::Write(const void *pBuffer, int NBytes) +void ReadLoggingStream::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(CommonException, NotSupported); } diff --git a/lib/common/ReadLoggingStream.h b/lib/common/ReadLoggingStream.h index b23b542c..4a01a45c 100644 --- a/lib/common/ReadLoggingStream.h +++ b/lib/common/ReadLoggingStream.h @@ -39,7 +39,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(IOStream::pos_type Offset, int SeekType); virtual void Close(); diff --git a/lib/common/SelfFlushingStream.h b/lib/common/SelfFlushingStream.h index 6865ab96..b4efa294 100644 --- a/lib/common/SelfFlushingStream.h +++ b/lib/common/SelfFlushingStream.h @@ -56,9 +56,10 @@ public: { return mrSource.BytesLeftToRead(); } - virtual void Write(const void *pBuffer, int NBytes) + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite) { - mrSource.Write(pBuffer, NBytes); + mrSource.Write(pBuffer, NBytes, Timeout); } virtual bool StreamDataLeft() { diff --git a/lib/common/StreamableMemBlock.cpp b/lib/common/StreamableMemBlock.cpp index b376f037..be3d0031 100644 --- a/lib/common/StreamableMemBlock.cpp +++ b/lib/common/StreamableMemBlock.cpp @@ -252,7 +252,9 @@ void StreamableMemBlock::ReadFromStream(IOStream &rStream, int Timeout) { // Get the size of the block int32_t size_s; - if(!rStream.ReadFullBuffer(&size_s, sizeof(size_s), 0 /* not interested in bytes read if this fails */)) + if(!rStream.ReadFullBuffer(&size_s, sizeof(size_s), + 0, /* not interested in bytes read if this fails */ + Timeout)) { THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead) } @@ -270,7 +272,9 @@ void StreamableMemBlock::ReadFromStream(IOStream &rStream, int Timeout) try { // Read in - if(!rStream.ReadFullBuffer(pblock, size, 0 /* not interested in bytes read if this fails */)) + if(!rStream.ReadFullBuffer(pblock, size, + 0, /* not interested in bytes read if this fails */ + Timeout)) { THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead) } diff --git a/lib/common/ZeroStream.cpp b/lib/common/ZeroStream.cpp index d11ed80c..e1342e6f 100644 --- a/lib/common/ZeroStream.cpp +++ b/lib/common/ZeroStream.cpp @@ -76,7 +76,7 @@ IOStream::pos_type ZeroStream::BytesLeftToRead() // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void ZeroStream::Write(const void *pBuffer, int NBytes) +void ZeroStream::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(CommonException, NotSupported); } diff --git a/lib/common/ZeroStream.h b/lib/common/ZeroStream.h index 0119045b..f91221b0 100644 --- a/lib/common/ZeroStream.h +++ b/lib/common/ZeroStream.h @@ -22,7 +22,8 @@ public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(IOStream::pos_type Offset, int SeekType); virtual void Close(); diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp index 7591961f..a78ec4a2 100644 --- a/lib/raidfile/RaidFileRead.cpp +++ b/lib/raidfile/RaidFileRead.cpp @@ -1721,7 +1721,7 @@ bool RaidFileRead::ReadDirectoryContents(int SetNumber, const std::string &rDirN // Created: 2003/08/21 // // -------------------------------------------------------------------------- -void RaidFileRead::Write(const void *pBuffer, int NBytes) +void RaidFileRead::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(RaidFileException, UnsupportedReadWriteOrClose) } diff --git a/lib/raidfile/RaidFileRead.h b/lib/raidfile/RaidFileRead.h index e746ed46..570443c8 100644 --- a/lib/raidfile/RaidFileRead.h +++ b/lib/raidfile/RaidFileRead.h @@ -56,7 +56,8 @@ public: static bool ReadDirectoryContents(int SetNumber, const std::string &rDirName, int DirReadType, std::vector &rOutput); // Common IOStream interface implementation - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual bool StreamClosed(); virtual pos_type BytesLeftToRead(); diff --git a/lib/raidfile/RaidFileWrite.cpp b/lib/raidfile/RaidFileWrite.cpp index 82aeef3d..ddc99fc7 100644 --- a/lib/raidfile/RaidFileWrite.cpp +++ b/lib/raidfile/RaidFileWrite.cpp @@ -243,7 +243,7 @@ void RaidFileWrite::Open(bool AllowOverwrite) // Created: 2003/07/10 // // -------------------------------------------------------------------------- -void RaidFileWrite::Write(const void *pBuffer, int Length) +void RaidFileWrite::Write(const void *pBuffer, int Length, int Timeout) { // open? if(mOSFileHandle == -1) diff --git a/lib/raidfile/RaidFileWrite.h b/lib/raidfile/RaidFileWrite.h index e2887167..4c5e8178 100644 --- a/lib/raidfile/RaidFileWrite.h +++ b/lib/raidfile/RaidFileWrite.h @@ -47,7 +47,8 @@ private: public: // IOStream interface virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); // will exception - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual pos_type GetPosition() const; virtual void Seek(pos_type Offset, int SeekType); virtual void Close(); // will discard the file! Use commit instead. diff --git a/lib/server/ProtocolUncertainStream.cpp b/lib/server/ProtocolUncertainStream.cpp index 336fd36d..aeb15816 100644 --- a/lib/server/ProtocolUncertainStream.cpp +++ b/lib/server/ProtocolUncertainStream.cpp @@ -173,7 +173,7 @@ IOStream::pos_type ProtocolUncertainStream::BytesLeftToRead() // Created: 2003/12/05 // // -------------------------------------------------------------------------- -void ProtocolUncertainStream::Write(const void *pBuffer, int NBytes) +void ProtocolUncertainStream::Write(const void *pBuffer, int NBytes, int Timeout) { THROW_EXCEPTION(ServerException, CantWriteToProtocolUncertainStream) } diff --git a/lib/server/ProtocolUncertainStream.h b/lib/server/ProtocolUncertainStream.h index 4954cf88..2e97ba6a 100644 --- a/lib/server/ProtocolUncertainStream.h +++ b/lib/server/ProtocolUncertainStream.h @@ -33,7 +33,8 @@ private: public: virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); virtual pos_type BytesLeftToRead(); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual bool StreamDataLeft(); virtual bool StreamClosed(); diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp index 7b46b024..dafb4338 100644 --- a/lib/server/SocketStream.cpp +++ b/lib/server/SocketStream.cpp @@ -34,6 +34,7 @@ #include "SocketStream.h" #include "CommonException.h" #include "Socket.h" +#include "Utils.h" #include "MemLeakFindOn.h" @@ -204,7 +205,9 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port) // -------------------------------------------------------------------------- int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) { - if(mSocketHandle == INVALID_SOCKET_VALUE) + CheckForMissingTimeout(Timeout); + + if(mSocketHandle == INVALID_SOCKET_VALUE) { THROW_EXCEPTION(ServerException, BadSocketHandle) } @@ -215,7 +218,7 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) p.fd = mSocketHandle; p.events = POLLIN; p.revents = 0; - switch(::poll(&p, 1, (Timeout == IOStream::TimeOutInfinite)?INFTIM:Timeout)) + switch(::poll(&p, 1, PollTimeout(Timeout))) { case -1: // error @@ -275,6 +278,43 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) return r; } +bool SocketStream::Poll(short Events, int Timeout) +{ + // Wait for data to send. + struct pollfd p; + p.fd = GetSocketHandle(); + p.events = Events; + p.revents = 0; + + box_time_t start = GetCurrentBoxTime(); + box_time_t end = start + MilliSecondsToBoxTime(Timeout); + int result; + + do + { + box_time_t now = GetCurrentBoxTime(); + result = ::poll(&p, 1, PollTimeout(end - now)); + } + while(result == -1 && errno == EINTR); + + switch(result) + { + case -1: + // error - Bad! + THROW_SYS_ERROR("Failed to poll socket", ServerException, + SocketPollError); + break; + + case 0: + // Condition not met, timed out + return false; + + default: + // good to go! + return true; + } +} + // -------------------------------------------------------------------------- // // Function @@ -283,7 +323,7 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void SocketStream::Write(const void *pBuffer, int NBytes) +void SocketStream::Write(const void *pBuffer, int NBytes, int Timeout) { if(mSocketHandle == INVALID_SOCKET_VALUE) { @@ -296,7 +336,9 @@ void SocketStream::Write(const void *pBuffer, int NBytes) // Bytes left to send int bytesLeft = NBytes; - + box_time_t start = GetCurrentBoxTime(); + box_time_t end = start + MilliSecondsToBoxTime(Timeout); + while(bytesLeft > 0) { // Try to send. @@ -327,23 +369,15 @@ void SocketStream::Write(const void *pBuffer, int NBytes) BOX_TRACE("Waiting to send data on socket " << mSocketHandle << " (" << bytesLeft << " of " << NBytes << " bytes left)"); - - // Wait for data to send. - struct pollfd p; - p.fd = mSocketHandle; - p.events = POLLOUT; - p.revents = 0; - - if(::poll(&p, 1, 16000 /* 16 seconds */) == -1) + + box_time_t now = GetCurrentBoxTime(); + + if(!Poll(POLLOUT, PollTimeout(end - now))) { - // Don't exception if it's just a signal - if(errno != EINTR) - { - BOX_LOG_SYS_ERROR("Failed to poll " - "socket"); - THROW_EXCEPTION(ServerException, - SocketPollError) - } + THROW_EXCEPTION_MESSAGE(ConnectionException, + Protocol_Timeout, "Timed out waiting " + "to send " << bytesLeft << " of " << + NBytes << " bytes"); } } } @@ -514,3 +548,11 @@ bool SocketStream::GetPeerCredentials(uid_t &rUidOut, gid_t &rGidOut) return false; } +void SocketStream::CheckForMissingTimeout(int Timeout) +{ + if (Timeout == IOStream::TimeOutInfinite) + { + BOX_WARNING("Network operation started with no timeout!"); + DumpStackBacktrace(); + } +} diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h index 2fb5e391..406d29e4 100644 --- a/lib/server/SocketStream.h +++ b/lib/server/SocketStream.h @@ -10,6 +10,9 @@ #ifndef SOCKETSTREAM__H #define SOCKETSTREAM__H +#include + +#include "BoxTime.h" #include "IOStream.h" #include "Socket.h" @@ -41,7 +44,8 @@ public: void Attach(int socket); virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual void Close(); virtual bool StreamDataLeft(); virtual bool StreamClosed(); @@ -53,6 +57,24 @@ public: protected: void MarkAsReadClosed() {mReadClosed = true;} void MarkAsWriteClosed() {mWriteClosed = true;} + void CheckForMissingTimeout(int Timeout); + + int PollTimeout(box_time_t Timeout) + { + if (Timeout < 0) + { + return 0; + } + else if (Timeout == IOStream::TimeOutInfinite || Timeout > INT_MAX) + { + return INFTIM; + } + else + { + return (int) Timeout; + } + } + bool Poll(short Events, int Timeout); private: tOSSocketHandle mSocketHandle; diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp index 127d697a..6ca172f6 100644 --- a/lib/server/SocketStreamTLS.cpp +++ b/lib/server/SocketStreamTLS.cpp @@ -230,16 +230,17 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer) // -------------------------------------------------------------------------- bool SocketStreamTLS::WaitWhenRetryRequired(int SSLErrorCode, int Timeout) { - struct pollfd p; - p.fd = GetSocketHandle(); + CheckForMissingTimeout(Timeout); + + short events; switch(SSLErrorCode) { case SSL_ERROR_WANT_READ: - p.events = POLLIN; + events = POLLIN; break; case SSL_ERROR_WANT_WRITE: - p.events = POLLOUT; + events = POLLOUT; break; default: @@ -247,45 +248,8 @@ bool SocketStreamTLS::WaitWhenRetryRequired(int SSLErrorCode, int Timeout) THROW_EXCEPTION(ServerException, Internal) break; } - p.revents = 0; - - int64_t start, end; - start = BoxTimeToMilliSeconds(GetCurrentBoxTime()); - end = start + Timeout; - int result; - - do - { - int64_t now = BoxTimeToMilliSeconds(GetCurrentBoxTime()); - int poll_timeout = (int)(end - now); - if (poll_timeout < 0) poll_timeout = 0; - if (Timeout == IOStream::TimeOutInfinite) - { - poll_timeout = INFTIM; - } - result = ::poll(&p, 1, poll_timeout); - } - while(result == -1 && errno == EINTR); - - switch(result) - { - case -1: - // error - Bad! - THROW_EXCEPTION(ServerException, SocketPollError) - break; - - case 0: - // Condition not met, timed out - return false; - break; - - default: - // good to go! - return true; - break; - } - return true; + return Poll(events, Timeout); } // -------------------------------------------------------------------------- @@ -298,6 +262,7 @@ bool SocketStreamTLS::WaitWhenRetryRequired(int SSLErrorCode, int Timeout) // -------------------------------------------------------------------------- int SocketStreamTLS::Read(void *pBuffer, int NBytes, int Timeout) { + CheckForMissingTimeout(Timeout); if(!mpSSL) {THROW_EXCEPTION(ServerException, TLSNoSSLObject)} // Make sure zero byte reads work as expected @@ -352,7 +317,7 @@ int SocketStreamTLS::Read(void *pBuffer, int NBytes, int Timeout) // Created: 2003/08/06 // // -------------------------------------------------------------------------- -void SocketStreamTLS::Write(const void *pBuffer, int NBytes) +void SocketStreamTLS::Write(const void *pBuffer, int NBytes, int Timeout) { if(!mpSSL) {THROW_EXCEPTION(ServerException, TLSNoSSLObject)} diff --git a/lib/server/SocketStreamTLS.h b/lib/server/SocketStreamTLS.h index bb40ed10..3fda98c1 100644 --- a/lib/server/SocketStreamTLS.h +++ b/lib/server/SocketStreamTLS.h @@ -43,7 +43,8 @@ public: void Handshake(const TLSContext &rContext, bool IsServer = false); virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite); - virtual void Write(const void *pBuffer, int NBytes); + virtual void Write(const void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); virtual void Close(); virtual void Shutdown(bool Read = true, bool Write = true); -- cgit v1.2.3