X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/95867b4efce9c8b3093d69a250eec361949ef77e..ac52d2b0fc5d688fd882c54a60592c9c9ce61a29:/src/unix/gsocket.cpp diff --git a/src/unix/gsocket.cpp b/src/unix/gsocket.cpp index 5cb9783b71..6efa6b76ad 100644 --- a/src/unix/gsocket.cpp +++ b/src/unix/gsocket.cpp @@ -12,22 +12,24 @@ * ------------------------------------------------------------------------- */ -#if defined(__WATCOMC__) #include "wx/wxprec.h" -#include -#include -#endif -#ifndef __GSOCKET_STANDALONE__ -#include "wx/defs.h" +#if wxUSE_SOCKETS + +#include "wx/gsocket.h" + +#include "wx/private/fd.h" +#include "wx/private/socket.h" #include "wx/private/gsocketiohandler.h" -#endif #if defined(__VISAGECPP__) #define BSD_SELECT /* use Berkeley Sockets select */ #endif -#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) +#if defined(__WATCOMC__) +#include +#include +#endif #include #include @@ -134,13 +136,6 @@ int _System soclose(int); #define SOCKOPTLEN_T WX_SOCKLEN_T #endif -/* - * MSW defines this, Unices don't. - */ -#ifndef INVALID_SOCKET -#define INVALID_SOCKET -1 -#endif - /* UnixWare reportedly needs this for FIONBIO definition */ #ifdef __UNIXWARE__ #include @@ -182,20 +177,9 @@ int _System soclose(int); # define GSOCKET_MSG_NOSIGNAL 0 #endif /* MSG_NOSIGNAL */ -#ifndef __GSOCKET_STANDALONE__ -# include "wx/unix/gsockunx.h" -# include "wx/unix/private.h" -# include "wx/gsocket.h" #if wxUSE_THREADS && (defined(HAVE_GETHOSTBYNAME) || defined(HAVE_GETSERVBYNAME)) # include "wx/thread.h" #endif -#else -# include "gsockunx.h" -# include "gsocket.h" -# ifndef WXUNUSED -# define WXUNUSED(x) -# endif -#endif /* __GSOCKET_STANDALONE__ */ #if defined(HAVE_GETHOSTBYNAME) static struct hostent * deepCopyHostent(struct hostent *h, @@ -450,12 +434,6 @@ struct servent *wxGetservbyname_r(const char *port, const char *protocol, # define GSocket_Debug(args) #endif /* __GSOCKET_DEBUG__ */ -#if wxUSE_IPV6 -typedef struct sockaddr_storage wxSockAddr; -#else -typedef struct sockaddr wxSockAddr; -#endif - /* Table of GUI-related functions. We must call them indirectly because * of wxBase and GUI separation: */ @@ -474,75 +452,18 @@ void GSocket_Cleanup() /* Constructors / Destructors for GSocket */ -GSocket::GSocket() +GSocket::GSocket(wxSocketBase& wxsocket) + : GSocketBase(wxsocket) { - int i; - - m_fd = INVALID_SOCKET; m_handler = NULL; - for (i=0;iInit_Socket(this); -} - -void GSocket::Close() -{ - if (m_use_events) - DisableEvents(); - - /* When running on OS X, the gsockosx implementation of GSocketGUIFunctionsTable - will close the socket during Disable_Events. However, it will only do this - if it is being used. That is, it won't do it in a console program. To - ensure we get the right behavior, we have gsockosx set m_fd = INVALID_SOCKET - if it has closed the socket which indicates to us (at runtime, instead of - at compile time as this had been before) that the socket has already - been closed. - */ - if(m_fd != INVALID_SOCKET) - close(m_fd); - m_fd = INVALID_SOCKET; } GSocket::~GSocket() { - assert(this); - - /* Check that the socket is really shutdowned */ - if (m_fd != INVALID_SOCKET) - Shutdown(); - - GSocketManager::Get()->Destroy_Socket(this); - delete m_handler; - - /* Destroy private addresses */ - if (m_local) - GAddress_destroy(m_local); - - if (m_peer) - GAddress_destroy(m_peer); - } /* GSocket_Shutdown: @@ -551,143 +472,10 @@ GSocket::~GSocket() */ void GSocket::Shutdown() { - int evt; - - assert(this); - - /* Don't allow events to fire after socket has been closed */ - if (m_use_events) + /* Don't allow events to fire after socket has been closed */ DisableEvents(); - /* If socket has been created, shutdown it */ - if (m_fd != INVALID_SOCKET) - { - shutdown(m_fd, 1); - Close(); - } - - /* Disable GUI callbacks */ - for (evt = 0; evt < GSOCK_MAX_EVENT; evt++) - m_cbacks[evt] = NULL; - - m_detected = GSOCK_LOST_FLAG; -} - -/* 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 GSocket::SetLocal(GAddress *address) -{ - assert(this); - - /* 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 GSocket::SetPeer(GAddress *address) -{ - assert(this); - - /* 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 *GSocket::GetLocal() -{ - GAddress *address; - wxSockAddr addr; - WX_SOCKLEN_T size = sizeof(addr); - GSocketError err; - - assert(this); - - /* 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, (WX_SOCKLEN_T *) &size) < 0) - { - m_error = GSOCK_IOERR; - return NULL; - } - - /* got a valid address from getsockname, create a GAddress object */ - address = GAddress_new(); - if (address == NULL) - { - m_error = GSOCK_MEMERR; - return NULL; - } - - err = _GAddress_translate_from(address, (sockaddr*)&addr, size); - if (err != GSOCK_NOERROR) - { - GAddress_destroy(address); - m_error = err; - return NULL; - } - - return address; -} - -GAddress *GSocket::GetPeer() -{ - assert(this); - - /* try to get it from the m_peer var */ - if (m_peer) - return GAddress_copy(m_peer); - - return NULL; + GSocketBase::Shutdown(); } /* Server specific parts */ @@ -741,8 +529,7 @@ GSocketError GSocket::SetServer() #endif ioctl(m_fd, FIONBIO, &arg); - if (m_use_events) - EnableEvents(); + EnableEvents(); /* allow a socket to re-bind if the socket is in the TIME_WAIT state after being previously closed. @@ -785,7 +572,7 @@ GSocketError GSocket::SetServer() * GSOCK_MEMERR - couldn't allocate memory. * GSOCK_IOERR - low-level error. */ -GSocket *GSocket::WaitConnection() +GSocket *GSocket::WaitConnection(wxSocketBase& wxsocket) { wxSockAddr from; WX_SOCKLEN_T fromlen = sizeof(from); @@ -803,7 +590,7 @@ GSocket *GSocket::WaitConnection() } /* Create a GSocket object for the new connection */ - connection = GSocket_new(); + connection = GSocket::Create(wxsocket); if (!connection) { @@ -822,7 +609,7 @@ GSocket *GSocket::WaitConnection() connection->m_fd = accept(m_fd, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen); /* Reenable CONNECTION events */ - Enable(GSOCK_CONNECTION); + EnableEvent(GSOCK_CONNECTION); if (connection->m_fd == INVALID_SOCKET) { @@ -872,15 +659,22 @@ void GSocket::Notify(bool flag) if (flag == m_use_events) return; m_use_events = flag; - EnableEvents(flag); + DoEnableEvents(flag); } -void GSocket::EnableEvents(bool flag) +void GSocket::DoEnableEvents(bool flag) { - if (flag) - GSocketManager::Get()->Enable_Events(this); - else - GSocketManager::Get()->Disable_Events(this); + GSocketManager * const manager = GSocketManager::Get(); + if ( flag ) + { + manager->Install_Callback(this, GSOCK_INPUT); + manager->Install_Callback(this, GSOCK_OUTPUT); + } + else // off + { + manager->Uninstall_Callback(this, GSOCK_INPUT); + manager->Uninstall_Callback(this, GSOCK_OUTPUT); + } } bool GSocket::SetReusable() @@ -949,7 +743,7 @@ GSocketError GSocket::Connect(GSocketStream stream) assert(this); /* Enable CONNECTION events (needed for nonblocking connections) */ - Enable(GSOCK_CONNECTION); + EnableEvent(GSOCK_CONNECTION); if (m_fd != INVALID_SOCKET) { @@ -1012,15 +806,14 @@ GSocketError GSocket::Connect(GSocketStream stream) /* Connect it to the peer address, with a timeout (see below) */ ret = connect(m_fd, m_peer->m_addr, m_peer->m_len); - /* We only call Enable_Events if we know we aren't shutting down the socket. - * NB: Enable_Events needs to be called whether the socket is blocking or + /* We only call EnableEvents() if we know we aren't shutting down the socket. + * NB: EnableEvents() needs to be called whether the socket is blocking or * non-blocking, it just shouldn't be called prior to knowing there is a * connection _if_ blocking sockets are being used. * If connect above returns 0, we are already connected and need to make the - * call to Enable_Events now. + * call to EnableEvents() now. */ - - if (m_use_events && (m_non_blocking || ret == 0)) + if ( m_non_blocking || (ret == 0) ) EnableEvents(); if (ret == -1) @@ -1046,8 +839,7 @@ GSocketError GSocket::Connect(GSocketStream stream) SOCKOPTLEN_T len = sizeof(error); getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*) &error, &len); - if (m_use_events) - EnableEvents(); + EnableEvents(); if (!error) return GSOCK_NOERROR; @@ -1127,8 +919,7 @@ GSocketError GSocket::SetNonOriented() #else ioctl(m_fd, FIONBIO, &arg); #endif - if (m_use_events) - EnableEvents(); + EnableEvents(); if (m_reusable) { @@ -1176,7 +967,7 @@ int GSocket::Read(char *buffer, int size) } /* Disable events during query of socket status */ - Disable(GSOCK_INPUT); + DisableEvent(GSOCK_INPUT); /* If the socket is blocking, wait for data (with a timeout) */ if (Input_Timeout() == GSOCK_TIMEDOUT) { @@ -1222,7 +1013,7 @@ int GSocket::Read(char *buffer, int size) } /* Enable events again now that we are done processing */ - Enable(GSOCK_INPUT); + EnableEvent(GSOCK_INPUT); return ret; } @@ -1275,7 +1066,7 @@ int GSocket::Write(const char *buffer, int size) * that the socket is writable until a read operation fails. Only then * will further OUTPUT events be posted. */ - Enable(GSOCK_OUTPUT); + EnableEvent(GSOCK_OUTPUT); return -1; } @@ -1285,112 +1076,6 @@ int GSocket::Write(const char *buffer, int size) return ret; } -/* GSocket_Select: - * Polls the socket to determine its status. This function will - * check for the events specified in the 'flags' parameter, and - * it will return a mask indicating which operations can be - * performed. This function won't block, regardless of the - * mode (blocking | nonblocking) of the socket. - */ -GSocketEventFlags GSocket::Select(GSocketEventFlags flags) -{ - assert(this); - - GSocketEventFlags result = 0; - fd_set readfds; - fd_set writefds; - fd_set exceptfds; - struct timeval tv; - - if (m_fd == -1) - return (GSOCK_LOST_FLAG & flags); - - /* Do not use a static struct, Linux can garble it */ - tv.tv_sec = 0; - tv.tv_usec = 0; - - wxFD_ZERO(&readfds); - wxFD_ZERO(&writefds); - wxFD_ZERO(&exceptfds); - wxFD_SET(m_fd, &readfds); - if (flags & GSOCK_OUTPUT_FLAG || flags & GSOCK_CONNECTION_FLAG) - wxFD_SET(m_fd, &writefds); - wxFD_SET(m_fd, &exceptfds); - - /* Check 'sticky' CONNECTION flag first */ - result |= GSOCK_CONNECTION_FLAG & m_detected; - - /* If we have already detected a LOST event, then don't try - * to do any further processing. - */ - if ((m_detected & GSOCK_LOST_FLAG) != 0) - { - m_establishing = false; - return (GSOCK_LOST_FLAG & flags); - } - - /* Try select now */ - if (select(m_fd + 1, &readfds, &writefds, &exceptfds, &tv) < 0) - { - /* What to do here? */ - return (result & flags); - } - - /* Check for exceptions and errors */ - if (wxFD_ISSET(m_fd, &exceptfds)) - { - m_establishing = false; - m_detected = GSOCK_LOST_FLAG; - - /* LOST event: Abort any further processing */ - return (GSOCK_LOST_FLAG & flags); - } - - /* Check for readability */ - if (wxFD_ISSET(m_fd, &readfds)) - { - result |= GSOCK_INPUT_FLAG; - - if (m_server && m_stream) - { - /* This is a TCP server socket that detected a connection. - While the INPUT_FLAG is also set, it doesn't matter on - this kind of sockets, as we can only Accept() from them. */ - m_detected |= GSOCK_CONNECTION_FLAG; - } - } - - /* Check for writability */ - if (wxFD_ISSET(m_fd, &writefds)) - { - 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) - { - m_detected = GSOCK_LOST_FLAG; - - /* LOST event: Abort any further processing */ - return (GSOCK_LOST_FLAG & flags); - } - else - { - m_detected |= GSOCK_CONNECTION_FLAG; - } - } - else - { - result |= GSOCK_OUTPUT_FLAG; - } - } - - return (result | m_detected) & flags; -} - /* Flags */ /* GSocket_SetNonBlocking: @@ -1406,17 +1091,6 @@ void GSocket::SetNonBlocking(bool non_block) m_non_blocking = non_block; } -/* GSocket_SetTimeout: - * Sets the timeout for blocking calls. Time is expressed in - * milliseconds. - */ -void GSocket::SetTimeout(unsigned long millisec) -{ - assert(this); - - m_timeout = millisec; -} - /* GSocket_GetError: * Returns the last error occurred for this socket. Note that successful * operations do not clear this back to GSOCK_NOERROR, so use it only @@ -1429,73 +1103,6 @@ GSocketError WXDLLIMPEXP_NET GSocket::GetError() return m_error; } -/* Callbacks */ - -/* GSOCK_INPUT: - * There is data to be read in the input buffer. If, after a read - * operation, there is still data available, the callback function will - * be called again. - * GSOCK_OUTPUT: - * The socket is available for writing. That is, the next write call - * won't block. This event is generated only once, when the connection is - * first established, and then only if a call failed with GSOCK_WOULDBLOCK, - * when the output buffer empties again. This means that the app should - * assume that it can write since the first OUTPUT event, and no more - * OUTPUT events will be generated unless an error occurs. - * GSOCK_CONNECTION: - * Connection successfully established, for client sockets, or incoming - * client connection, for server sockets. Wait for this event (also watch - * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. - * GSOCK_LOST: - * The connection is lost (or a connection request failed); this could - * be due to a failure, or due to the peer closing it gracefully. - */ - -/* GSocket_SetCallback: - * Enables the callbacks specified by 'flags'. Note that 'flags' - * may be a combination of flags OR'ed toghether, so the same - * callback function can be made to accept different events. - * The callback function must have the following prototype: - * - * void function(GSocket *socket, GSocketEvent event, char *cdata) - */ -void GSocket::SetCallback(GSocketEventFlags flags, - GSocketCallback callback, char *cdata) -{ - int count; - - assert(this); - - for (count = 0; count < GSOCK_MAX_EVENT; count++) - { - if ((flags & (1 << count)) != 0) - { - m_cbacks[count] = callback; - m_data[count] = cdata; - } - } -} - -/* GSocket_UnsetCallback: - * Disables all callbacks specified by 'flags', which may be a - * combination of flags OR'ed toghether. - */ -void GSocket::UnsetCallback(GSocketEventFlags flags) -{ - int count; - - assert(this); - - for (count = 0; count < GSOCK_MAX_EVENT; count++) - { - if ((flags & (1 << count)) != 0) - { - m_cbacks[count] = NULL; - m_data[count] = NULL; - } - } -} - GSocketError GSocket::GetSockOpt(int level, int optname, void *optval, int *optlen) { @@ -1514,14 +1121,7 @@ GSocketError GSocket::SetSockOpt(int level, int optname, return GSOCK_OPTERR; } -#define CALL_CALLBACK(socket, event) { \ - socket->Disable(event); \ - if (socket->m_cbacks[event]) \ - socket->m_cbacks[event](socket, event, socket->m_data[event]); \ -} - - -void GSocket::Enable(GSocketEvent event) +void GSocket::EnableEvent(GSocketEvent event) { if (m_use_events) { @@ -1530,7 +1130,7 @@ void GSocket::Enable(GSocketEvent event) } } -void GSocket::Disable(GSocketEvent event) +void GSocket::DisableEvent(GSocketEvent event) { if (m_use_events) { @@ -1545,13 +1145,11 @@ void GSocket::Disable(GSocketEvent event) */ GSocketError GSocket::Input_Timeout() { - struct timeval tv; fd_set readfds; int ret; - /* Linux select() will overwrite the struct on return */ - tv.tv_sec = (m_timeout / 1000); - tv.tv_usec = (m_timeout % 1000) * 1000; + // Linux select() will overwrite the struct on return so make a copy + struct timeval tv = m_timeout; if (!m_non_blocking) { @@ -1586,13 +1184,11 @@ GSocketError GSocket::Input_Timeout() */ GSocketError GSocket::Output_Timeout() { - struct timeval tv; fd_set writefds; int ret; - /* Linux select() will overwrite the struct on return */ - tv.tv_sec = (m_timeout / 1000); - tv.tv_usec = (m_timeout % 1000) * 1000; + // Linux select() will overwrite the struct on return so make a copy + struct timeval tv = m_timeout; GSocket_Debug( ("m_non_blocking has: %d\n", (int)m_non_blocking) ); @@ -1741,6 +1337,15 @@ int GSocket::Send_Dgram(const char *buffer, int size) return ret; } +void GSocket::OnStateChange(GSocketEvent event) +{ + DisableEvent(event); + NotifyOnStateChange(event); + + if ( event == GSOCK_LOST ) + Shutdown(); +} + void GSocket::Detected_Read() { char c; @@ -1758,8 +1363,7 @@ void GSocket::Detected_Read() { m_establishing = false; - CALL_CALLBACK(this, GSOCK_LOST); - Shutdown(); + OnStateChange(GSOCK_LOST); return; } @@ -1767,26 +1371,25 @@ void GSocket::Detected_Read() if (num > 0) { - CALL_CALLBACK(this, GSOCK_INPUT); + OnStateChange(GSOCK_INPUT); } else { if (m_server && m_stream) { - CALL_CALLBACK(this, GSOCK_CONNECTION); + OnStateChange(GSOCK_CONNECTION); } else if (num == 0) { if (m_stream) { /* graceful shutdown */ - CALL_CALLBACK(this, GSOCK_LOST); - Shutdown(); + OnStateChange(GSOCK_LOST); } else { /* Empty datagram received */ - CALL_CALLBACK(this, GSOCK_INPUT); + OnStateChange(GSOCK_INPUT); } } else @@ -1794,12 +1397,11 @@ void GSocket::Detected_Read() /* Do not throw a lost event in cases where the socket isn't really lost */ if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINTR)) { - CALL_CALLBACK(this, GSOCK_INPUT); + OnStateChange(GSOCK_INPUT); } else { - CALL_CALLBACK(this, GSOCK_LOST); - Shutdown(); + OnStateChange(GSOCK_LOST); } } } @@ -1814,8 +1416,7 @@ void GSocket::Detected_Write() { m_establishing = false; - CALL_CALLBACK(this, GSOCK_LOST); - Shutdown(); + OnStateChange(GSOCK_LOST); return; } @@ -1830,37 +1431,24 @@ void GSocket::Detected_Write() if (error) { - CALL_CALLBACK(this, GSOCK_LOST); - Shutdown(); + OnStateChange(GSOCK_LOST); } else { - CALL_CALLBACK(this, GSOCK_CONNECTION); + OnStateChange(GSOCK_CONNECTION); /* We have to fire this event by hand because CONNECTION (for clients) * and OUTPUT are internally the same and we just disabled CONNECTION * events with the above macro. */ - CALL_CALLBACK(this, GSOCK_OUTPUT); + OnStateChange(GSOCK_OUTPUT); } } else { - CALL_CALLBACK(this, GSOCK_OUTPUT); + OnStateChange(GSOCK_OUTPUT); } } -/* Compatibility functions for GSocket */ -GSocket *GSocket_new(void) -{ - GSocket *newsocket = new GSocket(); - if (newsocket->IsOk()) - return newsocket; - - delete newsocket; - - return NULL; -} - /* * ------------------------------------------------------------------------- * GAddress @@ -2460,4 +2048,4 @@ GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf) return GSOCK_NOERROR; } #endif /* !defined(__VISAGECPP__) */ -#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */ +#endif /* wxUSE_SOCKETS */