--- /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);
+ }
+}