#include "internal/time.h"
static void aon_write_finish(QUIC_CONNECTION *qc);
+static int ensure_channel(QUIC_CONNECTION *qc);
/*
* QUIC Front-End I/O API: Common Utilities
*/
/* SSL_shutdown */
-int ossl_quic_shutdown(SSL *s)
+static int quic_shutdown_wait(void *arg)
{
- QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+ QUIC_CONNECTION *qc = arg;
- if (!expect_quic_conn(qc))
- return 0;
+ return qc->ch == NULL || ossl_quic_channel_is_terminated(qc->ch);
+}
- if (qc->ch != NULL)
- ossl_quic_channel_local_close(qc->ch);
+int ossl_quic_conn_shutdown(QUIC_CONNECTION *qc, uint64_t flags,
+ const SSL_SHUTDOWN_EX_ARGS *args,
+ size_t args_len)
+{
+ if (!ensure_channel(qc))
+ return -1;
- return 1;
+ ossl_quic_channel_local_close(qc->ch,
+ args != NULL ? args->quic_error_code : 0);
+
+ /* TODO(QUIC): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */
+
+ if (ossl_quic_channel_is_terminated(qc->ch))
+ return 1;
+
+ if (blocking_mode(qc) && (flags & SSL_SHUTDOWN_FLAG_RAPID) == 0)
+ block_until_pred(qc, quic_shutdown_wait, NULL, 0);
+ else
+ ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(qc->ch));
+
+ return ossl_quic_channel_is_terminated(qc->ch);
}
/* SSL_ctrl */
return 1;
}
-/*
- * Creates a channel and configures it with the information we have accumulated
- * via calls made to us from the application prior to starting a handshake
- * attempt.
- */
-static int ensure_channel_and_start(QUIC_CONNECTION *qc)
+static int ensure_channel(QUIC_CONNECTION *qc)
{
QUIC_CHANNEL_ARGS args = {0};
if (qc->ch == NULL)
return 0;
+ return 1;
+}
+
+/*
+ * Creates a channel and configures it with the information we have accumulated
+ * via calls made to us from the application prior to starting a handshake
+ * attempt.
+ */
+static int ensure_channel_and_start(QUIC_CONNECTION *qc)
+{
+ if (!ensure_channel(qc))
+ return 0;
+
if (!configure_channel(qc)
|| !ossl_quic_channel_start(qc->ch)) {
ossl_quic_channel_free(qc->ch);
* (BIO/)SSL_read => ossl_quic_read
* (BIO/)SSL_write => ossl_quic_write
* SSL_pending => ossl_quic_pending
+ * SSL_stream_conclude => ossl_quic_conn_stream_conclude
*/
/* SSL_get_error */
{
int is_fin = 0;
+ /* If the receive part of the stream is over, issue EOF. */
+ if (stream->recv_fin_retired)
+ return QUIC_RAISE_NORMAL_ERROR(qc, SSL_ERROR_ZERO_RETURN);
+
if (stream->rstream == NULL)
return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
{
struct quic_read_again_args *args = arg;
- if (!ossl_quic_channel_is_active(args->qc->ch))
+ if (!ossl_quic_channel_is_active(args->qc->ch)) {
/* If connection is torn down due to an error while blocking, stop. */
+ QUIC_RAISE_NON_NORMAL_ERROR(args->qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
return -1;
+ }
if (!quic_read_actual(args->qc, args->stream,
args->buf, args->len, args->bytes_read,
if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch))
return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
- /* If we haven't finished the handshake, try to advance it.*/
+ /* If we haven't finished the handshake, try to advance it. */
if (ossl_quic_do_handshake(qc) < 1)
- return 0;
+ return 0; /* ossl_quic_do_handshake raised error here */
if (qc->stream0 == NULL)
return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
if (!quic_read_actual(qc, qc->stream0, buf, len, bytes_read, peek))
- return 0;
+ return 0; /* quic_read_actual raised error here */
if (*bytes_read > 0) {
/*
args.peek = peek;
res = block_until_pred(qc, quic_read_again, &args, 0);
- if (res <= 0) {
- if (!ossl_quic_channel_is_active(qc->ch))
- return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
- else
- return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
- }
+ if (res == 0)
+ return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+ else if (res < 0)
+ return 0; /* quic_read_again raised error here */
return 1;
} else {
return avail;
}
+/*
+ * SSL_stream_conclude
+ * -------------------
+ */
+int ossl_quic_conn_stream_conclude(QUIC_CONNECTION *qc)
+{
+ QUIC_STREAM *qs = qc->stream0;
+
+ if (qs == NULL || qs->sstream == NULL)
+ return 0;
+
+ if (!ossl_quic_channel_is_active(qc->ch)
+ || ossl_quic_sstream_get_final_size(qs->sstream, NULL))
+ return 1;
+
+ ossl_quic_sstream_fin(qs->sstream);
+ quic_post_write(qc, 1, 1);
+ return 1;
+}
+
/*
* QUIC Front-End I/O API: SSL_CTX Management
* ==========================================