]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/gsocket.c
Ops. wxUSE_XXX and wxUSE_STREAMS are separated again :-)
[wxWidgets.git] / src / unix / gsocket.c
index c4b51b9aa5904fef76833abf25126a1c8fdbd883..3174b57a7a0746c51217ba18dfa0ac82b6a02cfc 100644 (file)
@@ -6,6 +6,10 @@
  * -------------------------------------------------------------------------
  */
 
  * -------------------------------------------------------------------------
  */
 
+#include "wx/setup.h"
+
+#if wxUSE_SOCKETS
+
 #include <assert.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <assert.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <errno.h>
 
 #include <string.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <string.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
 
 #ifdef sun
 
 #ifdef sun
-  #include <sys/filio.h>
+#    include <sys/filio.h>
 #endif
 
 #ifdef sgi
 #endif
 
 #ifdef sgi
-  #include <bstring.h>
+#    include <bstring.h>
 #endif
 
 #include <signal.h>
 #endif
 
 #include <signal.h>
-/* #include <features.h> */
 
 
-#include "wx/setup.h"
 #include "wx/gsocket.h"
 #include "wx/gsocket.h"
-#include "gsockunx.h"
+#include "wx/unix/gsockunx.h"
 
 #ifndef SOCKLEN_T
 
 
 #ifndef SOCKLEN_T
 
 
 #endif
 
 
 #endif
 
+#define MASK_SIGNAL() \
+{ \
+  void (*old_handler)(int); \
+\
+  old_handler = signal(SIGPIPE, SIG_IGN);
+
+#define UNMASK_SIGNAL() \
+  signal(SIGPIPE, old_handler); \
+}
+
+#define ENABLE_TIMEOUT(socket) \
+{ \
+  struct itimerval old_ival, new_ival; \
+  void (*old_timer_sig)(int); \
+\
+  old_timer_sig = signal(SIGALRM, SIG_DFL); \
+  siginterrupt(SIGALRM, 1); \
+  new_ival.it_value.tv_sec = socket->m_timeout / 1000; \
+  new_ival.it_value.tv_usec = (socket->m_timeout % 1000) * 1000; \
+  new_ival.it_interval.tv_sec = 0; \
+  new_ival.it_interval.tv_usec = 0; \
+  setitimer(ITIMER_REAL, &new_ival, &old_ival);
+
+#define DISABLE_TIMEOUT(socket) \
+  signal(SIGALRM, old_timer_sig); \
+  siginterrupt(SIGALRM, 0); \
+  setitimer(ITIMER_REAL, &old_ival, NULL); \
+}
+
 /* Global initialisers */
 
 /* Global initialisers */
 
-void GSocket_Init()
+bool GSocket_Init()
 {
 {
+  return TRUE;
 }
 
 void GSocket_Cleanup()
 }
 
 void GSocket_Cleanup()
@@ -71,9 +106,12 @@ GSocket *GSocket_new()
 
   socket = (GSocket *)malloc(sizeof(GSocket));
 
 
   socket = (GSocket *)malloc(sizeof(GSocket));
 
+  if (socket == NULL)
+    return NULL;
+
   socket->m_fd                  = -1;
   for (i=0;i<GSOCK_MAX_EVENT;i++) {
   socket->m_fd                  = -1;
   for (i=0;i<GSOCK_MAX_EVENT;i++) {
-    socket->m_fbacks[i]         = NULL;
+    socket->m_cbacks[i]         = NULL;
     socket->m_iocalls[i]        = FALSE;
   }
   socket->m_local               = NULL;
     socket->m_iocalls[i]        = FALSE;
   }
   socket->m_local               = NULL;
@@ -82,8 +120,12 @@ GSocket *GSocket_new()
   socket->m_server             = FALSE;
   socket->m_stream             = TRUE;
   socket->m_gui_dependent      = NULL;
   socket->m_server             = FALSE;
   socket->m_stream             = TRUE;
   socket->m_gui_dependent      = NULL;
-  socket->m_blocking           = FALSE;
+  socket->m_non_blocking       = FALSE;
+  socket->m_timeout             = 10*60*1000;
+                                      /* 10 minutes * 60 sec * 1000 millisec */
+  socket->m_establishing        = FALSE;
 
 
+  /* We initialize the GUI specific entries here */
   _GSocket_GUI_Init(socket);
 
   return socket;
   _GSocket_GUI_Init(socket);
 
   return socket;
@@ -93,17 +135,21 @@ void GSocket_destroy(GSocket *socket)
 {
   assert(socket != NULL);
 
 {
   assert(socket != NULL);
 
+  /* First, we check that the socket is really shutdowned */
   if (socket->m_fd != -1)
     GSocket_Shutdown(socket);
 
   if (socket->m_fd != -1)
     GSocket_Shutdown(socket);
 
+  /* We destroy GUI specific variables */
   _GSocket_GUI_Destroy(socket);
 
   _GSocket_GUI_Destroy(socket);
 
+  /* We destroy private addresses */
   if (socket->m_local)
     GAddress_destroy(socket->m_local);
 
   if (socket->m_peer)
     GAddress_destroy(socket->m_peer);
 
   if (socket->m_local)
     GAddress_destroy(socket->m_local);
 
   if (socket->m_peer)
     GAddress_destroy(socket->m_peer);
 
+  /* We destroy socket itself */
   free(socket);
 }
 
   free(socket);
 }
 
@@ -113,14 +159,16 @@ void GSocket_Shutdown(GSocket *socket)
 
   assert(socket != NULL);
 
 
   assert(socket != NULL);
 
+  /* If socket has been created, we shutdown it */
   if (socket->m_fd != -1) {
     shutdown(socket->m_fd, 2);
     close(socket->m_fd);
     socket->m_fd = -1;
   }
 
   if (socket->m_fd != -1) {
     shutdown(socket->m_fd, 2);
     close(socket->m_fd);
     socket->m_fd = -1;
   }
 
+  /* We also disable GUI callbacks */
   for (evt=0;evt<GSOCK_MAX_EVENT;evt++)
   for (evt=0;evt<GSOCK_MAX_EVENT;evt++)
-    _GSocket_Uninstall_Fallback(socket, evt);
+    _GSocket_Uninstall_Callback(socket, evt);
 }
 
 /* Address handling */
 }
 
 /* Address handling */
@@ -129,11 +177,15 @@ GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address)
 {
   assert(socket != NULL);
 
 {
   assert(socket != NULL);
 
-  if ((socket->m_fd != -1 && !socket->m_server))
+  if ((socket->m_fd != -1 && !socket->m_server)) {
+    socket->m_error = GSOCK_INVSOCK;
     return GSOCK_INVSOCK;
     return GSOCK_INVSOCK;
+  }
 
 
-  if (address == NULL || address->m_family == GSOCK_NOFAMILY)
+  if (address == NULL || address->m_family == GSOCK_NOFAMILY) {
+    socket->m_error = GSOCK_INVADDR;
     return GSOCK_INVADDR;
     return GSOCK_INVADDR;
+  }
 
   if (socket->m_local)
     GAddress_destroy(socket->m_local);
 
   if (socket->m_local)
     GAddress_destroy(socket->m_local);
@@ -165,6 +217,7 @@ GAddress *GSocket_GetLocal(GSocket *socket)
   GAddress *address;
   struct sockaddr addr;
   SOCKLEN_T size;
   GAddress *address;
   struct sockaddr addr;
   SOCKLEN_T size;
+  GSocketError err;
 
   assert(socket != NULL);
 
 
   assert(socket != NULL);
 
@@ -184,7 +237,15 @@ GAddress *GSocket_GetLocal(GSocket *socket)
   }
 
   address = GAddress_new();
   }
 
   address = GAddress_new();
-  _GAddress_translate_from(address, &addr, size);
+  if (address == NULL) {
+    socket->m_error = GSOCK_MEMERR;
+    return NULL;
+  }
+  socket->m_error = _GAddress_translate_from(address, &addr, size);
+  if (socket->m_error != GSOCK_NOERROR) {
+    GAddress_destroy(address);
+    return NULL;
+  }
 
   return address;
 }
 
   return address;
 }
@@ -224,18 +285,19 @@ GSocketError GSocket_SetServer(GSocket *sck)
     return GSOCK_INVADDR;
   }
 
     return GSOCK_INVADDR;
   }
 
-  if (sck->m_stream)
-    type = SOCK_STREAM;
-  else
-    type = SOCK_DGRAM;
+  /* We always have a stream here  */
+  sck->m_stream = TRUE;
+  sck->m_server = TRUE;
 
 
-  sck->m_fd = socket(sck->m_local->m_realfamily, type, 0);
+  /* Create the socket */
+  sck->m_fd = socket(sck->m_local->m_realfamily, SOCK_STREAM, 0);
 
   if (sck->m_fd == -1) {
     sck->m_error = GSOCK_IOERR;
     return GSOCK_IOERR;
   }
 
 
   if (sck->m_fd == -1) {
     sck->m_error = GSOCK_IOERR;
     return GSOCK_IOERR;
   }
 
+  /* Bind the socket to the LOCAL address */
   if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) < 0) {
     close(sck->m_fd);
     sck->m_fd = -1;
   if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) < 0) {
     close(sck->m_fd);
     sck->m_fd = -1;
@@ -243,6 +305,7 @@ GSocketError GSocket_SetServer(GSocket *sck)
     return GSOCK_IOERR;
   }
 
     return GSOCK_IOERR;
   }
 
+  /* Enable listening up to 5 connections */
   if (listen(sck->m_fd, 5) < 0) {
     close(sck->m_fd);
     sck->m_fd = -1;
   if (listen(sck->m_fd, 5) < 0) {
     close(sck->m_fd);
     sck->m_fd = -1;
@@ -250,10 +313,10 @@ GSocketError GSocket_SetServer(GSocket *sck)
     return GSOCK_IOERR;
   }
 
     return GSOCK_IOERR;
   }
 
-  sck->m_server = TRUE;
+  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
+  GSocket_SetTimeout(sck, sck->m_timeout);
 
   return GSOCK_NOERROR;
 
   return GSOCK_NOERROR;
-     
 }
 
 /*
 }
 
 /*
@@ -265,22 +328,44 @@ GSocket *GSocket_WaitConnection(GSocket *socket)
 
   assert(socket != NULL);
 
 
   assert(socket != NULL);
 
+  /* If the socket has already been created, we exit immediately */
   if (socket->m_fd == -1 || !socket->m_server) {
     socket->m_error = GSOCK_INVSOCK;
     return NULL;
   }
 
   if (socket->m_fd == -1 || !socket->m_server) {
     socket->m_error = GSOCK_INVSOCK;
     return NULL;
   }
 
+  /* Reenable GSOCK_CONNECTION event */
   _GSocket_Enable(socket, GSOCK_CONNECTION);
 
   _GSocket_Enable(socket, GSOCK_CONNECTION);
 
+  /* Create a GSocket object for the new connection */
   connection = GSocket_new();
   connection = GSocket_new();
+  if (!connection) {
+    connection->m_error = GSOCK_MEMERR;
+    return NULL;
+  }
 
 
+  /* Accept the incoming connection */
+  ENABLE_TIMEOUT(connection);
   connection->m_fd = accept(socket->m_fd, NULL, NULL);
   connection->m_fd = accept(socket->m_fd, NULL, NULL);
+  DISABLE_TIMEOUT(connection);
   if (connection->m_fd == -1) {
     GSocket_destroy(connection);
   if (connection->m_fd == -1) {
     GSocket_destroy(connection);
-    socket->m_error = GSOCK_IOERR;
+    switch(errno) {
+    case EINTR:
+    case ETIMEDOUT:
+      connection->m_error = GSOCK_TIMEDOUT;
+      break;
+    case EWOULDBLOCK:
+      connection->m_error = GSOCK_WOULDBLOCK;
+      break;
+    default:
+      connection->m_error = GSOCK_IOERR;
+      break;
+    }
     return NULL;
   }
 
     return NULL;
   }
 
+  /* Initialize all fields */
   connection->m_stream   = TRUE;
   connection->m_server   = FALSE;
   connection->m_oriented = TRUE;
   connection->m_stream   = TRUE;
   connection->m_server   = FALSE;
   connection->m_oriented = TRUE;
@@ -308,8 +393,15 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
   sck->m_server   = FALSE;
   sck->m_oriented = FALSE;
 
   sck->m_server   = FALSE;
   sck->m_oriented = FALSE;
 
+  /* Create the socket */
   sck->m_fd = socket(sck->m_local->m_realfamily, SOCK_DGRAM, 0);
 
   sck->m_fd = socket(sck->m_local->m_realfamily, SOCK_DGRAM, 0);
 
+  if (sck->m_fd < 0) {
+    sck->m_error = GSOCK_IOERR;
+    return GSOCK_IOERR;
+  }
+
+  /* Bind it to the LOCAL address */
   if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) < 0) {
     close(sck->m_fd);
     sck->m_fd    = -1;
   if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) < 0) {
     close(sck->m_fd);
     sck->m_fd    = -1;
@@ -317,6 +409,9 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
     return GSOCK_IOERR;
   }
 
     return GSOCK_IOERR;
   }
 
+  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
+  GSocket_SetTimeout(sck, sck->m_timeout);
+
   return GSOCK_NOERROR;
 }
 
   return GSOCK_NOERROR;
 }
 
@@ -329,7 +424,7 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
 */
 GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
 {
 */
 GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
 {
-  int type;
+  int type, err;
 
   assert(sck != NULL);
 
 
   assert(sck != NULL);
 
@@ -343,6 +438,7 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
     return GSOCK_INVADDR;
   }
 
     return GSOCK_INVADDR;
   }
 
+  /* Test whether we want the socket to be a stream (e.g. TCP) */
   sck->m_stream = (stream == GSOCK_STREAMED);
   sck->m_oriented = TRUE;
 
   sck->m_stream = (stream == GSOCK_STREAMED);
   sck->m_oriented = TRUE;
 
@@ -351,6 +447,7 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
   else
     type = SOCK_DGRAM;
 
   else
     type = SOCK_DGRAM;
 
+  /* Create the socket */
   sck->m_fd = socket(sck->m_peer->m_realfamily, type, 0);
 
   if (sck->m_fd == -1) {
   sck->m_fd = socket(sck->m_peer->m_realfamily, type, 0);
 
   if (sck->m_fd == -1) {
@@ -358,17 +455,34 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
     return GSOCK_IOERR;
   }
 
     return GSOCK_IOERR;
   }
 
-  if (connect(sck->m_fd, sck->m_peer->m_addr,
-              sck->m_peer->m_len) != 0) {
+  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
+  GSocket_SetTimeout(sck, sck->m_timeout);
+
+  /* Connect it to the PEER address */
+  ENABLE_TIMEOUT(sck);
+  err = connect(sck->m_fd, sck->m_peer->m_addr, sck->m_peer->m_len);
+  DISABLE_TIMEOUT(sck);
+
+  if (err != 0 && errno != EINPROGRESS) {
     close(sck->m_fd);
     sck->m_fd = -1;
     close(sck->m_fd);
     sck->m_fd = -1;
-    sck->m_error = GSOCK_IOERR;
+    switch (errno) {
+    case EINTR:
+    case ETIMEDOUT:
+      sck->m_error = GSOCK_TIMEDOUT;
+      break;
+    default:
+      sck->m_error = GSOCK_IOERR;
+      break;
+    }
     return GSOCK_IOERR;
   }
   
     return GSOCK_IOERR;
   }
   
-  sck->m_server = FALSE;
+  /* It is not a server */
+  sck->m_server       = FALSE;
+  sck->m_establishing = (errno == EINPROGRESS);
 
 
-  return GSOCK_NOERROR;
+  return (sck->m_establishing) ? GSOCK_WOULDBLOCK : GSOCK_NOERROR;
 }
 
 /* Generic IO */
 }
 
 /* Generic IO */
@@ -383,9 +497,10 @@ int GSocket_Read(GSocket *socket, char *buffer, int size)
     return -1;
   }
 
     return -1;
   }
 
+  /* Reenable GSOCK_INPUT event */
   _GSocket_Enable(socket, GSOCK_INPUT);
 
   _GSocket_Enable(socket, GSOCK_INPUT);
 
-  if (socket->m_oriented)
+  if (socket->m_stream)
     return _GSocket_Recv_Stream(socket, buffer, size);
   else
     return _GSocket_Recv_Dgram(socket, buffer, size);
     return _GSocket_Recv_Stream(socket, buffer, size);
   else
     return _GSocket_Recv_Dgram(socket, buffer, size);
@@ -403,7 +518,7 @@ int GSocket_Write(GSocket *socket, const char *buffer,
 
   _GSocket_Enable(socket, GSOCK_OUTPUT);
 
 
   _GSocket_Enable(socket, GSOCK_OUTPUT);
 
-  if (socket->m_oriented)
+  if (socket->m_stream)
     return _GSocket_Send_Stream(socket, buffer, size);
   else
     return _GSocket_Send_Dgram(socket, buffer, size);
     return _GSocket_Send_Stream(socket, buffer, size);
   else
     return _GSocket_Send_Dgram(socket, buffer, size);
@@ -435,17 +550,28 @@ bool GSocket_DataAvailable(GSocket *socket)
 /* Flags */
 
 /*
 /* Flags */
 
 /*
-  GSocket_SetBlocking() puts the socket in non-blocking mode. This is useful
+  GSocket_SetNonBlocking() puts the socket in non-blocking mode. This is useful
   if we don't want to wait.
 */
   if we don't want to wait.
 */
-void GSocket_SetBlocking(GSocket *socket, bool block)
+void GSocket_SetNonBlocking(GSocket *socket, bool non_block)
 {
   assert(socket != NULL);
 
 {
   assert(socket != NULL);
 
-  socket->m_blocking = block;
+  socket->m_non_blocking = non_block;
 
   if (socket->m_fd != -1)
 
   if (socket->m_fd != -1)
-    ioctl(socket->m_fd, FIONBIO, &block);
+    ioctl(socket->m_fd, FIONBIO, &non_block);
+}
+
+/*
+ * GSocket_SetTimeout()
+ */
+
+void GSocket_SetTimeout(GSocket *socket, unsigned long millisec)
+{
+  assert(socket != NULL);
+
+  socket->m_timeout = millisec;
 }
 
 /*
 }
 
 /*
@@ -462,7 +588,7 @@ GSocketError GSocket_GetError(GSocket *socket)
 /* Callbacks */
 
 /* 
 /* Callbacks */
 
 /* 
-   Only one fallback is possible for each event (INPUT, OUTPUT, CONNECTION)
+   Only one callback is possible for each event (INPUT, OUTPUT, CONNECTION)
    INPUT: The function is called when there is at least a byte in the 
           input buffer
    OUTPUT: The function is called when the system is sure the next write call
    INPUT: The function is called when there is at least a byte in the 
           input buffer
    OUTPUT: The function is called when the system is sure the next write call
@@ -472,7 +598,7 @@ GSocketError GSocket_GetError(GSocket *socket)
             Server socket -> a client request a connection
    LOST: the connection is lost
 
             Server socket -> a client request a connection
    LOST: the connection is lost
 
-   SetFallback accepts a combination of these flags so a same callback can
+   SetCallback accepts a combination of these flags so a same callback can
    receive different events.
 
    An event is generated only once and its state is reseted when the relative
    receive different events.
 
    An event is generated only once and its state is reseted when the relative
@@ -480,29 +606,29 @@ GSocketError GSocket_GetError(GSocket *socket)
    For example: INPUT -> GSocket_Read()
                 CONNECTION -> GSocket_Accept()
 */
    For example: INPUT -> GSocket_Read()
                 CONNECTION -> GSocket_Accept()
 */
-void GSocket_SetFallback(GSocket *socket, GSocketEventFlags event,
-                        GSocketFallback fallback, char *cdata)
+void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event,
+                        GSocketCallback callback, char *cdata)
 {
   int count;
 
   assert (socket != NULL);
 
   for (count=0;count<GSOCK_MAX_EVENT;count++) {
 {
   int count;
 
   assert (socket != NULL);
 
   for (count=0;count<GSOCK_MAX_EVENT;count++) {
+    /* We test each flag and, if it is enabled, we enable the corresponding
+       event */
     if ((event & (1 << count)) != 0) {
     if ((event & (1 << count)) != 0) {
-      socket->m_fbacks[count] = fallback;
+      socket->m_cbacks[count] = callback;
       socket->m_data[count] = cdata;
       socket->m_data[count] = cdata;
-
-      _GSocket_Install_Fallback(socket, count);
       _GSocket_Enable(socket, count);
     }
   }
 }
 
 /*
       _GSocket_Enable(socket, count);
     }
   }
 }
 
 /*
-  UnsetFallback will disables all fallbacks specified by "event".
+  UnsetCallback will disables all callbacks specified by "event".
   NOTE: event may be a combination of flags
 */
   NOTE: event may be a combination of flags
 */
-void GSocket_UnsetFallback(GSocket *socket, GSocketEventFlags event)
+void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags event)
 {
   int count = 0;
 
 {
   int count = 0;
 
@@ -511,42 +637,31 @@ void GSocket_UnsetFallback(GSocket *socket, GSocketEventFlags event)
   for (count=0;count<GSOCK_MAX_EVENT;count++) {
     if ((event & (1 << count)) != 0) {
       _GSocket_Disable(socket, count);
   for (count=0;count<GSOCK_MAX_EVENT;count++) {
     if ((event & (1 << count)) != 0) {
       _GSocket_Disable(socket, count);
-      socket->m_fbacks[count] = NULL;
-      _GSocket_Uninstall_Fallback(socket, count);
+      socket->m_cbacks[count] = NULL;
     }
   }
 }
 
     }
   }
 }
 
-#define CALL_FALLBACK(socket, event) \
+#define CALL_CALLBACK(socket, event) \
 if (socket->m_iocalls[event] && \
 if (socket->m_iocalls[event] && \
-    socket->m_fbacks[event]) {\
+    socket->m_cbacks[event]) {\
   _GSocket_Disable(socket, event); \
   _GSocket_Disable(socket, event); \
-  socket->m_fbacks[event](socket, event, \
+  socket->m_cbacks[event](socket, event, \
                    socket->m_data[event]); \
 }
 
                    socket->m_data[event]); \
 }
 
-#define MASK_SIGNAL() \
-{ \
-  void (*old_handler)(int); \
-\
-  old_handler = signal(SIGPIPE, SIG_IGN);
-
-#define UNMASK_SIGNAL() \
-  signal(SIGPIPE, old_handler); \
-}
-
 void _GSocket_Enable(GSocket *socket, GSocketEvent event)
 {
   socket->m_iocalls[event] = TRUE;
 void _GSocket_Enable(GSocket *socket, GSocketEvent event)
 {
   socket->m_iocalls[event] = TRUE;
-  if (socket->m_fbacks[event])
-    _GSocket_Install_Fallback(socket, event);
+  if (socket->m_cbacks[event])
+    _GSocket_Install_Callback(socket, event);
 }
 
 void _GSocket_Disable(GSocket *socket, GSocketEvent event)
 {
   socket->m_iocalls[event] = FALSE;
 }
 
 void _GSocket_Disable(GSocket *socket, GSocketEvent event)
 {
   socket->m_iocalls[event] = FALSE;
-  if (socket->m_fbacks[event])
-    _GSocket_Uninstall_Fallback(socket, event);
+  if (socket->m_cbacks[event])
+    _GSocket_Uninstall_Callback(socket, event);
 }
 
 int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
 }
 
 int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
@@ -554,10 +669,22 @@ int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
   int ret;
 
   MASK_SIGNAL();
   int ret;
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = recv(socket->m_fd, buffer, size, 0);
   ret = recv(socket->m_fd, buffer, size, 0);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
   UNMASK_SIGNAL();
-  if (ret == -1) {
-    socket->m_error = GSOCK_IOERR;
+
+  if (ret == -1 &&
+      errno != ETIMEDOUT && errno != EWOULDBLOCK && errno != EINTR) {
+      socket->m_error = GSOCK_IOERR;
+      return -1;
+  }
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
+    return -1;
+  }
+  if (errno == ETIMEDOUT || errno == EINTR) {
+    socket->m_error = GSOCK_TIMEDOUT;
     return -1;
   }
   return ret;
     return -1;
   }
   return ret;
@@ -566,23 +693,45 @@ int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
 int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
 {
   struct sockaddr from;
 int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
 {
   struct sockaddr from;
-  
   SOCKLEN_T fromlen;
   int ret;
   SOCKLEN_T fromlen;
   int ret;
+  GSocketError err;
 
   fromlen = sizeof(from);
 
   MASK_SIGNAL();
 
   fromlen = sizeof(from);
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = recvfrom(socket->m_fd, buffer, size, 0, &from, &fromlen);
   ret = recvfrom(socket->m_fd, buffer, size, 0, &from, &fromlen);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
   UNMASK_SIGNAL();
-  if (ret == -1) {
+  if (ret == -1 && errno != EWOULDBLOCK && errno != EINTR && errno != ETIMEDOUT) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
+    return -1;
+  }
+  if (errno == ETIMEDOUT || errno == EINTR) {
+    socket->m_error = GSOCK_TIMEDOUT;
+    return -1;
+  }
 
 
-  if (!socket->m_peer)
+  /* Translate a system address into a GSocket address */
+  if (!socket->m_peer) {
     socket->m_peer = GAddress_new();
     socket->m_peer = GAddress_new();
-  _GAddress_translate_from(socket->m_peer, &from, fromlen);
+    if (!socket->m_peer) {
+      socket->m_error = GSOCK_MEMERR;
+      return -1;
+    }
+  }
+  err = _GAddress_translate_from(socket->m_peer, &from, fromlen);
+  if (err != GSOCK_NOERROR) {
+    GAddress_destroy(socket->m_peer);
+    socket->m_peer  = NULL;
+    socket->m_error = err;
+    return -1;
+  }
 
   return ret;
 }
 
   return ret;
 }
@@ -590,14 +739,25 @@ int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
 int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size)
 {
   int ret;
 int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size)
 {
   int ret;
+  GSocketError err;
 
   MASK_SIGNAL();
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = send(socket->m_fd, buffer, size, 0);
   ret = send(socket->m_fd, buffer, size, 0);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
   UNMASK_SIGNAL();
-  if (ret == -1) {
+  if (ret == -1 && errno != EWOULDBLOCK && errno != ETIMEDOUT && errno != EINTR) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
+    return -1;
+  }
+  if (errno == ETIMEDOUT || errno == EINTR) {
+    socket->m_error = GSOCK_TIMEDOUT;
+    return -1;
+  }
   return ret;
 }
 
   return ret;
 }
 
@@ -605,23 +765,36 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size)
 {
   struct sockaddr *addr;
   int len, ret;
 {
   struct sockaddr *addr;
   int len, ret;
+  GSocketError err;
 
   if (!socket->m_peer) {
     socket->m_error = GSOCK_INVADDR;
     return -1;
   }
 
 
   if (!socket->m_peer) {
     socket->m_error = GSOCK_INVADDR;
     return -1;
   }
 
-  _GAddress_translate_to(socket->m_peer, &addr, &len);
+  err = _GAddress_translate_to(socket->m_peer, &addr, &len);
+  if (err != GSOCK_NOERROR) {
+    socket->m_error = err;
+    return -1;
+  }
 
   MASK_SIGNAL();
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = sendto(socket->m_fd, buffer, size, 0, addr, len);
   ret = sendto(socket->m_fd, buffer, size, 0, addr, len);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
   UNMASK_SIGNAL();
-  if (ret == -1) {
+
+  /* Frees memory allocated from _GAddress_translate_to */
+  free(addr);
+
+  if (ret == -1 && errno != EWOULDBLOCK) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
-
-  free(addr);
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
+    return -1;
+  }
 
   return ret;
 }
 
   return ret;
 }
@@ -635,26 +808,38 @@ void _GSocket_Detected_Read(GSocket *socket)
     ret = recv(socket->m_fd, &c, 1, MSG_PEEK);
 
     if (ret < 0 && socket->m_server) {
     ret = recv(socket->m_fd, &c, 1, MSG_PEEK);
 
     if (ret < 0 && socket->m_server) {
-      CALL_FALLBACK(socket, GSOCK_CONNECTION);
+      CALL_CALLBACK(socket, GSOCK_CONNECTION);
       return;
     }
 
     if (ret > 0) {
       return;
     }
 
     if (ret > 0) {
-      CALL_FALLBACK(socket, GSOCK_INPUT);
+      CALL_CALLBACK(socket, GSOCK_INPUT);
     } else {
     } else {
-      CALL_FALLBACK(socket, GSOCK_LOST);
+      CALL_CALLBACK(socket, GSOCK_LOST);
     }
   }
 }
 
 void _GSocket_Detected_Write(GSocket *socket)
 {
     }
   }
 }
 
 void _GSocket_Detected_Write(GSocket *socket)
 {
-  CALL_FALLBACK(socket, GSOCK_OUTPUT);
-}
+  if (socket->m_establishing) {
+    int error, len;
+
+    len = sizeof(error);
 
 
-#undef CALL_FALLBACK 
-#undef MASK_SIGNAL
-#undef UNMASK_SIGNAL
+    socket->m_establishing = FALSE;
+    getsockopt(socket->m_fd, SOL_SOCKET, SO_ERROR, &error, &len);
+
+    if (error) {
+      socket->m_error = GSOCK_IOERR;
+      GSocket_Shutdown(socket);
+    } else
+      socket->m_error = GSOCK_NOERROR;
+
+    CALL_CALLBACK(socket, GSOCK_CONNECTION);
+  } else
+    CALL_CALLBACK(socket, GSOCK_OUTPUT);
+}
 
 /*
  * -------------------------------------------------------------------------
 
 /*
  * -------------------------------------------------------------------------
@@ -662,10 +847,16 @@ void _GSocket_Detected_Write(GSocket *socket)
  * -------------------------------------------------------------------------
  */
 
  * -------------------------------------------------------------------------
  */
 
+/* CHECK_ADDRESS verifies that the current family is either GSOCK_NOFAMILY or
+ * GSOCK_*family*. In case it is GSOCK_NOFAMILY, it initializes address to be
+ * a GSOCK_*family*. In other cases, it returns GSOCK_INVADDR.
+ */
 #define CHECK_ADDRESS(address, family, retval) \
 { \
   if (address->m_family == GSOCK_NOFAMILY) \
 #define CHECK_ADDRESS(address, family, retval) \
 { \
   if (address->m_family == GSOCK_NOFAMILY) \
-    _GAddress_Init_##family(address); \
+    if (_GAddress_Init_##family(address) != GSOCK_NOERROR) {\
+      return address->m_error; \
+    }\
   if (address->m_family != GSOCK_##family) {\
     address->m_error = GSOCK_INVADDR; \
     return retval; \
   if (address->m_family != GSOCK_##family) {\
     address->m_error = GSOCK_INVADDR; \
     return retval; \
@@ -678,6 +869,9 @@ GAddress *GAddress_new()
 
   address = (GAddress *)malloc(sizeof(GAddress));
 
 
   address = (GAddress *)malloc(sizeof(GAddress));
 
+  if (address == NULL)
+    return NULL;
+
   address->m_family  = GSOCK_NOFAMILY;
   address->m_addr    = NULL;
   address->m_len     = 0;
   address->m_family  = GSOCK_NOFAMILY;
   address->m_addr    = NULL;
   address->m_len     = 0;
@@ -692,10 +886,18 @@ GAddress *GAddress_copy(GAddress *address)
   assert(address != NULL);
 
   addr2 = (GAddress *)malloc(sizeof(GAddress));
   assert(address != NULL);
 
   addr2 = (GAddress *)malloc(sizeof(GAddress));
+
+  if (addr2 == NULL)
+    return NULL;
+
   memcpy(addr2, address, sizeof(GAddress));
 
   if (address->m_addr) {
     addr2->m_addr = (struct sockaddr *)malloc(addr2->m_len);
   memcpy(addr2, address, sizeof(GAddress));
 
   if (address->m_addr) {
     addr2->m_addr = (struct sockaddr *)malloc(addr2->m_len);
+    if (addr2->m_addr == NULL) {
+      free(addr2);
+      return NULL;
+    }
     memcpy(addr2->m_addr, address->m_addr, addr2->m_len);
   }
 
     memcpy(addr2->m_addr, address->m_addr, addr2->m_len);
   }
 
@@ -723,7 +925,7 @@ GAddressType GAddress_GetFamily(GAddress *address)
   return address->m_family;
 }
 
   return address->m_family;
 }
 
-void _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len){
+GSocketError _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len){
   address->m_realfamily = addr->sa_family;
   switch (addr->sa_family) {
   case AF_INET:
   address->m_realfamily = addr->sa_family;
   switch (addr->sa_family) {
   case AF_INET:
@@ -739,7 +941,8 @@ void _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len)
 #endif
   default:
     {
 #endif
   default:
     {
-    /* TODO error */
+    address->m_error = GSOCK_INVOP;
+    return GSOCK_INVOP;
     }
   }
 
     }
   }
 
@@ -748,20 +951,32 @@ void _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len)
 
   address->m_len  = len;
   address->m_addr = (struct sockaddr *)malloc(len);
 
   address->m_len  = len;
   address->m_addr = (struct sockaddr *)malloc(len);
+  if (address->m_addr == NULL) {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
   memcpy(address->m_addr, addr, len);
   memcpy(address->m_addr, addr, len);
+
+  return GSOCK_NOERROR;
 }
 
 }
 
-void _GAddress_translate_to(GAddress *address,
-                            struct sockaddr **addr, int *len)
+GSocketError _GAddress_translate_to(GAddress *address,
+                                    struct sockaddr **addr, int *len)
 {
   if (!address->m_addr) {
 {
   if (!address->m_addr) {
-    /* TODO error */
-    return;
+    address->m_error = GSOCK_INVADDR;
+    return GSOCK_INVADDR;
   }
 
   *len = address->m_len;
   *addr = (struct sockaddr *)malloc(address->m_len);
   }
 
   *len = address->m_len;
   *addr = (struct sockaddr *)malloc(address->m_len);
+  if (*addr == NULL) {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
+
   memcpy(*addr, address->m_addr, address->m_len);
   memcpy(*addr, address->m_addr, address->m_len);
+  return GSOCK_NOERROR;
 }
 
 /*
 }
 
 /*
@@ -770,14 +985,22 @@ void _GAddress_translate_to(GAddress *address,
  * -------------------------------------------------------------------------
  */
 
  * -------------------------------------------------------------------------
  */
 
-void _GAddress_Init_INET(GAddress *address)
+GSocketError _GAddress_Init_INET(GAddress *address)
 {
 {
+  address->m_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in));
+  if (address->m_addr == NULL) {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
+
   address->m_len  = sizeof(struct sockaddr_in);
   address->m_len  = sizeof(struct sockaddr_in);
-  address->m_addr = (struct sockaddr *)malloc(address->m_len);
+
   address->m_family = GSOCK_INET;
   address->m_realfamily = PF_INET;
   ((struct sockaddr_in *)address->m_addr)->sin_family = AF_INET;
   ((struct sockaddr_in *)address->m_addr)->sin_addr.s_addr   = INADDR_ANY;
   address->m_family = GSOCK_INET;
   address->m_realfamily = PF_INET;
   ((struct sockaddr_in *)address->m_addr)->sin_family = AF_INET;
   ((struct sockaddr_in *)address->m_addr)->sin_addr.s_addr   = INADDR_ANY;
+
+  return GSOCK_NOERROR;
 }
 
 GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
 }
 
 GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
@@ -791,10 +1014,19 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
 
   addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr);
 
 
   addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr);
 
-  /* only name for the moment */
+  /* If it is a numeric host name, convert it now */
+#if defined(HAVE_INET_ATON)
   if (inet_aton(hostname, addr) == 0) {
   if (inet_aton(hostname, addr) == 0) {
+#elif defined(HAVE_INET_ADDR)
+  /* Fix from Guillermo Rodriguez Garcia <guille@iies.es> */
+  if ( (addr->s_addr = inet_addr(hostname)) == -1 ) {
+#else
+  /* Use gethostbyname by default */
+  if (1) {
+#endif
     struct in_addr *array_addr;
 
     struct in_addr *array_addr;
 
+    /* It is a real name, we solve it */
     if ((he = gethostbyname(hostname)) == NULL) {
       address->m_error = GSOCK_NOHOST;
       return GSOCK_NOHOST;
     if ((he = gethostbyname(hostname)) == NULL) {
       address->m_error = GSOCK_NOHOST;
       return GSOCK_NOHOST;
@@ -831,10 +1063,9 @@ GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port,
 
   if (!port) {
     address->m_error = GSOCK_INVPORT;
 
   if (!port) {
     address->m_error = GSOCK_INVPORT;
-    return GSOCK_INVOP;
+    return GSOCK_INVPORT;
   }
  
   }
  
-  /* TODO: TCP or UDP */
   se = getservbyname(port, protocol);
   if (!se) {
     if (isdigit(port[0])) {
   se = getservbyname(port, protocol);
   if (!se) {
     if (isdigit(port[0])) {
@@ -921,14 +1152,21 @@ unsigned short GAddress_INET_GetPort(GAddress *address)
  * -------------------------------------------------------------------------
  */
 
  * -------------------------------------------------------------------------
  */
 
-void _GAddress_Init_UNIX(GAddress *address)
+GSocketError _GAddress_Init_UNIX(GAddress *address)
 {
 {
-  address->m_len  = sizeof(struct sockaddr_un);
   address->m_addr = (struct sockaddr *)malloc(address->m_len);
   address->m_addr = (struct sockaddr *)malloc(address->m_len);
+  if (address->m_addr == NULL) {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
+
+  address->m_len  = sizeof(struct sockaddr_un);
   address->m_family = GSOCK_UNIX;
   address->m_realfamily = PF_UNIX;
   ((struct sockaddr_un *)address->m_addr)->sun_family = AF_UNIX;
   ((struct sockaddr_un *)address->m_addr)->sun_path[0] = 0;
   address->m_family = GSOCK_UNIX;
   address->m_realfamily = PF_UNIX;
   ((struct sockaddr_un *)address->m_addr)->sun_family = AF_UNIX;
   ((struct sockaddr_un *)address->m_addr)->sun_path[0] = 0;
+
+  return TRUE;
 }
 
 GSocketError GAddress_UNIX_SetPath(GAddress *address, const char *path)
 }
 
 GSocketError GAddress_UNIX_SetPath(GAddress *address, const char *path)
@@ -958,3 +1196,6 @@ GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf)
 
   return GSOCK_NOERROR;
 }
 
   return GSOCK_NOERROR;
 }
+
+#endif
+  /* wxUSE_SOCKETS */