1 /*
2 * stream-tube-channel.h - high level API for StreamTube channels
3 *
4 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:stream-tube-channel
23 * @title: TpStreamTubeChannel
24 * @short_description: proxy object for a stream tube channel
25 *
26 * #TpStreamTubeChannel is a sub-class of #TpChannel providing convenient API
27 * to offer and accept a stream tube.
28 *
29 * Since: 0.13.2
30 */
31
32 /**
33 * TpStreamTubeChannel:
34 *
35 * Data structure representing a #TpStreamTubeChannel.
36 *
37 * Since: 0.13.2
38 */
39
40 /**
41 * TpStreamTubeChannelClass:
42 *
43 * The class of a #TpStreamTubeChannel.
44 *
45 * Since: 0.13.2
46 */
47
48 #include "config.h"
49
50 #include "telepathy-glib/stream-tube-channel.h"
51
52 #include <telepathy-glib/contact.h>
53 #include <telepathy-glib/dbus.h>
54 #include <telepathy-glib/enums.h>
55 #include <telepathy-glib/gnio-util.h>
56 #include <telepathy-glib/gtypes.h>
57 #include <telepathy-glib/interfaces.h>
58 #include <telepathy-glib/proxy-subclass.h>
59 #include <telepathy-glib/stream-tube-connection-internal.h>
60 #include <telepathy-glib/util-internal.h>
61 #include <telepathy-glib/util.h>
62 #include <telepathy-glib/variant-util-internal.h>
63
64 #define DEBUG_FLAG TP_DEBUG_CHANNEL
65 #include "telepathy-glib/channel-internal.h"
66 #include "telepathy-glib/debug-internal.h"
67 #include "telepathy-glib/automatic-client-factory-internal.h"
68
69 #include <stdio.h>
70 #include <glib/gstdio.h>
71
72 #ifdef HAVE_GIO_UNIX
73 #include <gio/gunixsocketaddress.h>
74 #include <gio/gunixconnection.h>
75 #endif /* HAVE_GIO_UNIX */
76
77 G_DEFINE_TYPE (TpStreamTubeChannel, tp_stream_tube_channel, TP_TYPE_CHANNEL)
78
79 /* Used to store the data of a NewRemoteConnection signal while we are waiting
80 * for the TCP connection identified by this signal */
81 typedef struct
82 {
83 TpHandle handle;
84 GValue *param;
85 guint connection_id;
86 gboolean rejected;
87 } SigWaitingConn;
88
89 static SigWaitingConn *
sig_waiting_conn_new(TpHandle handle,const GValue * param,guint connection_id,gboolean rejected)90 sig_waiting_conn_new (TpHandle handle,
91 const GValue *param,
92 guint connection_id,
93 gboolean rejected)
94 {
95 SigWaitingConn *ret = g_slice_new0 (SigWaitingConn);
96
97 ret->handle = handle;
98 ret->param = tp_g_value_slice_dup (param);
99 ret->connection_id = connection_id;
100 ret->rejected = rejected;
101 return ret;
102 }
103
104 static void
sig_waiting_conn_free(SigWaitingConn * sig)105 sig_waiting_conn_free (SigWaitingConn *sig)
106 {
107 g_assert (sig != NULL);
108
109 tp_g_value_slice_free (sig->param);
110 g_slice_free (SigWaitingConn, sig);
111 }
112
113 typedef struct
114 {
115 GSocketConnection *conn;
116 /* Used only with TP_SOCKET_ACCESS_CONTROL_CREDENTIALS to store the byte
117 * read with the credentials. */
118 guchar byte;
119 } ConnWaitingSig;
120
121 static ConnWaitingSig *
conn_waiting_sig_new(GSocketConnection * conn,guchar byte)122 conn_waiting_sig_new (GSocketConnection *conn,
123 guchar byte)
124 {
125 ConnWaitingSig *ret = g_slice_new0 (ConnWaitingSig);
126
127 ret->conn = g_object_ref (conn);
128 ret->byte = byte;
129 return ret;
130 }
131
132 static void
conn_waiting_sig_free(ConnWaitingSig * c)133 conn_waiting_sig_free (ConnWaitingSig *c)
134 {
135 g_assert (c != NULL);
136
137 g_object_unref (c->conn);
138 g_slice_free (ConnWaitingSig, c);
139 }
140
141 struct _TpStreamTubeChannelPrivate
142 {
143 GHashTable *parameters;
144
145 /* Offering side */
146 GSocketService *service;
147 GSocketAddress *address;
148 gchar *unix_tmpdir;
149 /* GSocketConnection we have accepted but are still waiting a
150 * NewRemoteConnection to identify them. Owned ConnWaitingSig. */
151 GSList *conn_waiting_sig;
152 /* NewRemoteConnection signals we have received but didn't accept their TCP
153 * connection yet. Owned SigWaitingConn. */
154 GSList *sig_waiting_conn;
155
156 /* Accepting side */
157 GSocket *client_socket;
158 /* The access_control_param we passed to Accept */
159 GValue *access_control_param;
160 /* Connection to the CM while we are waiting for its
161 * ID (NewLocalConnection) */
162 GSocketConnection *local_conn_waiting_id;
163 /* ID received from NewLocalConnection stored while the connection has not
164 * be connected yet. */
165 guint local_conn_id;
166 /* TRUE if local_conn_id is meaningfull (0 can be a valid ID so we can't use
167 * it to check if NewLocalConnection has been received :\ ) */
168 gboolean local_conn_id_set;
169
170 TpSocketAddressType socket_type;
171 TpSocketAccessControl access_control;
172
173 GSimpleAsyncResult *result;
174
175 /* (guint) connection ID => weakly reffed TpStreamTubeConnection */
176 GHashTable *tube_connections;
177 };
178
179 enum
180 {
181 PROP_SERVICE = 1,
182 PROP_PARAMETERS,
183 PROP_PARAMETERS_VARDICT
184 };
185
186 enum /* signals */
187 {
188 INCOMING,
189 LAST_SIGNAL
190 };
191
192 static guint _signals[LAST_SIGNAL] = { 0, };
193
194 static void
remote_connection_destroyed_cb(gpointer user_data,GObject * conn)195 remote_connection_destroyed_cb (gpointer user_data,
196 GObject *conn)
197 {
198 /* The GSocketConnection has been destroyed, removing it from the hash */
199 TpStreamTubeChannel *self = user_data;
200 GHashTableIter iter;
201 gpointer value;
202
203 g_hash_table_iter_init (&iter, self->priv->tube_connections);
204 while (g_hash_table_iter_next (&iter, NULL, &value))
205 {
206 if (value == conn)
207 {
208 g_hash_table_iter_remove (&iter);
209 break;
210 }
211 }
212 }
213
214 static void
tp_stream_tube_channel_dispose(GObject * obj)215 tp_stream_tube_channel_dispose (GObject *obj)
216 {
217 TpStreamTubeChannel *self = (TpStreamTubeChannel *) obj;
218
219 if (self->priv->service != NULL)
220 {
221 g_socket_service_stop (self->priv->service);
222
223 tp_clear_object (&self->priv->service);
224 }
225
226 tp_clear_object (&self->priv->result);
227 tp_clear_pointer (&self->priv->parameters, g_hash_table_unref);
228
229 g_slist_foreach (self->priv->conn_waiting_sig, (GFunc) conn_waiting_sig_free,
230 NULL);
231 tp_clear_pointer (&self->priv->conn_waiting_sig, g_slist_free);
232
233 g_slist_foreach (self->priv->sig_waiting_conn, (GFunc) sig_waiting_conn_free,
234 NULL);
235 tp_clear_pointer (&self->priv->sig_waiting_conn, g_slist_free);
236
237 if (self->priv->tube_connections != NULL)
238 {
239 GHashTableIter iter;
240 gpointer conn;
241
242 g_hash_table_iter_init (&iter, self->priv->tube_connections);
243 while (g_hash_table_iter_next (&iter, NULL, &conn))
244 {
245 g_object_weak_unref (conn, remote_connection_destroyed_cb, self);
246 }
247
248 g_hash_table_unref (self->priv->tube_connections);
249 self->priv->tube_connections = NULL;
250 }
251
252 if (self->priv->address != NULL)
253 {
254 #ifdef HAVE_GIO_UNIX
255 /* check if we need to remove the temporary file we created */
256 if (G_IS_UNIX_SOCKET_ADDRESS (self->priv->address))
257 {
258 const gchar *path;
259
260 path = g_unix_socket_address_get_path (
261 G_UNIX_SOCKET_ADDRESS (self->priv->address));
262 g_unlink (path);
263 }
264 #endif /* HAVE_GIO_UNIX */
265
266 g_object_unref (self->priv->address);
267 self->priv->address = NULL;
268 }
269
270 if (self->priv->unix_tmpdir != NULL)
271 {
272 g_rmdir (self->priv->unix_tmpdir);
273 g_free (self->priv->unix_tmpdir);
274 self->priv->unix_tmpdir = NULL;
275 }
276
277 tp_clear_pointer (&self->priv->access_control_param, tp_g_value_slice_free);
278 tp_clear_object (&self->priv->local_conn_waiting_id);
279 tp_clear_object (&self->priv->client_socket);
280
281 G_OBJECT_CLASS (tp_stream_tube_channel_parent_class)->dispose (obj);
282 }
283
284 static void
tp_stream_tube_channel_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)285 tp_stream_tube_channel_get_property (GObject *object,
286 guint property_id,
287 GValue *value,
288 GParamSpec *pspec)
289 {
290 TpStreamTubeChannel *self = (TpStreamTubeChannel *) object;
291
292 switch (property_id)
293 {
294 case PROP_SERVICE:
295 g_value_set_string (value, tp_stream_tube_channel_get_service (self));
296 break;
297
298 case PROP_PARAMETERS:
299 g_value_set_boxed (value, self->priv->parameters);
300 break;
301
302 case PROP_PARAMETERS_VARDICT:
303 g_value_take_variant (value,
304 tp_stream_tube_channel_dup_parameters_vardict (self));
305 break;
306
307 default:
308 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
309 break;
310 }
311 }
312
313 static void
connection_closed_cb(TpChannel * channel,guint connection_id,const gchar * err,const gchar * message,gpointer user_data,GObject * weak_object)314 connection_closed_cb (TpChannel *channel,
315 guint connection_id,
316 const gchar *err,
317 const gchar *message,
318 gpointer user_data,
319 GObject *weak_object)
320 {
321 TpStreamTubeChannel *self = (TpStreamTubeChannel *) weak_object;
322 TpStreamTubeConnection *tube_conn;
323 GError *error = NULL;
324
325 DEBUG ("Got ConnectionClosed signal on connection %u: %s (%s)",
326 connection_id, err, message);
327
328 tube_conn = g_hash_table_lookup (self->priv->tube_connections,
329 GUINT_TO_POINTER (connection_id));
330 if (tube_conn == NULL)
331 {
332 DEBUG ("No connection with ID %u; ignoring", connection_id);
333 return;
334 }
335
336 tp_proxy_dbus_error_to_gerror (self, err, message, &error);
337
338 _tp_stream_tube_connection_fire_closed (tube_conn, error);
339
340 g_error_free (error);
341 }
342
343 static void
tp_stream_tube_channel_constructed(GObject * obj)344 tp_stream_tube_channel_constructed (GObject *obj)
345 {
346 TpStreamTubeChannel *self = (TpStreamTubeChannel *) obj;
347 void (*chain_up) (GObject *) =
348 ((GObjectClass *) tp_stream_tube_channel_parent_class)->constructed;
349 TpChannel *chan = (TpChannel *) obj;
350 GHashTable *props;
351 GError *err = NULL;
352
353 if (chain_up != NULL)
354 chain_up (obj);
355
356 if (tp_channel_get_channel_type_id (chan) !=
357 TP_IFACE_QUARK_CHANNEL_TYPE_STREAM_TUBE)
358 {
359 GError error = { TP_DBUS_ERRORS, TP_DBUS_ERROR_INCONSISTENT,
360 "Channel is not a stream tube" };
361
362 DEBUG ("Channel is not a stream tube: %s", tp_channel_get_channel_type (
363 chan));
364
365 tp_proxy_invalidate (TP_PROXY (self), &error);
366 return;
367 }
368
369 props = _tp_channel_get_immutable_properties (TP_CHANNEL (self));
370
371 if (tp_asv_get_string (props, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE)
372 == NULL)
373 {
374 GError error = { TP_DBUS_ERRORS, TP_DBUS_ERROR_INCONSISTENT,
375 "Tube doesn't have StreamTube.Service property" };
376
377 DEBUG ("%s", error.message);
378
379 tp_proxy_invalidate (TP_PROXY (self), &error);
380 return;
381 }
382
383 /* Tube.Parameters is immutable for incoming tubes. For outgoing ones,
384 * it's defined when offering the tube. */
385 if (!tp_channel_get_requested (TP_CHANNEL (self)))
386 {
387 GHashTable *params;
388
389 params = tp_asv_get_boxed (props,
390 TP_PROP_CHANNEL_INTERFACE_TUBE_PARAMETERS,
391 TP_HASH_TYPE_STRING_VARIANT_MAP);
392
393 if (params == NULL)
394 {
395 DEBUG ("Incoming tube doesn't have Tube.Parameters property");
396
397 self->priv->parameters = tp_asv_new (NULL, NULL);
398 }
399 else
400 {
401 self->priv->parameters = g_boxed_copy (
402 TP_HASH_TYPE_STRING_VARIANT_MAP, params);
403 }
404 }
405
406 tp_cli_channel_type_stream_tube_connect_to_connection_closed (
407 TP_CHANNEL (self), connection_closed_cb, NULL, NULL,
408 G_OBJECT (self), &err);
409
410 if (err != NULL)
411 {
412 DEBUG ("Failed to connect to ConnectionClosed signal: %s",
413 err->message);
414
415 g_error_free (err);
416 }
417 }
418
419 static void
tp_stream_tube_channel_class_init(TpStreamTubeChannelClass * klass)420 tp_stream_tube_channel_class_init (TpStreamTubeChannelClass *klass)
421 {
422 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
423 GParamSpec *param_spec;
424
425 gobject_class->constructed = tp_stream_tube_channel_constructed;
426 gobject_class->get_property = tp_stream_tube_channel_get_property;
427 gobject_class->dispose = tp_stream_tube_channel_dispose;
428
429 /**
430 * TpStreamTubeChannel:service:
431 *
432 * A string representing the service name that will be used over the tube.
433 *
434 * Since: 0.13.2
435 */
436 param_spec = g_param_spec_string ("service", "Service",
437 "The service of the stream tube",
438 NULL,
439 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
440 g_object_class_install_property (gobject_class, PROP_SERVICE, param_spec);
441
442 /**
443 * TpStreamTubeChannel:parameters:
444 *
445 * A string to #GValue #GHashTable representing the parameters of the tube.
446 *
447 * Will be %NULL for outgoing tubes until the tube has been offered.
448 *
449 * In high-level language bindings, use
450 * #TpStreamTubeChannel:parameters-vardict or
451 * tp_stream_tube_channel_dup_parameters_vardict() to get the same
452 * information in a more convenient format.
453 *
454 * Since: 0.13.2
455 */
456 param_spec = g_param_spec_boxed ("parameters", "Parameters",
457 "The parameters of the stream tube",
458 TP_HASH_TYPE_STRING_VARIANT_MAP,
459 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
460 g_object_class_install_property (gobject_class, PROP_PARAMETERS, param_spec);
461
462 /**
463 * TpStreamTubeChannel:parameters-vardict:
464 *
465 * A %G_VARIANT_TYPE_VARDICT representing the parameters of the tube.
466 *
467 * Will be %NULL for outgoing tubes until the tube has been offered.
468 *
469 * Since: 0.19.10
470 */
471 param_spec = g_param_spec_variant ("parameters-vardict", "Parameters",
472 "The parameters of the stream tube",
473 G_VARIANT_TYPE_VARDICT, NULL,
474 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
475 g_object_class_install_property (gobject_class, PROP_PARAMETERS_VARDICT,
476 param_spec);
477
478 /**
479 * TpStreamTubeChannel::incoming:
480 * @self: the #TpStreamTubeChannel
481 * @tube_connection: the #TpStreamTubeConnection for the connection
482 *
483 * The ::incoming signal is emitted on offered Tubes when a new incoming
484 * connection is made from a remote user (one accepting the Tube).
485 *
486 * Consumers of this signal must take their own references to
487 * @tube_connection
488 */
489 _signals[INCOMING] = g_signal_new ("incoming",
490 G_OBJECT_CLASS_TYPE (klass),
491 G_SIGNAL_RUN_LAST,
492 0, NULL, NULL, NULL,
493 G_TYPE_NONE,
494 1, TP_TYPE_STREAM_TUBE_CONNECTION);
495
496 g_type_class_add_private (gobject_class, sizeof (TpStreamTubeChannelPrivate));
497 }
498
499 static void
tp_stream_tube_channel_init(TpStreamTubeChannel * self)500 tp_stream_tube_channel_init (TpStreamTubeChannel *self)
501 {
502 self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), TP_TYPE_STREAM_TUBE_CHANNEL,
503 TpStreamTubeChannelPrivate);
504
505 self->priv->tube_connections = g_hash_table_new (NULL, NULL);
506 }
507
508
509 /**
510 * tp_stream_tube_channel_new:
511 * @conn: a #TpConnection; may not be %NULL
512 * @object_path: the object path of the channel; may not be %NULL
513 * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
514 * the immutable properties of the channel,
515 * as signalled by the NewChannel D-Bus signal or returned by the
516 * CreateChannel and EnsureChannel D-Bus methods: a mapping from
517 * strings (D-Bus interface name + "." + property name) to #GValue instances
518 * @error: used to indicate the error if %NULL is returned
519 *
520 * Creates a new #TpStreamTubeChannel proxy object from the provided path and
521 * properties. Most developers will not need to use this function; use
522 * #TpAutomaticProxyFactory to automatically create #TpStreamTubeChannel proxy
523 * objects.
524 *
525 * Returns: (transfer full): a newly-created #TpStreamTubeChannel proxy
526 *
527 * Since: 0.13.2
528 * Deprecated: Use tp_simple_client_factory_ensure_channel() instead.
529 */
530 TpStreamTubeChannel *
tp_stream_tube_channel_new(TpConnection * conn,const gchar * object_path,const GHashTable * immutable_properties,GError ** error)531 tp_stream_tube_channel_new (TpConnection *conn,
532 const gchar *object_path,
533 const GHashTable *immutable_properties,
534 GError **error)
535 {
536 return _tp_stream_tube_channel_new_with_factory (NULL, conn, object_path,
537 immutable_properties, error);
538 }
539
540 TpStreamTubeChannel *
_tp_stream_tube_channel_new_with_factory(TpSimpleClientFactory * factory,TpConnection * conn,const gchar * object_path,const GHashTable * immutable_properties,GError ** error)541 _tp_stream_tube_channel_new_with_factory (
542 TpSimpleClientFactory *factory,
543 TpConnection *conn,
544 const gchar *object_path,
545 const GHashTable *immutable_properties,
546 GError **error)
547 {
548 TpProxy *conn_proxy = (TpProxy *) conn;
549
550 g_return_val_if_fail (TP_IS_CONNECTION (conn), NULL);
551 g_return_val_if_fail (object_path != NULL, NULL);
552 g_return_val_if_fail (immutable_properties != NULL, NULL);
553
554 if (!tp_dbus_check_valid_object_path (object_path, error))
555 return NULL;
556
557 return g_object_new (TP_TYPE_STREAM_TUBE_CHANNEL,
558 "connection", conn,
559 "dbus-daemon", conn_proxy->dbus_daemon,
560 "bus-name", conn_proxy->bus_name,
561 "object-path", object_path,
562 "handle-type", (guint) TP_UNKNOWN_HANDLE_TYPE,
563 "channel-properties", immutable_properties,
564 "factory", factory,
565 NULL);
566 }
567
568 static void
operation_failed(TpStreamTubeChannel * self,const GError * error)569 operation_failed (TpStreamTubeChannel *self,
570 const GError *error)
571 {
572 g_simple_async_result_set_from_error (self->priv->result, error);
573
574 g_simple_async_result_complete_in_idle (self->priv->result);
575 tp_clear_object (&self->priv->result);
576 }
577
578 static void
complete_accept_operation(TpStreamTubeChannel * self,TpStreamTubeConnection * tube_conn)579 complete_accept_operation (TpStreamTubeChannel *self,
580 TpStreamTubeConnection *tube_conn)
581 {
582 g_simple_async_result_set_op_res_gpointer (self->priv->result,
583 g_object_ref (tube_conn), g_object_unref);
584 g_simple_async_result_complete (self->priv->result);
585 tp_clear_object (&self->priv->result);
586 }
587
588 static void
new_local_connection_with_contact(TpConnection * conn,guint n_contacts,TpContact * const * contacts,guint n_failed,const TpHandle * failed,const GError * in_error,gpointer user_data,GObject * obj)589 new_local_connection_with_contact (TpConnection *conn,
590 guint n_contacts,
591 TpContact * const *contacts,
592 guint n_failed,
593 const TpHandle *failed,
594 const GError *in_error,
595 gpointer user_data,
596 GObject *obj)
597 {
598 TpStreamTubeChannel *self = (TpStreamTubeChannel *) obj;
599 TpContact *contact;
600 TpStreamTubeConnection *tube_conn = user_data;
601
602 if (in_error != NULL)
603 {
604 DEBUG ("Failed to prepare TpContact: %s", in_error->message);
605 return;
606 }
607
608 if (n_failed > 0)
609 {
610 DEBUG ("Failed to prepare TpContact (InvalidHandle)");
611 return;
612 }
613
614 contact = contacts[0];
615 _tp_stream_tube_connection_set_contact (tube_conn, contact);
616
617 complete_accept_operation (self, tube_conn);
618 }
619
620 static void
new_local_connection_identified(TpStreamTubeChannel * self,GSocketConnection * conn,guint connection_id)621 new_local_connection_identified (TpStreamTubeChannel *self,
622 GSocketConnection *conn,
623 guint connection_id)
624 {
625 TpHandle initiator_handle;
626 TpStreamTubeConnection *tube_conn;
627 TpConnection *connection;
628 GArray *features;
629
630 tube_conn = _tp_stream_tube_connection_new (conn, self);
631
632 g_hash_table_insert (self->priv->tube_connections,
633 GUINT_TO_POINTER (connection_id), tube_conn);
634
635 g_object_weak_ref (G_OBJECT (tube_conn), remote_connection_destroyed_cb,
636 self);
637
638 /* We are accepting a tube so the contact of the connection is the
639 * initiator of the tube */
640 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
641 initiator_handle = tp_channel_get_initiator_handle (TP_CHANNEL (self));
642
643 connection = tp_channel_get_connection (TP_CHANNEL (self));
644 features = tp_simple_client_factory_dup_contact_features (
645 tp_proxy_get_factory (connection), connection);
646
647 /* Pass ownership of tube_conn to the function */
648 tp_connection_get_contacts_by_handle (connection,
649 1, &initiator_handle,
650 features->len, (TpContactFeature *) features->data,
651 new_local_connection_with_contact,
652 tube_conn, g_object_unref, G_OBJECT (self));
653 G_GNUC_END_IGNORE_DEPRECATIONS
654
655 g_array_unref (features);
656 }
657
658 #ifdef HAVE_GIO_UNIX
659 static void
send_credentials_cb(GObject * source,GAsyncResult * result,gpointer user_data)660 send_credentials_cb (GObject *source,
661 GAsyncResult *result,
662 gpointer user_data)
663 {
664 TpStreamTubeChannel *self = user_data;
665 GError *error = NULL;
666
667 if (!tp_unix_connection_send_credentials_with_byte_finish (
668 (GSocketConnection *) source, result, &error))
669 {
670 DEBUG ("Failed to send credentials: %s", error->message);
671
672 operation_failed (self, error);
673 g_clear_error (&error);
674 }
675 }
676 #endif
677
678 static void
client_socket_connected(TpStreamTubeChannel * self)679 client_socket_connected (TpStreamTubeChannel *self)
680 {
681 GSocketConnection *conn;
682
683 conn = g_socket_connection_factory_create_connection (
684 self->priv->client_socket);
685 g_assert (conn);
686
687 DEBUG ("Stream Tube socket connected");
688
689 #ifdef HAVE_GIO_UNIX
690 if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS)
691 {
692 guchar byte;
693
694 byte = g_value_get_uchar (self->priv->access_control_param);
695 tp_unix_connection_send_credentials_with_byte_async (conn, byte, NULL,
696 send_credentials_cb, self);
697 }
698 #endif
699
700 if (self->priv->local_conn_id_set)
701 {
702 new_local_connection_identified (self, conn, self->priv->local_conn_id);
703
704 self->priv->local_conn_id_set = FALSE;
705 }
706 else
707 {
708 /* Wait for NewLocalConnection signal */
709
710 /* This assume that we never connect more than once. Or at least that we
711 * wait to have identify a connection before making a new connection. */
712 g_assert (self->priv->local_conn_waiting_id == NULL);
713 self->priv->local_conn_waiting_id = g_object_ref (conn);
714 }
715
716 g_object_unref (conn);
717 }
718
719 static gboolean
client_socket_cb(GSocket * socket,GIOCondition condition,TpStreamTubeChannel * self)720 client_socket_cb (GSocket *socket,
721 GIOCondition condition,
722 TpStreamTubeChannel *self)
723 {
724 GError *error = NULL;
725
726 if (!g_socket_check_connect_result (socket, &error))
727 {
728 DEBUG ("Failed to connect to socket: %s", error->message);
729
730 operation_failed (self, error);
731 g_error_free (error);
732 return FALSE;
733 }
734
735 client_socket_connected (self);
736
737 return FALSE;
738 }
739
740 static void
new_local_connection_cb(TpChannel * proxy,guint connection_id,gpointer user_data,GObject * weak_object)741 new_local_connection_cb (TpChannel *proxy,
742 guint connection_id,
743 gpointer user_data,
744 GObject *weak_object)
745 {
746 TpStreamTubeChannel *self = (TpStreamTubeChannel *) weak_object;
747
748 if (self->priv->local_conn_waiting_id != NULL)
749 {
750 /* We got the ID of the connection */
751
752 new_local_connection_identified (self, self->priv->local_conn_waiting_id,
753 connection_id);
754
755 tp_clear_object (&self->priv->local_conn_waiting_id);
756 return;
757 }
758
759 /* Wait that the connection is connected */
760 self->priv->local_conn_id = connection_id;
761 self->priv->local_conn_id_set = TRUE;
762 }
763
764 static void
_channel_accepted(TpChannel * channel,const GValue * addressv,const GError * in_error,gpointer user_data,GObject * obj)765 _channel_accepted (TpChannel *channel,
766 const GValue *addressv,
767 const GError *in_error,
768 gpointer user_data,
769 GObject *obj)
770 {
771 TpStreamTubeChannel *self = (TpStreamTubeChannel *) obj;
772 GSocketAddress *remote_address;
773 GError *error = NULL;
774
775 if (in_error != NULL)
776 {
777 DEBUG ("Failed to Accept Stream Tube: %s", in_error->message);
778
779 operation_failed (self, in_error);
780 return;
781 }
782
783 tp_cli_channel_type_stream_tube_connect_to_new_local_connection (
784 TP_CHANNEL (self), new_local_connection_cb, NULL, NULL,
785 G_OBJECT (self), &error);
786
787 if (error != NULL)
788 {
789 DEBUG ("Failed to connect to NewLocalConnection signal");
790 operation_failed (self, error);
791
792 g_error_free (error);
793 return;
794 }
795
796 remote_address = tp_g_socket_address_from_variant (self->priv->socket_type,
797 addressv, &error);
798 if (error != NULL)
799 {
800 DEBUG ("Failed to convert address: %s", error->message);
801
802 operation_failed (self, error);
803 g_error_free (error);
804 return;
805 }
806
807 /* Connect to CM */
808 g_socket_set_blocking (self->priv->client_socket, FALSE);
809 g_socket_connect (self->priv->client_socket, remote_address, NULL, &error);
810
811 if (error == NULL)
812 {
813 /* Socket is connected */
814 client_socket_connected (self);
815 goto out;
816 }
817 else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
818 {
819 /* We have to wait that the socket is connected */
820 GSource *source;
821
822 source = g_socket_create_source (self->priv->client_socket,
823 G_IO_OUT, NULL);
824
825 g_source_attach (source, g_main_context_get_thread_default ());
826
827 g_source_set_callback (source, (GSourceFunc) client_socket_cb,
828 self, NULL);
829
830 g_error_free (error);
831 g_source_unref (source);
832 }
833 else
834 {
835 DEBUG ("Failed to connect to CM: %s", error->message);
836
837 operation_failed (self, error);
838
839 g_error_free (error);
840 }
841
842 out:
843 g_object_unref (remote_address);
844 }
845
846
847 /**
848 * tp_stream_tube_channel_accept_async:
849 * @self: an incoming #TpStreamTubeChannel
850 * @callback: a callback to call when the tube has been accepted
851 * @user_data: data to pass to @callback
852 *
853 * Accept an incoming stream tube. When the tube has been accepted, @callback
854 * will be called. You can then call tp_stream_tube_channel_accept_finish()
855 * to get a #TpStreamTubeConnection connected to the tube.
856 *
857 * Since: 0.13.2
858 */
859 void
tp_stream_tube_channel_accept_async(TpStreamTubeChannel * self,GAsyncReadyCallback callback,gpointer user_data)860 tp_stream_tube_channel_accept_async (TpStreamTubeChannel *self,
861 GAsyncReadyCallback callback,
862 gpointer user_data)
863 {
864 GHashTable *properties;
865 GHashTable *supported_sockets;
866 GError *error = NULL;
867
868 g_return_if_fail (TP_IS_STREAM_TUBE_CHANNEL (self));
869 g_return_if_fail (self->priv->result == NULL);
870
871 if (self->priv->access_control_param != NULL)
872 {
873 g_simple_async_report_error_in_idle (G_OBJECT (self), callback, user_data,
874 TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube has already be accepted");
875
876 return;
877 }
878
879 self->priv->result = g_simple_async_result_new (G_OBJECT (self), callback,
880 user_data, tp_stream_tube_channel_accept_async);
881
882 properties = _tp_channel_get_immutable_properties (TP_CHANNEL (self));
883 supported_sockets = tp_asv_get_boxed (properties,
884 TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SUPPORTED_SOCKET_TYPES,
885 TP_HASH_TYPE_SUPPORTED_SOCKET_MAP);
886
887 if (!_tp_set_socket_address_type_and_access_control_type (supported_sockets,
888 &self->priv->socket_type, &self->priv->access_control, &error))
889 {
890 operation_failed (self, error);
891
892 g_clear_error (&error);
893 return;
894 }
895
896 DEBUG ("Using socket type %u with access control %u", self->priv->socket_type,
897 self->priv->access_control);
898
899 self->priv->client_socket = _tp_create_client_socket (self->priv->socket_type,
900 &error);
901
902 if (error != NULL)
903 {
904 DEBUG ("Failed to create socket: %s", error->message);
905
906 operation_failed (self, error);
907 g_clear_error (&error);
908 return;
909 }
910
911 switch (self->priv->access_control)
912 {
913 case TP_SOCKET_ACCESS_CONTROL_LOCALHOST:
914 /* Put a dummy value */
915 self->priv->access_control_param = tp_g_value_slice_new_uint (0);
916 break;
917
918 case TP_SOCKET_ACCESS_CONTROL_PORT:
919 {
920 GSocketAddress *addr;
921 guint16 port;
922
923 addr = g_socket_get_local_address (self->priv->client_socket, &error);
924 if (addr == NULL)
925 {
926 DEBUG ("Failed to get local address of client socket: %s",
927 error->message);
928
929 operation_failed (self, error);
930 g_error_free (error);
931 return;
932 }
933
934 port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
935 self->priv->access_control_param = tp_g_value_slice_new_uint (port);
936
937 g_object_unref (addr);
938 }
939 break;
940
941 case TP_SOCKET_ACCESS_CONTROL_CREDENTIALS:
942 self->priv->access_control_param = tp_g_value_slice_new_byte (
943 g_random_int_range (0, G_MAXUINT8));
944 break;
945
946 default:
947 g_assert_not_reached ();
948 }
949
950 /* Call Accept */
951 tp_cli_channel_type_stream_tube_call_accept (TP_CHANNEL (self), -1,
952 self->priv->socket_type, self->priv->access_control,
953 self->priv->access_control_param, _channel_accepted,
954 NULL, NULL, G_OBJECT (self));
955 }
956
957
958 /**
959 * tp_stream_tube_channel_accept_finish:
960 * @self: a #TpStreamTubeChannel
961 * @result: a #GAsyncResult
962 * @error: a #GError to fill
963 *
964 * Finishes accepting an incoming stream tube. The returned
965 * #TpStreamTubeConnection can then be used to exchange data through the tube.
966 *
967 * Returns: (transfer full): a newly created #TpStreamTubeConnection
968 *
969 * Since: 0.13.2
970 */
971 TpStreamTubeConnection *
tp_stream_tube_channel_accept_finish(TpStreamTubeChannel * self,GAsyncResult * result,GError ** error)972 tp_stream_tube_channel_accept_finish (TpStreamTubeChannel *self,
973 GAsyncResult *result,
974 GError **error)
975 {
976 _tp_implement_finish_return_copy_pointer (self,
977 tp_stream_tube_channel_accept_async, g_object_ref)
978 }
979
980 static void
_new_remote_connection_with_contact(TpConnection * conn,guint n_contacts,TpContact * const * contacts,guint n_failed,const TpHandle * failed,const GError * in_error,gpointer user_data,GObject * obj)981 _new_remote_connection_with_contact (TpConnection *conn,
982 guint n_contacts,
983 TpContact * const *contacts,
984 guint n_failed,
985 const TpHandle *failed,
986 const GError *in_error,
987 gpointer user_data,
988 GObject *obj)
989 {
990 TpStreamTubeChannel *self = (TpStreamTubeChannel *) obj;
991 TpContact *contact;
992 TpStreamTubeConnection *tube_conn = user_data;
993
994 if (in_error != NULL)
995 {
996 DEBUG ("Failed to prepare TpContact: %s", in_error->message);
997 return;
998 }
999
1000 if (n_failed > 0)
1001 {
1002 DEBUG ("Failed to prepare TpContact (InvalidHandle)");
1003 return;
1004 }
1005
1006 contact = contacts[0];
1007
1008 _tp_stream_tube_connection_set_contact (tube_conn, contact);
1009
1010 DEBUG ("Accepting incoming GIOStream from %s",
1011 tp_contact_get_identifier (contact));
1012
1013 g_signal_emit (self, _signals[INCOMING], 0, tube_conn);
1014
1015 /* anyone receiving the signal is required to hold their own reference */
1016 }
1017
1018 static gboolean
sig_match_conn(TpStreamTubeChannel * self,SigWaitingConn * sig,ConnWaitingSig * c)1019 sig_match_conn (TpStreamTubeChannel *self,
1020 SigWaitingConn *sig,
1021 ConnWaitingSig *c)
1022 {
1023 if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_PORT)
1024 {
1025 /* Use the port to identify the connection */
1026 guint port;
1027 GSocketAddress *address;
1028 GError *error = NULL;
1029
1030 address = g_socket_connection_get_remote_address (c->conn, &error);
1031 if (address == NULL)
1032 {
1033 DEBUG ("Failed to get connection address: %s", error->message);
1034
1035 g_error_free (error);
1036 return FALSE;
1037 }
1038
1039 dbus_g_type_struct_get (sig->param, 1, &port, G_MAXINT);
1040
1041 if (port == g_inet_socket_address_get_port (
1042 G_INET_SOCKET_ADDRESS (address)))
1043 {
1044 DEBUG ("Identified connection %u using port %u",
1045 port, sig->connection_id);
1046
1047 g_object_unref (address);
1048 return TRUE;
1049 }
1050
1051 g_object_unref (address);
1052 }
1053 else if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS)
1054 {
1055 guchar byte;
1056
1057 byte = g_value_get_uchar (sig->param);
1058
1059 return byte == c->byte;
1060 }
1061 else
1062 {
1063 DEBUG ("Can't properly identify connection as we are using "
1064 "access control %u. Assume it's the head of the list",
1065 self->priv->access_control);
1066
1067 return TRUE;
1068 }
1069
1070 return FALSE;
1071 }
1072
1073 static gboolean
can_identify_contact(TpStreamTubeChannel * self)1074 can_identify_contact (TpStreamTubeChannel *self)
1075 {
1076 TpHandleType handle_type;
1077
1078 tp_channel_get_handle (TP_CHANNEL (self), &handle_type);
1079
1080 /* With contact stream tube, it's always the same contact connecting to the
1081 * tube */
1082 if (handle_type == TP_HANDLE_TYPE_CONTACT)
1083 return TRUE;
1084
1085 /* Room stream tube, we need either the Credentials or Port access control
1086 * to properly identify connections. */
1087 if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS ||
1088 self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_PORT)
1089 return TRUE;
1090
1091 return FALSE;
1092 }
1093
1094 static void
connection_identified(TpStreamTubeChannel * self,GSocketConnection * conn,TpHandle handle,guint connection_id)1095 connection_identified (TpStreamTubeChannel *self,
1096 GSocketConnection *conn,
1097 TpHandle handle,
1098 guint connection_id)
1099 {
1100 TpStreamTubeConnection *tube_conn;
1101
1102 tube_conn = _tp_stream_tube_connection_new (conn, self);
1103
1104 g_hash_table_insert (self->priv->tube_connections,
1105 GUINT_TO_POINTER (connection_id), tube_conn);
1106
1107 g_object_weak_ref (G_OBJECT (tube_conn), remote_connection_destroyed_cb,
1108 self);
1109
1110 if (can_identify_contact (self))
1111 {
1112 TpConnection *connection;
1113 GArray *features;
1114
1115 connection = tp_channel_get_connection (TP_CHANNEL (self));
1116 features = tp_simple_client_factory_dup_contact_features (
1117 tp_proxy_get_factory (connection), connection);
1118
1119 /* Spec does not give the id with the handle */
1120 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1121 /* Pass the ref on tube_conn to the function */
1122 tp_connection_get_contacts_by_handle (connection,
1123 1, &handle,
1124 features->len, (TpContactFeature *) features->data,
1125 _new_remote_connection_with_contact,
1126 tube_conn, g_object_unref, G_OBJECT (self));
1127 G_GNUC_END_IGNORE_DEPRECATIONS
1128
1129 g_array_unref (features);
1130 }
1131 else
1132 {
1133 g_signal_emit (self, _signals[INCOMING], 0, tube_conn);
1134
1135 g_object_unref (tube_conn);
1136 }
1137 }
1138
1139 static void
stream_tube_connection_closed_cb(GObject * source,GAsyncResult * result,gpointer user_data)1140 stream_tube_connection_closed_cb (GObject *source,
1141 GAsyncResult *result,
1142 gpointer user_data)
1143 {
1144 GError *error = NULL;
1145
1146 if (!g_io_stream_close_finish (G_IO_STREAM (source), result, &error))
1147 {
1148 DEBUG ("Failed to close connection: %s", error->message);
1149
1150 g_error_free (error);
1151 return;
1152 }
1153 }
1154
1155 static void
connection_rejected(TpStreamTubeChannel * self,GSocketConnection * conn,TpHandle handle,guint connection_id)1156 connection_rejected (TpStreamTubeChannel *self,
1157 GSocketConnection *conn,
1158 TpHandle handle,
1159 guint connection_id)
1160 {
1161 DEBUG ("Reject connection %u with contact %u", connection_id, handle);
1162
1163 g_io_stream_close_async (G_IO_STREAM (conn), G_PRIORITY_DEFAULT, NULL,
1164 stream_tube_connection_closed_cb, self);
1165 }
1166
1167 static void
_new_remote_connection(TpChannel * channel,guint handle,const GValue * param,guint connection_id,gpointer user_data,GObject * obj)1168 _new_remote_connection (TpChannel *channel,
1169 guint handle,
1170 const GValue *param,
1171 guint connection_id,
1172 gpointer user_data,
1173 GObject *obj)
1174 {
1175 TpStreamTubeChannel *self = (TpStreamTubeChannel *) obj;
1176 GSList *l;
1177 ConnWaitingSig *found_conn = NULL;
1178 SigWaitingConn *sig;
1179 TpHandle chan_handle;
1180 TpHandleType handle_type;
1181 gboolean rejected = FALSE;
1182
1183 chan_handle = tp_channel_get_handle (channel, &handle_type);
1184 if (handle_type == TP_HANDLE_TYPE_CONTACT &&
1185 handle != chan_handle)
1186 {
1187 DEBUG ("CM claimed that handle %u connected to the stream tube, "
1188 "but as a contact stream tube we should only get connection from "
1189 "handle %u", handle, chan_handle);
1190
1191 rejected = TRUE;
1192 }
1193
1194 sig = sig_waiting_conn_new (handle, param, connection_id, rejected);
1195
1196 for (l = self->priv->conn_waiting_sig; l != NULL && found_conn == NULL;
1197 l = g_slist_next (l))
1198 {
1199 ConnWaitingSig *conn = l->data;
1200
1201 if (sig_match_conn (self, sig, conn))
1202 found_conn = conn;
1203
1204 }
1205
1206 if (found_conn == NULL)
1207 {
1208 DEBUG ("Didn't find any connection for %u. Waiting for more",
1209 connection_id);
1210
1211 /* Pass ownership of sig to the list */
1212 self->priv->sig_waiting_conn = g_slist_append (
1213 self->priv->sig_waiting_conn, sig);
1214 return;
1215 }
1216
1217 /* We found a connection */
1218 self->priv->conn_waiting_sig = g_slist_remove (
1219 self->priv->conn_waiting_sig, found_conn);
1220
1221 if (rejected)
1222 connection_rejected (self, found_conn->conn, handle, connection_id);
1223 else
1224 connection_identified (self, found_conn->conn, handle, connection_id);
1225
1226 sig_waiting_conn_free (sig);
1227 conn_waiting_sig_free (found_conn);
1228 }
1229
1230 static void
_channel_offered(TpChannel * channel,const GError * in_error,gpointer user_data,GObject * obj)1231 _channel_offered (TpChannel *channel,
1232 const GError *in_error,
1233 gpointer user_data,
1234 GObject *obj)
1235 {
1236 TpStreamTubeChannel *self = (TpStreamTubeChannel *) obj;
1237
1238 if (in_error != NULL)
1239 {
1240 DEBUG ("Failed to Offer Stream Tube: %s", in_error->message);
1241
1242 operation_failed (self, in_error);
1243 return;
1244 }
1245
1246 DEBUG ("Stream Tube offered");
1247
1248 g_simple_async_result_complete_in_idle (self->priv->result);
1249 tp_clear_object (&self->priv->result);
1250 }
1251
1252
1253 static void
_offer_with_address(TpStreamTubeChannel * self,GHashTable * params)1254 _offer_with_address (TpStreamTubeChannel *self,
1255 GHashTable *params)
1256 {
1257 GValue *addressv = NULL;
1258 GError *error = NULL;
1259
1260 addressv = tp_address_variant_from_g_socket_address (self->priv->address,
1261 &self->priv->socket_type, &error);
1262 if (error != NULL)
1263 {
1264 operation_failed (self, error);
1265
1266 g_clear_error (&error);
1267 goto finally;
1268 }
1269
1270 /* Connect the NewRemoteConnection signal */
1271 tp_cli_channel_type_stream_tube_connect_to_new_remote_connection (
1272 TP_CHANNEL (self), _new_remote_connection,
1273 NULL, NULL, G_OBJECT (self), &error);
1274 if (error != NULL)
1275 {
1276 operation_failed (self, error);
1277
1278 g_clear_error (&error);
1279 goto finally;
1280 }
1281
1282 g_assert (self->priv->parameters == NULL);
1283 if (params != NULL)
1284 self->priv->parameters = g_hash_table_ref (params);
1285 else
1286 self->priv->parameters = tp_asv_new (NULL, NULL);
1287
1288 g_object_notify (G_OBJECT (self), "parameters");
1289 g_object_notify (G_OBJECT (self), "parameters-vardict");
1290
1291 /* Call Offer */
1292 tp_cli_channel_type_stream_tube_call_offer (TP_CHANNEL (self), -1,
1293 self->priv->socket_type, addressv, self->priv->access_control,
1294 self->priv->parameters, _channel_offered, NULL, NULL, G_OBJECT (self));
1295
1296 finally:
1297 if (addressv != NULL)
1298 tp_g_value_slice_free (addressv);
1299 }
1300
1301 static SigWaitingConn *
find_sig_for_conn(TpStreamTubeChannel * self,ConnWaitingSig * c)1302 find_sig_for_conn (TpStreamTubeChannel *self,
1303 ConnWaitingSig *c)
1304 {
1305 GSList *l;
1306
1307 for (l = self->priv->sig_waiting_conn; l != NULL; l = g_slist_next (l))
1308 {
1309 SigWaitingConn *sig = l->data;
1310
1311 if (sig_match_conn (self, sig, c))
1312 return sig;
1313 }
1314
1315 return NULL;
1316 }
1317
1318 static void
credentials_received(TpStreamTubeChannel * self,GSocketConnection * conn,guchar byte)1319 credentials_received (TpStreamTubeChannel *self,
1320 GSocketConnection *conn,
1321 guchar byte)
1322 {
1323 SigWaitingConn *sig;
1324 ConnWaitingSig *c;
1325
1326 c = conn_waiting_sig_new (conn, byte);
1327
1328 sig = find_sig_for_conn (self, c);
1329 if (sig == NULL)
1330 {
1331 DEBUG ("Can't identify the connection, wait for NewRemoteConnection sig");
1332
1333 /* Pass ownership to the list */
1334 self->priv->conn_waiting_sig = g_slist_append (
1335 self->priv->conn_waiting_sig, c);
1336
1337 return;
1338 }
1339
1340 /* Connection has been identified */
1341 self->priv->sig_waiting_conn = g_slist_remove (self->priv->sig_waiting_conn,
1342 sig);
1343
1344 if (sig->rejected)
1345 connection_rejected (self, conn, sig->handle, sig->connection_id);
1346 else
1347 connection_identified (self, conn, sig->handle, sig->connection_id);
1348
1349 sig_waiting_conn_free (sig);
1350 conn_waiting_sig_free (c);
1351 }
1352
1353 #ifdef HAVE_GIO_UNIX
1354 static void
receive_credentials_cb(GObject * source,GAsyncResult * result,gpointer user_data)1355 receive_credentials_cb (GObject *source,
1356 GAsyncResult *result,
1357 gpointer user_data)
1358 {
1359 TpStreamTubeChannel *self = user_data;
1360 GSocketConnection *conn = (GSocketConnection *) source;
1361 GCredentials *creds;
1362 guchar byte;
1363 uid_t uid;
1364 GError *error = NULL;
1365
1366 creds = tp_unix_connection_receive_credentials_with_byte_finish (conn, result,
1367 &byte, &error);
1368
1369 if (creds == NULL)
1370 {
1371 DEBUG ("Failed to receive credentials: %s", error->message);
1372 g_error_free (error);
1373 return;
1374 }
1375
1376 uid = g_credentials_get_unix_user (creds, &error);
1377 if (uid != geteuid ())
1378 {
1379 DEBUG ("Wrong credentials received (user: %u)", uid);
1380 return;
1381 }
1382
1383 credentials_received (self, conn, byte);
1384
1385 g_object_unref (creds);
1386 }
1387 #endif
1388
1389 static void
service_incoming_cb(GSocketService * service,GSocketConnection * conn,GObject * source_object,gpointer user_data)1390 service_incoming_cb (GSocketService *service,
1391 GSocketConnection *conn,
1392 GObject *source_object,
1393 gpointer user_data)
1394 {
1395 TpStreamTubeChannel *self = user_data;
1396
1397 DEBUG ("New incoming connection");
1398
1399 #ifdef HAVE_GIO_UNIX
1400 /* Check the credentials if needed */
1401 if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS)
1402 {
1403 tp_unix_connection_receive_credentials_with_byte_async (conn, NULL,
1404 receive_credentials_cb, self);
1405 return;
1406 }
1407 #endif
1408
1409 credentials_received (self, conn, 0);
1410 }
1411
1412 /**
1413 * tp_stream_tube_channel_offer_async:
1414 * @self: an outgoing #TpStreamTubeChannel
1415 * @params: (allow-none) (transfer none): parameters of the tube, or %NULL
1416 * @callback: a callback to call when the tube has been offered
1417 * @user_data: data to pass to @callback
1418 *
1419 * Offer an outgoing stream tube. When the tube has been offered, @callback
1420 * will be called. You can then call tp_stream_tube_channel_offer_finish()
1421 * to get the result of the operation.
1422 *
1423 * You have to connect to the #TpStreamTubeChannel::incoming signal to get a
1424 * #TpStreamTubeConnection each time a contact establishes a connection to
1425 * the tube.
1426 *
1427 * Since: 0.13.2
1428 */
1429 void
tp_stream_tube_channel_offer_async(TpStreamTubeChannel * self,GHashTable * params,GAsyncReadyCallback callback,gpointer user_data)1430 tp_stream_tube_channel_offer_async (TpStreamTubeChannel *self,
1431 GHashTable *params,
1432 GAsyncReadyCallback callback,
1433 gpointer user_data)
1434 {
1435 GHashTable *properties;
1436 GHashTable *supported_sockets;
1437 GError *error = NULL;
1438
1439 g_return_if_fail (TP_IS_STREAM_TUBE_CHANNEL (self));
1440 g_return_if_fail (self->priv->result == NULL);
1441 g_return_if_fail (tp_channel_get_requested (TP_CHANNEL (self)));
1442
1443 if (self->priv->service != NULL)
1444 {
1445 g_critical ("Can't reoffer Tube!");
1446 return;
1447 }
1448
1449 self->priv->result = g_simple_async_result_new (G_OBJECT (self), callback,
1450 user_data, tp_stream_tube_channel_offer_async);
1451
1452 properties = _tp_channel_get_immutable_properties (TP_CHANNEL (self));
1453 supported_sockets = tp_asv_get_boxed (properties,
1454 TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SUPPORTED_SOCKET_TYPES,
1455 TP_HASH_TYPE_SUPPORTED_SOCKET_MAP);
1456
1457 if (!_tp_set_socket_address_type_and_access_control_type (supported_sockets,
1458 &self->priv->socket_type, &self->priv->access_control, &error))
1459 {
1460 operation_failed (self, error);
1461
1462 g_clear_error (&error);
1463 return;
1464 }
1465
1466 DEBUG ("Using socket type %u with access control %u", self->priv->socket_type,
1467 self->priv->access_control);
1468
1469 self->priv->service = g_socket_service_new ();
1470
1471 switch (self->priv->socket_type)
1472 {
1473 #ifdef HAVE_GIO_UNIX
1474 case TP_SOCKET_ADDRESS_TYPE_UNIX:
1475 {
1476 self->priv->address = _tp_create_temp_unix_socket (
1477 self->priv->service, &self->priv->unix_tmpdir, &error);
1478
1479 /* check there wasn't an error on the final attempt */
1480 if (self->priv->address == NULL)
1481 {
1482 operation_failed (self, error);
1483
1484 g_clear_error (&error);
1485 return;
1486 }
1487 }
1488
1489 break;
1490 #endif /* HAVE_GIO_UNIX */
1491
1492 case TP_SOCKET_ADDRESS_TYPE_IPV4:
1493 case TP_SOCKET_ADDRESS_TYPE_IPV6:
1494 {
1495 GInetAddress *localhost;
1496 GSocketAddress *in_address;
1497
1498 localhost = g_inet_address_new_loopback (
1499 self->priv->socket_type == TP_SOCKET_ADDRESS_TYPE_IPV4 ?
1500 G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6);
1501 in_address = g_inet_socket_address_new (localhost, 0);
1502
1503 g_socket_listener_add_address (
1504 G_SOCKET_LISTENER (self->priv->service), in_address,
1505 G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT,
1506 NULL, &self->priv->address, &error);
1507
1508 g_object_unref (localhost);
1509 g_object_unref (in_address);
1510
1511 if (error != NULL)
1512 {
1513 operation_failed (self, error);
1514
1515 g_clear_error (&error);
1516 return;
1517 }
1518
1519 break;
1520 }
1521
1522 default:
1523 /* should have already errored */
1524 g_assert_not_reached ();
1525 break;
1526 }
1527
1528 tp_g_signal_connect_object (self->priv->service, "incoming",
1529 G_CALLBACK (service_incoming_cb), self, 0);
1530
1531 g_socket_service_start (self->priv->service);
1532
1533 _offer_with_address (self, params);
1534 }
1535
1536 /**
1537 * tp_stream_tube_channel_offer_finish:
1538 * @self: a #TpStreamTubeChannel
1539 * @result: a #GAsyncResult
1540 * @error: a #GError to fill
1541 *
1542 * Finishes offering an outgoing stream tube.
1543 *
1544 * Returns: %TRUE when a Tube has been successfully offered; %FALSE otherwise
1545 *
1546 * Since: 0.13.2
1547 */
1548 gboolean
tp_stream_tube_channel_offer_finish(TpStreamTubeChannel * self,GAsyncResult * result,GError ** error)1549 tp_stream_tube_channel_offer_finish (TpStreamTubeChannel *self,
1550 GAsyncResult *result,
1551 GError **error)
1552 {
1553 _tp_implement_finish_void (self, tp_stream_tube_channel_offer_async)
1554 }
1555
1556 /**
1557 * tp_stream_tube_channel_get_service:
1558 * @self: a #TpStreamTubeChannel
1559 *
1560 * Return the #TpStreamTubeChannel:service property
1561 *
1562 * Returns: (transfer none): the value of #TpStreamTubeChannel:service
1563 *
1564 * Since: 0.13.2
1565 */
1566 const gchar *
tp_stream_tube_channel_get_service(TpStreamTubeChannel * self)1567 tp_stream_tube_channel_get_service (TpStreamTubeChannel *self)
1568 {
1569 GHashTable *props;
1570
1571 props = _tp_channel_get_immutable_properties (TP_CHANNEL (self));
1572
1573 return tp_asv_get_string (props, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE);
1574 }
1575
1576 /**
1577 * tp_stream_tube_channel_get_parameters: (skip)
1578 * @self: a #TpStreamTubeChannel
1579 *
1580 * Return the #TpStreamTubeChannel:parameters property
1581 *
1582 * Returns: (transfer none) (element-type utf8 GObject.Value):
1583 * the value of #TpStreamTubeChannel:parameters
1584 *
1585 * Since: 0.13.2
1586 */
1587 GHashTable *
tp_stream_tube_channel_get_parameters(TpStreamTubeChannel * self)1588 tp_stream_tube_channel_get_parameters (TpStreamTubeChannel *self)
1589 {
1590 return self->priv->parameters;
1591 }
1592
1593 /**
1594 * tp_stream_tube_channel_dup_parameters_vardict:
1595 * @self: a #TpStreamTubeChannel
1596 *
1597 * Return the parameters of the dbus-tube channel in a variant of
1598 * type %G_VARIANT_TYPE_VARDICT whose keys are strings representing
1599 * parameter names and values are variants representing corresponding
1600 * parameter values set by the offerer when offering this channel.
1601 *
1602 * The GVariant returned is %NULL if this is an outgoing tube that has not
1603 * yet been offered or the parameters property has not been set.
1604 *
1605 * Use g_variant_lookup(), g_variant_lookup_value(), or tp_vardict_get_uint32()
1606 * and similar functions for convenient access to the values.
1607 *
1608 * Returns: (transfer full): a new reference to a #GVariant
1609 *
1610 * Since: 0.19.10
1611 */
1612 GVariant *
tp_stream_tube_channel_dup_parameters_vardict(TpStreamTubeChannel * self)1613 tp_stream_tube_channel_dup_parameters_vardict (TpStreamTubeChannel *self)
1614 {
1615 g_return_val_if_fail (TP_IS_STREAM_TUBE_CHANNEL (self), NULL);
1616
1617 if (self->priv->parameters == NULL)
1618 return NULL;
1619
1620 return _tp_asv_to_vardict (self->priv->parameters);
1621 }
1622