tutorial.rst revision 7483dee0
1********
2Tutorial
3********
4
5.. highlight:: c
6
7Introduction
8============
9
10The LSQUIC library provides facilities for operating a QUIC (Google QUIC
11or IETF QUIC) server or client with optional HTTP (or HTTP/3) functionality.
12To do that, it specifies an application programming interface (API) and
13exposes several basic object types to operate upon:
14
15- engine;
16- connection; and
17- stream.
18
19An engine manages connections, processes incoming packets, and schedules
20outgoing packets.  An engine operates in one of two modes: client or server.
21
22The LSQUIC library does not use sockets to receive and send packets; that is
23handled by the user-supplied callbacks.  The library also does not mandate
24the use of any particular event loop.  Instead, it has functions to help the
25user schedule events.  (Thus, using an event loop is not even strictly
26necessary.)  The various callbacks and settings are supplied to the engine
27constructor.
28
29A connection carries one or more streams, ensures reliable data delivery,
30and handles the protocol details.
31
32A stream usually corresponds to a request/response pair: a client sends
33its request over a single stream and a server sends its response back
34using the same stream.  This is the Google QUIC and HTTP/3 use case.
35Nevertheless, the library does not limit one to this scenario.  Any
36application protocol can be implemented using LSQUIC -- as long as it
37can be implemented using the QUIC transport protocol.  The library provides
38hooks for stream events: when a stream is created or closed, when it has
39data to read or when it can be written to, and so on.
40
41In the following sections, we will describe how to:
42
43- initialize the library;
44- configure and instantiate an engine object;
45- send and receive packets; and
46- work with connections and streams.
47
48Include Files
49-------------
50
51A single include file, :file:`lsquic.h`, contains all the necessary
52LSQUIC declarations:
53
54::
55
56    #include <lsquic.h>
57
58Library Initialization
59======================
60
61Before the first engine object is instantiate, the library must be
62initialized using :func:`lsquic_global_init()`:
63
64::
65
66    if (0 != lsquic_global_init(LSQUIC_GLOBAL_CLIENT|LSQUIC_GLOBAL_SERVER))
67    {
68        exit(EXIT_FAILURE);
69    }
70    /* OK, do something useful */
71
72If you plan to instantiate engines only in a single mode, client or server,
73you can omit the appropriate flag.
74
75After all engines have been destroyed and the LSQUIC library is no longer
76going to be used, the global initialization can be undone:
77
78::
79
80    lsquic_global_cleanup();
81    exit(EXIT_SUCCESS);
82
83Engine Instantiation
84====================
85
86Engine instantiation is performed by :func:`lsquic_engine_new()`:
87
88::
89
90    /* Create an engine in server mode with HTTP behavior: */
91    lsquic_engine_t *engine
92        = lsquic_engine_new(LSENG_SERVER|LSENG_HTTP, &engine_api);
93
94The engine mode is selected by using the :macro:`LSENG_SERVER` flag.
95If present, the engine will be in server mode; if not, the engine will
96be in client mode.  If you need both server and client functionality
97in your program, instantiate two engines (or as many as you like).
98
99Using the :macro:`LSENG_HTTP` flag enables the HTTP behavior:  The library
100hides the interaction between the HTTP application layer and the QUIC
101transport layer and presents a simple, unified (between Google QUIC and
102HTTP/3) way of sending and receiving HTTP messages.  Behind the scenes,
103the library will compress and uncompress HTTP headers, add and remove
104HTTP/3 stream framing, and operate the necessary control streams.
105
106Engine Configuration
107--------------------
108
109The second argument to :func:`lsquic_engine_new()` is a pointer to
110a struct of type :type:`lsquic_engine_api`.  This structure lists
111several user-specified function pointers that the engine is to use
112to perform various functions.  Mandatory among these are:
113
114- function to set packets out, :member:`lsquic_engine_api.ea_packets_out`;
115- functions linked to connection and stream events,
116  :member:`lsquic_engine_api.ea_stream_if`;
117- function to look up certificate to use, :member:`lsquic_engine_api.ea_lookup_cert` (in server mode); and
118- function to fetch SSL context, :member:`lsquic_engine_api.ea_get_ssl_ctx` (in server mode).
119
120The minimal structure for a client will look like this:
121
122::
123
124    lsquic_engine_api engine_api = {
125        .ea_packets_out     = send_packets_out,
126        .ea_packets_out_ctx = (void *) sockfd,  /* For example */
127        .ea_stream_if       = &stream_callbacks,
128        .ea_stream_if_ctx   = &some_context,
129    };
130
131Engine Settings
132---------------
133
134Engine settings can be changed by specifying
135:member:`lsquic_engine_api.ea_settings`.  There are **many** parameters
136to tweak: supported QUIC versions, amount of memory dedicated to connections
137and streams, various timeout values, and so on.  See
138:ref:`apiref-engine-settings` for full details.  If ``ea_settings`` is set
139to ``NULL``, the engine will use the defaults, which should be OK.
140
141Sending Packets
142===============
143
144The :member:`lsquic_engine_api.ea_packets_out` is the function that gets
145called when an engine instance has packets to send.  It could look like
146this:
147
148::
149
150    /* Return number of packets sent or -1 on error */
151    static int
152    send_packets_out (void *ctx, const struct lsquic_out_spec *specs,
153                                                    unsigned n_specs)
154    {
155        struct msghdr msg;
156        int sockfd;
157        unsigned n;
158
159        memset(&msg, 0, sizeof(msg));
160        sockfd = (int) (uintptr_t) ctx;
161
162        for (n = 0; n < n_specs; ++n)
163        {
164            msg.msg_name       = (void *) specs[n].dest_sa;
165            msg.msg_namelen    = sizeof(struct sockaddr_in);
166            msg.msg_iov        = specs[n].iov;
167            msg.msg_iovlen     = specs[n].iovlen;
168            if (sendmsg(sockfd, &msg, 0) < 0)
169                break;
170        }
171
172        return (int) n;
173    }
174
175Note that the version above is very simple.  :type:`lsquic_out_spec`
176also specifies local address as well as ECN value.  These are set
177using ancillary data in a platform-dependent way.
178
179Receiving Packets
180=================
181
182The user reads packets and provides them to an engine instance using
183:func:`lsquic_engine_packet_in()`.
184
185*TODO*
186
187Running Connections
188===================
189
190A connection needs to be processed once in a while.  It needs to be
191processed when one of the following is true:
192
193- There are incoming packets;
194- A stream is both readable by the user code and the user code wants
195  to read from it;
196- A stream is both writeable by the user code and the user code wants
197  to write to it;
198- User has written to stream outside of on_write() callbacks (that is
199  allowed) and now there are packets ready to be sent;
200- A timer (pacer, retransmission, idle, etc) has expired;
201- A control frame needs to be sent out;
202- A stream needs to be serviced or created.
203
204Each of these use cases is handled by a single function,
205:func:`lsquic_engine_process_conns()`.
206
207The connections to which the conditions above apply are processed (or
208"ticked") in the least recently ticked order.  After calling this function,
209you can see when is the next time a connection needs to be processed using
210:func:`lsquic_engine_earliest_adv_tick()`.
211
212Based on this value, next event can be scheduled (in the event loop of
213your choice).
214
215::
216
217
218Stream Reading and Writing
219==========================
220
221Reading from (or writing to) a stream is best down when that stream is
222readable (or writeable).  To register an interest in an event,
223