gstreamer/gst/tcp/gsttcpserversink.c

461 lines
13 KiB
C
Raw Normal View History

/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
*
* 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., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-tcpserversink
* @title: tcpserversink
* @see_also: #multifdsink
Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipe... Original commit message from CVS: * docs/plugins/gst-plugins-base-plugins-docs.sgml: * docs/plugins/gst-plugins-base-plugins-overrides.txt: * docs/plugins/gst-plugins-base-plugins-sections.txt: * docs/plugins/gst-plugins-base-plugins.args: * docs/plugins/gst-plugins-base-plugins.hierarchy: * docs/plugins/gst-plugins-base-plugins.interfaces: * docs/plugins/gst-plugins-base-plugins.prerequisites: * docs/plugins/gst-plugins-base-plugins.signals: * docs/plugins/inspect/plugin-adder.xml: * docs/plugins/inspect/plugin-alsa.xml: * docs/plugins/inspect/plugin-audioconvert.xml: * docs/plugins/inspect/plugin-audiorate.xml: * docs/plugins/inspect/plugin-audioresample.xml: * docs/plugins/inspect/plugin-audiotestsrc.xml: * docs/plugins/inspect/plugin-cdparanoia.xml: * docs/plugins/inspect/plugin-decodebin.xml: * docs/plugins/inspect/plugin-ffmpegcolorspace.xml: * docs/plugins/inspect/plugin-gdp.xml: * docs/plugins/inspect/plugin-gnomevfs.xml: * docs/plugins/inspect/plugin-libvisual.xml: * docs/plugins/inspect/plugin-ogg.xml: * docs/plugins/inspect/plugin-pango.xml: * docs/plugins/inspect/plugin-playback.xml: * docs/plugins/inspect/plugin-queue2.xml: * docs/plugins/inspect/plugin-subparse.xml: * docs/plugins/inspect/plugin-tcp.xml: * docs/plugins/inspect/plugin-theora.xml: * docs/plugins/inspect/plugin-typefindfunctions.xml: * docs/plugins/inspect/plugin-uridecodebin.xml: * docs/plugins/inspect/plugin-video4linux.xml: * docs/plugins/inspect/plugin-videorate.xml: * docs/plugins/inspect/plugin-videoscale.xml: * docs/plugins/inspect/plugin-videotestsrc.xml: * docs/plugins/inspect/plugin-volume.xml: * docs/plugins/inspect/plugin-vorbis.xml: * docs/plugins/inspect/plugin-ximagesink.xml: * docs/plugins/inspect/plugin-xvimagesink.xml: * ext/alsa/gstalsamixer.c: * ext/alsa/gstalsasink.c: * ext/alsa/gstalsasrc.c: * ext/gio/gstgiosink.c: * ext/gio/gstgiosrc.c: * ext/gio/gstgiostreamsink.c: * ext/gio/gstgiostreamsrc.c: * ext/gnomevfs/gstgnomevfssink.c: * ext/gnomevfs/gstgnomevfssrc.c: * ext/ogg/gstoggdemux.c: * ext/ogg/gstoggmux.c: * ext/pango/gstclockoverlay.c: * ext/pango/gsttextoverlay.c: * ext/pango/gsttextrender.c: * ext/pango/gsttimeoverlay.c: * ext/theora/theoradec.c: * ext/theora/theoraenc.c: * ext/theora/theoraparse.c: * ext/vorbis/vorbisdec.c: * ext/vorbis/vorbisenc.c: * ext/vorbis/vorbisparse.c: * ext/vorbis/vorbistag.c: * gst/adder/gstadder.c: * gst/audioconvert/gstaudioconvert.c: * gst/audioresample/gstaudioresample.c: * gst/audiotestsrc/gstaudiotestsrc.c: * gst/ffmpegcolorspace/gstffmpegcolorspace.c: * gst/gdp/gstgdpdepay.c: * gst/gdp/gstgdppay.c: * gst/playback/gstdecodebin2.c: * gst/playback/gstplaybin.c: * gst/playback/gstplaybin2.c: * gst/playback/gstqueue2.c: * gst/playback/gsturidecodebin.c: * gst/tcp/gstmultifdsink.c: * gst/tcp/gsttcpserversink.c: * gst/videorate/gstvideorate.c: * gst/videoscale/gstvideoscale.c: * gst/videotestsrc/gstvideotestsrc.c: * gst/volume/gstvolume.c: * sys/ximage/ximagesink.c: * sys/xvimage/xvimagesink.c: Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipelines are "simple" pipelines.
2008-07-10 21:06:06 +00:00
*
* ## Example launch line (server):
* |[
* gst-launch-1.0 fdsrc fd=1 ! tcpserversink port=3000
* ]|
* ## Example launch line (client):
* |[
* gst-launch-1.0 tcpclientsrc port=3000 ! fdsink fd=2
* ]|
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst-i18n-plugin.h>
#include <string.h> /* memset */
#include "gsttcp.h"
#include "gsttcpserversink.h"
#define TCP_BACKLOG 5
GST_DEBUG_CATEGORY_STATIC (tcpserversink_debug);
#define GST_CAT_DEFAULT (tcpserversink_debug)
enum
{
PROP_0,
PROP_HOST,
PROP_PORT,
PROP_CURRENT_PORT
};
static void gst_tcp_server_sink_finalize (GObject * gobject);
2012-01-26 22:19:33 +00:00
static gboolean gst_tcp_server_sink_init_send (GstMultiHandleSink * this);
static gboolean gst_tcp_server_sink_close (GstMultiHandleSink * this);
static void gst_tcp_server_sink_removed (GstMultiHandleSink * sink,
GstMultiSinkHandle handle);
static void gst_tcp_server_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
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_SOCKET_SINK);
static void
gst_tcp_server_sink_class_init (GstTCPServerSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
2012-01-26 22:19:33 +00:00
GstMultiHandleSinkClass *gstmultihandlesink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
2012-01-26 22:19:33 +00:00
gstmultihandlesink_class = (GstMultiHandleSinkClass *) 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;
Ported tcp plugins to 0.9. Original commit message from CVS: * configure.ac: * gst/tcp/Makefile.am: * gst/tcp/README: * gst/tcp/gstmultifdsink.c: (gst_multifdsink_get_type), (gst_multifdsink_base_init), (gst_multifdsink_class_init), (gst_multifdsink_init), (gst_multifdsink_remove_client_link), (is_sync_frame), (gst_multifdsink_handle_client_write), (gst_multifdsink_render), (gst_multifdsink_start), (gst_multifdsink_stop), (gst_multifdsink_change_state): * gst/tcp/gstmultifdsink.h: * gst/tcp/gsttcp.c: (gst_tcp_host_to_ip), (gst_tcp_gdp_read_buffer), (gst_tcp_gdp_read_caps), (gst_tcp_gdp_write_buffer), (gst_tcp_gdp_write_caps): * gst/tcp/gsttcp.h: * gst/tcp/gsttcpclientsink.c: (gst_tcpclientsink_class_init), (gst_tcpclientsink_init), (gst_tcpclientsink_setcaps), (gst_tcpclientsink_render), (gst_tcpclientsink_start), (gst_tcpclientsink_stop), (gst_tcpclientsink_change_state): * gst/tcp/gsttcpclientsink.h: * gst/tcp/gsttcpclientsrc.c: (gst_tcpclientsrc_get_type), (gst_tcpclientsrc_base_init), (gst_tcpclientsrc_class_init), (gst_tcpclientsrc_init), (gst_tcpclientsrc_getcaps), (gst_tcpclientsrc_create), (gst_tcpclientsrc_start), (gst_tcpclientsrc_stop), (gst_tcpclientsrc_unlock): * gst/tcp/gsttcpclientsrc.h: * gst/tcp/gsttcpplugin.c: (plugin_init): * gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init): * gst/tcp/gsttcpserversink.h: * gst/tcp/gsttcpserversrc.c: (gst_tcpserversrc_get_type), (gst_tcpserversrc_base_init), (gst_tcpserversrc_class_init), (gst_tcpserversrc_init), (gst_tcpserversrc_finalize), (gst_tcpserversrc_create), (gst_tcpserversrc_start), (gst_tcpserversrc_stop): * gst/tcp/gsttcpserversrc.h: * gst/tcp/gsttcpsink.c: * gst/tcp/gsttcpsink.h: * gst/tcp/gsttcpsrc.c: * gst/tcp/gsttcpsrc.h: Ported tcp plugins to 0.9.
2005-07-05 10:21:40 +00:00
/* FIXME 2.0: Rename this to bind-address, host does not make much
* sense here */
g_object_class_install_property (gobject_class, PROP_HOST,
g_param_spec_string ("host", "host", "The host/IP to listen on",
Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory u... Original commit message from CVS: * configure.ac: * ext/alsa/gstalsamixerelement.c: (gst_alsa_mixer_element_class_init): * ext/alsa/gstalsasink.c: (gst_alsasink_class_init): * ext/alsa/gstalsasrc.c: (gst_alsasrc_class_init): * ext/cdparanoia/gstcdparanoiasrc.c: (gst_cd_paranoia_src_class_init): * ext/gio/gstgiosink.c: (gst_gio_sink_class_init): * ext/gio/gstgiosrc.c: (gst_gio_src_class_init): * ext/gio/gstgiostreamsink.c: (gst_gio_stream_sink_class_init): * ext/gio/gstgiostreamsrc.c: (gst_gio_stream_src_class_init): * ext/gnomevfs/gstgnomevfssink.c: (gst_gnome_vfs_sink_class_init): * ext/gnomevfs/gstgnomevfssrc.c: (gst_gnome_vfs_src_class_init): * ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init): * ext/pango/gsttextoverlay.c: (gst_text_overlay_class_init): * ext/pango/gsttextrender.c: (gst_text_render_class_init): * ext/theora/theoradec.c: (gst_theora_dec_class_init): * ext/theora/theoraenc.c: (gst_theora_enc_class_init): * ext/theora/theoraparse.c: (gst_theora_parse_class_init): * ext/vorbis/vorbisenc.c: (gst_vorbis_enc_class_init): * gst-libs/gst/audio/gstaudiofiltertemplate.c: (gst_audio_filter_template_class_init): * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_class_init): * gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_class_init): * gst-libs/gst/cdda/gstcddabasesrc.c: (gst_cdda_base_src_class_init): * gst-libs/gst/interfaces/mixertrack.c: (gst_mixer_track_class_init): * gst-libs/gst/rtp/gstbasertpdepayload.c: (gst_base_rtp_depayload_class_init): * gst-libs/gst/rtp/gstbasertppayload.c: (gst_basertppayload_class_init): * gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_class_init): * gst/audiorate/gstaudiorate.c: (gst_audio_rate_class_init): * gst/audioresample/gstaudioresample.c: (gst_audioresample_class_init): * gst/audiotestsrc/gstaudiotestsrc.c: (gst_audio_test_src_class_init): * gst/gdp/gstgdppay.c: (gst_gdp_pay_class_init): * gst/playback/gstdecodebin2.c: (gst_decode_bin_class_init): * gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init), (preroll_unlinked): * gst/playback/gstplaybin.c: (gst_play_bin_class_init): * gst/playback/gstplaybin2.c: (gst_play_bin_class_init): * gst/playback/gstplaysink.c: (gst_play_sink_class_init): * gst/playback/gstqueue2.c: (gst_queue_class_init): * gst/playback/gststreaminfo.c: (gst_stream_info_class_init): * gst/playback/gststreamselector.c: (gst_selector_pad_class_init), (gst_stream_selector_class_init): * gst/playback/gsturidecodebin.c: (gst_uri_decode_bin_class_init): * gst/subparse/gstsubparse.c: (gst_sub_parse_class_init): * gst/tcp/gstmultifdsink.c: (gst_multi_fd_sink_class_init): * gst/tcp/gsttcpclientsink.c: (gst_tcp_client_sink_class_init): * gst/tcp/gsttcpclientsrc.c: (gst_tcp_client_src_class_init): * gst/tcp/gsttcpserversink.c: (gst_tcp_server_sink_class_init): * gst/tcp/gsttcpserversrc.c: (gst_tcp_server_src_class_init): * gst/videorate/gstvideorate.c: (gst_video_rate_class_init): * gst/videoscale/gstvideoscale.c: (gst_video_scale_class_init): * gst/videotestsrc/gstvideotestsrc.c: (gst_video_test_src_class_init): * gst/volume/gstvolume.c: (gst_volume_class_init): * sys/v4l/gstv4lelement.c: (gst_v4lelement_class_init): * sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_class_init): * sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_class_init): * sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init): * sys/ximage/ximagesink.c: (gst_ximagesink_class_init): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_class_init): Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory usage, fewer allocations and thus less memory defragmentation. Depend on core CVS for this. Fixes bug #523806.
2008-03-22 15:00:53 +00:00
TCP_DEFAULT_HOST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PORT,
g_param_spec_int ("port", "port",
"The port to listen to (0=random available port)",
Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory u... Original commit message from CVS: * configure.ac: * ext/alsa/gstalsamixerelement.c: (gst_alsa_mixer_element_class_init): * ext/alsa/gstalsasink.c: (gst_alsasink_class_init): * ext/alsa/gstalsasrc.c: (gst_alsasrc_class_init): * ext/cdparanoia/gstcdparanoiasrc.c: (gst_cd_paranoia_src_class_init): * ext/gio/gstgiosink.c: (gst_gio_sink_class_init): * ext/gio/gstgiosrc.c: (gst_gio_src_class_init): * ext/gio/gstgiostreamsink.c: (gst_gio_stream_sink_class_init): * ext/gio/gstgiostreamsrc.c: (gst_gio_stream_src_class_init): * ext/gnomevfs/gstgnomevfssink.c: (gst_gnome_vfs_sink_class_init): * ext/gnomevfs/gstgnomevfssrc.c: (gst_gnome_vfs_src_class_init): * ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init): * ext/pango/gsttextoverlay.c: (gst_text_overlay_class_init): * ext/pango/gsttextrender.c: (gst_text_render_class_init): * ext/theora/theoradec.c: (gst_theora_dec_class_init): * ext/theora/theoraenc.c: (gst_theora_enc_class_init): * ext/theora/theoraparse.c: (gst_theora_parse_class_init): * ext/vorbis/vorbisenc.c: (gst_vorbis_enc_class_init): * gst-libs/gst/audio/gstaudiofiltertemplate.c: (gst_audio_filter_template_class_init): * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_class_init): * gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_class_init): * gst-libs/gst/cdda/gstcddabasesrc.c: (gst_cdda_base_src_class_init): * gst-libs/gst/interfaces/mixertrack.c: (gst_mixer_track_class_init): * gst-libs/gst/rtp/gstbasertpdepayload.c: (gst_base_rtp_depayload_class_init): * gst-libs/gst/rtp/gstbasertppayload.c: (gst_basertppayload_class_init): * gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_class_init): * gst/audiorate/gstaudiorate.c: (gst_audio_rate_class_init): * gst/audioresample/gstaudioresample.c: (gst_audioresample_class_init): * gst/audiotestsrc/gstaudiotestsrc.c: (gst_audio_test_src_class_init): * gst/gdp/gstgdppay.c: (gst_gdp_pay_class_init): * gst/playback/gstdecodebin2.c: (gst_decode_bin_class_init): * gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init), (preroll_unlinked): * gst/playback/gstplaybin.c: (gst_play_bin_class_init): * gst/playback/gstplaybin2.c: (gst_play_bin_class_init): * gst/playback/gstplaysink.c: (gst_play_sink_class_init): * gst/playback/gstqueue2.c: (gst_queue_class_init): * gst/playback/gststreaminfo.c: (gst_stream_info_class_init): * gst/playback/gststreamselector.c: (gst_selector_pad_class_init), (gst_stream_selector_class_init): * gst/playback/gsturidecodebin.c: (gst_uri_decode_bin_class_init): * gst/subparse/gstsubparse.c: (gst_sub_parse_class_init): * gst/tcp/gstmultifdsink.c: (gst_multi_fd_sink_class_init): * gst/tcp/gsttcpclientsink.c: (gst_tcp_client_sink_class_init): * gst/tcp/gsttcpclientsrc.c: (gst_tcp_client_src_class_init): * gst/tcp/gsttcpserversink.c: (gst_tcp_server_sink_class_init): * gst/tcp/gsttcpserversrc.c: (gst_tcp_server_src_class_init): * gst/videorate/gstvideorate.c: (gst_video_rate_class_init): * gst/videoscale/gstvideoscale.c: (gst_video_scale_class_init): * gst/videotestsrc/gstvideotestsrc.c: (gst_video_test_src_class_init): * gst/volume/gstvolume.c: (gst_volume_class_init): * sys/v4l/gstv4lelement.c: (gst_v4lelement_class_init): * sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_class_init): * sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_class_init): * sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init): * sys/ximage/ximagesink.c: (gst_ximagesink_class_init): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_class_init): Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory usage, fewer allocations and thus less memory defragmentation. Depend on core CVS for this. Fixes bug #523806.
2008-03-22 15:00:53 +00:00
0, TCP_HIGHEST_PORT, TCP_DEFAULT_PORT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstTCPServerSink:current-port:
*
* The port number the socket is currently bound to. Applications can use
* this property to retrieve the port number actually bound to in case
* the port requested was 0 (=allocate a random available port).
*
* Since: 1.0.2
**/
g_object_class_install_property (gobject_class, PROP_CURRENT_PORT,
g_param_spec_int ("current-port", "current-port",
"The port number the socket is currently bound to", 0,
TCP_HIGHEST_PORT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (gstelement_class,
"TCP server sink", "Sink/Network",
"Send data as a server over the network via TCP",
"Thomas Vander Stichele <thomas at apestaart dot org>");
2012-01-26 22:19:33 +00:00
gstmultihandlesink_class->init = gst_tcp_server_sink_init_send;
gstmultihandlesink_class->close = gst_tcp_server_sink_close;
2012-01-28 17:07:46 +00:00
gstmultihandlesink_class->removed = gst_tcp_server_sink_removed;
GST_DEBUG_CATEGORY_INIT (tcpserversink_debug, "tcpserversink", 0, "TCP sink");
}
static void
gst_tcp_server_sink_init (GstTCPServerSink * this)
{
this->server_port = TCP_DEFAULT_PORT;
/* should support as minimum 576 for IPV4 and 1500 for IPV6 */
/* this->mtu = 1500; */
this->host = g_strdup (TCP_DEFAULT_HOST);
this->server_socket = NULL;
}
static void
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);
}
/* handle a read request on the server,
* which indicates a new client connection */
static gboolean
gst_tcp_server_sink_handle_server_read (GstTCPServerSink * sink)
{
GstMultiSinkHandle handle;
GSocket *client_socket;
GError *err = NULL;
/* wait on server socket for connections */
client_socket =
g_socket_accept (sink->server_socket, sink->element.cancellable, &err);
if (!client_socket)
goto accept_failed;
handle.socket = client_socket;
/* gst_multi_handle_sink_add does not take ownership of client_socket */
gst_multi_handle_sink_add (GST_MULTI_HANDLE_SINK (sink), handle);
#ifndef GST_DISABLE_GST_DEBUG
{
GInetSocketAddress *addr =
G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (client_socket,
NULL));
if (addr) {
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);
g_object_unref (addr);
} else {
/* This can happen when the client immediately closes the connection */
GST_DEBUG_OBJECT (sink, "added new client (no address) with socket %p",
client_socket);
}
}
#endif
g_object_unref (client_socket);
return TRUE;
/* ERRORS */
accept_failed:
{
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
("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 (GstMultiHandleSink * sink,
GstMultiSinkHandle handle)
{
GError *err = NULL;
GST_DEBUG_OBJECT (sink, "closing socket");
if (!g_socket_close (handle.socket, &err)) {
GST_ERROR_OBJECT (sink, "Failed to close socket: %s", err->message);
g_clear_error (&err);
}
}
static gboolean
gst_tcp_server_sink_socket_condition (GSocket * socket, GIOCondition condition,
GstTCPServerSink * sink)
{
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;
error:
GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL),
("client connection failed"));
return FALSE;
}
static void
gst_tcp_server_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstTCPServerSink *sink;
sink = GST_TCP_SERVER_SINK (object);
switch (prop_id) {
case PROP_HOST:
if (!g_value_get_string (value)) {
g_warning ("host property cannot be NULL");
break;
}
g_free (sink->host);
sink->host = g_value_dup_string (value);
break;
case PROP_PORT:
sink->server_port = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_tcp_server_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstTCPServerSink *sink;
sink = GST_TCP_SERVER_SINK (object);
switch (prop_id) {
case PROP_HOST:
g_value_set_string (value, sink->host);
break;
case PROP_PORT:
g_value_set_int (value, sink->server_port);
break;
case PROP_CURRENT_PORT:
g_value_set_int (value, g_atomic_int_get (&sink->current_port));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* create a socket for sending to remote machine */
static gboolean
2012-01-26 22:19:33 +00:00
gst_tcp_server_sink_init_send (GstMultiHandleSink * parent)
{
GstTCPServerSink *this = GST_TCP_SERVER_SINK (parent);
GError *err = NULL;
GInetAddress *addr;
GSocketAddress *saddr;
GResolver *resolver;
gint bound_port;
/* look up name if we need to */
addr = g_inet_address_new_from_string (this->host);
if (!addr) {
GList *results;
resolver = g_resolver_get_default ();
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));
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
2012-01-17 11:08:17 +00:00
saddr = g_inet_socket_address_new (addr, this->server_port);
g_object_unref (addr);
/* create the server listener socket */
this->server_socket =
g_socket_new (g_socket_address_get_family (saddr), 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 socket %p",
this->server_socket);
g_socket_set_blocking (this->server_socket, FALSE);
/* bind it */
GST_DEBUG_OBJECT (this, "binding server socket to address");
if (!g_socket_bind (this->server_socket, saddr, TRUE, &err))
goto bind_failed;
2012-01-17 11:08:17 +00:00
g_object_unref (saddr);
GST_DEBUG_OBJECT (this, "listening on server socket");
g_socket_set_listen_backlog (this->server_socket, TCP_BACKLOG);
if (!g_socket_listen (this->server_socket, &err))
goto listen_failed;
GST_DEBUG_OBJECT (this, "listened on server socket %p", this->server_socket);
if (this->server_port == 0) {
saddr = g_socket_get_local_address (this->server_socket, NULL);
bound_port = g_inet_socket_address_get_port ((GInetSocketAddress *) saddr);
g_object_unref (saddr);
} else {
bound_port = this->server_port;
}
GST_DEBUG_OBJECT (this, "listening on port %d", bound_port);
g_atomic_int_set (&this->current_port, bound_port);
g_object_notify (G_OBJECT (this), "current-port");
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);
gst/tcp/: Abstracted away the select call, implemented poll (yes we ran into the 1024 limit in production). Original commit message from CVS: * gst/tcp/Makefile.am: * gst/tcp/gstfdset.c: (gst_fdset_mode_get_type), (nearest_pow), (ensure_size), (gst_fdset_new), (gst_fdset_free), (gst_fdset_set_mode), (gst_fdset_get_mode), (gst_fdset_add_fd), (gst_fdset_remove_fd), (gst_fdset_fd_ctl_write), (gst_fdset_fd_ctl_read), (gst_fdset_fd_has_closed), (gst_fdset_fd_has_error), (gst_fdset_fd_can_read), (gst_fdset_fd_can_write), (gst_fdset_wait): * gst/tcp/gstfdset.h: * gst/tcp/gstmultifdsink.c: (gst_unit_type_get_type), (gst_multifdsink_class_init), (gst_multifdsink_init), (gst_multifdsink_add), (gst_multifdsink_remove), (gst_multifdsink_clear), (gst_multifdsink_get_stats), (gst_multifdsink_remove_client_link), (gst_multifdsink_handle_client_read), (gst_multifdsink_client_queue_data), (gst_multifdsink_client_queue_caps), (gst_multifdsink_client_queue_buffer), (gst_multifdsink_handle_client_write), (gst_multifdsink_recover_client), (gst_multifdsink_queue_buffer), (gst_multifdsink_handle_clients), (gst_multifdsink_set_property), (gst_multifdsink_get_property), (gst_multifdsink_init_send), (gst_multifdsink_close): * gst/tcp/gstmultifdsink.h: * gst/tcp/gsttcpserversink.c: (gst_tcpserversink_class_init), (gst_tcpserversink_init), (gst_tcpserversink_handle_server_read), (gst_tcpserversink_handle_wait), (gst_tcpserversink_init_send), (gst_tcpserversink_close): * gst/tcp/gsttcpserversink.h: Abstracted away the select call, implemented poll (yes we ran into the 1024 limit in production).
2004-08-11 15:58:48 +00:00
return TRUE;
/* ERRORS */
no_socket:
{
GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
("Failed to create socket: %s", err->message));
g_clear_error (&err);
2012-01-17 11:08:17 +00:00
g_object_unref (saddr);
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);
g_object_unref (resolver);
return FALSE;
}
bind_failed:
{
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);
2012-01-26 22:19:33 +00:00
gst_tcp_server_sink_close (GST_MULTI_HANDLE_SINK (&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);
2012-01-26 22:19:33 +00:00
gst_tcp_server_sink_close (GST_MULTI_HANDLE_SINK (&this->element));
return FALSE;
}
}
static gboolean
2012-01-26 22:19:33 +00:00
gst_tcp_server_sink_close (GstMultiHandleSink * parent)
{
GstTCPServerSink *this = GST_TCP_SERVER_SINK (parent);
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;
g_atomic_int_set (&this->current_port, 0);
g_object_notify (G_OBJECT (this), "current-port");
}
return TRUE;
}