* Read bytes from socket. This will either read the full number of bytes requested * or return False on error or timeout. * This function can be interrupted by calling InterruptSocks5() * * @param data Buffer to receive into * @param len Length of data to receive * @param timeout Timeout in milliseconds for receive operation * * @note This function requires that hSocket is in non-blockin
| 245 | * @note This function requires that hSocket is in non-blocking mode. |
| 246 | */ |
| 247 | static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket) |
| 248 | { |
| 249 | int64_t curTime = GetTimeMillis(); |
| 250 | int64_t endTime = curTime + timeout; |
| 251 | // Maximum time to wait in one select call. It will take up until this time (in millis) |
| 252 | // to break off in case of an interruption. |
| 253 | const int64_t maxWait = 1000; |
| 254 | while (len > 0 && curTime < endTime) { |
| 255 | ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first |
| 256 | if (ret > 0) { |
| 257 | len -= ret; |
| 258 | data += ret; |
| 259 | } else if (ret == 0) { // Unexpected disconnection |
| 260 | return IntrRecvError::Disconnected; |
| 261 | } else { // Other error or blocking |
| 262 | int nErr = WSAGetLastError(); |
| 263 | if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { |
| 264 | if (!IsSelectableSocket(hSocket)) { |
| 265 | return IntrRecvError::NetworkError; |
| 266 | } |
| 267 | struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); |
| 268 | fd_set fdset; |
| 269 | FD_ZERO(&fdset); |
| 270 | FD_SET(hSocket, &fdset); |
| 271 | int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval); |
| 272 | if (nRet == SOCKET_ERROR) { |
| 273 | return IntrRecvError::NetworkError; |
| 274 | } |
| 275 | } else { |
| 276 | return IntrRecvError::NetworkError; |
| 277 | } |
| 278 | } |
| 279 | if (interruptSocks5Recv) |
| 280 | return IntrRecvError::Interrupted; |
| 281 | curTime = GetTimeMillis(); |
| 282 | } |
| 283 | return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout; |
| 284 | } |
| 285 | |
| 286 | /** Credentials for proxy authentication */ |
| 287 | struct ProxyCredentials |
no test coverage detected