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 } |
|