-
-
Save baines/cdb966f8d9e5fb35eeb28edfc0e57a0a to your computer and use it in GitHub Desktop.
libcurl multi http2 bug test case
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 <errno.h> | |
#include <curl/curl.h> | |
#include <sys/epoll.h> | |
#include <sys/timerfd.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
enum { | |
FD_CURL = (1ul << 32), | |
FD_CURL_TIMER = (1ul << 33), | |
FD_WAIT_TIMER = (1ul << 34), | |
}; | |
#define WAIT_TIME (3*60+30) | |
static CURLM* curl; | |
static int curl_timer; | |
static int wait_timer; | |
static int epoll; | |
static int sent; | |
static int seconds; | |
static int curl_cb_socket(CURL* c, curl_socket_t sock, int what, void* uarg, void* sarg){ | |
int op = EPOLL_CTL_MOD; | |
//printf("Socket cb [%d] [%d]\n", sock, what); | |
if(!sarg){ | |
curl_multi_assign(curl, sock, (void*)(size_t)sock); | |
op = EPOLL_CTL_ADD; | |
} else if(what == CURL_POLL_REMOVE){ | |
curl_multi_assign(curl, sock, NULL); | |
op = EPOLL_CTL_DEL; | |
} | |
struct epoll_event ev = { | |
.data.u64 = (FD_CURL | sock) | |
}; | |
if(what & CURL_POLL_IN) ev.events |= EPOLLIN; | |
if(what & CURL_POLL_OUT) ev.events |= EPOLLOUT; | |
if(epoll_ctl(epoll, op, sock, &ev) == -1){ | |
perror("epoll_ctl"); | |
} | |
return 0; | |
} | |
static int curl_cb_timer(CURLM* multi, long timeout_ms, void* uarg){ | |
struct itimerspec it = {}; | |
//printf("Timer cb [%ld]\n", timeout_ms); | |
if(timeout_ms != -1){ | |
it.it_value.tv_sec = timeout_ms / 1000; | |
it.it_value.tv_nsec = 1 + (timeout_ms % 1000) * 1000000L; | |
} | |
timerfd_settime(curl_timer, 0, &it, NULL); | |
return 0; | |
} | |
static size_t net_curl_cb(char* ptr, size_t sz, size_t nmemb, void* data){ | |
return sz * nmemb; | |
} | |
static void curl_send(void){ | |
CURL* c = curl_easy_init(); | |
curl_easy_setopt(c, CURLOPT_URL, "https://en.wikipedia.org/"); | |
curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, &net_curl_cb); | |
curl_easy_setopt(c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); | |
curl_easy_setopt(c, CURLOPT_VERBOSE, 1L); | |
curl_multi_add_handle(curl, c); | |
} | |
static void net_update(int emask, int socket){ | |
int curlmask = 0; | |
if(emask & EPOLLIN) curlmask |= CURL_CSELECT_IN; | |
if(emask & EPOLLOUT) curlmask |= CURL_CSELECT_OUT; | |
if(emask & EPOLLERR) curlmask |= CURL_CSELECT_ERR; | |
int blah; | |
curl_multi_socket_action(curl, socket, curlmask, &blah); | |
CURLMsg* cm; | |
while((cm = curl_multi_info_read(curl, &blah))){ | |
if(cm->msg != CURLMSG_DONE) continue; | |
printf("--- Msg [%p] Result: [%d] [%s] ---\n", cm->easy_handle, cm->data.result, curl_easy_strerror(cm->data.result)); | |
if(!sent){ | |
sent = 1; | |
} else { | |
exit(0); | |
} | |
} | |
} | |
static void timerfd_clear(int fd){ | |
uint64_t blah; | |
ssize_t ret; | |
do { | |
ret = read(fd, &blah, 8); | |
} while(ret == -1 && errno == EAGAIN); | |
} | |
static void epoll_dispatch(struct epoll_event* e){ | |
if(e->data.u64 & FD_CURL){ | |
net_update(e->events, e->data.u64 & UINT32_MAX); | |
} else if(e->data.u64 & FD_CURL_TIMER){ | |
timerfd_clear(e->data.u64 & UINT32_MAX); | |
net_update(e->events, CURL_SOCKET_TIMEOUT); | |
} else if(e->data.u64 & FD_WAIT_TIMER){ | |
timerfd_clear(e->data.u64 & UINT32_MAX); | |
seconds++; | |
if(seconds < WAIT_TIME){ | |
printf("\r--- Sending second message in %d Seconds... --- ", WAIT_TIME - seconds); | |
fflush(stdout); | |
} else if(seconds == WAIT_TIME){ | |
puts(""); | |
curl_send(); | |
} | |
} | |
} | |
int main(void){ | |
epoll = epoll_create1(0); | |
curl_timer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); | |
wait_timer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); | |
struct epoll_event ev = { .events = EPOLLIN }; | |
ev.data.u64 = (FD_CURL_TIMER | curl_timer), | |
epoll_ctl(epoll, EPOLL_CTL_ADD, curl_timer, &ev); | |
ev.data.u64 = (FD_WAIT_TIMER | wait_timer), | |
epoll_ctl(epoll, EPOLL_CTL_ADD, wait_timer, &ev); | |
curl = curl_multi_init(); | |
curl_multi_setopt(curl, CURLMOPT_SOCKETFUNCTION, &curl_cb_socket); | |
curl_multi_setopt(curl, CURLMOPT_TIMERFUNCTION , &curl_cb_timer); | |
puts("--- Sending first message... ---"); | |
curl_send(); | |
struct itimerspec it = { | |
.it_value.tv_sec = 1, | |
.it_interval.tv_sec = 1, | |
}; | |
timerfd_settime(wait_timer, 0, &it, NULL); | |
struct epoll_event buf[8]; | |
for(;;){ | |
int n = epoll_wait(epoll, buf, 8, -1); | |
if(n < 0){ | |
perror("epoll"); | |
continue; | |
} | |
for(int i = 0; i < n; ++i){ | |
epoll_dispatch(buf + i); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment