* -------------------------------------------------------------------------
*/
-#if defined(__WATCOMC__)
#include "wx/wxprec.h"
-#include <errno.h>
-#include <nerrno.h>
-#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 <errno.h>
+#include <nerrno.h>
+#endif
#include <assert.h>
#include <sys/types.h>
#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 <sys/filio.h>
# 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,
/* Table of GUI-related functions. We must call them indirectly because
* of wxBase and GUI separation: */
-static GSocketGUIFunctionsTable *gs_gui_functions;
-
-class GSocketGUIFunctionsTableNull: public GSocketGUIFunctionsTable
+bool GSocket_Init()
{
-public:
- virtual bool OnInit();
- virtual void OnExit();
- virtual bool CanUseEventLoop();
- virtual bool Init_Socket(GSocket *socket);
- virtual void Destroy_Socket(GSocket *socket);
- virtual void Install_Callback(GSocket *socket, GSocketEvent event);
- virtual void Uninstall_Callback(GSocket *socket, GSocketEvent event);
- virtual void Enable_Events(GSocket *socket);
- virtual void Disable_Events(GSocket *socket);
-};
-
-bool GSocketGUIFunctionsTableNull::OnInit()
-{ return true; }
-void GSocketGUIFunctionsTableNull::OnExit()
-{}
-bool GSocketGUIFunctionsTableNull::CanUseEventLoop()
-{ return false; }
-bool GSocketGUIFunctionsTableNull::Init_Socket(GSocket *WXUNUSED(socket))
-{ return true; }
-void GSocketGUIFunctionsTableNull::Destroy_Socket(GSocket *WXUNUSED(socket))
-{}
-void GSocketGUIFunctionsTableNull::Install_Callback(GSocket *WXUNUSED(socket), GSocketEvent WXUNUSED(event))
-{}
-void GSocketGUIFunctionsTableNull::Uninstall_Callback(GSocket *WXUNUSED(socket), GSocketEvent WXUNUSED(event))
-{}
-void GSocketGUIFunctionsTableNull::Enable_Events(GSocket *WXUNUSED(socket))
-{}
-void GSocketGUIFunctionsTableNull::Disable_Events(GSocket *WXUNUSED(socket))
-{}
-/* Global initialisers */
-
-void GSocket_SetGUIFunctions(GSocketGUIFunctionsTable *guifunc)
-{
- gs_gui_functions = guifunc;
+ GSocketManager * const manager = GSocketManager::Get();
+ return manager && manager->OnInit();
}
-int GSocket_Init(void)
+void GSocket_Cleanup()
{
- if (!gs_gui_functions)
- {
- static GSocketGUIFunctionsTableNull table;
- gs_gui_functions = &table;
- }
- if ( !gs_gui_functions->OnInit() )
- return 0;
- return 1;
-}
-
-void GSocket_Cleanup(void)
-{
- if (gs_gui_functions)
- {
- gs_gui_functions->OnExit();
- }
+ GSocketManager * const manager = GSocketManager::Get();
+ if ( manager )
+ manager->OnExit();
}
/* Constructors / Destructors for GSocket */
-GSocket::GSocket()
+GSocket::GSocket(wxSocketBase& wxsocket)
+ : GSocketBase(wxsocket)
{
- int i;
-
- m_fd = INVALID_SOCKET;
m_handler = NULL;
- for (i=0;i<GSOCK_MAX_EVENT;i++)
- {
- m_cbacks[i] = NULL;
- }
- m_detected = 0;
- m_local = NULL;
- m_peer = NULL;
- m_error = GSOCK_NOERROR;
- m_server = false;
- m_stream = true;
m_gui_dependent = NULL;
- m_non_blocking = false;
- m_reusable = false;
- m_broadcast = false;
- m_dobind = true;
- m_timeout = 10*60*1000;
- /* 10 minutes * 60 sec * 1000 millisec */
- m_establishing = false;
- m_initialRecvBufferSize = -1;
- m_initialSendBufferSize = -1;
-
- assert(gs_gui_functions);
- /* Per-socket GUI-specific initialization */
- m_ok = gs_gui_functions->Init_Socket(this);
-}
-
-void GSocket::Close()
-{
- gs_gui_functions->Disable_Events(this);
-
- /* 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;
+ m_use_events = false;
}
GSocket::~GSocket()
{
- assert(this);
-
- /* Check that the socket is really shutdowned */
- if (m_fd != INVALID_SOCKET)
- Shutdown();
-
- /* Per-socket GUI-specific cleanup */
- gs_gui_functions->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:
*/
void GSocket::Shutdown()
{
- int evt;
-
- assert(this);
-
- /* Don't allow events to fire after socket has been closed */
- gs_gui_functions->Disable_Events(this);
-
- /* 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;
- struct sockaddr 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;
- }
+ /* Don't allow events to fire after socket has been closed */
+ DisableEvents();
- if (getsockname(m_fd, &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, &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 */
#endif
ioctl(m_fd, FIONBIO, &arg);
- gs_gui_functions->Enable_Events(this);
+ EnableEvents();
/* allow a socket to re-bind if the socket is in the TIME_WAIT
state after being previously closed.
* GSOCK_MEMERR - couldn't allocate memory.
* GSOCK_IOERR - low-level error.
*/
-GSocket *GSocket::WaitConnection()
+GSocket *GSocket::WaitConnection(wxSocketBase& wxsocket)
{
- struct sockaddr from;
+ wxSockAddr from;
WX_SOCKLEN_T fromlen = sizeof(from);
GSocket *connection;
GSocketError err;
}
/* Create a GSocket object for the new connection */
- connection = GSocket_new();
+ connection = GSocket::Create(wxsocket);
if (!connection)
{
return NULL;
}
- connection->m_fd = accept(m_fd, &from, (WX_SOCKLEN_T *) &fromlen);
+ 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)
{
return NULL;
}
- err = _GAddress_translate_from(connection->m_peer, &from, fromlen);
+ err = _GAddress_translate_from(connection->m_peer, (sockaddr*)&from, fromlen);
if (err != GSOCK_NOERROR)
{
delete connection;
#else
ioctl(connection->m_fd, FIONBIO, &arg);
#endif
- gs_gui_functions->Enable_Events(connection);
+ if (m_use_events)
+ connection->Notify(true);
return connection;
}
+void GSocket::Notify(bool flag)
+{
+ if (flag == m_use_events)
+ return;
+ m_use_events = flag;
+ DoEnableEvents(flag);
+}
+
+void GSocket::DoEnableEvents(bool flag)
+{
+ 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()
{
/* socket must not be null, and must not be in use/already bound */
assert(this);
/* Enable CONNECTION events (needed for nonblocking connections) */
- Enable(GSOCK_CONNECTION);
+ EnableEvent(GSOCK_CONNECTION);
if (m_fd != INVALID_SOCKET)
{
/* 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_non_blocking || ret == 0)
- gs_gui_functions->Enable_Events(this);
+ if ( m_non_blocking || (ret == 0) )
+ EnableEvents();
if (ret == -1)
{
SOCKOPTLEN_T len = sizeof(error);
getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*) &error, &len);
-
- gs_gui_functions->Enable_Events(this);
+ EnableEvents();
if (!error)
return GSOCK_NOERROR;
#else
ioctl(m_fd, FIONBIO, &arg);
#endif
- gs_gui_functions->Enable_Events(this);
+ EnableEvents();
if (m_reusable)
{
}
/* 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) {
else
ret = Recv_Dgram(buffer, size);
- /* If recv returned zero, then the connection has been gracefully closed.
- * Otherwise, recv has returned an error (-1), in which case we have lost the
- * socket only if errno does _not_ indicate that there may be more data to read.
+ /*
+ * If recv returned zero for a TCP socket (if m_stream == NULL, it's an UDP
+ * socket and empty datagrams are possible), then the connection has been
+ * gracefully closed.
+ *
+ * Otherwise, recv has returned an error (-1), in which case we have lost
+ * the socket only if errno does _not_ indicate that there may be more data
+ * to read.
*/
- if (ret == 0)
+ if ((ret == 0) && m_stream)
{
/* Make sure wxSOCKET_LOST event gets sent and shut down the socket */
- m_detected = GSOCK_LOST_FLAG;
- Detected_Read();
- return 0;
+ if (m_use_events)
+ {
+ m_detected = GSOCK_LOST_FLAG;
+ Detected_Read();
+ return 0;
+ }
}
else if (ret == -1)
{
}
/* Enable events again now that we are done processing */
- Enable(GSOCK_INPUT);
+ EnableEvent(GSOCK_INPUT);
return ret;
}
* 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;
}
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)
-{
- if (!gs_gui_functions->CanUseEventLoop())
- {
-
- GSocketEventFlags result = 0;
- fd_set readfds;
- fd_set writefds;
- fd_set exceptfds;
- struct timeval tv;
-
- assert(this);
-
- if (m_fd == -1)
- return (GSOCK_LOST_FLAG & flags);
-
- /* Do not use a static struct, Linux can garble it */
- tv.tv_sec = m_timeout / 1000;
- tv.tv_usec = (m_timeout % 1000) * 1000;
-
- 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. */
- result |= GSOCK_CONNECTION_FLAG;
- 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
- {
- result |= GSOCK_CONNECTION_FLAG;
- m_detected |= GSOCK_CONNECTION_FLAG;
- }
- }
- else
- {
- result |= GSOCK_OUTPUT_FLAG;
- }
- }
-
- return (result & flags);
-
- }
- else
- {
- assert(this);
- return flags & m_detected;
- }
-}
-
/* Flags */
/* GSocket_SetNonBlocking:
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
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)
{
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)
{
- m_detected &= ~(1 << event);
- gs_gui_functions->Install_Callback(this, event);
+ if (m_use_events)
+ {
+ m_detected &= ~(1 << event);
+ GSocketManager::Get()->Install_Callback(this, event);
+ }
}
-void GSocket::Disable(GSocketEvent event)
+void GSocket::DisableEvent(GSocketEvent event)
{
- m_detected |= (1 << event);
- gs_gui_functions->Uninstall_Callback(this, event);
+ if (m_use_events)
+ {
+ m_detected |= (1 << event);
+ GSocketManager::Get()->Uninstall_Callback(this, event);
+ }
}
/* _GSocket_Input_Timeout:
*/
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)
{
*/
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) );
int GSocket::Recv_Dgram(char *buffer, int size)
{
- struct sockaddr from;
+ wxSockAddr from;
WX_SOCKLEN_T fromlen = sizeof(from);
int ret;
GSocketError err;
do
{
- ret = recvfrom(m_fd, buffer, size, 0, &from, (WX_SOCKLEN_T *) &fromlen);
+ ret = recvfrom(m_fd, buffer, size, 0, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen);
}
while (ret == -1 && errno == EINTR); /* Loop until not interrupted */
}
}
- err = _GAddress_translate_from(m_peer, &from, fromlen);
+ err = _GAddress_translate_from(m_peer, (sockaddr*)&from, fromlen);
if (err != GSOCK_NOERROR)
{
GAddress_destroy(m_peer);
return ret;
}
+void GSocket::OnStateChange(GSocketEvent event)
+{
+ DisableEvent(event);
+ NotifyOnStateChange(event);
+
+ if ( event == GSOCK_LOST )
+ Shutdown();
+}
+
void GSocket::Detected_Read()
{
char c;
{
m_establishing = false;
- CALL_CALLBACK(this, GSOCK_LOST);
- Shutdown();
+ OnStateChange(GSOCK_LOST);
return;
}
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)
{
- /* graceful shutdown */
- CALL_CALLBACK(this, GSOCK_LOST);
- Shutdown();
+ if (m_stream)
+ {
+ /* graceful shutdown */
+ OnStateChange(GSOCK_LOST);
+ }
+ else
+ {
+ /* Empty datagram received */
+ OnStateChange(GSOCK_INPUT);
+ }
}
else
{
/* 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);
}
}
}
{
m_establishing = false;
- CALL_CALLBACK(this, GSOCK_LOST);
- Shutdown();
+ OnStateChange(GSOCK_LOST);
return;
}
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
case AF_UNIX:
address->m_family = GSOCK_UNIX;
break;
-#ifdef AF_INET6
+#if wxUSE_IPV6
case AF_INET6:
address->m_family = GSOCK_INET6;
break;
-#endif
+#endif // wxUSE_IPV6
default:
{
address->m_error = GSOCK_INVOP;
return ntohs(addr->sin_port);
}
+#if wxUSE_IPV6
+/*
+ * -------------------------------------------------------------------------
+ * Internet IPv6 address family
+ * -------------------------------------------------------------------------
+ */
+
+GSocketError _GAddress_Init_INET6(GAddress *address)
+{
+ struct in6_addr any_address = IN6ADDR_ANY_INIT;
+ address->m_len = sizeof(struct sockaddr_in6);
+ address->m_addr = (struct sockaddr *) malloc(address->m_len);
+ if (address->m_addr == NULL)
+ {
+ address->m_error = GSOCK_MEMERR;
+ return GSOCK_MEMERR;
+ }
+ memset(address->m_addr,0,address->m_len);
+
+ address->m_family = GSOCK_INET6;
+ address->m_realfamily = AF_INET6;
+ ((struct sockaddr_in6 *)address->m_addr)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *)address->m_addr)->sin6_addr = any_address;
+
+ return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET6_SetHostName(GAddress *address, const char *hostname)
+{
+ assert(address != NULL);
+ CHECK_ADDRESS(address, INET6);
+
+ addrinfo hints;
+ memset( & hints, 0, sizeof( hints ) );
+ hints.ai_family = AF_INET6;
+ addrinfo * info = 0;
+ if ( getaddrinfo( hostname, "0", & hints, & info ) || ! info )
+ {
+ address->m_error = GSOCK_NOHOST;
+ return GSOCK_NOHOST;
+ }
+
+ memcpy( address->m_addr, info->ai_addr, info->ai_addrlen );
+ freeaddrinfo( info );
+ return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET6_SetAnyAddress(GAddress *address)
+{
+ assert(address != NULL);
+
+ CHECK_ADDRESS(address, INET6);
+
+ struct in6_addr addr;
+ memset( & addr, 0, sizeof( addr ) );
+ return GAddress_INET6_SetHostAddress(address, addr);
+}
+GSocketError GAddress_INET6_SetHostAddress(GAddress *address,
+ struct in6_addr hostaddr)
+{
+ assert(address != NULL);
+
+ CHECK_ADDRESS(address, INET6);
+
+ ((struct sockaddr_in6 *)address->m_addr)->sin6_addr = hostaddr;
+
+ return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET6_SetPortName(GAddress *address, const char *port,
+ const char *protocol)
+{
+ struct servent *se;
+ struct sockaddr_in6 *addr;
+
+ assert(address != NULL);
+ CHECK_ADDRESS(address, INET6);
+
+ if (!port)
+ {
+ address->m_error = GSOCK_INVPORT;
+ return GSOCK_INVPORT;
+ }
+
+ se = getservbyname(port, protocol);
+ if (!se)
+ {
+ if (isdigit(port[0]))
+ {
+ int port_int;
+
+ port_int = atoi(port);
+ addr = (struct sockaddr_in6 *)address->m_addr;
+ addr->sin6_port = htons((u_short) port_int);
+ return GSOCK_NOERROR;
+ }
+
+ address->m_error = GSOCK_INVPORT;
+ return GSOCK_INVPORT;
+ }
+
+ addr = (struct sockaddr_in6 *)address->m_addr;
+ addr->sin6_port = se->s_port;
+
+ return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET6_SetPort(GAddress *address, unsigned short port)
+{
+ struct sockaddr_in6 *addr;
+
+ assert(address != NULL);
+ CHECK_ADDRESS(address, INET6);
+
+ addr = (struct sockaddr_in6 *)address->m_addr;
+ addr->sin6_port = htons(port);
+
+ return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET6_GetHostName(GAddress *address, char *hostname, size_t sbuf)
+{
+ struct hostent *he;
+ char *addr_buf;
+ struct sockaddr_in6 *addr;
+
+ assert(address != NULL);
+ CHECK_ADDRESS(address, INET6);
+
+ addr = (struct sockaddr_in6 *)address->m_addr;
+ addr_buf = (char *)&(addr->sin6_addr);
+
+ he = gethostbyaddr(addr_buf, sizeof(addr->sin6_addr), AF_INET6);
+ if (he == NULL)
+ {
+ address->m_error = GSOCK_NOHOST;
+ return GSOCK_NOHOST;
+ }
+
+ strncpy(hostname, he->h_name, sbuf);
+
+ return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET6_GetHostAddress(GAddress *address,struct in6_addr *hostaddr)
+{
+ assert(address != NULL);
+ assert(hostaddr != NULL);
+ CHECK_ADDRESS_RETVAL(address, INET6, GSOCK_INVADDR);
+ *hostaddr = ( (struct sockaddr_in6 *)address->m_addr )->sin6_addr;
+ return GSOCK_NOERROR;
+}
+
+unsigned short GAddress_INET6_GetPort(GAddress *address)
+{
+ assert(address != NULL);
+ CHECK_ADDRESS_RETVAL(address, INET6, 0);
+
+ return ntohs( ((struct sockaddr_in6 *)address->m_addr)->sin6_port );
+}
+
+#endif // wxUSE_IPV6
+
/*
* -------------------------------------------------------------------------
* Unix address family
return GSOCK_NOERROR;
}
#endif /* !defined(__VISAGECPP__) */
-#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */
+#endif /* wxUSE_SOCKETS */