1 /*
2 * gibber-bytestream-oob.c - Source for GibberBytestreamOOB
3 * Copyright (C) 2007 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 "gibber-bytestream-oob.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include <glib.h>
30
31 #include <wocky/wocky.h>
32
33 #include "gibber-sockets.h"
34 #include "gibber-bytestream-iface.h"
35 #include "gibber-linklocal-transport.h"
36 #include "gibber-util.h"
37 #include "gibber-transport.h"
38 #include "gibber-fd-transport.h"
39 #include "gibber-listener.h"
40
41 #define DEBUG_FLAG DEBUG_BYTESTREAM
42 #include "gibber-debug.h"
43
44 #include "gibber-signals-marshal.h"
45
46 static void
47 bytestream_iface_init (gpointer g_iface, gpointer iface_data);
48
49 G_DEFINE_TYPE_WITH_CODE (GibberBytestreamOOB, gibber_bytestream_oob,
50 G_TYPE_OBJECT,
51 G_IMPLEMENT_INTERFACE (GIBBER_TYPE_BYTESTREAM_IFACE,
52 bytestream_iface_init));
53
54 /* properties */
55 enum
56 {
57 PROP_PORTER = 1,
58 PROP_CONTACT,
59 PROP_SELF_ID,
60 PROP_PEER_ID,
61 PROP_STREAM_ID,
62 PROP_STREAM_INIT_IQ,
63 PROP_STATE,
64 PROP_HOST,
65 PROP_PROTOCOL,
66 LAST_PROPERTY
67 };
68
69 typedef struct _GibberBytestreamIBBPrivate GibberBytestreamOOBPrivate;
70 struct _GibberBytestreamIBBPrivate
71 {
72 WockyPorter *porter;
73 WockyContact *contact;
74 gchar *self_id;
75 gchar *peer_id;
76 gchar *stream_id;
77 WockyStanza *stream_init_iq;
78 /* ID of the OOB opening stanza. We'll reply to
79 * it when we the bytestream is closed */
80 gchar *stream_open_id;
81 guint stanza_received_id;
82 GibberBytestreamState state;
83 gchar *host;
84 gchar *url;
85
86 /* Are we the recipient of this bytestream?
87 * If not we are the sender */
88 gboolean recipient;
89 GibberTransport *transport;
90 gboolean write_blocked;
91 gboolean read_blocked;
92 GibberListener *listener;
93
94 GibberBytestreamOOBCheckAddrFunc check_addr_func;
95 gpointer check_addr_func_data;
96
97 gboolean dispose_has_run;
98 };
99
100 #define GIBBER_BYTESTREAM_OOB_GET_PRIVATE(obj) \
101 ((GibberBytestreamOOBPrivate *) (GibberBytestreamOOB *) obj->priv)
102
103 static void gibber_bytestream_oob_do_close (GibberBytestreamOOB *self,
104 GError *error, gboolean can_wait);
105 static void bytestream_closed (GibberBytestreamOOB *self);
106
107 static void
gibber_bytestream_oob_init(GibberBytestreamOOB * self)108 gibber_bytestream_oob_init (GibberBytestreamOOB *self)
109 {
110 GibberBytestreamOOBPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
111 GIBBER_TYPE_BYTESTREAM_OOB, GibberBytestreamOOBPrivate);
112
113 self->priv = priv;
114 priv->dispose_has_run = FALSE;
115 }
116
117 static WockyStanza *
make_iq_oob_sucess_response(const gchar * from,const gchar * to,const gchar * id)118 make_iq_oob_sucess_response (const gchar *from,
119 const gchar *to,
120 const gchar *id)
121 {
122 return wocky_stanza_build (
123 WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_RESULT,
124 from, to,
125 WOCKY_NODE_ATTRIBUTE, "id", id,
126 NULL);
127 }
128
129 static void
transport_handler(GibberTransport * transport,GibberBuffer * data,gpointer user_data)130 transport_handler (GibberTransport *transport,
131 GibberBuffer *data,
132 gpointer user_data)
133 {
134 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (user_data);
135 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
136 GString *buffer;
137
138 buffer = g_string_new_len ((const gchar *) data->data, data->length);
139
140 g_signal_emit_by_name (G_OBJECT (self), "data-received", priv->peer_id,
141 buffer);
142
143 g_string_free (buffer, TRUE);
144 }
145
146 static void
transport_connected_cb(GibberTransport * transport,GibberBytestreamOOB * self)147 transport_connected_cb (GibberTransport *transport,
148 GibberBytestreamOOB *self)
149 {
150 DEBUG ("transport connected. Bytestream is now open");
151 g_object_set (self, "state", GIBBER_BYTESTREAM_STATE_OPEN,
152 NULL);
153 }
154
155 static void
transport_disconnected_cb(GibberTransport * transport,GibberBytestreamOOB * self)156 transport_disconnected_cb (GibberTransport *transport,
157 GibberBytestreamOOB *self)
158 {
159 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
160 if (priv->state == GIBBER_BYTESTREAM_STATE_CLOSED)
161 return;
162
163 DEBUG ("transport disconnected. close the bytestream");
164
165 if (priv->state == GIBBER_BYTESTREAM_STATE_ACCEPTED)
166 {
167 /* Connection to host failed */
168 GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_ITEM_NOT_FOUND,
169 "connection failed" };
170
171 gibber_bytestream_iface_close (GIBBER_BYTESTREAM_IFACE (self), &e);
172 }
173 else
174 {
175 gibber_bytestream_iface_close (GIBBER_BYTESTREAM_IFACE (self), NULL);
176 }
177 }
178
179 static void
change_write_blocked_state(GibberBytestreamOOB * self,gboolean blocked)180 change_write_blocked_state (GibberBytestreamOOB *self,
181 gboolean blocked)
182 {
183 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
184
185 if (priv->write_blocked == blocked)
186 return;
187
188 priv->write_blocked = blocked;
189 g_signal_emit_by_name (self, "write-blocked", blocked);
190 }
191
192 static void
transport_buffer_empty_cb(GibberTransport * transport,GibberBytestreamOOB * self)193 transport_buffer_empty_cb (GibberTransport *transport,
194 GibberBytestreamOOB *self)
195 {
196 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
197
198 if (priv->state == GIBBER_BYTESTREAM_STATE_CLOSING)
199 {
200 DEBUG ("buffer is now empty. Bytestream can be closed");
201 bytestream_closed (self);
202 }
203 else if (priv->write_blocked)
204 {
205 DEBUG ("buffer is empty, unblock write to the bytestream");
206 change_write_blocked_state (self, FALSE);
207 }
208 }
209
210 static void
set_transport(GibberBytestreamOOB * self,GibberTransport * transport)211 set_transport (GibberBytestreamOOB *self,
212 GibberTransport *transport)
213 {
214 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
215
216 g_assert (priv->transport == NULL);
217
218 priv->transport = g_object_ref (transport);
219 gibber_transport_set_handler (transport, transport_handler, self);
220
221 /* The transport will already be connected if it is created from
222 * GibberListener. In this case, set the bytestream to open, otherwise
223 * it will be done in transport_connected_cb. */
224 if (gibber_transport_get_state (transport) == GIBBER_TRANSPORT_CONNECTED)
225 {
226 g_object_set (self, "state", GIBBER_BYTESTREAM_STATE_OPEN,
227 NULL);
228 }
229
230 g_signal_connect (transport, "connected",
231 G_CALLBACK (transport_connected_cb), self);
232 g_signal_connect (transport, "disconnected",
233 G_CALLBACK (transport_disconnected_cb), self);
234 g_signal_connect (transport, "buffer-empty",
235 G_CALLBACK (transport_buffer_empty_cb), self);
236 }
237
238 static void
connect_to_url(GibberBytestreamOOB * self)239 connect_to_url (GibberBytestreamOOB *self)
240 {
241 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
242 GibberLLTransport *ll_transport;
243 GSocketConnection *conn;
244 GSocketAddress *socket_address = NULL;
245 gchar **tokens;
246 union {
247 struct sockaddr_storage storage;
248 struct sockaddr_in in;
249 } addr;
250 const gchar *port;
251 gint portnum = 0;
252 const gchar *url;
253 GError *error = NULL;
254
255 /* TODO: if we want to support IPv6 literals, we have to remove
256 * [] around the address */
257
258 url = priv->url + strlen ("x-tcp://");
259 tokens = g_strsplit (url, ":", 2);
260 port = tokens[1];
261
262 if (port != NULL)
263 portnum = atoi (port);
264
265 if (portnum <= 0 || portnum > G_MAXUINT16)
266 {
267 /* I'm too lazy to create more specific errors for this as it should
268 * never happen while using salut anyway.. */
269 GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_NOT_ACCEPTABLE,
270 "Invalid port number" };
271 DEBUG ("Invalid port number: %s", port);
272 gibber_bytestream_iface_close (GIBBER_BYTESTREAM_IFACE (self), &e);
273 goto out;
274 }
275
276 conn = wocky_meta_porter_borrow_connection (WOCKY_META_PORTER (priv->porter),
277 WOCKY_LL_CONTACT (priv->contact));
278
279 if (conn != NULL)
280 socket_address = g_socket_connection_get_remote_address (conn, NULL);
281
282 if (conn == NULL || socket_address == NULL)
283 {
284 /* I'm too lazy to create more specific errors for this as it should
285 * never happen while using salut anyway.. */
286 GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_ITEM_NOT_FOUND,
287 "Unsable get socket address for the control connection" };
288 DEBUG ("Could not get socket address for the control connection" );
289 gibber_bytestream_iface_close (GIBBER_BYTESTREAM_IFACE (self), &e);
290 goto out;
291 }
292
293 if (!g_socket_address_to_native (G_SOCKET_ADDRESS (socket_address), &(addr.storage),
294 sizeof (addr.storage), &error))
295 {
296 GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_ITEM_NOT_FOUND,
297 "Failed to turn socket address into bytes" };
298 DEBUG ("Failed to get native socket address: %s", error->message);
299 gibber_bytestream_iface_close (GIBBER_BYTESTREAM_IFACE (self), &e);
300 g_clear_error (&error);
301 goto out;
302 }
303
304 /* FIXME: this is a hack until we get the normalization of v6-in-v4
305 * addresses in GLib. See bgo#646082 */
306 gibber_normalize_address (&(addr.storage));
307
308 addr.in.sin_port = g_htons ((guint16) portnum);
309
310 ll_transport = gibber_ll_transport_new ();
311 set_transport (self, GIBBER_TRANSPORT (ll_transport));
312 gibber_ll_transport_open_sockaddr (ll_transport, &addr.storage, NULL);
313 g_object_unref (ll_transport);
314
315 out:
316 if (socket_address != NULL)
317 g_object_unref (socket_address);
318
319 g_strfreev (tokens);
320 }
321
322 static void
opened_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)323 opened_cb (GObject *source_object,
324 GAsyncResult *result,
325 gpointer user_data)
326 {
327 WockyMetaPorter *porter = WOCKY_META_PORTER (source_object);
328 GibberBytestreamOOB *self = user_data;
329 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
330 GError *error = NULL;
331
332 if (!wocky_meta_porter_open_finish (porter, result, &error))
333 {
334 DEBUG ("failed to open connection to contact");
335 g_clear_error (&error);
336 }
337 else
338 {
339 connect_to_url (self);
340 }
341
342 g_free (priv->url);
343
344 wocky_meta_porter_unhold (porter, priv->contact);
345 }
346
347 static gboolean
parse_oob_init_iq(GibberBytestreamOOB * self,WockyStanza * stanza)348 parse_oob_init_iq (GibberBytestreamOOB *self,
349 WockyStanza *stanza)
350 {
351 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
352 WockyNode *query_node, *url_node;
353 WockyStanzaType type;
354 WockyStanzaSubType sub_type;
355 const gchar *stream_id, *url;
356 WockyNode *node = wocky_stanza_get_top_node (stanza);
357
358 wocky_stanza_get_type_info (stanza, &type, &sub_type);
359
360 if (type != WOCKY_STANZA_TYPE_IQ ||
361 sub_type != WOCKY_STANZA_SUB_TYPE_SET)
362 return FALSE;
363
364 query_node = wocky_node_get_child_ns (node, "query",
365 WOCKY_XMPP_NS_IQ_OOB);
366 if (query_node == NULL)
367 return FALSE;
368
369 stream_id = wocky_node_get_attribute (query_node, "sid");
370 if (stream_id == NULL || strcmp (stream_id, priv->stream_id) != 0)
371 return FALSE;
372
373 url_node = wocky_node_get_child (query_node, "url");
374 if (url_node == NULL)
375 return FALSE;
376 url = url_node->content;
377
378 priv->recipient = TRUE;
379 priv->stream_open_id = g_strdup (wocky_node_get_attribute (
380 node, "id"));
381
382 if (!g_str_has_prefix (url, "x-tcp://"))
383 {
384 GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_ITEM_NOT_FOUND,
385 "URL is not a TCP URL" };
386
387 DEBUG ("URL is not a TCP URL: %s. Close the bytestream", priv->url);
388 gibber_bytestream_iface_close (GIBBER_BYTESTREAM_IFACE (self), &e);
389 return TRUE;
390 }
391
392 priv->url = g_strdup (url);
393
394 wocky_meta_porter_open_async (WOCKY_META_PORTER (priv->porter),
395 WOCKY_LL_CONTACT (priv->contact), NULL, opened_cb, self);
396
397 return TRUE;
398 }
399
400 static gboolean
parse_oob_iq_result(GibberBytestreamOOB * self,WockyStanza * stanza)401 parse_oob_iq_result (GibberBytestreamOOB *self,
402 WockyStanza *stanza)
403 {
404 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
405 WockyStanzaType type;
406 WockyStanzaSubType sub_type;
407 const gchar *id;
408 WockyNode *node = wocky_stanza_get_top_node (stanza);
409
410 if (priv->recipient)
411 /* Only the sender have to wait for the IQ reply */
412 return FALSE;
413
414 wocky_stanza_get_type_info (stanza, &type, &sub_type);
415
416 if (type != WOCKY_STANZA_TYPE_IQ ||
417 sub_type != WOCKY_STANZA_SUB_TYPE_RESULT)
418 return FALSE;
419
420 /* FIXME: we should check if it's the right sender */
421 id = wocky_node_get_attribute (node, "id");
422
423 if (id == NULL || strcmp (id, priv->stream_open_id) != 0)
424 return FALSE;
425
426 DEBUG ("received OOB close stanza - ignoring");
427
428 return TRUE;
429 }
430
431 static gboolean
received_stanza_cb(WockyPorter * porter,WockyStanza * stanza,gpointer user_data)432 received_stanza_cb (WockyPorter *porter,
433 WockyStanza *stanza,
434 gpointer user_data)
435 {
436 GibberBytestreamOOB *self = (GibberBytestreamOOB *) user_data;
437 WockyNode *node = wocky_stanza_get_top_node (stanza);
438 const gchar *from;
439
440 /* discard invalid stanza */
441 from = wocky_node_get_attribute (node, "from");
442 if (from == NULL)
443 {
444 DEBUG ("got a message without a from field");
445 return FALSE;
446 }
447
448 if (parse_oob_init_iq (self, stanza))
449 return TRUE;
450
451 if (parse_oob_iq_result (self, stanza))
452 return TRUE;
453
454 return FALSE;
455 }
456
457 static void
gibber_bytestream_oob_dispose(GObject * object)458 gibber_bytestream_oob_dispose (GObject *object)
459 {
460 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (object);
461 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
462
463 if (priv->dispose_has_run)
464 return;
465
466 priv->dispose_has_run = TRUE;
467
468 if (priv->state != GIBBER_BYTESTREAM_STATE_CLOSED)
469 {
470 if (priv->state == GIBBER_BYTESTREAM_STATE_CLOSING)
471 {
472 bytestream_closed (self);
473 }
474 else
475 {
476 gibber_bytestream_oob_do_close (self, NULL, FALSE);
477 }
478 }
479
480 if (priv->listener != NULL)
481 {
482 g_object_unref (priv->listener);
483 priv->listener = NULL;
484 }
485
486 if (priv->porter != NULL)
487 {
488 wocky_porter_unregister_handler (priv->porter, priv->stanza_received_id);
489 priv->stanza_received_id = 0;
490 g_object_unref (priv->porter);
491 priv->porter = NULL;
492 }
493
494 if (priv->contact != NULL)
495 {
496 g_object_unref (priv->contact);
497 priv->contact = NULL;
498 }
499
500 if (priv->stream_init_iq != NULL)
501 {
502 g_object_unref (priv->stream_init_iq);
503 priv->stream_init_iq = NULL;
504 }
505
506 G_OBJECT_CLASS (gibber_bytestream_oob_parent_class)->dispose (object);
507 }
508
509 static void
gibber_bytestream_oob_finalize(GObject * object)510 gibber_bytestream_oob_finalize (GObject *object)
511 {
512 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (object);
513 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
514
515 g_free (priv->stream_id);
516 g_free (priv->stream_open_id);
517 g_free (priv->host);
518 g_free (priv->self_id);
519 g_free (priv->peer_id);
520
521 G_OBJECT_CLASS (gibber_bytestream_oob_parent_class)->finalize (object);
522 }
523
524 static void
gibber_bytestream_oob_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)525 gibber_bytestream_oob_get_property (GObject *object,
526 guint property_id,
527 GValue *value,
528 GParamSpec *pspec)
529 {
530 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (object);
531 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
532
533 switch (property_id)
534 {
535 case PROP_PORTER:
536 g_value_set_object (value, priv->porter);
537 break;
538 case PROP_CONTACT:
539 g_value_set_object (value, priv->contact);
540 break;
541 case PROP_SELF_ID:
542 g_value_set_string (value, priv->self_id);
543 break;
544 case PROP_PEER_ID:
545 g_value_set_string (value, priv->peer_id);
546 break;
547 case PROP_STREAM_ID:
548 g_value_set_string (value, priv->stream_id);
549 break;
550 case PROP_STREAM_INIT_IQ:
551 g_value_set_object (value, priv->stream_init_iq);
552 break;
553 case PROP_STATE:
554 g_value_set_uint (value, priv->state);
555 break;
556 case PROP_HOST:
557 g_value_set_string (value, priv->host);
558 break;
559 case PROP_PROTOCOL:
560 g_value_set_string (value, WOCKY_XMPP_NS_IQ_OOB);
561 break;
562 default:
563 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
564 break;
565 }
566 }
567
568 static void
make_porter_connections(GibberBytestreamOOB * self)569 make_porter_connections (GibberBytestreamOOB *self)
570 {
571 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
572 gchar *jid;
573
574 jid = wocky_contact_dup_jid (priv->contact);
575
576 priv->stanza_received_id = wocky_porter_register_handler_from (priv->porter,
577 WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_TYPE_NONE, jid,
578 WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, received_stanza_cb, self, NULL);
579
580 g_free (jid);
581 }
582
583 static void
gibber_bytestream_oob_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)584 gibber_bytestream_oob_set_property (GObject *object,
585 guint property_id,
586 const GValue *value,
587 GParamSpec *pspec)
588 {
589 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (object);
590 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
591
592 switch (property_id)
593 {
594 case PROP_PORTER:
595 priv->porter = g_value_dup_object (value);
596 break;
597 case PROP_CONTACT:
598 priv->contact = g_value_dup_object (value);
599 break;
600 case PROP_SELF_ID:
601 g_free (priv->self_id);
602 priv->self_id = g_value_dup_string (value);
603 break;
604 case PROP_PEER_ID:
605 g_free (priv->peer_id);
606 priv->peer_id = g_value_dup_string (value);
607 break;
608 case PROP_STREAM_ID:
609 g_free (priv->stream_id);
610 priv->stream_id = g_value_dup_string (value);
611 break;
612 case PROP_STREAM_INIT_IQ:
613 priv->stream_init_iq = g_value_dup_object (value);
614 break;
615 case PROP_STATE:
616 if (priv->state != g_value_get_uint (value))
617 {
618 priv->state = g_value_get_uint (value);
619 g_signal_emit_by_name (object, "state-changed", priv->state);
620 }
621 break;
622 case PROP_HOST:
623 g_free (priv->host);
624 priv->host = g_value_dup_string (value);
625 break;
626 default:
627 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
628 break;
629 }
630 }
631
632 static GObject *
gibber_bytestream_oob_constructor(GType type,guint n_props,GObjectConstructParam * props)633 gibber_bytestream_oob_constructor (GType type,
634 guint n_props,
635 GObjectConstructParam *props)
636 {
637 GObject *obj;
638 GibberBytestreamOOBPrivate *priv;
639
640 obj = G_OBJECT_CLASS (gibber_bytestream_oob_parent_class)->
641 constructor (type, n_props, props);
642
643 priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (GIBBER_BYTESTREAM_OOB (obj));
644
645 g_assert (priv->self_id != NULL);
646 g_assert (priv->peer_id != NULL);
647 g_assert (priv->stream_id != NULL);
648 g_assert (priv->porter != NULL);
649 g_assert (priv->contact != NULL);
650
651 return obj;
652 }
653
654 static void
gibber_bytestream_oob_constructed(GObject * obj)655 gibber_bytestream_oob_constructed (GObject *obj)
656 {
657 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (obj);
658 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
659
660 if (G_OBJECT_CLASS (gibber_bytestream_oob_parent_class)->constructed != NULL)
661 G_OBJECT_CLASS (gibber_bytestream_oob_parent_class)->constructed (obj);
662
663 if (priv->porter != NULL && priv->contact != NULL)
664 make_porter_connections (self);
665 }
666
667
668 static void
gibber_bytestream_oob_class_init(GibberBytestreamOOBClass * gibber_bytestream_oob_class)669 gibber_bytestream_oob_class_init (
670 GibberBytestreamOOBClass *gibber_bytestream_oob_class)
671 {
672 GObjectClass *object_class = G_OBJECT_CLASS (gibber_bytestream_oob_class);
673 GParamSpec *param_spec;
674
675 g_type_class_add_private (gibber_bytestream_oob_class,
676 sizeof (GibberBytestreamOOBPrivate));
677
678 object_class->dispose = gibber_bytestream_oob_dispose;
679 object_class->finalize = gibber_bytestream_oob_finalize;
680
681 object_class->get_property = gibber_bytestream_oob_get_property;
682 object_class->set_property = gibber_bytestream_oob_set_property;
683 object_class->constructor = gibber_bytestream_oob_constructor;
684 object_class->constructed = gibber_bytestream_oob_constructed;
685
686 g_object_class_override_property (object_class, PROP_SELF_ID,
687 "self-id");
688 g_object_class_override_property (object_class, PROP_PEER_ID,
689 "peer-id");
690 g_object_class_override_property (object_class, PROP_STREAM_ID,
691 "stream-id");
692 g_object_class_override_property (object_class, PROP_STATE,
693 "state");
694 g_object_class_override_property (object_class, PROP_PROTOCOL,
695 "protocol");
696
697 param_spec = g_param_spec_object (
698 "porter",
699 "WockyPorter object",
700 "Wocky porter object used for communication by this "
701 "bytestream if it's a private one",
702 WOCKY_TYPE_PORTER,
703 G_PARAM_CONSTRUCT_ONLY |
704 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
705 g_object_class_install_property (object_class, PROP_PORTER,
706 param_spec);
707
708 param_spec = g_param_spec_object (
709 "contact",
710 "WockyContact object",
711 "Contact object used for communication by this "
712 "bytestream if it's a private one",
713 WOCKY_TYPE_CONTACT,
714 G_PARAM_CONSTRUCT_ONLY |
715 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
716 g_object_class_install_property (object_class, PROP_CONTACT,
717 param_spec);
718
719 param_spec = g_param_spec_object (
720 "stream-init-iq",
721 "stream init IQ",
722 "the iq of the SI request",
723 WOCKY_TYPE_STANZA,
724 G_PARAM_CONSTRUCT_ONLY |
725 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
726 g_object_class_install_property (object_class, PROP_STREAM_INIT_IQ,
727 param_spec);
728
729 param_spec = g_param_spec_string (
730 "host",
731 "host",
732 "The hostname to use in the OOB URL. Literal are not allowed",
733 "",
734 G_PARAM_CONSTRUCT_ONLY |
735 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
736 g_object_class_install_property (object_class, PROP_HOST,
737 param_spec);
738 }
739
740 /*
741 * gibber_bytestream_oob_send
742 *
743 * Implements gibber_bytestream_iface_send on GibberBytestreamIface
744 */
745 static gboolean
gibber_bytestream_oob_send(GibberBytestreamIface * bytestream,guint len,const gchar * str)746 gibber_bytestream_oob_send (GibberBytestreamIface *bytestream,
747 guint len,
748 const gchar *str)
749 {
750 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (bytestream);
751 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
752 GError *error = NULL;
753
754 if (priv->state != GIBBER_BYTESTREAM_STATE_OPEN)
755 {
756 DEBUG ("can't send data through a not open bytestream (state: %d)",
757 priv->state);
758 return FALSE;
759 }
760
761 if (priv->write_blocked)
762 {
763 DEBUG ("sending data while the bytestream was blocked");
764 }
765
766 DEBUG ("send %u bytes through bytestream", len);
767 if (!gibber_transport_send (priv->transport, (const guint8 *) str, len,
768 &error))
769 {
770 DEBUG ("sending failed: %s", error->message);
771 g_error_free (error);
772
773 gibber_bytestream_iface_close (GIBBER_BYTESTREAM_IFACE (self), NULL);
774 return FALSE;
775 }
776
777 if (!gibber_transport_buffer_is_empty (priv->transport))
778 {
779 /* We >don't want to send more data while the buffer isn't empty */
780 DEBUG ("buffer isn't empty. Block write to the bytestream");
781 change_write_blocked_state (self, TRUE);
782 }
783
784 return TRUE;
785 }
786
787 static WockyStanza *
create_si_accept_iq(GibberBytestreamOOB * self)788 create_si_accept_iq (GibberBytestreamOOB *self)
789 {
790 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
791
792 return wocky_stanza_build_iq_result (priv->stream_init_iq,
793 '(', "si",
794 ':', WOCKY_XMPP_NS_SI,
795 '(', "feature",
796 ':', WOCKY_XMPP_NS_FEATURENEG,
797 '(', "x",
798 ':', WOCKY_XMPP_NS_DATA,
799 '@', "type", "submit",
800 '(', "field",
801 '@', "var", "stream-method",
802 '(', "value",
803 '$', WOCKY_XMPP_NS_IQ_OOB,
804 ')',
805 ')',
806 ')',
807 ')',
808 ')', NULL);
809 }
810
811 /*
812 * gibber_bytestream_oob_accept
813 *
814 * Implements gibber_bytestream_iface_accept on GibberBytestreamIface
815 */
816 static void
gibber_bytestream_oob_accept(GibberBytestreamIface * bytestream,GibberBytestreamAugmentSiAcceptReply func,gpointer user_data)817 gibber_bytestream_oob_accept (GibberBytestreamIface *bytestream,
818 GibberBytestreamAugmentSiAcceptReply func,
819 gpointer user_data)
820 {
821 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (bytestream);
822 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
823 WockyStanza *stanza;
824 WockyNode *node;
825 WockyNode *si;
826
827 if (priv->state != GIBBER_BYTESTREAM_STATE_LOCAL_PENDING)
828 {
829 /* The stream was previoulsy or automatically accepted */
830 DEBUG ("stream was already accepted");
831 return;
832 }
833
834 stanza = create_si_accept_iq (self);
835 node = wocky_stanza_get_top_node (stanza);
836 si = wocky_node_get_child_ns (node, "si", WOCKY_XMPP_NS_SI);
837 g_assert (si != NULL);
838
839 if (func != NULL)
840 {
841 /* let the caller add his profile specific data */
842 func (si, user_data);
843 }
844
845 wocky_porter_send (priv->porter, stanza);
846
847 DEBUG ("stream is now accepted");
848 g_object_set (self, "state", GIBBER_BYTESTREAM_STATE_ACCEPTED, NULL);
849 g_object_unref (stanza);
850 }
851
852 static void
bytestream_closed(GibberBytestreamOOB * self)853 bytestream_closed (GibberBytestreamOOB *self)
854 {
855 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
856
857 if (priv->recipient)
858 {
859 WockyStanza *stanza;
860
861 /* As described in the XEP, we send result IQ when we have
862 * finished to use the OOB */
863 stanza = make_iq_oob_sucess_response (priv->self_id,
864 priv->peer_id, priv->stream_open_id);
865 wocky_stanza_set_to_contact (stanza, priv->contact);
866
867 DEBUG ("send OOB close stanza");
868
869 wocky_porter_send (priv->porter, stanza);
870 g_object_unref (stanza);
871 }
872 else
873 {
874 /* We are the sender. Don't have to send anything */
875 }
876
877 if (priv->transport != NULL)
878 {
879 g_signal_handlers_disconnect_matched (priv->transport,
880 G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
881 gibber_transport_disconnect (priv->transport);
882 g_object_unref (priv->transport);
883 priv->transport = NULL;
884 }
885
886 g_object_set (self, "state", GIBBER_BYTESTREAM_STATE_CLOSED, NULL);
887 }
888
889 static void
gibber_bytestream_oob_decline(GibberBytestreamOOB * self,GError * error)890 gibber_bytestream_oob_decline (GibberBytestreamOOB *self,
891 GError *error)
892 {
893 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
894
895 g_return_if_fail (priv->state == GIBBER_BYTESTREAM_STATE_LOCAL_PENDING);
896
897 if (error != NULL
898 && (error->domain == WOCKY_XMPP_ERROR || error->domain == WOCKY_SI_ERROR))
899 {
900 wocky_porter_send_iq_gerror (priv->porter, priv->stream_init_iq, error);
901 }
902 else
903 {
904 wocky_porter_send_iq_error (priv->porter, priv->stream_init_iq,
905 WOCKY_XMPP_ERROR_FORBIDDEN, "Offer declined");
906 }
907 }
908
909 static void
gibber_bytestream_oob_do_close(GibberBytestreamOOB * self,GError * error,gboolean can_wait)910 gibber_bytestream_oob_do_close (GibberBytestreamOOB *self,
911 GError *error,
912 gboolean can_wait)
913 {
914 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
915
916 if (priv->state == GIBBER_BYTESTREAM_STATE_CLOSED)
917 /* bytestream already closed, do nothing */
918 return;
919
920 if (priv->state == GIBBER_BYTESTREAM_STATE_LOCAL_PENDING)
921 {
922 /* Stream was created using SI so we decline the request */
923 gibber_bytestream_oob_decline (self, error);
924 }
925
926 g_object_set (self, "state", GIBBER_BYTESTREAM_STATE_CLOSING, NULL);
927 if (can_wait && priv->transport != NULL &&
928 !gibber_transport_buffer_is_empty (priv->transport))
929 {
930 DEBUG ("Wait transport buffer is empty before close the bytestream");
931 }
932 else
933 {
934 DEBUG ("Transport buffer is empty, we can close the bytestream");
935 bytestream_closed (self);
936 }
937 }
938
939 /*
940 * gibber_bytestream_oob_close
941 *
942 * Implements gibber_bytestream_iface_close on GibberBytestreamIface
943 */
944 static void
gibber_bytestream_oob_close(GibberBytestreamIface * bytestream,GError * error)945 gibber_bytestream_oob_close (GibberBytestreamIface *bytestream,
946 GError *error)
947 {
948 gibber_bytestream_oob_do_close (GIBBER_BYTESTREAM_OOB (bytestream), error,
949 TRUE);
950 }
951
952 static WockyStanza *
make_oob_init_iq(const gchar * from,const gchar * to,const gchar * stream_id,const gchar * url)953 make_oob_init_iq (const gchar *from,
954 const gchar *to,
955 const gchar *stream_id,
956 const gchar *url)
957 {
958 return wocky_stanza_build (
959 WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
960 from, to,
961 '(', "query",
962 ':', WOCKY_XMPP_NS_IQ_OOB,
963 '@', "sid", stream_id,
964 '(', "url",
965 '$', url,
966 ')',
967 ')', NULL);
968 }
969
970 static void
new_connection_cb(GibberListener * listener,GibberTransport * transport,struct sockaddr * addr,guint size,gpointer user_data)971 new_connection_cb (GibberListener *listener,
972 GibberTransport *transport,
973 struct sockaddr *addr,
974 guint size,
975 gpointer user_data)
976 {
977 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (user_data);
978 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
979
980 if (priv->check_addr_func != NULL && !priv->check_addr_func (self, addr,
981 size, priv->check_addr_func_data))
982 {
983 DEBUG ("connection refused by the bytestream user");
984 return;
985 }
986
987 DEBUG("New connection..");
988
989 set_transport (self, transport);
990 }
991
992 /*
993 * gibber_bytestream_oob_initiate
994 *
995 * Implements gibber_bytestream_iface_initiate on GibberBytestreamIface
996 */
997 static gboolean
gibber_bytestream_oob_initiate(GibberBytestreamIface * bytestream)998 gibber_bytestream_oob_initiate (GibberBytestreamIface *bytestream)
999 {
1000 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (bytestream);
1001 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
1002 WockyStanza *stanza;
1003 WockyNode *node;
1004 const gchar *id;
1005 int port;
1006 gchar *url;
1007
1008 if (priv->state != GIBBER_BYTESTREAM_STATE_INITIATING)
1009 {
1010 DEBUG ("bytestream is not is the initiating state (state %d)",
1011 priv->state);
1012 return FALSE;
1013 }
1014 g_assert (priv->host != NULL);
1015
1016 priv->recipient = FALSE;
1017
1018 g_assert (priv->listener == NULL);
1019 priv->listener = gibber_listener_new ();
1020
1021 g_signal_connect (priv->listener, "new-connection",
1022 G_CALLBACK (new_connection_cb), self);
1023
1024 if (!gibber_listener_listen_tcp (priv->listener, 0, NULL))
1025 {
1026 DEBUG ("can't listen for incoming connection");
1027 return FALSE;
1028 }
1029 port = gibber_listener_get_port (priv->listener);
1030
1031 url = g_strdup_printf ("x-tcp://%s:%d", priv->host, port);
1032
1033 stanza = make_oob_init_iq (priv->self_id, priv->peer_id,
1034 priv->stream_id, url);
1035 g_free (url);
1036 wocky_stanza_set_to_contact (stanza, priv->contact);
1037 node = wocky_stanza_get_top_node (stanza);
1038
1039 id = wocky_node_get_attribute (node, "id");
1040 if (id == NULL)
1041 {
1042 /* let the porter generate the IQ id for us */
1043 wocky_porter_send_iq_async (priv->porter, stanza,
1044 NULL, NULL, NULL);
1045
1046 priv->stream_open_id = g_strdup (
1047 wocky_node_get_attribute (node, "id"));
1048 }
1049 else
1050 {
1051 /* save the stream open ID */
1052 priv->stream_open_id = g_strdup (id);
1053
1054 wocky_porter_send (priv->porter, stanza);
1055 }
1056
1057 g_object_unref (stanza);
1058
1059 return TRUE;
1060 }
1061
1062 void
gibber_bytestream_oob_set_check_addr_func(GibberBytestreamOOB * self,GibberBytestreamOOBCheckAddrFunc func,gpointer user_data)1063 gibber_bytestream_oob_set_check_addr_func (
1064 GibberBytestreamOOB *self,
1065 GibberBytestreamOOBCheckAddrFunc func,
1066 gpointer user_data)
1067 {
1068 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
1069
1070 priv->check_addr_func = func;
1071 priv->check_addr_func_data = user_data;
1072 }
1073
1074 static void
gibber_bytestream_oob_block_reading(GibberBytestreamIface * bytestream,gboolean block)1075 gibber_bytestream_oob_block_reading (GibberBytestreamIface *bytestream,
1076 gboolean block)
1077 {
1078 GibberBytestreamOOB *self = GIBBER_BYTESTREAM_OOB (bytestream);
1079 GibberBytestreamOOBPrivate *priv = GIBBER_BYTESTREAM_OOB_GET_PRIVATE (self);
1080
1081 if (priv->read_blocked == block)
1082 return;
1083
1084 priv->read_blocked = block;
1085
1086 DEBUG ("%s the transport bytestream", block ? "block": "unblock");
1087 gibber_transport_block_receiving (priv->transport, block);
1088 }
1089
1090 static void
bytestream_iface_init(gpointer g_iface,gpointer iface_data)1091 bytestream_iface_init (gpointer g_iface,
1092 gpointer iface_data)
1093 {
1094 GibberBytestreamIfaceClass *klass = (GibberBytestreamIfaceClass *) g_iface;
1095
1096 klass->initiate = gibber_bytestream_oob_initiate;
1097 klass->send = gibber_bytestream_oob_send;
1098 klass->close = gibber_bytestream_oob_close;
1099 klass->accept = gibber_bytestream_oob_accept;
1100 klass->block_reading = gibber_bytestream_oob_block_reading;
1101 }
1102