aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasil Dimov <vd@FreeBSD.org>2021-05-04 12:06:44 +0200
committerVasil Dimov <vd@FreeBSD.org>2022-06-09 13:34:27 +0200
commitcc74459768063a923fb6220a4f420eaf211aee7b (patch)
treed0d044422b29af67de3f064963024210f66c89d5
parente18fd4763e77d1e19208effa9f1a08c5b29fea8e (diff)
net: also wait for exceptional events in Sock::Wait()
This mimics closely `CConnman::SocketEvents()` and the underlying `poll(2)`.
-rw-r--r--src/i2p.cpp4
-rw-r--r--src/util/sock.cpp12
-rw-r--r--src/util/sock.h19
3 files changed, 26 insertions, 9 deletions
diff --git a/src/i2p.cpp b/src/i2p.cpp
index e08b5461fe..1ebc1052b1 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -150,8 +150,8 @@ bool Session::Accept(Connection& conn)
throw std::runtime_error("wait on socket failed");
}
- if ((occurred & Sock::RECV) == 0) {
- // Timeout, no incoming connections within MAX_WAIT_FOR_IO.
+ if (occurred == 0) {
+ // Timeout, no incoming connections or errors within MAX_WAIT_FOR_IO.
continue;
}
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index 3579af4458..8b86cf74ab 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -136,6 +136,9 @@ bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occur
if (fd.revents & POLLOUT) {
*occurred |= SEND;
}
+ if (fd.revents & (POLLERR | POLLHUP)) {
+ *occurred |= ERR;
+ }
}
return true;
@@ -146,8 +149,10 @@ bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occur
fd_set fdset_recv;
fd_set fdset_send;
+ fd_set fdset_err;
FD_ZERO(&fdset_recv);
FD_ZERO(&fdset_send);
+ FD_ZERO(&fdset_err);
if (requested & RECV) {
FD_SET(m_socket, &fdset_recv);
@@ -157,9 +162,11 @@ bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occur
FD_SET(m_socket, &fdset_send);
}
+ FD_SET(m_socket, &fdset_err);
+
timeval timeout_struct = MillisToTimeval(timeout);
- if (select(m_socket + 1, &fdset_recv, &fdset_send, nullptr, &timeout_struct) == SOCKET_ERROR) {
+ if (select(m_socket + 1, &fdset_recv, &fdset_send, &fdset_err, &timeout_struct) == SOCKET_ERROR) {
return false;
}
@@ -171,6 +178,9 @@ bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occur
if (FD_ISSET(m_socket, &fdset_send)) {
*occurred |= SEND;
}
+ if (FD_ISSET(m_socket, &fdset_err)) {
+ *occurred |= ERR;
+ }
}
return true;
diff --git a/src/util/sock.h b/src/util/sock.h
index dd2913a66c..e6419eb8ce 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -130,21 +130,28 @@ public:
/**
* If passed to `Wait()`, then it will wait for readiness to read from the socket.
*/
- static constexpr Event RECV = 0b01;
+ static constexpr Event RECV = 0b001;
/**
* If passed to `Wait()`, then it will wait for readiness to send to the socket.
*/
- static constexpr Event SEND = 0b10;
+ static constexpr Event SEND = 0b010;
+
+ /**
+ * Ignored if passed to `Wait()`, but could be set in the occurred events if an
+ * exceptional condition has occurred on the socket or if it has been disconnected.
+ */
+ static constexpr Event ERR = 0b100;
/**
* Wait for readiness for input (recv) or output (send).
* @param[in] timeout Wait this much for at least one of the requested events to occur.
* @param[in] requested Wait for those events, bitwise-or of `RECV` and `SEND`.
- * @param[out] occurred If not nullptr and `true` is returned, then upon return this
- * indicates which of the requested events occurred. A timeout is indicated by return
- * value of `true` and `occurred` being set to 0.
- * @return true on success and false otherwise
+ * @param[out] occurred If not nullptr and the function returns `true`, then this
+ * indicates which of the requested events occurred (`ERR` will be added, even if
+ * not requested, if an exceptional event occurs on the socket).
+ * A timeout is indicated by return value of `true` and `occurred` being set to 0.
+ * @return true on success (or timeout, if `occurred` of 0 is returned), false otherwise
*/
[[nodiscard]] virtual bool Wait(std::chrono::milliseconds timeout,
Event requested,