From c91574928d42adcd48eb30064570f6a57461549f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 12 Jul 2008 02:28:12 +0000 Subject: [PATCH] add wxSocket::IsClosed(), use it to implement Eof() in wxSocketStream git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54590 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/socket.h | 3 ++ interface/wx/socket.h | 11 +++++ src/common/sckstrm.cpp | 14 ++++-- src/common/socket.cpp | 100 ++++++++++++++++++++++++++--------------- 4 files changed, 89 insertions(+), 39 deletions(-) diff --git a/include/wx/socket.h b/include/wx/socket.h index a07c7bf6fb..056de5ee5a 100644 --- a/include/wx/socket.h +++ b/include/wx/socket.h @@ -113,6 +113,7 @@ public: bool Ok() const { return IsOk(); } bool IsOk() const { return (m_socket != NULL); } bool Error() const { return m_error; } + bool IsClosed() const { return m_closed; } bool IsConnected() const { return m_connected; } bool IsData() { return WaitForRead(0, 0); } bool IsDisconnected() const { return !IsConnected(); } @@ -199,6 +200,8 @@ private: bool m_reading; // busy reading? bool m_writing; // busy writing? bool m_error; // did last IO call fail? + bool m_closed; // was the other end closed? + // (notice that m_error is also set then) wxUint32 m_lcount; // last IO transaction size unsigned long m_timeout; // IO timeout value wxList m_states; // stack of states diff --git a/interface/wx/socket.h b/interface/wx/socket.h index 4248752b6d..5edc0cf306 100644 --- a/interface/wx/socket.h +++ b/interface/wx/socket.h @@ -499,6 +499,10 @@ public: Returns @true if an error occurred in the last IO operation. Use this function to check for an error condition after one of the following calls: Discard, Peek, Read, ReadMsg, Unread, Write, WriteMsg. + + Notice that this function will return @true even if the other end of a + (connected, i.e. TCP) socket was orderly closed by the peer. Use + IsClosed() to check for this. */ bool Error() const; @@ -567,6 +571,13 @@ public: */ bool IsConnected() const; + /** + Return @true if the other end of the socket was closed by the peer. + + Notice that Error() will return @true as well when this happens. + */ + bool IsClosed() const; + /** This function waits until the socket is readable. This might mean that queued data is available for reading or, for streamed sockets, that diff --git a/src/common/sckstrm.cpp b/src/common/sckstrm.cpp index cb3d65b13b..f060b3fd1f 100644 --- a/src/common/sckstrm.cpp +++ b/src/common/sckstrm.cpp @@ -41,8 +41,11 @@ wxSocketOutputStream::~wxSocketOutputStream() size_t wxSocketOutputStream::OnSysWrite(const void *buffer, size_t size) { - size_t ret = m_o_socket->Write((const char *)buffer, size).LastCount(); - m_lasterror = m_o_socket->Error() ? wxSTREAM_WRITE_ERROR : wxSTREAM_NO_ERROR; + const size_t ret = m_o_socket->Write(buffer, size).LastCount(); + m_lasterror = m_o_socket->Error() + ? m_o_socket->IsClosed() ? wxSTREAM_EOF + : wxSTREAM_WRITE_ERROR + : wxSTREAM_NO_ERROR; return ret; } @@ -61,8 +64,11 @@ wxSocketInputStream::~wxSocketInputStream() size_t wxSocketInputStream::OnSysRead(void *buffer, size_t size) { - size_t ret = m_i_socket->Read((char *)buffer, size).LastCount(); - m_lasterror = m_i_socket->Error() ? wxSTREAM_READ_ERROR : wxSTREAM_NO_ERROR; + const size_t ret = m_i_socket->Read(buffer, size).LastCount(); + m_lasterror = m_i_socket->Error() + ? m_i_socket->IsClosed() ? wxSTREAM_EOF + : wxSTREAM_READ_ERROR + : wxSTREAM_NO_ERROR; return ret; } diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 70a788017c..a4f8583376 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -203,7 +203,8 @@ void wxSocketBase::Init() m_establishing = m_reading = m_writing = - m_error = false; + m_error = + m_closed = false; m_lcount = 0; m_timeout = 600; m_beingDeleted = false; @@ -339,8 +340,10 @@ wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes) return *this; } -wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes) +wxUint32 wxSocketBase::_Read(void* buffer_, wxUint32 nbytes) { + char *buffer = (char *)buffer_; + int total; // Try the pushback buffer first @@ -365,35 +368,53 @@ wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes) if (m_flags & wxSOCKET_NOWAIT) { m_socket->SetNonBlocking(1); - ret = m_socket->Read((char *)buffer, nbytes); + ret = m_socket->Read(buffer, nbytes); m_socket->SetNonBlocking(0); - if (ret > 0) - total += ret; + if ( ret < 0 ) + return 0; + + total += ret; } - else + else // blocking socket { - bool more = true; - - while (more) + for ( ;; ) { + // dispatch events unless disabled if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() ) break; - ret = m_socket->Read((char *)buffer, nbytes); + ret = m_socket->Read(buffer, nbytes); + if ( ret == 0 ) + { + // for connection-oriented (e.g. TCP) sockets we can only read 0 + // bytes if the other end has been closed, and for connectionless + // ones (UDP) this flag doesn't make sense anyhow so we can set it to + // true too without doing any harm + m_closed = true; + break; + } - if (ret > 0) + if ( ret < 0 ) { - total += ret; - nbytes -= ret; - buffer = (char *)buffer + ret; + // this will be always interpreted as error by Read() + return 0; } - // If we got here and wxSOCKET_WAITALL is not set, we can leave - // now. Otherwise, wait until we recv all the data or until there - // is an error. - // - more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL)); + total += ret; + + // if wxSOCKET_WAITALL is not set, we can leave now as we did read + // something + if ( !(m_flags & wxSOCKET_WAITALL) ) + break; + + // otherwise check if read the maximal requested amount of data + nbytes -= ret; + if ( !nbytes ) + break; + + // we didn't, so continue reading + buffer = (char *)buffer + ret; } } @@ -538,8 +559,10 @@ wxSocketBase& wxSocketBase::Write(const void *buffer, wxUint32 nbytes) return *this; } -wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes) +wxUint32 wxSocketBase::_Write(const void *buffer_, wxUint32 nbytes) { + const char *buffer = (const char *)buffer_; + wxUint32 total = 0; // If the socket is invalid or parameters are ill, return immediately @@ -556,35 +579,42 @@ wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes) if (m_flags & wxSOCKET_NOWAIT) { m_socket->SetNonBlocking(1); - ret = m_socket->Write((const char *)buffer, nbytes); + ret = m_socket->Write(buffer, nbytes); m_socket->SetNonBlocking(0); if (ret > 0) total = ret; } - else + else // blocking socket { - bool more = true; - - while (more) + for ( ;; ) { if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) break; - ret = m_socket->Write((const char *)buffer, nbytes); + ret = m_socket->Write(buffer, nbytes); - if (ret > 0) + // see comments for similar logic for ret handling in _Read() + if ( ret == 0 ) { - total += ret; - nbytes -= ret; - buffer = (const char *)buffer + ret; + m_closed = true; + break; } - // If we got here and wxSOCKET_WAITALL is not set, we can leave - // now. Otherwise, wait until we send all the data or until there - // is an error. - // - more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL)); + if ( ret < 0 ) + { + return 0; + } + + total += ret; + if ( !(m_flags & wxSOCKET_WAITALL) ) + break; + + nbytes -= ret; + if ( !nbytes ) + break; + + buffer = (const char *)buffer + ret; } } -- 2.45.2