X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/52fbdb5892cea0b262bd3271d496a4e7b1955f63..4175794e0361c78ad63984cd01e4378677803dbc:/src/common/socket.cpp diff --git a/src/common/socket.cpp b/src/common/socket.cpp index fa5da95246..95669073cd 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -51,12 +51,30 @@ // discard buffer #define MAX_DISCARD_SIZE (10 * 1024) -// what to do within waits +// what to do within waits: in wxBase we don't do anything as we don't have +// the event loop anyhow (for now). In GUI apps we have 2 cases: from the main +// thread itself we have to call wxYield() to let the events (including the +// GUI events and the low-level (not wxWindows) events from GSocket) be +// processed. From another thread it is enough to just call wxThread::Yield() +// which will give away the rest of our time slice: the explanation is that +// the events will be processed by the main thread anyhow, without calling +// wxYield(), but we don't want to eat the CPU time uselessly while sitting +// in the loop waiting for the data #if wxUSE_GUI - #define PROCESS_EVENTS() wxYield() -#else - #define PROCESS_EVENTS() -#endif + #if wxUSE_THREADS + #define PROCESS_EVENTS() \ + { \ + if ( wxThread::IsMain() ) \ + wxYield(); \ + else \ + wxThread::Yield(); \ + } + #else // !wxUSE_THREADS + #define PROCESS_EVENTS() wxYield() + #endif // wxUSE_THREADS/!wxUSE_THREADS +#else // !wxUSE_GUI + #define PROCESS_EVENTS() +#endif // wxUSE_GUI/!wxUSE_GUI // -------------------------------------------------------------------------- // wxWin macros @@ -92,6 +110,44 @@ public: // wxSocketBase // ========================================================================== +// -------------------------------------------------------------------------- +// Initialization and shutdown +// -------------------------------------------------------------------------- + +// FIXME-MT: all this is MT-unsafe, of course, we should protect all accesses +// to m_countInit with a crit section +size_t wxSocketBase::m_countInit = 0; + +bool wxSocketBase::IsInitialized() +{ + return m_countInit > 0; +} + +bool wxSocketBase::Initialize() +{ + if ( !m_countInit++ ) + { + if ( !GSocket_Init() ) + { + m_countInit--; + + return FALSE; + } + } + + return TRUE; +} + +void wxSocketBase::Shutdown() +{ + // we should be initialized + wxASSERT_MSG( m_countInit, _T("extra call to Shutdown()") ); + if ( !--m_countInit ) + { + GSocket_Cleanup(); + } +} + // -------------------------------------------------------------------------- // Ctor and dtor // -------------------------------------------------------------------------- @@ -127,6 +183,13 @@ void wxSocketBase::Init() m_cbk = NULL; m_cdata = NULL; #endif // WXWIN_COMPATIBILITY + + if ( !IsInitialized() ) + { + // this Initialize() will be undone by wxSocketModule::OnExit(), all the + // other calls to it should be matched by a call to Shutdown() + Initialize(); + } } wxSocketBase::wxSocketBase() @@ -244,32 +307,38 @@ wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes) nbytes -= total; buffer = (char *)buffer + total; - // If the socket is invalid or we got all the data, return now - if (!m_socket || !nbytes) + // Return now in one of the following cases: + // - the socket is invalid, + // - we got all the data, + // - we got *some* data and we are not using wxSOCKET_WAITALL. + if ( !m_socket || + !nbytes || + ((total != 0) && !(m_flags & wxSOCKET_WAITALL)) ) return total; // Possible combinations (they are checked in this order) // wxSOCKET_NOWAIT - // wxSOCKET_WAITALL | wxSOCKET_BLOCK - // wxSOCKET_WAITALL + // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) // wxSOCKET_BLOCK // wxSOCKET_NONE // if (m_flags & wxSOCKET_NOWAIT) { - GSocket_SetNonBlocking(m_socket, TRUE); + GSocket_SetNonBlocking(m_socket, 1); ret = GSocket_Read(m_socket, (char *)buffer, nbytes); - GSocket_SetNonBlocking(m_socket, FALSE); + GSocket_SetNonBlocking(m_socket, 0); if (ret > 0) total += ret; } - else if (m_flags & wxSOCKET_WAITALL) + else { - while (ret > 0 && nbytes > 0) + bool more = TRUE; + + while (more) { - if (!(m_flags & wxSOCKET_BLOCK) && !WaitForRead()) - break; + if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() ) + break; ret = GSocket_Read(m_socket, (char *)buffer, nbytes); @@ -279,16 +348,12 @@ wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes) nbytes -= ret; buffer = (char *)buffer + ret; } - } - } - else - { - if ((m_flags & wxSOCKET_BLOCK) || WaitForRead()) - { - ret = GSocket_Read(m_socket, (char *)buffer, nbytes); - if (ret > 0) - total += ret; + // 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)); } } @@ -324,7 +389,7 @@ wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes) if (sig != 0xfeeddead) { - wxLogWarning( _("wxSocket: invalid signature in ReadMsg.")); + wxLogWarning(_("wxSocket: invalid signature in ReadMsg.")); goto exit; } @@ -378,7 +443,7 @@ wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes) if (sig != 0xdeadfeed) { - wxLogWarning( _("wxSocket: invalid signature in ReadMsg.")); + wxLogWarning(_("wxSocket: invalid signature in ReadMsg.")); goto exit; } @@ -438,51 +503,48 @@ wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes) wxUint32 total = 0; int ret = 1; - // If the socket is invalid, return immediately - if (!m_socket) + // If the socket is invalid or parameters are ill, return immediately + if (!m_socket || !buffer || !nbytes) return 0; // Possible combinations (they are checked in this order) // wxSOCKET_NOWAIT - // wxSOCKET_WAITALL | wxSOCKET_BLOCK - // wxSOCKET_WAITALL + // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) // wxSOCKET_BLOCK // wxSOCKET_NONE // if (m_flags & wxSOCKET_NOWAIT) { - GSocket_SetNonBlocking(m_socket, TRUE); + GSocket_SetNonBlocking(m_socket, 1); ret = GSocket_Write(m_socket, (const char *)buffer, nbytes); - GSocket_SetNonBlocking(m_socket, FALSE); + GSocket_SetNonBlocking(m_socket, 0); if (ret > 0) total = ret; } - else if (m_flags & wxSOCKET_WAITALL) + else { - while (ret > 0 && nbytes > 0) + bool more = TRUE; + + while (more) { - if (!(m_flags & wxSOCKET_BLOCK) && !WaitForWrite()) - break; + if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) + break; ret = GSocket_Write(m_socket, (const char *)buffer, nbytes); - + if (ret > 0) { total += ret; nbytes -= ret; buffer = (const char *)buffer + ret; } - } - } - else - { - if ((m_flags & wxSOCKET_BLOCK) || WaitForWrite()) - { - ret = GSocket_Write(m_socket, (const char *)buffer, nbytes); - if (ret > 0) - total = ret; + // 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)); } } @@ -845,9 +907,10 @@ char *wxSocketBase::CallbackData(char *data) // decoupled from wx_socket_callback and thus they suffer from a variety // of problems. Avoid them where possible and use events instead. -static void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket), - GSocketEvent notification, - char *cdata) +extern "C" +void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket), + GSocketEvent notification, + char *cdata) { wxSocketBase *sckobj = (wxSocketBase *)cdata; @@ -901,7 +964,7 @@ void wxSocketBase::OnRequest(wxSocketNotify notification) case GSOCK_CONNECTION: flag = GSOCK_CONNECTION_FLAG; break; case GSOCK_LOST: flag = GSOCK_LOST_FLAG; break; default: - wxLogWarning( _("wxSocket: unknown event!.")); + wxLogWarning(_("wxSocket: unknown event!.")); return; } @@ -993,7 +1056,7 @@ wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek) // ========================================================================== -// wxSocketServer +// wxSocketServer // ========================================================================== // -------------------------------------------------------------------------- @@ -1042,12 +1105,12 @@ bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait) // again. if (!wait) - GSocket_SetNonBlocking(m_socket, TRUE); + GSocket_SetNonBlocking(m_socket, 1); child_socket = GSocket_WaitConnection(m_socket); if (!wait) - GSocket_SetNonBlocking(m_socket, FALSE); + GSocket_SetNonBlocking(m_socket, 0); if (!child_socket) return FALSE; @@ -1071,7 +1134,10 @@ wxSocketBase *wxSocketServer::Accept(bool wait) sock->SetFlags(m_flags); if (!AcceptWith(*sock, wait)) - return NULL; + { + sock->Destroy(); + sock = NULL; + } return sock; } @@ -1130,13 +1196,13 @@ bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait) // again. if (!wait) - GSocket_SetNonBlocking(m_socket, TRUE); + GSocket_SetNonBlocking(m_socket, 1); GSocket_SetPeer(m_socket, addr_man.GetAddress()); err = GSocket_Connect(m_socket, GSOCK_STREAMED); if (!wait) - GSocket_SetNonBlocking(m_socket, FALSE); + GSocket_SetNonBlocking(m_socket, 0); if (err != GSOCK_NOERROR) { @@ -1215,36 +1281,27 @@ wxDatagramSocket& wxDatagramSocket::SendTo( wxSockAddress& addr, return (*this); } -// ========================================================================== -// wxSocketEvent -// ========================================================================== - -wxSocketEvent::wxSocketEvent(int id) : wxEvent(id) -{ - SetEventType( (wxEventType)wxEVT_SOCKET ); -} - -void wxSocketEvent::CopyObject(wxObject& object_dest) const -{ - wxSocketEvent *event = (wxSocketEvent *)&object_dest; - - wxEvent::CopyObject(object_dest); - - event->m_event = m_event; - event->m_clientData = m_clientData; -} - // ========================================================================== // wxSocketModule // ========================================================================== class WXDLLEXPORT wxSocketModule : public wxModule { - DECLARE_DYNAMIC_CLASS(wxSocketModule) - public: - bool OnInit() { return GSocket_Init(); } - void OnExit() { GSocket_Cleanup(); } + virtual bool OnInit() + { + // wxSocketBase will call GSocket_Init() itself when/if needed + return TRUE; + } + + virtual void OnExit() + { + if ( wxSocketBase::IsInitialized() ) + wxSocketBase::Shutdown(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxSocketModule) }; IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule)