Coverage Report

Created: 2026-10-28 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl_fuzzer/openssl_contract_shim.cc
Line
Count
Source
1
/*
2
 * Copyright (C) Max Dymond, <cmeister2@gmail.com>, et al.
3
 *
4
 * SPDX-License-Identifier: curl
5
 */
6
7
#include <openssl/ssl.h>
8
9
#include <array>
10
#include <atomic>
11
#include <cstddef>
12
#include <cstdio>
13
#include <cstdlib>
14
#include <mutex>
15
#include <type_traits>
16
17
namespace {
18
19
// SSL_get_error classifies a preceding I/O result for one SSL object. Keep
20
// pending results keyed by that object so interleaved connections cannot
21
// replace one another's classification state.
22
struct PendingIoCall {
23
  const SSL *ssl = nullptr;
24
  const char *api = nullptr;
25
  long long result = 0;
26
};
27
28
struct FatalConnection {
29
  const SSL *ssl = nullptr;
30
  const char *io_api = nullptr;
31
  long long io_result = 0;
32
  int ssl_error = SSL_ERROR_NONE;
33
};
34
35
// Fixed tables keep allocation-failure fuzzing from disabling or perturbing
36
// the monitor.
37
constexpr std::size_t kMaximumTrackedConnections = 256;
38
std::array<PendingIoCall, kMaximumTrackedConnections> pending_io_calls{};
39
std::mutex pending_io_calls_mutex;
40
std::atomic<std::size_t> pending_io_call_count{0};
41
42
constexpr std::size_t kMaximumFatalConnections = kMaximumTrackedConnections;
43
std::array<FatalConnection, kMaximumFatalConnections> fatal_connections{};
44
std::mutex fatal_connections_mutex;
45
std::atomic<std::size_t> fatal_connection_count{0};
46
47
// Static libssl contains calls to public SSL APIs. --wrap redirects those
48
// calls too, so calls made while a real OpenSSL function is running bypass the
49
// monitor and cannot replace the application call being classified.
50
thread_local unsigned real_call_depth = 0;
51
52
class RealCallScope {
53
public:
54
4.51M
  RealCallScope() { ++real_call_depth; }
55
4.51M
  ~RealCallScope() { --real_call_depth; }
56
57
  RealCallScope(const RealCallScope &) = delete;
58
  RealCallScope &operator=(const RealCallScope &) = delete;
59
};
60
61
4.67M
bool IsRealCallActive() { return real_call_depth != 0; }
62
63
0
const char *ErrorName(int ssl_error) {
64
0
  switch (ssl_error) {
65
0
  case SSL_ERROR_SSL:
66
0
    return "SSL_ERROR_SSL";
67
0
  case SSL_ERROR_SYSCALL:
68
0
    return "SSL_ERROR_SYSCALL";
69
0
  default:
70
0
    return "unknown fatal error";
71
0
  }
72
0
}
73
74
[[noreturn]] void AbortContractViolation(const char *attempted_api,
75
0
                                         const FatalConnection &fatal) {
76
0
  std::fprintf(stderr,
77
0
               "OpenSSL contract assertion failed: %s called on SSL %p "
78
0
               "after %s returned %lld and SSL_get_error classified it as "
79
0
               "%s; no further I/O or SSL_shutdown is allowed\n",
80
0
               attempted_api, static_cast<const void *>(fatal.ssl),
81
0
               fatal.io_api, fatal.io_result, ErrorName(fatal.ssl_error));
82
0
  std::fflush(stderr);
83
0
  std::abort();
84
0
}
85
86
0
[[noreturn]] void AbortPendingOverflow(const PendingIoCall &call) {
87
0
  std::fprintf(stderr,
88
0
               "OpenSSL contract assertion failed: cannot track SSL %p "
89
0
               "after %s returned %lld; pending-I/O table is full\n",
90
0
               static_cast<const void *>(call.ssl), call.api, call.result);
91
0
  std::fflush(stderr);
92
0
  std::abort();
93
0
}
94
95
0
[[noreturn]] void AbortFatalOverflow(const PendingIoCall &call, int ssl_error) {
96
0
  std::fprintf(stderr,
97
0
               "OpenSSL contract assertion failed: cannot track SSL %p "
98
0
               "after %s returned %lld and SSL_get_error classified it as "
99
0
               "%s; fatal-connection table is full\n",
100
0
               static_cast<const void *>(call.ssl), call.api, call.result,
101
0
               ErrorName(ssl_error));
102
0
  std::fflush(stderr);
103
0
  std::abort();
104
0
}
105
106
3.00M
PendingIoCall *FindPendingIoCall(const SSL *ssl) {
107
385M
  for (PendingIoCall &call : pending_io_calls) {
108
385M
    if (call.ssl == ssl) {
109
1.50M
      return &call;
110
1.50M
    }
111
385M
  }
112
1.50M
  return nullptr;
113
3.00M
}
114
115
33.8k
FatalConnection *FindFatalConnection(const SSL *ssl) {
116
5.09M
  for (FatalConnection &fatal : fatal_connections) {
117
5.09M
    if (fatal.ssl == ssl) {
118
14.0k
      return &fatal;
119
14.0k
    }
120
5.09M
  }
121
19.8k
  return nullptr;
122
33.8k
}
123
124
2.69M
void CheckUsable(const SSL *ssl, const char *attempted_api) {
125
2.69M
  if (ssl == nullptr ||
126
2.69M
      fatal_connection_count.load(std::memory_order_acquire) == 0) {
127
2.69M
    return;
128
2.69M
  }
129
130
4.66k
  FatalConnection fatal;
131
4.66k
  {
132
4.66k
    std::lock_guard<std::mutex> lock(fatal_connections_mutex);
133
4.66k
    const FatalConnection *tracked = FindFatalConnection(ssl);
134
4.66k
    if (tracked != nullptr) {
135
0
      fatal = *tracked;
136
0
    }
137
4.66k
  }
138
4.66k
  if (fatal.ssl != nullptr) {
139
0
    AbortContractViolation(attempted_api, fatal);
140
0
  }
141
4.66k
}
142
143
1.51M
void ForgetPendingIoCall(const SSL *ssl) {
144
1.51M
  if (ssl == nullptr ||
145
1.51M
      pending_io_call_count.load(std::memory_order_acquire) == 0) {
146
1.50M
    return;
147
1.50M
  }
148
149
14.1k
  std::lock_guard<std::mutex> lock(pending_io_calls_mutex);
150
14.1k
  PendingIoCall *call = FindPendingIoCall(ssl);
151
14.1k
  if (call != nullptr) {
152
14.1k
    *call = PendingIoCall{};
153
14.1k
    pending_io_call_count.fetch_sub(1, std::memory_order_release);
154
14.1k
  }
155
14.1k
}
156
157
void RecordIoResult(const SSL *ssl, const char *api, long long result,
158
2.69M
                    bool zero_is_non_error = false) {
159
2.69M
  if (ssl == nullptr) {
160
0
    return;
161
0
  }
162
2.69M
  if (result > 0 || (zero_is_non_error && result == 0)) {
163
1.19M
    ForgetPendingIoCall(ssl);
164
1.19M
    return;
165
1.19M
  }
166
167
1.50M
  PendingIoCall recorded;
168
1.50M
  recorded.ssl = ssl;
169
1.50M
  recorded.api = api;
170
1.50M
  recorded.result = result;
171
1.50M
  bool table_full = false;
172
1.50M
  bool added = false;
173
1.50M
  {
174
1.50M
    std::lock_guard<std::mutex> lock(pending_io_calls_mutex);
175
1.50M
    PendingIoCall *call = FindPendingIoCall(ssl);
176
1.50M
    if (call == nullptr) {
177
1.50M
      for (PendingIoCall &entry : pending_io_calls) {
178
1.50M
        if (entry.ssl == nullptr) {
179
1.50M
          call = &entry;
180
1.50M
          added = true;
181
1.50M
          break;
182
1.50M
        }
183
1.50M
      }
184
1.50M
    }
185
1.50M
    if (call != nullptr) {
186
1.50M
      *call = recorded;
187
1.50M
      if (added) {
188
1.50M
        pending_io_call_count.fetch_add(1, std::memory_order_release);
189
1.50M
      }
190
1.50M
    } else {
191
0
      table_full = true;
192
0
    }
193
1.50M
  }
194
1.50M
  if (table_full) {
195
0
    AbortPendingOverflow(recorded);
196
0
  }
197
1.50M
}
198
199
1.50M
void RecordSslError(const SSL *ssl, int io_result, int ssl_error) {
200
1.50M
  if (ssl == nullptr ||
201
1.50M
      pending_io_call_count.load(std::memory_order_acquire) == 0) {
202
16.2k
    return;
203
16.2k
  }
204
205
1.48M
  PendingIoCall classified_call;
206
1.48M
  {
207
1.48M
    std::lock_guard<std::mutex> lock(pending_io_calls_mutex);
208
1.48M
    PendingIoCall *pending = FindPendingIoCall(ssl);
209
1.48M
    if (pending == nullptr || pending->result != io_result) {
210
0
      return;
211
0
    }
212
1.48M
    classified_call = *pending;
213
1.48M
    *pending = PendingIoCall{};
214
1.48M
    pending_io_call_count.fetch_sub(1, std::memory_order_release);
215
1.48M
  }
216
1.48M
  if (ssl_error != SSL_ERROR_SSL && ssl_error != SSL_ERROR_SYSCALL) {
217
1.47M
    return;
218
1.47M
  }
219
220
14.0k
  bool table_full = false;
221
14.0k
  bool added = false;
222
14.0k
  {
223
14.0k
    std::lock_guard<std::mutex> lock(fatal_connections_mutex);
224
14.0k
    FatalConnection *fatal = FindFatalConnection(ssl);
225
14.0k
    if (fatal == nullptr) {
226
14.3k
      for (FatalConnection &entry : fatal_connections) {
227
14.3k
        if (entry.ssl == nullptr) {
228
14.0k
          fatal = &entry;
229
14.0k
          added = true;
230
14.0k
          break;
231
14.0k
        }
232
14.3k
      }
233
14.0k
    }
234
14.0k
    if (fatal != nullptr) {
235
14.0k
      fatal->ssl = ssl;
236
14.0k
      fatal->io_api = classified_call.api;
237
14.0k
      fatal->io_result = classified_call.result;
238
14.0k
      fatal->ssl_error = ssl_error;
239
14.0k
      if (added) {
240
14.0k
        fatal_connection_count.fetch_add(1, std::memory_order_release);
241
14.0k
      }
242
14.0k
    } else {
243
0
      table_full = true;
244
0
    }
245
14.0k
  }
246
14.0k
  if (table_full) {
247
0
    AbortFatalOverflow(classified_call, ssl_error);
248
0
  }
249
14.0k
}
250
251
318k
void ForgetConnection(const SSL *ssl) {
252
318k
  ForgetPendingIoCall(ssl);
253
318k
  if (ssl == nullptr ||
254
318k
      fatal_connection_count.load(std::memory_order_acquire) == 0) {
255
303k
    return;
256
303k
  }
257
258
15.1k
  std::lock_guard<std::mutex> lock(fatal_connections_mutex);
259
15.1k
  FatalConnection *fatal = FindFatalConnection(ssl);
260
15.1k
  if (fatal != nullptr) {
261
14.0k
    *fatal = FatalConnection{};
262
14.0k
    fatal_connection_count.fetch_sub(1, std::memory_order_release);
263
14.0k
  }
264
15.1k
}
265
266
} // namespace
267
268
// GNU ld and lld provide each __real_* symbol when the final link uses the
269
// matching --wrap option. decltype ties these declarations to the installed
270
// OpenSSL headers and makes signature drift a compile-time failure.
271
extern "C" decltype(SSL_new) __real_SSL_new;
272
extern "C" decltype(SSL_free) __real_SSL_free;
273
extern "C" decltype(SSL_clear) __real_SSL_clear;
274
extern "C" decltype(SSL_get_error) __real_SSL_get_error;
275
extern "C" decltype(SSL_accept) __real_SSL_accept;
276
extern "C" decltype(SSL_connect) __real_SSL_connect;
277
extern "C" decltype(SSL_do_handshake) __real_SSL_do_handshake;
278
extern "C" decltype(SSL_read) __real_SSL_read;
279
extern "C" decltype(SSL_read_ex) __real_SSL_read_ex;
280
extern "C" decltype(SSL_read_early_data) __real_SSL_read_early_data;
281
extern "C" decltype(SSL_peek) __real_SSL_peek;
282
extern "C" decltype(SSL_peek_ex) __real_SSL_peek_ex;
283
extern "C" decltype(SSL_sendfile) __real_SSL_sendfile;
284
extern "C" decltype(SSL_write) __real_SSL_write;
285
extern "C" decltype(SSL_write_ex) __real_SSL_write_ex;
286
extern "C" decltype(SSL_write_ex2) __real_SSL_write_ex2;
287
extern "C" decltype(SSL_write_early_data) __real_SSL_write_early_data;
288
extern "C" decltype(SSL_shutdown) __real_SSL_shutdown;
289
extern "C" decltype(SSL_shutdown_ex) __real_SSL_shutdown_ex;
290
291
159k
extern "C" SSL *__wrap_SSL_new(SSL_CTX *ctx) {
292
159k
  if (IsRealCallActive()) {
293
0
    return __real_SSL_new(ctx);
294
0
  }
295
159k
  SSL *ssl;
296
159k
  {
297
159k
    RealCallScope real_call;
298
159k
    ssl = __real_SSL_new(ctx);
299
159k
  }
300
  // OpenSSL's allocator may reuse a recently freed address.
301
159k
  ForgetConnection(ssl);
302
159k
  return ssl;
303
159k
}
304
static_assert(std::is_same<decltype(SSL_new), decltype(__wrap_SSL_new)>::value,
305
              "SSL_new signature changed");
306
307
159k
extern "C" void __wrap_SSL_free(SSL *ssl) {
308
159k
  if (IsRealCallActive()) {
309
0
    __real_SSL_free(ssl);
310
0
    return;
311
0
  }
312
159k
  ForgetConnection(ssl);
313
159k
  RealCallScope real_call;
314
159k
  __real_SSL_free(ssl);
315
159k
}
316
static_assert(
317
    std::is_same<decltype(SSL_free), decltype(__wrap_SSL_free)>::value,
318
    "SSL_free signature changed");
319
320
158k
extern "C" int __wrap_SSL_clear(SSL *ssl) {
321
158k
  if (IsRealCallActive()) {
322
158k
    return __real_SSL_clear(ssl);
323
158k
  }
324
0
  int result;
325
0
  {
326
0
    RealCallScope real_call;
327
0
    result = __real_SSL_clear(ssl);
328
0
  }
329
0
  if (result == 1) {
330
    // A successful clear starts a new connection on the same SSL object.
331
0
    ForgetConnection(ssl);
332
0
  }
333
0
  return result;
334
158k
}
335
static_assert(
336
    std::is_same<decltype(SSL_clear), decltype(__wrap_SSL_clear)>::value,
337
    "SSL_clear signature changed");
338
339
1.50M
extern "C" int __wrap_SSL_get_error(const SSL *ssl, int io_result) {
340
1.50M
  if (IsRealCallActive()) {
341
1.29k
    return __real_SSL_get_error(ssl, io_result);
342
1.29k
  }
343
1.50M
  int ssl_error;
344
1.50M
  {
345
1.50M
    RealCallScope real_call;
346
1.50M
    ssl_error = __real_SSL_get_error(ssl, io_result);
347
1.50M
  }
348
1.50M
  RecordSslError(ssl, io_result, ssl_error);
349
1.50M
  return ssl_error;
350
1.50M
}
351
static_assert(std::is_same<decltype(SSL_get_error),
352
                           decltype(__wrap_SSL_get_error)>::value,
353
              "SSL_get_error signature changed");
354
355
#define DEFINE_IO_WRAPPER_WITH_POLICY(name, parameters, arguments,             \
356
                                      zero_is_non_error)                       \
357
  extern "C" auto __wrap_##name parameters                                     \
358
2.69M
      ->decltype(__real_##name arguments) {                                    \
359
2.69M
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
2.69M
    CheckUsable(ssl, #name);                                                   \
363
2.69M
    decltype(__real_##name arguments) result;                                  \
364
2.69M
    {                                                                          \
365
2.69M
      RealCallScope real_call;                                                 \
366
2.69M
      result = __real_##name arguments;                                        \
367
2.69M
    }                                                                          \
368
2.69M
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
2.69M
                   zero_is_non_error);                                         \
370
2.69M
    return result;                                                             \
371
2.69M
  }                                                                            \
__wrap_SSL_accept
Line
Count
Source
358
196k
      ->decltype(__real_##name arguments) {                                    \
359
196k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
196k
    CheckUsable(ssl, #name);                                                   \
363
196k
    decltype(__real_##name arguments) result;                                  \
364
196k
    {                                                                          \
365
196k
      RealCallScope real_call;                                                 \
366
196k
      result = __real_##name arguments;                                        \
367
196k
    }                                                                          \
368
196k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
196k
                   zero_is_non_error);                                         \
370
196k
    return result;                                                             \
371
196k
  }                                                                            \
__wrap_SSL_connect
Line
Count
Source
358
142k
      ->decltype(__real_##name arguments) {                                    \
359
142k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
142k
    CheckUsable(ssl, #name);                                                   \
363
142k
    decltype(__real_##name arguments) result;                                  \
364
142k
    {                                                                          \
365
142k
      RealCallScope real_call;                                                 \
366
142k
      result = __real_##name arguments;                                        \
367
142k
    }                                                                          \
368
142k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
142k
                   zero_is_non_error);                                         \
370
142k
    return result;                                                             \
371
142k
  }                                                                            \
__wrap_SSL_do_handshake
Line
Count
Source
358
37.5k
      ->decltype(__real_##name arguments) {                                    \
359
37.5k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
37.5k
    CheckUsable(ssl, #name);                                                   \
363
37.5k
    decltype(__real_##name arguments) result;                                  \
364
37.5k
    {                                                                          \
365
37.5k
      RealCallScope real_call;                                                 \
366
37.5k
      result = __real_##name arguments;                                        \
367
37.5k
    }                                                                          \
368
37.5k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
37.5k
                   zero_is_non_error);                                         \
370
37.5k
    return result;                                                             \
371
37.5k
  }                                                                            \
__wrap_SSL_read
Line
Count
Source
358
682k
      ->decltype(__real_##name arguments) {                                    \
359
682k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
682k
    CheckUsable(ssl, #name);                                                   \
363
682k
    decltype(__real_##name arguments) result;                                  \
364
682k
    {                                                                          \
365
682k
      RealCallScope real_call;                                                 \
366
682k
      result = __real_##name arguments;                                        \
367
682k
    }                                                                          \
368
682k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
682k
                   zero_is_non_error);                                         \
370
682k
    return result;                                                             \
371
682k
  }                                                                            \
__wrap_SSL_read_ex
Line
Count
Source
358
1.12M
      ->decltype(__real_##name arguments) {                                    \
359
1.12M
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
1.12M
    CheckUsable(ssl, #name);                                                   \
363
1.12M
    decltype(__real_##name arguments) result;                                  \
364
1.12M
    {                                                                          \
365
1.12M
      RealCallScope real_call;                                                 \
366
1.12M
      result = __real_##name arguments;                                        \
367
1.12M
    }                                                                          \
368
1.12M
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
1.12M
                   zero_is_non_error);                                         \
370
1.12M
    return result;                                                             \
371
1.12M
  }                                                                            \
Unexecuted instantiation: __wrap_SSL_read_early_data
Unexecuted instantiation: __wrap_SSL_peek
Unexecuted instantiation: __wrap_SSL_peek_ex
Unexecuted instantiation: __wrap_SSL_sendfile
__wrap_SSL_write
Line
Count
Source
358
280k
      ->decltype(__real_##name arguments) {                                    \
359
280k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
280k
    CheckUsable(ssl, #name);                                                   \
363
280k
    decltype(__real_##name arguments) result;                                  \
364
280k
    {                                                                          \
365
280k
      RealCallScope real_call;                                                 \
366
280k
      result = __real_##name arguments;                                        \
367
280k
    }                                                                          \
368
280k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
280k
                   zero_is_non_error);                                         \
370
280k
    return result;                                                             \
371
280k
  }                                                                            \
__wrap_SSL_write_ex
Line
Count
Source
358
155k
      ->decltype(__real_##name arguments) {                                    \
359
155k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
155k
    CheckUsable(ssl, #name);                                                   \
363
155k
    decltype(__real_##name arguments) result;                                  \
364
155k
    {                                                                          \
365
155k
      RealCallScope real_call;                                                 \
366
155k
      result = __real_##name arguments;                                        \
367
155k
    }                                                                          \
368
155k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
155k
                   zero_is_non_error);                                         \
370
155k
    return result;                                                             \
371
155k
  }                                                                            \
Unexecuted instantiation: __wrap_SSL_write_ex2
Unexecuted instantiation: __wrap_SSL_write_early_data
__wrap_SSL_shutdown
Line
Count
Source
358
74.9k
      ->decltype(__real_##name arguments) {                                    \
359
74.9k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
74.9k
    CheckUsable(ssl, #name);                                                   \
363
74.9k
    decltype(__real_##name arguments) result;                                  \
364
74.9k
    {                                                                          \
365
74.9k
      RealCallScope real_call;                                                 \
366
74.9k
      result = __real_##name arguments;                                        \
367
74.9k
    }                                                                          \
368
74.9k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
74.9k
                   zero_is_non_error);                                         \
370
74.9k
    return result;                                                             \
371
74.9k
  }                                                                            \
Unexecuted instantiation: __wrap_SSL_shutdown_ex
372
  static_assert(std::is_same<decltype(name), decltype(__wrap_##name)>::value,  \
373
                #name " signature changed");
374
375
#define DEFINE_IO_WRAPPER(name, parameters, arguments)                         \
376
  DEFINE_IO_WRAPPER_WITH_POLICY(name, parameters, arguments, false)
377
378
#define DEFINE_ZERO_NONERROR_WRAPPER(name, parameters, arguments)              \
379
  DEFINE_IO_WRAPPER_WITH_POLICY(name, parameters, arguments, true)
380
381
DEFINE_IO_WRAPPER(SSL_accept, (SSL * ssl), (ssl))
382
DEFINE_IO_WRAPPER(SSL_connect, (SSL * ssl), (ssl))
383
DEFINE_IO_WRAPPER(SSL_do_handshake, (SSL * ssl), (ssl))
384
DEFINE_IO_WRAPPER(SSL_read, (SSL * ssl, void *buffer, int length),
385
                  (ssl, buffer, length))
386
DEFINE_IO_WRAPPER(SSL_read_ex,
387
                  (SSL * ssl, void *buffer, size_t length, size_t *readbytes),
388
                  (ssl, buffer, length, readbytes))
389
DEFINE_IO_WRAPPER(SSL_read_early_data,
390
                  (SSL * ssl, void *buffer, size_t length, size_t *readbytes),
391
                  (ssl, buffer, length, readbytes))
392
DEFINE_IO_WRAPPER(SSL_peek, (SSL * ssl, void *buffer, int length),
393
                  (ssl, buffer, length))
394
DEFINE_IO_WRAPPER(SSL_peek_ex,
395
                  (SSL * ssl, void *buffer, size_t length, size_t *readbytes),
396
                  (ssl, buffer, length, readbytes))
397
DEFINE_ZERO_NONERROR_WRAPPER(SSL_sendfile,
398
                             (SSL * ssl, int fd, off_t offset, size_t size,
399
                              int flags),
400
                             (ssl, fd, offset, size, flags))
401
DEFINE_IO_WRAPPER(SSL_write, (SSL * ssl, const void *buffer, int length),
402
                  (ssl, buffer, length))
403
DEFINE_IO_WRAPPER(SSL_write_ex,
404
                  (SSL * ssl, const void *buffer, size_t length,
405
                   size_t *written),
406
                  (ssl, buffer, length, written))
407
DEFINE_IO_WRAPPER(SSL_write_ex2,
408
                  (SSL * ssl, const void *buffer, size_t length, uint64_t flags,
409
                   size_t *written),
410
                  (ssl, buffer, length, flags, written))
411
DEFINE_IO_WRAPPER(SSL_write_early_data,
412
                  (SSL * ssl, const void *buffer, size_t length,
413
                   size_t *written),
414
                  (ssl, buffer, length, written))
415
DEFINE_ZERO_NONERROR_WRAPPER(SSL_shutdown, (SSL * ssl), (ssl))
416
DEFINE_ZERO_NONERROR_WRAPPER(SSL_shutdown_ex,
417
                             (SSL * ssl, uint64_t flags,
418
                              const SSL_SHUTDOWN_EX_ARGS *args,
419
                              size_t args_length),
420
                             (ssl, flags, args, args_length))
421
422
#undef DEFINE_ZERO_NONERROR_WRAPPER
423
#undef DEFINE_IO_WRAPPER
424
#undef DEFINE_IO_WRAPPER_WITH_POLICY