switch from select to poll to deal with Android 9 giving us high socket fds when calling ::connect
This commit is contained in:
parent
e8a20c7e8a
commit
6b8aa43ec0
@ -17,6 +17,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -49,25 +50,21 @@ namespace ix
|
|||||||
int sockfd,
|
int sockfd,
|
||||||
std::shared_ptr<SelectInterrupt> selectInterrupt)
|
std::shared_ptr<SelectInterrupt> selectInterrupt)
|
||||||
{
|
{
|
||||||
fd_set rfds;
|
//
|
||||||
fd_set wfds;
|
// We used to use ::select to poll but on Android 9 we get large fds out of ::connect
|
||||||
fd_set efds;
|
// which crash in FD_SET as they are larger than FD_SETSIZE.
|
||||||
FD_ZERO(&rfds);
|
// Switching to ::poll does fix that.
|
||||||
FD_ZERO(&wfds);
|
//
|
||||||
FD_ZERO(&efds);
|
// However poll isn't as portable as select and has bugs on Windows, so we should write a
|
||||||
|
// shim to fallback to select on those platforms.
|
||||||
|
// See https://github.com/mpv-player/mpv/pull/5203/files for such a select wrapper.
|
||||||
|
//
|
||||||
|
int nfds = 1;
|
||||||
|
struct pollfd fds[2];
|
||||||
|
|
||||||
// FD_SET cannot handle fds larger than FD_SETSIZE.
|
fds[0].fd = sockfd;
|
||||||
if (sockfd >= FD_SETSIZE)
|
fds[0].events = (readyToRead) ? POLLIN : POLLOUT;
|
||||||
{
|
fds[0].events |= POLLERR;
|
||||||
return PollResultType::Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_set* fds = (readyToRead) ? &rfds : & wfds;
|
|
||||||
if (sockfd != -1)
|
|
||||||
{
|
|
||||||
FD_SET(sockfd, fds);
|
|
||||||
FD_SET(sockfd, &efds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// File descriptor used to interrupt select when needed
|
// File descriptor used to interrupt select when needed
|
||||||
int interruptFd = -1;
|
int interruptFd = -1;
|
||||||
@ -75,27 +72,15 @@ namespace ix
|
|||||||
{
|
{
|
||||||
interruptFd = selectInterrupt->getFd();
|
interruptFd = selectInterrupt->getFd();
|
||||||
|
|
||||||
// FD_SET cannot handle fds larger than FD_SETSIZE.
|
|
||||||
if (interruptFd >= FD_SETSIZE)
|
|
||||||
{
|
|
||||||
return PollResultType::Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interruptFd != -1)
|
if (interruptFd != -1)
|
||||||
{
|
{
|
||||||
FD_SET(interruptFd, fds);
|
nfds = 2;
|
||||||
|
fds[1].fd = interruptFd;
|
||||||
|
fds[1].events = POLLIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval timeout;
|
int ret = ::poll(fds, nfds, timeoutMs);
|
||||||
timeout.tv_sec = timeoutMs / 1000;
|
|
||||||
timeout.tv_usec = 1000 * (timeoutMs % 1000);
|
|
||||||
|
|
||||||
// Compute the highest fd.
|
|
||||||
int nfds = (std::max)(sockfd, interruptFd);
|
|
||||||
|
|
||||||
int ret = ::select(nfds + 1, &rfds, &wfds, &efds,
|
|
||||||
(timeoutMs < 0) ? nullptr : &timeout);
|
|
||||||
|
|
||||||
PollResultType pollResult = PollResultType::ReadyForRead;
|
PollResultType pollResult = PollResultType::ReadyForRead;
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -106,7 +91,7 @@ namespace ix
|
|||||||
{
|
{
|
||||||
pollResult = PollResultType::Timeout;
|
pollResult = PollResultType::Timeout;
|
||||||
}
|
}
|
||||||
else if (interruptFd != -1 && FD_ISSET(interruptFd, &rfds))
|
else if (interruptFd != -1 && fds[1].revents & POLLIN)
|
||||||
{
|
{
|
||||||
uint64_t value = selectInterrupt->read();
|
uint64_t value = selectInterrupt->read();
|
||||||
|
|
||||||
@ -119,17 +104,17 @@ namespace ix
|
|||||||
pollResult = PollResultType::CloseRequest;
|
pollResult = PollResultType::CloseRequest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sockfd != -1 && readyToRead && FD_ISSET(sockfd, &rfds))
|
else if (sockfd != -1 && readyToRead && fds[0].revents & POLLIN)
|
||||||
{
|
{
|
||||||
pollResult = PollResultType::ReadyForRead;
|
pollResult = PollResultType::ReadyForRead;
|
||||||
}
|
}
|
||||||
else if (sockfd != -1 && !readyToRead && FD_ISSET(sockfd, &wfds))
|
else if (sockfd != -1 && !readyToRead && fds[0].revents & POLLOUT)
|
||||||
{
|
{
|
||||||
pollResult = PollResultType::ReadyForWrite;
|
pollResult = PollResultType::ReadyForWrite;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// On connect error, in async mode, windows will write to the exceptions fds
|
// On connect error, in async mode, windows will write to the exceptions fds
|
||||||
if (FD_ISSET(fd, &efds))
|
if (fds[0].revents & POLLERR)
|
||||||
{
|
{
|
||||||
pollResult = PollResultType::Error;
|
pollResult = PollResultType::Error;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user