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