comparison src/event/ngx_event_quic.c @ 7674:4ae9ac69ab93 quic

HTTP/QUIC interface reworked. - events handling moved into src/event/ngx_event_quic.c - http invokes once ngx_quic_run() and passes stream callback (diff to original http_request.c is now minimal) - streams are stored in rbtree using ID as a key - when a new stream is registered, appropriate callback is called - ngx_quic_stream_t type represents STREAM and stored in c->qs
author Vladimir Homutov <vl@nginx.com>
date Thu, 12 Mar 2020 16:54:43 +0300
parents cc8d211cb45c
children 36fe31ce9582
comparison
equal deleted inserted replaced
7673:cc8d211cb45c 7674:4ae9ac69ab93
4 */ 4 */
5 5
6 6
7 #include <ngx_config.h> 7 #include <ngx_config.h>
8 #include <ngx_core.h> 8 #include <ngx_core.h>
9 #include <ngx_event.h>
9 10
10 11
11 #define quic_version 0xff000018 12 #define quic_version 0xff000018
12 13
13 #define NGX_AES_128_GCM_SHA256 0x1301 14 #define NGX_AES_128_GCM_SHA256 0x1301
226 ngx_quic_secret_t client_hs; 227 ngx_quic_secret_t client_hs;
227 ngx_quic_secret_t client_ad; 228 ngx_quic_secret_t client_ad;
228 ngx_quic_secret_t server_in; 229 ngx_quic_secret_t server_in;
229 ngx_quic_secret_t server_hs; 230 ngx_quic_secret_t server_hs;
230 ngx_quic_secret_t server_ad; 231 ngx_quic_secret_t server_ad;
232
233 /* streams */
234 ngx_rbtree_t stree;
235 ngx_rbtree_node_t stree_sentinel;
236 ngx_msec_t stream_timeout;
237 ngx_connection_handler_pt stream_handler;
231 }; 238 };
239
240
241 typedef struct {
242 ngx_rbtree_node_t node;
243 ngx_buf_t *b;
244 ngx_connection_t *c;
245 ngx_quic_stream_t s;
246 } ngx_quic_stream_node_t;
232 247
233 248
234 typedef struct { 249 typedef struct {
235 ngx_quic_secret_t *secret; 250 ngx_quic_secret_t *secret;
236 ngx_uint_t type; 251 ngx_uint_t type;
257 } ngx_quic_header_t; 272 } ngx_quic_header_t;
258 273
259 274
260 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, 275 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
261 ngx_quic_header_t *pkt); 276 ngx_quic_header_t *pkt);
262 277 static void ngx_quic_close_connection(ngx_connection_t *c);
278
279 static ngx_quic_stream_node_t *ngx_quic_stream_lookup(ngx_rbtree_t *rbtree,
280 ngx_uint_t key);
281 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp,
282 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
283
284 static void ngx_quic_handshake_handler(ngx_event_t *rev);
263 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, 285 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c,
264 ngx_quic_header_t *pkt); 286 ngx_quic_header_t *pkt);
265 static ngx_int_t ngx_quic_app_input(ngx_connection_t *c, 287 static ngx_int_t ngx_quic_app_input(ngx_connection_t *c,
266 ngx_quic_header_t *pkt); 288 ngx_quic_header_t *pkt);
267 289
346 { 368 {
347 SSL_CTX_set_quic_method(ctx, &quic_method); 369 SSL_CTX_set_quic_method(ctx, &quic_method);
348 } 370 }
349 371
350 372
351 ngx_int_t 373 void
352 ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) 374 ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_msec_t timeout,
353 { 375 ngx_connection_handler_pt handler)
354 u_char *p; 376 {
377 ngx_buf_t *b;
355 ngx_quic_header_t pkt; 378 ngx_quic_header_t pkt;
356 379
380 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic handshake");
381
382 c->log->action = "QUIC handshaking";
383
357 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); 384 ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
385
386 b = c->buffer;
358 387
359 pkt.raw = b; 388 pkt.raw = b;
360 pkt.data = b->start; 389 pkt.data = b->start;
361 pkt.len = b->last - b->start; 390 pkt.len = b->last - b->start;
362 391
392 if (ngx_quic_new_connection(c, ssl, &pkt) != NGX_OK) {
393 ngx_quic_close_connection(c);
394 return;
395 }
396
397 // we don't need stream handler for initial packet processing
398 c->quic->stream_handler = handler;
399 c->quic->stream_timeout = timeout;
400
401 ngx_add_timer(c->read, timeout);
402
403 c->read->handler = ngx_quic_handshake_handler;
404
405 return;
406 }
407
408
409 static void
410 ngx_quic_handshake_handler(ngx_event_t *rev)
411 {
412 ssize_t n;
413 ngx_connection_t *c;
414 u_char buf[512];
415 ngx_buf_t b;
416
417 b.start = buf;
418 b.end = buf + 512;
419 b.pos = b.last = b.start;
420
421 c = rev->data;
422
423 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, rev->log, 0, "quic handshake handler");
424
425 if (rev->timedout) {
426 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
427 ngx_quic_close_connection(c);
428 return;
429 }
430
431 if (c->close) {
432 ngx_quic_close_connection(c);
433 return;
434 }
435
436 n = c->recv(c, b.start, b.end - b.start);
437
438 if (n == NGX_AGAIN) {
439 return;
440 }
441
442 if (n == NGX_ERROR) {
443 c->read->eof = 1;
444 ngx_quic_close_connection(c);
445 return;
446 }
447
448 b.last += n;
449
450 if (ngx_quic_input(c, NULL, &b) != NGX_OK) {
451 ngx_quic_close_connection(c);
452 return;
453 }
454 }
455
456
457 static void
458 ngx_quic_close_connection(ngx_connection_t *c)
459 {
460 ngx_pool_t *pool;
461
462 /* XXX wait for all streams to close */
463
464 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
465 "close quic connection: %d", c->fd);
466
467 (void) ngx_ssl_shutdown(c);
468
469 #if (NGX_STAT_STUB)
470 (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
471 #endif
472
473 c->destroyed = 1;
474
475 pool = c->pool;
476
477 ngx_close_connection(c);
478
479 ngx_destroy_pool(pool);
480 }
481
482
483 ngx_connection_t *
484 ngx_quic_create_uni_stream(ngx_connection_t *c)
485 {
486 /* XXX */
487 return NULL;
488 }
489
490
491 ngx_int_t
492 ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
493 {
494 u_char *p;
495 ngx_quic_header_t pkt;
496
363 if (c->quic == NULL) { 497 if (c->quic == NULL) {
364 return ngx_quic_new_connection(c, ssl, &pkt); 498 // XXX: possible?
499 ngx_log_error(NGX_LOG_INFO, c->log, 0, "BUG: no QUIC in connection");
500 return NGX_ERROR;
365 } 501 }
366 502
367 p = b->start; 503 p = b->start;
368 504
369 do { 505 do {
1647 1783
1648 /* process all payload from the current packet and generate ack if required */ 1784 /* process all payload from the current packet and generate ack if required */
1649 static ngx_int_t 1785 static ngx_int_t
1650 ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt) 1786 ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
1651 { 1787 {
1652 u_char *end, *p; 1788 u_char *end, *p;
1653 ssize_t len; 1789 ssize_t len;
1654 ngx_uint_t ack_this; 1790 ngx_buf_t *b;
1655 ngx_quic_frame_t frame, *ack_frame; 1791 ngx_uint_t ack_this;
1656 ngx_quic_connection_t *qc; 1792 ngx_quic_frame_t frame, *ack_frame;
1793 ngx_quic_connection_t *qc;
1794 ngx_quic_stream_node_t *sn;
1657 1795
1658 qc = c->quic; 1796 qc = c->quic;
1659 1797
1660 p = pkt->payload.data; 1798 p = pkt->payload.data;
1661 end = p + pkt->payload.len; 1799 end = p + pkt->payload.len;
1733 frame.type, 1871 frame.type,
1734 frame.u.stream.stream_id, 1872 frame.u.stream.stream_id,
1735 frame.u.stream.offset, 1873 frame.u.stream.offset,
1736 frame.u.stream.length); 1874 frame.u.stream.length);
1737 1875
1876
1877 sn = ngx_quic_stream_lookup(&qc->stree, frame.u.stream.stream_id);
1878 if (sn == NULL) {
1879 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "stream is new");
1880
1881 sn = ngx_pcalloc(c->pool, sizeof(ngx_quic_stream_node_t));
1882 if (sn == NULL) {
1883 return NGX_ERROR;
1884 }
1885
1886 sn->c = ngx_get_connection(-1, c->log); // TODO: free on connection termination
1887 if (sn->c == NULL) {
1888 return NGX_ERROR;
1889 }
1890
1891 sn->node.key = frame.u.stream.stream_id;
1892 sn->b = ngx_create_temp_buf(c->pool, 16 * 1024); // XXX enough for everyone
1893 if (sn->b == NULL) {
1894 return NGX_ERROR;
1895 }
1896 b = sn->b;
1897
1898 ngx_memcpy(b->start, frame.u.stream.data, frame.u.stream.length);
1899 b->last = b->start + frame.u.stream.length;
1900
1901 ngx_rbtree_insert(&qc->stree, &sn->node);
1902
1903 sn->s.id = frame.u.stream.stream_id;
1904 sn->s.parent = c;
1905 sn->c->qs = &sn->s;
1906
1907 qc->stream_handler(sn->c);
1908
1909 } else {
1910 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "existing stream");
1911 b = sn->b;
1912
1913 if ((size_t) (b->end - b->pos) < frame.u.stream.length) {
1914 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1915 "no space in stream buffer");
1916 return NGX_ERROR;
1917 }
1918
1919 ngx_memcpy(b->pos, frame.u.stream.data, frame.u.stream.length);
1920 b->pos += frame.u.stream.length;
1921
1922 // TODO: ngx_post_event(&c->read, &ngx_posted_events) ???
1923 }
1924
1738 ngx_quic_hexdump0(c->log, "STREAM.data", 1925 ngx_quic_hexdump0(c->log, "STREAM.data",
1739 frame.u.stream.data, frame.u.stream.length); 1926 frame.u.stream.data, frame.u.stream.length);
1740 break; 1927 break;
1741 1928
1742 default: 1929 default:
1775 1962
1776 return ngx_quic_output(c); 1963 return ngx_quic_output(c);
1777 } 1964 }
1778 1965
1779 1966
1967 static void
1968 ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp,
1969 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1970 {
1971 ngx_rbtree_node_t **p;
1972 ngx_quic_stream_node_t *qn, *qnt;
1973
1974 for ( ;; ) {
1975
1976 if (node->key < temp->key) {
1977
1978 p = &temp->left;
1979
1980 } else if (node->key > temp->key) {
1981
1982 p = &temp->right;
1983
1984 } else { /* node->key == temp->key */
1985
1986 qn = (ngx_quic_stream_node_t *) &node->color;
1987 qnt = (ngx_quic_stream_node_t *) &temp->color;
1988
1989 if (qn->c < qnt->c) {
1990 p = &temp->left;
1991 } else {
1992 p = &temp->right;
1993 }
1994 }
1995
1996 if (*p == sentinel) {
1997 break;
1998 }
1999
2000 temp = *p;
2001 }
2002
2003 *p = node;
2004 node->parent = temp;
2005 node->left = sentinel;
2006 node->right = sentinel;
2007 ngx_rbt_red(node);
2008 }
2009
2010
2011 static ngx_quic_stream_node_t *
2012 ngx_quic_stream_lookup(ngx_rbtree_t *rbtree, ngx_uint_t key)
2013 {
2014 ngx_rbtree_node_t *node, *sentinel;
2015
2016 node = rbtree->root;
2017 sentinel = rbtree->sentinel;
2018
2019 while (node != sentinel) {
2020
2021 if (key == node->key) {
2022 return (ngx_quic_stream_node_t *) node;
2023 }
2024
2025 node = (key < node->key) ? node->left : node->right;
2026 }
2027
2028 return NULL;
2029 }
2030
2031
1780 static ngx_int_t 2032 static ngx_int_t
1781 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, 2033 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
1782 ngx_quic_header_t *pkt) 2034 ngx_quic_header_t *pkt)
1783 { 2035 {
1784 ngx_quic_connection_t *qc; 2036 ngx_quic_connection_t *qc;
1804 2056
1805 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); 2057 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
1806 if (qc == NULL) { 2058 if (qc == NULL) {
1807 return NGX_ERROR; 2059 return NGX_ERROR;
1808 } 2060 }
2061
2062 ngx_rbtree_init(&qc->stree, &qc->stree_sentinel,
2063 ngx_quic_rbtree_insert_stream);
1809 2064
1810 c->quic = qc; 2065 c->quic = qc;
1811 qc->ssl = ssl; 2066 qc->ssl = ssl;
1812 2067
1813 qc->dcid.len = pkt->dcid.len; 2068 qc->dcid.len = pkt->dcid.len;