[telepathy-gabble/master] add JingleTransportRawUdp

Senko Rasic senko.rasic at collabora.co.uk
Mon Jun 29 04:43:01 PDT 2009


---
 src/Makefile.am               |    2 +
 src/jingle-transport-rawudp.c |  467 +++++++++++++++++++++++++++++++++++++++++
 src/jingle-transport-rawudp.h |   65 ++++++
 3 files changed, 534 insertions(+), 0 deletions(-)
 create mode 100644 src/jingle-transport-rawudp.c
 create mode 100644 src/jingle-transport-rawudp.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 62b6a1a..5bab478 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -73,6 +73,8 @@ libgabble_convenience_la_SOURCES = \
     jingle-session.c \
     jingle-transport-google.h \
     jingle-transport-google.c \
+    jingle-transport-rawudp.h \
+    jingle-transport-rawudp.c \
     jingle-transport-iface.h \
     jingle-transport-iface.c \
     media-channel.h \
diff --git a/src/jingle-transport-rawudp.c b/src/jingle-transport-rawudp.c
new file mode 100644
index 0000000..4934e43
--- /dev/null
+++ b/src/jingle-transport-rawudp.c
@@ -0,0 +1,467 @@
+/*
+ * jingle-transport-rawudp.c - Source for GabbleJingleTransportRawUdp
+ *
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "jingle-transport-rawudp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include <loudmouth/loudmouth.h>
+
+#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
+
+#include "connection.h"
+#include "debug.h"
+#include "jingle-content.h"
+#include "jingle-factory.h"
+#include "jingle-session.h"
+#include "namespaces.h"
+#include "util.h"
+
+static void
+transport_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (GabbleJingleTransportRawUdp,
+    gabble_jingle_transport_rawudp, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (GABBLE_TYPE_JINGLE_TRANSPORT_IFACE,
+        transport_iface_init));
+
+/* signal enum */
+enum
+{
+  NEW_CANDIDATES,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+/* properties */
+enum
+{
+  PROP_CONTENT = 1,
+  PROP_TRANSPORT_NS,
+  PROP_STATE,
+  LAST_PROPERTY
+};
+
+struct _GabbleJingleTransportRawUdpPrivate
+{
+  GabbleJingleContent *content;
+  JingleTransportState state;
+  gchar *transport_ns;
+
+  GList *local_candidates;
+
+  /* A pointer into "local_candidates" list to mark the
+   * candidates that are still not transmitted, or NULL
+   * if all of them are transmitted. */
+
+  GList *pending_candidates;
+  GList *remote_candidates;
+  gboolean dispose_has_run;
+};
+
+#define GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE(o) ((o)->priv)
+
+static void transmit_candidates (GabbleJingleTransportRawUdp *transport,
+    GList *candidates);
+
+static void
+gabble_jingle_transport_rawudp_init (GabbleJingleTransportRawUdp *obj)
+{
+  GabbleJingleTransportRawUdpPrivate *priv =
+     G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP,
+         GabbleJingleTransportRawUdpPrivate);
+  obj->priv = priv;
+
+  priv->dispose_has_run = FALSE;
+}
+
+static void
+gabble_jingle_transport_rawudp_dispose (GObject *object)
+{
+  GabbleJingleTransportRawUdp *trans = GABBLE_JINGLE_TRANSPORT_RAWUDP (object);
+  GabbleJingleTransportRawUdpPrivate *priv = GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (trans);
+
+  if (priv->dispose_has_run)
+    return;
+
+  DEBUG ("dispose called");
+  priv->dispose_has_run = TRUE;
+
+  jingle_transport_free_candidates (priv->remote_candidates);
+  priv->remote_candidates = NULL;
+
+  jingle_transport_free_candidates (priv->local_candidates);
+  priv->local_candidates = NULL;
+
+  g_free (priv->transport_ns);
+  priv->transport_ns = NULL;
+
+  if (G_OBJECT_CLASS (gabble_jingle_transport_rawudp_parent_class)->dispose)
+    G_OBJECT_CLASS (gabble_jingle_transport_rawudp_parent_class)->dispose (object);
+}
+
+static void
+gabble_jingle_transport_rawudp_get_property (GObject *object,
+                                             guint property_id,
+                                             GValue *value,
+                                             GParamSpec *pspec)
+{
+  GabbleJingleTransportRawUdp *trans = GABBLE_JINGLE_TRANSPORT_RAWUDP (object);
+  GabbleJingleTransportRawUdpPrivate *priv = GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (trans);
+
+  switch (property_id) {
+    case PROP_CONTENT:
+      g_value_set_object (value, priv->content);
+      break;
+    case PROP_TRANSPORT_NS:
+      g_value_set_string (value, priv->transport_ns);
+      break;
+    case PROP_STATE:
+      g_value_set_uint (value, priv->state);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gabble_jingle_transport_rawudp_set_property (GObject *object,
+                                             guint property_id,
+                                             const GValue *value,
+                                             GParamSpec *pspec)
+{
+  GabbleJingleTransportRawUdp *trans = GABBLE_JINGLE_TRANSPORT_RAWUDP (object);
+  GabbleJingleTransportRawUdpPrivate *priv =
+      GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (trans);
+
+  switch (property_id) {
+    case PROP_CONTENT:
+      priv->content = g_value_get_object (value);
+      break;
+    case PROP_TRANSPORT_NS:
+      g_free (priv->transport_ns);
+      priv->transport_ns = g_value_dup_string (value);
+      break;
+    case PROP_STATE:
+      priv->state = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gabble_jingle_transport_rawudp_class_init (GabbleJingleTransportRawUdpClass *cls)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (cls);
+  GParamSpec *param_spec;
+
+  g_type_class_add_private (cls, sizeof (GabbleJingleTransportRawUdpPrivate));
+
+  object_class->get_property = gabble_jingle_transport_rawudp_get_property;
+  object_class->set_property = gabble_jingle_transport_rawudp_set_property;
+  object_class->dispose = gabble_jingle_transport_rawudp_dispose;
+
+  /* property definitions */
+  param_spec = g_param_spec_object ("content", "GabbleJingleContent object",
+                                    "Jingle content object using this transport.",
+                                    GABBLE_TYPE_JINGLE_CONTENT,
+                                    G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_STATIC_NICK |
+                                    G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_CONTENT, param_spec);
+
+  param_spec = g_param_spec_string ("transport-ns", "Transport namespace",
+                                    "Namespace identifying the transport type.",
+                                    NULL,
+                                    G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_STATIC_NICK |
+                                    G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec);
+
+  param_spec = g_param_spec_uint ("state",
+                                  "Connection state for the transport.",
+                                  "Enum specifying the connection state of the transport.",
+                                  JINGLE_TRANSPORT_STATE_DISCONNECTED,
+                                  JINGLE_TRANSPORT_STATE_CONNECTED,
+                                  JINGLE_TRANSPORT_STATE_DISCONNECTED,
+                                  G_PARAM_READWRITE |
+                                  G_PARAM_STATIC_NAME |
+                                  G_PARAM_STATIC_NICK |
+                                  G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_STATE, param_spec);
+
+  /* signal definitions */
+  signals[NEW_CANDIDATES] = g_signal_new (
+    "new-candidates",
+    G_TYPE_FROM_CLASS (cls),
+    G_SIGNAL_RUN_LAST,
+    0,
+    NULL, NULL,
+    g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+}
+
+#define SET_BAD_REQ(txt...) g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST, txt)
+#define SET_OUT_ORDER(txt...) g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_JINGLE_OUT_OF_ORDER, txt)
+#define SET_CONFLICT(txt...) g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_CONFLICT, txt)
+
+static void
+parse_candidates (GabbleJingleTransportIface *obj,
+    LmMessageNode *transport_node, GError **error)
+{
+  GabbleJingleTransportRawUdp *t = GABBLE_JINGLE_TRANSPORT_RAWUDP (obj);
+  GabbleJingleTransportRawUdpPrivate *priv =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (t);
+  GList *candidates = NULL;
+  LmMessageNode *node;
+
+  DEBUG ("called");
+
+  for (node = transport_node->children; node; node = node->next)
+    {
+      const gchar *id, *ip, *str;
+      guint port, gen, component = 1;
+      JingleCandidate *c;
+
+      if (tp_strdiff (node->name, "candidate"))
+          continue;
+
+      str = lm_message_node_get_attribute (node, "component");
+      if (str != NULL)
+          component = atoi (str);
+
+      /* FIXME: are RTCP components usable in raw-udp? */
+      if (component != 1)
+        {
+          DEBUG ("Ignoring non-RTP component %d for now", component);
+          continue;
+        }
+
+      id = lm_message_node_get_attribute (node, "id");
+      if (id == NULL)
+          break;
+
+      ip = lm_message_node_get_attribute (node, "ip");
+      if (ip == NULL)
+          break;
+
+      str = lm_message_node_get_attribute (node, "port");
+      if (str == NULL)
+          break;
+      port = atoi (str);
+
+      str = lm_message_node_get_attribute (node, "generation");
+      if (str == NULL)
+          break;
+      gen = atoi (str);
+
+      /* FIXME: we're using "user" Tp field for the candidate ID */
+      c = jingle_candidate_new (component, ip, port,
+          JINGLE_TRANSPORT_PROTOCOL_UDP,
+          1.0, JINGLE_CANDIDATE_TYPE_LOCAL, id, NULL, 0, gen);
+
+      candidates = g_list_append (candidates, c);
+    }
+
+  if (node != NULL)
+    {
+      DEBUG ("not all nodes were processed, reporting error");
+      /* rollback these */
+      jingle_transport_free_candidates (candidates);
+      SET_BAD_REQ ("invalid candidate");
+      return;
+    }
+
+  DEBUG ("emitting %d new remote candidates", g_list_length (candidates));
+
+  g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates);
+
+  /* if we got any candidates, overwrite previous with new ones */
+  if (candidates != NULL)
+    {
+      /* FIXME: we assume there are no RTCP components and just try the
+       * first candidate */
+      JingleCandidate *c = candidates->data;
+
+      jingle_transport_free_candidates (priv->remote_candidates);
+      priv->remote_candidates = candidates;
+    }
+}
+
+static void
+transmit_candidates (GabbleJingleTransportRawUdp *transport, GList *candidates)
+{
+  GabbleJingleTransportRawUdpPrivate *priv =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (transport);
+  GList *li;
+  LmMessage *msg;
+  LmMessageNode *trans_node, *sess_node;
+  const gchar *cname, *cns;
+  gboolean created_by_initiator = FALSE;
+
+  msg = gabble_jingle_session_new_message (priv->content->session,
+    JINGLE_ACTION_TRANSPORT_INFO, &sess_node);
+
+  g_object_get (GABBLE_JINGLE_CONTENT (priv->content),
+      "name", &cname, "content-ns", &cns, "created-by-initiator",
+      &created_by_initiator, NULL);
+
+  /* we need the <content> ... */
+  trans_node = lm_message_node_add_child (sess_node, "content", NULL);
+  lm_message_node_set_attribute (trans_node, "xmlns", cns);
+  lm_message_node_set_attribute (trans_node, "name", cname);
+  /* FIXME: this also needs to be done for google-p2p, and checked in tests */
+  /* FIXME:2: content object should produce the content node, we shouldn't
+   * have to do it here! */
+  lm_message_node_set_attribute (trans_node, "creator",
+      created_by_initiator ? "initiator" : "responder");
+
+  /* .. and the <transport> node */
+  trans_node = lm_message_node_add_child (trans_node, "transport", NULL);
+  lm_message_node_set_attribute (trans_node, "xmlns", priv->transport_ns);
+
+  for (li = candidates; li; li = li->next)
+    {
+      JingleCandidate *c = (JingleCandidate *) li->data;
+      gchar port_str[16];
+      LmMessageNode *cnode;
+
+      sprintf (port_str, "%d", c->port);
+
+      /* FIXME: we're missing component attrib, and have hardcoded net/gen */
+      cnode = lm_message_node_add_child (trans_node, "candidate", NULL);
+      lm_message_node_set_attributes (cnode,
+          "ip", c->address,
+          "port", port_str,
+          "id", c->username,
+          "network", "0",
+          "generation", "0",
+          NULL);
+    }
+
+  gabble_jingle_session_send (priv->content->session, msg, NULL, NULL);
+}
+
+/* Takes in a list of slice-allocated JingleCandidate structs */
+static void
+add_candidates (GabbleJingleTransportIface *obj, GList *new_candidates)
+{
+  GabbleJingleTransportRawUdp *transport =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP (obj);
+  GabbleJingleTransportRawUdpPrivate *priv =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (transport);
+  JingleContentState state;
+
+  g_object_get (priv->content, "state", &state, NULL);
+
+  if (state > JINGLE_CONTENT_STATE_EMPTY)
+    {
+      DEBUG ("content already signalled, transmitting candidates");
+      transmit_candidates (transport, new_candidates);
+      priv->pending_candidates = NULL;
+    }
+  else
+    {
+      DEBUG ("content not signalled yet, waiting with candidates");
+
+      /* if we already have pending candidates, the new ones will
+       * be in the local_candidates list after them. but these
+       * are the first pending ones, we must mark them. */
+      if (priv->pending_candidates == NULL)
+        priv->pending_candidates = new_candidates;
+  }
+
+  priv->local_candidates = g_list_concat (priv->local_candidates,
+      new_candidates);
+}
+
+static void
+retransmit_candidates (GabbleJingleTransportIface *obj, gboolean all)
+{
+  GabbleJingleTransportRawUdp *transport =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP (obj);
+  GabbleJingleTransportRawUdpPrivate *priv =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (transport);
+
+  if (all)
+    {
+      /* for gtalk3, we might have to retransmit everything */
+      transmit_candidates (transport, priv->local_candidates);
+      priv->pending_candidates = NULL;
+    }
+  else
+    {
+      /* in case content was ready after we wanted to transmit
+       * them originally, we are called to retranmit them */
+      if (priv->pending_candidates != NULL) {
+          transmit_candidates (transport, priv->pending_candidates);
+          priv->pending_candidates = NULL;
+      }
+    }
+}
+
+static GList *
+get_remote_candidates (GabbleJingleTransportIface *iface)
+{
+  GabbleJingleTransportRawUdp *transport =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP (iface);
+  GabbleJingleTransportRawUdpPrivate *priv =
+    GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_PRIVATE (transport);
+
+  return priv->remote_candidates;
+}
+
+static JingleTransportType
+get_transport_type (void)
+{
+  DEBUG ("called");
+
+  return JINGLE_TRANSPORT_RAW_UDP;
+}
+
+static void
+transport_iface_init (gpointer g_iface, gpointer iface_data)
+{
+  GabbleJingleTransportIfaceClass *klass = (GabbleJingleTransportIfaceClass *) g_iface;
+
+  klass->parse_candidates = parse_candidates;
+  klass->add_candidates = add_candidates;
+  klass->retransmit_candidates = retransmit_candidates;
+  klass->get_remote_candidates = get_remote_candidates;
+  klass->get_transport_type = get_transport_type;
+}
+
+void
+jingle_transport_rawudp_register (GabbleJingleFactory *factory)
+{
+  gabble_jingle_factory_register_transport (factory,
+      NS_JINGLE_TRANSPORT_RAWUDP,
+      GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP);
+}
+
diff --git a/src/jingle-transport-rawudp.h b/src/jingle-transport-rawudp.h
new file mode 100644
index 0000000..5b8b610
--- /dev/null
+++ b/src/jingle-transport-rawudp.h
@@ -0,0 +1,65 @@
+/*
+ * jingle-transport-rawudp.h - Header for GabbleJingleTransportRawUdp
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __JINGLE_TRANSPORT_RAWUDP_H__
+#define __JINGLE_TRANSPORT_RAWUDP_H__
+
+#include <glib-object.h>
+#include <loudmouth/loudmouth.h>
+
+#include "types.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GabbleJingleTransportRawUdpClass GabbleJingleTransportRawUdpClass;
+
+GType gabble_jingle_transport_rawudp_get_type (void);
+
+/* TYPE MACROS */
+#define GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP \
+  (gabble_jingle_transport_rawudp_get_type ())
+#define GABBLE_JINGLE_TRANSPORT_RAWUDP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP, \
+                              GabbleJingleTransportRawUdp))
+#define GABBLE_JINGLE_TRANSPORT_RAWUDP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP, \
+                           GabbleJingleTransportRawUdpClass))
+#define GABBLE_IS_JINGLE_TRANSPORT_RAWUDP(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP))
+#define GABBLE_IS_JINGLE_TRANSPORT_RAWUDP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP))
+#define GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP, \
+                              GabbleJingleTransportRawUdpClass))
+
+struct _GabbleJingleTransportRawUdpClass {
+    GObjectClass parent_class;
+};
+
+typedef struct _GabbleJingleTransportRawUdpPrivate GabbleJingleTransportRawUdpPrivate;
+
+struct _GabbleJingleTransportRawUdp {
+    GObject parent;
+    GabbleJingleTransportRawUdpPrivate *priv;
+};
+
+void jingle_transport_rawudp_register (GabbleJingleFactory *factory);
+
+#endif /* __JINGLE_TRANSPORT_RAWUDP_H__ */
+
-- 
1.5.6.5




More information about the telepathy-commits mailing list