X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/40e7c0b9133bc1cbcb8fc81854cc11a381a1c066..c48d6cdf1fd6b249e95af88e0988fc46fc87b5b9:/src/common/socket.cpp diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 9273719a28..2487fddcfb 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -41,7 +41,9 @@ #include "wx/stopwatch.h" #include "wx/thread.h" #include "wx/evtloop.h" + #include "wx/private/fd.h" +#include "wx/private/socket.h" // DLL options compatibility check: #include "wx/build.h" @@ -158,9 +160,9 @@ void GSocketManager::Init() // ========================================================================== /* static */ -GSocket *GSocketBase::Create() +GSocket *GSocketBase::Create(wxSocketBase& wxsocket) { - GSocket * const newsocket = new GSocket(); + GSocket * const newsocket = new GSocket(wxsocket); if ( !GSocketManager::Get()->Init_Socket(newsocket) ) { delete newsocket; @@ -170,7 +172,8 @@ GSocket *GSocketBase::Create() return newsocket; } -GSocketBase::GSocketBase() +GSocketBase::GSocketBase(wxSocketBase& wxsocket) + : m_wxsocket(&wxsocket) { m_fd = INVALID_SOCKET; m_detected = 0; @@ -180,12 +183,8 @@ GSocketBase::GSocketBase() m_server = false; m_stream = true; m_non_blocking = false; -#ifdef __WINDOWS__ - m_timeout.tv_sec = 10 * 60; /* 10 minutes */ - m_timeout.tv_usec = 0; -#else - m_timeout = 10*60*1000; /* 10 minutes * 60 sec * 1000 millisec */ -#endif + + SetTimeout(wxsocket.GetTimeout() * 1000); m_establishing = false; m_reusable = false; @@ -193,9 +192,6 @@ GSocketBase::GSocketBase() m_dobind = true; m_initialRecvBufferSize = -1; m_initialSendBufferSize = -1; - - for ( int i = 0; i < GSOCK_MAX_EVENT; i++ ) - m_cbacks[i] = NULL; } GSocketBase::~GSocketBase() @@ -214,6 +210,15 @@ GSocketBase::~GSocketBase() GSocketManager::Get()->Destroy_Socket(static_cast(this)); } +void GSocketBase::Close() +{ + if ( m_fd != INVALID_SOCKET ) + { + GSocketManager::Get()->Close_Socket(static_cast(this)); + m_fd = INVALID_SOCKET; + } +} + /* GSocket_Shutdown: * Disallow further read/write operations on this socket, close * the fd and disable all callbacks. @@ -226,13 +231,133 @@ void GSocketBase::Shutdown() Close(); } - /* Disable GUI callbacks */ - for ( int evt = 0; evt < GSOCK_MAX_EVENT; evt++ ) - m_cbacks[evt] = NULL; - m_detected = GSOCK_LOST_FLAG; } +/* GSocket_SetTimeout: + * Sets the timeout for blocking calls. Time is expressed in + * milliseconds. + */ +void GSocketBase::SetTimeout(unsigned long millis) +{ + m_timeout.tv_sec = (millis / 1000); + m_timeout.tv_usec = (millis % 1000) * 1000; +} + +void GSocketBase::NotifyOnStateChange(GSocketEvent event) +{ + // GSocketEvent and wxSocketNotify enums have the same elements with the + // same values + m_wxsocket->OnRequest(static_cast(event)); +} + +/* Address handling */ + +/* GSocket_SetLocal: + * GSocket_GetLocal: + * GSocket_SetPeer: + * GSocket_GetPeer: + * Set or get the local or peer address for this socket. The 'set' + * functions return GSOCK_NOERROR on success, an error code otherwise. + * The 'get' functions return a pointer to a GAddress object on success, + * or NULL otherwise, in which case they set the error code of the + * corresponding GSocket. + * + * Error codes: + * GSOCK_INVSOCK - the socket is not valid. + * GSOCK_INVADDR - the address is not valid. + */ +GSocketError GSocketBase::SetLocal(GAddress *address) +{ + /* the socket must be initialized, or it must be a server */ + if (m_fd != INVALID_SOCKET && !m_server) + { + m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (m_local) + GAddress_destroy(m_local); + + m_local = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GSocketError GSocketBase::SetPeer(GAddress *address) +{ + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (m_peer) + GAddress_destroy(m_peer); + + m_peer = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GAddress *GSocketBase::GetLocal() +{ + GAddress *address; + wxSockAddr addr; + WX_SOCKLEN_T size = sizeof(addr); + GSocketError err; + + /* try to get it from the m_local var first */ + if (m_local) + return GAddress_copy(m_local); + + /* else, if the socket is initialized, try getsockname */ + if (m_fd == INVALID_SOCKET) + { + m_error = GSOCK_INVSOCK; + return NULL; + } + + if (getsockname(m_fd, (sockaddr*)&addr, &size) == SOCKET_ERROR) + { + m_error = GSOCK_IOERR; + return NULL; + } + + /* got a valid address from getsockname, create a GAddress object */ + if ((address = GAddress_new()) == NULL) + { + m_error = GSOCK_MEMERR; + return NULL; + } + + if ((err = _GAddress_translate_from(address, (sockaddr*)&addr, size)) != GSOCK_NOERROR) + { + GAddress_destroy(address); + m_error = err; + return NULL; + } + + return address; +} + +GAddress *GSocketBase::GetPeer() +{ + /* try to get it from the m_peer var */ + if (m_peer) + return GAddress_copy(m_peer); + + return NULL; +} + // ========================================================================== // wxSocketBase // ========================================================================== @@ -395,18 +520,7 @@ bool wxSocketBase::Close() InterruptWait(); if (m_socket) - { - // Disable callbacks - m_socket->UnsetCallback( - GSOCK_INPUT_FLAG | - GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | - GSOCK_CONNECTION_FLAG - ); - - // Shutdown the connection m_socket->Shutdown(); - } m_connected = false; m_establishing = false; @@ -1152,34 +1266,6 @@ void wxSocketBase::SetFlags(wxSocketFlags flags) // Event handling // -------------------------------------------------------------------------- -// A note on how events are processed, which is probably the most -// difficult thing to get working right while keeping the same API -// and functionality for all platforms. -// -// When GSocket detects an event, it calls wx_socket_callback, which in -// turn just calls wxSocketBase::OnRequest in the corresponding wxSocket -// object. OnRequest does some housekeeping, and if the event is to be -// propagated to the user, it creates a new wxSocketEvent object and -// posts it. The event is not processed immediately, but delayed with -// AddPendingEvent instead. This is necessary in order to decouple the -// event processing from wx_socket_callback; otherwise, subsequent IO -// calls made from the user event handler would fail, as gtk callbacks -// are not reentrant. -// -// Note that, unlike events, user callbacks (now deprecated) are _not_ -// decoupled from wx_socket_callback and thus they suffer from a variety -// of problems. Avoid them where possible and use events instead. - -extern "C" -void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket), - GSocketEvent notification, - char *cdata) -{ - wxSocketBase *sckobj = (wxSocketBase *)cdata; - - sckobj->OnRequest((wxSocketNotify) notification); -} - void wxSocketBase::OnRequest(wxSocketNotify notification) { switch(notification) @@ -1324,7 +1410,7 @@ wxSocketServer::wxSocketServer(const wxSockAddress& addr_man, { wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") ); - m_socket = GSocket::Create(); + m_socket = GSocket::Create(*this); if (!m_socket) { @@ -1355,11 +1441,6 @@ wxSocketServer::wxSocketServer(const wxSockAddress& addr_man, return; } - m_socket->SetTimeout(m_timeout * 1000); - m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char *)this); - wxLogTrace( wxTRACE_Socket, _T("wxSocketServer on fd %d"), m_socket->m_fd ); } @@ -1376,20 +1457,14 @@ bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait) // When we are finished, we put the socket to blocking mode // again. wxSocketUnblocker unblock(m_socket, !wait); - GSocket * const child_socket = m_socket->WaitConnection(); + sock.m_socket = m_socket->WaitConnection(sock); - if (!child_socket) + if ( !sock.m_socket ) return false; sock.m_type = wxSOCKET_BASE; - sock.m_socket = child_socket; sock.m_connected = true; - sock.m_socket->SetTimeout(sock.m_timeout * 1000); - sock.m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char *)&sock); - return true; } @@ -1487,23 +1562,13 @@ bool wxSocketClient::DoConnect(const wxSockAddress& addr_man, delete m_socket; } - m_socket = GSocket::Create(); + m_socket = GSocket::Create(*this); m_connected = false; m_establishing = false; if (!m_socket) return false; - m_socket->SetTimeout(m_timeout * 1000); - m_socket->SetCallback( - GSOCK_INPUT_FLAG | - GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | - GSOCK_CONNECTION_FLAG, - wx_socket_callback, - (char *)this - ); - // If wait == false, then the call should be nonblocking. When we are // finished, we put the socket to blocking mode again. wxSocketUnblocker unblock(m_socket, !wait); @@ -1602,13 +1667,11 @@ wxDatagramSocket::wxDatagramSocket( const wxSockAddress& addr, : wxSocketBase( flags, wxSOCKET_DATAGRAM ) { // Create the socket - m_socket = GSocket::Create(); + m_socket = GSocket::Create(*this); if (!m_socket) - { - wxFAIL_MSG( _T("datagram socket not new'd") ); return; - } + m_socket->Notify(m_notify); // Setup the socket as non connection oriented m_socket->SetLocal(addr.GetAddress()); @@ -1634,10 +1697,6 @@ wxDatagramSocket::wxDatagramSocket( const wxSockAddress& addr, // Initialize all stuff m_connected = false; m_establishing = false; - m_socket->SetTimeout( m_timeout * 1000 ); - m_socket->SetCallback( GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char*)this ); } wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr,