multisocketsink: Re-add QoS DSCP property
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 16 Jan 2012 11:17:00 +0000 (12:17 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 16 Jan 2012 11:17:00 +0000 (12:17 +0100)
gst/tcp/gstmultisocketsink.c
gst/tcp/gstmultisocketsink.h

index 157f332ab7eb6871e1b9ca27764bad9d3567fc14..8622d3d1ea3f305497bd91085219fbc083496fef 100644 (file)
 #include "gstmultisocketsink.h"
 #include "gsttcp-marshal.h"
 
+#ifndef G_OS_WIN32
+#include <netinet/in.h>
+#endif
+
 #define NOT_IMPLEMENTED 0
 
 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
@@ -160,6 +164,7 @@ enum
 #define DEFAULT_BURST_FORMAT            GST_FORMAT_UNDEFINED
 #define DEFAULT_BURST_VALUE             0
 
+#define DEFAULT_QOS_DSCP                -1
 #define DEFAULT_HANDLE_READ             TRUE
 
 #define DEFAULT_RESEND_STREAMHEADER      TRUE
@@ -192,6 +197,8 @@ enum
   PROP_BURST_FORMAT,
   PROP_BURST_VALUE,
 
+  PROP_QOS_DSCP,
+
   PROP_HANDLE_READ,
 
   PROP_RESEND_STREAMHEADER,
@@ -406,6 +413,12 @@ gst_multi_socket_sink_class_init (GstMultiSocketSinkClass * klass)
           "The amount of burst expressed in burst-unit", 0, G_MAXUINT64,
           DEFAULT_BURST_VALUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_QOS_DSCP,
+      g_param_spec_int ("qos-dscp", "QoS diff srv code point",
+          "Quality of Service, differentiated services code point (-1 default)",
+          -1, 63, DEFAULT_QOS_DSCP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   /**
    * GstMultiSocketSink::handle-read
    *
@@ -634,6 +647,7 @@ gst_multi_socket_sink_init (GstMultiSocketSink * this)
   this->def_burst_format = DEFAULT_BURST_FORMAT;
   this->def_burst_value = DEFAULT_BURST_VALUE;
 
+  this->qos_dscp = DEFAULT_QOS_DSCP;
   this->handle_read = DEFAULT_HANDLE_READ;
 
   this->resend_streamheader = DEFAULT_RESEND_STREAMHEADER;
@@ -661,6 +675,87 @@ gst_multi_socket_sink_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static gint
+setup_dscp_client (GstMultiSocketSink * sink, GstSocketClient * client)
+{
+#ifndef IP_TOS
+  return 0;
+#else
+  gint tos;
+  gint ret;
+  int fd;
+  union gst_sockaddr
+  {
+    struct sockaddr sa;
+    struct sockaddr_in6 sa_in6;
+    struct sockaddr_storage sa_stor;
+  } sa;
+  socklen_t slen = sizeof (sa);
+  gint af;
+
+  /* don't touch */
+  if (sink->qos_dscp < 0)
+    return 0;
+
+  fd = g_socket_get_fd (client->socket);
+
+  if ((ret = getsockname (fd, &sa.sa, &slen)) < 0) {
+    GST_DEBUG_OBJECT (sink, "could not get sockname: %s", g_strerror (errno));
+    return ret;
+  }
+
+  af = sa.sa.sa_family;
+
+  /* if this is an IPv4-mapped address then do IPv4 QoS */
+  if (af == AF_INET6) {
+
+    GST_DEBUG_OBJECT (sink, "check IP6 socket");
+    if (IN6_IS_ADDR_V4MAPPED (&(sa.sa_in6.sin6_addr))) {
+      GST_DEBUG_OBJECT (sink, "mapped to IPV4");
+      af = AF_INET;
+    }
+  }
+
+  /* extract and shift 6 bits of the DSCP */
+  tos = (sink->qos_dscp & 0x3f) << 2;
+
+  switch (af) {
+    case AF_INET:
+      ret = setsockopt (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
+      break;
+    case AF_INET6:
+#ifdef IPV6_TCLASS
+      ret = setsockopt (fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos));
+      break;
+#endif
+    default:
+      ret = 0;
+      GST_ERROR_OBJECT (sink, "unsupported AF");
+      break;
+  }
+  if (ret)
+    GST_DEBUG_OBJECT (sink, "could not set DSCP: %s", g_strerror (errno));
+
+  return ret;
+#endif
+}
+
+static void
+setup_dscp (GstMultiSocketSink * sink)
+{
+  GList *clients;
+
+  CLIENTS_LOCK (sink);
+  for (clients = sink->clients; clients; clients = clients->next) {
+    GstSocketClient *client;
+
+    client = clients->data;
+
+    setup_dscp_client (sink, client);
+  }
+  CLIENTS_UNLOCK (sink);
+}
+
 /* "add-full" signal implementation */
 void
 gst_multi_socket_sink_add_full (GstMultiSocketSink * sink, GSocket * socket,
@@ -736,6 +831,8 @@ gst_multi_socket_sink_add_full (GstMultiSocketSink * sink, GSocket * socket,
     g_source_attach (client->source, sink->main_context);
   }
 
+  setup_dscp_client (sink, client);
+
   CLIENTS_UNLOCK (sink);
 
   g_signal_emit (G_OBJECT (sink),
@@ -2383,6 +2480,10 @@ gst_multi_socket_sink_set_property (GObject * object, guint prop_id,
     case PROP_BURST_VALUE:
       multisocketsink->def_burst_value = g_value_get_uint64 (value);
       break;
+    case PROP_QOS_DSCP:
+      multisocketsink->qos_dscp = g_value_get_int (value);
+      setup_dscp (multisocketsink);
+      break;
     case PROP_HANDLE_READ:
       multisocketsink->handle_read = g_value_get_boolean (value);
       break;
@@ -2459,6 +2560,9 @@ gst_multi_socket_sink_get_property (GObject * object, guint prop_id,
     case PROP_BURST_VALUE:
       g_value_set_uint64 (value, multisocketsink->def_burst_value);
       break;
+    case PROP_QOS_DSCP:
+      g_value_set_int (value, multisocketsink->qos_dscp);
+      break;
     case PROP_HANDLE_READ:
       g_value_set_boolean (value, multisocketsink->handle_read);
       break;
index 051b4d51faa8f4809717de8f31a20d733225d01d..f373d90ae848d25e9dfd70c00245159f2de2c188 100644 (file)
@@ -190,6 +190,7 @@ struct _GstMultiSocketSink {
   gboolean previous_buffer_in_caps;
 
   guint mtu;
+  gint qos_dscp;
   gboolean handle_read;
 
   GArray *bufqueue;     /* global queue of buffers */