summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2010-08-01 23:41:44 (GMT)
committerMarcel Holtmann <marcel@holtmann.org>2010-08-01 23:41:44 (GMT)
commit21277c943191120d84839713caefb762ca918016 (patch)
treeb36261385fa44b3433b5b0ae51c0e328ba4675da
parent2509163e47302bef6afe494b11720d510760a0ed (diff)
downloadconnman-21277c943191120d84839713caefb762ca918016.zip
connman-21277c943191120d84839713caefb762ca918016.tar.gz
connman-21277c943191120d84839713caefb762ca918016.tar.bz2
Add some initial support for HTTP to web service library
-rw-r--r--gweb/gweb.c244
-rw-r--r--gweb/gweb.h15
2 files changed, 257 insertions, 2 deletions
diff --git a/gweb/gweb.c b/gweb/gweb.c
index 2dda02b..31a41dc 100644
--- a/gweb/gweb.c
+++ b/gweb/gweb.c
@@ -24,13 +24,36 @@
#endif
#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
#include "gweb.h"
+struct web_session {
+ GWeb *web;
+
+ char *address;
+ char *host;
+ uint16_t port;
+ unsigned long flags;
+
+ GIOChannel *transport_channel;
+ guint transport_watch;
+};
+
struct _GWeb {
gint ref_count;
+ guint next_query_id;
+
+ int index;
+ GList *session_list;
+
GWebDebugFunc debug_func;
gpointer debug_data;
};
@@ -51,16 +74,52 @@ static inline void debug(GWeb *web, const char *format, ...)
va_end(ap);
}
-GWeb *g_web_new(void)
+static void free_session(struct web_session *session)
+{
+ if (session == NULL)
+ return;
+
+ if (session->transport_watch > 0)
+ g_source_remove(session->transport_watch);
+
+ if (session->transport_channel != NULL)
+ g_io_channel_unref(session->transport_channel);
+
+ g_free(session->host);
+ g_free(session->address);
+ g_free(session);
+}
+
+static void flush_sessions(GWeb *web)
+{
+ GList *list;
+
+ for (list = g_list_first(web->session_list);
+ list; list = g_list_next(list))
+ free_session(list->data);
+
+ g_list_free(web->session_list);
+ web->session_list = NULL;
+}
+
+GWeb *g_web_new(int index)
{
GWeb *web;
+ if (index < 0)
+ return NULL;
+
web = g_try_new0(GWeb, 1);
if (web == NULL)
return NULL;
web->ref_count = 1;
+ web->next_query_id = 1;
+
+ web->index = index;
+ web->session_list = NULL;
+
return web;
}
@@ -82,6 +141,8 @@ void g_web_unref(GWeb *web)
if (g_atomic_int_dec_and_test(&web->ref_count) == FALSE)
return;
+ flush_sessions(web);
+
g_free(web);
}
@@ -93,3 +154,184 @@ void g_web_set_debug(GWeb *web, GWebDebugFunc func, gpointer user_data)
web->debug_func = func;
web->debug_data = user_data;
}
+
+static gboolean received_data(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct web_session *session = user_data;
+ unsigned char buf[4096];
+ int sk, len;
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ session->transport_watch = 0;
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(session->transport_channel);
+
+ memset(buf, 0, sizeof(buf));
+ len = recv(sk, buf, sizeof(buf) - 1, 0);
+
+ printf("%s", buf);
+
+ return TRUE;
+}
+
+static int connect_session_transport(struct web_session *session)
+{
+ struct sockaddr_in sin;
+ int sk;
+
+ sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ return -EIO;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(session->port);
+ sin.sin_addr.s_addr = inet_addr(session->address);
+
+ if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ close(sk);
+ return -EIO;
+ }
+
+ session->transport_channel = g_io_channel_unix_new(sk);
+ if (session->transport_channel == NULL) {
+ close(sk);
+ return -ENOMEM;
+ }
+
+ g_io_channel_set_close_on_unref(session->transport_channel, TRUE);
+
+ session->transport_watch = g_io_add_watch(session->transport_channel,
+ G_IO_IN, received_data,
+ session);
+
+ return 0;
+}
+
+static void start_request(struct web_session *session, const char *request)
+{
+ GString *buf;
+ char *str;
+ ssize_t len;
+ int sk;
+
+ debug(session->web, "request %s from %s", request, session->host);
+
+ sk = g_io_channel_unix_get_fd(session->transport_channel);
+
+ buf = g_string_new(NULL);
+ g_string_append_printf(buf, "GET %s HTTP/1.1\r\n", request);
+ g_string_append_printf(buf, "Host: %s\r\n", session->host);
+ g_string_append_printf(buf, "User-Agent: ConnMan/%s\r\n", VERSION);
+ g_string_append(buf, "Accept: */*\r\n");
+ g_string_append(buf, "\r\n");
+ str = g_string_free(buf, FALSE);
+
+ len = send(sk, str, strlen(str), 0);
+
+ printf("%s", str);
+
+ g_free(str);
+}
+
+static char *parse_url(struct web_session *session, const char *url)
+{
+ char *scheme, *host, *port, *path, *request;
+
+ scheme = g_strdup(url);
+ if (scheme == NULL)
+ return NULL;
+
+ host = strstr(scheme, "://");
+ if (host != NULL) {
+ *host = '\0';
+ host += 3;
+
+ if (strcasecmp(scheme, "https") == 0)
+ session->port = 443;
+ else if (strcasecmp(scheme, "http") == 0)
+ session->port = 80;
+ else {
+ g_free(scheme);
+ return NULL;
+ }
+ } else {
+ host = scheme;
+ session->port = 80;
+ }
+
+ path = strchr(host, '/');
+ if (path != NULL)
+ *(path++) = '\0';
+
+ request = g_strdup_printf("/%s", path ? path : "");
+
+ port = strrchr(host, ':');
+ if (port != NULL) {
+ char *end;
+ int tmp = strtol(port + 1, &end, 10);
+
+ if (*end == '\0') {
+ *port = '\0';
+ session->port = tmp;
+ }
+ }
+
+ session->host = g_strdup(host);
+
+ g_free(scheme);
+
+ return request;
+}
+
+guint g_web_request(GWeb *web, GWebMethod method, const char *url,
+ GWebResultFunc func, gpointer user_data)
+{
+ struct web_session *session;
+ char *request;
+
+ if (web == NULL || url == NULL)
+ return 0;
+
+ debug(web, "request %s", url);
+
+ session = g_try_new0(struct web_session, 1);
+ if (session == NULL)
+ return 0;
+
+ request = parse_url(session, url);
+ if (request == NULL) {
+ g_free(session);
+ return 0;
+ }
+
+ if (inet_aton(session->host, NULL) == 0) {
+ g_free(session);
+ return 0;
+ }
+
+ session->address = g_strdup(session->host);
+
+ debug(web, "host %s:%u", session->host, session->port);
+
+ if (connect_session_transport(session) < 0) {
+ g_free(request);
+ free_session(session);
+ return FALSE;
+ }
+
+ session->web = web;
+
+ web->session_list = g_list_append(web->session_list, session);
+
+ debug(web, "creating session %s:%u", session->address, session->port);
+
+ start_request(session, request);
+
+ g_free(request);
+
+ return web->next_query_id++;
+}
diff --git a/gweb/gweb.h b/gweb/gweb.h
index c081431..0b997d5 100644
--- a/gweb/gweb.h
+++ b/gweb/gweb.h
@@ -22,6 +22,8 @@
#ifndef __G_WEB_H
#define __G_WEB_H
+#include <stdint.h>
+
#include <glib.h>
#ifdef __cplusplus
@@ -32,15 +34,26 @@ struct _GWeb;
typedef struct _GWeb GWeb;
+typedef enum {
+ G_WEB_METHOD_GET,
+} GWebMethod;
+
+typedef void (*GWebResultFunc)(uint16_t status, gpointer user_data);
+
typedef void (*GWebDebugFunc)(const char *str, gpointer user_data);
-GWeb *g_web_new(void);
+GWeb *g_web_new(int index);
GWeb *g_web_ref(GWeb *web);
void g_web_unref(GWeb *web);
void g_web_set_debug(GWeb *web, GWebDebugFunc func, gpointer user_data);
+guint g_web_request(GWeb *web, GWebMethod method, const char *url,
+ GWebResultFunc func, gpointer user_data);
+
+gboolean g_web_cancel(GWeb *web, guint id);
+
#ifdef __cplusplus
}
#endif