tcpserversink: Port to GIO

And change multifdsink to GIO too and rename it to multisocketsink
because it only works on GSockets now, not generic fds.
This commit is contained in:
Sebastian Dröge 2012-01-16 10:08:24 +01:00
parent d29c7826ab
commit 17254bbd23
10 changed files with 949 additions and 1193 deletions

View file

@ -82,7 +82,7 @@ EXTRA_HFILES = \
$(top_srcdir)/gst/playback/gstsubtitleoverlay.h \
$(top_srcdir)/gst/audiorate/gstaudiorate.h \
$(top_srcdir)/gst/audioresample/gstaudioresample.h \
$(top_srcdir)/gst/tcp/gstmultifdsink.h \
$(top_srcdir)/gst/tcp/gstmultisocketsink.h \
$(top_srcdir)/gst/tcp/gsttcpclientsrc.h \
$(top_srcdir)/gst/tcp/gsttcpclientsink.h \
$(top_srcdir)/gst/tcp/gsttcpserversrc.h \

View file

@ -16,8 +16,8 @@ BUILT_SOURCES = $(built_sources) $(built_headers)
libgsttcp_la_SOURCES = \
gsttcpplugin.c \
gsttcp.c \
gstmultifdsink.c \
gsttcpclientsrc.c gsttcpclientsink.c \
gstmultisocketsink.c \
gsttcpserversrc.c gsttcpserversink.c
nodist_libgsttcp_la_SOURCES = \
@ -29,10 +29,9 @@ libgsttcp_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS)
libgsttcp_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = \
gsttcpplugin.h \
gsttcp.h \
gstmultifdsink.h \
gsttcpclientsrc.h gsttcpclientsink.h \
gstmultisocketsink.h \
gsttcpserversrc.h gsttcpserversink.h
CLEANFILES = $(BUILT_SOURCES)

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,8 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
* Copyright (C) <2011> Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -19,38 +21,37 @@
*/
#ifndef __GST_MULTI_FD_SINK_H__
#define __GST_MULTI_FD_SINK_H__
#ifndef __GST_MULTI_SOCKET_SINK_H__
#define __GST_MULTI_SOCKET_SINK_H__
#include <gst/gst.h>
#include <gst/base/gstbasesink.h>
#include <gio/gio.h>
G_BEGIN_DECLS
#include "gsttcp.h"
#define GST_TYPE_MULTI_FD_SINK \
(gst_multi_fd_sink_get_type())
#define GST_MULTI_FD_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTI_FD_SINK,GstMultiFdSink))
#define GST_MULTI_FD_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTI_FD_SINK,GstMultiFdSinkClass))
#define GST_IS_MULTI_FD_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTI_FD_SINK))
#define GST_IS_MULTI_FD_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTI_FD_SINK))
#define GST_MULTI_FD_SINK_GET_CLASS(klass) \
(G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_MULTI_FD_SINK, GstMultiFdSinkClass))
#define GST_TYPE_MULTI_SOCKET_SINK \
(gst_multi_socket_sink_get_type())
#define GST_MULTI_SOCKET_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTI_SOCKET_SINK,GstMultiSocketSink))
#define GST_MULTI_SOCKET_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTI_SOCKET_SINK,GstMultiSocketSinkClass))
#define GST_IS_MULTI_SOCKET_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTI_SOCKET_SINK))
#define GST_IS_MULTI_SOCKET_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTI_SOCKET_SINK))
#define GST_MULTI_SOCKET_SINK_GET_CLASS(klass) \
(G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_MULTI_SOCKET_SINK, GstMultiSocketSinkClass))
typedef struct _GstMultiFdSink GstMultiFdSink;
typedef struct _GstMultiFdSinkClass GstMultiFdSinkClass;
typedef struct _GstMultiSocketSink GstMultiSocketSink;
typedef struct _GstMultiSocketSinkClass GstMultiSocketSinkClass;
typedef enum {
GST_MULTI_FD_SINK_OPEN = (GST_ELEMENT_FLAG_LAST << 0),
GST_MULTI_SOCKET_SINK_OPEN = (GST_ELEMENT_FLAG_LAST << 0),
GST_MULTI_FD_SINK_FLAG_LAST = (GST_ELEMENT_FLAG_LAST << 2)
} GstMultiFdSinkFlags;
GST_MULTI_SOCKET_SINK_FLAG_LAST = (GST_ELEMENT_FLAG_LAST << 2)
} GstMultiSocketSinkFlags;
/**
* GstRecoverPolicy:
@ -95,23 +96,6 @@ typedef enum
GST_SYNC_METHOD_BURST_WITH_KEYFRAME
} GstSyncMethod;
/**
* GstTCPUnitType:
* @GST_TCP_UNIT_TYPE_UNDEFINED: undefined
* @GST_TCP_UNIT_TYPE_BUFFERS : buffers
* @GST_TCP_UNIT_TYPE_TIME : timeunits (in nanoseconds)
* @GST_TCP_UNIT_TYPE_BYTES : bytes
*
* The units used to specify limits.
*/
typedef enum
{
GST_TCP_UNIT_TYPE_UNDEFINED,
GST_TCP_UNIT_TYPE_BUFFERS,
GST_TCP_UNIT_TYPE_TIME,
GST_TCP_UNIT_TYPE_BYTES
} GstTCPUnitType;
/**
* GstClientStatus:
* @GST_CLIENT_STATUS_OK : client is ok
@ -123,7 +107,7 @@ typedef enum
* @GST_CLIENT_STATUS_FLUSHING : client is flushing out the remaining buffers.
*
* This specifies the reason why a client was removed from
* multifdsink and is received in the "client-removed" signal.
* multisocketsink and is received in the "client-removed" signal.
*/
typedef enum
{
@ -139,30 +123,29 @@ typedef enum
/* structure for a client
*/
typedef struct {
GstPollFD fd;
GSocket *socket;
GSource *source;
gint bufpos; /* position of this client in the global queue */
gint flushcount; /* the remaining number of buffers to flush out or -1 if the
client is not flushing. */
GstClientStatus status;
gboolean is_socket;
GSList *sending; /* the buffers we need to send */
gint bufoffset; /* offset in the first buffer */
gboolean discont;
gboolean caps_sent;
gboolean new_connection;
gboolean currently_removing;
/* method to sync client when connecting */
GstSyncMethod sync_method;
GstTCPUnitType burst_min_unit;
GstFormat burst_min_format;
guint64 burst_min_value;
GstTCPUnitType burst_max_unit;
GstFormat burst_max_format;
guint64 burst_max_value;
GstCaps *caps; /* caps of last queued buffer */
@ -176,19 +159,19 @@ typedef struct {
guint64 avg_queue_size;
guint64 first_buffer_ts;
guint64 last_buffer_ts;
} GstTCPClient;
} GstSocketClient;
#define CLIENTS_LOCK_INIT(fdsink) (g_static_rec_mutex_init(&fdsink->clientslock))
#define CLIENTS_LOCK_FREE(fdsink) (g_static_rec_mutex_free(&fdsink->clientslock))
#define CLIENTS_LOCK(fdsink) (g_static_rec_mutex_lock(&fdsink->clientslock))
#define CLIENTS_UNLOCK(fdsink) (g_static_rec_mutex_unlock(&fdsink->clientslock))
#define CLIENTS_LOCK_INIT(socketsink) (g_static_rec_mutex_init(&socketsink->clientslock))
#define CLIENTS_LOCK_FREE(socketsink) (g_static_rec_mutex_free(&socketsink->clientslock))
#define CLIENTS_LOCK(socketsink) (g_static_rec_mutex_lock(&socketsink->clientslock))
#define CLIENTS_UNLOCK(socketsink) (g_static_rec_mutex_unlock(&socketsink->clientslock))
/**
* GstMultiFdSink:
* GstMultiSocketSink:
*
* The multifdsink object structure.
* The multisocketsink object structure.
*/
struct _GstMultiFdSink {
struct _GstMultiSocketSink {
GstBaseSink element;
/*< private >*/
@ -197,17 +180,16 @@ struct _GstMultiFdSink {
GStaticRecMutex clientslock; /* lock to protect the clients list */
GList *clients; /* list of clients we are serving */
GHashTable *fd_hash; /* index on fd to client */
GHashTable *socket_hash; /* index on socket to client */
guint clients_cookie; /* Cookie to detect changes to the clients list */
gint mode;
GstPoll *fdset;
GMainContext *main_context;
GCancellable *cancellable;
GSList *streamheader; /* GSList of GstBuffers to use as streamheader */
gboolean previous_buffer_in_caps;
guint mtu;
gint qos_dscp;
gboolean handle_read;
GArray *bufqueue; /* global queue of buffers */
@ -217,14 +199,14 @@ struct _GstMultiFdSink {
/* these values are used to check if a client is reading fast
* enough and to control receovery */
GstTCPUnitType unit_type;/* the type of the units */
GstFormat unit_type;/* the format of the units */
gint64 units_max; /* max units to queue for a client */
gint64 units_soft_max; /* max units a client can lag before recovery starts */
GstRecoverPolicy recover_policy;
GstClockTime timeout; /* max amount of nanoseconds to remain idle */
GstSyncMethod def_sync_method; /* what method to use for connecting clients */
GstTCPUnitType def_burst_unit;
GstFormat def_burst_format;
guint64 def_burst_value;
/* these values are used to control the amount of data
@ -244,42 +226,41 @@ struct _GstMultiFdSink {
guint8 header_flags;
};
struct _GstMultiFdSinkClass {
struct _GstMultiSocketSinkClass {
GstBaseSinkClass parent_class;
/* element methods */
void (*add) (GstMultiFdSink *sink, int fd);
void (*add_full) (GstMultiFdSink *sink, int fd, GstSyncMethod sync,
GstTCPUnitType format, guint64 value,
GstTCPUnitType max_unit, guint64 max_value);
void (*remove) (GstMultiFdSink *sink, int fd);
void (*remove_flush) (GstMultiFdSink *sink, int fd);
void (*clear) (GstMultiFdSink *sink);
GValueArray* (*get_stats) (GstMultiFdSink *sink, int fd);
void (*add) (GstMultiSocketSink *sink, GSocket *socket);
void (*add_full) (GstMultiSocketSink *sink, GSocket *socket, GstSyncMethod sync,
GstFormat format, guint64 value,
GstFormat max_format, guint64 max_value);
void (*remove) (GstMultiSocketSink *sink, GSocket *socket);
void (*remove_flush) (GstMultiSocketSink *sink, GSocket *socket);
void (*clear) (GstMultiSocketSink *sink);
GstStructure* (*get_stats) (GstMultiSocketSink *sink, GSocket *socket);
/* vtable */
gboolean (*init) (GstMultiFdSink *sink);
gboolean (*wait) (GstMultiFdSink *sink, GstPoll *set);
gboolean (*close) (GstMultiFdSink *sink);
void (*removed) (GstMultiFdSink *sink, int fd);
gboolean (*init) (GstMultiSocketSink *sink);
gboolean (*close) (GstMultiSocketSink *sink);
void (*removed) (GstMultiSocketSink *sink, GSocket *socket);
/* signals */
void (*client_added) (GstElement *element, gint fd);
void (*client_removed) (GstElement *element, gint fd, GstClientStatus status);
void (*client_fd_removed) (GstElement *element, gint fd);
void (*client_added) (GstElement *element, GSocket *socket);
void (*client_removed) (GstElement *element, GSocket *socket, GstClientStatus status);
void (*client_socket_removed) (GstElement *element, GSocket *socket);
};
GType gst_multi_fd_sink_get_type (void);
GType gst_multi_socket_sink_get_type (void);
void gst_multi_fd_sink_add (GstMultiFdSink *sink, int fd);
void gst_multi_fd_sink_add_full (GstMultiFdSink *sink, int fd, GstSyncMethod sync,
GstTCPUnitType min_unit, guint64 min_value,
GstTCPUnitType max_unit, guint64 max_value);
void gst_multi_fd_sink_remove (GstMultiFdSink *sink, int fd);
void gst_multi_fd_sink_remove_flush (GstMultiFdSink *sink, int fd);
void gst_multi_fd_sink_clear (GstMultiFdSink *sink);
GValueArray* gst_multi_fd_sink_get_stats (GstMultiFdSink *sink, int fd);
void gst_multi_socket_sink_add (GstMultiSocketSink *sink, GSocket *socket);
void gst_multi_socket_sink_add_full (GstMultiSocketSink *sink, GSocket *socket, GstSyncMethod sync,
GstFormat min_format, guint64 min_value,
GstFormat max_format, guint64 max_value);
void gst_multi_socket_sink_remove (GstMultiSocketSink *sink, GSocket *socket);
void gst_multi_socket_sink_remove_flush (GstMultiSocketSink *sink, GSocket *socket);
void gst_multi_socket_sink_clear (GstMultiSocketSink *sink);
GstStructure* gst_multi_socket_sink_get_stats (GstMultiSocketSink *sink, GSocket *socket);
G_END_DECLS
#endif /* __GST_MULTI_FD_SINK_H__ */
#endif /* __GST_MULTI_SOCKET_SINK_H__ */

View file

@ -1,5 +1,4 @@
VOID:STRING,UINT
VOID:INT
VOID:INT,BOXED
VOID:INT,ENUM,INT,UINT64,INT,UINT64
BOXED:INT
VOID:OBJECT,ENUM
VOID:OBJECT,ENUM,ENUM,UINT64,ENUM,UINT64
BOXED:OBJECT

View file

@ -25,7 +25,6 @@
#include "gsttcp-enumtypes.h"
#include <gst/gst.h>
#undef GST_DISABLE_DEPRECATED
#define TCP_HIGHEST_PORT 65535
#define TCP_DEFAULT_HOST "localhost"

View file

@ -25,7 +25,7 @@
#include "gsttcpclientsink.h"
#include "gsttcpserversrc.h"
#include "gsttcpserversink.h"
#include "gstmultifdsink.h"
#include "gstmultisocketsink.h"
GST_DEBUG_CATEGORY (tcp_debug);
@ -44,8 +44,8 @@ plugin_init (GstPlugin * plugin)
if (!gst_element_register (plugin, "tcpserversrc", GST_RANK_NONE,
GST_TYPE_TCP_SERVER_SRC))
return FALSE;
if (!gst_element_register (plugin, "multifdsink", GST_RANK_NONE,
GST_TYPE_MULTI_FD_SINK))
if (!gst_element_register (plugin, "multisocketsink", GST_RANK_NONE,
GST_TYPE_MULTI_SOCKET_SINK))
return FALSE;
GST_DEBUG_CATEGORY_INIT (tcp_debug, "tcp", 0, "TCP calls");

View file

@ -1,40 +0,0 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_TCP_H__
#define __GST_TCP_H__
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
typedef enum
{
CONTROL_ZERO,
CONTROL_NONE,
CONTROL_TCP
} Gst_TCP_Control;
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_TCP_H__ */

View file

@ -41,10 +41,6 @@
#include <sys/ioctl.h>
#ifdef HAVE_FIONREAD_IN_SYS_FILIO
#include <sys/filio.h>
#endif
#include "gsttcp.h"
#include "gsttcpserversink.h"
#include "gsttcp-marshal.h"
@ -56,18 +52,17 @@ GST_DEBUG_CATEGORY_STATIC (tcpserversink_debug);
enum
{
ARG_0,
ARG_HOST,
ARG_PORT,
PROP_0,
PROP_HOST,
PROP_PORT,
};
static void gst_tcp_server_sink_finalize (GObject * gobject);
static gboolean gst_tcp_server_sink_handle_wait (GstMultiFdSink * sink,
GstPoll * set);
static gboolean gst_tcp_server_sink_init_send (GstMultiFdSink * this);
static gboolean gst_tcp_server_sink_close (GstMultiFdSink * this);
static void gst_tcp_server_sink_removed (GstMultiFdSink * sink, int fd);
static gboolean gst_tcp_server_sink_init_send (GstMultiSocketSink * this);
static gboolean gst_tcp_server_sink_close (GstMultiSocketSink * this);
static void gst_tcp_server_sink_removed (GstMultiSocketSink * sink,
GSocket * socket);
static void gst_tcp_server_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
@ -75,27 +70,28 @@ static void gst_tcp_server_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
#define gst_tcp_server_sink_parent_class parent_class
G_DEFINE_TYPE (GstTCPServerSink, gst_tcp_server_sink, GST_TYPE_MULTI_FD_SINK);
G_DEFINE_TYPE (GstTCPServerSink, gst_tcp_server_sink,
GST_TYPE_MULTI_SOCKET_SINK);
static void
gst_tcp_server_sink_class_init (GstTCPServerSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstMultiFdSinkClass *gstmultifdsink_class;
GstMultiSocketSinkClass *gstmultifdsink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstmultifdsink_class = (GstMultiFdSinkClass *) klass;
gstmultifdsink_class = (GstMultiSocketSinkClass *) klass;
gobject_class->set_property = gst_tcp_server_sink_set_property;
gobject_class->get_property = gst_tcp_server_sink_get_property;
gobject_class->finalize = gst_tcp_server_sink_finalize;
g_object_class_install_property (gobject_class, ARG_HOST,
g_object_class_install_property (gobject_class, PROP_HOST,
g_param_spec_string ("host", "host", "The host/IP to send the packets to",
TCP_DEFAULT_HOST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, ARG_PORT,
g_object_class_install_property (gobject_class, PROP_PORT,
g_param_spec_int ("port", "port", "The port to send the packets to",
0, TCP_HIGHEST_PORT, TCP_DEFAULT_PORT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
@ -106,7 +102,6 @@ gst_tcp_server_sink_class_init (GstTCPServerSinkClass * klass)
"Thomas Vander Stichele <thomas at apestaart dot org>");
gstmultifdsink_class->init = gst_tcp_server_sink_init_send;
gstmultifdsink_class->wait = gst_tcp_server_sink_handle_wait;
gstmultifdsink_class->close = gst_tcp_server_sink_close;
gstmultifdsink_class->removed = gst_tcp_server_sink_removed;
@ -121,7 +116,7 @@ gst_tcp_server_sink_init (GstTCPServerSink * this)
/* this->mtu = 1500; */
this->host = g_strdup (TCP_DEFAULT_HOST);
this->server_sock.fd = -1;
this->server_socket = NULL;
}
static void
@ -129,7 +124,11 @@ gst_tcp_server_sink_finalize (GObject * gobject)
{
GstTCPServerSink *this = GST_TCP_SERVER_SINK (gobject);
if (this->server_socket)
g_object_unref (this->server_socket);
this->server_socket = NULL;
g_free (this->host);
this->host = NULL;
G_OBJECT_CLASS (parent_class)->finalize (gobject);
}
@ -139,26 +138,31 @@ gst_tcp_server_sink_finalize (GObject * gobject)
static gboolean
gst_tcp_server_sink_handle_server_read (GstTCPServerSink * sink)
{
/* new client */
int client_sock_fd;
struct sockaddr_in client_address;
socklen_t client_address_len;
GSocket *client_socket;
GError *err = NULL;
/* For some stupid reason, client_address and client_address_len has to be
* zeroed */
memset (&client_address, 0, sizeof (client_address));
client_address_len = 0;
client_sock_fd =
accept (sink->server_sock.fd, (struct sockaddr *) &client_address,
&client_address_len);
if (client_sock_fd == -1)
/* wait on server socket for connections */
client_socket =
g_socket_accept (sink->server_socket, sink->element.cancellable, &err);
if (!client_socket)
goto accept_failed;
gst_multi_fd_sink_add (GST_MULTI_FD_SINK (sink), client_sock_fd);
gst_multi_socket_sink_add (GST_MULTI_SOCKET_SINK (sink), client_socket);
GST_DEBUG_OBJECT (sink, "added new client ip %s with fd %d",
inet_ntoa (client_address.sin_addr), client_sock_fd);
#ifndef GST_DISABLE_GST_DEBUG
{
GInetSocketAddress *addr =
G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (client_socket,
NULL));
gchar *ip =
g_inet_address_to_string (g_inet_socket_address_get_address (addr));
GST_DEBUG_OBJECT (sink, "added new client ip %s:%u with socket %p",
ip, g_inet_socket_address_get_port (addr), client_socket);
g_free (ip);
}
#endif
return TRUE;
@ -166,45 +170,47 @@ gst_tcp_server_sink_handle_server_read (GstTCPServerSink * sink)
accept_failed:
{
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
("Could not accept client on server socket %d: %s (%d)",
sink->server_sock.fd, g_strerror (errno), errno));
("Could not accept client on server socket %p: %s",
sink->server_socket, err->message));
g_clear_error (&err);
return FALSE;
}
}
static void
gst_tcp_server_sink_removed (GstMultiFdSink * sink, int fd)
gst_tcp_server_sink_removed (GstMultiSocketSink * sink, GSocket * socket)
{
#ifndef GST_DISABLE_GST_DEBUG
GstTCPServerSink *this = GST_TCP_SERVER_SINK (sink);
#endif
GError *err = NULL;
GST_LOG_OBJECT (this, "closing fd %d", fd);
if (close (fd) < 0) {
GST_WARNING_OBJECT (this, "error closing fd %d: %s", fd,
g_strerror (errno));
GST_DEBUG_OBJECT (this, "closing socket");
if (!g_socket_close (socket, &err)) {
GST_ERROR_OBJECT (this, "Failed to close socket: %s", err->message);
g_clear_error (&err);
}
}
static gboolean
gst_tcp_server_sink_handle_wait (GstMultiFdSink * sink, GstPoll * set)
gst_tcp_server_sink_socket_condition (GSocket * socket, GIOCondition condition,
GstTCPServerSink * sink)
{
GstTCPServerSink *this = GST_TCP_SERVER_SINK (sink);
if (gst_poll_fd_can_read (set, &this->server_sock)) {
/* handle new client connection on server socket */
if (!gst_tcp_server_sink_handle_server_read (this))
goto connection_failed;
if ((condition & G_IO_ERR)) {
goto error;
} else if ((condition & G_IO_IN) || (condition & G_IO_PRI)) {
if (!gst_tcp_server_sink_handle_server_read (sink))
return FALSE;
}
return TRUE;
/* ERRORS */
connection_failed:
{
GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
("client connection failed: %s", g_strerror (errno)));
return FALSE;
}
error:
GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL),
("client connection failed"));
return FALSE;
}
static void
@ -217,7 +223,7 @@ gst_tcp_server_sink_set_property (GObject * object, guint prop_id,
sink = GST_TCP_SERVER_SINK (object);
switch (prop_id) {
case ARG_HOST:
case PROP_HOST:
if (!g_value_get_string (value)) {
g_warning ("host property cannot be NULL");
break;
@ -225,10 +231,9 @@ gst_tcp_server_sink_set_property (GObject * object, guint prop_id,
g_free (sink->host);
sink->host = g_strdup (g_value_get_string (value));
break;
case ARG_PORT:
case PROP_PORT:
sink->server_port = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -245,13 +250,12 @@ gst_tcp_server_sink_get_property (GObject * object, guint prop_id,
sink = GST_TCP_SERVER_SINK (object);
switch (prop_id) {
case ARG_HOST:
case PROP_HOST:
g_value_set_string (value, sink->host);
break;
case ARG_PORT:
case PROP_PORT:
g_value_set_int (value, sink->server_port);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -261,111 +265,152 @@ gst_tcp_server_sink_get_property (GObject * object, guint prop_id,
/* create a socket for sending to remote machine */
static gboolean
gst_tcp_server_sink_init_send (GstMultiFdSink * parent)
gst_tcp_server_sink_init_send (GstMultiSocketSink * parent)
{
int ret;
GstTCPServerSink *this = GST_TCP_SERVER_SINK (parent);
GError *err = NULL;
GInetAddress *addr;
GSocketAddress *saddr;
/* create sending server socket */
if ((this->server_sock.fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
/* create the server listener socket */
this->server_socket =
g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_TCP, &err);
if (!this->server_socket)
goto no_socket;
GST_DEBUG_OBJECT (this, "opened sending server socket with fd %d",
this->server_sock.fd);
GST_DEBUG_OBJECT (this, "opened sending server socket with socket %p",
this->server_socket);
/* make address reusable */
ret = 1;
if (setsockopt (this->server_sock.fd, SOL_SOCKET, SO_REUSEADDR,
(void *) &ret, sizeof (ret)) < 0)
goto reuse_failed;
/* look up name if we need to */
addr = g_inet_address_new_from_string (this->host);
if (!addr) {
GResolver *resolver = g_resolver_get_default ();
GList *results;
/* keep connection alive; avoids SIGPIPE during write */
ret = 1;
if (setsockopt (this->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE,
(void *) &ret, sizeof (ret)) < 0)
goto keepalive_failed;
results =
g_resolver_lookup_by_name (resolver, this->host,
this->element.cancellable, &err);
if (!results)
goto name_resolve;
addr = G_INET_ADDRESS (g_object_ref (results->data));
/* name the socket */
memset (&this->server_sin, 0, sizeof (this->server_sin));
this->server_sin.sin_family = AF_INET; /* network socket */
this->server_sin.sin_port = htons (this->server_port); /* on port */
this->server_sin.sin_addr.s_addr = htonl (INADDR_ANY); /* for hosts */
g_resolver_free_addresses (results);
g_object_unref (resolver);
}
#ifndef GST_DISABLE_GST_DEBUG
{
gchar *ip = g_inet_address_to_string (addr);
GST_DEBUG_OBJECT (this, "IP address for host %s is %s", this->host, ip);
g_free (ip);
}
#endif
g_socket_set_blocking (this->server_socket, FALSE);
/* bind it */
saddr = g_inet_socket_address_new (addr, this->server_port);
GST_DEBUG_OBJECT (this, "binding server socket to address");
ret = bind (this->server_sock.fd, (struct sockaddr *) &this->server_sin,
sizeof (this->server_sin));
if (ret)
if (!g_socket_bind (this->server_socket, saddr, TRUE, &err))
goto bind_failed;
/* set the server socket to nonblocking */
fcntl (this->server_sock.fd, F_SETFL, O_NONBLOCK);
GST_DEBUG_OBJECT (this, "listening on server socket");
g_socket_set_listen_backlog (this->server_socket, TCP_BACKLOG);
GST_DEBUG_OBJECT (this, "listening on server socket %d with queue of %d",
this->server_sock.fd, TCP_BACKLOG);
if (listen (this->server_sock.fd, TCP_BACKLOG) == -1)
if (!g_socket_listen (this->server_socket, &err))
goto listen_failed;
GST_DEBUG_OBJECT (this,
"listened on server socket %d, returning from connection setup",
this->server_sock.fd);
"listened on server socket %p, returning from connection setup",
this->server_socket);
gst_poll_add_fd (parent->fdset, &this->server_sock);
gst_poll_fd_ctl_read (parent->fdset, &this->server_sock, TRUE);
this->server_source =
g_socket_create_source (this->server_socket,
G_IO_IN | G_IO_OUT | G_IO_PRI | G_IO_ERR | G_IO_HUP,
this->element.cancellable);
g_source_set_callback (this->server_source,
(GSourceFunc) gst_tcp_server_sink_socket_condition, gst_object_ref (this),
(GDestroyNotify) gst_object_unref);
g_source_attach (this->server_source, this->element.main_context);
return TRUE;
/* ERRORS */
no_socket:
{
GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE, (NULL), GST_ERROR_SYSTEM);
return FALSE;
}
reuse_failed:
{
gst_tcp_socket_close (&this->server_sock);
GST_ELEMENT_ERROR (this, RESOURCE, SETTINGS, (NULL),
("Could not setsockopt: %s", g_strerror (errno)));
return FALSE;
}
keepalive_failed:
{
gst_tcp_socket_close (&this->server_sock);
GST_ELEMENT_ERROR (this, RESOURCE, SETTINGS, (NULL),
("Could not setsockopt: %s", g_strerror (errno)));
return FALSE;
}
listen_failed:
{
gst_tcp_socket_close (&this->server_sock);
GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
("Could not listen on server socket: %s", g_strerror (errno)));
("Failed to create socket: %s", err->message));
g_clear_error (&err);
return FALSE;
}
name_resolve:
{
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
GST_DEBUG_OBJECT (this, "Cancelled name resolval");
} else {
GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
("Failed to resolve host '%s': %s", this->host, err->message));
}
g_clear_error (&err);
gst_tcp_server_sink_close (&this->element);
return FALSE;
}
bind_failed:
{
gst_tcp_socket_close (&this->server_sock);
switch (errno) {
default:
GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
("bind on port %d failed: %s", this->server_port,
g_strerror (errno)));
break;
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
GST_DEBUG_OBJECT (this, "Cancelled binding");
} else {
GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
("Failed to bind on host '%s:%d': %s", this->host, this->server_port,
err->message));
}
g_clear_error (&err);
g_object_unref (saddr);
g_object_unref (addr);
gst_tcp_server_sink_close (&this->element);
return FALSE;
}
listen_failed:
{
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
GST_DEBUG_OBJECT (this, "Cancelled listening");
} else {
GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
("Failed to listen on host '%s:%d': %s", this->host,
this->server_port, err->message));
}
g_clear_error (&err);
g_object_unref (saddr);
g_object_unref (addr);
gst_tcp_server_sink_close (&this->element);
return FALSE;
}
}
static gboolean
gst_tcp_server_sink_close (GstMultiFdSink * parent)
gst_tcp_server_sink_close (GstMultiSocketSink * parent)
{
GstTCPServerSink *this = GST_TCP_SERVER_SINK (parent);
if (this->server_sock.fd != -1) {
gst_poll_remove_fd (parent->fdset, &this->server_sock);
close (this->server_sock.fd);
this->server_sock.fd = -1;
if (this->server_source) {
g_source_destroy (this->server_source);
g_source_unref (this->server_source);
this->server_source = NULL;
}
if (this->server_socket) {
GError *err = NULL;
GST_DEBUG_OBJECT (this, "closing socket");
if (!g_socket_close (this->server_socket, &err)) {
GST_ERROR_OBJECT (this, "Failed to close socket: %s", err->message);
g_clear_error (&err);
}
g_object_unref (this->server_socket);
this->server_socket = NULL;
}
return TRUE;
}

View file

@ -24,23 +24,11 @@
#include <gst/gst.h>
#include <gio/gio.h>
G_BEGIN_DECLS
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include "gstmultifdsink.h"
#include "gstmultisocketsink.h"
#define GST_TYPE_TCP_SERVER_SINK \
(gst_tcp_server_sink_get_type())
@ -68,19 +56,17 @@ typedef enum {
* Opaque data structure.
*/
struct _GstTCPServerSink {
GstMultiFdSink element;
GstMultiSocketSink element;
/* server information */
int server_port;
gint server_port;
gchar *host;
struct sockaddr_in server_sin;
/* socket */
GstPollFD server_sock;
GSocket *server_socket;
GSource *server_source;
};
struct _GstTCPServerSinkClass {
GstMultiFdSinkClass parent_class;
GstMultiSocketSinkClass parent_class;
};
GType gst_tcp_server_sink_get_type (void);