diff options
author | Ognyan Tonchev <ognyan@axis.com> | 2014-03-02 11:58:58 +0100 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2014-03-03 10:44:58 +0100 |
commit | b8cee317f44532cb8469017798f4ead34ce3e3ba (patch) | |
tree | 0b069221c598d0d026f17c908b045e26d8b3ccbd | |
parent | ff531f04bbef25e288c89fe0c6f2c22d43770205 (diff) | |
download | gstreamer-plugins-base-b8cee317f44532cb8469017798f4ead34ce3e3ba.tar.gz |
rtspconnection: Call closed() when GET is closed in tunneled mode
This patch adds read source on the write socket in tunneled
mode and we get a callback when client disconnects the GET
channel.
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=725313
-rw-r--r-- | gst-libs/gst/rtsp/gstrtspconnection.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/gst-libs/gst/rtsp/gstrtspconnection.c b/gst-libs/gst/rtsp/gstrtspconnection.c index 3a0f377b2..58577e96c 100644 --- a/gst-libs/gst/rtsp/gstrtspconnection.c +++ b/gst-libs/gst/rtsp/gstrtspconnection.c @@ -115,6 +115,9 @@ struct _GstRTSPConnection GInputStream *input_stream; GOutputStream *output_stream; + /* this is a read source we add on the write socket in tunneled mode to be + * able to detect when client disconnects the GET channel */ + GInputStream *control_stream; /* connection state */ GSocket *read_socket; @@ -317,6 +320,7 @@ gst_rtsp_connection_create_from_socket (GSocket * socket, const gchar * ip, newconn->write_socket = newconn->read_socket = newconn->socket0; newconn->input_stream = g_io_stream_get_input_stream (stream); newconn->output_stream = g_io_stream_get_output_stream (stream); + newconn->control_stream = NULL; newconn->remote_ip = g_strdup (ip); newconn->local_ip = local_ip; newconn->initial_buffer = g_strdup (initial_buffer); @@ -588,6 +592,7 @@ setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout, gchar * uri) conn->socket1 = socket; conn->write_socket = conn->socket1; conn->output_stream = g_io_stream_get_output_stream (conn->stream1); + conn->control_stream = NULL; /* create the POST request for the write connection */ GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_POST, uri), @@ -729,6 +734,7 @@ gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout) conn->write_socket = conn->socket0; conn->input_stream = g_io_stream_get_input_stream (conn->stream0); conn->output_stream = g_io_stream_get_output_stream (conn->stream0); + conn->control_stream = NULL; if (conn->tunneled) { res = setup_tunneling (conn, timeout, uri); @@ -2755,6 +2761,7 @@ gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn, conn->socket1 = conn2->socket0; conn->stream1 = conn2->stream0; conn->input_stream = conn2->input_stream; + conn->control_stream = g_io_stream_get_input_stream (conn->stream0); /* clean up some of the state of conn2 */ g_cancellable_cancel (conn2->cancellable); @@ -2763,6 +2770,7 @@ gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn, conn2->stream0 = NULL; conn2->input_stream = NULL; conn2->output_stream = NULL; + conn2->control_stream = NULL; g_cancellable_reset (conn2->cancellable); /* We make socket0 the write socket and socket1 the read socket. */ @@ -2846,6 +2854,7 @@ struct _GstRTSPWatch GSource *readsrc; GSource *writesrc; + GSource *controlsrc; gboolean keep_running; @@ -2887,6 +2896,62 @@ gst_rtsp_source_check (GSource * source) } static gboolean +gst_rtsp_source_dispatch_read_get_channel (GPollableInputStream * stream, + GstRTSPWatch * watch) +{ + gssize count; + guint8 buffer[1024]; + GError *error = NULL; + + /* try to read in order to be able to detect errors, we read 1k in case some + * client actually decides to send data on the GET channel */ + count = g_pollable_input_stream_read_nonblocking (stream, buffer, 1024, NULL, + &error); + if (count == 0) { + /* other end closed the socket */ + goto eof; + } + + if (count < 0) { + GST_DEBUG ("%s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { + g_clear_error (&error); + goto done; + } + g_clear_error (&error); + goto read_error; + } + + /* client sent data on the GET channel, ignore it */ + +done: + return TRUE; + + /* ERRORS */ +eof: + { + if (watch->funcs.closed) + watch->funcs.closed (watch, watch->user_data); + + /* the read connection was closed, stop the watch now */ + watch->keep_running = FALSE; + + return FALSE; + } +read_error: + { + if (watch->funcs.error_full) + watch->funcs.error_full (watch, GST_RTSP_ESYS, &watch->message, + 0, watch->user_data); + else if (watch->funcs.error) + watch->funcs.error (watch, GST_RTSP_ESYS, watch->user_data); + + goto eof; + } +} + +static gboolean gst_rtsp_source_dispatch_read (GPollableInputStream * stream, GstRTSPWatch * watch) { @@ -3054,6 +3119,21 @@ gst_rtsp_source_dispatch_write (GPollableOutputStream * stream, watch->writesrc = NULL; /* we create and add the write source again when we actually have * something to write */ + + /* since write source is now removed we add read source on the write + * socket instead to be able to detect when client closes get channel + * in tunneled mode */ + if (watch->conn->control_stream) { + watch->controlsrc = + g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM + (watch->conn->control_stream), NULL); + g_source_set_callback (watch->controlsrc, + (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch, + NULL); + g_source_add_child_source ((GSource *) watch, watch->controlsrc); + } else { + watch->controlsrc = NULL; + } } break; } @@ -3134,6 +3214,8 @@ gst_rtsp_source_finalize (GSource * source) g_source_unref (watch->readsrc); if (watch->writesrc) g_source_unref (watch->writesrc); + if (watch->controlsrc) + g_source_unref (watch->controlsrc); g_mutex_clear (&watch->mutex); @@ -3217,6 +3299,11 @@ gst_rtsp_watch_reset (GstRTSPWatch * watch) g_source_unref (watch->writesrc); watch->writesrc = NULL; } + if (watch->controlsrc) { + g_source_remove_child_source ((GSource *) watch, watch->controlsrc); + g_source_unref (watch->controlsrc); + watch->controlsrc = NULL; + } if (watch->conn->input_stream) { watch->readsrc = @@ -3231,6 +3318,20 @@ gst_rtsp_watch_reset (GstRTSPWatch * watch) /* we create and add the write source when we actually have something to * write */ + + /* when write source is not added we add read source on the write socket + * instead to be able to detect when client closes get channel in tunneled + * mode */ + if (watch->conn->control_stream) { + watch->controlsrc = + g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM + (watch->conn->control_stream), NULL); + g_source_set_callback (watch->controlsrc, + (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch, NULL); + g_source_add_child_source ((GSource *) watch, watch->controlsrc); + } else { + watch->controlsrc = NULL; + } } /** @@ -3400,6 +3501,14 @@ gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data, * socket */ context = ((GSource *) watch)->context; if (!watch->writesrc) { + /* remove the read source on the write socket, we will be able to detect + * errors while writing */ + if (watch->controlsrc) { + g_source_remove_child_source ((GSource *) watch, watch->controlsrc); + g_source_unref (watch->controlsrc); + watch->controlsrc = NULL; + } + watch->writesrc = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (watch->conn->output_stream), NULL); |