1 /*
2 * bytestream-factory.c - Source for GabbleBytestreamFactory
3 * Copyright (C) 2007-2008 Collabora Ltd.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "config.h"
21 #include "bytestream-factory.h"
22
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28 #include <wocky/wocky.h>
29 #include <telepathy-glib/telepathy-glib.h>
30 #include <telepathy-glib/telepathy-glib-dbus.h>
31
32 #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM
33
34 #include "bytestream-ibb.h"
35 #include "bytestream-iface.h"
36 #include "bytestream-muc.h"
37 #include "bytestream-multiple.h"
38 #include "bytestream-socks5.h"
39 #include "connection.h"
40 #include "conn-util.h"
41 #include "debug.h"
42 #include "disco.h"
43 #include "namespaces.h"
44 #include "presence-cache.h"
45 #include "private-tubes-factory.h"
46 #include "util.h"
47
48 G_DEFINE_TYPE (GabbleBytestreamFactory, gabble_bytestream_factory,
49 G_TYPE_OBJECT);
50
51 /* The number of proxy we'll try to have at a minimum in the cache. */
52 #define NB_MIN_SOCKS5_PROXIES 3
53 #define FALLBACK_PROXY_CACHE_SIZE 5
54 #define SOCKS5_PROXY_TIMEOUT 10
55
56 #define TELEPATHY_PROXIES_SERVICE "proxies.telepathy.im"
57 /* The life time (in seconds) of the proxies list discovered using
58 * TELEPATHY_PROXIES_SERVICE */
59 /* 6 hours */
60 #define PROXIES_LIST_LIFE_TIME 6 * 60 * 60
61
62 /* properties */
63 enum
64 {
65 PROP_CONNECTION = 1,
66 LAST_PROPERTY
67 };
68
69 typedef struct
70 {
71 gchar *jid;
72 gchar *stream;
73 } BytestreamIdentifier;
74
75 typedef struct
76 {
77 const gchar *jid;
78 const gchar *stream;
79 } ConstBytestreamIdentifier;
80
81 static gboolean
bytestream_id_equal(gconstpointer v1,gconstpointer v2)82 bytestream_id_equal (gconstpointer v1,
83 gconstpointer v2)
84 {
85 const ConstBytestreamIdentifier *left = v1;
86 const ConstBytestreamIdentifier *right = v2;
87
88 return (!tp_strdiff (left->jid, right->jid)) &&
89 (!tp_strdiff (left->stream, right->stream));
90 }
91
92 static guint
bytestream_id_hash(gconstpointer v)93 bytestream_id_hash (gconstpointer v)
94 {
95 const ConstBytestreamIdentifier *bsid = v;
96
97 return g_str_hash (bsid->jid) ^ g_str_hash (bsid->stream);
98 }
99
100 static BytestreamIdentifier *
bytestream_id_new(GabbleBytestreamIface * bytestream)101 bytestream_id_new (GabbleBytestreamIface *bytestream)
102 {
103 BytestreamIdentifier *bsid = g_slice_new (BytestreamIdentifier);
104
105 g_object_get (bytestream,
106 "stream-id", &(bsid->stream),
107 "peer-jid", &(bsid->jid),
108 NULL);
109 return bsid;
110 }
111
112 static void
bytestream_id_free(gpointer v)113 bytestream_id_free (gpointer v)
114 {
115 BytestreamIdentifier *bsid = v;
116
117 g_free (bsid->jid);
118 g_free (bsid->stream);
119 g_slice_free (BytestreamIdentifier, bsid);
120 }
121
122 static GabbleSocks5Proxy *
gabble_socks5_proxy_new(const gchar * jid,const gchar * host,guint16 port)123 gabble_socks5_proxy_new (const gchar *jid,
124 const gchar *host,
125 guint16 port)
126 {
127 GabbleSocks5Proxy *proxy;
128
129 proxy = g_slice_new (GabbleSocks5Proxy);
130 proxy->jid = g_strdup (jid);
131 proxy->host = g_strdup (host);
132 proxy->port = port;
133
134 return proxy;
135 }
136
137 static void
gabble_socks5_proxy_free(GabbleSocks5Proxy * proxy)138 gabble_socks5_proxy_free (GabbleSocks5Proxy *proxy)
139 {
140 g_free (proxy->jid);
141 g_free (proxy->host);
142
143 g_slice_free (GabbleSocks5Proxy, proxy);
144 }
145
146 struct _GabbleBytestreamFactoryPrivate
147 {
148 GabbleConnection *conn;
149 guint iq_si_cb;
150 guint iq_ibb_cb;
151 guint iq_socks5_cb;
152 guint msg_data_cb;
153
154 /* SI-initiated bytestreams - data sent by normal messages, IQs used to
155 * open and close.
156 *
157 * BytestreamIdentifier -> GabbleBytestreamIBB */
158 GHashTable *ibb_bytestreams;
159 /* BytestreamIdentifier -> GabbleBytestreamSocks5 */
160 GHashTable *socks5_bytestreams;
161
162 /* MUC pseudo-IBB - data sent by groupchat messages, IQs not allowed.
163 *
164 * BytestreamIdentifier -> GabbleBytestreamMuc */
165 GHashTable *muc_bytestreams;
166
167 /* SI-initiated bytestreams - real data sent through another bytestream.
168 *
169 * BytestreamIdentifier -> GabbleBytestreamMultiple */
170 GHashTable *multiple_bytestreams;
171
172 /* List of GabbleSocks5Proxy discovered on the connection */
173 GSList *socks5_proxies;
174 /* List of GabbleSocks5Proxy found using the fallback-socks5-proxies param */
175 GSList *socks5_fallback_proxies;
176 /* List of SOCKS5's jids that have not been queried yet */
177 GSList *socks5_potential_proxies;
178 /* Next proxy on socks5_potential_proxies that we'll query */
179 GSList *next_query;
180
181 /* Time stamp of the proxies list received from TELEPATHY_PROXIES_SERVICE */
182 GTimeVal proxies_list_stamp;
183
184 gboolean dispose_has_run;
185 };
186
187 #define GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE(obj) ((obj)->priv)
188
189 static gboolean bytestream_factory_msg_data_cb (
190 WockyPorter *porter,
191 WockyStanza *msg,
192 gpointer user_data);
193
194 static gboolean bytestream_factory_iq_si_cb (
195 WockyPorter *porter,
196 WockyStanza *msg,
197 gpointer user_data);
198
199 static gboolean bytestream_factory_iq_ibb_cb (
200 WockyPorter *porter,
201 WockyStanza *msg,
202 gpointer user_data);
203
204 static gboolean handle_socks5_query_iq (
205 WockyPorter *porter,
206 WockyStanza *msg,
207 gpointer user_data);
208
209 static void query_proxies (GabbleBytestreamFactory *self,
210 guint nb_proxies_needed);
211
212 static GSList * randomize_g_slist (GSList *list);
213
214 static void
gabble_bytestream_factory_init(GabbleBytestreamFactory * self)215 gabble_bytestream_factory_init (GabbleBytestreamFactory *self)
216 {
217 GabbleBytestreamFactoryPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
218 GABBLE_TYPE_BYTESTREAM_FACTORY, GabbleBytestreamFactoryPrivate);
219
220 self->priv = priv;
221
222 priv->ibb_bytestreams = g_hash_table_new_full (bytestream_id_hash,
223 bytestream_id_equal, bytestream_id_free, g_object_unref);
224
225 priv->muc_bytestreams = g_hash_table_new_full (bytestream_id_hash,
226 bytestream_id_equal, bytestream_id_free, g_object_unref);
227
228 priv->socks5_bytestreams = g_hash_table_new_full (bytestream_id_hash,
229 bytestream_id_equal, bytestream_id_free, g_object_unref);
230
231 priv->multiple_bytestreams = g_hash_table_new_full (bytestream_id_hash,
232 bytestream_id_equal, bytestream_id_free, g_object_unref);
233
234 memset (&priv->proxies_list_stamp, 0, sizeof (GTimeVal));
235 }
236
237 static gint
cmp_proxy(gconstpointer a,gconstpointer b)238 cmp_proxy (gconstpointer a,
239 gconstpointer b)
240 {
241 GabbleSocks5Proxy *proxy_a = (GabbleSocks5Proxy *) a;
242 GabbleSocks5Proxy *proxy_b = (GabbleSocks5Proxy *) b;
243
244 /* Streamhost are identified by their jid */
245 return strcmp (proxy_a->jid, proxy_b->jid);
246 }
247
248 static void
add_proxy_to_list(GabbleBytestreamFactory * self,GabbleSocks5Proxy * proxy,gboolean fallback)249 add_proxy_to_list (GabbleBytestreamFactory *self,
250 GabbleSocks5Proxy *proxy,
251 gboolean fallback)
252 {
253 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
254 self);
255 GSList **list;
256 GSList *found;
257
258 if (fallback)
259 {
260 list = &priv->socks5_fallback_proxies;
261 }
262 else
263 {
264 list = &priv->socks5_proxies;
265 }
266
267 found = g_slist_find_custom (*list, proxy, cmp_proxy);
268 if (found != NULL)
269 {
270 DEBUG ("%s SOCKS5 proxy (%s %s:%d) is already known; "
271 "move it to the head of the list",
272 fallback ? "Fallback": "Discovered",
273 proxy->jid, proxy->host, proxy->port);
274
275 *list = g_slist_delete_link (*list, found);
276 }
277 else
278 {
279 DEBUG ("Add %s SOCKS5 proxy: %s %s:%d",
280 fallback ? "fallback": "discovered",
281 proxy->jid, proxy->host, proxy->port);
282
283 if (fallback && g_slist_length (*list) >= FALLBACK_PROXY_CACHE_SIZE)
284 {
285 GSList *last;
286 GabbleSocks5Proxy *oldest;
287
288 last = g_slist_last (*list);
289 oldest = last->data;
290
291 DEBUG ("Proxy cache is full, remove the oldest entry (%s)",
292 oldest->jid);
293
294 *list = g_slist_delete_link (*list, last);
295 gabble_socks5_proxy_free (oldest);
296 }
297 }
298
299 *list = g_slist_prepend (*list, proxy);
300 }
301
302 static void
socks5_proxy_query_reply_cb(GabbleConnection * conn,WockyStanza * sent_msg,WockyStanza * reply_msg,GObject * obj,gpointer user_data)303 socks5_proxy_query_reply_cb (GabbleConnection *conn,
304 WockyStanza *sent_msg,
305 WockyStanza *reply_msg,
306 GObject *obj,
307 gpointer user_data)
308 {
309 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (obj);
310 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
311 self);
312 WockyNode *query, *streamhost;
313 const gchar *from;
314 const gchar *jid, *host, *portstr;
315 gint64 port;
316 GabbleSocks5Proxy *proxy;
317 gboolean fallback = GPOINTER_TO_INT (user_data);
318 GSList *found = NULL;
319
320 from = wocky_node_get_attribute (
321 wocky_stanza_get_top_node (reply_msg), "from");
322 if (from == NULL)
323 goto fail;
324
325 if (wocky_stanza_extract_errors (reply_msg, NULL, NULL, NULL, NULL))
326 goto fail;
327
328 query = wocky_node_get_child_ns (
329 wocky_stanza_get_top_node (reply_msg), "query", NS_BYTESTREAMS);
330 if (query == NULL)
331 goto fail;
332
333 streamhost = wocky_node_get_child (query, "streamhost");
334 if (streamhost == NULL)
335 goto fail;
336
337 jid = wocky_node_get_attribute (streamhost, "jid");
338 host = wocky_node_get_attribute (streamhost, "host");
339 portstr = wocky_node_get_attribute (streamhost, "port");
340
341 if (jid == NULL || host == NULL || portstr == NULL)
342 goto fail;
343
344 port = g_ascii_strtoll (portstr, NULL, 10);
345
346 if (port <= 0 || port > G_MAXUINT16)
347 goto fail;
348
349 proxy = gabble_socks5_proxy_new (jid, host, port);
350
351 add_proxy_to_list (self , proxy, fallback);
352
353 return;
354
355 fail:
356 if (fallback && from != NULL)
357 {
358 /* Remove the buggy proxy so we won't query it anymore */
359 found = g_slist_find_custom (priv->socks5_potential_proxies,
360 from, (GCompareFunc) strcmp);
361
362 if (found != NULL)
363 {
364 DEBUG ("remove proxy %s", from);
365 g_free (found->data);
366
367 priv->socks5_potential_proxies = g_slist_delete_link (
368 priv->socks5_potential_proxies, found);
369 }
370 }
371
372 /* Try to get another proxy as this one failed */
373 query_proxies (self, 1);
374 }
375
376 static void
send_proxy_query(GabbleBytestreamFactory * self,const gchar * jid,gboolean fallback)377 send_proxy_query (GabbleBytestreamFactory *self,
378 const gchar *jid,
379 gboolean fallback)
380 {
381 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
382 self);
383 WockyStanza *query;
384
385 DEBUG ("send SOCKS5 query to %s", jid);
386
387 query = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_GET,
388 NULL, jid,
389 '(', "query",
390 ':', NS_BYTESTREAMS,
391 ')', NULL);
392
393 _gabble_connection_send_with_reply (priv->conn, query,
394 socks5_proxy_query_reply_cb, G_OBJECT (self), GINT_TO_POINTER (fallback),
395 NULL);
396
397 g_object_unref (query);
398 }
399
400 static void
disco_item_found_cb(GabbleDisco * disco,GabbleDiscoItem * item,GabbleBytestreamFactory * self)401 disco_item_found_cb (GabbleDisco *disco,
402 GabbleDiscoItem *item,
403 GabbleBytestreamFactory *self)
404 {
405 if (tp_strdiff (item->category, "proxy") ||
406 tp_strdiff (item->type, "bytestreams"))
407 return;
408
409 send_proxy_query (self, item->jid, FALSE);
410 }
411
412 static void
query_proxies(GabbleBytestreamFactory * self,guint nb_proxies_needed)413 query_proxies (GabbleBytestreamFactory *self,
414 guint nb_proxies_needed)
415 {
416 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
417 self);
418 guint i;
419
420 /* We don't want to query more than once the same proxy */
421 nb_proxies_needed = MIN (nb_proxies_needed,
422 g_slist_length (priv->socks5_potential_proxies));
423
424 for (i = 0; i < nb_proxies_needed; i++)
425 {
426 gchar *jid;
427
428 if (priv->next_query == NULL)
429 priv->next_query = priv->socks5_potential_proxies;
430
431 jid = priv->next_query->data;
432 send_proxy_query (self, jid, TRUE);
433
434 priv->next_query = g_slist_next (priv->next_query);
435 }
436 }
437
438 static void
proxies_disco_cb(GabbleDisco * disco,GabbleDiscoRequest * request,const gchar * j,const gchar * n,WockyNode * query_result,GError * error,gpointer user_data)439 proxies_disco_cb (GabbleDisco *disco,
440 GabbleDiscoRequest *request,
441 const gchar *j,
442 const gchar *n,
443 WockyNode *query_result,
444 GError *error,
445 gpointer user_data)
446 {
447 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
448 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
449 self);
450 WockyNodeIter i;
451 WockyNode *node;
452 GSList *new_list = NULL;
453
454 if (error != NULL)
455 {
456 DEBUG ("disco failed: %s", error->message);
457 return;
458 }
459
460 wocky_node_iter_init (&i, query_result, "item", NULL);
461 while (wocky_node_iter_next (&i, &node))
462 {
463 const gchar *jid = wocky_node_get_attribute (node, "jid");
464 if (jid == NULL)
465 continue;
466
467 DEBUG ("Discovered proxy %s", jid);
468
469 new_list = g_slist_prepend (new_list, g_strdup (jid));
470 }
471
472 g_get_current_time (&priv->proxies_list_stamp);
473
474 if (new_list == NULL)
475 return;
476
477 /* replace the old list by the new one */
478 g_slist_foreach (priv->socks5_potential_proxies, (GFunc) g_free, NULL);
479 g_slist_free (priv->socks5_potential_proxies);
480
481 /* randomize the list to not always use the same proxies */
482 priv->socks5_potential_proxies = randomize_g_slist (new_list);
483 priv->next_query = priv->socks5_potential_proxies;
484
485 gabble_bytestream_factory_query_socks5_proxies (self);
486 }
487
488 /* Query TELEPATHY_PROXIES_SERVICE to get a list of proxies */
489 static void
get_proxies_list(GabbleBytestreamFactory * self)490 get_proxies_list (GabbleBytestreamFactory *self)
491 {
492 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
493 self);
494
495 DEBUG ("Ask %s for proxies", TELEPATHY_PROXIES_SERVICE);
496
497 gabble_disco_request (priv->conn->disco, GABBLE_DISCO_TYPE_ITEMS,
498 TELEPATHY_PROXIES_SERVICE, NULL, proxies_disco_cb, self, G_OBJECT (self),
499 NULL);
500 }
501
502 /* ask to the factory to try to find more proxies if needed */
503 void
gabble_bytestream_factory_query_socks5_proxies(GabbleBytestreamFactory * self)504 gabble_bytestream_factory_query_socks5_proxies (GabbleBytestreamFactory *self)
505 {
506 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
507 self);
508 guint nb_proxies_found;
509 guint nb_proxies_needed;
510 GTimeVal now;
511
512 if (priv->socks5_potential_proxies == NULL)
513 {
514 DEBUG ("No proxies list; request one");
515 get_proxies_list (self);
516 return;
517 }
518
519 g_get_current_time (&now);
520 if (now.tv_sec - priv->proxies_list_stamp.tv_sec > PROXIES_LIST_LIFE_TIME)
521 {
522 DEBUG ("Proxies list has expired; request a new one");
523 get_proxies_list (self);
524 }
525
526 nb_proxies_found = g_slist_length (priv->socks5_proxies) +
527 g_slist_length (priv->socks5_fallback_proxies);
528
529 if (nb_proxies_found >= NB_MIN_SOCKS5_PROXIES)
530 {
531 DEBUG ("we already have discovered enough proxies (%u); "
532 "request just one to refresh our cache",
533 nb_proxies_found);
534 nb_proxies_needed = 1;
535 }
536 else
537 {
538 nb_proxies_needed = NB_MIN_SOCKS5_PROXIES - nb_proxies_found;
539 DEBUG ("Need %u more proxies", nb_proxies_needed);
540 }
541
542 query_proxies (self, nb_proxies_needed);
543 }
544
545 static GSList *
randomize_g_slist(GSList * list)546 randomize_g_slist (GSList *list)
547 {
548 guint len;
549 guint i;
550 GSList *new_head, *new_tail;
551
552 len = g_slist_length (list);
553 if (len <= 1)
554 return list;
555
556 i = g_random_int_range (0, len);
557 if (i == 0)
558 return list;
559
560 /* Cut the list at the i th position and make it the new head of the
561 * list */
562 new_tail = g_slist_nth (list, i - 1);
563 g_assert (new_tail != NULL);
564
565 new_head = new_tail->next;
566 g_assert (new_head != NULL);
567
568 new_tail->next = NULL;
569
570 return g_slist_concat (new_head, list);
571 }
572
573 static void
porter_available_cb(GabbleConnection * conn,WockyPorter * porter,gpointer user_data)574 porter_available_cb (
575 GabbleConnection *conn,
576 WockyPorter *porter,
577 gpointer user_data)
578 {
579 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
580 GabbleBytestreamFactoryPrivate *priv = self->priv;
581
582 priv->msg_data_cb = wocky_porter_register_handler_from_anyone (porter,
583 WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE,
584 WOCKY_PORTER_HANDLER_PRIORITY_MAX,
585 bytestream_factory_msg_data_cb, self,
586 NULL);
587
588 priv->iq_si_cb = wocky_porter_register_handler_from_anyone (porter,
589 WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
590 WOCKY_PORTER_HANDLER_PRIORITY_MAX,
591 bytestream_factory_iq_si_cb, self,
592 '(', "si", ':', NS_SI,
593 ')',
594 NULL);
595
596 priv->iq_ibb_cb = wocky_porter_register_handler_from_anyone (porter,
597 WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_NONE,
598 WOCKY_PORTER_HANDLER_PRIORITY_MAX,
599 bytestream_factory_iq_ibb_cb, self,
600 NULL);
601
602 priv->iq_socks5_cb = wocky_porter_register_handler_from_anyone (porter,
603 WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
604 WOCKY_PORTER_HANDLER_PRIORITY_MAX,
605 handle_socks5_query_iq, self,
606 '(', "query", ':', NS_BYTESTREAMS, ')',
607 NULL);
608 }
609
610 static void
conn_status_changed_cb(GabbleConnection * conn,TpConnectionStatus status,TpConnectionStatusReason reason,gpointer user_data)611 conn_status_changed_cb (GabbleConnection *conn,
612 TpConnectionStatus status,
613 TpConnectionStatusReason reason,
614 gpointer user_data)
615 {
616 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
617 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
618 self);
619
620 if (status == TP_CONNECTION_STATUS_CONNECTED)
621 {
622 GStrv jids;
623 guint i;
624
625 /* we can't intialize socks5_potential_proxies in the constructor
626 * because Connection's properties are not set yet at this point */
627 g_object_get (priv->conn, "fallback-socks5-proxies", &jids, NULL);
628
629 for (i = 0; jids != NULL && jids[i] != NULL; i++)
630 {
631 priv->socks5_potential_proxies = g_slist_prepend (
632 priv->socks5_potential_proxies, g_strdup (jids[i]));
633 }
634
635 /* randomize the list to not always use the same proxies */
636 priv->socks5_potential_proxies = randomize_g_slist (
637 priv->socks5_potential_proxies);
638
639 priv->next_query = priv->socks5_potential_proxies;
640
641 g_strfreev (jids);
642 }
643 }
644
645 static GObject *
gabble_bytestream_factory_constructor(GType type,guint n_props,GObjectConstructParam * props)646 gabble_bytestream_factory_constructor (GType type,
647 guint n_props,
648 GObjectConstructParam *props)
649 {
650 GObject *obj;
651 GabbleBytestreamFactory *self;
652 GabbleBytestreamFactoryPrivate *priv;
653
654 obj = G_OBJECT_CLASS (gabble_bytestream_factory_parent_class)->
655 constructor (type, n_props, props);
656
657 self = GABBLE_BYTESTREAM_FACTORY (obj);
658 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
659
660 /* Track SOCKS5 proxy available on the connection */
661 gabble_signal_connect_weak (priv->conn->disco, "item-found",
662 G_CALLBACK (disco_item_found_cb), G_OBJECT (self));
663
664 gabble_signal_connect_weak (priv->conn, "status-changed",
665 G_CALLBACK (conn_status_changed_cb), G_OBJECT (self));
666 tp_g_signal_connect_object (priv->conn, "porter-available",
667 G_CALLBACK (porter_available_cb), self, 0);
668
669 return obj;
670 }
671
672 static void
gabble_bytestream_factory_dispose(GObject * object)673 gabble_bytestream_factory_dispose (GObject *object)
674 {
675 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (object);
676 GabbleBytestreamFactoryPrivate *priv =
677 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
678 GSList *proxies, *l;
679
680 if (priv->dispose_has_run)
681 return;
682
683 DEBUG ("dispose called");
684 priv->dispose_has_run = TRUE;
685
686 if (priv->msg_data_cb != 0)
687 {
688 WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
689
690 wocky_porter_unregister_handler (porter, priv->msg_data_cb);
691 wocky_porter_unregister_handler (porter, priv->iq_si_cb);
692 wocky_porter_unregister_handler (porter, priv->iq_ibb_cb);
693 wocky_porter_unregister_handler (porter, priv->iq_socks5_cb);
694 }
695
696 g_hash_table_unref (priv->ibb_bytestreams);
697 priv->ibb_bytestreams = NULL;
698
699 g_hash_table_unref (priv->muc_bytestreams);
700 priv->muc_bytestreams = NULL;
701
702 g_hash_table_unref (priv->socks5_bytestreams);
703 priv->socks5_bytestreams = NULL;
704
705 g_hash_table_unref (priv->multiple_bytestreams);
706 priv->multiple_bytestreams = NULL;
707
708 proxies = g_slist_concat (priv->socks5_proxies,
709 priv->socks5_fallback_proxies);
710
711 for (l = proxies; l != NULL; l = g_slist_next (l))
712 {
713 GabbleSocks5Proxy *proxy = (GabbleSocks5Proxy *) l->data;
714
715 gabble_socks5_proxy_free (proxy);
716 }
717 g_slist_free (proxies);
718
719 priv->socks5_proxies = NULL;
720 priv->socks5_fallback_proxies = NULL;
721
722 g_slist_foreach (priv->socks5_potential_proxies, (GFunc) g_free, NULL);
723 g_slist_free (priv->socks5_potential_proxies);
724 priv->socks5_potential_proxies = NULL;
725
726 if (G_OBJECT_CLASS (gabble_bytestream_factory_parent_class)->dispose)
727 G_OBJECT_CLASS (gabble_bytestream_factory_parent_class)->dispose (object);
728 }
729
730 static void
gabble_bytestream_factory_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)731 gabble_bytestream_factory_get_property (GObject *object,
732 guint property_id,
733 GValue *value,
734 GParamSpec *pspec)
735 {
736 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (object);
737 GabbleBytestreamFactoryPrivate *priv =
738 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
739
740 switch (property_id)
741 {
742 case PROP_CONNECTION:
743 g_value_set_object (value, priv->conn);
744 break;
745 default:
746 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
747 break;
748 }
749 }
750
751 static void
gabble_bytestream_factory_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)752 gabble_bytestream_factory_set_property (GObject *object,
753 guint property_id,
754 const GValue *value,
755 GParamSpec *pspec)
756 {
757 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (object);
758 GabbleBytestreamFactoryPrivate *priv =
759 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
760
761 switch (property_id)
762 {
763 case PROP_CONNECTION:
764 priv->conn = g_value_get_object (value);
765 break;
766 default:
767 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
768 break;
769 }
770 }
771
772 static void
gabble_bytestream_factory_class_init(GabbleBytestreamFactoryClass * gabble_bytestream_factory_class)773 gabble_bytestream_factory_class_init (
774 GabbleBytestreamFactoryClass *gabble_bytestream_factory_class)
775 {
776 GObjectClass *object_class =
777 G_OBJECT_CLASS (gabble_bytestream_factory_class);
778 GParamSpec *param_spec;
779
780 g_type_class_add_private (gabble_bytestream_factory_class,
781 sizeof (GabbleBytestreamFactoryPrivate));
782
783 object_class->constructor = gabble_bytestream_factory_constructor;
784 object_class->dispose = gabble_bytestream_factory_dispose;
785
786 object_class->get_property = gabble_bytestream_factory_get_property;
787 object_class->set_property = gabble_bytestream_factory_set_property;
788
789 param_spec = g_param_spec_object (
790 "connection",
791 "GabbleConnection object",
792 "Gabble connection object that owns this bytestream factory object.",
793 GABBLE_TYPE_CONNECTION,
794 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
795 g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
796 }
797
798 static void
remove_bytestream(GabbleBytestreamFactory * self,GabbleBytestreamIface * bytestream)799 remove_bytestream (GabbleBytestreamFactory *self,
800 GabbleBytestreamIface *bytestream)
801 {
802 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE
803 (self);
804 BytestreamIdentifier bsid = { NULL, NULL };
805 guint handle_type;
806 GHashTable *table = NULL;
807
808 g_object_get (bytestream,
809 "stream-id", &(bsid.stream),
810 "peer-jid", &(bsid.jid),
811 "peer-handle-type", &handle_type,
812 NULL);
813
814 if (handle_type == TP_HANDLE_TYPE_ROOM)
815 {
816 table = priv->muc_bytestreams;
817 }
818 else
819 {
820 if (GABBLE_IS_BYTESTREAM_IBB (bytestream))
821 table = priv->ibb_bytestreams;
822 else if (GABBLE_IS_BYTESTREAM_SOCKS5 (bytestream))
823 table = priv->socks5_bytestreams;
824 else if (GABBLE_IS_BYTESTREAM_MULTIPLE (bytestream))
825 table = priv->multiple_bytestreams;
826 }
827
828 if (table == NULL)
829 return;
830
831 DEBUG ("removing bytestream: <%s> from <%s>", bsid.stream, bsid.jid);
832 g_hash_table_remove (table, &bsid);
833
834 g_free (bsid.stream);
835 g_free (bsid.jid);
836 }
837
838 /**
839 * streaminit_parse_request
840 *
841 * Parses a SI request, or returns FALSE if it can't be parsed.
842 *
843 * The items in the linked list of stream methods are borrowed
844 * from the message; their lifetime is only as long as that of the
845 * message.
846 */
847 static gboolean
streaminit_parse_request(WockyStanza * message,WockyNode * si,const gchar ** profile,const gchar ** from,const gchar ** stream_id,const gchar ** stream_init_id,const gchar ** mime_type,GSList ** stream_methods,gboolean * multiple)848 streaminit_parse_request (WockyStanza *message,
849 WockyNode *si,
850 const gchar **profile,
851 const gchar **from,
852 const gchar **stream_id,
853 const gchar **stream_init_id,
854 const gchar **mime_type,
855 GSList **stream_methods,
856 gboolean *multiple)
857 {
858 WockyNode *iq = wocky_stanza_get_top_node (message);
859 WockyNode *feature, *x, *si_multiple, *field;
860 WockyNodeIter i, j;
861
862 *stream_init_id = wocky_node_get_attribute (iq, "id");
863
864 *from = wocky_node_get_attribute (iq, "from");
865 if (*from == NULL)
866 {
867 STANZA_DEBUG (message, "got a message without a from field");
868 return FALSE;
869 }
870
871 /* Parse <si> */
872
873 *stream_id = wocky_node_get_attribute (si, "id");
874 if (*stream_id == NULL)
875 {
876 STANZA_DEBUG (message, "got a SI request without a stream id field");
877 return FALSE;
878 }
879
880 *mime_type = wocky_node_get_attribute (si, "mime-type");
881 /* if no mime_type is defined, XEP-0095 says to assume "binary/octect-stream"
882 * which is presumably a typo for "application/octet-stream" */
883
884 *profile = wocky_node_get_attribute (si, "profile");
885 if (*profile == NULL)
886 {
887 STANZA_DEBUG (message, "got a SI request without a profile field");
888 return FALSE;
889 }
890
891 /* Parse <feature> */
892 feature = wocky_node_get_child_ns (si, "feature",
893 NS_FEATURENEG);
894 if (feature == NULL)
895 {
896 STANZA_DEBUG (message, "got a SI request without a feature field");
897 return FALSE;
898 }
899
900 x = wocky_node_get_child_ns (feature, "x", NS_X_DATA);
901 if (x == NULL)
902 {
903 STANZA_DEBUG (message, "got a SI request without a X data field");
904 return FALSE;
905 }
906
907 wocky_node_iter_init (&i, x, NULL, NULL);
908 while (wocky_node_iter_next (&i, &field))
909 {
910 WockyNode *stream_method;
911
912 if (tp_strdiff (wocky_node_get_attribute (field, "var"),
913 "stream-method"))
914 /* some future field, ignore it */
915 continue;
916
917 if (tp_strdiff (wocky_node_get_attribute (field, "type"),
918 "list-single"))
919 {
920 STANZA_DEBUG (message, "SI request's stream-method field was "
921 "not of type list-single");
922 return FALSE;
923 }
924
925 /* Get the stream methods offered */
926 *stream_methods = NULL;
927 wocky_node_iter_init (&j, field, NULL, NULL);
928 while (wocky_node_iter_next (&j, &stream_method))
929 {
930 WockyNode *value;
931 const gchar *stream_method_str;
932
933 value = wocky_node_get_child (stream_method, "value");
934 if (value == NULL)
935 continue;
936
937 stream_method_str = value->content;
938 if (!tp_strdiff (stream_method_str, ""))
939 continue;
940
941 DEBUG ("Got stream-method %s", stream_method_str);
942
943 /* Append to the stream_methods list */
944 *stream_methods = g_slist_append (*stream_methods,
945 (gchar *) stream_method_str);
946 }
947
948 /* no need to parse the rest of the fields, we've found the one we
949 * wanted */
950 break;
951 }
952
953 if (*stream_methods == NULL)
954 {
955 STANZA_DEBUG (message,
956 "got a SI request without stream method proposed");
957 return FALSE;
958 }
959
960 si_multiple = wocky_node_get_child_ns (si, "si-multiple", NS_SI_MULTIPLE);
961 if (si_multiple == NULL)
962 *multiple = FALSE;
963 else
964 *multiple = TRUE;
965
966 return TRUE;
967 }
968
969 /**
970 * gabble_bytestream_factory_make_stream_init_iq
971 *
972 * @full_jid: the full jid of the contact to whom we want to offer the stream
973 * @stream_id: the stream ID of the new stream
974 * @profile: the profile associated with the stream
975 *
976 * Create a SI request IQ as described in XEP-0095.
977 *
978 * The MIME type is not set - the receiving client will assume
979 * application/octet-stream unless the caller sets a MIME type explicitly.
980 */
981 WockyStanza *
gabble_bytestream_factory_make_stream_init_iq(const gchar * full_jid,const gchar * stream_id,const gchar * profile)982 gabble_bytestream_factory_make_stream_init_iq (const gchar *full_jid,
983 const gchar *stream_id,
984 const gchar *profile)
985 {
986 return wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
987 NULL, full_jid,
988 '(', "si",
989 ':', NS_SI,
990 '@', "id", stream_id,
991 '@', "profile", profile,
992 '(', "feature",
993 ':', NS_FEATURENEG,
994 '(', "x",
995 ':', NS_X_DATA,
996 '@', "type", "form",
997 '(', "field",
998 '@', "var", "stream-method",
999 '@', "type", "list-single",
1000 '(', "option",
1001 '(', "value", '$', NS_BYTESTREAMS,
1002 ')',
1003 ')',
1004 '(', "option",
1005 '(', "value", '$', NS_IBB,
1006 ')',
1007 ')',
1008 ')',
1009 ')',
1010 ')',
1011 '(', "si-multiple",
1012 ':', NS_SI_MULTIPLE,
1013 ')',
1014 ')', NULL);
1015 }
1016
1017 static gboolean
stream_method_supported(const gchar * stream_method)1018 stream_method_supported (const gchar *stream_method)
1019 {
1020 /* IBB */
1021 if (!tp_strdiff (stream_method, NS_IBB))
1022 return TRUE;
1023
1024 /* Sock5 */
1025 if (!tp_strdiff (stream_method, NS_BYTESTREAMS))
1026 return TRUE;
1027
1028 return FALSE;
1029 }
1030
1031 static GabbleBytestreamMultiple *gabble_bytestream_factory_create_multiple (
1032 GabbleBytestreamFactory *self, TpHandle peer_handle,
1033 const gchar *stream_id, const gchar *stream_init_id,
1034 const gchar *peer_resource, const gchar *self_jid,
1035 GabbleBytestreamState state);
1036
1037 static GabbleBytestreamIBB *gabble_bytestream_factory_create_ibb (
1038 GabbleBytestreamFactory *fac, TpHandle peer_handle, const gchar *stream_id,
1039 const gchar *stream_init_id, const gchar *peer_resource,
1040 GabbleBytestreamState state);
1041
1042 static GabbleBytestreamSocks5 *gabble_bytestream_factory_create_socks5 (
1043 GabbleBytestreamFactory *fac, TpHandle peer_handle, const gchar *stream_id,
1044 const gchar *stream_init_id, const gchar *peer_resource,
1045 const gchar *self_jid, GabbleBytestreamState state);
1046
1047 static void
si_tube_received(GabbleBytestreamFactory * self,WockyStanza * msg,WockyNode * si,GabbleBytestreamIface * bytestream,TpHandle peer_handle,TpHandle room_handle,const gchar * stream_id)1048 si_tube_received (GabbleBytestreamFactory *self,
1049 WockyStanza *msg,
1050 WockyNode *si,
1051 GabbleBytestreamIface *bytestream,
1052 TpHandle peer_handle,
1053 TpHandle room_handle,
1054 const gchar *stream_id)
1055 {
1056 GabbleBytestreamFactoryPrivate *priv =
1057 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1058
1059 /* A Tubes SI request can be:
1060 * - a 1-1 new tube offer
1061 * - a 1-1 tube extra bytestream offer
1062 * - a muc tube extra bytestream offer
1063 */
1064 if (wocky_node_get_child_ns (si, "tube", NS_TUBES) != NULL)
1065 {
1066 /* The SI request is a tube offer */
1067 gabble_private_tubes_factory_handle_si_tube_request (
1068 priv->conn->private_tubes_factory, bytestream, peer_handle,
1069 stream_id, msg);
1070 }
1071 else if (wocky_node_get_child_ns (si, "stream", NS_TUBES)
1072 != NULL)
1073 {
1074 /* The SI request is an extra bytestream for a 1-1 tube */
1075 gabble_private_tubes_factory_handle_si_stream_request (
1076 priv->conn->private_tubes_factory, bytestream, peer_handle,
1077 stream_id, msg);
1078 }
1079 else if (wocky_node_get_child_ns (si, "muc-stream",
1080 NS_TUBES) != NULL)
1081 {
1082 /* The SI request is an extra bytestream for a muc tube */
1083
1084 if (room_handle == 0)
1085 {
1086 GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
1087 "<muc-stream> is only valid in a MUC context" };
1088
1089 gabble_bytestream_iface_close (bytestream, &e);
1090 }
1091 else
1092 {
1093 gabble_muc_factory_handle_si_stream_request (priv->conn->muc_factory,
1094 bytestream, room_handle, stream_id, msg);
1095 }
1096 }
1097 else
1098 {
1099 GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
1100 "Invalid tube SI request: expected <tube>, <stream> or "
1101 "<muc-stream>" };
1102
1103 /* Invalid tube SI request */
1104 STANZA_DEBUG (msg, e.message);
1105 gabble_bytestream_iface_close (bytestream, &e);
1106 }
1107 }
1108
1109 /**
1110 * bytestream_factory_iq_si_cb:
1111 *
1112 * Called by Wocky when we get an incoming <iq>. This handler is concerned
1113 * with Stream Initiation requests (XEP-0095).
1114 *
1115 */
1116 static gboolean
bytestream_factory_iq_si_cb(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1117 bytestream_factory_iq_si_cb (
1118 WockyPorter *porter,
1119 WockyStanza *msg,
1120 gpointer user_data)
1121 {
1122 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1123 GabbleBytestreamFactoryPrivate *priv =
1124 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1125 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
1126 (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT);
1127 TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
1128 (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM);
1129 WockyNode *si;
1130 TpHandle peer_handle = 0, room_handle;
1131 GabbleBytestreamIface *bytestream = NULL;
1132 GSList *l;
1133 const gchar *profile, *from, *stream_id, *stream_init_id, *mime_type;
1134 GSList *stream_methods = NULL;
1135 gboolean multiple;
1136 gchar *peer_resource = NULL;
1137 gchar *self_jid = NULL;
1138
1139 si = wocky_node_get_child_ns (
1140 wocky_stanza_get_top_node (msg), "si", NS_SI);
1141 g_return_val_if_fail (si != NULL, FALSE);
1142
1143 /* after this point, the message is for us, so in all cases we either handle
1144 * it or send an error reply */
1145
1146 if (!streaminit_parse_request (msg, si, &profile, &from, &stream_id,
1147 &stream_init_id, &mime_type, &stream_methods, &multiple))
1148 {
1149 wocky_porter_send_iq_error (porter, msg,
1150 WOCKY_XMPP_ERROR_BAD_REQUEST, "failed to parse SI request");
1151 goto out;
1152 }
1153
1154 DEBUG ("received a SI request");
1155
1156 room_handle = gabble_get_room_handle_from_jid (room_repo, from);
1157
1158 if (room_handle == 0)
1159 {
1160 /* jid is not a muc jid so we need contact's resource */
1161
1162 if (!wocky_decode_jid (from, NULL, NULL, &peer_resource))
1163 {
1164 DEBUG ("Got an SI IQ response from a bad JID. Ignoring.");
1165 goto out;
1166 }
1167
1168 if (!peer_resource)
1169 {
1170 DEBUG ("Got an SI IQ response from a JID without a resource."
1171 "Ignoring.");
1172 goto out;
1173 }
1174
1175 peer_handle = tp_handle_ensure (contact_repo, from, NULL, NULL);
1176
1177 /* we are not in a muc so our own jid is the one in the 'to' attribute */
1178 self_jid = g_strdup (wocky_node_get_attribute (
1179 wocky_stanza_get_top_node (msg), "to"));
1180 }
1181 else
1182 {
1183 /* we are in a muc so need to get our muc jid */
1184 GabbleMucChannel *muc;
1185
1186 peer_handle = tp_handle_ensure (contact_repo, from,
1187 GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
1188
1189 muc = gabble_muc_factory_find_text_channel (priv->conn->muc_factory,
1190 room_handle);
1191
1192 if (muc == NULL)
1193 {
1194 DEBUG ("Got an IQ from a muc in which we are not. Ignoring.");
1195 goto out;
1196 }
1197
1198 g_object_get (muc, "self-jid", &self_jid, NULL);
1199 }
1200
1201 if (peer_handle == 0)
1202 {
1203 wocky_porter_send_iq_error (porter, msg,
1204 WOCKY_XMPP_ERROR_JID_MALFORMED, NULL);
1205 goto out;
1206 }
1207
1208 if (multiple)
1209 {
1210 DEBUG ("Receiver supports multi bytestreams");
1211
1212 bytestream = (GabbleBytestreamIface *)
1213 gabble_bytestream_factory_create_multiple (self, peer_handle,
1214 stream_id, stream_init_id, peer_resource, self_jid,
1215 GABBLE_BYTESTREAM_STATE_LOCAL_PENDING);
1216 }
1217
1218 /* check stream method */
1219 for (l = stream_methods; l != NULL; l = l->next)
1220 {
1221 if (multiple)
1222 {
1223 if (stream_method_supported (l->data))
1224 {
1225 DEBUG ("add %s to multi-bytestream methods",
1226 (const gchar *) l->data);
1227
1228 gabble_bytestream_multiple_add_stream_method (
1229 GABBLE_BYTESTREAM_MULTIPLE (bytestream), l->data);
1230 }
1231 else
1232 {
1233 DEBUG ("skip unsupported stream method: %s",
1234 (const gchar *) l->data);
1235 }
1236 }
1237 else
1238 {
1239 /* We create the stream according the stream method chosen.
1240 * User has to accept it */
1241 DEBUG ("Receiver doesn't support multi bytestreams. He chose %s",
1242 (const gchar *) l->data);
1243
1244 bytestream = gabble_bytestream_factory_create_from_method (self,
1245 l->data, peer_handle, stream_id, stream_init_id, peer_resource,
1246 self_jid, GABBLE_BYTESTREAM_STATE_LOCAL_PENDING);
1247 if (bytestream != NULL)
1248 break;
1249 }
1250 }
1251
1252 if (bytestream == NULL)
1253 {
1254 GError error = { WOCKY_SI_ERROR, WOCKY_SI_ERROR_NO_VALID_STREAMS, "" };
1255
1256 DEBUG ("SI request doesn't contain any supported stream methods.");
1257 wocky_porter_send_iq_gerror (porter, msg, &error);
1258 goto out;
1259 }
1260
1261 if (multiple)
1262 {
1263 /* Is there at least one stream method? */
1264 if (!gabble_bytestream_multiple_has_stream_method (
1265 GABBLE_BYTESTREAM_MULTIPLE (bytestream)))
1266 {
1267 GError e = { WOCKY_SI_ERROR, WOCKY_SI_ERROR_NO_VALID_STREAMS, "" };
1268 DEBUG ("No valid stream method in the multi bytestream. Closing");
1269
1270 gabble_bytestream_iface_close (bytestream, &e);
1271 goto out;
1272 }
1273 }
1274
1275 /* Now that we have a bytestream, it's responsible for declining the IQ
1276 * if needed. */
1277
1278 /* We inform the right factory we received a SI request */
1279 if (!tp_strdiff (profile, NS_TUBES))
1280 {
1281 si_tube_received (self, msg, si, bytestream, peer_handle, room_handle,
1282 stream_id);
1283 }
1284 #ifdef ENABLE_FILE_TRANSFER
1285 else if (!tp_strdiff (profile, NS_FILE_TRANSFER))
1286 {
1287 gabble_ft_manager_handle_si_request (priv->conn->ft_manager, bytestream,
1288 peer_handle, stream_id, msg);
1289 }
1290 #endif
1291 else
1292 {
1293 GError e = { WOCKY_SI_ERROR, WOCKY_SI_ERROR_BAD_PROFILE, "" };
1294 DEBUG ("SI profile unsupported: %s", profile);
1295
1296 gabble_bytestream_iface_close (bytestream, &e);
1297 }
1298
1299 out:
1300 g_slist_free (stream_methods);
1301 g_free (peer_resource);
1302 g_free (self_jid);
1303
1304 return TRUE;
1305 }
1306
1307 static gboolean
handle_ibb_open_iq(GabbleBytestreamFactory * self,WockyStanza * msg)1308 handle_ibb_open_iq (GabbleBytestreamFactory *self,
1309 WockyStanza *msg)
1310 {
1311 GabbleBytestreamFactoryPrivate *priv =
1312 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1313 WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
1314 GabbleBytestreamIBB *bytestream;
1315 WockyNode *open_node;
1316 ConstBytestreamIdentifier bsid = { NULL, NULL };
1317 const gchar *tmp;
1318 guint state;
1319 WockyStanzaSubType sub_type;
1320
1321 wocky_stanza_get_type_info (msg, NULL, &sub_type);
1322 if (sub_type != WOCKY_STANZA_SUB_TYPE_SET)
1323 return FALSE;
1324
1325 open_node = wocky_node_get_child_ns (
1326 wocky_stanza_get_top_node (msg), "open", NS_IBB);
1327 if (open_node == NULL)
1328 return FALSE;
1329
1330 bsid.jid = wocky_node_get_attribute (
1331 wocky_stanza_get_top_node (msg), "from");
1332 if (bsid.jid == NULL)
1333 {
1334 DEBUG ("got a message without a from field");
1335 wocky_porter_send_iq_error (porter, msg,
1336 WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1337 return TRUE;
1338 }
1339
1340 bsid.stream = wocky_node_get_attribute (open_node, "sid");
1341 if (bsid.stream == NULL)
1342 {
1343 DEBUG ("IBB open stanza doesn't contain stream id");
1344 wocky_porter_send_iq_error (porter, msg,
1345 WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1346 return TRUE;
1347 }
1348
1349 bytestream = g_hash_table_lookup (priv->ibb_bytestreams, &bsid);
1350 if (bytestream == NULL)
1351 {
1352 /* We don't accept streams not previously announced using SI */
1353 DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1354 wocky_porter_send_iq_error (porter, msg,
1355 WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1356 return TRUE;
1357 }
1358
1359 g_object_get (bytestream, "state", &state, NULL);
1360
1361 if (state != GABBLE_BYTESTREAM_STATE_ACCEPTED)
1362 {
1363 /* We don't accept streams not previously accepted using SI */
1364 DEBUG ("unaccepted stream: <%s> from <%s>", bsid.stream, bsid.jid);
1365 wocky_porter_send_iq_error (porter, msg,
1366 WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1367 return TRUE;
1368 }
1369
1370 tmp = wocky_node_get_attribute (open_node, "block-size");
1371 if (tmp != NULL)
1372 {
1373 guint block_size = strtoul (tmp, NULL, 10);
1374
1375 if (block_size > 0)
1376 g_object_set (bytestream, "block-size", block_size, NULL);
1377 }
1378
1379 g_object_set (bytestream, "state", GABBLE_BYTESTREAM_STATE_OPEN,
1380 NULL);
1381
1382 wocky_porter_acknowledge_iq (porter, msg, NULL);
1383
1384 return TRUE;
1385 }
1386
1387 static gboolean
handle_ibb_close_iq(GabbleBytestreamFactory * self,WockyStanza * msg)1388 handle_ibb_close_iq (GabbleBytestreamFactory *self,
1389 WockyStanza *msg)
1390 {
1391 GabbleBytestreamFactoryPrivate *priv =
1392 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1393 WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
1394 ConstBytestreamIdentifier bsid = { NULL, NULL };
1395 GabbleBytestreamIBB *bytestream;
1396 WockyNode *close_node;
1397 WockyStanzaSubType sub_type;
1398
1399 wocky_stanza_get_type_info (msg, NULL, &sub_type);
1400 if (sub_type != WOCKY_STANZA_SUB_TYPE_SET)
1401 return FALSE;
1402
1403 close_node = wocky_node_get_child_ns (
1404 wocky_stanza_get_top_node (msg), "close", NS_IBB);
1405 if (close_node == NULL)
1406 return FALSE;
1407
1408 bsid.jid = wocky_node_get_attribute (wocky_stanza_get_top_node (msg),
1409 "from");
1410 if (bsid.jid == NULL)
1411 {
1412 DEBUG ("got a message without a from field");
1413 wocky_porter_send_iq_error (porter, msg,
1414 WOCKY_XMPP_ERROR_BAD_REQUEST, "IBB <close> has no 'from' attribute");
1415 return TRUE;
1416 }
1417
1418 bsid.stream = wocky_node_get_attribute (close_node, "sid");
1419 if (bsid.stream == NULL)
1420 {
1421 DEBUG ("IBB close stanza doesn't contain stream id");
1422 wocky_porter_send_iq_error (porter, msg,
1423 WOCKY_XMPP_ERROR_BAD_REQUEST, "IBB <close> has no stream ID");
1424 return TRUE;
1425 }
1426
1427 bytestream = g_hash_table_lookup (priv->ibb_bytestreams, &bsid);
1428 if (bytestream == NULL)
1429 {
1430 DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1431 wocky_porter_send_iq_error (porter, msg,
1432 WOCKY_XMPP_ERROR_ITEM_NOT_FOUND, NULL);
1433 }
1434 else
1435 {
1436 gabble_bytestream_ibb_close_received (bytestream, msg);
1437 }
1438
1439 return TRUE;
1440 }
1441
1442 /* IBB can be transported over either IQs or messages, so msg can either be
1443 * an <iq> or a <message>. If it's an <iq> we need to reply to it.
1444 *
1445 * Return TRUE if we take responsibility for this message. */
1446 static gboolean
handle_ibb_data(GabbleBytestreamFactory * self,WockyStanza * msg,gboolean is_iq)1447 handle_ibb_data (GabbleBytestreamFactory *self,
1448 WockyStanza *msg,
1449 gboolean is_iq)
1450 {
1451 GabbleBytestreamFactoryPrivate *priv =
1452 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1453 WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
1454 GabbleBytestreamIBB *bytestream = NULL;
1455 WockyNode *data;
1456 ConstBytestreamIdentifier bsid = { NULL, NULL };
1457 WockyStanzaSubType sub_type;
1458
1459 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1460
1461 wocky_stanza_get_type_info (msg, NULL, &sub_type);
1462 if (is_iq && sub_type != WOCKY_STANZA_SUB_TYPE_SET)
1463 return FALSE;
1464
1465 data = wocky_node_get_child_ns (
1466 wocky_stanza_get_top_node (msg), "data", NS_IBB);
1467 if (data == NULL)
1468 return FALSE;
1469
1470 bsid.jid = wocky_node_get_attribute (wocky_stanza_get_top_node (msg),
1471 "from");
1472 if (bsid.jid == NULL)
1473 {
1474 DEBUG ("got a message without a from field");
1475 if (is_iq)
1476 wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1477 "IBB <close> has no 'from' attribute");
1478 return TRUE;
1479 }
1480
1481 bsid.stream = wocky_node_get_attribute (data, "sid");
1482 if (bsid.stream == NULL)
1483 {
1484 DEBUG ("got a IBB message data without a stream id field");
1485 if (is_iq)
1486 wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1487 "IBB <data> needs a stream ID");
1488 return TRUE;
1489 }
1490
1491 bytestream = g_hash_table_lookup (priv->ibb_bytestreams, &bsid);
1492
1493 if (bytestream == NULL)
1494 {
1495 DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1496 if (is_iq)
1497 wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1498 "IBB <data> has unknown stream ID");
1499
1500 return TRUE;
1501 }
1502
1503 gabble_bytestream_ibb_receive (bytestream, msg, is_iq);
1504
1505 return TRUE;
1506 }
1507
1508 static gboolean
handle_muc_data(GabbleBytestreamFactory * self,WockyStanza * msg)1509 handle_muc_data (GabbleBytestreamFactory *self,
1510 WockyStanza *msg)
1511 {
1512 GabbleBytestreamFactoryPrivate *priv =
1513 GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1514 GabbleBytestreamMuc *bytestream = NULL;
1515 WockyNode *data;
1516 ConstBytestreamIdentifier bsid = { NULL, NULL };
1517 gchar *room_name;
1518 const gchar *from;
1519
1520 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1521
1522 data = wocky_node_get_child_ns (
1523 wocky_stanza_get_top_node (msg), "data", NS_MUC_BYTESTREAM);
1524 if (data == NULL)
1525 return FALSE;
1526
1527 from = wocky_node_get_attribute (
1528 wocky_stanza_get_top_node (msg), "from");
1529 if (from == NULL)
1530 {
1531 DEBUG ("got a message without a from field");
1532 return TRUE;
1533 }
1534
1535 bsid.stream = wocky_node_get_attribute (data, "sid");
1536 if (bsid.stream == NULL)
1537 {
1538 DEBUG ("got a pseudo IBB muc message data without a stream id field");
1539 return TRUE;
1540 }
1541
1542 room_name = gabble_remove_resource (from);
1543 bsid.jid = room_name;
1544 bytestream = g_hash_table_lookup (priv->muc_bytestreams, &bsid);
1545
1546 if (bytestream == NULL)
1547 {
1548 DEBUG ("unknown muc stream: <%s> from <%s>", bsid.stream, bsid.jid);
1549 g_free (room_name);
1550 return TRUE;
1551 }
1552 g_assert (GABBLE_IS_BYTESTREAM_MUC (bytestream));
1553
1554 gabble_bytestream_muc_receive (bytestream, msg);
1555
1556 g_free (room_name);
1557 return TRUE;
1558 }
1559
1560 /**
1561 * bytestream_factory_iq_ibb_cb:
1562 *
1563 * Called by Wocky when we get an incoming <iq>.
1564 * This handler is concerned with IBB iq's.
1565 *
1566 */
1567 static gboolean
bytestream_factory_iq_ibb_cb(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1568 bytestream_factory_iq_ibb_cb (
1569 WockyPorter *porter,
1570 WockyStanza *msg,
1571 gpointer user_data)
1572 {
1573 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1574
1575 if (handle_ibb_open_iq (self, msg))
1576 return TRUE;
1577
1578 if (handle_ibb_close_iq (self, msg))
1579 return TRUE;
1580
1581 if (handle_ibb_data (self, msg, TRUE))
1582 return TRUE;
1583
1584 return FALSE;
1585 }
1586
1587 /**
1588 * bytestream_factory_msg_data_cb
1589 *
1590 * Called by Wocky when we get an incoming <message>.
1591 * This handler handles IBB data and pseudo IBB Muc data.
1592 */
1593 static gboolean
bytestream_factory_msg_data_cb(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1594 bytestream_factory_msg_data_cb (
1595 WockyPorter *porter,
1596 WockyStanza *msg,
1597 gpointer user_data)
1598 {
1599 GabbleBytestreamFactory *self = user_data;
1600
1601 if (handle_ibb_data (self, msg, FALSE))
1602 return TRUE;
1603
1604 if (handle_muc_data (self, msg))
1605 return TRUE;
1606
1607 return FALSE;
1608 }
1609
1610 static gboolean
handle_socks5_query_iq(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1611 handle_socks5_query_iq (
1612 WockyPorter *porter,
1613 WockyStanza *msg,
1614 gpointer user_data)
1615 {
1616 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1617 GabbleBytestreamFactoryPrivate *priv = self->priv;
1618 GabbleBytestreamSocks5 *bytestream;
1619 WockyNode *query_node, *child_node;
1620 ConstBytestreamIdentifier bsid = { NULL, NULL };
1621 const gchar *tmp;
1622 WockyNodeIter i;
1623
1624 query_node = wocky_node_get_child_ns (
1625 wocky_stanza_get_top_node (msg), "query", NS_BYTESTREAMS);
1626 g_return_val_if_fail (query_node != NULL, FALSE);
1627
1628 bsid.jid = wocky_node_get_attribute (
1629 wocky_stanza_get_top_node (msg), "from");
1630 if (bsid.jid == NULL)
1631 {
1632 DEBUG ("got a message without a from field");
1633 wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1634 "SOCKS5 <query> has no 'from' attribute");
1635 return TRUE;
1636 }
1637
1638 bsid.stream = wocky_node_get_attribute (query_node, "sid");
1639 if (bsid.stream == NULL)
1640 {
1641 DEBUG ("SOCKS5 query stanza doesn't contain stream id");
1642 wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1643 "SOCKS5 <query> has no stream ID");
1644 return TRUE;
1645 }
1646
1647 bytestream = g_hash_table_lookup (priv->socks5_bytestreams, &bsid);
1648 if (bytestream == NULL)
1649 {
1650 /* We don't accept streams not previously announced using SI */
1651 DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1652 wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_ITEM_NOT_FOUND,
1653 "SOCKS5 <query> has an unknown stream ID");
1654 return TRUE;
1655 }
1656
1657 tmp = wocky_node_get_attribute (query_node, "mode");
1658 /* If this attribute is missing, the default value of "tcp" MUST be assumed */
1659 if (tmp != NULL && tp_strdiff (tmp, "tcp"))
1660 {
1661 DEBUG ("non-TCP SOCKS5 bytestreams are not supported");
1662 wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1663 "SOCKS5 non-TCP bytestreams are not supported");
1664 return TRUE;
1665 }
1666
1667 wocky_node_iter_init (&i, query_node, "streamhost", NULL);
1668 while (wocky_node_iter_next (&i, &child_node))
1669 {
1670 gabble_bytestream_socks5_add_streamhost (bytestream, child_node);
1671 }
1672
1673 gabble_bytestream_socks5_connect_to_streamhost (bytestream, msg);
1674
1675 return TRUE;
1676 }
1677
1678 GabbleBytestreamFactory *
gabble_bytestream_factory_new(GabbleConnection * conn)1679 gabble_bytestream_factory_new (GabbleConnection *conn)
1680 {
1681 GabbleBytestreamFactory *factory;
1682
1683 g_return_val_if_fail (GABBLE_IS_CONNECTION (conn), NULL);
1684
1685 factory = GABBLE_BYTESTREAM_FACTORY (
1686 g_object_new (GABBLE_TYPE_BYTESTREAM_FACTORY,
1687 "connection", conn,
1688 NULL));
1689
1690 return factory;
1691 }
1692
1693 static void
bytestream_state_changed_cb(GabbleBytestreamIface * bytestream,GabbleBytestreamState state,gpointer user_data)1694 bytestream_state_changed_cb (GabbleBytestreamIface *bytestream,
1695 GabbleBytestreamState state,
1696 gpointer user_data)
1697 {
1698 GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1699 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
1700 self);
1701
1702 if (priv->dispose_has_run)
1703 return;
1704
1705 if (state == GABBLE_BYTESTREAM_STATE_CLOSED)
1706 {
1707 remove_bytestream (self, bytestream);
1708 }
1709 }
1710
1711 gchar *
gabble_bytestream_factory_generate_stream_id(void)1712 gabble_bytestream_factory_generate_stream_id (void)
1713 {
1714 gchar *stream_id;
1715
1716 stream_id = g_strdup_printf ("%lu-%u", (unsigned long) time (NULL),
1717 g_random_int ());
1718
1719 return stream_id;
1720 }
1721
1722 GabbleBytestreamIface *
gabble_bytestream_factory_create_from_method(GabbleBytestreamFactory * self,const gchar * stream_method,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,const gchar * self_jid,GabbleBytestreamState state)1723 gabble_bytestream_factory_create_from_method (GabbleBytestreamFactory *self,
1724 const gchar *stream_method,
1725 TpHandle peer_handle,
1726 const gchar *stream_id,
1727 const gchar *stream_init_id,
1728 const gchar *peer_resource,
1729 const gchar *self_jid,
1730 GabbleBytestreamState state)
1731 {
1732 GabbleBytestreamIface *bytestream = NULL;
1733
1734 if (!tp_strdiff (stream_method, NS_IBB))
1735 {
1736 bytestream = GABBLE_BYTESTREAM_IFACE (
1737 gabble_bytestream_factory_create_ibb (self, peer_handle,
1738 stream_id, stream_init_id, peer_resource, state));
1739 }
1740 else if (!tp_strdiff (stream_method, NS_BYTESTREAMS))
1741 {
1742 bytestream = GABBLE_BYTESTREAM_IFACE (
1743 gabble_bytestream_factory_create_socks5 (self, peer_handle,
1744 stream_id, stream_init_id, peer_resource, self_jid, state));
1745 }
1746
1747 return bytestream;
1748 }
1749
1750 static GabbleBytestreamIBB *
gabble_bytestream_factory_create_ibb(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,GabbleBytestreamState state)1751 gabble_bytestream_factory_create_ibb (GabbleBytestreamFactory *self,
1752 TpHandle peer_handle,
1753 const gchar *stream_id,
1754 const gchar *stream_init_id,
1755 const gchar *peer_resource,
1756 GabbleBytestreamState state)
1757 {
1758 GabbleBytestreamFactoryPrivate *priv;
1759 GabbleBytestreamIBB *ibb;
1760 BytestreamIdentifier *id;
1761
1762 g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1763 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1764
1765 ibb = g_object_new (GABBLE_TYPE_BYTESTREAM_IBB,
1766 "connection", priv->conn,
1767 "peer-handle", peer_handle,
1768 "stream-id", stream_id,
1769 "state", state,
1770 "stream-init-id", stream_init_id,
1771 "peer-resource", peer_resource,
1772 NULL);
1773
1774 gabble_signal_connect_weak (ibb, "state-changed",
1775 G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1776
1777 id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (ibb));
1778 DEBUG ("add IBB bytestream <%s> from <%s>", id->stream, id->jid);
1779 g_hash_table_insert (priv->ibb_bytestreams, id, ibb);
1780
1781 return ibb;
1782 }
1783
1784 GabbleBytestreamMuc *
gabble_bytestream_factory_create_muc(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,GabbleBytestreamState state)1785 gabble_bytestream_factory_create_muc (GabbleBytestreamFactory *self,
1786 TpHandle peer_handle,
1787 const gchar *stream_id,
1788 GabbleBytestreamState state)
1789 {
1790 GabbleBytestreamFactoryPrivate *priv;
1791 GabbleBytestreamMuc *bytestream;
1792 BytestreamIdentifier *id;
1793
1794 g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1795 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1796
1797 bytestream = g_object_new (GABBLE_TYPE_BYTESTREAM_MUC,
1798 "connection", priv->conn,
1799 "peer-handle", peer_handle,
1800 "stream-id", stream_id,
1801 "state", state,
1802 NULL);
1803
1804 gabble_signal_connect_weak (bytestream, "state-changed",
1805 G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1806
1807 id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (bytestream));
1808 DEBUG ("add muc bytestream <%s> from <%s>", id->stream, id->jid);
1809 g_hash_table_insert (priv->muc_bytestreams, id, bytestream);
1810
1811 return bytestream;
1812 }
1813
1814 static GabbleBytestreamSocks5 *
gabble_bytestream_factory_create_socks5(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,const gchar * self_jid,GabbleBytestreamState state)1815 gabble_bytestream_factory_create_socks5 (GabbleBytestreamFactory *self,
1816 TpHandle peer_handle,
1817 const gchar *stream_id,
1818 const gchar *stream_init_id,
1819 const gchar *peer_resource,
1820 const gchar *self_jid,
1821 GabbleBytestreamState state)
1822 {
1823 GabbleBytestreamFactoryPrivate *priv;
1824 GabbleBytestreamSocks5 *socks5;
1825 BytestreamIdentifier *id;
1826
1827 g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1828 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1829
1830 socks5 = g_object_new (GABBLE_TYPE_BYTESTREAM_SOCKS5,
1831 "connection", priv->conn,
1832 "peer-handle", peer_handle,
1833 "stream-id", stream_id,
1834 "state", state,
1835 "stream-init-id", stream_init_id,
1836 "peer-resource", peer_resource,
1837 "self-jid", self_jid,
1838 NULL);
1839
1840 gabble_signal_connect_weak (socks5, "state-changed",
1841 G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1842
1843 id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (socks5));
1844 DEBUG ("add SOCKS5 bytestream <%s> from <%s>", id->stream, id->jid);
1845 g_hash_table_insert (priv->socks5_bytestreams, id, socks5);
1846
1847 return socks5;
1848 }
1849
1850 static GabbleBytestreamMultiple *
gabble_bytestream_factory_create_multiple(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,const gchar * self_jid,GabbleBytestreamState state)1851 gabble_bytestream_factory_create_multiple (GabbleBytestreamFactory *self,
1852 TpHandle peer_handle,
1853 const gchar *stream_id,
1854 const gchar *stream_init_id,
1855 const gchar *peer_resource,
1856 const gchar *self_jid,
1857 GabbleBytestreamState state)
1858 {
1859 GabbleBytestreamFactoryPrivate *priv;
1860 GabbleBytestreamMultiple *multiple;
1861 BytestreamIdentifier *id;
1862
1863 g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1864 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1865
1866 multiple = g_object_new (GABBLE_TYPE_BYTESTREAM_MULTIPLE,
1867 "connection", priv->conn,
1868 "peer-handle", peer_handle,
1869 "stream-id", stream_id,
1870 "state", state,
1871 "stream-init-id", stream_init_id,
1872 "peer-resource", peer_resource,
1873 "factory", self,
1874 "self-jid", self_jid,
1875 NULL);
1876
1877 gabble_signal_connect_weak (multiple, "state-changed",
1878 G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1879
1880 id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (multiple));
1881 DEBUG ("add multi bytestream <%s> from <%s>", id->stream, id->jid);
1882 g_hash_table_insert (priv->multiple_bytestreams, id, multiple);
1883
1884 return multiple;
1885 }
1886
1887 static GabbleBytestreamIface *
streaminit_get_multiple_bytestream(GabbleBytestreamFactory * self,WockyStanza * reply_msg,WockyNode * si,const gchar * stream_id,TpHandle peer_handle,const gchar * peer_resource,const gchar * self_jid)1888 streaminit_get_multiple_bytestream (GabbleBytestreamFactory *self,
1889 WockyStanza *reply_msg,
1890 WockyNode *si,
1891 const gchar *stream_id,
1892 TpHandle peer_handle,
1893 const gchar *peer_resource,
1894 const gchar *self_jid)
1895 {
1896 /* If the other client supports si-multiple we have directly a list of
1897 * supported methods inside <value/> tags */
1898 WockyNode *si_multi;
1899 const gchar *stream_method;
1900 GabbleBytestreamMultiple *bytestream = NULL;
1901 WockyNode *value;
1902 WockyNodeIter i;
1903
1904 si_multi = wocky_node_get_child_ns (si, "si-multiple",
1905 NS_SI_MULTIPLE);
1906 if (si_multi == NULL)
1907 return NULL;
1908
1909 bytestream = gabble_bytestream_factory_create_multiple (self, peer_handle,
1910 stream_id, NULL, peer_resource, self_jid,
1911 GABBLE_BYTESTREAM_STATE_INITIATING);
1912
1913 wocky_node_iter_init (&i, si_multi, "value", NULL);
1914 while (wocky_node_iter_next (&i, &value))
1915 {
1916 stream_method = value->content;
1917 if (!stream_method_supported (stream_method))
1918 {
1919 DEBUG ("got a si-multiple reply with an unsupported "
1920 "stream method: %s", stream_method);
1921 continue;
1922 }
1923
1924 gabble_bytestream_multiple_add_stream_method (bytestream, stream_method);
1925 }
1926
1927 return GABBLE_BYTESTREAM_IFACE (bytestream);
1928 }
1929
1930 static GabbleBytestreamIface *
streaminit_get_bytestream(GabbleBytestreamFactory * self,WockyStanza * reply_msg,WockyNode * si,const gchar * stream_id,TpHandle peer_handle,const gchar * peer_resource,const gchar * self_jid)1931 streaminit_get_bytestream (GabbleBytestreamFactory *self,
1932 WockyStanza *reply_msg,
1933 WockyNode *si,
1934 const gchar *stream_id,
1935 TpHandle peer_handle,
1936 const gchar *peer_resource,
1937 const gchar *self_jid)
1938 {
1939 WockyNode *feature, *x, *value, *field;
1940 GabbleBytestreamIface *bytestream = NULL;
1941 const gchar *stream_method;
1942 WockyNodeIter i;
1943
1944 feature = wocky_node_get_child_ns (si, "feature",
1945 NS_FEATURENEG);
1946 if (feature == NULL)
1947 {
1948 STANZA_DEBUG (reply_msg, "got a SI reply without a feature field");
1949 return NULL;
1950 }
1951
1952 x = wocky_node_get_child_ns (feature, "x", NS_X_DATA);
1953 if (x == NULL)
1954 {
1955 STANZA_DEBUG (reply_msg, "got a SI reply without a x field");
1956 return NULL;
1957 }
1958
1959 wocky_node_iter_init (&i, x, NULL, NULL);
1960 while (wocky_node_iter_next (&i, &field))
1961 {
1962 if (tp_strdiff (wocky_node_get_attribute (field, "var"),
1963 "stream-method"))
1964 /* some future field, ignore it */
1965 continue;
1966
1967 value = wocky_node_get_child (field, "value");
1968 if (value == NULL)
1969 {
1970 STANZA_DEBUG (reply_msg, "SI reply's stream-method field "
1971 "doesn't contain stream-method value");
1972 return NULL;
1973 }
1974
1975 stream_method = value->content;
1976 bytestream = gabble_bytestream_factory_create_from_method (self,
1977 stream_method, peer_handle, stream_id, NULL, peer_resource, self_jid,
1978 GABBLE_BYTESTREAM_STATE_INITIATING);
1979
1980 /* no need to parse the rest of the fields, we've found the one we
1981 * wanted */
1982 break;
1983 }
1984
1985 return bytestream;
1986 }
1987
1988 struct _streaminit_reply_cb_data
1989 {
1990 GabbleBytestreamFactory *self;
1991 gchar *stream_id;
1992 GabbleBytestreamFactoryNegotiateReplyFunc func;
1993 TpWeakRef *weak_object;
1994 };
1995
1996 /* Called when we receive the reply of a SI request */
1997 static void
streaminit_reply_cb(GObject * source,GAsyncResult * result,gpointer user_data)1998 streaminit_reply_cb (
1999 GObject *source,
2000 GAsyncResult *result,
2001 gpointer user_data)
2002 {
2003 GabbleConnection *conn = GABBLE_CONNECTION (source);
2004 struct _streaminit_reply_cb_data *data = user_data;
2005 GabbleBytestreamFactory *self = data->self;
2006 GabbleBytestreamFactoryPrivate *priv = self->priv;
2007 GabbleBytestreamIface *bytestream = NULL;
2008 gchar *peer_resource = NULL;
2009 WockyNode *si;
2010 const gchar *from;
2011 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
2012 (TpBaseConnection *) conn, TP_HANDLE_TYPE_CONTACT);
2013 TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
2014 (TpBaseConnection *) conn, TP_HANDLE_TYPE_ROOM);
2015 TpHandle peer_handle = 0;
2016 TpHandle room_handle;
2017 gboolean success = FALSE;
2018 gchar *self_jid = NULL;
2019 GObject *object = tp_weak_ref_dup_object (data->weak_object);
2020 WockyStanza *reply_msg = NULL;
2021
2022 if (object == NULL)
2023 {
2024 DEBUG ("Object which requested the bytestream was disposed. Ignoring");
2025 goto END;
2026 }
2027
2028 if (!conn_util_send_iq_finish (conn, result, &reply_msg, NULL))
2029 {
2030 DEBUG ("stream %s declined", data->stream_id);
2031 goto END;
2032 }
2033
2034 /* stream accepted */
2035
2036 from = wocky_node_get_attribute (
2037 wocky_stanza_get_top_node (reply_msg), "from");
2038 if (from == NULL)
2039 {
2040 STANZA_DEBUG (reply_msg, "got a message without a from field");
2041 goto END;
2042 }
2043
2044 peer_handle = tp_handle_ensure (contact_repo, from, NULL, NULL);
2045 room_handle = gabble_get_room_handle_from_jid (room_repo, from);
2046
2047 if (room_handle == 0)
2048 {
2049 /* jid is not a muc jid so we need contact's resource */
2050
2051 if (!wocky_decode_jid (from, NULL, NULL, &peer_resource))
2052 {
2053 DEBUG ("Got an SI request with a bad JID");
2054 goto END;
2055 }
2056
2057 if (peer_resource == NULL)
2058 {
2059 DEBUG ("Got an SI request from a JID without a resource; ignoring");
2060 goto END;
2061 }
2062
2063 /* we are not in a muc so our own jid is the one in the 'to' attribute */
2064 self_jid = g_strdup (wocky_node_get_attribute (
2065 wocky_stanza_get_top_node (reply_msg), "to"));
2066 }
2067 else
2068 {
2069 /* we are in a muc so need to get our muc jid */
2070 GabbleMucChannel *muc;
2071
2072 muc = gabble_muc_factory_find_text_channel (priv->conn->muc_factory,
2073 room_handle);
2074
2075 if (muc == NULL)
2076 {
2077 DEBUG ("Got an IQ from a muc in which we are not. Ignoring");
2078 goto END;
2079 }
2080
2081 g_object_get (muc, "self-jid", &self_jid, NULL);
2082 }
2083
2084 si = wocky_node_get_child_ns (
2085 wocky_stanza_get_top_node (reply_msg), "si", NS_SI);
2086 if (si == NULL)
2087 {
2088 STANZA_DEBUG (reply_msg, "got a SI reply without a si field");
2089 goto END;
2090 }
2091
2092 /* Try to build a multiple bytestream with fallback methods */
2093 bytestream = streaminit_get_multiple_bytestream (self, reply_msg, si,
2094 data->stream_id, peer_handle, peer_resource, self_jid);
2095 /* FIXME: check if there is at least one stream method */
2096
2097 if (bytestream == NULL)
2098 /* The other client doesn't suppport si-multiple, use the normal XEP-095
2099 * method */
2100 bytestream = streaminit_get_bytestream (self, reply_msg, si,
2101 data->stream_id, peer_handle, peer_resource, self_jid);
2102
2103 if (bytestream == NULL)
2104 goto END;
2105
2106 DEBUG ("stream %s accepted", data->stream_id);
2107
2108 /* Let's start the initiation of the stream */
2109 if (gabble_bytestream_iface_initiate (bytestream))
2110 {
2111 /* FIXME: we should really only "succeed" when our <open> succeeds.
2112 * It only really matters from the point of view of the data->func */
2113 success = TRUE;
2114 }
2115
2116 END:
2117 if (!success && bytestream != NULL)
2118 {
2119 remove_bytestream (self, bytestream);
2120 bytestream = NULL;
2121 }
2122
2123 /* user callback */
2124 if (object != NULL)
2125 {
2126 data->func (bytestream, reply_msg,
2127 object, tp_weak_ref_get_user_data (data->weak_object));
2128 g_clear_object (&object);
2129 }
2130
2131 if (peer_resource != NULL)
2132 g_free (peer_resource);
2133
2134 g_clear_object (&reply_msg);
2135 g_clear_object (&data->self);
2136 g_free (self_jid);
2137 g_free (data->stream_id);
2138 tp_weak_ref_destroy (data->weak_object);
2139 g_slice_free (struct _streaminit_reply_cb_data, data);
2140 }
2141
2142 /*
2143 * gabble_bytestream_factory_negotiate_stream:
2144 *
2145 * @msg: the SI negotiation IQ (created using
2146 * gabble_bytestream_factory_make_stream_init_iq)
2147 * @stream_id: the stream identifier
2148 * @func: the callback to call when we receive the answser of the request
2149 * @user_data: user data to pass to the callback
2150 * @object: the handler will follow the lifetime of this object,
2151 * which means that if the object is destroyed the callback will not be invoked.
2152 *
2153 * Send a Stream Initiation (XEP-0095) request.
2154 */
2155 void
gabble_bytestream_factory_negotiate_stream(GabbleBytestreamFactory * self,WockyStanza * msg,const gchar * stream_id,GabbleBytestreamFactoryNegotiateReplyFunc func,gpointer user_data,GObject * object)2156 gabble_bytestream_factory_negotiate_stream (GabbleBytestreamFactory *self,
2157 WockyStanza *msg,
2158 const gchar *stream_id,
2159 GabbleBytestreamFactoryNegotiateReplyFunc func,
2160 gpointer user_data,
2161 GObject *object)
2162 {
2163 GabbleBytestreamFactoryPrivate *priv;
2164 struct _streaminit_reply_cb_data *data;
2165
2166 g_assert (GABBLE_IS_BYTESTREAM_FACTORY (self));
2167 g_assert (stream_id != NULL);
2168 g_assert (func != NULL);
2169 g_assert (object != NULL);
2170
2171 priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
2172
2173 data = g_slice_new (struct _streaminit_reply_cb_data);
2174 data->self = g_object_ref (self);
2175 data->stream_id = g_strdup (stream_id);
2176 data->func = func;
2177 data->weak_object = tp_weak_ref_new (object, user_data, NULL);
2178
2179 conn_util_send_iq_async (priv->conn, msg, NULL,
2180 streaminit_reply_cb, data);
2181 }
2182
2183 /*
2184 * gabble_bytestream_factory_make_accept_iq
2185 *
2186 * @full_jid: the full jid of the stream initiator
2187 * @stream_init_id: the id of the SI request
2188 * @stream_method: the stream method chosen (one of them proposed
2189 * in the SI request)
2190 *
2191 * Create an IQ stanza accepting a stream in response to
2192 * a SI request (XEP-0095).
2193 *
2194 */
2195 WockyStanza *
gabble_bytestream_factory_make_accept_iq(const gchar * full_jid,const gchar * stream_init_id,const gchar * stream_method)2196 gabble_bytestream_factory_make_accept_iq (const gchar *full_jid,
2197 const gchar *stream_init_id,
2198 const gchar *stream_method)
2199 {
2200 return wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_RESULT,
2201 NULL, full_jid,
2202 '@', "id", stream_init_id,
2203 '(', "si",
2204 ':', NS_SI,
2205 '(', "feature",
2206 ':', NS_FEATURENEG,
2207 '(', "x",
2208 ':', NS_X_DATA,
2209 '@', "type", "submit",
2210 '(', "field",
2211 '@', "var", "stream-method",
2212 '(', "value", '$', stream_method, ')',
2213 ')',
2214 ')',
2215 ')',
2216 ')', NULL);
2217 }
2218
2219 /*
2220 * gabble_bytestream_factory_make_multi_accept_iq
2221 *
2222 * @full_jid: the full jid of the stream initiator
2223 * @stream_init_id: the id of the SI request
2224 * @stream_methods: a list of the accepted string methods
2225 *
2226 * Create an IQ stanza accepting a stream in response to
2227 * a si-multiple SI request.
2228 *
2229 */
2230 WockyStanza *
gabble_bytestream_factory_make_multi_accept_iq(const gchar * full_jid,const gchar * stream_init_id,GList * stream_methods)2231 gabble_bytestream_factory_make_multi_accept_iq (const gchar *full_jid,
2232 const gchar *stream_init_id,
2233 GList *stream_methods)
2234 {
2235 WockyStanza *msg;
2236 WockyNode *multi_node;
2237 GList *l;
2238
2239 msg = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_RESULT,
2240 NULL, full_jid,
2241 '@', "id", stream_init_id,
2242 '(', "si",
2243 ':', NS_SI,
2244 '(', "si-multiple",
2245 ':', NS_SI_MULTIPLE,
2246 '*', &multi_node,
2247 ')',
2248 ')', NULL);
2249
2250 for (l = stream_methods; l != NULL; l = l->next)
2251 {
2252 wocky_node_add_child_with_content (multi_node, "value", l->data);
2253 }
2254
2255 return msg;
2256 }
2257
2258 GSList *
gabble_bytestream_factory_get_socks5_proxies(GabbleBytestreamFactory * self)2259 gabble_bytestream_factory_get_socks5_proxies (GabbleBytestreamFactory *self)
2260 {
2261 GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
2262 self);
2263
2264 return g_slist_concat (g_slist_copy (priv->socks5_proxies),
2265 g_slist_copy (priv->socks5_fallback_proxies));
2266 }
2267