Logo Search packages:      
Sourcecode: farsight version File versions  Download package

udp-transmitter.c

/*
 * udp-transmitter.c - Source for UDP transmitter implementation
 *
 * Farsight Voice+Video library
 * Copyright (C) 2007 Collabora Ltd.
 * Copyright (C) 2007 Nokia Corporation
 *   @author Philippe Kalaf <philippe.kalaf@collabora.co.uk>
 *
 * This program 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 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 Lesser 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 "udp-transmitter.h"

#include "farsight-transport.h"

#include "helpers/farsight-interfaces.h"

#include "stun.h"

#include <unistd.h>
#include <string.h>

#ifndef G_OS_WIN32
# include <arpa/inet.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
#else
# include <winsock2.h>
#endif


/* For Win32 */
#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0
#endif

#include <gst/gst.h>

#define DEFAULT_AUDIO_PORT 7078
#define DEFAULT_VIDEO_PORT 9078

#define DEFAULT_STUN_TIMEOUT 10 /* in seconds */
#define DEFAULT_STUN_PORT 3478

struct _FarsightUDPTransmitterPrivate
{
  gboolean disposed;
  gboolean prepared;

  GstElement *gst_src;
  GstElement *gst_sink;
  guint16 local_port;
  gint local_socket; /* socket used for symetric RTP */

  gchar *stun_ip;
  guint stun_port;
  GIOChannel *stun_ioc; /* GIOChannel used for the STUN */
  guint stun_timeoutid; /* id of the GSource for the STUN timeout*/
  guint stun_source;
  guint stun_source_error;
};


enum
{
  PROP_0,
  PROP_STUN_IP,
  PROP_STUN_PORT,
};

#define FARSIGHT_UDP_TRANSMITTER_GET_PRIVATE(o)  \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FARSIGHT_TYPE_UDP_TRANSMITTER, \
                                FarsightUDPTransmitterPrivate))

static void farsight_udp_transmitter_class_init (FarsightUDPTransmitterClass *klass);
static void farsight_udp_transmitter_init (FarsightUDPTransmitter *udp_transmitter);

static gboolean
farsight_udp_transmitter_prepare (FarsightTransmitter *transmitter);

/*
static gboolean
farsight_udp_transmitter_stop (FarsightTransmitter *transmitter);

static void
farsight_udp_transmitter_add_remote_candidates (FarsightTransmitter *transmitter,
    const GList *remote_candidate_list);
*/

static void farsight_udp_transmitter_dispose (GObject *object);
static void farsight_udp_transmitter_finalize (GObject *object);

static GstElement*
farsight_udp_transmitter_get_gst_src (FarsightTransmitter *transmitter);
static GstElement*
farsight_udp_transmitter_get_gst_sink (FarsightTransmitter *transmitter);

static void
farsight_udp_transmitter_create_source (FarsightUDPTransmitter *self);
static void
farsight_udp_transmitter_configure_source (FarsightUDPTransmitter *self);
static void
farsight_udp_transmitter_create_sink (FarsightUDPTransmitter *self);
static void
farsight_udp_transmitter_configure_sink (FarsightUDPTransmitter *self);
static void
farsight_udp_transmitter_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec);
static void
farsight_udp_transmitter_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec);

static void
farsight_udp_transmitter_use_local_ips (FarsightUDPTransmitter *transmitter);
static gboolean
farsight_udp_transmitter_start_stun (FarsightUDPTransmitter *transmitter);
static void
farsight_udp_transmitter_stop_stun (FarsightUDPTransmitter *transmitter);
static gboolean 
farsight_udp_transmitter_handle_stun (GIOChannel *source,
    GIOCondition condition, gpointer data);
static gboolean 
farsight_udp_transmitter_handle_stun_error (GIOChannel *source,
    GIOCondition condition, gpointer data);
static gboolean 
farsight_udp_transmitter_stun_timeout (gpointer data);



FarsightTransmitterClass *udp_transmitter_parent_class = NULL;

static GType type = 0;

GType
farsight_udp_transmitter_get_type (void)
{
  return type;
}

static void 
farsight_udp_transmitter_register_type (GTypeModule *module)
{
  static const GTypeInfo info = {
      sizeof (FarsightUDPTransmitterClass),
      NULL,
      NULL,
      (GClassInitFunc) farsight_udp_transmitter_class_init,
      NULL,
      NULL,
      sizeof (FarsightUDPTransmitter),
      0,
      (GInstanceInitFunc) farsight_udp_transmitter_init
    };

    type = g_type_module_register_type (module, FARSIGHT_TYPE_TRANSMITTER,
        "FarsightUDPTransmitter", &info, 0);
}

static void
farsight_udp_transmitter_class_init (FarsightUDPTransmitterClass *klass)
{
  GObjectClass *gobject_class;
  FarsightTransmitterClass *farsight_transmitter_class;

  gobject_class = (GObjectClass *) klass;
  farsight_transmitter_class = (FarsightTransmitterClass *) klass;
  udp_transmitter_parent_class = g_type_class_peek_parent (klass);

  gobject_class->dispose = farsight_udp_transmitter_dispose;
  gobject_class->finalize = farsight_udp_transmitter_finalize;
  
  gobject_class->set_property = farsight_udp_transmitter_set_property;
  gobject_class->get_property = farsight_udp_transmitter_get_property;
  

  g_object_class_install_property (gobject_class, PROP_STUN_IP,
      g_param_spec_string ("stun-ip", "STUN server IP address",
        "The IP address of the STUN server to use",
        NULL, G_PARAM_WRITABLE));

  g_object_class_install_property (gobject_class, PROP_STUN_PORT,
      g_param_spec_uint ("stun-port", "STUN server port",
          "The port to the STUN server", 1, 65535, DEFAULT_STUN_PORT, 
          G_PARAM_READWRITE));



  farsight_transmitter_class->prepare = farsight_udp_transmitter_prepare;
  /*
  farsight_transmitter_class->stop = farsight_udp_transmitter_stop;
  farsight_transmitter_class->add_remote_candidates =
    farsight_udp_transmitter_add_remote_candidates;
    */
  farsight_transmitter_class->get_gst_src =
    farsight_udp_transmitter_get_gst_src;
  farsight_transmitter_class->get_gst_sink =
    farsight_udp_transmitter_get_gst_sink;

  g_type_class_add_private (klass, sizeof (FarsightUDPTransmitterPrivate));
}

static void
farsight_udp_transmitter_init (FarsightUDPTransmitter *self)
{
  self->priv = FARSIGHT_UDP_TRANSMITTER_GET_PRIVATE (self);

  self->priv->local_socket = -1;
  self->priv->local_port = 0;
  
  self->priv->stun_port = DEFAULT_STUN_PORT;
  self->priv->stun_ip = NULL;
  self->priv->stun_ioc = NULL;
  self->priv->stun_timeoutid = 0;
}

static gboolean
farsight_udp_transmitter_prepare (FarsightTransmitter *transmitter)
{
  FarsightUDPTransmitter *self = FARSIGHT_UDP_TRANSMITTER (transmitter);
  guint16 port;
  guint media_type;
  struct sockaddr_in address;
  gint sock;
  gint bindresult = -1;

  if (self->priv->prepared)
    return FALSE;
  self->priv->prepared = TRUE;

  /* There isn't really any connection state in plain UDP, let's just
   * say we are connecting here, and connected when we are done
   * creating our udp gst elements */
  farsight_transmitter_signal_connection_state_changed (transmitter,
      FARSIGHT_TRANSMITTER_STATE_CONNECTING);

  g_object_get (G_OBJECT (transmitter), "media-type", &media_type, NULL);
  switch (media_type) {
    case FARSIGHT_MEDIA_TYPE_AUDIO:
      port = DEFAULT_AUDIO_PORT;
      break;
    case FARSIGHT_MEDIA_TYPE_VIDEO:
      port = DEFAULT_VIDEO_PORT;
      break;
    default:
      port = 1024;
  }

  g_message ("Media type is %d", media_type);

  if ((sock = socket (AF_INET,SOCK_DGRAM,0)) > 0) {
    g_debug ("The socket was created");
  } else {
    g_debug ("Error creating socket");
    return FALSE;
  }

  while (bindresult != 0)
  {
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons (port);
    bindresult = bind (sock, (struct sockaddr *) &address, sizeof (address));
    if (bindresult != 0)
    {
      g_debug ("could not bind port %d", port);
      port += 2;
      if (port == 0) {
        g_warning ("Could not bind socket to a port");
        close (sock);
        return FALSE;
      }
    }
  }
  g_debug ("bound to port %d", port);
  self->priv->local_socket = sock;
  self->priv->local_port = port;
  /* \ TODO */

  if (self->priv->stun_ip != NULL &&
      self->priv->stun_port != 0) {
    if (farsight_udp_transmitter_start_stun (self) == FALSE) {
      farsight_udp_transmitter_use_local_ips (self);
    }
  } else {
    farsight_udp_transmitter_use_local_ips (self);
  }


  if (self->priv->gst_src)
  {
    farsight_udp_transmitter_configure_source (self);
  }
  else
  {
    farsight_udp_transmitter_create_source (self);
  }

  if (self->priv->gst_sink)
  {
    farsight_udp_transmitter_configure_sink (self);
  }
  else
  {
    farsight_udp_transmitter_create_sink (self);
  }

  return TRUE;
}

#if 0
static gboolean
farsight_udp_transmitter_stop (FarsightTransmitter *transmitter)
{
}

static void
farsight_udp_transmitter_add_remote_candidates (FarsightTransmitter *transmitter,
    GList *remote_candidate_list)
{
  /* we don't need to do anything, we are using a dynudpsink therefore rtpbin
   * will give us the appropriate GstNetBuffers with dest information */
}
#endif

static GstElement*
farsight_udp_transmitter_get_gst_src (FarsightTransmitter *transmitter)
{
  FarsightUDPTransmitter *self = FARSIGHT_UDP_TRANSMITTER (transmitter);
  if (!self->priv->gst_src)
  {
    farsight_udp_transmitter_create_source (self);
  }
  return self->priv->gst_src;
}

static GstElement*
farsight_udp_transmitter_get_gst_sink (FarsightTransmitter *transmitter)
{
  FarsightUDPTransmitter *self = FARSIGHT_UDP_TRANSMITTER (transmitter);
  if (!self->priv->gst_sink)
  {
    farsight_udp_transmitter_create_sink (self);
  }
  return self->priv->gst_sink;
}

static void
farsight_udp_transmitter_dispose (GObject *object)
{
  FarsightUDPTransmitter *self = FARSIGHT_UDP_TRANSMITTER (object);

  if (self->priv->disposed) {
    /* If dispose did already run, return. */
    return;
  }

  if (self->priv->stun_timeoutid) {
    g_source_remove (self->priv->stun_timeoutid);
    self->priv->stun_timeoutid = 0;
  }

  if (self->priv->stun_source) {
    g_source_remove (self->priv->stun_source);
    self->priv->stun_source = 0;
  }

  if (self->priv->stun_source_error) {
    g_source_remove (self->priv->stun_source_error);
    self->priv->stun_source_error = 0;
  }

  if (self->priv->stun_ioc) {
    g_io_channel_unref (self->priv->stun_ioc);
    self->priv->stun_ioc = NULL;
  }

  self->priv->disposed = TRUE;

  /* chain up to parent */
  G_OBJECT_CLASS (udp_transmitter_parent_class)->dispose (object);
}

static void
farsight_udp_transmitter_finalize (GObject *object)
{
  FarsightUDPTransmitter *self = FARSIGHT_UDP_TRANSMITTER (object);

  g_return_if_fail (self != NULL);
  g_return_if_fail (FARSIGHT_IS_UDP_TRANSMITTER (self));

  G_OBJECT_CLASS (udp_transmitter_parent_class)->finalize (object);
}

static void
farsight_udp_transmitter_create_source (FarsightUDPTransmitter *self)
{
  self->priv->gst_src =
    gst_element_factory_make ("udpsrc", "udpsrc");

  if (self->priv->gst_src == NULL)
  {
    GST_ERROR("Could not add udpsrc!");
    return;
  }

  farsight_udp_transmitter_configure_source (self);
}

static void 
farsight_udp_transmitter_configure_source (FarsightUDPTransmitter *self)
{
  if (self->priv->local_socket != -1 && self->priv->stun_ioc == NULL)
  {
    g_object_set (G_OBJECT(self->priv->gst_src), "sockfd",
        self->priv->local_socket, NULL);

    farsight_transmitter_signal_connection_state_changed (
        FARSIGHT_TRANSMITTER (self),
        FARSIGHT_TRANSMITTER_STATE_CONNECTED);
  }

  g_object_set (G_OBJECT(self->priv->gst_src), "port",
      self->priv->local_port, NULL);



}

static void
farsight_udp_transmitter_create_sink (FarsightUDPTransmitter *self)
{
  self->priv->gst_sink =
    gst_element_factory_make ("dynudpsink", "rtpsinkelement");

  if (self->priv->gst_sink == NULL)
  {
    GST_ERROR("Could not add dynudpsink!");
    return;
  }

  farsight_udp_transmitter_configure_sink (self);

}

static void
farsight_udp_transmitter_configure_sink (FarsightUDPTransmitter *self)
{
  g_object_set (G_OBJECT(self->priv->gst_sink), "sync", FALSE, NULL);

  if (self->priv->local_socket != -1)
  {
    g_object_set (G_OBJECT(self->priv->gst_sink), "sockfd",
        self->priv->local_socket, NULL);
  }
}


static void
farsight_udp_transmitter_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec)
{
  FarsightUDPTransmitter *self = FARSIGHT_UDP_TRANSMITTER (object);

  switch (prop_id) {
    case PROP_STUN_IP:
      self->priv->stun_ip = g_value_dup_string (value);
      break;
    case PROP_STUN_PORT:
      self->priv->stun_port = g_value_get_uint (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
farsight_udp_transmitter_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec)
{
  FarsightUDPTransmitter *self = FARSIGHT_UDP_TRANSMITTER (object);

  switch (prop_id) {
    case PROP_STUN_IP:
      g_value_set_string (value, self->priv->stun_ip);
      break;
    case PROP_STUN_PORT:
      g_value_set_uint (value, self->priv->stun_port);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}


static GObject *
farsight_udp_transmitter_new (void)
{
  return g_object_new(FARSIGHT_TYPE_UDP_TRANSMITTER, NULL);
}

static void
farsight_udp_transmitter_use_local_ips (FarsightUDPTransmitter *transmitter)
{
  FarsightTransportInfo *trans;
  GList *ips = NULL;
  gint i = 1;
  GList *current;

  ips = farsight_get_local_ips(FALSE);
 
  for (current = ips; current; current = g_list_next(current)) {
    trans = g_new0 (FarsightTransportInfo,1);
    trans->candidate_id = g_strdup_printf ("L%d", i++);
    trans->component = 1;
    trans->ip = g_strdup (current->data);
    trans->port = transmitter->priv->local_port;
    trans->proto = FARSIGHT_NETWORK_PROTOCOL_UDP;
    trans->proto_subtype = g_strdup ("RTP");
    trans->proto_profile = g_strdup ("AVP");
    trans->preference = 1.0;
    trans->type = FARSIGHT_CANDIDATE_TYPE_LOCAL;
    farsight_transmitter_signal_new_native_candidate (FARSIGHT_TRANSMITTER (transmitter), trans);
  }

  farsight_transmitter_signal_native_candidates_prepared (FARSIGHT_TRANSMITTER (transmitter));

  /* free list of ips */
  g_list_foreach (ips, (GFunc) g_free, NULL);
  g_list_free (ips);

}


static gboolean
farsight_udp_transmitter_start_stun (FarsightUDPTransmitter *transmitter) 
{
  StunMessage *msg;
  gchar *packed;
  guint length;
  struct sockaddr_in addrto;
  struct addrinfo hints;
  struct addrinfo *result = NULL;
  int retval;

  g_return_val_if_fail (transmitter != NULL, FALSE);
  g_return_val_if_fail (transmitter->priv->local_socket >= 0, FALSE);
  g_return_val_if_fail (transmitter->priv->stun_ioc == NULL, FALSE);
  g_return_val_if_fail (transmitter->priv->stun_port != 0, FALSE);
  g_return_val_if_fail (transmitter->priv->stun_ip != NULL, FALSE);

  g_debug ("Trying to get outside IP using STUN server %s:%u\n",
      transmitter->priv->stun_ip, transmitter->priv->stun_port);

  memset (&hints, 0, sizeof (struct addrinfo));
  hints.ai_family = AF_INET;
  hints.ai_flags = AI_NUMERICHOST;
  retval = getaddrinfo (transmitter->priv->stun_ip, NULL, &hints, &result);
  if (retval != 0) {
    g_warning ("Invalid IP address for STUN server: %s", gai_strerror (retval));
    return FALSE;
  }
  memcpy (&addrto, result->ai_addr, sizeof(struct sockaddr_in));
  freeaddrinfo (result);

  addrto.sin_family = AF_INET;
  addrto.sin_port = htons (transmitter->priv->stun_port);

  msg = stun_message_new (STUN_MESSAGE_BINDING_REQUEST, NULL, 0);
  if (!msg)
    return FALSE;

  
  length = stun_message_pack (msg, &packed);

  if (sendto (transmitter->priv->local_socket, packed, length, 0, 
          (struct sockaddr *)&addrto, sizeof(addrto)) != length) {
    g_free (packed);
    stun_message_free (msg);
    return FALSE;
  }

  g_free (packed);
  stun_message_free (msg);

  transmitter->priv->stun_ioc =
    g_io_channel_unix_new (transmitter->priv->local_socket);

  transmitter->priv->stun_source =
      g_io_add_watch (transmitter->priv->stun_ioc, G_IO_IN,
          farsight_udp_transmitter_handle_stun, transmitter);

  transmitter->priv->stun_source_error =
      g_io_add_watch (transmitter->priv->stun_ioc, G_IO_ERR|G_IO_HUP|G_IO_NVAL,
          farsight_udp_transmitter_handle_stun_error, transmitter);

  transmitter->priv->stun_timeoutid = g_timeout_add (
      DEFAULT_STUN_TIMEOUT * 1000, farsight_udp_transmitter_stun_timeout, 
      transmitter);

  if (!transmitter->priv->stun_source ||
      !transmitter->priv->stun_source_error ||
      !transmitter->priv->stun_timeoutid) {
    farsight_udp_transmitter_stop_stun (transmitter);
    return FALSE;
  }


  return TRUE;
}

static void
farsight_udp_transmitter_stop_stun (FarsightUDPTransmitter *transmitter)
{
  g_return_if_fail (transmitter);
  g_return_if_fail (FARSIGHT_IS_UDP_TRANSMITTER (transmitter));


  if (transmitter->priv->stun_ioc) {
    g_io_channel_unref (transmitter->priv->stun_ioc);
    transmitter->priv->stun_ioc = NULL;
  }

  if (transmitter->priv->stun_source) {
    g_source_remove (transmitter->priv->stun_source);
    transmitter->priv->stun_source = 0;
  }

  if (transmitter->priv->stun_source_error) {
    g_source_remove (transmitter->priv->stun_source_error);
    transmitter->priv->stun_source_error = 0;
  }

  if (transmitter->priv->stun_timeoutid) {
    g_source_remove (transmitter->priv->stun_timeoutid);
    transmitter->priv->stun_timeoutid = 0;
  }

  farsight_udp_transmitter_configure_source (transmitter);
}

static gboolean 
farsight_udp_transmitter_handle_stun (GIOChannel *source,
    GIOCondition condition, gpointer data)
{
  FarsightUDPTransmitter *transmitter = FARSIGHT_UDP_TRANSMITTER (data);
  FarsightTransportInfo *trans = NULL;
  gchar buffer[256];
  int read;
  
  StunMessage *msg;
  StunAttribute **attr;

  read = recvfrom (transmitter->priv->local_socket, buffer, 256, 
      MSG_DONTWAIT, NULL, NULL);

  if (read < 0) {
    if (errno == EAGAIN) {
      g_debug ("Got EAGAIN, but we had something?\n");
      return TRUE;
    }
    perror ("stun error\n");
    goto out_err;
  }

  g_debug ("Got some kind of STUN reply\n");

  msg = stun_message_unpack (read, buffer);
  if (!msg) {
    g_warning ("Invalid STUN reply");
    goto out_err;
  }

  for (attr = msg->attributes; *attr; attr++) {
    if ((*attr)->type == STUN_ATTRIBUTE_MAPPED_ADDRESS) {

      trans = g_new0 (FarsightTransportInfo,1);
      trans->candidate_id = g_strdup ("L1");
      trans->component = 1;
      trans->ip = g_strdup_printf ("%u.%u.%u.%u",
          ((*attr)->address.ip & 0xff000000) >> 24,
          ((*attr)->address.ip & 0x00ff0000) >> 16,
          ((*attr)->address.ip & 0x0000ff00) >>  8,
          ((*attr)->address.ip & 0x000000ff));
      trans->port = (*attr)->address.port;
      trans->proto = FARSIGHT_NETWORK_PROTOCOL_UDP;
      trans->proto_subtype = g_strdup ("RTP");
      trans->proto_profile = g_strdup ("AVP");
      trans->preference = 1.0;
      trans->type = FARSIGHT_CANDIDATE_TYPE_DERIVED;
      farsight_transmitter_signal_new_native_candidate (FARSIGHT_TRANSMITTER (transmitter), 
          trans);

      g_message ("Stun server says we are %u.%u.%u.%u %u\n", 
          ((*attr)->address.ip & 0xff000000) >> 24,
          ((*attr)->address.ip & 0x00ff0000) >> 16,
          ((*attr)->address.ip & 0x0000ff00) >>  8,
          ((*attr)->address.ip & 0x000000ff),(*attr)->address.port);

      farsight_transmitter_signal_native_candidates_prepared (FARSIGHT_TRANSMITTER (transmitter));

      break;
    }
  }

  stun_message_free (msg);

  if (!trans)
    g_debug ("Got STUN reply without a mapped-address");

 out_err:

  if (trans) {
    /* We got an adress */
    farsight_udp_transmitter_stop_stun (transmitter);
    return FALSE;
  } else {
    /* No address, lets see if another valid STUN replies comes later */
    return TRUE;
  }
}

static gboolean 
farsight_udp_transmitter_handle_stun_error (GIOChannel *source,
    GIOCondition condition, gpointer data)
{
  FarsightUDPTransmitter *transmitter = FARSIGHT_UDP_TRANSMITTER (data);

  farsight_udp_transmitter_stop_stun (transmitter);

  farsight_transmitter_signal_error (FARSIGHT_TRANSMITTER (transmitter), 
      FARSIGHT_TRANSMITTER_ERROR_UNKNOWN,
      "Socket error while waiting for STUN reply");

  return FALSE;
}

static gboolean 
farsight_udp_transmitter_stun_timeout (gpointer data)
{
  FarsightUDPTransmitter *transmitter = FARSIGHT_UDP_TRANSMITTER (data);

  if (!transmitter)
    return FALSE;

  farsight_udp_transmitter_stop_stun (transmitter);

  g_message ("Timeout after %d seconds while trying to do STUN, "
      "using local interfaces instead", DEFAULT_STUN_TIMEOUT);

  farsight_udp_transmitter_use_local_ips (transmitter);

  return FALSE;
}

static gboolean 
init_plugin (FarsightPlugin *plugin)
{
  farsight_udp_transmitter_register_type (G_TYPE_MODULE (plugin));
  
  return TRUE;
}

static FarsightPluginInfo plugin_info = {
    FARSIGHT_MAJOR_VERSION,
    FARSIGHT_MINOR_VERSION,
    "RAW UDP transmitter",                              /* description */
    "0.1.0",                                            /* version */
    "Farsight Project",  /* author */
    "http://farsight.sf.net/",                          /* homepage */
    NULL,                                               /* unload */
    farsight_udp_transmitter_new,                       /* new */
};

FARSIGHT_INIT_PLUGIN (init_plugin, plugin_info);

Generated by  Doxygen 1.6.0   Back to index