Skip to content

Instantly share code, notes, and snippets.

@romuloceccon
Created October 11, 2013 20:36
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 romuloceccon/6941606 to your computer and use it in GitHub Desktop.
Save romuloceccon/6941606 to your computer and use it in GitHub Desktop.
This example reproduces an issue with curl 7.32 or older: when adding an easy handle which sets CURLOPT_RESOLVE to a multi handle curl will sometimes consider the entry expired and check the default DNS servers instead.
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <curl/curl.h>
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
return size * nmemb;
}
int debug_callback(CURL *curl, curl_infotype info, char *msg, size_t len, void *ptr)
{
if (info == CURLINFO_TEXT)
fprintf(stderr, "debug: %.*s", (int) len, msg);
return 0;
}
int do_request(CURLM *multi_handle, char const *url, char const *resolve)
{
CURL *handle;
int still_running;
int i;
int result = 0;
struct curl_slist *resolve_list = NULL;
CURLMsg *msg;
int msgs_left;
handle = curl_easy_init();
resolve_list = curl_slist_append(resolve_list, resolve);
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(handle, CURLOPT_RESOLVE, resolve_list);
curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, debug_callback);
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
curl_easy_setopt(handle, CURLOPT_DNS_CACHE_TIMEOUT, 2);
curl_multi_add_handle(multi_handle, handle);
curl_multi_perform(multi_handle, &still_running);
do {
struct timeval timeout;
int rc; /* select() return code */
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -1;
long curl_timeo = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
/* set a suitable timeout to play around with */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
curl_multi_timeout(multi_handle, &curl_timeo);
if(curl_timeo >= 0) {
timeout.tv_sec = curl_timeo / 1000;
if(timeout.tv_sec > 1)
timeout.tv_sec = 1;
else
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
/* get file descriptors from the transfers */
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
/* In a real-world program you OF COURSE check the return code of the
function calls. On success, the value of maxfd is guaranteed to be
greater or equal than -1. We call select(maxfd + 1, ...), specially in
case of (maxfd == -1), we call select(0, ...), which is basically equal
to sleep. */
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc) {
case -1:
/* select error */
break;
case 0: /* timeout */
default: /* action */
curl_multi_perform(multi_handle, &still_running);
break;
}
} while(still_running);
while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
if (msg->msg == CURLMSG_DONE && msg->easy_handle == handle) {
result = msg->data.result;
printf("HTTP transfer completed with status %d\n", result);
}
}
curl_multi_remove_handle(multi_handle, handle);
curl_easy_cleanup(handle);
curl_slist_free_all(resolve_list);
return result;
}
int main(void)
{
int i;
CURLM *multi;
char const *url = "http://fake.host/";
char const *resolve = "fake.host:80:137.56.161.173";
multi = curl_multi_init();
for (i = 0; i < 30; i++)
{
if (do_request(multi, url, resolve) == CURLE_COULDNT_RESOLVE_HOST)
break;
/* if you remove the following call the problem apparently goes away */
sleep(2);
}
curl_multi_cleanup(multi);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment