X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2ada746fb47bf68c9f2dab6399a6cd5510320984..a25484eb1391b53e6f0c1205af4b3a23183e512e:/src/unix/gsocket.cpp diff --git a/src/unix/gsocket.cpp b/src/unix/gsocket.cpp index 8bcb88fb0a..1d1b9cec69 100644 --- a/src/unix/gsocket.cpp +++ b/src/unix/gsocket.cpp @@ -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 {