/** * 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 boost thread interrupt. * * @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-blocking mode. */ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket) { int64_t curTime = GetTimeMillis(); int64_t endTime = curTime + timeout; // Maximum time to wait in one select call. It will take up until this time (in millis) // to break off in case of an interruption. const int64_t maxWait = 1000; while (len > 0 && curTime < endTime) { ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first if (ret > 0) { len -= ret; data += ret; } else if (ret == 0) { // Unexpected disconnection return false; } else { // Other error or blocking int nErr = WSAGetLastError(); if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); fd_set fdset; FD_ZERO(&fdset); FD_SET(hSocket, &fdset); int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval); if (nRet == SOCKET_ERROR) { return false; } } else { return false; } } boost::this_thread::interruption_point(); curTime = GetTimeMillis(); } return len == 0; }
void TorController::disconnected_cb(TorControlConnection& conn) { // Stop advertising service when disconnected if (service.IsValid()) RemoveLocal(service); service = CService(); if (!reconnect) return; LogPrint("tor", "tor: Not connected to Tor control port %s, trying to reconnect\n", target); // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); if (reconnect_ev) event_add(reconnect_ev, &time); reconnect_timeout *= RECONNECT_TIMEOUT_EXP; }