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
    // No buffer space available.
48
    NoBufferSpace,
49
    // Other error codes cannot be mapped to any one above in getErrorCode().
50
    UnknownError
51
  };
52
638
  virtual ~IoError() = default;
53

            
54
  virtual IoErrorCode getErrorCode() const PURE;
55
  virtual std::string getErrorDetails() const PURE;
56
  virtual int getSystemErrorCode() const PURE;
57

            
58
  // Wrap an IoError* in unique_ptr with custom deleter that doesn't delete.
59
568858
  static IoErrorPtr reusedStatic(IoError* err) {
60
568863
    return {err, [](IoError*) {}};
61
568858
  }
62
  // Wrap an IoError* in unique_ptr with custom deleter.
63
619
  static IoErrorPtr wrap(IoError* err) {
64
619
    return {err, [](IoError* err) { delete err; }};
65
619
  }
66
  // Use this non-error for the success case.
67
3148480
  static IoErrorPtr none() {
68
3148480
    return {nullptr, [](IoError*) {}};
69
3148480
  }
70
};
71

            
72
/**
73
 * Basic type for return result which has a return code and error code defined
74
 * according to different implementations.
75
 * If the call succeeds, ok() should return true and |return_value_| is valid. Otherwise |err_|
76
 * can be passed into IoError::getErrorCode() to extract the error. In this
77
 * case, |return_value_| is invalid.
78
 */
79
template <typename ReturnValue> struct IoCallResult {
80
  IoCallResult(ReturnValue return_value, IoErrorPtr err)
81
3819351
      : return_value_(return_value), err_(std::move(err)) {}
82

            
83
  IoCallResult(IoCallResult<ReturnValue>&& result) noexcept
84
1306
      : return_value_(std::move(result.return_value_)), err_(std::move(result.err_)) {}
85

            
86
3820781
  virtual ~IoCallResult() = default;
87

            
88
598407
  IoCallResult& operator=(IoCallResult&& result) noexcept {
89
598407
    return_value_ = result.return_value_;
90
598407
    err_ = std::move(result.err_);
91
598407
    return *this;
92
598407
  }
93

            
94
  /**
95
   * @return true if the call succeeds.
96
   */
97
6857102
  bool ok() const { return err_ == nullptr; }
98

            
99
  /**
100
   * This return code is frequent enough that we have a separate function to check.
101
   * @return true if the system call failed because the socket would block.
102
   */
103
913
  bool wouldBlock() const { return !ok() && err_->getErrorCode() == IoError::IoErrorCode::Again; }
104

            
105
  ReturnValue return_value_;
106
  IoErrorPtr err_;
107
};
108

            
109
using IoCallBoolResult = IoCallResult<bool>;
110
using IoCallSizeResult = IoCallResult<ssize_t>;
111
using IoCallUint64Result = IoCallResult<uint64_t>;
112

            
113
3428
inline Api::IoCallUint64Result ioCallUint64ResultNoError() {
114
3428
  return {0, IoErrorPtr(nullptr, [](IoError*) {})};
115
3428
}
116

            
117
} // namespace Api
118
} // namespace Envoy