Skip to content

Instantly share code, notes, and snippets.

@baines

baines/main.c Secret

Created October 13, 2017 22:30
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 baines/cdb966f8d9e5fb35eeb28edfc0e57a0a to your computer and use it in GitHub Desktop.
Save baines/cdb966f8d9e5fb35eeb28edfc0e57a0a to your computer and use it in GitHub Desktop.
libcurl multi http2 bug test case
#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