1
#include "source/common/tls/io_handle_bio.h"
2

            
3
#include "envoy/buffer/buffer.h"
4
#include "envoy/network/io_handle.h"
5

            
6
#include "openssl/bio.h"
7
#include "openssl/err.h"
8

            
9
namespace Envoy {
10
namespace Extensions {
11
namespace TransportSockets {
12
namespace Tls {
13

            
14
namespace {
15

            
16
// NOLINTNEXTLINE(readability-identifier-naming)
17
107174
inline Envoy::Network::IoHandle* bio_io_handle(BIO* bio) {
18
107174
  return reinterpret_cast<Envoy::Network::IoHandle*>(BIO_get_data(bio));
19
107174
}
20

            
21
// NOLINTNEXTLINE(readability-identifier-naming)
22
81059
int io_handle_read(BIO* b, char* out, int outl) {
23
81059
  if (out == nullptr) {
24
    return 0;
25
  }
26

            
27
81059
  Envoy::Buffer::RawSlice slice;
28
81059
  slice.mem_ = out;
29
81059
  slice.len_ = outl;
30
81059
  auto result = bio_io_handle(b)->readv(outl, &slice, 1);
31
81059
  BIO_clear_retry_flags(b);
32
81059
  if (!result.ok()) {
33
13987
    auto err = result.err_->getErrorCode();
34
13987
    if (err == Api::IoError::IoErrorCode::Again || err == Api::IoError::IoErrorCode::Interrupt) {
35
13979
      BIO_set_retry_read(b);
36
13979
    } else {
37
8
      ERR_put_error(ERR_LIB_SYS, 0, result.err_->getSystemErrorCode(), __FILE__, __LINE__);
38
8
    }
39
13987
    return -1;
40
13987
  }
41
67072
  return result.return_value_;
42
81059
}
43

            
44
// NOLINTNEXTLINE(readability-identifier-naming)
45
26115
int io_handle_write(BIO* b, const char* in, int inl) {
46
26115
  Envoy::Buffer::RawSlice slice;
47
26115
  slice.mem_ = const_cast<char*>(in);
48
26115
  slice.len_ = inl;
49
26115
  auto result = bio_io_handle(b)->writev(&slice, 1);
50
26115
  BIO_clear_retry_flags(b);
51
26115
  if (!result.ok()) {
52
72
    auto err = result.err_->getErrorCode();
53
72
    if (err == Api::IoError::IoErrorCode::Again || err == Api::IoError::IoErrorCode::Interrupt) {
54
29
      BIO_set_retry_write(b);
55
72
    } else {
56
43
      ERR_put_error(ERR_LIB_SYS, 0, result.err_->getSystemErrorCode(), __FILE__, __LINE__);
57
43
    }
58
72
    return -1;
59
72
  }
60
26043
  return result.return_value_;
61
26115
}
62

            
63
// NOLINTNEXTLINE(readability-identifier-naming)
64
4344
long io_handle_ctrl(BIO*, int cmd, long, void*) {
65
4344
  long ret = 1;
66

            
67
4344
  switch (cmd) {
68
4343
  case BIO_CTRL_FLUSH:
69
4343
    ret = 1;
70
4343
    break;
71
1
  default:
72
1
    ret = 0;
73
1
    break;
74
4344
  }
75
4344
  return ret;
76
4344
}
77

            
78
// NOLINTNEXTLINE(readability-identifier-naming)
79
2474
const BIO_METHOD* BIO_s_io_handle(void) {
80
2474
  static const BIO_METHOD* method = [&] {
81
76
    BIO_METHOD* ret = BIO_meth_new(BIO_TYPE_SOCKET, "io_handle");
82
76
    RELEASE_ASSERT(ret != nullptr, "");
83
76
    RELEASE_ASSERT(BIO_meth_set_read(ret, io_handle_read), "");
84
76
    RELEASE_ASSERT(BIO_meth_set_write(ret, io_handle_write), "");
85
76
    RELEASE_ASSERT(BIO_meth_set_ctrl(ret, io_handle_ctrl), "");
86
76
    return ret;
87
76
  }();
88
2474
  return method;
89
2474
}
90

            
91
} // namespace
92

            
93
// NOLINTNEXTLINE(readability-identifier-naming)
94
2474
BIO* BIO_new_io_handle(Envoy::Network::IoHandle* io_handle) {
95
2474
  BIO* b;
96

            
97
2474
  b = BIO_new(BIO_s_io_handle());
98
2474
  RELEASE_ASSERT(b != nullptr, "");
99

            
100
  // Initialize the BIO
101
2474
  BIO_set_data(b, io_handle);
102
2474
  BIO_set_init(b, 1);
103

            
104
2474
  return b;
105
2474
}
106

            
107
} // namespace Tls
108
} // namespace TransportSockets
109
} // namespace Extensions
110
} // namespace Envoy