summaryrefslogtreecommitdiffstats
path: root/src/libknot/quic/quic_conn.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libknot/quic/quic_conn.h')
-rw-r--r--src/libknot/quic/quic_conn.h326
1 files changed, 326 insertions, 0 deletions
diff --git a/src/libknot/quic/quic_conn.h b/src/libknot/quic/quic_conn.h
new file mode 100644
index 0000000..64ead51
--- /dev/null
+++ b/src/libknot/quic/quic_conn.h
@@ -0,0 +1,326 @@
+/* Copyright (C) 2023 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*!
+ * \file
+ *
+ * \brief QUIC connection management.
+ *
+ * \addtogroup quic
+ * @{
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/uio.h>
+
+#define MAX_STREAMS_PER_CONN 10 // this limits the number of un-finished streams per conn (i.e. if response has been recvd with FIN, it doesn't count)
+
+struct ngtcp2_cid; // declaration taken from wherever in ngtcp2
+struct knot_quic_creds;
+struct knot_quic_reply;
+struct knot_sweep_stats;
+
+// those are equivalent to contrib/ucw/lists.h , just must not be included.
+typedef struct knot_quic_ucw_node {
+ struct knot_quic_ucw_node *next, *prev;
+} knot_quic_ucw_node_t;
+typedef struct knot_quic_ucw_list {
+ knot_quic_ucw_node_t head, tail;
+} knot_quic_ucw_list_t;
+
+typedef struct {
+ void *get_conn;
+ void *user_data;
+} nc_conn_ref_placeholder_t;
+
+typedef struct {
+ knot_quic_ucw_node_t node;
+ size_t len;
+ uint8_t buf[];
+} knot_quic_obuf_t;
+
+typedef struct {
+ struct iovec inbuf;
+ struct knot_tcp_inbufs_upd_res *inbufs;
+ size_t firstib_consumed;
+ knot_quic_ucw_list_t outbufs;
+ size_t obufs_size;
+
+ knot_quic_obuf_t *unsent_obuf;
+ size_t first_offset;
+ size_t unsent_offset;
+} knot_quic_stream_t;
+
+typedef enum {
+ KNOT_QUIC_CONN_HANDSHAKE_DONE = (1 << 0),
+ KNOT_QUIC_CONN_SESSION_TAKEN = (1 << 1),
+} knot_quic_conn_flag_t;
+
+typedef struct knot_quic_conn {
+ int heap_node_placeholder; // MUST be first field of the struct
+ uint64_t next_expiry;
+
+ nc_conn_ref_placeholder_t conn_ref; // placeholder for internal struct ngtcp2_crypto_conn_ref
+
+ struct ngtcp2_conn *conn;
+
+ struct gnutls_session_int *tls_session;
+
+ knot_quic_stream_t *streams;
+ int16_t streams_count; // number of allocated streams structures
+ int16_t stream_inprocess; // index of first stream that has complete incomming data to be processed (aka inbuf_fin)
+ knot_quic_conn_flag_t flags;
+ int qlog_fd;
+ int64_t streams_first; // stream_id/4 of first allocated stream
+ size_t ibufs_size;
+ size_t obufs_size;
+
+ struct knot_quic_table *quic_table;
+
+ struct knot_quic_conn *next;
+} knot_quic_conn_t;
+
+typedef struct knot_quic_cid {
+ uint8_t cid_placeholder[32];
+ knot_quic_conn_t *conn;
+ struct knot_quic_cid *next;
+} knot_quic_cid_t;
+
+typedef struct knot_quic_table {
+ uint32_t flags; // unused yet
+ size_t size;
+ size_t usage;
+ size_t pointers;
+ size_t max_conns;
+ size_t ibufs_max;
+ size_t obufs_max;
+ size_t ibufs_size;
+ size_t obufs_size;
+ size_t udp_payload_limit; // for simplicity not distinguishing IPv4/6
+ void (*log_cb)(const char *);
+ const char *qlog_dir;
+ uint64_t hash_secret[4];
+ struct knot_quic_creds *creds;
+ struct heap *expiry_heap;
+ knot_quic_cid_t *conns[];
+} knot_quic_table_t;
+
+/*!
+ * \brief Allocate QUIC connections hash table.
+ *
+ * \param max_conns Maximum nuber of connections.
+ * \param max_ibufs Maximum size of buffers for fragmented incomming DNS msgs.
+ * \param max_obufs Maximum size of buffers for un-ACKed outgoing data.
+ * \param udp_payload Maximum UDP payload size (both IPv4 and 6).
+ * \param creds QUIC crypto context..
+ *
+ * \return Allocated table, or NULL.
+ */
+knot_quic_table_t *knot_quic_table_new(size_t max_conns, size_t max_ibufs, size_t max_obufs,
+ size_t udp_payload, struct knot_quic_creds *creds);
+
+/*!
+ * \brief Free QUIC table including its contents.
+ *
+ * \param table Table to be freed.
+ */
+void knot_quic_table_free(knot_quic_table_t *table);
+
+/*!
+ * \brief Close timed out connections and some oldest ones if table full.
+ *
+ * \param table QUIC table to be cleaned up.
+ * \param sweep_reply Optional: reply structure to send sweep-initiated packets to the client.
+ * \param stats Out: sweep statistics.
+ */
+void knot_quic_table_sweep(knot_quic_table_t *table, struct knot_quic_reply *sweep_reply,
+ struct knot_sweep_stats *stats);
+
+/*!
+ * \brief Add new connection/CID link to table.
+ *
+ * \param conn QUIC connection linked.
+ * \param cid New CID to be added.
+ * \param table QUIC table to be modified.
+ *
+ * \return Pointer on the CID reference in table, or NULL.
+ */
+knot_quic_cid_t **quic_table_insert(knot_quic_conn_t *conn,
+ const struct ngtcp2_cid *cid,
+ knot_quic_table_t *table);
+
+/*!
+ * \brief Add new connection to the table, allocating conn struct.
+ *
+ * \param ngconn Ngtcp2 conn struct.
+ * \param cid CID to be linked (usually oscid for server).
+ * \param table QUIC table to be modified.
+ *
+ * \return Allocated (and linked) Knot conn struct, or NULL.
+ */
+knot_quic_conn_t *quic_table_add(struct ngtcp2_conn *ngconn,
+ const struct ngtcp2_cid *cid,
+ knot_quic_table_t *table);
+
+/*!
+ * \brief Lookup connection/CID link in table.
+ *
+ * \param cid CID to be searched for.
+ * \param table QUIC table.
+ *
+ * \return Pointer on the CID reference in table, or NULL.
+ */
+knot_quic_cid_t **quic_table_lookup2(const struct ngtcp2_cid *cid,
+ knot_quic_table_t *table);
+
+/*!
+ * \brief Lookup QUIC connection in table.
+ *
+ * \param cid CID to be searched for.
+ * \param table QUIC table.
+ *
+ * \return Connection that the CID belongs to, or NULL.
+ */
+knot_quic_conn_t *quic_table_lookup(const struct ngtcp2_cid *cid,
+ knot_quic_table_t *table);
+
+/*!
+ * \brief Re-schedule connection expiry timer.
+ */
+void quic_conn_mark_used(knot_quic_conn_t *conn, knot_quic_table_t *table);
+
+/*!
+ * \brief Remove connection/CID link from table.
+ *
+ * \param pcid CID to be removed.
+ * \param table QUIC table.
+ */
+void quic_table_rem2(knot_quic_cid_t **pcid, knot_quic_table_t *table);
+
+/*!
+ * \brief Remove specified stream from QUIC connection, freeing all buffers.
+ *
+ * \param conn QUIC connection to remove from.
+ * \param stream_id Stream QUIC ID.
+ */
+void knot_quic_conn_stream_free(knot_quic_conn_t *conn, int64_t stream_id);
+
+/*!
+ * \brief Remove and deinitialize connection completely.
+ *
+ * \param conn Connection to be removed.
+ * \param table Table to remove from.
+ */
+void knot_quic_table_rem(knot_quic_conn_t *conn, knot_quic_table_t *table);
+
+/*!
+ * \brief Fetch or initialize a QUIC stream.
+ *
+ * \param conn QUIC connection.
+ * \param stream_id Stream QUIC ID.
+ * \param create Trigger stream creation if not exists.
+ *
+ * \return Stream or NULL.
+ */
+knot_quic_stream_t *knot_quic_conn_get_stream(knot_quic_conn_t *conn,
+ int64_t stream_id, bool create);
+
+/*!
+ * \brief Create a new, subsequent stream.
+ */
+knot_quic_stream_t *knot_quic_conn_new_stream(knot_quic_conn_t *conn);
+
+/*!
+ * \brief Process incomming stream data to stream structure.
+ *
+ * \param conn QUIC connection that has received data.
+ * \param stream_id Stream QUIC ID of the incomming data.
+ * \param data Incomming payload data.
+ * \param len Incomming payload data length.
+ * \param fin FIN flag set for incomming data.
+ *
+ * \return KNOT_E*
+ */
+int knot_quic_stream_recv_data(knot_quic_conn_t *conn, int64_t stream_id,
+ const uint8_t *data, size_t len, bool fin);
+
+/*!
+ * \brief Get next stream which has pending incomming data to be processed.
+ *
+ * \param conn QUIC connection.
+ * \param stream_id Out: strem QUIC ID of the returned stream.
+ *
+ * \return Stream with incomming data.
+ */
+knot_quic_stream_t *knot_quic_stream_get_process(knot_quic_conn_t *conn,
+ int64_t *stream_id);
+
+/*!
+ * \brief Add outgiong data to the stream for sending.
+ *
+ * \param conn QUIC connection that shall send data.
+ * \param stream_id Stream ID for outgoing data.
+ * \param data Data payload.
+ * \param len Data payload length.
+ *
+ * \return NULL if error, or pinter at the data in outgiong buffer.
+ */
+uint8_t *knot_quic_stream_add_data(knot_quic_conn_t *conn, int64_t stream_id,
+ uint8_t *data, size_t len);
+
+/*!
+ * \brief Mark outgiong data as acknowledged after ACK received.
+ *
+ * \param conn QUIC connection that received ACK.
+ * \param stream_id Stream ID of ACKed data.
+ * \param end_acked Offset of ACKed data + ACKed length.
+ * \param keep_stream Don't free the stream even when ACKed all outgoing data.
+ */
+void knot_quic_stream_ack_data(knot_quic_conn_t *conn, int64_t stream_id,
+ size_t end_acked, bool keep_stream);
+
+/*!
+ * \brief Mark outgoing data as sent.
+ *
+ * \param conn QUIC connection that sent data.
+ * \param stream_id Stream ID of sent data.
+ * \param amount_sent Length of sent data.
+ */
+void knot_quic_stream_mark_sent(knot_quic_conn_t *conn, int64_t stream_id,
+ size_t amount_sent);
+
+/*!
+ * \brief Free rest of resources of closed conns.
+ *
+ * \param conns Array with recently used conns (possibly NULLs).
+ * \param n_conns Size of the array.
+ */
+void knot_quic_cleanup(knot_quic_conn_t *conns[], size_t n_conns);
+
+/*!
+ * \brief Toggle sending Retry packet as a reaction to Initial packet of new connection.
+ *
+ * \param table Connection table.
+ *
+ * \return True if instead of continuing handshake, Retry packet shall be sent
+ * to verify counterpart's address.
+ */
+bool quic_require_retry(knot_quic_table_t *table);
+
+/*! @} */