X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2f10f4238afa739b528d4115a5f2e8a0e87f2bcb..c2a331e02732bb6a04a42ebf646d54b4373ad122:/src/common/socket.cpp diff --git a/src/common/socket.cpp b/src/common/socket.cpp index c5b1bab4e4..6e41b0e4c3 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -6,14 +6,14 @@ // Copyright: (C) 1999-1997, Guilhem Lavaux // (C) 2000-1999, Guillermo Rodriguez Garcia // RCS_ID: $Id$ -// License: see wxWindows license +// License: see wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ========================================================================== // Declarations // ========================================================================== -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "socket.h" #endif @@ -27,6 +27,7 @@ #if wxUSE_SOCKETS #include "wx/app.h" +#include "wx/apptrait.h" #include "wx/defs.h" #include "wx/object.h" #include "wx/string.h" @@ -37,13 +38,13 @@ #include "wx/intl.h" #include "wx/event.h" -#if wxUSE_GUI - #include "wx/gdicmn.h" // for wxPendingDelete -#endif // wxUSE_GUI - #include "wx/sckaddr.h" #include "wx/socket.h" +// DLL options compatibility check: +#include "wx/build.h" +WX_CHECK_BUILD_OPTIONS("wxNet") + // -------------------------------------------------------------------------- // macros and constants // -------------------------------------------------------------------------- @@ -51,30 +52,26 @@ // discard buffer #define MAX_DISCARD_SIZE (10 * 1024) -// 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 - #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 +// what to do within waits: 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_THREADS + #define PROCESS_EVENTS() \ + { \ + if ( wxThread::IsMain() ) \ + wxYield(); \ + else \ + wxThread::Yield(); \ + } +#else // !wxUSE_THREADS + #define PROCESS_EVENTS() wxYield() +#endif // wxUSE_THREADS/!wxUSE_THREADS + +#define wxTRACE_Socket _T("wxSocket") // -------------------------------------------------------------------------- // wxWin macros @@ -104,12 +101,58 @@ public: public: wxSocketState() : wxObject() {} + + DECLARE_NO_COPY_CLASS(wxSocketState) }; // ========================================================================== // 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++ ) + { + wxAppTraits *traits = wxAppConsole::GetInstance() ? + wxAppConsole::GetInstance()->GetTraits() : NULL; + GSocketGUIFunctionsTable *functions = + traits ? traits->GetSocketGUIFunctionsTable() : NULL; + GSocket_SetGUIFunctions(functions); + + 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 // -------------------------------------------------------------------------- @@ -145,6 +188,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() @@ -164,9 +214,9 @@ wxSocketBase::~wxSocketBase() { // Just in case the app called Destroy() *and* then deleted // the socket immediately: don't leave dangling pointers. -#if wxUSE_GUI - wxPendingDelete.DeleteObject(this); -#endif + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits ) + traits->RemoveFromPendingDelete(this); // Shutdown and close the socket if (!m_beingDeleted) @@ -194,12 +244,18 @@ bool wxSocketBase::Destroy() // Supress events from now on Notify(FALSE); -#if wxUSE_GUI - if ( !wxPendingDelete.Member(this) ) - wxPendingDelete.Append(this); -#else - delete this; -#endif + // 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; } @@ -481,7 +537,7 @@ wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes) { bool more = TRUE; - while (more) + while (more) { if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) break; @@ -510,7 +566,6 @@ wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes) { wxUint32 total; bool error; - int old_flags; struct { unsigned char sig[4]; @@ -522,7 +577,6 @@ wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes) error = TRUE; total = 0; - old_flags = m_flags; SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); msg.sig[0] = (unsigned char) 0xad; @@ -576,7 +630,6 @@ wxSocketBase& wxSocketBase::Unread(const void *buffer, wxUint32 nbytes) wxSocketBase& wxSocketBase::Discard() { - int old_flags; char *buffer = new char[MAX_DISCARD_SIZE]; wxUint32 ret; wxUint32 total = 0; @@ -584,7 +637,6 @@ wxSocketBase& wxSocketBase::Discard() // Mask read events m_reading = TRUE; - old_flags = m_flags; SetFlags(wxSOCKET_NOWAIT); do @@ -732,6 +784,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); @@ -776,14 +834,14 @@ void wxSocketBase::SaveState() void wxSocketBase::RestoreState() { - wxNode *node; + wxList::compatibility_iterator node; wxSocketState *state; - node = m_states.Last(); + node = m_states.GetLast(); if (!node) return; - state = (wxSocketState *)node->Data(); + state = (wxSocketState *)node->GetData(); m_flags = state->m_flags; m_notify = state->m_notify; @@ -794,7 +852,7 @@ void wxSocketBase::RestoreState() m_cdata = state->m_cdata; #endif // WXWIN_COMPATIBILITY - delete node; + m_states.Erase(node); delete state; } @@ -862,9 +920,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; @@ -1010,7 +1069,7 @@ wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek) // ========================================================================== -// wxSocketServer +// wxSocketServer // ========================================================================== // -------------------------------------------------------------------------- @@ -1021,26 +1080,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); } // -------------------------------------------------------------------------- @@ -1088,7 +1153,10 @@ wxSocketBase *wxSocketServer::Accept(bool wait) sock->SetFlags(m_flags); if (!AcceptWith(*sock, wait)) - return NULL; + { + sock->Destroy(); + sock = NULL; + } return sock; } @@ -1232,39 +1300,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 +class 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