xref: /freebsd/crypto/openssl/crypto/bio/bss_dgram_pair.c (revision 1523ccfd9c8c254f7928143d31c305384b05fd11)
1 /*
2  * Copyright 2022-2026 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         dgram_pair_free(bio);
309         ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
310         return 0;
311     }
312 
313     b->grows_on_write = 1;
314 
315     bio->init = 1;
316     return 1;
317 }
318 
dgram_pair_free(BIO * bio)319 static int dgram_pair_free(BIO *bio)
320 {
321     struct bio_dgram_pair_st *b;
322 
323     if (bio == NULL)
324         return 0;
325 
326     b = bio->ptr;
327     if (!ossl_assert(b != NULL))
328         return 0;
329 
330     /* We are being freed. Disconnect any peer and destroy buffers. */
331     dgram_pair_ctrl_destroy_bio_pair(bio);
332 
333     CRYPTO_THREAD_lock_free(b->lock);
334     OPENSSL_free(b);
335     return 1;
336 }
337 
338 /* BIO_make_bio_pair (BIO_C_MAKE_BIO_PAIR) */
dgram_pair_ctrl_make_bio_pair(BIO * bio1,BIO * bio2)339 static int dgram_pair_ctrl_make_bio_pair(BIO *bio1, BIO *bio2)
340 {
341     struct bio_dgram_pair_st *b1, *b2;
342 
343     /* peer must be non-NULL. */
344     if (bio1 == NULL || bio2 == NULL) {
345         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
346         return 0;
347     }
348 
349     /* Ensure the BIO we have been passed is actually a dgram pair BIO. */
350     if (bio1->method != &dgram_pair_method || bio2->method != &dgram_pair_method) {
351         ERR_raise_data(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT,
352             "both BIOs must be BIO_dgram_pair");
353         return 0;
354     }
355 
356     b1 = bio1->ptr;
357     b2 = bio2->ptr;
358 
359     if (!ossl_assert(b1 != NULL && b2 != NULL)) {
360         ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
361         return 0;
362     }
363 
364     /*
365      * This ctrl cannot be used to associate a BIO pair half which is already
366      * associated.
367      */
368     if (b1->peer != NULL || b2->peer != NULL) {
369         ERR_raise_data(ERR_LIB_BIO, BIO_R_IN_USE,
370             "cannot associate a BIO_dgram_pair which is already in use");
371         return 0;
372     }
373 
374     if (!ossl_assert(b1->req_buf_len >= MIN_BUF_LEN
375             && b2->req_buf_len >= MIN_BUF_LEN)) {
376         ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
377         return 0;
378     }
379 
380     if (b1->rbuf.len != b1->req_buf_len)
381         if (ring_buf_init(&b1->rbuf, b1->req_buf_len) == 0) {
382             ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
383             return 0;
384         }
385 
386     if (b2->rbuf.len != b2->req_buf_len)
387         if (ring_buf_init(&b2->rbuf, b2->req_buf_len) == 0) {
388             ERR_raise(ERR_LIB_BIO, ERR_R_BIO_LIB);
389             ring_buf_destroy(&b1->rbuf);
390             return 0;
391         }
392 
393     b1->peer = bio2;
394     b2->peer = bio1;
395     b1->role = 0;
396     b2->role = 1;
397     bio1->init = 1;
398     bio2->init = 1;
399     return 1;
400 }
401 
402 /* BIO_destroy_bio_pair (BIO_C_DESTROY_BIO_PAIR) */
dgram_pair_ctrl_destroy_bio_pair(BIO * bio1)403 static int dgram_pair_ctrl_destroy_bio_pair(BIO *bio1)
404 {
405     BIO *bio2;
406     struct bio_dgram_pair_st *b1 = bio1->ptr, *b2;
407 
408     ring_buf_destroy(&b1->rbuf);
409     bio1->init = 0;
410 
411     BIO_ADDR_free(b1->local_addr);
412 
413     /* Early return if we don't have a peer. */
414     if (b1->peer == NULL)
415         return 1;
416 
417     bio2 = b1->peer;
418     b2 = bio2->ptr;
419 
420     /* Invariant. */
421     if (!ossl_assert(b2->peer == bio1))
422         return 0;
423 
424     /* Free buffers. */
425     ring_buf_destroy(&b2->rbuf);
426 
427     bio2->init = 0;
428     b1->peer = NULL;
429     b2->peer = NULL;
430     return 1;
431 }
432 
433 /* BIO_eof (BIO_CTRL_EOF) */
dgram_pair_ctrl_eof(BIO * bio)434 static int dgram_pair_ctrl_eof(BIO *bio)
435 {
436     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
437 
438     if (!ossl_assert(b != NULL))
439         return -1;
440 
441     /* If we aren't initialized, we can never read anything */
442     if (!bio->init)
443         return 1;
444     if (!is_dgram_pair(b))
445         return 0;
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 | BIO_DGRAM_CAP_PROVIDES_DST_ADDR)) == 0;
565 }
566 
567 /* BIO_dgram_get_effective_caps (BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS) */
dgram_pair_ctrl_get_effective_caps(BIO * bio)568 static int dgram_pair_ctrl_get_effective_caps(BIO *bio)
569 {
570     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
571 
572     if (b->peer == NULL)
573         return 0;
574 
575     peerb = b->peer->ptr;
576 
577     return peerb->cap;
578 }
579 
580 /* BIO_dgram_get_caps (BIO_CTRL_DGRAM_GET_CAPS) */
dgram_pair_ctrl_get_caps(BIO * bio)581 static uint32_t dgram_pair_ctrl_get_caps(BIO *bio)
582 {
583     struct bio_dgram_pair_st *b = bio->ptr;
584 
585     return b->cap;
586 }
587 
588 /* BIO_dgram_set_caps (BIO_CTRL_DGRAM_SET_CAPS) */
dgram_pair_ctrl_set_caps(BIO * bio,uint32_t caps)589 static int dgram_pair_ctrl_set_caps(BIO *bio, uint32_t caps)
590 {
591     struct bio_dgram_pair_st *b = bio->ptr;
592 
593     b->cap = caps;
594     return 1;
595 }
596 
597 /* BIO_dgram_get_local_addr_enable (BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE) */
dgram_pair_ctrl_get_local_addr_enable(BIO * bio)598 static int dgram_pair_ctrl_get_local_addr_enable(BIO *bio)
599 {
600     struct bio_dgram_pair_st *b = bio->ptr;
601 
602     return b->local_addr_enable;
603 }
604 
605 /* BIO_dgram_set_local_addr_enable (BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE) */
dgram_pair_ctrl_set_local_addr_enable(BIO * bio,int enable)606 static int dgram_pair_ctrl_set_local_addr_enable(BIO *bio, int enable)
607 {
608     struct bio_dgram_pair_st *b = bio->ptr;
609 
610     if (dgram_pair_ctrl_get_local_addr_cap(bio) == 0)
611         return 0;
612 
613     b->local_addr_enable = (enable != 0 ? 1 : 0);
614     return 1;
615 }
616 
617 /* BIO_dgram_get_mtu (BIO_CTRL_DGRAM_GET_MTU) */
dgram_pair_ctrl_get_mtu(BIO * bio)618 static int dgram_pair_ctrl_get_mtu(BIO *bio)
619 {
620     struct bio_dgram_pair_st *b = bio->ptr;
621 
622     return b->mtu;
623 }
624 
625 /* BIO_dgram_set_mtu (BIO_CTRL_DGRAM_SET_MTU) */
dgram_pair_ctrl_set_mtu(BIO * bio,size_t mtu)626 static int dgram_pair_ctrl_set_mtu(BIO *bio, size_t mtu)
627 {
628     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
629 
630     b->mtu = mtu;
631 
632     if (b->peer != NULL) {
633         peerb = b->peer->ptr;
634         peerb->mtu = mtu;
635     }
636 
637     return 1;
638 }
639 
640 /* BIO_dgram_set0_local_addr (BIO_CTRL_DGRAM_SET0_LOCAL_ADDR) */
dgram_pair_ctrl_set0_local_addr(BIO * bio,BIO_ADDR * addr)641 static int dgram_pair_ctrl_set0_local_addr(BIO *bio, BIO_ADDR *addr)
642 {
643     struct bio_dgram_pair_st *b = bio->ptr;
644 
645     BIO_ADDR_free(b->local_addr);
646     b->local_addr = addr;
647     return 1;
648 }
649 
650 /* Partially threadsafe (some commands) */
dgram_mem_ctrl(BIO * bio,int cmd,long num,void * ptr)651 static long dgram_mem_ctrl(BIO *bio, int cmd, long num, void *ptr)
652 {
653     long ret = 1;
654     struct bio_dgram_pair_st *b = bio->ptr;
655 
656     if (!ossl_assert(b != NULL))
657         return 0;
658 
659     switch (cmd) {
660     /*
661      * BIO_set_write_buf_size: Set the size of the ring buffer used for storing
662      * datagrams. No more writes can be performed once the buffer is filled up,
663      * until reads are performed. This cannot be used after a peer is connected.
664      */
665     case BIO_C_SET_WRITE_BUF_SIZE: /* Non-threadsafe */
666         ret = (long)dgram_pair_ctrl_set_write_buf_size(bio, (size_t)num);
667         break;
668 
669     /*
670      * BIO_get_write_buf_size: Get ring buffer size.
671      */
672     case BIO_C_GET_WRITE_BUF_SIZE: /* Non-threadsafe */
673         ret = (long)b->req_buf_len;
674         break;
675 
676     /*
677      * BIO_reset: Clear all data which was written to this side of the pair.
678      */
679     case BIO_CTRL_RESET: /* Non-threadsafe */
680         dgram_pair_ctrl_reset(bio);
681         break;
682 
683     /*
684      * BIO_get_write_guarantee: Any BIO_write providing a buffer less than or
685      * equal to this value is guaranteed to succeed.
686      */
687     case BIO_C_GET_WRITE_GUARANTEE: /* Threadsafe */
688         ret = (long)dgram_pair_ctrl_get_write_guarantee(bio);
689         break;
690 
691     /* BIO_pending: Bytes available to read. */
692     case BIO_CTRL_PENDING: /* Threadsafe */
693         ret = (long)dgram_pair_ctrl_pending(bio);
694         break;
695 
696     /* BIO_flush: No-op. */
697     case BIO_CTRL_FLUSH: /* Threadsafe */
698         break;
699 
700     /* BIO_dgram_get_no_trunc */
701     case BIO_CTRL_DGRAM_GET_NO_TRUNC: /* Non-threadsafe */
702         ret = (long)b->no_trunc;
703         break;
704 
705     /* BIO_dgram_set_no_trunc */
706     case BIO_CTRL_DGRAM_SET_NO_TRUNC: /* Non-threadsafe */
707         b->no_trunc = (num > 0);
708         break;
709 
710     /* BIO_dgram_get_local_addr_enable */
711     case BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE: /* Non-threadsafe */
712         *(int *)ptr = (int)dgram_pair_ctrl_get_local_addr_enable(bio);
713         break;
714 
715     /* BIO_dgram_set_local_addr_enable */
716     case BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE: /* Non-threadsafe */
717         ret = (long)dgram_pair_ctrl_set_local_addr_enable(bio, num);
718         break;
719 
720     /* BIO_dgram_get_local_addr_cap: Can local addresses be supported? */
721     case BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP: /* Non-threadsafe */
722         ret = (long)dgram_pair_ctrl_get_local_addr_cap(bio);
723         break;
724 
725     /* BIO_dgram_get_effective_caps */
726     case BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS: /* Non-threadsafe */
727     /* BIO_dgram_get_caps */
728     case BIO_CTRL_DGRAM_GET_CAPS: /* Non-threadsafe */
729         ret = (long)dgram_pair_ctrl_get_caps(bio);
730         break;
731 
732     /* BIO_dgram_set_caps */
733     case BIO_CTRL_DGRAM_SET_CAPS: /* Non-threadsafe */
734         ret = (long)dgram_pair_ctrl_set_caps(bio, (uint32_t)num);
735         break;
736 
737     /* BIO_dgram_get_mtu */
738     case BIO_CTRL_DGRAM_GET_MTU: /* Non-threadsafe */
739         ret = (long)dgram_pair_ctrl_get_mtu(bio);
740         break;
741 
742     /* BIO_dgram_set_mtu */
743     case BIO_CTRL_DGRAM_SET_MTU: /* Non-threadsafe */
744         ret = (long)dgram_pair_ctrl_set_mtu(bio, (uint32_t)num);
745         break;
746 
747     case BIO_CTRL_DGRAM_SET0_LOCAL_ADDR:
748         ret = (long)dgram_pair_ctrl_set0_local_addr(bio, (BIO_ADDR *)ptr);
749         break;
750 
751     /*
752      * BIO_eof: Returns whether this half of the BIO pair is empty of data to
753      * read.
754      */
755     case BIO_CTRL_EOF: /* Non-threadsafe */
756         ret = (long)dgram_pair_ctrl_eof(bio);
757         break;
758 
759     default:
760         ret = 0;
761         break;
762     }
763 
764     return ret;
765 }
766 
dgram_pair_ctrl(BIO * bio,int cmd,long num,void * ptr)767 static long dgram_pair_ctrl(BIO *bio, int cmd, long num, void *ptr)
768 {
769     long ret = 1;
770 
771     switch (cmd) {
772     /*
773      * BIO_make_bio_pair: this is usually used by BIO_new_dgram_pair, though it
774      * may be used manually after manually creating each half of a BIO pair
775      * using BIO_new. This only needs to be called on one of the BIOs.
776      */
777     case BIO_C_MAKE_BIO_PAIR: /* Non-threadsafe */
778         ret = (long)dgram_pair_ctrl_make_bio_pair(bio, (BIO *)ptr);
779         break;
780 
781     /*
782      * BIO_destroy_bio_pair: Manually disconnect two halves of a BIO pair so
783      * that they are no longer peers.
784      */
785     case BIO_C_DESTROY_BIO_PAIR: /* Non-threadsafe */
786         dgram_pair_ctrl_destroy_bio_pair(bio);
787         break;
788 
789     /* BIO_dgram_get_effective_caps */
790     case BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS: /* Non-threadsafe */
791         ret = (long)dgram_pair_ctrl_get_effective_caps(bio);
792         break;
793 
794     default:
795         ret = dgram_mem_ctrl(bio, cmd, num, ptr);
796         break;
797     }
798 
799     return ret;
800 }
801 
BIO_new_bio_dgram_pair(BIO ** pbio1,size_t writebuf1,BIO ** pbio2,size_t writebuf2)802 int BIO_new_bio_dgram_pair(BIO **pbio1, size_t writebuf1,
803     BIO **pbio2, size_t writebuf2)
804 {
805     int ret = 0;
806     long r;
807     BIO *bio1 = NULL, *bio2 = NULL;
808 
809     bio1 = BIO_new(BIO_s_dgram_pair());
810     if (bio1 == NULL)
811         goto err;
812 
813     bio2 = BIO_new(BIO_s_dgram_pair());
814     if (bio2 == NULL)
815         goto err;
816 
817     if (writebuf1 > 0) {
818         r = BIO_set_write_buf_size(bio1, writebuf1);
819         if (r == 0)
820             goto err;
821     }
822 
823     if (writebuf2 > 0) {
824         r = BIO_set_write_buf_size(bio2, writebuf2);
825         if (r == 0)
826             goto err;
827     }
828 
829     r = BIO_make_bio_pair(bio1, bio2);
830     if (r == 0)
831         goto err;
832 
833     ret = 1;
834 err:
835     if (ret == 0) {
836         BIO_free(bio1);
837         bio1 = NULL;
838         BIO_free(bio2);
839         bio2 = NULL;
840     }
841 
842     *pbio1 = bio1;
843     *pbio2 = bio2;
844     return ret;
845 }
846 
847 /* Must hold peer write lock */
dgram_pair_read_inner(struct bio_dgram_pair_st * b,uint8_t * buf,size_t sz)848 static size_t dgram_pair_read_inner(struct bio_dgram_pair_st *b, uint8_t *buf, size_t sz)
849 {
850     size_t total_read = 0;
851 
852     /*
853      * We repeat pops from the ring buffer for as long as we have more
854      * application *buffer to fill until we fail. We may not be able to pop
855      * enough data to fill the buffer in one operation if the ring buffer wraps
856      * around, but there may still be more data available.
857      */
858     while (sz > 0) {
859         uint8_t *src_buf = NULL;
860         size_t src_len = 0;
861 
862         /*
863          * There are two BIO instances, each with a ringbuf. We read from the
864          * peer ringbuf and write to our own ringbuf.
865          */
866         ring_buf_tail(&b->rbuf, &src_buf, &src_len);
867         if (src_len == 0)
868             break;
869 
870         if (src_len > sz)
871             src_len = sz;
872 
873         if (buf != NULL)
874             memcpy(buf, src_buf, src_len);
875 
876         ring_buf_pop(&b->rbuf, src_len);
877 
878         if (buf != NULL)
879             buf += src_len;
880         total_read += src_len;
881         sz -= src_len;
882     }
883 
884     return total_read;
885 }
886 
887 /*
888  * Must hold peer write lock. Returns number of bytes processed or negated BIO
889  * response code.
890  */
dgram_pair_read_actual(BIO * bio,char * buf,size_t sz,BIO_ADDR * local,BIO_ADDR * peer,int is_multi)891 static ossl_ssize_t dgram_pair_read_actual(BIO *bio, char *buf, size_t sz,
892     BIO_ADDR *local, BIO_ADDR *peer,
893     int is_multi)
894 {
895     size_t l, trunc = 0, saved_idx, saved_count;
896     struct bio_dgram_pair_st *b = bio->ptr, *readb;
897     struct dgram_hdr hdr;
898 
899     if (!is_multi)
900         BIO_clear_retry_flags(bio);
901 
902     if (!bio->init)
903         return -BIO_R_UNINITIALIZED;
904 
905     if (!ossl_assert(b != NULL))
906         return -BIO_R_TRANSFER_ERROR;
907 
908     if (is_dgram_pair(b))
909         readb = b->peer->ptr;
910     else
911         readb = b;
912     if (!ossl_assert(readb != NULL && readb->rbuf.start != NULL))
913         return -BIO_R_TRANSFER_ERROR;
914 
915     if (sz > 0 && buf == NULL)
916         return -BIO_R_INVALID_ARGUMENT;
917 
918     /* If the caller wants to know the local address, it must be enabled */
919     if (local != NULL && b->local_addr_enable == 0)
920         return -BIO_R_LOCAL_ADDR_NOT_AVAILABLE;
921 
922     /* Read the header. */
923     saved_idx = readb->rbuf.idx[1];
924     saved_count = readb->rbuf.count;
925     l = dgram_pair_read_inner(readb, (uint8_t *)&hdr, sizeof(hdr));
926     if (l == 0) {
927         /* Buffer was empty. */
928         if (!is_multi)
929             BIO_set_retry_read(bio);
930         return -BIO_R_NON_FATAL;
931     }
932 
933     if (!ossl_assert(l == sizeof(hdr)))
934         /*
935          * This should not be possible as headers (and their following payloads)
936          * should always be written atomically.
937          */
938         return -BIO_R_BROKEN_PIPE;
939 
940     if (sz > hdr.len) {
941         sz = hdr.len;
942     } else if (sz < hdr.len) {
943         /* Truncation is occurring. */
944         trunc = hdr.len - sz;
945         if (b->no_trunc) {
946             /* Restore original state. */
947             readb->rbuf.idx[1] = saved_idx;
948             readb->rbuf.count = saved_count;
949             return -BIO_R_NON_FATAL;
950         }
951     }
952 
953     l = dgram_pair_read_inner(readb, (uint8_t *)buf, sz);
954     if (!ossl_assert(l == sz))
955         /* We were somehow not able to read the entire datagram. */
956         return -BIO_R_TRANSFER_ERROR;
957 
958     /*
959      * If the datagram was truncated due to an inadequate buffer, discard the
960      * remainder.
961      */
962     if (trunc > 0 && !ossl_assert(dgram_pair_read_inner(readb, NULL, trunc) == trunc))
963         /* We were somehow not able to read/skip the entire datagram. */
964         return -BIO_R_TRANSFER_ERROR;
965 
966     if (local != NULL)
967         *local = hdr.dst_addr;
968     if (peer != NULL)
969         *peer = hdr.src_addr;
970 
971     return (ossl_ssize_t)l;
972 }
973 
974 /* Threadsafe */
dgram_pair_lock_both_write(struct bio_dgram_pair_st * a,struct bio_dgram_pair_st * b)975 static int dgram_pair_lock_both_write(struct bio_dgram_pair_st *a,
976     struct bio_dgram_pair_st *b)
977 {
978     struct bio_dgram_pair_st *x, *y;
979 
980     x = (a->role == 1) ? a : b;
981     y = (a->role == 1) ? b : a;
982 
983     if (!ossl_assert(a->role != b->role))
984         return 0;
985 
986     if (!ossl_assert(a != b && x != y))
987         return 0;
988 
989     if (CRYPTO_THREAD_write_lock(x->lock) == 0)
990         return 0;
991 
992     if (CRYPTO_THREAD_write_lock(y->lock) == 0) {
993         CRYPTO_THREAD_unlock(x->lock);
994         return 0;
995     }
996 
997     return 1;
998 }
999 
dgram_pair_unlock_both(struct bio_dgram_pair_st * a,struct bio_dgram_pair_st * b)1000 static void dgram_pair_unlock_both(struct bio_dgram_pair_st *a,
1001     struct bio_dgram_pair_st *b)
1002 {
1003     CRYPTO_THREAD_unlock(a->lock);
1004     CRYPTO_THREAD_unlock(b->lock);
1005 }
1006 
1007 /* Threadsafe */
dgram_pair_read(BIO * bio,char * buf,int sz_)1008 static int dgram_pair_read(BIO *bio, char *buf, int sz_)
1009 {
1010     int ret;
1011     ossl_ssize_t l;
1012     struct bio_dgram_pair_st *b = bio->ptr, *peerb;
1013 
1014     if (sz_ < 0) {
1015         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
1016         return -1;
1017     }
1018 
1019     if (b->peer == NULL) {
1020         ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
1021         return -1;
1022     }
1023 
1024     peerb = b->peer->ptr;
1025 
1026     /*
1027      * For BIO_read we have to acquire both locks because we touch the retry
1028      * flags on the local bio. (This is avoided in the recvmmsg case as it does
1029      * not touch the retry flags.)
1030      */
1031     if (dgram_pair_lock_both_write(peerb, b) == 0) {
1032         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1033         return -1;
1034     }
1035 
1036     l = dgram_pair_read_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
1037     if (l < 0) {
1038         if (l != -BIO_R_NON_FATAL)
1039             ERR_raise(ERR_LIB_BIO, -l);
1040         ret = -1;
1041     } else {
1042         ret = (int)l;
1043     }
1044 
1045     dgram_pair_unlock_both(peerb, b);
1046     return ret;
1047 }
1048 
1049 /* Threadsafe */
dgram_pair_recvmmsg(BIO * bio,BIO_MSG * msg,size_t stride,size_t num_msg,uint64_t flags,size_t * num_processed)1050 static int dgram_pair_recvmmsg(BIO *bio, BIO_MSG *msg,
1051     size_t stride, size_t num_msg,
1052     uint64_t flags,
1053     size_t *num_processed)
1054 {
1055     int ret;
1056     ossl_ssize_t l;
1057     BIO_MSG *m;
1058     size_t i;
1059     struct bio_dgram_pair_st *b = bio->ptr, *readb;
1060 
1061     if (num_msg == 0) {
1062         *num_processed = 0;
1063         return 1;
1064     }
1065 
1066     if (!bio->init) {
1067         ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
1068         *num_processed = 0;
1069         return 0;
1070     }
1071 
1072     if (is_dgram_pair(b))
1073         readb = b->peer->ptr;
1074     else
1075         readb = b;
1076 
1077     if (CRYPTO_THREAD_write_lock(readb->lock) == 0) {
1078         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1079         *num_processed = 0;
1080         return 0;
1081     }
1082 
1083     for (i = 0; i < num_msg; ++i) {
1084         m = &BIO_MSG_N(msg, i);
1085         l = dgram_pair_read_actual(bio, m->data, m->data_len,
1086             m->local, m->peer, 1);
1087         if (l < 0) {
1088             *num_processed = i;
1089             if (i > 0) {
1090                 ret = 1;
1091             } else {
1092                 ERR_raise(ERR_LIB_BIO, -l);
1093                 ret = 0;
1094             }
1095             goto out;
1096         }
1097 
1098         m->data_len = l;
1099         m->flags = 0;
1100     }
1101 
1102     *num_processed = i;
1103     ret = 1;
1104 out:
1105     CRYPTO_THREAD_unlock(readb->lock);
1106     return ret;
1107 }
1108 
1109 /* Threadsafe */
dgram_mem_read(BIO * bio,char * buf,int sz_)1110 static int dgram_mem_read(BIO *bio, char *buf, int sz_)
1111 {
1112     int ret;
1113     ossl_ssize_t l;
1114     struct bio_dgram_pair_st *b = bio->ptr;
1115 
1116     if (sz_ < 0) {
1117         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
1118         return -1;
1119     }
1120 
1121     if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
1122         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1123         return -1;
1124     }
1125 
1126     l = dgram_pair_read_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
1127     if (l < 0) {
1128         if (l != -BIO_R_NON_FATAL)
1129             ERR_raise(ERR_LIB_BIO, -l);
1130         ret = -1;
1131     } else {
1132         ret = (int)l;
1133     }
1134 
1135     CRYPTO_THREAD_unlock(b->lock);
1136     return ret;
1137 }
1138 
1139 /*
1140  * Calculate the array growth based on the target size.
1141  *
1142  * The growth factor is a rational number and is defined by a numerator
1143  * and a denominator.  According to Andrew Koenig in his paper "Why Are
1144  * Vectors Efficient?" from JOOP 11(5) 1998, this factor should be less
1145  * than the golden ratio (1.618...).
1146  *
1147  * We use an expansion factor of 8 / 5 = 1.6
1148  */
1149 static const size_t max_rbuf_size = SIZE_MAX / 2; /* unlimited in practice */
compute_rbuf_growth(size_t target,size_t current)1150 static ossl_inline size_t compute_rbuf_growth(size_t target, size_t current)
1151 {
1152     int err = 0;
1153 
1154     while (current < target) {
1155         if (current >= max_rbuf_size)
1156             return 0;
1157 
1158         current = safe_muldiv_size_t(current, 8, 5, &err);
1159         if (err)
1160             return 0;
1161         if (current >= max_rbuf_size)
1162             current = max_rbuf_size;
1163     }
1164     return current;
1165 }
1166 
1167 /* Must hold local write lock */
dgram_pair_write_inner(struct bio_dgram_pair_st * b,const uint8_t * buf,size_t sz)1168 static size_t dgram_pair_write_inner(struct bio_dgram_pair_st *b,
1169     const uint8_t *buf, size_t sz)
1170 {
1171     size_t total_written = 0;
1172 
1173     /*
1174      * We repeat pushes to the ring buffer for as long as we have data until we
1175      * fail. We may not be able to push in one operation if the ring buffer
1176      * wraps around, but there may still be more room for data.
1177      */
1178     while (sz > 0) {
1179         size_t dst_len;
1180         uint8_t *dst_buf;
1181 
1182         /*
1183          * There are two BIO instances, each with a ringbuf. We write to our own
1184          * ringbuf and read from the peer ringbuf.
1185          */
1186         ring_buf_head(&b->rbuf, &dst_buf, &dst_len);
1187         if (dst_len == 0) {
1188             size_t new_len;
1189 
1190             if (!b->grows_on_write) /* resize only if size not set explicitly */
1191                 break;
1192             /* increase the size */
1193             new_len = compute_rbuf_growth(b->req_buf_len + sz, b->req_buf_len);
1194             if (new_len == 0 || !ring_buf_resize(&b->rbuf, new_len))
1195                 break;
1196             b->req_buf_len = new_len;
1197         }
1198 
1199         if (dst_len > sz)
1200             dst_len = sz;
1201 
1202         memcpy(dst_buf, buf, dst_len);
1203         ring_buf_push(&b->rbuf, dst_len);
1204 
1205         buf += dst_len;
1206         sz -= dst_len;
1207         total_written += dst_len;
1208     }
1209 
1210     return total_written;
1211 }
1212 
1213 /*
1214  * Must hold local write lock. Returns number of bytes processed or negated BIO
1215  * response code.
1216  */
dgram_pair_write_actual(BIO * bio,const char * buf,size_t sz,const BIO_ADDR * local,const BIO_ADDR * peer,int is_multi)1217 static ossl_ssize_t dgram_pair_write_actual(BIO *bio, const char *buf, size_t sz,
1218     const BIO_ADDR *local, const BIO_ADDR *peer,
1219     int is_multi)
1220 {
1221     static const BIO_ADDR zero_addr;
1222     size_t saved_idx, saved_count;
1223     struct bio_dgram_pair_st *b = bio->ptr, *readb;
1224     struct dgram_hdr hdr = { 0 };
1225 
1226     if (!is_multi)
1227         BIO_clear_retry_flags(bio);
1228 
1229     if (!bio->init)
1230         return -BIO_R_UNINITIALIZED;
1231 
1232     if (!ossl_assert(b != NULL && b->rbuf.start != NULL))
1233         return -BIO_R_TRANSFER_ERROR;
1234 
1235     if (sz > 0 && buf == NULL)
1236         return -BIO_R_INVALID_ARGUMENT;
1237 
1238     if (local != NULL && b->local_addr_enable == 0)
1239         return -BIO_R_LOCAL_ADDR_NOT_AVAILABLE;
1240 
1241     if (is_dgram_pair(b))
1242         readb = b->peer->ptr;
1243     else
1244         readb = b;
1245     if (peer != NULL && (readb->cap & BIO_DGRAM_CAP_HANDLES_DST_ADDR) == 0)
1246         return -BIO_R_PEER_ADDR_NOT_AVAILABLE;
1247 
1248     hdr.len = sz;
1249     hdr.dst_addr = (peer != NULL ? *peer : zero_addr);
1250     if (local == NULL)
1251         local = b->local_addr;
1252     hdr.src_addr = (local != NULL ? *local : zero_addr);
1253 
1254     saved_idx = b->rbuf.idx[0];
1255     saved_count = b->rbuf.count;
1256     if (dgram_pair_write_inner(b, (const uint8_t *)&hdr, sizeof(hdr)) != sizeof(hdr)
1257         || dgram_pair_write_inner(b, (const uint8_t *)buf, sz) != sz) {
1258         /*
1259          * We were not able to push the header and the entirety of the payload
1260          * onto the ring buffer, so abort and roll back the ring buffer state.
1261          */
1262         b->rbuf.idx[0] = saved_idx;
1263         b->rbuf.count = saved_count;
1264         if (!is_multi)
1265             BIO_set_retry_write(bio);
1266         return -BIO_R_NON_FATAL;
1267     }
1268 
1269     return sz;
1270 }
1271 
1272 /* Threadsafe */
dgram_pair_write(BIO * bio,const char * buf,int sz_)1273 static int dgram_pair_write(BIO *bio, const char *buf, int sz_)
1274 {
1275     int ret;
1276     ossl_ssize_t l;
1277     struct bio_dgram_pair_st *b = bio->ptr;
1278 
1279     if (sz_ < 0) {
1280         ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
1281         return -1;
1282     }
1283 
1284     if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
1285         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1286         return -1;
1287     }
1288 
1289     l = dgram_pair_write_actual(bio, buf, (size_t)sz_, NULL, NULL, 0);
1290     if (l < 0) {
1291         ERR_raise(ERR_LIB_BIO, -l);
1292         ret = -1;
1293     } else {
1294         ret = (int)l;
1295     }
1296 
1297     CRYPTO_THREAD_unlock(b->lock);
1298     return ret;
1299 }
1300 
1301 /* Threadsafe */
dgram_pair_sendmmsg(BIO * bio,BIO_MSG * msg,size_t stride,size_t num_msg,uint64_t flags,size_t * num_processed)1302 static int dgram_pair_sendmmsg(BIO *bio, BIO_MSG *msg,
1303     size_t stride, size_t num_msg,
1304     uint64_t flags, size_t *num_processed)
1305 {
1306     ossl_ssize_t ret, l;
1307     BIO_MSG *m;
1308     size_t i;
1309     struct bio_dgram_pair_st *b = bio->ptr;
1310 
1311     if (num_msg == 0) {
1312         *num_processed = 0;
1313         return 1;
1314     }
1315 
1316     if (CRYPTO_THREAD_write_lock(b->lock) == 0) {
1317         ERR_raise(ERR_LIB_BIO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
1318         *num_processed = 0;
1319         return 0;
1320     }
1321 
1322     for (i = 0; i < num_msg; ++i) {
1323         m = &BIO_MSG_N(msg, i);
1324         l = dgram_pair_write_actual(bio, m->data, m->data_len,
1325             m->local, m->peer, 1);
1326         if (l < 0) {
1327             *num_processed = i;
1328             if (i > 0) {
1329                 ret = 1;
1330             } else {
1331                 ERR_raise(ERR_LIB_BIO, -l);
1332                 ret = 0;
1333             }
1334             goto out;
1335         }
1336 
1337         m->flags = 0;
1338     }
1339 
1340     *num_processed = i;
1341     ret = 1;
1342 out:
1343     CRYPTO_THREAD_unlock(b->lock);
1344     return ret;
1345 }
1346 
1347 #endif
1348