tutorial.rst revision aedecb45
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 ``LSENG_SERVER`` flag. If 95present, the engine will be in server mode; if not, the engine will 96be in client mode. 97 98Using the ``LSENG_HTTP`` flag enables the HTTP behavior: The library 99hides the interaction between the HTTP application layer and the QUIC 100transport layer and presents a simple, unified (between Google QUIC and 101HTTP/3) way of sending and receiving HTTP messages. Behind the scenes, 102the library will compress and uncompress HTTP headers, add and remove 103HTTP/3 stream framing, and operate the necessary control streams. 104 105Engine Configuration 106-------------------- 107 108The second argument to :func:`lsquic_engine_new()` is a pointer to 109a struct of type :type:`lsquic_engine_api`. This structure lists 110several user-specified function pointers that the engine is to use 111to perform various functions. Mandatory among these are: 112 113- function to set packets out, :member:`lsquic_engine_api.ea_packets_out`; 114- functions linked to connection and stream events, 115 :member:`lsquic_engine_api.ea_stream_if`; 116- function to look up certificate to use, :member:`lsquic_engine_api.ea_lookup_cert` (in server mode); and 117- function to fetch SSL context, :member:`lsquic_engine_api.ea_get_ssl_ctx` (in server mode). 118 119The minimal structure for a client will look like this: 120 121:: 122 123 lsquic_engine_api engine_api = { 124 .ea_packets_out = send_packets_out, 125 .ea_packets_out_ctx = (void *) sockfd, /* For example */ 126 .ea_stream_if = &stream_callbacks, 127 .ea_stream_if_ctx = &some_context, 128 }; 129 130Engine Settings 131--------------- 132 133Engine settings can be changed by specifying 134:member:`lsquic_engine_api.ea_settings`. There are **many** parameters 135to tweak: supported QUIC versions, amount of memory dedicated to connections 136and streams, various timeout values, and so on. See 137:ref:`apiref-engine-settings` for full details. If ``ea_settings`` is set 138to ``NULL``, the engine will use the defaults, which should be OK. 139 140Sending Packets 141=============== 142 143The :member:`lsquic_engine_api.ea_packets_out` is the function that gets 144called when an engine instance has packets to send. It could look like 145this: 146 147:: 148 149 /* Return number of packets sent or -1 on error */ 150 static int 151 send_packets_out (void *ctx, const struct lsquic_out_spec *specs, 152 unsigned n_specs) 153 { 154 struct msghdr msg; 155 int sockfd; 156 unsigned n; 157 158 memset(&msg, 0, sizeof(msg)); 159 sockfd = (int) (uintptr_t) ctx; 160 161 for (n = 0; n < n_specs; ++n) 162 { 163 msg.msg_name = (void *) specs[n].dest_sa; 164 msg.msg_namelen = sizeof(struct sockaddr_in); 165 msg.msg_iov = specs[n].iov; 166 msg.msg_iovlen = specs[n].iovlen; 167 if (sendmsg(sockfd, &msg, 0) < 0) 168 break; 169 } 170 171 return (int) n; 172 } 173 174Note that the version above is very simple. :type:`lsquic_out_spec` 175also specifies local address as well as ECN value. These are set 176using ancillary data in a platform-dependent way. 177 178Receiving Packets 179================= 180 181The user reads packets and provides them to an engine instance using 182:func:`lsquic_engine_packet_in()`. 183 184*TODO* 185 186Running Connections 187=================== 188 189A connection needs to be processed once in a while. It needs to be 190processed when one of the following is true: 191 192- There are incoming packets; 193- A stream is both readable by the user code and the user code wants 194 to read from it; 195- A stream is both writeable by the user code and the user code wants 196 to write to it; 197- User has written to stream outside of on_write() callbacks (that is 198 allowed) and now there are packets ready to be sent; 199- A timer (pacer, retransmission, idle, etc) has expired; 200- A control frame needs to be sent out; 201- A stream needs to be serviced or created. 202 203Each of these use cases is handled by a single function, 204:func:`lsquic_engine_process_conns()`. 205 206The connections to which the conditions above apply are processed (or 207"ticked") in the least recently ticked order. After calling this function, 208you can see when is the next time a connection needs to be processed using 209:func:`lsquic_engine_earliest_adv_tick()`. 210 211Based on this value, next event can be scheduled (in the event loop of 212your choice). 213 214:: 215 216 217Stream Reading and Writing 218========================== 219 220Reading from (or writing to) a stream is best down when that stream is 221readable (or writeable). To register an interest in an event, 222