+ manager->OnExit();
+ }
+}
+
+// --------------------------------------------------------------------------
+// Ctor and dtor
+// --------------------------------------------------------------------------
+
+void wxSocketBase::Init()
+{
+ m_impl = NULL;
+ m_type = wxSOCKET_UNINIT;
+
+ // state
+ m_flags = 0;
+ m_connected =
+ m_establishing =
+ m_reading =
+ m_writing =
+ m_closed = false;
+ m_lcount = 0;
+ m_timeout = 600;
+ m_beingDeleted = false;
+
+ // pushback buffer
+ m_unread = NULL;
+ m_unrd_size = 0;
+ m_unrd_cur = 0;
+
+ // events
+ m_id = wxID_ANY;
+ m_handler = NULL;
+ m_clientData = NULL;
+ m_notify = false;
+ m_eventmask =
+ m_eventsgot = 0;
+
+ if ( !IsInitialized() )
+ {
+ // this Initialize() will be undone by wxSocketModule::OnExit(), all
+ // the other calls to it should be matched by a call to Shutdown()
+ if (!Initialize())
+ wxLogError("Cannot initialize wxSocketBase");
+ }
+}
+
+wxSocketBase::wxSocketBase()
+{
+ Init();
+}
+
+wxSocketBase::wxSocketBase(wxSocketFlags flags, wxSocketType type)
+{
+ Init();
+
+ SetFlags(flags);
+
+ m_type = type;
+}
+
+wxSocketBase::~wxSocketBase()
+{
+ // Just in case the app called Destroy() *and* then deleted the socket
+ // immediately: don't leave dangling pointers.
+ wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
+ if ( traits )
+ traits->RemoveFromPendingDelete(this);
+
+ // Shutdown and close the socket
+ if (!m_beingDeleted)
+ Close();
+
+ // Destroy the implementation object
+ delete m_impl;
+
+ // Free the pushback buffer
+ if (m_unread)
+ free(m_unread);
+}
+
+bool wxSocketBase::Destroy()
+{
+ // Delayed destruction: the socket will be deleted during the next idle
+ // loop iteration. This ensures that all pending events have been
+ // processed.
+ m_beingDeleted = true;
+
+ // Shutdown and close the socket
+ Close();
+
+ // Suppress events from now on
+ Notify(false);
+
+ // schedule this object for deletion
+ wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
+ if ( traits )
+ {
+ // let the traits object decide what to do with us
+ traits->ScheduleForDestroy(this);
+ }
+ else // no app or no traits
+ {
+ // in wxBase we might have no app object at all, don't leak memory
+ delete this;
+ }
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// simple accessors
+// ----------------------------------------------------------------------------
+
+void wxSocketBase::SetError(wxSocketError error)
+{
+ m_impl->m_error = error;
+}
+
+wxSocketError wxSocketBase::LastError() const
+{
+ return m_impl->GetError();
+}
+
+// --------------------------------------------------------------------------
+// Basic IO calls
+// --------------------------------------------------------------------------
+
+// The following IO operations update m_lcount:
+// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard}
+bool wxSocketBase::Close()
+{
+ // Interrupt pending waits
+ InterruptWait();
+
+ ShutdownOutput();
+
+ m_connected = false;
+ m_establishing = false;
+ return true;
+}
+
+void wxSocketBase::ShutdownOutput()
+{
+ if ( m_impl )
+ m_impl->Shutdown();
+}
+
+wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes)
+{
+ wxSocketReadGuard read(this);
+
+ m_lcount = DoRead(buffer, nbytes);
+
+ return *this;
+}
+
+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_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 )
+ 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;