]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/gsocket.c
Whole lot of stuff for new wxFileDialog
[wxWidgets.git] / src / unix / gsocket.c
index 7d489ecdd05767c8692d5683dd3d559fd42273b1..2ffafc86b6993ac60e806f8c349d0853966e723d 100644 (file)
@@ -3,25 +3,13 @@
  * Name:    gsocket.c
  * Purpose: GSocket main Unix file
  * CVSID:   $Id$
  * Name:    gsocket.c
  * Purpose: GSocket main Unix file
  * CVSID:   $Id$
- * Log:     $Log$
- * Log:     Revision 1.2  1999/07/23 09:48:31  KB
- * Log:     Fixed stupid new bugs :-(
- * Log:
- * Log:     Revision 1.1  1999/07/22 17:51:54  GL
- * Log:     Added GSocket for Unix (only GTK for the moment)
- * Log:     Updated wxSocket to use GSocket API
- * Log:     Added a progress bar to client.cpp
- * Log:     Added CopyTo to wxMemoryOutputStream to copy the internal buffer to a specified buffer.
- * Log:     Various changes/fixes to the high-level protocols FTP/HTTP
- * Log:     Various Unicode fixes
- * Log:     Removed sckint.*
- * Log:
- * Log:     Revision 1.2  1999/07/18 15:52:34  guilhem
- * Log:     * Copyright, etc.
- * Log:
  * -------------------------------------------------------------------------
  */
 
  * -------------------------------------------------------------------------
  */
 
+#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 <wx/setup.h>
-#include <wx/gsocket.h>
+
+#include "wx/gsocket.h"
 #include "gsockunx.h"
 
 #ifndef SOCKLEN_T
 #include "gsockunx.h"
 
 #ifndef SOCKLEN_T
-#      define SOCKLEN_T int
+
+#ifdef __GLIBC__
+#      if __GLIBC__ == 2
+#         define SOCKLEN_T socklen_t
+#      endif
+#else
+#      define SOCKLEN_T int
+#endif
+
 #endif
 
 #endif
 
+#if !defined(__LINUX__) && !defined(__FREEBSD__)
+#   define CAN_USE_TIMEOUT
+#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+#   if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 1)
+#      define CAN_USE_TIMEOUT
+#   endif
+#endif
+
+/* Global initialisers */
+
+bool GSocket_Init()
+{
+  return TRUE;
+}
+
+void GSocket_Cleanup()
+{
+}
+
 /* Constructors / Destructors */
 
 GSocket *GSocket_new()
 /* Constructors / Destructors */
 
 GSocket *GSocket_new()
@@ -67,9 +85,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;
@@ -78,8 +99,11 @@ 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 */
 
 
+  /* We initialize the GUI specific entries here */
   _GSocket_GUI_Init(socket);
 
   return socket;
   _GSocket_GUI_Init(socket);
 
   return socket;
@@ -89,17 +113,21 @@ void GSocket_destroy(GSocket *socket)
 {
   assert(socket != NULL);
 
 {
   assert(socket != NULL);
 
-  _GSocket_GUI_Destroy(socket);
-
+  /* 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);
+
+  /* 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);
 }
 
@@ -109,25 +137,35 @@ void GSocket_Shutdown(GSocket *socket)
 
   assert(socket != NULL);
 
 
   assert(socket != NULL);
 
+  /* If socket has been created, we shutdown it */
   if (socket->m_fd != -1) {
   if (socket->m_fd != -1) {
-    shutdown(socket->m_fd, 2);
+    /* Only oriented connection should be shutdowned */
+    if (socket->m_oriented)
+      shutdown(socket->m_fd, 2);
     close(socket->m_fd);
     socket->m_fd = -1;
   }
 
     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 */
 
 GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address)
 {
 }
 
 /* Address handling */
 
 GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address)
 {
-  if (socket == NULL || (socket->m_fd != -1 && !socket->m_server))
+  assert(socket != NULL);
+
+  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);
@@ -139,8 +177,7 @@ GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address)
 
 GSocketError GSocket_SetPeer(GSocket *socket, GAddress *address)
 {
 
 GSocketError GSocket_SetPeer(GSocket *socket, GAddress *address)
 {
-  if (socket == NULL)
-    return GSOCK_INVSOCK;
+  assert(socket != NULL);
 
   if (address == NULL || address->m_family == GSOCK_NOFAMILY) {
     socket->m_error = GSOCK_INVADDR;
 
   if (address == NULL || address->m_family == GSOCK_NOFAMILY) {
     socket->m_error = GSOCK_INVADDR;
@@ -179,7 +216,14 @@ 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;
+  }
+  if (_GAddress_translate_from(address, &addr, size) != GSOCK_NOERROR) {
+    GAddress_destroy(address);
+    return NULL;
+  }
 
   return address;
 }
 
   return address;
 }
@@ -200,7 +244,8 @@ GAddress *GSocket_GetPeer(GSocket *socket)
   GSocket_SetServer() setup the socket as a server. It uses the "Local" field
   of GSocket. "Local" must be set by GSocket_SetLocal() before
   GSocket_SetServer() is called. GSOCK_INVSOCK if socket has been initialized.
   GSocket_SetServer() setup the socket as a server. It uses the "Local" field
   of GSocket. "Local" must be set by GSocket_SetLocal() before
   GSocket_SetServer() is called. GSOCK_INVSOCK if socket has been initialized.
-  In the other cases, it returns GSOCK_INVADDR.
+  In case, you haven't yet defined the local address, it returns GSOCK_INVADDR.
+  In the other cases it returns GSOCK_IOERR.
 */
 GSocketError GSocket_SetServer(GSocket *sck)
 {
 */
 GSocketError GSocket_SetServer(GSocket *sck)
 {
@@ -218,18 +263,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;
@@ -237,6 +283,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;
@@ -244,10 +291,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;
-     
 }
 
 /*
 }
 
 /*
@@ -259,15 +306,19 @@ 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();
 
+  /* Accept the incoming connection */
   connection->m_fd = accept(socket->m_fd, NULL, NULL);
   if (connection->m_fd == -1) {
     GSocket_destroy(connection);
   connection->m_fd = accept(socket->m_fd, NULL, NULL);
   if (connection->m_fd == -1) {
     GSocket_destroy(connection);
@@ -275,6 +326,7 @@ GSocket *GSocket_WaitConnection(GSocket *socket)
     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;
@@ -302,8 +354,10 @@ 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);
 
+  /* 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;
@@ -311,6 +365,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;
 }
 
@@ -337,6 +394,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;
 
@@ -345,6 +403,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) {
@@ -352,6 +411,7 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
     return GSOCK_IOERR;
   }
 
     return GSOCK_IOERR;
   }
 
+  /* Connect it to the PEER address */
   if (connect(sck->m_fd, sck->m_peer->m_addr,
               sck->m_peer->m_len) != 0) {
     close(sck->m_fd);
   if (connect(sck->m_fd, sck->m_peer->m_addr,
               sck->m_peer->m_len) != 0) {
     close(sck->m_fd);
@@ -360,8 +420,12 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
     return GSOCK_IOERR;
   }
   
     return GSOCK_IOERR;
   }
   
+  /* It is not a server */
   sck->m_server = FALSE;
 
   sck->m_server = FALSE;
 
+  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
+  GSocket_SetTimeout(sck, sck->m_timeout);
+
   return GSOCK_NOERROR;
 }
 
   return GSOCK_NOERROR;
 }
 
@@ -377,9 +441,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);
@@ -397,7 +462,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);
@@ -429,17 +494,47 @@ 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;
+ /* Neither GLIBC 2.0 nor the kernel 2.0.36 define SO_SNDTIMEO or
+    SO_RCVTIMEO. The man pages, that these flags should exist but
+    are read only. RR. */
+ /* OK, restrict this to GLIBC 2.1. GL. */
+ /* Anyway, they seem to pose problems: I need to know the socket level and
+    it varies (may be SOL_TCP, SOL_UDP, ...). I disables this and use the
+    other solution. GL. */
+#if 0
+#ifdef CAN_USE_TIMEOUT 
+  if (socket->m_fd != -1) {
+    struct timeval tval;
+
+    tval.tv_sec = millisec / 1000;
+    tval.tv_usec = (millisec % 1000) * 1000;
+    setsockopt(socket->m_fd, SOL_SOCKET, SO_SNDTIMEO, &tval, sizeof(tval));
+    setsockopt(socket->m_fd, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(tval));
+  }
+#endif
+#endif
 }
 
 /*
 }
 
 /*
@@ -456,7 +551,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
@@ -466,7 +561,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
@@ -474,29 +569,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;
 
@@ -505,17 +600,16 @@ 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) \
 if (socket->m_iocalls[event] && \
     }
   }
 }
 
 #define CALL_FALLBACK(socket, 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]); \
 }
 
@@ -529,18 +623,37 @@ if (socket->m_iocalls[event] && \
   signal(SIGPIPE, old_handler); \
 }
 
   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); \
+}
+
 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)
@@ -548,33 +661,54 @@ 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) {
+
+  if (ret == -1 && errno != EWOULDBLOCK) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
+    return -1;
+  }
   return ret;
 }
 
 int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
 {
   struct sockaddr from;
   return ret;
 }
 
 int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
 {
   struct sockaddr from;
-  int fromlen, ret;
+  SOCKLEN_T fromlen;
+  int ret;
 
   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) {
     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 (!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;
+    }
+  }
+  if (_GAddress_translate_from(socket->m_peer, &from, fromlen) != GSOCK_NOERROR)
+    return -1;
 
   return ret;
 }
 
   return ret;
 }
@@ -584,12 +718,18 @@ int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size)
   int ret;
 
   MASK_SIGNAL();
   int ret;
 
   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) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
+    return -1;
+  }
   return ret;
 }
 
   return ret;
 }
 
@@ -603,17 +743,27 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size)
     return -1;
   }
 
     return -1;
   }
 
-  _GAddress_translate_to(socket->m_peer, &addr, &len);
+  if (_GAddress_translate_to(socket->m_peer, &addr, &len) != GSOCK_NOERROR) {
+    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;
 }
@@ -654,10 +804,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; \
@@ -670,6 +826,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;
@@ -684,10 +843,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);
   }
 
@@ -715,7 +882,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:
@@ -730,8 +897,10 @@ void _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len)
     break;
 #endif
   default:
     break;
 #endif
   default:
-
-    /* TODO error */
+    {
+    address->m_error = GSOCK_INVOP;
+    return GSOCK_INVOP;
+    }
   }
 
   if (address->m_addr)
   }
 
   if (address->m_addr)
@@ -739,20 +908,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;
 }
 
 /*
 }
 
 /*
@@ -761,14 +942,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)
@@ -782,10 +971,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;
@@ -811,7 +1009,8 @@ GSocketError GAddress_INET_SetHostAddress(GAddress *address,
   return GSOCK_NOERROR;
 }
 
   return GSOCK_NOERROR;
 }
 
-GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port)
+GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port,
+                                       const char *protocol)
 {
   struct servent *se;
   struct sockaddr_in *addr;
 {
   struct servent *se;
   struct sockaddr_in *addr;
@@ -821,11 +1020,10 @@ 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, "tcp");
+  se = getservbyname(port, protocol);
   if (!se) {
     if (isdigit(port[0])) {
       int port_int;
   if (!se) {
     if (isdigit(port[0])) {
       int port_int;
@@ -911,14 +1109,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)
@@ -948,3 +1153,6 @@ GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf)
 
   return GSOCK_NOERROR;
 }
 
   return GSOCK_NOERROR;
 }
+
+#endif
+  /* wxUSE_SOCKETS */