Skip to content

Instantly share code, notes, and snippets.

@jeroen
Last active January 8, 2019 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeroen/9ae92521411479fe58a19d2ce588dec9 to your computer and use it in GitHub Desktop.
Save jeroen/9ae92521411479fe58a19d2ce588dec9 to your computer and use it in GitHub Desktop.
libcurl fd bug
/* Test program to verify that CURLMOPT_MAX_TOTAL_CONNECTIONS works as expected */
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include <curl/curl.h>
/* Configure max concurrent connections */
#define MY_MAXCON 4
/* Count open connections from the FD's */
int print_multi_fd(CURLM *multi_handle){
int max_fd, i, num_read = 0, num_write = 0, num_exc = 0;
fd_set read_fd_set, write_fd_set, exc_fd_set;
FD_ZERO(&read_fd_set);
FD_ZERO(&write_fd_set);
FD_ZERO(&exc_fd_set);
curl_multi_fdset(multi_handle, &read_fd_set, &write_fd_set, &exc_fd_set, &max_fd);
for (i = 0; i <= max_fd; i++){
if (FD_ISSET(i, &read_fd_set)) num_read++;
if (FD_ISSET(i, &write_fd_set)) num_write++;
if (FD_ISSET(i, &exc_fd_set)) num_exc++;
}
fprintf(stderr, "Open Descriptors: READ %d, WRITE %d, EXC %d\n", num_read, num_write, num_exc);
return num_read;
}
int main(void){
int ret = 0;
CURLM *multi_handle;
FILE *output = fopen("/dev/null", "w");
curl_global_init(CURL_GLOBAL_DEFAULT);
/* init a multi stack */
multi_handle = curl_multi_init();
/* disable multiplexing so request count matches connection count */
curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_NOTHING);
curl_multi_setopt(multi_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, (long) MY_MAXCON);
curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, (long) MY_MAXCON);
/* Add some requests */
for(int i = 7; i >= 0; i--){
char url[100] = "";
sprintf(url, "https://eu.httpbin.org/delay/%d", i);
CURL *http_handle = curl_easy_init();
curl_easy_setopt(http_handle, CURLOPT_URL, url);
curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, output);
curl_multi_add_handle(multi_handle, http_handle);
}
/* we start some action by calling perform right away */
int running_handles = 0; /* keep number of running handles */
do {
curl_multi_perform(multi_handle, &running_handles);
int msgq = 0;
do {
CURLMsg *m = curl_multi_info_read(multi_handle, &msgq);
if(m && (m->msg == CURLMSG_DONE)){
long res_status;
curl_easy_getinfo(m->easy_handle, CURLINFO_RESPONSE_CODE, &res_status);
fprintf(stderr, "Req complete (HTTP %ld). Remaining: %d (max con: %d)\n", res_status, running_handles, MY_MAXCON);
int expected_con = fmin(running_handles, MY_MAXCON);
int num_read = print_multi_fd(multi_handle);
if(num_read != expected_con){
fprintf(stderr, "FAIL: read_fd_set does not have expected length %d!\n", expected_con);
ret = 1;
}
curl_multi_remove_handle(multi_handle, m->easy_handle);
curl_easy_cleanup(m->easy_handle);
}
} while(msgq > 0);
} while(running_handles > 0);
curl_multi_cleanup(multi_handle);
curl_global_cleanup();
if(!ret)
fprintf(stderr, "SUCCESS! All good!\n");
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment