curl support - round 2
Paul P Komkoff Jr <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Organization | Department of Fish & Wildlife |
| Message-ID | <[email protected]> |
After having it ran here for about two weeks - here is another round of curl patch. This is very work in progress but it really works, and I feel that it works better than gwlib client. Now curl-specific portions isolated with ifdefs so to make it actually work you need to make CURL_SUPPORT define way into, e.g with CFLAGS=-DCURL_SUPPORT before ./configure or whatever. Also I added sample code to acinclude.m4 and configure.in - but it is not making any curl-related decisions yet. Ah. And I also fixed AC_LIBOBJ usage in configure.in - my autoconf complained on it. Actually, I need much wider testing just because I want to solve almost all design problems (if any) before adding features like config file parsing, etc. (* For example, I just hit an issue with timeouts - say, http://host and host cannot be contacted - which timeout value I should pass to http fetching code to not break anything? quick look at wapbox behavior shows couple of Timeout-A and in about 30 sec. my phone got timed out. *) Enjoy. -- Paul P 'Stingray' Komkoff Jr // http://stingr.net/key <- my pgp key This message represents the official view of the voices in my head
curl.patch
(text/plain, 9.5 KB)
# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/02/22 19:42:53+03:00 [email protected] # Add curl support to wapbox # # gw/wapbox.c # 2004/02/22 19:42:52+03:00 [email protected] +12 -0 # curl support - add # # gw/wap-appl.c # 2004/02/22 19:42:52+03:00 [email protected] +167 -1 # curl support - add # # configure.in # 2004/02/22 19:42:52+03:00 [email protected] +8 -2 # fix ac_libobjs # execute curl detection macros # # acinclude.m4 # 2004/02/22 19:42:52+03:00 [email protected] +34 -0 # add curl detection macros # diff -Nru a/acinclude.m4 b/acinclude.m4 --- a/acinclude.m4 Mon Feb 23 00:08:51 2004 +++ b/acinclude.m4 Mon Feb 23 00:08:51 2004 @@ -159,3 +159,37 @@ fi ]) +dnl MY_CURL +dnl ------- +dnl set my_cv_curl_vers to the version of libcurl or NONE +dnl if libcurl is not found or is too old + +AC_DEFUN(MY_CURL,[ + AC_CACHE_VAL(my_cv_curl_vers,[ + my_cv_curl_vers=NONE + dnl check is the plain-text version of the required version + check="7.9.7" + dnl check_hex must be UPPERCASE if any hex letters are present + check_hex="070907" + + AC_MSG_CHECKING([for curl >= $check]) + + if eval curl-config --version 2>/dev/null >/dev/null; then + ver=`curl-config --version | sed -e "s/libcurl //g"` + hex_ver=`curl-config --vernum | tr 'a-f' 'A-F'` + ok=`echo "ibase=16; if($hex_ver>=$check_hex) $hex_ver else 0" | bc` + + if test x$ok != x0; then + my_cv_curl_vers="$ver" + AC_MSG_RESULT([$my_cv_curl_vers]) + else + AC_MSG_RESULT(FAILED) + AC_MSG_WARN([$ver is too old. Need version $check or higher.]) + fi + else + AC_MSG_RESULT(FAILED) + AC_MSG_WARN([curl-config was not found]) + fi + ]) +]) + diff -Nru a/configure.in b/configure.in --- a/configure.in Mon Feb 23 00:08:51 2004 +++ b/configure.in Mon Feb 23 00:08:51 2004 @@ -130,14 +130,20 @@ dnl Checks for library functions. AC_CHECK_FUNCS(gettimeofday select socket strdup getopt_long localtime_r gmtime_r backtrace srandom) -AC_CHECK_FUNC(getopt, , LIBOBJS="$LIBOBJS utils/attgetopt.o") -AC_SUBST(LIBOBJS) +AC_CHECK_FUNC(getopt, , AC_LIBOBJ="utils/attgetopt") + dnl Check if we have reentrant gethostbyname and which one AC_CHECK_FUNC(gethostbyname_r, [ AC_FUNC_WHICH_GETHOSTBYNAME_R ], [ AC_CHECK_FUNC(gethostbyname,[], [ AC_MSG_ERROR([Couldnot find gethostbyname_r nor gethostbyname functions])])] ) + +dnl curl support - sample code + +MY_CURL +LIBS="$LIBS $(curl-config --libs)" +CFLAGS="$CFLAGS $(curl-config --cflags)" dnl Extra feature checks diff -Nru a/gw/wap-appl.c b/gw/wap-appl.c --- a/gw/wap-appl.c Mon Feb 23 00:08:51 2004 +++ b/gw/wap-appl.c Mon Feb 23 00:08:51 2004 @@ -98,6 +98,10 @@ #include "wap-error.h" #include "wap-maps.h" +#ifdef CURL_SUPPORT +#include <curl/curl.h> +#endif + #define ENABLE_NOT_ACCEPTED /* @@ -158,6 +162,154 @@ List *request_headers; }; +#ifdef CURL_SUPPORT +static CURLM* CurlMClient = NULL; +static int pipeh[2] = { 0 }; + +struct curl_http_request { + Octstr * body; + void * id; + + Octstr* reply; + List* headers; + + struct curl_slist * request_headers; + Octstr * url; +}; + +static size_t curl_writefunc(void *ptr, size_t size, size_t nmemb, void *stream) { + Octstr * s = stream; + int realsize = size * nmemb; + + if (s == NULL) return realsize; + octstr_append_data(s, ptr, realsize); + return realsize; +} + +static size_t curl_headfunc(void *ptr, size_t size, size_t nmemb, void *stream) { + List * l = stream; + int realsize = size * nmemb; + Octstr * s; + + if (l == NULL) return realsize; + s = octstr_create_from_data(ptr, realsize); + octstr_strip_crlfs(s); + if ((octstr_len(s) == 0) || (octstr_search_char(s, ':', 0) == -1)) { + octstr_destroy(s); + } else { + list_append(l, s); + } + return realsize; +} + +void curl_start_request(int method, Octstr *url, + List *headers, Octstr *body, int follow, void *id) { + CURL* req = NULL; + struct curl_http_request * bfd = gw_malloc(sizeof(struct curl_http_request)); + + int i = 0; + + req = curl_easy_init(); + bfd->url = octstr_duplicate(url); + bfd->request_headers = NULL; + bfd->body = NULL; + curl_easy_setopt(req, CURLOPT_URL, octstr_get_cstr(bfd->url)); + + if (method == HTTP_METHOD_POST) { + curl_easy_setopt(req, CURLOPT_POST, 1); + bfd->body = octstr_duplicate(body); + curl_easy_setopt(req, CURLOPT_POSTFIELDS, octstr_get_cstr(bfd->body)); + curl_easy_setopt(req, CURLOPT_POSTFIELDSIZE, octstr_len(bfd->body)); + } + + if (method == HTTP_METHOD_HEAD) + curl_easy_setopt(req, CURLOPT_NOBODY, 1); + + curl_easy_setopt(req, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(req, CURLOPT_NOPROGRESS, 1); + curl_easy_setopt(req, CURLOPT_MUTE, 1); + curl_easy_setopt(req, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(req, CURLOPT_ENCODING, ""); + curl_easy_setopt(req, CURLOPT_TIMEOUT, 60); + + for (i = 0; i < list_len(headers); i++) { + bfd->request_headers = curl_slist_append(bfd->request_headers, octstr_get_cstr(list_get(headers, i))); + } + + curl_easy_setopt(req, CURLOPT_HTTPHEADER, bfd->request_headers); + + bfd->id = id; + bfd->reply = octstr_create(""); + bfd->headers = list_create(); + + curl_easy_setopt(req, CURLOPT_PRIVATE, bfd); + + curl_easy_setopt(req, CURLOPT_WRITEFUNCTION, curl_writefunc); + curl_easy_setopt(req, CURLOPT_HEADERFUNCTION, curl_headfunc); + curl_easy_setopt(req, CURLOPT_WRITEDATA, bfd->reply); + curl_easy_setopt(req, CURLOPT_WRITEHEADER, bfd->headers); + + curl_multi_add_handle(CurlMClient, req); + write(pipeh[1], "X", 1); +} + +void *curl_receive_result(int *status, Octstr **final_url, + List **headers, Octstr **body) { + fd_set f_read, f_write, f_exc; + int maxfd = 0; + int transfers = 0, msgs = 0; + char x; + struct curl_http_request * bfd; + void * p; + char* furl; + CURLMsg * msg; + CURL* hnd; + int result = 0; + + while (1) { + while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(CurlMClient, &transfers)); + while (msg = curl_multi_info_read(CurlMClient, &msgs)) { + hnd = msg->easy_handle; + result = msg->data.result; + curl_multi_remove_handle(CurlMClient, hnd); + if (CURLE_OK != curl_easy_getinfo(hnd, CURLINFO_PRIVATE, &bfd)) bfd = NULL; + if (bfd == NULL) continue; + if (CURLE_OK != curl_easy_getinfo(hnd, CURLINFO_HTTP_CODE, status)) (*status) = -1; + if (result != CURLE_OK) (*status) = -1; + + (*headers) = bfd->headers; + (*body) = bfd->reply; + if (CURLE_OK == curl_easy_getinfo(hnd, CURLINFO_EFFECTIVE_URL, &furl)) + (*final_url) = octstr_create(furl); + else (*final_url) = NULL; + p = bfd->id; + curl_easy_cleanup(hnd); + if (bfd->request_headers) curl_slist_free_all(bfd->request_headers); + octstr_destroy(bfd->url); + octstr_destroy(bfd->body); + gw_free(bfd); + return p; + } + + FD_ZERO(&f_read); + FD_ZERO(&f_write); + FD_ZERO(&f_exc); + + curl_multi_fdset(CurlMClient, &f_read, &f_write, &f_exc, &maxfd); + if (maxfd < pipeh[0]) maxfd = pipeh[0]; + FD_SET(pipeh[0], &f_read); + if (select(maxfd + 1, &f_read, &f_write, &f_exc, NULL) >= 0) { + if (FD_ISSET(pipeh[0], &f_read)) { + if (read(pipeh[0], &x, 1) == 1) { + continue; + } else { + return NULL; + } + } + } else return NULL; + } +} +#endif /* * WSP smart error messaging @@ -244,6 +396,10 @@ void wap_appl_init(Cfg *cfg) { gw_assert(run_status == limbo); +#ifdef CURL_SUPPORT + pipe(pipeh); + CurlMClient = curl_multi_init(); +#endif queue = list_create(); fetches = counter_create(); list_add_producer(queue); @@ -267,6 +423,9 @@ list_remove_producer(queue); gwthread_join_every(main_thread); +#ifdef CURL_SUPPORT + close(pipeh[1]); +#endif http_caller_signal_shutdown(caller); gwthread_join_every(return_replies_thread); @@ -1060,8 +1219,11 @@ List *headers; while (run_status == running) { - +#ifdef CURL_SUPPORT + p = curl_receive_result(&status, &final_url, &headers, &body); +#else p = http_receive_result(caller, &status, &final_url, &headers, &body); +#endif if (p == NULL) break; @@ -1262,8 +1424,12 @@ p->request_headers = actual_headers; /* issue the request to the HTTP server */ +#ifdef CURL_SUPPORT + curl_start_request(http_name2method(method), url, actual_headers, request_body, 0, p); +#else http_start_request(caller, http_name2method(method), url, actual_headers, request_body, 0, p, NULL); +#endif octstr_destroy(request_body); } diff -Nru a/gw/wapbox.c b/gw/wapbox.c --- a/gw/wapbox.c Mon Feb 23 00:08:51 2004 +++ b/gw/wapbox.c Mon Feb 23 00:08:51 2004 @@ -85,6 +85,10 @@ #endif #include "radius/radius_acct.h" +#ifdef CURL_SUPPORT +#include <curl/curl.h> +#endif + static void config_reload(int reload); static long logfilelevel=-1; @@ -671,6 +675,10 @@ cf_index = get_and_set_debugs(argc, argv, NULL); setup_signal_handlers(); + +#ifdef CURL_SUPPORT + curl_global_init(CURL_GLOBAL_ALL); +#endif if (argv[cf_index] == NULL) config_filename = octstr_create("kannel.conf"); @@ -823,6 +831,10 @@ } gwlib_shutdown(); + +#ifdef CURL_SUPPORT + curl_global_cleanup(); +#endif /* now really restart */ if (restart)