]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/sockunix.cpp
move Ellipsize() to wxControl so it can be easily used by other controls
[wxWidgets.git] / src / unix / sockunix.cpp
index 0a0fbac7167e4d7d2addc37012110d573091dfeb..d0020dfbdb31c2611b4ddfb60ef1d330339db554 100644 (file)
@@ -18,7 +18,6 @@
 #include "wx/private/fd.h"
 #include "wx/private/socket.h"
 #include "wx/unix/private/sockunix.h"
-#include "wx/private/gsocketiohandler.h"
 
 #if defined(__VISAGECPP__)
 #define BSD_SELECT /* use Berkeley Sockets select */
@@ -147,33 +146,9 @@ int _System soclose(int);
 #define INADDR_NONE INADDR_BROADCAST
 #endif
 
-#if defined(__VISAGECPP__) || defined(__WATCOMC__)
-
-    #define MASK_SIGNAL() {
-    #define UNMASK_SIGNAL() }
-
-#else
-    extern "C" { typedef void (*wxSigHandler)(int); }
-
-    #define MASK_SIGNAL()                       \
-    {                                           \
-        wxSigHandler old_handler = signal(SIGPIPE, SIG_IGN);
-
-    #define UNMASK_SIGNAL()                     \
-        signal(SIGPIPE, old_handler);           \
-    }
-
-#endif
-
-/* If a SIGPIPE is issued by a socket call on a remotely closed socket,
-   the program will "crash" unless it explicitly handles the SIGPIPE.
-   By using MSG_NOSIGNAL, the SIGPIPE is suppressed. Later, we will
-   use SO_NOSIGPIPE (if available), the BSD equivalent. */
-#ifdef MSG_NOSIGNAL
-#  define GSOCKET_MSG_NOSIGNAL MSG_NOSIGNAL
-#else /* MSG_NOSIGNAL not available (FreeBSD including OS X) */
-#  define GSOCKET_MSG_NOSIGNAL 0
-#endif /* MSG_NOSIGNAL */
+// ----------------------------------------------------------------------------
+// implementation of thread-safe/reentrant functions if they're missing
+// ----------------------------------------------------------------------------
 
 #if wxUSE_THREADS && (defined(HAVE_GETHOSTBYNAME) || defined(HAVE_GETSERVBYNAME))
 #  include "wx/thread.h"
@@ -425,134 +400,46 @@ struct servent *wxGetservbyname_r(const char *port, const char *protocol,
   return se;
 }
 
-/* debugging helpers */
-#ifdef __GSOCKET_DEBUG__
-#  define SOCKET_DEBUG(args) printf args
-#else
-#  define SOCKET_DEBUG(args)
-#endif /* __GSOCKET_DEBUG__ */
-
-/* Constructors / Destructors for wxSocketImplUnix */
+// ============================================================================
+// wxSocketImpl implementation
+// ============================================================================
 
-wxSocketImplUnix::wxSocketImplUnix(wxSocketBase& wxsocket)
-    : wxSocketImpl(wxsocket)
+/* static */
+wxSocketImpl *wxSocketImpl::Create(wxSocketBase& wxsocket)
 {
-    m_fds[0] =
-    m_fds[1] = -1;
-
-    m_use_events = false;
+    return new wxSocketImplUnix(wxsocket);
 }
 
-/*
- *  Disallow further read/write operations on this socket, close
- *  the fd and disable all callbacks.
- */
-void wxSocketImplUnix::Shutdown()
-{
-    /* Don't allow events to fire after socket has been closed */
-    DisableEvents();
 
-    wxSocketImpl::Shutdown();
-}
-
-/*
- *  Waits for an incoming client connection. Returns a pointer to
- *  a wxSocketImplUnix object, or NULL if there was an error, in which case
- *  the last error field will be updated for the calling wxSocketImplUnix.
- *
- *  Error codes (set in the calling wxSocketImplUnix)
- *    wxSOCKET_INVSOCK    - the socket is not valid or not a server.
- *    wxSOCKET_TIMEDOUT   - timeout, no incoming connections.
- *    wxSOCKET_WOULDBLOCK - the call would block and the socket is nonblocking.
- *    wxSOCKET_MEMERR     - couldn't allocate memory.
- *    wxSOCKET_IOERR      - low-level error.
- */
-wxSocketImpl *wxSocketImplUnix::WaitConnection(wxSocketBase& wxsocket)
+wxSocketError wxSocketImplUnix::GetLastError() const
 {
-  wxSockAddr from;
-  WX_SOCKLEN_T fromlen = sizeof(from);
-  wxSocketImpl *connection;
-  wxSocketError err;
-  int arg = 1;
-
-  /* If the socket has already been created, we exit immediately */
-  if (m_fd == INVALID_SOCKET || !m_server)
-  {
-    m_error = wxSOCKET_INVSOCK;
-    return NULL;
-  }
-
-  /* Create a wxSocketImplUnix object for the new connection */
-  connection = wxSocketImplUnix::Create(wxsocket);
-
-  if (!connection)
-  {
-    m_error = wxSOCKET_MEMERR;
-    return NULL;
-  }
-
-  /* Wait for a connection (with timeout) */
-  if (Input_Timeout() == wxSOCKET_TIMEDOUT)
-  {
-    delete connection;
-    /* m_error set by Input_Timeout */
-    return NULL;
-  }
-
-  connection->m_fd = accept(m_fd, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen);
-
-  /* Reenable CONNECTION events */
-  EnableEvent(wxSOCKET_CONNECTION);
-
-  if (connection->m_fd == INVALID_SOCKET)
-  {
-    if (errno == EWOULDBLOCK)
-      m_error = wxSOCKET_WOULDBLOCK;
-    else
-      m_error = wxSOCKET_IOERR;
-
-    delete connection;
-    return NULL;
-  }
-
-  /* Initialize all fields */
-  connection->m_server   = false;
-  connection->m_stream   = true;
-
-  /* Setup the peer address field */
-  connection->m_peer = GAddress_new();
-  if (!connection->m_peer)
-  {
-    delete connection;
-    m_error = wxSOCKET_MEMERR;
-    return NULL;
-  }
-
-  err = _GAddress_translate_from(connection->m_peer, (sockaddr*)&from, fromlen);
-  if (err != wxSOCKET_NOERROR)
-  {
-    delete connection;
-    m_error = err;
-    return NULL;
-  }
-
-#if defined(__EMX__) || defined(__VISAGECPP__)
-  ioctl(connection->m_fd, FIONBIO, (char*)&arg, sizeof(arg));
-#else
-  ioctl(connection->m_fd, FIONBIO, &arg);
-#endif
-  if (m_use_events)
-    connection->Notify(true);
-
-  return connection;
-}
-
-void wxSocketImplUnix::Notify(bool flag)
-{
-    if (flag == m_use_events)
-        return;
-    m_use_events = flag;
-    DoEnableEvents(flag);
+    switch ( errno )
+    {
+        case 0:
+            return wxSOCKET_NOERROR;
+
+        case ENOTSOCK:
+            return wxSOCKET_INVSOCK;
+
+        // unfortunately EAGAIN only has the "would block" meaning for read(),
+        // not for connect() for which it means something rather different but
+        // we can't distinguish between these two situations currently...
+        //
+        // also notice that EWOULDBLOCK can be different from EAGAIN on some
+        // systems (HP-UX being the only known example) while it's defined as
+        // EAGAIN on most others (e.g. Linux)
+        case EAGAIN:
+#ifdef EWOULDBLOCK
+    #if EWOULDBLOCK != EAGAIN
+        case EWOULDBLOCK:
+    #endif
+#endif // EWOULDBLOCK
+        case EINPROGRESS:
+            return wxSOCKET_WOULDBLOCK;
+
+        default:
+            return wxSOCKET_IOERR;
+    }
 }
 
 void wxSocketImplUnix::DoEnableEvents(bool flag)
@@ -570,443 +457,25 @@ void wxSocketImplUnix::DoEnableEvents(bool flag)
     }
 }
 
-wxSocketError wxSocketImplUnix::DoHandleConnect(int ret)
-{
-  /* We only call EnableEvents() if we know we aren't shutting down the socket.
-   * NB: EnableEvents() needs to be called whether the socket is blocking or
-   * non-blocking, it just shouldn't be called prior to knowing there is a
-   * connection _if_ blocking sockets are being used.
-   * If connect above returns 0, we are already connected and need to make the
-   * call to EnableEvents() now.
-   */
-  if ( m_non_blocking || (ret == 0) )
-    EnableEvents();
-
-  if (ret == -1)
-  {
-    const int err = errno;
-
-    /* If connect failed with EINPROGRESS and the wxSocketImplUnix object
-     * is in blocking mode, we select() for the specified timeout
-     * checking for writability to see if the connection request
-     * completes.
-     */
-    if ((err == EINPROGRESS) && (!m_non_blocking))
-    {
-      if (Output_Timeout() == wxSOCKET_TIMEDOUT)
-      {
-        Close();
-        /* m_error is set in Output_Timeout */
-        return wxSOCKET_TIMEDOUT;
-      }
-      else
-      {
-        int error;
-        SOCKOPTLEN_T len = sizeof(error);
-
-        getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*) &error, &len);
-        EnableEvents();
-
-        if (!error)
-          return wxSOCKET_NOERROR;
-      }
-    }
-
-    /* If connect failed with EINPROGRESS and the wxSocketImplUnix object
-     * is set to nonblocking, we set m_error to wxSOCKET_WOULDBLOCK
-     * (and return wxSOCKET_WOULDBLOCK) but we don't close the socket;
-     * this way if the connection completes, a wxSOCKET_CONNECTION
-     * event will be generated, if enabled.
-     */
-    if ((err == EINPROGRESS) && (m_non_blocking))
-    {
-      m_establishing = true;
-      m_error = wxSOCKET_WOULDBLOCK;
-      return wxSOCKET_WOULDBLOCK;
-    }
-
-    /* If connect failed with an error other than EINPROGRESS,
-     * then the call to Connect has failed.
-     */
-    Close();
-    m_error = wxSOCKET_IOERR;
-
-    return wxSOCKET_IOERR;
-  }
-
-  return wxSOCKET_NOERROR;
-}
-
-/* Generic IO */
-
-/* Like recv(), send(), ... */
-int wxSocketImplUnix::Read(char *buffer, int size)
-{
-  int ret;
-
-  if (m_fd == INVALID_SOCKET || m_server)
-  {
-    m_error = wxSOCKET_INVSOCK;
-    return -1;
-  }
-
-  /* Disable events during query of socket status */
-  DisableEvent(wxSOCKET_INPUT);
-
-  /* If the socket is blocking, wait for data (with a timeout) */
-  if (Input_Timeout() == wxSOCKET_TIMEDOUT) {
-    m_error = wxSOCKET_TIMEDOUT;
-    /* Don't return here immediately, otherwise socket events would not be
-     * re-enabled! */
-    ret = -1;
-  }
-  else
-  {
-    /* Read the data */
-    if (m_stream)
-      ret = Recv_Stream(buffer, size);
-    else
-      ret = Recv_Dgram(buffer, size);
-
-    /*
-     * If recv returned zero for a TCP socket (if m_stream == NULL, it's an UDP
-     * socket and empty datagrams are possible), then the connection has been
-     * gracefully closed.
-     *
-     * Otherwise, recv has returned an error (-1), in which case we have lost
-     * the socket only if errno does _not_ indicate that there may be more data
-     * to read.
-     */
-    if ((ret == 0) && m_stream)
-    {
-      /* Make sure wxSOCKET_LOST event gets sent and shut down the socket */
-      if (m_use_events)
-      {
-        m_detected = wxSOCKET_LOST_FLAG;
-        Detected_Read();
-        return 0;
-      }
-    }
-    else if (ret == -1)
-    {
-      if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
-        m_error = wxSOCKET_WOULDBLOCK;
-      else
-        m_error = wxSOCKET_IOERR;
-    }
-  }
-
-  /* Enable events again now that we are done processing */
-  EnableEvent(wxSOCKET_INPUT);
-
-  return ret;
-}
-
-int wxSocketImplUnix::Write(const char *buffer, int size)
-{
-  int ret;
-
-  SOCKET_DEBUG(( "Write #1, size %d\n", size ));
-
-  if (m_fd == INVALID_SOCKET || m_server)
-  {
-    m_error = wxSOCKET_INVSOCK;
-    return -1;
-  }
-
-  SOCKET_DEBUG(( "Write #2, size %d\n", size ));
-
-  /* If the socket is blocking, wait for writability (with a timeout) */
-  if (Output_Timeout() == wxSOCKET_TIMEDOUT)
-    return -1;
-
-  SOCKET_DEBUG(( "Write #3, size %d\n", size ));
-
-  /* Write the data */
-  if (m_stream)
-    ret = Send_Stream(buffer, size);
-  else
-    ret = Send_Dgram(buffer, size);
-
-  SOCKET_DEBUG(( "Write #4, size %d\n", size ));
-
-  if (ret == -1)
-  {
-    if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
-    {
-      m_error = wxSOCKET_WOULDBLOCK;
-      SOCKET_DEBUG(( "Write error WOULDBLOCK\n" ));
-    }
-    else
-    {
-      m_error = wxSOCKET_IOERR;
-      SOCKET_DEBUG(( "Write error IOERR\n" ));
-    }
-
-    /* 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.
-     */
-    EnableEvent(wxSOCKET_OUTPUT);
-
-    return -1;
-  }
-
-  SOCKET_DEBUG(( "Write #5, size %d ret %d\n", size, ret ));
-
-  return ret;
-}
-
-/* Flags */
-
-void wxSocketImplUnix::EnableEvent(wxSocketNotify event)
-{
-    if (m_use_events)
-    {
-        m_detected &= ~(1 << event);
-        wxSocketManager::Get()->Install_Callback(this, event);
-    }
-}
-
-void wxSocketImplUnix::DisableEvent(wxSocketNotify event)
-{
-    if (m_use_events)
-    {
-        m_detected |= (1 << event);
-        wxSocketManager::Get()->Uninstall_Callback(this, event);
-    }
-}
-
-/*
- *  For blocking sockets, wait until data is available or
- *  until timeout ellapses.
- */
-wxSocketError wxSocketImplUnix::Input_Timeout()
-{
-  fd_set readfds;
-  int ret;
-
-  // Linux select() will overwrite the struct on return so make a copy
-  struct timeval tv = m_timeout;
-
-  if (!m_non_blocking)
-  {
-    wxFD_ZERO(&readfds);
-    wxFD_SET(m_fd, &readfds);
-    ret = select(m_fd + 1, &readfds, NULL, NULL, &tv);
-    if (ret == 0)
-    {
-      SOCKET_DEBUG(( "Input_Timeout, select returned 0\n" ));
-      m_error = wxSOCKET_TIMEDOUT;
-      return wxSOCKET_TIMEDOUT;
-    }
-
-    if (ret == -1)
-    {
-      SOCKET_DEBUG(( "Input_Timeout, select returned -1\n" ));
-      if (errno == EBADF) { SOCKET_DEBUG(( "Invalid file descriptor\n" )); }
-      if (errno == EINTR) { SOCKET_DEBUG(( "A non blocked signal was caught\n" )); }
-      if (errno == EINVAL) { SOCKET_DEBUG(( "The highest number descriptor is negative\n" )); }
-      if (errno == ENOMEM) { SOCKET_DEBUG(( "Not enough memory\n" )); }
-      m_error = wxSOCKET_TIMEDOUT;
-      return wxSOCKET_TIMEDOUT;
-    }
-  }
-
-  return wxSOCKET_NOERROR;
-}
-
-/*
- *  For blocking sockets, wait until data can be sent without
- *  blocking or until timeout ellapses.
- */
-wxSocketError wxSocketImplUnix::Output_Timeout()
-{
-  fd_set writefds;
-  int ret;
-
-  // Linux select() will overwrite the struct on return so make a copy
-  struct timeval tv = m_timeout;
-
-  SOCKET_DEBUG( ("m_non_blocking has: %d\n", (int)m_non_blocking) );
-
-  if (!m_non_blocking)
-  {
-    wxFD_ZERO(&writefds);
-    wxFD_SET(m_fd, &writefds);
-    ret = select(m_fd + 1, NULL, &writefds, NULL, &tv);
-    if (ret == 0)
-    {
-      SOCKET_DEBUG(( "Output_Timeout, select returned 0\n" ));
-      m_error = wxSOCKET_TIMEDOUT;
-      return wxSOCKET_TIMEDOUT;
-    }
-
-    if (ret == -1)
-    {
-      SOCKET_DEBUG(( "Output_Timeout, select returned -1\n" ));
-      if (errno == EBADF) { SOCKET_DEBUG(( "Invalid file descriptor\n" )); }
-      if (errno == EINTR) { SOCKET_DEBUG(( "A non blocked signal was caught\n" )); }
-      if (errno == EINVAL) { SOCKET_DEBUG(( "The highest number descriptor is negative\n" )); }
-      if (errno == ENOMEM) { SOCKET_DEBUG(( "Not enough memory\n" )); }
-      m_error = wxSOCKET_TIMEDOUT;
-      return wxSOCKET_TIMEDOUT;
-    }
-
-    if ( ! wxFD_ISSET(m_fd, &writefds) )
-    {
-        SOCKET_DEBUG(( "Output_Timeout is buggy!\n" ));
-    }
-    else
-    {
-        SOCKET_DEBUG(( "Output_Timeout seems correct\n" ));
-    }
-  }
-  else
-  {
-    SOCKET_DEBUG(( "Output_Timeout, didn't try select!\n" ));
-  }
-
-  return wxSOCKET_NOERROR;
-}
-
-int wxSocketImplUnix::Recv_Stream(char *buffer, int size)
-{
-  int ret;
-  do
-  {
-    ret = recv(m_fd, buffer, size, GSOCKET_MSG_NOSIGNAL);
-  }
-  while (ret == -1 && errno == EINTR); /* Loop until not interrupted */
-
-  return ret;
-}
-
-int wxSocketImplUnix::Recv_Dgram(char *buffer, int size)
-{
-  wxSockAddr from;
-  WX_SOCKLEN_T fromlen = sizeof(from);
-  int ret;
-  wxSocketError err;
-
-  fromlen = sizeof(from);
-
-  do
-  {
-    ret = recvfrom(m_fd, buffer, size, 0, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen);
-  }
-  while (ret == -1 && errno == EINTR); /* Loop until not interrupted */
-
-  if (ret == -1)
-    return -1;
-
-  /* Translate a system address into a wxSocketImplUnix address */
-  if (!m_peer)
-  {
-    m_peer = GAddress_new();
-    if (!m_peer)
-    {
-      m_error = wxSOCKET_MEMERR;
-      return -1;
-    }
-  }
-
-  err = _GAddress_translate_from(m_peer, (sockaddr*)&from, fromlen);
-  if (err != wxSOCKET_NOERROR)
-  {
-    GAddress_destroy(m_peer);
-    m_peer  = NULL;
-    m_error = err;
-    return -1;
-  }
-
-  return ret;
-}
-
-int wxSocketImplUnix::Send_Stream(const char *buffer, int size)
-{
-  int ret;
-
-  MASK_SIGNAL();
-
-  do
-  {
-    ret = send(m_fd, (char *)buffer, size, GSOCKET_MSG_NOSIGNAL);
-  }
-  while (ret == -1 && errno == EINTR); /* Loop until not interrupted */
-
-  UNMASK_SIGNAL();
-
-  return ret;
-}
-
-int wxSocketImplUnix::Send_Dgram(const char *buffer, int size)
-{
-  struct sockaddr *addr;
-  int len, ret;
-  wxSocketError err;
-
-  if (!m_peer)
-  {
-    m_error = wxSOCKET_INVADDR;
-    return -1;
-  }
-
-  err = _GAddress_translate_to(m_peer, &addr, &len);
-  if (err != wxSOCKET_NOERROR)
-  {
-    m_error = err;
-    return -1;
-  }
-
-  MASK_SIGNAL();
-
-  do
-  {
-    ret = sendto(m_fd, (char *)buffer, size, 0, addr, len);
-  }
-  while (ret == -1 && errno == EINTR); /* Loop until not interrupted */
-
-  UNMASK_SIGNAL();
-
-  /* Frees memory allocated from _GAddress_translate_to */
-  free(addr);
-
-  return ret;
-}
 
 void wxSocketImplUnix::OnStateChange(wxSocketNotify event)
 {
-    DisableEvent(event);
     NotifyOnStateChange(event);
 
     if ( event == wxSOCKET_LOST )
         Shutdown();
 }
 
-void wxSocketImplUnix::Detected_Read()
+void wxSocketImplUnix::OnReadWaiting()
 {
   char c;
 
-  /* Safeguard against straggling call to Detected_Read */
   if (m_fd == INVALID_SOCKET)
   {
     return;
   }
 
-  /* If we have already detected a LOST event, then don't try
-   * to do any further processing.
-   */
-  if ((m_detected & wxSOCKET_LOST_FLAG) != 0)
-  {
-    m_establishing = false;
-
-    OnStateChange(wxSOCKET_LOST);
-    return;
-  }
-
-  int num =  recv(m_fd, &c, 1, MSG_PEEK | GSOCKET_MSG_NOSIGNAL);
+  int num =  recv(m_fd, &c, 1, MSG_PEEK);
 
   if (num > 0)
   {
@@ -1046,19 +515,8 @@ void wxSocketImplUnix::Detected_Read()
   }
 }
 
-void wxSocketImplUnix::Detected_Write()
+void wxSocketImplUnix::OnWriteWaiting()
 {
-  /* If we have already detected a LOST event, then don't try
-   * to do any further processing.
-   */
-  if ((m_detected & wxSOCKET_LOST_FLAG) != 0)
-  {
-    m_establishing = false;
-
-    OnStateChange(wxSOCKET_LOST);
-    return;
-  }
-
   if (m_establishing && !m_server)
   {
     int error;
@@ -1088,6 +546,11 @@ void wxSocketImplUnix::Detected_Write()
   }
 }
 
+void wxSocketImplUnix::OnExceptionWaiting()
+{
+    wxFAIL_MSG( "not supposed to be called" );
+}
+
 /*
  * -------------------------------------------------------------------------
  * GAddress
@@ -1687,4 +1150,5 @@ wxSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf)
   return wxSOCKET_NOERROR;
 }
 #endif  /* !defined(__VISAGECPP__) */
+
 #endif  /* wxUSE_SOCKETS */