Last active
December 25, 2015 15:19
-
-
Save jbandela/6997417 to your computer and use it in GitHub Desktop.
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 <stdlib.h> | |
#include <curl/curl.h> | |
#include <cppcomponents_libuv/cppcomponents_libuv.hpp> | |
#include<vector> | |
using namespace cppcomponents_libuv; | |
using namespace cppcomponents; | |
CURLM *curl_handle; | |
Timer timeout; | |
typedef struct curl_context_s { | |
use<IPoll> poll_handle; | |
std::vector<char> curl_error = std::vector<char>(CURL_ERROR_SIZE + 1 ); | |
} curl_context_t; | |
curl_context_t* create_curl_context() | |
{ | |
curl_context_t *context; | |
context = new curl_context_t; | |
//context->poll_handle = Poll{ sockfd, false }; | |
return context; | |
} | |
// | |
//void curl_close_cb(uv_handle_t *handle) | |
//{ | |
// curl_context_t* context = (curl_context_t*)handle->data; | |
// free(context); | |
//} | |
void destroy_curl_context(curl_context_t *context) | |
{ | |
//uv_close((uv_handle_t*)&context->poll_handle, curl_close_cb); | |
context->poll_handle.Close().Then([context](Future<void> f){ | |
delete context; | |
}); | |
} | |
size_t callback(char *ptr, size_t size, size_t nmemb, void *userdata){ | |
std::string s(ptr, ptr + size*nmemb); | |
return s.size(); | |
} | |
void add_download(const char *url, int num) | |
{ | |
char filename[50]; | |
FILE *file; | |
CURL *handle; | |
sprintf(filename, "%d.download", num); | |
file = fopen(filename, "w"); | |
if (file == NULL) { | |
fprintf(stderr, "Error opening %s\n", filename); | |
return; | |
} | |
auto pcontext = create_curl_context(); | |
handle = curl_easy_init(); | |
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, callback); | |
curl_easy_setopt(handle, CURLOPT_URL, url); | |
//curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0); | |
//curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); | |
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, &(pcontext->curl_error[0])); | |
curl_easy_setopt(handle, CURLOPT_PRIVATE, reinterpret_cast<char*>(pcontext)); | |
curl_multi_add_handle(curl_handle, handle); | |
fprintf(stderr, "Added download %s -> %s\n", url, filename); | |
} | |
void curl_perform(use<IPoll>, int status, int events, curl_socket_t sockfd) | |
{ | |
int running_handles; | |
int flags = 0; | |
char *done_url; | |
CURLMsg *message; | |
int pending; | |
timeout.Stop(); | |
if (events & Constants::PollEvent::Readable) | |
flags |= CURL_CSELECT_IN; | |
if (events & Constants::PollEvent::Writable) | |
flags |= CURL_CSELECT_OUT; | |
curl_multi_socket_action(curl_handle, sockfd, flags, | |
&running_handles); | |
while ((message = curl_multi_info_read(curl_handle, &pending))) { | |
switch (message->msg) { | |
case CURLMSG_DONE: | |
curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, | |
&done_url); | |
printf("%s DONE\n", done_url); | |
{ | |
auto easy = message->easy_handle; | |
char* charpcontext = 0; | |
curl_easy_getinfo(easy, CURLINFO_PRIVATE, &charpcontext); | |
auto pcontext = reinterpret_cast<curl_context_t*>(charpcontext); | |
curl_multi_remove_handle(curl_handle, message->easy_handle); | |
curl_easy_cleanup(easy); | |
destroy_curl_context(pcontext); | |
} | |
break; | |
default: | |
fprintf(stderr, "CURLMSG default\n"); | |
abort(); | |
} | |
} | |
} | |
//void on_timeout(uv_timer_t *req, int status) | |
//{ | |
// int running_handles; | |
// curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, | |
// &running_handles); | |
//} | |
void start_timeout(CURLM *multi, long timeout_ms, void *userp) | |
{ | |
if (timeout_ms <= 0) | |
timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in | |
a bit */ | |
timeout.Start([multi](use<ITimer>, int status){ | |
int running_handles; | |
curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, | |
&running_handles); | |
}, std::chrono::milliseconds{ timeout_ms }); | |
} | |
int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, | |
void *) | |
{ | |
char* charpcontext = 0; | |
curl_easy_getinfo(easy, CURLINFO_PRIVATE, &charpcontext); | |
auto curl_context = reinterpret_cast<curl_context_t*>(charpcontext); | |
if (action == CURL_POLL_IN || action == CURL_POLL_OUT) { | |
if (!(curl_context->poll_handle)) { | |
curl_context->poll_handle = Poll{ s, false }; | |
} | |
} | |
switch (action) { | |
case CURL_POLL_IN: | |
using namespace std::placeholders; | |
curl_context->poll_handle.Start(Constants::PollEvent::Readable, std::bind(curl_perform,_1, _2, _3, s)); | |
break; | |
case CURL_POLL_OUT: | |
curl_context->poll_handle.Start(Constants::PollEvent::Writable, std::bind(curl_perform,_1, _2, _3, s)); | |
break; | |
case CURL_POLL_REMOVE: | |
if (curl_context->poll_handle) { | |
curl_context->poll_handle.Stop(); | |
curl_context->poll_handle = nullptr; | |
} | |
break; | |
default: | |
abort(); | |
} | |
return 0; | |
} | |
int main(int argc, char **argv) | |
{ | |
auto loop = Loop::DefaultLoop(); | |
if (argc <= 1) | |
return 0; | |
if (curl_global_init(CURL_GLOBAL_ALL)) { | |
fprintf(stderr, "Could not init cURL\n"); | |
return 1; | |
} | |
curl_handle = curl_multi_init(); | |
curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); | |
curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); | |
while (argc-- > 1) { | |
add_download(argv[argc], argc); | |
} | |
loop.Run(); | |
curl_multi_cleanup(curl_handle); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment