Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/envoy/api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "io_error_interface",
hdrs = ["io_error.h"],
)

envoy_cc_library(
name = "os_sys_calls_interface",
hdrs = ["os_sys_calls.h"],
Expand Down
87 changes: 87 additions & 0 deletions include/envoy/api/io_error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#pragma once

#include <memory>
#include <string>

#include "envoy/common/platform.h"
#include "envoy/common/pure.h"

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.
#define ENVOY_ERROR_AGAIN reinterpret_cast<Api::IoError*>(0x01)
Comment thread
dnoe marked this conversation as resolved.

/**
* Base class for any I/O error.
*/
class IoError {
public:
enum class IoErrorCode {
// No data available right now, try again later.
Again,
// Not supported.
NoSupport,
// Address family not supported.
AddressFamilyNoSupport,
// During non-blocking connect, the connection cannot be completed immediately.
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;
};

using IoErrorDeleterType = void (*)(IoError*);
using IoErrorPtr = std::unique_ptr<IoError, IoErrorDeleterType>;

/**
* Basic type for return result which has a return code and error code defined
* according to different implementations.
*/
template <typename T> struct IoCallResult {
IoCallResult(T rc, IoErrorPtr err) : rc_(rc), err_(std::move(err)) {}

IoCallResult(IoCallResult<T>&& result) : rc_(result.rc_), err_(std::move(result.err_)) {}

virtual ~IoCallResult() {}

T rc_;
IoErrorPtr err_;
};

using IoCallBoolResult = IoCallResult<bool>;
using IoCallSizeResult = IoCallResult<ssize_t>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that IoCallBoolResult and IoCallSizeResult types are unused. I'd drop them off.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're left overs from #6072. I'll remove them.

using IoCallUintResult = IoCallResult<uint64_t>;

} // namespace Api
} // namespace Envoy
5 changes: 4 additions & 1 deletion include/envoy/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ envoy_cc_library(
envoy_cc_library(
name = "io_handle_interface",
hdrs = ["io_handle.h"],
deps = ["//source/common/common:assert_lib"],
deps = [
"//include/envoy/api:io_error_interface",
"//source/common/common:assert_lib",
],
)

envoy_cc_library(
Expand Down
74 changes: 2 additions & 72 deletions include/envoy/network/io_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,14 @@

#include <memory>

#include "envoy/api/io_error.h"
#include "envoy/common/pure.h"

#include "common/common/assert.h"

namespace Envoy {
namespace Network {

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, IoHandleCallResult has to be instantiated with a deleter that does not
// deallocate memory for this error.
#define ENVOY_ERROR_AGAIN reinterpret_cast<IoError*>(0x01)

/**
* Base class for any I/O error.
*/
class IoError {
public:
enum class IoErrorCode {
// No data available right now, try again later.
Again,
// Not supported.
NoSupport,
// Address family not supported.
AddressFamilyNoSupport,
// During non-blocking connect, the connection cannot be completed immediately.
InProgress,
// Permission denied.
Permission,
// 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;
};

using IoErrorDeleterType = void (*)(IoError*);
using IoErrorPtr = std::unique_ptr<IoError, IoErrorDeleterType>;

/**
* Basic type for return result which has a return code and error code defined
* according to different implementations.
*/
template <typename T> struct IoHandleCallResult {
IoHandleCallResult(T rc, IoErrorPtr err) : rc_(rc), err_(std::move(err)) {}

IoHandleCallResult(IoHandleCallResult<T>&& result)
: rc_(result.rc_), err_(std::move(result.err_)) {}

virtual ~IoHandleCallResult() {}

T rc_;
IoErrorPtr err_;
};

using IoHandleCallUintResult = IoHandleCallResult<uint64_t>;

/**
* IoHandle: an abstract interface for all I/O operations
*/
Expand All @@ -98,7 +28,7 @@ class IoHandle {
/**
* Clean up IoHandle resources
*/
virtual IoHandleCallUintResult close() PURE;
virtual Api::IoCallUintResult close() PURE;

/**
* Return true if close() hasn't been called.
Expand Down
8 changes: 4 additions & 4 deletions source/common/network/io_socket_handle_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ using Envoy::Api::SysCallSizeResult;
namespace Envoy {
namespace Network {

IoError::IoErrorCode IoSocketError::errorCode() const {
Api::IoError::IoErrorCode IoSocketError::errorCode() const {
switch (errno_) {
case EAGAIN:
// EAGAIN should use specific error ENVOY_ERROR_AGAIN.
Expand All @@ -39,18 +39,18 @@ IoSocketHandleImpl::~IoSocketHandleImpl() {
}

// Deallocate memory only if the error is not ENVOY_ERROR_AGAIN.
void deleteIoError(IoError* err) {
void deleteIoError(Api::IoError* err) {
ASSERT(err != nullptr);
if (err != ENVOY_ERROR_AGAIN) {
delete err;
}
}

IoHandleCallUintResult IoSocketHandleImpl::close() {
Api::IoCallUintResult IoSocketHandleImpl::close() {
ASSERT(fd_ != -1);
const int rc = ::close(fd_);
fd_ = -1;
return IoHandleCallResult<uint64_t>(rc, IoErrorPtr(nullptr, deleteIoError));
return Api::IoCallResult<uint64_t>(rc, Api::IoErrorPtr(nullptr, deleteIoError));
}

bool IoSocketHandleImpl::isOpen() const { return fd_ != -1; }
Expand Down
4 changes: 2 additions & 2 deletions source/common/network/io_socket_handle_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
namespace Envoy {
namespace Network {

class IoSocketError : public IoError {
class IoSocketError : public Api::IoError {
public:
explicit IoSocketError(int sys_errno) : errno_(sys_errno) {}

Expand All @@ -33,7 +33,7 @@ class IoSocketHandleImpl : public IoHandle {
// TODO(sbelair2) To be removed when the fd is fully abstracted from clients.
int fd() const override { return fd_; }

IoHandleCallUintResult close() override;
Api::IoCallUintResult close() override;

bool isOpen() const override;

Expand Down
24 changes: 12 additions & 12 deletions test/common/network/io_socket_handle_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,30 @@ namespace {

TEST(IoSocketHandleImplTest, TestIoSocketError) {
IoSocketError error1(EAGAIN);
EXPECT_DEATH(IoError::getErrorCode(error1), "");
EXPECT_DEATH(Api::IoError::getErrorCode(error1), "");

EXPECT_EQ("Try again later", IoError::getErrorDetails(*ENVOY_ERROR_AGAIN));
EXPECT_EQ("Try again later", Api::IoError::getErrorDetails(*ENVOY_ERROR_AGAIN));

IoSocketError error3(ENOTSUP);
EXPECT_EQ(IoSocketError::IoErrorCode::NoSupport, IoError::getErrorCode(error3));
EXPECT_EQ(::strerror(ENOTSUP), IoError::getErrorDetails(error3));
EXPECT_EQ(IoSocketError::IoErrorCode::NoSupport, Api::IoError::getErrorCode(error3));
EXPECT_EQ(::strerror(ENOTSUP), Api::IoError::getErrorDetails(error3));

IoSocketError error4(EAFNOSUPPORT);
EXPECT_EQ(IoSocketError::IoErrorCode::AddressFamilyNoSupport, IoError::getErrorCode(error4));
EXPECT_EQ(::strerror(EAFNOSUPPORT), IoError::getErrorDetails(error4));
EXPECT_EQ(IoSocketError::IoErrorCode::AddressFamilyNoSupport, Api::IoError::getErrorCode(error4));
EXPECT_EQ(::strerror(EAFNOSUPPORT), Api::IoError::getErrorDetails(error4));

IoSocketError error5(EINPROGRESS);
EXPECT_EQ(IoSocketError::IoErrorCode::InProgress, IoError::getErrorCode(error5));
EXPECT_EQ(::strerror(EINPROGRESS), IoError::getErrorDetails(error5));
EXPECT_EQ(IoSocketError::IoErrorCode::InProgress, Api::IoError::getErrorCode(error5));
EXPECT_EQ(::strerror(EINPROGRESS), Api::IoError::getErrorDetails(error5));

IoSocketError error6(EPERM);
EXPECT_EQ(IoSocketError::IoErrorCode::Permission, IoError::getErrorCode(error6));
EXPECT_EQ(::strerror(EPERM), IoError::getErrorDetails(error6));
EXPECT_EQ(IoSocketError::IoErrorCode::Permission, Api::IoError::getErrorCode(error6));
EXPECT_EQ(::strerror(EPERM), Api::IoError::getErrorDetails(error6));

// Random unknown error.
IoSocketError error7(123);
EXPECT_EQ(IoSocketError::IoErrorCode::UnknownError, IoError::getErrorCode(error7));
EXPECT_EQ(::strerror(123), IoError::getErrorDetails(error7));
EXPECT_EQ(IoSocketError::IoErrorCode::UnknownError, Api::IoError::getErrorCode(error7));
EXPECT_EQ(::strerror(123), Api::IoError::getErrorDetails(error7));
}

} // namespace
Expand Down