1The ngtcp2 programmers' guide for early adopters 2================================================ 3 4This document is written for early adopters of ngtcp2 library. It 5describes a brief introduction of programming ngtcp2. 6 7Prerequisites 8------------- 9 10Reading `QUIC transport 11<https://datatracker.ietf.org/doc/html/rfc9000>`_ and `QUIC TLS 12<https://datatracker.ietf.org/doc/html/rfc9001>`_ documents helps you 13a lot to write QUIC application. They describes how TLS is integrated 14into QUIC and why the existing TLS stack cannot be used with QUIC. 15 16QUIC requires the special interface from TLS stack, which is probably 17not available from most of the existing TLS stacks. As far as I know, 18the TLS stacks maintained by the active participants of QUIC working 19group only get this interface at the time of this writing. In order 20to build QUIC application you have to choose one of them. Here is the 21list of TLS stacks which are supposed to provide such interface and 22for which we provide crypto helper libraries: 23 24* `OpenSSL with QUIC support 25 <https://github.com/quictls/openssl/tree/OpenSSL_1_1_1l+quic>`_ 26* GnuTLS >= 3.7.2 27* BoringSSL 28 29Creating ngtcp2_conn object 30--------------------------- 31 32:type:`ngtcp2_conn` is the primary object to present a single QUIC 33connection. Use `ngtcp2_conn_client_new()` for client application, 34and `ngtcp2_conn_server_new()` for server. 35 36They require :type:`ngtcp2_callbacks`, :type:`ngtcp2_settings`, and 37:type:`ngtcp2_transport_params` objects. 38 39The :type:`ngtcp2_callbacks` contains the callback functions which 40:type:`ngtcp2_conn` calls when a specific event happens, say, 41receiving stream data or stream is closed, etc. Some of the callback 42functions are optional. For client application, the following 43callback functions must be set: 44 45* :member:`client_initial <ngtcp2_callbacks.client_initial>`: 46 `ngtcp2_crypto_client_initial_cb()` can be passed directly. 47* :member:`recv_crypto_data <ngtcp2_callbacks.recv_crypto_data>`: 48 `ngtcp2_crypto_recv_crypto_data_cb()` can be passed directly. 49* :member:`encrypt <ngtcp2_callbacks.encrypt>`: 50 `ngtcp2_crypto_encrypt_cb()` can be passed directly. 51* :member:`decrypt <ngtcp2_callbacks.decrypt>`: 52 `ngtcp2_crypto_decrypt_cb()` can be passed directly. 53* :member:`hp_mask <ngtcp2_callbacks.hp_mask>`: 54 `ngtcp2_crypto_hp_mask_cb()` can be passed directly. 55* :member:`recv_retry <ngtcp2_callbacks.recv_retry>`: 56 `ngtcp2_crypto_recv_retry_cb()` can be passed directly. 57* :member:`rand <ngtcp2_callbacks.rand>` 58* :member:`get_new_connection_id 59 <ngtcp2_callbacks.get_new_connection_id>` 60* :member:`update_key <ngtcp2_callbacks.update_key>`: 61 `ngtcp2_crypto_update_key_cb()` can be passed directly. 62* :member:`delete_crypto_aead_ctx 63 <ngtcp2_callbacks.delete_crypto_aead_ctx>`: 64 `ngtcp2_crypto_delete_crypto_aead_ctx_cb()` can be passed directly. 65* :member:`delete_crypto_cipher_ctx 66 <ngtcp2_callbacks.delete_crypto_cipher_ctx>`: 67 `ngtcp2_crypto_delete_crypto_cipher_ctx_cb()` can be passed 68 directly. 69* :member:`get_path_challenge_data <ngtcp2_get_path_challenge_data>`: 70 `ngtcp2_crypto_get_path_challenge_data_cb()` can be passed directly. 71 72For server application, the following callback functions must be set: 73 74* :member:`recv_client_initial 75 <ngtcp2_callbacks.recv_client_initial>`: 76 `ngtcp2_crypto_recv_client_initial_cb()` can be passed directly. 77* :member:`recv_crypto_data <ngtcp2_callbacks.recv_crypto_data>`: 78 `ngtcp2_crypto_recv_crypto_data_cb()` can be passed directly. 79* :member:`encrypt <ngtcp2_callbacks.encrypt>`: 80 `ngtcp2_crypto_encrypt_cb()` can be passed directly. 81* :member:`decrypt <ngtcp2_callbacks.decrypt>`: 82 `ngtcp2_crypto_decrypt_cb()` can be passed directly. 83* :member:`hp_mask <ngtcp2_callbacks.hp_mask>`: 84 `ngtcp2_crypto_hp_mask_cb()` can be passed directly. 85* :member:`rand <ngtcp2_callbacks.rand>` 86* :member:`get_new_connection_id 87 <ngtcp2_callbacks.get_new_connection_id>` 88* :member:`update_key <ngtcp2_callbacks.update_key>`: 89 `ngtcp2_crypto_update_key_cb()` can be passed directly. 90* :member:`delete_crypto_aead_ctx 91 <ngtcp2_callbacks.delete_crypto_aead_ctx>`: 92 `ngtcp2_crypto_delete_crypto_aead_ctx_cb()` can be passed directly. 93* :member:`delete_crypto_cipher_ctx 94 <ngtcp2_callbacks.delete_crypto_cipher_ctx>`: 95 `ngtcp2_crypto_delete_crypto_cipher_ctx_cb()` can be passed 96 directly. 97* :member:`get_path_challenge_data <ngtcp2_get_path_challenge_data>`: 98 `ngtcp2_crypto_get_path_challenge_data_cb()` can be passed directly. 99 100``ngtcp2_crypto_*`` functions are a part of :doc:`ngtcp2 crypto API 101<crypto_apiref>` which provides easy integration with the supported 102TLS backend. It vastly simplifies TLS integration and is strongly 103recommended. 104 105:type:`ngtcp2_settings` contains the settings for QUIC connection. 106All fields must be set. Application should call 107`ngtcp2_settings_default()` to set the default values. It would be 108very useful to enable debug logging by setting logging function to 109:member:`ngtcp2_settings.log_printf` field. ngtcp2 library relies on 110the timestamp fed from application. The initial timestamp must be 111passed to ``initial_ts`` field in nanosecond resolution. ngtcp2 cares 112about the difference from that initial value. It could be any 113timestamp which increases monotonically, and actual value does not 114matter. 115 116:type:`ngtcp2_transport_params` contains QUIC transport parameters 117which is sent to a remote endpoint during handshake. All fields must 118be set. Application should call `ngtcp2_transport_params_default()` 119to set the default values. 120 121Client application has to supply Connection IDs to 122`ngtcp2_conn_client_new()`. The *dcid* parameter is the destination 123connection ID (DCID), and which should be random byte string and at 124least 8 bytes long. The *scid* is the source connection ID (SCID) 125which identifies the client itself. The *version* parameter is the 126QUIC version to use. It should be :macro:`NGTCP2_PROTO_VER_V1`. 127 128Similarly, server application has to supply these parameters to 129`ngtcp2_conn_server_new()`. But the *dcid* must be the same value 130which is received from client (which is client SCID). The *scid* is 131chosen by server. Don't use DCID in client packet as server SCID. 132The *version* parameter is the QUIC version to use. It should be 133:macro:`NGTCP2_PROTO_VER_V1`. 134 135A path is very important to QUIC connection. It is the pair of 136endpoints, local and remote. The path passed to 137`ngtcp2_conn_client_new()` and `ngtcp2_conn_server_new()` is a network 138path that handshake is performed. The path must not change during 139handshake. After handshake is confirmed, client can migrate to new 140path. An application must provide actual path to the API function to 141tell the library where a packet comes from. The "write" API function 142takes path parameter and fills it to which the packet should be sent. 143 144TLS integration 145--------------- 146 147Use of :doc:`ngtcp2 crypto API <crypto_apiref>` is strongly 148recommended because it vastly simplifies the TLS integration. 149 150The most of the TLS work is done by the callback functions passed to 151:type:`ngtcp2_callbacks` object. There are some operations left to 152application has to perform to make TLS integration work. 153 154When TLS stack generates new secrets, they have to be installed to 155:type:`ngtcp2_conn` by calling 156`ngtcp2_crypto_derive_and_install_rx_key()` and 157`ngtcp2_crypto_derive_and_install_tx_key()`. 158 159When TLS stack generates new crypto data to send, they must be passed 160to :type:`ngtcp2_conn` by calling `ngtcp2_conn_submit_crypto_data()`. 161 162When QUIC handshake is completed, 163:member:`ngtcp2_callbacks.handshake_completed` callback function is 164called. The local and remote endpoint independently declare handshake 165completion. The endpoint has to confirm that the other endpoint also 166finished handshake. When the handshake is confirmed, client side 167:type:`ngtcp2_conn` will call 168:member:`ngtcp2_callbacks.handshake_confirmed` callback function. 169Server confirms handshake when it declares handshake completion, 170therefore, separate handshake confirmation callback is not called. 171 172Read and write packets 173---------------------- 174 175`ngtcp2_conn_read_pkt()` processes the incoming QUIC packets. In 176order to write QUIC packets, call `ngtcp2_conn_writev_stream()` or 177`ngtcp2_conn_write_pkt()`. 178 179In order to send stream data, the application has to first open a 180stream. Use `ngtcp2_conn_open_bidi_stream()` to open bidirectional 181stream. For unidirectional stream, call 182`ngtcp2_conn_open_uni_stream()`. Call `ngtcp2_conn_writev_stream()` 183to send stream data. 184 185If BBR congestion control algorithm is used, the additional API 186functions are required when sending QUIC packets. BBR needs pacing 187packets. `ngtcp2_conn_get_send_quantum()` returns the number of bytes 188that can be sent without packet spacing. After one or more calls of 189`ngtcp2_conn_writev_stream()` (it can be called multiple times to fill 190the buffer sized up to `ngtcp2_conn_get_send_quantum()` bytes), call 191`ngtcp2_conn_update_pkt_tx_time()` to set the timer when the next 192packet should be sent. The timer is integrated into 193`ngtcp2_conn_get_expiry()`. 194 195Packet handling on server side 196------------------------------ 197 198Any incoming UDP datagram should be first processed by 199`ngtcp2_pkt_decode_version_cid()`. It can handle Connection ID more 200than 20 bytes which is the maximum length defined in QUIC v1. If the 201function returns :macro:`NGTCP2_ERR_VERSION_NEGOTIATION`, server 202should send Version Negotiation packet. Use 203`ngtcp2_pkt_write_version_negotiation()` for this purpose. If 204`ngtcp2_pkt_decode_version_cid()` succeeds, then check whether the UDP 205datagram belongs to any existing connection by looking up connection 206tables by Destination Connection ID. If it belongs to an existing 207connection, pass the UDP datagram to `ngtcp2_conn_read_pkt()`. If it 208does not belong to any existing connection, it should be passed to 209`ngtcp2_accept()`. If it returns :macro:`NGTCP2_ERR_RETRY`, the 210server should send Retry packet (use `ngtcp2_crypto_write_retry()` to 211create Retry packet). If it returns 212:macro:`NGTCP2_ERR_VERSION_NEGOTIATION`, the server should send 213Version Negotiation packet. If it returns an other negative error 214code, just drop the packet to the floor and take no action, or send 215Stateless Reset packet (use `ngtcp2_pkt_write_stateless_reset()` to 216create Stateless Reset packet). Otherwise, the UDP datagram is 217acceptable as a new connection. Create :type:`ngtcp2_conn` object and 218pass the UDP datagram to `ngtcp2_conn_read_pkt()`. 219 220Dealing with early data 221----------------------- 222 223Client application has to load resumed TLS session. It also has to 224set the remembered transport parameters using 225`ngtcp2_conn_set_early_remote_transport_params()` function. 226 227Other than that, there is no difference between early data and 1RTT 228data in terms of API usage. 229 230If early data is rejected by a server, client must call 231`ngtcp2_conn_early_data_rejected`. All connection states altered 232during early data transmission are undone. The library does not 233retransmit early data to server as 1RTT data. If an application 234wishes to resend data, it has to reopen streams and writes data again. 235See `ngtcp2_conn_early_data_rejected`. 236 237Stream data ownership 238-------------------------------- 239 240Stream data passed to :type:`ngtcp2_conn` must be held by application 241until :member:`ngtcp2_callbacks.acked_stream_data_offset` callbacks is 242invoked, telling that the those data are acknowledged by the remote 243endpoint and no longer used by the library. 244 245Timers 246------ 247 248The library does not ask an operating system any timestamp. Instead, 249an application has to supply timestamp to the library. The type of 250timestamp in ngtcp2 library is :type:`ngtcp2_tstamp` which is 251nanosecond resolution. The library only cares the difference of 252timestamp, so it does not have to be a system clock. A monotonic 253clock should work better. It should be same clock passed to 254:type:`ngtcp2_settings`. 255 256`ngtcp2_conn_get_expiry()` tells an application when timer fires. 257When timer fires, call `ngtcp2_conn_handle_expiry()` and 258`ngtcp2_conn_write_pkt()` (or `ngtcp2_conn_writev_stream()`). 259 260After calling these functions, new expiry will be set. The 261application should call `ngtcp2_conn_get_expiry()` to restart timer. 262 263Application also handles connection idle timeout. 264`ngtcp2_conn_get_idle_expiry()` returns the current idle expiry. If 265idle timer is expired, the connection should be closed without calling 266`ngtcp2_conn_write_connection_close()`. 267 268Connection migration 269-------------------- 270 271In QUIC, client application can migrate to a new local address. 272`ngtcp2_conn_initiate_immediate_migration()` migrates to a new local 273address without checking reachability. On the other hand, 274`ngtcp2_conn_initiate_migration()` migrates to a new local address 275after a new path is validated (thus reachability is established). 276 277Closing connection 278------------------ 279 280In order to close QUIC connection, call 281`ngtcp2_conn_write_connection_close()` or 282`ngtcp2_conn_write_application_close()`. 283 284Error handling in general 285------------------------- 286 287In general, when error is returned from the ngtcp2 library function, 288just close QUIC connection. 289 290If `ngtcp2_err_is_fatal()` returns true with the returned error code, 291:type:`ngtcp2_conn` object must be deleted with `ngtcp2_conn_del()` 292without any ngtcp2 library functions. Otherwise, call 293`ngtcp2_conn_write_connection_close()` to get terminal packet. 294Sending it finishes QUIC connection. 295 296If :macro:`NGTCP2_ERR_DROP_CONN` is returned from 297`ngtcp2_conn_read_pkt`, a connection should be dropped without calling 298`ngtcp2_conn_write_connection_close()`. 299 300The following error codes must be considered as transitional, and 301application should keep connection alive: 302 303* :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED` 304* :macro:`NGTCP2_ERR_STREAM_SHUT_WR` 305* :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` 306* :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED` 307