diff options
Diffstat (limited to 'src/event/quic/ngx_event_quic_connid.c')
| -rw-r--r-- | src/event/quic/ngx_event_quic_connid.c | 467 |
1 files changed, 228 insertions, 239 deletions
diff --git a/src/event/quic/ngx_event_quic_connid.c b/src/event/quic/ngx_event_quic_connid.c index faf5d9c83..a30e7ef35 100644 --- a/src/event/quic/ngx_event_quic_connid.c +++ b/src/event/quic/ngx_event_quic_connid.c @@ -9,103 +9,24 @@ #include <ngx_event.h> #include <ngx_event_quic_connection.h> - #define NGX_QUIC_MAX_SERVER_IDS 8 -static ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id); #if (NGX_QUIC_BPF) static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id); #endif -static ngx_int_t ngx_quic_retire_connection_id(ngx_connection_t *c, +static ngx_int_t ngx_quic_send_retire_connection_id(ngx_connection_t *c, enum ssl_encryption_level_t level, uint64_t seqnum); -static ngx_quic_server_id_t *ngx_quic_insert_server_id(ngx_connection_t *c, - ngx_quic_connection_t *qc, ngx_str_t *id); + static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc); -static ngx_quic_server_id_t *ngx_quic_alloc_server_id(ngx_connection_t *c, - ngx_quic_connection_t *qc); +static ngx_int_t ngx_quic_replace_retired_client_id(ngx_connection_t *c, + ngx_quic_client_id_t *retired_cid); +static ngx_int_t ngx_quic_send_server_id(ngx_connection_t *c, + ngx_quic_server_id_t *sid); ngx_int_t -ngx_quic_setup_connection_ids(ngx_connection_t *c, ngx_quic_connection_t *qc, - ngx_quic_header_t *pkt) -{ - ngx_quic_server_id_t *sid, *osid; - ngx_quic_client_id_t *cid; - - /* - * qc->nclient_ids = 0 - * qc->nserver_ids = 0 - * qc->max_retired_seqnum = 0 - */ - - ngx_queue_init(&qc->client_ids); - ngx_queue_init(&qc->server_ids); - ngx_queue_init(&qc->free_client_ids); - ngx_queue_init(&qc->free_server_ids); - - qc->odcid.len = pkt->odcid.len; - qc->odcid.data = ngx_pstrdup(c->pool, &pkt->odcid); - if (qc->odcid.data == NULL) { - return NGX_ERROR; - } - - qc->tp.original_dcid = qc->odcid; - - qc->scid.len = pkt->scid.len; - qc->scid.data = ngx_pstrdup(c->pool, &pkt->scid); - if (qc->scid.data == NULL) { - return NGX_ERROR; - } - - qc->dcid.len = NGX_QUIC_SERVER_CID_LEN; - qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len); - if (qc->dcid.data == NULL) { - return NGX_ERROR; - } - - if (ngx_quic_create_server_id(c, qc->dcid.data) != NGX_OK) { - return NGX_ERROR; - } - - qc->tp.initial_scid = qc->dcid; - - cid = ngx_quic_alloc_client_id(c, qc); - if (cid == NULL) { - return NGX_ERROR; - } - - cid->seqnum = 0; - cid->len = pkt->scid.len; - ngx_memcpy(cid->id, pkt->scid.data, pkt->scid.len); - - ngx_queue_insert_tail(&qc->client_ids, &cid->queue); - qc->nclient_ids++; - qc->client_seqnum = 0; - - qc->server_seqnum = NGX_QUIC_UNSET_PN; - - osid = ngx_quic_insert_server_id(c, qc, &qc->odcid); - if (osid == NULL) { - return NGX_ERROR; - } - - qc->server_seqnum = 0; - - sid = ngx_quic_insert_server_id(c, qc, &qc->dcid); - if (sid == NULL) { - ngx_rbtree_delete(&c->listening->rbtree, &osid->udp.node); - return NGX_ERROR; - } - - c->udp = &sid->udp; - - return NGX_OK; -} - - -static ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id) { if (RAND_bytes(id, NGX_QUIC_SERVER_CID_LEN) != 1) { @@ -120,9 +41,6 @@ ngx_quic_create_server_id(ngx_connection_t *c, u_char *id) } #endif - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic create server id %*xs", - (size_t) NGX_QUIC_SERVER_CID_LEN, id); return NGX_OK; } @@ -155,12 +73,11 @@ ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id) #endif - - ngx_int_t ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f) { + ngx_str_t id; ngx_queue_t *q; ngx_quic_client_id_t *cid, *item; ngx_quic_connection_t *qc; @@ -177,7 +94,9 @@ ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, * done so for that sequence number. */ - if (ngx_quic_retire_connection_id(c, pkt->level, f->seqnum) != NGX_OK) { + if (ngx_quic_send_retire_connection_id(c, pkt->level, f->seqnum) + != NGX_OK) + { return NGX_ERROR; } @@ -220,25 +139,11 @@ ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, } else { - cid = ngx_quic_alloc_client_id(c, qc); - if (cid == NULL) { - return NGX_ERROR; - } - - cid->seqnum = f->seqnum; - cid->len = f->len; - ngx_memcpy(cid->id, f->cid, f->len); - - ngx_memcpy(cid->sr_token, f->srt, NGX_QUIC_SR_TOKEN_LEN); + id.data = f->cid; + id.len = f->len; - ngx_queue_insert_tail(&qc->client_ids, &cid->queue); - qc->nclient_ids++; - - /* always use latest available connection id */ - if (f->seqnum > qc->client_seqnum) { - qc->scid.len = cid->len; - qc->scid.data = cid->id; - qc->client_seqnum = f->seqnum; + if (ngx_quic_create_client_id(c, &id, f->seqnum, f->srt) == NULL) { + return NGX_ERROR; } } @@ -269,15 +174,20 @@ retire: /* this connection id must be retired */ - if (ngx_quic_retire_connection_id(c, pkt->level, cid->seqnum) + if (ngx_quic_send_retire_connection_id(c, pkt->level, cid->seqnum) != NGX_OK) { return NGX_ERROR; } - ngx_queue_remove(&cid->queue); - ngx_queue_insert_head(&qc->free_client_ids, &cid->queue); - qc->nclient_ids--; + if (cid->refcnt) { + /* we are going to retire client id which is in use */ + if (ngx_quic_replace_retired_client_id(c, cid) != NGX_OK) { + return NGX_ERROR; + } + } + + ngx_quic_unref_client_id(c, cid); } done: @@ -300,7 +210,7 @@ done: static ngx_int_t -ngx_quic_retire_connection_id(ngx_connection_t *c, +ngx_quic_send_retire_connection_id(ngx_connection_t *c, enum ssl_encryption_level_t level, uint64_t seqnum) { ngx_quic_frame_t *frame; @@ -319,214 +229,293 @@ ngx_quic_retire_connection_id(ngx_connection_t *c, ngx_quic_queue_frame(qc, frame); + /* we are no longer going to use this client id */ + return NGX_OK; } -ngx_int_t -ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, - ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f) +static ngx_quic_client_id_t * +ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc) +{ + ngx_queue_t *q; + ngx_quic_client_id_t *cid; + + if (!ngx_queue_empty(&qc->free_client_ids)) { + + q = ngx_queue_head(&qc->free_client_ids); + cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); + + ngx_queue_remove(&cid->queue); + + ngx_memzero(cid, sizeof(ngx_quic_client_id_t)); + + } else { + + cid = ngx_pcalloc(c->pool, sizeof(ngx_quic_client_id_t)); + if (cid == NULL) { + return NULL; + } + } + + return cid; +} + + +ngx_quic_client_id_t * +ngx_quic_create_client_id(ngx_connection_t *c, ngx_str_t *id, + uint64_t seqnum, u_char *token) +{ + ngx_quic_client_id_t *cid; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + cid = ngx_quic_alloc_client_id(c, qc); + if (cid == NULL) { + return NULL; + } + + cid->seqnum = seqnum; + + cid->len = id->len; + ngx_memcpy(cid->id, id->data, id->len); + + if (token) { + ngx_memcpy(cid->sr_token, token, NGX_QUIC_SR_TOKEN_LEN); + } + + ngx_queue_insert_tail(&qc->client_ids, &cid->queue); + qc->nclient_ids++; + + if (seqnum > qc->client_seqnum) { + qc->client_seqnum = seqnum; + } + + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic cid #%uL received id:%uz:%xV:%*xs", + cid->seqnum, id->len, id, + (size_t) NGX_QUIC_SR_TOKEN_LEN, cid->sr_token); + + return cid; +} + + +ngx_quic_client_id_t * +ngx_quic_next_client_id(ngx_connection_t *c) { ngx_queue_t *q; - ngx_quic_server_id_t *sid; + ngx_quic_client_id_t *cid; ngx_quic_connection_t *qc; qc = ngx_quic_get_connection(c); - for (q = ngx_queue_head(&qc->server_ids); - q != ngx_queue_sentinel(&qc->server_ids); + for (q = ngx_queue_head(&qc->client_ids); + q != ngx_queue_sentinel(&qc->client_ids); q = ngx_queue_next(q)) { - sid = ngx_queue_data(q, ngx_quic_server_id_t, queue); + cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); - if (sid->seqnum == f->sequence_number) { - ngx_queue_remove(q); - ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue); - ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node); - qc->nserver_ids--; - break; + if (cid->refcnt == 0) { + return cid; } } - return ngx_quic_issue_server_ids(c); + return NULL; } ngx_int_t -ngx_quic_issue_server_ids(ngx_connection_t *c) +ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f) { - ngx_str_t dcid; - ngx_uint_t n; - ngx_quic_frame_t *frame; - ngx_quic_server_id_t *sid; + ngx_quic_path_t *path; + ngx_quic_socket_t *qsock, **tmp; + ngx_quic_client_id_t *cid; ngx_quic_connection_t *qc; - u_char id[NGX_QUIC_SERVER_CID_LEN]; qc = ngx_quic_get_connection(c); - n = ngx_min(NGX_QUIC_MAX_SERVER_IDS, qc->ctp.active_connection_id_limit); + qsock = ngx_quic_find_socket(c, f->sequence_number); + if (qsock == NULL) { + return NGX_OK; + } - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic issue server ids has:%ui max:%ui", qc->nserver_ids, n); + if (qsock->sid.seqnum == qc->socket->sid.seqnum) { + tmp = &qc->socket; - while (qc->nserver_ids < n) { - if (ngx_quic_create_server_id(c, id) != NGX_OK) { - return NGX_ERROR; - } + } else if (qc->backup && qsock->sid.seqnum == qc->backup->sid.seqnum) { + tmp = &qc->backup; - dcid.len = NGX_QUIC_SERVER_CID_LEN; - dcid.data = id; + } else { + tmp = NULL; + } - sid = ngx_quic_insert_server_id(c, qc, &dcid); - if (sid == NULL) { - return NGX_ERROR; - } + if (ngx_quic_create_sockets(c) != NGX_OK) { + return NGX_ERROR; + } - frame = ngx_quic_alloc_frame(c); - if (frame == NULL) { - return NGX_ERROR; - } + if (tmp) { + /* replace socket in use (active or backup) */ - frame->level = ssl_encryption_application; - frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID; - frame->u.ncid.seqnum = sid->seqnum; - frame->u.ncid.retire = 0; - frame->u.ncid.len = NGX_QUIC_SERVER_CID_LEN; - ngx_memcpy(frame->u.ncid.cid, id, NGX_QUIC_SERVER_CID_LEN); + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic %s socket #%uL:%uL:%uL retired", + (*tmp) == qc->socket ? "active" : "backup", + (*tmp)->sid.seqnum, (*tmp)->cid->seqnum, + (*tmp)->path->seqnum); - if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key, - frame->u.ncid.srt) - != NGX_OK) - { + qsock = ngx_quic_get_unconnected_socket(c); + if (qsock == NULL) { return NGX_ERROR; } - ngx_quic_queue_frame(qc, frame); + path = (*tmp)->path; + cid = (*tmp)->cid; + + ngx_quic_connect(c, qsock, path, cid); + + + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic %s socket is now #%uL:%uL:%uL (%s)", + (*tmp) == qc->socket ? "active" : "backup", + qsock->sid.seqnum, qsock->cid->seqnum, + qsock->path->seqnum, + ngx_quic_path_state_str(qsock->path)); + + ngx_quic_close_socket(c, *tmp); /* no longer used */ + + *tmp = qsock; } return NGX_OK; } -void -ngx_quic_clear_temp_server_ids(ngx_connection_t *c) +ngx_int_t +ngx_quic_create_sockets(ngx_connection_t *c) { - ngx_queue_t *q, *next; - ngx_quic_server_id_t *sid; + ngx_uint_t n; + ngx_quic_socket_t *qsock; ngx_quic_connection_t *qc; qc = ngx_quic_get_connection(c); - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic clear temp server ids"); + n = ngx_min(NGX_QUIC_MAX_SERVER_IDS, qc->ctp.active_connection_id_limit); - for (q = ngx_queue_head(&qc->server_ids); - q != ngx_queue_sentinel(&qc->server_ids); - q = next) - { - next = ngx_queue_next(q); - sid = ngx_queue_data(q, ngx_quic_server_id_t, queue); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic create sockets has:%ui max:%ui", qc->nsockets, n); - if (sid->seqnum != NGX_QUIC_UNSET_PN) { - continue; + while (qc->nsockets < n) { + + qsock = ngx_quic_alloc_socket(c, qc); + if (qsock == NULL) { + return NGX_ERROR; + } + + if (ngx_quic_listen(c, qc, qsock) != NGX_OK) { + return NGX_ERROR; } - ngx_queue_remove(q); - ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue); - ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node); - qc->nserver_ids--; + if (ngx_quic_send_server_id(c, &qsock->sid) != NGX_OK) { + return NGX_ERROR; + } } + + return NGX_OK; } -static ngx_quic_server_id_t * -ngx_quic_insert_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc, - ngx_str_t *id) +static ngx_int_t +ngx_quic_send_server_id(ngx_connection_t *c, ngx_quic_server_id_t *sid) { - ngx_str_t dcid; - ngx_quic_server_id_t *sid; - - sid = ngx_quic_alloc_server_id(c, qc); - if (sid == NULL) { - return NULL; - } + ngx_str_t dcid; + ngx_quic_frame_t *frame; + ngx_quic_connection_t *qc; - sid->quic = qc; + qc = ngx_quic_get_connection(c); - sid->seqnum = qc->server_seqnum; + dcid.len = sid->len; + dcid.data = sid->id; - if (qc->server_seqnum != NGX_QUIC_UNSET_PN) { - qc->server_seqnum++; + frame = ngx_quic_alloc_frame(c); + if (frame == NULL) { + return NGX_ERROR; } - sid->len = id->len; - ngx_memcpy(sid->id, id->data, id->len); + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID; + frame->u.ncid.seqnum = sid->seqnum; + frame->u.ncid.retire = 0; + frame->u.ncid.len = NGX_QUIC_SERVER_CID_LEN; + ngx_memcpy(frame->u.ncid.cid, sid->id, NGX_QUIC_SERVER_CID_LEN); - ngx_queue_insert_tail(&qc->server_ids, &sid->queue); - qc->nserver_ids++; - - dcid.data = sid->id; - dcid.len = sid->len; - - ngx_insert_udp_connection(c, &sid->udp, &dcid); + if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key, + frame->u.ncid.srt) + != NGX_OK) + { + return NGX_ERROR; + } - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic insert server id seqnum:%uL id len:%uz %xV", - sid->seqnum, id->len, id); + ngx_quic_queue_frame(qc, frame); - return sid; + return NGX_OK; } -static ngx_quic_client_id_t * -ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc) +static ngx_int_t +ngx_quic_replace_retired_client_id(ngx_connection_t *c, + ngx_quic_client_id_t *retired_cid) { - ngx_queue_t *q; - ngx_quic_client_id_t *cid; + ngx_queue_t *q; + ngx_quic_socket_t *qsock; + ngx_quic_client_id_t *cid; + ngx_quic_connection_t *qc; - if (!ngx_queue_empty(&qc->free_client_ids)) { + qc = ngx_quic_get_connection(c); - q = ngx_queue_head(&qc->free_client_ids); - cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); + for (q = ngx_queue_head(&qc->sockets); + q != ngx_queue_sentinel(&qc->sockets); + q = ngx_queue_next(q)) + { + qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); - ngx_queue_remove(&cid->queue); + if (qsock->cid == retired_cid) { - ngx_memzero(cid, sizeof(ngx_quic_client_id_t)); + cid = ngx_quic_next_client_id(c); + if (cid == NULL) { + return NGX_ERROR; + } - } else { + qsock->cid = cid; + cid->refcnt++; - cid = ngx_pcalloc(c->pool, sizeof(ngx_quic_client_id_t)); - if (cid == NULL) { - return NULL; + ngx_quic_unref_client_id(c, retired_cid); + + if (retired_cid->refcnt == 0) { + return NGX_OK; + } } } - return cid; + return NGX_OK; } -static ngx_quic_server_id_t * -ngx_quic_alloc_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc) +void +ngx_quic_unref_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid) { - ngx_queue_t *q; - ngx_quic_server_id_t *sid; - - if (!ngx_queue_empty(&qc->free_server_ids)) { - - q = ngx_queue_head(&qc->free_server_ids); - sid = ngx_queue_data(q, ngx_quic_server_id_t, queue); + ngx_quic_connection_t *qc; - ngx_queue_remove(&sid->queue); + cid->refcnt--; - ngx_memzero(sid, sizeof(ngx_quic_server_id_t)); + if (cid->refcnt) { + return; + } - } else { + qc = ngx_quic_get_connection(c); - sid = ngx_pcalloc(c->pool, sizeof(ngx_quic_server_id_t)); - if (sid == NULL) { - return NULL; - } - } + ngx_queue_remove(&cid->queue); + ngx_queue_insert_head(&qc->free_client_ids, &cid->queue); - return sid; + qc->nclient_ids--; } |
