blob: f05c2693937031513e95e90be0428b17476c89ad [file] [log] [blame]
Willy Tarreau62f52692017-10-08 23:01:42 +02001/*
2 * HTTP/2 mux-demux for connections
3 *
4 * Copyright 2017 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <common/cfgparse.h>
14#include <common/config.h>
Willy Tarreau5ab6b572017-09-22 08:05:00 +020015#include <common/h2.h>
16#include <common/hpack-tbl.h>
Willy Tarreaue4820742017-07-27 13:37:23 +020017#include <common/net_helper.h>
Willy Tarreau35dbd5d2017-09-22 09:13:49 +020018#include <proto/applet.h>
Willy Tarreau62f52692017-10-08 23:01:42 +020019#include <proto/connection.h>
Willy Tarreau3ccf4b22017-10-13 19:07:26 +020020#include <proto/h1.h>
Willy Tarreau62f52692017-10-08 23:01:42 +020021#include <proto/stream.h>
Willy Tarreau5ab6b572017-09-22 08:05:00 +020022#include <eb32tree.h>
Willy Tarreau62f52692017-10-08 23:01:42 +020023
24
Willy Tarreau2a856182017-05-16 15:20:39 +020025/* dummy streams returned for idle and closed states */
26static const struct h2s *h2_closed_stream;
27static const struct h2s *h2_idle_stream;
28
Willy Tarreau5ab6b572017-09-22 08:05:00 +020029/* the h2c connection pool */
30static struct pool_head *pool2_h2c;
Willy Tarreau18312642017-10-11 07:57:07 +020031/* the h2s stream pool */
32static struct pool_head *pool2_h2s;
Willy Tarreau5ab6b572017-09-22 08:05:00 +020033
34/* Connection flags (32 bit), in h2c->flags */
35#define H2_CF_NONE 0x00000000
36
Willy Tarreau2e5b60e2017-09-25 11:49:03 +020037/* Flags indicating why writing to the mux is blocked. */
38#define H2_CF_MUX_MALLOC 0x00000001 // mux blocked on lack of connection's mux buffer
39#define H2_CF_MUX_MFULL 0x00000002 // mux blocked on connection's mux buffer full
40#define H2_CF_MUX_BLOCK_ANY 0x00000003 // aggregate of the mux flags above
41
42/* Flags indicating why writing to the demux is blocked. */
43#define H2_CF_DEM_DALLOC 0x00000004 // demux blocked on lack of connection's demux buffer
44#define H2_CF_DEM_DFULL 0x00000008 // demux blocked on connection's demux buffer full
45#define H2_CF_DEM_MBUSY 0x00000010 // demux blocked on connection's mux side busy
46#define H2_CF_DEM_MROOM 0x00000020 // demux blocked on lack of room in mux buffer
47#define H2_CF_DEM_SALLOC 0x00000040 // demux blocked on lack of stream's request buffer
48#define H2_CF_DEM_SFULL 0x00000080 // demux blocked on stream request buffer full
49#define H2_CF_DEM_BLOCK_ANY 0x000000FC // aggregate of the demux flags above
50
Willy Tarreau081d4722017-05-16 21:51:05 +020051/* other flags */
52#define H2_CF_GOAWAY_SENT 0x00000100 // a GOAWAY frame was successfully sent
53#define H2_CF_GOAWAY_FAILED 0x00000200 // a GOAWAY frame failed to be sent
54
55
Willy Tarreau5ab6b572017-09-22 08:05:00 +020056/* H2 connection state, in h2c->st0 */
57enum h2_cs {
58 H2_CS_PREFACE, // init done, waiting for connection preface
59 H2_CS_SETTINGS1, // preface OK, waiting for first settings frame
60 H2_CS_FRAME_H, // first settings frame ok, waiting for frame header
61 H2_CS_FRAME_P, // frame header OK, waiting for frame payload
62 H2_CS_FRAME_A, // frame payload OK, trying to send ACK/RST frame
63 H2_CS_ERROR, // send GOAWAY(errcode) and close the connection ASAP
64 H2_CS_ERROR2, // GOAWAY(errcode) sent, close the connection ASAP
65 H2_CS_ENTRIES // must be last
66} __attribute__((packed));
67
68/* H2 connection descriptor */
69struct h2c {
70 struct connection *conn;
71
72 enum h2_cs st0; /* mux state */
73 enum h2_err errcode; /* H2 err code (H2_ERR_*) */
74
75 /* 16 bit hole here */
76 uint32_t flags; /* connection flags: H2_CF_* */
77 int32_t max_id; /* highest ID known on this connection, <0 before preface */
78 uint32_t rcvd_c; /* newly received data to ACK for the connection */
79 uint32_t rcvd_s; /* newly received data to ACK for the current stream (dsi) */
80
81 /* states for the demux direction */
82 struct hpack_dht *ddht; /* demux dynamic header table */
83 struct buffer *dbuf; /* demux buffer */
84
85 int32_t dsi; /* demux stream ID (<0 = idle) */
86 int32_t dfl; /* demux frame length (if dsi >= 0) */
87 int8_t dft; /* demux frame type (if dsi >= 0) */
88 int8_t dff; /* demux frame flags (if dsi >= 0) */
89 /* 16 bit hole here */
90 int32_t last_sid; /* last processed stream ID for GOAWAY, <0 before preface */
91
92 /* states for the mux direction */
93 struct buffer *mbuf; /* mux buffer */
94 int32_t msi; /* mux stream ID (<0 = idle) */
95 int32_t mfl; /* mux frame length (if dsi >= 0) */
96 int8_t mft; /* mux frame type (if dsi >= 0) */
97 int8_t mff; /* mux frame flags (if dsi >= 0) */
98 /* 16 bit hole here */
99 int32_t miw; /* mux initial window size for all new streams */
100 int32_t mws; /* mux window size. Can be negative. */
101 int32_t mfs; /* mux's max frame size */
102
103 struct eb_root streams_by_id; /* all active streams by their ID */
104 struct list send_list; /* list of blocked streams requesting to send */
105 struct list fctl_list; /* list of streams blocked by connection's fctl */
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200106 struct buffer_wait dbuf_wait; /* wait list for demux buffer allocation */
Willy Tarreau14398122017-09-22 14:26:04 +0200107 struct buffer_wait mbuf_wait; /* wait list for mux buffer allocation */
Willy Tarreau5ab6b572017-09-22 08:05:00 +0200108};
109
Willy Tarreau18312642017-10-11 07:57:07 +0200110/* H2 stream state, in h2s->st */
111enum h2_ss {
112 H2_SS_IDLE = 0, // idle
113 H2_SS_RLOC, // reserved(local)
114 H2_SS_RREM, // reserved(remote)
115 H2_SS_OPEN, // open
116 H2_SS_HREM, // half-closed(remote)
117 H2_SS_HLOC, // half-closed(local)
Willy Tarreau96060ba2017-10-16 18:34:34 +0200118 H2_SS_ERROR, // an error needs to be sent using RST_STREAM
119 H2_SS_RESET, // closed after sending RST_STREAM
Willy Tarreau18312642017-10-11 07:57:07 +0200120 H2_SS_CLOSED, // closed
121 H2_SS_ENTRIES // must be last
122} __attribute__((packed));
123
124/* HTTP/2 stream flags (32 bit), in h2s->flags */
125#define H2_SF_NONE 0x00000000
126#define H2_SF_ES_RCVD 0x00000001
127#define H2_SF_ES_SENT 0x00000002
128
129#define H2_SF_RST_RCVD 0x00000004 // received RST_STREAM
130#define H2_SF_RST_SENT 0x00000008 // sent RST_STREAM
131
Willy Tarreau2e5b60e2017-09-25 11:49:03 +0200132/* stream flags indicating the reason the stream is blocked */
133#define H2_SF_BLK_MBUSY 0x00000010 // blocked waiting for mux access (transient)
134#define H2_SF_BLK_MROOM 0x00000020 // blocked waiting for room in the mux
135#define H2_SF_BLK_MFCTL 0x00000040 // blocked due to mux fctl
136#define H2_SF_BLK_SFCTL 0x00000080 // blocked due to stream fctl
137#define H2_SF_BLK_ANY 0x000000F0 // any of the reasons above
138
Willy Tarreau18312642017-10-11 07:57:07 +0200139/* H2 stream descriptor, describing the stream as it appears in the H2C, and as
140 * it is being processed in the internal HTTP representation (H1 for now).
141 */
142struct h2s {
143 struct conn_stream *cs;
144 struct h2c *h2c;
145 struct h1m req, res; /* request and response parser state for H1 */
146 struct eb32_node by_id; /* place in h2c's streams_by_id */
147 struct list list; /* position in active/blocked lists if blocked>0 */
148 int32_t id; /* stream ID */
149 uint32_t flags; /* H2_SF_* */
150 int mws; /* mux window size for this stream */
151 enum h2_err errcode; /* H2 err code (H2_ERR_*) */
152 enum h2_ss st;
153};
Willy Tarreau5ab6b572017-09-22 08:05:00 +0200154
Willy Tarreauc6405142017-09-21 20:23:50 +0200155/* descriptor for an h2 frame header */
156struct h2_fh {
157 uint32_t len; /* length, host order, 24 bits */
158 uint32_t sid; /* stream id, host order, 31 bits */
159 uint8_t ft; /* frame type */
160 uint8_t ff; /* frame flags */
161};
162
Willy Tarreaufe20e5b2017-07-27 11:42:14 +0200163/* a few settings from the global section */
164static int h2_settings_header_table_size = 4096; /* initial value */
Willy Tarreaue6baec02017-07-27 11:45:11 +0200165static int h2_settings_initial_window_size = 65535; /* initial value */
Willy Tarreau5242ef82017-07-27 11:47:28 +0200166static int h2_settings_max_concurrent_streams = 100;
Willy Tarreaufe20e5b2017-07-27 11:42:14 +0200167
Willy Tarreau2a856182017-05-16 15:20:39 +0200168/* a dmumy closed stream */
169static const struct h2s *h2_closed_stream = &(const struct h2s){
170 .cs = NULL,
171 .h2c = NULL,
172 .st = H2_SS_CLOSED,
173 .id = 0,
174};
175
176/* and a dummy idle stream for use with any unannounced stream */
177static const struct h2s *h2_idle_stream = &(const struct h2s){
178 .cs = NULL,
179 .h2c = NULL,
180 .st = H2_SS_IDLE,
181 .id = 0,
182};
183
Willy Tarreaufe20e5b2017-07-27 11:42:14 +0200184
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200185/*****************************************************/
186/* functions below are for dynamic buffer management */
187/*****************************************************/
188
189/* re-enables receiving on mux <target> after a buffer was allocated. It returns
190 * 1 if the allocation succeeds, in which case the connection is woken up, or 0
191 * if it's impossible to wake up and we prefer to be woken up later.
192 */
193static int h2_dbuf_available(void *target)
194{
195 struct h2c *h2c = target;
196
197 /* take the buffer now as we'll get scheduled waiting for ->wake() */
198 if (b_alloc_margin(&h2c->dbuf, 0)) {
Willy Tarreau1b62c5c2017-09-25 11:55:01 +0200199 h2c->flags &= ~H2_CF_DEM_DALLOC;
200 if (!(h2c->flags & H2_CF_DEM_BLOCK_ANY))
201 conn_xprt_want_recv(h2c->conn);
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200202 return 1;
203 }
204 return 0;
205}
206
207static inline struct buffer *h2_get_dbuf(struct h2c *h2c)
208{
209 struct buffer *buf = NULL;
210
211 if (likely(LIST_ISEMPTY(&h2c->dbuf_wait.list)) &&
212 unlikely((buf = b_alloc_margin(&h2c->dbuf, 0)) == NULL)) {
213 h2c->dbuf_wait.target = h2c->conn;
214 h2c->dbuf_wait.wakeup_cb = h2_dbuf_available;
215 SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
216 LIST_ADDQ(&buffer_wq, &h2c->dbuf_wait.list);
217 SPIN_UNLOCK(BUF_WQ_LOCK, &buffer_wq_lock);
218 __conn_xprt_stop_recv(h2c->conn);
219 }
220 return buf;
221}
222
223static inline void h2_release_dbuf(struct h2c *h2c)
224{
225 if (h2c->dbuf->size) {
226 b_free(&h2c->dbuf);
227 offer_buffers(h2c->dbuf_wait.target,
228 tasks_run_queue + applets_active_queue);
229 }
230}
231
Willy Tarreau14398122017-09-22 14:26:04 +0200232/* re-enables sending on mux <target> after a buffer was allocated. It returns
233 * 1 if the allocation succeeds, in which case the connection is woken up, or 0
234 * if it's impossible to wake up and we prefer to be woken up later.
235 */
236static int h2_mbuf_available(void *target)
237{
238 struct h2c *h2c = target;
239
240 /* take the buffer now as we'll get scheduled waiting for ->wake(). */
241 if (b_alloc_margin(&h2c->mbuf, 0)) {
Willy Tarreau1b62c5c2017-09-25 11:55:01 +0200242 if (h2c->flags & H2_CF_MUX_MALLOC) {
243 h2c->flags &= ~H2_CF_MUX_MALLOC;
244 if (!(h2c->flags & H2_CF_MUX_BLOCK_ANY))
245 conn_xprt_want_send(h2c->conn);
246 }
247
248 if (h2c->flags & H2_CF_DEM_MROOM) {
249 h2c->flags &= ~H2_CF_DEM_MROOM;
250 if (!(h2c->flags & H2_CF_DEM_BLOCK_ANY))
251 conn_xprt_want_recv(h2c->conn);
252 }
253
Willy Tarreau14398122017-09-22 14:26:04 +0200254 /* FIXME: we should in fact call something like h2_update_poll()
255 * now to recompte the polling. For now it will be enough like
256 * this.
257 */
Willy Tarreau14398122017-09-22 14:26:04 +0200258 return 1;
259 }
260 return 0;
261}
262
263static inline struct buffer *h2_get_mbuf(struct h2c *h2c)
264{
265 struct buffer *buf = NULL;
266
267 if (likely(LIST_ISEMPTY(&h2c->mbuf_wait.list)) &&
268 unlikely((buf = b_alloc_margin(&h2c->mbuf, 0)) == NULL)) {
269 h2c->mbuf_wait.target = h2c;
270 h2c->mbuf_wait.wakeup_cb = h2_mbuf_available;
271 SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
272 LIST_ADDQ(&buffer_wq, &h2c->mbuf_wait.list);
273 SPIN_UNLOCK(BUF_WQ_LOCK, &buffer_wq_lock);
274
275 /* FIXME: we should in fact only block the direction being
276 * currently used. For now it will be enough like this.
277 */
278 __conn_xprt_stop_send(h2c->conn);
279 __conn_xprt_stop_recv(h2c->conn);
280 }
281 return buf;
282}
283
284static inline void h2_release_mbuf(struct h2c *h2c)
285{
286 if (h2c->mbuf->size) {
287 b_free(&h2c->mbuf);
288 offer_buffers(h2c->mbuf_wait.target,
289 tasks_run_queue + applets_active_queue);
290 }
291}
292
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200293
Willy Tarreau62f52692017-10-08 23:01:42 +0200294/*****************************************************************/
295/* functions below are dedicated to the mux setup and management */
296/*****************************************************************/
297
Willy Tarreau32218eb2017-09-22 08:07:25 +0200298/* tries to initialize the inbound h2c mux. Returns < 0 in case of failure. */
299static int h2c_frt_init(struct connection *conn)
300{
301 struct h2c *h2c;
302
303 h2c = pool_alloc2(pool2_h2c);
304 if (!h2c)
305 goto fail;
306
307 h2c->ddht = hpack_dht_alloc(h2_settings_header_table_size);
308 if (!h2c->ddht)
309 goto fail;
310
311 /* Initialise the context. */
312 h2c->st0 = H2_CS_PREFACE;
313 h2c->conn = conn;
314 h2c->max_id = -1;
315 h2c->errcode = H2_ERR_NO_ERROR;
316 h2c->flags = H2_CF_NONE;
317 h2c->rcvd_c = 0;
318 h2c->rcvd_s = 0;
319
320 h2c->dbuf = &buf_empty;
321 h2c->dsi = -1;
322 h2c->msi = -1;
323 h2c->last_sid = -1;
324
325 h2c->mbuf = &buf_empty;
326 h2c->miw = 65535; /* mux initial window size */
327 h2c->mws = 65535; /* mux window size */
328 h2c->mfs = 16384; /* initial max frame size */
329 h2c->streams_by_id = EB_ROOT_UNIQUE;
330 LIST_INIT(&h2c->send_list);
331 LIST_INIT(&h2c->fctl_list);
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200332 LIST_INIT(&h2c->dbuf_wait.list);
Willy Tarreau14398122017-09-22 14:26:04 +0200333 LIST_INIT(&h2c->mbuf_wait.list);
Willy Tarreau32218eb2017-09-22 08:07:25 +0200334 conn->mux_ctx = h2c;
335
336 conn_xprt_want_recv(conn);
337 /* mux->wake will be called soon to complete the operation */
338 return 0;
339 fail:
340 pool_free2(pool2_h2c, h2c);
341 return -1;
342}
343
Willy Tarreau62f52692017-10-08 23:01:42 +0200344/* Initialize the mux once it's attached. For outgoing connections, the context
345 * is already initialized before installing the mux, so we detect incoming
346 * connections from the fact that the context is still NULL. Returns < 0 on
347 * error.
348 */
349static int h2_init(struct connection *conn)
350{
351 if (conn->mux_ctx) {
352 /* we don't support outgoing connections for now */
353 return -1;
354 }
355
Willy Tarreau32218eb2017-09-22 08:07:25 +0200356 return h2c_frt_init(conn);
Willy Tarreau62f52692017-10-08 23:01:42 +0200357}
358
Willy Tarreau2373acc2017-10-12 17:35:14 +0200359/* returns the stream associated with id <id> or NULL if not found */
360static inline struct h2s *h2c_st_by_id(struct h2c *h2c, int id)
361{
362 struct eb32_node *node;
363
Willy Tarreau2a856182017-05-16 15:20:39 +0200364 if (id > h2c->max_id)
365 return (struct h2s *)h2_idle_stream;
366
Willy Tarreau2373acc2017-10-12 17:35:14 +0200367 node = eb32_lookup(&h2c->streams_by_id, id);
368 if (!node)
Willy Tarreau2a856182017-05-16 15:20:39 +0200369 return (struct h2s *)h2_closed_stream;
Willy Tarreau2373acc2017-10-12 17:35:14 +0200370
371 return container_of(node, struct h2s, by_id);
372}
373
Willy Tarreau62f52692017-10-08 23:01:42 +0200374/* release function for a connection. This one should be called to free all
375 * resources allocated to the mux.
376 */
377static void h2_release(struct connection *conn)
378{
Willy Tarreau32218eb2017-09-22 08:07:25 +0200379 struct h2c *h2c = conn->mux_ctx;
380
381 LIST_DEL(&conn->list);
382
383 if (h2c) {
384 hpack_dht_free(h2c->ddht);
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200385 h2_release_dbuf(h2c);
386 SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
387 LIST_DEL(&h2c->dbuf_wait.list);
388 SPIN_UNLOCK(BUF_WQ_LOCK, &buffer_wq_lock);
Willy Tarreau14398122017-09-22 14:26:04 +0200389
390 h2_release_mbuf(h2c);
391 SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
392 LIST_DEL(&h2c->mbuf_wait.list);
393 SPIN_UNLOCK(BUF_WQ_LOCK, &buffer_wq_lock);
394
Willy Tarreau32218eb2017-09-22 08:07:25 +0200395 pool_free2(pool2_h2c, h2c);
396 }
397
398 conn->mux = NULL;
399 conn->mux_ctx = NULL;
400
401 conn_stop_tracking(conn);
402 conn_full_close(conn);
403 if (conn->destroy_cb)
404 conn->destroy_cb(conn);
405 conn_free(conn);
Willy Tarreau62f52692017-10-08 23:01:42 +0200406}
407
408
Willy Tarreau71681172017-10-23 14:39:06 +0200409/******************************************************/
410/* functions below are for the H2 protocol processing */
411/******************************************************/
412
413/* returns the stream if of stream <h2s> or 0 if <h2s> is NULL */
414static inline int h2s_id(const struct h2s *h2s)
415{
416 return h2s ? h2s->id : 0;
417}
418
Willy Tarreau5b5e6872017-09-25 16:17:25 +0200419/* returns true of the mux is currently busy as seen from stream <h2s> */
420static inline int h2c_mux_busy(const struct h2c *h2c, const struct h2s *h2s)
421{
422 if (h2c->msi < 0)
423 return 0;
424
425 if (h2c->msi == h2s_id(h2s))
426 return 0;
427
428 return 1;
429}
430
Willy Tarreau741d6df2017-10-17 08:00:59 +0200431/* marks an error on the connection */
432static inline void h2c_error(struct h2c *h2c, enum h2_err err)
433{
434 h2c->errcode = err;
435 h2c->st0 = H2_CS_ERROR;
436}
437
Willy Tarreau2e43f082017-10-17 08:03:59 +0200438/* marks an error on the stream */
439static inline void h2s_error(struct h2s *h2s, enum h2_err err)
440{
441 if (h2s->st > H2_SS_IDLE && h2s->st < H2_SS_ERROR) {
442 h2s->errcode = err;
443 h2s->st = H2_SS_ERROR;
444 if (h2s->cs)
445 h2s->cs->flags |= CS_FL_ERROR;
446 }
447}
448
Willy Tarreaue4820742017-07-27 13:37:23 +0200449/* writes the 24-bit frame size <len> at address <frame> */
450static inline void h2_set_frame_size(void *frame, uint32_t len)
451{
452 uint8_t *out = frame;
453
454 *out = len >> 16;
455 write_n16(out + 1, len);
456}
457
Willy Tarreau54c15062017-10-10 17:10:03 +0200458/* reads <bytes> bytes from buffer <b> starting at relative offset <o> from the
459 * current pointer, dealing with wrapping, and stores the result in <dst>. It's
460 * the caller's responsibility to verify that there are at least <bytes> bytes
461 * available in the buffer's input prior to calling this function.
462 */
463static inline void h2_get_buf_bytes(void *dst, size_t bytes,
464 const struct buffer *b, int o)
465{
466 readv_bytes(dst, bytes, b_ptr(b, o), b_end(b) - b_ptr(b, o), b->data);
467}
468
469static inline uint16_t h2_get_n16(const struct buffer *b, int o)
470{
471 return readv_n16(b_ptr(b, o), b_end(b) - b_ptr(b, o), b->data);
472}
473
474static inline uint32_t h2_get_n32(const struct buffer *b, int o)
475{
476 return readv_n32(b_ptr(b, o), b_end(b) - b_ptr(b, o), b->data);
477}
478
479static inline uint64_t h2_get_n64(const struct buffer *b, int o)
480{
481 return readv_n64(b_ptr(b, o), b_end(b) - b_ptr(b, o), b->data);
482}
483
484
Willy Tarreau715d5312017-07-11 15:20:24 +0200485/* Peeks an H2 frame header from buffer <b> into descriptor <h>. The algorithm
486 * is not obvious. It turns out that H2 headers are neither aligned nor do they
487 * use regular sizes. And to add to the trouble, the buffer may wrap so each
488 * byte read must be checked. The header is formed like this :
489 *
490 * b0 b1 b2 b3 b4 b5..b8
491 * +----------+---------+--------+----+----+----------------------+
492 * |len[23:16]|len[15:8]|len[7:0]|type|flag|sid[31:0] (big endian)|
493 * +----------+---------+--------+----+----+----------------------+
494 *
495 * Here we read a big-endian 64 bit word from h[1]. This way in a single read
496 * we get the sid properly aligned and ordered, and 16 bits of len properly
497 * ordered as well. The type and flags can be extracted using bit shifts from
498 * the word, and only one extra read is needed to fetch len[16:23].
499 * Returns zero if some bytes are missing, otherwise non-zero on success.
500 */
501static int h2_peek_frame_hdr(const struct buffer *b, struct h2_fh *h)
502{
503 uint64_t w;
504
505 if (b->i < 9)
506 return 0;
507
508 w = readv_n64(b_ptr(b,1), b_end(b) - b_ptr(b,1), b->data);
509 h->len = *b->p << 16;
510 h->sid = w & 0x7FFFFFFF; /* RFC7540#4.1: R bit must be ignored */
511 h->ff = w >> 32;
512 h->ft = w >> 40;
513 h->len += w >> 48;
514 return 1;
515}
516
517/* skip the next 9 bytes corresponding to the frame header possibly parsed by
518 * h2_peek_frame_hdr() above.
519 */
520static inline void h2_skip_frame_hdr(struct buffer *b)
521{
522 bi_del(b, 9);
523}
524
525/* same as above, automatically advances the buffer on success */
526static inline int h2_get_frame_hdr(struct buffer *b, struct h2_fh *h)
527{
528 int ret;
529
530 ret = h2_peek_frame_hdr(b, h);
531 if (ret > 0)
532 h2_skip_frame_hdr(b);
533 return ret;
534}
535
Willy Tarreau3ccf4b22017-10-13 19:07:26 +0200536/* creates a new stream <id> on the h2c connection and returns it, or NULL in
537 * case of memory allocation error.
538 */
539static struct h2s *h2c_stream_new(struct h2c *h2c, int id)
540{
541 struct conn_stream *cs;
542 struct h2s *h2s;
543
544 h2s = pool_alloc2(pool2_h2s);
545 if (!h2s)
546 goto out;
547
548 h2s->h2c = h2c;
549 h2s->mws = h2c->miw;
550 h2s->flags = H2_SF_NONE;
551 h2s->errcode = H2_ERR_NO_ERROR;
552 h2s->st = H2_SS_IDLE;
553 h1m_init(&h2s->req);
554 h1m_init(&h2s->res);
555 h2s->by_id.key = h2s->id = id;
556 h2c->max_id = id;
557 LIST_INIT(&h2s->list);
558
559 eb32_insert(&h2c->streams_by_id, &h2s->by_id);
560
561 cs = cs_new(h2c->conn);
562 if (!cs)
563 goto out_close;
564
565 h2s->cs = cs;
566 cs->ctx = h2s;
567
568 if (stream_create_from_cs(cs) < 0)
569 goto out_free_cs;
570
571 /* OK done, the stream lives its own life now */
572 return h2s;
573
574 out_free_cs:
575 cs_free(cs);
576 out_close:
577 eb32_delete(&h2s->by_id);
578 pool_free2(pool2_h2s, h2s);
579 h2s = NULL;
580 out:
581 return h2s;
582}
583
Willy Tarreau52eed752017-09-22 15:05:09 +0200584/* Try to receive a connection preface, then upon success try to send our
585 * preface which is a SETTINGS frame. Returns > 0 on success or zero on
586 * missing data. It may return an error in h2c.
587 */
588static int h2c_frt_recv_preface(struct h2c *h2c)
589{
590 int ret1;
591
592 ret1 = b_isteq(h2c->dbuf, 0, h2c->dbuf->i, ist(H2_CONN_PREFACE));
593
594 if (unlikely(ret1 <= 0)) {
595 if (ret1 < 0 || conn_xprt_read0_pending(h2c->conn))
596 h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
597 return 0;
598 }
599
600 bi_del(h2c->dbuf, ret1);
601
602 return ret1;
603}
604
Willy Tarreau081d4722017-05-16 21:51:05 +0200605/* try to send a GOAWAY frame on the connection to report an error or a graceful
606 * shutdown, with h2c->errcode as the error code. Returns > 0 on success or zero
607 * if nothing was done. It uses h2c->last_sid as the advertised ID, or copies it
608 * from h2c->max_id if it's not set yet (<0). In case of lack of room to write
609 * the message, it subscribes the requester (either <h2s> or <h2c>) to future
610 * notifications. It sets H2_CF_GOAWAY_SENT on success, and H2_CF_GOAWAY_FAILED
611 * on unrecoverable failure. It will not attempt to send one again in this last
612 * case so that it is safe to use h2c_error() to report such errors.
613 */
614static int h2c_send_goaway_error(struct h2c *h2c, struct h2s *h2s)
615{
616 struct buffer *res;
617 char str[17];
618 int ret;
619
620 if (h2c->flags & H2_CF_GOAWAY_FAILED)
621 return 1; // claim that it worked
622
623 if (h2c_mux_busy(h2c, h2s)) {
624 if (h2s)
625 h2s->flags |= H2_SF_BLK_MBUSY;
626 else
627 h2c->flags |= H2_CF_DEM_MBUSY;
628 return 0;
629 }
630
631 res = h2_get_mbuf(h2c);
632 if (!res) {
633 h2c->flags |= H2_CF_MUX_MALLOC;
634 if (h2s)
635 h2s->flags |= H2_SF_BLK_MROOM;
636 else
637 h2c->flags |= H2_CF_DEM_MROOM;
638 return 0;
639 }
640
641 /* len: 8, type: 7, flags: none, sid: 0 */
642 memcpy(str, "\x00\x00\x08\x07\x00\x00\x00\x00\x00", 9);
643
644 if (h2c->last_sid < 0)
645 h2c->last_sid = h2c->max_id;
646
647 write_n32(str + 9, h2c->last_sid);
648 write_n32(str + 13, h2c->errcode);
649 ret = bo_istput(res, ist2(str, 17));
650 if (unlikely(ret <= 0)) {
651 if (!ret) {
652 h2c->flags |= H2_CF_MUX_MFULL;
653 if (h2s)
654 h2s->flags |= H2_SF_BLK_MROOM;
655 else
656 h2c->flags |= H2_CF_DEM_MROOM;
657 return 0;
658 }
659 else {
660 /* we cannot report this error using GOAWAY, so we mark
661 * it and claim a success.
662 */
663 h2c_error(h2c, H2_ERR_INTERNAL_ERROR);
664 h2c->flags |= H2_CF_GOAWAY_FAILED;
665 return 1;
666 }
667 }
668 h2c->flags |= H2_CF_GOAWAY_SENT;
669 return ret;
670}
671
Willy Tarreaubc933932017-10-09 16:21:43 +0200672/* process Rx frames to be demultiplexed */
673static void h2_process_demux(struct h2c *h2c)
674{
Willy Tarreau081d4722017-05-16 21:51:05 +0200675 if (h2c->st0 >= H2_CS_ERROR)
676 return;
Willy Tarreau52eed752017-09-22 15:05:09 +0200677
678 if (unlikely(h2c->st0 < H2_CS_FRAME_H)) {
679 if (h2c->st0 == H2_CS_PREFACE) {
680 if (unlikely(h2c_frt_recv_preface(h2c) <= 0)) {
681 /* RFC7540#3.5: a GOAWAY frame MAY be omitted */
682 if (h2c->st0 == H2_CS_ERROR)
683 h2c->st0 = H2_CS_ERROR2;
684 goto fail;
685 }
686
687 h2c->max_id = 0;
688 h2c->st0 = H2_CS_SETTINGS1;
689 }
690 /* deal with SETTINGS here */
691 }
692 return;
693
694 fail:
695 /* we can go here on missing data, blocked response or error */
696 return;
Willy Tarreaubc933932017-10-09 16:21:43 +0200697}
698
699/* process Tx frames from streams to be multiplexed. Returns > 0 if it reached
700 * the end.
701 */
702static int h2_process_mux(struct h2c *h2c)
703{
Willy Tarreau081d4722017-05-16 21:51:05 +0200704 if (unlikely(h2c->st0 > H2_CS_ERROR)) {
705 if (h2c->st0 == H2_CS_ERROR) {
706 if (h2c->max_id >= 0) {
707 h2c_send_goaway_error(h2c, NULL);
708 if (h2c->flags & H2_CF_MUX_BLOCK_ANY)
709 return 0;
710 }
711
712 h2c->st0 = H2_CS_ERROR2; // sent (or failed hard) !
713 }
714 return 1;
715 }
Willy Tarreaubc933932017-10-09 16:21:43 +0200716 return 1;
717}
718
Willy Tarreau71681172017-10-23 14:39:06 +0200719
Willy Tarreau62f52692017-10-08 23:01:42 +0200720/*********************************************************/
721/* functions below are I/O callbacks from the connection */
722/*********************************************************/
723
724/* callback called on recv event by the connection handler */
725static void h2_recv(struct connection *conn)
726{
Willy Tarreaua2af5122017-10-09 11:56:46 +0200727 struct h2c *h2c = conn->mux_ctx;
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200728 struct buffer *buf;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200729 int max;
730
731 if (conn->flags & CO_FL_ERROR)
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200732 return;
733
734 if (h2c->flags & H2_CF_DEM_BLOCK_ANY)
735 return;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200736
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200737 buf = h2_get_dbuf(h2c);
Willy Tarreau1b62c5c2017-09-25 11:55:01 +0200738 if (!buf) {
739 h2c->flags |= H2_CF_DEM_DALLOC;
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200740 return;
Willy Tarreau1b62c5c2017-09-25 11:55:01 +0200741 }
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200742
Willy Tarreaua2af5122017-10-09 11:56:46 +0200743 /* note: buf->o == 0 */
744 max = buf->size - buf->i;
745 if (!max) {
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200746 h2c->flags |= H2_CF_DEM_DFULL;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200747 return;
748 }
749
750 conn->xprt->rcv_buf(conn, buf, max);
751 if (conn->flags & CO_FL_ERROR)
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200752 return;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200753
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200754 if (!buf->i) {
Willy Tarreau35dbd5d2017-09-22 09:13:49 +0200755 h2_release_dbuf(h2c);
Willy Tarreaua2af5122017-10-09 11:56:46 +0200756 return;
757 }
758
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200759 if (buf->i == buf->size)
760 h2c->flags |= H2_CF_DEM_DFULL;
761
Willy Tarreaubc933932017-10-09 16:21:43 +0200762 h2_process_demux(h2c);
Willy Tarreaua2af5122017-10-09 11:56:46 +0200763
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200764 /* after streams have been processed, we should have made some room */
Willy Tarreau081d4722017-05-16 21:51:05 +0200765 if (h2c->st0 >= H2_CS_ERROR)
766 buf->i = 0;
767
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200768 if (buf->i != buf->size)
769 h2c->flags &= ~H2_CF_DEM_DFULL;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200770 return;
Willy Tarreau62f52692017-10-08 23:01:42 +0200771}
772
773/* callback called on send event by the connection handler */
774static void h2_send(struct connection *conn)
775{
Willy Tarreaua2af5122017-10-09 11:56:46 +0200776 struct h2c *h2c = conn->mux_ctx;
Willy Tarreaubc933932017-10-09 16:21:43 +0200777 int done;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200778
779 if (conn->flags & CO_FL_ERROR)
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200780 return;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200781
782 if (conn->flags & (CO_FL_HANDSHAKE|CO_FL_WAIT_L4_CONN|CO_FL_WAIT_L6_CONN)) {
783 /* a handshake was requested */
784 return;
785 }
786
Willy Tarreaubc933932017-10-09 16:21:43 +0200787 /* This loop is quite simple : it tries to fill as much as it can from
788 * pending streams into the existing buffer until it's reportedly full
789 * or the end of send requests is reached. Then it tries to send this
790 * buffer's contents out, marks it not full if at least one byte could
791 * be sent, and tries again.
792 *
793 * The snd_buf() function normally takes a "flags" argument which may
794 * be made of a combination of CO_SFL_MSG_MORE to indicate that more
795 * data immediately comes and CO_SFL_STREAMER to indicate that the
796 * connection is streaming lots of data (used to increase TLS record
797 * size at the expense of latency). The former can be sent any time
798 * there's a buffer full flag, as it indicates at least one stream
799 * attempted to send and failed so there are pending data. An
800 * alternative would be to set it as long as there's an active stream
801 * but that would be problematic for ACKs until we have an absolute
802 * guarantee that all waiters have at least one byte to send. The
803 * latter should possibly not be set for now.
804 */
805
806 done = 0;
807 while (!done) {
808 unsigned int flags = 0;
809
810 /* fill as much as we can into the current buffer */
811 while (((h2c->flags & (H2_CF_MUX_MFULL|H2_CF_MUX_MALLOC)) == 0) && !done)
812 done = h2_process_mux(h2c);
813
814 if (conn->flags & CO_FL_ERROR)
815 break;
816
817 if (h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MBUSY | H2_CF_DEM_MROOM))
818 flags |= CO_SFL_MSG_MORE;
819
820 if (conn->xprt->snd_buf(conn, h2c->mbuf, flags) <= 0)
821 break;
822
823 /* wrote at least one byte, the buffer is not full anymore */
824 h2c->flags &= ~(H2_CF_MUX_MFULL | H2_CF_DEM_MROOM);
825 }
826
Willy Tarreaua2af5122017-10-09 11:56:46 +0200827 if (conn->flags & CO_FL_SOCK_WR_SH) {
828 /* output closed, nothing to send, clear the buffer to release it */
829 h2c->mbuf->o = 0;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200830 }
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200831}
Willy Tarreaua2af5122017-10-09 11:56:46 +0200832
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200833/* call the wake up function of all streams attached to the connection */
834static void h2_wake_all_streams(struct h2c *h2c)
835{
836 struct eb32_node *node;
837 struct h2s *h2s;
838 unsigned int flags = 0;
Willy Tarreau14398122017-09-22 14:26:04 +0200839
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200840 if (h2c->st0 >= H2_CS_ERROR || h2c->conn->flags & CO_FL_ERROR)
841 flags |= CS_FL_ERROR;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200842
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200843 if (conn_xprt_read0_pending(h2c->conn))
844 flags |= CS_FL_EOS;
Willy Tarreaua2af5122017-10-09 11:56:46 +0200845
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200846 node = eb32_first(&h2c->streams_by_id);
847 while (node) {
848 h2s = container_of(node, struct h2s, by_id);
849 node = eb32_next(node);
850 if (h2s->cs) {
851 h2s->cs->flags |= flags;
852 /* recv is used to force to detect CS_FL_EOS that wake()
853 * doesn't handle in the stream int code.
854 */
855 h2s->cs->data_cb->recv(h2s->cs);
856 h2s->cs->data_cb->wake(h2s->cs);
857 }
858 }
Willy Tarreau62f52692017-10-08 23:01:42 +0200859}
860
861/* callback called on any event by the connection handler.
862 * It applies changes and returns zero, or < 0 if it wants immediate
863 * destruction of the connection (which normally doesn not happen in h2).
864 */
865static int h2_wake(struct connection *conn)
866{
Willy Tarreaua2af5122017-10-09 11:56:46 +0200867 struct h2c *h2c = conn->mux_ctx;
868
Willy Tarreau26bd7612017-10-09 16:47:04 +0200869 if (conn->flags & CO_FL_ERROR || conn_xprt_read0_pending(conn) ||
Willy Tarreau29a98242017-10-31 06:59:15 +0100870 h2c->st0 == H2_CS_ERROR2 || h2c->flags & H2_CF_GOAWAY_FAILED ||
871 (eb_is_empty(&h2c->streams_by_id) && h2c->last_sid >= 0 &&
872 h2c->max_id >= h2c->last_sid)) {
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200873 h2_wake_all_streams(h2c);
874
875 if (eb_is_empty(&h2c->streams_by_id)) {
876 /* no more stream, kill the connection now */
877 h2_release(conn);
878 return -1;
879 }
880 else {
881 /* some streams still there, we need to signal them all and
882 * wait for their departure.
883 */
884 __conn_xprt_stop_recv(conn);
885 __conn_xprt_stop_send(conn);
886 return 0;
887 }
888 }
889
890 if (!h2c->dbuf->i)
891 h2_release_dbuf(h2c);
892
893 /* stop being notified of incoming data if we can't process them */
894 if (h2c->st0 >= H2_CS_ERROR ||
895 (h2c->flags & H2_CF_DEM_BLOCK_ANY) || conn_xprt_read0_pending(conn)) {
896 /* FIXME: we should clear a read timeout here */
897 __conn_xprt_stop_recv(conn);
898 }
899 else {
900 /* FIXME: we should (re-)arm a read timeout here */
901 __conn_xprt_want_recv(conn);
902 }
903
904 /* adjust output polling */
Willy Tarreau51606832017-10-17 15:30:07 +0200905 if (!(conn->flags & CO_FL_SOCK_WR_SH) &&
906 (h2c->st0 == H2_CS_ERROR ||
907 h2c->mbuf->o ||
908 (h2c->mws > 0 && !LIST_ISEMPTY(&h2c->fctl_list)) ||
909 (!(h2c->flags & H2_CF_MUX_BLOCK_ANY) && !LIST_ISEMPTY(&h2c->send_list)))) {
Willy Tarreaufbe3b4f2017-10-09 15:14:19 +0200910 /* FIXME: we should (re-)arm a send timeout here */
911 __conn_xprt_want_send(conn);
912 }
913 else {
914 /* FIXME: we should clear a send timeout here */
915 h2_release_mbuf(h2c);
916 __conn_xprt_stop_send(conn);
Willy Tarreaua2af5122017-10-09 11:56:46 +0200917 }
918
Willy Tarreau62f52692017-10-08 23:01:42 +0200919 return 0;
920}
921
922/*******************************************/
923/* functions below are used by the streams */
924/*******************************************/
925
926/*
927 * Attach a new stream to a connection
928 * (Used for outgoing connections)
929 */
930static struct conn_stream *h2_attach(struct connection *conn)
931{
932 return NULL;
933}
934
935/* callback used to update the mux's polling flags after changing a cs' status.
936 * The caller (cs_update_mux_polling) will take care of propagating any changes
937 * to the transport layer.
938 */
939static void h2_update_poll(struct conn_stream *cs)
940{
Willy Tarreau1d393222017-10-17 10:26:19 +0200941 struct h2s *h2s = cs->ctx;
942
943 if (!h2s)
944 return;
945
946 /* Note: the stream and stream-int code doesn't allow us to perform a
947 * synchronous send() here unfortunately, because this code is called
948 * as si_update() from the process_stream() context. This means that
949 * we have to queue the current cs and defer its processing after the
950 * connection's cs list is processed anyway.
951 */
952
953 if (cs->flags & CS_FL_DATA_WR_ENA) {
954 if (LIST_ISEMPTY(&h2s->list)) {
955 if (LIST_ISEMPTY(&h2s->h2c->send_list) &&
956 !h2s->h2c->mbuf->o && // not yet subscribed
957 !(cs->conn->flags & CO_FL_SOCK_WR_SH))
958 conn_xprt_want_send(cs->conn);
959 LIST_ADDQ(&h2s->h2c->send_list, &h2s->list);
960 }
961 }
962 else if (!LIST_ISEMPTY(&h2s->list)) {
963 LIST_DEL(&h2s->list);
964 LIST_INIT(&h2s->list);
965 h2s->flags &= ~(H2_SF_BLK_MBUSY | H2_SF_BLK_MROOM | H2_SF_BLK_MFCTL);
966 }
967
968 /* this can happen from within si_chk_snd() */
969 if (h2s->h2c->mbuf->o && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
970 conn_xprt_want_send(cs->conn);
Willy Tarreau62f52692017-10-08 23:01:42 +0200971}
972
973/*
974 * Detach the stream from the connection and possibly release the connection.
975 */
976static void h2_detach(struct conn_stream *cs)
977{
978}
979
980static void h2_shutr(struct conn_stream *cs, enum cs_shr_mode mode)
981{
982}
983
984static void h2_shutw(struct conn_stream *cs, enum cs_shw_mode mode)
985{
986}
987
988/*
989 * Called from the upper layer, to get more data
990 */
991static int h2_rcv_buf(struct conn_stream *cs, struct buffer *buf, int count)
992{
993 /* FIXME: not handled for now */
994 cs->flags |= CS_FL_ERROR;
995 return 0;
996}
997
998/* Called from the upper layer, to send data */
999static int h2_snd_buf(struct conn_stream *cs, struct buffer *buf, int flags)
1000{
1001 /* FIXME: not handled for now */
1002 cs->flags |= CS_FL_ERROR;
1003 return 0;
1004}
1005
1006
1007/*******************************************************/
1008/* functions below are dedicated to the config parsers */
1009/*******************************************************/
1010
Willy Tarreaufe20e5b2017-07-27 11:42:14 +02001011/* config parser for global "tune.h2.header-table-size" */
1012static int h2_parse_header_table_size(char **args, int section_type, struct proxy *curpx,
1013 struct proxy *defpx, const char *file, int line,
1014 char **err)
1015{
1016 if (too_many_args(1, args, err, NULL))
1017 return -1;
1018
1019 h2_settings_header_table_size = atoi(args[1]);
1020 if (h2_settings_header_table_size < 4096 || h2_settings_header_table_size > 65536) {
1021 memprintf(err, "'%s' expects a numeric value between 4096 and 65536.", args[0]);
1022 return -1;
1023 }
1024 return 0;
1025}
Willy Tarreau62f52692017-10-08 23:01:42 +02001026
Willy Tarreaue6baec02017-07-27 11:45:11 +02001027/* config parser for global "tune.h2.initial-window-size" */
1028static int h2_parse_initial_window_size(char **args, int section_type, struct proxy *curpx,
1029 struct proxy *defpx, const char *file, int line,
1030 char **err)
1031{
1032 if (too_many_args(1, args, err, NULL))
1033 return -1;
1034
1035 h2_settings_initial_window_size = atoi(args[1]);
1036 if (h2_settings_initial_window_size < 0) {
1037 memprintf(err, "'%s' expects a positive numeric value.", args[0]);
1038 return -1;
1039 }
1040 return 0;
1041}
1042
Willy Tarreau5242ef82017-07-27 11:47:28 +02001043/* config parser for global "tune.h2.max-concurrent-streams" */
1044static int h2_parse_max_concurrent_streams(char **args, int section_type, struct proxy *curpx,
1045 struct proxy *defpx, const char *file, int line,
1046 char **err)
1047{
1048 if (too_many_args(1, args, err, NULL))
1049 return -1;
1050
1051 h2_settings_max_concurrent_streams = atoi(args[1]);
1052 if (h2_settings_max_concurrent_streams < 0) {
1053 memprintf(err, "'%s' expects a positive numeric value.", args[0]);
1054 return -1;
1055 }
1056 return 0;
1057}
1058
Willy Tarreau62f52692017-10-08 23:01:42 +02001059
1060/****************************************/
1061/* MUX initialization and instanciation */
1062/***************************************/
1063
1064/* The mux operations */
1065const struct mux_ops h2_ops = {
1066 .init = h2_init,
1067 .recv = h2_recv,
1068 .send = h2_send,
1069 .wake = h2_wake,
1070 .update_poll = h2_update_poll,
1071 .rcv_buf = h2_rcv_buf,
1072 .snd_buf = h2_snd_buf,
1073 .attach = h2_attach,
1074 .detach = h2_detach,
1075 .shutr = h2_shutr,
1076 .shutw = h2_shutw,
1077 .release = h2_release,
1078 .name = "H2",
1079};
1080
1081/* ALPN selection : this mux registers ALPN tolen "h2" */
1082static struct alpn_mux_list alpn_mux_h2 =
1083 { .token = IST("h2"), .mode = ALPN_MODE_HTTP, .mux = &h2_ops };
1084
1085/* config keyword parsers */
1086static struct cfg_kw_list cfg_kws = {ILH, {
Willy Tarreaufe20e5b2017-07-27 11:42:14 +02001087 { CFG_GLOBAL, "tune.h2.header-table-size", h2_parse_header_table_size },
Willy Tarreaue6baec02017-07-27 11:45:11 +02001088 { CFG_GLOBAL, "tune.h2.initial-window-size", h2_parse_initial_window_size },
Willy Tarreau5242ef82017-07-27 11:47:28 +02001089 { CFG_GLOBAL, "tune.h2.max-concurrent-streams", h2_parse_max_concurrent_streams },
Willy Tarreau62f52692017-10-08 23:01:42 +02001090 { 0, NULL, NULL }
1091}};
1092
Willy Tarreau5ab6b572017-09-22 08:05:00 +02001093static void __h2_deinit(void)
1094{
Willy Tarreau18312642017-10-11 07:57:07 +02001095 pool_destroy2(pool2_h2s);
Willy Tarreau5ab6b572017-09-22 08:05:00 +02001096 pool_destroy2(pool2_h2c);
1097}
1098
Willy Tarreau62f52692017-10-08 23:01:42 +02001099__attribute__((constructor))
1100static void __h2_init(void)
1101{
1102 alpn_register_mux(&alpn_mux_h2);
1103 cfg_register_keywords(&cfg_kws);
Willy Tarreau5ab6b572017-09-22 08:05:00 +02001104 hap_register_post_deinit(__h2_deinit);
1105 pool2_h2c = create_pool("h2c", sizeof(struct h2c), MEM_F_SHARED);
Willy Tarreau18312642017-10-11 07:57:07 +02001106 pool2_h2s = create_pool("h2s", sizeof(struct h2s), MEM_F_SHARED);
Willy Tarreau62f52692017-10-08 23:01:42 +02001107}