From: Stefan Eissing Date: Thu, 11 Sep 2025 12:12:04 +0000 (+0200) Subject: ngtcp2: check error code on connect failure X-Git-Tag: rc-8_17_0-1~406 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=115fe808f2346b9c02d2720d8f575098e473a5d2;p=thirdparty%2Fcurl.git ngtcp2: check error code on connect failure Access the error codes of ngtcp2 when a connect attempt failes. Trace the information for analysis. Treat errors as permanent failure by default, trigger retrying only when the server refused without indicating an error. Closes #18521 --- diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 6470f1506d..3f7c58d08a 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2578,11 +2578,31 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, out: if(result == CURLE_RECV_ERROR && ctx->qconn && ngtcp2_conn_in_draining_period(ctx->qconn)) { - /* When a QUIC server instance is shutting down, it may send us a - * CONNECTION_CLOSE right away. Our connection then enters the DRAINING - * state. The CONNECT may work in the near future again. Indicate - * that as a "weird" reply. */ - result = CURLE_WEIRD_SERVER_REPLY; + const ngtcp2_ccerr *cerr = ngtcp2_conn_get_ccerr(ctx->qconn); + + result = CURLE_COULDNT_CONNECT; + if(cerr) { + CURL_TRC_CF(data, cf, "connect error, type=%d, code=%" + FMT_PRIu64, + cerr->type, (curl_uint64_t)cerr->error_code); + switch(cerr->type) { + case NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION: + CURL_TRC_CF(data, cf, "error in version negotiation"); + break; + default: + if(cerr->error_code >= NGTCP2_CRYPTO_ERROR) { + CURL_TRC_CF(data, cf, "crypto error, tls alert=%u", + (unsigned int)(cerr->error_code & 0xffu)); + } + else if(cerr->error_code == NGTCP2_CONNECTION_REFUSED) { + CURL_TRC_CF(data, cf, "connection refused by server"); + /* When a QUIC server instance is shutting down, it may send us a + * CONNECTION_CLOSE with this code right away. We want + * to keep on trying in this case. */ + result = CURLE_WEIRD_SERVER_REPLY; + } + } + } } #ifndef CURL_DISABLE_VERBOSE_STRINGS diff --git a/tests/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py index 0bd46ac360..dfb416334c 100644 --- a/tests/http/testenv/nghttpx.py +++ b/tests/http/testenv/nghttpx.py @@ -124,15 +124,16 @@ class Nghttpx: running = self._process self._process = None os.kill(running.pid, signal.SIGQUIT) - end_wait = datetime.now() + timeout + end_wait = datetime.now() + timedelta(seconds=5) if not self.start(wait_live=False): self._process = running return False while datetime.now() < end_wait: try: log.debug(f'waiting for nghttpx({running.pid}) to exit.') - running.wait(2) + running.wait(1) log.debug(f'nghttpx({running.pid}) terminated -> {running.returncode}') + running = None break except subprocess.TimeoutExpired: log.warning(f'nghttpx({running.pid}), not shut down yet.') @@ -142,7 +143,7 @@ class Nghttpx: os.kill(running.pid, signal.SIGKILL) running.terminate() running.wait(1) - return self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT)) + return self.wait_live(timeout=timeout) return False def wait_dead(self, timeout: timedelta):