+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_READ )
+                {
+                    // 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_READ) || !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_READ) )
+            break;
+
+        nbytes -= ret;
+        buffer += ret;
+    }