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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.