int ossl_quic_channel_start(QUIC_CHANNEL *ch);
/* Start a locally initiated connection shutdown. */
-void ossl_quic_channel_local_close(QUIC_CHANNEL *ch);
+void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code);
/*
* Called when the handshake is confirmed.
__owur int ossl_quic_read(SSL *s, void *buf, size_t len, size_t *readbytes);
__owur int ossl_quic_peek(SSL *s, void *buf, size_t len, size_t *readbytes);
__owur int ossl_quic_write(SSL *s, const void *buf, size_t len, size_t *written);
-__owur int ossl_quic_shutdown(SSL *s);
__owur long ossl_quic_ctrl(SSL *s, int cmd, long larg, void *parg);
__owur long ossl_quic_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg);
__owur long ossl_quic_callback_ctrl(SSL *s, int cmd, void (*fp) (void));
__owur int ossl_quic_get_error(const QUIC_CONNECTION *qc, int i);
__owur int ossl_quic_conn_get_blocking_mode(const QUIC_CONNECTION *qc);
__owur int ossl_quic_conn_set_blocking_mode(QUIC_CONNECTION *qc, int blocking);
+__owur int ossl_quic_conn_shutdown(QUIC_CONNECTION *qc, uint64_t flags,
+ const SSL_SHUTDOWN_EX_ARGS *args,
+ size_t args_len);
+__owur int ossl_quic_conn_stream_conclude(QUIC_CONNECTION *qc);
void ossl_quic_conn_set0_net_rbio(QUIC_CONNECTION *qc, BIO *net_wbio);
void ossl_quic_conn_set0_net_wbio(QUIC_CONNECTION *qc, BIO *net_wbio);
BIO *ossl_quic_conn_get_net_rbio(const QUIC_CONNECTION *qc);
__owur int SSL_get_blocking_mode(SSL *s);
__owur int SSL_set_initial_peer_addr(SSL *s, const BIO_ADDR *peer_addr);
+typedef struct ssl_shutdown_ex_args_st {
+ uint64_t quic_error_code;
+ const char *quic_reason;
+} SSL_SHUTDOWN_EX_ARGS;
+
+#define SSL_SHUTDOWN_FLAG_RAPID (1U << 0)
+#define SSL_SHUTDOWN_FLAG_IMMEDIATE (1U << 1)
+
+__owur int SSL_shutdown_ex(SSL *ssl, uint64_t flags,
+ const SSL_SHUTDOWN_EX_ARGS *args,
+ size_t args_len);
+
# ifndef OPENSSL_NO_DEPRECATED_1_1_0
# define SSL_cache_hit(s) SSL_session_reused(s)
# endif
}
/* Start a locally initiated connection shutdown. */
-void ossl_quic_channel_local_close(QUIC_CHANNEL *ch)
+void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code)
{
QUIC_TERMINATE_CAUSE tcause = {0};
if (ossl_quic_channel_is_term_any(ch))
return;
- tcause.app = 1;
+ tcause.app = 1;
+ tcause.error_code = app_error_code;
ch_start_terminating(ch, &tcause, 0);
}
#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_IMMEDIATE */
+
+ 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);
ossl_quic_read, \
ossl_quic_peek, \
ossl_quic_write, \
- ossl_quic_shutdown, \
+ NULL /* shutdown */, \
NULL /* renegotiate */, \
ossl_quic_renegotiate_check, \
NULL /* read_bytes */, \
* (see ssl3_shutdown).
*/
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+ QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+ if (qc != NULL)
+ return ossl_quic_conn_shutdown(qc, 0, NULL, 0);
+#endif
if (sc == NULL)
return -1;
QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
if (qc == NULL)
- return -1;
+ return 0;
return ossl_quic_conn_set_initial_peer_addr(qc, peer_addr);
#else
- return -1;
+ return 0;
+#endif
+}
+
+int SSL_shutdown_ex(SSL *ssl, uint64_t flags,
+ const SSL_SHUTDOWN_EX_ARGS *args,
+ size_t args_len)
+{
+#ifndef OPENSSL_NO_QUIC
+ QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(ssl);
+
+ if (qc == NULL)
+ return SSL_shutdown(ssl);
+
+ return ossl_quic_conn_shutdown(qc, flags, args, args_len);
+#else
+ return SSL_shutdown(ssl);
#endif
}
SSL_set_initial_peer_addr ? 3_2_0 EXIST::FUNCTION:
SSL_net_read_desired ? 3_2_0 EXIST::FUNCTION:
SSL_net_write_desired ? 3_2_0 EXIST::FUNCTION:
+SSL_shutdown_ex ? 3_2_0 EXIST::FUNCTION: