Codebase list ssh-contact / debian/0.4-1 src / service.c
debian/0.4-1

Tree @debian/0.4-1 (Download .tar.gz)

service.c @debian/0.4-1

637bcfc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ba1279e
637bcfc
 
 
 
 
ba1279e
637bcfc
 
ba1279e
 
 
 
 
637bcfc
ba1279e
 
637bcfc
ba1279e
637bcfc
 
 
 
ba1279e
637bcfc
 
ba1279e
 
 
 
 
 
637bcfc
 
 
ba1279e
 
 
637bcfc
ba1279e
 
 
 
 
 
 
 
 
 
 
 
 
 
637bcfc
ba1279e
637bcfc
 
 
ba1279e
637bcfc
ba1279e
 
 
637bcfc
ba1279e
 
637bcfc
 
 
 
 
ba1279e
637bcfc
 
ba1279e
637bcfc
 
 
 
ba1279e
 
 
637bcfc
 
 
ba1279e
 
637bcfc
ba1279e
637bcfc
 
 
 
ba1279e
637bcfc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ba1279e
 
 
637bcfc
ba1279e
 
 
637bcfc
ba1279e
 
637bcfc
 
ba1279e
637bcfc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
 * Copyright (C) 2010 Xavier Claessens <xclaesse@gmail.com>
 * Copyright (C) 2010 Collabora Ltd.
 *
 * 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., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

#include "config.h"

#include <stdlib.h>

#include <gio/gio.h>
#include <telepathy-glib/telepathy-glib.h>

#include "common.h"

static GMainLoop *loop = NULL;
static GList *channel_list = NULL;

static void
channel_invalidated_cb (TpChannel *channel,
    guint domain,
    gint code,
    gchar *message,
    gpointer user_data)
{
  channel_list = g_list_remove (channel_list, channel);
  g_object_unref (channel);

  if (channel_list == NULL)
    g_main_loop_quit (loop);
}

static void
session_complete (TpChannel *channel, const GError *error)
{
  if (error != NULL)
    {
      g_debug ("Error for channel %p: %s", channel,
          error ? error->message : "No error message");
    }

  tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
}

static void
splice_cb (GObject *source_object,
    GAsyncResult *res,
    gpointer channel)
{
  GError *error = NULL;

  _g_io_stream_splice_finish (res, &error);
  session_complete (channel, error);
  g_clear_error (&error);
}

static void
accept_tube_cb (GObject *object,
    GAsyncResult *res,
    gpointer user_data)
{
  TpChannel *channel = TP_CHANNEL (object);
  TpStreamTubeConnection *stc;
  GInetAddress *inet_address = NULL;
  GSocketAddress *socket_address = NULL;
  GSocket *socket = NULL;
  GSocketConnection *tube_connection = NULL;
  GSocketConnection *sshd_connection = NULL;
  GError *error = NULL;

  stc = tp_stream_tube_channel_accept_finish (TP_STREAM_TUBE_CHANNEL (channel),
      res, &error);
  if (stc == NULL)
    goto OUT;

  tube_connection = tp_stream_tube_connection_get_socket_connection (stc);

  /* Connect to the sshd */
  inet_address = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
  socket_address = g_inet_socket_address_new (inet_address, 22);
  socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM,
      G_SOCKET_PROTOCOL_DEFAULT, &error);
  if (socket == NULL)
    goto OUT;
  if (!g_socket_connect (socket, socket_address, NULL, &error))
    goto OUT;
  sshd_connection = g_socket_connection_factory_create_connection (socket);

  /* Splice tube and ssh connections */
  _g_io_stream_splice_async (G_IO_STREAM (tube_connection),
      G_IO_STREAM (sshd_connection), _G_IO_STREAM_SPLICE_NONE,
      G_PRIORITY_DEFAULT, NULL, splice_cb, channel);

OUT:

  if (error != NULL)
    session_complete (channel, error);

  tp_clear_object (&stc);
  tp_clear_object (&inet_address);
  tp_clear_object (&socket_address);
  tp_clear_object (&socket);
  tp_clear_object (&sshd_connection);
  g_clear_error (&error);
}

static void
got_channel_cb (TpSimpleHandler *handler,
    TpAccount *account,
    TpConnection *connection,
    GList *channels,
    GList *requests_satisfied,
    gint64 user_action_time,
    TpHandleChannelsContext *context,
    gpointer user_data)
{
  GList *l;

  for (l = channels; l != NULL; l = l->next)
    {
      if (TP_IS_STREAM_TUBE_CHANNEL (l->data))
        {
          TpStreamTubeChannel *channel = l->data;

          channel_list = g_list_prepend (channel_list, g_object_ref (channel));
          g_signal_connect (channel, "invalidated",
              G_CALLBACK (channel_invalidated_cb), NULL);

          tp_stream_tube_channel_accept_async (channel, accept_tube_cb, NULL);
        }
    }

  tp_handle_channels_context_accept (context);
}

int
main (gint argc, gchar *argv[])
{
  TpDBusDaemon *dbus = NULL;
  TpBaseClient *client = NULL;
  gboolean success = TRUE;
  GError *error = NULL;

  g_type_init ();

  dbus = tp_dbus_daemon_dup (&error);
  if (dbus == NULL)
    goto OUT;

  client = tp_simple_handler_new (dbus, FALSE, FALSE, "SSHContact",
      FALSE, got_channel_cb, NULL, NULL);

  tp_base_client_take_handler_filter (client, tp_asv_new (
      TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
        TP_IFACE_CHANNEL_TYPE_STREAM_TUBE,
      TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
        TP_HANDLE_TYPE_CONTACT,
      TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE, G_TYPE_STRING,
        TUBE_SERVICE,
      TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN,
        FALSE,
      NULL));

  if (!tp_base_client_register (client, &error))
    goto OUT;

  loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (loop);

OUT:

  if (error != NULL)
    {
      g_debug ("Error: %s", error->message);
      success = FALSE;
    }

  tp_clear_pointer (&loop, g_main_loop_unref);
  tp_clear_object (&dbus);
  tp_clear_object (&client);
  g_clear_error (&error);

  return success ? EXIT_SUCCESS : EXIT_FAILURE;
}