client: handle lost_tunnel callbacks

Handle lost_tunnel callbacks and use it to store the tunnelid back into the
hashtable so that we can reuse it for when the client reopens the POST
socket.
Close the connection after a TEARDOWN.
Make sure or watchid is cleared when the watch is removed.

Fixes #612915
This commit is contained in:
Wim Taymans 2010-04-06 11:13:51 +02:00
parent 09b97dd4ac
commit 30c31a65eb

View file

@ -322,6 +322,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
size = GST_BUFFER_SIZE (buffer);
gst_rtsp_message_take_body (&message, data, size);
/* FIXME, client->watch could have been finalized here, we need to keep an
* extra refcount to the watch. */
gst_rtsp_watch_send_message (client->watch, &message, NULL);
gst_rtsp_message_steal_body (&message, &data, &size);
@ -333,6 +335,7 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
static void
link_stream (GstRTSPClient * client, GstRTSPSessionStream * stream)
{
GST_DEBUG ("client %p: linking stream %p", client, stream);
gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data,
(GstRTSPSendFunc) do_send_data, client, NULL);
client->streams = g_list_prepend (client->streams, stream);
@ -341,6 +344,7 @@ link_stream (GstRTSPClient * client, GstRTSPSessionStream * stream)
static void
unlink_stream (GstRTSPClient * client, GstRTSPSessionStream * stream)
{
GST_DEBUG ("client %p: unlinking stream %p", client, stream);
gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL);
client->streams = g_list_remove (client->streams, stream);
}
@ -350,6 +354,7 @@ unlink_streams (GstRTSPClient * client)
{
GList *walk;
GST_DEBUG ("client %p: unlinking streams", client);
for (walk = client->streams; walk; walk = g_list_next (walk)) {
GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
@ -419,8 +424,17 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri,
gst_rtsp_message_init_response (&response, code,
gst_rtsp_status_as_text (code), request);
gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONNECTION, "close");
send_response (client, session, &response);
GST_DEBUG ("client %p: closing connection", client);
if (client->watchid) {
g_source_destroy ((GSource *) client->watch);
client->watchid = 0;
}
gst_rtsp_connection_close (client->connection);
return TRUE;
/* ERRORS */
@ -1122,6 +1136,7 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
if (!(client->sessions = g_list_remove (client->sessions, session))) {
GST_INFO ("all sessions finalized, close the connection");
g_source_destroy ((GSource *) client->watch);
client->watchid = 0;
}
}
@ -1439,6 +1454,7 @@ closed (GstRTSPWatch * watch, gpointer user_data)
if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
g_mutex_lock (tunnels_lock);
/* remove from tunnelids */
g_hash_table_remove (tunnels, tunnelid);
g_mutex_unlock (tunnels_lock);
}
@ -1478,22 +1494,17 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result,
return GST_RTSP_OK;
}
static GstRTSPStatusCode
tunnel_start (GstRTSPWatch * watch, gpointer user_data)
static gboolean
remember_tunnel (GstRTSPClient * client)
{
GstRTSPClient *client;
const gchar *tunnelid;
client = GST_RTSP_CLIENT (user_data);
GST_INFO ("client %p: tunnel start", client);
/* store client in the pending tunnels */
tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
if (tunnelid == NULL)
goto no_tunnelid;
GST_INFO ("client %p: inserting %s", client, tunnelid);
GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
/* we can't have two clients connecting with the same tunnelid */
g_mutex_lock (tunnels_lock);
@ -1503,22 +1514,59 @@ tunnel_start (GstRTSPWatch * watch, gpointer user_data)
g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
g_mutex_unlock (tunnels_lock);
return GST_RTSP_STS_OK;
return TRUE;
/* ERRORS */
no_tunnelid:
{
GST_INFO ("client %p: no tunnelid provided", client);
return GST_RTSP_STS_SERVICE_UNAVAILABLE;
GST_ERROR ("client %p: no tunnelid provided", client);
return FALSE;
}
tunnel_existed:
{
g_mutex_unlock (tunnels_lock);
GST_INFO ("client %p: tunnel session %s existed", client, tunnelid);
GST_ERROR ("client %p: tunnel session %s already existed", client, tunnelid);
return FALSE;
}
}
static GstRTSPStatusCode
tunnel_start (GstRTSPWatch * watch, gpointer user_data)
{
GstRTSPClient *client;
client = GST_RTSP_CLIENT (user_data);
GST_INFO ("client %p: tunnel start (connection %p)", client, client->connection);
if (!remember_tunnel (client))
goto tunnel_error;
return GST_RTSP_STS_OK;
/* ERRORS */
tunnel_error:
{
GST_ERROR ("client %p: error starting tunnel", client);
return GST_RTSP_STS_SERVICE_UNAVAILABLE;
}
}
static GstRTSPResult
tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
{
GstRTSPClient *client;
client = GST_RTSP_CLIENT (user_data);
GST_INFO ("client %p: tunnel lost (connection %p)", client, client->connection);
/* ignore error, it'll only be a problem when the client does a POST again */
remember_tunnel (client);
return GST_RTSP_OK;
}
static GstRTSPResult
tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
{
@ -1543,7 +1591,8 @@ tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
g_hash_table_remove (tunnels, tunnelid);
g_mutex_unlock (tunnels_lock);
GST_INFO ("client %p: found tunnel %p", client, oclient);
GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
oclient->connection, client->connection);
/* merge the tunnels into the first client */
gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
@ -1577,9 +1626,18 @@ static GstRTSPWatchFuncs watch_funcs = {
error,
tunnel_start,
tunnel_complete,
error_full
error_full,
tunnel_lost
};
static void
client_watch_notify (GstRTSPClient * client)
{
GST_INFO ("client %p: watch destroyed", client);
client->watchid = 0;
g_object_unref (client);
}
/**
* gst_rtsp_client_attach:
* @client: a #GstRTSPClient
@ -1637,7 +1695,7 @@ gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel)
/* create watch for the connection and attach */
client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
g_object_ref (client), g_object_unref);
g_object_ref (client), (GDestroyNotify) client_watch_notify);
/* find the context to add the watch */
if ((source = g_main_current_source ()))