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