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