QUIC: introduced QUIC buffers.

Buffers are used to hold frame data.  They have a fixed size and are reused
after being freed.
This commit is contained in:
Roman Arutyunyan 2020-12-01 19:11:01 +00:00
parent 0fdfd7f7fa
commit 73a64aa9eb
5 changed files with 381 additions and 146 deletions

2
README
View File

@ -237,7 +237,7 @@ Example configuration:
#define NGX_QUIC_DEBUG_PACKETS
#define NGX_QUIC_DEBUG_FRAMES
#define NGX_QUIC_DEBUG_FRAMES_ALLOC
#define NGX_QUIC_DEBUG_ALLOC
#define NGX_QUIC_DEBUG_CRYPTO
6. Contributing

View File

@ -143,7 +143,6 @@ typedef struct {
ngx_event_t push;
ngx_event_t pto;
ngx_event_t close;
ngx_queue_t free_frames;
ngx_msec_t last_cc;
ngx_msec_t latest_rtt;
@ -153,8 +152,12 @@ typedef struct {
ngx_uint_t pto_count;
#if (NGX_DEBUG)
ngx_queue_t free_frames;
ngx_chain_t *free_bufs;
#ifdef NGX_QUIC_DEBUG_ALLOC
ngx_uint_t nframes;
ngx_uint_t nbufs;
#endif
ngx_quic_streams_t streams;
@ -265,7 +268,7 @@ static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c);
static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c);
static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_ack_frame_t *f);
ngx_quic_header_t *pkt, ngx_quic_frame_t *f);
static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c,
ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max,
ngx_msec_t *send_time);
@ -361,7 +364,7 @@ static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c,
static size_t ngx_quic_max_stream_frame(ngx_quic_connection_t *qc);
static size_t ngx_quic_max_stream_flow(ngx_connection_t *c);
static void ngx_quic_stream_cleanup_handler(void *data);
static ngx_quic_frame_t *ngx_quic_alloc_frame(ngx_connection_t *c, size_t size);
static ngx_quic_frame_t *ngx_quic_alloc_frame(ngx_connection_t *c);
static void ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame);
static void ngx_quic_congestion_ack(ngx_connection_t *c,
@ -369,6 +372,13 @@ static void ngx_quic_congestion_ack(ngx_connection_t *c,
static void ngx_quic_congestion_lost(ngx_connection_t *c,
ngx_quic_frame_t *frame);
static ngx_chain_t *ngx_quic_alloc_buf(ngx_connection_t *c);
static void ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in);
static ngx_chain_t *ngx_quic_copy_buf(ngx_connection_t *c, u_char *data,
size_t len);
static ngx_chain_t *ngx_quic_copy_chain(ngx_connection_t *c, ngx_chain_t *in,
size_t limit);
static SSL_QUIC_METHOD quic_method = {
#if BORINGSSL_API_VERSION >= 10
@ -414,8 +424,14 @@ ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx)
p = ngx_slprintf(p, last, "ACK n:%ui delay:%uL ",
f->u.ack.range_count, f->u.ack.delay);
pos = f->u.ack.ranges_start;
end = f->u.ack.ranges_end;
if (f->data) {
pos = f->data->buf->pos;
end = f->data->buf->end;
} else {
pos = NULL;
end = NULL;
}
largest = f->u.ack.largest;
smallest = f->u.ack.largest - f->u.ack.first_range;
@ -507,8 +523,16 @@ ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx)
}
#ifdef NGX_QUIC_DEBUG_FRAMES
p = ngx_slprintf(p, last, " data len:%uL %*xs", f->u.stream.length,
(size_t) f->u.stream.length, f->u.stream.data);
{
ngx_chain_t *cl;
p = ngx_slprintf(p, last, " data:");
for (cl = f->data; cl; cl = cl->next) {
p = ngx_slprintf(p, last, "%*xs",
cl->buf->last - cl->buf->pos, cl->buf->pos);
}
}
#endif
break;
@ -885,18 +909,20 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
fsize = ngx_min(limit, (size_t) (end - p));
frame = ngx_quic_alloc_frame(c, fsize);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return 0;
}
ngx_memcpy(frame->data, p, fsize);
frame->data = ngx_quic_copy_buf(c, p, fsize);
if (frame->data == NGX_CHAIN_ERROR) {
return 0;
}
frame->level = level;
frame->type = NGX_QUIC_FT_CRYPTO;
frame->u.crypto.offset = fs->sent;
frame->u.crypto.length = fsize;
frame->u.crypto.data = frame->data;
fs->sent += fsize;
p += fsize;
@ -1870,15 +1896,6 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc)
ngx_delete_posted_event(&qc->push);
}
for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) {
ngx_quic_free_frames(c, &qc->crypto[i].frames);
}
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ngx_quic_free_frames(c, &qc->send_ctx[i].frames);
ngx_quic_free_frames(c, &qc->send_ctx[i].sent);
}
while (!ngx_queue_empty(&qc->server_ids)) {
q = ngx_queue_head(&qc->server_ids);
sid = ngx_queue_data(q, ngx_quic_server_id_t, queue);
@ -2438,7 +2455,9 @@ ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
{
u_char *end, *p;
ssize_t len;
ngx_buf_t buf;
ngx_uint_t do_close;
ngx_chain_t chain;
ngx_quic_frame_t frame;
ngx_quic_connection_t *qc;
@ -2472,6 +2491,12 @@ ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
c->log->action = "parsing frames";
ngx_memzero(&buf, sizeof(ngx_buf_t));
chain.buf = &buf;
chain.next = NULL;
frame.data = &chain;
len = ngx_quic_parse_frame(pkt, p, end, &frame);
if (len < 0) {
@ -2488,7 +2513,7 @@ ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
switch (frame.type) {
case NGX_QUIC_FT_ACK:
if (ngx_quic_handle_ack_frame(c, pkt, &frame.u.ack) != NGX_OK) {
if (ngx_quic_handle_ack_frame(c, pkt, &frame) != NGX_OK) {
return NGX_ERROR;
}
@ -2922,7 +2947,7 @@ ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
{
ngx_quic_frame_t *frame;
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -2999,10 +3024,11 @@ ngx_quic_drop_ack_ranges(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
static ngx_int_t
ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
{
u_char *p;
size_t ranges_len;
size_t len, left;
uint64_t ack_delay;
ngx_buf_t *b;
ngx_uint_t i;
ngx_chain_t *cl, **ll;
ngx_quic_frame_t *frame;
ngx_quic_connection_t *qc;
@ -3017,33 +3043,51 @@ ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
ack_delay = 0;
}
ranges_len = 0;
for (i = 0; i < ctx->nranges; i++) {
ranges_len += ngx_quic_create_ack_range(NULL, ctx->ranges[i].gap,
ctx->ranges[i].range);
}
frame = ngx_quic_alloc_frame(c, ranges_len);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
p = frame->data;
ll = &frame->data;
b = NULL;
for (i = 0; i < ctx->nranges; i++) {
p += ngx_quic_create_ack_range(p, ctx->ranges[i].gap,
ctx->ranges[i].range);
len = ngx_quic_create_ack_range(NULL, ctx->ranges[i].gap,
ctx->ranges[i].range);
left = b ? b->end - b->last : 0;
if (left < len) {
cl = ngx_quic_alloc_buf(c);
if (cl == NULL) {
return NGX_ERROR;
}
*ll = cl;
ll = &cl->next;
b = cl->buf;
left = b->end - b->last;
if (left < len) {
return NGX_ERROR;
}
}
b->last += ngx_quic_create_ack_range(b->last, ctx->ranges[i].gap,
ctx->ranges[i].range);
frame->u.ack.ranges_length += len;
}
*ll = NULL;
frame->level = ctx->level;
frame->type = NGX_QUIC_FT_ACK;
frame->u.ack.largest = ctx->largest_range;
frame->u.ack.delay = ack_delay;
frame->u.ack.range_count = ctx->nranges;
frame->u.ack.first_range = ctx->first_range;
frame->u.ack.ranges_start = frame->data;
frame->u.ack.ranges_end = frame->data + ranges_len;
ngx_quic_queue_frame(qc, frame);
@ -3077,7 +3121,7 @@ ngx_quic_send_cc(ngx_connection_t *c)
return NGX_OK;
}
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -3118,7 +3162,7 @@ ngx_quic_send_new_token(ngx_connection_t *c)
return NGX_ERROR;
}
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -3136,7 +3180,7 @@ ngx_quic_send_new_token(ngx_connection_t *c)
static ngx_int_t
ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_ack_frame_t *ack)
ngx_quic_frame_t *f)
{
ssize_t n;
u_char *pos, *end;
@ -3144,6 +3188,7 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_msec_t send_time;
ngx_uint_t i;
ngx_quic_send_ctx_t *ctx;
ngx_quic_ack_frame_t *ack;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
@ -3153,6 +3198,8 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_handle_ack_frame level:%d", pkt->level);
ack = &f->u.ack;
/*
* If any computed packet number is negative, an endpoint MUST
* generate a connection error of type FRAME_ENCODING_ERROR.
@ -3194,8 +3241,14 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
}
}
pos = ack->ranges_start;
end = ack->ranges_end;
if (f->data) {
pos = f->data->buf->pos;
end = f->data->buf->last;
} else {
pos = NULL;
end = NULL;
}
for (i = 0; i < ack->range_count; i++) {
@ -3537,7 +3590,9 @@ static ngx_int_t
ngx_quic_adjust_frame_offset(ngx_connection_t *c, ngx_quic_frame_t *frame,
uint64_t offset_in)
{
size_t tail;
size_t tail, n;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_quic_ordered_frame_t *f;
f = &frame->u.ord;
@ -3558,9 +3613,21 @@ ngx_quic_adjust_frame_offset(ngx_connection_t *c, ngx_quic_frame_t *frame,
/* intersecting range: adjust data size */
f->offset += tail;
f->data += tail;
f->length -= tail;
for (cl = frame->data; cl; cl = cl->next) {
b = cl->buf;
n = ngx_buf_size(b);
if (n >= tail) {
b->pos += tail;
break;
}
cl->buf->pos = cl->buf->last;
tail -= n;
}
return NGX_OK;
}
@ -3569,7 +3636,6 @@ static ngx_int_t
ngx_quic_buffer_frame(ngx_connection_t *c, ngx_quic_frames_stream_t *fs,
ngx_quic_frame_t *frame)
{
u_char *data;
ngx_queue_t *q;
ngx_quic_frame_t *dst, *item;
ngx_quic_ordered_frame_t *f, *df;
@ -3581,19 +3647,19 @@ ngx_quic_buffer_frame(ngx_connection_t *c, ngx_quic_frames_stream_t *fs,
/* frame start offset is in the future, buffer it */
dst = ngx_quic_alloc_frame(c, f->length);
dst = ngx_quic_alloc_frame(c);
if (dst == NULL) {
return NGX_ERROR;
}
data = dst->data;
ngx_memcpy(dst, frame, sizeof(ngx_quic_frame_t));
dst->data = data;
ngx_memcpy(dst->data, f->data, f->length);
dst->data = ngx_quic_copy_chain(c, frame->data, 0);
if (dst->data == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
df = &dst->u.ord;
df->data = dst->data;
fs->total += f->length;
@ -3671,15 +3737,14 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
static ngx_int_t
ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
{
int n, sslerr;
ngx_ssl_conn_t *ssl_conn;
ngx_quic_connection_t *qc;
ngx_quic_crypto_frame_t *f;
int n, sslerr;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_ssl_conn_t *ssl_conn;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
f = &frame->u.crypto;
ssl_conn = c->ssl->connection;
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
@ -3687,12 +3752,16 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
(int) SSL_quic_read_level(ssl_conn),
(int) SSL_quic_write_level(ssl_conn));
if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn),
f->data, f->length))
{
ngx_ssl_error(NGX_LOG_INFO, c->log, 0,
"SSL_provide_quic_data() failed");
return NGX_ERROR;
for (cl = frame->data; cl; cl = cl->next) {
b = cl->buf;
if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn),
b->pos, b->last - b->pos))
{
ngx_ssl_error(NGX_LOG_INFO, c->log, 0,
"SSL_provide_quic_data() failed");
return NGX_ERROR;
}
}
n = SSL_do_handshake(ssl_conn);
@ -3730,7 +3799,7 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
c->ssl->handshaked = 1;
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -3858,6 +3927,7 @@ ngx_quic_stream_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
uint64_t id;
ngx_buf_t *b;
ngx_event_t *rev;
ngx_chain_t *cl;
ngx_quic_stream_t *sn;
ngx_quic_connection_t *qc;
ngx_quic_stream_frame_t *f;
@ -3881,7 +3951,10 @@ ngx_quic_stream_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
b->pos = b->start;
}
b->last = ngx_cpymem(b->last, f->data, f->length);
for (cl = frame->data; cl; cl = cl->next) {
b->last = ngx_cpymem(b->last, cl->buf->pos,
cl->buf->last - cl->buf->pos);
}
rev = sn->c->read;
rev->ready = 1;
@ -3992,7 +4065,7 @@ ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c,
n = sn->fs.received + (b->pos - b->start) + (b->end - b->last);
}
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -4215,7 +4288,7 @@ ngx_quic_handle_path_challenge_frame(ngx_connection_t *c,
qc = ngx_quic_get_connection(c);
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -4381,7 +4454,7 @@ ngx_quic_retire_connection_id(ngx_connection_t *c,
qc = ngx_quic_get_connection(c);
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -4455,7 +4528,7 @@ ngx_quic_issue_server_ids(ngx_connection_t *c)
return NGX_ERROR;
}
frame = ngx_quic_alloc_frame(c, 0);
frame = ngx_quic_alloc_frame(c);
if (frame == NULL) {
return NGX_ERROR;
}
@ -5634,7 +5707,7 @@ ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size)
qs->id, len, size);
if (!rev->pending_eof) {
frame = ngx_quic_alloc_frame(pc, 0);
frame = ngx_quic_alloc_frame(pc);
if (frame == NULL) {
return NGX_ERROR;
}
@ -5650,7 +5723,7 @@ ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size)
if ((qc->streams.recv_max_data / 2) < qc->streams.received) {
frame = ngx_quic_alloc_frame(pc, 0);
frame = ngx_quic_alloc_frame(pc);
if (frame == NULL) {
return NGX_ERROR;
@ -5703,13 +5776,9 @@ ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, size_t size)
static ngx_chain_t *
ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
{
u_char *p;
size_t n, max, max_frame, max_flow, max_limit, len;
size_t n, max, max_frame, max_flow, max_limit;
#if (NGX_DEBUG)
size_t sent;
#endif
ngx_buf_t *b;
#if (NGX_DEBUG)
ngx_uint_t nframes;
#endif
ngx_event_t *wev;
@ -5763,7 +5832,7 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
break;
}
frame = ngx_quic_alloc_frame(pc, n);
frame = ngx_quic_alloc_frame(pc);
if (frame == NULL) {
return NGX_CHAIN_ERROR;
}
@ -5778,7 +5847,6 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
frame->u.stream.stream_id = qs->id;
frame->u.stream.offset = c->sent;
frame->u.stream.length = n;
frame->u.stream.data = frame->data;
c->sent += n;
qc->streams.sent += n;
@ -5793,18 +5861,9 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
nframes++;
#endif
for (p = frame->data; n > 0; cl = cl->next) {
b = cl->buf;
if (!ngx_buf_in_memory(b)) {
continue;
}
len = ngx_min(n, (size_t) (b->last - b->pos));
p = ngx_cpymem(p, b->pos, len);
b->pos += len;
n -= len;
frame->data = ngx_quic_copy_chain(pc, cl, n);
if (frame->data == NGX_CHAIN_ERROR) {
return NGX_CHAIN_ERROR;
}
ngx_quic_queue_frame(qc, frame);
@ -5916,7 +5975,7 @@ ngx_quic_stream_cleanup_handler(void *data)
|| (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0)
{
if (!c->read->pending_eof && !c->read->error) {
frame = ngx_quic_alloc_frame(pc, 0);
frame = ngx_quic_alloc_frame(pc);
if (frame == NULL) {
return;
}
@ -5931,7 +5990,7 @@ ngx_quic_stream_cleanup_handler(void *data)
}
if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) {
frame = ngx_quic_alloc_frame(pc, 0);
frame = ngx_quic_alloc_frame(pc);
if (frame == NULL) {
return;
}
@ -5959,7 +6018,7 @@ ngx_quic_stream_cleanup_handler(void *data)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic stream id:0x%xL send fin", qs->id);
frame = ngx_quic_alloc_frame(pc, 0);
frame = ngx_quic_alloc_frame(pc);
if (frame == NULL) {
return;
}
@ -5974,7 +6033,6 @@ ngx_quic_stream_cleanup_handler(void *data)
frame->u.stream.stream_id = qs->id;
frame->u.stream.offset = c->sent;
frame->u.stream.length = 0;
frame->u.stream.data = NULL;
ngx_quic_queue_frame(qc, frame);
@ -5983,23 +6041,12 @@ ngx_quic_stream_cleanup_handler(void *data)
static ngx_quic_frame_t *
ngx_quic_alloc_frame(ngx_connection_t *c, size_t size)
ngx_quic_alloc_frame(ngx_connection_t *c)
{
u_char *p;
ngx_queue_t *q;
ngx_quic_frame_t *frame;
ngx_quic_connection_t *qc;
if (size) {
p = ngx_alloc(size, c->log);
if (p == NULL) {
return NULL;
}
} else {
p = NULL;
}
qc = ngx_quic_get_connection(c);
if (!ngx_queue_empty(&qc->free_frames)) {
@ -6009,7 +6056,7 @@ ngx_quic_alloc_frame(ngx_connection_t *c, size_t size)
ngx_queue_remove(&frame->queue);
#ifdef NGX_QUIC_DEBUG_FRAMES_ALLOC
#ifdef NGX_QUIC_DEBUG_ALLOC
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic reuse frame n:%ui", qc->nframes);
#endif
@ -6017,15 +6064,12 @@ ngx_quic_alloc_frame(ngx_connection_t *c, size_t size)
} else {
frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t));
if (frame == NULL) {
ngx_free(p);
return NULL;
}
#if (NGX_DEBUG)
#ifdef NGX_QUIC_DEBUG_ALLOC
++qc->nframes;
#endif
#ifdef NGX_QUIC_DEBUG_FRAMES_ALLOC
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic alloc frame n:%ui", qc->nframes);
#endif
@ -6033,8 +6077,6 @@ ngx_quic_alloc_frame(ngx_connection_t *c, size_t size)
ngx_memzero(frame, sizeof(ngx_quic_frame_t));
frame->data = p;
return frame;
}
@ -6140,13 +6182,12 @@ ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame)
qc = ngx_quic_get_connection(c);
if (frame->data) {
ngx_free(frame->data);
frame->data = NULL;
ngx_quic_free_bufs(c, frame->data);
}
ngx_queue_insert_head(&qc->free_frames, &frame->queue);
#ifdef NGX_QUIC_DEBUG_FRAMES_ALLOC
#ifdef NGX_QUIC_DEBUG_ALLOC
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic free frame n:%ui", qc->nframes);
#endif
@ -6165,3 +6206,170 @@ ngx_quic_version(ngx_connection_t *c)
return (version & 0xff000000) == 0xff000000 ? version & 0xff : version;
}
static ngx_chain_t *
ngx_quic_alloc_buf(ngx_connection_t *c)
{
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
if (qc->free_bufs) {
cl = qc->free_bufs;
qc->free_bufs = cl->next;
b = cl->buf;
b->pos = b->start;
b->last = b->start;
#ifdef NGX_QUIC_DEBUG_ALLOC
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic reuse buffer n:%ui", qc->nbufs);
#endif
return cl;
}
cl = ngx_alloc_chain_link(c->pool);
if (cl == NULL) {
return NULL;
}
b = ngx_create_temp_buf(c->pool, NGX_QUIC_BUFFER_SIZE);
if (b == NULL) {
return NULL;
}
b->tag = (ngx_buf_tag_t) &ngx_quic_alloc_buf;
cl->buf = b;
#ifdef NGX_QUIC_DEBUG_ALLOC
++qc->nbufs;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic alloc buffer n:%ui", qc->nbufs);
#endif
return cl;
}
static void
ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in)
{
ngx_chain_t *cl;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
while (in) {
#ifdef NGX_QUIC_DEBUG_ALLOC
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic free buffer n:%ui", qc->nbufs);
#endif
cl = in;
in = in->next;
cl->next = qc->free_bufs;
qc->free_bufs = cl;
}
}
static ngx_chain_t *
ngx_quic_copy_buf(ngx_connection_t *c, u_char *data, size_t len)
{
size_t n;
ngx_buf_t *b;
ngx_chain_t *cl, *out, **ll;
out = NULL;
ll = &out;
while (len) {
cl = ngx_quic_alloc_buf(c);
if (cl == NULL) {
return NGX_CHAIN_ERROR;
}
b = cl->buf;
n = ngx_min((size_t) (b->end - b->last), len);
b->last = ngx_cpymem(b->last, data, n);
data += n;
len -= n;
*ll = cl;
ll = &cl->next;
}
*ll = NULL;
return out;
}
static ngx_chain_t *
ngx_quic_copy_chain(ngx_connection_t *c, ngx_chain_t *in, size_t limit)
{
size_t n;
ngx_buf_t *b;
ngx_chain_t *cl, *out, **ll;
out = NULL;
ll = &out;
while (in) {
if (!ngx_buf_in_memory(in->buf) || ngx_buf_size(in->buf) == 0) {
in = in->next;
continue;
}
cl = ngx_quic_alloc_buf(c);
if (cl == NULL) {
return NGX_CHAIN_ERROR;
}
*ll = cl;
ll = &cl->next;
b = cl->buf;
while (in && b->last != b->end) {
n = ngx_min(in->buf->last - in->buf->pos, b->end - b->last);
if (limit > 0 && n > limit) {
n = limit;
}
b->last = ngx_cpymem(b->last, in->buf->pos, n);
in->buf->pos += n;
if (in->buf->pos == in->buf->last) {
in = in->next;
}
if (limit > 0) {
if (limit == n) {
goto done;
}
limit -= n;
}
}
}
done:
*ll = NULL;
return out;
}

View File

@ -61,6 +61,8 @@
#define NGX_QUIC_MAX_SERVER_IDS 8
#define NGX_QUIC_BUFFER_SIZE 4096
#define ngx_quic_get_connection(c) ((ngx_quic_connection_t *)(c)->udp)
@ -135,7 +137,7 @@ ngx_int_t ngx_quic_get_packet_dcid(ngx_log_t *log, u_char *data, size_t len,
/* #define NGX_QUIC_DEBUG_PACKETS */ /* dump packet contents */
/* #define NGX_QUIC_DEBUG_FRAMES */ /* dump frames contents */
/* #define NGX_QUIC_DEBUG_FRAMES_ALLOC */ /* log frames alloc/reuse/free */
/* #define NGX_QUIC_DEBUG_ALLOC */ /* log frames and bufs alloc */
/* #define NGX_QUIC_DEBUG_CRYPTO */
#endif /* _NGX_EVENT_QUIC_H_INCLUDED_ */

View File

@ -87,15 +87,17 @@ static size_t ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out,
static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt,
ngx_uint_t frame_type);
static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack);
static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack,
ngx_chain_t *ranges);
static size_t ngx_quic_create_stop_sending(u_char *p,
ngx_quic_stop_sending_frame_t *ss);
static size_t ngx_quic_create_crypto(u_char *p,
ngx_quic_crypto_frame_t *crypto);
ngx_quic_crypto_frame_t *crypto, ngx_chain_t *data);
static size_t ngx_quic_create_hs_done(u_char *p);
static size_t ngx_quic_create_new_token(u_char *p,
ngx_quic_new_token_frame_t *token);
static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf);
static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf,
ngx_chain_t *data);
static size_t ngx_quic_create_max_streams(u_char *p,
ngx_quic_max_streams_frame_t *ms);
static size_t ngx_quic_create_max_stream_data(u_char *p,
@ -703,8 +705,11 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
{
u_char *p;
uint64_t varint;
ngx_buf_t *b;
ngx_uint_t i;
b = f->data->buf;
p = start;
p = ngx_quic_parse_int(p, end, &varint);
@ -736,11 +741,13 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
goto error;
}
p = ngx_quic_read_bytes(p, end, f->u.crypto.length, &f->u.crypto.data);
p = ngx_quic_read_bytes(p, end, f->u.crypto.length, &b->pos);
if (p == NULL) {
goto error;
}
b->last = p;
break;
case NGX_QUIC_FT_PADDING:
@ -762,7 +769,7 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
goto error;
}
f->u.ack.ranges_start = p;
b->pos = p;
/* process all ranges to get bounds, values are ignored */
for (i = 0; i < f->u.ack.range_count; i++) {
@ -777,7 +784,9 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
}
}
f->u.ack.ranges_end = p;
b->last = p;
f->u.ack.ranges_length = b->last - b->pos;
if (f->type == NGX_QUIC_FT_ACK_ECN) {
@ -914,12 +923,12 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
f->u.stream.length = end - p; /* up to packet end */
}
p = ngx_quic_read_bytes(p, end, f->u.stream.length,
&f->u.stream.data);
p = ngx_quic_read_bytes(p, end, f->u.stream.length, &b->pos);
if (p == NULL) {
goto error;
}
b->last = p;
break;
case NGX_QUIC_FT_MAX_DATA:
@ -1192,13 +1201,13 @@ ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
switch (f->type) {
case NGX_QUIC_FT_ACK:
f->need_ack = 0;
return ngx_quic_create_ack(p, &f->u.ack);
return ngx_quic_create_ack(p, &f->u.ack, f->data);
case NGX_QUIC_FT_STOP_SENDING:
return ngx_quic_create_stop_sending(p, &f->u.stop_sending);
case NGX_QUIC_FT_CRYPTO:
return ngx_quic_create_crypto(p, &f->u.crypto);
return ngx_quic_create_crypto(p, &f->u.crypto, f->data);
case NGX_QUIC_FT_HANDSHAKE_DONE:
return ngx_quic_create_hs_done(p);
@ -1214,7 +1223,7 @@ ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
case NGX_QUIC_FT_STREAM5:
case NGX_QUIC_FT_STREAM6:
case NGX_QUIC_FT_STREAM7:
return ngx_quic_create_stream(p, &f->u.stream);
return ngx_quic_create_stream(p, &f->u.stream, f->data);
case NGX_QUIC_FT_CONNECTION_CLOSE:
case NGX_QUIC_FT_CONNECTION_CLOSE_APP:
@ -1247,10 +1256,11 @@ ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
static size_t
ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack)
ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack, ngx_chain_t *ranges)
{
size_t len;
u_char *start;
size_t len;
u_char *start;
ngx_buf_t *b;
if (p == NULL) {
len = ngx_quic_varint_len(NGX_QUIC_FT_ACK);
@ -1258,7 +1268,7 @@ ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack)
len += ngx_quic_varint_len(ack->delay);
len += ngx_quic_varint_len(ack->range_count);
len += ngx_quic_varint_len(ack->first_range);
len += ack->ranges_end - ack->ranges_start;
len += ack->ranges_length;
return len;
}
@ -1270,7 +1280,12 @@ ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack)
ngx_quic_build_int(&p, ack->delay);
ngx_quic_build_int(&p, ack->range_count);
ngx_quic_build_int(&p, ack->first_range);
p = ngx_cpymem(p, ack->ranges_start, ack->ranges_end - ack->ranges_start);
while (ranges) {
b = ranges->buf;
p = ngx_cpymem(p, b->pos, b->last - b->pos);
ranges = ranges->next;
}
return p - start;
}
@ -1300,10 +1315,12 @@ ngx_quic_create_stop_sending(u_char *p, ngx_quic_stop_sending_frame_t *ss)
static size_t
ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto)
ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto,
ngx_chain_t *data)
{
size_t len;
u_char *start;
size_t len;
u_char *start;
ngx_buf_t *b;
if (p == NULL) {
len = ngx_quic_varint_len(NGX_QUIC_FT_CRYPTO);
@ -1319,7 +1336,12 @@ ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto)
ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO);
ngx_quic_build_int(&p, crypto->offset);
ngx_quic_build_int(&p, crypto->length);
p = ngx_cpymem(p, crypto->data, crypto->length);
while (data) {
b = data->buf;
p = ngx_cpymem(p, b->pos, b->last - b->pos);
data = data->next;
}
return p - start;
}
@ -1367,10 +1389,12 @@ ngx_quic_create_new_token(u_char *p, ngx_quic_new_token_frame_t *token)
static size_t
ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf)
ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf,
ngx_chain_t *data)
{
size_t len;
u_char *start;
size_t len;
u_char *start;
ngx_buf_t *b;
if (p == NULL) {
len = ngx_quic_varint_len(sf->type);
@ -1401,7 +1425,11 @@ ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf)
/* length is always present in generated frames */
ngx_quic_build_int(&p, sf->length);
p = ngx_cpymem(p, sf->data, sf->length);
while (data) {
b = data->buf;
p = ngx_cpymem(p, b->pos, b->last - b->pos);
data = data->next;
}
return p - start;
}

View File

@ -144,8 +144,7 @@ typedef struct {
uint64_t ect0;
uint64_t ect1;
uint64_t ce;
u_char *ranges_start;
u_char *ranges_end;
uint64_t ranges_length;
} ngx_quic_ack_frame_t;
@ -171,7 +170,6 @@ typedef struct {
typedef struct {
uint64_t offset;
uint64_t length;
u_char *data;
} ngx_quic_ordered_frame_t;
typedef ngx_quic_ordered_frame_t ngx_quic_crypto_frame_t;
@ -181,7 +179,6 @@ typedef struct {
/* initial fields same as in ngx_quic_ordered_frame_t */
uint64_t offset;
uint64_t length;
u_char *data;
uint8_t type;
uint64_t stream_id;
@ -270,7 +267,7 @@ struct ngx_quic_frame_s {
ngx_uint_t need_ack;
/* unsigned need_ack:1; */
u_char *data;
ngx_chain_t *data;
union {
ngx_quic_ack_frame_t ack;
ngx_quic_crypto_frame_t crypto;