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
107646
inline Envoy::Network::IoHandle* bio_io_handle(BIO* bio) {
18
107646
  return reinterpret_cast<Envoy::Network::IoHandle*>(BIO_get_data(bio));
19
107646
}
20

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

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

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

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

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

            
78
// NOLINTNEXTLINE(readability-identifier-naming)
79
2505
const BIO_METHOD* BIO_s_io_handle(void) {
80
2505
  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
2505
  return method;
89
2505
}
90

            
91
} // namespace
92

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

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

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

            
104
2505
  return b;
105
2505
}
106

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