client: wait until the TEARDOWN response is sent to close the connection
authorAlessandro Decina <alessandro.d@gmail.com>
Sat, 17 Nov 2012 13:51:52 +0000 (14:51 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 20 Nov 2012 08:32:19 +0000 (09:32 +0100)
Responses can be sent async so we need to wait until the TEARDOWN response has
been written before we close the connection to the client. This avoids the risk
of writing/polling closed sockets.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=688535

gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-client.h

index 9389160..799b42e 100644 (file)
@@ -174,6 +174,7 @@ static void
 gst_rtsp_client_init (GstRTSPClient * client)
 {
   client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS;
+  client->teardown_response_seq = 0;
 }
 
 static void
@@ -300,7 +301,7 @@ gst_rtsp_client_new (void)
 
 static void
 send_response (GstRTSPClient * client, GstRTSPSession * session,
-    GstRTSPMessage * response)
+    GstRTSPMessage * response, guint * id)
 {
   gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER,
       "GStreamer RTSP server");
@@ -318,7 +319,7 @@ send_response (GstRTSPClient * client, GstRTSPSession * session,
     gst_rtsp_message_dump (response);
   }
 
-  gst_rtsp_watch_send_message (client->watch, response, NULL);
+  gst_rtsp_watch_send_message (client->watch, response, id);
   gst_rtsp_message_unset (response);
 }
 
@@ -329,7 +330,7 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
   gst_rtsp_message_init_response (state->response, code,
       gst_rtsp_status_as_text (code), state->request);
 
-  send_response (client, NULL, state->response);
+  send_response (client, NULL, state->response, NULL);
 }
 
 static void
@@ -344,7 +345,7 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth,
     gst_rtsp_auth_setup_auth (auth, client, 0, state);
   }
 
-  send_response (client, state->session, state->response);
+  send_response (client, state->session, state->response, NULL);
 }
 
 
@@ -603,14 +604,15 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state)
   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION,
       "close");
 
-  send_response (client, session, state->response);
+  /* send the response and store the seq number so we can wait until it's
+   * written to the client to close the connection */
+  send_response (client, session, state->response,
+      &client->teardown_response_seq);
 
   /* we emit the signal before closing the connection */
   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
       0, state);
 
-  close_connection (client);
-
   return TRUE;
 
   /* ERRORS */
@@ -646,7 +648,7 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state)
     if (res != GST_RTSP_OK)
       goto bad_request;
 
-    send_response (client, state->session, state->response);
+    send_response (client, state->session, state->response, NULL);
   }
 
   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
@@ -682,7 +684,7 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state)
     if (res != GST_RTSP_OK)
       goto bad_request;
 
-    send_response (client, state->session, state->response);
+    send_response (client, state->session, state->response, NULL);
   }
 
   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
@@ -731,7 +733,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state)
   gst_rtsp_message_init_response (state->response, code,
       gst_rtsp_status_as_text (code), state->request);
 
-  send_response (client, session, state->response);
+  send_response (client, session, state->response, NULL);
 
   /* the state is now READY */
   media->state = GST_RTSP_STATE_READY;
@@ -853,7 +855,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
   str = gst_rtsp_media_get_range_string (media->media, TRUE);
   gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str);
 
-  send_response (client, session, state->response);
+  send_response (client, session, state->response, NULL);
 
   /* start playing after sending the request */
   gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
@@ -1179,7 +1181,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
       trans_str);
   g_free (trans_str);
 
-  send_response (client, session, state->response);
+  send_response (client, session, state->response, NULL);
 
   /* update the state */
   switch (sessmedia->state) {
@@ -1368,7 +1370,7 @@ handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state)
   gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str));
   gst_sdp_message_free (sdp);
 
-  send_response (client, state->session, state->response);
+  send_response (client, state->session, state->response, NULL);
 
   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
       0, state);
@@ -1410,7 +1412,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPClientState * state)
   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str);
   g_free (str);
 
-  send_response (client, state->session, state->response);
+  send_response (client, state->session, state->response, NULL);
 
   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
       0, state);
@@ -1891,11 +1893,13 @@ message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
 static GstRTSPResult
 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
 {
-  /* GstRTSPClient *client; */
-
-  /* client = GST_RTSP_CLIENT (user_data); */
+  GstRTSPClient *client;
 
-  /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */
+  client = GST_RTSP_CLIENT (user_data);
+  if (client->teardown_response_seq && client->teardown_response_seq == cseq) {
+    client->teardown_response_seq = 0;
+    close_connection (client);
+  }
 
   return GST_RTSP_OK;
 }
index 71a28ad..dd4e712 100644 (file)
@@ -107,6 +107,8 @@ struct _GstRTSPClient {
 
   GList *transports;
   GList *sessions;
+
+  guint teardown_response_seq;
 };
 
 struct _GstRTSPClientClass {