diff options
Diffstat (limited to 'btpd/http.c')
| -rw-r--r-- | btpd/http.c | 251 |
1 files changed, 0 insertions, 251 deletions
diff --git a/btpd/http.c b/btpd/http.c deleted file mode 100644 index f1e6b7e..0000000 --- a/btpd/http.c +++ /dev/null @@ -1,251 +0,0 @@ -#include <pthread.h> -#include <stdarg.h> -#include <string.h> -#include <unistd.h> -#include <curl/curl.h> - -#include "btpd.h" -#include "http.h" - -#define MAX_DOWNLOAD (1 << 18) // 256kB -#define CURL_SELECT_TIME (& (struct timeval) { 1, 0 }) - -enum http_state { - HS_ADD, - HS_ACTIVE, - HS_DONE, - HS_NOADD, - HS_CANCEL -}; - -struct http { - long t_created; - enum http_state state; - char *url; - CURL *curlh; - struct http_res res; - BTPDQ_ENTRY(http) entry; - void (*cb)(struct http *, struct http_res *, void *); - void *cb_arg; -}; - -BTPDQ_HEAD(http_tq, http); - -static struct http_tq m_httpq = BTPDQ_HEAD_INITIALIZER(m_httpq); -static pthread_mutex_t m_httpq_lock; -static pthread_cond_t m_httpq_cond; -static CURLM *m_curlh; - -static size_t -http_write_cb(void *ptr, size_t size, size_t nmemb, void *arg) -{ - char *mem; - struct http_res *res = arg; - size_t nbytes = size * nmemb; - size_t nlength = res->length + nbytes; - if (nlength > MAX_DOWNLOAD) - return 0; - if ((mem = realloc(res->content, nlength)) == NULL) - return 0; - res->content = mem; - bcopy(ptr, res->content + res->length, nbytes); - res->length = nlength; - return nbytes; -} - -int -http_get(struct http **ret, - void (*cb)(struct http *, struct http_res *, void *), void *arg, - const char *fmt, ...) -{ - struct http *h = btpd_calloc(1, sizeof(*h)); - - h->state = HS_ADD; - h->cb = cb; - h->cb_arg = arg; - h->t_created = btpd_seconds; - if ((h->curlh = curl_easy_init()) == NULL) - btpd_err("Fatal error in curl.\n"); - - va_list ap; - va_start(ap, fmt); - if (vasprintf(&h->url, fmt, ap) == -1) - btpd_err("Out of memory.\n"); - va_end(ap); - - curl_easy_setopt(h->curlh, CURLOPT_URL, h->url); - curl_easy_setopt(h->curlh, CURLOPT_USERAGENT, BTPD_VERSION); - curl_easy_setopt(h->curlh, CURLOPT_WRITEFUNCTION, http_write_cb); - curl_easy_setopt(h->curlh, CURLOPT_WRITEDATA, &h->res); - curl_easy_setopt(h->curlh, CURLOPT_FOLLOWLOCATION, 1); - - pthread_mutex_lock(&m_httpq_lock); - BTPDQ_INSERT_TAIL(&m_httpq, h, entry); - pthread_mutex_unlock(&m_httpq_lock); - pthread_cond_signal(&m_httpq_cond); - - if (ret != NULL) - *ret = h; - - return 0; -} - -long -http_server_busy_time(const char *url, long s) -{ - struct http *h; - size_t len = strlen(url); - - pthread_mutex_lock(&m_httpq_lock); - h = BTPDQ_LAST(&m_httpq, http_tq); - while (h != NULL && - !((h->state == HS_ACTIVE || h->state == HS_ADD) && - strncmp(url, h->url, len) == 0)) - h = BTPDQ_PREV(h, http_tq, entry); - pthread_mutex_unlock(&m_httpq_lock); - - if (h == NULL || btpd_seconds - h->t_created >= s) - return 0; - else - return s - (btpd_seconds - h->t_created); -} - -void -http_cancel(struct http *http) -{ - pthread_mutex_lock(&m_httpq_lock); - if (http->state == HS_ADD) - http->state = HS_NOADD; - else - http->state = HS_CANCEL; - pthread_mutex_unlock(&m_httpq_lock); -} - -int -http_succeeded(struct http_res *res) -{ - return res->res == HRES_OK && res->code >= 200 && res->code < 300; -} - -static void -http_td_cb(void *arg) -{ - struct http *h = arg; - if (h->res.res == HRES_OK) - curl_easy_getinfo(h->curlh, CURLINFO_RESPONSE_CODE, &h->res.code); - if (h->res.res == HRES_FAIL) - h->res.errmsg = curl_easy_strerror(h->res.code); - if (h->state != HS_CANCEL) - h->cb(h, &h->res, h->cb_arg); - curl_easy_cleanup(h->curlh); - if (h->res.content != NULL) - free(h->res.content); - free(h->url); - free(h); -} - -static void -http_td_actions(void) -{ - int nmsgs; - struct http *http, *next; - struct http_tq postq; - CURLMsg *cmsg; - - pthread_mutex_lock(&m_httpq_lock); - do { - while (BTPDQ_EMPTY(&m_httpq)) - pthread_cond_wait(&m_httpq_cond, &m_httpq_lock); - - BTPDQ_INIT(&postq); - - BTPDQ_FOREACH_MUTABLE(http, &m_httpq, entry, next) { - switch (http->state) { - case HS_ADD: - curl_multi_add_handle(m_curlh, http->curlh); - http->state = HS_ACTIVE; - break; - case HS_CANCEL: - curl_multi_remove_handle(m_curlh, http->curlh); - case HS_NOADD: - BTPDQ_REMOVE(&m_httpq, http, entry); - BTPDQ_INSERT_TAIL(&postq, http, entry); - http->state = HS_CANCEL; - http->res.res = HRES_CANCEL; - break; - case HS_DONE: - abort(); - default: - break; - } - } - - while ((cmsg = curl_multi_info_read(m_curlh, &nmsgs)) != NULL) { - BTPDQ_FOREACH(http, &m_httpq, entry) { - if (http->curlh == cmsg->easy_handle) - break; - } - assert(http != NULL); - BTPDQ_REMOVE(&m_httpq, http, entry); - BTPDQ_INSERT_TAIL(&postq, http, entry); - http->state = HS_DONE; - if (cmsg->data.result == 0) - http->res.res = HRES_OK; - else { - http->res.res = HRES_FAIL; - http->res.code = cmsg->data.result; - } - curl_multi_remove_handle(m_curlh, http->curlh); - } - - if (!BTPDQ_EMPTY(&postq)) { - pthread_mutex_unlock(&m_httpq_lock); - td_post_begin(); - BTPDQ_FOREACH(http, &postq, entry) - td_post(http_td_cb, http); - td_post_end(); - pthread_mutex_lock(&m_httpq_lock); - } - } while (BTPDQ_EMPTY(&m_httpq)); - pthread_mutex_unlock(&m_httpq_lock); -} - -static void -http_td(void *arg) -{ - fd_set rset, wset, eset; - int maxfd, nbusy; - - for (;;) { - http_td_actions(); - - while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(m_curlh, &nbusy)) - ; - - if (nbusy > 0) { - FD_ZERO(&rset); - FD_ZERO(&wset); - FD_ZERO(&eset); - curl_multi_fdset(m_curlh, &rset, &wset, &eset, &maxfd); - select(maxfd + 1, &rset, &wset, &eset, CURL_SELECT_TIME); - } - } -} - -static void -errdie(int err) -{ - if (err != 0) - btpd_err("Fatal error in http_init.\n"); -} - -void -http_init(void) -{ - pthread_t ret; - errdie(curl_global_init(0)); - errdie((m_curlh = curl_multi_init()) == NULL); - errdie(pthread_mutex_init(&m_httpq_lock, NULL)); - errdie(pthread_cond_init(&m_httpq_cond, NULL)); - errdie(pthread_create(&ret, NULL, (void *(*)(void *))http_td, NULL)); -} |