Changes in curl 7.64.1 close cause curl to close the socket in the connection cache upon reuse if CURLOPT_CONNECT_ONLY and CURLOPT_MAXCONNECTS are both set to 1 - this makes using curl_send and curl_recv impossible because curl reports "Failed to get recent socket"
I did this
- create an easy handle
- Set options to CURLOPT_URL ("http://www.example.com"), CURLOPT_VERBOSE (1L), CURLOPT_NOPROGRESS (1L), CURLOPT_CONNECT_ONLY (1L), and CURLOPT_MAXCONNECTS (1L)
- Execute the following
a. call curl_easy_perform - watch it succeed.
b. use curl_send to send the following "GET / HTTP/1.1\r\nHost: www.example.com\r\n"
c. use curl_recv to recv the response
- repeat step 3. curl informs you that the "connection cache is full, closing the oldest one", curl_easy_perform will succeed, but curl_send will fail with error 1 unsupported protocol
I expected the following
The handle can be reused for both send and recv and the socket doesn't get closed.
curl/libcurl version
7.64.1.
tested on 7.60, 7.63, 7.64.0 - all work, the problem seems isolated to 7.64.1
[curl -V output]
operating system
Linux and others
demonstration
this sample demonstrates the problem
#include <stdio.h>
#include <string.h>
#include <curl.h>
int SendRecv(CURL* curl, char* buffer, size_t buffersize)
{
size_t nsize = 0, size = 0;
char getMsg[] = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
CURLcode res = curl_easy_send(curl, getMsg, strlen(getMsg), &size);
printf("send curl code:%s (%d),\n%s\n", curl_easy_strerror(res), res, getMsg);
memset(buffer, 0, buffersize);
do
{
res = curl_easy_recv(curl, buffer + nsize, buffersize - nsize, &size);
nsize += size;
} while (buffersize - nsize > 0 && res == CURLE_AGAIN);
buffer[size < 300 ? size : 300] = 0; // just show some of it for illustrative purposes
printf("recv curl code:%s (%d)\n%s\n", curl_easy_strerror(res), res, buffer);
}
int main(int argc, char* argv[])
{
const char* url = "http://www.example.com";
CURL* curl = NULL;
CURLcode res;
char buffer[4096];
res = curl_global_init(CURL_GLOBAL_DEFAULT);
if( res != CURLE_OK )
{
goto bail;
}
curl = curl_easy_init();
if (curl == NULL)
{
goto bail;
};
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 1L);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
printf("\n curl_easy_perform failed! %s (%d).\n", curl_easy_strerror(res), res);
goto bail;
}
printf("\n curl_easy_perform succeeded!\n");
SendRecv(curl, buffer, sizeof(buffer));
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
printf("\n curl_easy_perform failed! %s (%d).\n", curl_easy_strerror(res), res);
goto bail;
}
printf("\n curl_easy_perform succeeded!\n");
SendRecv(curl, buffer, sizeof(buffer));
bail:
curl_easy_cleanup(curl);
curl_global_cleanup();
return 0;
}
problem
I tracked the problem to the the below code
diff --git a/lib/conncache.c b/lib/conncache.c
index 39302ba7b..d61b3bcf7 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -477,7 +477,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
while(curr) {
conn = curr->ptr;
- if(!CONN_INUSE(conn) && !conn->data) {
+ if(!CONN_INUSE(conn)/* && !conn->data*/) {
/* Set higher score for the age passed since the connection was used */
score = Curl_timediff(now, conn->now);
@@ -535,7 +535,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
while(curr) {
conn = curr->ptr;
- if(!CONN_INUSE(conn) && !conn->data) {
+ if(!CONN_INUSE(conn) /* && !conn->data */) {
/* Set higher score for the age passed since the connection was used */
score = Curl_timediff(now, conn->now);
Changes in curl 7.64.1 close cause curl to close the socket in the connection cache upon reuse if CURLOPT_CONNECT_ONLY and CURLOPT_MAXCONNECTS are both set to 1 - this makes using curl_send and curl_recv impossible because curl reports "Failed to get recent socket"
I did this
a. call curl_easy_perform - watch it succeed.
b. use curl_send to send the following "GET / HTTP/1.1\r\nHost: www.example.com\r\n"
c. use curl_recv to recv the response
I expected the following
The handle can be reused for both send and recv and the socket doesn't get closed.
curl/libcurl version
7.64.1.
tested on 7.60, 7.63, 7.64.0 - all work, the problem seems isolated to 7.64.1
[curl -V output]
operating system
Linux and others
demonstration
this sample demonstrates the problem
problem
I tracked the problem to the the below code