+wxUint32 wxSocketBase::DoRead(void* buffer_, wxUint32 nbytes)
+{
+ wxCHECK_MSG( m_impl, 0, "socket must be valid" );
+
+ // We use pointer arithmetic here which doesn't work with void pointers.
+ char *buffer = static_cast<char *>(buffer_);
+ wxCHECK_MSG( buffer, 0, "NULL buffer" );
+
+ // Try the push back buffer first, even before checking whether the socket
+ // is valid to allow reading previously pushed back data from an already
+ // closed socket.
+ wxUint32 total = GetPushback(buffer, nbytes, false);
+ nbytes -= total;
+ buffer += total;
+
+ while ( nbytes )
+ {
+ // our socket is non-blocking so Read() will return immediately if
+ // there is nothing to read yet and it's more efficient to try it first
+ // before entering DoWait() which is going to start dispatching GUI
+ // events and, even more importantly, we must do this under Windows
+ // where we're not going to get notifications about socket being ready
+ // for reading before we read all the existing data from it
+ const int ret = !m_impl->m_stream || m_connected
+ ? m_impl->Read(buffer, nbytes)
+ : 0;
+ if ( ret == -1 )
+ {
+ if ( m_impl->GetLastError() == wxSOCKET_WOULDBLOCK )
+ {
+ // if we don't want to wait, just return immediately
+ if ( m_flags & wxSOCKET_NOWAIT )
+ {
+ // this shouldn't be counted as an error in this case
+ SetError(wxSOCKET_NOERROR);
+ break;
+ }
+
+ // otherwise wait until the socket becomes ready for reading or
+ // an error occurs on it
+ if ( !DoWaitWithTimeout(wxSOCKET_INPUT_FLAG) )
+ {
+ // and exit if the timeout elapsed before it did
+ SetError(wxSOCKET_TIMEDOUT);
+ break;
+ }
+
+ // retry reading
+ continue;
+ }
+ else // "real" error
+ {
+ SetError(wxSOCKET_IOERR);
+ break;
+ }
+ }
+ else 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;
+
+ // we're not going to read anything else and so if we haven't read
+ // anything (or not everything in wxSOCKET_WAITALL case) already,
+ // signal an error
+ if ( (m_flags & wxSOCKET_WAITALL) || !total )
+ SetError(wxSOCKET_IOERR);
+ break;
+ }
+
+ total += ret;
+
+ // if we are happy to read something and not the entire nbytes bytes,
+ // then we're done
+ if ( !(m_flags & wxSOCKET_WAITALL) )
+ break;
+
+ nbytes -= ret;
+ buffer += ret;
+ }