From: Hugo Landau Date: Mon, 9 Jan 2023 15:44:42 +0000 (+0000) Subject: QUIC QTX: Handle network errors explicitly X-Git-Tag: openssl-3.2.0-alpha1~1459 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0550829f53fe74f884e382ec0ec323342f77d181;p=thirdparty%2Fopenssl.git QUIC QTX: Handle network errors explicitly Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/19703) --- diff --git a/include/internal/quic_record_tx.h b/include/internal/quic_record_tx.h index d010a2f64a3..ba2cf7fe788 100644 --- a/include/internal/quic_record_tx.h +++ b/include/internal/quic_record_tx.h @@ -210,8 +210,27 @@ void ossl_qtx_finish_dgram(OSSL_QTX *qtx); * is desired. The queue is drained into the OS's sockets as much as possible. * To determine if there is still data to be sent after calling this function, * use ossl_qtx_get_queue_len_bytes(). + * + * Returns one of the following values: + * + * QTX_FLUSH_NET_RES_OK + * Either no packets are currently queued for transmission, + * or at least one packet was successfully submitted. + * + * QTX_FLUSH_NET_RES_TRANSIENT_FAIL + * The underlying network write BIO indicated a transient error + * (e.g. buffers full). + * + * QTX_FLUSH_NET_RES_PERMANENT_FAIL + * Internal error (e.g. assertion or allocation error) + * or the underlying network write BIO indicated a non-transient + * error. */ -void ossl_qtx_flush_net(OSSL_QTX *qtx); +#define QTX_FLUSH_NET_RES_OK 1 +#define QTX_FLUSH_NET_RES_TRANSIENT_FAIL (-1) +#define QTX_FLUSH_NET_RES_PERMANENT_FAIL (-2) + +int ossl_qtx_flush_net(OSSL_QTX *qtx); /* * Diagnostic function. If there is any datagram pending transmission, pops it diff --git a/ssl/quic/quic_record_tx.c b/ssl/quic/quic_record_tx.c index 0cea8c13f57..dddb29663ca 100644 --- a/ssl/quic/quic_record_tx.c +++ b/ssl/quic/quic_record_tx.c @@ -812,14 +812,18 @@ static void txe_to_msg(TXE *txe, BIO_MSG *msg) #define MAX_MSGS_PER_SEND 32 -void ossl_qtx_flush_net(OSSL_QTX *qtx) +int ossl_qtx_flush_net(OSSL_QTX *qtx) { BIO_MSG msg[MAX_MSGS_PER_SEND]; - size_t wr, i; + size_t wr, i, total_written = 0; TXE *txe; + int res; + + if (ossl_list_txe_head(&qtx->pending) == NULL) + return QTX_FLUSH_NET_RES_OK; /* Nothing to send. */ if (qtx->bio == NULL) - return; + return QTX_FLUSH_NET_RES_PERMANENT_FAIL; for (;;) { for (txe = ossl_list_txe_head(&qtx->pending), i = 0; @@ -829,21 +833,46 @@ void ossl_qtx_flush_net(OSSL_QTX *qtx) if (!i) /* Nothing to send. */ - return; + break; - if (!BIO_sendmmsg(qtx->bio, msg, sizeof(BIO_MSG), i, 0, &wr) || wr == 0) + ERR_set_mark(); + res = BIO_sendmmsg(qtx->bio, msg, sizeof(BIO_MSG), i, 0, &wr); + if (res && wr == 0) { + /* + * Treat 0 messages sent as a transient error and just stop for now. + */ + ERR_clear_last_mark(); + break; + } else if (!res) { /* * We did not get anything, so further calls will probably not * succeed either. */ - break; + if (BIO_err_is_non_fatal(ERR_peek_last_error())) { + /* Transient error, just stop for now, clearing the error. */ + ERR_pop_to_mark(); + break; + } else { + /* Non-transient error, fail and do not clear the error. */ + ERR_clear_last_mark(); + return QTX_FLUSH_NET_RES_PERMANENT_FAIL; + } + } + + ERR_clear_last_mark(); /* * Remove everything which was successfully sent from the pending queue. */ for (i = 0; i < wr; ++i) qtx_pending_to_free(qtx); + + total_written += wr; } + + return total_written > 0 + ? QTX_FLUSH_NET_RES_OK + : QTX_FLUSH_NET_RES_TRANSIENT_FAIL; } int ossl_qtx_pop_net(OSSL_QTX *qtx, BIO_MSG *msg)