packeted_bio.cc
Go to the documentation of this file.
1 /* Copyright (c) 2014, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include "packeted_bio.h"
16 
17 #include <assert.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include <openssl/mem.h>
23 
24 #include "../../crypto/internal.h"
25 
26 
27 namespace {
28 
29 extern const BIO_METHOD g_packeted_bio_method;
30 
31 const uint8_t kOpcodePacket = 'P';
32 const uint8_t kOpcodeTimeout = 'T';
33 const uint8_t kOpcodeTimeoutAck = 't';
34 
35 struct PacketedBio {
36  explicit PacketedBio(timeval *clock_arg)
37  : clock(clock_arg) {
38  OPENSSL_memset(&timeout, 0, sizeof(timeout));
39  }
40 
41  bool HasTimeout() const {
42  return timeout.tv_sec != 0 || timeout.tv_usec != 0;
43  }
44 
46  timeval *clock;
47 };
48 
49 PacketedBio *GetData(BIO *bio) {
50  if (bio->method != &g_packeted_bio_method) {
51  return NULL;
52  }
53  return (PacketedBio *)bio->ptr;
54 }
55 
56 // ReadAll reads |len| bytes from |bio| into |out|. It returns 1 on success and
57 // 0 or -1 on error.
58 static int ReadAll(BIO *bio, uint8_t *out, size_t len) {
59  while (len > 0) {
60  int chunk_len = INT_MAX;
61  if (len <= INT_MAX) {
62  chunk_len = (int)len;
63  }
64  int ret = BIO_read(bio, out, chunk_len);
65  if (ret <= 0) {
66  return ret;
67  }
68  out += ret;
69  len -= ret;
70  }
71  return 1;
72 }
73 
74 static int PacketedWrite(BIO *bio, const char *in, int inl) {
75  if (bio->next_bio == NULL) {
76  return 0;
77  }
78 
80 
81  // Write the header.
82  uint8_t header[5];
83  header[0] = kOpcodePacket;
84  header[1] = (inl >> 24) & 0xff;
85  header[2] = (inl >> 16) & 0xff;
86  header[3] = (inl >> 8) & 0xff;
87  header[4] = inl & 0xff;
88  int ret = BIO_write(bio->next_bio, header, sizeof(header));
89  if (ret <= 0) {
91  return ret;
92  }
93 
94  // Write the buffer.
95  ret = BIO_write(bio->next_bio, in, inl);
96  if (ret < 0 || (inl > 0 && ret == 0)) {
98  return ret;
99  }
100  assert(ret == inl);
101  return ret;
102 }
103 
104 static int PacketedRead(BIO *bio, char *out, int outl) {
105  PacketedBio *data = GetData(bio);
106  if (bio->next_bio == NULL) {
107  return 0;
108  }
109 
111 
112  // Read the opcode.
113  uint8_t opcode;
114  int ret = ReadAll(bio->next_bio, &opcode, sizeof(opcode));
115  if (ret <= 0) {
116  BIO_copy_next_retry(bio);
117  return ret;
118  }
119 
120  if (opcode == kOpcodeTimeout) {
121  // The caller is required to advance any pending timeouts before continuing.
122  if (data->HasTimeout()) {
123  fprintf(stderr, "Unprocessed timeout!\n");
124  return -1;
125  }
126 
127  // Process the timeout.
128  uint8_t buf[8];
129  ret = ReadAll(bio->next_bio, buf, sizeof(buf));
130  if (ret <= 0) {
131  BIO_copy_next_retry(bio);
132  return ret;
133  }
134  uint64_t timeout = (static_cast<uint64_t>(buf[0]) << 56) |
135  (static_cast<uint64_t>(buf[1]) << 48) |
136  (static_cast<uint64_t>(buf[2]) << 40) |
137  (static_cast<uint64_t>(buf[3]) << 32) |
138  (static_cast<uint64_t>(buf[4]) << 24) |
139  (static_cast<uint64_t>(buf[5]) << 16) |
140  (static_cast<uint64_t>(buf[6]) << 8) |
141  static_cast<uint64_t>(buf[7]);
142  timeout /= 1000; // Convert nanoseconds to microseconds.
143 
144  data->timeout.tv_usec = timeout % 1000000;
145  data->timeout.tv_sec = timeout / 1000000;
146 
147  // Send an ACK to the peer.
148  ret = BIO_write(bio->next_bio, &kOpcodeTimeoutAck, 1);
149  if (ret <= 0) {
150  return ret;
151  }
152  assert(ret == 1);
153 
154  // Signal to the caller to retry the read, after advancing the clock.
155  BIO_set_retry_read(bio);
156  return -1;
157  }
158 
159  if (opcode != kOpcodePacket) {
160  fprintf(stderr, "Unknown opcode, %u\n", opcode);
161  return -1;
162  }
163 
164  // Read the length prefix.
165  uint8_t len_bytes[4];
166  ret = ReadAll(bio->next_bio, len_bytes, sizeof(len_bytes));
167  if (ret <= 0) {
168  BIO_copy_next_retry(bio);
169  return ret;
170  }
171 
172  uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
173  (len_bytes[2] << 8) | len_bytes[3];
175  if (buf == NULL) {
176  return -1;
177  }
178  ret = ReadAll(bio->next_bio, buf, len);
179  if (ret <= 0) {
180  fprintf(stderr, "Packeted BIO was truncated\n");
181  return -1;
182  }
183 
184  if (outl > (int)len) {
185  outl = len;
186  }
187  OPENSSL_memcpy(out, buf, outl);
188  OPENSSL_free(buf);
189  return outl;
190 }
191 
192 static long PacketedCtrl(BIO *bio, int cmd, long num, void *ptr) {
193  if (bio->next_bio == NULL) {
194  return 0;
195  }
196 
198  int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
199  BIO_copy_next_retry(bio);
200  return ret;
201 }
202 
203 static int PacketedNew(BIO *bio) {
204  bio->init = 1;
205  return 1;
206 }
207 
208 static int PacketedFree(BIO *bio) {
209  if (bio == NULL) {
210  return 0;
211  }
212 
213  delete GetData(bio);
214  bio->init = 0;
215  return 1;
216 }
217 
218 static long PacketedCallbackCtrl(BIO *bio, int cmd, bio_info_cb fp) {
219  if (bio->next_bio == NULL) {
220  return 0;
221  }
222  return BIO_callback_ctrl(bio->next_bio, cmd, fp);
223 }
224 
225 const BIO_METHOD g_packeted_bio_method = {
227  "packeted bio",
228  PacketedWrite,
229  PacketedRead,
230  NULL /* puts */,
231  NULL /* gets */,
232  PacketedCtrl,
233  PacketedNew,
234  PacketedFree,
235  PacketedCallbackCtrl,
236 };
237 
238 } // namespace
239 
240 bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock) {
241  bssl::UniquePtr<BIO> bio(BIO_new(&g_packeted_bio_method));
242  if (!bio) {
243  return nullptr;
244  }
245  bio->ptr = new PacketedBio(clock);
246  return bio;
247 }
248 
250  PacketedBio *data = GetData(bio);
251  if (data == nullptr) {
252  return false;
253  }
254 
255  if (!data->HasTimeout()) {
256  return false;
257  }
258 
259  data->clock->tv_usec += data->timeout.tv_usec;
260  data->clock->tv_sec += data->clock->tv_usec / 1000000;
261  data->clock->tv_usec %= 1000000;
262  data->clock->tv_sec += data->timeout.tv_sec;
263  OPENSSL_memset(&data->timeout, 0, sizeof(data->timeout));
264  return true;
265 }
bio_method_st
Definition: bio.h:808
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
bio_info_cb
long(* bio_info_cb)(BIO *bio, int event, const char *parg, int cmd, long larg, long return_value)
Definition: bio.h:246
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
bio_st::next_bio
BIO * next_bio
Definition: bio.h:841
bio_st
Definition: bio.h:822
bio_st::ptr
void * ptr
Definition: bio.h:838
BIO_TYPE_FILTER
#define BIO_TYPE_FILTER
Definition: bio.h:801
string.h
bio_st::init
int init
Definition: bio.h:826
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
BIO_write
#define BIO_write
Definition: boringssl_prefix_symbols.h:870
BIO_read
#define BIO_read
Definition: boringssl_prefix_symbols.h:831
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
PacketedBioAdvanceClock
bool PacketedBioAdvanceClock(BIO *bio)
Definition: packeted_bio.cc:249
OPENSSL_memset
static void * OPENSSL_memset(void *dst, int c, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:835
BIO_copy_next_retry
#define BIO_copy_next_retry
Definition: boringssl_prefix_symbols.h:778
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
OPENSSL_malloc
#define OPENSSL_malloc
Definition: boringssl_prefix_symbols.h:1885
in
const char * in
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:391
xds_interop_client.int
int
Definition: xds_interop_client.py:113
BIO_ctrl
#define BIO_ctrl
Definition: boringssl_prefix_symbols.h:779
bio_st::method
const BIO_METHOD * method
Definition: bio.h:823
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
OPENSSL_memcpy
static void * OPENSSL_memcpy(void *dst, const void *src, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:819
header
struct absl::base_internal::@2940::AllocList::Header header
regen-readme.cmd
cmd
Definition: regen-readme.py:21
BIO_callback_ctrl
#define BIO_callback_ctrl
Definition: boringssl_prefix_symbols.h:775
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
BIO_new
#define BIO_new
Definition: boringssl_prefix_symbols.h:814
packeted_bio.h
ReadAll
bool ReadAll(std::vector< uint8_t > *out, FILE *file)
Definition: boringssl-with-bazel/src/tool/file.cc:27
timeval
Definition: setup_once.h:113
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
absl::span_internal::GetData
constexpr auto GetData(C &c) noexcept -> decltype(GetDataImpl(c, 0))
Definition: abseil-cpp/absl/types/internal/span.h:49
xds_manager.num
num
Definition: xds_manager.py:56
PacketedBioCreate
bssl::UniquePtr< BIO > PacketedBioCreate(timeval *clock)
Definition: packeted_bio.cc:240
mem.h
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
opcode
opcode
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:6290
OPENSSL_free
#define OPENSSL_free
Definition: boringssl_prefix_symbols.h:1869
BIO_set_retry_read
#define BIO_set_retry_read
Definition: boringssl_prefix_symbols.h:853
timeout
uv_timer_t timeout
Definition: libuv/docs/code/uvwget/main.c:9
BIO_clear_retry_flags
#define BIO_clear_retry_flags
Definition: boringssl_prefix_symbols.h:777


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:38