move the libevent2 <> CURL stuff into the library
This commit is contained in:
parent
1be026187c
commit
42183539d3
@ -11,11 +11,13 @@ SET(SOURCES
|
|||||||
"include/dc/account.h"
|
"include/dc/account.h"
|
||||||
"include/dc/api.h"
|
"include/dc/api.h"
|
||||||
"include/dc/apisync.h"
|
"include/dc/apisync.h"
|
||||||
|
"include/dc/loop.h"
|
||||||
"include/dc/refable.h"
|
"include/dc/refable.h"
|
||||||
"include/dc/util.h"
|
"include/dc/util.h"
|
||||||
"src/account.c"
|
"src/account.c"
|
||||||
"src/api.c"
|
"src/api.c"
|
||||||
"src/apisync.c"
|
"src/apisync.c"
|
||||||
|
"src/loop.c"
|
||||||
"src/refable.c"
|
"src/refable.c"
|
||||||
"src/util.c"
|
"src/util.c"
|
||||||
)
|
)
|
||||||
|
48
libdc/include/dc/loop.h
Normal file
48
libdc/include/dc/loop.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef DC_LOOP_H
|
||||||
|
#define DC_LOOP_H
|
||||||
|
|
||||||
|
#include <dc/api.h>
|
||||||
|
|
||||||
|
#include <event.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct dc_loop_;
|
||||||
|
typedef struct dc_loop_ *dc_loop_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple CURLM <--> libevent2 loop and handler if you don't want
|
||||||
|
* to bother rolling your own.
|
||||||
|
*/
|
||||||
|
dc_loop_t dc_loop_new(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you already have either the CURL multi handle, or the event
|
||||||
|
* base handle, use this function. Either can be NULL. If both are
|
||||||
|
* NULL both are allocated for you.
|
||||||
|
*/
|
||||||
|
dc_loop_t dc_loop_new_full(struct event_base *base, CURLM *multi);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the CURL multi handle in use by this loop.
|
||||||
|
*/
|
||||||
|
CURLM *dc_loop_curl(dc_loop_t l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the event base used by this loop.
|
||||||
|
*/
|
||||||
|
struct event_base *dc_loop_event_base(dc_loop_t l);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an API handle that this loop should feed.
|
||||||
|
*/
|
||||||
|
void dc_loop_add_api(dc_loop_t loop, dc_api_t api);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop once, and process one message in the queues of the event
|
||||||
|
* base, and one message from the queue of the CURL multi events.
|
||||||
|
*/
|
||||||
|
bool dc_loop_once(dc_loop_t l);
|
||||||
|
|
||||||
|
#endif
|
221
libdc/src/loop.c
221
libdc/src/loop.c
@ -1,6 +1,223 @@
|
|||||||
#include <dc/loop.h>
|
#include <dc/loop.h>
|
||||||
|
#include <dc/refable.h>
|
||||||
|
|
||||||
struct nc_loop_
|
#include "internal.h"
|
||||||
|
|
||||||
|
struct dc_loop_
|
||||||
{
|
{
|
||||||
nc_refable_t ref;
|
dc_refable_t ref;
|
||||||
|
|
||||||
|
struct event_base *base;
|
||||||
|
struct event *timer;
|
||||||
|
CURLM *multi;
|
||||||
|
|
||||||
|
bool base_owner;
|
||||||
|
bool multi_owner;
|
||||||
|
|
||||||
|
GPtrArray *apis;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void dc_loop_free(dc_loop_t p)
|
||||||
|
{
|
||||||
|
return_if_true(p == NULL,);
|
||||||
|
|
||||||
|
if (p->timer != NULL) {
|
||||||
|
evtimer_del(p->timer);
|
||||||
|
event_free(p->timer);
|
||||||
|
p->timer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->multi_owner && p->multi != NULL) {
|
||||||
|
curl_multi_cleanup(p->multi);
|
||||||
|
p->multi = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->base_owner && p->base != NULL) {
|
||||||
|
event_base_free(p->base);
|
||||||
|
p->base = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->apis != NULL) {
|
||||||
|
g_ptr_array_unref(p->apis);
|
||||||
|
p->apis = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void socket_handler(int sock, short what, void *data)
|
||||||
|
{
|
||||||
|
int unused = 0;
|
||||||
|
dc_loop_t loop = (dc_loop_t)data;
|
||||||
|
|
||||||
|
if ((what & EV_READ) == EV_READ) {
|
||||||
|
curl_multi_socket_action(loop->multi, sock, CURL_CSELECT_IN, &unused);
|
||||||
|
} else if ((what & EV_WRITE) == EV_WRITE) {
|
||||||
|
curl_multi_socket_action(loop->multi, sock, CURL_CSELECT_OUT, &unused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mcurl_handler(CURL *easy, curl_socket_t s, int what, void *userp, void *socketp)
|
||||||
|
{
|
||||||
|
struct event *event = (struct event *)socketp;
|
||||||
|
dc_loop_t loop = (dc_loop_t)userp;
|
||||||
|
|
||||||
|
if (what == CURL_POLL_REMOVE) {
|
||||||
|
if (event != NULL) {
|
||||||
|
event_del(event);
|
||||||
|
event_free(event);
|
||||||
|
curl_multi_assign(loop->multi, s, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int stat =
|
||||||
|
((what & CURL_POLL_IN) ? EV_READ : 0) |
|
||||||
|
((what & CURL_POLL_OUT) ? EV_WRITE : 0) |
|
||||||
|
EV_PERSIST
|
||||||
|
;
|
||||||
|
|
||||||
|
if (event == NULL) {
|
||||||
|
event = event_new(loop->base, s, stat, socket_handler, loop);
|
||||||
|
if (event == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
curl_multi_assign(loop->multi, s, event);
|
||||||
|
} else {
|
||||||
|
event_del(event);
|
||||||
|
event_assign(event, loop->base, s, stat, socket_handler,loop);
|
||||||
|
event_add(event, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_handler(int sock, short what, void *data)
|
||||||
|
{
|
||||||
|
int running = 0;
|
||||||
|
dc_loop_t loop = (dc_loop_t)data;
|
||||||
|
curl_multi_socket_action(loop->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcurl_timer(CURLM *curl, long timeout, void *ptr)
|
||||||
|
{
|
||||||
|
int running = 0;
|
||||||
|
struct timeval tm;
|
||||||
|
dc_loop_t loop = (dc_loop_t)ptr;
|
||||||
|
|
||||||
|
if (timeout == -1) {
|
||||||
|
evtimer_del(loop->timer);
|
||||||
|
} else if (timeout == 0) {
|
||||||
|
curl_multi_socket_action(loop->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
|
} else if (timeout > 0) {
|
||||||
|
tm.tv_sec = timeout / 1000;
|
||||||
|
tm.tv_usec = (timeout % 1000) * 1000;
|
||||||
|
evtimer_add(loop->timer, &tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_loop_t dc_loop_new(void)
|
||||||
|
{
|
||||||
|
return dc_loop_new_full(NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_loop_t dc_loop_new_full(struct event_base *base, CURLM *multi)
|
||||||
|
{
|
||||||
|
dc_loop_t ptr = calloc(1, sizeof(struct dc_loop_));
|
||||||
|
return_if_true(ptr == NULL, NULL);
|
||||||
|
|
||||||
|
ptr->ref.cleanup = (dc_cleanup_t)dc_loop_free;
|
||||||
|
|
||||||
|
if (base != NULL) {
|
||||||
|
ptr->base = base;
|
||||||
|
ptr->base_owner = false;
|
||||||
|
} else {
|
||||||
|
ptr->base = event_base_new();
|
||||||
|
goto_if_true(ptr->base == NULL, fail);
|
||||||
|
ptr->base_owner = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multi != NULL) {
|
||||||
|
ptr->multi = multi;
|
||||||
|
ptr->multi_owner = false;
|
||||||
|
} else {
|
||||||
|
ptr->multi = curl_multi_init();
|
||||||
|
goto_if_true(ptr->multi == NULL, fail);
|
||||||
|
ptr->multi_owner = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr->apis = g_ptr_array_new();
|
||||||
|
goto_if_true(ptr->apis == NULL, fail);
|
||||||
|
|
||||||
|
ptr->timer = evtimer_new(ptr->base, timer_handler, ptr);
|
||||||
|
goto_if_true(ptr->timer == NULL, fail);
|
||||||
|
|
||||||
|
curl_multi_setopt(ptr->multi, CURLMOPT_SOCKETDATA, ptr);
|
||||||
|
curl_multi_setopt(ptr->multi, CURLMOPT_SOCKETFUNCTION, mcurl_handler);
|
||||||
|
|
||||||
|
curl_multi_setopt(ptr->multi, CURLMOPT_TIMERDATA, ptr);
|
||||||
|
curl_multi_setopt(ptr->multi, CURLMOPT_TIMERFUNCTION, mcurl_timer);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
dc_loop_free(ptr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLM *dc_loop_curl(dc_loop_t l)
|
||||||
|
{
|
||||||
|
return_if_true(l == NULL, NULL);
|
||||||
|
return l->multi;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct event_base *dc_loop_event_base(dc_loop_t l)
|
||||||
|
{
|
||||||
|
return_if_true(l == NULL, NULL);
|
||||||
|
return l->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dc_loop_add_api(dc_loop_t l, dc_api_t a)
|
||||||
|
{
|
||||||
|
return_if_true(l == NULL || a == NULL,);
|
||||||
|
dc_api_t p = dc_ref(a);
|
||||||
|
|
||||||
|
dc_api_set_event_base(p, l->base);
|
||||||
|
dc_api_set_curl_multi(p, l->multi);
|
||||||
|
|
||||||
|
g_ptr_array_add(l->apis, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dc_loop_once(dc_loop_t l)
|
||||||
|
{
|
||||||
|
return_if_true(l == NULL, false);
|
||||||
|
|
||||||
|
int ret = 0, remain = 0;
|
||||||
|
struct CURLMsg *msg = NULL;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
ret = event_base_loop(l->base, EVLOOP_ONCE|EVLOOP_NONBLOCK);
|
||||||
|
if (ret < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = curl_multi_info_read(l->multi, &remain);
|
||||||
|
if (msg != NULL) {
|
||||||
|
if (remain <= 0) {
|
||||||
|
if (evtimer_pending(l->timer, NULL)) {
|
||||||
|
evtimer_del(l->timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msg->msg == CURLMSG_DONE) {
|
||||||
|
for (i = 0; i < l->apis->len; i++) {
|
||||||
|
dc_api_t api = g_ptr_array_index(l->apis, i);
|
||||||
|
dc_api_signal(api, msg->easy_handle, msg->data.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
144
ncdc/src/ncdc.c
144
ncdc/src/ncdc.c
@ -1,14 +1,15 @@
|
|||||||
#include <ncdc/ncdc.h>
|
#include <ncdc/ncdc.h>
|
||||||
|
|
||||||
|
#include <dc/refable.h>
|
||||||
#include <dc/api.h>
|
#include <dc/api.h>
|
||||||
|
#include <dc/loop.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* event base for libevent
|
/* event base for libevent
|
||||||
*/
|
*/
|
||||||
struct event_base *base = NULL;
|
|
||||||
struct event *stdin_ev = NULL;
|
struct event *stdin_ev = NULL;
|
||||||
struct event *timer = NULL;
|
|
||||||
|
|
||||||
/* we loop in a different thread
|
/* we loop in a different thread
|
||||||
*/
|
*/
|
||||||
@ -20,14 +21,9 @@ char *dc_config_file = NULL;
|
|||||||
|
|
||||||
static GKeyFile *config = NULL;
|
static GKeyFile *config = NULL;
|
||||||
|
|
||||||
/* global curl multi for API access
|
dc_loop_t loop = NULL;
|
||||||
*/
|
|
||||||
CURLM *curl = NULL;
|
|
||||||
|
|
||||||
dc_api_t api = NULL;
|
dc_api_t api = NULL;
|
||||||
|
|
||||||
static void handle_multi_info(void);
|
|
||||||
|
|
||||||
static void sighandler(int sig)
|
static void sighandler(int sig)
|
||||||
{
|
{
|
||||||
exit(3);
|
exit(3);
|
||||||
@ -41,128 +37,39 @@ static void cleanup(void)
|
|||||||
stdin_ev = NULL;
|
stdin_ev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer != NULL) {
|
|
||||||
evtimer_del(timer);
|
|
||||||
event_free(timer);
|
|
||||||
timer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
done = true;
|
done = true;
|
||||||
pthread_join(looper, NULL);
|
pthread_join(looper, NULL);
|
||||||
|
|
||||||
curl_multi_cleanup(curl);
|
dc_unref(api);
|
||||||
curl = NULL;
|
dc_unref(loop);
|
||||||
|
|
||||||
event_base_free(base);
|
|
||||||
base = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stdin_handler(int sock, short what, void *data)
|
static void stdin_handler(int sock, short what, void *data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mcurl_socket_handler(int sock, short what, void *data)
|
|
||||||
{
|
|
||||||
int unused = 0;
|
|
||||||
|
|
||||||
if ((what & EV_READ) == EV_READ) {
|
|
||||||
curl_multi_socket_action(curl, sock, CURL_CSELECT_IN, &unused);
|
|
||||||
} else if ((what & EV_WRITE) == EV_WRITE) {
|
|
||||||
curl_multi_socket_action(curl, sock, CURL_CSELECT_OUT, &unused);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_handler(int sock, short what, void *data)
|
|
||||||
{
|
|
||||||
int running = 0;
|
|
||||||
curl_multi_socket_action(curl, CURL_SOCKET_TIMEOUT, 0, &running);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mcurl_timer(CURLM *curl, long timeout, void *ptr)
|
|
||||||
{
|
|
||||||
int running = 0;
|
|
||||||
struct timeval tm;
|
|
||||||
|
|
||||||
if (timeout == -1) {
|
|
||||||
evtimer_del(timer);
|
|
||||||
} else if (timeout == 0) {
|
|
||||||
curl_multi_socket_action(curl, CURL_SOCKET_TIMEOUT, 0, &running);
|
|
||||||
} else if (timeout > 0) {
|
|
||||||
tm.tv_sec = timeout / 1000;
|
|
||||||
tm.tv_usec = (timeout % 1000) * 1000;
|
|
||||||
evtimer_add(timer, &tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
mcurl_handler(CURL *easy, curl_socket_t s, int what, void *userp, void *socketp)
|
|
||||||
{
|
|
||||||
struct event *event = (struct event *)socketp;
|
|
||||||
|
|
||||||
if (what == CURL_POLL_REMOVE) {
|
|
||||||
if (event != NULL) {
|
|
||||||
event_del(event);
|
|
||||||
event_free(event);
|
|
||||||
curl_multi_assign(curl, s, NULL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int stat =
|
|
||||||
((what & CURL_POLL_IN) ? EV_READ : 0) |
|
|
||||||
((what & CURL_POLL_OUT) ? EV_WRITE : 0) |
|
|
||||||
EV_PERSIST
|
|
||||||
;
|
|
||||||
|
|
||||||
if (event == NULL) {
|
|
||||||
event = event_new(base, s, stat, mcurl_socket_handler, NULL);
|
|
||||||
if (event == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
curl_multi_assign(curl, s, event);
|
|
||||||
} else {
|
|
||||||
event_del(event);
|
|
||||||
event_assign(event, base, s, stat, mcurl_socket_handler, NULL);
|
|
||||||
event_add(event, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool init_everything(void)
|
static bool init_everything(void)
|
||||||
{
|
{
|
||||||
evthread_use_pthreads();
|
evthread_use_pthreads();
|
||||||
|
|
||||||
base = event_base_new();
|
loop = dc_loop_new();
|
||||||
return_if_true(base == NULL, false);
|
return_if_true(loop == NULL, false);
|
||||||
|
|
||||||
/* add handle for STDIN, this info will then be fed to the UI
|
/* add handle for STDIN, this info will then be fed to the UI
|
||||||
*/
|
*/
|
||||||
stdin_ev = event_new(base, 0 /* stdin */, EV_READ|EV_PERSIST,
|
stdin_ev = event_new(dc_loop_event_base(loop), 0 /* stdin */,
|
||||||
|
EV_READ|EV_PERSIST,
|
||||||
stdin_handler, NULL
|
stdin_handler, NULL
|
||||||
);
|
);
|
||||||
return_if_true(stdin_ev == NULL, false);
|
return_if_true(stdin_ev == NULL, false);
|
||||||
event_add(stdin_ev, NULL);
|
event_add(stdin_ev, NULL);
|
||||||
|
|
||||||
timer = evtimer_new(base, timer_handler, NULL);
|
|
||||||
return_if_true(timer == NULL, false);
|
|
||||||
|
|
||||||
/* create curl multi and feed that to the API too
|
|
||||||
*/
|
|
||||||
curl = curl_multi_init();
|
|
||||||
return_if_true(curl == NULL, false);
|
|
||||||
|
|
||||||
curl_multi_setopt(curl, CURLMOPT_SOCKETFUNCTION, mcurl_handler);
|
|
||||||
curl_multi_setopt(curl, CURLMOPT_TIMERFUNCTION, mcurl_timer);
|
|
||||||
|
|
||||||
/* initialise event
|
/* initialise event
|
||||||
*/
|
*/
|
||||||
api = dc_api_new();
|
api = dc_api_new();
|
||||||
return_if_true(api == NULL, false);
|
return_if_true(api == NULL, false);
|
||||||
|
|
||||||
dc_api_set_event_base(api, base);
|
dc_loop_add_api(loop, api);
|
||||||
dc_api_set_curl_multi(api, curl);
|
|
||||||
|
|
||||||
config = g_key_file_new();
|
config = g_key_file_new();
|
||||||
return_if_true(config == NULL, false);
|
return_if_true(config == NULL, false);
|
||||||
@ -172,39 +79,14 @@ static bool init_everything(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_multi_info(void)
|
|
||||||
{
|
|
||||||
struct CURLMsg *msg = NULL;
|
|
||||||
int remain = 0;
|
|
||||||
|
|
||||||
/* check for finished multi curls
|
|
||||||
*/
|
|
||||||
msg = curl_multi_info_read(curl, &remain);
|
|
||||||
if (msg != NULL) {
|
|
||||||
if (remain <= 0) {
|
|
||||||
if (evtimer_pending(timer, NULL)) {
|
|
||||||
evtimer_del(timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (msg->msg == CURLMSG_DONE) {
|
|
||||||
dc_api_signal(api, msg->easy_handle, msg->data.result);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
usleep(10 * 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *loop_thread(void *arg)
|
static void *loop_thread(void *arg)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
ret = event_base_loop(base, EVLOOP_ONCE|EVLOOP_NONBLOCK);
|
if (!dc_loop_once(loop)) {
|
||||||
if (ret < 0) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_multi_info();
|
usleep(10 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user