Remove build warning
[platform/upstream/libsoup.git] / libsoup / soup-connection.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-connection.c: A single HTTP/HTTPS connection
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include "soup-connection.h"
13 #include "soup.h"
14 #include "soup-message-queue.h"
15 #include "soup-misc-private.h"
16
17 #include "TIZEN.h"
18
19 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
20 #include <sys/prctl.h>
21 #ifndef PR_TASK_PERF_USER_TRACE
22 #define PR_TASK_PERF_USER_TRACE 666
23 #endif
24 #define MAX_STRING_LEN 256
25
26 static void prctl_with_url(const char *prestr, const char *url)
27 {
28         char s[MAX_STRING_LEN] = "";
29         int len_max = 120;
30         int len_pre = strlen(prestr);
31         int len_url = strlen(url);
32
33         strncpy(s, prestr, len_pre);
34         if(len_pre + len_url < len_max) {
35                 strncpy(s+len_pre, url, len_url);
36         }
37         else {
38                 int len_part = len_max - len_pre - 10;
39                 strncpy(s+len_pre, url, len_part);
40                 strncpy(s+len_pre+len_part, "...", MAX_STRING_LEN-len_pre-len_part-1);
41                 strncpy(s+len_pre+len_part+3, url+len_url-7, 7);
42         }
43         prctl(PR_TASK_PERF_USER_TRACE, s, strlen(s));
44 }
45
46 static void prctl_with_url_and_free(const char *prestr, char *url)
47 {
48         prctl_with_url(prestr, url);
49         g_free(url);
50 }
51 #endif
52
53 typedef struct {
54         SoupSocket  *socket;
55
56         SoupAddress *local_addr;
57         SoupURI *remote_uri, *proxy_uri;
58         GProxyResolver *proxy_resolver;
59         GTlsDatabase *tlsdb;
60         gboolean ssl, ssl_strict, ssl_fallback;
61
62         GMainContext *async_context;
63         gboolean      use_thread_context;
64
65         SoupMessage *current_msg;
66         SoupConnectionState state;
67         time_t       unused_timeout;
68         guint        io_timeout, idle_timeout;
69         GSource     *idle_timeout_src;
70         gboolean     reusable;
71 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
72         SoupMessageQueueItem *cur_item;
73 #endif
74
75 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
76         gboolean     widget_engine;
77 #endif
78 } SoupConnectionPrivate;
79 #define SOUP_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_CONNECTION, SoupConnectionPrivate))
80
81 G_DEFINE_TYPE (SoupConnection, soup_connection, G_TYPE_OBJECT)
82
83 enum {
84         EVENT,
85         DISCONNECTED,
86 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
87         DYNAMIC_CERTIFICATEPATH,
88 #endif
89 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
90         ACCEPT_CERTIFICATE,
91 #endif
92         LAST_SIGNAL
93 };
94
95 static guint signals[LAST_SIGNAL] = { 0 };
96
97 enum {
98         PROP_0,
99
100         PROP_LOCAL_ADDRESS,
101         PROP_REMOTE_URI,
102         PROP_PROXY_RESOLVER,
103         PROP_SSL,
104         PROP_SSL_CREDS,
105         PROP_SSL_STRICT,
106         PROP_SSL_FALLBACK,
107         PROP_ASYNC_CONTEXT,
108         PROP_USE_THREAD_CONTEXT,
109         PROP_TIMEOUT,
110         PROP_IDLE_TIMEOUT,
111         PROP_STATE,
112 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
113         PROP_WIDGET_ENGINE,
114 #endif
115
116         LAST_PROP
117 };
118
119 static void stop_idle_timer (SoupConnectionPrivate *priv);
120
121 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
122 static void clear_current_item (SoupConnection *conn);
123 #endif
124
125 /* Number of seconds after which we close a connection that hasn't yet
126  * been used.
127  */
128 #define SOUP_CONNECTION_UNUSED_TIMEOUT 3
129
130 static void
131 soup_connection_init (SoupConnection *conn)
132 {
133 }
134
135 static void
136 soup_connection_finalize (GObject *object)
137 {
138         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
139
140         g_clear_pointer (&priv->remote_uri, soup_uri_free);
141         g_clear_pointer (&priv->proxy_uri, soup_uri_free);
142         g_clear_object (&priv->tlsdb);
143         g_clear_object (&priv->proxy_resolver);
144         g_clear_object (&priv->local_addr);
145         g_clear_pointer (&priv->async_context, g_main_context_unref);
146
147         G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
148 }
149
150 static void
151 soup_connection_dispose (GObject *object)
152 {
153         SoupConnection *conn = SOUP_CONNECTION (object);
154         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
155
156         stop_idle_timer (priv);
157
158 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
159         if (priv->cur_item) {
160                 clear_current_item (conn);
161         }
162 #endif
163         if (priv->socket) {
164                 g_warning ("Disposing connection while connected");
165                 soup_connection_disconnect (conn);
166         }
167
168         G_OBJECT_CLASS (soup_connection_parent_class)->dispose (object);
169 }
170
171 static void
172 soup_connection_set_property (GObject *object, guint prop_id,
173                               const GValue *value, GParamSpec *pspec)
174 {
175         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
176
177         switch (prop_id) {
178         case PROP_LOCAL_ADDRESS:
179                 priv->local_addr = g_value_dup_object (value);
180                 break;
181         case PROP_REMOTE_URI:
182                 priv->remote_uri = g_value_dup_boxed (value);
183                 break;
184         case PROP_PROXY_RESOLVER:
185                 priv->proxy_resolver = g_value_dup_object (value);
186                 break;
187         case PROP_SSL:
188                 priv->ssl = g_value_get_boolean (value);
189                 break;
190         case PROP_SSL_CREDS:
191                 if (priv->tlsdb)
192                         g_object_unref (priv->tlsdb);
193                 priv->tlsdb = g_value_dup_object (value);
194                 break;
195         case PROP_SSL_STRICT:
196                 priv->ssl_strict = g_value_get_boolean (value);
197                 break;
198         case PROP_SSL_FALLBACK:
199                 priv->ssl_fallback = g_value_get_boolean (value);
200                 break;
201         case PROP_ASYNC_CONTEXT:
202                 priv->async_context = g_value_get_pointer (value);
203                 if (priv->async_context)
204                         g_main_context_ref (priv->async_context);
205                 break;
206         case PROP_USE_THREAD_CONTEXT:
207                 priv->use_thread_context = g_value_get_boolean (value);
208                 break;
209         case PROP_TIMEOUT:
210                 priv->io_timeout = g_value_get_uint (value);
211                 break;
212         case PROP_IDLE_TIMEOUT:
213                 priv->idle_timeout = g_value_get_uint (value);
214                 break;
215         case PROP_STATE:
216                 soup_connection_set_state (SOUP_CONNECTION (object), g_value_get_uint (value));
217                 break;
218 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
219         case PROP_WIDGET_ENGINE:
220                 priv->widget_engine = g_value_get_boolean (value);
221                 break;
222 #endif
223         default:
224                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225                 break;
226         }
227 }
228
229 static void
230 soup_connection_get_property (GObject *object, guint prop_id,
231                               GValue *value, GParamSpec *pspec)
232 {
233         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
234
235         switch (prop_id) {
236         case PROP_LOCAL_ADDRESS:
237                 g_value_set_object (value, priv->local_addr);
238                 break;
239         case PROP_REMOTE_URI:
240                 g_value_set_boxed (value, priv->remote_uri);
241                 break;
242         case PROP_SSL:
243                 g_value_set_boolean (value, priv->ssl);
244                 break;
245         case PROP_SSL_CREDS:
246                 g_value_set_object (value, priv->tlsdb);
247                 break;
248         case PROP_SSL_STRICT:
249                 g_value_set_boolean (value, priv->ssl_strict);
250                 break;
251         case PROP_SSL_FALLBACK:
252                 g_value_set_boolean (value, priv->ssl_fallback);
253                 break;
254         case PROP_ASYNC_CONTEXT:
255                 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
256                 break;
257         case PROP_USE_THREAD_CONTEXT:
258                 g_value_set_boolean (value, priv->use_thread_context);
259                 break;
260         case PROP_TIMEOUT:
261                 g_value_set_uint (value, priv->io_timeout);
262                 break;
263         case PROP_IDLE_TIMEOUT:
264                 g_value_set_uint (value, priv->idle_timeout);
265                 break;
266         case PROP_STATE:
267                 g_value_set_enum (value, priv->state);
268                 break;
269 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
270         case PROP_WIDGET_ENGINE:
271                 g_value_set_boolean (value, priv->widget_engine);
272                 break;
273 #endif
274         default:
275                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
276                 break;
277         }
278 }
279
280 static void
281 soup_connection_class_init (SoupConnectionClass *connection_class)
282 {
283         GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
284
285         g_type_class_add_private (connection_class, sizeof (SoupConnectionPrivate));
286
287         /* virtual method override */
288         object_class->dispose = soup_connection_dispose;
289         object_class->finalize = soup_connection_finalize;
290         object_class->set_property = soup_connection_set_property;
291         object_class->get_property = soup_connection_get_property;
292
293         /* signals */
294         signals[EVENT] =
295                 g_signal_new ("event",
296                               G_OBJECT_CLASS_TYPE (object_class),
297                               G_SIGNAL_RUN_FIRST,
298                               0,
299                               NULL, NULL,
300                               NULL,
301                               G_TYPE_NONE, 2,
302                               G_TYPE_SOCKET_CLIENT_EVENT,
303                               G_TYPE_IO_STREAM);
304         signals[DISCONNECTED] =
305                 g_signal_new ("disconnected",
306                               G_OBJECT_CLASS_TYPE (object_class),
307                               G_SIGNAL_RUN_FIRST,
308                               G_STRUCT_OFFSET (SoupConnectionClass, disconnected),
309                               NULL, NULL,
310                               NULL,
311                               G_TYPE_NONE, 0);
312 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
313         signals[ACCEPT_CERTIFICATE] =
314                 g_signal_new ("accept-certificate",
315                               G_OBJECT_CLASS_TYPE (object_class),
316                               G_SIGNAL_RUN_LAST,
317                               0,
318                               NULL, NULL,
319                               NULL,
320                               G_TYPE_BOOLEAN, 2,
321                               G_TYPE_TLS_CERTIFICATE,
322                               G_TYPE_TLS_CERTIFICATE_FLAGS);
323 #endif
324
325 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
326         signals[DYNAMIC_CERTIFICATEPATH] =
327                 g_signal_new ("dynamic-certificatePath",
328                               G_OBJECT_CLASS_TYPE (object_class),
329                               G_SIGNAL_RUN_LAST,
330                               0,
331                               NULL, NULL,
332                               NULL,
333                               G_TYPE_POINTER, 1,
334                               G_TYPE_POINTER);
335 #endif
336
337         /* properties */
338         g_object_class_install_property (
339                 object_class, PROP_LOCAL_ADDRESS,
340                 g_param_spec_object (SOUP_CONNECTION_LOCAL_ADDRESS,
341                                      "Local address",
342                                      "Address of local end of socket",
343                                      SOUP_TYPE_ADDRESS,
344                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
345         g_object_class_install_property (
346                 object_class, PROP_REMOTE_URI,
347                 g_param_spec_boxed (SOUP_CONNECTION_REMOTE_URI,
348                                     "Remote URI",
349                                     "The URI of the HTTP server",
350                                     SOUP_TYPE_URI,
351                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
352         g_object_class_install_property (
353                 object_class, PROP_PROXY_RESOLVER,
354                 g_param_spec_object (SOUP_CONNECTION_PROXY_RESOLVER,
355                                      "Proxy resolver",
356                                      "GProxyResolver to use",
357                                      G_TYPE_PROXY_RESOLVER,
358                                      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
359         g_object_class_install_property (
360                 object_class, PROP_SSL,
361                 g_param_spec_boolean (SOUP_CONNECTION_SSL,
362                                       "SSL",
363                                       "Whether this is an SSL connection",
364                                       FALSE,
365                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
366         g_object_class_install_property (
367                 object_class, PROP_SSL_CREDS,
368                 g_param_spec_object (SOUP_CONNECTION_SSL_CREDENTIALS,
369                                      "SSL credentials",
370                                      "SSL credentials for this connection",
371                                      G_TYPE_TLS_DATABASE,
372                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
373         g_object_class_install_property (
374                 object_class, PROP_SSL_STRICT,
375                 g_param_spec_boolean (SOUP_CONNECTION_SSL_STRICT,
376                                       "Strictly validate SSL certificates",
377                                       "Whether certificate errors should be considered a connection error",
378                                       TRUE,
379                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
380         g_object_class_install_property (
381                 object_class, PROP_SSL_FALLBACK,
382                 g_param_spec_boolean (SOUP_CONNECTION_SSL_FALLBACK,
383                                       "SSLv3 fallback",
384                                       "Use SSLv3 instead of TLS",
385                                       FALSE,
386                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
387         g_object_class_install_property (
388                 object_class, PROP_ASYNC_CONTEXT,
389                 g_param_spec_pointer (SOUP_CONNECTION_ASYNC_CONTEXT,
390                                       "Async GMainContext",
391                                       "GMainContext to dispatch this connection's async I/O in",
392                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
393         g_object_class_install_property (
394                 object_class, PROP_USE_THREAD_CONTEXT,
395                 g_param_spec_boolean (SOUP_CONNECTION_USE_THREAD_CONTEXT,
396                                       "Use thread context",
397                                       "Use g_main_context_get_thread_default",
398                                       FALSE,
399                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
400         g_object_class_install_property (
401                 object_class, PROP_TIMEOUT,
402                 g_param_spec_uint (SOUP_CONNECTION_TIMEOUT,
403                                    "Timeout value",
404                                    "Value in seconds to timeout a blocking I/O",
405                                    0, G_MAXUINT, 0,
406                                    G_PARAM_READWRITE));
407         g_object_class_install_property (
408                 object_class, PROP_IDLE_TIMEOUT,
409                 g_param_spec_uint (SOUP_CONNECTION_IDLE_TIMEOUT,
410                                    "Idle Timeout",
411                                    "Connection lifetime when idle",
412                                    0, G_MAXUINT, 0,
413                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
414         g_object_class_install_property (
415                 object_class, PROP_STATE,
416                 g_param_spec_enum (SOUP_CONNECTION_STATE,
417                                    "Connection state",
418                                    "Current state of connection",
419                                    SOUP_TYPE_CONNECTION_STATE, SOUP_CONNECTION_NEW,
420                                    G_PARAM_READWRITE));
421 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
422         g_object_class_install_property (
423                 object_class, PROP_WIDGET_ENGINE,
424                 g_param_spec_boolean (SOUP_CONNECTION_WIDGET_ENGINE,
425                                       "widget engine",
426                                       "Whether or not to be running Widget Engine",
427                                       FALSE,
428                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
429 #endif
430 }
431
432 static void
433 soup_connection_event (SoupConnection      *conn,
434                        GSocketClientEvent   event,
435                        GIOStream           *connection)
436 {
437         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
438
439         if (!connection && priv->socket)
440                 connection = soup_socket_get_connection (priv->socket);
441
442         g_signal_emit (conn, signals[EVENT], 0,
443                        event, connection);
444 }
445
446 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
447 static const char*
448 soup_connection_dynamic_client_certificate (SoupSocket *sock,
449                                             const char* current_host,
450                                             gpointer user_data)
451 {
452         SoupConnection* conn = user_data;
453         const char* get_certpath = NULL;
454
455         g_signal_emit (conn, signals[DYNAMIC_CERTIFICATEPATH], 0,
456                        current_host, &get_certpath);
457
458         return get_certpath;
459 }
460 #endif
461 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
462 static gboolean
463 soup_connection_accept_certificate (SoupSocket *sock,
464                                     GTlsCertificate* certificate,
465                                     GTlsCertificateFlags errors,
466                                     gpointer user_data)
467 {
468         SoupConnection* conn = user_data;
469         gboolean accept = FALSE;
470
471         g_signal_emit (conn, signals[ACCEPT_CERTIFICATE], 0,
472                        certificate, errors, &accept);
473
474         return accept;
475 }
476 #endif
477
478 static gboolean
479 idle_timeout (gpointer conn)
480 {
481         soup_connection_disconnect (conn);
482         return FALSE;
483 }
484
485 static void
486 start_idle_timer (SoupConnection *conn)
487 {
488         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
489
490         if (priv->idle_timeout > 0 && !priv->idle_timeout_src) {
491                 priv->idle_timeout_src =
492                         soup_add_timeout (priv->async_context,
493                                           priv->idle_timeout * 1000,
494                                           idle_timeout, conn);
495         }
496 }
497
498 static void
499 stop_idle_timer (SoupConnectionPrivate *priv)
500 {
501         if (priv->idle_timeout_src) {
502                 g_source_destroy (priv->idle_timeout_src);
503                 priv->idle_timeout_src = NULL;
504         }
505 }
506
507 static void
508 current_msg_got_body (SoupMessage *msg, gpointer user_data)
509 {
510         SoupConnection *conn = user_data;
511         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
512
513         priv->unused_timeout = 0;
514
515         if (priv->proxy_uri &&
516             msg->method == SOUP_METHOD_CONNECT &&
517             SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
518                 soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATED, NULL);
519
520                 /* We're now effectively no longer proxying */
521                 g_clear_pointer (&priv->proxy_uri, soup_uri_free);
522         }
523
524         priv->reusable = soup_message_is_keepalive (msg);
525 }
526
527 static void
528 clear_current_msg (SoupConnection *conn)
529 {
530         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
531         SoupMessage *msg;
532
533         msg = priv->current_msg;
534         priv->current_msg = NULL;
535
536         g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (current_msg_got_body), conn);
537         g_object_unref (msg);
538 }
539
540 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
541 gboolean
542 soup_connection_has_current_item (SoupConnection *conn)
543 {
544         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
545
546         if (priv)
547                 return (priv->cur_item == NULL) ? FALSE : TRUE;
548         else
549                 return FALSE;
550 }
551
552 SoupMessageQueueItem *
553 soup_connection_get_current_item (SoupConnection *conn)
554 {
555         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
556
557         if (priv)
558                 return priv->cur_item;
559         else
560                 return NULL;
561 }
562
563 static void
564 clear_current_item (SoupConnection *conn)
565 {
566         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
567
568         g_return_if_fail (priv != NULL);
569
570         g_object_freeze_notify (G_OBJECT (conn));
571         if (priv->cur_item)
572                 priv->cur_item = NULL;
573 }
574
575 static void
576 set_current_item (SoupConnection *conn, SoupMessageQueueItem *item)
577 {
578         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
579
580         g_return_if_fail (priv != NULL);
581
582         priv->cur_item = item;
583 }
584
585
586
587 /* soup_connection_set_current_item() sets only item, and does not change any state.
588  * That is what this function is different from set_current_item() above. */
589 void
590 soup_connection_set_current_item (SoupConnection *conn, SoupMessageQueueItem *item)
591 {
592         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
593
594         g_return_if_fail (priv != NULL);
595         g_return_if_fail (priv->cur_item == NULL);
596
597         g_object_freeze_notify (G_OBJECT (conn));
598
599         stop_idle_timer (priv);
600
601         priv->cur_item = item;
602
603         g_object_thaw_notify (G_OBJECT (conn));
604 }
605 #endif
606
607 static void
608 set_current_msg (SoupConnection *conn, SoupMessage *msg)
609 {
610         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
611
612         g_return_if_fail (priv->state == SOUP_CONNECTION_IN_USE);
613
614         g_object_freeze_notify (G_OBJECT (conn));
615
616         if (priv->current_msg) {
617                 g_return_if_fail (priv->current_msg->method == SOUP_METHOD_CONNECT);
618                 clear_current_msg (conn);
619         }
620
621         stop_idle_timer (priv);
622
623         priv->current_msg = g_object_ref (msg);
624         priv->reusable = FALSE;
625
626         g_signal_connect (msg, "got-body",
627                           G_CALLBACK (current_msg_got_body), conn);
628
629         if (priv->proxy_uri && msg->method == SOUP_METHOD_CONNECT)
630                 soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATING, NULL);
631
632         g_object_thaw_notify (G_OBJECT (conn));
633 }
634
635 static void
636 re_emit_socket_event (SoupSocket          *socket,
637                       GSocketClientEvent   event,
638                       GIOStream           *connection,
639                       gpointer             user_data)
640 {
641         SoupConnection *conn = user_data;
642
643         /* We handle COMPLETE ourselves */
644         if (event != G_SOCKET_CLIENT_COMPLETE)
645                 soup_connection_event (conn, event, connection);
646 }
647
648 static void
649 socket_connect_finished (GTask *task, SoupSocket *sock, GError *error)
650 {
651         SoupConnection *conn = g_task_get_source_object (task);
652         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
653
654         if (priv->async_context && !priv->use_thread_context)
655                 g_main_context_pop_thread_default (priv->async_context);
656
657         g_signal_handlers_disconnect_by_func (sock, G_CALLBACK (re_emit_socket_event), conn);
658
659         if (!error) {
660                 if (priv->ssl && !priv->proxy_uri) {
661                         soup_connection_event (conn,
662                                                G_SOCKET_CLIENT_TLS_HANDSHAKED,
663                                                NULL);
664                 }
665                 if (!priv->ssl || !priv->proxy_uri) {
666                         soup_connection_event (conn,
667                                                G_SOCKET_CLIENT_COMPLETE,
668                                                NULL);
669                 }
670
671                 soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
672                 priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
673                 start_idle_timer (conn);
674
675                 g_task_return_boolean (task, TRUE);
676         } else
677                 g_task_return_error (task, error);
678         g_object_unref (task);
679 }
680
681 static void
682 socket_handshake_complete (GObject *object, GAsyncResult *result, gpointer user_data)
683 {
684         SoupSocket *sock = SOUP_SOCKET (object);
685         GTask *task = user_data;
686         GError *error = NULL;
687
688         soup_socket_handshake_finish (sock, result, &error);
689         socket_connect_finished (task, sock, error);
690 }
691
692 static void
693 socket_connect_complete (GObject *object, GAsyncResult *result, gpointer user_data)
694 {
695         SoupSocket *sock = SOUP_SOCKET (object);
696         GTask *task = user_data;
697         SoupConnection *conn = g_task_get_source_object (task);
698         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
699         GError *error = NULL;
700
701         if (!soup_socket_connect_finish_internal (sock, result, &error)) {
702                 socket_connect_finished (task, sock, error);
703                 return;
704         }
705
706         priv->proxy_uri = soup_socket_get_http_proxy_uri (sock);
707
708         if (priv->ssl && !priv->proxy_uri) {
709                 soup_connection_event (conn,
710                                        G_SOCKET_CLIENT_TLS_HANDSHAKING,
711                                        NULL);
712
713                 soup_socket_handshake_async (sock, priv->remote_uri->host,
714                                              g_task_get_cancellable (task),
715                                              socket_handshake_complete, task);
716                 return;
717         }
718
719         socket_connect_finished (task, sock, NULL);
720 }
721
722 void
723 soup_connection_connect_async (SoupConnection      *conn,
724                                GCancellable        *cancellable,
725                                GAsyncReadyCallback  callback,
726                                gpointer             user_data)
727 {
728         SoupConnectionPrivate *priv;
729         SoupAddress *remote_addr;
730         GTask *task;
731
732         g_return_if_fail (SOUP_IS_CONNECTION (conn));
733         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
734         g_return_if_fail (priv->socket == NULL);
735
736         soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
737
738         /* Set the protocol to ensure correct proxy resolution. */
739         remote_addr =
740                 g_object_new (SOUP_TYPE_ADDRESS,
741                               SOUP_ADDRESS_NAME, priv->remote_uri->host,
742                               SOUP_ADDRESS_PORT, priv->remote_uri->port,
743                               SOUP_ADDRESS_PROTOCOL, priv->remote_uri->scheme,
744                               NULL);
745
746         priv->socket =
747                 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
748                                  SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
749                                  SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
750                                  SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
751                                  SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
752                                  SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context,
753                                  SOUP_SOCKET_PROXY_RESOLVER, priv->proxy_resolver,
754                                  SOUP_SOCKET_TIMEOUT, priv->io_timeout,
755                                  SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
756                                  SOUP_SOCKET_LOCAL_ADDRESS, priv->local_addr,
757 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
758                                  SOUP_SOCKET_WIDGET_ENGINE, priv->widget_engine,
759 #endif
760                                  NULL);
761         g_object_unref (remote_addr);
762
763         g_signal_connect (priv->socket, "event",
764                           G_CALLBACK (re_emit_socket_event), conn);
765 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
766         g_signal_connect (priv->socket, "accept-certificate",
767                           G_CALLBACK (soup_connection_accept_certificate), conn);
768 #endif
769
770 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
771         g_signal_connect (priv->socket, "dynamic-certificatePath",
772                                   G_CALLBACK (soup_connection_dynamic_client_certificate), conn);
773 #endif
774         if (priv->async_context && !priv->use_thread_context)
775                 g_main_context_push_thread_default (priv->async_context);
776         task = g_task_new (conn, cancellable, callback, user_data);
777
778         soup_socket_connect_async_internal (priv->socket, cancellable,
779                                             socket_connect_complete, task);
780 }
781
782 gboolean
783 soup_connection_connect_finish (SoupConnection  *conn,
784                                 GAsyncResult    *result,
785                                 GError         **error)
786 {
787         return g_task_propagate_boolean (G_TASK (result), error);
788 }
789
790 gboolean
791 soup_connection_connect_sync (SoupConnection  *conn,
792                               GCancellable    *cancellable,
793                               GError         **error)
794 {
795         SoupConnectionPrivate *priv;
796         guint event_id = 0;
797         SoupAddress *remote_addr;
798         gboolean success = TRUE;
799
800         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
801         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
802         g_return_val_if_fail (priv->socket == NULL, FALSE);
803
804         soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
805
806         /* Set the protocol to ensure correct proxy resolution. */
807         remote_addr =
808                 g_object_new (SOUP_TYPE_ADDRESS,
809                               SOUP_ADDRESS_NAME, priv->remote_uri->host,
810                               SOUP_ADDRESS_PORT, priv->remote_uri->port,
811                               SOUP_ADDRESS_PROTOCOL, priv->remote_uri->scheme,
812                               NULL);
813
814         priv->socket =
815                 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
816                                  SOUP_SOCKET_PROXY_RESOLVER, priv->proxy_resolver,
817                                  SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
818                                  SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
819                                  SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
820                                  SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
821                                  SOUP_SOCKET_TIMEOUT, priv->io_timeout,
822                                  SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
823                                  SOUP_SOCKET_LOCAL_ADDRESS, priv->local_addr,
824 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
825                                  SOUP_SOCKET_WIDGET_ENGINE, priv->widget_engine,
826 #endif
827                                  NULL);
828         g_object_unref (remote_addr);
829
830         event_id = g_signal_connect (priv->socket, "event",
831                                      G_CALLBACK (re_emit_socket_event), conn);
832 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
833         g_signal_connect (priv->socket, "accept-certificate",
834                           G_CALLBACK (soup_connection_accept_certificate), conn);
835 #endif
836
837         if (!soup_socket_connect_sync_internal (priv->socket, cancellable, error)) {
838                 success = FALSE;
839                 goto done;
840         }
841
842         priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
843
844         if (priv->ssl && !priv->proxy_uri) {
845                 soup_connection_event (conn,
846                                        G_SOCKET_CLIENT_TLS_HANDSHAKING,
847                                        NULL);
848                 if (!soup_socket_handshake_sync (priv->socket,
849                                                  priv->remote_uri->host,
850                                                  cancellable, error)) {
851                         success = FALSE;
852                         goto done;
853                 }
854                 soup_connection_event (conn,
855                                        G_SOCKET_CLIENT_TLS_HANDSHAKED,
856                                        NULL);
857         }
858
859         if (!priv->ssl || !priv->proxy_uri) {
860                 soup_connection_event (conn,
861                                        G_SOCKET_CLIENT_COMPLETE,
862                                        NULL);
863         }
864         soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
865         priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
866         start_idle_timer (conn);
867
868  done:
869         if (priv->socket && event_id)
870                 g_signal_handler_disconnect (priv->socket, event_id);
871
872         return success;
873 }
874
875 gboolean
876 soup_connection_is_tunnelled (SoupConnection *conn)
877 {
878         SoupConnectionPrivate *priv;
879
880         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
881         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
882
883         return priv->ssl && priv->proxy_uri != NULL;
884 }
885
886 gboolean
887 soup_connection_start_ssl_sync (SoupConnection  *conn,
888                                 GCancellable    *cancellable,
889                                 GError         **error)
890 {
891         SoupConnectionPrivate *priv;
892
893         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
894         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
895
896         soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
897         if (soup_socket_handshake_sync (priv->socket, priv->remote_uri->host,
898                                         cancellable, error)) {
899                 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
900                 soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
901                 return TRUE;
902         } else
903                 return FALSE;
904 }
905
906 static void
907 start_ssl_completed (GObject *object, GAsyncResult *result, gpointer user_data)
908 {
909         GTask *task = user_data;
910         SoupConnection *conn = g_task_get_source_object (task);
911         SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
912         GError *error = NULL;
913
914         if (priv->async_context && !priv->use_thread_context)
915                 g_main_context_pop_thread_default (priv->async_context);
916
917         if (soup_socket_handshake_finish (priv->socket, result, &error)) {
918                 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
919                 soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
920                 g_task_return_boolean (task, TRUE);
921 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
922                 prctl_with_url_and_free("[EVT] soup handshake complete : ", soup_uri_to_string(soup_connection_get_remote_uri(conn), FALSE));
923 #endif
924         } else
925                 g_task_return_error (task, error);
926         g_object_unref (task);
927 }
928
929 void
930 soup_connection_start_ssl_async (SoupConnection      *conn,
931                                  GCancellable        *cancellable,
932                                  GAsyncReadyCallback  callback,
933                                  gpointer             user_data)
934 {
935         SoupConnectionPrivate *priv;
936         GTask *task;
937
938         g_return_if_fail (SOUP_IS_CONNECTION (conn));
939         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
940
941         soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
942
943         if (priv->async_context && !priv->use_thread_context)
944                 g_main_context_push_thread_default (priv->async_context);
945         task = g_task_new (conn, cancellable, callback, user_data);
946
947         soup_socket_handshake_async (priv->socket, priv->remote_uri->host,
948                                      cancellable, start_ssl_completed, task);
949 }
950
951 gboolean
952 soup_connection_start_ssl_finish (SoupConnection  *conn,
953                                   GAsyncResult    *result,
954                                   GError         **error)
955 {
956         return g_task_propagate_boolean (G_TASK (result), error);
957 }
958
959 /**
960  * soup_connection_disconnect:
961  * @conn: a connection
962  *
963  * Disconnects @conn's socket and emits a %disconnected signal.
964  * After calling this, @conn will be essentially useless.
965  **/
966 void
967 soup_connection_disconnect (SoupConnection *conn)
968 {
969         SoupConnectionPrivate *priv;
970         SoupConnectionState old_state;
971
972         g_return_if_fail (SOUP_IS_CONNECTION (conn));
973         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
974
975         old_state = priv->state;
976         if (old_state != SOUP_CONNECTION_DISCONNECTED)
977                 soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
978
979         if (priv->socket) {
980                 SoupSocket *socket = priv->socket;
981
982                 priv->socket = NULL;
983                 soup_socket_disconnect (socket);
984                 g_object_unref (socket);
985         }
986
987         if (old_state != SOUP_CONNECTION_DISCONNECTED)
988                 g_signal_emit (conn, signals[DISCONNECTED], 0);
989 }
990
991 SoupSocket *
992 soup_connection_get_socket (SoupConnection *conn)
993 {
994         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
995
996         return SOUP_CONNECTION_GET_PRIVATE (conn)->socket;
997 }
998
999 SoupURI *
1000 soup_connection_get_remote_uri (SoupConnection *conn)
1001 {
1002         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1003
1004         return SOUP_CONNECTION_GET_PRIVATE (conn)->remote_uri;
1005 }
1006
1007 SoupURI *
1008 soup_connection_get_proxy_uri (SoupConnection *conn)
1009 {
1010         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1011
1012         return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri;
1013 }
1014
1015 gboolean
1016 soup_connection_is_via_proxy (SoupConnection *conn)
1017 {
1018         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
1019
1020         return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri != NULL;
1021 }
1022
1023 SoupConnectionState
1024 soup_connection_get_state (SoupConnection *conn)
1025 {
1026         SoupConnectionPrivate *priv;
1027
1028         g_return_val_if_fail (SOUP_IS_CONNECTION (conn),
1029                               SOUP_CONNECTION_DISCONNECTED);
1030         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1031
1032         if (priv->state == SOUP_CONNECTION_IDLE &&
1033             g_socket_condition_check (soup_socket_get_gsocket (priv->socket), G_IO_IN))
1034                 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
1035
1036         if (priv->state == SOUP_CONNECTION_IDLE &&
1037             priv->unused_timeout && priv->unused_timeout < time (NULL))
1038                 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
1039
1040         return priv->state;
1041 }
1042
1043 void
1044 soup_connection_set_state (SoupConnection *conn, SoupConnectionState state)
1045 {
1046         SoupConnectionPrivate *priv;
1047
1048         g_return_if_fail (SOUP_IS_CONNECTION (conn));
1049         g_return_if_fail (state >= SOUP_CONNECTION_NEW &&
1050                           state <= SOUP_CONNECTION_DISCONNECTED);
1051
1052         g_object_freeze_notify (G_OBJECT (conn));
1053
1054         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1055
1056         if (priv->current_msg) {
1057                 g_warn_if_fail (state == SOUP_CONNECTION_IDLE ||
1058                                 state == SOUP_CONNECTION_DISCONNECTED);
1059 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1060                 clear_current_item (conn);
1061 #endif
1062                 clear_current_msg (conn);
1063         }
1064
1065         if (state == SOUP_CONNECTION_IDLE && !priv->reusable) {
1066                 /* This will recursively call set_state() */
1067                 soup_connection_disconnect (conn);
1068         } else {
1069                 priv->state = state;
1070
1071                 if (priv->state == SOUP_CONNECTION_IDLE)
1072                         start_idle_timer (conn);
1073
1074                 g_object_notify (G_OBJECT (conn), "state");
1075         }
1076
1077         g_object_thaw_notify (G_OBJECT (conn));
1078 }
1079
1080 gboolean
1081 soup_connection_get_ever_used (SoupConnection *conn)
1082 {
1083         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
1084
1085         return SOUP_CONNECTION_GET_PRIVATE (conn)->unused_timeout == 0;
1086 }
1087
1088 gboolean
1089 soup_connection_get_ssl_fallback (SoupConnection *conn)
1090 {
1091         return SOUP_CONNECTION_GET_PRIVATE (conn)->ssl_fallback;
1092 }
1093
1094 void
1095 soup_connection_send_request (SoupConnection          *conn,
1096                               SoupMessageQueueItem    *item,
1097                               SoupMessageCompletionFn  completion_cb,
1098                               gpointer                 user_data)
1099 {
1100         SoupConnectionPrivate *priv;
1101
1102         g_return_if_fail (SOUP_IS_CONNECTION (conn));
1103         g_return_if_fail (item != NULL);
1104         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1105         g_return_if_fail (priv->state != SOUP_CONNECTION_NEW &&
1106                           priv->state != SOUP_CONNECTION_DISCONNECTED);
1107
1108 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1109         set_current_item (conn, item);
1110         set_current_msg (conn, item->msg);
1111 #else
1112         if (item->msg != priv->current_msg)
1113                 set_current_msg (conn, item->msg);
1114         else
1115                 priv->reusable = FALSE;
1116 #endif
1117
1118         soup_message_send_request (item, completion_cb, user_data);
1119 }
1120
1121 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1122 void
1123 soup_connection_set_pre_connect_idle (SoupConnection *conn)
1124 {
1125         SoupConnectionPrivate *priv = NULL;
1126
1127         g_return_if_fail (SOUP_IS_CONNECTION (conn));
1128         priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1129
1130         if (priv) {
1131                 if (priv->state == SOUP_CONNECTION_IN_USE)
1132                         priv->state = SOUP_CONNECTION_IDLE;
1133         }
1134 }
1135 #endif