Skip to content

Commit 7e1007a

Browse files
committed
Merge bitcoin/bitcoin#25421: net: convert standalone IsSelectableSocket() and SetSocketNonBlocking() to Sock methods
b527b54 net: convert standalone SetSocketNonBlocking() to Sock::SetNonBlocking() (Vasil Dimov) 29f66f7 moveonly: move SetSocketNonBlocking() from netbase to util/sock (Vasil Dimov) b4bac55 net: convert standalone IsSelectableSocket() to Sock::IsSelectable() (Vasil Dimov) 5db7d2c moveonly: move IsSelectableSocket() from compat.h to sock.{h,cpp} (Vasil Dimov) Pull request description: _This is a piece of #21878, chopped off to ease review._ * convert standalone `IsSelectableSocket()` to `Sock::IsSelectable()` * convert standalone `SetSocketNonBlocking()` to `Sock::SetNonBlocking()` This further encapsulates syscalls inside the `Sock` class and makes the callers mockable. ACKs for top commit: jonatack: ACK b527b54 review/debug build/unit tests at each commit, cross-referenced the changes with `man select` and `man errno`, ran a signet node on the last commit with ip4/ip6//tor/i2p/cjdns and network connections were nominal dergoegge: Code review ACK b527b54 Tree-SHA512: af783ce558c7a89e173f7ab323fb3517103d765c19b5d14de29f64706b4e1fea3653492e8ea73ae972699986aaddf2ae72c7cfaa7dad7614254283083b7d2632
2 parents cc12b89 + b527b54 commit 7e1007a

File tree

9 files changed

+80
-34
lines changed

9 files changed

+80
-34
lines changed

src/compat/compat.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,6 @@ typedef char* sockopt_arg_type;
109109
#define USE_POLL
110110
#endif
111111

112-
bool static inline IsSelectableSocket(const SOCKET& s) {
113-
#if defined(USE_POLL) || defined(WIN32)
114-
return true;
115-
#else
116-
return (s < FD_SETSIZE);
117-
#endif
118-
}
119-
120112
// MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define it as 0
121113
#if !defined(MSG_NOSIGNAL)
122114
#define MSG_NOSIGNAL 0

src/net.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
970970
return;
971971
}
972972

973-
if (!IsSelectableSocket(sock->Get()))
974-
{
973+
if (!sock->IsSelectable()) {
975974
LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
976975
return;
977976
}

src/netbase.cpp

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,7 @@ enum class IntrRecvError {
304304
* read.
305305
*
306306
* @see This function can be interrupted by calling InterruptSocks5(bool).
307-
* Sockets can be made non-blocking with SetSocketNonBlocking(const
308-
* SOCKET&).
307+
* Sockets can be made non-blocking with Sock::SetNonBlocking().
309308
*/
310309
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock)
311310
{
@@ -503,7 +502,7 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
503502

504503
// Ensure that waiting for I/O on this socket won't result in undefined
505504
// behavior.
506-
if (!IsSelectableSocket(sock->Get())) {
505+
if (!sock->IsSelectable()) {
507506
LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
508507
return nullptr;
509508
}
@@ -525,7 +524,7 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
525524
}
526525

527526
// Set the non-blocking option on the socket.
528-
if (!SetSocketNonBlocking(sock->Get())) {
527+
if (!sock->SetNonBlocking()) {
529528
LogPrintf("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError()));
530529
return nullptr;
531530
}
@@ -717,21 +716,6 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
717716
return false;
718717
}
719718

720-
bool SetSocketNonBlocking(const SOCKET& hSocket)
721-
{
722-
#ifdef WIN32
723-
u_long nOne = 1;
724-
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
725-
#else
726-
int fFlags = fcntl(hSocket, F_GETFL, 0);
727-
if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
728-
#endif
729-
return false;
730-
}
731-
732-
return true;
733-
}
734-
735719
void InterruptSocks5(bool interrupt)
736720
{
737721
interruptSocks5Recv = interrupt;

src/netbase.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,6 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
221221
*/
222222
bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
223223

224-
/** Enable non-blocking mode for a socket */
225-
bool SetSocketNonBlocking(const SOCKET& hSocket);
226224
void InterruptSocks5(bool interrupt);
227225

228226
/**

src/test/fuzz/util.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <memory>
1717

1818
FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
19-
: m_fuzzed_data_provider{fuzzed_data_provider}
19+
: m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()}
2020
{
2121
m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET);
2222
}
@@ -254,6 +254,24 @@ int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
254254
return 0;
255255
}
256256

257+
bool FuzzedSock::SetNonBlocking() const
258+
{
259+
constexpr std::array setnonblocking_errnos{
260+
EBADF,
261+
EPERM,
262+
};
263+
if (m_fuzzed_data_provider.ConsumeBool()) {
264+
SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
265+
return false;
266+
}
267+
return true;
268+
}
269+
270+
bool FuzzedSock::IsSelectable() const
271+
{
272+
return m_selectable;
273+
}
274+
257275
bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
258276
{
259277
constexpr std::array wait_errnos{

src/test/fuzz/util.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ class FuzzedSock : public Sock
4747
*/
4848
mutable std::optional<uint8_t> m_peek_data;
4949

50+
/**
51+
* Whether to pretend that the socket is select(2)-able. This is randomly set in the
52+
* constructor. It should remain constant so that repeated calls to `IsSelectable()`
53+
* return the same value.
54+
*/
55+
const bool m_selectable;
56+
5057
public:
5158
explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
5259

@@ -72,6 +79,10 @@ class FuzzedSock : public Sock
7279

7380
int GetSockName(sockaddr* name, socklen_t* name_len) const override;
7481

82+
bool SetNonBlocking() const override;
83+
84+
bool IsSelectable() const override;
85+
7586
bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
7687

7788
bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;

src/test/util/net.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ class StaticContentsSock : public Sock
166166
return 0;
167167
}
168168

169+
bool SetNonBlocking() const override { return true; }
170+
171+
bool IsSelectable() const override { return true; }
172+
169173
bool Wait(std::chrono::milliseconds timeout,
170174
Event requested,
171175
Event* occurred = nullptr) const override

src/util/sock.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,34 @@ int Sock::GetSockName(sockaddr* name, socklen_t* name_len) const
117117
return getsockname(m_socket, name, name_len);
118118
}
119119

120+
bool Sock::SetNonBlocking() const
121+
{
122+
#ifdef WIN32
123+
u_long on{1};
124+
if (ioctlsocket(m_socket, FIONBIO, &on) == SOCKET_ERROR) {
125+
return false;
126+
}
127+
#else
128+
const int flags{fcntl(m_socket, F_GETFL, 0)};
129+
if (flags == SOCKET_ERROR) {
130+
return false;
131+
}
132+
if (fcntl(m_socket, F_SETFL, flags | O_NONBLOCK) == SOCKET_ERROR) {
133+
return false;
134+
}
135+
#endif
136+
return true;
137+
}
138+
139+
bool Sock::IsSelectable() const
140+
{
141+
#if defined(USE_POLL) || defined(WIN32)
142+
return true;
143+
#else
144+
return m_socket < FD_SETSIZE;
145+
#endif
146+
}
147+
120148
bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
121149
{
122150
// We need a `shared_ptr` owning `this` for `WaitMany()`, but don't want
@@ -185,10 +213,10 @@ bool Sock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per
185213
SOCKET socket_max{0};
186214

187215
for (const auto& [sock, events] : events_per_sock) {
188-
const auto& s = sock->m_socket;
189-
if (!IsSelectableSocket(s)) {
216+
if (!sock->IsSelectable()) {
190217
return false;
191218
}
219+
const auto& s = sock->m_socket;
192220
if (events.requested & RECV) {
193221
FD_SET(s, &recv);
194222
}

src/util/sock.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,18 @@ class Sock
133133
*/
134134
[[nodiscard]] virtual int GetSockName(sockaddr* name, socklen_t* name_len) const;
135135

136+
/**
137+
* Set the non-blocking option on the socket.
138+
* @return true if set successfully
139+
*/
140+
[[nodiscard]] virtual bool SetNonBlocking() const;
141+
142+
/**
143+
* Check if the underlying socket can be used for `select(2)` (or the `Wait()` method).
144+
* @return true if selectable
145+
*/
146+
[[nodiscard]] virtual bool IsSelectable() const;
147+
136148
using Event = uint8_t;
137149

138150
/**

0 commit comments

Comments
 (0)