QUIC: ngx_quic_buffer_t object.

The object is used instead of ngx_chain_t pointer for buffer operations like
ngx_quic_write_chain() and ngx_quic_read_chain().  These functions are renamed
to ngx_quic_write_buffer() and ngx_quic_read_buffer().
This commit is contained in:
Roman Arutyunyan 2022-02-14 15:27:59 +03:00
parent 28919d3e59
commit 8363d84edd
7 changed files with 129 additions and 103 deletions

View File

@ -1077,7 +1077,7 @@ ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level)
ctx = ngx_quic_get_send_ctx(qc, level);
ngx_quic_free_chain(c, ctx->crypto);
ngx_quic_free_buffer(c, &ctx->crypto);
while (!ngx_queue_empty(&ctx->sent)) {
q = ngx_queue_head(&ctx->sent);

View File

@ -48,6 +48,13 @@ typedef enum {
} ngx_quic_stream_recv_state_e;
typedef struct {
uint64_t size;
uint64_t offset;
ngx_chain_t *chain;
} ngx_quic_buffer_t;
typedef struct {
ngx_ssl_t *ssl;
@ -84,13 +91,12 @@ struct ngx_quic_stream_s {
uint64_t recv_offset;
uint64_t recv_window;
uint64_t recv_last;
uint64_t recv_size;
uint64_t recv_final_size;
ngx_chain_t *in;
ngx_chain_t *out;
ngx_uint_t cancelable; /* unsigned cancelable:1; */
ngx_quic_buffer_t send;
ngx_quic_buffer_t recv;
ngx_quic_stream_send_state_e send_state;
ngx_quic_stream_recv_state_e recv_state;
ngx_uint_t cancelable; /* unsigned cancelable:1; */
};

View File

@ -160,8 +160,7 @@ typedef struct {
struct ngx_quic_send_ctx_s {
enum ssl_encryption_level_t level;
ngx_chain_t *crypto;
uint64_t crypto_received;
ngx_quic_buffer_t crypto;
uint64_t crypto_sent;
uint64_t pnum; /* to be sent */

View File

@ -340,6 +340,7 @@ ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, size_t len)
{
size_t shrink;
ngx_quic_frame_t *nf;
ngx_quic_buffer_t qb;
ngx_quic_ordered_frame_t *of, *onf;
switch (f->type) {
@ -375,6 +376,14 @@ ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, size_t len)
return NGX_ERROR;
}
ngx_memzero(&qb, sizeof(ngx_quic_buffer_t));
qb.chain = f->data;
f->data = ngx_quic_read_buffer(c, &qb, of->length);
if (f->data == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
nf = ngx_quic_alloc_frame(c);
if (nf == NULL) {
return NGX_ERROR;
@ -385,11 +394,7 @@ ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, size_t len)
onf->offset += of->length;
onf->length = shrink;
nf->len = ngx_quic_create_frame(NULL, nf);
f->data = ngx_quic_read_chain(c, &nf->data, of->length);
if (f->data == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
nf->data = qb.chain;
if (f->type == NGX_QUIC_FT_STREAM) {
f->u.stream.fin = 0;
@ -402,13 +407,13 @@ ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, size_t len)
ngx_chain_t *
ngx_quic_read_chain(ngx_connection_t *c, ngx_chain_t **chain, off_t limit)
ngx_quic_read_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, uint64_t limit)
{
off_t n;
uint64_t n;
ngx_buf_t *b;
ngx_chain_t *out, **ll;
out = *chain;
out = qb->chain;
for (ll = &out; *ll; ll = &(*ll)->next) {
b = (*ll)->buf;
@ -433,15 +438,53 @@ ngx_quic_read_chain(ngx_connection_t *c, ngx_chain_t **chain, off_t limit)
}
limit -= n;
qb->offset += n;
}
*chain = *ll;
qb->chain = *ll;
*ll = NULL;
return out;
}
void
ngx_quic_skip_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
uint64_t offset)
{
size_t n;
ngx_buf_t *b;
ngx_chain_t *cl;
while (qb->chain) {
if (qb->offset >= offset) {
break;
}
cl = qb->chain;
b = cl->buf;
n = b->last - b->pos;
if (qb->offset + n > offset) {
n = offset - qb->offset;
b->pos += n;
qb->offset += n;
break;
}
qb->offset += n;
qb->chain = cl->next;
cl->next = NULL;
ngx_quic_free_chain(c, cl);
}
if (qb->chain == NULL) {
qb->offset = offset;
}
}
ngx_chain_t *
ngx_quic_alloc_chain(ngx_connection_t *c)
{
@ -496,17 +539,16 @@ ngx_quic_copy_buf(ngx_connection_t *c, u_char *data, size_t len)
ngx_chain_t *
ngx_quic_write_chain(ngx_connection_t *c, ngx_chain_t **chain, ngx_chain_t *in,
off_t limit, off_t offset, size_t *size)
ngx_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
ngx_chain_t *in, uint64_t limit, uint64_t offset)
{
off_t n;
u_char *p;
uint64_t n, base;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_chain_t *cl, **chain;
if (size) {
*size = 0;
}
base = qb->offset;
chain = &qb->chain;
while (in && limit) {
cl = *chain;
@ -526,21 +568,21 @@ ngx_quic_write_chain(ngx_connection_t *c, ngx_chain_t **chain, ngx_chain_t *in,
b = cl->buf;
n = b->last - b->pos;
if (n <= offset) {
offset -= n;
if (base + n <= offset) {
base += n;
chain = &cl->next;
continue;
}
if (b->sync && offset > 0) {
if (ngx_quic_split_chain(c, cl, offset) != NGX_OK) {
if (b->sync && offset > base) {
if (ngx_quic_split_chain(c, cl, offset - base) != NGX_OK) {
return NGX_CHAIN_ERROR;
}
continue;
}
p = b->pos + offset;
p = b->pos + (offset - base);
while (in) {
@ -558,10 +600,7 @@ ngx_quic_write_chain(ngx_connection_t *c, ngx_chain_t **chain, ngx_chain_t *in,
if (b->sync) {
ngx_memcpy(p, in->buf->pos, n);
if (size) {
*size += n;
}
qb->size += n;
}
p += n;
@ -588,6 +627,15 @@ ngx_quic_write_chain(ngx_connection_t *c, ngx_chain_t **chain, ngx_chain_t *in,
}
void
ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb)
{
ngx_quic_free_chain(c, qb->chain);
qb->chain = NULL;
}
#if (NGX_DEBUG)
void

View File

@ -28,10 +28,14 @@ ngx_chain_t *ngx_quic_copy_buf(ngx_connection_t *c, u_char *data,
size_t len);
void ngx_quic_trim_chain(ngx_chain_t *in, size_t size);
void ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in);
ngx_chain_t *ngx_quic_read_chain(ngx_connection_t *c, ngx_chain_t **chain,
off_t limit);
ngx_chain_t *ngx_quic_write_chain(ngx_connection_t *c, ngx_chain_t **chain,
ngx_chain_t *in, off_t limit, off_t offset, size_t *size);
ngx_chain_t *ngx_quic_read_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
uint64_t limit);
ngx_chain_t *ngx_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
ngx_chain_t *in, uint64_t limit, uint64_t offset);
void ngx_quic_skip_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
uint64_t offset);
void ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb);
#if (NGX_DEBUG)
void ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx);

View File

@ -331,10 +331,8 @@ ngx_int_t
ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_frame_t *frame)
{
size_t len;
uint64_t last;
ngx_buf_t *b;
ngx_chain_t *cl, **ll;
ngx_chain_t *cl;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
ngx_quic_crypto_frame_t *f;
@ -346,12 +344,12 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
/* no overflow since both values are 62-bit */
last = f->offset + f->length;
if (last > ctx->crypto_received + NGX_QUIC_MAX_BUFFERED) {
if (last > ctx->crypto.offset + NGX_QUIC_MAX_BUFFERED) {
qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED;
return NGX_ERROR;
}
if (last <= ctx->crypto_received) {
if (last <= ctx->crypto.offset) {
if (pkt->level == ssl_encryption_initial) {
/* speeding up handshake completion */
@ -368,45 +366,23 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
return NGX_OK;
}
if (f->offset > ctx->crypto_received) {
if (ngx_quic_write_chain(c, &ctx->crypto, frame->data, f->length,
f->offset - ctx->crypto_received, NULL)
if (f->offset == ctx->crypto.offset) {
if (ngx_quic_crypto_input(c, frame->data) != NGX_OK) {
return NGX_ERROR;
}
ngx_quic_skip_buffer(c, &ctx->crypto, last);
} else {
if (ngx_quic_write_buffer(c, &ctx->crypto, frame->data, f->length,
f->offset)
== NGX_CHAIN_ERROR)
{
return NGX_ERROR;
}
return NGX_OK;
}
ngx_quic_trim_chain(frame->data, ctx->crypto_received - f->offset);
if (ngx_quic_crypto_input(c, frame->data) != NGX_OK) {
return NGX_ERROR;
}
ngx_quic_trim_chain(ctx->crypto, last - ctx->crypto_received);
ctx->crypto_received = last;
cl = ctx->crypto;
ll = &cl;
len = 0;
while (*ll) {
b = (*ll)->buf;
if (b->sync && b->pos != b->last) {
/* hole */
break;
}
len += b->last - b->pos;
ll = &(*ll)->next;
}
ctx->crypto_received += len;
ctx->crypto = *ll;
*ll = NULL;
cl = ngx_quic_read_buffer(c, &ctx->crypto, (uint64_t) -1);
if (cl) {
if (ngx_quic_crypto_input(c, cl) != NGX_OK) {

View File

@ -261,8 +261,7 @@ ngx_quic_do_reset_stream(ngx_quic_stream_t *qs, ngx_uint_t err)
ngx_quic_queue_frame(qc, frame);
ngx_quic_free_chain(pc, qs->out);
qs->out = NULL;
ngx_quic_free_buffer(pc, &qs->send);
return NGX_OK;
}
@ -760,7 +759,7 @@ ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size)
return 0;
}
in = ngx_quic_read_chain(pc, &qs->in, size);
in = ngx_quic_read_buffer(pc, &qs->recv, size);
if (in == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
@ -835,8 +834,7 @@ 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)
{
off_t flow;
size_t n;
uint64_t n, flow;
ngx_event_t *wev;
ngx_connection_t *pc;
ngx_quic_stream_t *qs;
@ -863,25 +861,27 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
return in;
}
if (limit == 0 || limit > flow) {
if (limit == 0 || limit > (off_t) flow) {
limit = flow;
}
in = ngx_quic_write_chain(pc, &qs->out, in, limit,
c->sent - qs->send_offset, &n);
n = qs->send.size;
in = ngx_quic_write_buffer(pc, &qs->send, in, limit, c->sent);
if (in == NGX_CHAIN_ERROR) {
return NGX_CHAIN_ERROR;
}
n = qs->send.size - n;
c->sent += n;
qc->streams.sent += n;
if (flow == (off_t) n) {
if (flow == n) {
wev->ready = 0;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic send_chain sent:%uz", n);
"quic send_chain sent:%uL", n);
if (ngx_quic_stream_flush(qs) != NGX_OK) {
return NGX_CHAIN_ERROR;
@ -894,10 +894,9 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
static ngx_int_t
ngx_quic_stream_flush(ngx_quic_stream_t *qs)
{
off_t limit;
size_t len;
off_t limit, len;
ngx_uint_t last;
ngx_chain_t *out, *cl;
ngx_chain_t *out;
ngx_quic_frame_t *frame;
ngx_connection_t *pc;
ngx_quic_connection_t *qc;
@ -919,20 +918,18 @@ ngx_quic_stream_flush(ngx_quic_stream_t *qs)
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0,
"quic stream id:0x%xL flush limit:%O", qs->id, limit);
out = ngx_quic_read_chain(pc, &qs->out, limit);
len = qs->send.offset;
out = ngx_quic_read_buffer(pc, &qs->send, limit);
if (out == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
len = 0;
len = qs->send.offset - len;
last = 0;
for (cl = out; cl; cl = cl->next) {
len += cl->buf->last - cl->buf->pos;
}
if (qs->send_final_size != (uint64_t) -1
&& qs->send_final_size == qs->send_offset + len)
&& qs->send_final_size == qs->send.offset)
{
qs->send_state = NGX_QUIC_STREAM_SEND_DATA_SENT;
last = 1;
@ -965,7 +962,7 @@ ngx_quic_stream_flush(ngx_quic_stream_t *qs)
qc->streams.send_offset += len;
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
"quic stream id:0x%xL flush len:%uz last:%ui",
"quic stream id:0x%xL flush len:%O last:%ui",
qs->id, len, last);
if (qs->connection == NULL) {
@ -1026,8 +1023,8 @@ ngx_quic_close_stream(ngx_quic_stream_t *qs)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0,
"quic stream id:0x%xL close", qs->id);
ngx_quic_free_chain(pc, qs->in);
ngx_quic_free_chain(pc, qs->out);
ngx_quic_free_buffer(pc, &qs->send);
ngx_quic_free_buffer(pc, &qs->recv);
ngx_rbtree_delete(&qc->streams.tree, &qs->node);
ngx_queue_insert_tail(&qc->streams.free, &qs->queue);
@ -1071,7 +1068,6 @@ ngx_int_t
ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_frame_t *frame)
{
size_t size;
uint64_t last;
ngx_quic_stream_t *qs;
ngx_quic_connection_t *qc;
@ -1140,17 +1136,14 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
qs->recv_state = NGX_QUIC_STREAM_RECV_SIZE_KNOWN;
}
if (ngx_quic_write_chain(c, &qs->in, frame->data, f->length,
f->offset - qs->recv_offset, &size)
if (ngx_quic_write_buffer(c, &qs->recv, frame->data, f->length, f->offset)
== NGX_CHAIN_ERROR)
{
return NGX_ERROR;
}
qs->recv_size += size;
if (qs->recv_state == NGX_QUIC_STREAM_RECV_SIZE_KNOWN
&& qs->recv_size == qs->recv_final_size)
&& qs->recv.size == qs->recv_final_size)
{
qs->recv_state = NGX_QUIC_STREAM_RECV_DATA_RECVD;
}