]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
utils: refactoring of QUIC code
authorJan Hák <jan.hak@nic.cz>
Mon, 8 Jan 2024 13:08:42 +0000 (14:08 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Mon, 22 Jan 2024 18:32:43 +0000 (19:32 +0100)
src/utils/common/quic.c
src/utils/common/quic.h

index c900538c5f1ca0d3cf78e0cb022216c3ed48637b..2763f1bc293eb0a2f85977417862f446656032a3 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -50,6 +50,7 @@ void quic_params_clean(quic_params_t *params)
 #include <ngtcp2/ngtcp2_crypto.h>
 #include <ngtcp2/ngtcp2_crypto_gnutls.h>
 
+#include "contrib/macros.h"
 #include "libdnssec/error.h"
 #include "libdnssec/random.h"
 #include "libknot/xdp/tcp_iobuf.h"
@@ -57,23 +58,20 @@ void quic_params_clean(quic_params_t *params)
 
 #define quic_get_encryption_level(level) ngtcp2_crypto_gnutls_from_gnutls_record_encryption_level(level)
 #define quic_send(ctx, sockfd, family) quic_send_data(ctx, sockfd, family, NULL, 0)
-#define quic_timeout(ts, wait) (((ts) + NGTCP2_SECONDS * (wait)) <= quic_timestamp())
-
-const gnutls_datum_t doq_alpn = {
-       (unsigned char *)"doq", 3
-};
-
 #define set_application_error(ctx, error_code, reason, reason_len) \
        ngtcp2_ccerr_set_application_error(&(ctx)->last_err, \
                error_code, reason, reason_len)
-
 #define set_transport_error(ctx, error_code, reason, reason_len) \
        ngtcp2_ccerr_set_transport_error(&(ctx)->last_err, \
                error_code, reason, reason_len)
 
+const gnutls_datum_t doq_alpn = {
+       (unsigned char *)"doq", 3
+};
+
 static int recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags,
-        int64_t stream_id, uint64_t offset, const uint8_t *data,
-        size_t datalen, void *user_data, void *stream_user_data)
+       int64_t stream_id, uint64_t offset, const uint8_t *data,
+       size_t datalen, void *user_data, void *stream_user_data)
 {
        (void)conn;
        (void)flags;
@@ -83,7 +81,9 @@ static int recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags,
        quic_ctx_t *ctx = (quic_ctx_t *)user_data;
 
        if (stream_id != ctx->stream.id) {
-               return 0;
+               const uint8_t msg[] = "Unknown stream";
+               set_application_error(ctx, DOQ_PROTOCOL_ERROR, msg, sizeof(msg) - 1);
+               return NGTCP2_ERR_CALLBACK_FAILURE;
        }
 
        struct iovec in = {
@@ -92,18 +92,20 @@ static int recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags,
        };
 
        int ret = knot_tcp_inbufs_upd(&ctx->stream.in_buffer, in, true,
-                       &ctx->stream.in_parsed, &ctx->stream.in_parsed_total);
+                                     &ctx->stream.in_parsed,
+                                     &ctx->stream.in_parsed_total);
        if (ret != KNOT_EOK) {
+               const uint8_t msg[] = "Malformed payload";
+               set_application_error(ctx, DOQ_PROTOCOL_ERROR, msg, sizeof(msg) - 1);
                return NGTCP2_ERR_CALLBACK_FAILURE;
        }
 
-       ctx->idle_ts = quic_timestamp();
        ctx->stream.in_parsed_it = 0;
        return 0;
 }
 
 static int stream_open_cb(ngtcp2_conn *conn, int64_t stream_id,
-        void *user_data)
+       void *user_data)
 {
        (void)conn;
 
@@ -113,8 +115,8 @@ static int stream_open_cb(ngtcp2_conn *conn, int64_t stream_id,
 }
 
 static int acked_stream_data_offset_cb(ngtcp2_conn *conn, int64_t stream_id,
-        uint64_t offset, uint64_t datalen, void *user_data,
-        void *stream_user_data)
+       uint64_t offset, uint64_t datalen, void *user_data,
+       void *stream_user_data)
 {
        (void)conn;
        (void)offset;
@@ -127,8 +129,9 @@ static int acked_stream_data_offset_cb(ngtcp2_conn *conn, int64_t stream_id,
        return KNOT_EOK;
 }
 
-static int stream_close_cb(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
-        uint64_t app_error_code, void *user_data, void *stream_user_data)
+static int stream_close_cb(ngtcp2_conn *conn, uint32_t flags,
+       int64_t stream_id, uint64_t app_error_code, void *user_data,
+       void *stream_user_data)
 {
        (void)conn;
        (void)flags;
@@ -144,7 +147,7 @@ static int stream_close_cb(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
 
 static int quic_open_bidi_stream(quic_ctx_t *ctx)
 {
-       if (ctx->stream.id != -1) {
+       if (ctx->stream.id >= 0) {
                return KNOT_EOK;
        }
 
@@ -152,29 +155,11 @@ static int quic_open_bidi_stream(quic_ctx_t *ctx)
        if (ret) {
                return KNOT_ERROR;
        }
-
-       ctx->stream.resets = 3;
-
        return KNOT_EOK;
 }
 
-static int extend_max_bidi_streams_cb(ngtcp2_conn *conn, uint64_t max_streams,
-        void *user_data)
-{
-       (void)conn;
-
-       quic_ctx_t *ctx = (quic_ctx_t *)user_data;
-       if(max_streams > 0) {
-               int ret = quic_open_bidi_stream(ctx);
-               if (ret != KNOT_EOK) {
-                       return NGTCP2_ERR_CALLBACK_FAILURE;
-               }
-       }
-       return 0;
-}
-
 static void rand_cb(uint8_t *dest, size_t destlen,
-        const ngtcp2_rand_ctx *rand_ctx)
+       const ngtcp2_rand_ctx *rand_ctx)
 {
        (void)rand_ctx;
 
@@ -182,7 +167,7 @@ static void rand_cb(uint8_t *dest, size_t destlen,
 }
 
 static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
-        uint8_t *token, size_t cidlen, void *user_data)
+       uint8_t *token, size_t cidlen, void *user_data)
 {
        (void)conn;
 
@@ -194,7 +179,8 @@ static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
        cid->datalen = cidlen;
 
        if (ngtcp2_crypto_generate_stateless_reset_token(token, ctx->secret,
-                       sizeof(ctx->secret), cid) != 0) {
+               sizeof(ctx->secret), cid) != 0)
+       {
                return NGTCP2_ERR_CALLBACK_FAILURE;
        }
 
@@ -202,16 +188,14 @@ static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
 }
 
 static int stream_reset_cb(ngtcp2_conn *conn, int64_t stream_id,
-                uint64_t final_size, uint64_t app_error_code, void *user_data,
-                void *stream_user_data)
+       uint64_t final_size, uint64_t app_error_code, void *user_data,
+       void *stream_user_data)
 {
        quic_ctx_t *ctx = (quic_ctx_t *)user_data;
        if (ctx->stream.id == stream_id) {
-               if (--ctx->stream.resets <= 0) {
-                       //TODO test
-                       set_transport_error(ctx, NGTCP2_PROTOCOL_VIOLATION, NULL, 0);
-                       quic_ctx_close(ctx);
-               }
+               set_transport_error(ctx, NGTCP2_PROTOCOL_VIOLATION, NULL, 0);
+               quic_ctx_close(ctx);
+               return NGTCP2_ERR_CALLBACK_FAILURE;
        }
 
        return 0;
@@ -226,6 +210,17 @@ static int handshake_confirmed_cb(ngtcp2_conn *conn, void *user_data)
        return 0;
 }
 
+static int recv_rx_key_cb(ngtcp2_conn *conn, ngtcp2_encryption_level level,
+       void *user_data)
+{
+       quic_ctx_t *ctx = user_data;
+       if (level == NGTCP2_ENCRYPTION_LEVEL_1RTT) {
+               ctx->state = CONNECTED;
+       }
+
+       return 0;
+}
+
 static const ngtcp2_callbacks quic_client_callbacks = {
        ngtcp2_crypto_client_initial_cb,
        NULL, /* recv_client_initial */
@@ -241,7 +236,7 @@ static const ngtcp2_callbacks quic_client_callbacks = {
        stream_close_cb,
        NULL, /* recv_stateless_reset */
        ngtcp2_crypto_recv_retry_cb,
-       extend_max_bidi_streams_cb,
+       NULL, /* extend_max_bidi_streams */
        NULL, /* extend_max_local_streams_uni */
        rand_cb,
        get_new_connection_id_cb,
@@ -264,13 +259,12 @@ static const ngtcp2_callbacks quic_client_callbacks = {
        ngtcp2_crypto_get_path_challenge_data_cb,
        NULL, /* stream_stop_sending */
        ngtcp2_crypto_version_negotiation_cb,
-       NULL, /* recv_rx_key */
+       recv_rx_key_cb,
        NULL  /* recv_tx_key */
 };
 
 static int hook_func(gnutls_session_t session, unsigned int htype,
-                     unsigned when, unsigned int incoming,
-                     const gnutls_datum_t *msg)
+       unsigned when, unsigned int incoming, const gnutls_datum_t *msg)
 {
        (void)session;
        (void)htype;
@@ -282,7 +276,7 @@ static int hook_func(gnutls_session_t session, unsigned int htype,
 }
 
 static int quic_send_data(quic_ctx_t *ctx, int sockfd, int family,
-        ngtcp2_vec *datav, size_t datavlen)
+       ngtcp2_vec *datav, size_t datavlen)
 {
        uint8_t enc_buf[MAX_PACKET_SIZE];
        struct iovec msg_iov = {
@@ -294,63 +288,54 @@ static int quic_send_data(quic_ctx_t *ctx, int sockfd, int family,
                .msg_iovlen = 1
        };
        uint64_t ts = quic_timestamp();
-       size_t tb_send = 0;
-       for (int i = 0; i < datavlen; ++i) {
-               tb_send += datav[i].len;
-       }
 
-       while(1) {
-               int64_t stream = -1;
-               uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_NONE;
-               if (datavlen != 0) {
-                       flags = NGTCP2_WRITE_STREAM_FLAG_FIN;
-                       stream = ctx->stream.id;
-               }
-               ngtcp2_ssize send_datalen = 0;
-               ngtcp2_ssize nwrite = ngtcp2_conn_writev_stream(ctx->conn,
-                               (ngtcp2_path *)ngtcp2_conn_get_path(ctx->conn),
-                               &ctx->pi, enc_buf, sizeof(enc_buf),
-                               &send_datalen, flags, stream, datav, datavlen,
-                               ts);
-               if (nwrite <= 0) {
-                       switch(nwrite) {
-                       case 0:
-                               ngtcp2_conn_update_pkt_tx_time(ctx->conn, ts);
-                               return KNOT_EOK;
-                       case NGTCP2_ERR_WRITE_MORE:
-                               assert(0);
-                               return KNOT_NET_ESEND;
-                       case NGTCP2_ERR_STREAM_SHUT_WR:
-                               ctx->stream.id = -1;
-                               // [[ fallthrough ]]
-                       default:
-                               set_transport_error(ctx,
-                                       ngtcp2_err_infer_quic_transport_error_code(nwrite),
-                                       NULL, 0);
+       uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_NONE;
+       int64_t stream_id = -1;
+       if (datavlen > 0) {
+               flags = NGTCP2_WRITE_STREAM_FLAG_FIN;
+               stream_id = ctx->stream.id;
+       }
+       ngtcp2_ssize send_datalen = 0;
+       ngtcp2_ssize nwrite = ngtcp2_conn_writev_stream(ctx->conn,
+               (ngtcp2_path *)ngtcp2_conn_get_path(ctx->conn), &ctx->pi,
+               enc_buf, sizeof(enc_buf), &send_datalen, flags, stream_id,
+               datav, datavlen, ts);
+       if (nwrite <= 0) {
+               switch(nwrite) {
+               case 0:
+                       ngtcp2_conn_update_pkt_tx_time(ctx->conn, ts);
+                       return KNOT_EOK;
+               case NGTCP2_ERR_WRITE_MORE:
+                       assert(0);
+                       return KNOT_NET_ESEND;
+               default:
+                       set_transport_error(ctx,
+                               ngtcp2_err_infer_quic_transport_error_code(nwrite),
+                               NULL, 0);
+                       if (ngtcp2_err_is_fatal(nwrite)) {
                                return KNOT_NET_ESEND;
+                       } else {
+                               return KNOT_EOK;
                        }
                }
-               if (send_datalen > 0) {
-                       tb_send -= send_datalen;
-               }
+       }
 
-               msg_iov.iov_len = (size_t)nwrite;
+       msg_iov.iov_len = (size_t)nwrite;
 
-               int ret = net_ecn_set(sockfd, family, ctx->pi.ecn);
-               if (ret != KNOT_EOK && ret != KNOT_ENOTSUP) {
-                       return ret;
-               }
+       int ret = net_ecn_set(sockfd, family, ctx->pi.ecn);
+       if (ret != KNOT_EOK && ret != KNOT_ENOTSUP) {
+               return ret;
+       }
 
-               if (sendmsg(sockfd, &msg, 0) == -1) {
-                       set_transport_error(ctx, NGTCP2_INTERNAL_ERROR, NULL,
-                                           0);
-                       return KNOT_NET_ESEND;
-               }
+       if (sendmsg(sockfd, &msg, 0) == -1) {
+               set_transport_error(ctx, NGTCP2_INTERNAL_ERROR, NULL, 0);
+               return KNOT_NET_ESEND;
+       }
 
-               if (tb_send == 0) {
-                       break;
-               }
+       if (send_datalen > 0) {
+               return send_datalen;
        }
+
        return KNOT_EOK;
 }
 
@@ -384,14 +369,10 @@ static int quic_recv(quic_ctx_t *ctx, int sockfd)
                                       ngtcp2_conn_get_path(ctx->conn),
                                       pi, enc_buf, nwrite,
                                       quic_timestamp());
-       if (ret != 0) {
-               if (ret == NGTCP2_ERR_DROP_CONN) {
-                       ctx->state = CLOSED;
-               } else if (ngtcp2_err_is_fatal(ret)) {
-                       set_transport_error(ctx,
-                               ngtcp2_err_infer_quic_transport_error_code(ret),
-                               NULL, 0);
-               }
+       if (ngtcp2_err_is_fatal(ret)) {
+               set_transport_error(ctx,
+                       ngtcp2_err_infer_quic_transport_error_code(ret),
+                       NULL, 0);
                return KNOT_NET_ERECV;
        }
        return KNOT_EOK;
@@ -467,23 +448,38 @@ int quic_ctx_init(quic_ctx_t *ctx, tls_ctx_t *tls_ctx, const quic_params_t *para
        };
        ctx->params = *params;
        ctx->tls = tls_ctx;
-       ctx->state = OPENING;
+       ctx->state = CLOSED;
        ctx->stream.id = -1;
        set_application_error(ctx, DOQ_NO_ERROR, NULL, 0);
        if (quic_generate_secret(ctx->secret, sizeof(ctx->secret)) != KNOT_EOK) {
                return KNOT_ENOMEM;
        }
 
-       gnutls_certificate_set_verify_function(tls_ctx->credentials,
-               verify_certificate);
+       gnutls_certificate_set_verify_function(
+               tls_ctx->credentials,
+               verify_certificate);
 
        return KNOT_EOK;
 }
 
+static int get_expiry(ngtcp2_conn *ctx)
+{
+       ngtcp2_tstamp now = quic_timestamp();
+       ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(ctx);
+       if (expiry == UINT64_MAX) {
+               return -1;
+       } else if (expiry < now) {
+               return 0;
+       }
+       /* ceil((expiry - now) / NGTCP2_MILLISECONDS) */
+       return (expiry - now + NGTCP2_MILLISECONDS - 1) / NGTCP2_MILLISECONDS;
+}
+
 int quic_ctx_connect(quic_ctx_t *ctx, int sockfd, struct addrinfo *dst_addr)
 {
        if (connect(sockfd, (const struct sockaddr *)(dst_addr->ai_addr),
-                   dst_addr->ai_addrlen) != 0) {
+                   dst_addr->ai_addrlen) != 0)
+       {
                return knot_map_errno();
        }
 
@@ -499,11 +495,9 @@ int quic_ctx_connect(quic_ctx_t *ctx, int sockfd, struct addrinfo *dst_addr)
                return ret;
        }
 
-       ctx->idle_ts = quic_timestamp();
-
        ngtcp2_settings settings;
        ngtcp2_settings_default(&settings);
-       settings.initial_ts = ctx->idle_ts;
+       settings.initial_ts = quic_timestamp();
        settings.handshake_timeout = ctx->tls->wait * NGTCP2_SECONDS;
 
        ngtcp2_transport_params params;
@@ -512,6 +506,8 @@ int quic_ctx_connect(quic_ctx_t *ctx, int sockfd, struct addrinfo *dst_addr)
        params.initial_max_streams_bidi = 0;
        params.initial_max_stream_data_bidi_local = NGTCP2_MAX_VARINT;
        params.initial_max_data = NGTCP2_MAX_VARINT;
+       params.max_ack_delay = 1 * NGTCP2_SECONDS;
+       params.max_idle_timeout = ctx->tls->wait * NGTCP2_SECONDS;
 
        struct sockaddr_in6 src_addr;
        socklen_t src_addr_len = sizeof(src_addr);
@@ -536,9 +532,9 @@ int quic_ctx_connect(quic_ctx_t *ctx, int sockfd, struct addrinfo *dst_addr)
                                   &settings, &params, NULL, ctx) != 0) {
                return KNOT_NET_ECONNECT;
        }
-
        gnutls_handshake_set_hook_function(ctx->tls->session,
-               GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, hook_func);
+                                          GNUTLS_HANDSHAKE_ANY,
+                                          GNUTLS_HOOK_POST, hook_func);
        ret = ngtcp2_crypto_gnutls_configure_client_session(ctx->tls->session);
        if (ret != KNOT_EOK) {
                return KNOT_NET_ECONNECT;
@@ -546,7 +542,6 @@ int quic_ctx_connect(quic_ctx_t *ctx, int sockfd, struct addrinfo *dst_addr)
        gnutls_session_set_ptr(ctx->tls->session, ctx);
        ngtcp2_conn_set_tls_native_handle(ctx->conn, ctx->tls->session);
 
-       // Initialize poll descriptor structure.
        struct pollfd pfd = {
                .fd = sockfd,
                .events = POLLIN,
@@ -554,45 +549,69 @@ int quic_ctx_connect(quic_ctx_t *ctx, int sockfd, struct addrinfo *dst_addr)
        };
        ctx->tls->sockfd = sockfd;
 
-       ret = quic_send(ctx, sockfd, dst_addr->ai_family);
-       if (ret != KNOT_EOK) {
-               return ret;
-       }
+       while (ctx->state != CONNECTED) {
+               ret = quic_send(ctx, sockfd, dst_addr->ai_family);
+               if (ret != KNOT_EOK) {
+                       return ret;
+               }
 
-       ret = poll(&pfd, 1, ctx->tls->wait * 1000);
-       if (ret == 0) {
-               WARN("QUIC, peer took too long to respond");
-               return KNOT_NET_ECONNECT;
-       } else if (ret < 0) {
-               return knot_map_errno();
+               int timeout = get_expiry(ctx->conn);
+               ret = poll(&pfd, 1, timeout);
+               if (ret == 0) {
+                       ret = ngtcp2_conn_handle_expiry(ctx->conn, quic_timestamp());
+               } else if (ret < 0) {
+                       return knot_map_errno();
+               }
+
+               ret = quic_recv(ctx, sockfd);
+               if (ret != KNOT_EOK) {
+                       return ret;
+               }
        }
 
-       ret = quic_recv(ctx, sockfd);
-       if (ret != KNOT_EOK) {
-               return ret;
+       return KNOT_EOK;
+}
+
+static int offset_span(ngtcp2_vec **vec, size_t *veclen, size_t sub)
+{
+       ngtcp2_vec *new_vec = *vec;
+       size_t new_veclen = *veclen;
+
+       while (sub) {
+               if (new_veclen == 0) {
+                       return KNOT_EINVAL;
+               }
+               size_t part = MIN(sub, new_vec->len);
+               new_vec->base += part;
+               new_vec->len -= part;
+               sub -= part;
+               const int empty = ((new_vec->len == 0) ? 1 : 0);
+               new_vec += empty;
+               new_veclen -= empty;
        }
+       *vec = new_vec;
+       *veclen = new_veclen;
 
        return KNOT_EOK;
 }
 
 int quic_send_dns_query(quic_ctx_t *ctx, int sockfd, struct addrinfo *srv,
-        const uint8_t *buf, const size_t buf_len)
+       const uint8_t *buf, const size_t buf_len)
 {
        if (ctx == NULL || buf == NULL) {
                return KNOT_EINVAL;
        }
 
+       if (ctx->state < CONNECTED) {
+               return KNOT_ECONN;
+       }
+
        uint16_t query_length = htons(buf_len);
        ngtcp2_vec datav[] = {
-               {
-                       .base = (uint8_t *)&query_length,
-                       .len = sizeof(uint16_t)
-               },{
-                       .base = (uint8_t *)buf,
-                       .len = buf_len
-               }
+               {(uint8_t *)&query_length, sizeof(uint16_t)},
+               {(uint8_t *)buf, buf_len}
        };
-       size_t datavlen = sizeof(datav)/sizeof(*datav);
+       size_t datavlen = sizeof(datav) / sizeof(*datav);
        ngtcp2_vec *pdatav = datav;
 
        struct pollfd pfd = {
@@ -601,36 +620,39 @@ int quic_send_dns_query(quic_ctx_t *ctx, int sockfd, struct addrinfo *srv,
                .revents = 0,
        };
 
-       // Open stream when connection keep-opened
-       if (ctx->stream.id == -1) {
-               quic_open_bidi_stream(ctx);
-               quic_send(ctx, sockfd, srv->ai_family);
+       assert(ctx->stream.id < 0);
+       int ret = quic_open_bidi_stream(ctx);
+       if (ret != KNOT_EOK) {
+               return ret;
        }
 
-       while (ctx->stream.out_ack == 0) {
-               if (quic_timeout(ctx->idle_ts, ctx->tls->wait)) {
-                       WARN("QUIC, failed to send");
-                       set_application_error(ctx, DOQ_REQUEST_CANCELLED,
-                                       (uint8_t *)"Connection timeout",
-                                       sizeof("Connection timeout") - 1);
-                       return KNOT_NET_ETIMEOUT;
-               }
-               int ret = quic_send_data(ctx, sockfd, srv->ai_family, pdatav,
-                                        datavlen);
-               if (ret != KNOT_EOK) {
+       ctx->stream.out_ack = 0;
+       for (ngtcp2_vec *it = datav; it < datav + datavlen; ++it) {
+               ctx->stream.out_ack += it->len;
+       }
+
+       while (ctx->stream.out_ack > 0) {
+               ret = quic_send_data(ctx, sockfd, srv->ai_family, pdatav, datavlen);
+               if (ret < 0) {
                        WARN("QUIC, failed to send");
                        return ret;
-               }
-               if (ctx->stream.out_ack > 0) {
-                       pdatav = NULL;
-                       datavlen = 0;
+               } else if (ret > 0) {
+                       ret = offset_span(&pdatav, &datavlen, ret);
+                       if (ret != KNOT_EOK) {
+                               return ret;
+                       }
                }
 
-               ret = poll(&pfd, 1, ctx->tls->wait * 1000);
+               int timeout = get_expiry(ctx->conn);
+               if (timeout > 0 && datavlen > 0) {
+                       continue;
+               }
+               ret = poll(&pfd, 1, timeout);
                if (ret < 0) {
                        WARN("QUIC, failed to send");
                        return knot_map_errno();
                } else if (ret == 0) {
+                       ret = ngtcp2_conn_handle_expiry(ctx->conn, quic_timestamp());
                        continue;
                }
                ret = quic_recv(ctx, sockfd);
@@ -638,16 +660,13 @@ int quic_send_dns_query(quic_ctx_t *ctx, int sockfd, struct addrinfo *srv,
                        WARN("QUIC, failed to send");
                        return ret;
                }
-               if (ctx->stream.in_parsed != NULL) {
-                       return KNOT_EOK;
-               }
        }
 
        return KNOT_EOK;
 }
 
 int quic_recv_dns_response(quic_ctx_t *ctx, uint8_t *buf, const size_t buf_len,
-        struct addrinfo *srv)
+       struct addrinfo *srv)
 {
        if (ctx == NULL || ctx->tls == NULL || buf == NULL) {
                return KNOT_EINVAL;
@@ -668,13 +687,16 @@ int quic_recv_dns_response(quic_ctx_t *ctx, uint8_t *buf, const size_t buf_len,
                .revents = 0,
        };
 
-       while (!quic_timeout(ctx->idle_ts, ctx->tls->wait)) {
-               ret = poll(&pfd, 1, ctx->tls->wait * 1000);
+       while (1) {
+               int timeout = get_expiry(ctx->conn);
+               ret = poll(&pfd, 1, timeout);
                if (ret < 0) {
                        WARN("QUIC, failed to receive reply (%s)",
                             knot_strerror(errno));
                        return knot_map_errno();
                } else if (ret == 0) {
+                       ret = ngtcp2_conn_handle_expiry(ctx->conn, quic_timestamp());
+                       WARN("QUIC, peer took too long to respond");
                        goto send;
                }
 
@@ -695,8 +717,8 @@ int quic_recv_dns_response(quic_ctx_t *ctx, uint8_t *buf, const size_t buf_len,
                        return KNOT_NET_ERECV;
                }
 
-
-               send: ret = quic_send(ctx, sockfd, srv->ai_family);
+       send:
+               ret = quic_send(ctx, sockfd, srv->ai_family);
                if (ret != KNOT_EOK) {
                        WARN("QUIC, failed to receive reply (%s)",
                             knot_strerror(ret));
@@ -705,15 +727,15 @@ int quic_recv_dns_response(quic_ctx_t *ctx, uint8_t *buf, const size_t buf_len,
        }
 
        WARN("QUIC, peer took too long to respond");
-       set_application_error(ctx, DOQ_REQUEST_CANCELLED,
-                       (uint8_t *)"Connection timeout",
-                       sizeof("Connection timeout") - 1);
+       const uint8_t msg[] = "Connection timeout";
+       set_application_error(ctx, DOQ_REQUEST_CANCELLED, msg, sizeof(msg) - 1);
+
        return KNOT_NET_ETIMEOUT;
 }
 
 #define quic_ctx_write_close(ctx, dest, dest_len, ts) \
        ngtcp2_conn_write_connection_close((ctx)->conn, (ngtcp2_path *)ngtcp2_conn_get_path((ctx)->conn), \
-               &(ctx)->pi, dest, dest_len, &(ctx)->last_err, ts)
+               &(ctx)->pi, dest, dest_len, &(ctx)->last_err, ts)
 
 void quic_ctx_close(quic_ctx_t *ctx)
 {
@@ -731,8 +753,8 @@ void quic_ctx_close(quic_ctx_t *ctx)
                .msg_iovlen = 1
        };
 
-       ngtcp2_ssize nwrite = quic_ctx_write_close(ctx, enc_buf,
-                       sizeof(enc_buf), quic_timestamp());
+       ngtcp2_ssize nwrite = quic_ctx_write_close(ctx, enc_buf, sizeof(enc_buf),
+                                                  quic_timestamp());
        if (nwrite <= 0) {
                return;
        }
index 71a78c796f79b915a27c47b700b73ddaf1890dfb..fd70d2700075af8375710c688145b8e615b17e29 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -40,10 +40,9 @@ void quic_params_clean(quic_params_t *params);
 #define QUIC_PRIORITY        "%DISABLE_TLS13_COMPAT_MODE:NORMAL:"QUIC_DEFAULT_VERSION":"QUIC_DEFAULT_GROUPS
 
 typedef enum {
-       OPENING,
-       CONNECTED,
-       CLOSING,
-       CLOSED
+       CLOSED,    // Initialized
+       CONNECTED, // RTT-0
+       VERIFIED,  // RTT-1
 } quic_state_t;
 
 typedef enum {
@@ -83,7 +82,6 @@ typedef struct {
                struct knot_tcp_inbufs_upd_res *in_parsed;
                size_t in_parsed_it;
                size_t in_parsed_total;
-               int resets;
        } stream;
        ngtcp2_ccerr last_err;
        uint8_t secret[32];
@@ -91,7 +89,6 @@ typedef struct {
        ngtcp2_conn *conn;
        ngtcp2_pkt_info pi;
        quic_state_t state;
-       uint64_t idle_ts;
 } quic_ctx_t;
 
 extern const gnutls_datum_t doq_alpn;