aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2023-11-09 15:30:15 +0000
committerHugo Landau <hlandau@openssl.org>2023-12-21 08:12:06 +0000
commit305133988742829f49e4d552f16ef09914317bdb (patch)
treece04adf19c05f20f00a300f1b8c8df6f45332d2e
parentff3a26b24f0bf7f0b24e97453ea138dd167adcb5 (diff)
downloadopenssl-305133988742829f49e4d552f16ef09914317bdb.tar.gz
QUIC PORT: Fix BIO_dgram usage under Winsock due to bind requirement
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/22674)
-rw-r--r--ssl/quic/quic_channel.c1
-rw-r--r--ssl/quic/quic_port.c20
-rw-r--r--ssl/quic/quic_port_local.h6
3 files changed, 27 insertions, 0 deletions
diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c
index 5bcd66c9e4..60bcc88f84 100644
--- a/ssl/quic/quic_channel.c
+++ b/ssl/quic/quic_channel.c
@@ -2255,6 +2255,7 @@ static int ch_tx(QUIC_CHANNEL *ch)
res = ossl_quic_tx_packetiser_generate(ch->txp, &status);
if (status.sent_pkt > 0) {
ch->have_sent_any_pkt = 1; /* Packet(s) were sent */
+ ch->port->have_sent_any_pkt = 1;
/*
* RFC 9000 s. 10.1. 'An endpoint also restarts its idle timer when
diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c
index e6dba46bf4..46f4b34f9b 100644
--- a/ssl/quic/quic_port.c
+++ b/ssl/quic/quic_port.c
@@ -323,6 +323,7 @@ QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls)
ch = port_make_channel(port, tls, /*is_server=*/1);
port->tserver_ch = ch;
+ port->is_server = 1;
return ch;
}
@@ -366,6 +367,25 @@ static void port_rx_pre(QUIC_PORT *port)
int ret;
/*
+ * Originally, this check (don't RX before we have sent anything if we are
+ * not a server, because there can't be anything) was just intended as a
+ * minor optimisation. However, it is actually required on Windows, and
+ * removing this check will cause Windows to break.
+ *
+ * The reason is that under Win32, recvfrom() does not work on a UDP socket
+ * which has not had bind() called (???). However, calling sendto() will
+ * automatically bind an unbound UDP socket. Therefore, if we call a Winsock
+ * recv-type function before calling a Winsock send-type function, that call
+ * will fail with WSAEINVAL, which we will regard as a permanent network
+ * error.
+ *
+ * Therefore, this check is essential as we do not require our API users to
+ * bind a socket first when using the API in client mode.
+ */
+ if (!port->is_server && !port->have_sent_any_pkt)
+ return;
+
+ /*
* Get DEMUX to BIO_recvmmsg from the network and queue incoming datagrams
* to the appropriate QRX instances.
*/
diff --git a/ssl/quic/quic_port_local.h b/ssl/quic/quic_port_local.h
index 38bb0193d8..968a48ac42 100644
--- a/ssl/quic/quic_port_local.h
+++ b/ssl/quic/quic_port_local.h
@@ -87,6 +87,12 @@ struct quic_port_st {
/* Inhibit tick for testing purposes? */
unsigned int inhibit_tick : 1;
+
+ /* Has this port sent any packet of any kind yet? */
+ unsigned int have_sent_any_pkt : 1;
+
+ /* Does this port allow incoming connections? */
+ unsigned int is_server : 1;
};
# endif