Branch data Line data Source code
# 1 : : // Copyright (c) 2020-2021 The Bitcoin Core developers
# 2 : : // Distributed under the MIT software license, see the accompanying
# 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 4 : :
# 5 : : #include <compat.h>
# 6 : : #include <logging.h>
# 7 : : #include <threadinterrupt.h>
# 8 : : #include <tinyformat.h>
# 9 : : #include <util/sock.h>
# 10 : : #include <util/system.h>
# 11 : : #include <util/time.h>
# 12 : :
# 13 : : #include <memory>
# 14 : : #include <stdexcept>
# 15 : : #include <string>
# 16 : :
# 17 : : #ifdef WIN32
# 18 : : #include <codecvt>
# 19 : : #include <locale>
# 20 : : #endif
# 21 : :
# 22 : : #ifdef USE_POLL
# 23 : : #include <poll.h>
# 24 : : #endif
# 25 : :
# 26 : : static inline bool IOErrorIsPermanent(int err)
# 27 : 0 : {
# 28 [ # # ][ # # ]: 0 : return err != WSAEAGAIN && err != WSAEINTR && err != WSAEWOULDBLOCK && err != WSAEINPROGRESS;
# [ # # ][ # # ]
# 29 : 0 : }
# 30 : :
# 31 : 6 : Sock::Sock() : m_socket(INVALID_SOCKET) {}
# 32 : :
# 33 : 2575 : Sock::Sock(SOCKET s) : m_socket(s) {}
# 34 : :
# 35 : : Sock::Sock(Sock&& other)
# 36 : 4 : {
# 37 : 4 : m_socket = other.m_socket;
# 38 : 4 : other.m_socket = INVALID_SOCKET;
# 39 : 4 : }
# 40 : :
# 41 : 2585 : Sock::~Sock() { Reset(); }
# 42 : :
# 43 : : Sock& Sock::operator=(Sock&& other)
# 44 : 4 : {
# 45 : 4 : Reset();
# 46 : 4 : m_socket = other.m_socket;
# 47 : 4 : other.m_socket = INVALID_SOCKET;
# 48 : 4 : return *this;
# 49 : 4 : }
# 50 : :
# 51 : 3241061 : SOCKET Sock::Get() const { return m_socket; }
# 52 : :
# 53 : : SOCKET Sock::Release()
# 54 : 2 : {
# 55 : 2 : const SOCKET s = m_socket;
# 56 : 2 : m_socket = INVALID_SOCKET;
# 57 : 2 : return s;
# 58 : 2 : }
# 59 : :
# 60 : 2603 : void Sock::Reset() { CloseSocket(m_socket); }
# 61 : :
# 62 : : ssize_t Sock::Send(const void* data, size_t len, int flags) const
# 63 : 222211 : {
# 64 : 222211 : return send(m_socket, static_cast<const char*>(data), len, flags);
# 65 : 222211 : }
# 66 : :
# 67 : : ssize_t Sock::Recv(void* buf, size_t len, int flags) const
# 68 : 130436 : {
# 69 : 130436 : return recv(m_socket, static_cast<char*>(buf), len, flags);
# 70 : 130436 : }
# 71 : :
# 72 : : int Sock::Connect(const sockaddr* addr, socklen_t addr_len) const
# 73 : 434 : {
# 74 : 434 : return connect(m_socket, addr, addr_len);
# 75 : 434 : }
# 76 : :
# 77 : : std::unique_ptr<Sock> Sock::Accept(sockaddr* addr, socklen_t* addr_len) const
# 78 : 679 : {
# 79 : : #ifdef WIN32
# 80 : : static constexpr auto ERR = INVALID_SOCKET;
# 81 : : #else
# 82 : 679 : static constexpr auto ERR = SOCKET_ERROR;
# 83 : 679 : #endif
# 84 : :
# 85 : 679 : std::unique_ptr<Sock> sock;
# 86 : :
# 87 : 679 : const auto socket = accept(m_socket, addr, addr_len);
# 88 [ + - ]: 679 : if (socket != ERR) {
# 89 : 679 : try {
# 90 : 679 : sock = std::make_unique<Sock>(socket);
# 91 : 679 : } catch (const std::exception&) {
# 92 : : #ifdef WIN32
# 93 : : closesocket(socket);
# 94 : : #else
# 95 : 0 : close(socket);
# 96 : 0 : #endif
# 97 : 0 : }
# 98 : 679 : }
# 99 : :
# 100 : 679 : return sock;
# 101 : 679 : }
# 102 : :
# 103 : : int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
# 104 : 418 : {
# 105 : 418 : return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len);
# 106 : 418 : }
# 107 : :
# 108 : : bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
# 109 : 469 : {
# 110 : : #ifdef USE_POLL
# 111 : : pollfd fd;
# 112 : : fd.fd = m_socket;
# 113 : : fd.events = 0;
# 114 : : if (requested & RECV) {
# 115 : : fd.events |= POLLIN;
# 116 : : }
# 117 : : if (requested & SEND) {
# 118 : : fd.events |= POLLOUT;
# 119 : : }
# 120 : :
# 121 : : if (poll(&fd, 1, count_milliseconds(timeout)) == SOCKET_ERROR) {
# 122 : : return false;
# 123 : : }
# 124 : :
# 125 : : if (occurred != nullptr) {
# 126 : : *occurred = 0;
# 127 : : if (fd.revents & POLLIN) {
# 128 : : *occurred |= RECV;
# 129 : : }
# 130 : : if (fd.revents & POLLOUT) {
# 131 : : *occurred |= SEND;
# 132 : : }
# 133 : : }
# 134 : :
# 135 : : return true;
# 136 : : #else
# 137 [ - + ]: 469 : if (!IsSelectableSocket(m_socket)) {
# 138 : 0 : return false;
# 139 : 0 : }
# 140 : :
# 141 : 469 : fd_set fdset_recv;
# 142 : 469 : fd_set fdset_send;
# 143 : 469 : FD_ZERO(&fdset_recv);
# 144 : 469 : FD_ZERO(&fdset_send);
# 145 : :
# 146 [ + - ]: 469 : if (requested & RECV) {
# 147 : 469 : FD_SET(m_socket, &fdset_recv);
# 148 : 469 : }
# 149 : :
# 150 [ + + ]: 469 : if (requested & SEND) {
# 151 : 423 : FD_SET(m_socket, &fdset_send);
# 152 : 423 : }
# 153 : :
# 154 : 469 : timeval timeout_struct = MillisToTimeval(timeout);
# 155 : :
# 156 [ - + ]: 469 : if (select(m_socket + 1, &fdset_recv, &fdset_send, nullptr, &timeout_struct) == SOCKET_ERROR) {
# 157 : 0 : return false;
# 158 : 0 : }
# 159 : :
# 160 [ + + ]: 469 : if (occurred != nullptr) {
# 161 : 423 : *occurred = 0;
# 162 : 423 : if (FD_ISSET(m_socket, &fdset_recv)) {
# 163 : 0 : *occurred |= RECV;
# 164 : 0 : }
# 165 : 423 : if (FD_ISSET(m_socket, &fdset_send)) {
# 166 : 418 : *occurred |= SEND;
# 167 : 418 : }
# 168 : 423 : }
# 169 : :
# 170 : 469 : return true;
# 171 : 469 : #endif /* USE_POLL */
# 172 : 469 : }
# 173 : :
# 174 : : void Sock::SendComplete(const std::string& data,
# 175 : : std::chrono::milliseconds timeout,
# 176 : : CThreadInterrupt& interrupt) const
# 177 : 6 : {
# 178 : 6 : const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
# 179 : 6 : size_t sent{0};
# 180 : :
# 181 : 6 : for (;;) {
# 182 : 6 : const ssize_t ret{Send(data.data() + sent, data.size() - sent, MSG_NOSIGNAL)};
# 183 : :
# 184 [ + - ]: 6 : if (ret > 0) {
# 185 : 6 : sent += static_cast<size_t>(ret);
# 186 [ + - ]: 6 : if (sent == data.size()) {
# 187 : 6 : break;
# 188 : 6 : }
# 189 : 6 : } else {
# 190 : 0 : const int err{WSAGetLastError()};
# 191 [ # # ]: 0 : if (IOErrorIsPermanent(err)) {
# 192 : 0 : throw std::runtime_error(strprintf("send(): %s", NetworkErrorString(err)));
# 193 : 0 : }
# 194 : 0 : }
# 195 : :
# 196 : 0 : const auto now = GetTime<std::chrono::milliseconds>();
# 197 : :
# 198 [ # # ]: 0 : if (now >= deadline) {
# 199 : 0 : throw std::runtime_error(strprintf(
# 200 : 0 : "Send timeout (sent only %u of %u bytes before that)", sent, data.size()));
# 201 : 0 : }
# 202 : :
# 203 [ # # ]: 0 : if (interrupt) {
# 204 : 0 : throw std::runtime_error(strprintf(
# 205 : 0 : "Send interrupted (sent only %u of %u bytes before that)", sent, data.size()));
# 206 : 0 : }
# 207 : :
# 208 : : // Wait for a short while (or the socket to become ready for sending) before retrying
# 209 : : // if nothing was sent.
# 210 : 0 : const auto wait_time = std::min(deadline - now, std::chrono::milliseconds{MAX_WAIT_FOR_IO});
# 211 : 0 : (void)Wait(wait_time, SEND);
# 212 : 0 : }
# 213 : 6 : }
# 214 : :
# 215 : : std::string Sock::RecvUntilTerminator(uint8_t terminator,
# 216 : : std::chrono::milliseconds timeout,
# 217 : : CThreadInterrupt& interrupt,
# 218 : : size_t max_data) const
# 219 : 4 : {
# 220 : 4 : const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
# 221 : 4 : std::string data;
# 222 : 4 : bool terminator_found{false};
# 223 : :
# 224 : : // We must not consume any bytes past the terminator from the socket.
# 225 : : // One option is to read one byte at a time and check if we have read a terminator.
# 226 : : // However that is very slow. Instead, we peek at what is in the socket and only read
# 227 : : // as many bytes as possible without crossing the terminator.
# 228 : : // Reading 64 MiB of random data with 262526 terminator chars takes 37 seconds to read
# 229 : : // one byte at a time VS 0.71 seconds with the "peek" solution below. Reading one byte
# 230 : : // at a time is about 50 times slower.
# 231 : :
# 232 : 264 : for (;;) {
# 233 [ + + ]: 264 : if (data.size() >= max_data) {
# 234 : 4 : throw std::runtime_error(
# 235 : 4 : strprintf("Received too many bytes without a terminator (%u)", data.size()));
# 236 : 4 : }
# 237 : :
# 238 : 260 : char buf[512];
# 239 : :
# 240 : 260 : const ssize_t peek_ret{Recv(buf, std::min(sizeof(buf), max_data - data.size()), MSG_PEEK)};
# 241 : :
# 242 : 260 : switch (peek_ret) {
# 243 [ - + ]: 0 : case -1: {
# 244 : 0 : const int err{WSAGetLastError()};
# 245 [ # # ]: 0 : if (IOErrorIsPermanent(err)) {
# 246 : 0 : throw std::runtime_error(strprintf("recv(): %s", NetworkErrorString(err)));
# 247 : 0 : }
# 248 : 0 : break;
# 249 : 0 : }
# 250 [ - + ]: 0 : case 0:
# 251 : 0 : throw std::runtime_error("Connection unexpectedly closed by peer");
# 252 [ + - ]: 260 : default:
# 253 : 260 : auto end = buf + peek_ret;
# 254 : 260 : auto terminator_pos = std::find(buf, end, terminator);
# 255 : 260 : terminator_found = terminator_pos != end;
# 256 : :
# 257 [ - + ]: 260 : const size_t try_len{terminator_found ? terminator_pos - buf + 1 :
# 258 : 260 : static_cast<size_t>(peek_ret)};
# 259 : :
# 260 : 260 : const ssize_t read_ret{Recv(buf, try_len, 0)};
# 261 : :
# 262 [ - + ][ - + ]: 260 : if (read_ret < 0 || static_cast<size_t>(read_ret) != try_len) {
# 263 : 0 : throw std::runtime_error(
# 264 : 0 : strprintf("recv() returned %u bytes on attempt to read %u bytes but previous "
# 265 : 0 : "peek claimed %u bytes are available",
# 266 : 0 : read_ret, try_len, peek_ret));
# 267 : 0 : }
# 268 : :
# 269 : : // Don't include the terminator in the output.
# 270 [ - + ]: 260 : const size_t append_len{terminator_found ? try_len - 1 : try_len};
# 271 : :
# 272 : 260 : data.append(buf, buf + append_len);
# 273 : :
# 274 [ - + ]: 260 : if (terminator_found) {
# 275 : 0 : return data;
# 276 : 0 : }
# 277 : 260 : }
# 278 : :
# 279 : 260 : const auto now = GetTime<std::chrono::milliseconds>();
# 280 : :
# 281 [ - + ]: 260 : if (now >= deadline) {
# 282 : 0 : throw std::runtime_error(strprintf(
# 283 : 0 : "Receive timeout (received %u bytes without terminator before that)", data.size()));
# 284 : 0 : }
# 285 : :
# 286 [ - + ]: 260 : if (interrupt) {
# 287 : 0 : throw std::runtime_error(strprintf(
# 288 : 0 : "Receive interrupted (received %u bytes without terminator before that)",
# 289 : 0 : data.size()));
# 290 : 0 : }
# 291 : :
# 292 : : // Wait for a short while (or the socket to become ready for reading) before retrying.
# 293 : 260 : const auto wait_time = std::min(deadline - now, std::chrono::milliseconds{MAX_WAIT_FOR_IO});
# 294 : 260 : (void)Wait(wait_time, RECV);
# 295 : 260 : }
# 296 : 4 : }
# 297 : :
# 298 : : bool Sock::IsConnected(std::string& errmsg) const
# 299 : 12 : {
# 300 [ + - ]: 12 : if (m_socket == INVALID_SOCKET) {
# 301 : 12 : errmsg = "not connected";
# 302 : 12 : return false;
# 303 : 12 : }
# 304 : :
# 305 : 0 : char c;
# 306 : 0 : switch (Recv(&c, sizeof(c), MSG_PEEK)) {
# 307 [ # # ]: 0 : case -1: {
# 308 : 0 : const int err = WSAGetLastError();
# 309 [ # # ]: 0 : if (IOErrorIsPermanent(err)) {
# 310 : 0 : errmsg = NetworkErrorString(err);
# 311 : 0 : return false;
# 312 : 0 : }
# 313 : 0 : return true;
# 314 : 0 : }
# 315 [ # # ]: 0 : case 0:
# 316 : 0 : errmsg = "closed";
# 317 : 0 : return false;
# 318 [ # # ]: 0 : default:
# 319 : 0 : return true;
# 320 : 0 : }
# 321 : 0 : }
# 322 : :
# 323 : : #ifdef WIN32
# 324 : : std::string NetworkErrorString(int err)
# 325 : : {
# 326 : : wchar_t buf[256];
# 327 : : buf[0] = 0;
# 328 : : if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
# 329 : : nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
# 330 : : buf, ARRAYSIZE(buf), nullptr))
# 331 : : {
# 332 : : return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);
# 333 : : }
# 334 : : else
# 335 : : {
# 336 : : return strprintf("Unknown error (%d)", err);
# 337 : : }
# 338 : : }
# 339 : : #else
# 340 : : std::string NetworkErrorString(int err)
# 341 : 21 : {
# 342 : 21 : char buf[256];
# 343 : 21 : buf[0] = 0;
# 344 : : /* Too bad there are two incompatible implementations of the
# 345 : : * thread-safe strerror. */
# 346 : 21 : const char *s;
# 347 : : #ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
# 348 : : s = strerror_r(err, buf, sizeof(buf));
# 349 : : #else /* POSIX variant always returns message in buffer */
# 350 : 21 : s = buf;
# 351 [ - + ]: 21 : if (strerror_r(err, buf, sizeof(buf)))
# 352 : 0 : buf[0] = 0;
# 353 : 21 : #endif
# 354 : 21 : return strprintf("%s (%d)", s, err);
# 355 : 21 : }
# 356 : : #endif
# 357 : :
# 358 : : bool CloseSocket(SOCKET& hSocket)
# 359 : 2605 : {
# 360 [ + + ]: 2605 : if (hSocket == INVALID_SOCKET)
# 361 : 36 : return false;
# 362 : : #ifdef WIN32
# 363 : : int ret = closesocket(hSocket);
# 364 : : #else
# 365 : 2569 : int ret = close(hSocket);
# 366 : 2569 : #endif
# 367 [ - + ]: 2569 : if (ret) {
# 368 : 0 : LogPrintf("Socket close failed: %d. Error: %s\n", hSocket, NetworkErrorString(WSAGetLastError()));
# 369 : 0 : }
# 370 : 2569 : hSocket = INVALID_SOCKET;
# 371 : 2569 : return ret != SOCKET_ERROR;
# 372 : 2605 : }
|