← Commit list

9e6673fb7d

ldm0
ldm0
2026-09-11
SUCCESS Duration: 425s

Subject

conncache: avoid evicting connect-only connections

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/conncache.c+2 -1
@@ -323,7 +323,8 @@ static struct connectdata *cpool_bundle_get_oldest_idle(
while(curr) {
conn = Curl_node_elem(curr);
- if(!CONN_INUSE(conn)) {
+ /* CONNECT_ONLY sockets remain in use by the application. */
+ if(!CONN_INUSE(conn) && !conn->bits.close && !conn->bits.connect_only) {
/* Set higher score for the age passed since the connection was used */
unused_ms = curlx_ptimediff_ms(pnow, &conn->created) - conn->lastused_ms;
if(unused_ms > oldest_ms) {
tests/data/Makefile.am+2 -0
@@ -2090,6 +2090,8 @@ TESTCASES = \
test3228 \
test3229 \
test3230 \
+ test3231 \
+ test3232 \
\
test3300 \
test3301 \
tests/data/test3231+46 -0
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+CONNECT_ONLY
+CURLMOPT_MAX_HOST_CONNECTIONS
+</keywords>
+</info>
+
+<reply>
+<data crlf="headers" nocheck="yes">
+HTTP/1.1 200 OK
+Content-Length: 0
+Connection: close
+
+</data>
+</reply>
+
+<client>
+<server>
+http
+</server>
+<features>
+http
+</features>
+<name>
+CONNECT_ONLY survives the per-host connection limit
+</name>
+<tool>
+lib%TESTNUMBER
+</tool>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER
+</command>
+</client>
+
+<verify>
+<protocol crlf="headers">
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>
tests/data/test3232+46 -0
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+CONNECT_ONLY
+CURLMOPT_MAX_TOTAL_CONNECTIONS
+</keywords>
+</info>
+
+<reply>
+<data crlf="headers" nocheck="yes">
+HTTP/1.1 200 OK
+Content-Length: 0
+Connection: close
+
+</data>
+</reply>
+
+<client>
+<server>
+http
+</server>
+<features>
+http
+</features>
+<name>
+CONNECT_ONLY survives the total connection limit
+</name>
+<tool>
+lib3231
+</tool>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER
+</command>
+</client>
+
+<verify>
+<protocol crlf="headers">
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>
tests/libtest/Makefile.inc+1 -0
@@ -329,5 +329,6 @@ TESTS_C = \
lib3105.c \
lib3207.c \
lib3208.c \
+ lib3231.c \
lib5000.c \
lib5004.c
tests/libtest/lib3231.c+131 -0
@@ -0,0 +1,131 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "first.h"
+
+static CURLcode connect_only_complete(CURLM *multi, CURL *easy)
+{
+ CURLcode result = CURLE_OK;
+ CURLMsg *msg;
+ int running;
+ int msgs_left;
+ int numfds;
+
+ do {
+ multi_perform(multi, &running);
+ abort_on_test_timeout();
+ if(running)
+ multi_poll(multi, NULL, 0, 1000, &numfds);
+ } while(running);
+
+ msg = curl_multi_info_read(multi, &msgs_left);
+ if(!msg || msg->msg != CURLMSG_DONE || msg->easy_handle != easy ||
+ msg->data.result != CURLE_OK || msgs_left) {
+ curl_mfprintf(stderr, "Unexpected transfer completion\n");
+ result = TEST_ERR_FAILURE;
+ }
+
+test_cleanup:
+ return result;
+}
+
+static CURLcode test_lib3231(const char *URL)
+{
+ CURL *connect_only = NULL;
+ CURL *http = NULL;
+ CURLM *multi = NULL;
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = CURL_SOCKET_BAD;
+ curl_off_t pending;
+ int running;
+
+ start_test_timing();
+ global_init(CURL_GLOBAL_ALL);
+ multi_init(multi);
+ if(testnum == 3232)
+ multi_setopt(multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, 1L);
+ else
+ multi_setopt(multi, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);
+
+ easy_init(connect_only);
+ easy_setopt(connect_only, CURLOPT_URL, URL);
+ easy_setopt(connect_only, CURLOPT_CONNECT_ONLY, 1L);
+ easy_setopt(connect_only, CURLOPT_VERBOSE, 1L);
+ multi_add_handle(multi, connect_only);
+
+ result = connect_only_complete(multi, connect_only);
+ if(result)
+ goto test_cleanup;
+
+ result = curl_easy_getinfo(connect_only, CURLINFO_ACTIVESOCKET, &sock);
+ if(result)
+ goto test_cleanup;
+ if(sock == CURL_SOCKET_BAD) {
+ curl_mfprintf(stderr, "CONNECT_ONLY did not retain its socket\n");
+ result = TEST_ERR_FAILURE;
+ goto test_cleanup;
+ }
+
+ /* Do not send or receive on connect_only before competing for its slot:
+ the completed transfer has detached, but the application still owns it. */
+ easy_init(http);
+ easy_setopt(http, CURLOPT_URL, URL);
+ easy_setopt(http, CURLOPT_VERBOSE, 1L);
+ multi_add_handle(multi, http);
+ multi_perform(multi, &running);
+
+ result = curl_easy_getinfo(connect_only, CURLINFO_ACTIVESOCKET, &sock);
+ if(result)
+ goto test_cleanup;
+ if(sock == CURL_SOCKET_BAD) {
+ curl_mfprintf(stderr,
+ "Connection limit evicted the CONNECT_ONLY socket\n");
+ result = TEST_ERR_FAILURE;
+ goto test_cleanup;
+ }
+
+ if(curl_multi_get_offt(multi, CURLMINFO_XFERS_PENDING, &pending) ||
+ pending != 1) {
+ curl_mfprintf(stderr,
+ "HTTP transfer did not wait for a connection slot\n");
+ result = TEST_ERR_FAILURE;
+ goto test_cleanup;
+ }
+
+ /* Releasing the application-owned connection must let HTTP proceed. */
+ multi_remove_handle(multi, connect_only);
+ curl_easy_cleanup(connect_only);
+ connect_only = NULL;
+ result = connect_only_complete(multi, http);
+
+test_cleanup:
+ if(multi && connect_only)
+ curl_multi_remove_handle(multi, connect_only);
+ if(multi && http)
+ curl_multi_remove_handle(multi, http);
+ curl_easy_cleanup(connect_only);
+ curl_easy_cleanup(http);
+ curl_multi_cleanup(multi);
+ curl_global_cleanup();
+ return result;
+}