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
# 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)