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