X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=src%2Fapi%2Finternal%2Fio%2FTcpSocket_p.cpp;h=d3909326dbd238823cb4bcaa9bf699cbbbc104c2;hb=153d8f44a0ae6aebd0323289d961e5c00ea2b212;hp=4ff53a8a1ae9c55bdcaff89aa362530bb9cb94c2;hpb=8077f86ef52bfb08c17430b797c737d217d41cf3;p=bamtools.git diff --git a/src/api/internal/io/TcpSocket_p.cpp b/src/api/internal/io/TcpSocket_p.cpp index 4ff53a8..d390932 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: 5 January 2012 (DB) // --------------------------------------------------------------------------- // Provides basic TCP I/O interface // *************************************************************************** @@ -14,6 +14,7 @@ using namespace BamTools; using namespace BamTools::Internal; #include +#include #include #include using namespace std; @@ -26,7 +27,7 @@ namespace BamTools { namespace Internal { // constants -static const size_t DEFAULT_BUFFER_SIZE = 0x4000; +static const size_t DEFAULT_BUFFER_SIZE = 0x10000; } // namespace Internal } // namespace BamTools @@ -42,7 +43,7 @@ TcpSocket::TcpSocket(void) , m_engine(0) , m_cachedSocketDescriptor(-1) , m_readBuffer(DEFAULT_BUFFER_SIZE) - , m_error(TcpSocket::UnknownSocketError) + , m_error(TcpSocket::NoError) , m_state(TcpSocket::UnconnectedState) { } @@ -69,16 +70,16 @@ bool TcpSocket::ConnectImpl(const HostInfo& hostInfo, { // skip if we're already connected if ( m_state == TcpSocket::ConnectedState ) { - m_error = TcpSocket::SocketResourceError; + m_error = TcpSocket::SocketResourceError; m_errorString = "socket already connected"; return false; } // reset socket state m_hostName = hostInfo.HostName(); - m_mode = mode; + m_mode = mode; m_state = TcpSocket::UnconnectedState; - m_error = TcpSocket::UnknownSocketError; + m_error = TcpSocket::NoError; // m_localPort = 0; m_remotePort = 0; // m_localAddress.Clear(); @@ -154,7 +155,7 @@ bool TcpSocket::ConnectToHost(const string& hostName, // if host name was IP address ("x.x.x.x" or IPv6 format) // otherwise host name was 'plain-text' ("www.foo.bar") // we need to look up IP address(es) - if ( hostAddress.HasIPAddress() ) + if ( hostAddress.HasIPAddress() ) info.SetAddresses( vector(1, hostAddress) ); else info = HostInfo::Lookup(hostName, port); @@ -243,82 +244,78 @@ 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 ) { // if we simply timed out if ( timedOut ) { + // TODO: get add'l error info from engine ? m_errorString = "TcpSocket::ReadFromSocket - timed out waiting for ready read"; - // get error from engine ? - return false; } - // otherwise, there was an error + // otherwise, there was some other error else { + // TODO: get add'l error info from engine ? m_errorString = "TcpSocket::ReadFromSocket - encountered error while waiting for ready read"; - // get error from engine ? - return false; } - } - // ######################################################################### - // clean this up - smells funky, but it's a key step so it has to be right - // ######################################################################### + // return failure + return -1; + } // 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 ) { + // TODO: get add'l error info from engine ? 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 ) { + // TODO: get add'l error info from engine ? 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) { // prep result byte buffer ByteArray result; - - size_t bufferMax = ((max > static_cast(string::npos)) ? string::npos : static_cast(max)); + size_t bufferMax = ((max > static_cast(UINT_MAX)) + ? UINT_MAX : static_cast(max)); result.Resize(bufferMax); // read data @@ -326,13 +323,13 @@ string TcpSocket::ReadLine(int64_t max) { if ( result.Size() == 0 ) { if ( bufferMax == 0 ) - bufferMax = string::npos; + bufferMax = UINT_MAX; result.Resize(1); int64_t readResult; do { - result.Resize( static_cast(std::min(bufferMax, result.Size() + DEFAULT_BUFFER_SIZE)) ); + result.Resize( static_cast(min(bufferMax, result.Size() + DEFAULT_BUFFER_SIZE)) ); readResult = ReadLine(result.Data()+readBytes, result.Size()-readBytes); if ( readResult > 0 || readBytes == 0 ) readBytes += readResult; @@ -352,13 +349,13 @@ string TcpSocket::ReadLine(int64_t max) { } int64_t TcpSocket::ReadLine(char* dest, size_t max) { - + // wait for buffer to contain line contents if ( !WaitForReadLine() ) { m_errorString = "TcpSocket::ReadLine - error waiting for read line"; return -1; } - + // leave room for null term if ( max < 2 ) return -1; @@ -398,11 +395,11 @@ bool TcpSocket::WaitForReadLine(void) { // wait until we can read a line (will return immediately if already capable) while ( !CanReadLine() ) { - if ( !ReadFromSocket() ) + if ( !ReadFromSocket() ) return false; } - // if we get here, success + // if we get here, success return true; } @@ -411,22 +408,23 @@ int64_t TcpSocket::Write(const char* data, const unsigned int numBytes) { // single-shot attempt at write (not buffered, just try to shove the data through socket) // this method purely exists to send 'small' HTTP requests/FTP commands from client to server - int64_t bytesWritten(0); - // 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 ready, return number of bytes written if ( isReadyWrite ) - bytesWritten = m_engine->Write(data, numBytes); + return m_engine->Write(data, numBytes); + + // otherwise, socket not ready for writing + // set error string depending on reason & return failure + if ( !timedOut ) { + // TODO: get add'l error info from engine ?? + m_errorString = "TcpSocket::Write - timed out waiting for ready-write"; + } else { - // timeout is OK (with current setup), we'll just return 0 & try again - // but we need to report if engine encountered some other error - if ( !timedOut ) { - // TODO: set error string - bytesWritten = -1; - } + // TODO: get add'l error info from engine ?? + m_errorString = "TcpSocket::Write - error encountered while waiting for ready-write"; } - - // return actual number of bytes written to socket - return bytesWritten; + return -1; }