2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 06:25:31 +00:00

DoH: close active server streams when finishing session

Under some circumstances a situation might occur when server-side
session gets finished while there are still active HTTP/2
streams. This would lead to isc_nm_httpsocket object leaks.

This commit fixes this behaviour as well as refactors failed_read_cb()
to allow better code reuse.
This commit is contained in:
Artem Boldariev
2021-05-06 16:44:09 +03:00
parent a9e97f28b7
commit 8c0ea01f34

View File

@@ -165,6 +165,12 @@ static void
failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result,
isc_nm_http_session_t *session);
static void
client_call_failed_read_cb(isc_result_t result, isc_nm_http_session_t *session);
static void
server_call_failed_read_cb(isc_result_t result, isc_nm_http_session_t *session);
static void
failed_read_cb(isc_result_t result, isc_nm_http_session_t *session);
@@ -420,23 +426,10 @@ finish_http_session(isc_nm_http_session_t *session) {
isc_nm_cancelread(session->handle);
}
if (!ISC_LIST_EMPTY(session->cstreams)) {
http_cstream_t *cstream =
ISC_LIST_HEAD(session->cstreams);
while (cstream != NULL) {
http_cstream_t *next = ISC_LIST_NEXT(cstream,
link);
ISC_LIST_DEQUEUE(session->cstreams, cstream,
link);
cstream->read_cb(
session->client_httphandle,
ISC_R_UNEXPECTED,
&(isc_region_t){ cstream->rbuf,
cstream->rbufsize },
cstream->read_cbarg);
put_http_cstream(session->mctx, cstream);
cstream = next;
}
if (session->client) {
client_call_failed_read_cb(ISC_R_UNEXPECTED, session);
} else {
server_call_failed_read_cb(ISC_R_UNEXPECTED, session);
}
isc_nmhandle_detach(&session->handle);
}
@@ -2401,29 +2394,63 @@ failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result,
}
static void
failed_read_cb(isc_result_t result, isc_nm_http_session_t *session) {
client_call_failed_read_cb(isc_result_t result,
isc_nm_http_session_t *session) {
http_cstream_t *cstream = NULL;
REQUIRE(VALID_HTTP2_SESSION(session));
REQUIRE(result != ISC_R_SUCCESS);
if (session->client) {
http_cstream_t *cstream = NULL;
cstream = ISC_LIST_HEAD(session->cstreams);
while (cstream != NULL) {
http_cstream_t *next = ISC_LIST_NEXT(cstream, link);
cstream->read_cb(session->client_httphandle, result,
&(isc_region_t){ cstream->rbuf,
cstream->rbufsize },
cstream->read_cbarg);
if (result != ISC_R_TIMEDOUT ||
!isc__nmsocket_timer_running(session->handle->sock))
{
ISC_LIST_DEQUEUE(session->cstreams, cstream,
link);
put_http_cstream(session->mctx, cstream);
}
cstream = next;
cstream = ISC_LIST_HEAD(session->cstreams);
while (cstream != NULL) {
http_cstream_t *next = ISC_LIST_NEXT(cstream, link);
cstream->read_cb(
session->client_httphandle, result,
&(isc_region_t){ cstream->rbuf, cstream->rbufsize },
cstream->read_cbarg);
if (result != ISC_R_TIMEDOUT ||
!isc__nmsocket_timer_running(session->handle->sock))
{
ISC_LIST_DEQUEUE(session->cstreams, cstream, link);
put_http_cstream(session->mctx, cstream);
}
cstream = next;
}
}
static void
server_call_failed_read_cb(isc_result_t result,
isc_nm_http_session_t *session) {
isc_nmsocket_h2_t *h2data = NULL; /* stream socket */
REQUIRE(VALID_HTTP2_SESSION(session));
REQUIRE(result != ISC_R_SUCCESS);
for (h2data = ISC_LIST_HEAD(session->sstreams); h2data != NULL;
h2data = ISC_LIST_NEXT(h2data, link))
{
failed_httpstream_read_cb(h2data->psock, result, session);
}
h2data = ISC_LIST_HEAD(session->sstreams);
while (h2data != NULL) {
isc_nmsocket_h2_t *next = ISC_LIST_NEXT(h2data, link);
ISC_LIST_DEQUEUE(session->sstreams, h2data, link);
/* Cleanup socket in place */
atomic_store(&h2data->psock->active, false);
atomic_store(&h2data->psock->closed, true);
isc__nmsocket_detach(&h2data->psock);
h2data = next;
}
}
static void
failed_read_cb(isc_result_t result, isc_nm_http_session_t *session) {
if (session->client) {
client_call_failed_read_cb(result, session);
/*
* If result was ISC_R_TIMEDOUT and the timer was reset,
* then we still have active streams and should not close
@@ -2433,26 +2460,7 @@ failed_read_cb(isc_result_t result, isc_nm_http_session_t *session) {
finish_http_session(session);
}
} else {
isc_nmsocket_h2_t *h2data = NULL; /* stream socket */
for (h2data = ISC_LIST_HEAD(session->sstreams); h2data != NULL;
h2data = ISC_LIST_NEXT(h2data, link))
{
failed_httpstream_read_cb(h2data->psock, result,
session);
}
h2data = ISC_LIST_HEAD(session->sstreams);
while (h2data != NULL) {
isc_nmsocket_h2_t *next = ISC_LIST_NEXT(h2data, link);
ISC_LIST_DEQUEUE(session->sstreams, h2data, link);
/* Cleanup socket in place */
atomic_store(&h2data->psock->active, false);
atomic_store(&h2data->psock->closed, true);
isc__nmsocket_detach(&h2data->psock);
h2data = next;
}
server_call_failed_read_cb(result, session);
/*
* All streams are now destroyed; close the session.
*/