diff --git a/include/envoy/api/io_error.h b/include/envoy/api/io_error.h index e1f4af3b1df7f..91c0a88e76f7f 100644 --- a/include/envoy/api/io_error.h +++ b/include/envoy/api/io_error.h @@ -9,16 +9,6 @@ namespace Envoy { namespace Api { -class IoError; - -// IoErrorCode::Again is used frequently. Define it to be a distinguishable address to avoid -// frequent memory allocation of IoError instance. -// If this is used, IoCallResult has to be instantiated with a deleter that does not -// deallocate memory for this error. -// TODO: This is probably not the best way to avoid allocations in the case of -// EAGAIN. This will be fixed as a part of #6037. -#define ENVOY_ERROR_AGAIN reinterpret_cast(0x01) - /** * Base class for any I/O error. */ @@ -35,32 +25,13 @@ class IoError { InProgress, // Permission denied. Permission, - // Bad handle - BadHandle, // Other error codes cannot be mapped to any one above in getErrorCode(). UnknownError }; virtual ~IoError() {} - // Map platform specific error into IoErrorCode. - // Needed to hide errorCode() in case of ENVOY_ERROR_AGAIN. - static IoErrorCode getErrorCode(const IoError& err) { - if (&err == ENVOY_ERROR_AGAIN) { - return IoErrorCode::Again; - } - return err.errorCode(); - } - - static std::string getErrorDetails(const IoError& err) { - if (&err == ENVOY_ERROR_AGAIN) { - return "Try again later"; - } - return err.errorDetails(); - } - -protected: - virtual IoErrorCode errorCode() const PURE; - virtual std::string errorDetails() const PURE; + virtual IoErrorCode getErrorCode() const PURE; + virtual std::string getErrorDetails() const PURE; }; using IoErrorDeleterType = void (*)(IoError*); @@ -69,19 +40,39 @@ using IoErrorPtr = std::unique_ptr; /** * Basic type for return result which has a return code and error code defined * according to different implementations. + * If the call succeeds, ok() should return true and |rc_| is valid. Otherwise |err_| + * can be passed into IoError::getErrorCode() to extract the error. In this + * case, |rc_| is invalid. */ -template struct IoCallResult { - IoCallResult(T rc, IoErrorPtr err) : rc_(rc), err_(std::move(err)) {} +template struct IoCallResult { + IoCallResult(ReturnValue rc, IoErrorPtr err) : rc_(rc), err_(std::move(err)) {} - IoCallResult(IoCallResult&& result) : rc_(result.rc_), err_(std::move(result.err_)) {} + IoCallResult(IoCallResult&& result) + : rc_(result.rc_), err_(std::move(result.err_)) {} virtual ~IoCallResult() {} - T rc_; + IoCallResult& operator=(IoCallResult&& result) { + rc_ = result.rc_; + err_ = std::move(result.err_); + return *this; + } + + /** + * @return true if the call succeeds. + */ + bool ok() const { return err_ == nullptr; } + + // TODO(danzh): rename it to be more meaningful, i.e. return_value_. + ReturnValue rc_; IoErrorPtr err_; }; -using IoCallUintResult = IoCallResult; +using IoCallUint64Result = IoCallResult; + +inline Api::IoCallUint64Result ioCallUint64ResultNoError() { + return IoCallUint64Result(0, IoErrorPtr(nullptr, [](IoError*) {})); +} } // namespace Api } // namespace Envoy diff --git a/include/envoy/buffer/BUILD b/include/envoy/buffer/BUILD index 3f04200863700..2a24c6fa24099 100644 --- a/include/envoy/buffer/BUILD +++ b/include/envoy/buffer/BUILD @@ -13,6 +13,7 @@ envoy_cc_library( hdrs = ["buffer.h"], deps = [ "//include/envoy/api:os_sys_calls_interface", + "//include/envoy/network:io_handle_interface", "//source/common/common:byte_order_lib", ], ) diff --git a/include/envoy/buffer/buffer.h b/include/envoy/buffer/buffer.h index 647b73e1b90ad..48f5c1842a0f6 100644 --- a/include/envoy/buffer/buffer.h +++ b/include/envoy/buffer/buffer.h @@ -8,6 +8,7 @@ #include "envoy/api/os_sys_calls.h" #include "envoy/common/exception.h" #include "envoy/common/pure.h" +#include "envoy/network/io_handle.h" #include "common/common/byte_order.h" @@ -165,12 +166,12 @@ class Instance { /** * Read from a file descriptor directly into the buffer. - * @param fd supplies the descriptor to read from. + * @param io_handle supplies the io handle to read from. * @param max_length supplies the maximum length to read. - * @return a Api::SysCallIntResult with rc_ = the number of bytes read if successful, or rc_ = -1 - * for failure. If the call is successful, errno_ shouldn't be used. + * @return a IoCallUint64Result with err_ = nullptr and rc_ = the number of bytes + * read if successful, or err_ = some IoError for failure. If call failed, rc_ shouldn't be used. */ - virtual Api::SysCallIntResult read(int fd, uint64_t max_length) PURE; + virtual Api::IoCallUint64Result read(Network::IoHandle& io_handle, uint64_t max_length) PURE; /** * Reserve space in the buffer. @@ -198,11 +199,12 @@ class Instance { /** * Write the buffer out to a file descriptor. - * @param fd supplies the descriptor to write to. - * @return a Api::SysCallIntResult with rc_ = the number of bytes written if successful, or rc_ = - * -1 for failure. If the call is successful, errno_ shouldn't be used. + * @param io_handle supplies the io_handle to write to. + * @return a IoCallUint64Result with err_ = nullptr and rc_ = the number of bytes + * written if successful, or err_ = some IoError for failure. If call failed, rc_ shouldn't be + * used. */ - virtual Api::SysCallIntResult write(int fd) PURE; + virtual Api::IoCallUint64Result write(Network::IoHandle& io_handle) PURE; /** * Copy an integer out of the buffer. diff --git a/include/envoy/network/io_handle.h b/include/envoy/network/io_handle.h index 9ea1f02f1c054..37ecec5d07344 100644 --- a/include/envoy/network/io_handle.h +++ b/include/envoy/network/io_handle.h @@ -1,12 +1,17 @@ #pragma once -#include - #include "envoy/api/io_error.h" #include "envoy/common/pure.h" namespace Envoy { +namespace Buffer { +struct RawSlice; +} // namespace Buffer + namespace Network { +namespace Address { +class Instance; +} // namespace Address /** * IoHandle: an abstract interface for all I/O operations @@ -26,12 +31,32 @@ class IoHandle { /** * Clean up IoHandle resources */ - virtual Api::IoCallUintResult close() PURE; + virtual Api::IoCallUint64Result close() PURE; /** * Return true if close() hasn't been called. */ virtual bool isOpen() const PURE; + + /** + * Read data into given slices. + * @param max_length supplies the maximum length to read. + * @param slices points to the output location. + * @param num_slice indicates the number of slices |slices| contains. + * @return a Api::IoCallUint64Result with err_ = an Api::IoError instance or + * err_ = nullptr and rc_ = the bytes read for success. + */ + virtual Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) PURE; + + /** + * Write the data in slices out. + * @param slices points to the location of data to be written. + * @param num_slice indicates number of slices |slices| contains. + * @return a Api::IoCallUint64Result with err_ = an Api::IoError instance or + * err_ = nullptr and rc_ = the bytes written for success. + */ + virtual Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) PURE; }; typedef std::unique_ptr IoHandlePtr; diff --git a/source/common/buffer/BUILD b/source/common/buffer/BUILD index 617cce095b2d0..f4e6d9602c190 100644 --- a/source/common/buffer/BUILD +++ b/source/common/buffer/BUILD @@ -24,7 +24,6 @@ envoy_cc_library( hdrs = ["buffer_impl.h"], deps = [ "//include/envoy/buffer:buffer_interface", - "//source/common/api:os_sys_calls_lib", "//source/common/common:non_copyable", "//source/common/common:stack_array", "//source/common/event:libevent_lib", diff --git a/source/common/buffer/buffer_impl.cc b/source/common/buffer/buffer_impl.cc index c09f743661cd4..d0f15d8154119 100644 --- a/source/common/buffer/buffer_impl.cc +++ b/source/common/buffer/buffer_impl.cc @@ -3,7 +3,6 @@ #include #include -#include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" #include "common/common/stack_array.h" @@ -124,44 +123,30 @@ void OwnedImpl::move(Instance& rhs, uint64_t length) { static_cast(rhs).postProcess(); } -Api::SysCallIntResult OwnedImpl::read(int fd, uint64_t max_length) { +Api::IoCallUint64Result OwnedImpl::read(Network::IoHandle& io_handle, uint64_t max_length) { if (max_length == 0) { - return {0, 0}; + return Api::ioCallUint64ResultNoError(); } constexpr uint64_t MaxSlices = 2; RawSlice slices[MaxSlices]; const uint64_t num_slices = reserve(max_length, slices, MaxSlices); - STACK_ARRAY(iov, iovec, num_slices); - uint64_t num_slices_to_read = 0; - uint64_t num_bytes_to_read = 0; - for (; num_slices_to_read < num_slices && num_bytes_to_read < max_length; num_slices_to_read++) { - iov[num_slices_to_read].iov_base = slices[num_slices_to_read].mem_; - const size_t slice_length = std::min(slices[num_slices_to_read].len_, - static_cast(max_length - num_bytes_to_read)); - iov[num_slices_to_read].iov_len = slice_length; - num_bytes_to_read += slice_length; - } - ASSERT(num_slices_to_read <= MaxSlices); - ASSERT(num_bytes_to_read <= max_length); - auto& os_syscalls = Api::OsSysCallsSingleton::get(); - const Api::SysCallSizeResult result = - os_syscalls.readv(fd, iov.begin(), static_cast(num_slices_to_read)); - if (result.rc_ < 0) { - return {static_cast(result.rc_), result.errno_}; - } - uint64_t num_slices_to_commit = 0; - uint64_t bytes_to_commit = result.rc_; - ASSERT(bytes_to_commit <= max_length); - while (bytes_to_commit != 0) { - slices[num_slices_to_commit].len_ = - std::min(slices[num_slices_to_commit].len_, static_cast(bytes_to_commit)); - ASSERT(bytes_to_commit >= slices[num_slices_to_commit].len_); - bytes_to_commit -= slices[num_slices_to_commit].len_; - num_slices_to_commit++; + Api::IoCallUint64Result result = io_handle.readv(max_length, slices, num_slices); + if (result.ok()) { + // Read succeeded. + uint64_t num_slices_to_commit = 0; + uint64_t bytes_to_commit = result.rc_; + ASSERT(bytes_to_commit <= max_length); + while (bytes_to_commit != 0) { + slices[num_slices_to_commit].len_ = + std::min(slices[num_slices_to_commit].len_, static_cast(bytes_to_commit)); + ASSERT(bytes_to_commit >= slices[num_slices_to_commit].len_); + bytes_to_commit -= slices[num_slices_to_commit].len_; + num_slices_to_commit++; + } + ASSERT(num_slices_to_commit <= num_slices); + commit(slices, num_slices_to_commit); } - ASSERT(num_slices_to_commit <= num_slices); - commit(slices, num_slices_to_commit); - return {static_cast(result.rc_), result.errno_}; + return result; } uint64_t OwnedImpl::reserve(uint64_t length, RawSlice* iovecs, uint64_t num_iovecs) { @@ -184,28 +169,15 @@ ssize_t OwnedImpl::search(const void* data, uint64_t size, size_t start) const { return result_ptr.pos; } -Api::SysCallIntResult OwnedImpl::write(int fd) { +Api::IoCallUint64Result OwnedImpl::write(Network::IoHandle& io_handle) { constexpr uint64_t MaxSlices = 16; RawSlice slices[MaxSlices]; const uint64_t num_slices = std::min(getRawSlices(slices, MaxSlices), MaxSlices); - STACK_ARRAY(iov, iovec, num_slices); - uint64_t num_slices_to_write = 0; - for (uint64_t i = 0; i < num_slices; i++) { - if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { - iov[num_slices_to_write].iov_base = slices[i].mem_; - iov[num_slices_to_write].iov_len = slices[i].len_; - num_slices_to_write++; - } - } - if (num_slices_to_write == 0) { - return {0, 0}; - } - auto& os_syscalls = Api::OsSysCallsSingleton::get(); - const Api::SysCallSizeResult result = os_syscalls.writev(fd, iov.begin(), num_slices_to_write); - if (result.rc_ > 0) { + Api::IoCallUint64Result result = io_handle.writev(slices, num_slices); + if (result.ok() && result.rc_ > 0) { drain(static_cast(result.rc_)); } - return {static_cast(result.rc_), result.errno_}; + return result; } OwnedImpl::OwnedImpl() : buffer_(evbuffer_new()) {} diff --git a/source/common/buffer/buffer_impl.h b/source/common/buffer/buffer_impl.h index e215d53ea81c8..dd48199513b9d 100644 --- a/source/common/buffer/buffer_impl.h +++ b/source/common/buffer/buffer_impl.h @@ -4,6 +4,7 @@ #include #include "envoy/buffer/buffer.h" +#include "envoy/network/io_handle.h" #include "common/common/non_copyable.h" #include "common/event/libevent.h" @@ -82,10 +83,10 @@ class OwnedImpl : public LibEventInstance { void* linearize(uint32_t size) override; void move(Instance& rhs) override; void move(Instance& rhs, uint64_t length) override; - Api::SysCallIntResult read(int fd, uint64_t max_length) override; + Api::IoCallUint64Result read(Network::IoHandle& io_handle, uint64_t max_length) override; uint64_t reserve(uint64_t length, RawSlice* iovecs, uint64_t num_iovecs) override; ssize_t search(const void* data, uint64_t size, size_t start) const override; - Api::SysCallIntResult write(int fd) override; + Api::IoCallUint64Result write(Network::IoHandle& io_handle) override; void postProcess() override {} std::string toString() const override; diff --git a/source/common/buffer/watermark_buffer.cc b/source/common/buffer/watermark_buffer.cc index 2e7cb5d9bd2e0..f8ef04bfefce8 100644 --- a/source/common/buffer/watermark_buffer.cc +++ b/source/common/buffer/watermark_buffer.cc @@ -50,8 +50,8 @@ void WatermarkBuffer::move(Instance& rhs, uint64_t length) { checkHighWatermark(); } -Api::SysCallIntResult WatermarkBuffer::read(int fd, uint64_t max_length) { - Api::SysCallIntResult result = OwnedImpl::read(fd, max_length); +Api::IoCallUint64Result WatermarkBuffer::read(Network::IoHandle& io_handle, uint64_t max_length) { + Api::IoCallUint64Result result = OwnedImpl::read(io_handle, max_length); checkHighWatermark(); return result; } @@ -62,8 +62,8 @@ uint64_t WatermarkBuffer::reserve(uint64_t length, RawSlice* iovecs, uint64_t nu return bytes_reserved; } -Api::SysCallIntResult WatermarkBuffer::write(int fd) { - Api::SysCallIntResult result = OwnedImpl::write(fd); +Api::IoCallUint64Result WatermarkBuffer::write(Network::IoHandle& io_handle) { + Api::IoCallUint64Result result = OwnedImpl::write(io_handle); checkLowWatermark(); return result; } diff --git a/source/common/buffer/watermark_buffer.h b/source/common/buffer/watermark_buffer.h index 31459570ddb81..9dd12d3d8aff9 100644 --- a/source/common/buffer/watermark_buffer.h +++ b/source/common/buffer/watermark_buffer.h @@ -30,9 +30,9 @@ class WatermarkBuffer : public OwnedImpl { void drain(uint64_t size) override; void move(Instance& rhs) override; void move(Instance& rhs, uint64_t length) override; - Api::SysCallIntResult read(int fd, uint64_t max_length) override; + Api::IoCallUint64Result read(Network::IoHandle& io_handle, uint64_t max_length) override; uint64_t reserve(uint64_t length, RawSlice* iovecs, uint64_t num_iovecs) override; - Api::SysCallIntResult write(int fd) override; + Api::IoCallUint64Result write(Network::IoHandle& io_handle) override; void postProcess() override { checkLowWatermark(); } void setWatermarks(uint32_t watermark) { setWatermarks(watermark / 2, watermark); } diff --git a/source/common/network/BUILD b/source/common/network/BUILD index d7abc47b000a3..6fe04e26417a6 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -102,14 +102,27 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "io_socket_error_lib", + srcs = ["io_socket_error_impl.cc"], + hdrs = ["io_socket_error_impl.h"], + deps = [ + "//include/envoy/api:io_error_interface", + "//source/common/common:assert_lib", + ], +) + envoy_cc_library( name = "io_socket_handle_lib", srcs = ["io_socket_handle_impl.cc"], hdrs = ["io_socket_handle_impl.h"], deps = [ + ":io_socket_error_lib", + "//include/envoy/buffer:buffer_interface", "//include/envoy/network:io_handle_interface", "//source/common/api:os_sys_calls_lib", "//source/common/common:assert_lib", + "//source/common/common:stack_array", ], ) diff --git a/source/common/network/io_socket_error_impl.cc b/source/common/network/io_socket_error_impl.cc new file mode 100644 index 0000000000000..8f625e3c02a5e --- /dev/null +++ b/source/common/network/io_socket_error_impl.cc @@ -0,0 +1,42 @@ +#include "common/network/io_socket_error_impl.h" + +#include "common/common/assert.h" + +namespace Envoy { +namespace Network { + +Api::IoError::IoErrorCode IoSocketError::getErrorCode() const { + switch (errno_) { + case EAGAIN: + ASSERT(this == IoSocketError::getIoSocketEagainInstance(), + "Didn't use getIoSocketEagainInstance() to generate `Again`."); + return IoErrorCode::Again; + case ENOTSUP: + return IoErrorCode::NoSupport; + case EAFNOSUPPORT: + return IoErrorCode::AddressFamilyNoSupport; + case EINPROGRESS: + return IoErrorCode::InProgress; + case EPERM: + return IoErrorCode::Permission; + default: + return IoErrorCode::UnknownError; + } +} + +std::string IoSocketError::getErrorDetails() const { return ::strerror(errno_); } + +IoSocketError* IoSocketError::getIoSocketEagainInstance() { + static auto* instance = new IoSocketError(EAGAIN); + return instance; +} + +void IoSocketError::deleteIoError(Api::IoError* err) { + ASSERT(err != nullptr); + if (err->getErrorCode() != Api::IoError::IoErrorCode::Again) { + delete err; + } +} + +} // namespace Network +} // namespace Envoy diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h new file mode 100644 index 0000000000000..a28e5c841eec0 --- /dev/null +++ b/source/common/network/io_socket_error_impl.h @@ -0,0 +1,32 @@ +#pragma once + +#include "envoy/api/io_error.h" + +#include "common/common/assert.h" + +namespace Envoy { +namespace Network { + +class IoSocketError : public Api::IoError { +public: + explicit IoSocketError(int sys_errno) : errno_(sys_errno) {} + + ~IoSocketError() override {} + + Api::IoError::IoErrorCode getErrorCode() const override; + std::string getErrorDetails() const override; + + // IoErrorCode::Again is used frequently. Define it to be a singleton to avoid frequent memory + // allocation of such instance. If this is used, IoHandleCallResult has to be instantiated with + // deleter deleteIoError() below to avoid deallocating memory for this error. + static IoSocketError* getIoSocketEagainInstance(); + + // Deallocate memory only if the error is not Again. + static void deleteIoError(Api::IoError* err); + +private: + int errno_; +}; + +} // namespace Network +} // namespace Envoy diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index 8a9cdee3c84d9..2265b5787ea77 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -4,7 +4,11 @@ #include -#include "common/common/assert.h" +#include "envoy/buffer/buffer.h" + +#include "common/api/os_sys_calls_impl.h" +#include "common/common/stack_array.h" +#include "common/network/io_socket_error_impl.h" using Envoy::Api::SysCallIntResult; using Envoy::Api::SysCallSizeResult; @@ -12,48 +16,74 @@ using Envoy::Api::SysCallSizeResult; namespace Envoy { namespace Network { -Api::IoError::IoErrorCode IoSocketError::errorCode() const { - switch (errno_) { - case EAGAIN: - // EAGAIN should use specific error ENVOY_ERROR_AGAIN. - NOT_REACHED_GCOVR_EXCL_LINE; - case ENOTSUP: - return IoErrorCode::NoSupport; - case EAFNOSUPPORT: - return IoErrorCode::AddressFamilyNoSupport; - case EINPROGRESS: - return IoErrorCode::InProgress; - case EPERM: - return IoErrorCode::Permission; - default: - return IoErrorCode::UnknownError; - } -} - -std::string IoSocketError::errorDetails() const { return ::strerror(errno_); } - IoSocketHandleImpl::~IoSocketHandleImpl() { if (fd_ != -1) { IoSocketHandleImpl::close(); } } -// Deallocate memory only if the error is not ENVOY_ERROR_AGAIN. -void deleteIoError(Api::IoError* err) { - ASSERT(err != nullptr); - if (err != ENVOY_ERROR_AGAIN) { - delete err; - } -} - -Api::IoCallUintResult IoSocketHandleImpl::close() { +Api::IoCallUint64Result IoSocketHandleImpl::close() { ASSERT(fd_ != -1); const int rc = ::close(fd_); fd_ = -1; - return Api::IoCallResult(rc, Api::IoErrorPtr(nullptr, deleteIoError)); + return Api::IoCallUint64Result(rc, Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); } bool IoSocketHandleImpl::isOpen() const { return fd_ != -1; } +Api::IoCallUint64Result IoSocketHandleImpl::readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) { + STACK_ARRAY(iov, iovec, num_slice); + uint64_t num_slices_to_read = 0; + uint64_t num_bytes_to_read = 0; + for (; num_slices_to_read < num_slice && num_bytes_to_read < max_length; num_slices_to_read++) { + iov[num_slices_to_read].iov_base = slices[num_slices_to_read].mem_; + const size_t slice_length = std::min(slices[num_slices_to_read].len_, + static_cast(max_length - num_bytes_to_read)); + iov[num_slices_to_read].iov_len = slice_length; + num_bytes_to_read += slice_length; + } + ASSERT(num_bytes_to_read <= max_length); + auto& os_syscalls = Api::OsSysCallsSingleton::get(); + const Api::SysCallSizeResult result = + os_syscalls.readv(fd_, iov.begin(), static_cast(num_slices_to_read)); + return sysCallResultToIoCallResult(result); +} + +Api::IoCallUint64Result IoSocketHandleImpl::writev(const Buffer::RawSlice* slices, + uint64_t num_slice) { + STACK_ARRAY(iov, iovec, num_slice); + uint64_t num_slices_to_write = 0; + for (uint64_t i = 0; i < num_slice; i++) { + if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { + iov[num_slices_to_write].iov_base = slices[i].mem_; + iov[num_slices_to_write].iov_len = slices[i].len_; + num_slices_to_write++; + } + } + if (num_slices_to_write == 0) { + return Api::ioCallUint64ResultNoError(); + } + auto& os_syscalls = Api::OsSysCallsSingleton::get(); + const Api::SysCallSizeResult result = os_syscalls.writev(fd_, iov.begin(), num_slices_to_write); + return sysCallResultToIoCallResult(result); +} + +Api::IoCallUint64Result +IoSocketHandleImpl::sysCallResultToIoCallResult(const Api::SysCallSizeResult& result) { + if (result.rc_ >= 0) { + // Return nullptr as IoError upon success. + return Api::IoCallUint64Result(result.rc_, + Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); + } + return Api::IoCallUint64Result( + /*rc=*/0, + (result.errno_ == EAGAIN + // EAGAIN is frequent enough that its memory allocation should be avoided. + ? Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError) + : Api::IoErrorPtr(new IoSocketError(result.errno_), IoSocketError::deleteIoError))); +} + } // namespace Network } // namespace Envoy diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index 2547e3817b6c6..3ba413a009a25 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -1,25 +1,12 @@ #pragma once +#include "envoy/api/io_error.h" #include "envoy/api/os_sys_calls.h" #include "envoy/network/io_handle.h" namespace Envoy { namespace Network { -class IoSocketError : public Api::IoError { -public: - explicit IoSocketError(int sys_errno) : errno_(sys_errno) {} - - ~IoSocketError() override {} - -private: - IoErrorCode errorCode() const override; - - std::string errorDetails() const override; - - int errno_; -}; - /** * IoHandle derivative for sockets */ @@ -33,11 +20,19 @@ class IoSocketHandleImpl : public IoHandle { // TODO(sbelair2) To be removed when the fd is fully abstracted from clients. int fd() const override { return fd_; } - Api::IoCallUintResult close() override; + Api::IoCallUint64Result close() override; bool isOpen() const override; + Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) override; + + Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; + private: + // Converts a SysCallSizeResult to IoCallUint64Result. + Api::IoCallUint64Result sysCallResultToIoCallResult(const Api::SysCallSizeResult& result); + int fd_; }; diff --git a/source/common/network/raw_buffer_socket.cc b/source/common/network/raw_buffer_socket.cc index 21dff87a8e0f5..df778ae425969 100644 --- a/source/common/network/raw_buffer_socket.cc +++ b/source/common/network/raw_buffer_socket.cc @@ -17,26 +17,28 @@ IoResult RawBufferSocket::doRead(Buffer::Instance& buffer) { bool end_stream = false; do { // 16K read is arbitrary. TODO(mattklein123) PERF: Tune the read size. - Api::SysCallIntResult result = buffer.read(callbacks_->ioHandle().fd(), 16384); - ENVOY_CONN_LOG(trace, "read returns: {}", callbacks_->connection(), result.rc_); + Api::IoCallUint64Result result = buffer.read(callbacks_->ioHandle(), 16384); - if (result.rc_ == 0) { - // Remote close. - end_stream = true; - break; - } else if (result.rc_ == -1) { - // Remote error (might be no data). - ENVOY_CONN_LOG(trace, "read error: {}", callbacks_->connection(), result.errno_); - if (result.errno_ != EAGAIN) { - action = PostIoAction::Close; + if (result.ok()) { + ENVOY_CONN_LOG(trace, "read returns: {}", callbacks_->connection(), result.rc_); + if (result.rc_ == 0) { + // Remote close. + end_stream = true; + break; } - break; - } else { bytes_read += result.rc_; if (callbacks_->shouldDrainReadBuffer()) { callbacks_->setReadBufferReady(); break; } + } else { + // Remote error (might be no data). + ENVOY_CONN_LOG(trace, "read error: {}", callbacks_->connection(), + result.err_->getErrorDetails()); + if (result.err_->getErrorCode() != Api::IoError::IoErrorCode::Again) { + action = PostIoAction::Close; + } + break; } } while (true); @@ -58,20 +60,20 @@ IoResult RawBufferSocket::doWrite(Buffer::Instance& buffer, bool end_stream) { action = PostIoAction::KeepOpen; break; } - Api::SysCallIntResult result = buffer.write(callbacks_->ioHandle().fd()); - ENVOY_CONN_LOG(trace, "write returns: {}", callbacks_->connection(), result.rc_); + Api::IoCallUint64Result result = buffer.write(callbacks_->ioHandle()); - if (result.rc_ == -1) { - ENVOY_CONN_LOG(trace, "write error: {} ({})", callbacks_->connection(), result.errno_, - strerror(result.errno_)); - if (result.errno_ == EAGAIN) { + if (result.ok()) { + ENVOY_CONN_LOG(trace, "write returns: {}", callbacks_->connection(), result.rc_); + bytes_written += result.rc_; + } else { + ENVOY_CONN_LOG(trace, "write error: {}", callbacks_->connection(), + result.err_->getErrorDetails()); + if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { action = PostIoAction::KeepOpen; } else { action = PostIoAction::Close; } break; - } else { - bytes_written += result.rc_; } } while (true); diff --git a/source/extensions/filters/network/dubbo_proxy/buffer_helper.h b/source/extensions/filters/network/dubbo_proxy/buffer_helper.h index 8b78cc7ff2875..3725621a9e12b 100644 --- a/source/extensions/filters/network/dubbo_proxy/buffer_helper.h +++ b/source/extensions/filters/network/dubbo_proxy/buffer_helper.h @@ -52,12 +52,14 @@ class BufferWrapper : public Buffer::Instance { } void move(Buffer::Instance&) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } void move(Buffer::Instance&, uint64_t) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - Api::SysCallIntResult read(int, uint64_t) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + Api::IoCallUint64Result read(Network::IoHandle&, uint64_t) override { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; + } uint64_t reserve(uint64_t, Buffer::RawSlice*, uint64_t) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } ssize_t search(const void*, uint64_t, size_t) const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - Api::SysCallIntResult write(int) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + Api::IoCallUint64Result write(Network::IoHandle&) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } private: Buffer::Instance& underlying_; diff --git a/test/common/buffer/BUILD b/test/common/buffer/BUILD index a9089cff74782..ee5036cd3e727 100644 --- a/test/common/buffer/BUILD +++ b/test/common/buffer/BUILD @@ -54,6 +54,7 @@ envoy_cc_test( srcs = ["owned_impl_test.cc"], deps = [ "//source/common/buffer:buffer_lib", + "//source/common/network:io_socket_handle_lib", "//test/mocks/api:api_mocks", "//test/test_common:threadsafe_singleton_injector_lib", ], @@ -65,6 +66,7 @@ envoy_cc_test( deps = [ "//source/common/buffer:buffer_lib", "//source/common/buffer:watermark_buffer_lib", + "//source/common/network:io_socket_handle_lib", ], ) diff --git a/test/common/buffer/buffer_fuzz_test.cc b/test/common/buffer/buffer_fuzz_test.cc index 329f41756a01e..6928e9c217f3d 100644 --- a/test/common/buffer/buffer_fuzz_test.cc +++ b/test/common/buffer/buffer_fuzz_test.cc @@ -6,6 +6,7 @@ #include "common/common/logger.h" #include "common/common/stack_array.h" #include "common/memory/stats.h" +#include "common/network/io_socket_handle_impl.h" #include "test/common/buffer/buffer_fuzz.pb.h" #include "test/fuzz/fuzz_runner.h" @@ -106,12 +107,11 @@ class StringBuffer : public Buffer::Instance { src.data_ = src.data_.substr(length); } - Api::SysCallIntResult read(int fd, uint64_t max_length) override { + Api::IoCallUint64Result read(Network::IoHandle& io_handle, uint64_t max_length) override { FUZZ_ASSERT(max_length <= MaxAllocation); - Api::SysCallIntResult result; - result.rc_ = ::read(fd, tmp_buf_.get(), max_length); - result.errno_ = errno; - FUZZ_ASSERT(result.rc_ > 0); + Buffer::RawSlice slice{tmp_buf_.get(), MaxAllocation}; + Api::IoCallUint64Result result = io_handle.readv(max_length, &slice, 1); + FUZZ_ASSERT(result.ok() && result.rc_ > 0); data_ += std::string(tmp_buf_.get(), result.rc_); return result; } @@ -130,11 +130,10 @@ class StringBuffer : public Buffer::Instance { std::string toString() const override { return data_; } - Api::SysCallIntResult write(int fd) override { - Api::SysCallIntResult result; - result.rc_ = ::write(fd, data_.data(), data_.size()); - result.errno_ = errno; - FUZZ_ASSERT(result.rc_ >= 0); + Api::IoCallUint64Result write(Network::IoHandle& io_handle) override { + const Buffer::RawSlice slice{const_cast(data_.data()), data_.size()}; + Api::IoCallUint64Result result = io_handle.writev(&slice, 1); + FUZZ_ASSERT(result.ok()); data_ = data_.substr(result.rc_); return result; } @@ -301,14 +300,15 @@ uint32_t bufferAction(Context& ctxt, char insert_value, uint32_t max_alloc, Buff } int pipe_fds[2] = {0, 0}; FUZZ_ASSERT(::pipe(pipe_fds) == 0); + Network::IoSocketHandleImpl io_handle(pipe_fds[0]); FUZZ_ASSERT(::fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == 0); FUZZ_ASSERT(::fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == 0); std::string data(max_length, insert_value); - const int rc = ::write(pipe_fds[1], data.data(), max_length); + const ssize_t rc = ::write(pipe_fds[1], data.data(), max_length); FUZZ_ASSERT(rc > 0); const uint32_t previous_length = target_buffer.length(); - FUZZ_ASSERT(target_buffer.read(pipe_fds[0], max_length).rc_ == rc); - FUZZ_ASSERT(::close(pipe_fds[0]) == 0); + Api::IoCallUint64Result result = target_buffer.read(io_handle, max_length); + FUZZ_ASSERT(result.rc_ == static_cast(rc)); FUZZ_ASSERT(::close(pipe_fds[1]) == 0); FUZZ_ASSERT(previous_length == target_buffer.search(data.data(), rc, previous_length)); break; @@ -316,27 +316,26 @@ uint32_t bufferAction(Context& ctxt, char insert_value, uint32_t max_alloc, Buff case test::common::buffer::Action::kWrite: { int pipe_fds[2] = {0, 0}; FUZZ_ASSERT(::pipe(pipe_fds) == 0); + Network::IoSocketHandleImpl io_handle(pipe_fds[1]); FUZZ_ASSERT(::fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == 0); FUZZ_ASSERT(::fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == 0); - int rc; + uint64_t rc; do { const bool empty = target_buffer.length() == 0; const std::string previous_data = target_buffer.toString(); - const auto result = target_buffer.write(pipe_fds[1]); + const auto result = target_buffer.write(io_handle); + FUZZ_ASSERT(result.ok()); rc = result.rc_; - ENVOY_LOG_MISC(trace, "Write rc: {} errno: {} ({})", rc, ::strerror(result.errno_), - result.errno_); + ENVOY_LOG_MISC(trace, "Write rc: {} errno: {}", rc, result.err_->getErrorDetails()); if (empty) { FUZZ_ASSERT(rc == 0); } else { - FUZZ_ASSERT(rc > 0); auto buf = std::make_unique(rc); - FUZZ_ASSERT(::read(pipe_fds[0], buf.get(), rc) == rc); + FUZZ_ASSERT(static_cast(::read(pipe_fds[0], buf.get(), rc)) == rc); FUZZ_ASSERT(::memcmp(buf.get(), previous_data.data(), rc) == 0); } } while (rc > 0); FUZZ_ASSERT(::close(pipe_fds[0]) == 0); - FUZZ_ASSERT(::close(pipe_fds[1]) == 0); break; } default: diff --git a/test/common/buffer/owned_impl_test.cc b/test/common/buffer/owned_impl_test.cc index 98d906f64a802..c4cc2b248c1b8 100644 --- a/test/common/buffer/owned_impl_test.cc +++ b/test/common/buffer/owned_impl_test.cc @@ -1,5 +1,7 @@ -#include "common/api/os_sys_calls_impl.h" +#include "envoy/api/io_error.h" + #include "common/buffer/buffer_impl.h" +#include "common/network/io_socket_handle_impl.h" #include "test/mocks/api/mocks.h" #include "test/test_common/threadsafe_singleton_injector.h" @@ -117,35 +119,47 @@ TEST_F(OwnedImplTest, Write) { TestThreadsafeSingletonInjector os_calls(&os_sys_calls); Buffer::OwnedImpl buffer; + Network::IoSocketHandleImpl io_handle; buffer.add("example"); EXPECT_CALL(os_sys_calls, writev(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{7, 0})); - Api::SysCallIntResult result = buffer.write(-1); + Api::IoCallUint64Result result = buffer.write(io_handle); + EXPECT_TRUE(result.ok()); EXPECT_EQ(7, result.rc_); EXPECT_EQ(0, buffer.length()); buffer.add("example"); EXPECT_CALL(os_sys_calls, writev(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{6, 0})); - result = buffer.write(-1); + result = buffer.write(io_handle); + EXPECT_TRUE(result.ok()); EXPECT_EQ(6, result.rc_); EXPECT_EQ(1, buffer.length()); EXPECT_CALL(os_sys_calls, writev(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{0, 0})); - result = buffer.write(-1); + result = buffer.write(io_handle); + EXPECT_TRUE(result.ok()); EXPECT_EQ(0, result.rc_); EXPECT_EQ(1, buffer.length()); EXPECT_CALL(os_sys_calls, writev(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{-1, 0})); - result = buffer.write(-1); - EXPECT_EQ(-1, result.rc_); + result = buffer.write(io_handle); + EXPECT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + EXPECT_EQ(0, result.rc_); + EXPECT_EQ(1, buffer.length()); + + EXPECT_CALL(os_sys_calls, writev(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{-1, EAGAIN})); + result = buffer.write(io_handle); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); + EXPECT_EQ(0, result.rc_); EXPECT_EQ(1, buffer.length()); EXPECT_CALL(os_sys_calls, writev(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{1, 0})); - result = buffer.write(-1); + result = buffer.write(io_handle); + EXPECT_TRUE(result.ok()); EXPECT_EQ(1, result.rc_); EXPECT_EQ(0, buffer.length()); EXPECT_CALL(os_sys_calls, writev(_, _, _)).Times(0); - result = buffer.write(-1); + result = buffer.write(io_handle); EXPECT_EQ(0, result.rc_); EXPECT_EQ(0, buffer.length()); } @@ -155,18 +169,27 @@ TEST_F(OwnedImplTest, Read) { TestThreadsafeSingletonInjector os_calls(&os_sys_calls); Buffer::OwnedImpl buffer; + Network::IoSocketHandleImpl io_handle; EXPECT_CALL(os_sys_calls, readv(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{0, 0})); - Api::SysCallIntResult result = buffer.read(-1, 100); + Api::IoCallUint64Result result = buffer.read(io_handle, 100); + EXPECT_TRUE(result.ok()); EXPECT_EQ(0, result.rc_); EXPECT_EQ(0, buffer.length()); EXPECT_CALL(os_sys_calls, readv(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{-1, 0})); - result = buffer.read(-1, 100); - EXPECT_EQ(-1, result.rc_); + result = buffer.read(io_handle, 100); + EXPECT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + EXPECT_EQ(0, result.rc_); + EXPECT_EQ(0, buffer.length()); + + EXPECT_CALL(os_sys_calls, readv(_, _, _)).WillOnce(Return(Api::SysCallSizeResult{-1, EAGAIN})); + result = buffer.read(io_handle, 100); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); + EXPECT_EQ(0, result.rc_); EXPECT_EQ(0, buffer.length()); EXPECT_CALL(os_sys_calls, readv(_, _, _)).Times(0); - result = buffer.read(-1, 0); + result = buffer.read(io_handle, 0); EXPECT_EQ(0, result.rc_); EXPECT_EQ(0, buffer.length()); } diff --git a/test/common/buffer/watermark_buffer_test.cc b/test/common/buffer/watermark_buffer_test.cc index e7f45ea56b8f3..4cad003f1364c 100644 --- a/test/common/buffer/watermark_buffer_test.cc +++ b/test/common/buffer/watermark_buffer_test.cc @@ -2,6 +2,7 @@ #include "common/buffer/buffer_impl.h" #include "common/buffer/watermark_buffer.h" +#include "common/network/io_socket_handle_impl.h" #include "gtest/gtest.h" @@ -177,10 +178,11 @@ TEST_F(WatermarkBufferTest, WatermarkFdFunctions) { EXPECT_EQ(0, times_low_watermark_called_); int bytes_written_total = 0; + Network::IoSocketHandleImpl io_handle1(pipe_fds[1]); while (bytes_written_total < 20) { - Api::SysCallIntResult result = buffer_.write(pipe_fds[1]); - if (result.rc_ < 0) { - ASSERT_EQ(EAGAIN, result.errno_); + Api::IoCallUint64Result result = buffer_.write(io_handle1); + if (!result.ok()) { + ASSERT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } else { bytes_written_total += result.rc_; } @@ -190,8 +192,9 @@ TEST_F(WatermarkBufferTest, WatermarkFdFunctions) { EXPECT_EQ(0, buffer_.length()); int bytes_read_total = 0; + Network::IoSocketHandleImpl io_handle2(pipe_fds[0]); while (bytes_read_total < 20) { - Api::SysCallIntResult result = buffer_.read(pipe_fds[0], 20); + Api::IoCallUint64Result result = buffer_.read(io_handle2, 20); bytes_read_total += result.rc_; } EXPECT_EQ(2, times_high_watermark_called_); diff --git a/test/common/network/connection_impl_test.cc b/test/common/network/connection_impl_test.cc index 38e8ce13f5b86..95a6c6062f5c7 100644 --- a/test/common/network/connection_impl_test.cc +++ b/test/common/network/connection_impl_test.cc @@ -734,9 +734,9 @@ TEST_P(ConnectionImplTest, WriteWithWatermarks) { .WillRepeatedly(DoAll(AddBufferToStringWithoutDraining(&data_written), Invoke(client_write_buffer_, &MockWatermarkBuffer::baseMove))); EXPECT_CALL(*client_write_buffer_, write(_)) - .WillOnce(Invoke([&](int fd) -> Api::SysCallIntResult { + .WillOnce(Invoke([&](IoHandle& io_handle) -> Api::IoCallUint64Result { dispatcher_->exit(); - return client_write_buffer_->failWrite(fd); + return client_write_buffer_->failWrite(io_handle); })); // The write() call on the connection will buffer enough data to bring the connection above the // high watermark and as the data will not flush it should not return below the watermark. @@ -819,8 +819,10 @@ TEST_P(ConnectionImplTest, WatermarkFuzzing) { EXPECT_CALL(*client_write_buffer_, move(_)) .WillOnce(Invoke(client_write_buffer_, &MockWatermarkBuffer::baseMove)); EXPECT_CALL(*client_write_buffer_, write(_)) - .WillOnce(DoAll(Invoke([&](int) -> void { client_write_buffer_->drain(bytes_to_flush); }), - Return(Api::SysCallIntResult{bytes_to_flush, 0}))) + .WillOnce( + DoAll(Invoke([&](IoHandle&) -> void { client_write_buffer_->drain(bytes_to_flush); }), + Return(testing::ByMove(Api::IoCallUint64Result( + bytes_to_flush, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})))))) .WillRepeatedly(testing::Invoke(client_write_buffer_, &MockWatermarkBuffer::failWrite)); client_connection_->write(buffer_to_write, false); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); diff --git a/test/common/network/io_socket_handle_impl_test.cc b/test/common/network/io_socket_handle_impl_test.cc index 25f034de2f12e..4aae5b5296d19 100644 --- a/test/common/network/io_socket_handle_impl_test.cc +++ b/test/common/network/io_socket_handle_impl_test.cc @@ -1,3 +1,4 @@ +#include "common/network/io_socket_error_impl.h" #include "common/network/io_socket_handle_impl.h" #include "gtest/gtest.h" @@ -8,30 +9,31 @@ namespace { TEST(IoSocketHandleImplTest, TestIoSocketError) { IoSocketError error1(EAGAIN); - EXPECT_DEATH(Api::IoError::getErrorCode(error1), ""); + EXPECT_DEBUG_DEATH(error1.getErrorCode(), + ".*assert failure: .* Details: Didn't use getIoSocketEagainInstance.*"); - EXPECT_EQ("Try again later", Api::IoError::getErrorDetails(*ENVOY_ERROR_AGAIN)); + EXPECT_EQ(::strerror(EAGAIN), IoSocketError::getIoSocketEagainInstance()->getErrorDetails()); IoSocketError error3(ENOTSUP); - EXPECT_EQ(IoSocketError::IoErrorCode::NoSupport, Api::IoError::getErrorCode(error3)); - EXPECT_EQ(::strerror(ENOTSUP), Api::IoError::getErrorDetails(error3)); + EXPECT_EQ(IoSocketError::IoErrorCode::NoSupport, error3.getErrorCode()); + EXPECT_EQ(::strerror(ENOTSUP), error3.getErrorDetails()); IoSocketError error4(EAFNOSUPPORT); - EXPECT_EQ(IoSocketError::IoErrorCode::AddressFamilyNoSupport, Api::IoError::getErrorCode(error4)); - EXPECT_EQ(::strerror(EAFNOSUPPORT), Api::IoError::getErrorDetails(error4)); + EXPECT_EQ(IoSocketError::IoErrorCode::AddressFamilyNoSupport, error4.getErrorCode()); + EXPECT_EQ(::strerror(EAFNOSUPPORT), error4.getErrorDetails()); IoSocketError error5(EINPROGRESS); - EXPECT_EQ(IoSocketError::IoErrorCode::InProgress, Api::IoError::getErrorCode(error5)); - EXPECT_EQ(::strerror(EINPROGRESS), Api::IoError::getErrorDetails(error5)); + EXPECT_EQ(IoSocketError::IoErrorCode::InProgress, error5.getErrorCode()); + EXPECT_EQ(::strerror(EINPROGRESS), error5.getErrorDetails()); IoSocketError error6(EPERM); - EXPECT_EQ(IoSocketError::IoErrorCode::Permission, Api::IoError::getErrorCode(error6)); - EXPECT_EQ(::strerror(EPERM), Api::IoError::getErrorDetails(error6)); + EXPECT_EQ(IoSocketError::IoErrorCode::Permission, error6.getErrorCode()); + EXPECT_EQ(::strerror(EPERM), error6.getErrorDetails()); // Random unknown error. IoSocketError error7(123); - EXPECT_EQ(IoSocketError::IoErrorCode::UnknownError, Api::IoError::getErrorCode(error7)); - EXPECT_EQ(::strerror(123), Api::IoError::getErrorDetails(error7)); + EXPECT_EQ(IoSocketError::IoErrorCode::UnknownError, error7.getErrorCode()); + EXPECT_EQ(::strerror(123), error7.getErrorDetails()); } } // namespace diff --git a/test/mocks/buffer/mocks.h b/test/mocks/buffer/mocks.h index c7db6d42f1661..36ce8dd0afe34 100644 --- a/test/mocks/buffer/mocks.h +++ b/test/mocks/buffer/mocks.h @@ -4,6 +4,7 @@ #include "common/buffer/buffer_impl.h" #include "common/buffer/watermark_buffer.h" +#include "common/network/io_socket_error_impl.h" #include "test/test_common/printers.h" #include "test/test_common/utility.h" @@ -18,7 +19,7 @@ template class MockBufferBase : public BaseClass { MockBufferBase(); MockBufferBase(std::function below_low, std::function above_high); - MOCK_METHOD1(write, Api::SysCallIntResult(int fd)); + MOCK_METHOD1(write, Api::IoCallUint64Result(Network::IoHandle& io_handle)); MOCK_METHOD1(move, void(Buffer::Instance& rhs)); MOCK_METHOD2(move, void(Buffer::Instance& rhs, uint64_t length)); MOCK_METHOD1(drain, void(uint64_t size)); @@ -26,9 +27,9 @@ template class MockBufferBase : public BaseClass { void baseMove(Buffer::Instance& rhs) { BaseClass::move(rhs); } void baseDrain(uint64_t size) { BaseClass::drain(size); } - Api::SysCallIntResult trackWrites(int fd) { - Api::SysCallIntResult result = BaseClass::write(fd); - if (result.rc_ > 0) { + Api::IoCallUint64Result trackWrites(Network::IoHandle& io_handle) { + Api::IoCallUint64Result result = BaseClass::write(io_handle); + if (result.ok() && result.rc_ > 0) { bytes_written_ += result.rc_; } return result; @@ -40,7 +41,11 @@ template class MockBufferBase : public BaseClass { } // A convenience function to invoke on write() which fails the write with EAGAIN. - Api::SysCallIntResult failWrite(int) { return {-1, EAGAIN}; } + Api::IoCallUint64Result failWrite(Network::IoHandle&) { + return Api::IoCallUint64Result( + /*rc=*/0, + Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), [](Api::IoError*) {})); + } int bytes_written() const { return bytes_written_; } uint64_t bytes_drained() const { return bytes_drained_; }