tcpserversrc: Add stats property
authorVivia Nikolaidou <vivia@ahiru.eu>
Thu, 12 Mar 2020 07:38:58 +0000 (09:38 +0200)
committerVivia Nikolaidou <vivia@ahiru.eu>
Wed, 6 May 2020 12:25:44 +0000 (15:25 +0300)
Like in tcpclientsrc

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/651>

gst/tcp/gsttcpclientsrc.c
gst/tcp/gsttcpserversrc.c
gst/tcp/gsttcpserversrc.h
gst/tcp/gsttcpsrcstats.c [new file with mode: 0644]
gst/tcp/gsttcpsrcstats.h [new file with mode: 0644]
gst/tcp/meson.build

index b007650..d64856e 100644 (file)
 #include "config.h"
 #endif
 
-/* macOS and iOS have the .h files but the tcp_info struct is private API */
-#if defined(HAVE_NETINET_TCP_H) && defined(HAVE_NETINET_IN_H) && defined(HAVE_SYS_SOCKET_H)
-#include <netinet/tcp.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#if defined(TCP_INFO)
-#define HAVE_SOCKET_METRIC_HEADERS
-#endif
-#endif
-
 #include <gst/gst-i18n-plugin.h>
 #include "gsttcpclientsrc.h"
+#include "gsttcpsrcstats.h"
 #include "gsttcp.h"
 
 GST_DEBUG_CATEGORY_STATIC (tcpclientsrc_debug);
@@ -576,36 +567,7 @@ gst_tcp_client_src_get_stats (GstTCPClientSrc * src)
   s = gst_structure_new ("GstTCPClientSrcStats",
       "bytes-received", G_TYPE_UINT64, src->bytes_received, NULL);
 
-#ifdef HAVE_SOCKET_METRIC_HEADERS
-  if (src->socket) {
-    struct tcp_info info;
-    socklen_t info_len = sizeof info;
-    int fd;
-
-    fd = g_socket_get_fd (src->socket);
-
-    if (getsockopt (fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) == 0) {
-      /* this is system-specific */
-#ifdef HAVE_BSD_TCP_INFO
-      gst_structure_set (s,
-          "reordering", G_TYPE_UINT, info.__tcpi_reordering,
-          "unacked", G_TYPE_UINT, info.__tcpi_unacked,
-          "sacked", G_TYPE_UINT, info.__tcpi_sacked,
-          "lost", G_TYPE_UINT, info.__tcpi_lost,
-          "retrans", G_TYPE_UINT, info.__tcpi_retrans,
-          "fackets", G_TYPE_UINT, info.__tcpi_fackets, NULL);
-#elif defined(HAVE_LINUX_TCP_INFO)
-      gst_structure_set (s,
-          "reordering", G_TYPE_UINT, info.tcpi_reordering,
-          "unacked", G_TYPE_UINT, info.tcpi_unacked,
-          "sacked", G_TYPE_UINT, info.tcpi_sacked,
-          "lost", G_TYPE_UINT, info.tcpi_lost,
-          "retrans", G_TYPE_UINT, info.tcpi_retrans,
-          "fackets", G_TYPE_UINT, info.tcpi_fackets, NULL);
-#endif
-    }
-  }
-#endif
+  gst_tcp_stats_from_socket (s, src->socket);
 
   return s;
 }
index 0218510..328f916 100644 (file)
@@ -42,6 +42,7 @@
 
 #include <gst/gst-i18n-plugin.h>
 #include "gsttcp.h"
+#include "gsttcpsrcstats.h"
 #include "gsttcpserversrc.h"
 
 GST_DEBUG_CATEGORY_STATIC (tcpserversrc_debug);
@@ -62,7 +63,8 @@ enum
   PROP_0,
   PROP_HOST,
   PROP_PORT,
-  PROP_CURRENT_PORT
+  PROP_CURRENT_PORT,
+  PROP_STATS,
 };
 
 #define gst_tcp_server_src_parent_class parent_class
@@ -81,6 +83,7 @@ static void gst_tcp_server_src_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_tcp_server_src_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
+static GstStructure *gst_tcp_server_src_get_stats (GstTCPServerSrc * src);
 
 static void
 gst_tcp_server_src_class_init (GstTCPServerSrcClass * klass)
@@ -123,6 +126,30 @@ gst_tcp_server_src_class_init (GstTCPServerSrcClass * klass)
           "The port number the socket is currently bound to", 0,
           TCP_HIGHEST_PORT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
+  /**
+   * GstTCPServerSrc::stats:
+   *
+   * Sends a GstStructure with statistics. We count bytes-received in a
+   * platform-independent way and the rest via the tcp_info struct, if it's
+   * available. The OS takes care of the TCP layer for us so we can't know it
+   * from here.
+   *
+   * Struct members:
+   *
+   * bytes-received (uint64): Total bytes received (platform-independent)
+   * reordering (uint): Amount of reordering (linux-specific)
+   * unacked (uint): Un-acked packets (linux-specific)
+   * sacked (uint): Selective acked packets (linux-specific)
+   * lost (uint): Lost packets (linux-specific)
+   * retrans (uint): Retransmits (linux-specific)
+   * fackets (uint): Forward acknowledgement (linux-specific)
+   *
+   * Since: 1.18
+   */
+  g_object_class_install_property (gobject_class, PROP_STATS,
+      g_param_spec_boxed ("stats", "Stats", "Retrieve a statistics structure",
+          GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
   gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
 
   gst_element_class_set_static_metadata (gstelement_class,
@@ -171,6 +198,8 @@ gst_tcp_server_src_finalize (GObject * gobject)
   g_free (src->host);
   src->host = NULL;
 
+  gst_clear_structure (&src->stats);
+
   G_OBJECT_CLASS (parent_class)->finalize (gobject);
 }
 
@@ -277,6 +306,7 @@ gst_tcp_server_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
     ret = GST_FLOW_OK;
     gst_buffer_unmap (*outbuf, &map);
     gst_buffer_resize (*outbuf, 0, rret);
+    src->bytes_received += read;
 
     GST_LOG_OBJECT (src,
         "Returning buffer from _get of size %" G_GSIZE_FORMAT ", ts %"
@@ -372,6 +402,9 @@ gst_tcp_server_src_get_property (GObject * object, guint prop_id,
     case PROP_CURRENT_PORT:
       g_value_set_int (value, g_atomic_int_get (&tcpserversrc->current_port));
       break;
+    case PROP_STATS:
+      g_value_take_boxed (value, gst_tcp_server_src_get_stats (tcpserversrc));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -389,6 +422,9 @@ gst_tcp_server_src_start (GstBaseSrc * bsrc)
   GResolver *resolver;
   gint bound_port = 0;
 
+  src->bytes_received = 0;
+  gst_clear_structure (&src->stats);
+
   /* look up name if we need to */
   addr = g_inet_address_new_from_string (src->host);
   if (!addr) {
@@ -516,6 +552,8 @@ gst_tcp_server_src_stop (GstBaseSrc * bsrc)
   if (src->client_socket) {
     GST_DEBUG_OBJECT (src, "closing socket");
 
+    src->stats = gst_tcp_server_src_get_stats (src);
+
     if (!g_socket_close (src->client_socket, &err)) {
       GST_ERROR_OBJECT (src, "Failed to close socket: %s", err->message);
       g_clear_error (&err);
@@ -564,3 +602,21 @@ gst_tcp_server_src_unlock_stop (GstBaseSrc * bsrc)
 
   return TRUE;
 }
+
+
+static GstStructure *
+gst_tcp_server_src_get_stats (GstTCPServerSrc * src)
+{
+  GstStructure *s;
+
+  /* we can't get the values post stop so just return the saved ones */
+  if (src->stats)
+    return gst_structure_copy (src->stats);
+
+  s = gst_structure_new ("GstTCPServerSrcStats",
+      "bytes-received", G_TYPE_UINT64, src->bytes_received, NULL);
+
+  gst_tcp_stats_from_socket (s, src->client_socket);
+
+  return s;
+}
index ad0a313..8cf5f73 100644 (file)
@@ -61,6 +61,9 @@ struct _GstTCPServerSrc {
   GCancellable *cancellable;
   GSocket *server_socket;
   GSocket *client_socket;
+
+  guint64 bytes_received;
+  GstStructure *stats;
 };
 
 struct _GstTCPServerSrcClass {
diff --git a/gst/tcp/gsttcpsrcstats.c b/gst/tcp/gsttcpsrcstats.c
new file mode 100644 (file)
index 0000000..d942cdc
--- /dev/null
@@ -0,0 +1,38 @@
+/* macOS and iOS have the .h files but the tcp_info struct is private API */
+#if defined(HAVE_NETINET_TCP_H) && defined(HAVE_NETINET_IN_H) && defined(HAVE_SYS_SOCKET_H)
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#if defined(TCP_INFO)
+#define HAVE_SOCKET_METRIC_HEADERS
+#endif
+#endif
+
+#include "gsttcpsrcstats.h"
+
+void
+gst_tcp_stats_from_socket (GstStructure * structure, GSocket * socket)
+{
+#ifdef HAVE_SOCKET_METRIC_HEADERS
+  if (getsockopt (fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) == 0) {
+    /* this is system-specific */
+#ifdef HAVE_BSD_TCP_INFO
+    gst_structure_set (s,
+        "reordering", G_TYPE_UINT, info.__tcpi_reordering,
+        "unacked", G_TYPE_UINT, info.__tcpi_unacked,
+        "sacked", G_TYPE_UINT, info.__tcpi_sacked,
+        "lost", G_TYPE_UINT, info.__tcpi_lost,
+        "retrans", G_TYPE_UINT, info.__tcpi_retrans,
+        "fackets", G_TYPE_UINT, info.__tcpi_fackets, NULL);
+#elif defined(HAVE_LINUX_TCP_INFO)
+    gst_structure_set (s,
+        "reordering", G_TYPE_UINT, info.tcpi_reordering,
+        "unacked", G_TYPE_UINT, info.tcpi_unacked,
+        "sacked", G_TYPE_UINT, info.tcpi_sacked,
+        "lost", G_TYPE_UINT, info.tcpi_lost,
+        "retrans", G_TYPE_UINT, info.tcpi_retrans,
+        "fackets", G_TYPE_UINT, info.tcpi_fackets, NULL);
+#endif
+  }
+#endif
+}
diff --git a/gst/tcp/gsttcpsrcstats.h b/gst/tcp/gsttcpsrcstats.h
new file mode 100644 (file)
index 0000000..5a75153
--- /dev/null
@@ -0,0 +1,4 @@
+#include <gst/gst.h>
+#include <gio/gio.h>
+
+void gst_tcp_stats_from_socket (GstStructure *structure, GSocket *socket);
index d89e265..93dfb60 100644 (file)
@@ -6,6 +6,7 @@ tcp_sources = [
   'gsttcpclientsink.c',
   'gsttcpserversrc.c',
   'gsttcpserversink.c',
+  'gsttcpsrcstats.c',
   'gsttcpplugin.c',
 ]