Created
October 11, 2013 20:36
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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