connect: improve happy eyeballs handling
For QUIC but also for regular TCP when the second family runs out of IPs with a failure while the first family is still trying to connect. Separated the timeout handling for IPv4 and IPv6 connections when they both have a number of addresses to iterate over.
This commit is contained in:
Родитель
325866fd6f
Коммит
dc90f51065
|
@ -560,7 +560,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
|
||||||
to the correct family */
|
to the correct family */
|
||||||
static struct Curl_addrinfo *ainext(struct connectdata *conn,
|
static struct Curl_addrinfo *ainext(struct connectdata *conn,
|
||||||
int tempindex,
|
int tempindex,
|
||||||
bool next) /* use current or next entry */
|
bool next) /* use next entry? */
|
||||||
{
|
{
|
||||||
struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
|
struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
|
||||||
if(ai && next)
|
if(ai && next)
|
||||||
|
@ -571,7 +571,7 @@ static struct Curl_addrinfo *ainext(struct connectdata *conn,
|
||||||
return ai;
|
return ai;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used within the multi interface. Try next IP address, return TRUE if no
|
/* Used within the multi interface. Try next IP address, returns error if no
|
||||||
more address exists or error */
|
more address exists or error */
|
||||||
static CURLcode trynextip(struct connectdata *conn,
|
static CURLcode trynextip(struct connectdata *conn,
|
||||||
int sockindex,
|
int sockindex,
|
||||||
|
@ -823,8 +823,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
timediff_t allow;
|
timediff_t allow;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct curltime now;
|
struct curltime now;
|
||||||
int rc;
|
int rc = 0;
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
|
DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
|
||||||
|
|
||||||
|
@ -859,49 +859,42 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
const int other = i ^ 1;
|
const int other = i ^ 1;
|
||||||
if(conn->tempsock[i] == CURL_SOCKET_BAD)
|
if(conn->tempsock[i] == CURL_SOCKET_BAD)
|
||||||
continue;
|
continue;
|
||||||
|
error = 0;
|
||||||
#ifdef ENABLE_QUIC
|
#ifdef ENABLE_QUIC
|
||||||
if(conn->transport == TRNSPRT_QUIC) {
|
if(conn->transport == TRNSPRT_QUIC) {
|
||||||
result = Curl_quic_is_connected(conn, i, connected);
|
result = Curl_quic_is_connected(conn, i, connected);
|
||||||
if(result) {
|
if(!result && *connected) {
|
||||||
error = SOCKERRNO;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if(*connected) {
|
|
||||||
/* use this socket from now on */
|
/* use this socket from now on */
|
||||||
conn->sock[sockindex] = conn->tempsock[i];
|
conn->sock[sockindex] = conn->tempsock[i];
|
||||||
conn->ip_addr = conn->tempaddr[i];
|
conn->ip_addr = conn->tempaddr[i];
|
||||||
conn->tempsock[i] = CURL_SOCKET_BAD;
|
conn->tempsock[i] = CURL_SOCKET_BAD;
|
||||||
post_SOCKS(conn, sockindex, connected);
|
post_SOCKS(conn, sockindex, connected);
|
||||||
connkeep(conn, "HTTP/3 default");
|
connkeep(conn, "HTTP/3 default");
|
||||||
return result;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
/* should we try another protocol family? */
|
if(result)
|
||||||
if(i == 0 && !conn->bits.parallel_connect &&
|
error = SOCKERRNO;
|
||||||
(Curl_timediff(now, conn->connecttime) >=
|
|
||||||
data->set.happy_eyeballs_timeout)) {
|
|
||||||
conn->bits.parallel_connect = TRUE; /* starting now */
|
|
||||||
trynextip(conn, sockindex, 1);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
#ifdef mpeix
|
#ifdef mpeix
|
||||||
/* Call this function once now, and ignore the results. We do this to
|
/* Call this function once now, and ignore the results. We do this to
|
||||||
"clear" the error state on the socket so that we can later read it
|
"clear" the error state on the socket so that we can later read it
|
||||||
reliably. This is reported necessary on the MPE/iX operating system. */
|
reliably. This is reported necessary on the MPE/iX operating
|
||||||
(void)verifyconnect(conn->tempsock[i], NULL);
|
system. */
|
||||||
|
(void)verifyconnect(conn->tempsock[i], NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* check socket for connect */
|
/* check socket for connect */
|
||||||
rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
|
rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
if(rc == 0) { /* no connection yet */
|
if(rc == 0) { /* no connection yet */
|
||||||
error = 0;
|
if(Curl_timediff(now, conn->connecttime) >=
|
||||||
if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
|
conn->timeoutms_per_addr[i]) {
|
||||||
infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
|
infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
|
||||||
"ms connect time, move on!\n", conn->timeoutms_per_addr);
|
"ms connect time, move on!\n", conn->timeoutms_per_addr[i]);
|
||||||
error = ETIMEDOUT;
|
error = ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,9 +939,6 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
else if(rc & CURL_CSELECT_ERR)
|
else if(rc & CURL_CSELECT_ERR)
|
||||||
(void)verifyconnect(conn->tempsock[i], &error);
|
(void)verifyconnect(conn->tempsock[i], &error);
|
||||||
|
|
||||||
#ifdef ENABLE_QUIC
|
|
||||||
error:
|
|
||||||
#endif
|
|
||||||
/*
|
/*
|
||||||
* The connection failed here, we should attempt to connect to the "next
|
* The connection failed here, we should attempt to connect to the "next
|
||||||
* address" for the given host. But first remember the latest error.
|
* address" for the given host. But first remember the latest error.
|
||||||
|
@ -968,7 +958,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
Curl_strerror(error, buffer, sizeof(buffer)));
|
Curl_strerror(error, buffer, sizeof(buffer)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
|
conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
|
||||||
allow : allow / 2;
|
allow : allow / 2;
|
||||||
ainext(conn, i, TRUE);
|
ainext(conn, i, TRUE);
|
||||||
status = trynextip(conn, sockindex, i);
|
status = trynextip(conn, sockindex, i);
|
||||||
|
@ -980,13 +970,15 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result) {
|
if(result &&
|
||||||
|
(conn->tempsock[0] == CURL_SOCKET_BAD) &&
|
||||||
|
(conn->tempsock[1] == CURL_SOCKET_BAD)) {
|
||||||
/* no more addresses to try */
|
/* no more addresses to try */
|
||||||
const char *hostname;
|
const char *hostname;
|
||||||
char buffer[STRERROR_LEN];
|
char buffer[STRERROR_LEN];
|
||||||
|
|
||||||
/* if the first address family runs out of addresses to try before
|
/* if the first address family runs out of addresses to try before the
|
||||||
the happy eyeball timeout, go ahead and try the next family now */
|
happy eyeball timeout, go ahead and try the next family now */
|
||||||
result = trynextip(conn, sockindex, 1);
|
result = trynextip(conn, sockindex, 1);
|
||||||
if(!result)
|
if(!result)
|
||||||
return result;
|
return result;
|
||||||
|
@ -1007,6 +999,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
hostname, conn->port,
|
hostname, conn->port,
|
||||||
Curl_strerror(error, buffer, sizeof(buffer)));
|
Curl_strerror(error, buffer, sizeof(buffer)));
|
||||||
|
|
||||||
|
Curl_quic_disconnect(conn, 0);
|
||||||
|
Curl_quic_disconnect(conn, 1);
|
||||||
|
|
||||||
#ifdef WSAETIMEDOUT
|
#ifdef WSAETIMEDOUT
|
||||||
if(WSAETIMEDOUT == data->state.os_errno)
|
if(WSAETIMEDOUT == data->state.os_errno)
|
||||||
result = CURLE_OPERATION_TIMEDOUT;
|
result = CURLE_OPERATION_TIMEDOUT;
|
||||||
|
@ -1015,6 +1010,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
result = CURLE_OPERATION_TIMEDOUT;
|
result = CURLE_OPERATION_TIMEDOUT;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
result = CURLE_OK; /* still trying */
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1206,8 +1203,10 @@ static CURLcode singleipconnect(struct connectdata *conn,
|
||||||
(void)curlx_nonblock(sockfd, TRUE);
|
(void)curlx_nonblock(sockfd, TRUE);
|
||||||
|
|
||||||
conn->connecttime = Curl_now();
|
conn->connecttime = Curl_now();
|
||||||
if(conn->num_addr > 1)
|
if(conn->num_addr > 1) {
|
||||||
Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
|
Curl_expire(data, conn->timeoutms_per_addr[0], EXPIRE_DNS_PER_NAME);
|
||||||
|
Curl_expire(data, conn->timeoutms_per_addr[1], EXPIRE_DNS_PER_NAME2);
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect TCP and QUIC sockets */
|
/* Connect TCP and QUIC sockets */
|
||||||
if(!isconnected && (conn->transport != TRNSPRT_UDP)) {
|
if(!isconnected && (conn->transport != TRNSPRT_UDP)) {
|
||||||
|
@ -1330,8 +1329,10 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD;
|
conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD;
|
||||||
|
|
||||||
/* Max time for the next connection attempt */
|
/* Max time for the next connection attempt */
|
||||||
conn->timeoutms_per_addr =
|
conn->timeoutms_per_addr[0] =
|
||||||
conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
|
conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
|
||||||
|
conn->timeoutms_per_addr[1] =
|
||||||
|
conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
|
||||||
|
|
||||||
conn->tempfamily[0] = conn->tempaddr[0]?
|
conn->tempfamily[0] = conn->tempaddr[0]?
|
||||||
conn->tempaddr[0]->ai_family:0;
|
conn->tempaddr[0]->ai_family:0;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
|
@ -47,11 +47,13 @@ int Curl_quic_ver(char *p, size_t len);
|
||||||
CURLcode Curl_quic_done_sending(struct connectdata *conn);
|
CURLcode Curl_quic_done_sending(struct connectdata *conn);
|
||||||
void Curl_quic_done(struct Curl_easy *data, bool premature);
|
void Curl_quic_done(struct Curl_easy *data, bool premature);
|
||||||
bool Curl_quic_data_pending(const struct Curl_easy *data);
|
bool Curl_quic_data_pending(const struct Curl_easy *data);
|
||||||
|
void Curl_quic_disconnect(struct connectdata *conn, int tempindex);
|
||||||
|
|
||||||
#else /* ENABLE_QUIC */
|
#else /* ENABLE_QUIC */
|
||||||
#define Curl_quic_done_sending(x)
|
#define Curl_quic_done_sending(x)
|
||||||
#define Curl_quic_done(x,y)
|
#define Curl_quic_done(x,y)
|
||||||
#define Curl_quic_data_pending(x)
|
#define Curl_quic_data_pending(x)
|
||||||
|
#define Curl_quic_disconnect(x,y)
|
||||||
#endif /* !ENABLE_QUIC */
|
#endif /* !ENABLE_QUIC */
|
||||||
|
|
||||||
#endif /* HEADER_CURL_QUIC_H */
|
#endif /* HEADER_CURL_QUIC_H */
|
||||||
|
|
|
@ -981,8 +981,10 @@ struct connectdata {
|
||||||
struct curltime connecttime;
|
struct curltime connecttime;
|
||||||
/* The two fields below get set in Curl_connecthost */
|
/* The two fields below get set in Curl_connecthost */
|
||||||
int num_addr; /* number of addresses to try to connect to */
|
int num_addr; /* number of addresses to try to connect to */
|
||||||
timediff_t timeoutms_per_addr; /* how long time in milliseconds to spend on
|
|
||||||
trying to connect to each IP address */
|
/* how long time in milliseconds to spend on trying to connect to each IP
|
||||||
|
address, per family */
|
||||||
|
timediff_t timeoutms_per_addr[2];
|
||||||
|
|
||||||
const struct Curl_handler *handler; /* Connection's protocol handler */
|
const struct Curl_handler *handler; /* Connection's protocol handler */
|
||||||
const struct Curl_handler *given; /* The protocol first given */
|
const struct Curl_handler *given; /* The protocol first given */
|
||||||
|
@ -1245,7 +1247,8 @@ typedef enum {
|
||||||
EXPIRE_100_TIMEOUT,
|
EXPIRE_100_TIMEOUT,
|
||||||
EXPIRE_ASYNC_NAME,
|
EXPIRE_ASYNC_NAME,
|
||||||
EXPIRE_CONNECTTIMEOUT,
|
EXPIRE_CONNECTTIMEOUT,
|
||||||
EXPIRE_DNS_PER_NAME,
|
EXPIRE_DNS_PER_NAME, /* family1 */
|
||||||
|
EXPIRE_DNS_PER_NAME2, /* family2 */
|
||||||
EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */
|
EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */
|
||||||
EXPIRE_HAPPY_EYEBALLS,
|
EXPIRE_HAPPY_EYEBALLS,
|
||||||
EXPIRE_MULTI_PENDING,
|
EXPIRE_MULTI_PENDING,
|
||||||
|
|
|
@ -256,11 +256,11 @@ static int quic_set_encryption_secrets(SSL *ssl,
|
||||||
int level = quic_from_ossl_level(ossl_level);
|
int level = quic_from_ossl_level(ossl_level);
|
||||||
|
|
||||||
if(ngtcp2_crypto_derive_and_install_rx_key(
|
if(ngtcp2_crypto_derive_and_install_rx_key(
|
||||||
qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
|
qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(ngtcp2_crypto_derive_and_install_tx_key(
|
if(ngtcp2_crypto_derive_and_install_tx_key(
|
||||||
qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
|
qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(level == NGTCP2_CRYPTO_LEVEL_APP) {
|
if(level == NGTCP2_CRYPTO_LEVEL_APP) {
|
||||||
|
@ -341,9 +341,7 @@ static int quic_init_ssl(struct quicsocket *qs)
|
||||||
/* this will need some attention when HTTPS proxy over QUIC get fixed */
|
/* this will need some attention when HTTPS proxy over QUIC get fixed */
|
||||||
const char * const hostname = qs->conn->host.name;
|
const char * const hostname = qs->conn->host.name;
|
||||||
|
|
||||||
if(qs->ssl)
|
DEBUGASSERT(!qs->ssl);
|
||||||
SSL_free(qs->ssl);
|
|
||||||
|
|
||||||
qs->ssl = SSL_new(qs->sslctx);
|
qs->ssl = SSL_new(qs->sslctx);
|
||||||
|
|
||||||
SSL_set_app_data(qs->ssl, qs);
|
SSL_set_app_data(qs->ssl, qs);
|
||||||
|
@ -375,11 +373,11 @@ static int secret_func(gnutls_session_t ssl,
|
||||||
|
|
||||||
if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
|
if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
|
||||||
ngtcp2_crypto_derive_and_install_rx_key(
|
ngtcp2_crypto_derive_and_install_rx_key(
|
||||||
qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
|
qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(ngtcp2_crypto_derive_and_install_tx_key(
|
if(ngtcp2_crypto_derive_and_install_tx_key(
|
||||||
qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
|
qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(level == NGTCP2_CRYPTO_LEVEL_APP) {
|
if(level == NGTCP2_CRYPTO_LEVEL_APP) {
|
||||||
|
@ -429,8 +427,8 @@ static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data,
|
||||||
ngtcp2_transport_params params;
|
ngtcp2_transport_params params;
|
||||||
|
|
||||||
if(ngtcp2_decode_transport_params(
|
if(ngtcp2_decode_transport_params(
|
||||||
¶ms, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS,
|
¶ms, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS,
|
||||||
data, data_size) != 0)
|
data, data_size) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(ngtcp2_conn_set_remote_transport_params(qs->qconn, ¶ms) != 0)
|
if(ngtcp2_conn_set_remote_transport_params(qs->qconn, ¶ms) != 0)
|
||||||
|
@ -471,8 +469,7 @@ static int quic_init_ssl(struct quicsocket *qs)
|
||||||
const char * const hostname = qs->conn->host.name;
|
const char * const hostname = qs->conn->host.name;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if(qs->ssl)
|
DEBUGASSERT(!qs->ssl);
|
||||||
gnutls_deinit(qs->ssl);
|
|
||||||
|
|
||||||
gnutls_init(&qs->ssl, GNUTLS_CLIENT);
|
gnutls_init(&qs->ssl, GNUTLS_CLIENT);
|
||||||
gnutls_session_set_ptr(qs->ssl, qs);
|
gnutls_session_set_ptr(qs->ssl, qs);
|
||||||
|
@ -782,6 +779,8 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
|
||||||
long port;
|
long port;
|
||||||
int qfd;
|
int qfd;
|
||||||
|
|
||||||
|
if(qs->conn)
|
||||||
|
Curl_quic_disconnect(conn, sockindex);
|
||||||
qs->conn = conn;
|
qs->conn = conn;
|
||||||
|
|
||||||
/* extract the used address as a string */
|
/* extract the used address as a string */
|
||||||
|
@ -880,11 +879,16 @@ static int ng_perform_getsock(const struct connectdata *conn,
|
||||||
return ng_getsock((struct connectdata *)conn, socks);
|
return ng_getsock((struct connectdata *)conn, socks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode qs_disconnect(struct quicsocket *qs)
|
static void qs_disconnect(struct quicsocket *qs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
if(qs->qlogfd != -1)
|
if(!qs->conn) /* already closed */
|
||||||
|
return;
|
||||||
|
qs->conn = NULL;
|
||||||
|
if(qs->qlogfd != -1) {
|
||||||
close(qs->qlogfd);
|
close(qs->qlogfd);
|
||||||
|
qs->qlogfd = -1;
|
||||||
|
}
|
||||||
if(qs->ssl)
|
if(qs->ssl)
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
SSL_free(qs->ssl);
|
SSL_free(qs->ssl);
|
||||||
|
@ -903,14 +907,22 @@ static CURLcode qs_disconnect(struct quicsocket *qs)
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
SSL_CTX_free(qs->sslctx);
|
SSL_CTX_free(qs->sslctx);
|
||||||
#endif
|
#endif
|
||||||
return CURLE_OK;
|
}
|
||||||
|
|
||||||
|
void Curl_quic_disconnect(struct connectdata *conn,
|
||||||
|
int tempindex)
|
||||||
|
{
|
||||||
|
if(conn->transport == TRNSPRT_QUIC)
|
||||||
|
qs_disconnect(&conn->hequic[tempindex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode ng_disconnect(struct connectdata *conn,
|
static CURLcode ng_disconnect(struct connectdata *conn,
|
||||||
bool dead_connection)
|
bool dead_connection)
|
||||||
{
|
{
|
||||||
(void)dead_connection;
|
(void)dead_connection;
|
||||||
return qs_disconnect(&conn->hequic[0]);
|
Curl_quic_disconnect(conn, 0);
|
||||||
|
Curl_quic_disconnect(conn, 1);
|
||||||
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ng_conncheck(struct connectdata *conn,
|
static unsigned int ng_conncheck(struct connectdata *conn,
|
||||||
|
|
|
@ -107,6 +107,14 @@ static CURLcode quiche_disconnect(struct connectdata *conn,
|
||||||
(void)dead_connection;
|
(void)dead_connection;
|
||||||
return qs_disconnect(qs);
|
return qs_disconnect(qs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Curl_quic_disconnect(struct connectdata *conn,
|
||||||
|
int tempindex)
|
||||||
|
{
|
||||||
|
if(conn->transport == TRNSPRT_QUIC)
|
||||||
|
qs_disconnect(&conn->hequic[tempindex]);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int quiche_conncheck(struct connectdata *conn,
|
static unsigned int quiche_conncheck(struct connectdata *conn,
|
||||||
unsigned int checks_to_perform)
|
unsigned int checks_to_perform)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче