comparison src/event/ngx_event_quic.c @ 7748:4cf00c14f11a quic

Safe QUIC stream creation.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 25 Mar 2020 12:56:21 +0300
parents 618a65de08b3
children 2935a11c55b6
comparison
equal deleted inserted replaced
7747:618a65de08b3 7748:4cf00c14f11a
12 typedef enum { 12 typedef enum {
13 NGX_QUIC_ST_INITIAL, /* connection just created */ 13 NGX_QUIC_ST_INITIAL, /* connection just created */
14 NGX_QUIC_ST_HANDSHAKE, /* handshake started */ 14 NGX_QUIC_ST_HANDSHAKE, /* handshake started */
15 NGX_QUIC_ST_APPLICATION /* handshake complete */ 15 NGX_QUIC_ST_APPLICATION /* handshake complete */
16 } ngx_quic_state_t; 16 } ngx_quic_state_t;
17
18
19 #define NGX_QUIC_STREAM_BUFSIZE 16384
20 17
21 18
22 typedef struct { 19 typedef struct {
23 ngx_rbtree_t tree; 20 ngx_rbtree_t tree;
24 ngx_rbtree_node_t sentinel; 21 ngx_rbtree_node_t sentinel;
120 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, 117 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp,
121 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); 118 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
122 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree, 119 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree,
123 ngx_uint_t key); 120 ngx_uint_t key);
124 static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c, 121 static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c,
125 ngx_uint_t id); 122 uint64_t id, size_t rcvbuf_size);
126 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, 123 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf,
127 size_t size); 124 size_t size);
128 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, 125 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf,
129 size_t size); 126 size_t size);
130 static void ngx_quic_stream_cleanup_handler(void *data); 127 static void ngx_quic_stream_cleanup_handler(void *data);
1094 1091
1095 static ngx_int_t 1092 static ngx_int_t
1096 ngx_quic_handle_stream_frame(ngx_connection_t *c, 1093 ngx_quic_handle_stream_frame(ngx_connection_t *c,
1097 ngx_quic_header_t *pkt, ngx_quic_stream_frame_t *f) 1094 ngx_quic_header_t *pkt, ngx_quic_stream_frame_t *f)
1098 { 1095 {
1096 size_t n;
1099 ngx_buf_t *b; 1097 ngx_buf_t *b;
1100 ngx_event_t *rev; 1098 ngx_event_t *rev;
1101 ngx_quic_stream_t *sn; 1099 ngx_quic_stream_t *sn;
1102 ngx_quic_connection_t *qc; 1100 ngx_quic_connection_t *qc;
1103 1101
1135 return NGX_OK; 1133 return NGX_OK;
1136 } 1134 }
1137 1135
1138 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "stream is new"); 1136 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "stream is new");
1139 1137
1140 sn = ngx_quic_create_stream(c, f->stream_id); 1138 n = (f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL)
1139 ? qc->tp.initial_max_stream_data_uni
1140 : qc->tp.initial_max_stream_data_bidi_remote;
1141
1142 if (n < NGX_QUIC_STREAM_BUFSIZE) {
1143 n = NGX_QUIC_STREAM_BUFSIZE;
1144 }
1145
1146 if (n < f->length) {
1147 ngx_log_error(NGX_LOG_INFO, c->log, 0, "no space in stream buffer");
1148 return NGX_ERROR;
1149 }
1150
1151 sn = ngx_quic_create_stream(c, f->stream_id, n);
1141 if (sn == NULL) { 1152 if (sn == NULL) {
1142 return NGX_ERROR; 1153 return NGX_ERROR;
1143 } 1154 }
1144 1155
1145 b = sn->b; 1156 b = sn->b;
1146 1157 b->last = ngx_cpymem(b->last, f->data, f->length);
1147 ngx_memcpy(b->start, f->data, f->length); 1158
1148 b->last = b->start + f->length; 1159 sn->c->read->ready = 1;
1149 1160
1150 qc->streams.handler(sn->c); 1161 qc->streams.handler(sn->c);
1151 1162
1152 return NGX_OK; 1163 return NGX_OK;
1153 } 1164 }
1417 "creating server uni stream #%ui id %ui", 1428 "creating server uni stream #%ui id %ui",
1418 qc->streams.id_counter, id); 1429 qc->streams.id_counter, id);
1419 1430
1420 qc->streams.id_counter++; 1431 qc->streams.id_counter++;
1421 1432
1422 sn = ngx_quic_create_stream(qs->parent, id); 1433 sn = ngx_quic_create_stream(qs->parent, id, 0);
1423 if (sn == NULL) { 1434 if (sn == NULL) {
1424 return NULL; 1435 return NULL;
1425 } 1436 }
1426 1437
1427 return sn->c; 1438 return sn->c;
1492 return NULL; 1503 return NULL;
1493 } 1504 }
1494 1505
1495 1506
1496 static ngx_quic_stream_t * 1507 static ngx_quic_stream_t *
1497 ngx_quic_create_stream(ngx_connection_t *c, ngx_uint_t id) 1508 ngx_quic_create_stream(ngx_connection_t *c, uint64_t id, size_t rcvbuf_size)
1498 { 1509 {
1499 size_t n; 1510 ngx_log_t *log;
1500 ngx_log_t *log; 1511 ngx_pool_t *pool;
1501 ngx_pool_t *pool; 1512 ngx_quic_stream_t *sn;
1502 ngx_event_t *rev, *wev; 1513 ngx_pool_cleanup_t *cln;
1503 ngx_quic_stream_t *sn;
1504 ngx_pool_cleanup_t *cln;
1505 ngx_quic_connection_t *qc;
1506
1507 qc = c->quic;
1508
1509 sn = ngx_pcalloc(c->pool, sizeof(ngx_quic_stream_t));
1510 if (sn == NULL) {
1511 return NULL;
1512 }
1513
1514 sn->c = ngx_get_connection(-1, c->log); // TODO: free on connection termination
1515 if (sn->c == NULL) {
1516 return NULL;
1517 }
1518 1514
1519 pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, c->log); 1515 pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, c->log);
1520 if (pool == NULL) { 1516 if (pool == NULL) {
1521 /* XXX free connection */ 1517 return NULL;
1522 // TODO: add pool cleanup handdler 1518 }
1519
1520 sn = ngx_pcalloc(pool, sizeof(ngx_quic_stream_t));
1521 if (sn == NULL) {
1522 ngx_destroy_pool(pool);
1523 return NULL;
1524 }
1525
1526 sn->node.key = id;
1527 sn->parent = c;
1528 sn->id = id;
1529
1530 sn->b = ngx_create_temp_buf(pool, rcvbuf_size);
1531 if (sn->b == NULL) {
1532 ngx_destroy_pool(pool);
1523 return NULL; 1533 return NULL;
1524 } 1534 }
1525 1535
1526 log = ngx_palloc(pool, sizeof(ngx_log_t)); 1536 log = ngx_palloc(pool, sizeof(ngx_log_t));
1527 if (log == NULL) { 1537 if (log == NULL) {
1528 /* XXX free pool and connection */ 1538 ngx_destroy_pool(pool);
1529 return NULL; 1539 return NULL;
1530 } 1540 }
1531 1541
1532 *log = *c->log; 1542 *log = *c->log;
1533 pool->log = log; 1543 pool->log = log;
1534 1544
1535 sn->c->log = log; 1545 sn->c = ngx_get_connection(-1, log);
1546 if (sn->c == NULL) {
1547 ngx_destroy_pool(pool);
1548 return NULL;
1549 }
1550
1551 sn->c->qs = sn;
1536 sn->c->pool = pool; 1552 sn->c->pool = pool;
1537 1553 sn->c->ssl = c->ssl;
1554 sn->c->sockaddr = c->sockaddr;
1538 sn->c->listening = c->listening; 1555 sn->c->listening = c->listening;
1539 sn->c->sockaddr = c->sockaddr; 1556 sn->c->addr_text = c->addr_text;
1540 sn->c->local_sockaddr = c->local_sockaddr; 1557 sn->c->local_sockaddr = c->local_sockaddr;
1541 sn->c->addr_text = c->addr_text;
1542 sn->c->ssl = c->ssl;
1543
1544 rev = sn->c->read;
1545 wev = sn->c->write;
1546
1547 rev->ready = 1;
1548
1549 rev->log = c->log;
1550 wev->log = c->log;
1551
1552 sn->c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); 1558 sn->c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
1553
1554 n = ngx_max(NGX_QUIC_STREAM_BUFSIZE,
1555 qc->tp.initial_max_stream_data_bidi_remote);
1556
1557 sn->node.key =id;
1558 sn->b = ngx_create_temp_buf(pool, n);
1559 if (sn->b == NULL) {
1560 return NULL;
1561 }
1562
1563 ngx_rbtree_insert(&qc->streams.tree, &sn->node);
1564
1565 sn->id = id;
1566 sn->parent = c;
1567 sn->c->qs = sn;
1568 1559
1569 sn->c->recv = ngx_quic_stream_recv; 1560 sn->c->recv = ngx_quic_stream_recv;
1570 sn->c->send = ngx_quic_stream_send; 1561 sn->c->send = ngx_quic_stream_send;
1571 sn->c->send_chain = ngx_quic_stream_send_chain; 1562 sn->c->send_chain = ngx_quic_stream_send_chain;
1563
1564 sn->c->read->log = c->log;
1565 sn->c->write->log = c->log;
1572 1566
1573 cln = ngx_pool_cleanup_add(pool, 0); 1567 cln = ngx_pool_cleanup_add(pool, 0);
1574 if (cln == NULL) { 1568 if (cln == NULL) {
1575 ngx_close_connection(sn->c); 1569 ngx_close_connection(sn->c);
1576 ngx_destroy_pool(pool); 1570 ngx_destroy_pool(pool);
1578 } 1572 }
1579 1573
1580 cln->handler = ngx_quic_stream_cleanup_handler; 1574 cln->handler = ngx_quic_stream_cleanup_handler;
1581 cln->data = sn->c; 1575 cln->data = sn->c;
1582 1576
1577 ngx_rbtree_insert(&c->quic->streams.tree, &sn->node);
1578
1583 return sn; 1579 return sn;
1584 } 1580 }
1585 1581
1586 1582
1587 static ssize_t 1583 static ssize_t