From: derek Date: Thu, 8 Dec 2011 05:26:10 +0000 (-0500) Subject: Fixed EOF issues on *nix platforms X-Git-Url: https://git.donarmstrong.com/?p=bamtools.git;a=commitdiff_plain;h=12002997e431049bfe0548340e14edb8f2638994 Fixed EOF issues on *nix platforms --- diff --git a/src/api/internal/io/BamFtp_p.cpp b/src/api/internal/io/BamFtp_p.cpp index d9f933c..a90a357 100644 --- a/src/api/internal/io/BamFtp_p.cpp +++ b/src/api/internal/io/BamFtp_p.cpp @@ -355,8 +355,10 @@ int64_t BamFtp::Read(char* data, const unsigned int numBytes) { // read bytes from data socket const int64_t socketBytesRead = ReadDataSocket(data+bytesReadSoFar, remainingBytes); - if ( socketBytesRead < 0 ) + if ( socketBytesRead < 0 ) // error return -1; + else if ( socketBytesRead == 0 ) // EOF + return bytesReadSoFar; bytesReadSoFar += socketBytesRead; m_filePosition += socketBytesRead; } diff --git a/src/api/internal/io/BamHttp_p.cpp b/src/api/internal/io/BamHttp_p.cpp index e2ade70..ba57337 100644 --- a/src/api/internal/io/BamHttp_p.cpp +++ b/src/api/internal/io/BamHttp_p.cpp @@ -2,7 +2,7 @@ // BamHttp_p.cpp (c) 2011 Derek Barnett // Marth Lab, Department of Biology, Boston College // --------------------------------------------------------------------------- -// Last modified: 10 November 2011 (DB) +// Last modified: 8 December 2011 (DB) // --------------------------------------------------------------------------- // Provides reading/writing of BAM files on HTTP server // *************************************************************************** @@ -229,8 +229,10 @@ int64_t BamHttp::Read(char* data, const unsigned int numBytes) { // try to read 'remainingBytes' from socket const int64_t socketBytesRead = ReadFromSocket(data+bytesReadSoFar, remainingBytes); - if ( socketBytesRead < 0 ) + if ( socketBytesRead < 0 ) // error return -1; + else if ( socketBytesRead == 0 ) // EOF + return bytesReadSoFar; bytesReadSoFar += socketBytesRead; m_filePosition += socketBytesRead; } @@ -247,8 +249,10 @@ int64_t BamHttp::Read(char* data, const unsigned int numBytes) { const size_t rangeRemainingBytes = m_endRangeFilePosition - m_filePosition; const size_t bytesToRead = std::min(remainingBytes, rangeRemainingBytes); const int64_t socketBytesRead = ReadFromSocket(data+bytesReadSoFar, bytesToRead); - if ( socketBytesRead < 0 ) + if ( socketBytesRead < 0 ) // error return -1; + else if ( socketBytesRead == 0 ) // EOF + return bytesReadSoFar; bytesReadSoFar += socketBytesRead; m_filePosition += socketBytesRead; } @@ -324,16 +328,22 @@ bool BamHttp::ReceiveResponse(void) { RaiiBuffer tmp(0x8000); int64_t numBytesRead = 0; while ( numBytesRead < m_filePosition ) { - int64_t result = ReadFromSocket(tmp.Buffer, 0x8000); - if ( result < 0 ) { + + const int64_t remaining = m_filePosition - numBytesRead; + const size_t bytesToRead = static_cast( (remaining > 0x8000) ? 0x8000 : remaining ); + const int64_t socketBytesRead = ReadFromSocket(tmp.Buffer, bytesToRead); + if ( socketBytesRead < 0 ) { // error Close(); return false; } - numBytesRead += result; + else if ( socketBytesRead == 0 ) // EOF + break; + + numBytesRead += socketBytesRead; } // return success - return true; + return ( numBytesRead == m_filePosition); } // on any other reponse status diff --git a/src/api/internal/io/RollingBuffer_p.h b/src/api/internal/io/RollingBuffer_p.h index e995f26..55550c0 100644 --- a/src/api/internal/io/RollingBuffer_p.h +++ b/src/api/internal/io/RollingBuffer_p.h @@ -2,7 +2,7 @@ // RollingBuffer_p.h (c) 2011 Derek Barnett // Marth Lab, Department of Biology, Boston College // --------------------------------------------------------------------------- -// Last modified: 10 November 2011 (DB) +// Last modified: 7 December 2011 (DB) // --------------------------------------------------------------------------- // Provides a dynamic I/O FIFO byte queue, which removes bytes as they are // read from the front of the buffer and grows to accept bytes being written @@ -62,11 +62,14 @@ class RollingBuffer { // reads until newline (or up to @maxLen bytes) // returns exactly how many bytes were read from buffer size_t ReadLine(char* dest, size_t max); - - const char* ReadPointer(void) const; // returns a C-fxn compatible char* to byte data - char* Reserve(size_t n); // ensures that buffer contains space for @n incoming bytes, returns write-able char* - size_t Size(void) const; // returns current number of bytes stored in buffer - void Write(const char* src, size_t n); // reserves space for @n bytes, then appends contents of @src to buffer + // returns a C-fxn compatible char* to byte data + const char* ReadPointer(void) const; + // ensures that buffer contains space for @n incoming bytes, returns write-able char* + char* Reserve(size_t n); + // returns current number of bytes stored in buffer + size_t Size(void) const; + // reserves space for @n bytes, then appends contents of @src to buffer + void Write(const char* src, size_t n); // data members private: diff --git a/src/api/internal/io/TcpSocketEngine_unix_p.cpp b/src/api/internal/io/TcpSocketEngine_unix_p.cpp index efcdf8d..5b100e4 100644 --- a/src/api/internal/io/TcpSocketEngine_unix_p.cpp +++ b/src/api/internal/io/TcpSocketEngine_unix_p.cpp @@ -182,25 +182,7 @@ int64_t TcpSocketEngine::nativeNumBytesAvailable(void) const { } int64_t TcpSocketEngine::nativeRead(char* dest, size_t max) { - - if ( !IsValid() ) - return -1; - - ssize_t ret = read(m_socketDescriptor, dest, max); - if ( ret < 0 ) { - ret = -1; - switch ( errno ) { - case EAGAIN : - // No data was available for reading - ret = -2; - break; - case ECONNRESET : - ret = 0; - break; - default: - break; - } - } + const ssize_t ret = read(m_socketDescriptor, dest, max); return static_cast(ret); } @@ -225,23 +207,6 @@ int TcpSocketEngine::nativeSelect(int msecs, bool isRead) const { } int64_t TcpSocketEngine::nativeWrite(const char* data, size_t length) { - - ssize_t writtenBytes = write(m_socketDescriptor, data, length); - if ( writtenBytes < 0 ) { - switch (errno) { - case EPIPE: - case ECONNRESET: - writtenBytes = -1; - m_socketError = TcpSocket::RemoteHostClosedError; - m_errorString = "remote host closed connection"; - Close(); - break; - case EAGAIN: - writtenBytes = 0; - break; - default: - break; - } - } + const ssize_t writtenBytes = write(m_socketDescriptor, data, length); return static_cast(writtenBytes); } diff --git a/src/api/internal/io/TcpSocket_p.cpp b/src/api/internal/io/TcpSocket_p.cpp index 4ff53a8..b27635e 100644 --- a/src/api/internal/io/TcpSocket_p.cpp +++ b/src/api/internal/io/TcpSocket_p.cpp @@ -2,7 +2,7 @@ // TcpSocket_p.cpp (c) 2011 Derek Barnett // Marth Lab, Department of Biology, Boston College // --------------------------------------------------------------------------- -// Last modified: 10 November 2011 (DB) +// Last modified: 7 December 2011 (DB) // --------------------------------------------------------------------------- // Provides basic TCP I/O interface // *************************************************************************** @@ -243,22 +243,32 @@ int64_t TcpSocket::Read(char* data, const unsigned int numBytes) { } // fetch data from socket, return 0 for success, -1 for failure - // since this should be called in a loop, we'll pull the actual bytes on next iteration - return ( ReadFromSocket() ? 0 : -1 ); + // since this should be called in a loop, + // we'll pull the actual bytes from the buffer on next iteration + const int64_t socketBytesRead = ReadFromSocket(); + if ( socketBytesRead < 0 ) { + // TODO: set error string/state ? + return -1; + } + + // we should have data now in buffer, try to fetch requested amount + // if nothing in buffer, we will return 0 bytes read (signals EOF reached) + const size_t numBytesRead = m_readBuffer.Read(data, numBytes); + return static_cast(numBytesRead); } -bool TcpSocket::ReadFromSocket(void) { +int64_t TcpSocket::ReadFromSocket(void) { // check for any socket engine errors if ( !m_engine->IsValid() ) { m_errorString = "TcpSocket::ReadFromSocket - socket disconnected"; ResetSocketEngine(); - return false; + return -1; } // wait for ready read bool timedOut; - bool isReadyRead = m_engine->WaitForRead(5000, &timedOut); + const bool isReadyRead = m_engine->WaitForRead(5000, &timedOut); // if not ready if ( !isReadyRead ) { @@ -267,50 +277,35 @@ bool TcpSocket::ReadFromSocket(void) { if ( timedOut ) { m_errorString = "TcpSocket::ReadFromSocket - timed out waiting for ready read"; // get error from engine ? - return false; + return -1; } // otherwise, there was an error else { m_errorString = "TcpSocket::ReadFromSocket - encountered error while waiting for ready read"; // get error from engine ? - return false; + return -1; } } - // ######################################################################### - // clean this up - smells funky, but it's a key step so it has to be right - // ######################################################################### - // get number of bytes available from socket - // (if 0, still try to read some data so we don't trigger any OS event behavior - // that respond to repeated access to a remote closed socket) - int64_t bytesToRead = m_engine->NumBytesAvailable(); + const int64_t bytesToRead = m_engine->NumBytesAvailable(); if ( bytesToRead < 0 ) { m_errorString = "TcpSocket::ReadFromSocket - encountered error while determining numBytesAvailable"; // get error from engine ? - return false; + return -1; } - else if ( bytesToRead == 0 ) - bytesToRead = 4096; // make space in buffer & read from socket char* buffer = m_readBuffer.Reserve(bytesToRead); - int64_t numBytesRead = m_engine->Read(buffer, bytesToRead); - - // if error while reading + const int64_t numBytesRead = m_engine->Read(buffer, bytesToRead); if ( numBytesRead == -1 ) { m_errorString = "TcpSocket::ReadFromSocket - encountered error while reading bytes"; // get error from engine ? - return false; } - // handle special case (no data, but not error) - if ( numBytesRead == -2 ) - m_readBuffer.Chop(bytesToRead); - - // return success - return true; + // return number of bytes actually read + return numBytesRead; } string TcpSocket::ReadLine(int64_t max) { @@ -415,7 +410,7 @@ int64_t TcpSocket::Write(const char* data, const unsigned int numBytes) { // wait for our socket to be write-able bool timedOut; - bool isReadyWrite = m_engine->WaitForWrite(3000, &timedOut); + const bool isReadyWrite = m_engine->WaitForWrite(3000, &timedOut); if ( isReadyWrite ) bytesWritten = m_engine->Write(data, numBytes); else { diff --git a/src/api/internal/io/TcpSocket_p.h b/src/api/internal/io/TcpSocket_p.h index 3c5f2fc..a25a11e 100644 --- a/src/api/internal/io/TcpSocket_p.h +++ b/src/api/internal/io/TcpSocket_p.h @@ -2,7 +2,7 @@ // TcpSocket_p.h (c) 2011 Derek Barnett // Marth Lab, Department of Biology, Boston College // --------------------------------------------------------------------------- -// Last modified: 10 November 2011 (DB) +// Last modified: 7 December 2011 (DB) // --------------------------------------------------------------------------- // Provides basic TCP I/O interface // *************************************************************************** @@ -95,7 +95,7 @@ class TcpSocket { const std::string& port, IBamIODevice::OpenMode mode); bool InitializeSocketEngine(HostAddress::NetworkProtocol protocol); - bool ReadFromSocket(void); + int64_t ReadFromSocket(void); void ResetSocketEngine(void); // data members