mirror of https://github.com/openssl/openssl
QUIC DEMUX: Allow MTU to vary over time and autodetect MTU
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19703)
This commit is contained in:
parent
6292519cd8
commit
d7668ff213
|
@ -126,6 +126,12 @@ struct quic_urxe_st {
|
|||
* QRX only; not used by the demuxer.
|
||||
*/
|
||||
char deferred;
|
||||
|
||||
/*
|
||||
* Used by the DEMUX to track if a URXE has been handed out. Used primarily
|
||||
* for debugging purposes.
|
||||
*/
|
||||
char demux_state;
|
||||
};
|
||||
|
||||
/* Accessors for URXE buffer. */
|
||||
|
@ -185,7 +191,6 @@ typedef void (ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg);
|
|||
*/
|
||||
QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
|
||||
size_t short_conn_id_len,
|
||||
size_t default_urxe_alloc_len,
|
||||
OSSL_TIME (*now)(void *arg),
|
||||
void *now_arg);
|
||||
|
||||
|
@ -196,10 +201,16 @@ QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
|
|||
void ossl_quic_demux_free(QUIC_DEMUX *demux);
|
||||
|
||||
/*
|
||||
* Changes the BIO which the demuxer reads from.
|
||||
* Changes the BIO which the demuxer reads from. This also sets the MTU if the
|
||||
* BIO supports querying the MTU.
|
||||
*/
|
||||
void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio);
|
||||
|
||||
/*
|
||||
* Changes the MTU in bytes we use to receive datagrams.
|
||||
*/
|
||||
int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu);
|
||||
|
||||
/*
|
||||
* Register a datagram handler callback for a connection ID.
|
||||
*
|
||||
|
|
|
@ -159,7 +159,7 @@ static int ch_init(QUIC_CHANNEL *ch)
|
|||
goto err;
|
||||
|
||||
if ((ch->demux = ossl_quic_demux_new(/*BIO=*/NULL, /*Short CID Len=*/0,
|
||||
1200, get_time, NULL)) == NULL)
|
||||
get_time, NULL)) == NULL)
|
||||
goto err;
|
||||
|
||||
qrx_args.demux = ch->demux;
|
||||
|
|
|
@ -12,8 +12,14 @@
|
|||
#include "internal/common.h"
|
||||
#include <openssl/lhash.h>
|
||||
|
||||
#define URXE_DEMUX_STATE_FREE 0 /* on urx_free list */
|
||||
#define URXE_DEMUX_STATE_PENDING 1 /* on urx_pending list */
|
||||
#define URXE_DEMUX_STATE_ISSUED 2 /* on neither list */
|
||||
|
||||
#define DEMUX_MAX_MSGS_PER_CALL 32
|
||||
|
||||
#define DEMUX_DEFAULT_MTU 1500
|
||||
|
||||
/* Structure used to track a given connection ID. */
|
||||
typedef struct quic_demux_conn_st QUIC_DEMUX_CONN;
|
||||
|
||||
|
@ -56,8 +62,11 @@ struct quic_demux_st {
|
|||
*/
|
||||
size_t short_conn_id_len;
|
||||
|
||||
/* Default URXE buffer size in bytes. */
|
||||
size_t default_urxe_alloc_len;
|
||||
/*
|
||||
* Our current understanding of the upper bound on an incoming datagram size
|
||||
* in bytes.
|
||||
*/
|
||||
size_t mtu;
|
||||
|
||||
/* Time retrieval callback. */
|
||||
OSSL_TIME (*now)(void *arg);
|
||||
|
@ -87,7 +96,6 @@ struct quic_demux_st {
|
|||
|
||||
QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
|
||||
size_t short_conn_id_len,
|
||||
size_t default_urxe_alloc_len,
|
||||
OSSL_TIME (*now)(void *arg),
|
||||
void *now_arg)
|
||||
{
|
||||
|
@ -99,7 +107,8 @@ QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
|
|||
|
||||
demux->net_bio = net_bio;
|
||||
demux->short_conn_id_len = short_conn_id_len;
|
||||
demux->default_urxe_alloc_len = default_urxe_alloc_len;
|
||||
/* We update this if possible when we get a BIO. */
|
||||
demux->mtu = DEMUX_DEFAULT_MTU;
|
||||
demux->now = now;
|
||||
demux->now_arg = now_arg;
|
||||
|
||||
|
@ -152,7 +161,29 @@ void ossl_quic_demux_free(QUIC_DEMUX *demux)
|
|||
|
||||
void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio)
|
||||
{
|
||||
unsigned int mtu;
|
||||
|
||||
demux->net_bio = net_bio;
|
||||
|
||||
if (net_bio != NULL) {
|
||||
/*
|
||||
* Try to determine our MTU if possible. The BIO is not required to
|
||||
* support this, in which case we remain at the last known MTU, or our
|
||||
* initial default.
|
||||
*/
|
||||
mtu = BIO_dgram_get_mtu(net_bio);
|
||||
if (mtu >= QUIC_MIN_INITIAL_DGRAM_LEN)
|
||||
ossl_quic_demux_set_mtu(demux, mtu); /* best effort */
|
||||
}
|
||||
}
|
||||
|
||||
int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu)
|
||||
{
|
||||
if (mtu < QUIC_MIN_INITIAL_DGRAM_LEN)
|
||||
return 0;
|
||||
|
||||
demux->mtu = mtu;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static QUIC_DEMUX_CONN *demux_get_by_conn_id(QUIC_DEMUX *demux,
|
||||
|
@ -265,21 +296,60 @@ static QUIC_URXE *demux_alloc_urxe(size_t alloc_len)
|
|||
return NULL;
|
||||
|
||||
ossl_list_urxe_init_elem(e);
|
||||
e->alloc_len = alloc_len;
|
||||
e->data_len = 0;
|
||||
e->alloc_len = alloc_len;
|
||||
e->data_len = 0;
|
||||
return e;
|
||||
}
|
||||
|
||||
static QUIC_URXE *demux_resize_urxe(QUIC_DEMUX *demux, QUIC_URXE *e,
|
||||
size_t new_alloc_len)
|
||||
{
|
||||
QUIC_URXE *e2, *prev;
|
||||
|
||||
if (!ossl_assert(e->demux_state == URXE_DEMUX_STATE_FREE))
|
||||
/* Never attempt to resize a URXE which is not on the free list. */
|
||||
return NULL;
|
||||
|
||||
prev = ossl_list_urxe_prev(e);
|
||||
ossl_list_urxe_remove(&demux->urx_free, e);
|
||||
|
||||
e2 = OPENSSL_realloc(e, sizeof(QUIC_URXE) + new_alloc_len);
|
||||
if (e2 == NULL) {
|
||||
/* Failed to resize, abort. */
|
||||
if (prev == NULL)
|
||||
ossl_list_urxe_insert_head(&demux->urx_free, e);
|
||||
else
|
||||
ossl_list_urxe_insert_after(&demux->urx_free, prev, e);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (prev == NULL)
|
||||
ossl_list_urxe_insert_head(&demux->urx_free, e2);
|
||||
else
|
||||
ossl_list_urxe_insert_after(&demux->urx_free, prev, e2);
|
||||
|
||||
e2->alloc_len = new_alloc_len;
|
||||
return e2;
|
||||
}
|
||||
|
||||
static QUIC_URXE *demux_reserve_urxe(QUIC_DEMUX *demux, QUIC_URXE *e,
|
||||
size_t alloc_len)
|
||||
{
|
||||
return e->alloc_len < alloc_len ? demux_resize_urxe(demux, e, alloc_len) : e;
|
||||
}
|
||||
|
||||
static int demux_ensure_free_urxe(QUIC_DEMUX *demux, size_t min_num_free)
|
||||
{
|
||||
QUIC_URXE *e;
|
||||
|
||||
while (ossl_list_urxe_num(&demux->urx_free) < min_num_free) {
|
||||
e = demux_alloc_urxe(demux->default_urxe_alloc_len);
|
||||
e = demux_alloc_urxe(demux->mtu);
|
||||
if (e == NULL)
|
||||
return 0;
|
||||
|
||||
ossl_list_urxe_insert_tail(&demux->urx_free, e);
|
||||
e->demux_state = URXE_DEMUX_STATE_FREE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -302,6 +372,7 @@ static int demux_recv(QUIC_DEMUX *demux)
|
|||
|
||||
/* This should never be called when we have any pending URXE. */
|
||||
assert(ossl_list_urxe_head(&demux->urx_pending) == NULL);
|
||||
assert(urxe->demux_state == URXE_DEMUX_STATE_FREE);
|
||||
|
||||
if (demux->net_bio == NULL)
|
||||
return 0;
|
||||
|
@ -320,6 +391,12 @@ static int demux_recv(QUIC_DEMUX *demux)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Ensure the URXE is big enough. */
|
||||
urxe = demux_reserve_urxe(demux, urxe, demux->mtu);
|
||||
if (urxe == NULL)
|
||||
/* Allocation error, fail. */
|
||||
return 0;
|
||||
|
||||
/* Ensure we zero any fields added to BIO_MSG at a later date. */
|
||||
memset(&msg[i], 0, sizeof(BIO_MSG));
|
||||
msg[i].data = ossl_quic_urxe_data(urxe);
|
||||
|
@ -346,6 +423,7 @@ static int demux_recv(QUIC_DEMUX *demux)
|
|||
/* Move from free list to pending list. */
|
||||
ossl_list_urxe_remove(&demux->urx_free, urxe);
|
||||
ossl_list_urxe_insert_tail(&demux->urx_pending, urxe);
|
||||
urxe->demux_state = URXE_DEMUX_STATE_PENDING;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -386,6 +464,8 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
|
|||
if (!ossl_assert(e == ossl_list_urxe_head(&demux->urx_pending)))
|
||||
return 0;
|
||||
|
||||
assert(e->demux_state == URXE_DEMUX_STATE_PENDING);
|
||||
|
||||
conn = demux_identify_conn(demux, e);
|
||||
if (conn == NULL) {
|
||||
/*
|
||||
|
@ -394,6 +474,7 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
|
|||
*/
|
||||
ossl_list_urxe_remove(&demux->urx_pending, e);
|
||||
ossl_list_urxe_insert_tail(&demux->urx_free, e);
|
||||
e->demux_state = URXE_DEMUX_STATE_FREE;
|
||||
return 1; /* keep processing pending URXEs */
|
||||
}
|
||||
|
||||
|
@ -402,6 +483,7 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
|
|||
* callback. (QUIC_DEMUX_CONN never has non-NULL cb.)
|
||||
*/
|
||||
ossl_list_urxe_remove(&demux->urx_pending, e);
|
||||
e->demux_state = URXE_DEMUX_STATE_ISSUED;
|
||||
conn->cb(e, conn->cb_arg);
|
||||
return 1;
|
||||
}
|
||||
|
@ -462,6 +544,12 @@ int ossl_quic_demux_inject(QUIC_DEMUX *demux,
|
|||
if (buf_len > urxe->alloc_len)
|
||||
return 0;
|
||||
|
||||
assert(urxe->demux_state == URXE_DEMUX_STATE_FREE);
|
||||
|
||||
urxe = demux_reserve_urxe(demux, urxe, buf_len);
|
||||
if (urxe == NULL)
|
||||
return 0;
|
||||
|
||||
memcpy(ossl_quic_urxe_data(urxe), buf, buf_len);
|
||||
urxe->data_len = buf_len;
|
||||
|
||||
|
@ -478,6 +566,7 @@ int ossl_quic_demux_inject(QUIC_DEMUX *demux,
|
|||
/* Move from free list to pending list. */
|
||||
ossl_list_urxe_remove(&demux->urx_free, urxe);
|
||||
ossl_list_urxe_insert_tail(&demux->urx_pending, urxe);
|
||||
urxe->demux_state = URXE_DEMUX_STATE_PENDING;
|
||||
|
||||
return demux_process_pending_urxl(demux);
|
||||
}
|
||||
|
@ -487,5 +576,7 @@ void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux,
|
|||
QUIC_URXE *e)
|
||||
{
|
||||
assert(ossl_list_urxe_prev(e) == NULL && ossl_list_urxe_next(e) == NULL);
|
||||
assert(e->demux_state == URXE_DEMUX_STATE_ISSUED);
|
||||
ossl_list_urxe_insert_tail(&demux->urx_free, e);
|
||||
e->demux_state = URXE_DEMUX_STATE_FREE;
|
||||
}
|
||||
|
|
|
@ -1704,7 +1704,6 @@ static int rx_state_ensure(struct rx_state *s)
|
|||
if (s->demux == NULL
|
||||
&& !TEST_ptr(s->demux = ossl_quic_demux_new(NULL,
|
||||
s->args.short_conn_id_len,
|
||||
1500,
|
||||
fake_time,
|
||||
NULL)))
|
||||
return 0;
|
||||
|
|
|
@ -183,7 +183,7 @@ static int helper_init(struct helper *h)
|
|||
if (!TEST_ptr(h->txp = ossl_quic_tx_packetiser_new(&h->args)))
|
||||
goto err;
|
||||
|
||||
if (!TEST_ptr(h->demux = ossl_quic_demux_new(h->bio2, 8, 1200,
|
||||
if (!TEST_ptr(h->demux = ossl_quic_demux_new(h->bio2, 8,
|
||||
fake_now, NULL)))
|
||||
goto err;
|
||||
|
||||
|
|
Loading…
Reference in New Issue