diff --git a/src/event/quic/ngx_event_quic_connid.c b/src/event/quic/ngx_event_quic_connid.c index 8b9805b1e..503a71b4e 100644 --- a/src/event/quic/ngx_event_quic_connid.c +++ b/src/event/quic/ngx_event_quic_connid.c @@ -403,6 +403,10 @@ ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, return NGX_OK; } + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic socket #%uL is retired", qsock->sid.seqnum); + + /* check if client is willing to retire sid we have in use */ if (qsock->sid.seqnum == qc->socket->sid.seqnum) { tmp = &qc->socket; @@ -410,46 +414,68 @@ ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c, tmp = &qc->backup; } else { - tmp = NULL; - } - if (ngx_quic_create_sockets(c) != NGX_OK) { - return NGX_ERROR; - } + ngx_quic_close_socket(c, qsock); - if (tmp) { - /* replace socket in use (active or backup) */ - - 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); - - qsock = ngx_quic_get_unconnected_socket(c); - if (qsock == NULL) { + /* restore socket count up to a limit after deletion */ + if (ngx_quic_create_sockets(c) != NGX_OK) { return NGX_ERROR; } - 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; } + /* preserve path/cid from retired socket */ + path = qsock->path; + cid = qsock->cid; + + /* ensure that closing_socket will not drop path and cid */ + path->refcnt++; + cid->refcnt++; + + ngx_quic_close_socket(c, qsock); + + /* restore original values */ + path->refcnt--; + cid->refcnt--; + + /* restore socket count up to a limit after deletion */ + if (ngx_quic_create_sockets(c) != NGX_OK) { + goto failed; + } + + qsock = ngx_quic_get_unconnected_socket(c); + if (qsock == NULL) { + qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR; + qc->error_reason = "not enough server IDs"; + goto failed; + } + + 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)); + + /* restore active/backup pointer in quic connection */ + *tmp = qsock; + return NGX_OK; + +failed: + + /* + * socket was closed, path and cid were preserved artifically + * to be reused, but it didn't happen, thus unref here + */ + + ngx_quic_unref_path(c, path); + ngx_quic_unref_client_id(c, cid); + + return NGX_ERROR; } diff --git a/src/event/quic/ngx_event_quic_socket.c b/src/event/quic/ngx_event_quic_socket.c index ddde68f09..3b507fca8 100644 --- a/src/event/quic/ngx_event_quic_socket.c +++ b/src/event/quic/ngx_event_quic_socket.c @@ -14,8 +14,6 @@ static ngx_int_t ngx_quic_create_temp_socket(ngx_connection_t *c, ngx_quic_connection_t *qc, ngx_str_t *dcid, ngx_quic_path_t *path, ngx_quic_client_id_t *cid); -static void ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path); - ngx_int_t ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc, @@ -207,7 +205,7 @@ ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock) } -static void +void ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path) { ngx_quic_connection_t *qc; diff --git a/src/event/quic/ngx_event_quic_socket.h b/src/event/quic/ngx_event_quic_socket.h index 1372822c0..72ed67ad0 100644 --- a/src/event/quic/ngx_event_quic_socket.h +++ b/src/event/quic/ngx_event_quic_socket.h @@ -22,6 +22,7 @@ ngx_int_t ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc, ngx_quic_socket_t *qsock); void ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock); +void ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path); void ngx_quic_connect(ngx_connection_t *c, ngx_quic_socket_t *qsock, ngx_quic_path_t *path, ngx_quic_client_id_t *cid);