Mercurial > hg > nginx-quic
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; |