loudmouth/src/lm-proxy.c
changeset 0 d0f3a028347a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/src/lm-proxy.c	Tue Feb 02 01:10:06 2010 +0200
@@ -0,0 +1,490 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004 Imendio AB
+ * Copyright (C) 2004 Josh Beam <josh@3ddrome.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <string.h>
+
+#ifndef G_OS_WIN32
+
+#include <unistd.h>
+#include <sys/socket.h>
+
+#else  /* G_OS_WIN32 */
+
+#include <winsock2.h>
+
+#endif /* G_OS_WIN32 */
+
+#include "lm-internals.h"
+#include "lm-proxy.h"
+#include "lm-debug.h"
+#include "lm-utils.h"
+
+struct _LmProxy {
+	LmProxyType  type;
+	gchar       *server;
+	guint        port;
+	gchar       *username;
+	gchar       *password;
+	guint        io_watch;
+
+        gint         ref_count;
+};
+
+static void          proxy_free              (LmProxy       *proxy);
+static gboolean      proxy_http_negotiate    (LmProxy       *proxy,
+					      gint           fd, 
+					      const gchar   *server,
+					      guint          port);
+static gboolean      proxy_negotiate         (LmProxy       *proxy,
+					      gint           fd,
+					      const gchar   *server,
+					      guint          port);
+static gboolean      proxy_http_read_cb      (GIOChannel    *source,
+					      GIOCondition   condition,
+					      gpointer       data);
+static gboolean      proxy_read_cb           (GIOChannel    *source,
+                                              GIOCondition   condition,
+                                              gpointer       data);
+
+static void
+proxy_free (LmProxy *proxy)
+{
+	g_free (proxy->server);
+	g_free (proxy->username);
+	g_free (proxy->password);
+
+	g_free (proxy);
+}
+
+static gboolean
+proxy_http_negotiate (LmProxy *proxy, gint fd, const gchar *server, guint port)
+{
+	gchar *str;
+
+	if (proxy->username && proxy->password) {
+		gchar *tmp1;
+		gchar *tmp2;
+
+		tmp1 = g_strdup_printf ("%s:%s",
+					proxy->username, 
+					proxy->password);
+		tmp2 = _lm_utils_base64_encode (tmp1);
+		g_free (tmp1);
+
+		str = g_strdup_printf ("CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: Basic %s\r\n\r\n",
+				       server, port,
+				       server, port,
+				       tmp2);
+		g_free (tmp2);
+	} else {
+		str = g_strdup_printf ("CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\n\r\n",
+				       server, port, 
+				       server, port);
+	}
+
+	send (fd, str, strlen (str), 0);
+	g_free (str);
+	return TRUE;
+}
+
+/* returns TRUE when connected through proxy */
+static gboolean
+proxy_http_read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+	gchar          buf[512];
+	gsize          bytes_read;
+	GError        *error = NULL;
+
+	g_io_channel_read_chars (source, buf, 512, &bytes_read, &error);
+
+	if (bytes_read < 16) {
+		return FALSE;
+	}
+
+	if (strncmp (buf, "HTTP/1.1 200", 12) != 0 &&
+	    strncmp (buf, "HTTP/1.0 200", 12) != 0) {
+		return FALSE;
+	}
+
+	if (strncmp (buf + (bytes_read - 4), "\r\n\r\n", 4) != 0) {
+		return FALSE;
+	}
+	UNUSED_FORMAL_PARAM(condition);
+	UNUSED_FORMAL_PARAM(data);
+	return TRUE;
+}
+
+static gboolean
+proxy_read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+	LmConnectData *connect_data;
+	LmConnection  *connection;
+	LmProxy       *proxy;
+	gboolean       retval = FALSE;
+
+	connect_data = (LmConnectData *) data;
+	connection = connect_data->connection;
+	proxy = lm_connection_get_proxy (connection);
+
+	g_return_val_if_fail (proxy != NULL, FALSE);
+
+	if (lm_connection_is_open (connection)) {
+		return FALSE;
+	}
+
+	switch (lm_proxy_get_type (proxy)) {
+	default:
+	case LM_PROXY_TYPE_NONE:
+		g_assert_not_reached ();
+		break;
+	case LM_PROXY_TYPE_HTTP:
+		retval = proxy_http_read_cb (source, condition, data);
+		break;
+	}
+
+	if (retval == TRUE) {
+		g_source_remove (proxy->io_watch);
+		_lm_socket_succeeded ((LmConnectData *) data);
+	}
+	//retval is false
+	//route call to connect_cb	
+	else
+	{
+	_lm_socket_failed_with_error(connect_data, _LM_SOCK_EINVAL);	
+	}
+	return FALSE;
+}
+
+gboolean
+proxy_negotiate (LmProxy *proxy, gint fd, const gchar *server, guint port)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+
+	switch (proxy->type) {
+	case LM_PROXY_TYPE_NONE:
+		return TRUE;
+	case LM_PROXY_TYPE_HTTP:
+		return proxy_http_negotiate (proxy, fd, server, port);
+	default:
+		g_assert_not_reached ();
+	}
+
+	return FALSE;
+}
+
+gboolean
+_lm_proxy_connect_cb (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+	LmConnection  *connection;
+	LmConnectData *connect_data;
+	LmProxy       *proxy;
+	int            error;
+	socklen_t      len;
+
+	connect_data = (LmConnectData *) data;
+	connection = connect_data->connection;
+	proxy = lm_connection_get_proxy (connection);
+
+	g_return_val_if_fail (proxy != NULL, FALSE);
+
+	if (condition == G_IO_ERR) {
+		len = sizeof (error);
+		_lm_sock_get_error (connect_data->fd, &error, &len);
+		_lm_socket_failed_with_error (connect_data, error);
+		return FALSE;
+	} else if (condition == G_IO_OUT) {
+		if (!proxy_negotiate (lm_connection_get_proxy (connection), connect_data->fd, lm_connection_get_server (connection), lm_connection_get_port (connection))) {
+			_lm_socket_failed (connect_data);
+			return FALSE;
+		}
+			
+		proxy->io_watch = g_io_add_watch (connect_data->io_channel,
+						  G_IO_IN|G_IO_ERR,
+						  (GIOFunc) proxy_read_cb,
+						  connect_data);
+	} else {
+		g_assert_not_reached ();
+	}
+	UNUSED_FORMAL_PARAM(source);
+	return FALSE;
+}
+
+/**
+ * lm_proxy_new
+ * @type: the type of the new proxy
+ * 
+ * Creates a new Proxy. Used #lm_connection_set_proxy to make a connection 
+ * user this proxy.
+ * 
+ * Return value: a newly create proxy
+ **/
+EXPORT_C LmProxy * 
+lm_proxy_new (LmProxyType type)
+{
+	LmProxy *proxy;
+
+	proxy = g_new0 (LmProxy, 1);
+	
+	proxy->ref_count = 1;
+	proxy->type = type;
+
+	switch (proxy->type) {
+	case LM_PROXY_TYPE_HTTP:
+		proxy->port = 8000;
+		break;
+	default:
+		proxy->port = 0;
+	}
+
+	return proxy;
+}
+
+/**
+ * lm_proxy_new_with_server
+ * @type: the type of the new proxy
+ * @server: the proxy server
+ * @port: the proxy server port
+ * 
+ * Creates a new Proxy. Use #lm_connection_set_proxy to make a connection 
+ * user this proxy.
+ * 
+ * Return value: a newly create proxy
+ **/
+EXPORT_C LmProxy *
+lm_proxy_new_with_server (LmProxyType  type,
+			  const gchar *server,
+			  guint        port)
+{
+	LmProxy *proxy;
+
+	proxy = lm_proxy_new (type);
+	lm_proxy_set_server (proxy, server);
+	lm_proxy_set_port (proxy, port);
+
+	return proxy;
+}
+
+/**
+ * lm_proxy_get_type
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the proxy type
+ * 
+ * Return value: the type 
+ **/
+EXPORT_C LmProxyType
+lm_proxy_get_type (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, LM_PROXY_TYPE_NONE);
+
+	return proxy->type;
+}
+
+/**
+ * lm_proxy_set_type
+ * @proxy: an #LmProxy
+ * @type: an LmProxyType
+ *
+ * Sets the proxy type for @proxy to @type. 
+ **/
+EXPORT_C void
+lm_proxy_set_type (LmProxy *proxy, LmProxyType type)
+{
+	g_return_if_fail (proxy != NULL);
+
+	proxy->type = type;
+}
+
+/**
+ * lm_proxy_get_server:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the server address that @proxy is using.
+ * 
+ * Return value: the proxy server address
+ **/
+EXPORT_C const gchar *
+lm_proxy_get_server (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	return proxy->server;
+}
+
+/**
+ * lm_proxy_set_server:
+ * @proxy: an #LmProxy
+ * @server: Address of the proxy server
+ * 
+ * Sets the server address for @proxy to @server. 
+ **/
+EXPORT_C void
+lm_proxy_set_server (LmProxy *proxy, const gchar *server)
+{
+	g_return_if_fail (proxy != NULL);
+	g_return_if_fail (server != NULL);
+	
+	g_free (proxy->server);
+	proxy->server = _lm_utils_hostname_to_punycode (server);
+}
+
+/**
+ * lm_proxy_get_port:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the port that @proxy is using.
+ * 
+ * Return value: The port 
+ **/
+EXPORT_C guint
+lm_proxy_get_port (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, 0);
+
+	return proxy->port;
+}
+
+/**
+ * lm_proxy_set_port:
+ * @proxy: an #LmProxy
+ * @port: proxy server port
+ * 
+ * Sets the server port that @proxy will be using.
+ **/
+EXPORT_C void
+lm_proxy_set_port (LmProxy *proxy, guint port)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	proxy->port = port;
+}
+
+/**
+ * lm_proxy_get_username:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the username that @proxy is using.
+ * 
+ * Return value: the username
+ **/
+EXPORT_C const gchar *
+lm_proxy_get_username (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	return proxy->username;
+}
+
+/**
+ * lm_proxy_set_username:
+ * @proxy: an #LmProxy
+ * @username: Username
+ * 
+ * Sets the username for @proxy to @username or %NULL to unset.  
+ **/
+EXPORT_C void
+lm_proxy_set_username (LmProxy *proxy, const gchar *username)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	g_free (proxy->username);
+	
+	if (username) {
+		proxy->username = g_strdup (username);
+	} else {
+		proxy->username = NULL;
+	}
+}
+/**
+ * lm_proxy_get_password:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the password that @proxy is using.
+ * 
+ * Return value: the proxy password
+ **/
+EXPORT_C const gchar *
+lm_proxy_get_password (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	return proxy->password;
+}
+
+/**
+ * lm_proxy_set_password:
+ * @proxy: an #LmProxy
+ * @password: Password
+ * 
+ * Sets the password for @proxy to @password or %NULL to unset. 
+ **/
+EXPORT_C void
+lm_proxy_set_password (LmProxy *proxy, const gchar *password)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	g_free (proxy->password);
+
+	if (password) {
+		proxy->password = g_strdup (password);
+	} else {
+		proxy->password = NULL;
+	}
+}
+
+/**
+ * lm_proxy_ref:
+ * @proxy: an #LmProxy
+ * 
+ * Adds a reference to @proxy.
+ * 
+ * Return value: the proxy
+ **/
+EXPORT_C LmProxy *
+lm_proxy_ref (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	proxy->ref_count++;
+	return proxy;
+}
+
+/**
+ * lm_proxy_unref
+ * @proxy: an #LmProxy
+ * 
+ * Removes a reference from @proxy. When no more references are present
+ * @proxy is freed.
+ **/
+EXPORT_C void
+lm_proxy_unref (LmProxy *proxy)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	proxy->ref_count--;
+
+	if (proxy->ref_count == 0) {
+		proxy_free (proxy);
+        }
+}