xref: /freebsd/crypto/openssl/crypto/bio/bss_dgram_pair.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1 /*
2  * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <stdio.h>
11 #include <errno.h>
12 #include "bio_local.h"
13 #include "internal/cryptlib.h"
14 #include "internal/safe_math.h"
15 
16 #if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
17 
18 OSSL_SAFE_MATH_UNSIGNED(size_t, size_t)
19 
20 /* ===========================================================================
21  * Byte-wise ring buffer which supports pushing and popping blocks of multiple
22  * bytes at a time.
23  */
24 struct ring_buf {
25     unsigned char *start; /* start of buffer */
26     size_t len; /* size of buffer allocation in bytes */
27     size_t count; /* number of bytes currently pushed */
28     /*
29      * These index into start. Where idx[0] == idx[1], the buffer is full
30      * (if count is nonzero) and empty otherwise.
31      */
32     size_t idx[2]; /* 0: head, 1: tail */
33 };
34 
ring_buf_init(struct ring_buf * r,size_t nbytes)35 static int ring_buf_init(struct ring_buf *r, size_t nbytes)
36 {
37     r->start = OPENSSL_malloc(nbytes);
38     if (r->start == NULL)
39         return 0;
40 
41     r->len = nbytes;
42     r->idx[0] = r->idx[1] = r->count = 0;
43     return 1;
44 }
45 
ring_buf_destroy(struct ring_buf * r)46 static void ring_buf_destroy(struct ring_buf *r)
47 {
48     OPENSSL_free(r->start);
49     r->start    = NULL;
50     r->len      = 0;
51     r->count    = 0;
52 }
53 
54 /*
55  * Get a pointer to the next place to write data to be pushed to the ring buffer
56  * (idx=0), or the next data to be popped from the ring buffer (idx=1). The
57  * pointer is written to *buf and the maximum number of bytes which can be
58  * read/written are written to *len. After writing data to the buffer, call
59  * ring_buf_push/pop() with the number of bytes actually read/written, which
60  * must not exceed the returned length.
61  */
ring_buf_head_tail(struct ring_buf * r,int idx,uint8_t ** buf,size_t * len)62 static void ring_buf_head_tail(struct ring_buf *r, int idx, uint8_t **buf, size_t *len)
63 {
64     size_t max_len = r->len - r->idx[idx];
65 
66     if (idx == 0 && max_len > r->len - r->count)
67         max_len = r->len - r->count;
68     if (idx == 1 && max_len > r->count)
69         max_len = r->count;
70 
71     *buf = (uint8_t *)r->start + r->idx[idx];
72     *len = max_len;
73 }
74 
75 #define ring_buf_head(r, buf, len) ring_buf_head_tail((r), 0, (buf), (len))
76 #define ring_buf_tail(r, buf, len) ring_buf_head_tail((r), 1, (buf), (len))
77 
78 /*
79  * Commit bytes to the ring buffer previously filled after a call to
80  * ring_buf_head().
81  */
ring_buf_push_pop(struct ring_buf * r,int idx,size_t num_bytes)82 static void ring_buf_push_pop(struct ring_buf *r, int idx, size_t num_bytes)
83 {
84     size_t new_idx;
85 
86     /* A single push/pop op cannot wrap around, though it can reach the end.
87      * If the caller adheres to the convention of using the length returned
88      * by ring_buf_head/tail(), this cannot happen.
89      */
90     if (!ossl_assert(num_bytes <= r->len - r->idx[idx]))
91         return;
92 
93     /*
94      * Must not overfill the buffer, or pop more than is in the buffer either.
95      */
96     if (!ossl_assert(idx != 0 ? num_bytes <= r->count
97                               : num_bytes + r->count <= r->len))
98         return;
99 
100     /* Update the index. */
101     new_idx = r->idx[idx] + num_bytes;
102     if (new_idx == r->len)
103         new_idx = 0;
104 
105     r->idx[idx] = new_idx;
106     if (idx != 0)
107         r->count -= num_bytes;
108     else
109         r->count += num_bytes;
110 }
111 
112 #define ring_buf_push(r, num_bytes) ring_buf_push_pop((r), 0, (num_bytes))
113 #define ring_buf_pop(r, num_bytes) ring_buf_push_pop((r), 1, (num_bytes))
114 
ring_buf_clear(struct ring_buf * r)115 static void ring_buf_clear(struct ring_buf *r)
116 {
117     r->idx[0] = r->idx[1] = r->count = 0;
118 }
119 
ring_buf_resize(struct ring_buf * r,size_t nbytes)120 static int ring_buf_resize(struct ring_buf *r, size_t nbytes)
121 {
122     unsigned char *new_start;
123 
124     if (r->start == NULL)
125         return ring_buf_init(r, nbytes);
126 
127     if (nbytes == r->len)
128         return 1;
129 
130     if (r->count > 0 && nbytes < r->len)
131         /* fail shrinking the ring buffer when there is any data in it */
132         return 0;
133 
134     new_start = OPENSSL_realloc(r->start, nbytes);
135     if (new_start == NULL)
136         return 0;
137 
138     /* Moving tail if it is after (or equal to) head */
139     if (r->count > 0) {
140         if (r->idx[0] <= r->idx[1]) {
141             size_t offset = nbytes - r->len;
142 
143             memmove(new_start + r->idx[1] + offset, new_start + r->idx[1],
144                     r->len - r->idx[1]);
145             r->idx[1] += offset;
146         }
147     } else {
148         /* just reset the head/tail because it might be pointing outside */
149         r->idx[0] = r->idx[1] = 0;
150     }
151 
152     r->start = new_start;
153     r->len = nbytes;
154 
155     return 1;
156 }
157 
158 /* ===========================================================================
159  * BIO_s_dgram_pair is documented in BIO_s_dgram_pair(3).
160  *
161  * INTERNAL DATA STRUCTURE
162  *
163  * This is managed internally by using a bytewise ring buffer which supports
164  * pushing and popping spans of multiple bytes at once. The ring buffer stores
165  * internal packets which look like this:
166  *
167  *   struct dgram_hdr hdr;
168  *   uint8_t data[];
169  *
170  * The header contains the length of the data and metadata such as
171  * source/destination addresses.
172  *
173  * The datagram pair BIO is designed to support both traditional
174  * BIO_read/BIO_write (likely to be used by applications) as well as
175  * BIO_recvmmsg/BIO_sendmmsg.
176  */
177 struct bio_dgram_pair_st;
178 static int dgram_pair_write(BIO *bio, const char *buf, int sz_);
179 static int dgram_pair_read(BIO *bio, char *buf, int sz_);
180 static int dgram_mem_read(BIO *bio, char *buf, int sz_);
181 static long dgram_pair_ctrl(BIO *bio, int cmd, long num, void *ptr);
182 static long dgram_mem_ctrl(BIO *bio, int cmd, long num, void *ptr);
183 static int dgram_pair_init(BIO *bio);
184 static int dgram_mem_init(BIO *bio);
185 static int dgram_pair_free(BIO *bio);
186 static int dgram_pair_sendmmsg(BIO *b, BIO_MSG *msg, size_t stride,
187                                size_t num_msg, uint64_t flags,
188                                size_t *num_processed);
189 static int dgram_pair_recvmmsg(BIO *b, BIO_MSG *msg, size_t stride,
190                                size_t num_msg, uint64_t flags,
191                                size_t *num_processed);
192 
193 static int dgram_pair_ctrl_destroy_bio_pair(BIO *bio1);
194 static size_t dgram_pair_read_inner(struct bio_dgram_pair_st *b, uint8_t *buf,
195                                     size_t sz);
196 
197 #define BIO_MSG_N(array, n) (*(BIO_MSG *)((char *)(array) + (n)*stride))
198 
199 static const BIO_METHOD dgram_pair_method = {
200     BIO_TYPE_DGRAM_PAIR,
201     "BIO dgram pair",
202     bwrite_conv,
203     dgram_pair_write,
204     bread_conv,
205     dgram_pair_read,
206     NULL, /* dgram_pair_puts */
207     NULL, /* dgram_pair_gets */
208     dgram_pair_ctrl,
209     dgram_pair_init,
210     dgram_pair_free,
211     NULL, /* dgram_pair_callback_ctrl */
212     dgram_pair_sendmmsg,
213     dgram_pair_recvmmsg,
214 };
215 
216 static const BIO_METHOD dgram_mem_method = {
217     BIO_TYPE_DGRAM_MEM,
218     "BIO dgram mem",
219     bwrite_conv,
220     dgram_pair_write,
221     bread_conv,
222     dgram_mem_read,
223     NULL, /* dgram_pair_puts */
224     NULL, /* dgram_pair_gets */
225     dgram_mem_ctrl,
226     dgram_mem_init,
227     dgram_pair_free,
228     NULL, /* dgram_pair_callback_ctrl */
229     dgram_pair_sendmmsg,
230     dgram_pair_recvmmsg,
231 };
232 
BIO_s_dgram_pair(void)233 const BIO_METHOD *BIO_s_dgram_pair(void)
234 {
235     return &dgram_pair_method;
236 }
237 
BIO_s_dgram_mem(void)238 const BIO_METHOD *BIO_s_dgram_mem(void)
239 {
240     return &dgram_mem_method;
241 }
242 
243 struct dgram_hdr {
244     size_t len; /* payload length in bytes, not including this struct */
245     BIO_ADDR src_addr, dst_addr; /* family == 0: not present */
246 };
247 
248 struct bio_dgram_pair_st {
249     /* The other half of the BIO pair. NULL for dgram_mem. */
250     BIO *peer;
251     /* Writes are directed to our own ringbuf and reads to our peer. */
252     struct ring_buf rbuf;
253     /* Requested size of rbuf buffer in bytes once we initialize. */
254     size_t req_buf_len;
255     /* Largest possible datagram size */
256     size_t mtu;
257     /* Capability flags. */
258     uint32_t cap;
259     /* The local address to use (if set) */
260     BIO_ADDR *local_addr;
261     /*
262      * This lock protects updates to our rbuf. Since writes are directed to our
263      * own rbuf, this means we use this lock for writes and our peer's lock for
264      * reads.
265      */
266     CRYPTO_RWLOCK *lock;
267     unsigned int no_trunc          : 1; /* Reads fail if they would truncate */
268     unsigned int local_addr_enable : 1; /* Can use BIO_MSG->local? */
269     unsigned int role              : 1; /* Determines lock order */
270     unsigned int grows_on_write    : 1; /* Set for BIO_s_dgram_mem only */
271 };
272 
273 #define MIN_BUF_LEN (1024)
274 
275 #define is_dgram_pair(b) (b->peer != NULL)
276 
dgram_pair_init(BIO * bio)277 static int dgram_pair_init(BIO *bio)
278 {
279     struct bio_dgram_pair_st *b = OPENSSL_zalloc(sizeof(*b));
280 
281     if (b == NULL)
282         return 0;
283 
284     b->mtu         = 1472;    /* conservative default MTU */
285     /* default buffer size */
286     b->req_buf_len = 9 * (sizeof(struct dgram_hdr) + b->mtu);
287 
288     b->lock = CRYPTO_THREAD_lock_new();
289     if (b->lock == NULL) {
290         OPENSSL_free(b);
291         return 0;
292     }
293 
294     bio->ptr = b;
295     return 1;
296 }
297 
dgram_mem_init(BIO * bio)298 static int dgram_mem_init(BIO *bio)
299 {
300     struct bio_dgram_pair_st *b;
301 
302     if (!dgram_pair_init(bio))
303         return 0;
304 
305     b = bio->ptr;
306 
307     if (ring_buf_init(&b->rbuf, b->req_buf_len) == 0) {
308         ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
309         return 0;
310     }
311 
312     b->grows_on_write = 1;
313 
314     bio->init = 1;
315     return 1;
316 }
317 
dgram_pair_free(BIO * bio)318 static int dgram_pair_free(BIO *bio)
319 {
320     struct bio_dgram_pair_st *b;
321 
322     if (bio == NULL)
323         return 0;
324 
325     b = bio->ptr;
326     if (!ossl_assert(b != NULL))
327         return 0;
328 
329     /* We are being freed. Disconnect any peer and destroy buffers. */
330     dgram_pair_ctrl_destroy_bio_pair(bio);
331 
332     CRYPTO_THREAD_lock_free(b->lock);
333     OPENSSL_free(b);
334     return 1;
335 }
336 
337 /* BIO_make_bio_pair (BIO_C_MAKE_BIO_PAIR) */
dgram_pair_ctrl_make_bio_pair(BIO * bio1,BIO * bio2)338 static int dgram_pair_ctrl_make_bio_pair(BIO *bio1, BIO *bio2)
339 {
340     struct bio_dgram_pair_st *b1, *b2;
341 
342     /* peer must be non-NULL. */
343     if (bio1 == NULL || bio2 == NULL) {
344         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
345         return 0;
346     }
347 
348     /* Ensure the BIO we have been passed is actually a dgram pair BIO. */
349     if (bio1->method != &dgram_pair_method || bio2->method != &dgram_pair_method) {
350         ERR_raise_data(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT,
351                        "both BIOs must be BIO_dgram_pair");
352         return 0;
353     }
354 
355     b1 = bio1->ptr;
356     b2 = bio2->ptr;
357 
358     if (!ossl_assert(b1 != NULL && b2 != NULL)) {
359         ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
360         return 0;
361     }
362 
363     /*
364      * This ctrl cannot be used to associate a BIO pair half which is already
365      * associated.
366      */
367     if (b1->peer != NULL || b2->peer != NULL) {
368         ERR_raise_data(ERR_LIB_BIO, BIO_R_IN_USE,
369                        "cannot associate a BIO_dgram_pair which is already in use");
370         return 0;
371     }
372 
373     if (!ossl_assert(b1->req_buf_len >= MIN_BUF_LEN
374                         && b2->req_buf_len >= MIN_BUF_LEN)) {
375         ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
376         return 0;
377     }
378 
379     if (b1->rbuf.len != b1->req_buf_len)
380         if (ring_buf_init(&b1->rbuf, b1->req_buf_len) == 0) {
381             ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
382             return 0;
383         }
384 
385     if (b2->rbuf.len != b2->req_buf_len)
386         if (ring_buf_init(&b2->rbuf, b2->req_buf_len) == 0) {
387             ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
388             ring_buf_destroy(&b1->rbuf);
389             return 0;
390         }
391 
392     b1->peer    = bio2;
393     b2->peer    = bio1;
394     b1->role    = 0;
395     b2->role    = 1;
396     bio1->init  = 1;
397     bio2->init  = 1;
398     return 1;
399 }
400 
401 /* BIO_destroy_bio_pair (BIO_C_DESTROY_BIO_PAIR) */
dgram_pair_ctrl_destroy_bio_pair(BIO * bio1)402 static int dgram_pair_ctrl_destroy_bio_pair(BIO *bio1)
403 {
404     BIO *bio2;
405     struct bio_dgram_pair_st *b1 = bio1->ptr, *b2;
406 
407     ring_buf_destroy(&b1->rbuf);
408     bio1->init = 0;
409 
410     BIO_ADDR_free(b1->local_addr);
411 
412     /* Early return if we don't have a peer. */
413     if (b1->peer == NULL)
414         return 1;
415 
416     bio2 = b1->peer;
417     b2 = bio2->ptr;
418 
419     /* Invariant. */
420     if (!ossl_assert(b2->peer == bio1))
421         return 0;
422 
423     /* Free buffers. */
424     ring_buf_destroy(&b2->rbuf);
425 
426     bio2->init = 0;
427     b1->peer = NULL;
428     b2->peer = NULL;
429     return 1;
430 }
431 
432 /* BIO_eof (BIO_CTRL_EOF) */
dgram_pair_ctrl_eof(BIO * bio)433 static int dgram_pair_ctrl_eof(BIO *bio)
434 {
435     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
436 
437     if (!ossl_assert(b != NULL))
438         return -1;
439 
440     /* If we aren't initialized, we can never read anything */
441     if (!bio->init)
442         return 1;
443     if (!is_dgram_pair(b))
444         return 0;
445 
446 
447     peerb = b->peer->ptr;
448     if (!ossl_assert(peerb != NULL))
449         return -1;
450 
451     /*
452      * Since we are emulating datagram semantics, never indicate EOF so long as
453      * we have a peer.
454      */
455     return 0;
456 }
457 
458 /* BIO_set_write_buf_size (BIO_C_SET_WRITE_BUF_SIZE) */
dgram_pair_ctrl_set_write_buf_size(BIO * bio,size_t len)459 static int dgram_pair_ctrl_set_write_buf_size(BIO *bio, size_t len)
460 {
461     struct bio_dgram_pair_st *b = bio->ptr;
462 
463     /* Changing buffer sizes is not permitted while a peer is connected. */
464     if (b->peer != NULL) {
465         ERR_raise(ERR_LIB_BIO, BIO_R_IN_USE);
466         return 0;
467     }
468 
469     /* Enforce minimum size. */
470     if (len < MIN_BUF_LEN)
471         len = MIN_BUF_LEN;
472 
473     if (b->rbuf.start != NULL) {
474         if (!ring_buf_resize(&b->rbuf, len))
475             return 0;
476     }
477 
478     b->req_buf_len = len;
479     b->grows_on_write = 0;
480     return 1;
481 }
482 
483 /* BIO_reset (BIO_CTRL_RESET) */
dgram_pair_ctrl_reset(BIO * bio)484 static int dgram_pair_ctrl_reset(BIO *bio)
485 {
486     struct bio_dgram_pair_st *b = bio->ptr;
487 
488     ring_buf_clear(&b->rbuf);
489     return 1;
490 }
491 
492 /* BIO_pending (BIO_CTRL_PENDING) (Threadsafe) */
dgram_pair_ctrl_pending(BIO * bio)493 static size_t dgram_pair_ctrl_pending(BIO *bio)
494 {
495     size_t saved_idx, saved_count;
496     struct bio_dgram_pair_st *b = bio->ptr, *readb;
497     struct dgram_hdr hdr;
498     size_t l;
499 
500     /* Safe to check; init may not change during this call */
501     if (!bio->init)
502         return 0;
503     if (is_dgram_pair(b))
504         readb = b->peer->ptr;
505     else
506         readb = b;
507 
508     if (CRYPTO_THREAD_write_lock(readb->lock) == 0)
509         return 0;
510 
511     saved_idx   = readb->rbuf.idx[1];
512     saved_count = readb->rbuf.count;
513 
514     l = dgram_pair_read_inner(readb, (uint8_t *)&hdr, sizeof(hdr));
515 
516     readb->rbuf.idx[1] = saved_idx;
517     readb->rbuf.count  = saved_count;
518 
519     CRYPTO_THREAD_unlock(readb->lock);
520 
521     if (!ossl_assert(l == 0 || l == sizeof(hdr)))
522         return 0;
523 
524     return l > 0 ? hdr.len : 0;
525 }
526 
527 /* BIO_get_write_guarantee (BIO_C_GET_WRITE_GUARANTEE) (Threadsafe) */
dgram_pair_ctrl_get_write_guarantee(BIO * bio)528 static size_t dgram_pair_ctrl_get_write_guarantee(BIO *bio)
529 {
530     size_t l;
531     struct bio_dgram_pair_st *b = bio->ptr;
532 
533     if (CRYPTO_THREAD_read_lock(b->lock) == 0)
534         return 0;
535 
536     l = b->rbuf.len - b->rbuf.count;
537     if (l >= sizeof(struct dgram_hdr))
538         l -= sizeof(struct dgram_hdr);
539 
540     /*
541      * If the amount of buffer space would not be enough to accommodate the
542      * worst-case size of a datagram, report no space available.
543      */
544     if (l < b->mtu)
545         l = 0;
546 
547     CRYPTO_THREAD_unlock(b->lock);
548     return l;
549 }
550 
551 /* BIO_dgram_get_local_addr_cap (BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP) */
dgram_pair_ctrl_get_local_addr_cap(BIO * bio)552 static int dgram_pair_ctrl_get_local_addr_cap(BIO *bio)
553 {
554     struct bio_dgram_pair_st *b = bio->ptr, *readb;
555 
556     if (!bio->init)
557         return 0;
558 
559     if (is_dgram_pair(b))
560         readb = b->peer->ptr;
561     else
562         readb = b;
563 
564     return (~readb->cap & (BIO_DGRAM_CAP_HANDLES_SRC_ADDR
565                            | BIO_DGRAM_CAP_PROVIDES_DST_ADDR)) == 0;
566 }
567 
568 /* BIO_dgram_get_effective_caps (BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS) */
dgram_pair_ctrl_get_effective_caps(BIO * bio)569 static int dgram_pair_ctrl_get_effective_caps(BIO *bio)
570 {
571     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
572 
573     if (b->peer == NULL)
574         return 0;
575 
576     peerb = b->peer->ptr;
577 
578     return peerb->cap;
579 }
580 
581 /* BIO_dgram_get_caps (BIO_CTRL_DGRAM_GET_CAPS) */
dgram_pair_ctrl_get_caps(BIO * bio)582 static uint32_t dgram_pair_ctrl_get_caps(BIO *bio)
583 {
584     struct bio_dgram_pair_st *b = bio->ptr;
585 
586     return b->cap;
587 }
588 
589 /* BIO_dgram_set_caps (BIO_CTRL_DGRAM_SET_CAPS) */
dgram_pair_ctrl_set_caps(BIO * bio,uint32_t caps)590 static int dgram_pair_ctrl_set_caps(BIO *bio, uint32_t caps)
591 {
592     struct bio_dgram_pair_st *b = bio->ptr;
593 
594     b->cap = caps;
595     return 1;
596 }
597 
598 /* BIO_dgram_get_local_addr_enable (BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE) */
dgram_pair_ctrl_get_local_addr_enable(BIO * bio)599 static int dgram_pair_ctrl_get_local_addr_enable(BIO *bio)
600 {
601     struct bio_dgram_pair_st *b = bio->ptr;
602 
603     return b->local_addr_enable;
604 }
605 
606 /* BIO_dgram_set_local_addr_enable (BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE) */
dgram_pair_ctrl_set_local_addr_enable(BIO * bio,int enable)607 static int dgram_pair_ctrl_set_local_addr_enable(BIO *bio, int enable)
608 {
609     struct bio_dgram_pair_st *b = bio->ptr;
610 
611     if (dgram_pair_ctrl_get_local_addr_cap(bio) == 0)
612         return 0;
613 
614     b->local_addr_enable = (enable != 0 ? 1 : 0);
615     return 1;
616 }
617 
618 /* BIO_dgram_get_mtu (BIO_CTRL_DGRAM_GET_MTU) */
dgram_pair_ctrl_get_mtu(BIO * bio)619 static int dgram_pair_ctrl_get_mtu(BIO *bio)
620 {
621     struct bio_dgram_pair_st *b = bio->ptr;
622 
623     return b->mtu;
624 }
625 
626 /* BIO_dgram_set_mtu (BIO_CTRL_DGRAM_SET_MTU) */
dgram_pair_ctrl_set_mtu(BIO * bio,size_t mtu)627 static int dgram_pair_ctrl_set_mtu(BIO *bio, size_t mtu)
628 {
629     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
630 
631     b->mtu = mtu;
632 
633     if (b->peer != NULL) {
634         peerb = b->peer->ptr;
635         peerb->mtu = mtu;
636     }
637 
638     return 1;
639 }
640 
641 /* BIO_dgram_set0_local_addr (BIO_CTRL_DGRAM_SET0_LOCAL_ADDR) */
dgram_pair_ctrl_set0_local_addr(BIO * bio,BIO_ADDR * addr)642 static int dgram_pair_ctrl_set0_local_addr(BIO *bio, BIO_ADDR *addr)
643 {
644     struct bio_dgram_pair_st *b = bio->ptr;
645 
646     BIO_ADDR_free(b->local_addr);
647     b->local_addr = addr;
648     return 1;
649 }
650 
651 /* Partially threadsafe (some commands) */
dgram_mem_ctrl(BIO * bio,int cmd,long num,void * ptr)652 static long dgram_mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
653 {
654     long ret = 1;
655     struct bio_dgram_pair_st *b = bio->ptr;
656 
657     if (!ossl_assert(b != NULL))
658         return 0;
659 
660     switch (cmd) {
661     /*
662      * BIO_set_write_buf_size: Set the size of the ring buffer used for storing
663      * datagrams. No more writes can be performed once the buffer is filled up,
664      * until reads are performed. This cannot be used after a peer is connected.
665      */
666     case BIO_C_SET_WRITE_BUF_SIZE: /* Non-threadsafe */
667         ret = (long)dgram_pair_ctrl_set_write_buf_size(bio, (size_t)num);
668         break;
669 
670     /*
671      * BIO_get_write_buf_size: Get ring buffer size.
672      */
673     case BIO_C_GET_WRITE_BUF_SIZE: /* Non-threadsafe */
674         ret = (long)b->req_buf_len;
675         break;
676 
677     /*
678      * BIO_reset: Clear all data which was written to this side of the pair.
679      */
680     case BIO_CTRL_RESET: /* Non-threadsafe */
681         dgram_pair_ctrl_reset(bio);
682         break;
683 
684     /*
685      * BIO_get_write_guarantee: Any BIO_write providing a buffer less than or
686      * equal to this value is guaranteed to succeed.
687      */
688     case BIO_C_GET_WRITE_GUARANTEE: /* Threadsafe */
689         ret = (long)dgram_pair_ctrl_get_write_guarantee(bio);
690         break;
691 
692     /* BIO_pending: Bytes available to read. */
693     case BIO_CTRL_PENDING: /* Threadsafe */
694         ret = (long)dgram_pair_ctrl_pending(bio);
695         break;
696 
697     /* BIO_flush: No-op. */
698     case BIO_CTRL_FLUSH: /* Threadsafe */
699         break;
700 
701     /* BIO_dgram_get_no_trunc */
702     case BIO_CTRL_DGRAM_GET_NO_TRUNC: /* Non-threadsafe */
703         ret = (long)b->no_trunc;
704         break;
705 
706     /* BIO_dgram_set_no_trunc */
707     case BIO_CTRL_DGRAM_SET_NO_TRUNC: /* Non-threadsafe */
708         b->no_trunc = (num > 0);
709         break;
710 
711     /* BIO_dgram_get_local_addr_enable */
712     case BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE: /* Non-threadsafe */
713         *(int *)ptr = (int)dgram_pair_ctrl_get_local_addr_enable(bio);
714         break;
715 
716     /* BIO_dgram_set_local_addr_enable */
717     case BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE: /* Non-threadsafe */
718         ret = (long)dgram_pair_ctrl_set_local_addr_enable(bio, num);
719         break;
720 
721     /* BIO_dgram_get_local_addr_cap: Can local addresses be supported? */
722     case BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP: /* Non-threadsafe */
723         ret = (long)dgram_pair_ctrl_get_local_addr_cap(bio);
724         break;
725 
726     /* BIO_dgram_get_effective_caps */
727     case BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS: /* Non-threadsafe */
728     /* BIO_dgram_get_caps */
729     case BIO_CTRL_DGRAM_GET_CAPS: /* Non-threadsafe */
730         ret = (long)dgram_pair_ctrl_get_caps(bio);
731         break;
732 
733     /* BIO_dgram_set_caps */
734     case BIO_CTRL_DGRAM_SET_CAPS: /* Non-threadsafe */
735         ret = (long)dgram_pair_ctrl_set_caps(bio, (uint32_t)num);
736         break;
737 
738     /* BIO_dgram_get_mtu */
739     case BIO_CTRL_DGRAM_GET_MTU: /* Non-threadsafe */
740         ret = (long)dgram_pair_ctrl_get_mtu(bio);
741         break;
742 
743     /* BIO_dgram_set_mtu */
744     case BIO_CTRL_DGRAM_SET_MTU: /* Non-threadsafe */
745         ret = (long)dgram_pair_ctrl_set_mtu(bio, (uint32_t)num);
746         break;
747 
748     case BIO_CTRL_DGRAM_SET0_LOCAL_ADDR:
749         ret = (long)dgram_pair_ctrl_set0_local_addr(bio, (BIO_ADDR *)ptr);
750         break;
751 
752     /*
753      * BIO_eof: Returns whether this half of the BIO pair is empty of data to
754      * read.
755      */
756     case BIO_CTRL_EOF: /* Non-threadsafe */
757         ret = (long)dgram_pair_ctrl_eof(bio);
758         break;
759 
760     default:
761         ret = 0;
762         break;
763     }
764 
765     return ret;
766 }
767 
dgram_pair_ctrl(BIO * bio,int cmd,long num,void * ptr)768 static long dgram_pair_ctrl(BIO *bio, int cmd, long num, void *ptr)
769 {
770     long ret = 1;
771 
772     switch (cmd) {
773     /*
774      * BIO_make_bio_pair: this is usually used by BIO_new_dgram_pair, though it
775      * may be used manually after manually creating each half of a BIO pair
776      * using BIO_new. This only needs to be called on one of the BIOs.
777      */
778     case BIO_C_MAKE_BIO_PAIR: /* Non-threadsafe */
779         ret = (long)dgram_pair_ctrl_make_bio_pair(bio, (BIO *)ptr);
780         break;
781 
782     /*
783      * BIO_destroy_bio_pair: Manually disconnect two halves of a BIO pair so
784      * that they are no longer peers.
785      */
786     case BIO_C_DESTROY_BIO_PAIR: /* Non-threadsafe */
787         dgram_pair_ctrl_destroy_bio_pair(bio);
788         break;
789 
790     /* BIO_dgram_get_effective_caps */
791     case BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS: /* Non-threadsafe */
792         ret = (long)dgram_pair_ctrl_get_effective_caps(bio);
793         break;
794 
795     default:
796         ret = dgram_mem_ctrl(bio, cmd, num, ptr);
797         break;
798     }
799 
800     return ret;
801 }
802 
BIO_new_bio_dgram_pair(BIO ** pbio1,size_t writebuf1,BIO ** pbio2,size_t writebuf2)803 int BIO_new_bio_dgram_pair(BIO **pbio1, size_t writebuf1,
804                            BIO **pbio2, size_t writebuf2)
805 {
806     int ret = 0;
807     long r;
808     BIO *bio1 = NULL, *bio2 = NULL;
809 
810     bio1 = BIO_new(BIO_s_dgram_pair());
811     if (bio1 == NULL)
812         goto err;
813 
814     bio2 = BIO_new(BIO_s_dgram_pair());
815     if (bio2 == NULL)
816         goto err;
817 
818     if (writebuf1 > 0) {
819         r = BIO_set_write_buf_size(bio1, writebuf1);
820         if (r == 0)
821             goto err;
822     }
823 
824     if (writebuf2 > 0) {
825         r = BIO_set_write_buf_size(bio2, writebuf2);
826         if (r == 0)
827             goto err;
828     }
829 
830     r = BIO_make_bio_pair(bio1, bio2);
831     if (r == 0)
832         goto err;
833 
834     ret = 1;
835 err:
836     if (ret == 0) {
837         BIO_free(bio1);
838         bio1 = NULL;
839         BIO_free(bio2);
840         bio2 = NULL;
841     }
842 
843     *pbio1 = bio1;
844     *pbio2 = bio2;
845     return ret;
846 }
847 
848 /* Must hold peer write lock */
dgram_pair_read_inner(struct bio_dgram_pair_st * b,uint8_t * buf,size_t sz)849 static size_t dgram_pair_read_inner(struct bio_dgram_pair_st *b, uint8_t *buf, size_t sz)
850 {
851     size_t total_read = 0;
852 
853     /*
854      * We repeat pops from the ring buffer for as long as we have more
855      * application *buffer to fill until we fail. We may not be able to pop
856      * enough data to fill the buffer in one operation if the ring buffer wraps
857      * around, but there may still be more data available.
858      */
859     while (sz > 0) {
860         uint8_t *src_buf = NULL;
861         size_t src_len = 0;
862 
863         /*
864          * There are two BIO instances, each with a ringbuf. We read from the
865          * peer ringbuf and write to our own ringbuf.
866          */
867         ring_buf_tail(&b->rbuf, &src_buf, &src_len);
868         if (src_len == 0)
869             break;
870 
871         if (src_len > sz)
872             src_len = sz;
873 
874         if (buf != NULL)
875             memcpy(buf, src_buf, src_len);
876 
877         ring_buf_pop(&b->rbuf, src_len);
878 
879         if (buf != NULL)
880             buf += src_len;
881         total_read  += src_len;
882         sz          -= src_len;
883     }
884 
885     return total_read;
886 }
887 
888 /*
889  * Must hold peer write lock. Returns number of bytes processed or negated BIO
890  * response code.
891  */
dgram_pair_read_actual(BIO * bio,char * buf,size_t sz,BIO_ADDR * local,BIO_ADDR * peer,int is_multi)892 static ossl_ssize_t dgram_pair_read_actual(BIO *bio, char *buf, size_t sz,
893                                            BIO_ADDR *local, BIO_ADDR *peer,
894                                            int is_multi)
895 {
896     size_t l, trunc = 0, saved_idx, saved_count;
897     struct bio_dgram_pair_st *b = bio->ptr, *readb;
898     struct dgram_hdr hdr;
899 
900     if (!is_multi)
901         BIO_clear_retry_flags(bio);
902 
903     if (!bio->init)
904         return -BIO_R_UNINITIALIZED;
905 
906     if (!ossl_assert(b != NULL))
907         return -BIO_R_TRANSFER_ERROR;
908 
909     if (is_dgram_pair(b))
910         readb = b->peer->ptr;
911     else
912         readb = b;
913     if (!ossl_assert(readb != NULL && readb->rbuf.start != NULL))
914         return -BIO_R_TRANSFER_ERROR;
915 
916     if (sz > 0 && buf == NULL)
917         return -BIO_R_INVALID_ARGUMENT;
918 
919     /* If the caller wants to know the local address, it must be enabled */
920     if (local != NULL && b->local_addr_enable == 0)
921         return -BIO_R_LOCAL_ADDR_NOT_AVAILABLE;
922 
923     /* Read the header. */
924     saved_idx   = readb->rbuf.idx[1];
925     saved_count = readb->rbuf.count;
926     l = dgram_pair_read_inner(readb, (uint8_t *)&hdr, sizeof(hdr));
927     if (l == 0) {
928         /* Buffer was empty. */
929         if (!is_multi)
930             BIO_set_retry_read(bio);
931         return -BIO_R_NON_FATAL;
932     }
933 
934     if (!ossl_assert(l == sizeof(hdr)))
935         /*
936          * This should not be possible as headers (and their following payloads)
937          * should always be written atomically.
938          */
939         return -BIO_R_BROKEN_PIPE;
940 
941     if (sz > hdr.len) {
942         sz = hdr.len;
943     } else if (sz < hdr.len) {
944         /* Truncation is occurring. */
945         trunc = hdr.len - sz;
946         if (b->no_trunc) {
947             /* Restore original state. */
948             readb->rbuf.idx[1] = saved_idx;
949             readb->rbuf.count  = saved_count;
950             return -BIO_R_NON_FATAL;
951         }
952     }
953 
954     l = dgram_pair_read_inner(readb, (uint8_t *)buf, sz);
955     if (!ossl_assert(l == sz))
956         /* We were somehow not able to read the entire datagram. */
957         return -BIO_R_TRANSFER_ERROR;
958 
959     /*
960      * If the datagram was truncated due to an inadequate buffer, discard the
961      * remainder.
962      */
963     if (trunc > 0 && !ossl_assert(dgram_pair_read_inner(readb, NULL, trunc) == trunc))
964         /* We were somehow not able to read/skip the entire datagram. */
965         return -BIO_R_TRANSFER_ERROR;
966 
967     if (local != NULL)
968         *local = hdr.dst_addr;
969     if (peer != NULL)
970         *peer  = hdr.src_addr;
971 
972     return (ossl_ssize_t)l;
973 }
974 
975 /* Threadsafe */
dgram_pair_lock_both_write(struct bio_dgram_pair_st * a,struct bio_dgram_pair_st * b)976 static int dgram_pair_lock_both_write(struct bio_dgram_pair_st *a,
977                                       struct bio_dgram_pair_st *b)
978 {
979     struct bio_dgram_pair_st *x, *y;
980 
981     x = (a->role == 1) ? a : b;
982     y = (a->role == 1) ? b : a;
983 
984     if (!ossl_assert(a->role != b->role))
985         return 0;
986 
987     if (!ossl_assert(a != b && x != y))
988         return 0;
989 
990     if (CRYPTO_THREAD_write_lock(x->lock) == 0)
991         return 0;
992 
993     if (CRYPTO_THREAD_write_lock(y->lock) == 0) {
994         CRYPTO_THREAD_unlock(x->lock);
995         return 0;
996     }
997 
998     return 1;
999 }
1000 
dgram_pair_unlock_both(struct bio_dgram_pair_st * a,struct bio_dgram_pair_st * b)1001 static void dgram_pair_unlock_both(struct bio_dgram_pair_st *a,
1002                                    struct bio_dgram_pair_st *b)
1003 {
1004     CRYPTO_THREAD_unlock(a->lock);
1005     CRYPTO_THREAD_unlock(b->lock);
1006 }
1007 
1008 /* Threadsafe */
dgram_pair_read(BIO * bio,char * buf,int sz_)1009 static int dgram_pair_read(BIO *bio, char *buf, int sz_)
1010 {
1011     int ret;
1012     ossl_ssize_t l;
1013     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
1014 
1015     if (sz_ < 0) {
1016         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
1017         return -1;
1018     }
1019 
1020     if (b->peer == NULL) {
1021         ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
1022         return -1;
1023     }
1024 
1025     peerb = b->peer->ptr;
1026 
1027     /*
1028      * For BIO_read we have to acquire both locks because we touch the retry
1029      * flags on the local bio. (This is avoided in the recvmmsg case as it does
1030      * not touch the retry flags.)
1031      */
1032     if (dgram_pair_lock_both_write(peerb, b) == 0) {
1033         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1034         return -1;
1035     }
1036 
1037     l = dgram_pair_read_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
1038     if (l < 0) {
1039         if (l != -BIO_R_NON_FATAL)
1040             ERR_raise(ERR_LIB_BIO, -l);
1041         ret = -1;
1042     } else {
1043         ret = (int)l;
1044     }
1045 
1046     dgram_pair_unlock_both(peerb, b);
1047     return ret;
1048 }
1049 
1050 /* Threadsafe */
dgram_pair_recvmmsg(BIO * bio,BIO_MSG * msg,size_t stride,size_t num_msg,uint64_t flags,size_t * num_processed)1051 static int dgram_pair_recvmmsg(BIO *bio, BIO_MSG *msg,
1052                                size_t stride, size_t num_msg,
1053                                uint64_t flags,
1054                                size_t *num_processed)
1055 {
1056     int ret;
1057     ossl_ssize_t l;
1058     BIO_MSG *m;
1059     size_t i;
1060     struct bio_dgram_pair_st *b = bio->ptr, *readb;
1061 
1062     if (num_msg == 0) {
1063         *num_processed = 0;
1064         return 1;
1065     }
1066 
1067     if (!bio->init) {
1068         ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
1069         *num_processed = 0;
1070         return 0;
1071     }
1072 
1073     if (is_dgram_pair(b))
1074         readb = b->peer->ptr;
1075     else
1076         readb = b;
1077 
1078     if (CRYPTO_THREAD_write_lock(readb->lock) == 0) {
1079         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1080         *num_processed = 0;
1081         return 0;
1082     }
1083 
1084     for (i = 0; i < num_msg; ++i) {
1085         m = &BIO_MSG_N(msg, i);
1086         l = dgram_pair_read_actual(bio, m->data, m->data_len,
1087                                    m->local, m->peer, 1);
1088         if (l < 0) {
1089             *num_processed = i;
1090             if (i > 0) {
1091                 ret = 1;
1092             } else {
1093                 ERR_raise(ERR_LIB_BIO, -l);
1094                 ret = 0;
1095             }
1096             goto out;
1097         }
1098 
1099         m->data_len = l;
1100         m->flags    = 0;
1101     }
1102 
1103     *num_processed = i;
1104     ret = 1;
1105 out:
1106     CRYPTO_THREAD_unlock(readb->lock);
1107     return ret;
1108 }
1109 
1110 /* Threadsafe */
dgram_mem_read(BIO * bio,char * buf,int sz_)1111 static int dgram_mem_read(BIO *bio, char *buf, int sz_)
1112 {
1113     int ret;
1114     ossl_ssize_t l;
1115     struct bio_dgram_pair_st *b = bio->ptr;
1116 
1117     if (sz_ < 0) {
1118         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
1119         return -1;
1120     }
1121 
1122     if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
1123         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1124         return -1;
1125     }
1126 
1127     l = dgram_pair_read_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
1128     if (l < 0) {
1129         if (l != -BIO_R_NON_FATAL)
1130             ERR_raise(ERR_LIB_BIO, -l);
1131         ret = -1;
1132     } else {
1133         ret = (int)l;
1134     }
1135 
1136     CRYPTO_THREAD_unlock(b->lock);
1137     return ret;
1138 }
1139 
1140 /*
1141  * Calculate the array growth based on the target size.
1142  *
1143  * The growth factor is a rational number and is defined by a numerator
1144  * and a denominator.  According to Andrew Koenig in his paper "Why Are
1145  * Vectors Efficient?" from JOOP 11(5) 1998, this factor should be less
1146  * than the golden ratio (1.618...).
1147  *
1148  * We use an expansion factor of 8 / 5 = 1.6
1149  */
1150 static const size_t max_rbuf_size = SIZE_MAX / 2; /* unlimited in practice */
compute_rbuf_growth(size_t target,size_t current)1151 static ossl_inline size_t compute_rbuf_growth(size_t target, size_t current)
1152 {
1153     int err = 0;
1154 
1155     while (current < target) {
1156         if (current >= max_rbuf_size)
1157             return 0;
1158 
1159         current = safe_muldiv_size_t(current, 8, 5, &err);
1160         if (err)
1161             return 0;
1162         if (current >= max_rbuf_size)
1163             current = max_rbuf_size;
1164     }
1165     return current;
1166 }
1167 
1168 /* Must hold local write lock */
dgram_pair_write_inner(struct bio_dgram_pair_st * b,const uint8_t * buf,size_t sz)1169 static size_t dgram_pair_write_inner(struct bio_dgram_pair_st *b,
1170                                      const uint8_t *buf, size_t sz)
1171 {
1172     size_t total_written = 0;
1173 
1174     /*
1175      * We repeat pushes to the ring buffer for as long as we have data until we
1176      * fail. We may not be able to push in one operation if the ring buffer
1177      * wraps around, but there may still be more room for data.
1178      */
1179     while (sz > 0) {
1180         size_t dst_len;
1181         uint8_t *dst_buf;
1182 
1183         /*
1184          * There are two BIO instances, each with a ringbuf. We write to our own
1185          * ringbuf and read from the peer ringbuf.
1186          */
1187         ring_buf_head(&b->rbuf, &dst_buf, &dst_len);
1188         if (dst_len == 0) {
1189             size_t new_len;
1190 
1191             if (!b->grows_on_write) /* resize only if size not set explicitly */
1192                 break;
1193             /* increase the size */
1194             new_len = compute_rbuf_growth(b->req_buf_len + sz, b->req_buf_len);
1195             if (new_len == 0 || !ring_buf_resize(&b->rbuf, new_len))
1196                 break;
1197             b->req_buf_len = new_len;
1198         }
1199 
1200         if (dst_len > sz)
1201             dst_len = sz;
1202 
1203         memcpy(dst_buf, buf, dst_len);
1204         ring_buf_push(&b->rbuf, dst_len);
1205 
1206         buf             += dst_len;
1207         sz              -= dst_len;
1208         total_written   += dst_len;
1209     }
1210 
1211     return total_written;
1212 }
1213 
1214 /*
1215  * Must hold local write lock. Returns number of bytes processed or negated BIO
1216  * response code.
1217  */
dgram_pair_write_actual(BIO * bio,const char * buf,size_t sz,const BIO_ADDR * local,const BIO_ADDR * peer,int is_multi)1218 static ossl_ssize_t dgram_pair_write_actual(BIO *bio, const char *buf, size_t sz,
1219                                             const BIO_ADDR *local, const BIO_ADDR *peer,
1220                                             int is_multi)
1221 {
1222     static const BIO_ADDR zero_addr;
1223     size_t saved_idx, saved_count;
1224     struct bio_dgram_pair_st *b = bio->ptr, *readb;
1225     struct dgram_hdr hdr = {0};
1226 
1227     if (!is_multi)
1228         BIO_clear_retry_flags(bio);
1229 
1230     if (!bio->init)
1231         return -BIO_R_UNINITIALIZED;
1232 
1233     if (!ossl_assert(b != NULL && b->rbuf.start != NULL))
1234         return -BIO_R_TRANSFER_ERROR;
1235 
1236     if (sz > 0 && buf == NULL)
1237         return -BIO_R_INVALID_ARGUMENT;
1238 
1239     if (local != NULL && b->local_addr_enable == 0)
1240         return -BIO_R_LOCAL_ADDR_NOT_AVAILABLE;
1241 
1242     if (is_dgram_pair(b))
1243         readb = b->peer->ptr;
1244     else
1245         readb = b;
1246     if (peer != NULL && (readb->cap & BIO_DGRAM_CAP_HANDLES_DST_ADDR) == 0)
1247         return -BIO_R_PEER_ADDR_NOT_AVAILABLE;
1248 
1249     hdr.len = sz;
1250     hdr.dst_addr = (peer != NULL ? *peer : zero_addr);
1251     if (local == NULL)
1252         local = b->local_addr;
1253     hdr.src_addr = (local != NULL ? *local : zero_addr);
1254 
1255     saved_idx   = b->rbuf.idx[0];
1256     saved_count = b->rbuf.count;
1257     if (dgram_pair_write_inner(b, (const uint8_t *)&hdr, sizeof(hdr)) != sizeof(hdr)
1258             || dgram_pair_write_inner(b, (const uint8_t *)buf, sz) != sz) {
1259         /*
1260          * We were not able to push the header and the entirety of the payload
1261          * onto the ring buffer, so abort and roll back the ring buffer state.
1262          */
1263         b->rbuf.idx[0] = saved_idx;
1264         b->rbuf.count  = saved_count;
1265         if (!is_multi)
1266             BIO_set_retry_write(bio);
1267         return -BIO_R_NON_FATAL;
1268     }
1269 
1270     return sz;
1271 }
1272 
1273 /* Threadsafe */
dgram_pair_write(BIO * bio,const char * buf,int sz_)1274 static int dgram_pair_write(BIO *bio, const char *buf, int sz_)
1275 {
1276     int ret;
1277     ossl_ssize_t l;
1278     struct bio_dgram_pair_st *b = bio->ptr;
1279 
1280     if (sz_ < 0) {
1281         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
1282         return -1;
1283     }
1284 
1285     if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
1286         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1287         return -1;
1288     }
1289 
1290     l = dgram_pair_write_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
1291     if (l < 0) {
1292         ERR_raise(ERR_LIB_BIO, -l);
1293         ret = -1;
1294     } else {
1295         ret = (int)l;
1296     }
1297 
1298     CRYPTO_THREAD_unlock(b->lock);
1299     return ret;
1300 }
1301 
1302 /* Threadsafe */
dgram_pair_sendmmsg(BIO * bio,BIO_MSG * msg,size_t stride,size_t num_msg,uint64_t flags,size_t * num_processed)1303 static int dgram_pair_sendmmsg(BIO *bio, BIO_MSG *msg,
1304                                size_t stride, size_t num_msg,
1305                                uint64_t flags, size_t *num_processed)
1306 {
1307     ossl_ssize_t ret, l;
1308     BIO_MSG *m;
1309     size_t i;
1310     struct bio_dgram_pair_st *b = bio->ptr;
1311 
1312     if (num_msg == 0) {
1313         *num_processed = 0;
1314         return 1;
1315     }
1316 
1317     if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
1318         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1319         *num_processed = 0;
1320         return 0;
1321     }
1322 
1323     for (i = 0; i < num_msg; ++i) {
1324         m = &BIO_MSG_N(msg, i);
1325         l = dgram_pair_write_actual(bio, m->data, m->data_len,
1326                                     m->local, m->peer, 1);
1327         if (l < 0) {
1328             *num_processed = i;
1329             if (i > 0) {
1330                 ret = 1;
1331             } else {
1332                 ERR_raise(ERR_LIB_BIO, -l);
1333                 ret = 0;
1334             }
1335             goto out;
1336         }
1337 
1338         m->flags = 0;
1339     }
1340 
1341     *num_processed = i;
1342     ret = 1;
1343 out:
1344     CRYPTO_THREAD_unlock(b->lock);
1345     return ret;
1346 }
1347 
1348 #endif
1349