Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/doc/designs/ddd/ddd-05-mem-nonblocking.c
34889 views
1
#include <sys/poll.h>
2
#include <openssl/ssl.h>
3
4
/*
5
* Demo 5: Client — Client Uses Memory BIO — Nonblocking
6
* =====================================================
7
*
8
* This is an example of (part of) an application which uses libssl in an
9
* asynchronous, nonblocking fashion. The application passes memory BIOs to
10
* OpenSSL, meaning that it controls both when data is read/written from an SSL
11
* object on the decrypted side but also when encrypted data from the network is
12
* shunted to/from OpenSSL. In this way OpenSSL is used as a pure state machine
13
* which does not make its own network I/O calls. OpenSSL never sees or creates
14
* any file descriptor for a network socket. The functions below show all
15
* interactions with libssl the application makes, and would hypothetically be
16
* linked into a larger application.
17
*/
18
typedef struct app_conn_st {
19
SSL *ssl;
20
BIO *ssl_bio, *net_bio;
21
int rx_need_tx, tx_need_rx;
22
} APP_CONN;
23
24
/*
25
* The application is initializing and wants an SSL_CTX which it will use for
26
* some number of outgoing connections, which it creates in subsequent calls to
27
* new_conn. The application may also call this function multiple times to
28
* create multiple SSL_CTX.
29
*/
30
SSL_CTX *create_ssl_ctx(void)
31
{
32
SSL_CTX *ctx;
33
34
#ifdef USE_QUIC
35
ctx = SSL_CTX_new(OSSL_QUIC_client_method());
36
#else
37
ctx = SSL_CTX_new(TLS_client_method());
38
#endif
39
if (ctx == NULL)
40
return NULL;
41
42
/* Enable trust chain verification. */
43
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
44
45
/* Load default root CA store. */
46
if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
47
SSL_CTX_free(ctx);
48
return NULL;
49
}
50
51
return ctx;
52
}
53
54
/*
55
* The application wants to create a new outgoing connection using a given
56
* SSL_CTX.
57
*
58
* hostname is a string like "openssl.org" used for certificate validation.
59
*/
60
APP_CONN *new_conn(SSL_CTX *ctx, const char *bare_hostname)
61
{
62
BIO *ssl_bio, *internal_bio, *net_bio;
63
APP_CONN *conn;
64
SSL *ssl;
65
#ifdef USE_QUIC
66
static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'};
67
#endif
68
69
conn = calloc(1, sizeof(APP_CONN));
70
if (conn == NULL)
71
return NULL;
72
73
ssl = conn->ssl = SSL_new(ctx);
74
if (ssl == NULL) {
75
free(conn);
76
return NULL;
77
}
78
79
SSL_set_connect_state(ssl); /* cannot fail */
80
81
#ifdef USE_QUIC
82
if (BIO_new_bio_dgram_pair(&internal_bio, 0, &net_bio, 0) <= 0) {
83
#else
84
if (BIO_new_bio_pair(&internal_bio, 0, &net_bio, 0) <= 0) {
85
#endif
86
SSL_free(ssl);
87
free(conn);
88
return NULL;
89
}
90
91
SSL_set_bio(ssl, internal_bio, internal_bio);
92
93
if (SSL_set1_host(ssl, bare_hostname) <= 0) {
94
SSL_free(ssl);
95
free(conn);
96
return NULL;
97
}
98
99
if (SSL_set_tlsext_host_name(ssl, bare_hostname) <= 0) {
100
SSL_free(ssl);
101
free(conn);
102
return NULL;
103
}
104
105
ssl_bio = BIO_new(BIO_f_ssl());
106
if (ssl_bio == NULL) {
107
SSL_free(ssl);
108
free(conn);
109
return NULL;
110
}
111
112
if (BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE) <= 0) {
113
SSL_free(ssl);
114
BIO_free(ssl_bio);
115
return NULL;
116
}
117
118
#ifdef USE_QUIC
119
/* Configure ALPN, which is required for QUIC. */
120
if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) {
121
/* Note: SSL_set_alpn_protos returns 1 for failure. */
122
SSL_free(ssl);
123
BIO_free(ssl_bio);
124
return NULL;
125
}
126
#endif
127
128
conn->ssl_bio = ssl_bio;
129
conn->net_bio = net_bio;
130
return conn;
131
}
132
133
/*
134
* Non-blocking transmission.
135
*
136
* Returns -1 on error. Returns -2 if the function would block (corresponds to
137
* EWOULDBLOCK).
138
*/
139
int tx(APP_CONN *conn, const void *buf, int buf_len)
140
{
141
int rc, l;
142
143
l = BIO_write(conn->ssl_bio, buf, buf_len);
144
if (l <= 0) {
145
rc = SSL_get_error(conn->ssl, l);
146
switch (rc) {
147
case SSL_ERROR_WANT_READ:
148
conn->tx_need_rx = 1;
149
case SSL_ERROR_WANT_CONNECT:
150
case SSL_ERROR_WANT_WRITE:
151
return -2;
152
default:
153
return -1;
154
}
155
} else {
156
conn->tx_need_rx = 0;
157
}
158
159
return l;
160
}
161
162
/*
163
* Non-blocking reception.
164
*
165
* Returns -1 on error. Returns -2 if the function would block (corresponds to
166
* EWOULDBLOCK).
167
*/
168
int rx(APP_CONN *conn, void *buf, int buf_len)
169
{
170
int rc, l;
171
172
l = BIO_read(conn->ssl_bio, buf, buf_len);
173
if (l <= 0) {
174
rc = SSL_get_error(conn->ssl, l);
175
switch (rc) {
176
case SSL_ERROR_WANT_WRITE:
177
conn->rx_need_tx = 1;
178
case SSL_ERROR_WANT_READ:
179
return -2;
180
default:
181
return -1;
182
}
183
} else {
184
conn->rx_need_tx = 0;
185
}
186
187
return l;
188
}
189
190
/*
191
* Called to get data which has been enqueued for transmission to the network
192
* by OpenSSL. For QUIC, this always outputs a single datagram.
193
*
194
* IMPORTANT (QUIC): If buf_len is inadequate to hold the datagram, it is truncated
195
* (similar to read(2)). A buffer size of at least 1472 must be used by default
196
* to guarantee this does not occur.
197
*/
198
int read_net_tx(APP_CONN *conn, void *buf, int buf_len)
199
{
200
return BIO_read(conn->net_bio, buf, buf_len);
201
}
202
203
/*
204
* Called to feed data which has been received from the network to OpenSSL.
205
*
206
* QUIC: buf must contain the entirety of a single datagram. It will be consumed
207
* entirely (return value == buf_len) or not at all.
208
*/
209
int write_net_rx(APP_CONN *conn, const void *buf, int buf_len)
210
{
211
return BIO_write(conn->net_bio, buf, buf_len);
212
}
213
214
/*
215
* Determine how much data can be written to the network RX BIO.
216
*/
217
size_t net_rx_space(APP_CONN *conn)
218
{
219
return BIO_ctrl_get_write_guarantee(conn->net_bio);
220
}
221
222
/*
223
* Determine how much data is currently queued for transmission in the network
224
* TX BIO.
225
*/
226
size_t net_tx_avail(APP_CONN *conn)
227
{
228
return BIO_ctrl_pending(conn->net_bio);
229
}
230
231
/*
232
* These functions returns zero or more of:
233
*
234
* POLLIN: The SSL state machine is interested in socket readability events.
235
*
236
* POLLOUT: The SSL state machine is interested in socket writeability events.
237
*
238
* POLLERR: The SSL state machine is interested in socket error events.
239
*
240
* get_conn_pending_tx returns events which may cause SSL_write to make
241
* progress and get_conn_pending_rx returns events which may cause SSL_read
242
* to make progress.
243
*/
244
int get_conn_pending_tx(APP_CONN *conn)
245
{
246
#ifdef USE_QUIC
247
return (SSL_net_read_desired(conn->ssl) ? POLLIN : 0)
248
| (SSL_net_write_desired(conn->ssl) ? POLLOUT : 0)
249
| POLLERR;
250
#else
251
return (conn->tx_need_rx ? POLLIN : 0) | POLLOUT | POLLERR;
252
#endif
253
}
254
255
int get_conn_pending_rx(APP_CONN *conn)
256
{
257
#ifdef USE_QUIC
258
return get_conn_pending_tx(conn);
259
#else
260
return (conn->rx_need_tx ? POLLOUT : 0) | POLLIN | POLLERR;
261
#endif
262
}
263
264
/*
265
* The application wants to close the connection and free bookkeeping
266
* structures.
267
*/
268
void teardown(APP_CONN *conn)
269
{
270
BIO_free_all(conn->ssl_bio);
271
BIO_free_all(conn->net_bio);
272
free(conn);
273
}
274
275
/*
276
* The application is shutting down and wants to free a previously
277
* created SSL_CTX.
278
*/
279
void teardown_ctx(SSL_CTX *ctx)
280
{
281
SSL_CTX_free(ctx);
282
}
283
284
/*
285
* ============================================================================
286
* Example driver for the above code. This is just to demonstrate that the code
287
* works and is not intended to be representative of a real application.
288
*/
289
#include <sys/types.h>
290
#include <sys/socket.h>
291
#include <sys/signal.h>
292
#include <netdb.h>
293
#include <unistd.h>
294
#include <fcntl.h>
295
#include <errno.h>
296
297
static int pump(APP_CONN *conn, int fd, int events, int timeout)
298
{
299
int l, l2;
300
char buf[2048]; /* QUIC: would need to be changed if < 1472 */
301
size_t wspace;
302
struct pollfd pfd = {0};
303
304
pfd.fd = fd;
305
pfd.events = (events & (POLLIN | POLLERR));
306
if (net_rx_space(conn) == 0)
307
pfd.events &= ~POLLIN;
308
if (net_tx_avail(conn) > 0)
309
pfd.events |= POLLOUT;
310
311
if ((pfd.events & (POLLIN|POLLOUT)) == 0)
312
return 1;
313
314
if (poll(&pfd, 1, timeout) == 0)
315
return -1;
316
317
if (pfd.revents & POLLIN) {
318
while ((wspace = net_rx_space(conn)) > 0) {
319
l = read(fd, buf, wspace > sizeof(buf) ? sizeof(buf) : wspace);
320
if (l <= 0) {
321
switch (errno) {
322
case EAGAIN:
323
goto stop;
324
default:
325
if (l == 0) /* EOF */
326
goto stop;
327
328
fprintf(stderr, "error on read: %d\n", errno);
329
return -1;
330
}
331
break;
332
}
333
l2 = write_net_rx(conn, buf, l);
334
if (l2 < l)
335
fprintf(stderr, "short write %d %d\n", l2, l);
336
} stop:;
337
}
338
339
if (pfd.revents & POLLOUT) {
340
for (;;) {
341
l = read_net_tx(conn, buf, sizeof(buf));
342
if (l <= 0)
343
break;
344
l2 = write(fd, buf, l);
345
if (l2 < l)
346
fprintf(stderr, "short read %d %d\n", l2, l);
347
}
348
}
349
350
return 1;
351
}
352
353
int main(int argc, char **argv)
354
{
355
int rc, fd = -1, res = 1;
356
static char tx_msg[300];
357
const char *tx_p = tx_msg;
358
char rx_buf[2048];
359
int l, tx_len;
360
int timeout = 2000 /* ms */;
361
APP_CONN *conn = NULL;
362
struct addrinfo hints = {0}, *result = NULL;
363
SSL_CTX *ctx = NULL;
364
365
if (argc < 3) {
366
fprintf(stderr, "usage: %s host port\n", argv[0]);
367
goto fail;
368
}
369
370
tx_len = snprintf(tx_msg, sizeof(tx_msg),
371
"GET / HTTP/1.0\r\nHost: %s\r\n\r\n",
372
argv[1]);
373
374
ctx = create_ssl_ctx();
375
if (ctx == NULL) {
376
fprintf(stderr, "cannot create SSL context\n");
377
goto fail;
378
}
379
380
hints.ai_family = AF_INET;
381
hints.ai_socktype = SOCK_STREAM;
382
hints.ai_flags = AI_PASSIVE;
383
rc = getaddrinfo(argv[1], argv[2], &hints, &result);
384
if (rc < 0) {
385
fprintf(stderr, "cannot resolve\n");
386
goto fail;
387
}
388
389
signal(SIGPIPE, SIG_IGN);
390
391
#ifdef USE_QUIC
392
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
393
#else
394
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
395
#endif
396
if (fd < 0) {
397
fprintf(stderr, "cannot create socket\n");
398
goto fail;
399
}
400
401
rc = connect(fd, result->ai_addr, result->ai_addrlen);
402
if (rc < 0) {
403
fprintf(stderr, "cannot connect\n");
404
goto fail;
405
}
406
407
rc = fcntl(fd, F_SETFL, O_NONBLOCK);
408
if (rc < 0) {
409
fprintf(stderr, "cannot make socket nonblocking\n");
410
goto fail;
411
}
412
413
conn = new_conn(ctx, argv[1]);
414
if (conn == NULL) {
415
fprintf(stderr, "cannot establish connection\n");
416
goto fail;
417
}
418
419
/* TX */
420
while (tx_len != 0) {
421
l = tx(conn, tx_p, tx_len);
422
if (l > 0) {
423
tx_p += l;
424
tx_len -= l;
425
} else if (l == -1) {
426
fprintf(stderr, "tx error\n");
427
} else if (l == -2) {
428
if (pump(conn, fd, get_conn_pending_tx(conn), timeout) != 1) {
429
fprintf(stderr, "pump error\n");
430
goto fail;
431
}
432
}
433
}
434
435
/* RX */
436
for (;;) {
437
l = rx(conn, rx_buf, sizeof(rx_buf));
438
if (l > 0) {
439
fwrite(rx_buf, 1, l, stdout);
440
} else if (l == -1) {
441
break;
442
} else if (l == -2) {
443
if (pump(conn, fd, get_conn_pending_rx(conn), timeout) != 1) {
444
fprintf(stderr, "pump error\n");
445
goto fail;
446
}
447
}
448
}
449
450
res = 0;
451
fail:
452
if (conn != NULL)
453
teardown(conn);
454
if (ctx != NULL)
455
teardown_ctx(ctx);
456
if (result != NULL)
457
freeaddrinfo(result);
458
return res;
459
}
460
461