| 172 | } |
| 173 | |
| 174 | void Sock::SendComplete(const std::string& data, |
| 175 | std::chrono::milliseconds timeout, |
| 176 | CThreadInterrupt& interrupt) const |
| 177 | { |
| 178 | const auto deadline = GetTime<std::chrono::milliseconds>() + timeout; |
| 179 | size_t sent{0}; |
| 180 | |
| 181 | for (;;) { |
| 182 | const ssize_t ret{Send(data.data() + sent, data.size() - sent, MSG_NOSIGNAL)}; |
| 183 | |
| 184 | if (ret > 0) { |
| 185 | sent += static_cast<size_t>(ret); |
| 186 | if (sent == data.size()) { |
| 187 | break; |
| 188 | } |
| 189 | } else { |
| 190 | const int err{WSAGetLastError()}; |
| 191 | if (IOErrorIsPermanent(err)) { |
| 192 | throw std::runtime_error(strprintf("send(): %s", NetworkErrorString(err))); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | const auto now = GetTime<std::chrono::milliseconds>(); |
| 197 | |
| 198 | if (now >= deadline) { |
| 199 | throw std::runtime_error(strprintf( |
| 200 | "Send timeout (sent only %u of %u bytes before that)", sent, data.size())); |
| 201 | } |
| 202 | |
| 203 | if (interrupt) { |
| 204 | throw std::runtime_error(strprintf( |
| 205 | "Send interrupted (sent only %u of %u bytes before that)", sent, data.size())); |
| 206 | } |
| 207 | |
| 208 | // Wait for a short while (or the socket to become ready for sending) before retrying |
| 209 | // if nothing was sent. |
| 210 | const auto wait_time = std::min(deadline - now, std::chrono::milliseconds{MAX_WAIT_FOR_IO}); |
| 211 | (void)Wait(wait_time, SEND); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | std::string Sock::RecvUntilTerminator(uint8_t terminator, |
| 216 | std::chrono::milliseconds timeout, |