diff options
author | Vasil Dimov <vd@FreeBSD.org> | 2021-05-04 12:06:44 +0200 |
---|---|---|
committer | Vasil Dimov <vd@FreeBSD.org> | 2022-06-09 13:34:27 +0200 |
commit | cc74459768063a923fb6220a4f420eaf211aee7b (patch) | |
tree | d0d044422b29af67de3f064963024210f66c89d5 | |
parent | e18fd4763e77d1e19208effa9f1a08c5b29fea8e (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.cpp | 4 | ||||
-rw-r--r-- | src/util/sock.cpp | 12 | ||||
-rw-r--r-- | src/util/sock.h | 19 |
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, |