diff -r 000000000000 -r d0f3a028347a loudmouth/src/lm-proxy.c --- /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 + * + * 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 + +#include +#include + +#ifndef G_OS_WIN32 + +#include +#include + +#else /* G_OS_WIN32 */ + +#include + +#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); + } +}