jingle-socks5/socks5.c
author Nicolas Cornu <nicolas.cornu@ensi-bourges.fr>
Sat, 14 Aug 2010 19:21:42 +0200
changeset 120 3e2085a44a5c
parent 118 f3408f4fe61a
child 122 8969dc3e2f14
permissions -rw-r--r--
Last strdup

/*
 * socks5.c
 *
 * Copyrigth (C) 2010 Nicolas Cornu <nicolas.cornu@ensi-bourges.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include "config.h"

#include <glib.h>

#include <mcabber/xmpp.h>
#include <mcabber/modules.h>
#include <mcabber/utils.h>
#include <mcabber/xmpp_helper.h>
#include <mcabber/logprint.h>
#include <mcabber/hooks.h>

#include <jingle/jingle.h>
#include <jingle/check.h>
#include <jingle/register.h>

#include "socks5.h"

gconstpointer jingle_socks5_check(JingleContent *cn, GError **err);
gboolean jingle_socks5_cmp(gconstpointer data1, gconstpointer data2);
void jingle_socks5_tomessage(gconstpointer data, LmMessageNode *node);
const gchar* jingle_socks5_xmlns(void);
gconstpointer jingle_socks5_new(void);
void jingle_socks5_send(session_content *sc, const gchar *to,
                        gconstpointer data, gchar *buf, gsize size);

static void jingle_socks5_init(void);
static void jingle_socks5_uninit(void);


const gchar *deps[] = { "jingle", NULL };

static JingleTransportFuncs funcs = {
  jingle_socks5_xmlns,
  jingle_socks5_check,
  jingle_socks5_tomessage,
  jingle_socks5_cmp,
  jingle_socks5_new,
  jingle_socks5_send
};

module_info_t  info_jingle_socks5bytestream = {
  .branch          = MCABBER_BRANCH,
  .api             = MCABBER_API_VERSION,
  .version         = PROJECT_VERSION,
  .description     = "Jingle Socks5 Bytestream (XEP-0260)\n",
  .requires        = deps,
  .init            = jingle_socks5_init,
  .uninit          = jingle_socks5_uninit,
  .next            = NULL,
};

static const gchar *jingle_s5b_types[] = {
  "assisted",
  "direct",
  "proxy",
  "tunnel",
  NULL
};

static const gchar *jingle_s5b_modes[] = {
  "tcp",
  "udp",
  NULL
};


gint index_in_array(const gchar *str, const gchar **array)
{
  gint i;
  for (i = 0; array[i]; i++) {
    if (!g_strcmp0(array[i], str)) {
      return i;
    }
  }
  return -1;
}

const gchar* jingle_socks5_xmlns(void)
{
  return NS_JINGLE_TRANSPORT_SOCKS5;
}

gconstpointer jingle_socks5_check(JingleContent *cn, GError **err)
{
  JingleSocks5 *js5b;
  LmMessageNode *node = cn->transport, *node2;
  const gchar *modestr;

  js5b = g_new0(JingleSocks5, 1);
  modestr    = lm_message_node_get_attribute(node, "mode");
  js5b->mode = index_in_array(modestr, jingle_s5b_modes);
  js5b->sid  = g_strdup(lm_message_node_get_attribute(node, "sid"));

  if (!js5b->sid) {
    g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
                "an attribute of the transport element is missing");
    g_free(js5b);
    return NULL;
  }

  for (node2 = node->children; node2; node2 = node2->next) {
    if (!g_strcmp0(node->name, "candidate")) {
      const gchar *portstr, *prioritystr, *typestr;
      JingleS5BCandidate *jc = g_new0(JingleS5BCandidate, 1);
      jc->cid      = g_strdup(lm_message_node_get_attribute(node2, "cid"));
      jc->host     = g_strdup(lm_message_node_get_attribute(node2, "host"));
      jc->jid      = g_strdup(lm_message_node_get_attribute(node2, "jid"));
      portstr      = lm_message_node_get_attribute(node2, "port");
      prioritystr  = lm_message_node_get_attribute(node2, "priority");
      typestr      = lm_message_node_get_attribute(node2, "type");

      if (!jc->cid || !jc->host || !jc->jid || !prioritystr) {
        g_free(jc);
        continue;
	  }
      jc->port     = g_ascii_strtoull(portstr, NULL, 10);
      jc->priority = g_ascii_strtoull(prioritystr, NULL, 10);
      jc->type     = index_in_array(typestr, jingle_s5b_types);

      if (jc->type == -1) {
        g_free(jc);
        continue;
	  }

      js5b->candidates = g_slist_append(js5b->candidates, jc);
    }
  }

  return (gconstpointer) js5b;
}

void jingle_socks5_tomessage(gconstpointer data, LmMessageNode *node)
{
  JingleSocks5 *js5 = (JingleSocks5*)data;
  JingleS5BCandidate *js5c;
  
  LmMessageNode *node2, *node3;
  gchar *port;
  gchar *priority;
  GSList *el;
  
  if (lm_message_node_get_child(node, "transport") != NULL)
    return;
  
  node2 = lm_message_node_add_child(node, "transport", NULL);

  lm_message_node_set_attributes(node2, "xmlns", NS_JINGLE_TRANSPORT_SOCKS5,
                                 "sid", js5->sid,
                                 "mode", jingle_s5b_modes[js5->mode],
                                 NULL);
  for (el = js5->candidates; el; el = el->next) {
    js5c = (JingleS5BCandidate*) el->data;
    node3 = lm_message_node_add_child(node2, "candidate", NULL);
    
    port = g_strdup_printf("%" G_GUINT16_FORMAT, js5c->port);
    priority = g_strdup_printf("%" G_GUINT64_FORMAT, js5c->priority);
    
    lm_message_node_set_attributes(node3, "cid", js5c->cid,
                                   "host", js5c->host,
                                   "jid", js5c->jid,
                                   "port", port,
                                   "priority", priority,
                                   "type", jingle_s5b_types[js5c->type],
                                   NULL);
    g_free(port);
    g_free(priority);
  }
}

static void jingle_socks5_init(void)
{
  jingle_register_transport(NS_JINGLE_TRANSPORT_SOCKS5, &funcs,
                            JINGLE_TRANSPORT_STREAMING,
                            JINGLE_TRANSPORT_HIGH);
  xmpp_add_feature(NS_JINGLE_TRANSPORT_SOCKS5);
}

static void jingle_socks5_uninit(void)
{
  xmpp_del_feature(NS_JINGLE_TRANSPORT_SOCKS5);
  jingle_unregister_transport(NS_JINGLE_TRANSPORT_SOCKS5);
}