]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/gsocket.c
Added a check for -lresolv in configure.in
[wxWidgets.git] / src / unix / gsocket.c
index aa3f28ae855141d06b00356e161d24eb7d471efd..2ffafc86b6993ac60e806f8c349d0853966e723d 100644 (file)
 
 #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()
@@ -82,7 +90,7 @@ GSocket *GSocket_new()
 
   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;
@@ -91,9 +99,9 @@ GSocket *GSocket_new()
   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
+                                      /* 10 minutes * 60 sec * 1000 millisec */
 
   /* We initialize the GUI specific entries here */
   _GSocket_GUI_Init(socket);
@@ -131,7 +139,9 @@ void GSocket_Shutdown(GSocket *socket)
 
   /* If socket has been created, we shutdown it */
   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;
   }
@@ -210,8 +220,7 @@ GAddress *GSocket_GetLocal(GSocket *socket)
     socket->m_error = GSOCK_MEMERR;
     return NULL;
   }
-  if (!_GAddress_translate_from(address, &addr, size)) {
-    socket->m_error = GSOCK_MEMERR;
+  if (_GAddress_translate_from(address, &addr, size) != GSOCK_NOERROR) {
     GAddress_destroy(address);
     return NULL;
   }
@@ -256,6 +265,7 @@ GSocketError GSocket_SetServer(GSocket *sck)
 
   /* We always have a stream here  */
   sck->m_stream = TRUE;
+  sck->m_server = TRUE;
 
   /* Create the socket */
   sck->m_fd = socket(sck->m_local->m_realfamily, SOCK_STREAM, 0);
@@ -281,7 +291,7 @@ GSocketError GSocket_SetServer(GSocket *sck)
     return GSOCK_IOERR;
   }
 
-  GSocket_SetNonBlocking(sck, sck->m_blocking);
+  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
   GSocket_SetTimeout(sck, sck->m_timeout);
 
   return GSOCK_NOERROR;
@@ -355,7 +365,7 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
     return GSOCK_IOERR;
   }
 
-  GSocket_SetNonBlocking(sck, sck->m_blocking);
+  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
   GSocket_SetTimeout(sck, sck->m_timeout);
 
   return GSOCK_NOERROR;
@@ -413,7 +423,7 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
   /* It is not a server */
   sck->m_server = FALSE;
 
-  GSocket_SetNonBlocking(sck, sck->m_blocking);
+  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
   GSocket_SetTimeout(sck, sck->m_timeout);
 
   return GSOCK_NOERROR;
@@ -491,34 +501,30 @@ void GSocket_SetNonBlocking(GSocket *socket, bool non_block)
 {
   assert(socket != NULL);
 
-  socket->m_blocking = block;
+  socket->m_non_blocking = non_block;
 
   if (socket->m_fd != -1)
-    ioctl(socket->m_fd, FIONBIO, &block);
+    ioctl(socket->m_fd, FIONBIO, &non_block);
 }
 
 /*
  * GSocket_SetTimeout()
  */
 
-#ifndef LINUX
-#   define CAN_USE_TIMEOUT
-#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-#   if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 1)
-#      define CAN_USE_TIMEOUT
-#   endif
-#endif
-
 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 
-  socket->m_timeout = millisec;
   if (socket->m_fd != -1) {
     struct timeval tval;
 
@@ -528,6 +534,7 @@ void GSocket_SetTimeout(GSocket *socket, unsigned long millisec)
     setsockopt(socket->m_fd, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(tval));
   }
 #endif
+#endif
 }
 
 /*
@@ -544,7 +551,7 @@ GSocketError GSocket_GetError(GSocket *socket)
 /* 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
@@ -563,7 +570,7 @@ GSocketError GSocket_GetError(GSocket *socket)
                 CONNECTION -> GSocket_Accept()
 */
 void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event,
-                        GSocketCallback fallback, char *cdata)
+                        GSocketCallback callback, char *cdata)
 {
   int count;
 
@@ -573,7 +580,7 @@ void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event,
     /* We test each flag and, if it is enabled, we enable the corresponding
        event */
     if ((event & (1 << count)) != 0) {
-      socket->m_fbacks[count] = fallback;
+      socket->m_cbacks[count] = callback;
       socket->m_data[count] = cdata;
       _GSocket_Enable(socket, count);
     }
@@ -581,7 +588,7 @@ void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event,
 }
 
 /*
-  UnsetCallback will disables all fallbacks specified by "event".
+  UnsetCallback will disables all callbacks specified by "event".
   NOTE: event may be a combination of flags
 */
 void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags event)
@@ -593,16 +600,16 @@ void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags event)
   for (count=0;count<GSOCK_MAX_EVENT;count++) {
     if ((event & (1 << count)) != 0) {
       _GSocket_Disable(socket, count);
-      socket->m_fbacks[count] = NULL;
+      socket->m_cbacks[count] = NULL;
     }
   }
 }
 
 #define CALL_FALLBACK(socket, event) \
 if (socket->m_iocalls[event] && \
-    socket->m_fbacks[event]) {\
+    socket->m_cbacks[event]) {\
   _GSocket_Disable(socket, event); \
-  socket->m_fbacks[event](socket, event, \
+  socket->m_cbacks[event](socket, event, \
                    socket->m_data[event]); \
 }
 
@@ -616,17 +623,36 @@ if (socket->m_iocalls[event] && \
   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;
-  if (socket->m_fbacks[event])
+  if (socket->m_cbacks[event])
     _GSocket_Install_Callback(socket, event);
 }
 
 void _GSocket_Disable(GSocket *socket, GSocketEvent event)
 {
   socket->m_iocalls[event] = FALSE;
-  if (socket->m_fbacks[event])
+  if (socket->m_cbacks[event])
     _GSocket_Uninstall_Callback(socket, event);
 }
 
@@ -635,14 +661,17 @@ int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
   int ret;
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = recv(socket->m_fd, buffer, size, 0);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
-  if (ret == -1 && errno != EAGAIN) {
+
+  if (ret == -1 && errno != EWOULDBLOCK) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
-  if (errno == EAGAIN) {
-    socket->m_error = GSOCK_TRYAGAIN;
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
     return -1;
   }
   return ret;
@@ -657,14 +686,16 @@ int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
   fromlen = sizeof(from);
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = recvfrom(socket->m_fd, buffer, size, 0, &from, &fromlen);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
-  if (ret == -1 && errno != EAGAIN) {
+  if (ret == -1 && errno != EWOULDBLOCK) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
-  if (errno == EAGAIN) {
-    socket->m_error = GSOCK_TRYAGAIN;
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
     return -1;
   }
 
@@ -676,10 +707,8 @@ int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
       return -1;
     }
   }
-  if (!_GAddress_translate_from(socket->m_peer, &from, fromlen)) {
-    socket->m_error = GSOCK_MEMERR;
+  if (_GAddress_translate_from(socket->m_peer, &from, fromlen) != GSOCK_NOERROR)
     return -1;
-  }
 
   return ret;
 }
@@ -689,14 +718,16 @@ int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size)
   int ret;
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = send(socket->m_fd, buffer, size, 0);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
-  if (ret == -1 && errno != EAGAIN) {
+  if (ret == -1 && errno != EWOULDBLOCK) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
-  if (errno == EAGAIN) {
-    socket->m_error = GSOCK_TRYAGAIN;
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
     return -1;
   }
   return ret;
@@ -712,24 +743,25 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size)
     return -1;
   }
 
-  if (!_GAddress_translate_to(socket->m_peer, &addr, &len)) {
-    socket->m_error = GSOCK_MEMERR;
+  if (_GAddress_translate_to(socket->m_peer, &addr, &len) != GSOCK_NOERROR) {
     return -1;
   }
 
   MASK_SIGNAL();
+  ENABLE_TIMEOUT(socket);
   ret = sendto(socket->m_fd, buffer, size, 0, addr, len);
+  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
 
   /* Frees memory allocated from _GAddress_translate_to */
   free(addr);
 
-  if (ret == -1 && errno != EAGAIN) {
+  if (ret == -1 && errno != EWOULDBLOCK) {
     socket->m_error = GSOCK_IOERR;
     return -1;
   }
-  if (errno == EAGAIN) {
-    socket->m_error = GSOCK_TRYAGAIN;
+  if (errno == EWOULDBLOCK) {
+    socket->m_error = GSOCK_WOULDBLOCK;
     return -1;
   }
 
@@ -779,9 +811,8 @@ void _GSocket_Detected_Write(GSocket *socket)
 #define CHECK_ADDRESS(address, family, retval) \
 { \
   if (address->m_family == GSOCK_NOFAMILY) \
-    if (!_GAddress_Init_##family(address)) {\
-      address->m_error = GSOCK_MEMERR; \
-      return retval; \
+    if (_GAddress_Init_##family(address) != GSOCK_NOERROR) {\
+      return address->m_error; \
     }\
   if (address->m_family != GSOCK_##family) {\
     address->m_error = GSOCK_INVADDR; \
@@ -851,7 +882,7 @@ GAddressType GAddress_GetFamily(GAddress *address)
   return address->m_family;
 }
 
-bool _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:
@@ -867,7 +898,8 @@ bool _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len)
 #endif
   default:
     {
-    /* TODO error */
+    address->m_error = GSOCK_INVOP;
+    return GSOCK_INVOP;
     }
   }
 
@@ -876,28 +908,32 @@ bool _GAddress_translate_from(GAddress *address, struct sockaddr *addr, int len)
 
   address->m_len  = len;
   address->m_addr = (struct sockaddr *)malloc(len);
-  if (address->m_addr == NULL)
-    return FALSE;
+  if (address->m_addr == NULL) {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
   memcpy(address->m_addr, addr, len);
 
-  return TRUE;
+  return GSOCK_NOERROR;
 }
 
-bool _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) {
-    /* TODO error */
-    return;
+    address->m_error = GSOCK_INVADDR;
+    return GSOCK_INVADDR;
   }
 
   *len = address->m_len;
   *addr = (struct sockaddr *)malloc(address->m_len);
-  if (*addr == NULL)
-    return FALSE;
+  if (*addr == NULL) {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
 
   memcpy(*addr, address->m_addr, address->m_len);
-  return TRUE;
+  return GSOCK_NOERROR;
 }
 
 /*
@@ -906,11 +942,13 @@ bool _GAddress_translate_to(GAddress *address,
  * -------------------------------------------------------------------------
  */
 
-bool _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)
-    return FALSE;
+  if (address->m_addr == NULL) {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
 
   address->m_len  = sizeof(struct sockaddr_in);
 
@@ -919,7 +957,7 @@ bool _GAddress_Init_INET(GAddress *address)
   ((struct sockaddr_in *)address->m_addr)->sin_family = AF_INET;
   ((struct sockaddr_in *)address->m_addr)->sin_addr.s_addr   = INADDR_ANY;
 
-  return TRUE;
+  return GSOCK_NOERROR;
 }
 
 GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
@@ -934,7 +972,15 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
   addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr);
 
   /* If it is a numeric host name, convert it now */
+#if defined(HAVE_INET_ATON)
   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;
 
     /* It is a real name, we solve it */
@@ -974,7 +1020,7 @@ GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port,
 
   if (!port) {
     address->m_error = GSOCK_INVPORT;
-    return GSOCK_INVOP;
+    return GSOCK_INVPORT;
   }
  
   se = getservbyname(port, protocol);
@@ -1063,11 +1109,13 @@ unsigned short GAddress_INET_GetPort(GAddress *address)
  * -------------------------------------------------------------------------
  */
 
-bool _GAddress_Init_UNIX(GAddress *address)
+GSocketError _GAddress_Init_UNIX(GAddress *address)
 {
   address->m_addr = (struct sockaddr *)malloc(address->m_len);
-  if (address->m_addr == NULL)
-    return FALSE;
+  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;
@@ -1106,4 +1154,5 @@ GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf)
   return GSOCK_NOERROR;
 }
 
-#endif // wxUSE_SOCKETS
+#endif
+  /* wxUSE_SOCKETS */