]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/gsocket.cpp
make wxSelectDispatcher ctor public, it can be useful to create it in places other...
[wxWidgets.git] / src / unix / gsocket.cpp
index 8bcb88fb0a1173f712d6210484f0bfd320720ac7..1d1b9cec698620fa8075b03c4acf143fd9aa1a92 100644 (file)
@@ -1198,11 +1198,16 @@ int GSocket::Read(char *buffer, int size)
     else
       ret = Recv_Dgram(buffer, size);
 
-    /* If recv returned zero, 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 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)
+    if ((ret == 0) && m_stream)
     {
       /* Make sure wxSOCKET_LOST event gets sent and shut down the socket */
       if (m_use_events)
@@ -1296,7 +1301,99 @@ GSocketEventFlags GSocket::Select(GSocketEventFlags flags)
 {
   assert(this);
 
-  return flags & m_detected;
+  GSocketEventFlags result = 0;
+  fd_set readfds;
+  fd_set writefds;
+  fd_set exceptfds;
+  struct timeval tv;
+
+  if (m_fd == -1)
+    return (GSOCK_LOST_FLAG & flags);
+
+  /* Do not use a static struct, Linux can garble it */
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  wxFD_ZERO(&readfds);
+  wxFD_ZERO(&writefds);
+  wxFD_ZERO(&exceptfds);
+  wxFD_SET(m_fd, &readfds);
+  if (flags & GSOCK_OUTPUT_FLAG || flags & GSOCK_CONNECTION_FLAG)
+    wxFD_SET(m_fd, &writefds);
+  wxFD_SET(m_fd, &exceptfds);
+
+  /* Check 'sticky' CONNECTION flag first */
+  result |= GSOCK_CONNECTION_FLAG & m_detected;
+
+  /* If we have already detected a LOST event, then don't try
+   * to do any further processing.
+   */
+  if ((m_detected & GSOCK_LOST_FLAG) != 0)
+  {
+    m_establishing = false;
+    return (GSOCK_LOST_FLAG & flags);
+  }
+
+  /* Try select now */
+  if (select(m_fd + 1, &readfds, &writefds, &exceptfds, &tv) < 0)
+  {
+    /* What to do here? */
+    return (result & flags);
+  }
+
+  /* Check for exceptions and errors */
+  if (wxFD_ISSET(m_fd, &exceptfds))
+  {
+    m_establishing = false;
+    m_detected = GSOCK_LOST_FLAG;
+
+    /* LOST event: Abort any further processing */
+    return (GSOCK_LOST_FLAG & flags);
+  }
+
+  /* Check for readability */
+  if (wxFD_ISSET(m_fd, &readfds))
+  {
+    result |= GSOCK_INPUT_FLAG;
+
+    if (m_server && m_stream)
+    {
+      /* This is a TCP server socket that detected a connection.
+         While the INPUT_FLAG is also set, it doesn't matter on
+         this kind of  sockets, as we can only Accept() from them. */
+      m_detected |= GSOCK_CONNECTION_FLAG;
+    }
+  }
+
+  /* Check for writability */
+  if (wxFD_ISSET(m_fd, &writefds))
+  {
+    if (m_establishing && !m_server)
+    {
+      int error;
+      SOCKOPTLEN_T len = sizeof(error);
+      m_establishing = false;
+      getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
+
+      if (error)
+      {
+        m_detected = GSOCK_LOST_FLAG;
+
+        /* LOST event: Abort any further processing */
+        return (GSOCK_LOST_FLAG & flags);
+      }
+      else
+      {
+        m_detected |= GSOCK_CONNECTION_FLAG;
+      }
+    }
+    else
+    {
+      result |= GSOCK_OUTPUT_FLAG;
+    }
+  }
+
+  return (result | m_detected) & flags;
 }
 
 /* Flags */
@@ -1685,9 +1782,17 @@ void GSocket::Detected_Read()
     }
     else if (num == 0)
     {
-      /* graceful shutdown */
-      CALL_CALLBACK(this, GSOCK_LOST);
-      Shutdown();
+      if (m_stream)
+      {
+        /* graceful shutdown */
+        CALL_CALLBACK(this, GSOCK_LOST);
+        Shutdown();
+      }
+      else
+      {
+        /* Empty datagram received */
+        CALL_CALLBACK(this, GSOCK_INPUT);
+      }
     }
     else
     {