loudmouth/src/lm-proxy.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
       
     2 /*
       
     3  * Copyright (C) 2004 Imendio AB
       
     4  * Copyright (C) 2004 Josh Beam <josh@3ddrome.com>
       
     5  *
       
     6  * This program is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public License as
       
     8  * published by the Free Software Foundation; either version 2 of the
       
     9  * License, or (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Lesser General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Lesser General Public
       
    17  * License along with this program; if not, write to the
       
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    19  * Boston, MA 02111-1307, USA.
       
    20  */
       
    21 
       
    22 #include <config.h>
       
    23 
       
    24 #include <glib.h>
       
    25 #include <string.h>
       
    26 
       
    27 #ifndef G_OS_WIN32
       
    28 
       
    29 #include <unistd.h>
       
    30 #include <sys/socket.h>
       
    31 
       
    32 #else  /* G_OS_WIN32 */
       
    33 
       
    34 #include <winsock2.h>
       
    35 
       
    36 #endif /* G_OS_WIN32 */
       
    37 
       
    38 #include "lm-internals.h"
       
    39 #include "lm-proxy.h"
       
    40 #include "lm-debug.h"
       
    41 #include "lm-utils.h"
       
    42 
       
    43 struct _LmProxy {
       
    44 	LmProxyType  type;
       
    45 	gchar       *server;
       
    46 	guint        port;
       
    47 	gchar       *username;
       
    48 	gchar       *password;
       
    49 	guint        io_watch;
       
    50 
       
    51         gint         ref_count;
       
    52 };
       
    53 
       
    54 static void          proxy_free              (LmProxy       *proxy);
       
    55 static gboolean      proxy_http_negotiate    (LmProxy       *proxy,
       
    56 					      gint           fd, 
       
    57 					      const gchar   *server,
       
    58 					      guint          port);
       
    59 static gboolean      proxy_negotiate         (LmProxy       *proxy,
       
    60 					      gint           fd,
       
    61 					      const gchar   *server,
       
    62 					      guint          port);
       
    63 static gboolean      proxy_http_read_cb      (GIOChannel    *source,
       
    64 					      GIOCondition   condition,
       
    65 					      gpointer       data);
       
    66 static gboolean      proxy_read_cb           (GIOChannel    *source,
       
    67                                               GIOCondition   condition,
       
    68                                               gpointer       data);
       
    69 
       
    70 static void
       
    71 proxy_free (LmProxy *proxy)
       
    72 {
       
    73 	g_free (proxy->server);
       
    74 	g_free (proxy->username);
       
    75 	g_free (proxy->password);
       
    76 
       
    77 	g_free (proxy);
       
    78 }
       
    79 
       
    80 static gboolean
       
    81 proxy_http_negotiate (LmProxy *proxy, gint fd, const gchar *server, guint port)
       
    82 {
       
    83 	gchar *str;
       
    84 
       
    85 	if (proxy->username && proxy->password) {
       
    86 		gchar *tmp1;
       
    87 		gchar *tmp2;
       
    88 
       
    89 		tmp1 = g_strdup_printf ("%s:%s",
       
    90 					proxy->username, 
       
    91 					proxy->password);
       
    92 		tmp2 = _lm_utils_base64_encode (tmp1);
       
    93 		g_free (tmp1);
       
    94 
       
    95 		str = g_strdup_printf ("CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: Basic %s\r\n\r\n",
       
    96 				       server, port,
       
    97 				       server, port,
       
    98 				       tmp2);
       
    99 		g_free (tmp2);
       
   100 	} else {
       
   101 		str = g_strdup_printf ("CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\n\r\n",
       
   102 				       server, port, 
       
   103 				       server, port);
       
   104 	}
       
   105 
       
   106 	send (fd, str, strlen (str), 0);
       
   107 	g_free (str);
       
   108 	return TRUE;
       
   109 }
       
   110 
       
   111 /* returns TRUE when connected through proxy */
       
   112 static gboolean
       
   113 proxy_http_read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
       
   114 {
       
   115 	gchar          buf[512];
       
   116 	gsize          bytes_read;
       
   117 	GError        *error = NULL;
       
   118 
       
   119 	g_io_channel_read_chars (source, buf, 512, &bytes_read, &error);
       
   120 
       
   121 	if (bytes_read < 16) {
       
   122 		return FALSE;
       
   123 	}
       
   124 
       
   125 	if (strncmp (buf, "HTTP/1.1 200", 12) != 0 &&
       
   126 	    strncmp (buf, "HTTP/1.0 200", 12) != 0) {
       
   127 		return FALSE;
       
   128 	}
       
   129 
       
   130 	if (strncmp (buf + (bytes_read - 4), "\r\n\r\n", 4) != 0) {
       
   131 		return FALSE;
       
   132 	}
       
   133 	UNUSED_FORMAL_PARAM(condition);
       
   134 	UNUSED_FORMAL_PARAM(data);
       
   135 	return TRUE;
       
   136 }
       
   137 
       
   138 static gboolean
       
   139 proxy_read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
       
   140 {
       
   141 	LmConnectData *connect_data;
       
   142 	LmConnection  *connection;
       
   143 	LmProxy       *proxy;
       
   144 	gboolean       retval = FALSE;
       
   145 
       
   146 	connect_data = (LmConnectData *) data;
       
   147 	connection = connect_data->connection;
       
   148 	proxy = lm_connection_get_proxy (connection);
       
   149 
       
   150 	g_return_val_if_fail (proxy != NULL, FALSE);
       
   151 
       
   152 	if (lm_connection_is_open (connection)) {
       
   153 		return FALSE;
       
   154 	}
       
   155 
       
   156 	switch (lm_proxy_get_type (proxy)) {
       
   157 	default:
       
   158 	case LM_PROXY_TYPE_NONE:
       
   159 		g_assert_not_reached ();
       
   160 		break;
       
   161 	case LM_PROXY_TYPE_HTTP:
       
   162 		retval = proxy_http_read_cb (source, condition, data);
       
   163 		break;
       
   164 	}
       
   165 
       
   166 	if (retval == TRUE) {
       
   167 		g_source_remove (proxy->io_watch);
       
   168 		_lm_socket_succeeded ((LmConnectData *) data);
       
   169 	}
       
   170 	//retval is false
       
   171 	//route call to connect_cb	
       
   172 	else
       
   173 	{
       
   174 	_lm_socket_failed_with_error(connect_data, _LM_SOCK_EINVAL);	
       
   175 	}
       
   176 	return FALSE;
       
   177 }
       
   178 
       
   179 gboolean
       
   180 proxy_negotiate (LmProxy *proxy, gint fd, const gchar *server, guint port)
       
   181 {
       
   182 	g_return_val_if_fail (proxy != NULL, FALSE);
       
   183 
       
   184 	switch (proxy->type) {
       
   185 	case LM_PROXY_TYPE_NONE:
       
   186 		return TRUE;
       
   187 	case LM_PROXY_TYPE_HTTP:
       
   188 		return proxy_http_negotiate (proxy, fd, server, port);
       
   189 	default:
       
   190 		g_assert_not_reached ();
       
   191 	}
       
   192 
       
   193 	return FALSE;
       
   194 }
       
   195 
       
   196 gboolean
       
   197 _lm_proxy_connect_cb (GIOChannel *source, GIOCondition condition, gpointer data)
       
   198 {
       
   199 	LmConnection  *connection;
       
   200 	LmConnectData *connect_data;
       
   201 	LmProxy       *proxy;
       
   202 	int            error;
       
   203 	socklen_t      len;
       
   204 
       
   205 	connect_data = (LmConnectData *) data;
       
   206 	connection = connect_data->connection;
       
   207 	proxy = lm_connection_get_proxy (connection);
       
   208 
       
   209 	g_return_val_if_fail (proxy != NULL, FALSE);
       
   210 
       
   211 	if (condition == G_IO_ERR) {
       
   212 		len = sizeof (error);
       
   213 		_lm_sock_get_error (connect_data->fd, &error, &len);
       
   214 		_lm_socket_failed_with_error (connect_data, error);
       
   215 		return FALSE;
       
   216 	} else if (condition == G_IO_OUT) {
       
   217 		if (!proxy_negotiate (lm_connection_get_proxy (connection), connect_data->fd, lm_connection_get_server (connection), lm_connection_get_port (connection))) {
       
   218 			_lm_socket_failed (connect_data);
       
   219 			return FALSE;
       
   220 		}
       
   221 			
       
   222 		proxy->io_watch = g_io_add_watch (connect_data->io_channel,
       
   223 						  G_IO_IN|G_IO_ERR,
       
   224 						  (GIOFunc) proxy_read_cb,
       
   225 						  connect_data);
       
   226 	} else {
       
   227 		g_assert_not_reached ();
       
   228 	}
       
   229 	UNUSED_FORMAL_PARAM(source);
       
   230 	return FALSE;
       
   231 }
       
   232 
       
   233 /**
       
   234  * lm_proxy_new
       
   235  * @type: the type of the new proxy
       
   236  * 
       
   237  * Creates a new Proxy. Used #lm_connection_set_proxy to make a connection 
       
   238  * user this proxy.
       
   239  * 
       
   240  * Return value: a newly create proxy
       
   241  **/
       
   242 EXPORT_C LmProxy * 
       
   243 lm_proxy_new (LmProxyType type)
       
   244 {
       
   245 	LmProxy *proxy;
       
   246 
       
   247 	proxy = g_new0 (LmProxy, 1);
       
   248 	
       
   249 	proxy->ref_count = 1;
       
   250 	proxy->type = type;
       
   251 
       
   252 	switch (proxy->type) {
       
   253 	case LM_PROXY_TYPE_HTTP:
       
   254 		proxy->port = 8000;
       
   255 		break;
       
   256 	default:
       
   257 		proxy->port = 0;
       
   258 	}
       
   259 
       
   260 	return proxy;
       
   261 }
       
   262 
       
   263 /**
       
   264  * lm_proxy_new_with_server
       
   265  * @type: the type of the new proxy
       
   266  * @server: the proxy server
       
   267  * @port: the proxy server port
       
   268  * 
       
   269  * Creates a new Proxy. Use #lm_connection_set_proxy to make a connection 
       
   270  * user this proxy.
       
   271  * 
       
   272  * Return value: a newly create proxy
       
   273  **/
       
   274 EXPORT_C LmProxy *
       
   275 lm_proxy_new_with_server (LmProxyType  type,
       
   276 			  const gchar *server,
       
   277 			  guint        port)
       
   278 {
       
   279 	LmProxy *proxy;
       
   280 
       
   281 	proxy = lm_proxy_new (type);
       
   282 	lm_proxy_set_server (proxy, server);
       
   283 	lm_proxy_set_port (proxy, port);
       
   284 
       
   285 	return proxy;
       
   286 }
       
   287 
       
   288 /**
       
   289  * lm_proxy_get_type
       
   290  * @proxy: an #LmProxy
       
   291  * 
       
   292  * Fetches the proxy type
       
   293  * 
       
   294  * Return value: the type 
       
   295  **/
       
   296 EXPORT_C LmProxyType
       
   297 lm_proxy_get_type (LmProxy *proxy)
       
   298 {
       
   299 	g_return_val_if_fail (proxy != NULL, LM_PROXY_TYPE_NONE);
       
   300 
       
   301 	return proxy->type;
       
   302 }
       
   303 
       
   304 /**
       
   305  * lm_proxy_set_type
       
   306  * @proxy: an #LmProxy
       
   307  * @type: an LmProxyType
       
   308  *
       
   309  * Sets the proxy type for @proxy to @type. 
       
   310  **/
       
   311 EXPORT_C void
       
   312 lm_proxy_set_type (LmProxy *proxy, LmProxyType type)
       
   313 {
       
   314 	g_return_if_fail (proxy != NULL);
       
   315 
       
   316 	proxy->type = type;
       
   317 }
       
   318 
       
   319 /**
       
   320  * lm_proxy_get_server:
       
   321  * @proxy: an #LmProxy
       
   322  * 
       
   323  * Fetches the server address that @proxy is using.
       
   324  * 
       
   325  * Return value: the proxy server address
       
   326  **/
       
   327 EXPORT_C const gchar *
       
   328 lm_proxy_get_server (LmProxy *proxy)
       
   329 {
       
   330 	g_return_val_if_fail (proxy != NULL, NULL);
       
   331 	
       
   332 	return proxy->server;
       
   333 }
       
   334 
       
   335 /**
       
   336  * lm_proxy_set_server:
       
   337  * @proxy: an #LmProxy
       
   338  * @server: Address of the proxy server
       
   339  * 
       
   340  * Sets the server address for @proxy to @server. 
       
   341  **/
       
   342 EXPORT_C void
       
   343 lm_proxy_set_server (LmProxy *proxy, const gchar *server)
       
   344 {
       
   345 	g_return_if_fail (proxy != NULL);
       
   346 	g_return_if_fail (server != NULL);
       
   347 	
       
   348 	g_free (proxy->server);
       
   349 	proxy->server = _lm_utils_hostname_to_punycode (server);
       
   350 }
       
   351 
       
   352 /**
       
   353  * lm_proxy_get_port:
       
   354  * @proxy: an #LmProxy
       
   355  * 
       
   356  * Fetches the port that @proxy is using.
       
   357  * 
       
   358  * Return value: The port 
       
   359  **/
       
   360 EXPORT_C guint
       
   361 lm_proxy_get_port (LmProxy *proxy)
       
   362 {
       
   363 	g_return_val_if_fail (proxy != NULL, 0);
       
   364 
       
   365 	return proxy->port;
       
   366 }
       
   367 
       
   368 /**
       
   369  * lm_proxy_set_port:
       
   370  * @proxy: an #LmProxy
       
   371  * @port: proxy server port
       
   372  * 
       
   373  * Sets the server port that @proxy will be using.
       
   374  **/
       
   375 EXPORT_C void
       
   376 lm_proxy_set_port (LmProxy *proxy, guint port)
       
   377 {
       
   378 	g_return_if_fail (proxy != NULL);
       
   379 	
       
   380 	proxy->port = port;
       
   381 }
       
   382 
       
   383 /**
       
   384  * lm_proxy_get_username:
       
   385  * @proxy: an #LmProxy
       
   386  * 
       
   387  * Fetches the username that @proxy is using.
       
   388  * 
       
   389  * Return value: the username
       
   390  **/
       
   391 EXPORT_C const gchar *
       
   392 lm_proxy_get_username (LmProxy *proxy)
       
   393 {
       
   394 	g_return_val_if_fail (proxy != NULL, NULL);
       
   395 	
       
   396 	return proxy->username;
       
   397 }
       
   398 
       
   399 /**
       
   400  * lm_proxy_set_username:
       
   401  * @proxy: an #LmProxy
       
   402  * @username: Username
       
   403  * 
       
   404  * Sets the username for @proxy to @username or %NULL to unset.  
       
   405  **/
       
   406 EXPORT_C void
       
   407 lm_proxy_set_username (LmProxy *proxy, const gchar *username)
       
   408 {
       
   409 	g_return_if_fail (proxy != NULL);
       
   410 	
       
   411 	g_free (proxy->username);
       
   412 	
       
   413 	if (username) {
       
   414 		proxy->username = g_strdup (username);
       
   415 	} else {
       
   416 		proxy->username = NULL;
       
   417 	}
       
   418 }
       
   419 /**
       
   420  * lm_proxy_get_password:
       
   421  * @proxy: an #LmProxy
       
   422  * 
       
   423  * Fetches the password that @proxy is using.
       
   424  * 
       
   425  * Return value: the proxy password
       
   426  **/
       
   427 EXPORT_C const gchar *
       
   428 lm_proxy_get_password (LmProxy *proxy)
       
   429 {
       
   430 	g_return_val_if_fail (proxy != NULL, NULL);
       
   431 	
       
   432 	return proxy->password;
       
   433 }
       
   434 
       
   435 /**
       
   436  * lm_proxy_set_password:
       
   437  * @proxy: an #LmProxy
       
   438  * @password: Password
       
   439  * 
       
   440  * Sets the password for @proxy to @password or %NULL to unset. 
       
   441  **/
       
   442 EXPORT_C void
       
   443 lm_proxy_set_password (LmProxy *proxy, const gchar *password)
       
   444 {
       
   445 	g_return_if_fail (proxy != NULL);
       
   446 	
       
   447 	g_free (proxy->password);
       
   448 
       
   449 	if (password) {
       
   450 		proxy->password = g_strdup (password);
       
   451 	} else {
       
   452 		proxy->password = NULL;
       
   453 	}
       
   454 }
       
   455 
       
   456 /**
       
   457  * lm_proxy_ref:
       
   458  * @proxy: an #LmProxy
       
   459  * 
       
   460  * Adds a reference to @proxy.
       
   461  * 
       
   462  * Return value: the proxy
       
   463  **/
       
   464 EXPORT_C LmProxy *
       
   465 lm_proxy_ref (LmProxy *proxy)
       
   466 {
       
   467 	g_return_val_if_fail (proxy != NULL, NULL);
       
   468 	
       
   469 	proxy->ref_count++;
       
   470 	return proxy;
       
   471 }
       
   472 
       
   473 /**
       
   474  * lm_proxy_unref
       
   475  * @proxy: an #LmProxy
       
   476  * 
       
   477  * Removes a reference from @proxy. When no more references are present
       
   478  * @proxy is freed.
       
   479  **/
       
   480 EXPORT_C void
       
   481 lm_proxy_unref (LmProxy *proxy)
       
   482 {
       
   483 	g_return_if_fail (proxy != NULL);
       
   484 	
       
   485 	proxy->ref_count--;
       
   486 
       
   487 	if (proxy->ref_count == 0) {
       
   488 		proxy_free (proxy);
       
   489         }
       
   490 }