]> git.saurik.com Git - wxWidgets.git/commitdiff
alternative direct CFSocket implementation, not yet for production use
authorStefan Csomor <csomor@advancedconcepts.ch>
Sun, 18 Apr 2004 16:59:52 +0000 (16:59 +0000)
committerStefan Csomor <csomor@advancedconcepts.ch>
Sun, 18 Apr 2004 16:59:52 +0000 (16:59 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@26862 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/mac/carbon/cfsocket.cpp [new file with mode: 0644]

diff --git a/src/mac/carbon/cfsocket.cpp b/src/mac/carbon/cfsocket.cpp
new file mode 100644 (file)
index 0000000..480beda
--- /dev/null
@@ -0,0 +1,2286 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:       socket.cpp
+// Purpose:    Socket handler classes
+// Authors:    Guilhem Lavaux, Guillermo Rodriguez Garcia
+// Created:    April 1997
+// Copyright:  (C) 1999-1997, Guilhem Lavaux
+//             (C) 2000-1999, Guillermo Rodriguez Garcia
+// RCS_ID:     $Id$
+// License:    see wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ==========================================================================
+// Declarations
+// ==========================================================================
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma implementation "socket.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#if wxUSE_SOCKETS
+
+#include "wx/app.h"
+#include "wx/apptrait.h"
+#include "wx/defs.h"
+#include "wx/object.h"
+#include "wx/string.h"
+#include "wx/timer.h"
+#include "wx/utils.h"
+#include "wx/module.h"
+#include "wx/log.h"
+#include "wx/intl.h"
+#include "wx/event.h"
+
+#include "wx/sckaddr.h"
+#include "wx/socket.h"
+#include "wx/mac/carbon/private.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#define HAVE_INET_ATON
+
+// DLL options compatibility check:
+#include "wx/build.h"
+WX_CHECK_BUILD_OPTIONS("wxNet")
+
+// --------------------------------------------------------------------------
+// macros and constants
+// --------------------------------------------------------------------------
+
+// discard buffer
+#define MAX_DISCARD_SIZE (10 * 1024)
+
+#ifndef INVALID_SOCKET
+#define INVALID_SOCKET -1
+#endif
+
+// what to do within waits: we have 2 cases: from the main thread itself we
+// have to call wxYield() to let the events (including the GUI events and the
+// low-level (not wxWindows) events from GSocket) be processed. From another
+// thread it is enough to just call wxThread::Yield() which will give away the
+// rest of our time slice: the explanation is that the events will be processed
+// by the main thread anyhow, without calling wxYield(), but we don't want to
+// eat the CPU time uselessly while sitting in the loop waiting for the data
+#if wxUSE_THREADS
+    #define PROCESS_EVENTS()        \
+    {                               \
+        if ( wxThread::IsMain() )   \
+            wxYield();              \
+        else                        \
+            wxThread::Yield();      \
+    }
+#else // !wxUSE_THREADS
+    #define PROCESS_EVENTS() wxYield()
+#endif // wxUSE_THREADS/!wxUSE_THREADS
+
+#define wxTRACE_Socket _T("wxSocket")
+
+// --------------------------------------------------------------------------
+// wxWin macros
+// --------------------------------------------------------------------------
+
+IMPLEMENT_CLASS(wxSocketBase, wxObject)
+IMPLEMENT_CLASS(wxSocketServer, wxSocketBase)
+IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)
+IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)
+IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)
+
+// --------------------------------------------------------------------------
+// private classes
+// --------------------------------------------------------------------------
+
+class wxSocketState : public wxObject
+{
+public:
+  wxSocketFlags            m_flags;
+  wxSocketEventFlags       m_eventmask;
+  bool                     m_notify;
+  void                    *m_clientData;
+
+public:
+  wxSocketState() : wxObject() {}
+
+    DECLARE_NO_COPY_CLASS(wxSocketState)
+};
+
+struct _GSocket
+{
+  CFSocketNativeHandle m_fd;
+  GAddress *m_local;
+  GAddress *m_peer;
+  GSocketError m_error;
+
+  int m_non_blocking;
+  int m_server;
+  int m_stream;
+  int m_oriented;
+  int m_establishing;
+  unsigned long m_timeout;
+
+
+  /* Callbacks */
+  GSocketEventFlags m_detected;
+  GSocketCallback m_cbacks[GSOCK_MAX_EVENT];
+  char *m_data[GSOCK_MAX_EVENT];
+
+  CFSocketRef           m_cfSocket;
+  CFRunLoopSourceRef    m_runLoopSource;
+  CFReadStreamRef       m_readStream ;
+  CFWriteStreamRef      m_writeStream ;
+} ;
+
+struct _GAddress
+{
+  struct sockaddr *m_addr;
+  size_t m_len;
+
+  GAddressType m_family;
+  int m_realfamily;
+
+  GSocketError m_error;
+  int somethingElse ;
+};
+
+void wxMacCFSocketCallback(CFSocketRef s, CFSocketCallBackType callbackType,
+                         CFDataRef address, const void* data, void* info) ;
+void _GSocket_Enable(GSocket *socket, GSocketEvent event) ;
+void _GSocket_Disable(GSocket *socket, GSocketEvent event) ;
+
+// ==========================================================================
+// wxSocketBase
+// ==========================================================================
+
+// --------------------------------------------------------------------------
+// Initialization and shutdown
+// --------------------------------------------------------------------------
+
+// FIXME-MT: all this is MT-unsafe, of course, we should protect all accesses
+//           to m_countInit with a crit section
+size_t wxSocketBase::m_countInit = 0;
+
+bool wxSocketBase::IsInitialized()
+{
+    return m_countInit > 0;
+}
+
+bool wxSocketBase::Initialize()
+{
+    if ( !m_countInit++ )
+    {
+#if 0
+        wxAppTraits *traits = wxAppConsole::GetInstance() ?
+                              wxAppConsole::GetInstance()->GetTraits() : NULL;
+        GSocketGUIFunctionsTable *functions = 
+            traits ? traits->GetSocketGUIFunctionsTable() : NULL;
+        GSocket_SetGUIFunctions(functions);
+        
+        if ( !GSocket_Init() )
+        {
+            m_countInit--;
+
+            return FALSE;
+        }
+#endif
+    }
+
+    return TRUE;
+}
+
+void wxSocketBase::Shutdown()
+{
+    // we should be initialized
+    wxASSERT_MSG( m_countInit, _T("extra call to Shutdown()") );
+    if ( !--m_countInit )
+    {
+#if 0
+        GSocket_Cleanup();
+#endif
+    }
+}
+
+// --------------------------------------------------------------------------
+// Ctor and dtor
+// --------------------------------------------------------------------------
+
+void wxSocketBase::Init()
+{
+  m_socket       = NULL;
+  m_type         = wxSOCKET_UNINIT;
+
+  // state
+  m_flags        = 0;
+  m_connected    =
+  m_establishing =
+  m_reading      =
+  m_writing      =
+  m_error        = FALSE;
+  m_lcount       = 0;
+  m_timeout      = 600;
+  m_beingDeleted = FALSE;
+
+  // pushback buffer
+  m_unread       = NULL;
+  m_unrd_size    = 0;
+  m_unrd_cur     = 0;
+
+  // events
+  m_id           = -1;
+  m_handler      = NULL;
+  m_clientData   = NULL;
+  m_notify       = FALSE;
+  m_eventmask    = 0;
+
+  if ( !IsInitialized() )
+  {
+      // this Initialize() will be undone by wxSocketModule::OnExit(), all the
+      // other calls to it should be matched by a call to Shutdown()
+      Initialize();
+  }
+}
+
+wxSocketBase::wxSocketBase()
+{
+  Init();
+}
+
+wxSocketBase::wxSocketBase(wxSocketFlags flags, wxSocketType type)
+{
+  Init();
+
+  m_flags = flags;
+  m_type  = type;
+}
+
+wxSocketBase::~wxSocketBase()
+{
+  // Just in case the app called Destroy() *and* then deleted
+  // the socket immediately: don't leave dangling pointers.
+  wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
+  if ( traits )
+      traits->RemoveFromPendingDelete(this);
+
+  // Shutdown and close the socket
+  if (!m_beingDeleted)
+    Close();
+
+  // Destroy the GSocket object
+  if (m_socket)
+  {
+    GSocket_destroy(m_socket);
+  }
+
+  // Free the pushback buffer
+  if (m_unread)
+    free(m_unread);
+}
+
+bool wxSocketBase::Destroy()
+{
+  // Delayed destruction: the socket will be deleted during the next
+  // idle loop iteration. This ensures that all pending events have
+  // been processed.
+  m_beingDeleted = TRUE;
+
+  // Shutdown and close the socket
+  Close();
+
+  // Supress events from now on
+  Notify(FALSE);
+
+  // schedule this object for deletion
+  wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
+  if ( traits )
+  {
+      // let the traits object decide what to do with us
+      traits->ScheduleForDestroy(this);
+  }
+  else // no app or no traits
+  {
+      // in wxBase we might have no app object at all, don't leak memory
+      delete this;
+  }
+
+  return TRUE;
+}
+
+// --------------------------------------------------------------------------
+// Basic IO calls
+// --------------------------------------------------------------------------
+
+// The following IO operations update m_error and m_lcount:
+// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard}
+//
+// TODO: Should Connect, Accept and AcceptWith update m_error?
+
+bool wxSocketBase::Close()
+{
+  // Interrupt pending waits
+  InterruptWait();
+
+  if (m_socket)
+  {
+    GSocket_Shutdown(m_socket);
+  }
+
+  m_connected = FALSE;
+  m_establishing = FALSE;
+  return TRUE;
+}
+
+wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes)
+{
+  // Mask read events
+  m_reading = TRUE;
+
+  m_lcount = _Read(buffer, nbytes);
+
+  // If in wxSOCKET_WAITALL mode, all bytes should have been read.
+  if (m_flags & wxSOCKET_WAITALL)
+    m_error = (m_lcount != nbytes);
+  else
+    m_error = (m_lcount == 0);
+
+  // Allow read events from now on
+  m_reading = FALSE;
+
+  return *this;
+}
+
+wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes)
+{
+  int total = 0;
+
+  // Try the pushback buffer first
+  total = GetPushback(buffer, nbytes, FALSE);
+  nbytes -= total;
+  buffer  = (char *)buffer + total;
+
+  // Return now in one of the following cases:
+  // - the socket is invalid,
+  // - we got all the data,
+  // - we got *some* data and we are not using wxSOCKET_WAITALL.
+  if ( !m_socket ||
+       !nbytes ||
+       ((total != 0) && !(m_flags & wxSOCKET_WAITALL)) )
+    return total;
+
+  // Possible combinations (they are checked in this order)
+  // wxSOCKET_NOWAIT
+  // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK)
+  // wxSOCKET_BLOCK
+  // wxSOCKET_NONE
+  //
+
+  int ret;
+  if (m_flags & wxSOCKET_NOWAIT)
+  {
+    GSocket_SetNonBlocking(m_socket, 1);
+    ret = GSocket_Read(m_socket, (char *)buffer, nbytes);
+    GSocket_SetNonBlocking(m_socket, 0);
+
+    if (ret > 0)
+      total += ret;
+  }
+  else
+  {
+    bool more = TRUE;
+
+    while (more)
+    {
+      if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() )
+        break;
+
+      ret = GSocket_Read(m_socket, (char *)buffer, nbytes);
+
+      if (ret > 0)
+      {
+        total  += ret;
+        nbytes -= ret;
+        buffer  = (char *)buffer + ret;
+      }
+
+      // If we got here and wxSOCKET_WAITALL is not set, we can leave
+      // now. Otherwise, wait until we recv all the data or until there
+      // is an error.
+      //
+      more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL));
+    }
+  }
+
+  return total;
+}
+
+wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes)
+{
+  wxUint32 len, len2, sig, total;
+  bool error;
+  int old_flags;
+  struct
+  {
+    unsigned char sig[4];
+    unsigned char len[4];
+  } msg;
+
+  // Mask read events
+  m_reading = TRUE;
+
+  total = 0;
+  error = TRUE;
+  old_flags = m_flags;
+  SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
+
+  if (_Read(&msg, sizeof(msg)) != sizeof(msg))
+    goto exit;
+
+  sig = (wxUint32)msg.sig[0];
+  sig |= (wxUint32)(msg.sig[1] << 8);
+  sig |= (wxUint32)(msg.sig[2] << 16);
+  sig |= (wxUint32)(msg.sig[3] << 24);
+
+  if (sig != 0xfeeddead)
+  {
+    wxLogWarning(_("wxSocket: invalid signature in ReadMsg."));
+    goto exit;
+  }
+
+  len = (wxUint32)msg.len[0];
+  len |= (wxUint32)(msg.len[1] << 8);
+  len |= (wxUint32)(msg.len[2] << 16);
+  len |= (wxUint32)(msg.len[3] << 24);
+
+  if (len > nbytes)
+  {
+    len2 = len - nbytes;
+    len = nbytes;
+  }
+  else
+    len2 = 0;
+
+  // Don't attemp to read if the msg was zero bytes long.
+  if (len)
+  {
+    total = _Read(buffer, len);
+
+    if (total != len)
+      goto exit;
+  }
+  if (len2)
+  {
+    char *discard_buffer = new char[MAX_DISCARD_SIZE];
+    long discard_len;
+
+    // NOTE: discarded bytes don't add to m_lcount.
+    do
+    {
+      discard_len = ((len2 > MAX_DISCARD_SIZE)? MAX_DISCARD_SIZE : len2);
+      discard_len = _Read(discard_buffer, (wxUint32)discard_len);
+      len2 -= (wxUint32)discard_len;
+    }
+    while ((discard_len > 0) && len2);
+
+    delete [] discard_buffer;
+
+    if (len2 != 0)
+      goto exit;
+  }
+  if (_Read(&msg, sizeof(msg)) != sizeof(msg))
+    goto exit;
+
+  sig = (wxUint32)msg.sig[0];
+  sig |= (wxUint32)(msg.sig[1] << 8);
+  sig |= (wxUint32)(msg.sig[2] << 16);
+  sig |= (wxUint32)(msg.sig[3] << 24);
+
+  if (sig != 0xdeadfeed)
+  {
+    wxLogWarning(_("wxSocket: invalid signature in ReadMsg."));
+    goto exit;
+  }
+
+  // everything was OK
+  error = FALSE;
+
+exit:
+  m_error = error;
+  m_lcount = total;
+  m_reading = FALSE;
+  SetFlags(old_flags);
+
+  return *this;
+}
+
+wxSocketBase& wxSocketBase::Peek(void* buffer, wxUint32 nbytes)
+{
+  // Mask read events
+  m_reading = TRUE;
+
+  m_lcount = _Read(buffer, nbytes);
+  Pushback(buffer, m_lcount);
+
+  // If in wxSOCKET_WAITALL mode, all bytes should have been read.
+  if (m_flags & wxSOCKET_WAITALL)
+    m_error = (m_lcount != nbytes);
+  else
+    m_error = (m_lcount == 0);
+
+  // Allow read events again
+  m_reading = FALSE;
+
+  return *this;
+}
+
+wxSocketBase& wxSocketBase::Write(const void *buffer, wxUint32 nbytes)
+{
+  // Mask write events
+  m_writing = TRUE;
+
+  m_lcount = _Write(buffer, nbytes);
+
+  // If in wxSOCKET_WAITALL mode, all bytes should have been written.
+  if (m_flags & wxSOCKET_WAITALL)
+    m_error = (m_lcount != nbytes);
+  else
+    m_error = (m_lcount == 0);
+
+  // Allow write events again
+  m_writing = FALSE;
+
+  return *this;
+}
+
+wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes)
+{
+  wxUint32 total = 0;
+
+  // If the socket is invalid or parameters are ill, return immediately
+  if (!m_socket || !buffer || !nbytes)
+    return 0;
+
+  // Possible combinations (they are checked in this order)
+  // wxSOCKET_NOWAIT
+  // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK)
+  // wxSOCKET_BLOCK
+  // wxSOCKET_NONE
+  //
+  int ret;
+  if (m_flags & wxSOCKET_NOWAIT)
+  {
+    GSocket_SetNonBlocking(m_socket, 1);
+    ret = GSocket_Write(m_socket, (const char *)buffer, nbytes);
+    GSocket_SetNonBlocking(m_socket, 0);
+
+    if (ret > 0)
+      total = ret;
+  }
+  else
+  {
+    bool more = TRUE;
+
+    while (more)
+    {
+      if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() )
+        break;
+
+      ret = GSocket_Write(m_socket, (const char *)buffer, nbytes);
+
+      if (ret > 0)
+      {
+        total  += ret;
+        nbytes -= ret;
+        buffer  = (const char *)buffer + ret;
+      }
+
+      // If we got here and wxSOCKET_WAITALL is not set, we can leave
+      // now. Otherwise, wait until we send all the data or until there
+      // is an error.
+      //
+      more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL));
+    }
+  }
+
+  return total;
+}
+
+wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes)
+{
+  wxUint32 total;
+  bool error;
+  struct
+  {
+    unsigned char sig[4];
+    unsigned char len[4];
+  } msg;
+
+  // Mask write events
+  m_writing = TRUE;
+
+  error = TRUE;
+  total = 0;
+  SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
+
+  msg.sig[0] = (unsigned char) 0xad;
+  msg.sig[1] = (unsigned char) 0xde;
+  msg.sig[2] = (unsigned char) 0xed;
+  msg.sig[3] = (unsigned char) 0xfe;
+
+  msg.len[0] = (unsigned char) (nbytes & 0xff);
+  msg.len[1] = (unsigned char) ((nbytes >> 8) & 0xff);
+  msg.len[2] = (unsigned char) ((nbytes >> 16) & 0xff);
+  msg.len[3] = (unsigned char) ((nbytes >> 24) & 0xff);
+
+  if (_Write(&msg, sizeof(msg)) < sizeof(msg))
+    goto exit;
+
+  total = _Write(buffer, nbytes);
+
+  if (total < nbytes)
+    goto exit;
+
+  msg.sig[0] = (unsigned char) 0xed;
+  msg.sig[1] = (unsigned char) 0xfe;
+  msg.sig[2] = (unsigned char) 0xad;
+  msg.sig[3] = (unsigned char) 0xde;
+  msg.len[0] = msg.len[1] = msg.len[2] = msg.len[3] = (char) 0;
+
+  if ((_Write(&msg, sizeof(msg))) < sizeof(msg))
+    goto exit;
+
+  // everything was OK
+  error = FALSE;
+
+exit:
+  m_error = error;
+  m_lcount = total;
+  m_writing = FALSE;
+
+  return *this;
+}
+
+wxSocketBase& wxSocketBase::Unread(const void *buffer, wxUint32 nbytes)
+{
+  if (nbytes != 0)
+    Pushback(buffer, nbytes);
+
+  m_error = FALSE;
+  m_lcount = nbytes;
+
+  return *this;
+}
+
+wxSocketBase& wxSocketBase::Discard()
+{
+  char *buffer = new char[MAX_DISCARD_SIZE];
+  wxUint32 ret;
+  wxUint32 total = 0;
+
+  // Mask read events
+  m_reading = TRUE;
+
+  SetFlags(wxSOCKET_NOWAIT);
+
+  do
+  {
+    ret = _Read(buffer, MAX_DISCARD_SIZE);
+    total += ret;
+  }
+  while (ret == MAX_DISCARD_SIZE);
+
+  delete[] buffer;
+  m_lcount = total;
+  m_error  = FALSE;
+
+  // Allow read events again
+  m_reading = FALSE;
+
+  return *this;
+}
+
+// --------------------------------------------------------------------------
+// Wait functions
+// --------------------------------------------------------------------------
+
+// All Wait functions poll the socket using GSocket_Select() to
+// check for the specified combination of conditions, until one
+// of these conditions become true, an error occurs, or the
+// timeout elapses. The polling loop calls PROCESS_EVENTS(), so
+// this won't block the GUI.
+
+bool wxSocketBase::_Wait(long seconds,
+                         long milliseconds,
+                         wxSocketEventFlags flags)
+{  
+
+  GSocketEventFlags result;
+  long timeout;
+
+  // Set this to TRUE to interrupt ongoing waits
+  m_interrupt = FALSE;
+
+  // Check for valid socket
+  if (!m_socket)
+    return FALSE;
+
+  // Check for valid timeout value.
+  if (seconds != -1)
+    timeout = seconds * 1000 + milliseconds;
+  else
+    timeout = m_timeout * 1000;
+
+#if !defined(wxUSE_GUI) || !wxUSE_GUI
+  GSocket_SetTimeout(m_socket, timeout);
+#endif 
+
+  // Wait in an active polling loop.
+  //
+  // NOTE: We duplicate some of the code in OnRequest, but this doesn't
+  //   hurt. It has to be here because the (GSocket) event might arrive
+  //   a bit delayed, and it has to be in OnRequest as well because we
+  //   don't know whether the Wait functions are being used.
+  //
+  // Do this at least once (important if timeout == 0, when
+  // we are just polling). Also, if just polling, do not yield.
+
+  wxStopWatch chrono;
+  bool done = FALSE;
+
+  while (!done)
+  {
+    result = GSocket_Select(m_socket, flags | GSOCK_LOST_FLAG);
+
+    // Incoming connection (server) or connection established (client)
+    if (result & GSOCK_CONNECTION_FLAG)
+    {
+      m_connected = TRUE;
+      m_establishing = FALSE;
+      return TRUE;
+    }
+
+    // Data available or output buffer ready
+    if ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG))
+    {
+      return TRUE;
+    }
+
+    // Connection lost
+    if (result & GSOCK_LOST_FLAG)
+    {
+      m_connected = FALSE;
+      m_establishing = FALSE;
+      return (flags & GSOCK_LOST_FLAG) != 0;
+    }
+
+    // Wait more?
+    if ((!timeout) || (chrono.Time() > timeout) || (m_interrupt))
+      done = TRUE;
+    else
+      PROCESS_EVENTS();
+  }
+
+  return FALSE;
+}
+
+bool wxSocketBase::Wait(long seconds, long milliseconds)
+{
+  return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG |
+                                      GSOCK_OUTPUT_FLAG |
+                                      GSOCK_CONNECTION_FLAG |
+                                      GSOCK_LOST_FLAG);
+}
+
+bool wxSocketBase::WaitForRead(long seconds, long milliseconds)
+{
+  // Check pushback buffer before entering _Wait
+  if (m_unread)
+    return TRUE;
+
+  // Note that GSOCK_INPUT_LOST has to be explicitly passed to
+  // _Wait becuase of the semantics of WaitForRead: a return
+  // value of TRUE means that a GSocket_Read call will return
+  // immediately, not that there is actually data to read.
+
+  return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG |
+                                      GSOCK_LOST_FLAG);
+}
+
+bool wxSocketBase::WaitForWrite(long seconds, long milliseconds)
+{
+  return _Wait(seconds, milliseconds, GSOCK_OUTPUT_FLAG);
+}
+
+bool wxSocketBase::WaitForLost(long seconds, long milliseconds)
+{
+  return _Wait(seconds, milliseconds, GSOCK_LOST_FLAG);
+}
+
+// --------------------------------------------------------------------------
+// Miscellaneous
+// --------------------------------------------------------------------------
+
+//
+// Get local or peer address
+//
+
+bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const
+{
+  GAddress *peer;
+
+  if (!m_socket)
+    return FALSE;
+
+  peer = GSocket_GetPeer(m_socket);
+
+    // copying a null address would just trigger an assert anyway
+
+  if (!peer)
+    return FALSE;
+
+  addr_man.SetAddress(peer);
+  GAddress_destroy(peer);
+
+  return TRUE;
+}
+
+bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const
+{
+#if 0
+  GAddress *local;
+
+  if (!m_socket)
+    return FALSE;
+
+  local = GSocket_GetLocal(m_socket);
+  addr_man.SetAddress(local);
+  GAddress_destroy(local);
+#endif
+  return TRUE;
+}
+
+//
+// Save and restore socket state
+//
+
+void wxSocketBase::SaveState()
+{
+  wxSocketState *state;
+
+  state = new wxSocketState();
+
+  state->m_flags      = m_flags;
+  state->m_notify     = m_notify;
+  state->m_eventmask  = m_eventmask;
+  state->m_clientData = m_clientData;
+
+  m_states.Append(state);
+}
+
+void wxSocketBase::RestoreState()
+{
+  wxList::compatibility_iterator node;
+  wxSocketState *state;
+
+  node = m_states.GetLast();
+  if (!node)
+    return;
+
+  state = (wxSocketState *)node->GetData();
+
+  m_flags      = state->m_flags;
+  m_notify     = state->m_notify;
+  m_eventmask  = state->m_eventmask;
+  m_clientData = state->m_clientData;
+  
+  m_states.Erase(node);
+  delete state;
+}
+
+//
+// Timeout and flags
+//
+
+void wxSocketBase::SetTimeout(long seconds)
+{
+  m_timeout = seconds;
+
+#if 0
+  if (m_socket)
+    GSocket_SetTimeout(m_socket, m_timeout * 1000);
+#endif
+}
+
+void wxSocketBase::SetFlags(wxSocketFlags flags)
+{
+  m_flags = flags;
+}
+
+
+// --------------------------------------------------------------------------
+// Event handling
+// --------------------------------------------------------------------------
+
+// A note on how events are processed, which is probably the most
+// difficult thing to get working right while keeping the same API
+// and functionality for all platforms.
+//
+// When GSocket detects an event, it calls wx_socket_callback, which in
+// turn just calls wxSocketBase::OnRequest in the corresponding wxSocket
+// object. OnRequest does some housekeeping, and if the event is to be
+// propagated to the user, it creates a new wxSocketEvent object and
+// posts it. The event is not processed immediately, but delayed with
+// AddPendingEvent instead. This is necessary in order to decouple the
+// event processing from wx_socket_callback; otherwise, subsequent IO
+// calls made from the user event handler would fail, as gtk callbacks
+// are not reentrant.
+//
+// Note that, unlike events, user callbacks (now deprecated) are _not_
+// decoupled from wx_socket_callback and thus they suffer from a variety
+// of problems. Avoid them where possible and use events instead.
+
+extern "C"
+void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket),
+                                    GSocketEvent notification,
+                                    char *cdata)
+{
+  wxSocketBase *sckobj = (wxSocketBase *)cdata;
+
+  sckobj->OnRequest((wxSocketNotify) notification);
+}
+
+void wxSocketBase::OnRequest(wxSocketNotify notification)
+{
+  // NOTE: We duplicate some of the code in _Wait, but this doesn't
+  //   hurt. It has to be here because the (GSocket) event might arrive
+  //   a bit delayed, and it has to be in _Wait as well because we don't
+  //   know whether the Wait functions are being used.
+
+  switch(notification)
+  {
+    case wxSOCKET_CONNECTION:
+      m_establishing = FALSE;
+      m_connected = TRUE;
+      break;
+
+    // If we are in the middle of a R/W operation, do not
+    // propagate events to users. Also, filter 'late' events
+    // which are no longer valid.
+
+    case wxSOCKET_INPUT:
+      if (m_reading || !GSocket_Select(m_socket, GSOCK_INPUT_FLAG))
+        return;
+      break;
+
+    case wxSOCKET_OUTPUT:
+      if (m_writing || !GSocket_Select(m_socket, GSOCK_OUTPUT_FLAG))
+        return;
+      break;
+
+    case wxSOCKET_LOST:
+      m_connected = FALSE;
+      m_establishing = FALSE;
+      break;
+
+    default:
+      break;
+  }
+
+  // Schedule the event
+
+  wxSocketEventFlags flag = 0;
+  wxUnusedVar(flag);
+  switch (notification)
+  {
+    case GSOCK_INPUT:      flag = GSOCK_INPUT_FLAG; break;
+    case GSOCK_OUTPUT:     flag = GSOCK_OUTPUT_FLAG; break;
+    case GSOCK_CONNECTION: flag = GSOCK_CONNECTION_FLAG; break;
+    case GSOCK_LOST:       flag = GSOCK_LOST_FLAG; break;
+    default:
+      wxLogWarning(_("wxSocket: unknown event!."));
+      return;
+  }
+
+  if (((m_eventmask & flag) == flag) && m_notify)
+  {
+    if (m_handler)
+    {
+      wxSocketEvent event(m_id);
+      event.m_event      = notification;
+      event.m_clientData = m_clientData;
+      event.SetEventObject(this);
+
+      m_handler->AddPendingEvent(event);
+    }
+  }
+}
+
+void wxSocketBase::Notify(bool notify)
+{
+  m_notify = notify;
+}
+
+void wxSocketBase::SetNotify(wxSocketEventFlags flags)
+{
+  m_eventmask = flags;
+}
+
+void wxSocketBase::SetEventHandler(wxEvtHandler& handler, int id)
+{
+  m_handler = &handler;
+  m_id      = id;
+}
+
+// --------------------------------------------------------------------------
+// Pushback buffer
+// --------------------------------------------------------------------------
+
+void wxSocketBase::Pushback(const void *buffer, wxUint32 size)
+{
+  if (!size) return;
+
+  if (m_unread == NULL)
+    m_unread = malloc(size);
+  else
+  {
+    void *tmp;
+
+    tmp = malloc(m_unrd_size + size);
+    memcpy((char *)tmp + size, m_unread, m_unrd_size);
+    free(m_unread);
+
+    m_unread = tmp;
+  }
+
+  m_unrd_size += size;
+
+  memcpy(m_unread, buffer, size);
+}
+
+wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek)
+{
+  if (!m_unrd_size)
+    return 0;
+
+  if (size > (m_unrd_size-m_unrd_cur))
+    size = m_unrd_size-m_unrd_cur;
+
+  memcpy(buffer, (char *)m_unread + m_unrd_cur, size);
+
+  if (!peek)
+  {
+    m_unrd_cur += size;
+    if (m_unrd_size == m_unrd_cur)
+    {
+      free(m_unread);
+      m_unread = NULL;
+      m_unrd_size = 0;
+      m_unrd_cur  = 0;
+    }
+  }
+
+  return size;
+}
+
+
+// ==========================================================================
+// wxSocketServer
+// ==========================================================================
+
+// --------------------------------------------------------------------------
+// Ctor
+// --------------------------------------------------------------------------
+
+wxSocketServer::wxSocketServer(wxSockAddress& addr_man,
+                               wxSocketFlags flags)
+              : wxSocketBase(flags, wxSOCKET_SERVER)
+{
+    wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") );
+
+    m_socket = GSocket_new();
+
+    if (!m_socket)
+    {
+        wxLogTrace( wxTRACE_Socket, _T("*** GSocket_new failed") );
+        return;
+    }
+
+        // Setup the socket as server
+
+#if 0
+    GSocket_SetLocal(m_socket, addr_man.GetAddress());
+    if (GSocket_SetServer(m_socket) != GSOCK_NOERROR)
+    {
+        GSocket_destroy(m_socket);
+        m_socket = NULL;
+
+        wxLogTrace( wxTRACE_Socket, _T("*** GSocket_SetServer failed") );
+        return;
+    }
+
+    GSocket_SetTimeout(m_socket, m_timeout * 1000);
+    GSocket_SetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
+                                  GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
+                                  wx_socket_callback, (char *)this);
+#endif
+}
+
+// --------------------------------------------------------------------------
+// Accept
+// --------------------------------------------------------------------------
+
+bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait)
+{
+  GSocket *child_socket;
+
+  if (!m_socket)
+    return FALSE;
+
+  // If wait == FALSE, then the call should be nonblocking.
+  // When we are finished, we put the socket to blocking mode
+  // again.
+
+#if 0
+  if (!wait)
+    GSocket_SetNonBlocking(m_socket, 1);
+
+  child_socket = GSocket_WaitConnection(m_socket);
+
+  if (!wait)
+    GSocket_SetNonBlocking(m_socket, 0);
+
+  if (!child_socket)
+    return FALSE;
+
+  sock.m_type = wxSOCKET_BASE;
+  sock.m_socket = child_socket;
+  sock.m_connected = TRUE;
+
+  GSocket_SetTimeout(sock.m_socket, sock.m_timeout * 1000);
+  GSocket_SetCallback(sock.m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
+                                     GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
+                                     wx_socket_callback, (char *)&sock);
+#endif
+  return TRUE;
+}
+
+wxSocketBase *wxSocketServer::Accept(bool wait)
+{
+  wxSocketBase* sock = new wxSocketBase();
+
+  sock->SetFlags(m_flags);
+
+  if (!AcceptWith(*sock, wait))
+  {
+    sock->Destroy();
+    sock = NULL;
+  }
+
+  return sock;
+}
+
+bool wxSocketServer::WaitForAccept(long seconds, long milliseconds)
+{
+  return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG);
+}
+
+// ==========================================================================
+// wxSocketClient
+// ==========================================================================
+
+// --------------------------------------------------------------------------
+// Ctor and dtor
+// --------------------------------------------------------------------------
+
+wxSocketClient::wxSocketClient(wxSocketFlags flags)
+              : wxSocketBase(flags, wxSOCKET_CLIENT)
+{
+}
+
+wxSocketClient::~wxSocketClient()
+{
+}
+
+// --------------------------------------------------------------------------
+// Connect
+// --------------------------------------------------------------------------
+
+bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait)
+{
+  GSocketError err ;
+
+  if (m_socket)
+  {
+    // Shutdown and destroy the socket
+    Close();
+    GSocket_destroy(m_socket);
+  }
+
+  m_socket = GSocket_new();
+  m_connected = FALSE;
+  m_establishing = FALSE;
+
+  if (!m_socket)
+    return FALSE;
+
+  GSocket_SetTimeout(m_socket, m_timeout * 1000);
+  GSocket_SetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
+                                GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
+                                wx_socket_callback, (char *)this);
+
+  // If wait == FALSE, then the call should be nonblocking.
+  // When we are finished, we put the socket to blocking mode
+  // again.
+
+  if (!wait)
+    GSocket_SetNonBlocking(m_socket, 1);
+
+  GSocket_SetPeer(m_socket, addr_man.GetAddress());
+  err = GSocket_Connect(m_socket, GSOCK_STREAMED);
+
+  if (!wait)
+    GSocket_SetNonBlocking(m_socket, 0);
+
+  if (err != GSOCK_NOERROR)
+  {
+    if (err == GSOCK_WOULDBLOCK)
+      m_establishing = TRUE;
+
+    return FALSE;
+  }
+
+  m_connected = TRUE;
+  return TRUE;
+}
+
+bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds)
+{
+  if (m_connected)                      // Already connected
+    return TRUE;
+
+  if (!m_establishing || !m_socket)     // No connection in progress
+    return FALSE;
+
+  return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG |
+                                      GSOCK_LOST_FLAG);
+}
+
+// ==========================================================================
+// wxDatagramSocket
+// ==========================================================================
+
+/* NOTE: experimental stuff - might change */
+
+wxDatagramSocket::wxDatagramSocket( wxSockAddress& addr,
+                                    wxSocketFlags flags )
+                : wxSocketBase( flags, wxSOCKET_DATAGRAM )
+{
+#if 0
+  // Create the socket
+  m_socket = GSocket_new();
+
+  if(!m_socket)
+    return;
+
+  // Setup the socket as non connection oriented
+  GSocket_SetLocal(m_socket, addr.GetAddress());
+  if( GSocket_SetNonOriented(m_socket) != GSOCK_NOERROR )
+  {
+    GSocket_destroy(m_socket);
+    m_socket = NULL;
+    return;
+  }
+
+  // Initialize all stuff
+  m_connected = FALSE;
+  m_establishing = FALSE;
+  GSocket_SetTimeout( m_socket, m_timeout );
+  GSocket_SetCallback( m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
+                                 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
+                                 wx_socket_callback, (char*)this );
+#endif
+}
+
+wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr,
+                                              void* buf,
+                                              wxUint32 nBytes )
+{
+    Read(buf, nBytes);
+    GetPeer(addr);
+    return (*this);
+}
+
+wxDatagramSocket& wxDatagramSocket::SendTo( wxSockAddress& addr,
+                                            const void* buf,
+                                            wxUint32 nBytes )
+{
+    GSocket_SetPeer(m_socket, addr.GetAddress());
+    Write(buf, nBytes);
+    return (*this);
+}
+
+/*
+ * -------------------------------------------------------------------------
+ * GAddress
+ * -------------------------------------------------------------------------
+ */
+
+/* CHECK_ADDRESS verifies that the current address family is either
+ * GSOCK_NOFAMILY or GSOCK_*family*, and if it is GSOCK_NOFAMILY, it
+ * initalizes it to be a GSOCK_*family*. In other cases, it returns
+ * an appropiate error code.
+ *
+ * CHECK_ADDRESS_RETVAL does the same but returning 'retval' on error.
+ */
+#define CHECK_ADDRESS(address, family)                              \
+{                                                                   \
+  if (address->m_family == GSOCK_NOFAMILY)                          \
+    if (_GAddress_Init_##family(address) != GSOCK_NOERROR)          \
+      return address->m_error;                                      \
+  if (address->m_family != GSOCK_##family)                          \
+  {                                                                 \
+    address->m_error = GSOCK_INVADDR;                               \
+    return GSOCK_INVADDR;                                           \
+  }                                                                 \
+}
+
+#define CHECK_ADDRESS_RETVAL(address, family, retval)               \
+{                                                                   \
+  if (address->m_family == GSOCK_NOFAMILY)                          \
+    if (_GAddress_Init_##family(address) != GSOCK_NOERROR)          \
+      return retval;                                                \
+  if (address->m_family != GSOCK_##family)                          \
+  {                                                                 \
+    address->m_error = GSOCK_INVADDR;                               \
+    return retval;                                                  \
+  }                                                                 \
+}
+
+
+GAddress *GAddress_new(void)
+{
+  GAddress *address;
+
+  if ((address = (GAddress *) malloc(sizeof(GAddress))) == NULL)
+    return NULL;
+
+  address->m_family  = GSOCK_NOFAMILY;
+  address->m_addr    = NULL;
+  address->m_len     = 0;
+
+  return address;
+}
+
+GAddress *GAddress_copy(GAddress *address)
+{
+  GAddress *addr2;
+
+  assert(address != NULL);
+
+  if ((addr2 = (GAddress *) malloc(sizeof(GAddress))) == NULL)
+    return NULL;
+
+  memcpy(addr2, address, sizeof(GAddress));
+
+  if (address->m_addr && address->m_len > 0)
+  {
+    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);
+  }
+
+  return addr2;
+}
+
+void GAddress_destroy(GAddress *address)
+{
+  assert(address != NULL);
+
+  if (address->m_addr)
+    free(address->m_addr);
+
+  free(address);
+}
+
+void GAddress_SetFamily(GAddress *address, GAddressType type)
+{
+  assert(address != NULL);
+
+  address->m_family = type;
+}
+
+GAddressType GAddress_GetFamily(GAddress *address)
+{
+  assert(address != NULL);
+
+  return address->m_family;
+}
+
+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_family = GSOCK_INET;
+      break;
+    case AF_UNIX:
+      address->m_family = GSOCK_UNIX;
+      break;
+#ifdef AF_INET6
+    case AF_INET6:
+      address->m_family = GSOCK_INET6;
+      break;
+#endif
+    default:
+    {
+      address->m_error = GSOCK_INVOP;
+      return GSOCK_INVOP;
+    }
+  }
+
+  if (address->m_addr)
+    free(address->m_addr);
+
+  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);
+
+  return GSOCK_NOERROR;
+}
+
+GSocketError _GAddress_translate_to(GAddress *address,
+                                    struct sockaddr **addr, int *len)
+{
+  if (!address->m_addr)
+  {
+    address->m_error = GSOCK_INVADDR;
+    return GSOCK_INVADDR;
+  }
+
+  *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);
+  return GSOCK_NOERROR;
+}
+
+/*
+ * -------------------------------------------------------------------------
+ * Internet address family
+ * -------------------------------------------------------------------------
+ */
+
+GSocketError _GAddress_Init_INET(GAddress *address)
+{
+  address->m_len  = sizeof(struct sockaddr_in);
+  address->m_addr = (struct sockaddr *) malloc(address->m_len);
+  if (address->m_addr == NULL)
+  {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
+
+  memset( address->m_addr , 0 , address->m_len ) ;
+  address->m_family = GSOCK_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)
+{
+  struct hostent *he;
+  struct in_addr *addr;
+
+  assert(address != NULL);
+
+  CHECK_ADDRESS(address, INET);
+
+  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)
+  if ( (addr->s_addr = inet_addr(hostname)) == -1 )
+  {
+#else
+  /* Use gethostbyname by default */
+#ifndef __WXMAC__
+  int val = 1;  /* VA doesn't like constants in conditional expressions */
+  if (val)
+#endif
+  {
+#endif
+    struct in_addr *array_addr;
+
+    /* It is a real name, we solve it */
+    if ((he = gethostbyname(hostname)) == NULL)
+    {
+      /* Reset to invalid address */
+      addr->s_addr = INADDR_NONE;
+      address->m_error = GSOCK_NOHOST;
+      return GSOCK_NOHOST;
+    }
+    array_addr = (struct in_addr *) *(he->h_addr_list);
+    addr->s_addr = array_addr[0].s_addr;
+  }
+  return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET_SetAnyAddress(GAddress *address)
+{
+  return GAddress_INET_SetHostAddress(address, INADDR_ANY);
+}
+
+GSocketError GAddress_INET_SetHostAddress(GAddress *address,
+                                          unsigned long hostaddr)
+{
+  struct in_addr *addr;
+
+  assert(address != NULL);
+
+  CHECK_ADDRESS(address, INET);
+
+  addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr);
+  addr->s_addr = htonl(hostaddr) ;
+
+  return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port,
+                                       const char *protocol)
+{
+  struct servent *se;
+  struct sockaddr_in *addr;
+
+  assert(address != NULL);
+  CHECK_ADDRESS(address, INET);
+
+  if (!port)
+  {
+    address->m_error = GSOCK_INVPORT;
+    return GSOCK_INVPORT;
+  }
+  se = getservbyname(port, protocol);
+  if (!se)
+  {
+    /* the cast to int suppresses compiler warnings about subscript having the
+       type char */
+    if (isdigit((int)port[0]))
+    {
+      int port_int;
+
+      port_int = atoi(port);
+      addr = (struct sockaddr_in *)address->m_addr;
+      addr->sin_port = htons(port_int);
+      return GSOCK_NOERROR;
+    }
+
+    address->m_error = GSOCK_INVPORT;
+    return GSOCK_INVPORT;
+  }
+
+  addr = (struct sockaddr_in *)address->m_addr;
+  addr->sin_port = se->s_port;
+
+  return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port)
+{
+  struct sockaddr_in *addr;
+
+  assert(address != NULL);
+  CHECK_ADDRESS(address, INET);
+  addr = (struct sockaddr_in *)address->m_addr;
+  addr->sin_port = htons(port);
+
+  return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t sbuf)
+{
+  struct hostent *he;
+  char *addr_buf;
+  struct sockaddr_in *addr;
+
+  assert(address != NULL); 
+  CHECK_ADDRESS(address, INET);
+
+  addr = (struct sockaddr_in *)address->m_addr;
+  addr_buf = (char *)&(addr->sin_addr);
+
+  he = gethostbyaddr(addr_buf, sizeof(addr->sin_addr), AF_INET);
+  if (he == NULL)
+  {
+    address->m_error = GSOCK_NOHOST;
+    return GSOCK_NOHOST;
+  }
+
+  strncpy(hostname, he->h_name, sbuf);
+
+  return GSOCK_NOERROR;
+}
+
+unsigned long GAddress_INET_GetHostAddress(GAddress *address)
+{
+  struct sockaddr_in *addr;
+
+  assert(address != NULL); 
+  CHECK_ADDRESS_RETVAL(address, INET, 0); 
+
+  addr = (struct sockaddr_in *)address->m_addr;
+
+  return ntohl(addr->sin_addr.s_addr) ;
+}
+
+unsigned short GAddress_INET_GetPort(GAddress *address)
+{
+  struct sockaddr_in *addr;
+
+  assert(address != NULL); 
+  CHECK_ADDRESS_RETVAL(address, INET, 0); 
+
+  addr = (struct sockaddr_in *)address->m_addr;
+  return ntohs(addr->sin_port);
+}
+
+/*
+ * -------------------------------------------------------------------------
+ * Unix address family
+ * -------------------------------------------------------------------------
+ */
+
+GSocketError _GAddress_Init_UNIX(GAddress *address)
+{
+  address->m_len  = sizeof(struct sockaddr_un);
+  address->m_addr = (struct sockaddr *)malloc(address->m_len);
+  if (address->m_addr == NULL)
+  {
+    address->m_error = GSOCK_MEMERR;
+    return GSOCK_MEMERR;
+  }
+
+  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 GSOCK_NOERROR;
+}
+
+#define UNIX_SOCK_PATHLEN (sizeof(addr->sun_path)/sizeof(addr->sun_path[0]))
+
+GSocketError GAddress_UNIX_SetPath(GAddress *address, const char *path)
+{
+  struct sockaddr_un *addr;
+
+  assert(address != NULL); 
+
+  CHECK_ADDRESS(address, UNIX); 
+
+  addr = ((struct sockaddr_un *)address->m_addr);
+  strncpy(addr->sun_path, path, UNIX_SOCK_PATHLEN);
+  addr->sun_path[UNIX_SOCK_PATHLEN - 1] = '\0';
+
+  return GSOCK_NOERROR;
+}
+
+GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf)
+{
+  struct sockaddr_un *addr;
+
+  assert(address != NULL);
+  CHECK_ADDRESS(address, UNIX);
+
+  addr = (struct sockaddr_un *)address->m_addr;
+
+  strncpy(path, addr->sun_path, sbuf);
+
+  return GSOCK_NOERROR;
+}
+
+/* Address handling */
+
+/* GSocket_SetLocal:
+ * GSocket_GetLocal:
+ * GSocket_SetPeer:
+ * GSocket_GetPeer:
+ *  Set or get the local or peer address for this socket. The 'set'
+ *  functions return GSOCK_NOERROR on success, an error code otherwise.
+ *  The 'get' functions return a pointer to a GAddress object on success,
+ *  or NULL otherwise, in which case they set the error code of the
+ *  corresponding GSocket.
+ *
+ *  Error codes:
+ *    GSOCK_INVSOCK - the socket is not valid.
+ *    GSOCK_INVADDR - the address is not valid.
+ */
+GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address)
+{
+  assert(socket != NULL);
+
+  /* the socket must be initialized, or it must be a server */
+  if ((socket->m_fd != INVALID_SOCKET && !socket->m_server))
+  {
+    socket->m_error = GSOCK_INVSOCK;
+    return GSOCK_INVSOCK;
+  }
+
+  /* check address */
+  if (address == NULL || address->m_family == GSOCK_NOFAMILY)
+  {
+    socket->m_error = GSOCK_INVADDR;
+    return GSOCK_INVADDR;
+  }
+
+  if (socket->m_local)
+    GAddress_destroy(socket->m_local);
+
+  socket->m_local = GAddress_copy(address);
+
+  return GSOCK_NOERROR;
+}
+
+GSocketError GSocket_SetPeer(GSocket *socket, GAddress *address)
+{
+  assert(socket != NULL);
+
+  /* check address */
+  if (address == NULL || address->m_family == GSOCK_NOFAMILY)
+  {
+    socket->m_error = GSOCK_INVADDR;
+    return GSOCK_INVADDR;
+  }
+
+  if (socket->m_peer)
+    GAddress_destroy(socket->m_peer);
+
+  socket->m_peer = GAddress_copy(address);
+
+  return GSOCK_NOERROR;
+}
+
+GAddress *GSocket_GetLocal(GSocket *socket)
+{
+  GAddress *address;
+  struct sockaddr addr;
+  socklen_t size = sizeof(addr);
+  GSocketError err;
+
+  assert(socket != NULL);
+
+  /* try to get it from the m_local var first */
+  if (socket->m_local)
+    return GAddress_copy(socket->m_local);
+
+  /* else, if the socket is initialized, try getsockname */
+  if (socket->m_fd == INVALID_SOCKET)
+  {
+    socket->m_error = GSOCK_INVSOCK;
+    return NULL;
+  }
+
+  if (getsockname(socket->m_fd, &addr, (socklen_t *) &size) < 0)
+  {
+    socket->m_error = GSOCK_IOERR;
+    return NULL;
+  }
+
+  /* got a valid address from getsockname, create a GAddress object */
+  address = GAddress_new();
+  if (address == NULL)
+  {
+    socket->m_error = GSOCK_MEMERR;
+    return NULL;
+  }
+
+  err = _GAddress_translate_from(address, &addr, size);
+  if (err != GSOCK_NOERROR)
+  {
+    GAddress_destroy(address);
+    socket->m_error = err;
+    return NULL;
+  }
+
+  return address;
+}
+
+GAddress *GSocket_GetPeer(GSocket *socket)
+{
+  assert(socket != NULL);
+
+  /* try to get it from the m_peer var */
+  if (socket->m_peer)
+    return GAddress_copy(socket->m_peer);
+
+  return NULL;
+}
+
+//
+//
+//
+
+
+GSocket *GSocket_new(void)
+{
+  GSocket *socket;
+  socket = (GSocket *)malloc(sizeof(GSocket));
+
+  if (socket == NULL)
+    return NULL;
+    
+  socket->m_fd                  = INVALID_SOCKET;
+
+  for (int i=0;i<GSOCK_MAX_EVENT;i++)
+  {
+    socket->m_cbacks[i]         = NULL;
+  }
+  socket->m_detected            = 0;
+
+  socket->m_local               = NULL;
+  socket->m_peer                = NULL;
+  socket->m_error               = GSOCK_NOERROR;
+
+  socket->m_non_blocking        = FALSE ;
+  socket->m_stream              = TRUE;
+//  socket->m_oriented            = TRUE;
+  socket->m_server              = FALSE;
+  socket->m_establishing        = FALSE;
+  socket->m_timeout             = 10*60*1000;
+                                /* 10 minutes * 60 sec * 1000 millisec */
+  
+  socket->m_cfSocket            = NULL ;
+  socket->m_runLoopSource       = NULL ;
+  socket->m_readStream          = NULL;
+  socket->m_writeStream         = NULL;
+    
+  return socket ;
+}
+
+void GSocket_close(GSocket *socket)
+{
+  if ( socket->m_cfSocket != NULL )
+  {
+    if ( socket->m_readStream )
+    {
+                 CFReadStreamClose(socket->m_readStream);
+      CFRelease( socket->m_readStream ) ;
+      socket->m_readStream = NULL ;
+    }
+    if ( socket->m_writeStream )
+    {
+                 CFWriteStreamClose(socket->m_writeStream);
+      CFRelease( socket->m_writeStream ) ;
+      socket->m_writeStream = NULL ;
+    }
+
+    CFSocketInvalidate( socket->m_cfSocket ) ;
+    CFRelease( socket->m_cfSocket ) ;
+    socket->m_cfSocket = NULL ;
+    socket->m_fd = INVALID_SOCKET ;
+  }
+}
+
+void GSocket_Shutdown(GSocket *socket)
+{
+  GSocket_close( socket ) ;
+
+  /* Disable GUI callbacks */
+  for (int evt = 0; evt < GSOCK_MAX_EVENT; evt++)
+    socket->m_cbacks[evt] = NULL;
+
+  socket->m_detected = GSOCK_LOST_FLAG;
+}
+
+void GSocket_destroy(GSocket *socket)
+{
+  assert(socket != NULL);
+
+  /* Check that the socket is really shutdowned */
+  if (socket->m_fd != INVALID_SOCKET)
+    GSocket_Shutdown(socket);
+
+  /* Destroy private addresses */
+  if (socket->m_local)
+    GAddress_destroy(socket->m_local);
+
+  if (socket->m_peer)
+    GAddress_destroy(socket->m_peer);
+
+  /* Destroy the socket itself */
+  free(socket);
+}
+
+GSocketError GSocket_Connect(GSocket *socket, GSocketStream stream)
+{
+  assert(socket != NULL);
+
+  if (socket->m_fd != INVALID_SOCKET)
+  {
+    socket->m_error = GSOCK_INVSOCK;
+    return GSOCK_INVSOCK;
+  }
+
+  if (!socket->m_peer)
+  {
+    socket->m_error = GSOCK_INVADDR;
+    return GSOCK_INVADDR;
+  }
+
+  /* Streamed or dgram socket? */
+  socket->m_stream   = (stream == GSOCK_STREAMED);
+  socket->m_oriented = TRUE;
+  socket->m_server   = FALSE;
+  socket->m_establishing = FALSE;
+
+  GSocketError returnErr = GSOCK_NOERROR ;
+  CFSocketError err ;
+  
+  CFAllocatorRef alloc = kCFAllocatorDefault ;
+  CFSocketContext ctx ;
+  memset( &ctx , 0 , sizeof( ctx ) ) ;
+  ctx.info = socket ;
+  socket->m_cfSocket = CFSocketCreate( alloc , socket->m_peer->m_realfamily ,
+     stream == GSOCK_STREAMED ? SOCK_STREAM : SOCK_DGRAM , 0 , 
+      kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack , wxMacCFSocketCallback , &ctx  ) ;
+  _GSocket_Enable(socket, GSOCK_CONNECTION);
+     
+  socket->m_fd = CFSocketGetNative( socket->m_cfSocket ) ; 
+
+  CFStreamCreatePairWithSocket ( alloc , socket->m_fd , &socket->m_readStream , &socket->m_writeStream  ); 
+       if ((socket->m_readStream == NULL) || (socket->m_writeStream == NULL))
+  {
+    GSocket_close(socket);
+    socket->m_error = GSOCK_IOERR;
+    return GSOCK_IOERR;
+  }
+    
+  if ( !CFReadStreamOpen( socket->m_readStream ) || !CFWriteStreamOpen( socket->m_writeStream ) )
+  {
+    GSocket_close(socket);
+    socket->m_error = GSOCK_IOERR;
+    return GSOCK_IOERR;
+  }
+  
+  CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(alloc , socket->m_cfSocket , 0);
+  CFRunLoopAddSource(CFRunLoopGetCurrent() , rls, kCFRunLoopCommonModes);
+  CFRelease(rls);
+  
+  CFDataRef address = CFDataCreateWithBytesNoCopy(alloc, (const UInt8*) socket->m_peer->m_addr, socket->m_peer->m_len , kCFAllocatorNull);
+  if ( !address )
+    return GSOCK_MEMERR ;
+    
+  err = CFSocketConnectToAddress( socket->m_cfSocket , address, socket->m_non_blocking ? -1 : socket->m_timeout / 1000  ) ;
+  CFRelease(address);
+  
+  if (err != kCFSocketSuccess)
+  {
+    if ( err == kCFSocketTimeout )
+    {  
+      GSocket_close(socket);
+      socket->m_error = GSOCK_TIMEDOUT ;
+      return GSOCK_TIMEDOUT ;
+    }
+    // we don't know whether a connect in progress will be issued like this
+    if ( err != kCFSocketTimeout && socket->m_non_blocking )
+    {
+      socket->m_establishing = TRUE;
+      socket->m_error = GSOCK_WOULDBLOCK;
+      return GSOCK_WOULDBLOCK;
+    }
+    
+    GSocket_close(socket);
+    socket->m_error = GSOCK_IOERR;
+    return GSOCK_IOERR;
+  }
+
+  return GSOCK_NOERROR;
+}
+
+/* Flags */
+
+/* GSocket_SetNonBlocking:
+ *  Sets the socket to non-blocking mode. All IO calls will return
+ *  immediately.
+ */
+void GSocket_SetNonBlocking(GSocket *socket, int non_block)
+{
+  assert(socket != NULL);
+
+//  GSocket_Debug( ("GSocket_SetNonBlocking: %d\n", (int)non_block) );
+
+  socket->m_non_blocking = non_block;
+}
+
+/* GSocket_SetTimeout:
+ *  Sets the timeout for blocking calls. Time is expressed in
+ *  milliseconds.
+ */
+void GSocket_SetTimeout(GSocket *socket, unsigned long millisec)
+{
+  assert(socket != NULL);
+
+  socket->m_timeout = millisec;
+}
+
+/* GSocket_GetError:
+ *  Returns the last error occured for this socket. Note that successful
+ *  operations do not clear this back to GSOCK_NOERROR, so use it only
+ *  after an error.
+ */
+GSocketError GSocket_GetError(GSocket *socket)
+{
+  assert(socket != NULL);
+
+  return socket->m_error;
+}
+
+/* Callbacks */
+
+/* GSOCK_INPUT:
+ *   There is data to be read in the input buffer. If, after a read
+ *   operation, there is still data available, the callback function will
+ *   be called again.
+ * GSOCK_OUTPUT:
+ *   The socket is available for writing. That is, the next write call 
+ *   won't block. This event is generated only once, when the connection is
+ *   first established, and then only if a call failed with GSOCK_WOULDBLOCK,
+ *   when the output buffer empties again. This means that the app should
+ *   assume that it can write since the first OUTPUT event, and no more
+ *   OUTPUT events will be generated unless an error occurs.
+ * GSOCK_CONNECTION:
+ *   Connection succesfully established, for client sockets, or incoming
+ *   client connection, for server sockets. Wait for this event (also watch
+ *   out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call.
+ * GSOCK_LOST:
+ *   The connection is lost (or a connection request failed); this could
+ *   be due to a failure, or due to the peer closing it gracefully.
+ */
+
+/* GSocket_SetCallback:
+ *  Enables the callbacks specified by 'flags'. Note that 'flags'
+ *  may be a combination of flags OR'ed toghether, so the same
+ *  callback function can be made to accept different events.
+ *  The callback function must have the following prototype:
+ *
+ *  void function(GSocket *socket, GSocketEvent event, char *cdata)
+ */
+void GSocket_SetCallback(GSocket *socket, GSocketEventFlags flags,
+                         GSocketCallback callback, char *cdata)
+{
+  int count;
+
+  assert(socket != NULL);
+
+  for (count = 0; count < GSOCK_MAX_EVENT; count++)
+  {
+    if ((flags & (1 << count)) != 0)
+    {
+      socket->m_cbacks[count] = callback;
+      socket->m_data[count] = cdata;
+    }
+  }
+}
+
+/* GSocket_UnsetCallback:
+ *  Disables all callbacks specified by 'flags', which may be a
+ *  combination of flags OR'ed toghether.
+ */
+void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags flags)
+{
+  int count;
+
+  assert(socket != NULL);
+
+  for (count = 0; count < GSOCK_MAX_EVENT; count++)
+  {
+    if ((flags & (1 << count)) != 0)
+    {
+      socket->m_cbacks[count] = NULL;
+      socket->m_data[count] = NULL;
+    }
+  }
+}
+
+
+#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_Install_Callback(GSocket *socket, GSocketEvent event)
+{
+    int c;
+    switch (event)
+    {
+     case GSOCK_CONNECTION:
+         if(socket->m_server)
+            c = kCFSocketReadCallBack;
+         else
+            c = kCFSocketConnectCallBack;
+         break;
+     case GSOCK_LOST:
+     case GSOCK_INPUT:
+         c = kCFSocketReadCallBack;
+         break;
+     case GSOCK_OUTPUT:
+         c = kCFSocketWriteCallBack;
+         break;
+     default:
+         c = 0;
+    }
+    CFSocketEnableCallBacks(socket->m_cfSocket, c);
+}
+
+void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
+{
+    int c;
+    switch (event)
+    {
+     case GSOCK_CONNECTION:
+         if(socket->m_server)
+            c = kCFSocketReadCallBack;
+         else
+            c = kCFSocketConnectCallBack;
+         break;
+     case GSOCK_LOST:
+     case GSOCK_INPUT:
+         c = kCFSocketReadCallBack;
+         break;
+     case GSOCK_OUTPUT:
+         c = kCFSocketWriteCallBack;
+         break;
+     default:
+         c = 0;
+    }
+    CFSocketDisableCallBacks(socket->m_cfSocket, c);
+}
+
+void _GSocket_Enable(GSocket *socket, GSocketEvent event)
+{
+  socket->m_detected &= ~(1 << event);
+  _GSocket_Install_Callback(socket, event);
+}
+
+void _GSocket_Disable(GSocket *socket, GSocketEvent event)
+{
+  socket->m_detected |= (1 << event);
+  _GSocket_Uninstall_Callback(socket, event);
+}
+
+void wxMacCFSocketCallback(CFSocketRef s, CFSocketCallBackType callbackType,
+                         CFDataRef address, const void* data, void* info)
+{
+  GSocket* socket = (GSocket*)info;
+
+  switch (callbackType)
+  {
+    case kCFSocketConnectCallBack:
+      if ( data )
+      {
+        SInt32 error = *((SInt32*)data) ;
+        CALL_CALLBACK( socket , GSOCK_LOST ) ;
+        GSocket_Shutdown(socket);
+      }
+      else
+      {
+        CALL_CALLBACK( socket , GSOCK_CONNECTION ) ;
+      }
+      break;
+    case kCFSocketReadCallBack:
+      CALL_CALLBACK( socket , GSOCK_INPUT ) ;
+      break;
+    case kCFSocketWriteCallBack:
+      CALL_CALLBACK( socket , GSOCK_OUTPUT ) ;
+      break;
+    default:
+      break;  /* We shouldn't get here. */
+  }
+}
+
+int GSocket_Read(GSocket *socket, char *buffer, int size)
+{
+  int ret = 0 ;
+
+  assert(socket != NULL);
+  // if ( !CFReadStreamHasBytesAvailable() )
+  ret = CFReadStreamRead( socket->m_readStream , (UInt8*) buffer , size ) ;
+
+  return ret;
+}
+
+int GSocket_Write(GSocket *socket, const char *buffer, int size)
+{                        
+  int ret;
+
+  assert(socket != NULL);
+  ret = CFWriteStreamWrite( socket->m_writeStream , (UInt8*) buffer , size ) ;
+  return ret;
+}
+
+GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags)
+{
+  assert(socket != NULL);
+  return flags & socket->m_detected;
+}
+
+// ==========================================================================
+// wxSocketModule
+// ==========================================================================
+
+class wxSocketModule : public wxModule
+{
+public:
+    virtual bool OnInit()
+    {
+        // wxSocketBase will call GSocket_Init() itself when/if needed
+        return TRUE;
+    }
+
+    virtual void OnExit()
+    {
+        if ( wxSocketBase::IsInitialized() )
+            wxSocketBase::Shutdown();
+    }
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxSocketModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule)
+
+#endif
+  // wxUSE_SOCKETS
+