#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);
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;
}
#include <gst/gst-i18n-plugin.h>
#include "gsttcp.h"
+#include "gsttcpsrcstats.h"
#include "gsttcpserversrc.h"
GST_DEBUG_CATEGORY_STATIC (tcpserversrc_debug);
PROP_0,
PROP_HOST,
PROP_PORT,
- PROP_CURRENT_PORT
+ PROP_CURRENT_PORT,
+ PROP_STATS,
};
#define gst_tcp_server_src_parent_class parent_class
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)
"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,
g_free (src->host);
src->host = NULL;
+ gst_clear_structure (&src->stats);
+
G_OBJECT_CLASS (parent_class)->finalize (gobject);
}
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 %"
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;
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) {
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);
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;
+}
GCancellable *cancellable;
GSocket *server_socket;
GSocket *client_socket;
+
+ guint64 bytes_received;
+ GstStructure *stats;
};
struct _GstTCPServerSrcClass {
--- /dev/null
+/* 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
+}
--- /dev/null
+#include <gst/gst.h>
+#include <gio/gio.h>
+
+void gst_tcp_stats_from_socket (GstStructure *structure, GSocket *socket);
'gsttcpclientsink.c',
'gsttcpserversrc.c',
'gsttcpserversink.c',
+ 'gsttcpsrcstats.c',
'gsttcpplugin.c',
]