Skip to content

Commit

Permalink
sock: introduce a generic Sock::SendComplete(const void*, size_t, ...)
Browse files Browse the repository at this point in the history
Use that in `Sock::SendComplete(const std::string&, ...)` and introduce
a new `Sock::SendComplete(const std::vector<uint8_t>&, ...)` to be used
in the `Socks5()` function.
  • Loading branch information
vasild committed Oct 13, 2023
1 parent 73dfa6d commit 70917bd
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 5 deletions.
25 changes: 20 additions & 5 deletions src/util/sock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,19 +242,20 @@ bool Sock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per
#endif /* USE_POLL */
}

void Sock::SendComplete(const std::string& data,
void Sock::SendComplete(const void* data,
size_t len,
std::chrono::milliseconds timeout,
CThreadInterrupt& interrupt) const
{
const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
size_t sent{0};

for (;;) {
const ssize_t ret{Send(data.data() + sent, data.size() - sent, MSG_NOSIGNAL)};
const ssize_t ret{Send(static_cast<const uint8_t*>(data) + sent, len - sent, MSG_NOSIGNAL)};

if (ret > 0) {
sent += static_cast<size_t>(ret);
if (sent == data.size()) {
if (sent == len) {
break;
}
} else {
Expand All @@ -268,12 +269,12 @@ void Sock::SendComplete(const std::string& data,

if (now >= deadline) {
throw std::runtime_error(strprintf(
"Send timeout (sent only %u of %u bytes before that)", sent, data.size()));
"Send timeout (sent only %u of %u bytes before that)", sent, len));
}

if (interrupt) {
throw std::runtime_error(strprintf(
"Send interrupted (sent only %u of %u bytes before that)", sent, data.size()));
"Send interrupted (sent only %u of %u bytes before that)", sent, len));
}

// Wait for a short while (or the socket to become ready for sending) before retrying
Expand All @@ -283,6 +284,20 @@ void Sock::SendComplete(const std::string& data,
}
}

void Sock::SendComplete(const std::string& data,
std::chrono::milliseconds timeout,
CThreadInterrupt& interrupt) const
{
SendComplete(data.data(), data.size(), timeout, interrupt);
}

void Sock::SendComplete(const std::vector<uint8_t>& data,
std::chrono::milliseconds timeout,
CThreadInterrupt& interrupt) const
{
SendComplete(data.data(), data.size(), timeout, interrupt);
}

std::string Sock::RecvUntilTerminator(uint8_t terminator,
std::chrono::milliseconds timeout,
CThreadInterrupt& interrupt,
Expand Down
16 changes: 16 additions & 0 deletions src/util/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,15 +223,31 @@ class Sock
/**
* Send the given data, retrying on transient errors.
* @param[in] data Data to send.
* @param[in] len Length of the data in bytes.
* @param[in] timeout Timeout for the entire operation.
* @param[in] interrupt If this is signaled then the operation is canceled.
* @throws std::runtime_error if the operation cannot be completed. In this case only some of
* the data will be written to the socket.
*/
virtual void SendComplete(const void* data,
size_t len,
std::chrono::milliseconds timeout,
CThreadInterrupt& interrupt) const;

/**
* Convenience method, equivalent to `SendComplete(data.data(), data.size(), timeout, interrupt)`.
*/
virtual void SendComplete(const std::string& data,
std::chrono::milliseconds timeout,
CThreadInterrupt& interrupt) const;

/**
* Convenience method, equivalent to `SendComplete(data.data(), data.size(), timeout, interrupt)`.
*/
virtual void SendComplete(const std::vector<uint8_t>& data,
std::chrono::milliseconds timeout,
CThreadInterrupt& interrupt) const;

/**
* Read from socket until a terminator character is encountered. Will never consume bytes past
* the terminator from the socket.
Expand Down

0 comments on commit 70917bd

Please sign in to comment.