Coverage Report

Created: 2025-12-31 06:58

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