Migrate UDPSocket to use poll()

This commit is contained in:
sfan5 2024-01-13 18:23:14 +01:00
parent e8008c1b21
commit ee727eb65e

@ -43,7 +43,7 @@ typedef int socklen_t;
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <fcntl.h> #include <fcntl.h>
#include <netdb.h> #include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#define LAST_SOCKET_ERR() (errno) #define LAST_SOCKET_ERR() (errno)
@ -332,46 +332,45 @@ void UDPSocket::setTimeoutMs(int timeout_ms)
bool UDPSocket::WaitData(int timeout_ms) bool UDPSocket::WaitData(int timeout_ms)
{ {
fd_set readset; timeout_ms = MYMAX(timeout_ms, 0);
int result;
// Initialize the set
FD_ZERO(&readset);
FD_SET(m_handle, &readset);
// Initialize time out struct
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = timeout_ms * 1000;
// select()
result = select(m_handle + 1, &readset, NULL, NULL, &tv);
if (result == 0)
return false;
int e = LAST_SOCKET_ERR();
#ifdef _WIN32 #ifdef _WIN32
if (result < 0 && (e == WSAEINTR || e == WSAEBADF)) { WSAPOLLFD pfd;
pfd.fd = m_handle;
pfd.events = POLLRDNORM;
int result = WSAPoll(&pfd, 1, timeout_ms);
#else #else
if (result < 0 && (e == EINTR || e == EBADF)) { struct pollfd pfd;
pfd.fd = m_handle;
pfd.events = POLLIN;
int result = poll(&pfd, 1, timeout_ms);
#endif #endif
// N.B. select() fails when sockets are destroyed on Connection's dtor
// with EBADF. Instead of doing tricky synchronization, allow this if (result == 0) {
return false; // No data
} else if (result > 0) {
// There might be data
return pfd.revents != 0;
}
// Error case
int e = LAST_SOCKET_ERR();
#ifdef _WIN32
if (e == WSAEINTR || e == WSAEBADF) {
#else
if (e == EINTR || e == EBADF) {
#endif
// N.B. poll() fails when sockets are destroyed on Connection's dtor
// with EBADF. Instead of doing tricky synchronization, allow this
// thread to exit but don't throw an exception. // thread to exit but don't throw an exception.
return false; return false;
} }
if (result < 0) { tracestream << (int)m_handle << ": poll failed: "
tracestream << (int)m_handle << ": Select failed: " << SOCKET_ERR_STR(e) << SOCKET_ERR_STR(e) << std::endl;
<< std::endl;
throw SocketException("Select failed"); throw SocketException("poll failed");
} else if (!FD_ISSET(m_handle, &readset)) {
// No data
return false;
}
// There is data
return true;
} }