Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash in select() call when file descriptor is above FD_SETSIZE #115

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 81 additions & 17 deletions servus/dnssd/servus.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
#include <poll.h>
#else
#include <winsock2.h>
#endif
#include <dns_sd.h>

Expand All @@ -41,12 +44,35 @@ class Servus : public servus::Servus::Impl
, _in(0)
, _result(servus::Servus::Result::PENDING)
{
#ifdef _MSC_VER
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
const int error = WSAGetLastError();
char errorMessage[256] = {0};

FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)errorMessage,
sizeof(errorMessage),
NULL
);

WARN << "WSAStartup error (" << error << "): " << errorMessage;

_result = servus::Servus::Result::POLL_ERROR;
}
#endif
}

virtual ~Servus()
{
withdraw();
endBrowsing();
#ifdef _MSC_VER
WSACleanup();
#endif
}

std::string getClassName() const { return "dnssd"; }
Expand Down Expand Up @@ -114,6 +140,9 @@ class Servus : public servus::Servus::Impl
DNSServiceRef _in; //!< used to browse()
int32_t _result;
std::string _browsedName;
#ifdef _MSC_VER
WSADATA wsaData;
#endif

servus::Servus::Result _browse(const ::servus::Servus::Interface addr)
{
Expand Down Expand Up @@ -160,41 +189,35 @@ class Servus : public servus::Servus::Impl
}
}

servus::Servus::Result _handleEvents(DNSServiceRef service,
const int32_t timeout = -1)
servus::Servus::Result _handleEvents(DNSServiceRef service, const int32_t timeout = -1)
{
assert(service);
if (!service)
return servus::Servus::Result(kDNSServiceErr_Unknown);

const int fd = DNSServiceRefSockFD(service);
const int nfds = fd + 1;

assert(fd >= 0);
if (fd < 0)
return servus::Servus::Result(kDNSServiceErr_BadParam);

#ifndef _MSC_VER
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN;

while (_result == servus::Servus::Result::PENDING)
{
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(fd, &fdSet);

struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;

const int result =
::select(nfds, &fdSet, 0, 0, timeout < 0 ? 0 : &tv);
const int result = poll(&fds, 1, timeout);
switch (result)
{
case 0: // timeout
_result = kDNSServiceErr_NoError;
break;

case -1: // error
WARN << "Select error: " << strerror(errno) << " (" << errno
<< ")" << std::endl;
WARN << "Poll error: " << strerror(errno) << " (" << errno
<< ")" << std::endl;
if (errno != EINTR)
{
withdraw();
Expand All @@ -203,23 +226,64 @@ class Servus : public servus::Servus::Impl
break;

default:
if (FD_ISSET(fd, &fdSet))
if (fds.revents & POLLIN)
{
const DNSServiceErrorType error =
DNSServiceProcessResult(service);

if (error != kDNSServiceErr_NoError)
{
WARN << "DNSServiceProcessResult error: " << error
<< std::endl;
<< std::endl;
withdraw();
_result = error;
}
}
break;
}
}
#else
WSAPOLLFD fds;
fds.fd = fd;
fds.events = POLLIN;

while (_result == servus::Servus::Result::PENDING)
{
const int result = WSAPoll(&fds, 1, timeout);
switch (result)
{
case 0: // timeout
_result = kDNSServiceErr_NoError;
break;

case -1: // error
WARN << "WSAPoll error: " << WSAGetLastError()
<< std::endl;
if (WSAGetLastError() != WSAEINTR)
{
withdraw();
_result = WSAGetLastError();
}
break;

default:
if (fds.revents & POLLIN)
{
const DNSServiceErrorType error =
DNSServiceProcessResult(service);

if (error != kDNSServiceErr_NoError)
{
WARN << "DNSServiceProcessResult error: " << error
<< std::endl;
withdraw();
_result = error;
}
}
break;
}
}
#endif
const servus::Servus::Result result(_result);
_result = servus::Servus::Result::PENDING; // reset for next operation
return result;
Expand Down