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