a60053769776842de22bddf99415aa0424476a7d
[platform/upstream/gst-rtsp-server.git] / gst / rtsp-server / rtsp-client.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  * Copyright (C) 2015 Centricular Ltd
4  *     Author: Sebastian Dröge <sebastian@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 /**
22  * SECTION:rtsp-client
23  * @short_description: A client connection state
24  * @see_also: #GstRTSPServer, #GstRTSPThreadPool
25  *
26  * The client object handles the connection with a client for as long as a TCP
27  * connection is open.
28  *
29  * A #GstRTSPClient is created by #GstRTSPServer when a new connection is
30  * accepted and it inherits the #GstRTSPMountPoints, #GstRTSPSessionPool,
31  * #GstRTSPAuth and #GstRTSPThreadPool from the server.
32  *
33  * The client connection should be configured with the #GstRTSPConnection using
34  * gst_rtsp_client_set_connection() before it can be attached to a #GMainContext
35  * using gst_rtsp_client_attach(). From then on the client will handle requests
36  * on the connection.
37  *
38  * Use gst_rtsp_client_session_filter() to iterate or modify all the
39  * #GstRTSPSession objects managed by the client object.
40  *
41  * Last reviewed on 2013-07-11 (1.0.0)
42  */
43
44 #include <stdio.h>
45 #include <string.h>
46
47 #include <gst/sdp/gstmikey.h>
48
49 #include "rtsp-client.h"
50 #include "rtsp-sdp.h"
51 #include "rtsp-params.h"
52
53 #define GST_RTSP_CLIENT_GET_PRIVATE(obj)  \
54    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate))
55
56 /* locking order:
57  * send_lock, lock, tunnels_lock
58  */
59
60 struct _GstRTSPClientPrivate
61 {
62   GMutex lock;                  /* protects everything else */
63   GMutex send_lock;
64   GMutex watch_lock;
65   GstRTSPConnection *connection;
66   GstRTSPWatch *watch;
67   GMainContext *watch_context;
68   guint close_seq;
69   gchar *server_ip;
70   gboolean is_ipv6;
71
72   GstRTSPClientSendFunc send_func;      /* protected by send_lock */
73   gpointer send_data;           /* protected by send_lock */
74   GDestroyNotify send_notify;   /* protected by send_lock */
75
76   GstRTSPSessionPool *session_pool;
77   gulong session_removed_id;
78   GstRTSPMountPoints *mount_points;
79   GstRTSPAuth *auth;
80   GstRTSPThreadPool *thread_pool;
81
82   /* used to cache the media in the last requested DESCRIBE so that
83    * we can pick it up in the next SETUP immediately */
84   gchar *path;
85   GstRTSPMedia *media;
86
87   GHashTable *transports;
88   GList *sessions;
89   guint sessions_cookie;
90
91   gboolean drop_backlog;
92 };
93
94 static GMutex tunnels_lock;
95 static GHashTable *tunnels;     /* protected by tunnels_lock */
96
97 /* FIXME make this configurable. We don't want to do this yet because it will
98  * be superceeded by a cache object later */
99 #define WATCH_BACKLOG_SIZE              100
100
101 #define DEFAULT_SESSION_POOL            NULL
102 #define DEFAULT_MOUNT_POINTS            NULL
103 #define DEFAULT_DROP_BACKLOG            TRUE
104
105 enum
106 {
107   PROP_0,
108   PROP_SESSION_POOL,
109   PROP_MOUNT_POINTS,
110   PROP_DROP_BACKLOG,
111   PROP_LAST
112 };
113
114 enum
115 {
116   SIGNAL_CLOSED,
117   SIGNAL_NEW_SESSION,
118   SIGNAL_OPTIONS_REQUEST,
119   SIGNAL_DESCRIBE_REQUEST,
120   SIGNAL_SETUP_REQUEST,
121   SIGNAL_PLAY_REQUEST,
122   SIGNAL_PAUSE_REQUEST,
123   SIGNAL_TEARDOWN_REQUEST,
124   SIGNAL_SET_PARAMETER_REQUEST,
125   SIGNAL_GET_PARAMETER_REQUEST,
126   SIGNAL_HANDLE_RESPONSE,
127   SIGNAL_SEND_MESSAGE,
128   SIGNAL_ANNOUNCE_REQUEST,
129   SIGNAL_RECORD_REQUEST,
130   SIGNAL_CHECK_REQUIREMENTS,
131   SIGNAL_LAST
132 };
133
134 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
135 #define GST_CAT_DEFAULT rtsp_client_debug
136
137 static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 };
138
139 static void gst_rtsp_client_get_property (GObject * object, guint propid,
140     GValue * value, GParamSpec * pspec);
141 static void gst_rtsp_client_set_property (GObject * object, guint propid,
142     const GValue * value, GParamSpec * pspec);
143 static void gst_rtsp_client_finalize (GObject * obj);
144
145 static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
146 static gboolean handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx,
147     GstRTSPMedia * media, GstSDPMessage * sdp);
148 static gboolean default_configure_client_media (GstRTSPClient * client,
149     GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx);
150 static gboolean default_configure_client_transport (GstRTSPClient * client,
151     GstRTSPContext * ctx, GstRTSPTransport * ct);
152 static GstRTSPResult default_params_set (GstRTSPClient * client,
153     GstRTSPContext * ctx);
154 static GstRTSPResult default_params_get (GstRTSPClient * client,
155     GstRTSPContext * ctx);
156 static gchar *default_make_path_from_uri (GstRTSPClient * client,
157     const GstRTSPUrl * uri);
158 static gboolean default_handle_options_request (GstRTSPClient * client,
159     GstRTSPContext * ctx);
160 static gboolean default_handle_set_param_request (GstRTSPClient * client,
161     GstRTSPContext * ctx);
162 static gboolean default_handle_get_param_request (GstRTSPClient * client,
163     GstRTSPContext * ctx);
164 static gboolean default_handle_play_request (GstRTSPClient * client,
165     GstRTSPContext * ctx);
166
167 static void client_session_removed (GstRTSPSessionPool * pool,
168     GstRTSPSession * session, GstRTSPClient * client);
169
170 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
171
172 static void
173 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
174 {
175   GObjectClass *gobject_class;
176
177   g_type_class_add_private (klass, sizeof (GstRTSPClientPrivate));
178
179   gobject_class = G_OBJECT_CLASS (klass);
180
181   gobject_class->get_property = gst_rtsp_client_get_property;
182   gobject_class->set_property = gst_rtsp_client_set_property;
183   gobject_class->finalize = gst_rtsp_client_finalize;
184
185   klass->create_sdp = create_sdp;
186   klass->handle_sdp = handle_sdp;
187   klass->configure_client_media = default_configure_client_media;
188   klass->configure_client_transport = default_configure_client_transport;
189   klass->params_set = default_params_set;
190   klass->params_get = default_params_get;
191   klass->make_path_from_uri = default_make_path_from_uri;
192   klass->handle_options_request = default_handle_options_request;
193   klass->handle_set_param_request = default_handle_set_param_request;
194   klass->handle_get_param_request = default_handle_get_param_request;
195   klass->handle_play_request = default_handle_play_request;
196
197   g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
198       g_param_spec_object ("session-pool", "Session Pool",
199           "The session pool to use for client session",
200           GST_TYPE_RTSP_SESSION_POOL,
201           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202
203   g_object_class_install_property (gobject_class, PROP_MOUNT_POINTS,
204       g_param_spec_object ("mount-points", "Mount Points",
205           "The mount points to use for client session",
206           GST_TYPE_RTSP_MOUNT_POINTS,
207           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
208
209   g_object_class_install_property (gobject_class, PROP_DROP_BACKLOG,
210       g_param_spec_boolean ("drop-backlog", "Drop Backlog",
211           "Drop data when the backlog queue is full",
212           DEFAULT_DROP_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213
214   gst_rtsp_client_signals[SIGNAL_CLOSED] =
215       g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
216       G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL,
217       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
218
219   gst_rtsp_client_signals[SIGNAL_NEW_SESSION] =
220       g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
221       G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL,
222       g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION);
223
224   gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] =
225       g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass),
226       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request),
227       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
228       GST_TYPE_RTSP_CONTEXT);
229
230   gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] =
231       g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass),
232       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request),
233       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
234       GST_TYPE_RTSP_CONTEXT);
235
236   gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] =
237       g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass),
238       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request),
239       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
240       GST_TYPE_RTSP_CONTEXT);
241
242   gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] =
243       g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass),
244       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request),
245       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
246       GST_TYPE_RTSP_CONTEXT);
247
248   gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] =
249       g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass),
250       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request),
251       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
252       GST_TYPE_RTSP_CONTEXT);
253
254   gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] =
255       g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass),
256       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request),
257       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
258       GST_TYPE_RTSP_CONTEXT);
259
260   gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] =
261       g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass),
262       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
263           set_parameter_request), NULL, NULL, g_cclosure_marshal_generic,
264       G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
265
266   gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] =
267       g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass),
268       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
269           get_parameter_request), NULL, NULL, g_cclosure_marshal_generic,
270       G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
271
272   gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE] =
273       g_signal_new ("handle-response", G_TYPE_FROM_CLASS (klass),
274       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
275           handle_response), NULL, NULL, g_cclosure_marshal_generic,
276       G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
277
278   /**
279    * GstRTSPClient::send-message:
280    * @client: The RTSP client
281    * @session: (type GstRtspServer.RTSPSession): The session
282    * @message: (type GstRtsp.RTSPMessage): The message
283    */
284   gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] =
285       g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass),
286       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
287           send_message), NULL, NULL, g_cclosure_marshal_generic,
288       G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER);
289
290   gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] =
291       g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass),
292       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request),
293       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
294       GST_TYPE_RTSP_CONTEXT);
295
296   gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] =
297       g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass),
298       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request),
299       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
300       GST_TYPE_RTSP_CONTEXT);
301
302   /**
303    * GstRTSPClient::check-requirements:
304    * @client: a #GstRTSPClient
305    * @ctx: a #GstRTSPContext
306    * @arr: a NULL-terminated array of strings
307    *
308    * Returns: a newly allocated string with comma-separated list of
309    *          unsupported options. An empty string must be returned if
310    *          all options are supported.
311    *
312    * Since: 1.6
313    */
314   gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS] =
315       g_signal_new ("check-requirements", G_TYPE_FROM_CLASS (klass),
316       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
317           check_requirements), NULL, NULL, g_cclosure_marshal_generic,
318       G_TYPE_STRING, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_STRV);
319
320   tunnels =
321       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
322   g_mutex_init (&tunnels_lock);
323
324   GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
325 }
326
327 static void
328 gst_rtsp_client_init (GstRTSPClient * client)
329 {
330   GstRTSPClientPrivate *priv = GST_RTSP_CLIENT_GET_PRIVATE (client);
331
332   client->priv = priv;
333
334   g_mutex_init (&priv->lock);
335   g_mutex_init (&priv->send_lock);
336   g_mutex_init (&priv->watch_lock);
337   priv->close_seq = 0;
338   priv->drop_backlog = DEFAULT_DROP_BACKLOG;
339   priv->transports =
340       g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
341       g_object_unref);
342 }
343
344 static GstRTSPFilterResult
345 filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
346     gpointer user_data)
347 {
348   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
349
350   return GST_RTSP_FILTER_REMOVE;
351 }
352
353 static void
354 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
355 {
356   GstRTSPClientPrivate *priv = client->priv;
357
358   g_mutex_lock (&priv->lock);
359   /* check if we already know about this session */
360   if (g_list_find (priv->sessions, session) == NULL) {
361     GST_INFO ("watching session %p", session);
362
363     priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session));
364     priv->sessions_cookie++;
365
366     /* connect removed session handler, it will be disconnected when the last
367      * session gets removed  */
368     if (priv->session_removed_id == 0)
369       priv->session_removed_id = g_signal_connect_data (priv->session_pool,
370           "session-removed", G_CALLBACK (client_session_removed),
371           g_object_ref (client), (GClosureNotify) g_object_unref, 0);
372   }
373   g_mutex_unlock (&priv->lock);
374
375   return;
376 }
377
378 /* should be called with lock */
379 static void
380 client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session,
381     GList * link)
382 {
383   GstRTSPClientPrivate *priv = client->priv;
384
385   GST_INFO ("client %p: unwatch session %p", client, session);
386
387   if (link == NULL) {
388     link = g_list_find (priv->sessions, session);
389     if (link == NULL)
390       return;
391   }
392
393   priv->sessions = g_list_delete_link (priv->sessions, link);
394   priv->sessions_cookie++;
395
396   /* if this was the last session, disconnect the handler.
397    * This will also drop the extra client ref */
398   if (!priv->sessions) {
399     g_signal_handler_disconnect (priv->session_pool, priv->session_removed_id);
400     priv->session_removed_id = 0;
401   }
402
403   /* remove the session */
404   g_object_unref (session);
405 }
406
407 static GstRTSPFilterResult
408 cleanup_session (GstRTSPClient * client, GstRTSPSession * sess,
409     gpointer user_data)
410 {
411   /* unlink all media managed in this session. This needs to happen
412    * without the client lock, so we really want to do it here. */
413   gst_rtsp_session_filter (sess, filter_session_media, client);
414
415   return GST_RTSP_FILTER_REMOVE;
416 }
417
418 static void
419 clean_cached_media (GstRTSPClient * client, gboolean unprepare)
420 {
421   GstRTSPClientPrivate *priv = client->priv;
422
423   if (priv->path) {
424     g_free (priv->path);
425     priv->path = NULL;
426   }
427   if (priv->media) {
428     if (unprepare)
429       gst_rtsp_media_unprepare (priv->media);
430     g_object_unref (priv->media);
431     priv->media = NULL;
432   }
433 }
434
435 /* A client is finalized when the connection is broken */
436 static void
437 gst_rtsp_client_finalize (GObject * obj)
438 {
439   GstRTSPClient *client = GST_RTSP_CLIENT (obj);
440   GstRTSPClientPrivate *priv = client->priv;
441
442   GST_INFO ("finalize client %p", client);
443
444   if (priv->watch)
445     gst_rtsp_watch_set_flushing (priv->watch, TRUE);
446   gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
447
448   if (priv->watch)
449     g_source_destroy ((GSource *) priv->watch);
450
451   if (priv->watch_context)
452     g_main_context_unref (priv->watch_context);
453
454   /* all sessions should have been removed by now. We keep a ref to
455    * the client object for the session removed handler. The ref is
456    * dropped when the last session is removed from the list. */
457   g_assert (priv->sessions == NULL);
458   g_assert (priv->session_removed_id == 0);
459
460   g_hash_table_unref (priv->transports);
461
462   if (priv->connection)
463     gst_rtsp_connection_free (priv->connection);
464   if (priv->session_pool) {
465     g_object_unref (priv->session_pool);
466   }
467   if (priv->mount_points)
468     g_object_unref (priv->mount_points);
469   if (priv->auth)
470     g_object_unref (priv->auth);
471   if (priv->thread_pool)
472     g_object_unref (priv->thread_pool);
473
474   clean_cached_media (client, TRUE);
475
476   g_free (priv->server_ip);
477   g_mutex_clear (&priv->lock);
478   g_mutex_clear (&priv->send_lock);
479   g_mutex_clear (&priv->watch_lock);
480
481   G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
482 }
483
484 static void
485 gst_rtsp_client_get_property (GObject * object, guint propid,
486     GValue * value, GParamSpec * pspec)
487 {
488   GstRTSPClient *client = GST_RTSP_CLIENT (object);
489   GstRTSPClientPrivate *priv = client->priv;
490
491   switch (propid) {
492     case PROP_SESSION_POOL:
493       g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
494       break;
495     case PROP_MOUNT_POINTS:
496       g_value_take_object (value, gst_rtsp_client_get_mount_points (client));
497       break;
498     case PROP_DROP_BACKLOG:
499       g_value_set_boolean (value, priv->drop_backlog);
500       break;
501     default:
502       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
503   }
504 }
505
506 static void
507 gst_rtsp_client_set_property (GObject * object, guint propid,
508     const GValue * value, GParamSpec * pspec)
509 {
510   GstRTSPClient *client = GST_RTSP_CLIENT (object);
511   GstRTSPClientPrivate *priv = client->priv;
512
513   switch (propid) {
514     case PROP_SESSION_POOL:
515       gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
516       break;
517     case PROP_MOUNT_POINTS:
518       gst_rtsp_client_set_mount_points (client, g_value_get_object (value));
519       break;
520     case PROP_DROP_BACKLOG:
521       g_mutex_lock (&priv->lock);
522       priv->drop_backlog = g_value_get_boolean (value);
523       g_mutex_unlock (&priv->lock);
524       break;
525     default:
526       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
527   }
528 }
529
530 /**
531  * gst_rtsp_client_new:
532  *
533  * Create a new #GstRTSPClient instance.
534  *
535  * Returns: (transfer full): a new #GstRTSPClient
536  */
537 GstRTSPClient *
538 gst_rtsp_client_new (void)
539 {
540   GstRTSPClient *result;
541
542   result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
543
544   return result;
545 }
546
547 static void
548 send_message (GstRTSPClient * client, GstRTSPContext * ctx,
549     GstRTSPMessage * message, gboolean close)
550 {
551   GstRTSPClientPrivate *priv = client->priv;
552
553   gst_rtsp_message_add_header (message, GST_RTSP_HDR_SERVER,
554       "GStreamer RTSP server");
555
556   /* remove any previous header */
557   gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
558
559   /* add the new session header for new session ids */
560   if (ctx->session) {
561     gst_rtsp_message_take_header (message, GST_RTSP_HDR_SESSION,
562         gst_rtsp_session_get_header (ctx->session));
563   }
564
565   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
566     gst_rtsp_message_dump (message);
567   }
568
569   if (close)
570     gst_rtsp_message_add_header (message, GST_RTSP_HDR_CONNECTION, "close");
571
572   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE],
573       0, ctx, message);
574
575   g_mutex_lock (&priv->send_lock);
576   if (priv->send_func)
577     priv->send_func (client, message, close, priv->send_data);
578   g_mutex_unlock (&priv->send_lock);
579
580   gst_rtsp_message_unset (message);
581 }
582
583 static void
584 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
585     GstRTSPContext * ctx)
586 {
587   gst_rtsp_message_init_response (ctx->response, code,
588       gst_rtsp_status_as_text (code), ctx->request);
589
590   ctx->session = NULL;
591
592   send_message (client, ctx, ctx->response, FALSE);
593 }
594
595 static void
596 send_option_not_supported_response (GstRTSPClient * client,
597     GstRTSPContext * ctx, const gchar * unsupported_options)
598 {
599   GstRTSPStatusCode code = GST_RTSP_STS_OPTION_NOT_SUPPORTED;
600
601   gst_rtsp_message_init_response (ctx->response, code,
602       gst_rtsp_status_as_text (code), ctx->request);
603
604   if (unsupported_options != NULL) {
605     gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_UNSUPPORTED,
606         unsupported_options);
607   }
608
609   ctx->session = NULL;
610
611   send_message (client, ctx, ctx->response, FALSE);
612 }
613
614 static gboolean
615 paths_are_equal (const gchar * path1, const gchar * path2, gint len2)
616 {
617   if (path1 == NULL || path2 == NULL)
618     return FALSE;
619
620   if (strlen (path1) != len2)
621     return FALSE;
622
623   if (strncmp (path1, path2, len2))
624     return FALSE;
625
626   return TRUE;
627 }
628
629 /* this function is called to initially find the media for the DESCRIBE request
630  * but is cached for when the same client (without breaking the connection) is
631  * doing a setup for the exact same url. */
632 static GstRTSPMedia *
633 find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path,
634     gint * matched)
635 {
636   GstRTSPClientPrivate *priv = client->priv;
637   GstRTSPMediaFactory *factory;
638   GstRTSPMedia *media;
639   gint path_len;
640
641   /* find the longest matching factory for the uri first */
642   if (!(factory = gst_rtsp_mount_points_match (priv->mount_points,
643               path, matched)))
644     goto no_factory;
645
646   ctx->factory = factory;
647
648   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS))
649     goto no_factory_access;
650
651   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT))
652     goto not_authorized;
653
654   if (matched)
655     path_len = *matched;
656   else
657     path_len = strlen (path);
658
659   if (!paths_are_equal (priv->path, path, path_len)) {
660     /* remove any previously cached values before we try to construct a new
661      * media for uri */
662     clean_cached_media (client, TRUE);
663
664     /* prepare the media and add it to the pipeline */
665     if (!(media = gst_rtsp_media_factory_construct (factory, ctx->uri)))
666       goto no_media;
667
668     ctx->media = media;
669
670     if (!(gst_rtsp_media_get_transport_mode (media) &
671             GST_RTSP_TRANSPORT_MODE_RECORD)) {
672       GstRTSPThread *thread;
673
674       thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool,
675           GST_RTSP_THREAD_TYPE_MEDIA, ctx);
676       if (thread == NULL)
677         goto no_thread;
678
679       /* prepare the media */
680       if (!gst_rtsp_media_prepare (media, thread))
681         goto no_prepare;
682     }
683
684     /* now keep track of the uri and the media */
685     priv->path = g_strndup (path, path_len);
686     priv->media = media;
687   } else {
688     /* we have seen this path before, used cached media */
689     media = priv->media;
690     ctx->media = media;
691     GST_INFO ("reusing cached media %p for path %s", media, priv->path);
692   }
693
694   g_object_unref (factory);
695   ctx->factory = NULL;
696
697   if (media)
698     g_object_ref (media);
699
700   return media;
701
702   /* ERRORS */
703 no_factory:
704   {
705     GST_ERROR ("client %p: no factory for path %s", client, path);
706     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
707     return NULL;
708   }
709 no_factory_access:
710   {
711     GST_ERROR ("client %p: not authorized to see factory path %s", client,
712         path);
713     /* error reply is already sent */
714     return NULL;
715   }
716 not_authorized:
717   {
718     GST_ERROR ("client %p: not authorized for factory path %s", client, path);
719     /* error reply is already sent */
720     return NULL;
721   }
722 no_media:
723   {
724     GST_ERROR ("client %p: can't create media", client);
725     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
726     g_object_unref (factory);
727     ctx->factory = NULL;
728     return NULL;
729   }
730 no_thread:
731   {
732     GST_ERROR ("client %p: can't create thread", client);
733     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
734     g_object_unref (media);
735     ctx->media = NULL;
736     g_object_unref (factory);
737     ctx->factory = NULL;
738     return NULL;
739   }
740 no_prepare:
741   {
742     GST_ERROR ("client %p: can't prepare media", client);
743     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
744     g_object_unref (media);
745     ctx->media = NULL;
746     g_object_unref (factory);
747     ctx->factory = NULL;
748     return NULL;
749   }
750 }
751
752 static gboolean
753 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
754 {
755   GstRTSPClientPrivate *priv = client->priv;
756   GstRTSPMessage message = { 0 };
757   GstRTSPResult res = GST_RTSP_OK;
758   GstMapInfo map_info;
759   guint8 *data;
760   guint usize;
761
762   gst_rtsp_message_init_data (&message, channel);
763
764   /* FIXME, need some sort of iovec RTSPMessage here */
765   if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ))
766     return FALSE;
767
768   gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
769
770   g_mutex_lock (&priv->send_lock);
771   if (priv->send_func)
772     res = priv->send_func (client, &message, FALSE, priv->send_data);
773   g_mutex_unlock (&priv->send_lock);
774
775   gst_rtsp_message_steal_body (&message, &data, &usize);
776   gst_buffer_unmap (buffer, &map_info);
777
778   gst_rtsp_message_unset (&message);
779
780   return res == GST_RTSP_OK;
781 }
782
783 /**
784  * gst_rtsp_client_close:
785  * @client: a #GstRTSPClient
786  *
787  * Close the connection of @client and remove all media it was managing.
788  *
789  * Since: 1.4
790  */
791 void
792 gst_rtsp_client_close (GstRTSPClient * client)
793 {
794   GstRTSPClientPrivate *priv = client->priv;
795   const gchar *tunnelid;
796
797   GST_DEBUG ("client %p: closing connection", client);
798
799   if (priv->connection) {
800     if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
801       g_mutex_lock (&tunnels_lock);
802       /* remove from tunnelids */
803       g_hash_table_remove (tunnels, tunnelid);
804       g_mutex_unlock (&tunnels_lock);
805     }
806     gst_rtsp_connection_close (priv->connection);
807   }
808
809   /* connection is now closed, destroy the watch which will also cause the
810    * closed signal to be emitted */
811   if (priv->watch) {
812     GST_DEBUG ("client %p: destroying watch", client);
813     g_source_destroy ((GSource *) priv->watch);
814     priv->watch = NULL;
815     gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
816     g_main_context_unref (priv->watch_context);
817     priv->watch_context = NULL;
818   }
819 }
820
821 static gchar *
822 default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
823 {
824   gchar *path;
825
826   if (uri->query)
827     path = g_strconcat (uri->abspath, "?", uri->query, NULL);
828   else
829     path = g_strdup (uri->abspath);
830
831   return path;
832 }
833
834 static gboolean
835 handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
836 {
837   GstRTSPClientPrivate *priv = client->priv;
838   GstRTSPClientClass *klass;
839   GstRTSPSession *session;
840   GstRTSPSessionMedia *sessmedia;
841   GstRTSPStatusCode code;
842   gchar *path;
843   gint matched;
844   gboolean keep_session;
845
846   if (!ctx->session)
847     goto no_session;
848
849   session = ctx->session;
850
851   if (!ctx->uri)
852     goto no_uri;
853
854   klass = GST_RTSP_CLIENT_GET_CLASS (client);
855   path = klass->make_path_from_uri (client, ctx->uri);
856
857   /* get a handle to the configuration of the media in the session */
858   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
859   if (!sessmedia)
860     goto not_found;
861
862   /* only aggregate control for now.. */
863   if (path[matched] != '\0')
864     goto no_aggregate;
865
866   g_free (path);
867
868   ctx->sessmedia = sessmedia;
869
870   /* we emit the signal before closing the connection */
871   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
872       0, ctx);
873
874   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
875
876   /* unmanage the media in the session, returns false if all media session
877    * are torn down. */
878   keep_session = gst_rtsp_session_release_media (session, sessmedia);
879
880   /* construct the response now */
881   code = GST_RTSP_STS_OK;
882   gst_rtsp_message_init_response (ctx->response, code,
883       gst_rtsp_status_as_text (code), ctx->request);
884
885   send_message (client, ctx, ctx->response, TRUE);
886
887   if (!keep_session) {
888     /* remove the session */
889     gst_rtsp_session_pool_remove (priv->session_pool, session);
890   }
891
892   return TRUE;
893
894   /* ERRORS */
895 no_session:
896   {
897     GST_ERROR ("client %p: no session", client);
898     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
899     return FALSE;
900   }
901 no_uri:
902   {
903     GST_ERROR ("client %p: no uri supplied", client);
904     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
905     return FALSE;
906   }
907 not_found:
908   {
909     GST_ERROR ("client %p: no media for uri", client);
910     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
911     g_free (path);
912     return FALSE;
913   }
914 no_aggregate:
915   {
916     GST_ERROR ("client %p: no aggregate path %s", client, path);
917     send_generic_response (client,
918         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
919     g_free (path);
920     return FALSE;
921   }
922 }
923
924 static GstRTSPResult
925 default_params_set (GstRTSPClient * client, GstRTSPContext * ctx)
926 {
927   GstRTSPResult res;
928
929   res = gst_rtsp_params_set (client, ctx);
930
931   return res;
932 }
933
934 static GstRTSPResult
935 default_params_get (GstRTSPClient * client, GstRTSPContext * ctx)
936 {
937   GstRTSPResult res;
938
939   res = gst_rtsp_params_get (client, ctx);
940
941   return res;
942 }
943
944 static gboolean
945 default_handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
946 {
947   GstRTSPResult res;
948   guint8 *data;
949   guint size;
950
951   res = gst_rtsp_message_get_body (ctx->request, &data, &size);
952   if (res != GST_RTSP_OK)
953     goto bad_request;
954
955   if (size == 0) {
956     /* no body, keep-alive request */
957     send_generic_response (client, GST_RTSP_STS_OK, ctx);
958   } else {
959     /* there is a body, handle the params */
960     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, ctx);
961     if (res != GST_RTSP_OK)
962       goto bad_request;
963
964     send_message (client, ctx, ctx->response, FALSE);
965   }
966
967   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
968       0, ctx);
969
970   return TRUE;
971
972   /* ERRORS */
973 bad_request:
974   {
975     GST_ERROR ("client %p: bad request", client);
976     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
977     return FALSE;
978   }
979 }
980
981 static gboolean
982 default_handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
983 {
984   GstRTSPResult res;
985   guint8 *data;
986   guint size;
987
988   res = gst_rtsp_message_get_body (ctx->request, &data, &size);
989   if (res != GST_RTSP_OK)
990     goto bad_request;
991
992   if (size == 0) {
993     /* no body, keep-alive request */
994     send_generic_response (client, GST_RTSP_STS_OK, ctx);
995   } else {
996     /* there is a body, handle the params */
997     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, ctx);
998     if (res != GST_RTSP_OK)
999       goto bad_request;
1000
1001     send_message (client, ctx, ctx->response, FALSE);
1002   }
1003
1004   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
1005       0, ctx);
1006
1007   return TRUE;
1008
1009   /* ERRORS */
1010 bad_request:
1011   {
1012     GST_ERROR ("client %p: bad request", client);
1013     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1014     return FALSE;
1015   }
1016 }
1017
1018 static gboolean
1019 handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
1020 {
1021   GstRTSPSession *session;
1022   GstRTSPClientClass *klass;
1023   GstRTSPSessionMedia *sessmedia;
1024   GstRTSPStatusCode code;
1025   GstRTSPState rtspstate;
1026   gchar *path;
1027   gint matched;
1028
1029   if (!(session = ctx->session))
1030     goto no_session;
1031
1032   if (!ctx->uri)
1033     goto no_uri;
1034
1035   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1036   path = klass->make_path_from_uri (client, ctx->uri);
1037
1038   /* get a handle to the configuration of the media in the session */
1039   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1040   if (!sessmedia)
1041     goto not_found;
1042
1043   if (path[matched] != '\0')
1044     goto no_aggregate;
1045
1046   g_free (path);
1047
1048   ctx->sessmedia = sessmedia;
1049
1050   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1051   /* the session state must be playing or recording */
1052   if (rtspstate != GST_RTSP_STATE_PLAYING &&
1053       rtspstate != GST_RTSP_STATE_RECORDING)
1054     goto invalid_state;
1055
1056   /* then pause sending */
1057   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED);
1058
1059   /* construct the response now */
1060   code = GST_RTSP_STS_OK;
1061   gst_rtsp_message_init_response (ctx->response, code,
1062       gst_rtsp_status_as_text (code), ctx->request);
1063
1064   send_message (client, ctx, ctx->response, FALSE);
1065
1066   /* the state is now READY */
1067   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1068
1069   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx);
1070
1071   return TRUE;
1072
1073   /* ERRORS */
1074 no_session:
1075   {
1076     GST_ERROR ("client %p: no seesion", client);
1077     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1078     return FALSE;
1079   }
1080 no_uri:
1081   {
1082     GST_ERROR ("client %p: no uri supplied", client);
1083     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1084     return FALSE;
1085   }
1086 not_found:
1087   {
1088     GST_ERROR ("client %p: no media for uri", client);
1089     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1090     g_free (path);
1091     return FALSE;
1092   }
1093 no_aggregate:
1094   {
1095     GST_ERROR ("client %p: no aggregate path %s", client, path);
1096     send_generic_response (client,
1097         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1098     g_free (path);
1099     return FALSE;
1100   }
1101 invalid_state:
1102   {
1103     GST_ERROR ("client %p: not PLAYING or RECORDING", client);
1104     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1105         ctx);
1106     return FALSE;
1107   }
1108 }
1109
1110 /* convert @url and @path to a URL used as a content base for the factory
1111  * located at @path */
1112 static gchar *
1113 make_base_url (GstRTSPClient * client, GstRTSPUrl * url, const gchar * path)
1114 {
1115   GstRTSPUrl tmp;
1116   gchar *result;
1117   const gchar *trail;
1118
1119   /* check for trailing '/' and append one */
1120   trail = (path[strlen (path) - 1] != '/' ? "/" : "");
1121
1122   tmp = *url;
1123   tmp.user = NULL;
1124   tmp.passwd = NULL;
1125   tmp.abspath = g_strdup_printf ("%s%s", path, trail);
1126   tmp.query = NULL;
1127   result = gst_rtsp_url_get_request_uri (&tmp);
1128   g_free (tmp.abspath);
1129
1130   return result;
1131 }
1132
1133 static gboolean
1134 default_handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
1135 {
1136   GstRTSPSession *session;
1137   GstRTSPClientClass *klass;
1138   GstRTSPSessionMedia *sessmedia;
1139   GstRTSPMedia *media;
1140   GstRTSPStatusCode code;
1141   GstRTSPUrl *uri;
1142   gchar *str;
1143   GstRTSPTimeRange *range;
1144   GstRTSPResult res;
1145   GstRTSPState rtspstate;
1146   GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
1147   gchar *path, *rtpinfo;
1148   gint matched;
1149
1150   if (!(session = ctx->session))
1151     goto no_session;
1152
1153   if (!(uri = ctx->uri))
1154     goto no_uri;
1155
1156   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1157   path = klass->make_path_from_uri (client, uri);
1158
1159   /* get a handle to the configuration of the media in the session */
1160   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1161   if (!sessmedia)
1162     goto not_found;
1163
1164   if (path[matched] != '\0')
1165     goto no_aggregate;
1166
1167   g_free (path);
1168
1169   ctx->sessmedia = sessmedia;
1170   ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
1171
1172   if (!(gst_rtsp_media_get_transport_mode (media) &
1173           GST_RTSP_TRANSPORT_MODE_PLAY))
1174     goto unsupported_mode;
1175
1176   /* the session state must be playing or ready */
1177   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1178   if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
1179     goto invalid_state;
1180
1181   /* in play we first unsuspend, media could be suspended from SDP or PAUSED */
1182   if (!gst_rtsp_media_unsuspend (media))
1183     goto unsuspend_failed;
1184
1185   /* parse the range header if we have one */
1186   res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0);
1187   if (res == GST_RTSP_OK) {
1188     if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
1189       GstRTSPMediaStatus media_status;
1190
1191       /* we have a range, seek to the position */
1192       unit = range->unit;
1193       gst_rtsp_media_seek (media, range);
1194       gst_rtsp_range_free (range);
1195
1196       media_status = gst_rtsp_media_get_status (media);
1197       if (media_status == GST_RTSP_MEDIA_STATUS_ERROR)
1198         goto seek_failed;
1199     }
1200   }
1201
1202   /* grab RTPInfo from the media now */
1203   rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia);
1204
1205   /* construct the response now */
1206   code = GST_RTSP_STS_OK;
1207   gst_rtsp_message_init_response (ctx->response, code,
1208       gst_rtsp_status_as_text (code), ctx->request);
1209
1210   /* add the RTP-Info header */
1211   if (rtpinfo)
1212     gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO,
1213         rtpinfo);
1214
1215   /* add the range */
1216   str = gst_rtsp_media_get_range_string (media, TRUE, unit);
1217   if (str)
1218     gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str);
1219
1220   send_message (client, ctx, ctx->response, FALSE);
1221
1222   /* start playing after sending the response */
1223   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
1224
1225   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
1226
1227   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx);
1228
1229   return TRUE;
1230
1231   /* ERRORS */
1232 no_session:
1233   {
1234     GST_ERROR ("client %p: no session", client);
1235     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1236     return FALSE;
1237   }
1238 no_uri:
1239   {
1240     GST_ERROR ("client %p: no uri supplied", client);
1241     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1242     return FALSE;
1243   }
1244 not_found:
1245   {
1246     GST_ERROR ("client %p: media not found", client);
1247     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1248     return FALSE;
1249   }
1250 no_aggregate:
1251   {
1252     GST_ERROR ("client %p: no aggregate path %s", client, path);
1253     send_generic_response (client,
1254         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1255     g_free (path);
1256     return FALSE;
1257   }
1258 invalid_state:
1259   {
1260     GST_ERROR ("client %p: not PLAYING or READY", client);
1261     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1262         ctx);
1263     return FALSE;
1264   }
1265 unsuspend_failed:
1266   {
1267     GST_ERROR ("client %p: unsuspend failed", client);
1268     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1269     return FALSE;
1270   }
1271 seek_failed:
1272   {
1273     GST_ERROR ("client %p: seek failed", client);
1274     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1275     return FALSE;
1276   }
1277 unsupported_mode:
1278   {
1279     GST_ERROR ("client %p: media does not support PLAY", client);
1280     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
1281     return FALSE;
1282   }
1283 }
1284
1285 static void
1286 do_keepalive (GstRTSPSession * session)
1287 {
1288   GST_INFO ("keep session %p alive", session);
1289   gst_rtsp_session_touch (session);
1290 }
1291
1292 /* parse @transport and return a valid transport in @tr. only transports
1293  * supported by @stream are returned. Returns FALSE if no valid transport
1294  * was found. */
1295 static gboolean
1296 parse_transport (const char *transport, GstRTSPStream * stream,
1297     GstRTSPTransport * tr)
1298 {
1299   gint i;
1300   gboolean res;
1301   gchar **transports;
1302
1303   res = FALSE;
1304   gst_rtsp_transport_init (tr);
1305
1306   GST_DEBUG ("parsing transports %s", transport);
1307
1308   transports = g_strsplit (transport, ",", 0);
1309
1310   /* loop through the transports, try to parse */
1311   for (i = 0; transports[i]; i++) {
1312     res = gst_rtsp_transport_parse (transports[i], tr);
1313     if (res != GST_RTSP_OK) {
1314       /* no valid transport, search some more */
1315       GST_WARNING ("could not parse transport %s", transports[i]);
1316       goto next;
1317     }
1318
1319     /* we have a transport, see if it's supported */
1320     if (!gst_rtsp_stream_is_transport_supported (stream, tr)) {
1321       GST_WARNING ("unsupported transport %s", transports[i]);
1322       goto next;
1323     }
1324
1325     /* we have a valid transport */
1326     GST_INFO ("found valid transport %s", transports[i]);
1327     res = TRUE;
1328     break;
1329
1330   next:
1331     gst_rtsp_transport_init (tr);
1332   }
1333   g_strfreev (transports);
1334
1335   return res;
1336 }
1337
1338 static gboolean
1339 default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
1340     GstRTSPStream * stream, GstRTSPContext * ctx)
1341 {
1342   GstRTSPMessage *request = ctx->request;
1343   gchar *blocksize_str;
1344
1345   if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
1346           &blocksize_str, 0) == GST_RTSP_OK) {
1347     guint64 blocksize;
1348     gchar *end;
1349
1350     blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
1351     if (end == blocksize_str)
1352       goto parse_failed;
1353
1354     /* we don't want to change the mtu when this media
1355      * can be shared because it impacts other clients */
1356     if (gst_rtsp_media_is_shared (media))
1357       goto done;
1358
1359     if (blocksize > G_MAXUINT)
1360       blocksize = G_MAXUINT;
1361
1362     gst_rtsp_stream_set_mtu (stream, blocksize);
1363   }
1364 done:
1365   return TRUE;
1366
1367   /* ERRORS */
1368 parse_failed:
1369   {
1370     GST_ERROR_OBJECT (client, "failed to parse blocksize");
1371     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1372     return FALSE;
1373   }
1374 }
1375
1376 static gboolean
1377 default_configure_client_transport (GstRTSPClient * client,
1378     GstRTSPContext * ctx, GstRTSPTransport * ct)
1379 {
1380   GstRTSPClientPrivate *priv = client->priv;
1381
1382   /* we have a valid transport now, set the destination of the client. */
1383   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1384     gboolean use_client_settings;
1385
1386     use_client_settings =
1387         gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS);
1388
1389     if (ct->destination && use_client_settings) {
1390       GstRTSPAddress *addr;
1391
1392       addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination,
1393           ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
1394
1395       if (addr == NULL)
1396         goto no_address;
1397
1398       gst_rtsp_address_free (addr);
1399     } else {
1400       GstRTSPAddress *addr;
1401       GSocketFamily family;
1402
1403       family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4;
1404
1405       addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family);
1406       if (addr == NULL)
1407         goto no_address;
1408
1409       g_free (ct->destination);
1410       ct->destination = g_strdup (addr->address);
1411       ct->port.min = addr->port;
1412       ct->port.max = addr->port + addr->n_ports - 1;
1413       ct->ttl = addr->ttl;
1414
1415       gst_rtsp_address_free (addr);
1416     }
1417   } else {
1418     GstRTSPUrl *url;
1419
1420     url = gst_rtsp_connection_get_url (priv->connection);
1421     g_free (ct->destination);
1422     ct->destination = g_strdup (url->host);
1423
1424     if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1425       GSocket *sock;
1426       GSocketAddress *addr;
1427
1428       sock = gst_rtsp_connection_get_read_socket (priv->connection);
1429       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1430         /* our read port is the sender port of client */
1431         ct->client_port.min =
1432             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1433         g_object_unref (addr);
1434       }
1435       if ((addr = g_socket_get_local_address (sock, NULL))) {
1436         ct->server_port.max =
1437             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1438         g_object_unref (addr);
1439       }
1440       sock = gst_rtsp_connection_get_write_socket (priv->connection);
1441       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1442         /* our write port is the receiver port of client */
1443         ct->client_port.max =
1444             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1445         g_object_unref (addr);
1446       }
1447       if ((addr = g_socket_get_local_address (sock, NULL))) {
1448         ct->server_port.min =
1449             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1450         g_object_unref (addr);
1451       }
1452       /* check if the client selected channels for TCP */
1453       if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1454         gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
1455             &ct->interleaved);
1456       }
1457     }
1458   }
1459   return TRUE;
1460
1461   /* ERRORS */
1462 no_address:
1463   {
1464     GST_ERROR_OBJECT (client, "failed to acquire address for stream");
1465     return FALSE;
1466   }
1467 }
1468
1469 static GstRTSPTransport *
1470 make_server_transport (GstRTSPClient * client, GstRTSPMedia * media,
1471     GstRTSPContext * ctx, GstRTSPTransport * ct)
1472 {
1473   GstRTSPTransport *st;
1474   GInetAddress *addr;
1475   GSocketFamily family;
1476
1477   /* prepare the server transport */
1478   gst_rtsp_transport_new (&st);
1479
1480   st->trans = ct->trans;
1481   st->profile = ct->profile;
1482   st->lower_transport = ct->lower_transport;
1483   st->mode_play = ct->mode_play;
1484   st->mode_record = ct->mode_record;
1485
1486   addr = g_inet_address_new_from_string (ct->destination);
1487
1488   if (!addr) {
1489     GST_ERROR ("failed to get inet addr from client destination");
1490     family = G_SOCKET_FAMILY_IPV4;
1491   } else {
1492     family = g_inet_address_get_family (addr);
1493     g_object_unref (addr);
1494     addr = NULL;
1495   }
1496
1497   switch (st->lower_transport) {
1498     case GST_RTSP_LOWER_TRANS_UDP:
1499       st->client_port = ct->client_port;
1500       gst_rtsp_stream_get_server_port (ctx->stream, &st->server_port, family);
1501       break;
1502     case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1503       st->port = ct->port;
1504       st->destination = g_strdup (ct->destination);
1505       st->ttl = ct->ttl;
1506       break;
1507     case GST_RTSP_LOWER_TRANS_TCP:
1508       st->interleaved = ct->interleaved;
1509       st->client_port = ct->client_port;
1510       st->server_port = ct->server_port;
1511     default:
1512       break;
1513   }
1514
1515   if ((gst_rtsp_media_get_transport_mode (media) &
1516           GST_RTSP_TRANSPORT_MODE_PLAY))
1517     gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc);
1518
1519   return st;
1520 }
1521
1522 #define AES_128_KEY_LEN 16
1523 #define AES_256_KEY_LEN 32
1524
1525 #define HMAC_32_KEY_LEN 4
1526 #define HMAC_80_KEY_LEN 10
1527
1528 static gboolean
1529 mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy)
1530 {
1531   const gchar *srtp_cipher;
1532   const gchar *srtp_auth;
1533   const GstMIKEYPayload *sp;
1534   guint i;
1535
1536   /* loop over Security policy until we find one containing policy */
1537   for (i = 0;; i++) {
1538     if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL)
1539       break;
1540
1541     if (((GstMIKEYPayloadSP *) sp)->policy == policy)
1542       break;
1543   }
1544
1545   /* the default ciphers */
1546   srtp_cipher = "aes-128-icm";
1547   srtp_auth = "hmac-sha1-80";
1548
1549   /* now override the defaults with what is in the Security Policy */
1550   if (sp != NULL) {
1551     guint len;
1552
1553     /* collect all the params and go over them */
1554     len = gst_mikey_payload_sp_get_n_params (sp);
1555     for (i = 0; i < len; i++) {
1556       const GstMIKEYPayloadSPParam *param =
1557           gst_mikey_payload_sp_get_param (sp, i);
1558
1559       switch (param->type) {
1560         case GST_MIKEY_SP_SRTP_ENC_ALG:
1561           switch (param->val[0]) {
1562             case 0:
1563               srtp_cipher = "null";
1564               break;
1565             case 2:
1566             case 1:
1567               srtp_cipher = "aes-128-icm";
1568               break;
1569             default:
1570               break;
1571           }
1572           break;
1573         case GST_MIKEY_SP_SRTP_ENC_KEY_LEN:
1574           switch (param->val[0]) {
1575             case AES_128_KEY_LEN:
1576               srtp_cipher = "aes-128-icm";
1577               break;
1578             case AES_256_KEY_LEN:
1579               srtp_cipher = "aes-256-icm";
1580               break;
1581             default:
1582               break;
1583           }
1584           break;
1585         case GST_MIKEY_SP_SRTP_AUTH_ALG:
1586           switch (param->val[0]) {
1587             case 0:
1588               srtp_auth = "null";
1589               break;
1590             case 2:
1591             case 1:
1592               srtp_auth = "hmac-sha1-80";
1593               break;
1594             default:
1595               break;
1596           }
1597           break;
1598         case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN:
1599           switch (param->val[0]) {
1600             case HMAC_32_KEY_LEN:
1601               srtp_auth = "hmac-sha1-32";
1602               break;
1603             case HMAC_80_KEY_LEN:
1604               srtp_auth = "hmac-sha1-80";
1605               break;
1606             default:
1607               break;
1608           }
1609           break;
1610         case GST_MIKEY_SP_SRTP_SRTP_ENC:
1611           break;
1612         case GST_MIKEY_SP_SRTP_SRTCP_ENC:
1613           break;
1614         default:
1615           break;
1616       }
1617     }
1618   }
1619   /* now configure the SRTP parameters */
1620   gst_caps_set_simple (caps,
1621       "srtp-cipher", G_TYPE_STRING, srtp_cipher,
1622       "srtp-auth", G_TYPE_STRING, srtp_auth,
1623       "srtcp-cipher", G_TYPE_STRING, srtp_cipher,
1624       "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
1625
1626   return TRUE;
1627 }
1628
1629 static gboolean
1630 handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx,
1631     guint8 * data, gsize size)
1632 {
1633   GstMIKEYMessage *msg;
1634   guint i, n_cs;
1635   GstCaps *caps = NULL;
1636   GstMIKEYPayloadKEMAC *kemac;
1637   const GstMIKEYPayloadKeyData *pkd;
1638   GstBuffer *key;
1639
1640   /* the MIKEY message contains a CSB or crypto session bundle. It is a
1641    * set of Crypto Sessions protected with the same master key.
1642    * In the context of SRTP, an RTP and its RTCP stream is part of a
1643    * crypto session */
1644   if ((msg = gst_mikey_message_new_from_data (data, size, NULL, NULL)) == NULL)
1645     goto parse_failed;
1646
1647   /* we can only handle SRTP crypto sessions for now */
1648   if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP)
1649     goto invalid_map_type;
1650
1651   /* get the number of crypto sessions. This maps SSRC to its
1652    * security parameters */
1653   n_cs = gst_mikey_message_get_n_cs (msg);
1654   if (n_cs == 0)
1655     goto no_crypto_sessions;
1656
1657   /* we also need keys */
1658   if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload
1659           (msg, GST_MIKEY_PT_KEMAC, 0)))
1660     goto no_keys;
1661
1662   /* we don't support encrypted keys */
1663   if (kemac->enc_alg != GST_MIKEY_ENC_NULL
1664       || kemac->mac_alg != GST_MIKEY_MAC_NULL)
1665     goto unsupported_encryption;
1666
1667   /* get Key data sub-payload */
1668   pkd = (const GstMIKEYPayloadKeyData *)
1669       gst_mikey_payload_kemac_get_sub (&kemac->pt, 0);
1670
1671   key =
1672       gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
1673       pkd->key_len);
1674
1675   /* go over all crypto sessions and create the security policy for each
1676    * SSRC */
1677   for (i = 0; i < n_cs; i++) {
1678     const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i);
1679
1680     caps = gst_caps_new_simple ("application/x-srtp",
1681         "ssrc", G_TYPE_UINT, map->ssrc,
1682         "roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL);
1683     mikey_apply_policy (caps, msg, map->policy);
1684
1685     gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps);
1686     gst_caps_unref (caps);
1687   }
1688   gst_mikey_message_unref (msg);
1689   gst_buffer_unref (key);
1690
1691   return TRUE;
1692
1693   /* ERRORS */
1694 parse_failed:
1695   {
1696     GST_DEBUG_OBJECT (client, "failed to parse MIKEY message");
1697     return FALSE;
1698   }
1699 invalid_map_type:
1700   {
1701     GST_DEBUG_OBJECT (client, "invalid map type %d", msg->map_type);
1702     goto cleanup_message;
1703   }
1704 no_crypto_sessions:
1705   {
1706     GST_DEBUG_OBJECT (client, "no crypto sessions");
1707     goto cleanup_message;
1708   }
1709 no_keys:
1710   {
1711     GST_DEBUG_OBJECT (client, "no keys found");
1712     goto cleanup_message;
1713   }
1714 unsupported_encryption:
1715   {
1716     GST_DEBUG_OBJECT (client, "unsupported key encryption");
1717     goto cleanup_message;
1718   }
1719 cleanup_message:
1720   {
1721     gst_mikey_message_unref (msg);
1722     return FALSE;
1723   }
1724 }
1725
1726 #define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"'))
1727
1728 static void
1729 strip_chars (gchar * str)
1730 {
1731   gchar *s;
1732   gsize len;
1733
1734   len = strlen (str);
1735   while (len--) {
1736     if (!IS_STRIP_CHAR (str[len]))
1737       break;
1738     str[len] = '\0';
1739   }
1740   for (s = str; *s && IS_STRIP_CHAR (*s); s++);
1741   memmove (str, s, len + 1);
1742 }
1743
1744 /* KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec)
1745  * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"]
1746  */
1747 static gboolean
1748 handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt)
1749 {
1750   gchar **specs;
1751   gint i, j;
1752
1753   specs = g_strsplit (keymgmt, ",", 0);
1754   for (i = 0; specs[i]; i++) {
1755     gchar **split;
1756
1757     split = g_strsplit (specs[i], ";", 0);
1758     for (j = 0; split[j]; j++) {
1759       g_strstrip (split[j]);
1760       if (g_str_has_prefix (split[j], "prot=")) {
1761         g_strstrip (split[j] + 5);
1762         if (!g_str_equal (split[j] + 5, "mikey"))
1763           break;
1764         GST_DEBUG ("found mikey");
1765       } else if (g_str_has_prefix (split[j], "uri=")) {
1766         strip_chars (split[j] + 4);
1767         GST_DEBUG ("found uri '%s'", split[j] + 4);
1768       } else if (g_str_has_prefix (split[j], "data=")) {
1769         guchar *data;
1770         gsize size;
1771         strip_chars (split[j] + 5);
1772         GST_DEBUG ("found data '%s'", split[j] + 5);
1773         data = g_base64_decode_inplace (split[j] + 5, &size);
1774         handle_mikey_data (client, ctx, data, size);
1775       }
1776     }
1777     g_strfreev (split);
1778   }
1779   g_strfreev (specs);
1780   return TRUE;
1781 }
1782
1783 static gboolean
1784 handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
1785 {
1786   GstRTSPClientPrivate *priv = client->priv;
1787   GstRTSPResult res;
1788   GstRTSPUrl *uri;
1789   gchar *transport, *keymgmt;
1790   GstRTSPTransport *ct, *st;
1791   GstRTSPStatusCode code;
1792   GstRTSPSession *session;
1793   GstRTSPStreamTransport *trans;
1794   gchar *trans_str;
1795   GstRTSPSessionMedia *sessmedia;
1796   GstRTSPMedia *media;
1797   GstRTSPStream *stream;
1798   GstRTSPState rtspstate;
1799   GstRTSPClientClass *klass;
1800   gchar *path, *control = NULL;
1801   gint matched;
1802   gboolean new_session = FALSE;
1803
1804   if (!ctx->uri)
1805     goto no_uri;
1806
1807   uri = ctx->uri;
1808   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1809   path = klass->make_path_from_uri (client, uri);
1810
1811   /* parse the transport */
1812   res =
1813       gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_TRANSPORT,
1814       &transport, 0);
1815   if (res != GST_RTSP_OK)
1816     goto no_transport;
1817
1818   /* we create the session after parsing stuff so that we don't make
1819    * a session for malformed requests */
1820   if (priv->session_pool == NULL)
1821     goto no_pool;
1822
1823   session = ctx->session;
1824
1825   if (session) {
1826     g_object_ref (session);
1827     /* get a handle to the configuration of the media in the session, this can
1828      * return NULL if this is a new url to manage in this session. */
1829     sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1830   } else {
1831     /* we need a new media configuration in this session */
1832     sessmedia = NULL;
1833   }
1834
1835   /* we have no session media, find one and manage it */
1836   if (sessmedia == NULL) {
1837     /* get a handle to the configuration of the media in the session */
1838     media = find_media (client, ctx, path, &matched);
1839   } else {
1840     if ((media = gst_rtsp_session_media_get_media (sessmedia)))
1841       g_object_ref (media);
1842     else
1843       goto media_not_found;
1844   }
1845   /* no media, not found then */
1846   if (media == NULL)
1847     goto media_not_found_no_reply;
1848
1849   if (path[matched] == '\0') {
1850     if (gst_rtsp_media_n_streams (media) == 1) {
1851       stream = gst_rtsp_media_get_stream (media, 0);
1852     } else {
1853       goto control_not_found;
1854     }
1855   } else {
1856     /* path is what matched. */
1857     path[matched] = '\0';
1858     /* control is remainder */
1859     control = &path[matched + 1];
1860
1861     /* find the stream now using the control part */
1862     stream = gst_rtsp_media_find_stream (media, control);
1863   }
1864
1865   if (stream == NULL)
1866     goto stream_not_found;
1867
1868   /* now we have a uri identifying a valid media and stream */
1869   ctx->stream = stream;
1870   ctx->media = media;
1871
1872   if (session == NULL) {
1873     /* create a session if this fails we probably reached our session limit or
1874      * something. */
1875     if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
1876       goto service_unavailable;
1877
1878     /* make sure this client is closed when the session is closed */
1879     client_watch_session (client, session);
1880
1881     new_session = TRUE;
1882     /* signal new session */
1883     g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
1884         session);
1885
1886     ctx->session = session;
1887   }
1888
1889   if (!klass->configure_client_media (client, media, stream, ctx))
1890     goto configure_media_failed_no_reply;
1891
1892   gst_rtsp_transport_new (&ct);
1893
1894   /* parse and find a usable supported transport */
1895   if (!parse_transport (transport, stream, ct))
1896     goto unsupported_transports;
1897
1898   if ((ct->mode_play
1899           && !(gst_rtsp_media_get_transport_mode (media) &
1900               GST_RTSP_TRANSPORT_MODE_PLAY)) || (ct->mode_record
1901           && !(gst_rtsp_media_get_transport_mode (media) &
1902               GST_RTSP_TRANSPORT_MODE_RECORD)))
1903     goto unsupported_mode;
1904
1905   /* parse the keymgmt */
1906   if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT,
1907           &keymgmt, 0) == GST_RTSP_OK) {
1908     if (!handle_keymgmt (client, ctx, keymgmt))
1909       goto keymgmt_error;
1910   }
1911
1912   if (sessmedia == NULL) {
1913     /* manage the media in our session now, if not done already  */
1914     sessmedia = gst_rtsp_session_manage_media (session, path, media);
1915     /* if we stil have no media, error */
1916     if (sessmedia == NULL)
1917       goto sessmedia_unavailable;
1918
1919     /* don't cache media anymore */
1920     clean_cached_media (client, FALSE);
1921   } else {
1922     g_object_unref (media);
1923   }
1924
1925   ctx->sessmedia = sessmedia;
1926
1927   /* update the client transport */
1928   if (!klass->configure_client_transport (client, ctx, ct))
1929     goto unsupported_client_transport;
1930
1931   /* set in the session media transport */
1932   trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
1933
1934   ctx->trans = trans;
1935
1936   /* configure the url used to set this transport, this we will use when
1937    * generating the response for the PLAY request */
1938   gst_rtsp_stream_transport_set_url (trans, uri);
1939   /* configure keepalive for this transport */
1940   gst_rtsp_stream_transport_set_keepalive (trans,
1941       (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
1942
1943   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1944     /* our callbacks to send data on this TCP connection */
1945     gst_rtsp_stream_transport_set_callbacks (trans,
1946         (GstRTSPSendFunc) do_send_data,
1947         (GstRTSPSendFunc) do_send_data, client, NULL);
1948
1949     g_hash_table_insert (priv->transports,
1950         GINT_TO_POINTER (ct->interleaved.min), trans);
1951     g_object_ref (trans);
1952     g_hash_table_insert (priv->transports,
1953         GINT_TO_POINTER (ct->interleaved.max), trans);
1954     g_object_ref (trans);
1955   }
1956
1957   /* create and serialize the server transport */
1958   st = make_server_transport (client, media, ctx, ct);
1959   trans_str = gst_rtsp_transport_as_text (st);
1960
1961   /* FIXME-WFD : Temporarily force to set profile string */
1962   trans_str = g_strjoinv ("RTP/AVP/UDP", g_strsplit (trans_str, "RTP/AVP", -1));
1963
1964   gst_rtsp_transport_free (st);
1965
1966   /* construct the response now */
1967   code = GST_RTSP_STS_OK;
1968   gst_rtsp_message_init_response (ctx->response, code,
1969       gst_rtsp_status_as_text (code), ctx->request);
1970
1971   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_TRANSPORT,
1972       trans_str);
1973   g_free (trans_str);
1974
1975   send_message (client, ctx, ctx->response, FALSE);
1976
1977   /* update the state */
1978   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1979   switch (rtspstate) {
1980     case GST_RTSP_STATE_PLAYING:
1981     case GST_RTSP_STATE_RECORDING:
1982     case GST_RTSP_STATE_READY:
1983       /* no state change */
1984       break;
1985     default:
1986       gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1987       break;
1988   }
1989   g_object_unref (session);
1990   g_free (path);
1991
1992   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx);
1993
1994   return TRUE;
1995
1996   /* ERRORS */
1997 no_uri:
1998   {
1999     GST_ERROR ("client %p: no uri", client);
2000     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2001     return FALSE;
2002   }
2003 no_transport:
2004   {
2005     GST_ERROR ("client %p: no transport", client);
2006     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2007     goto cleanup_path;
2008   }
2009 no_pool:
2010   {
2011     GST_ERROR ("client %p: no session pool configured", client);
2012     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2013     goto cleanup_path;
2014   }
2015 media_not_found_no_reply:
2016   {
2017     GST_ERROR ("client %p: media '%s' not found", client, path);
2018     /* error reply is already sent */
2019     goto cleanup_path;
2020   }
2021 media_not_found:
2022   {
2023     GST_ERROR ("client %p: media '%s' not found", client, path);
2024     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2025     goto cleanup_path;
2026   }
2027 control_not_found:
2028   {
2029     GST_ERROR ("client %p: no control in path '%s'", client, path);
2030     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2031     g_object_unref (media);
2032     goto cleanup_path;
2033   }
2034 stream_not_found:
2035   {
2036     GST_ERROR ("client %p: stream '%s' not found", client,
2037         GST_STR_NULL (control));
2038     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2039     g_object_unref (media);
2040     goto cleanup_path;
2041   }
2042 service_unavailable:
2043   {
2044     GST_ERROR ("client %p: can't create session", client);
2045     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2046     g_object_unref (media);
2047     goto cleanup_path;
2048   }
2049 sessmedia_unavailable:
2050   {
2051     GST_ERROR ("client %p: can't create session media", client);
2052     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2053     g_object_unref (media);
2054     goto cleanup_session;
2055   }
2056 configure_media_failed_no_reply:
2057   {
2058     GST_ERROR ("client %p: configure_media failed", client);
2059     /* error reply is already sent */
2060     goto cleanup_session;
2061   }
2062 unsupported_transports:
2063   {
2064     GST_ERROR ("client %p: unsupported transports", client);
2065     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2066     goto cleanup_transport;
2067   }
2068 unsupported_client_transport:
2069   {
2070     GST_ERROR ("client %p: unsupported client transport", client);
2071     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2072     goto cleanup_transport;
2073   }
2074 unsupported_mode:
2075   {
2076     GST_ERROR ("client %p: unsupported mode (media play: %d, media record: %d, "
2077         "mode play: %d, mode record: %d)", client,
2078         ! !(gst_rtsp_media_get_transport_mode (media) &
2079             GST_RTSP_TRANSPORT_MODE_PLAY),
2080         ! !(gst_rtsp_media_get_transport_mode (media) &
2081             GST_RTSP_TRANSPORT_MODE_RECORD), ct->mode_play, ct->mode_record);
2082     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2083     goto cleanup_transport;
2084   }
2085 keymgmt_error:
2086   {
2087     GST_ERROR ("client %p: keymgmt error", client);
2088     send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx);
2089     goto cleanup_transport;
2090   }
2091   {
2092   cleanup_transport:
2093     gst_rtsp_transport_free (ct);
2094   cleanup_session:
2095     if (new_session)
2096       gst_rtsp_session_pool_remove (priv->session_pool, session);
2097     g_object_unref (session);
2098   cleanup_path:
2099     g_free (path);
2100     return FALSE;
2101   }
2102 }
2103
2104 static GstSDPMessage *
2105 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
2106 {
2107   GstRTSPClientPrivate *priv = client->priv;
2108   GstSDPMessage *sdp;
2109   GstSDPInfo info;
2110   const gchar *proto;
2111   guint64 session_id_tmp;
2112   gchar session_id[21];
2113
2114   gst_sdp_message_new (&sdp);
2115
2116   /* some standard things first */
2117   gst_sdp_message_set_version (sdp, "0");
2118
2119   if (priv->is_ipv6)
2120     proto = "IP6";
2121   else
2122     proto = "IP4";
2123
2124   session_id_tmp = (((guint64) g_random_int ()) << 32) | g_random_int ();
2125   g_snprintf (session_id, sizeof (session_id), "%" G_GUINT64_FORMAT,
2126       session_id_tmp);
2127
2128   gst_sdp_message_set_origin (sdp, "-", session_id, "1", "IN", proto,
2129       priv->server_ip);
2130
2131   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
2132   gst_sdp_message_set_information (sdp, "rtsp-server");
2133   gst_sdp_message_add_time (sdp, "0", "0", NULL);
2134   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
2135   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
2136   gst_sdp_message_add_attribute (sdp, "control", "*");
2137
2138   info.is_ipv6 = priv->is_ipv6;
2139   info.server_ip = priv->server_ip;
2140
2141   /* create an SDP for the media object */
2142   if (!gst_rtsp_media_setup_sdp (media, sdp, &info))
2143     goto no_sdp;
2144
2145   return sdp;
2146
2147   /* ERRORS */
2148 no_sdp:
2149   {
2150     GST_ERROR ("client %p: could not create SDP", client);
2151     gst_sdp_message_free (sdp);
2152     return NULL;
2153   }
2154 }
2155
2156 /* for the describe we must generate an SDP */
2157 static gboolean
2158 handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx)
2159 {
2160   GstRTSPClientPrivate *priv = client->priv;
2161   GstRTSPResult res;
2162   GstSDPMessage *sdp;
2163   guint i;
2164   gchar *path, *str;
2165   GstRTSPMedia *media;
2166   GstRTSPClientClass *klass;
2167
2168   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2169
2170   if (!ctx->uri)
2171     goto no_uri;
2172
2173   /* check what kind of format is accepted, we don't really do anything with it
2174    * and always return SDP for now. */
2175   for (i = 0;; i++) {
2176     gchar *accept;
2177
2178     res =
2179         gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT,
2180         &accept, i);
2181     if (res == GST_RTSP_ENOTIMPL)
2182       break;
2183
2184     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
2185       break;
2186   }
2187
2188   if (!priv->mount_points)
2189     goto no_mount_points;
2190
2191   if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
2192     goto no_path;
2193
2194   /* find the media object for the uri */
2195   if (!(media = find_media (client, ctx, path, NULL)))
2196     goto no_media;
2197
2198   if (!(gst_rtsp_media_get_transport_mode (media) &
2199           GST_RTSP_TRANSPORT_MODE_PLAY))
2200     goto unsupported_mode;
2201
2202   /* create an SDP for the media object on this client */
2203   if (!(sdp = klass->create_sdp (client, media)))
2204     goto no_sdp;
2205
2206   /* we suspend after the describe */
2207   gst_rtsp_media_suspend (media);
2208   g_object_unref (media);
2209
2210   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2211       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2212
2213   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_TYPE,
2214       "application/sdp");
2215
2216   /* content base for some clients that might screw up creating the setup uri */
2217   str = make_base_url (client, ctx->uri, path);
2218   g_free (path);
2219
2220   GST_INFO ("adding content-base: %s", str);
2221   gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, str);
2222
2223   /* add SDP to the response body */
2224   str = gst_sdp_message_as_text (sdp);
2225   gst_rtsp_message_take_body (ctx->response, (guint8 *) str, strlen (str));
2226   gst_sdp_message_free (sdp);
2227
2228   send_message (client, ctx, ctx->response, FALSE);
2229
2230   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
2231       0, ctx);
2232
2233   return TRUE;
2234
2235   /* ERRORS */
2236 no_uri:
2237   {
2238     GST_ERROR ("client %p: no uri", client);
2239     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2240     return FALSE;
2241   }
2242 no_mount_points:
2243   {
2244     GST_ERROR ("client %p: no mount points configured", client);
2245     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2246     return FALSE;
2247   }
2248 no_path:
2249   {
2250     GST_ERROR ("client %p: can't find path for url", client);
2251     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2252     return FALSE;
2253   }
2254 no_media:
2255   {
2256     GST_ERROR ("client %p: no media", client);
2257     g_free (path);
2258     /* error reply is already sent */
2259     return FALSE;
2260   }
2261 unsupported_mode:
2262   {
2263     GST_ERROR ("client %p: media does not support DESCRIBE", client);
2264     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
2265     g_free (path);
2266     g_object_unref (media);
2267     return FALSE;
2268   }
2269 no_sdp:
2270   {
2271     GST_ERROR ("client %p: can't create SDP", client);
2272     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2273     g_free (path);
2274     g_object_unref (media);
2275     return FALSE;
2276   }
2277 }
2278
2279 static gboolean
2280 handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPMedia * media,
2281     GstSDPMessage * sdp)
2282 {
2283   GstRTSPClientPrivate *priv = client->priv;
2284   GstRTSPThread *thread;
2285
2286   /* create an SDP for the media object */
2287   if (!gst_rtsp_media_handle_sdp (media, sdp))
2288     goto unhandled_sdp;
2289
2290   thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool,
2291       GST_RTSP_THREAD_TYPE_MEDIA, ctx);
2292   if (thread == NULL)
2293     goto no_thread;
2294
2295   /* prepare the media */
2296   if (!gst_rtsp_media_prepare (media, thread))
2297     goto no_prepare;
2298
2299   return TRUE;
2300
2301   /* ERRORS */
2302 unhandled_sdp:
2303   {
2304     GST_ERROR ("client %p: could not handle SDP", client);
2305     return FALSE;
2306   }
2307 no_thread:
2308   {
2309     GST_ERROR ("client %p: can't create thread", client);
2310     return FALSE;
2311   }
2312 no_prepare:
2313   {
2314     GST_ERROR ("client %p: can't prepare media", client);
2315     return FALSE;
2316   }
2317 }
2318
2319 static gboolean
2320 handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx)
2321 {
2322   GstRTSPClientPrivate *priv = client->priv;
2323   GstRTSPClientClass *klass;
2324   GstSDPResult sres;
2325   GstSDPMessage *sdp;
2326   GstRTSPMedia *media;
2327   gchar *path, *cont = NULL;
2328   guint8 *data;
2329   guint size;
2330
2331   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2332
2333   if (!ctx->uri)
2334     goto no_uri;
2335
2336   if (!priv->mount_points)
2337     goto no_mount_points;
2338
2339   /* check if reply is SDP */
2340   gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_CONTENT_TYPE, &cont,
2341       0);
2342   /* could not be set but since the request returned OK, we assume it
2343    * was SDP, else check it. */
2344   if (cont) {
2345     if (g_ascii_strcasecmp (cont, "application/sdp") != 0)
2346       goto wrong_content_type;
2347   }
2348
2349   /* get message body and parse as SDP */
2350   gst_rtsp_message_get_body (ctx->request, &data, &size);
2351   if (data == NULL || size == 0)
2352     goto no_message;
2353
2354   GST_DEBUG ("client %p: parse SDP...", client);
2355   gst_sdp_message_new (&sdp);
2356   sres = gst_sdp_message_parse_buffer (data, size, sdp);
2357   if (sres != GST_SDP_OK)
2358     goto sdp_parse_failed;
2359
2360   if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
2361     goto no_path;
2362
2363   /* find the media object for the uri */
2364   if (!(media = find_media (client, ctx, path, NULL)))
2365     goto no_media;
2366
2367   if (!(gst_rtsp_media_get_transport_mode (media) &
2368           GST_RTSP_TRANSPORT_MODE_RECORD))
2369     goto unsupported_mode;
2370
2371   /* Tell client subclass about the media */
2372   if (!klass->handle_sdp (client, ctx, media, sdp))
2373     goto unhandled_sdp;
2374
2375   /* we suspend after the announce */
2376   gst_rtsp_media_suspend (media);
2377   g_object_unref (media);
2378
2379   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2380       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2381
2382   send_message (client, ctx, ctx->response, FALSE);
2383
2384   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST],
2385       0, ctx);
2386
2387   gst_sdp_message_free (sdp);
2388   g_free (path);
2389   return TRUE;
2390
2391 no_uri:
2392   {
2393     GST_ERROR ("client %p: no uri", client);
2394     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2395     return FALSE;
2396   }
2397 no_mount_points:
2398   {
2399     GST_ERROR ("client %p: no mount points configured", client);
2400     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2401     return FALSE;
2402   }
2403 no_path:
2404   {
2405     GST_ERROR ("client %p: can't find path for url", client);
2406     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2407     gst_sdp_message_free (sdp);
2408     return FALSE;
2409   }
2410 wrong_content_type:
2411   {
2412     GST_ERROR ("client %p: unknown content type", client);
2413     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2414     return FALSE;
2415   }
2416 no_message:
2417   {
2418     GST_ERROR ("client %p: can't find SDP message", client);
2419     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2420     return FALSE;
2421   }
2422 sdp_parse_failed:
2423   {
2424     GST_ERROR ("client %p: failed to parse SDP message", client);
2425     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2426     gst_sdp_message_free (sdp);
2427     return FALSE;
2428   }
2429 no_media:
2430   {
2431     GST_ERROR ("client %p: no media", client);
2432     g_free (path);
2433     /* error reply is already sent */
2434     gst_sdp_message_free (sdp);
2435     return FALSE;
2436   }
2437 unsupported_mode:
2438   {
2439     GST_ERROR ("client %p: media does not support ANNOUNCE", client);
2440     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
2441     g_free (path);
2442     g_object_unref (media);
2443     gst_sdp_message_free (sdp);
2444     return FALSE;
2445   }
2446 unhandled_sdp:
2447   {
2448     GST_ERROR ("client %p: can't handle SDP", client);
2449     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx);
2450     g_free (path);
2451     g_object_unref (media);
2452     gst_sdp_message_free (sdp);
2453     return FALSE;
2454   }
2455 }
2456
2457 static gboolean
2458 handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx)
2459 {
2460   GstRTSPSession *session;
2461   GstRTSPClientClass *klass;
2462   GstRTSPSessionMedia *sessmedia;
2463   GstRTSPMedia *media;
2464   GstRTSPUrl *uri;
2465   GstRTSPState rtspstate;
2466   gchar *path;
2467   gint matched;
2468
2469   if (!(session = ctx->session))
2470     goto no_session;
2471
2472   if (!(uri = ctx->uri))
2473     goto no_uri;
2474
2475   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2476   path = klass->make_path_from_uri (client, uri);
2477
2478   /* get a handle to the configuration of the media in the session */
2479   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
2480   if (!sessmedia)
2481     goto not_found;
2482
2483   if (path[matched] != '\0')
2484     goto no_aggregate;
2485
2486   g_free (path);
2487
2488   ctx->sessmedia = sessmedia;
2489   ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
2490
2491   if (!(gst_rtsp_media_get_transport_mode (media) &
2492           GST_RTSP_TRANSPORT_MODE_RECORD))
2493     goto unsupported_mode;
2494
2495   /* the session state must be playing or ready */
2496   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
2497   if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
2498     goto invalid_state;
2499
2500   /* in play we first unsuspend, media could be suspended from SDP or PAUSED */
2501   if (!gst_rtsp_media_unsuspend (media))
2502     goto unsuspend_failed;
2503
2504   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2505       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2506
2507   send_message (client, ctx, ctx->response, FALSE);
2508
2509   /* start playing after sending the response */
2510   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
2511
2512   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
2513
2514   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST], 0,
2515       ctx);
2516
2517   return TRUE;
2518
2519   /* ERRORS */
2520 no_session:
2521   {
2522     GST_ERROR ("client %p: no session", client);
2523     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2524     return FALSE;
2525   }
2526 no_uri:
2527   {
2528     GST_ERROR ("client %p: no uri supplied", client);
2529     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2530     return FALSE;
2531   }
2532 not_found:
2533   {
2534     GST_ERROR ("client %p: media not found", client);
2535     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2536     return FALSE;
2537   }
2538 no_aggregate:
2539   {
2540     GST_ERROR ("client %p: no aggregate path %s", client, path);
2541     send_generic_response (client,
2542         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
2543     g_free (path);
2544     return FALSE;
2545   }
2546 unsupported_mode:
2547   {
2548     GST_ERROR ("client %p: media does not support RECORD", client);
2549     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
2550     return FALSE;
2551   }
2552 invalid_state:
2553   {
2554     GST_ERROR ("client %p: not PLAYING or READY", client);
2555     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
2556         ctx);
2557     return FALSE;
2558   }
2559 unsuspend_failed:
2560   {
2561     GST_ERROR ("client %p: unsuspend failed", client);
2562     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2563     return FALSE;
2564   }
2565 }
2566
2567 static gboolean
2568 default_handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
2569 {
2570   GstRTSPMethod options;
2571   gchar *str;
2572
2573   options = GST_RTSP_DESCRIBE |
2574       GST_RTSP_OPTIONS |
2575       GST_RTSP_PAUSE |
2576       GST_RTSP_PLAY |
2577       GST_RTSP_SETUP |
2578       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
2579
2580   str = gst_rtsp_options_as_text (options);
2581
2582   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2583       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2584
2585   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str);
2586   g_free (str);
2587
2588   send_message (client, ctx, ctx->response, FALSE);
2589
2590   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
2591       0, ctx);
2592
2593   return TRUE;
2594 }
2595
2596 /* remove duplicate and trailing '/' */
2597 static void
2598 sanitize_uri (GstRTSPUrl * uri)
2599 {
2600   gint i, len;
2601   gchar *s, *d;
2602   gboolean have_slash, prev_slash;
2603
2604   s = d = uri->abspath;
2605   len = strlen (uri->abspath);
2606
2607   prev_slash = FALSE;
2608
2609   for (i = 0; i < len; i++) {
2610     have_slash = s[i] == '/';
2611     *d = s[i];
2612     if (!have_slash || !prev_slash)
2613       d++;
2614     prev_slash = have_slash;
2615   }
2616   len = d - uri->abspath;
2617   /* don't remove the first slash if that's the only thing left */
2618   if (len > 1 && *(d - 1) == '/')
2619     d--;
2620   *d = '\0';
2621 }
2622
2623 /* is called when the session is removed from its session pool. */
2624 static void
2625 client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session,
2626     GstRTSPClient * client)
2627 {
2628   GstRTSPClientPrivate *priv = client->priv;
2629
2630   GST_INFO ("client %p: session %p removed", client, session);
2631
2632   g_mutex_lock (&priv->lock);
2633   if (priv->watch != NULL)
2634     gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0);
2635   client_unwatch_session (client, session, NULL);
2636   if (priv->watch != NULL)
2637     gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
2638   g_mutex_unlock (&priv->lock);
2639 }
2640
2641 /* Check for Require headers. Returns TRUE if there are no Require headers,
2642  * otherwise lets the application decide which headers are supported.
2643  * By default all headers are unsupported.
2644  * If there are unsupported options, FALSE will be returned together with
2645  * a newly-allocated string of (comma-separated) unsupported options in
2646  * the unsupported_reqs variable.
2647  *
2648  * There may be multiple Require headers, but we must send one single
2649  * Unsupported header with all the unsupported options as response. If
2650  * an incoming Require header contained a comma-separated list of options
2651  * GstRtspConnection will already have split that list up into multiple
2652  * headers.
2653  */
2654 static gboolean
2655 check_request_requirements (GstRTSPContext * ctx, gchar ** unsupported_reqs)
2656 {
2657   GstRTSPResult res;
2658   GPtrArray *arr = NULL;
2659   GstRTSPMessage *msg = ctx->request;
2660   gchar *reqs = NULL;
2661   gint i;
2662   gchar *sig_result = NULL;
2663   gboolean result = TRUE;
2664
2665   i = 0;
2666   do {
2667     res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++);
2668
2669     if (res == GST_RTSP_ENOTIMPL)
2670       break;
2671
2672     if (arr == NULL)
2673       arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
2674
2675     g_ptr_array_add (arr, g_strdup (reqs));
2676   }
2677   while (TRUE);
2678
2679   /* if we don't have any Require headers at all, all is fine */
2680   if (i == 1)
2681     return TRUE;
2682
2683   /* otherwise we've now processed at all the Require headers */
2684   g_ptr_array_add (arr, NULL);
2685
2686   g_signal_emit (ctx->client,
2687       gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS], 0, ctx,
2688       (gchar **) arr->pdata, &sig_result);
2689
2690   if (sig_result == NULL) {
2691     /* no supported options, just report all of the required ones as
2692      * unsupported */
2693     *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata);
2694     result = FALSE;
2695     goto done;
2696   }
2697
2698   if (strlen (sig_result) == 0)
2699     g_free (sig_result);
2700   else {
2701     *unsupported_reqs = sig_result;
2702     result = FALSE;
2703   }
2704
2705 done:
2706   g_ptr_array_unref (arr);
2707   return result;
2708 }
2709
2710 static void
2711 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
2712 {
2713   GstRTSPClientPrivate *priv = client->priv;
2714   GstRTSPMethod method;
2715   const gchar *uristr;
2716   GstRTSPUrl *uri = NULL;
2717   GstRTSPVersion version;
2718   GstRTSPResult res;
2719   GstRTSPSession *session = NULL;
2720   GstRTSPContext sctx = { NULL }, *ctx;
2721   GstRTSPMessage response = { 0 };
2722   gchar *unsupported_reqs = NULL;
2723   gchar *sessid;
2724   GstRTSPClientClass *klass;
2725
2726   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2727
2728   if (!(ctx = gst_rtsp_context_get_current ())) {
2729     ctx = &sctx;
2730     ctx->auth = priv->auth;
2731     gst_rtsp_context_push_current (ctx);
2732   }
2733
2734   ctx->conn = priv->connection;
2735   ctx->client = client;
2736   ctx->request = request;
2737   ctx->response = &response;
2738
2739   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
2740     gst_rtsp_message_dump (request);
2741   }
2742
2743   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
2744
2745   GST_INFO ("client %p: received a request %s %s %s", client,
2746       gst_rtsp_method_as_text (method), uristr,
2747       gst_rtsp_version_as_text (version));
2748
2749   /* we can only handle 1.0 requests */
2750   if (version != GST_RTSP_VERSION_1_0)
2751     goto not_supported;
2752
2753   ctx->method = method;
2754
2755   /* we always try to parse the url first */
2756   if (strcmp (uristr, "*") == 0) {
2757     /* special case where we have * as uri, keep uri = NULL */
2758   } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
2759     /* check if the uristr is an absolute path <=> scheme and host information
2760      * is missing */
2761     gchar *scheme;
2762
2763     scheme = g_uri_parse_scheme (uristr);
2764     if (scheme == NULL && g_str_has_prefix (uristr, "/")) {
2765       gchar *absolute_uristr = NULL;
2766
2767       GST_WARNING_OBJECT (client, "request doesn't contain absolute url");
2768       if (priv->server_ip == NULL) {
2769         GST_WARNING_OBJECT (client, "host information missing");
2770         goto bad_request;
2771       }
2772
2773       absolute_uristr =
2774           g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr);
2775
2776       GST_DEBUG_OBJECT (client, "absolute url: %s", absolute_uristr);
2777       if (gst_rtsp_url_parse (absolute_uristr, &uri) != GST_RTSP_OK) {
2778         g_free (absolute_uristr);
2779         goto bad_request;
2780       }
2781       g_free (absolute_uristr);
2782     } else {
2783       g_free (scheme);
2784       goto bad_request;
2785     }
2786   }
2787
2788   /* get the session if there is any */
2789   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
2790   if (res == GST_RTSP_OK) {
2791     if (priv->session_pool == NULL)
2792       goto no_pool;
2793
2794     /* we had a session in the request, find it again */
2795     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
2796       goto session_not_found;
2797
2798     /* we add the session to the client list of watched sessions. When a session
2799      * disappears because it times out, we will be notified. If all sessions are
2800      * gone, we will close the connection */
2801     client_watch_session (client, session);
2802   }
2803
2804   /* sanitize the uri */
2805   if (uri)
2806     sanitize_uri (uri);
2807   ctx->uri = uri;
2808   ctx->session = session;
2809
2810   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL))
2811     goto not_authorized;
2812
2813   /* handle any 'Require' headers */
2814   if (!check_request_requirements (ctx, &unsupported_reqs))
2815     goto unsupported_requirement;
2816
2817   /* the backlog must be unlimited while processing requests.
2818    * the causes of this are two cases of deadlocks while streaming over TCP:
2819    *
2820    * 1. consider the scenario where the media pipeline's streaming thread
2821    * is blocking in the appsink (taking the appsink's preroll lock) because
2822    * the backlog is full. when a PAUSE request is received by the RTSP
2823    * client thread then the the state of the session media ought to change
2824    * to PAUSED. while most elements in the pipeline can change state this
2825    * can never happen for the appsink since its preroll lock is taken by
2826    * another thread.
2827    *
2828    * 2. consider the scenario where the media pipeline's streaming thread
2829    * is blocking in the appsink new_sample callback (taking the send lock
2830    * in RTSP client) because the backlog is full. when e.g. a GET request
2831    * is received by the RTSP client thread then a response ought to be sent
2832    * but this can never happen since it requires taking the send lock
2833    * already taken by another thread.
2834    *
2835    * the reason that the backlog is never emptied is that the source used
2836    * for dequeing messages from the backlog is never dispatched because it
2837    * is attached to the same mainloop as the source receving RTSP requests and
2838    * therefore run by the RTSP client thread which is alreayd blocking.
2839    *
2840    * without significant changes the easiest way to cope with this is to
2841    * not block indefinitely when the backlog is full, but rather let the
2842    * backlog grow in size. this in effect means that there can not be any
2843    * upper boundary on its size.
2844    */
2845   if (priv->watch != NULL)
2846     gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0);
2847
2848   /* now see what is asked and dispatch to a dedicated handler */
2849   switch (method) {
2850     case GST_RTSP_OPTIONS:
2851       klass->handle_options_request (client, ctx);
2852       break;
2853     case GST_RTSP_DESCRIBE:
2854       handle_describe_request (client, ctx);
2855       break;
2856     case GST_RTSP_SETUP:
2857       handle_setup_request (client, ctx);
2858       break;
2859     case GST_RTSP_PLAY:
2860       klass->handle_play_request (client, ctx);
2861       break;
2862     case GST_RTSP_PAUSE:
2863       handle_pause_request (client, ctx);
2864       break;
2865     case GST_RTSP_TEARDOWN:
2866       handle_teardown_request (client, ctx);
2867       break;
2868     case GST_RTSP_SET_PARAMETER:
2869       klass->handle_set_param_request (client, ctx);
2870       break;
2871     case GST_RTSP_GET_PARAMETER:
2872       klass->handle_get_param_request (client, ctx);
2873       break;
2874     case GST_RTSP_ANNOUNCE:
2875       handle_announce_request (client, ctx);
2876       break;
2877     case GST_RTSP_RECORD:
2878       handle_record_request (client, ctx);
2879       break;
2880     case GST_RTSP_REDIRECT:
2881       if (priv->watch != NULL)
2882         gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
2883       goto not_implemented;
2884     case GST_RTSP_INVALID:
2885     default:
2886       if (priv->watch != NULL)
2887         gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
2888       goto bad_request;
2889   }
2890
2891   if (priv->watch != NULL)
2892     gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
2893
2894 done:
2895   if (ctx == &sctx)
2896     gst_rtsp_context_pop_current (ctx);
2897   if (session)
2898     g_object_unref (session);
2899   if (uri)
2900     gst_rtsp_url_free (uri);
2901   return;
2902
2903   /* ERRORS */
2904 not_supported:
2905   {
2906     GST_ERROR ("client %p: version %d not supported", client, version);
2907     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
2908         ctx);
2909     goto done;
2910   }
2911 bad_request:
2912   {
2913     GST_ERROR ("client %p: bad request", client);
2914     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2915     goto done;
2916   }
2917 no_pool:
2918   {
2919     GST_ERROR ("client %p: no pool configured", client);
2920     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2921     goto done;
2922   }
2923 session_not_found:
2924   {
2925     GST_ERROR ("client %p: session not found", client);
2926     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2927     goto done;
2928   }
2929 not_authorized:
2930   {
2931     GST_ERROR ("client %p: not allowed", client);
2932     /* error reply is already sent */
2933     goto done;
2934   }
2935 unsupported_requirement:
2936   {
2937     GST_ERROR ("client %p: Required option is not supported (%s)", client,
2938         unsupported_reqs);
2939     send_option_not_supported_response (client, ctx, unsupported_reqs);
2940     g_free (unsupported_reqs);
2941     goto done;
2942   }
2943 not_implemented:
2944   {
2945     GST_ERROR ("client %p: method %d not implemented", client, method);
2946     send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
2947     goto done;
2948   }
2949 }
2950
2951
2952 static void
2953 handle_response (GstRTSPClient * client, GstRTSPMessage * response)
2954 {
2955   GstRTSPClientPrivate *priv = client->priv;
2956   GstRTSPResult res;
2957   GstRTSPSession *session = NULL;
2958   GstRTSPContext sctx = { NULL }, *ctx;
2959   gchar *sessid;
2960
2961   if (!(ctx = gst_rtsp_context_get_current ())) {
2962     ctx = &sctx;
2963     ctx->auth = priv->auth;
2964     gst_rtsp_context_push_current (ctx);
2965   }
2966
2967   ctx->conn = priv->connection;
2968   ctx->client = client;
2969   ctx->request = NULL;
2970   ctx->uri = NULL;
2971   ctx->method = GST_RTSP_INVALID;
2972   ctx->response = response;
2973
2974   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
2975     gst_rtsp_message_dump (response);
2976   }
2977
2978   GST_INFO ("client %p: received a response", client);
2979
2980   /* get the session if there is any */
2981   res =
2982       gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &sessid, 0);
2983   if (res == GST_RTSP_OK) {
2984     if (priv->session_pool == NULL)
2985       goto no_pool;
2986
2987     /* we had a session in the request, find it again */
2988     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
2989       goto session_not_found;
2990
2991     /* we add the session to the client list of watched sessions. When a session
2992      * disappears because it times out, we will be notified. If all sessions are
2993      * gone, we will close the connection */
2994     client_watch_session (client, session);
2995   }
2996
2997   ctx->session = session;
2998
2999   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE],
3000       0, ctx);
3001
3002 done:
3003   if (ctx == &sctx)
3004     gst_rtsp_context_pop_current (ctx);
3005   if (session)
3006     g_object_unref (session);
3007   return;
3008
3009 no_pool:
3010   {
3011     GST_ERROR ("client %p: no pool configured", client);
3012     goto done;
3013   }
3014 session_not_found:
3015   {
3016     GST_ERROR ("client %p: session not found", client);
3017     goto done;
3018   }
3019 }
3020
3021 static void
3022 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
3023 {
3024   GstRTSPClientPrivate *priv = client->priv;
3025   GstRTSPResult res;
3026   guint8 channel;
3027   guint8 *data;
3028   guint size;
3029   GstBuffer *buffer;
3030   GstRTSPStreamTransport *trans;
3031
3032   /* find the stream for this message */
3033   res = gst_rtsp_message_parse_data (message, &channel);
3034   if (res != GST_RTSP_OK)
3035     return;
3036
3037   gst_rtsp_message_get_body (message, &data, &size);
3038   if (size < 2)
3039     goto invalid_length;
3040
3041   gst_rtsp_message_steal_body (message, &data, &size);
3042
3043   /* Strip trailing \0 (which GstRTSPConnection adds) */
3044   --size;
3045
3046   buffer = gst_buffer_new_wrapped (data, size);
3047
3048   trans =
3049       g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel));
3050   if (trans) {
3051     /* dispatch to the stream based on the channel number */
3052     GST_LOG_OBJECT (client, "%u bytes of data on channel %u", size, channel);
3053     gst_rtsp_stream_transport_recv_data (trans, channel, buffer);
3054   } else {
3055     GST_DEBUG_OBJECT (client, "received %u bytes of data for "
3056         "unknown channel %u", size, channel);
3057     gst_buffer_unref (buffer);
3058   }
3059
3060   return;
3061
3062 /* ERRORS */
3063 invalid_length:
3064   {
3065     GST_DEBUG ("client %p: Short message received, ignoring", client);
3066     return;
3067   }
3068 }
3069
3070 /**
3071  * gst_rtsp_client_set_session_pool:
3072  * @client: a #GstRTSPClient
3073  * @pool: (transfer none): a #GstRTSPSessionPool
3074  *
3075  * Set @pool as the sessionpool for @client which it will use to find
3076  * or allocate sessions. the sessionpool is usually inherited from the server
3077  * that created the client but can be overridden later.
3078  */
3079 void
3080 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
3081     GstRTSPSessionPool * pool)
3082 {
3083   GstRTSPSessionPool *old;
3084   GstRTSPClientPrivate *priv;
3085
3086   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3087
3088   priv = client->priv;
3089
3090   if (pool)
3091     g_object_ref (pool);
3092
3093   g_mutex_lock (&priv->lock);
3094   old = priv->session_pool;
3095   priv->session_pool = pool;
3096
3097   if (priv->session_removed_id) {
3098     g_signal_handler_disconnect (old, priv->session_removed_id);
3099     priv->session_removed_id = 0;
3100   }
3101   g_mutex_unlock (&priv->lock);
3102
3103   /* FIXME, should remove all sessions from the old pool for this client */
3104   if (old)
3105     g_object_unref (old);
3106 }
3107
3108 /**
3109  * gst_rtsp_client_get_session_pool:
3110  * @client: a #GstRTSPClient
3111  *
3112  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
3113  *
3114  * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage.
3115  */
3116 GstRTSPSessionPool *
3117 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
3118 {
3119   GstRTSPClientPrivate *priv;
3120   GstRTSPSessionPool *result;
3121
3122   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3123
3124   priv = client->priv;
3125
3126   g_mutex_lock (&priv->lock);
3127   if ((result = priv->session_pool))
3128     g_object_ref (result);
3129   g_mutex_unlock (&priv->lock);
3130
3131   return result;
3132 }
3133
3134 /**
3135  * gst_rtsp_client_set_mount_points:
3136  * @client: a #GstRTSPClient
3137  * @mounts: (transfer none): a #GstRTSPMountPoints
3138  *
3139  * Set @mounts as the mount points for @client which it will use to map urls
3140  * to media streams. These mount points are usually inherited from the server that
3141  * created the client but can be overriden later.
3142  */
3143 void
3144 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
3145     GstRTSPMountPoints * mounts)
3146 {
3147   GstRTSPClientPrivate *priv;
3148   GstRTSPMountPoints *old;
3149
3150   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3151
3152   priv = client->priv;
3153
3154   if (mounts)
3155     g_object_ref (mounts);
3156
3157   g_mutex_lock (&priv->lock);
3158   old = priv->mount_points;
3159   priv->mount_points = mounts;
3160   g_mutex_unlock (&priv->lock);
3161
3162   if (old)
3163     g_object_unref (old);
3164 }
3165
3166 /**
3167  * gst_rtsp_client_get_mount_points:
3168  * @client: a #GstRTSPClient
3169  *
3170  * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
3171  *
3172  * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage.
3173  */
3174 GstRTSPMountPoints *
3175 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
3176 {
3177   GstRTSPClientPrivate *priv;
3178   GstRTSPMountPoints *result;
3179
3180   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3181
3182   priv = client->priv;
3183
3184   g_mutex_lock (&priv->lock);
3185   if ((result = priv->mount_points))
3186     g_object_ref (result);
3187   g_mutex_unlock (&priv->lock);
3188
3189   return result;
3190 }
3191
3192 /**
3193  * gst_rtsp_client_set_auth:
3194  * @client: a #GstRTSPClient
3195  * @auth: (transfer none): a #GstRTSPAuth
3196  *
3197  * configure @auth to be used as the authentication manager of @client.
3198  */
3199 void
3200 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
3201 {
3202   GstRTSPClientPrivate *priv;
3203   GstRTSPAuth *old;
3204
3205   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3206
3207   priv = client->priv;
3208
3209   if (auth)
3210     g_object_ref (auth);
3211
3212   g_mutex_lock (&priv->lock);
3213   old = priv->auth;
3214   priv->auth = auth;
3215   g_mutex_unlock (&priv->lock);
3216
3217   if (old)
3218     g_object_unref (old);
3219 }
3220
3221
3222 /**
3223  * gst_rtsp_client_get_auth:
3224  * @client: a #GstRTSPClient
3225  *
3226  * Get the #GstRTSPAuth used as the authentication manager of @client.
3227  *
3228  * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after
3229  * usage.
3230  */
3231 GstRTSPAuth *
3232 gst_rtsp_client_get_auth (GstRTSPClient * client)
3233 {
3234   GstRTSPClientPrivate *priv;
3235   GstRTSPAuth *result;
3236
3237   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3238
3239   priv = client->priv;
3240
3241   g_mutex_lock (&priv->lock);
3242   if ((result = priv->auth))
3243     g_object_ref (result);
3244   g_mutex_unlock (&priv->lock);
3245
3246   return result;
3247 }
3248
3249 /**
3250  * gst_rtsp_client_set_thread_pool:
3251  * @client: a #GstRTSPClient
3252  * @pool: (transfer none): a #GstRTSPThreadPool
3253  *
3254  * configure @pool to be used as the thread pool of @client.
3255  */
3256 void
3257 gst_rtsp_client_set_thread_pool (GstRTSPClient * client,
3258     GstRTSPThreadPool * pool)
3259 {
3260   GstRTSPClientPrivate *priv;
3261   GstRTSPThreadPool *old;
3262
3263   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3264
3265   priv = client->priv;
3266
3267   if (pool)
3268     g_object_ref (pool);
3269
3270   g_mutex_lock (&priv->lock);
3271   old = priv->thread_pool;
3272   priv->thread_pool = pool;
3273   g_mutex_unlock (&priv->lock);
3274
3275   if (old)
3276     g_object_unref (old);
3277 }
3278
3279 /**
3280  * gst_rtsp_client_get_thread_pool:
3281  * @client: a #GstRTSPClient
3282  *
3283  * Get the #GstRTSPThreadPool used as the thread pool of @client.
3284  *
3285  * Returns: (transfer full): the #GstRTSPThreadPool of @client. g_object_unref() after
3286  * usage.
3287  */
3288 GstRTSPThreadPool *
3289 gst_rtsp_client_get_thread_pool (GstRTSPClient * client)
3290 {
3291   GstRTSPClientPrivate *priv;
3292   GstRTSPThreadPool *result;
3293
3294   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3295
3296   priv = client->priv;
3297
3298   g_mutex_lock (&priv->lock);
3299   if ((result = priv->thread_pool))
3300     g_object_ref (result);
3301   g_mutex_unlock (&priv->lock);
3302
3303   return result;
3304 }
3305
3306 /**
3307  * gst_rtsp_client_set_connection:
3308  * @client: a #GstRTSPClient
3309  * @conn: (transfer full): a #GstRTSPConnection
3310  *
3311  * Set the #GstRTSPConnection of @client. This function takes ownership of
3312  * @conn.
3313  *
3314  * Returns: %TRUE on success.
3315  */
3316 gboolean
3317 gst_rtsp_client_set_connection (GstRTSPClient * client,
3318     GstRTSPConnection * conn)
3319 {
3320   GstRTSPClientPrivate *priv;
3321   GSocket *read_socket;
3322   GSocketAddress *address;
3323   GstRTSPUrl *url;
3324   GError *error = NULL;
3325
3326   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
3327   g_return_val_if_fail (conn != NULL, FALSE);
3328
3329   priv = client->priv;
3330
3331   read_socket = gst_rtsp_connection_get_read_socket (conn);
3332
3333   if (!(address = g_socket_get_local_address (read_socket, &error)))
3334     goto no_address;
3335
3336   g_free (priv->server_ip);
3337   /* keep the original ip that the client connected to */
3338   if (G_IS_INET_SOCKET_ADDRESS (address)) {
3339     GInetAddress *iaddr;
3340
3341     iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
3342
3343     /* socket might be ipv6 but adress still ipv4 */
3344     priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6;
3345     priv->server_ip = g_inet_address_to_string (iaddr);
3346     g_object_unref (address);
3347   } else {
3348     priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
3349     priv->server_ip = g_strdup ("unknown");
3350   }
3351
3352   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
3353       priv->server_ip, priv->is_ipv6);
3354
3355   url = gst_rtsp_connection_get_url (conn);
3356   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
3357
3358   priv->connection = conn;
3359
3360   return TRUE;
3361
3362   /* ERRORS */
3363 no_address:
3364   {
3365     GST_ERROR ("could not get local address %s", error->message);
3366     g_error_free (error);
3367     return FALSE;
3368   }
3369 }
3370
3371 /**
3372  * gst_rtsp_client_get_connection:
3373  * @client: a #GstRTSPClient
3374  *
3375  * Get the #GstRTSPConnection of @client.
3376  *
3377  * Returns: (transfer none): the #GstRTSPConnection of @client.
3378  * The connection object returned remains valid until the client is freed.
3379  */
3380 GstRTSPConnection *
3381 gst_rtsp_client_get_connection (GstRTSPClient * client)
3382 {
3383   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3384
3385   return client->priv->connection;
3386 }
3387
3388 /**
3389  * gst_rtsp_client_set_send_func:
3390  * @client: a #GstRTSPClient
3391  * @func: (scope notified): a #GstRTSPClientSendFunc
3392  * @user_data: (closure): user data passed to @func
3393  * @notify: (allow-none): called when @user_data is no longer in use
3394  *
3395  * Set @func as the callback that will be called when a new message needs to be
3396  * sent to the client. @user_data is passed to @func and @notify is called when
3397  * @user_data is no longer in use.
3398  *
3399  * By default, the client will send the messages on the #GstRTSPConnection that
3400  * was configured with gst_rtsp_client_attach() was called.
3401  */
3402 void
3403 gst_rtsp_client_set_send_func (GstRTSPClient * client,
3404     GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
3405 {
3406   GstRTSPClientPrivate *priv;
3407   GDestroyNotify old_notify;
3408   gpointer old_data;
3409
3410   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3411
3412   priv = client->priv;
3413
3414   g_mutex_lock (&priv->send_lock);
3415   priv->send_func = func;
3416   old_notify = priv->send_notify;
3417   old_data = priv->send_data;
3418   priv->send_notify = notify;
3419   priv->send_data = user_data;
3420   g_mutex_unlock (&priv->send_lock);
3421
3422   if (old_notify)
3423     old_notify (old_data);
3424 }
3425
3426 /**
3427  * gst_rtsp_client_handle_message:
3428  * @client: a #GstRTSPClient
3429  * @message: (transfer none): an #GstRTSPMessage
3430  *
3431  * Let the client handle @message.
3432  *
3433  * Returns: a #GstRTSPResult.
3434  */
3435 GstRTSPResult
3436 gst_rtsp_client_handle_message (GstRTSPClient * client,
3437     GstRTSPMessage * message)
3438 {
3439   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
3440   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
3441
3442   switch (message->type) {
3443     case GST_RTSP_MESSAGE_REQUEST:
3444       handle_request (client, message);
3445       break;
3446     case GST_RTSP_MESSAGE_RESPONSE:
3447       handle_response (client, message);
3448       break;
3449     case GST_RTSP_MESSAGE_DATA:
3450       handle_data (client, message);
3451       break;
3452     default:
3453       break;
3454   }
3455   return GST_RTSP_OK;
3456 }
3457
3458 /**
3459  * gst_rtsp_client_send_message:
3460  * @client: a #GstRTSPClient
3461  * @session: (allow-none) (transfer none): a #GstRTSPSession to send
3462  *   the message to or %NULL
3463  * @message: (transfer none): The #GstRTSPMessage to send
3464  *
3465  * Send a message message to the remote end. @message must be a
3466  * #GST_RTSP_MESSAGE_REQUEST or a #GST_RTSP_MESSAGE_RESPONSE.
3467  */
3468 GstRTSPResult
3469 gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session,
3470     GstRTSPMessage * message)
3471 {
3472   GstRTSPContext sctx = { NULL }
3473   , *ctx;
3474   GstRTSPClientPrivate *priv;
3475
3476   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
3477   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
3478   g_return_val_if_fail (message->type == GST_RTSP_MESSAGE_REQUEST ||
3479       message->type == GST_RTSP_MESSAGE_RESPONSE, GST_RTSP_EINVAL);
3480
3481   priv = client->priv;
3482
3483   if (!(ctx = gst_rtsp_context_get_current ())) {
3484     ctx = &sctx;
3485     ctx->auth = priv->auth;
3486     gst_rtsp_context_push_current (ctx);
3487   }
3488
3489   ctx->conn = priv->connection;
3490   ctx->client = client;
3491   ctx->session = session;
3492
3493   send_message (client, ctx, message, FALSE);
3494
3495   if (ctx == &sctx)
3496     gst_rtsp_context_pop_current (ctx);
3497
3498   return GST_RTSP_OK;
3499 }
3500
3501 static GstRTSPResult
3502 do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
3503     gboolean close, gpointer user_data)
3504 {
3505   GstRTSPClientPrivate *priv = client->priv;
3506   GstRTSPResult ret;
3507   GTimeVal time;
3508
3509   time.tv_sec = 1;
3510   time.tv_usec = 0;
3511
3512   do {
3513     /* send the response and store the seq number so we can wait until it's
3514      * written to the client to close the connection */
3515     ret =
3516         gst_rtsp_watch_send_message (priv->watch, message,
3517         close ? &priv->close_seq : NULL);
3518     if (ret == GST_RTSP_OK)
3519       break;
3520
3521     if (ret != GST_RTSP_ENOMEM)
3522       goto error;
3523
3524     /* drop backlog */
3525     if (priv->drop_backlog)
3526       break;
3527
3528     /* queue was full, wait for more space */
3529     GST_DEBUG_OBJECT (client, "waiting for backlog");
3530     ret = gst_rtsp_watch_wait_backlog (priv->watch, &time);
3531     GST_DEBUG_OBJECT (client, "Resend due to backlog full");
3532   } while (ret != GST_RTSP_EINTR);
3533
3534   return ret;
3535
3536   /* ERRORS */
3537 error:
3538   {
3539     GST_DEBUG_OBJECT (client, "got error %d", ret);
3540     return ret;
3541   }
3542 }
3543
3544 static GstRTSPResult
3545 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
3546     gpointer user_data)
3547 {
3548   return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
3549 }
3550
3551 static GstRTSPResult
3552 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
3553 {
3554   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3555   GstRTSPClientPrivate *priv = client->priv;
3556
3557   if (priv->close_seq && priv->close_seq == cseq) {
3558     GST_INFO ("client %p: send close message", client);
3559     priv->close_seq = 0;
3560     gst_rtsp_client_close (client);
3561   }
3562
3563   return GST_RTSP_OK;
3564 }
3565
3566 static GstRTSPResult
3567 closed (GstRTSPWatch * watch, gpointer user_data)
3568 {
3569   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3570   GstRTSPClientPrivate *priv = client->priv;
3571   const gchar *tunnelid;
3572
3573   GST_INFO ("client %p: connection closed", client);
3574
3575   if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
3576     g_mutex_lock (&tunnels_lock);
3577     /* remove from tunnelids */
3578     g_hash_table_remove (tunnels, tunnelid);
3579     g_mutex_unlock (&tunnels_lock);
3580   }
3581
3582   gst_rtsp_watch_set_flushing (watch, TRUE);
3583   g_mutex_lock (&priv->watch_lock);
3584   gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
3585   g_mutex_unlock (&priv->watch_lock);
3586
3587   return GST_RTSP_OK;
3588 }
3589
3590 static GstRTSPResult
3591 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
3592 {
3593   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3594   gchar *str;
3595
3596   str = gst_rtsp_strresult (result);
3597   GST_INFO ("client %p: received an error %s", client, str);
3598   g_free (str);
3599
3600   return GST_RTSP_OK;
3601 }
3602
3603 static GstRTSPResult
3604 error_full (GstRTSPWatch * watch, GstRTSPResult result,
3605     GstRTSPMessage * message, guint id, gpointer user_data)
3606 {
3607   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3608   gchar *str;
3609
3610   str = gst_rtsp_strresult (result);
3611   GST_INFO
3612       ("client %p: error when handling message %p with id %d: %s",
3613       client, message, id, str);
3614   g_free (str);
3615
3616   return GST_RTSP_OK;
3617 }
3618
3619 static gboolean
3620 remember_tunnel (GstRTSPClient * client)
3621 {
3622   GstRTSPClientPrivate *priv = client->priv;
3623   const gchar *tunnelid;
3624
3625   /* store client in the pending tunnels */
3626   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
3627   if (tunnelid == NULL)
3628     goto no_tunnelid;
3629
3630   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
3631
3632   /* we can't have two clients connecting with the same tunnelid */
3633   g_mutex_lock (&tunnels_lock);
3634   if (g_hash_table_lookup (tunnels, tunnelid))
3635     goto tunnel_existed;
3636
3637   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
3638   g_mutex_unlock (&tunnels_lock);
3639
3640   return TRUE;
3641
3642   /* ERRORS */
3643 no_tunnelid:
3644   {
3645     GST_ERROR ("client %p: no tunnelid provided", client);
3646     return FALSE;
3647   }
3648 tunnel_existed:
3649   {
3650     g_mutex_unlock (&tunnels_lock);
3651     GST_ERROR ("client %p: tunnel session %s already existed", client,
3652         tunnelid);
3653     return FALSE;
3654   }
3655 }
3656
3657 static GstRTSPResult
3658 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
3659 {
3660   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3661   GstRTSPClientPrivate *priv = client->priv;
3662
3663   GST_WARNING ("client %p: tunnel lost (connection %p)", client,
3664       priv->connection);
3665
3666   /* ignore error, it'll only be a problem when the client does a POST again */
3667   remember_tunnel (client);
3668
3669   return GST_RTSP_OK;
3670 }
3671
3672 static gboolean
3673 handle_tunnel (GstRTSPClient * client)
3674 {
3675   GstRTSPClientPrivate *priv = client->priv;
3676   GstRTSPClient *oclient;
3677   GstRTSPClientPrivate *opriv;
3678   const gchar *tunnelid;
3679
3680   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
3681   if (tunnelid == NULL)
3682     goto no_tunnelid;
3683
3684   /* check for previous tunnel */
3685   g_mutex_lock (&tunnels_lock);
3686   oclient = g_hash_table_lookup (tunnels, tunnelid);
3687
3688   if (oclient == NULL) {
3689     /* no previous tunnel, remember tunnel */
3690     g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
3691     g_mutex_unlock (&tunnels_lock);
3692
3693     GST_INFO ("client %p: no previous tunnel found, remembering tunnel (%p)",
3694         client, priv->connection);
3695   } else {
3696     /* merge both tunnels into the first client */
3697     /* remove the old client from the table. ref before because removing it will
3698      * remove the ref to it. */
3699     g_object_ref (oclient);
3700     g_hash_table_remove (tunnels, tunnelid);
3701     g_mutex_unlock (&tunnels_lock);
3702
3703     opriv = oclient->priv;
3704
3705     g_mutex_lock (&opriv->watch_lock);
3706     if (opriv->watch == NULL)
3707       goto tunnel_closed;
3708
3709     GST_INFO ("client %p: found previous tunnel %p (old %p, new %p)", client,
3710         oclient, opriv->connection, priv->connection);
3711
3712     gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
3713     gst_rtsp_watch_reset (priv->watch);
3714     gst_rtsp_watch_reset (opriv->watch);
3715     g_mutex_unlock (&opriv->watch_lock);
3716     g_object_unref (oclient);
3717
3718     /* the old client owns the tunnel now, the new one will be freed */
3719     g_source_destroy ((GSource *) priv->watch);
3720     priv->watch = NULL;
3721     gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
3722   }
3723
3724   return TRUE;
3725
3726   /* ERRORS */
3727 no_tunnelid:
3728   {
3729     GST_ERROR ("client %p: no tunnelid provided", client);
3730     return FALSE;
3731   }
3732 tunnel_closed:
3733   {
3734     GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
3735     g_mutex_unlock (&opriv->watch_lock);
3736     g_object_unref (oclient);
3737     return FALSE;
3738   }
3739 }
3740
3741 static GstRTSPStatusCode
3742 tunnel_get (GstRTSPWatch * watch, gpointer user_data)
3743 {
3744   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3745
3746   GST_INFO ("client %p: tunnel get (connection %p)", client,
3747       client->priv->connection);
3748
3749   if (!handle_tunnel (client)) {
3750     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
3751   }
3752
3753   return GST_RTSP_STS_OK;
3754 }
3755
3756 static GstRTSPResult
3757 tunnel_post (GstRTSPWatch * watch, gpointer user_data)
3758 {
3759   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3760
3761   GST_INFO ("client %p: tunnel post (connection %p)", client,
3762       client->priv->connection);
3763
3764   if (!handle_tunnel (client)) {
3765     return GST_RTSP_ERROR;
3766   }
3767
3768   return GST_RTSP_OK;
3769 }
3770
3771 static GstRTSPResult
3772 tunnel_http_response (GstRTSPWatch * watch, GstRTSPMessage * request,
3773     GstRTSPMessage * response, gpointer user_data)
3774 {
3775   GstRTSPClientClass *klass;
3776
3777   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3778   klass = GST_RTSP_CLIENT_GET_CLASS (client);
3779
3780   if (klass->tunnel_http_response) {
3781     klass->tunnel_http_response (client, request, response);
3782   }
3783
3784   return GST_RTSP_OK;
3785 }
3786
3787 static GstRTSPWatchFuncs watch_funcs = {
3788   message_received,
3789   message_sent,
3790   closed,
3791   error,
3792   tunnel_get,
3793   tunnel_post,
3794   error_full,
3795   tunnel_lost,
3796   tunnel_http_response
3797 };
3798
3799 static void
3800 client_watch_notify (GstRTSPClient * client)
3801 {
3802   GstRTSPClientPrivate *priv = client->priv;
3803
3804   GST_INFO ("client %p: watch destroyed", client);
3805   priv->watch = NULL;
3806   /* remove all sessions and so drop the extra client ref */
3807   gst_rtsp_client_session_filter (client, cleanup_session, NULL);
3808   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
3809   g_object_unref (client);
3810 }
3811
3812 /**
3813  * gst_rtsp_client_attach:
3814  * @client: a #GstRTSPClient
3815  * @context: (allow-none): a #GMainContext
3816  *
3817  * Attaches @client to @context. When the mainloop for @context is run, the
3818  * client will be dispatched. When @context is %NULL, the default context will be
3819  * used).
3820  *
3821  * This function should be called when the client properties and urls are fully
3822  * configured and the client is ready to start.
3823  *
3824  * Returns: the ID (greater than 0) for the source within the GMainContext.
3825  */
3826 guint
3827 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
3828 {
3829   GstRTSPClientPrivate *priv;
3830   guint res;
3831
3832   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
3833   priv = client->priv;
3834   g_return_val_if_fail (priv->connection != NULL, 0);
3835   g_return_val_if_fail (priv->watch == NULL, 0);
3836
3837   /* make sure noone will free the context before the watch is destroyed */
3838   priv->watch_context = g_main_context_ref (context);
3839
3840   /* create watch for the connection and attach */
3841   priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
3842       g_object_ref (client), (GDestroyNotify) client_watch_notify);
3843   gst_rtsp_client_set_send_func (client, do_send_message, priv->watch,
3844       (GDestroyNotify) gst_rtsp_watch_unref);
3845
3846   gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3847
3848   GST_INFO ("client %p: attaching to context %p", client, context);
3849   res = gst_rtsp_watch_attach (priv->watch, context);
3850
3851   return res;
3852 }
3853
3854 /**
3855  * gst_rtsp_client_session_filter:
3856  * @client: a #GstRTSPClient
3857  * @func: (scope call) (allow-none): a callback
3858  * @user_data: user data passed to @func
3859  *
3860  * Call @func for each session managed by @client. The result value of @func
3861  * determines what happens to the session. @func will be called with @client
3862  * locked so no further actions on @client can be performed from @func.
3863  *
3864  * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from
3865  * @client.
3866  *
3867  * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @client.
3868  *
3869  * If @func returns #GST_RTSP_FILTER_REF, the session will remain in @client but
3870  * will also be added with an additional ref to the result #GList of this
3871  * function..
3872  *
3873  * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each session.
3874  *
3875  * Returns: (element-type GstRTSPSession) (transfer full): a #GList with all
3876  * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each
3877  * element in the #GList should be unreffed before the list is freed.
3878  */
3879 GList *
3880 gst_rtsp_client_session_filter (GstRTSPClient * client,
3881     GstRTSPClientSessionFilterFunc func, gpointer user_data)
3882 {
3883   GstRTSPClientPrivate *priv;
3884   GList *result, *walk, *next;
3885   GHashTable *visited;
3886   guint cookie;
3887
3888   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3889
3890   priv = client->priv;
3891
3892   result = NULL;
3893   if (func)
3894     visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
3895
3896   g_mutex_lock (&priv->lock);
3897 restart:
3898   cookie = priv->sessions_cookie;
3899   for (walk = priv->sessions; walk; walk = next) {
3900     GstRTSPSession *sess = walk->data;
3901     GstRTSPFilterResult res;
3902     gboolean changed;
3903
3904     next = g_list_next (walk);
3905
3906     if (func) {
3907       /* only visit each session once */
3908       if (g_hash_table_contains (visited, sess))
3909         continue;
3910
3911       g_hash_table_add (visited, g_object_ref (sess));
3912       g_mutex_unlock (&priv->lock);
3913
3914       res = func (client, sess, user_data);
3915
3916       g_mutex_lock (&priv->lock);
3917     } else
3918       res = GST_RTSP_FILTER_REF;
3919
3920     changed = (cookie != priv->sessions_cookie);
3921
3922     switch (res) {
3923       case GST_RTSP_FILTER_REMOVE:
3924         /* stop watching the session and pretend it went away, if the list was
3925          * changed, we can't use the current list position, try to see if we
3926          * still have the session */
3927         client_unwatch_session (client, sess, changed ? NULL : walk);
3928         cookie = priv->sessions_cookie;
3929         break;
3930       case GST_RTSP_FILTER_REF:
3931         result = g_list_prepend (result, g_object_ref (sess));
3932         break;
3933       case GST_RTSP_FILTER_KEEP:
3934       default:
3935         break;
3936     }
3937     if (changed)
3938       goto restart;
3939   }
3940   g_mutex_unlock (&priv->lock);
3941
3942   if (func)
3943     g_hash_table_unref (visited);
3944
3945   return result;
3946 }
3947
3948 /**
3949  * gst_rtsp_client_set_watch_flushing:
3950  * @client: a #GstRTSPClient
3951  * @val: a boolean value
3952  *
3953  * sets watch flushing to @val on watch to accet/ignore new messages.
3954  */
3955 void
3956 gst_rtsp_client_set_watch_flushing (GstRTSPClient * client, gboolean val)
3957 {
3958   GstRTSPClientPrivate *priv = NULL;
3959   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3960
3961   priv = GST_RTSP_CLIENT_GET_PRIVATE (client);
3962
3963   /* make sure we unblock/block the backlog and accept/don't accept new messages on the watch */
3964   if (priv->watch != NULL)
3965   {
3966      GST_INFO("Set watch flushing as %d", val);
3967      gst_rtsp_watch_set_flushing (priv->watch, val);
3968   }
3969 }