<commit_before>/*
 * jingle-factory.c - Support for XEP-0166 (Jingle)
 *
 * Copyright (C) 2006-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-factory.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-media-rtp.h"
#include "jingle-session.h"
#include "jingle-transport-google.h"
#include "namespaces.h"
#include "util.h"

G_DEFINE_TYPE(GabbleJingleFactory, gabble_jingle_factory, G_TYPE_OBJECT);

/* signal enum */
enum
{
    NEW_SESSION,
    LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = {0};

/* properties */
enum
{
  PROP_CONNECTION = 1,
  LAST_PROPERTY
};


struct _GabbleJingleFactoryPrivate
{
  GabbleConnection *conn;
  LmMessageHandler *jingle_cb;
  LmMessageHandler *jingle_info_cb;
  GHashTable *content_types;
  GHashTable *transports;
  GHashTable *sessions;

  gchar *stun_server;
  guint16 stun_port;
  gchar *relay_token;
  gboolean get_stun_from_jingle;
  gboolean dispose_has_run;
};

#define GABBLE_JINGLE_FACTORY_GET_PRIVATE(o) ((o)->priv)

static LmHandlerResult jingle_cb (LmMessageHandler *handler,
    LmConnection *lmconn, LmMessage *message, gpointer user_data);
static GabbleJingleSession *create_session (GabbleJingleFactory *fac,
    const gchar *sid, TpHandle peer, const gchar *peer_resource);

static void session_terminated_cb (GabbleJingleSession *sess,
    gboolean local_terminator, GabbleJingleFactory *fac);

static void connection_status_changed_cb (GabbleConnection *conn,
    guint status, guint reason, GabbleJingleFactory *self);

static void
gabble_jingle_factory_init (GabbleJingleFactory *obj)
{
  GabbleJingleFactoryPrivate *priv =
     G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_FACTORY,
         GabbleJingleFactoryPrivate);
  obj->priv = priv;

  priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal,
      g_free, g_object_unref);

  priv->transports = g_hash_table_new_full (g_str_hash, g_str_equal,
      NULL, NULL);

  priv->content_types = g_hash_table_new_full (g_str_hash, g_str_equal,
      NULL, NULL);

  priv->jingle_cb = NULL;

  priv->conn = NULL;
  priv->dispose_has_run = FALSE;
}

static void
take_stun_server (GabbleJingleFactory *self,
                  gchar *stun_server,
                  guint16 stun_port)
{
  g_free (self->priv->stun_server);
  self->priv->stun_server = stun_server;
  self->priv->stun_port = stun_port;
}

/*
 * jingle_info_cb
 *
 * Called by loudmouth when we get an incoming <iq>. This handler
 * is concerned only with Jingle info queries.
 */
static LmHandlerResult
jingle_info_cb (LmMessageHandler *handler,
                LmConnection *lmconn,
                LmMessage *message,
                gpointer user_data)
{
  GabbleJingleFactory *fac = GABBLE_JINGLE_FACTORY (user_data);
  GabbleJingleFactoryPrivate *priv = GABBLE_JINGLE_FACTORY_GET_PRIVATE (fac);
  LmMessageSubType sub_type;
  LmMessageNode *query_node, *node;

  query_node = lm_message_node_get_child_with_namespace (message->node,
      "query", NS_GOOGLE_JINGLE_INFO);

  if (query_node == NULL)
    return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;

  sub_type = lm_message_get_sub_type (message);

  if (sub_type == LM_MESSAGE_SUB_TYPE_ERROR)
    {
      GabbleXmppError xmpp_error = XMPP_ERROR_UNDEFINED_CONDITION;

      node = lm_message_node_get_child (message->node, "error");
      if (node != NULL)
        {
          xmpp_error = gabble_xmpp_error_from_node (node, NULL);
        }

      DEBUG ("jingle info error: %s", gabble_xmpp_error_string (xmpp_error));

      return LM_HANDLER_RESULT_REMOVE_MESSAGE;
    }

  if (sub_type != LM_MESSAGE_SUB_TYPE_RESULT &&
      sub_type != LM_MESSAGE_SUB_TYPE_SET)
    {
      DEBUG ("jingle info: unexpected IQ type, ignoring");

      return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
    }

  if (fac->priv->get_stun_from_jingle)
    node = lm_message_node_get_child (query_node, "stun");
  else
    node = NULL;

  if (node != NULL)
    {
      node = lm_message_node_get_child (node, "server");

      if (node != NULL)
        {
          const gchar *server;
          const gchar *port_attr;
          guint port = GABBLE_PARAMS_DEFAULT_STUN_PORT;

          server = lm_message_node_get_attribute (node, "host");
          port_attr = lm_message_node_get_attribute (node, "udp");

          if (port_attr != NULL)
            port = atoi (port_attr);

          if (server != NULL && port > 0 && port <= G_MAXUINT16)
            {
              DEBUG ("jingle info: got stun server %s, port %u", server,
                  port);
              take_stun_server (fac, server, port);
            }
        }
    }

  node = lm_message_node_get_child (query_node, "relay");

  if (node != NULL)
    {
      node = lm_message_node_get_child (node, "token");

      if (node != NULL)
        {
          const gchar *token;

          token = lm_message_node_get_value (node);

          if (token != NULL)
            {
              DEBUG ("jingle info: got relay token %s", token);
              g_free (fac->priv->relay_token);
              fac->priv->relay_token = g_strdup (token);
            }<commit_msg>GabbleJingleFactory: Resolve STUN server hostname to address<commit_after>/*
 * jingle-factory.c - Support for XEP-0166 (Jingle)
 *
 * Copyright (C) 2006-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-factory.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>

#include <lib/gibber/gibber-resolver.h>
#include <loudmouth/loudmouth.h>

#define DEBUG_FLAG GABBLE_DEBUG_MEDIA

#include "connection.h"
#include "debug.h"
#include "jingle-media-rtp.h"
#include "jingle-session.h"
#include "jingle-transport-google.h"
#include "namespaces.h"
#include "util.h"

G_DEFINE_TYPE(GabbleJingleFactory, gabble_jingle_factory, G_TYPE_OBJECT);

/* signal enum */
enum
{
    NEW_SESSION,
    LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = {0};

/* properties */
enum
{
  PROP_CONNECTION = 1,
  LAST_PROPERTY
};


struct _GabbleJingleFactoryPrivate
{
  GabbleConnection *conn;
  LmMessageHandler *jingle_cb;
  LmMessageHandler *jingle_info_cb;
  GHashTable *content_types;
  GHashTable *transports;
  GHashTable *sessions;
  GibberResolver *resolver;

  gchar *stun_server;
  guint16 stun_port;
  gchar *relay_token;
  gboolean get_stun_from_jingle;
  gboolean dispose_has_run;
};

#define GABBLE_JINGLE_FACTORY_GET_PRIVATE(o) ((o)->priv)

static LmHandlerResult jingle_cb (LmMessageHandler *handler,
    LmConnection *lmconn, LmMessage *message, gpointer user_data);
static GabbleJingleSession *create_session (GabbleJingleFactory *fac,
    const gchar *sid, TpHandle peer, const gchar *peer_resource);

static void session_terminated_cb (GabbleJingleSession *sess,
    gboolean local_terminator, GabbleJingleFactory *fac);

static void connection_status_changed_cb (GabbleConnection *conn,
    guint status, guint reason, GabbleJingleFactory *self);

static void
gabble_jingle_factory_init (GabbleJingleFactory *obj)
{
  GabbleJingleFactoryPrivate *priv =
     G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_FACTORY,
         GabbleJingleFactoryPrivate);
  obj->priv = priv;

  priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal,
      g_free, g_object_unref);

  priv->transports = g_hash_table_new_full (g_str_hash, g_str_equal,
      NULL, NULL);

  priv->content_types = g_hash_table_new_full (g_str_hash, g_str_equal,
      NULL, NULL);

  priv->jingle_cb = NULL;

  priv->conn = NULL;
  priv->dispose_has_run = FALSE;
  priv->resolver = gibber_resolver_get_resolver ();
}

typedef struct {
    gchar *stun_server;
    guint16 stun_port;
} PendingStunServer;

static void
pending_stun_server_free (gpointer p)
{
  PendingStunServer *data = p;

  g_free (data->stun_server);
  g_slice_free (PendingStunServer, p);
}

static void
stun_server_resolved_cb (GibberResolver *resolver,
                         GList *entries,
                         GError *error,
                         gpointer user_data,
                         GObject *object)
{
  GabbleJingleFactory *self = GABBLE_JINGLE_FACTORY (object);
  PendingStunServer *data = user_data;
  GibberResolverAddrInfo *info;
  GError *e = NULL;
  gchar *stun_server;

  if (error != NULL)
    {
      DEBUG ("Failed to resolve STUN server %s:%u: %s",
          data->stun_server, data->stun_port, error->message);
      return;
    }

  if (entries == NULL)
    {
      DEBUG ("No results for STUN server %s:%u",
          data->stun_server, data->stun_port);
      return;
    }

  info = entries->data;

  if (!gibber_resolver_sockaddr_to_str ((struct sockaddr *) &(info->sockaddr),
        info->sockaddr_len, &stun_server, NULL, &e))
    {
      DEBUG ("Couldn't convert resolved address of %s to string: %s",
          data->stun_server, e->message);
      g_error_free (e);
      return;
    }

  DEBUG ("Resolved STUN server %s:%u to %s:%u", data->stun_server,
      data->stun_port, stun_server, data->stun_port);

  g_free (self->priv->stun_server);
  self->priv->stun_server = stun_server;
  self->priv->stun_port = data->stun_port;
}

static void
take_stun_server (GabbleJingleFactory *self,
                  gchar *stun_server,
                  guint16 stun_port)
{
  PendingStunServer *data = g_slice_new0 (PendingStunServer);

  if (stun_server == NULL)
    return;

  DEBUG ("Resolving STUN server %s:%u", stun_server, stun_port);
  data->stun_server = stun_server;
  data->stun_port = stun_port;

  gibber_resolver_addrinfo (self->priv->resolver, stun_server, NULL,
      AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0,
      stun_server_resolved_cb, data, pending_stun_server_free,
      G_OBJECT (self));
}

/*
 * jingle_info_cb
 *
 * Called by loudmouth when we get an incoming <iq>. This handler
 * is concerned only with Jingle info queries.
 */
static LmHandlerResult
jingle_info_cb (LmMessageHandler *handler,
                LmConnection *lmconn,
                LmMessage *message,
                gpointer user_data)
{
  GabbleJingleFactory *fac = GABBLE_JINGLE_FACTORY (user_data);
  GabbleJingleFactoryPrivate *priv = GABBLE_JINGLE_FACTORY_GET_PRIVATE (fac);
  LmMessageSubType sub_type;
  LmMessageNode *query_node, *node;

  query_node = lm_message_node_get_child_with_namespace (message->node,
      "query", NS_GOOGLE_JINGLE_INFO);

  if (query_node == NULL)
    return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;

  sub_type = lm_message_get_sub_type (message);

  if (sub_type == LM_MESSAGE_SUB_TYPE_ERROR)
    {
      GabbleXmppError xmpp_error = XMPP_ERROR_UNDEFINED_CONDITION;

      node = lm_message_node_get_child (message->node, "error");
      if (node != NULL)
        {
          xmpp_error = gabble_xmpp_error_from_node (node, NULL);
        }

      DEBUG ("jingle info error: %s", gabble_xmpp_error_string (xmpp_error));

      return LM_HANDLER_RESULT_REMOVE_MESSAGE;
    }

  if (sub_type != LM_MESSAGE_SUB_TYPE_RESULT &&
      sub_type != LM_MESSAGE_SUB_TYPE_SET)
    {
      DEBUG ("jingle info: unexpected IQ type, ignoring");

      return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
    }

  if (fac->priv->get_stun_from_jingle)
    node = lm_message_node_get_child (query_node, "stun");
  else
    node = NULL;

  if (node != NULL)
    {
      node = lm_message_node_get_child (node, "server");

      if (node != NULL)
        {
          const gchar *server;
          const gchar *port_attr;
          guint port = GABBLE_PARAMS_DEFAULT_STUN_PORT;

          server = lm_message_node_get_attribute (node, "host");
          port_attr = lm_message_node_get_attribute (node, "udp");

          if (port_attr != NULL)
            port = atoi (port_attr);

          if (server != NULL && port > 0 && port <= G_MAXUINT16)
            {
              DEBUG ("jingle info: got stun server %s, port %u", server,
                  port);
              take_stun_server (fac, g_strdup (server), port);
            }
        }
    }

  node = lm_message_node_get_child (query_node, "relay");

  if (node != NULL)
    {
      node = lm_message_node_get_child (node, "token");

      if (node != NULL)
        {
          const gchar *token;

          token = lm_message_node_get_value (node);

          if (token != NULL)
            {
              DEBUG ("jingle info: got relay token %s", token);
              g_free (fac->priv->relay_token);
              fac->priv->relay_token = g_strdup (token);
            }
{'fraction_non_alphanumeric': 0.09570270464165291, 'fraction_numerical': 0.0051653633689647755, 'mean_word_length': 3.322480620155039, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 82, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1961125', 'n_tokens_mistral': 4916, 'n_tokens_neox': 4725, 'n_words': 1141}