]> git.saurik.com Git - wxWidgets.git/commitdiff
bugfixes
authorGuillermo Rodriguez Garcia <guille@iies.es>
Thu, 30 Sep 1999 23:53:10 +0000 (23:53 +0000)
committerGuillermo Rodriguez Garcia <guille@iies.es>
Thu, 30 Sep 1999 23:53:10 +0000 (23:53 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3772 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/gsockmsw.h
include/wx/socket.h
include/wx/unix/gsockunx.h
src/gtk/gsockgtk.c
src/gtk1/gsockgtk.c
src/motif/gsockmot.cpp
src/unix/gsocket.c

index 6cd735b092a05233d506622d84398ce04fddb28f..e745060b5817c42bbce2746a8d27ccb3400df8ef 100644 (file)
@@ -36,6 +36,7 @@ struct _GSocket
   GAddress *m_peer;
   GSocketError m_error;
 
+  /* Attributes */
   bool m_non_blocking;
   bool m_server;
   bool m_stream;
@@ -43,6 +44,7 @@ struct _GSocket
   struct timeval m_timeout;
 
   /* Callbacks */
+  GSocketEventFlags m_detected;
   GSocketCallback m_cbacks[GSOCK_MAX_EVENT];
   char *m_data[GSOCK_MAX_EVENT];
   int m_msgnumber;
@@ -72,7 +74,8 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size);
 
 /* Callbacks */
 
-void _GSocket_Configure_Callbacks(GSocket *socket);
+void _GSocket_Enable_Events(GSocket *socket);
+void _GSocket_Disable_Events(GSocket *socket);
 LRESULT CALLBACK _GSocket_Internal_WinProc(HWND, UINT, WPARAM, LPARAM);
 
 /* GAddress */
index d74c44d2964f0538a391f4c6d4dc1d02d7279775..d069f2904f73f64493dcd00f616bfb4b9ab9b0b8 100644 (file)
@@ -23,6 +23,7 @@
 // ---------------------------------------------------------------------------
 // wxSocket headers (generic)
 // ---------------------------------------------------------------------------
+
 #ifdef WXPREC
 #  include "wx/wxprec.h"
 #else
@@ -63,9 +64,19 @@ typedef enum {
   wxSOCKET_INVPORT = GSOCK_INVPORT,
   wxSOCKET_WOULDBLOCK = GSOCK_WOULDBLOCK,
   wxSOCKET_TIMEDOUT = GSOCK_TIMEDOUT,
-  wxSOCKET_MEMERR = GSOCK_MEMERR
+  wxSOCKET_MEMERR = GSOCK_MEMERR,
+  wxSOCKET_BUSY
 } wxSocketError;
 
+enum {
+  wxSOCKET_NONE = 0,
+  wxSOCKET_NOWAIT = 1,
+  wxSOCKET_WAITALL = 2,
+  wxSOCKET_BLOCK = 4
+};
+
+typedef int wxSockFlags;
+
 // ------------------------------------------------------------------------
 // wxSocket base
 // ------------------------------------------------------------------------
@@ -77,43 +88,64 @@ class WXDLLEXPORT wxSocketBase : public wxEvtHandler
   DECLARE_CLASS(wxSocketBase)
 public:
 
-  enum { NONE=0, NOWAIT=1, WAITALL=2, SPEED=4 };
-  typedef int wxSockFlags;
+  enum {
+    NONE = wxSOCKET_NONE,
+    NOWAIT = wxSOCKET_NOWAIT,
+    WAITALL = wxSOCKET_WAITALL,
+    SPEED = wxSOCKET_BLOCK
+  };
+
+  typedef ::wxSockFlags wxSockFlags;
+
   // Type of request
 
   enum wxSockType { SOCK_CLIENT, SOCK_SERVER, SOCK_INTERNAL, SOCK_UNINIT };
   typedef void (*wxSockCbk)(wxSocketBase& sock, wxSocketNotify evt, char *cdata);
 
 protected:
-  GSocket *m_socket;                   // wxSocket socket
+  GSocket *m_socket;            // GSocket
+  int m_id;                     // Socket id (for event handler)
+
+  // Attributes
   wxSockFlags m_flags;                 // wxSocket flags
   wxSockType m_type;                   // wxSocket type
-  wxSocketEventFlags m_neededreq;   // Which events we are interested in
-  wxUint32 m_lcount;                   // Last IO request size
+  wxSocketEventFlags m_neededreq;   // Event mask
+  bool m_notify_state;          // Notify events to users?
+  bool m_connected;             // Connected ?
+  bool m_establishing;          // Establishing connection ?
+  bool m_reading;               // Busy reading?
+  bool m_writing;               // Busy writing?
+  bool m_error;                 // Did last IO call fail ?
+  wxUint32 m_lcount;            // Last IO transaction size
   unsigned long m_timeout;             // IO timeout value
-                     
+  wxList m_states;              // Stack of states
+
   char *m_unread;               // Pushback buffer
   wxUint32 m_unrd_size;                        // Pushback buffer size
-  wxUint32 m_unrd_cur;                 // Pushback pointer
-
-  wxSockCbk m_cbk;              // C callback
-  char *m_cdata;                // C callback data
-
-  bool m_connected;             // Connected ?
-  bool m_establishing;          // Pending connections ?
-  bool m_notify_state;                 // Notify state
-  int m_id;                     // Socket id (for event handler)
-
-  // Defering variables
-  enum {
-    DEFER_READ, DEFER_WRITE, NO_DEFER
+  wxUint32 m_unrd_cur;          // Pushback pointer (index into buffer)
+
+  // Async IO variables
+  enum
+  {
+    NO_DEFER = 0,
+    DEFER_READ = 1,
+    DEFER_WRITE = 2
   } m_defering;                 // Defering state
   char *m_defer_buffer;         // Defering target buffer
   wxUint32 m_defer_nbytes;      // Defering buffer size
   wxTimer *m_defer_timer;       // Timer for defering mode
 
-  bool m_error;                 // Did an error occur in last IO call ?
-  wxList m_states;              // Stack of states
+/*
+  char *m_read_buffer;          // Target buffer (read)
+  char *m_write_buffer;         // Target buffer (write)
+  wxUint32 m_read_nbytes;       // Buffer size (read)
+  wxUint32 m_write_nbytes;      // Buffer size (write)
+  wxTimer *m_read_timer;        // Timer (read)
+  wxTimer *m_write_timer;       // Timer (write)
+*/
+
+  wxSockCbk m_cbk;              // C callback
+  char *m_cdata;                // C callback data
 
 public:
   wxSocketBase();
@@ -127,7 +159,7 @@ public:
   wxSocketBase& Unread(const char *buffer, wxUint32 nbytes);
   wxSocketBase& ReadMsg(char *buffer, wxUint32 nbytes);
   wxSocketBase& WriteMsg(const char *buffer, wxUint32 nbytes);
-  void Discard();
+  wxSocketBase& Discard();
 
   // Status
   inline bool Ok() const { return (m_socket != NULL); };
@@ -135,7 +167,7 @@ public:
   inline bool IsConnected() const { return m_connected; };
   inline bool IsDisconnected() const { return !IsConnected(); };
   inline bool IsNoWait() const { return ((m_flags & NOWAIT) != 0); };
-  bool IsData() const;
+  inline bool IsData() { return WaitForRead(0, 0); };
   inline wxUint32 LastCount() const { return m_lcount; }
   inline wxSocketError LastError() const { return (wxSocketError)GSocket_GetError(m_socket); }
   inline wxSockType GetType() const { return m_type; }
@@ -145,9 +177,9 @@ public:
   virtual bool GetLocal(wxSockAddress& addr_man) const;
 
   // Set attributes and flags
-  void SetFlags(wxSockFlags _flags);
-  wxSockFlags GetFlags() const;
   void SetTimeout(long seconds);
+  void SetFlags(wxSockFlags flags);
+  inline wxSockFlags GetFlags() const { return m_flags; };
 
   // Wait functions
   //   seconds = -1 means default timeout (change with SetTimeout)
@@ -178,9 +210,7 @@ public:
   // Public internal callback
   virtual void OldOnNotify(wxSocketNotify WXUNUSED(evt));
 
-  // Do NOT use these functions; they should be protected!
-  void CreatePushbackAfter(const char *buffer, wxUint32 size);
-  void CreatePushbackBefore(const char *buffer, wxUint32 size);
+  // Do NOT use this function; it should be protected!
   void OnRequest(wxSocketNotify req_evt);
 
 protected:
@@ -198,13 +228,17 @@ public:
 protected:
 #endif
 
+  // Low level IO
+  wxUint32 _Read(char* buffer, wxUint32 nbytes);
+  wxUint32 _Write(const char *buffer, wxUint32 nbytes);
   bool _Wait(long seconds, long milliseconds, wxSocketEventFlags flags);
 
-  int DeferRead(char *buffer, wxUint32 nbytes);
-  int DeferWrite(const char *buffer, wxUint32 nbytes);
+  wxUint32 DeferRead(char *buffer, wxUint32 nbytes);
+  wxUint32 DeferWrite(const char *buffer, wxUint32 nbytes);
   void DoDefer();
 
-  // Pushback library
+  // Pushbacks
+  void Pushback(const char *buffer, wxUint32 size);
   wxUint32 GetPushback(char *buffer, wxUint32 size, bool peek);
 };
 
index 1ae5b4248d0c57b76befaaec6c789c93f56576f6..99562423049cc0c105193720f415538ba0efd920 100644 (file)
@@ -5,14 +5,22 @@
  * CVSID:   $Id$
  * -------------------------------------------------------------------------
  */
+
 #ifndef __GSOCK_UNX_H
 #define __GSOCK_UNX_H
 
+#ifndef __GSOCKET_STANDALONE__
 #include "wx/setup.h"
+#endif
 
-#if wxUSE_SOCKETS
+#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__)
 
+#ifndef __GSOCKET_STANDALONE__
 #include "wx/gsocket.h"
+#else
+#include "gsocket.h"
+#endif
+
 
 #ifdef __cplusplus
 extern "C" {
@@ -20,27 +28,31 @@ extern "C" {
 
 
 /* Definition of GSocket */
-struct _GSocket {
+struct _GSocket
+{
   int m_fd;
-  GAddress *m_local, *m_peer;
+  GAddress *m_local;
+  GAddress *m_peer;
   GSocketError m_error;
 
-  bool m_non_blocking, m_server, m_stream, m_oriented;
+  bool m_non_blocking;
+  bool m_server;
+  bool m_stream;
+  bool m_oriented;
   bool m_establishing;
   unsigned long m_timeout;
 
   /* Callbacks */
+  GSocketEventFlags m_detected;
   GSocketCallback m_cbacks[GSOCK_MAX_EVENT];
   char *m_data[GSOCK_MAX_EVENT];
 
-  /* IO calls associated */
-  bool m_iocalls[GSOCK_MAX_EVENT];
-
   char *m_gui_dependent;
 };
 
 /* Definition of GAddress */
-struct _GAddress {
+struct _GAddress
+{
   struct sockaddr *m_addr;
   size_t m_len;
 
@@ -50,39 +62,43 @@ struct _GAddress {
   GSocketError m_error;
 };
 
-void _GSocket_Enable(GSocket *socket, GSocketEvent event);
-void _GSocket_Disable(GSocket *socket, GSocketEvent event);
-void _GSocket_Configure_Callbacks(GSocket *socket);
+/* Input / Output */
+
+GSocketError _GSocket_Input_Timeout(GSocket *socket);
+GSocketError _GSocket_Output_Timeout(GSocket *socket);
 int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size);
 int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size);
 int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size);
 int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size);
-void _GSocket_Install_Callback(GSocket *socket, GSocketEvent count);
-void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent count);
+
+/* Callbacks */
+
+void _GSocket_Enable(GSocket *socket, GSocketEvent event);
+void _GSocket_Disable(GSocket *socket, GSocketEvent event);
 void _GSocket_Detected_Read(GSocket *socket);
 void _GSocket_Detected_Write(GSocket *socket);
+
 void _GSocket_GUI_Init(GSocket *socket);
 void _GSocket_GUI_Destroy(GSocket *socket);
+void _GSocket_Enable_Events(GSocket *socket);
+void _GSocket_Disable_Events(GSocket *socket);
+void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event);
+void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event);
+
+/* GAddress */
 
-/* Translaters returns false when memory is exhausted */
 GSocketError _GAddress_translate_from(GAddress *address,
                                       struct sockaddr *addr, int len);
 GSocketError _GAddress_translate_to(GAddress *address,
                                     struct sockaddr **addr, int *len);
 
-/* Initialisers returns FALSE when an error happened in the initialisation */
-
-/* Internet address family */
 GSocketError _GAddress_Init_INET(GAddress *address);
-/* Local address family */
 GSocketError _GAddress_Init_UNIX(GAddress *address);
 
 #ifdef __cplusplus
 }
-#endif /* __cplusplus */
+#endif  /* __cplusplus */
 
-#endif
-    /* wxUSE_SOCKETS */
+#endif  /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */
 
-#endif
-    /* __GSOCK_UNX_H */
+#endif  /* __GSOCK_UNX_H */
index 8677ef3626e627a2280faedea17fd9f30e65ed9b..5bfb166c1596475e5f62bb6dfcbfaca2685096e8 100644 (file)
 #if wxUSE_SOCKETS
 
 #include <stdlib.h>
+#include <stdio.h>
 #include "gdk/gdk.h"
 #include "glib.h"
 #include "wx/gsocket.h"
 #include "wx/unix/gsockunx.h"
 
-void _GSocket_GDK_Input(gpointer data, gint source, GdkInputCondition condition)
+
+void _GSocket_GDK_Input(gpointer data,
+                        gint source,
+                        GdkInputCondition condition)
 {
   GSocket *socket = (GSocket *)data;
 
@@ -30,63 +34,56 @@ void _GSocket_GUI_Init(GSocket *socket)
   int i;
   gint *m_id;
 
-  socket->m_gui_dependent = (char *)malloc(sizeof(gint)*3);
+  socket->m_gui_dependent = (char *)malloc(sizeof(gint)*2);
   m_id = (gint *)(socket->m_gui_dependent);
 
-  for (i=0;i<3;i++)
-    m_id[i] = -1;
+  m_id[0] = -1;
+  m_id[1] = -1;
 }
 
 void _GSocket_GUI_Destroy(GSocket *socket)
 {
-  int i;
-  gint *m_id;
-
-  m_id = (gint *)(socket->m_gui_dependent);
-
-  for (i=0;i<3;i++)
-    if (m_id[i] == -1)
-      gdk_input_remove(m_id[i]);
-
   free(socket->m_gui_dependent);
 }
 
 void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event)
 {
-  GdkInputCondition flag;
+  gint *m_id = (gint *)(socket->m_gui_dependent);
   int c;
-  gint *m_id;
 
-  m_id = (gint *)(socket->m_gui_dependent);
+  if (socket->m_fd == -1)
+    return;
 
-  switch (event) {
-  case GSOCK_CONNECTION:
-  case GSOCK_LOST:
-  case GSOCK_INPUT: c = 0; flag = GDK_INPUT_READ; break;
-  case GSOCK_OUTPUT: c = 1;flag = GDK_INPUT_WRITE; break;
-  default: return;
+  switch (event)
+  {
+    case GSOCK_LOST:       /* fall-through */
+    case GSOCK_INPUT:      c = 0; break; 
+    case GSOCK_OUTPUT:     c = 1; break;
+    case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
+    default: return;
   }
 
   if (m_id[c] != -1)
     gdk_input_remove(m_id[c]);
 
-  m_id[c] = gdk_input_add(socket->m_fd, flag, 
-                          _GSocket_GDK_Input, (gpointer)socket);
+  m_id[c] = gdk_input_add(socket->m_fd,
+                          (c ? GDK_INPUT_WRITE : GDK_INPUT_READ),
+                          _GSocket_GDK_Input,
+                          (gpointer)socket);
 }
 
 void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
 {
+  gint *m_id = (gint *)(socket->m_gui_dependent);
   int c;
-  gint *m_id;
-
-  m_id = (gint *)(socket->m_gui_dependent);
 
-  switch (event) {
-  case GSOCK_CONNECTION: 
-  case GSOCK_LOST:
-  case GSOCK_INPUT: c = 0; break;
-  case GSOCK_OUTPUT: c = 1; break;
-  default: return;
+  switch (event)
+  {
+    case GSOCK_LOST:       /* fall-through */
+    case GSOCK_INPUT:      c = 0; break; 
+    case GSOCK_OUTPUT:     c = 1; break;
+    case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
+    default: return;
   }
 
   if (m_id[c] != -1)
@@ -95,13 +92,16 @@ void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
   m_id[c] = -1;
 }
 
-unsigned long GSocket_GetEventID(GSocket *socket)
+void _GSocket_Enable_Events(GSocket *socket)
 {
-  return 0;
+  _GSocket_Install_Callback(socket, GSOCK_INPUT);
+  _GSocket_Install_Callback(socket, GSOCK_OUTPUT);
 }
 
-void GSocket_DoEvent(unsigned long evt_id)
+void _GSocket_Disable_Events(GSocket *socket)
 {
+  _GSocket_Uninstall_Callback(socket, GSOCK_INPUT);
+  _GSocket_Uninstall_Callback(socket, GSOCK_OUTPUT);
 }
 
 #endif /* wxUSE_SOCKETS */
index 8677ef3626e627a2280faedea17fd9f30e65ed9b..5bfb166c1596475e5f62bb6dfcbfaca2685096e8 100644 (file)
 #if wxUSE_SOCKETS
 
 #include <stdlib.h>
+#include <stdio.h>
 #include "gdk/gdk.h"
 #include "glib.h"
 #include "wx/gsocket.h"
 #include "wx/unix/gsockunx.h"
 
-void _GSocket_GDK_Input(gpointer data, gint source, GdkInputCondition condition)
+
+void _GSocket_GDK_Input(gpointer data,
+                        gint source,
+                        GdkInputCondition condition)
 {
   GSocket *socket = (GSocket *)data;
 
@@ -30,63 +34,56 @@ void _GSocket_GUI_Init(GSocket *socket)
   int i;
   gint *m_id;
 
-  socket->m_gui_dependent = (char *)malloc(sizeof(gint)*3);
+  socket->m_gui_dependent = (char *)malloc(sizeof(gint)*2);
   m_id = (gint *)(socket->m_gui_dependent);
 
-  for (i=0;i<3;i++)
-    m_id[i] = -1;
+  m_id[0] = -1;
+  m_id[1] = -1;
 }
 
 void _GSocket_GUI_Destroy(GSocket *socket)
 {
-  int i;
-  gint *m_id;
-
-  m_id = (gint *)(socket->m_gui_dependent);
-
-  for (i=0;i<3;i++)
-    if (m_id[i] == -1)
-      gdk_input_remove(m_id[i]);
-
   free(socket->m_gui_dependent);
 }
 
 void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event)
 {
-  GdkInputCondition flag;
+  gint *m_id = (gint *)(socket->m_gui_dependent);
   int c;
-  gint *m_id;
 
-  m_id = (gint *)(socket->m_gui_dependent);
+  if (socket->m_fd == -1)
+    return;
 
-  switch (event) {
-  case GSOCK_CONNECTION:
-  case GSOCK_LOST:
-  case GSOCK_INPUT: c = 0; flag = GDK_INPUT_READ; break;
-  case GSOCK_OUTPUT: c = 1;flag = GDK_INPUT_WRITE; break;
-  default: return;
+  switch (event)
+  {
+    case GSOCK_LOST:       /* fall-through */
+    case GSOCK_INPUT:      c = 0; break; 
+    case GSOCK_OUTPUT:     c = 1; break;
+    case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
+    default: return;
   }
 
   if (m_id[c] != -1)
     gdk_input_remove(m_id[c]);
 
-  m_id[c] = gdk_input_add(socket->m_fd, flag, 
-                          _GSocket_GDK_Input, (gpointer)socket);
+  m_id[c] = gdk_input_add(socket->m_fd,
+                          (c ? GDK_INPUT_WRITE : GDK_INPUT_READ),
+                          _GSocket_GDK_Input,
+                          (gpointer)socket);
 }
 
 void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
 {
+  gint *m_id = (gint *)(socket->m_gui_dependent);
   int c;
-  gint *m_id;
-
-  m_id = (gint *)(socket->m_gui_dependent);
 
-  switch (event) {
-  case GSOCK_CONNECTION: 
-  case GSOCK_LOST:
-  case GSOCK_INPUT: c = 0; break;
-  case GSOCK_OUTPUT: c = 1; break;
-  default: return;
+  switch (event)
+  {
+    case GSOCK_LOST:       /* fall-through */
+    case GSOCK_INPUT:      c = 0; break; 
+    case GSOCK_OUTPUT:     c = 1; break;
+    case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
+    default: return;
   }
 
   if (m_id[c] != -1)
@@ -95,13 +92,16 @@ void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
   m_id[c] = -1;
 }
 
-unsigned long GSocket_GetEventID(GSocket *socket)
+void _GSocket_Enable_Events(GSocket *socket)
 {
-  return 0;
+  _GSocket_Install_Callback(socket, GSOCK_INPUT);
+  _GSocket_Install_Callback(socket, GSOCK_OUTPUT);
 }
 
-void GSocket_DoEvent(unsigned long evt_id)
+void _GSocket_Disable_Events(GSocket *socket)
 {
+  _GSocket_Uninstall_Callback(socket, GSOCK_INPUT);
+  _GSocket_Uninstall_Callback(socket, GSOCK_OUTPUT);
 }
 
 #endif /* wxUSE_SOCKETS */
index 7d8dbf7e9964438d6cb53523967cf8a342404a02..d7ed9ebf908c1e5f77e945772dd33247cfd9e3e7 100644 (file)
@@ -11,9 +11,9 @@
 
 #include <stdlib.h>
 #include <X11/Intrinsic.h>
-#include <wx/gsocket.h>
-#include <wx/app.h>
-#include <wx/unix/gsockunx.h>
+#include "wx/gsocket.h"
+#include "wx/app.h"
+#include "wx/unix/gsockunx.h"
 
 #define wxAPP_CONTEXT ((XtAppContext)wxTheApp->GetAppContext())
 
@@ -38,70 +38,66 @@ void _GSocket_GUI_Init(GSocket *socket)
   int i;
   int *m_id;
 
-  socket->m_gui_dependent = (char *)malloc(sizeof(int)*3);
+  socket->m_gui_dependent = (char *)malloc(sizeof(int)*2);
   m_id = (int *)(socket->m_gui_dependent);
 
-  for (i=0;i<3;i++)
-    m_id[i] = -1;
+  m_id[0] = -1;
+  m_id[1] = -1;
 }
 
 void _GSocket_GUI_Destroy(GSocket *socket)
 {
-  int i;
-  int *m_id;
-
-  m_id = (int *)(socket->m_gui_dependent);
-
-  for (i=0;i<3;i++)
-    if (m_id[i] == -1)
-      XtRemoveInput(m_id[i]);
-
   free(socket->m_gui_dependent);
 }
 
 void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event)
 {
-  int *m_id;
+  int *m_id = (int *)(socket->m_gui_dependent);
+  int c;
 
-  m_id = (int *)(socket->m_gui_dependent);
+  if (socket->m_fd == -1)
+    return;
 
-  switch (event) {
-  case GSOCK_CONNECTION:
-  case GSOCK_LOST:
-  case GSOCK_INPUT: 
-     if (m_id[0] != -1)
-       XtRemoveInput(m_id[0]);
+  switch (event)
+  {
+    case GSOCK_LOST:       /* fall-through */
+    case GSOCK_INPUT:      c = 0; break; 
+    case GSOCK_OUTPUT:     c = 1; break;
+    case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
+    default: return;
+  }
+
+  if (m_id[c] != -1)
+    XtRemoveInput(m_id[c]);
+
+  if (c == 0)
+  {
      m_id[0] = XtAppAddInput(wxAPP_CONTEXT, socket->m_fd,
                              (XtPointer *)XtInputReadMask,
                              (XtInputCallbackProc) _GSocket_Motif_Input,
                              (XtPointer) socket);
-     break;
-  case GSOCK_OUTPUT:
-     if (m_id[1] != -1)
-       XtRemoveInput(m_id[1]);
+  }
+  else
+  {
      m_id[1] = XtAppAddInput(wxAPP_CONTEXT, socket->m_fd,
                              (XtPointer *)XtInputWriteMask,
                              (XtInputCallbackProc) _GSocket_Motif_Output,
                              (XtPointer) socket);
-     break;
-  default: return;
   }
 }
 
 void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
 {
+  int *m_id = (int *)(socket->m_gui_dependent);
   int c;
-  int *m_id;
-
-  m_id = (int *)(socket->m_gui_dependent);
 
-  switch (event) {
-  case GSOCK_CONNECTION: 
-  case GSOCK_LOST:
-  case GSOCK_INPUT: c = 0; break;
-  case GSOCK_OUTPUT: c = 1; break;
-     break;
-  default: return;
+  switch (event)
+  {
+    case GSOCK_LOST:       /* fall-through */
+    case GSOCK_INPUT:      c = 0; break; 
+    case GSOCK_OUTPUT:     c = 1; break;
+    case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break;
+    default: return;
   }
 
   if (m_id[c] != -1)
@@ -110,13 +106,16 @@ void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
   m_id[c] = -1;
 }
 
-unsigned long GSocket_GetEventID(GSocket *socket)
+void _GSocket_Enable_Events(GSocket *socket)
 {
-  return 0;
+  _GSocket_Install_Callback(socket, GSOCK_INPUT);
+  _GSocket_Install_Callback(socket, GSOCK_OUTPUT);
 }
 
-void GSocket_DoEvent(unsigned long evt_id)
+void _GSocket_Disable_Events(GSocket *socket)
 {
+  _GSocket_Uninstall_Callback(socket, GSOCK_INPUT);
+  _GSocket_Uninstall_Callback(socket, GSOCK_OUTPUT);
 }
 
 #endif // wxUSE_SOCKETS
index 55a198c16a71b9eef63d50e14e08a09b93dd992b..1d0c60ec76bf672fd396bb2e3e8c1f7a7a385380 100644 (file)
 
 #endif
 
-#define MASK_SIGNAL() \
-{ \
-  void (*old_handler)(int); \
-\
+#define MASK_SIGNAL()                       \
+{                                           \
+  void (*old_handler)(int);                 \
+                                            \
   old_handler = signal(SIGPIPE, SIG_IGN);
 
-#define UNMASK_SIGNAL() \
-  signal(SIGPIPE, old_handler); \
+#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 */
 
@@ -110,10 +92,11 @@ GSocket *GSocket_new()
     return NULL;
 
   socket->m_fd                  = -1;
-  for (i=0;i<GSOCK_MAX_EVENT;i++) {
+  for (i=0;i<GSOCK_MAX_EVENT;i++)
+  {
     socket->m_cbacks[i]         = NULL;
-    socket->m_iocalls[i]        = FALSE;
   }
+  socket->m_detected            = 0;
   socket->m_local               = NULL;
   socket->m_peer                = NULL;
   socket->m_error               = GSOCK_NOERROR;
@@ -160,15 +143,19 @@ void GSocket_Shutdown(GSocket *socket)
   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);
     close(socket->m_fd);
     socket->m_fd = -1;
   }
 
   /* We also disable GUI callbacks */
-  for (evt=0;evt<GSOCK_MAX_EVENT;evt++)
-    _GSocket_Uninstall_Callback(socket, evt);
+  for (evt = 0; evt < GSOCK_MAX_EVENT; evt++)
+    socket->m_cbacks[evt] = NULL;
+
+  socket->m_detected = 0;
+  _GSocket_Disable_Events(socket);
 }
 
 /* Address handling */
@@ -272,6 +259,7 @@ GAddress *GSocket_GetPeer(GSocket *socket)
 GSocketError GSocket_SetServer(GSocket *sck)
 {
   int type;
+  int arg = 1;
 
   assert(sck != NULL);
 
@@ -297,6 +285,9 @@ GSocketError GSocket_SetServer(GSocket *sck)
     return GSOCK_IOERR;
   }
 
+  ioctl(sck->m_fd, FIONBIO, &arg);
+  _GSocket_Enable_Events(sck);
+
   /* 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);
@@ -313,10 +304,6 @@ GSocketError GSocket_SetServer(GSocket *sck)
     return GSOCK_IOERR;
   }
 
-  _GSocket_Configure_Callbacks(sck);
-  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
-  GSocket_SetTimeout(sck, sck->m_timeout);
-
   return GSOCK_NOERROR;
 }
 
@@ -326,54 +313,56 @@ GSocketError GSocket_SetServer(GSocket *sck)
 GSocket *GSocket_WaitConnection(GSocket *socket)
 {
   GSocket *connection;
+  int arg = 1;
 
   assert(socket != NULL);
 
+  /* Reenable CONNECTION events */
+  _GSocket_Enable(socket, GSOCK_CONNECTION);
+
   /* If the socket has already been created, we exit immediately */
-  if (socket->m_fd == -1 || !socket->m_server) {
+  if (socket->m_fd == -1 || !socket->m_server)
+  {
     socket->m_error = GSOCK_INVSOCK;
     return NULL;
   }
 
-  /* Reenable GSOCK_CONNECTION event */
-  _GSocket_Enable(socket, GSOCK_CONNECTION);
-
   /* Create a GSocket object for the new connection */
   connection = GSocket_new();
-  if (!connection) {
+  if (!connection)
+  {
     connection->m_error = GSOCK_MEMERR;
     return NULL;
   }
 
   /* Accept the incoming connection */
-  ENABLE_TIMEOUT(connection);
+  if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT)
+  {
+    GSocket_destroy(connection);
+    /* socket->m_error set by _GSocket_Input_Timeout */
+    return NULL;
+  }
+
   connection->m_fd = accept(socket->m_fd, NULL, NULL);
-  DISABLE_TIMEOUT(connection);
-  if (connection->m_fd == -1) {
+
+  if (connection->m_fd == -1)
+  {
+    if (errno == EWOULDBLOCK)
+      socket->m_error = GSOCK_WOULDBLOCK;
+    else
+      socket->m_error = GSOCK_IOERR;
+
     GSocket_destroy(connection);
-    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;
   }
 
   /* Initialize all fields */
-  connection->m_stream   = TRUE;
   connection->m_server   = FALSE;
+  connection->m_stream   = TRUE;
   connection->m_oriented = TRUE;
 
-  _GSocket_Configure_Callbacks(connection);
-  GSocket_SetNonBlocking(connection, connection->m_non_blocking);
-  GSocket_SetTimeout(connection, connection->m_timeout);
+  ioctl(connection->m_fd, FIONBIO, &arg);
+  _GSocket_Enable_Events(connection);
 
   return connection;
 }
@@ -382,6 +371,8 @@ GSocket *GSocket_WaitConnection(GSocket *socket)
 
 GSocketError GSocket_SetNonOriented(GSocket *sck)
 {
+  int arg = 1;
+
   assert(sck != NULL);
 
   if (sck->m_fd != -1) {
@@ -406,6 +397,9 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
     return GSOCK_IOERR;
   }
 
+  ioctl(sck->m_fd, FIONBIO, &arg);
+  _GSocket_Enable_Events(sck);
+
   /* 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);
@@ -414,10 +408,6 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
     return GSOCK_IOERR;
   }
 
-  _GSocket_Configure_Callbacks(sck);
-  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
-  GSocket_SetTimeout(sck, sck->m_timeout);
-
   return GSOCK_NOERROR;
 }
 
@@ -434,23 +424,31 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
  */
 GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
 {
-  int type, err;
+  int type, err, ret;
+  int arg = 1;
 
   assert(sck != NULL);
 
-  if (sck->m_fd != -1) {
+  /* Enable CONNECTION events (needed for nonblocking connections) */
+  _GSocket_Enable(sck, GSOCK_CONNECTION);
+
+  if (sck->m_fd != -1)
+  {
     sck->m_error = GSOCK_INVSOCK;
     return GSOCK_INVSOCK;
   }
 
-  if (!sck->m_peer) {
+  if (!sck->m_peer)
+  {
     sck->m_error = 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_stream   = (stream == GSOCK_STREAMED);
   sck->m_oriented = TRUE;
+  sck->m_server   = FALSE;
+  sck->m_establishing = FALSE;
 
   if (sck->m_stream)
     type = SOCK_STREAM;
@@ -465,35 +463,66 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
     return GSOCK_IOERR;
   }
 
-  _GSocket_Configure_Callbacks(sck);
-  GSocket_SetNonBlocking(sck, sck->m_non_blocking);
-  GSocket_SetTimeout(sck, sck->m_timeout);
+  ioctl(sck->m_fd, FIONBIO, &arg);
+  _GSocket_Enable_Events(sck);
 
   /* 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);
+  ret = connect(sck->m_fd, sck->m_peer->m_addr, sck->m_peer->m_len);
+
+  if (ret == -1)
+  {
+    err = errno;
+
+    /* If connect failed with EINPROGRESS and the GSocket object
+     * is in blocking mode, we select() for the specified timeout
+     * checking for writability to see if the connection request
+     * completes.
+     */
+    if ((err == EINPROGRESS) && (!sck->m_non_blocking))
+    {
+      if (_GSocket_Output_Timeout(sck) == GSOCK_TIMEDOUT)
+      {
+        close(sck->m_fd);
+        sck->m_fd = -1;
+        /* sck->m_error is set in _GSocket_Output_Timeout */
+        fprintf(stderr, "Blocking connect timeouts\n");
+        return GSOCK_TIMEDOUT;
+      }
+      else
+      {
+        fprintf(stderr, "Blocking connect OK\n");
+        return GSOCK_NOERROR;
+      }
+    }
 
-  if (err != 0 && errno != EINPROGRESS) {
+    /* If connect failed with EINPROGRESS and the GSocket object
+     * is set to nonblocking, we set m_error to GSOCK_WOULDBLOCK
+     * (and return GSOCK_WOULDBLOCK) but we don't close the socket;
+     * this way if the connection completes, a GSOCK_CONNECTION
+     * event will be generated, if enabled.
+     */
+    if ((err == EINPROGRESS) && (sck->m_non_blocking))
+    {
+      sck->m_error = GSOCK_WOULDBLOCK;
+      sck->m_establishing = TRUE;
+      fprintf(stderr, "Nonblocking connect in progress\n");
+
+      return GSOCK_WOULDBLOCK;
+    }
+
+    /* If connect failed with an error other than EINPROGRESS,
+     * then the call to GSocket_Connect has failed.
+     */
     close(sck->m_fd);
     sck->m_fd = -1;
-    switch (errno) {
-    case EINTR:
-    case ETIMEDOUT:
-      sck->m_error = GSOCK_TIMEDOUT;
-      break;
-    default:
-      sck->m_error = GSOCK_IOERR;
-      break;
-    }
+    sck->m_error = GSOCK_IOERR;
+
+    fprintf(stderr, "Connect failed (generic err)\n");
     return GSOCK_IOERR;
   }
-  
-  /* It is not a server */
-  sck->m_server       = FALSE;
-  sck->m_establishing = (errno == EINPROGRESS);
 
-  return (sck->m_establishing) ? GSOCK_WOULDBLOCK : GSOCK_NOERROR;
+  fprintf(stderr, "Connect OK\n");
+  return GSOCK_NOERROR;
 }
 
 /* Generic IO */
@@ -501,38 +530,75 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
 /* Like recv(), send(), ... */
 int GSocket_Read(GSocket *socket, char *buffer, int size)
 {
+  int ret;
+
   assert(socket != NULL);
 
-  if (socket->m_fd == -1 || socket->m_server) {
+  /* Reenable INPUT events */
+  _GSocket_Enable(socket, GSOCK_INPUT);
+
+  if (socket->m_fd == -1 || socket->m_server)
+  {
     socket->m_error = GSOCK_INVSOCK;
     return -1;
   }
 
-  /* Reenable GSOCK_INPUT event */
-  _GSocket_Enable(socket, GSOCK_INPUT);
+  if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT)
+    return -1;
 
   if (socket->m_stream)
-    return _GSocket_Recv_Stream(socket, buffer, size);
+    ret = _GSocket_Recv_Stream(socket, buffer, size);
   else
-    return _GSocket_Recv_Dgram(socket, buffer, size);
+    ret = _GSocket_Recv_Dgram(socket, buffer, size);
+    
+  if (ret == -1)
+  {
+    if (errno == EWOULDBLOCK)
+      socket->m_error = GSOCK_WOULDBLOCK;
+    else
+      socket->m_error = GSOCK_IOERR;
+  }
+  
+  return ret;
 }
 
 int GSocket_Write(GSocket *socket, const char *buffer,
                  int size)
 {
+  int ret;
+
   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 -1;
   }
 
-  _GSocket_Enable(socket, GSOCK_OUTPUT);
+  if (_GSocket_Output_Timeout(socket) == GSOCK_TIMEDOUT)
+    return -1;
 
   if (socket->m_stream)
-    return _GSocket_Send_Stream(socket, buffer, size);
+    ret = _GSocket_Send_Stream(socket, buffer, size);
   else
-    return _GSocket_Send_Dgram(socket, buffer, size);
+    ret = _GSocket_Send_Dgram(socket, buffer, size);
+    
+  if (ret == -1)
+  {
+    if (errno == EWOULDBLOCK)
+      socket->m_error = GSOCK_WOULDBLOCK;
+    else
+      socket->m_error = GSOCK_IOERR;
+
+    /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect
+     * in MSW). Once the first OUTPUT event is received, users can assume
+     * that the socket is writable until a read operation fails. Only then
+     * will further OUTPUT events be posted.
+     */
+    _GSocket_Enable(socket, GSOCK_OUTPUT);
+  }
+  
+  return ret;
 }
 
 /* GSocket_Select:
@@ -544,62 +610,9 @@ int GSocket_Write(GSocket *socket, const char *buffer,
  */
 GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags)
 {
-  fd_set readfds, writefds, exceptfds;
-  struct timeval tv;
-  GSocketEventFlags mask;
-  int error, len;
-
   assert(socket != NULL);
 
-  if (socket->m_fd == -1)
-  {
-    socket->m_error = GSOCK_INVSOCK;
-    return FALSE;
-  }
-
-  FD_ZERO(&readfds);
-  FD_ZERO(&writefds);
-  FD_ZERO(&exceptfds);
-  FD_SET(socket->m_fd, &readfds);
-  FD_SET(socket->m_fd, &writefds);
-  FD_SET(socket->m_fd, &exceptfds);
-
-  tv.tv_sec = 0;
-  tv.tv_usec = 0;
-  select(socket->m_fd + 1, &readfds, &writefds, &exceptfds, &tv);
-
-  mask = 0;
-
-  /* If select() says that the socket is readable, then we have
-   * no way to distinguish if that means 'data available' (to
-   * recv) or 'incoming connection' (to accept). The same goes
-   * for writability: we cannot distinguish between 'you can
-   * send data' and 'connection request completed'. So we will
-   * assume the following: if the flag was set upon entry,
-   * that means that the event was possible.
-   */
-  if (FD_ISSET(socket->m_fd, &readfds))
-  {
-    mask |= (flags & GSOCK_CONNECTION_FLAG);
-    mask |= (flags & GSOCK_INPUT_FLAG);
-  }
-  if (FD_ISSET(socket->m_fd, &writefds))
-  {
-    if (socket->m_establishing)
-    {
-      getsockopt(socket->m_fd, SOL_SOCKET, SO_ERROR, &error, &len);
-
-      if (error)
-        mask |= (flags & GSOCK_LOST_FLAG);
-      else
-        mask |= (flags & GSOCK_CONNECTION_FLAG);
-    }
-    mask |= (flags & GSOCK_OUTPUT_FLAG);
-  }
-  if (FD_ISSET(socket->m_fd, &exceptfds))
-    mask |= (flags & GSOCK_LOST_FLAG);
-
-  return mask;
+  return (flags & socket->m_detected);
 }
 
 /* Flags */
@@ -613,9 +626,6 @@ void GSocket_SetNonBlocking(GSocket *socket, bool non_block)
   assert(socket != NULL);
 
   socket->m_non_blocking = non_block;
-
-  if (socket->m_fd != -1)
-    ioctl(socket->m_fd, FIONBIO, &non_block);
 }
 
 /* GSocket_SetTimeout:
@@ -670,17 +680,16 @@ void GSocket_SetCallback(GSocket *socket, GSocketEventFlags flags,
 {
   int count;
 
-  assert (socket != NULL);
+  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 ((flags & (1 << count)) != 0) {
+  for (count = 0; count < GSOCK_MAX_EVENT; count++)
+  {
+    if ((flags & (1 << count)) != 0)
+    {
       socket->m_cbacks[count] = callback;
       socket->m_data[count] = cdata;
     }
   }
-  _GSocket_Configure_Callbacks(socket);
 }
 
 /* GSocket_UnsetCallback:
@@ -693,44 +702,85 @@ void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags flags)
 
   assert(socket != NULL);
 
-  for (count=0;count<GSOCK_MAX_EVENT;count++) {
-    if ((flags & (1 << count)) != 0) {
+  for (count = 0; count < GSOCK_MAX_EVENT; count++)
+  {
+    if ((flags & (1 << count)) != 0)
+    {
       socket->m_cbacks[count] = NULL;
+      socket->m_data[count] = NULL;
     }
   }
-  _GSocket_Configure_Callbacks(socket);
 }
 
-#define CALL_CALLBACK(socket, event)                                \
-if (socket->m_iocalls[event] && socket->m_cbacks[event]) {          \
-  _GSocket_Disable(socket, event);                                  \
-  socket->m_cbacks[event](socket, event, socket->m_data[event]);    \
+#define CALL_CALLBACK(socket, event) {                                  \
+  _GSocket_Disable(socket, event);                                      \
+  if (socket->m_cbacks[event])                                          \
+    socket->m_cbacks[event](socket, event, socket->m_data[event]);      \
 }
 
+
 void _GSocket_Enable(GSocket *socket, GSocketEvent event)
 {
-  socket->m_iocalls[event] = TRUE;
-  if (socket->m_cbacks[event])
-    _GSocket_Install_Callback(socket, event);
+  socket->m_detected &= ~(1 << event);
+  _GSocket_Install_Callback(socket, event);
 }
 
 void _GSocket_Disable(GSocket *socket, GSocketEvent event)
 {
-  socket->m_iocalls[event] = FALSE;
-  if (socket->m_cbacks[event])
-    _GSocket_Uninstall_Callback(socket, event);
+  socket->m_detected |= (1 << event);
+  _GSocket_Uninstall_Callback(socket, event);
 }
 
-void _GSocket_Configure_Callbacks(GSocket *socket)
+/* _GSocket_Input_Timeout:
+ *  For blocking sockets, wait until data is available or
+ *  until timeout ellapses.
+ */
+GSocketError _GSocket_Input_Timeout(GSocket *socket)
 {
-  int count;
-  for (count=0;count<GSOCK_MAX_EVENT;count++) {
-    if ((socket->m_cbacks[count]) != NULL) {
-      _GSocket_Enable(socket, count);
-    } else {
-      _GSocket_Disable(socket, count);
+  struct timeval tv;
+  fd_set readfds;
+
+  /* Linux select() will overwrite the struct on return */
+  tv.tv_sec  = (socket->m_timeout / 1000);
+  tv.tv_usec = (socket->m_timeout % 1000) * 1000;
+
+  if (!socket->m_non_blocking)
+  {
+    FD_ZERO(&readfds);
+    FD_SET(socket->m_fd, &readfds);
+    if (select(socket->m_fd + 1, &readfds, NULL, NULL, &tv) == 0)
+    {
+      socket->m_error = GSOCK_TIMEDOUT;
+      return GSOCK_TIMEDOUT;
     }
   }
+  return GSOCK_NOERROR;
+}
+
+/* _GSocket_Output_Timeout:
+ *  For blocking sockets, wait until data can be sent without
+ *  blocking or until timeout ellapses.
+ */
+GSocketError _GSocket_Output_Timeout(GSocket *socket)
+{
+  struct timeval tv;
+  fd_set writefds;
+
+  /* Linux select() will overwrite the struct on return */
+  tv.tv_sec  = (socket->m_timeout / 1000);
+  tv.tv_usec = (socket->m_timeout % 1000) * 1000;
+
+  if (!socket->m_non_blocking)
+  {
+    FD_ZERO(&writefds);
+    FD_SET(socket->m_fd, &writefds);
+    if (select(socket->m_fd + 1, NULL, &writefds, NULL, &tv) == 0)
+    {
+      socket->m_error = GSOCK_TIMEDOUT;
+      return GSOCK_TIMEDOUT;
+    }
+  }
+  return GSOCK_NOERROR;
 }
 
 int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
@@ -738,24 +788,9 @@ 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 != 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;
 }
 
@@ -769,33 +804,25 @@ 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 != EWOULDBLOCK && errno != EINTR && errno != ETIMEDOUT) {
-    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;
+
+  if (ret == -1)
     return -1;
-  }
 
   /* Translate a system address into a GSocket address */
-  if (!socket->m_peer) {
+  if (!socket->m_peer)
+  {
     socket->m_peer = GAddress_new();
-    if (!socket->m_peer) {
+    if (!socket->m_peer)
+    {
       socket->m_error = GSOCK_MEMERR;
       return -1;
     }
   }
   err = _GAddress_translate_from(socket->m_peer, &from, fromlen);
-  if (err != GSOCK_NOERROR) {
+  if (err != GSOCK_NOERROR)
+  {
     GAddress_destroy(socket->m_peer);
     socket->m_peer  = NULL;
     socket->m_error = err;
@@ -811,22 +838,9 @@ int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size)
   GSocketError err;
 
   MASK_SIGNAL();
-  ENABLE_TIMEOUT(socket);
   ret = send(socket->m_fd, buffer, size, 0);
-  DISABLE_TIMEOUT(socket);
   UNMASK_SIGNAL();
-  if (ret == -1 && errno != EWOULDBLOCK && errno != ETIMEDOUT && 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;
 }
 
@@ -848,23 +862,12 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size)
   }
 
   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 != EWOULDBLOCK) {
-    socket->m_error = GSOCK_IOERR;
-    return -1;
-  }
-  if (errno == EWOULDBLOCK) {
-    socket->m_error = GSOCK_WOULDBLOCK;
-    return -1;
-  }
-
   return ret;
 }
 
@@ -873,17 +876,22 @@ void _GSocket_Detected_Read(GSocket *socket)
   char c;
   int ret;
 
-  if (socket->m_stream) {
+  if (socket->m_stream)
+  {
     ret = recv(socket->m_fd, &c, 1, MSG_PEEK);
 
-    if (ret < 0 && socket->m_server) {
+    if (ret < 0 && socket->m_server)
+    {
       CALL_CALLBACK(socket, GSOCK_CONNECTION);
       return;
     }
 
-    if (ret > 0) {
+    if (ret > 0)
+    {
       CALL_CALLBACK(socket, GSOCK_INPUT);
-    } else {
+    }
+    else
+    {
       CALL_CALLBACK(socket, GSOCK_LOST);
     }
   }
@@ -891,23 +899,33 @@ void _GSocket_Detected_Read(GSocket *socket)
 
 void _GSocket_Detected_Write(GSocket *socket)
 {
-  if (socket->m_establishing) {
+  if (socket->m_establishing && !socket->m_server)
+  {
     int error, len;
 
-    len = sizeof(error);
-
     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;
+    len = sizeof(error);
+    getsockopt(socket->m_fd, SOL_SOCKET, SO_ERROR, &error, &len);
 
-    CALL_CALLBACK(socket, GSOCK_CONNECTION);
-  } else
+    if (error)
+    {
+      CALL_CALLBACK(socket, GSOCK_LOST);
+    }
+    else
+    {
+      CALL_CALLBACK(socket, 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(socket, GSOCK_OUTPUT);
+    }
+  }
+  else
+  {
     CALL_CALLBACK(socket, GSOCK_OUTPUT);
+  }
 }
 
 /*