mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-06-18 04:41:21 +02:00
Implement poll() on systems which support it properly.
This eliminates the restriction on maximum socket descriptor number.
This commit is contained in:
parent
28211a4bc9
commit
11cc491a28
@ -92,8 +92,15 @@ typedef void* sockopt_arg_type;
|
|||||||
typedef char* sockopt_arg_type;
|
typedef char* sockopt_arg_type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Note these both should work with the current usage of poll, but best to be safe
|
||||||
|
// WIN32 poll is broken https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/
|
||||||
|
// __APPLE__ poll is broke https://github.com/bitcoin/bitcoin/pull/14336#issuecomment-437384408
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define USE_POLL
|
||||||
|
#endif
|
||||||
|
|
||||||
bool static inline IsSelectableSocket(const SOCKET& s) {
|
bool static inline IsSelectableSocket(const SOCKET& s) {
|
||||||
#ifdef WIN32
|
#if defined(USE_POLL) || defined(WIN32)
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return (s < FD_SETSIZE);
|
return (s < FD_SETSIZE);
|
||||||
|
49
src/net.cpp
49
src/net.cpp
@ -26,6 +26,10 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_POLL
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
#include <miniupnpc/miniupnpc.h>
|
#include <miniupnpc/miniupnpc.h>
|
||||||
#include <miniupnpc/miniwget.h>
|
#include <miniupnpc/miniwget.h>
|
||||||
@ -33,6 +37,7 @@
|
|||||||
#include <miniupnpc/upnperrors.h>
|
#include <miniupnpc/upnperrors.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@ -1307,6 +1312,49 @@ bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &s
|
|||||||
return !recv_set.empty() || !send_set.empty() || !error_set.empty();
|
return !recv_set.empty() || !send_set.empty() || !error_set.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_POLL
|
||||||
|
void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
|
||||||
|
{
|
||||||
|
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
|
||||||
|
if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
|
||||||
|
interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<SOCKET, struct pollfd> pollfds;
|
||||||
|
for (SOCKET socket_id : recv_select_set) {
|
||||||
|
pollfds[socket_id].fd = socket_id;
|
||||||
|
pollfds[socket_id].events |= POLLIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SOCKET socket_id : send_select_set) {
|
||||||
|
pollfds[socket_id].fd = socket_id;
|
||||||
|
pollfds[socket_id].events |= POLLOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SOCKET socket_id : error_select_set) {
|
||||||
|
pollfds[socket_id].fd = socket_id;
|
||||||
|
// These flags are ignored, but we set them for clarity
|
||||||
|
pollfds[socket_id].events |= POLLERR|POLLHUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<struct pollfd> vpollfds;
|
||||||
|
vpollfds.reserve(pollfds.size());
|
||||||
|
for (auto it : pollfds) {
|
||||||
|
vpollfds.push_back(std::move(it.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poll(vpollfds.data(), vpollfds.size(), SELECT_TIMEOUT_MILLISECONDS) < 0) return;
|
||||||
|
|
||||||
|
if (interruptNet) return;
|
||||||
|
|
||||||
|
for (struct pollfd pollfd_entry : vpollfds) {
|
||||||
|
if (pollfd_entry.revents & POLLIN) recv_set.insert(pollfd_entry.fd);
|
||||||
|
if (pollfd_entry.revents & POLLOUT) send_set.insert(pollfd_entry.fd);
|
||||||
|
if (pollfd_entry.revents & (POLLERR|POLLHUP)) error_set.insert(pollfd_entry.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
|
void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
|
||||||
{
|
{
|
||||||
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
|
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
|
||||||
@ -1380,6 +1428,7 @@ void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void CConnman::SocketHandler()
|
void CConnman::SocketHandler()
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_POLL
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(MSG_NOSIGNAL)
|
#if !defined(MSG_NOSIGNAL)
|
||||||
#define MSG_NOSIGNAL 0
|
#define MSG_NOSIGNAL 0
|
||||||
#endif
|
#endif
|
||||||
@ -264,11 +268,19 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
|
|||||||
if (!IsSelectableSocket(hSocket)) {
|
if (!IsSelectableSocket(hSocket)) {
|
||||||
return IntrRecvError::NetworkError;
|
return IntrRecvError::NetworkError;
|
||||||
}
|
}
|
||||||
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
|
int timeout_ms = std::min(endTime - curTime, maxWait);
|
||||||
|
#ifdef USE_POLL
|
||||||
|
struct pollfd pollfd = {};
|
||||||
|
pollfd.fd = hSocket;
|
||||||
|
pollfd.events = POLLIN | POLLOUT;
|
||||||
|
int nRet = poll(&pollfd, 1, timeout_ms);
|
||||||
|
#else
|
||||||
|
struct timeval tval = MillisToTimeval(timeout_ms);
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(hSocket, &fdset);
|
FD_SET(hSocket, &fdset);
|
||||||
int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
|
int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
|
||||||
|
#endif
|
||||||
if (nRet == SOCKET_ERROR) {
|
if (nRet == SOCKET_ERROR) {
|
||||||
return IntrRecvError::NetworkError;
|
return IntrRecvError::NetworkError;
|
||||||
}
|
}
|
||||||
@ -499,11 +511,18 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
|
|||||||
// WSAEINVAL is here because some legacy version of winsock uses it
|
// WSAEINVAL is here because some legacy version of winsock uses it
|
||||||
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
|
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_POLL
|
||||||
|
struct pollfd pollfd = {};
|
||||||
|
pollfd.fd = hSocket;
|
||||||
|
pollfd.events = POLLIN | POLLOUT;
|
||||||
|
int nRet = poll(&pollfd, 1, nTimeout);
|
||||||
|
#else
|
||||||
struct timeval timeout = MillisToTimeval(nTimeout);
|
struct timeval timeout = MillisToTimeval(nTimeout);
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(hSocket, &fdset);
|
FD_SET(hSocket, &fdset);
|
||||||
int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
|
int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
|
||||||
|
#endif
|
||||||
if (nRet == 0)
|
if (nRet == 0)
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
|
LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user