X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/8c6fa3fbaccc22127280bf77a48fab5a3ee0716e..46b0747592074017ff0ea4b33d4a7194235886e5:/libs/common/blockio.cpp diff --git a/libs/common/blockio.cpp b/libs/common/blockio.cpp new file mode 100644 index 00000000..04fd1d81 --- /dev/null +++ b/libs/common/blockio.cpp @@ -0,0 +1,102 @@ +#include "stg/blockio.h" + +namespace +{ + +void* adjust(void* base, size_t shift) +{ + char* ptr = static_cast(base); + return ptr + shift; +} + +} // namspace anonymous + +using STG::BlockReader; +using STG::BlockWriter; + +BlockReader::BlockReader(const IOVec& ioVec) + : m_dest(ioVec), + m_remainder(0) +{ + for (size_t i = 0; i < m_dest.size(); ++i) + m_remainder += m_dest[i].iov_len; +} + +bool BlockReader::read(int socket) +{ + if (m_remainder == 0) + return true; + + size_t offset = m_dest.size() - 1; + size_t toRead = m_remainder; + while (offset > 0) { + if (toRead < m_dest[offset].iov_len) + break; + toRead -= m_dest[offset].iov_len; + --offset; + } + + IOVec dest(m_dest.size() - offset); + for (size_t i = 0; i < dest.size(); ++i) { + if (i == 0) { + dest[0].iov_len = toRead; + dest[0].iov_base = adjust(m_dest[offset].iov_base, m_dest[offset].iov_len - toRead); + } else { + dest[i] = m_dest[offset + i]; + } + } + + ssize_t res = readv(socket, dest.data(), dest.size()); + if (res < 0) + return false; + if (res == 0) + return m_remainder == 0; + if (res < static_cast(m_remainder)) + m_remainder -= res; + else + m_remainder = 0; + return true; +} + +BlockWriter::BlockWriter(const IOVec& ioVec) + : m_source(ioVec), + m_remainder(0) +{ + for (size_t i = 0; i < m_source.size(); ++i) + m_remainder += m_source[i].iov_len; +} + +bool BlockWriter::write(int socket) +{ + if (m_remainder == 0) + return true; + + size_t offset = m_source.size() - 1; + size_t toWrite = m_remainder; + while (offset > 0) { + if (toWrite < m_source[offset].iov_len) + break; + toWrite -= m_source[offset].iov_len; + --offset; + } + + IOVec source(m_source.size() - offset); + for (size_t i = 0; i < source.size(); ++i) { + if (i == 0) { + source[0].iov_len = toWrite; + source[0].iov_base = adjust(m_source[offset].iov_base, m_source[offset].iov_len - toWrite); + } else { + source[i] = m_source[offset + i]; + } + } + ssize_t res = writev(socket, source.data(), source.size()); + if (res < 0) + return false; + if (res == 0) + return m_remainder == 0; + if (res < static_cast(m_remainder)) + m_remainder -= res; + else + m_remainder = 0; + return true; +}