X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1f0500b3ee1255cc71624bc58b83d0d954b2d45e..07243717e26bda497d5a8b325c2e6acf4ee033cf:/src/common/socket.cpp diff --git a/src/common/socket.cpp b/src/common/socket.cpp index b2947da8e8..2848d09a9a 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -51,12 +51,32 @@ // 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 + +#define wxTRACE_Socket _T("wxSocket") // -------------------------------------------------------------------------- // wxWin macros @@ -92,6 +112,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 +185,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() @@ -463,7 +528,7 @@ wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes) { bool more = TRUE; - while (more) + while (more) { if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) break; @@ -714,6 +779,12 @@ bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const return FALSE; peer = GSocket_GetPeer(m_socket); + + // copying a null address would just trigger an assert anyway + + if (!peer) + return FALSE; + addr_man.SetAddress(peer); GAddress_destroy(peer); @@ -844,9 +915,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; @@ -992,7 +1064,7 @@ wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek) // ========================================================================== -// wxSocketServer +// wxSocketServer // ========================================================================== // -------------------------------------------------------------------------- @@ -1003,26 +1075,32 @@ wxSocketServer::wxSocketServer(wxSockAddress& addr_man, wxSocketFlags flags) : wxSocketBase(flags, wxSOCKET_SERVER) { - // Create the socket - m_socket = GSocket_new(); + wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") ); - if (!m_socket) - return; + m_socket = GSocket_new(); - // Setup the socket as server - GSocket_SetLocal(m_socket, addr_man.GetAddress()); - if (GSocket_SetServer(m_socket) != GSOCK_NOERROR) - { - GSocket_destroy(m_socket); - m_socket = NULL; - return; - } + if (!m_socket) + { + wxLogTrace( wxTRACE_Socket, _T("*** GSocket_new failed") ); + return; + } - GSocket_SetTimeout(m_socket, m_timeout * 1000); - GSocket_SetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char *)this); + // Setup the socket as server + GSocket_SetLocal(m_socket, addr_man.GetAddress()); + if (GSocket_SetServer(m_socket) != GSOCK_NOERROR) + { + GSocket_destroy(m_socket); + m_socket = NULL; + + wxLogTrace( wxTRACE_Socket, _T("*** GSocket_SetServer failed") ); + return; + } + + GSocket_SetTimeout(m_socket, m_timeout * 1000); + GSocket_SetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | + GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, + wx_socket_callback, (char *)this); } // -------------------------------------------------------------------------- @@ -1070,7 +1148,10 @@ wxSocketBase *wxSocketServer::Accept(bool wait) sock->SetFlags(m_flags); if (!AcceptWith(*sock, wait)) - return NULL; + { + sock->Destroy(); + sock = NULL; + } return sock; } @@ -1214,39 +1295,32 @@ 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() != 0; } - 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) #endif // wxUSE_SOCKETS + +// vi:sts=4:sw=4:et