Line data Source code
1 : #pragma once 2 : 3 : #include <memory> 4 : #include <string> 5 : 6 : #include "envoy/common/platform.h" 7 : #include "envoy/common/pure.h" 8 : 9 : namespace Envoy { 10 : namespace Api { 11 : 12 : class IoError; 13 : 14 : using IoErrorDeleterType = void (*)(IoError*); 15 : using IoErrorPtr = std::unique_ptr<IoError, IoErrorDeleterType>; 16 : 17 : /** 18 : * Base class for any I/O error. 19 : */ 20 : class IoError { 21 : public: 22 : enum class IoErrorCode { 23 : // No data available right now, try again later. 24 : Again, 25 : // Not supported. 26 : NoSupport, 27 : // Address family not supported. 28 : AddressFamilyNoSupport, 29 : // During non-blocking connect, the connection cannot be completed immediately. 30 : InProgress, 31 : // Permission denied. 32 : Permission, 33 : // Message too big to send. 34 : MessageTooBig, 35 : // Kernel interrupt. 36 : Interrupt, 37 : // Requested a nonexistent interface or a non-local source address. 38 : AddressNotAvailable, 39 : // Bad file descriptor. 40 : BadFd, 41 : // An existing connection was forcibly closed by the remote host. 42 : ConnectionReset, 43 : // Network is unreachable due to network settings. 44 : NetworkUnreachable, 45 : // Invalid arguments passed in. 46 : InvalidArgument, 47 : // Other error codes cannot be mapped to any one above in getErrorCode(). 48 : UnknownError 49 : }; 50 88 : virtual ~IoError() = default; 51 : 52 : virtual IoErrorCode getErrorCode() const PURE; 53 : virtual std::string getErrorDetails() const PURE; 54 : virtual int getSystemErrorCode() const PURE; 55 : 56 : // Wrap an IoError* in unique_ptr with custom deleter that doesn't delete. 57 1692 : static IoErrorPtr reusedStatic(IoError* err) { 58 1693 : return {err, [](IoError*) {}}; 59 1692 : } 60 : // Wrap an IoError* in unique_ptr with custom deleter. 61 88 : static IoErrorPtr wrap(IoError* err) { 62 88 : return {err, [](IoError* err) { delete err; }}; 63 88 : } 64 : // Use this non-error for the success case. 65 19891 : static IoErrorPtr none() { 66 19891 : return {nullptr, [](IoError*) {}}; 67 19891 : } 68 : }; 69 : 70 : /** 71 : * Basic type for return result which has a return code and error code defined 72 : * according to different implementations. 73 : * If the call succeeds, ok() should return true and |return_value_| is valid. Otherwise |err_| 74 : * can be passed into IoError::getErrorCode() to extract the error. In this 75 : * case, |return_value_| is invalid. 76 : */ 77 : template <typename ReturnValue> struct IoCallResult { 78 : IoCallResult(ReturnValue return_value, IoErrorPtr err) 79 23929 : : return_value_(return_value), err_(std::move(err)) {} 80 : 81 : IoCallResult(IoCallResult<ReturnValue>&& result) noexcept 82 14753 : : return_value_(std::move(result.return_value_)), err_(std::move(result.err_)) {} 83 : 84 38682 : virtual ~IoCallResult() = default; 85 : 86 668 : IoCallResult& operator=(IoCallResult&& result) noexcept { 87 668 : return_value_ = result.return_value_; 88 668 : err_ = std::move(result.err_); 89 668 : return *this; 90 668 : } 91 : 92 : /** 93 : * @return true if the call succeeds. 94 : */ 95 26271 : bool ok() const { return err_ == nullptr; } 96 : 97 : /** 98 : * This return code is frequent enough that we have a separate function to check. 99 : * @return true if the system call failed because the socket would block. 100 : */ 101 0 : bool wouldBlock() const { return !ok() && err_->getErrorCode() == IoError::IoErrorCode::Again; } 102 : 103 : ReturnValue return_value_; 104 : IoErrorPtr err_; 105 : }; 106 : 107 : using IoCallBoolResult = IoCallResult<bool>; 108 : using IoCallSizeResult = IoCallResult<ssize_t>; 109 : using IoCallUint64Result = IoCallResult<uint64_t>; 110 : 111 796 : inline Api::IoCallUint64Result ioCallUint64ResultNoError() { 112 796 : return {0, IoErrorPtr(nullptr, [](IoError*) {})}; 113 796 : } 114 : 115 : } // namespace Api 116 : } // namespace Envoy