From: Wilfried Goesgens Date: Sun, 15 May 2011 10:43:11 +0000 (+0000) Subject: work on libev <-> libcurl integration X-Git-Tag: v8.11~1057 X-Git-Url: https://code.citadel.org/?a=commitdiff_plain;h=5bf419fda3cd8b09cd424d4c67fdf68c9352d0eb;p=citadel.git work on libev <-> libcurl integration - move libcurl handlers into the libev file; they need to be initialized to close to separate - add some logging; First successfull CURL notification via libev! --- diff --git a/citadel/modules/curl/serv_curl.c b/citadel/modules/curl/serv_curl.c deleted file mode 100644 index 94e11e495..000000000 --- a/citadel/modules/curl/serv_curl.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright (c) 1998-2009 by the citadel.org team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * thanks to some guy in #libev - */ - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include - -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" - -#include "ctdl_module.h" -#include "serv_curl.h" - -evcurl_global_data global; - - -extern struct ev_loop *event_base; - -void SockStateCb(void *data, int sock, int read, int write); - -#define MOPT(s, v) \ - do { \ - sta = curl_multi_setopt(mhnd, (CURLMOPT_##s), (v)); \ - if (sta) { \ - CtdlLogPrintf(CTDL_ERR, "error setting option " #s " on curl multi handle: %s\n", curl_easy_strerror(sta)); \ - exit (1); \ - } \ -} while (0) - - -void ____InitC_ares_dns(AsyncIO *IO) -{ - int optmask = 0; - if (IO->DNSChannel == NULL) { - optmask |= ARES_OPT_SOCK_STATE_CB; - IO->DNSOptions.sock_state_cb = SockStateCb; - IO->DNSOptions.sock_state_cb_data = IO; - ares_init_options(&IO->DNSChannel, &IO->DNSOptions, optmask); - } -} - - - -/***************************************************************************** - * libevent / c-ares integration * - *****************************************************************************/ -static void ____DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - ares_process_fd(IO->DNSChannel, ARES_SOCKET_BAD, IO->dns_send_event.fd); -} -static void ____DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - ares_process_fd(IO->DNSChannel, IO->dns_recv_event.fd, ARES_SOCKET_BAD); -} - -void ____SockStateCb(void *data, int sock, int read, int write) -{ -/* - struct timeval tvbuf, maxtv, *ret; - - int64_t time = 10; -*/ - AsyncIO *IO = data; -/* already inside of the event queue. */ - - if (read) { - if ((IO->dns_recv_event.fd != sock) && - (IO->dns_recv_event.fd != 0)) { - ev_io_stop(event_base, &IO->dns_recv_event); - } - IO->dns_recv_event.fd = sock; - ev_io_init(&IO->dns_recv_event, ____DNS_recv_callback, IO->dns_recv_event.fd, EV_READ); - IO->dns_recv_event.data = IO; - ev_io_start(event_base, &IO->dns_recv_event); - } - if (write) { - if ((IO->dns_send_event.fd != sock) && - (IO->dns_send_event.fd != 0)) { - ev_io_stop(event_base, &IO->dns_send_event); - } - IO->dns_send_event.fd = sock; - ev_io_init(&IO->dns_send_event, ____DNS_send_callback, IO->dns_send_event.fd, EV_WRITE); - IO->dns_send_event.data = IO; - ev_io_start(event_base, &IO->dns_send_event); - } -/* - - ev_io_start(event_base, &IO->dns_io_event); - - maxtv.tv_sec = time/1000; - maxtv.tv_usec = (time % 1000) * 1000; - - ret = ares_timeout(IO->DNSChannel, &maxtv, &tvbuf); - } -*/ - if ((read == 0) && (write == 0)) { - ev_io_stop(event_base, &IO->dns_recv_event); - ev_io_stop(event_base, &IO->dns_send_event); - } -} - - - - - - -static void -gotstatus(evcurl_global_data *global, int nnrun) -{ - CURLM *mhnd; - CURLMsg *msg; - int nmsg; -/* - if (EVCURL_GLOBAL_MAGIC != global.magic) - { - CtdlLogPrintf(CTDL_ERR, "internal error: gotstatus on wrong struct"); - return; - } -*/ - global->nrun = nnrun; - mhnd = global->mhnd; - - CtdlLogPrintf(CTDL_ERR, "about to call curl_multi_info_read\n"); - while ((msg = curl_multi_info_read(mhnd, &nmsg))) { - CtdlLogPrintf(CTDL_ERR, "got curl multi_info message msg=%d", msg->msg); - if (CURLMSG_DONE == msg->msg) { - CtdlLogPrintf(CTDL_ERR, "request complete\n"); - CURL *chnd = msg->easy_handle; - char *chandle; - CURLcode sta = curl_easy_getinfo(chnd, CURLINFO_PRIVATE, &chandle); - if (sta) - CtdlLogPrintf(CTDL_ERR, "error asking curl for private cookie of curl handle: %s\n", curl_easy_strerror(sta)); - evcurl_request_data *handle = (void *)chandle; - if (global != handle->global || chnd != handle->chnd) - CtdlLogPrintf(CTDL_ERR, "internal evcurl error: unknown curl handle completed\n"); - sta = msg->data.result; - if (sta) { - CtdlLogPrintf(CTDL_ERR, "error description: %s\n", handle->errdesc); - CtdlLogPrintf(CTDL_ERR, "error performing request: %s\n", curl_easy_strerror(sta)); - } - long httpcode; - sta = curl_easy_getinfo(chnd, CURLINFO_RESPONSE_CODE, &httpcode); - if (sta) - CtdlLogPrintf(CTDL_ERR, "error asking curl for response code from request: %s\n", curl_easy_strerror(sta)); - CtdlLogPrintf(CTDL_ERR, "http response code was %ld\n", (long)httpcode); - CURLMcode msta = curl_multi_remove_handle(mhnd, chnd); - if (msta) - CtdlLogPrintf(CTDL_ERR, "warning problem detaching completed handle from curl multi: %s\n", curl_multi_strerror(msta)); - handle->attached = 0; - } - } - if (0 == nnrun) { - ev_unloop(EV_DEFAULT, EVUNLOOP_ONE); /* remove in production */ - } -} - -static void -stepmulti(evcurl_global_data *global, curl_socket_t fd) { - int nnrun; - CURLMcode msta = curl_multi_socket_action(global->mhnd, fd, 0, &nnrun); - if (msta) - CtdlLogPrintf(CTDL_ERR, "error in curl processing events on multi handle, fd %d: %s\n", (int)fd, curl_multi_strerror(msta)); - if (global->nrun != nnrun) - gotstatus(global, nnrun); -} - -static void -gottime(struct ev_loop *loop, ev_timer *timeev, int events) { - CtdlLogPrintf(CTDL_ERR,"waking up curl for timeout\n"); - evcurl_global_data *global = (void *)timeev->data; - stepmulti(global, CURL_SOCKET_TIMEOUT); -} - -static void -gotio(struct ev_loop *loop, ev_io *ioev, int events) { - CtdlLogPrintf(CTDL_ERR,"waking up curl for io on fd %d\n", (int)ioev->fd); - sockwatcher_data *sockwatcher = (void *)ioev->data; - stepmulti(sockwatcher->global, ioev->fd); -} - -static size_t -gotdata(void *data, size_t size, size_t nmemb, void *cglobal) { - evcurl_request_data *D = (evcurl_request_data*) data; - return CurlFillStrBuf_callback(D->ReplyData, size, nmemb, cglobal); -} - -static int -gotwatchtime(CURLM *multi, long tblock_ms, void *cglobal) { - CtdlLogPrintf(CTDL_ERR,"gotwatchtime called %ld ms\n", tblock_ms); - evcurl_global_data *global = cglobal; - ev_timer_stop(EV_DEFAULT, &global->timeev); - if (tblock_ms < 0 || 14000 < tblock_ms) - tblock_ms = 14000; - ev_timer_set(&global->timeev, 0.5e-3 + 1.0e-3 * tblock_ms, 14.0); - ev_timer_start(EV_DEFAULT_UC, &global->timeev); - return 0; -} - -static int -gotwatchsock(CURL *easy, curl_socket_t fd, int action, void *cglobal, void *csockwatcher) { - evcurl_global_data *global = cglobal; - CURLM *mhnd = global->mhnd; - CtdlLogPrintf(CTDL_ERR,"gotwatchsock called fd=%d action=%d\n", (int)fd, action); - sockwatcher_data *sockwatcher = csockwatcher; - if (!sockwatcher) { - CtdlLogPrintf(CTDL_ERR,"called first time to register this sockwatcker\n"); - sockwatcher = malloc(sizeof(sockwatcher_data)); - sockwatcher->global = global; - ev_init(&sockwatcher->ioev, &gotio); - sockwatcher->ioev.data = (void *)sockwatcher; - curl_multi_assign(mhnd, fd, sockwatcher); - } - if (CURL_POLL_REMOVE == action) { - CtdlLogPrintf(CTDL_ERR,"called last time to unregister this sockwatcher\n"); - free(sockwatcher); - } else { - int events = (action & CURL_POLL_IN ? EV_READ : 0) | (action & CURL_POLL_OUT ? EV_WRITE : 0); - ev_io_stop(EV_DEFAULT, &sockwatcher->ioev); - if (events) { - ev_io_set(&sockwatcher->ioev, fd, events); - ev_io_start(EV_DEFAULT, &sockwatcher->ioev); - } - } - return 0; -} - -void curl_init_connectionpool(void) -{ - CURLM *mhnd ; -// global.magic = EVCURL_GLOBAL_MAGIC; - - ev_timer_init(&global.timeev, &gottime, 14.0, 14.0); - global.timeev.data = (void *)&global; - global.nrun = -1; - CURLcode sta = curl_global_init(CURL_GLOBAL_ALL); - /* note: probably replace with curl_global_init_mem if used with perl */ - if (sta) - { - CtdlLogPrintf(CTDL_ERR,"error initializing curl library: %s\n", curl_easy_strerror(sta)); - exit(1); - } -/* - if (!ev_default_loop(EVFLAG_AUTO)) - { - CtdlLogPrintf(CTDL_ERR,"error initializing libev\n"); - exit(2); - } -*/ - mhnd = global.mhnd = curl_multi_init(); - if (!mhnd) - { - CtdlLogPrintf(CTDL_ERR,"error initializing curl multi handle\n"); - exit(3); - } - - MOPT(SOCKETFUNCTION, &gotwatchsock); - MOPT(SOCKETDATA, (void *)&global); - MOPT(TIMERFUNCTION, &gotwatchtime); - MOPT(TIMERDATA, (void *)&global); - - /* well, just there to fire the sample request?*/ - ev_timer_start(EV_DEFAULT, &global.timeev); - return; -} - - - - -int evcurl_init(evcurl_request_data *handle, - void *CustomData, - const char* Desc, - int CallBack) -{ - CURLcode sta; - CURL *chnd; - - handle->global = &global; - handle->attached = 0; - chnd = handle->chnd = curl_easy_init(); - if (!chnd) - { - CtdlLogPrintf(CTDL_ERR, "error initializing curl handle\n"); - return 1; - } - - strcpy(handle->errdesc, Desc); - - OPT(VERBOSE, (long)1); - /* unset in production */ - OPT(NOPROGRESS, (long)1); - OPT(NOSIGNAL, (long)1); - OPT(FAILONERROR, (long)1); - OPT(ENCODING, ""); - OPT(FOLLOWLOCATION, (long)1); - OPT(MAXREDIRS, (long)7); - OPT(USERAGENT, CITADEL); - - OPT(TIMEOUT, (long)1800); - OPT(LOW_SPEED_LIMIT, (long)64); - OPT(LOW_SPEED_TIME, (long)600); - OPT(CONNECTTIMEOUT, (long)600); - OPT(PRIVATE, (void *)handle); - - - OPT(WRITEFUNCTION, &gotdata); - OPT(WRITEDATA, (void *)handle); - OPT(ERRORBUFFER, handle->errdesc); - - /* point to a structure that points back to the perl structure and stuff */ - OPT(URL, handle->URL->PlainUrl); - if (StrLength(handle->URL->CurlCreds)) - { - OPT(HTTPAUTH, (long)CURLAUTH_BASIC); - OPT(USERPWD, ChrPtr(handle->URL->CurlCreds)); - } -#ifdef CURLOPT_HTTP_CONTENT_DECODING - OPT(HTTP_CONTENT_DECODING, 1); - OPT(ENCODING, ""); -#endif - if (StrLength(handle->PostData) > 0) - { - OPT(POSTFIELDS, ChrPtr(handle->PostData)); - OPT(POSTFIELDSIZE, StrLength(handle->PostData)); - - } - else if ((handle->PlainPostDataLen != 0) && (handle->PlainPostData != NULL)) - { - OPT(POSTFIELDS, handle->PlainPostData); - OPT(POSTFIELDSIZE, handle->PlainPostDataLen); - } - - if (handle->headers != NULL) - OPT(HTTPHEADER, handle->headers); - - return 1; -} - -void -evcurl_handle_start(evcurl_request_data *handle) -{ - CURLMcode msta = curl_multi_add_handle(handle->global->mhnd, handle->chnd); - if (msta) - CtdlLogPrintf(CTDL_ERR, "error attaching to curl multi handle: %s\n", curl_multi_strerror(msta)); - handle->attached = 1; -} - - - -CTDL_MODULE_INIT(curl_client) -{ - if (!threading) - { -// curl_init_connectionpool(); -/* - int r = ares_library_init(ARES_LIB_INIT_ALL); - if (0 != r) { - // TODO - // ThrowException(Exception::Error(String::New(ares_strerror(r)))); -//// assert(r == 0); - } -*/ } - return "curl"; -} diff --git a/citadel/modules/curl/serv_curl.h b/citadel/modules/curl/serv_curl.h deleted file mode 100644 index 295e32856..000000000 --- a/citadel/modules/curl/serv_curl.h +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -typedef struct _evcurl_global_data { - int magic; - CURLM *mhnd; - ev_timer timeev; - int nrun; -} evcurl_global_data; - -typedef struct _evcurl_request_data -{ - evcurl_global_data *global; - CURL *chnd; - char errdesc[CURL_ERROR_SIZE]; - int attached; - char* PlainPostData; - long PlainPostDataLen; - StrBuf *PostData; - StrBuf *ReplyData; - ParsedURL *URL; - struct curl_slist * headers; -} evcurl_request_data; - -typedef struct _sockwatcher_data -{ - evcurl_global_data *global; - ev_io ioev; -} sockwatcher_data; - - - - -#define OPT(s, v) \ - do { \ - sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v)); \ - if (sta) { \ - CtdlLogPrintf(CTDL_ERR, "error setting option " #s " on curl handle: %s", curl_easy_strerror(sta)); \ - } } while (0) - - -int evcurl_init(evcurl_request_data *handle, - void *CustomData, - const char* Desc, - int CallBack); - -void evcurl_handle_start(evcurl_request_data *handle); diff --git a/citadel/modules/eventclient/serv_curl.h b/citadel/modules/eventclient/serv_curl.h new file mode 100644 index 000000000..6559c93c0 --- /dev/null +++ b/citadel/modules/eventclient/serv_curl.h @@ -0,0 +1,46 @@ +#include + +typedef struct _evcurl_global_data { + int magic; + CURLM *mhnd; + ev_timer timeev; + int nrun; +} evcurl_global_data; + +typedef struct _evcurl_request_data +{ + evcurl_global_data *global; + CURL *chnd; + char errdesc[CURL_ERROR_SIZE]; + int attached; + char* PlainPostData; + long PlainPostDataLen; + StrBuf *PostData; + StrBuf *ReplyData; + ParsedURL *URL; + struct curl_slist * headers; +} evcurl_request_data; + +typedef struct _sockwatcher_data +{ + evcurl_global_data *global; + ev_io ioev; +} sockwatcher_data; + + + + +#define OPT(s, v) \ + do { \ + sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v)); \ + if (sta) { \ + CtdlLogPrintf(CTDL_ERR, "error setting option " #s " on curl handle: %s", curl_easy_strerror(sta)); \ + } } while (0) + + +int evcurl_init(evcurl_request_data *handle, + void *CustomData, + const char* Desc, + int CallBack); + +void evcurl_handle_start(evcurl_request_data *handle);