+ return *this;
+}
+
+// --------------------------------------------------------------------------
+// Wait functions
+// --------------------------------------------------------------------------
+
+/*
+ This function will check for the events specified in the flags parameter,
+ and it will return a mask indicating which operations can be performed.
+ */
+wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags,
+ const timeval *timeout)
+{
+ if ( m_fd == INVALID_SOCKET )
+ return (wxSOCKET_LOST_FLAG & flags);
+
+ struct timeval tv;
+ if ( timeout )
+ tv = *timeout;
+ else
+ tv.tv_sec = tv.tv_usec = 0;
+
+ // prepare the FD sets, passing NULL for the one(s) we don't use
+ fd_set
+ readfds, *preadfds = NULL,
+ writefds, *pwritefds = NULL,
+ exceptfds; // always want to know about errors
+
+ if ( flags & wxSOCKET_INPUT_FLAG )
+ preadfds = &readfds;
+
+ if ( flags & wxSOCKET_OUTPUT_FLAG )
+ pwritefds = &writefds;
+
+ // When using non-blocking connect() the client socket becomes connected
+ // (successfully or not) when it becomes writable but when using
+ // non-blocking accept() the server socket becomes connected when it
+ // becomes readable.
+ if ( flags & wxSOCKET_CONNECTION_FLAG )
+ {
+ if ( m_server )
+ preadfds = &readfds;
+ else
+ pwritefds = &writefds;
+ }
+
+ if ( preadfds )
+ {
+ wxFD_ZERO(preadfds);
+ wxFD_SET(m_fd, preadfds);
+ }
+
+ if ( pwritefds )
+ {
+ wxFD_ZERO(pwritefds);
+ wxFD_SET(m_fd, pwritefds);
+ }
+
+ wxFD_ZERO(&exceptfds);
+ wxFD_SET(m_fd, &exceptfds);
+
+ const int rc = select(m_fd + 1, preadfds, pwritefds, &exceptfds, &tv);
+
+ // check for errors first
+ if ( rc == -1 || wxFD_ISSET(m_fd, &exceptfds) )
+ {
+ m_establishing = false;
+
+ return wxSOCKET_LOST_FLAG & flags;
+ }
+
+ if ( rc == 0 )
+ return 0;
+
+ wxASSERT_MSG( rc == 1, "unexpected select() return value" );
+
+ wxSocketEventFlags detected = 0;
+ if ( preadfds && wxFD_ISSET(m_fd, preadfds) )
+ detected |= wxSOCKET_INPUT_FLAG;
+
+ if ( pwritefds && wxFD_ISSET(m_fd, pwritefds) )
+ {
+ // check for the case of non-blocking connect()
+ if ( m_establishing && !m_server )
+ {
+ int error;
+ SOCKOPTLEN_T len = sizeof(error);
+ m_establishing = false;
+ getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
+
+ if ( error )
+ detected = wxSOCKET_LOST_FLAG;
+ else
+ detected |= wxSOCKET_CONNECTION_FLAG;
+ }
+ else // not called to get non-blocking connect() status
+ {
+ detected |= wxSOCKET_OUTPUT_FLAG;
+ }
+ }
+
+ return detected & flags;
+}
+
+int
+wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
+{
+ // Use either the provided timeout or the default timeout value associated
+ // with this socket.
+ //
+ // TODO: allow waiting forever, see #9443
+ const long timeout = seconds == -1 ? m_timeout * 1000
+ : seconds * 1000 + milliseconds;
+
+ return DoWait(timeout, flags);
+}
+
+int
+wxSocketBase::DoWait(long timeout, wxSocketEventFlags flags)
+{
+ wxCHECK_MSG( m_impl, -1, "can't wait on invalid socket" );
+
+ // we're never going to become ready in a TCP client if we're not connected
+ // any more (OTOH a server can call this to precisely wait for a connection
+ // so do wait for it in this case and UDP client is never "connected")
+ if ( !m_impl->IsServer() &&
+ m_impl->m_stream && !m_connected && !m_establishing )
+ return -1;
+
+ // This can be set to true from Interrupt() to exit this function a.s.a.p.
+ m_interrupt = false;
+
+
+ const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
+
+ // Get the active event loop which we'll use for the message dispatching
+ // when running in the main thread unless this was explicitly disabled by
+ // setting wxSOCKET_BLOCK flag
+ wxEventLoopBase *eventLoop;
+ if ( !(m_flags & wxSOCKET_BLOCK) && wxIsMainThread() )
+ {
+ eventLoop = wxEventLoop::GetActive();
+ }
+ else // in worker thread
+ {
+ // We never dispatch messages from threads other than the main one.
+ eventLoop = NULL;
+ }
+
+ // Make sure the events we're interested in are enabled before waiting for
+ // them: this is really necessary here as otherwise this could happen:
+ // 1. DoRead(wxSOCKET_WAITALL) is called
+ // 2. There is nothing to read so DoWait(wxSOCKET_INPUT_FLAG) is called
+ // 3. Some, but not all data appears, wxSocketImplUnix::OnReadWaiting()
+ // is called and wxSOCKET_INPUT_FLAG events are disabled in it
+ // 4. Because of wxSOCKET_WAITALL we call DoWait() again but the events
+ // are still disabled and we block forever
+ //
+ // More elegant solution would be nice but for now simply re-enabling the
+ // events here will do
+ m_impl->ReenableEvents(flags & (wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG));
+
+
+ // Wait until we receive the event we're waiting for or the timeout expires
+ // (but note that we always execute the loop at least once, even if timeout
+ // is 0 as this is used for polling)
+ int rc = 0;
+ for ( bool firstTime = true; !m_interrupt; firstTime = false )
+ {
+ long timeLeft = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis());
+ if ( timeLeft < 0 )
+ {
+ if ( !firstTime )
+ break; // timed out
+
+ timeLeft = 0;
+ }
+
+ wxSocketEventFlags events;
+ if ( eventLoop )
+ {
+ // reset them before starting to wait
+ m_eventsgot = 0;
+
+ eventLoop->DispatchTimeout(timeLeft);
+
+ events = m_eventsgot;
+ }
+ else // no event loop or waiting in another thread
+ {
+ // as explained below, we should always check for wxSOCKET_LOST_FLAG
+ timeval tv;
+ SetTimeValFromMS(tv, timeLeft);
+ events = m_impl->Select(flags | wxSOCKET_LOST_FLAG, &tv);
+ }
+
+ // always check for wxSOCKET_LOST_FLAG, even if flags doesn't include
+ // it, as continuing to wait for anything else after getting it is
+ // pointless
+ if ( events & wxSOCKET_LOST_FLAG )
+ {
+ m_connected = false;
+ m_establishing = false;
+ rc = -1;
+ break;
+ }
+
+ // otherwise mask out the bits we're not interested in
+ events &= flags;
+
+ // Incoming connection (server) or connection established (client)?
+ if ( events & wxSOCKET_CONNECTION_FLAG )
+ {
+ m_connected = true;
+ m_establishing = false;
+ rc = true;
+ break;
+ }
+
+ // Data available or output buffer ready?
+ if ( (events & wxSOCKET_INPUT_FLAG) || (events & wxSOCKET_OUTPUT_FLAG) )
+ {
+ rc = true;
+ break;
+ }
+ }
+
+ return rc;