client: Destroy the rtsp watch after connection close
[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_generic,
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   /* connection is now closed, destroy the watch which will also cause the
800    * closed signal to be emitted */
801   if (priv->watch) {
802     GST_DEBUG ("client %p: destroying watch", client);
803     g_source_destroy ((GSource *) priv->watch);
804     priv->watch = NULL;
805     gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
806   }
807 }
808
809 static gchar *
810 default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
811 {
812   gchar *path;
813
814   if (uri->query)
815     path = g_strconcat (uri->abspath, "?", uri->query, NULL);
816   else
817     path = g_strdup (uri->abspath);
818
819   return path;
820 }
821
822 static gboolean
823 handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
824 {
825   GstRTSPClientPrivate *priv = client->priv;
826   GstRTSPClientClass *klass;
827   GstRTSPSession *session;
828   GstRTSPSessionMedia *sessmedia;
829   GstRTSPStatusCode code;
830   gchar *path;
831   gint matched;
832
833   if (!ctx->session)
834     goto no_session;
835
836   session = ctx->session;
837
838   if (!ctx->uri)
839     goto no_uri;
840
841   klass = GST_RTSP_CLIENT_GET_CLASS (client);
842   path = klass->make_path_from_uri (client, ctx->uri);
843
844   /* get a handle to the configuration of the media in the session */
845   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
846   if (!sessmedia)
847     goto not_found;
848
849   /* only aggregate control for now.. */
850   if (path[matched] != '\0')
851     goto no_aggregate;
852
853   g_free (path);
854
855   ctx->sessmedia = sessmedia;
856
857   /* we emit the signal before closing the connection */
858   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
859       0, ctx);
860
861   /* make sure we unblock the backlog and don't accept new messages
862    * on the watch */
863   gst_rtsp_watch_set_flushing (priv->watch, TRUE);
864
865   /* unlink the all TCP callbacks */
866   unlink_session_transports (client, session, sessmedia);
867
868   /* remove the session from the watched sessions */
869   client_unwatch_session (client, session);
870
871   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
872
873   /* allow messages again so that we can send the reply */
874   gst_rtsp_watch_set_flushing (priv->watch, FALSE);
875
876   /* unmanage the media in the session, returns false if all media session
877    * are torn down. */
878   if (!gst_rtsp_session_release_media (session, sessmedia)) {
879     /* remove the session */
880     gst_rtsp_session_pool_remove (priv->session_pool, session);
881   }
882   /* construct the response now */
883   code = GST_RTSP_STS_OK;
884   gst_rtsp_message_init_response (ctx->response, code,
885       gst_rtsp_status_as_text (code), ctx->request);
886
887   send_message (client, ctx, ctx->response, TRUE);
888
889   return TRUE;
890
891   /* ERRORS */
892 no_session:
893   {
894     GST_ERROR ("client %p: no session", client);
895     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
896     return FALSE;
897   }
898 no_uri:
899   {
900     GST_ERROR ("client %p: no uri supplied", client);
901     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
902     return FALSE;
903   }
904 not_found:
905   {
906     GST_ERROR ("client %p: no media for uri", client);
907     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
908     g_free (path);
909     return FALSE;
910   }
911 no_aggregate:
912   {
913     GST_ERROR ("client %p: no aggregate path %s", client, path);
914     send_generic_response (client,
915         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
916     g_free (path);
917     return FALSE;
918   }
919 }
920
921 static GstRTSPResult
922 default_params_set (GstRTSPClient * client, GstRTSPContext * ctx)
923 {
924   GstRTSPResult res;
925
926   res = gst_rtsp_params_set (client, ctx);
927
928   return res;
929 }
930
931 static GstRTSPResult
932 default_params_get (GstRTSPClient * client, GstRTSPContext * ctx)
933 {
934   GstRTSPResult res;
935
936   res = gst_rtsp_params_get (client, ctx);
937
938   return res;
939 }
940
941 static gboolean
942 handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
943 {
944   GstRTSPResult res;
945   guint8 *data;
946   guint size;
947
948   res = gst_rtsp_message_get_body (ctx->request, &data, &size);
949   if (res != GST_RTSP_OK)
950     goto bad_request;
951
952   if (size == 0) {
953     /* no body, keep-alive request */
954     send_generic_response (client, GST_RTSP_STS_OK, ctx);
955   } else {
956     /* there is a body, handle the params */
957     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, ctx);
958     if (res != GST_RTSP_OK)
959       goto bad_request;
960
961     send_message (client, ctx, ctx->response, FALSE);
962   }
963
964   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
965       0, ctx);
966
967   return TRUE;
968
969   /* ERRORS */
970 bad_request:
971   {
972     GST_ERROR ("client %p: bad request", client);
973     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
974     return FALSE;
975   }
976 }
977
978 static gboolean
979 handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
980 {
981   GstRTSPResult res;
982   guint8 *data;
983   guint size;
984
985   res = gst_rtsp_message_get_body (ctx->request, &data, &size);
986   if (res != GST_RTSP_OK)
987     goto bad_request;
988
989   if (size == 0) {
990     /* no body, keep-alive request */
991     send_generic_response (client, GST_RTSP_STS_OK, ctx);
992   } else {
993     /* there is a body, handle the params */
994     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, ctx);
995     if (res != GST_RTSP_OK)
996       goto bad_request;
997
998     send_message (client, ctx, ctx->response, FALSE);
999   }
1000
1001   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
1002       0, ctx);
1003
1004   return TRUE;
1005
1006   /* ERRORS */
1007 bad_request:
1008   {
1009     GST_ERROR ("client %p: bad request", client);
1010     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1011     return FALSE;
1012   }
1013 }
1014
1015 static gboolean
1016 handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
1017 {
1018   GstRTSPSession *session;
1019   GstRTSPClientClass *klass;
1020   GstRTSPSessionMedia *sessmedia;
1021   GstRTSPStatusCode code;
1022   GstRTSPState rtspstate;
1023   gchar *path;
1024   gint matched;
1025
1026   if (!(session = ctx->session))
1027     goto no_session;
1028
1029   if (!ctx->uri)
1030     goto no_uri;
1031
1032   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1033   path = klass->make_path_from_uri (client, ctx->uri);
1034
1035   /* get a handle to the configuration of the media in the session */
1036   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1037   if (!sessmedia)
1038     goto not_found;
1039
1040   if (path[matched] != '\0')
1041     goto no_aggregate;
1042
1043   g_free (path);
1044
1045   ctx->sessmedia = sessmedia;
1046
1047   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1048   /* the session state must be playing or recording */
1049   if (rtspstate != GST_RTSP_STATE_PLAYING &&
1050       rtspstate != GST_RTSP_STATE_RECORDING)
1051     goto invalid_state;
1052
1053   /* unlink the all TCP callbacks */
1054   unlink_session_transports (client, session, sessmedia);
1055
1056   /* then pause sending */
1057   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED);
1058
1059   /* construct the response now */
1060   code = GST_RTSP_STS_OK;
1061   gst_rtsp_message_init_response (ctx->response, code,
1062       gst_rtsp_status_as_text (code), ctx->request);
1063
1064   send_message (client, ctx, ctx->response, FALSE);
1065
1066   /* the state is now READY */
1067   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1068
1069   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx);
1070
1071   return TRUE;
1072
1073   /* ERRORS */
1074 no_session:
1075   {
1076     GST_ERROR ("client %p: no seesion", client);
1077     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1078     return FALSE;
1079   }
1080 no_uri:
1081   {
1082     GST_ERROR ("client %p: no uri supplied", client);
1083     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1084     return FALSE;
1085   }
1086 not_found:
1087   {
1088     GST_ERROR ("client %p: no media for uri", client);
1089     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1090     g_free (path);
1091     return FALSE;
1092   }
1093 no_aggregate:
1094   {
1095     GST_ERROR ("client %p: no aggregate path %s", client, path);
1096     send_generic_response (client,
1097         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1098     g_free (path);
1099     return FALSE;
1100   }
1101 invalid_state:
1102   {
1103     GST_ERROR ("client %p: not PLAYING or RECORDING", client);
1104     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1105         ctx);
1106     return FALSE;
1107   }
1108 }
1109
1110 /* convert @url and @path to a URL used as a content base for the factory
1111  * located at @path */
1112 static gchar *
1113 make_base_url (GstRTSPClient * client, GstRTSPUrl * url, const gchar * path)
1114 {
1115   GstRTSPUrl tmp;
1116   gchar *result;
1117   const gchar *trail;
1118
1119   /* check for trailing '/' and append one */
1120   trail = (path[strlen (path) - 1] != '/' ? "/" : "");
1121
1122   tmp = *url;
1123   tmp.user = NULL;
1124   tmp.passwd = NULL;
1125   tmp.abspath = g_strdup_printf ("%s%s", path, trail);
1126   tmp.query = NULL;
1127   result = gst_rtsp_url_get_request_uri (&tmp);
1128   g_free (tmp.abspath);
1129
1130   return result;
1131 }
1132
1133 static gboolean
1134 handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
1135 {
1136   GstRTSPSession *session;
1137   GstRTSPClientClass *klass;
1138   GstRTSPSessionMedia *sessmedia;
1139   GstRTSPMedia *media;
1140   GstRTSPStatusCode code;
1141   GstRTSPUrl *uri;
1142   gchar *str;
1143   GstRTSPTimeRange *range;
1144   GstRTSPResult res;
1145   GstRTSPState rtspstate;
1146   GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
1147   gchar *path, *rtpinfo;
1148   gint matched;
1149
1150   if (!(session = ctx->session))
1151     goto no_session;
1152
1153   if (!(uri = ctx->uri))
1154     goto no_uri;
1155
1156   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1157   path = klass->make_path_from_uri (client, uri);
1158
1159   /* get a handle to the configuration of the media in the session */
1160   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1161   if (!sessmedia)
1162     goto not_found;
1163
1164   if (path[matched] != '\0')
1165     goto no_aggregate;
1166
1167   g_free (path);
1168
1169   ctx->sessmedia = sessmedia;
1170   ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
1171
1172   /* the session state must be playing or ready */
1173   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1174   if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
1175     goto invalid_state;
1176
1177   /* in play we first unsuspend, media could be suspended from SDP or PAUSED */
1178   if (!gst_rtsp_media_unsuspend (media))
1179     goto unsuspend_failed;
1180
1181   /* parse the range header if we have one */
1182   res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0);
1183   if (res == GST_RTSP_OK) {
1184     if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
1185       /* we have a range, seek to the position */
1186       unit = range->unit;
1187       gst_rtsp_media_seek (media, range);
1188       gst_rtsp_range_free (range);
1189     }
1190   }
1191
1192   /* link the all TCP callbacks */
1193   link_session_transports (client, session, sessmedia);
1194
1195   /* grab RTPInfo from the media now */
1196   rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia);
1197
1198   /* construct the response now */
1199   code = GST_RTSP_STS_OK;
1200   gst_rtsp_message_init_response (ctx->response, code,
1201       gst_rtsp_status_as_text (code), ctx->request);
1202
1203   /* add the RTP-Info header */
1204   if (rtpinfo)
1205     gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO,
1206         rtpinfo);
1207
1208   /* add the range */
1209   str = gst_rtsp_media_get_range_string (media, TRUE, unit);
1210   if (str)
1211     gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str);
1212
1213   send_message (client, ctx, ctx->response, FALSE);
1214
1215   /* start playing after sending the response */
1216   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
1217
1218   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
1219
1220   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx);
1221
1222   return TRUE;
1223
1224   /* ERRORS */
1225 no_session:
1226   {
1227     GST_ERROR ("client %p: no session", client);
1228     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1229     return FALSE;
1230   }
1231 no_uri:
1232   {
1233     GST_ERROR ("client %p: no uri supplied", client);
1234     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1235     return FALSE;
1236   }
1237 not_found:
1238   {
1239     GST_ERROR ("client %p: media not found", client);
1240     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1241     return FALSE;
1242   }
1243 no_aggregate:
1244   {
1245     GST_ERROR ("client %p: no aggregate path %s", client, path);
1246     send_generic_response (client,
1247         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1248     g_free (path);
1249     return FALSE;
1250   }
1251 invalid_state:
1252   {
1253     GST_ERROR ("client %p: not PLAYING or READY", client);
1254     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1255         ctx);
1256     return FALSE;
1257   }
1258 unsuspend_failed:
1259   {
1260     GST_ERROR ("client %p: unsuspend failed", client);
1261     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1262     return FALSE;
1263   }
1264 }
1265
1266 static void
1267 do_keepalive (GstRTSPSession * session)
1268 {
1269   GST_INFO ("keep session %p alive", session);
1270   gst_rtsp_session_touch (session);
1271 }
1272
1273 /* parse @transport and return a valid transport in @tr. only transports
1274  * supported by @stream are returned. Returns FALSE if no valid transport
1275  * was found. */
1276 static gboolean
1277 parse_transport (const char *transport, GstRTSPStream * stream,
1278     GstRTSPTransport * tr)
1279 {
1280   gint i;
1281   gboolean res;
1282   gchar **transports;
1283
1284   res = FALSE;
1285   gst_rtsp_transport_init (tr);
1286
1287   GST_DEBUG ("parsing transports %s", transport);
1288
1289   transports = g_strsplit (transport, ",", 0);
1290
1291   /* loop through the transports, try to parse */
1292   for (i = 0; transports[i]; i++) {
1293     res = gst_rtsp_transport_parse (transports[i], tr);
1294     if (res != GST_RTSP_OK) {
1295       /* no valid transport, search some more */
1296       GST_WARNING ("could not parse transport %s", transports[i]);
1297       goto next;
1298     }
1299
1300     /* we have a transport, see if it's supported */
1301     if (!gst_rtsp_stream_is_transport_supported (stream, tr)) {
1302       GST_WARNING ("unsupported transport %s", transports[i]);
1303       goto next;
1304     }
1305
1306     /* we have a valid transport */
1307     GST_INFO ("found valid transport %s", transports[i]);
1308     res = TRUE;
1309     break;
1310
1311   next:
1312     gst_rtsp_transport_init (tr);
1313   }
1314   g_strfreev (transports);
1315
1316   return res;
1317 }
1318
1319 static gboolean
1320 default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
1321     GstRTSPStream * stream, GstRTSPContext * ctx)
1322 {
1323   GstRTSPMessage *request = ctx->request;
1324   gchar *blocksize_str;
1325
1326   if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
1327           &blocksize_str, 0) == GST_RTSP_OK) {
1328     guint64 blocksize;
1329     gchar *end;
1330
1331     blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
1332     if (end == blocksize_str)
1333       goto parse_failed;
1334
1335     /* we don't want to change the mtu when this media
1336      * can be shared because it impacts other clients */
1337     if (gst_rtsp_media_is_shared (media))
1338       goto done;
1339
1340     if (blocksize > G_MAXUINT)
1341       blocksize = G_MAXUINT;
1342
1343     gst_rtsp_stream_set_mtu (stream, blocksize);
1344   }
1345 done:
1346   return TRUE;
1347
1348   /* ERRORS */
1349 parse_failed:
1350   {
1351     GST_ERROR_OBJECT (client, "failed to parse blocksize");
1352     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1353     return FALSE;
1354   }
1355 }
1356
1357 static gboolean
1358 default_configure_client_transport (GstRTSPClient * client,
1359     GstRTSPContext * ctx, GstRTSPTransport * ct)
1360 {
1361   GstRTSPClientPrivate *priv = client->priv;
1362
1363   /* we have a valid transport now, set the destination of the client. */
1364   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1365     gboolean use_client_settings;
1366
1367     use_client_settings =
1368         gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS);
1369
1370     if (ct->destination && use_client_settings) {
1371       GstRTSPAddress *addr;
1372
1373       addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination,
1374           ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
1375
1376       if (addr == NULL)
1377         goto no_address;
1378
1379       gst_rtsp_address_free (addr);
1380     } else {
1381       GstRTSPAddress *addr;
1382       GSocketFamily family;
1383
1384       family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4;
1385
1386       addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family);
1387       if (addr == NULL)
1388         goto no_address;
1389
1390       g_free (ct->destination);
1391       ct->destination = g_strdup (addr->address);
1392       ct->port.min = addr->port;
1393       ct->port.max = addr->port + addr->n_ports - 1;
1394       ct->ttl = addr->ttl;
1395
1396       gst_rtsp_address_free (addr);
1397     }
1398   } else {
1399     GstRTSPUrl *url;
1400
1401     url = gst_rtsp_connection_get_url (priv->connection);
1402     g_free (ct->destination);
1403     ct->destination = g_strdup (url->host);
1404
1405     if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1406       GSocket *sock;
1407       GSocketAddress *addr;
1408
1409       sock = gst_rtsp_connection_get_read_socket (priv->connection);
1410       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1411         /* our read port is the sender port of client */
1412         ct->client_port.min =
1413             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1414         g_object_unref (addr);
1415       }
1416       if ((addr = g_socket_get_local_address (sock, NULL))) {
1417         ct->server_port.max =
1418             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1419         g_object_unref (addr);
1420       }
1421       sock = gst_rtsp_connection_get_write_socket (priv->connection);
1422       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1423         /* our write port is the receiver port of client */
1424         ct->client_port.max =
1425             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1426         g_object_unref (addr);
1427       }
1428       if ((addr = g_socket_get_local_address (sock, NULL))) {
1429         ct->server_port.min =
1430             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1431         g_object_unref (addr);
1432       }
1433       /* check if the client selected channels for TCP */
1434       if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1435         gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
1436             &ct->interleaved);
1437       }
1438     }
1439   }
1440   return TRUE;
1441
1442   /* ERRORS */
1443 no_address:
1444   {
1445     GST_ERROR_OBJECT (client, "failed to acquire address for stream");
1446     return FALSE;
1447   }
1448 }
1449
1450 static GstRTSPTransport *
1451 make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx,
1452     GstRTSPTransport * ct)
1453 {
1454   GstRTSPTransport *st;
1455   GInetAddress *addr;
1456   GSocketFamily family;
1457
1458   /* prepare the server transport */
1459   gst_rtsp_transport_new (&st);
1460
1461   st->trans = ct->trans;
1462   st->profile = ct->profile;
1463   st->lower_transport = ct->lower_transport;
1464
1465   addr = g_inet_address_new_from_string (ct->destination);
1466
1467   if (!addr) {
1468     GST_ERROR ("failed to get inet addr from client destination");
1469     family = G_SOCKET_FAMILY_IPV4;
1470   } else {
1471     family = g_inet_address_get_family (addr);
1472     g_object_unref (addr);
1473     addr = NULL;
1474   }
1475
1476   switch (st->lower_transport) {
1477     case GST_RTSP_LOWER_TRANS_UDP:
1478       st->client_port = ct->client_port;
1479       gst_rtsp_stream_get_server_port (ctx->stream, &st->server_port, family);
1480       break;
1481     case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1482       st->port = ct->port;
1483       st->destination = g_strdup (ct->destination);
1484       st->ttl = ct->ttl;
1485       break;
1486     case GST_RTSP_LOWER_TRANS_TCP:
1487       st->interleaved = ct->interleaved;
1488       st->client_port = ct->client_port;
1489       st->server_port = ct->server_port;
1490     default:
1491       break;
1492   }
1493
1494   gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc);
1495
1496   return st;
1497 }
1498
1499 static gboolean
1500 mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy)
1501 {
1502   const gchar *srtp_cipher;
1503   const gchar *srtp_auth;
1504   const GstMIKEYPayload *sp;
1505   guint i;
1506
1507   /* loop over Security policy until we find one containing policy */
1508   for (i = 0;; i++) {
1509     if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL)
1510       break;
1511
1512     if (((GstMIKEYPayloadSP *) sp)->policy == policy)
1513       break;
1514   }
1515
1516   /* the default ciphers */
1517   srtp_cipher = "aes-128-icm";
1518   srtp_auth = "hmac-sha1-80";
1519
1520   /* now override the defaults with what is in the Security Policy */
1521   if (sp != NULL) {
1522     guint len;
1523
1524     /* collect all the params and go over them */
1525     len = gst_mikey_payload_sp_get_n_params (sp);
1526     for (i = 0; i < len; i++) {
1527       const GstMIKEYPayloadSPParam *param =
1528           gst_mikey_payload_sp_get_param (sp, i);
1529
1530       switch (param->type) {
1531         case GST_MIKEY_SP_SRTP_ENC_ALG:
1532           switch (param->val[0]) {
1533             case 0:
1534               srtp_cipher = "null";
1535               break;
1536             case 2:
1537             case 1:
1538               srtp_cipher = "aes-128-icm";
1539               break;
1540             default:
1541               break;
1542           }
1543           break;
1544         case GST_MIKEY_SP_SRTP_AUTH_ALG:
1545           switch (param->val[0]) {
1546             case 0:
1547               srtp_auth = "null";
1548               break;
1549             case 2:
1550             case 1:
1551               srtp_auth = "hmac-sha1-80";
1552               break;
1553             default:
1554               break;
1555           }
1556           break;
1557         case GST_MIKEY_SP_SRTP_SRTP_ENC:
1558           break;
1559         case GST_MIKEY_SP_SRTP_SRTCP_ENC:
1560           break;
1561         default:
1562           break;
1563       }
1564     }
1565   }
1566   /* now configure the SRTP parameters */
1567   gst_caps_set_simple (caps,
1568       "srtp-cipher", G_TYPE_STRING, srtp_cipher,
1569       "srtp-auth", G_TYPE_STRING, srtp_auth,
1570       "srtcp-cipher", G_TYPE_STRING, srtp_cipher,
1571       "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
1572
1573   return TRUE;
1574 }
1575
1576 static gboolean
1577 handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx,
1578     guint8 * data, gsize size)
1579 {
1580   GstMIKEYMessage *msg;
1581   guint i, n_cs;
1582   GstCaps *caps = NULL;
1583   GstMIKEYPayloadKEMAC *kemac;
1584   const GstMIKEYPayloadKeyData *pkd;
1585   GstBuffer *key;
1586
1587   /* the MIKEY message contains a CSB or crypto session bundle. It is a
1588    * set of Crypto Sessions protected with the same master key.
1589    * In the context of SRTP, an RTP and its RTCP stream is part of a
1590    * crypto session */
1591   if ((msg = gst_mikey_message_new_from_data (data, size, NULL, NULL)) == NULL)
1592     goto parse_failed;
1593
1594   /* we can only handle SRTP crypto sessions for now */
1595   if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP)
1596     goto invalid_map_type;
1597
1598   /* get the number of crypto sessions. This maps SSRC to its
1599    * security parameters */
1600   n_cs = gst_mikey_message_get_n_cs (msg);
1601   if (n_cs == 0)
1602     goto no_crypto_sessions;
1603
1604   /* we also need keys */
1605   if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload
1606           (msg, GST_MIKEY_PT_KEMAC, 0)))
1607     goto no_keys;
1608
1609   /* we don't support encrypted keys */
1610   if (kemac->enc_alg != GST_MIKEY_ENC_NULL
1611       || kemac->mac_alg != GST_MIKEY_MAC_NULL)
1612     goto unsupported_encryption;
1613
1614   /* get Key data sub-payload */
1615   pkd = (const GstMIKEYPayloadKeyData *)
1616       gst_mikey_payload_kemac_get_sub (&kemac->pt, 0);
1617
1618   key =
1619       gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
1620       pkd->key_len);
1621
1622   /* go over all crypto sessions and create the security policy for each
1623    * SSRC */
1624   for (i = 0; i < n_cs; i++) {
1625     const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i);
1626
1627     caps = gst_caps_new_simple ("application/x-srtp",
1628         "ssrc", G_TYPE_UINT, map->ssrc,
1629         "roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL);
1630     mikey_apply_policy (caps, msg, map->policy);
1631
1632     gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps);
1633     gst_caps_unref (caps);
1634   }
1635   gst_mikey_message_free (msg);
1636
1637   return TRUE;
1638
1639   /* ERRORS */
1640 parse_failed:
1641   {
1642     GST_DEBUG_OBJECT (client, "failed to parse MIKEY message");
1643     return FALSE;
1644   }
1645 invalid_map_type:
1646   {
1647     GST_DEBUG_OBJECT (client, "invalid map type %d", msg->map_type);
1648     goto cleanup_message;
1649   }
1650 no_crypto_sessions:
1651   {
1652     GST_DEBUG_OBJECT (client, "no crypto sessions");
1653     goto cleanup_message;
1654   }
1655 no_keys:
1656   {
1657     GST_DEBUG_OBJECT (client, "no keys found");
1658     goto cleanup_message;
1659   }
1660 unsupported_encryption:
1661   {
1662     GST_DEBUG_OBJECT (client, "unsupported key encryption");
1663     goto cleanup_message;
1664   }
1665 cleanup_message:
1666   {
1667     gst_mikey_message_free (msg);
1668     return FALSE;
1669   }
1670 }
1671
1672 #define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"'))
1673
1674 static void
1675 strip_chars (gchar * str)
1676 {
1677   gchar *s;
1678   gsize len;
1679
1680   len = strlen (str);
1681   while (len--) {
1682     if (!IS_STRIP_CHAR (str[len]))
1683       break;
1684     str[len] = '\0';
1685   }
1686   for (s = str; *s && IS_STRIP_CHAR (*s); s++);
1687   memmove (str, s, len + 1);
1688 }
1689
1690 /**
1691  * KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec)
1692  * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"]
1693  */
1694 static gboolean
1695 handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt)
1696 {
1697   gchar **specs;
1698   gint i, j;
1699
1700   specs = g_strsplit (keymgmt, ",", 0);
1701   for (i = 0; specs[i]; i++) {
1702     gchar **split;
1703
1704     split = g_strsplit (specs[i], ";", 0);
1705     for (j = 0; split[j]; j++) {
1706       g_strstrip (split[j]);
1707       if (g_str_has_prefix (split[j], "prot=")) {
1708         g_strstrip (split[j] + 5);
1709         if (!g_str_equal (split[j] + 5, "mikey"))
1710           break;
1711         GST_DEBUG ("found mikey");
1712       } else if (g_str_has_prefix (split[j], "uri=")) {
1713         strip_chars (split[j] + 4);
1714         GST_DEBUG ("found uri '%s'", split[j] + 4);
1715       } else if (g_str_has_prefix (split[j], "data=")) {
1716         guchar *data;
1717         gsize size;
1718         strip_chars (split[j] + 5);
1719         GST_DEBUG ("found data '%s'", split[j] + 5);
1720         data = g_base64_decode_inplace (split[j] + 5, &size);
1721         handle_mikey_data (client, ctx, data, size);
1722       }
1723     }
1724   }
1725   return TRUE;
1726 }
1727
1728 static gboolean
1729 handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
1730 {
1731   GstRTSPClientPrivate *priv = client->priv;
1732   GstRTSPResult res;
1733   GstRTSPUrl *uri;
1734   gchar *transport, *keymgmt;
1735   GstRTSPTransport *ct, *st;
1736   GstRTSPStatusCode code;
1737   GstRTSPSession *session;
1738   GstRTSPStreamTransport *trans;
1739   gchar *trans_str;
1740   GstRTSPSessionMedia *sessmedia;
1741   GstRTSPMedia *media;
1742   GstRTSPStream *stream;
1743   GstRTSPState rtspstate;
1744   GstRTSPClientClass *klass;
1745   gchar *path, *control;
1746   gint matched;
1747
1748   if (!ctx->uri)
1749     goto no_uri;
1750
1751   uri = ctx->uri;
1752   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1753   path = klass->make_path_from_uri (client, uri);
1754
1755   /* parse the transport */
1756   res =
1757       gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_TRANSPORT,
1758       &transport, 0);
1759   if (res != GST_RTSP_OK)
1760     goto no_transport;
1761
1762   /* we create the session after parsing stuff so that we don't make
1763    * a session for malformed requests */
1764   if (priv->session_pool == NULL)
1765     goto no_pool;
1766
1767   session = ctx->session;
1768
1769   if (session) {
1770     g_object_ref (session);
1771     /* get a handle to the configuration of the media in the session, this can
1772      * return NULL if this is a new url to manage in this session. */
1773     sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1774   } else {
1775     /* we need a new media configuration in this session */
1776     sessmedia = NULL;
1777   }
1778
1779   /* we have no session media, find one and manage it */
1780   if (sessmedia == NULL) {
1781     /* get a handle to the configuration of the media in the session */
1782     media = find_media (client, ctx, path, &matched);
1783   } else {
1784     if ((media = gst_rtsp_session_media_get_media (sessmedia)))
1785       g_object_ref (media);
1786     else
1787       goto media_not_found;
1788   }
1789   /* no media, not found then */
1790   if (media == NULL)
1791     goto media_not_found_no_reply;
1792
1793   if (path[matched] == '\0')
1794     goto control_not_found;
1795
1796   /* path is what matched. */
1797   path[matched] = '\0';
1798   /* control is remainder */
1799   control = &path[matched + 1];
1800
1801   /* find the stream now using the control part */
1802   stream = gst_rtsp_media_find_stream (media, control);
1803   if (stream == NULL)
1804     goto stream_not_found;
1805
1806   /* now we have a uri identifying a valid media and stream */
1807   ctx->stream = stream;
1808   ctx->media = media;
1809
1810   if (session == NULL) {
1811     /* create a session if this fails we probably reached our session limit or
1812      * something. */
1813     if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
1814       goto service_unavailable;
1815
1816     /* make sure this client is closed when the session is closed */
1817     client_watch_session (client, session);
1818
1819     /* signal new session */
1820     g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
1821         session);
1822
1823     ctx->session = session;
1824   }
1825
1826   if (sessmedia == NULL) {
1827     /* manage the media in our session now, if not done already  */
1828     sessmedia = gst_rtsp_session_manage_media (session, path, media);
1829     /* if we stil have no media, error */
1830     if (sessmedia == NULL)
1831       goto sessmedia_unavailable;
1832   } else {
1833     g_object_unref (media);
1834   }
1835
1836   ctx->sessmedia = sessmedia;
1837
1838   if (!klass->configure_client_media (client, media, stream, ctx))
1839     goto configure_media_failed_no_reply;
1840
1841   gst_rtsp_transport_new (&ct);
1842
1843   /* parse and find a usable supported transport */
1844   if (!parse_transport (transport, stream, ct))
1845     goto unsupported_transports;
1846
1847   /* update the client transport */
1848   if (!klass->configure_client_transport (client, ctx, ct))
1849     goto unsupported_client_transport;
1850
1851   /* parse the keymgmt */
1852   if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT,
1853           &keymgmt, 0) == GST_RTSP_OK) {
1854     if (!handle_keymgmt (client, ctx, keymgmt))
1855       goto keymgmt_error;
1856   }
1857
1858   /* set in the session media transport */
1859   trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
1860
1861   /* configure the url used to set this transport, this we will use when
1862    * generating the response for the PLAY request */
1863   gst_rtsp_stream_transport_set_url (trans, uri);
1864
1865   /* configure keepalive for this transport */
1866   gst_rtsp_stream_transport_set_keepalive (trans,
1867       (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
1868
1869   /* create and serialize the server transport */
1870   st = make_server_transport (client, ctx, ct);
1871   trans_str = gst_rtsp_transport_as_text (st);
1872   gst_rtsp_transport_free (st);
1873
1874   /* construct the response now */
1875   code = GST_RTSP_STS_OK;
1876   gst_rtsp_message_init_response (ctx->response, code,
1877       gst_rtsp_status_as_text (code), ctx->request);
1878
1879   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_TRANSPORT,
1880       trans_str);
1881   g_free (trans_str);
1882
1883   send_message (client, ctx, ctx->response, FALSE);
1884
1885   /* update the state */
1886   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1887   switch (rtspstate) {
1888     case GST_RTSP_STATE_PLAYING:
1889     case GST_RTSP_STATE_RECORDING:
1890     case GST_RTSP_STATE_READY:
1891       /* no state change */
1892       break;
1893     default:
1894       gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1895       break;
1896   }
1897   g_object_unref (session);
1898   g_free (path);
1899
1900   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx);
1901
1902   return TRUE;
1903
1904   /* ERRORS */
1905 no_uri:
1906   {
1907     GST_ERROR ("client %p: no uri", client);
1908     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1909     return FALSE;
1910   }
1911 no_transport:
1912   {
1913     GST_ERROR ("client %p: no transport", client);
1914     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
1915     goto cleanup_path;
1916   }
1917 no_pool:
1918   {
1919     GST_ERROR ("client %p: no session pool configured", client);
1920     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1921     goto cleanup_path;
1922   }
1923 media_not_found_no_reply:
1924   {
1925     GST_ERROR ("client %p: media '%s' not found", client, path);
1926     /* error reply is already sent */
1927     goto cleanup_path;
1928   }
1929 media_not_found:
1930   {
1931     GST_ERROR ("client %p: media '%s' not found", client, path);
1932     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1933     goto cleanup_path;
1934   }
1935 control_not_found:
1936   {
1937     GST_ERROR ("client %p: no control in path '%s'", client, path);
1938     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1939     g_object_unref (media);
1940     goto cleanup_path;
1941   }
1942 stream_not_found:
1943   {
1944     GST_ERROR ("client %p: stream '%s' not found", client, control);
1945     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1946     g_object_unref (media);
1947     goto cleanup_path;
1948   }
1949 service_unavailable:
1950   {
1951     GST_ERROR ("client %p: can't create session", client);
1952     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1953     g_object_unref (media);
1954     goto cleanup_path;
1955   }
1956 sessmedia_unavailable:
1957   {
1958     GST_ERROR ("client %p: can't create session media", client);
1959     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1960     g_object_unref (media);
1961     goto cleanup_session;
1962   }
1963 configure_media_failed_no_reply:
1964   {
1965     GST_ERROR ("client %p: configure_media failed", client);
1966     /* error reply is already sent */
1967     goto cleanup_session;
1968   }
1969 unsupported_transports:
1970   {
1971     GST_ERROR ("client %p: unsupported transports", client);
1972     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
1973     goto cleanup_transport;
1974   }
1975 unsupported_client_transport:
1976   {
1977     GST_ERROR ("client %p: unsupported client transport", client);
1978     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
1979     goto cleanup_transport;
1980   }
1981 keymgmt_error:
1982   {
1983     GST_ERROR ("client %p: keymgmt error", client);
1984     send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx);
1985     goto cleanup_transport;
1986   }
1987   {
1988   cleanup_transport:
1989     gst_rtsp_transport_free (ct);
1990   cleanup_session:
1991     g_object_unref (session);
1992   cleanup_path:
1993     g_free (path);
1994     return FALSE;
1995   }
1996 }
1997
1998 static GstSDPMessage *
1999 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
2000 {
2001   GstRTSPClientPrivate *priv = client->priv;
2002   GstSDPMessage *sdp;
2003   GstSDPInfo info;
2004   const gchar *proto;
2005
2006   gst_sdp_message_new (&sdp);
2007
2008   /* some standard things first */
2009   gst_sdp_message_set_version (sdp, "0");
2010
2011   if (priv->is_ipv6)
2012     proto = "IP6";
2013   else
2014     proto = "IP4";
2015
2016   gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
2017       priv->server_ip);
2018
2019   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
2020   gst_sdp_message_set_information (sdp, "rtsp-server");
2021   gst_sdp_message_add_time (sdp, "0", "0", NULL);
2022   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
2023   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
2024   gst_sdp_message_add_attribute (sdp, "control", "*");
2025
2026   info.is_ipv6 = priv->is_ipv6;
2027   info.server_ip = priv->server_ip;
2028
2029   /* create an SDP for the media object */
2030   if (!gst_rtsp_media_setup_sdp (media, sdp, &info))
2031     goto no_sdp;
2032
2033   return sdp;
2034
2035   /* ERRORS */
2036 no_sdp:
2037   {
2038     GST_ERROR ("client %p: could not create SDP", client);
2039     gst_sdp_message_free (sdp);
2040     return NULL;
2041   }
2042 }
2043
2044 /* for the describe we must generate an SDP */
2045 static gboolean
2046 handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx)
2047 {
2048   GstRTSPClientPrivate *priv = client->priv;
2049   GstRTSPResult res;
2050   GstSDPMessage *sdp;
2051   guint i;
2052   gchar *path, *str;
2053   GstRTSPMedia *media;
2054   GstRTSPClientClass *klass;
2055
2056   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2057
2058   if (!ctx->uri)
2059     goto no_uri;
2060
2061   /* check what kind of format is accepted, we don't really do anything with it
2062    * and always return SDP for now. */
2063   for (i = 0;; i++) {
2064     gchar *accept;
2065
2066     res =
2067         gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT,
2068         &accept, i);
2069     if (res == GST_RTSP_ENOTIMPL)
2070       break;
2071
2072     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
2073       break;
2074   }
2075
2076   if (!priv->mount_points)
2077     goto no_mount_points;
2078
2079   if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
2080     goto no_path;
2081
2082   /* find the media object for the uri */
2083   if (!(media = find_media (client, ctx, path, NULL)))
2084     goto no_media;
2085
2086   /* create an SDP for the media object on this client */
2087   if (!(sdp = klass->create_sdp (client, media)))
2088     goto no_sdp;
2089
2090   /* we suspend after the describe */
2091   gst_rtsp_media_suspend (media);
2092   g_object_unref (media);
2093
2094   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2095       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2096
2097   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_TYPE,
2098       "application/sdp");
2099
2100   /* content base for some clients that might screw up creating the setup uri */
2101   str = make_base_url (client, ctx->uri, path);
2102   g_free (path);
2103
2104   GST_INFO ("adding content-base: %s", str);
2105   gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, str);
2106
2107   /* add SDP to the response body */
2108   str = gst_sdp_message_as_text (sdp);
2109   gst_rtsp_message_take_body (ctx->response, (guint8 *) str, strlen (str));
2110   gst_sdp_message_free (sdp);
2111
2112   send_message (client, ctx, ctx->response, FALSE);
2113
2114   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
2115       0, ctx);
2116
2117   return TRUE;
2118
2119   /* ERRORS */
2120 no_uri:
2121   {
2122     GST_ERROR ("client %p: no uri", client);
2123     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2124     return FALSE;
2125   }
2126 no_mount_points:
2127   {
2128     GST_ERROR ("client %p: no mount points configured", client);
2129     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2130     return FALSE;
2131   }
2132 no_path:
2133   {
2134     GST_ERROR ("client %p: can't find path for url", client);
2135     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2136     return FALSE;
2137   }
2138 no_media:
2139   {
2140     GST_ERROR ("client %p: no media", client);
2141     g_free (path);
2142     /* error reply is already sent */
2143     return FALSE;
2144   }
2145 no_sdp:
2146   {
2147     GST_ERROR ("client %p: can't create SDP", client);
2148     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2149     g_free (path);
2150     g_object_unref (media);
2151     return FALSE;
2152   }
2153 }
2154
2155 static gboolean
2156 handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
2157 {
2158   GstRTSPMethod options;
2159   gchar *str;
2160
2161   options = GST_RTSP_DESCRIBE |
2162       GST_RTSP_OPTIONS |
2163       GST_RTSP_PAUSE |
2164       GST_RTSP_PLAY |
2165       GST_RTSP_SETUP |
2166       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
2167
2168   str = gst_rtsp_options_as_text (options);
2169
2170   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2171       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2172
2173   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str);
2174   g_free (str);
2175
2176   send_message (client, ctx, ctx->response, FALSE);
2177
2178   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
2179       0, ctx);
2180
2181   return TRUE;
2182 }
2183
2184 /* remove duplicate and trailing '/' */
2185 static void
2186 sanitize_uri (GstRTSPUrl * uri)
2187 {
2188   gint i, len;
2189   gchar *s, *d;
2190   gboolean have_slash, prev_slash;
2191
2192   s = d = uri->abspath;
2193   len = strlen (uri->abspath);
2194
2195   prev_slash = FALSE;
2196
2197   for (i = 0; i < len; i++) {
2198     have_slash = s[i] == '/';
2199     *d = s[i];
2200     if (!have_slash || !prev_slash)
2201       d++;
2202     prev_slash = have_slash;
2203   }
2204   len = d - uri->abspath;
2205   /* don't remove the first slash if that's the only thing left */
2206   if (len > 1 && *(d - 1) == '/')
2207     d--;
2208   *d = '\0';
2209 }
2210
2211 static void
2212 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
2213 {
2214   GstRTSPClientPrivate *priv = client->priv;
2215
2216   GST_INFO ("client %p: session %p finished", client, session);
2217
2218   /* unlink all media managed in this session */
2219   client_unlink_session (client, session);
2220
2221   /* remove the session */
2222   if (!(priv->sessions = g_list_remove (priv->sessions, session))) {
2223     GST_INFO ("client %p: all sessions finalized, close the connection",
2224         client);
2225     close_connection (client);
2226   }
2227 }
2228
2229 /* Returns TRUE if there are no Require headers, otherwise returns FALSE
2230  * and also returns a newly-allocated string of (comma-separated) unsupported
2231  * options in the unsupported_reqs variable .
2232  *
2233  * There may be multiple Require headers, but we must send one single
2234  * Unsupported header with all the unsupported options as response. If
2235  * an incoming Require header contained a comma-separated list of options
2236  * GstRtspConnection will already have split that list up into multiple
2237  * headers.
2238  *
2239  * TODO: allow the application to decide what features are supported
2240  */
2241 static gboolean
2242 check_request_requirements (GstRTSPMessage * msg, gchar ** unsupported_reqs)
2243 {
2244   GstRTSPResult res;
2245   GPtrArray *arr = NULL;
2246   gchar *reqs = NULL;
2247   gint i;
2248
2249   i = 0;
2250   do {
2251     res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++);
2252
2253     if (res == GST_RTSP_ENOTIMPL)
2254       break;
2255
2256     if (arr == NULL)
2257       arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
2258
2259     g_ptr_array_add (arr, g_strdup (reqs));
2260   }
2261   while (TRUE);
2262
2263   /* if we don't have any Require headers at all, all is fine */
2264   if (i == 1)
2265     return TRUE;
2266
2267   /* otherwise we've now processed at all the Require headers */
2268   g_ptr_array_add (arr, NULL);
2269
2270   /* for now we don't commit to supporting anything, so will just report
2271    * all of the required options as unsupported */
2272   *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata);
2273
2274   g_ptr_array_unref (arr);
2275   return FALSE;
2276 }
2277
2278 static void
2279 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
2280 {
2281   GstRTSPClientPrivate *priv = client->priv;
2282   GstRTSPMethod method;
2283   const gchar *uristr;
2284   GstRTSPUrl *uri = NULL;
2285   GstRTSPVersion version;
2286   GstRTSPResult res;
2287   GstRTSPSession *session = NULL;
2288   GstRTSPContext sctx = { NULL }, *ctx;
2289   GstRTSPMessage response = { 0 };
2290   gchar *unsupported_reqs = NULL;
2291   gchar *sessid;
2292
2293   if (!(ctx = gst_rtsp_context_get_current ())) {
2294     ctx = &sctx;
2295     ctx->auth = priv->auth;
2296     gst_rtsp_context_push_current (ctx);
2297   }
2298
2299   ctx->conn = priv->connection;
2300   ctx->client = client;
2301   ctx->request = request;
2302   ctx->response = &response;
2303
2304   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
2305     gst_rtsp_message_dump (request);
2306   }
2307
2308   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
2309
2310   GST_INFO ("client %p: received a request %s %s %s", client,
2311       gst_rtsp_method_as_text (method), uristr,
2312       gst_rtsp_version_as_text (version));
2313
2314   /* we can only handle 1.0 requests */
2315   if (version != GST_RTSP_VERSION_1_0)
2316     goto not_supported;
2317
2318   ctx->method = method;
2319
2320   /* we always try to parse the url first */
2321   if (strcmp (uristr, "*") == 0) {
2322     /* special case where we have * as uri, keep uri = NULL */
2323   } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
2324     /* check if the uristr is an absolute path <=> scheme and host information
2325      * is missing */
2326     gchar *scheme;
2327
2328     scheme = g_uri_parse_scheme (uristr);
2329     if (scheme == NULL && g_str_has_prefix (uristr, "/")) {
2330       gchar *absolute_uristr = NULL;
2331
2332       GST_WARNING_OBJECT (client, "request doesn't contain absolute url");
2333       if (priv->server_ip == NULL) {
2334         GST_WARNING_OBJECT (client, "host information missing");
2335         goto bad_request;
2336       }
2337
2338       absolute_uristr =
2339           g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr);
2340
2341       GST_DEBUG_OBJECT (client, "absolute url: %s", absolute_uristr);
2342       if (gst_rtsp_url_parse (absolute_uristr, &uri) != GST_RTSP_OK) {
2343         g_free (absolute_uristr);
2344         goto bad_request;
2345       }
2346       g_free (absolute_uristr);
2347     } else {
2348       g_free (scheme);
2349       goto bad_request;
2350     }
2351   }
2352
2353   /* get the session if there is any */
2354   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
2355   if (res == GST_RTSP_OK) {
2356     if (priv->session_pool == NULL)
2357       goto no_pool;
2358
2359     /* we had a session in the request, find it again */
2360     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
2361       goto session_not_found;
2362
2363     /* we add the session to the client list of watched sessions. When a session
2364      * disappears because it times out, we will be notified. If all sessions are
2365      * gone, we will close the connection */
2366     client_watch_session (client, session);
2367   }
2368
2369   /* sanitize the uri */
2370   if (uri)
2371     sanitize_uri (uri);
2372   ctx->uri = uri;
2373   ctx->session = session;
2374
2375   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL))
2376     goto not_authorized;
2377
2378   /* handle any 'Require' headers */
2379   if (!check_request_requirements (ctx->request, &unsupported_reqs))
2380     goto unsupported_requirement;
2381
2382   /* now see what is asked and dispatch to a dedicated handler */
2383   switch (method) {
2384     case GST_RTSP_OPTIONS:
2385       handle_options_request (client, ctx);
2386       break;
2387     case GST_RTSP_DESCRIBE:
2388       handle_describe_request (client, ctx);
2389       break;
2390     case GST_RTSP_SETUP:
2391       handle_setup_request (client, ctx);
2392       break;
2393     case GST_RTSP_PLAY:
2394       handle_play_request (client, ctx);
2395       break;
2396     case GST_RTSP_PAUSE:
2397       handle_pause_request (client, ctx);
2398       break;
2399     case GST_RTSP_TEARDOWN:
2400       handle_teardown_request (client, ctx);
2401       break;
2402     case GST_RTSP_SET_PARAMETER:
2403       handle_set_param_request (client, ctx);
2404       break;
2405     case GST_RTSP_GET_PARAMETER:
2406       handle_get_param_request (client, ctx);
2407       break;
2408     case GST_RTSP_ANNOUNCE:
2409     case GST_RTSP_RECORD:
2410     case GST_RTSP_REDIRECT:
2411       goto not_implemented;
2412     case GST_RTSP_INVALID:
2413     default:
2414       goto bad_request;
2415   }
2416
2417 done:
2418   if (ctx == &sctx)
2419     gst_rtsp_context_pop_current (ctx);
2420   if (session)
2421     g_object_unref (session);
2422   if (uri)
2423     gst_rtsp_url_free (uri);
2424   return;
2425
2426   /* ERRORS */
2427 not_supported:
2428   {
2429     GST_ERROR ("client %p: version %d not supported", client, version);
2430     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
2431         ctx);
2432     goto done;
2433   }
2434 bad_request:
2435   {
2436     GST_ERROR ("client %p: bad request", client);
2437     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2438     goto done;
2439   }
2440 no_pool:
2441   {
2442     GST_ERROR ("client %p: no pool configured", client);
2443     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2444     goto done;
2445   }
2446 session_not_found:
2447   {
2448     GST_ERROR ("client %p: session not found", client);
2449     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2450     goto done;
2451   }
2452 not_authorized:
2453   {
2454     GST_ERROR ("client %p: not allowed", client);
2455     /* error reply is already sent */
2456     goto done;
2457   }
2458 unsupported_requirement:
2459   {
2460     GST_ERROR ("client %p: Required option is not supported (%s)", client,
2461         unsupported_reqs);
2462     send_option_not_supported_response (client, ctx, unsupported_reqs);
2463     g_free (unsupported_reqs);
2464     goto done;
2465   }
2466 not_implemented:
2467   {
2468     GST_ERROR ("client %p: method %d not implemented", client, method);
2469     send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
2470     goto done;
2471   }
2472 }
2473
2474
2475 static void
2476 handle_response (GstRTSPClient * client, GstRTSPMessage * response)
2477 {
2478   GstRTSPClientPrivate *priv = client->priv;
2479   GstRTSPResult res;
2480   GstRTSPSession *session = NULL;
2481   GstRTSPContext sctx = { NULL }, *ctx;
2482   gchar *sessid;
2483
2484   if (!(ctx = gst_rtsp_context_get_current ())) {
2485     ctx = &sctx;
2486     ctx->auth = priv->auth;
2487     gst_rtsp_context_push_current (ctx);
2488   }
2489
2490   ctx->conn = priv->connection;
2491   ctx->client = client;
2492   ctx->request = NULL;
2493   ctx->uri = NULL;
2494   ctx->method = GST_RTSP_INVALID;
2495   ctx->response = response;
2496
2497   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
2498     gst_rtsp_message_dump (response);
2499   }
2500
2501   GST_INFO ("client %p: received a response", client);
2502
2503   /* get the session if there is any */
2504   res =
2505       gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &sessid, 0);
2506   if (res == GST_RTSP_OK) {
2507     if (priv->session_pool == NULL)
2508       goto no_pool;
2509
2510     /* we had a session in the request, find it again */
2511     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
2512       goto session_not_found;
2513
2514     /* we add the session to the client list of watched sessions. When a session
2515      * disappears because it times out, we will be notified. If all sessions are
2516      * gone, we will close the connection */
2517     client_watch_session (client, session);
2518   }
2519
2520   ctx->session = session;
2521
2522   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE],
2523       0, ctx);
2524
2525 done:
2526   if (ctx == &sctx)
2527     gst_rtsp_context_pop_current (ctx);
2528   if (session)
2529     g_object_unref (session);
2530   return;
2531
2532 no_pool:
2533   {
2534     GST_ERROR ("client %p: no pool configured", client);
2535     goto done;
2536   }
2537 session_not_found:
2538   {
2539     GST_ERROR ("client %p: session not found", client);
2540     goto done;
2541   }
2542 }
2543
2544 static void
2545 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
2546 {
2547   GstRTSPClientPrivate *priv = client->priv;
2548   GstRTSPResult res;
2549   guint8 channel;
2550   GList *walk;
2551   guint8 *data;
2552   guint size;
2553   GstBuffer *buffer;
2554   gboolean handled;
2555
2556   /* find the stream for this message */
2557   res = gst_rtsp_message_parse_data (message, &channel);
2558   if (res != GST_RTSP_OK)
2559     return;
2560
2561   gst_rtsp_message_steal_body (message, &data, &size);
2562
2563   buffer = gst_buffer_new_wrapped (data, size);
2564
2565   handled = FALSE;
2566   for (walk = priv->transports; walk; walk = g_list_next (walk)) {
2567     GstRTSPStreamTransport *trans;
2568     GstRTSPStream *stream;
2569     const GstRTSPTransport *tr;
2570
2571     trans = walk->data;
2572
2573     tr = gst_rtsp_stream_transport_get_transport (trans);
2574     stream = gst_rtsp_stream_transport_get_stream (trans);
2575
2576     /* check for TCP transport */
2577     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
2578       /* dispatch to the stream based on the channel number */
2579       if (tr->interleaved.min == channel) {
2580         gst_rtsp_stream_recv_rtp (stream, buffer);
2581         handled = TRUE;
2582         break;
2583       } else if (tr->interleaved.max == channel) {
2584         gst_rtsp_stream_recv_rtcp (stream, buffer);
2585         handled = TRUE;
2586         break;
2587       }
2588     }
2589   }
2590   if (!handled)
2591     gst_buffer_unref (buffer);
2592 }
2593
2594 /**
2595  * gst_rtsp_client_set_session_pool:
2596  * @client: a #GstRTSPClient
2597  * @pool: (transfer none): a #GstRTSPSessionPool
2598  *
2599  * Set @pool as the sessionpool for @client which it will use to find
2600  * or allocate sessions. the sessionpool is usually inherited from the server
2601  * that created the client but can be overridden later.
2602  */
2603 void
2604 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
2605     GstRTSPSessionPool * pool)
2606 {
2607   GstRTSPSessionPool *old;
2608   GstRTSPClientPrivate *priv;
2609
2610   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2611
2612   priv = client->priv;
2613
2614   if (pool)
2615     g_object_ref (pool);
2616
2617   g_mutex_lock (&priv->lock);
2618   old = priv->session_pool;
2619   priv->session_pool = pool;
2620   g_mutex_unlock (&priv->lock);
2621
2622   if (old)
2623     g_object_unref (old);
2624 }
2625
2626 /**
2627  * gst_rtsp_client_get_session_pool:
2628  * @client: a #GstRTSPClient
2629  *
2630  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
2631  *
2632  * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage.
2633  */
2634 GstRTSPSessionPool *
2635 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
2636 {
2637   GstRTSPClientPrivate *priv;
2638   GstRTSPSessionPool *result;
2639
2640   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2641
2642   priv = client->priv;
2643
2644   g_mutex_lock (&priv->lock);
2645   if ((result = priv->session_pool))
2646     g_object_ref (result);
2647   g_mutex_unlock (&priv->lock);
2648
2649   return result;
2650 }
2651
2652 /**
2653  * gst_rtsp_client_set_mount_points:
2654  * @client: a #GstRTSPClient
2655  * @mounts: (transfer none): a #GstRTSPMountPoints
2656  *
2657  * Set @mounts as the mount points for @client which it will use to map urls
2658  * to media streams. These mount points are usually inherited from the server that
2659  * created the client but can be overriden later.
2660  */
2661 void
2662 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
2663     GstRTSPMountPoints * mounts)
2664 {
2665   GstRTSPClientPrivate *priv;
2666   GstRTSPMountPoints *old;
2667
2668   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2669
2670   priv = client->priv;
2671
2672   if (mounts)
2673     g_object_ref (mounts);
2674
2675   g_mutex_lock (&priv->lock);
2676   old = priv->mount_points;
2677   priv->mount_points = mounts;
2678   g_mutex_unlock (&priv->lock);
2679
2680   if (old)
2681     g_object_unref (old);
2682 }
2683
2684 /**
2685  * gst_rtsp_client_get_mount_points:
2686  * @client: a #GstRTSPClient
2687  *
2688  * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
2689  *
2690  * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage.
2691  */
2692 GstRTSPMountPoints *
2693 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
2694 {
2695   GstRTSPClientPrivate *priv;
2696   GstRTSPMountPoints *result;
2697
2698   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2699
2700   priv = client->priv;
2701
2702   g_mutex_lock (&priv->lock);
2703   if ((result = priv->mount_points))
2704     g_object_ref (result);
2705   g_mutex_unlock (&priv->lock);
2706
2707   return result;
2708 }
2709
2710 /**
2711  * gst_rtsp_client_set_auth:
2712  * @client: a #GstRTSPClient
2713  * @auth: (transfer none): a #GstRTSPAuth
2714  *
2715  * configure @auth to be used as the authentication manager of @client.
2716  */
2717 void
2718 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
2719 {
2720   GstRTSPClientPrivate *priv;
2721   GstRTSPAuth *old;
2722
2723   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2724
2725   priv = client->priv;
2726
2727   if (auth)
2728     g_object_ref (auth);
2729
2730   g_mutex_lock (&priv->lock);
2731   old = priv->auth;
2732   priv->auth = auth;
2733   g_mutex_unlock (&priv->lock);
2734
2735   if (old)
2736     g_object_unref (old);
2737 }
2738
2739
2740 /**
2741  * gst_rtsp_client_get_auth:
2742  * @client: a #GstRTSPClient
2743  *
2744  * Get the #GstRTSPAuth used as the authentication manager of @client.
2745  *
2746  * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after
2747  * usage.
2748  */
2749 GstRTSPAuth *
2750 gst_rtsp_client_get_auth (GstRTSPClient * client)
2751 {
2752   GstRTSPClientPrivate *priv;
2753   GstRTSPAuth *result;
2754
2755   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2756
2757   priv = client->priv;
2758
2759   g_mutex_lock (&priv->lock);
2760   if ((result = priv->auth))
2761     g_object_ref (result);
2762   g_mutex_unlock (&priv->lock);
2763
2764   return result;
2765 }
2766
2767 /**
2768  * gst_rtsp_client_set_thread_pool:
2769  * @client: a #GstRTSPClient
2770  * @pool: (transfer none): a #GstRTSPThreadPool
2771  *
2772  * configure @pool to be used as the thread pool of @client.
2773  */
2774 void
2775 gst_rtsp_client_set_thread_pool (GstRTSPClient * client,
2776     GstRTSPThreadPool * pool)
2777 {
2778   GstRTSPClientPrivate *priv;
2779   GstRTSPThreadPool *old;
2780
2781   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2782
2783   priv = client->priv;
2784
2785   if (pool)
2786     g_object_ref (pool);
2787
2788   g_mutex_lock (&priv->lock);
2789   old = priv->thread_pool;
2790   priv->thread_pool = pool;
2791   g_mutex_unlock (&priv->lock);
2792
2793   if (old)
2794     g_object_unref (old);
2795 }
2796
2797 /**
2798  * gst_rtsp_client_get_thread_pool:
2799  * @client: a #GstRTSPClient
2800  *
2801  * Get the #GstRTSPThreadPool used as the thread pool of @client.
2802  *
2803  * Returns: (transfer full): the #GstRTSPThreadPool of @client. g_object_unref() after
2804  * usage.
2805  */
2806 GstRTSPThreadPool *
2807 gst_rtsp_client_get_thread_pool (GstRTSPClient * client)
2808 {
2809   GstRTSPClientPrivate *priv;
2810   GstRTSPThreadPool *result;
2811
2812   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2813
2814   priv = client->priv;
2815
2816   g_mutex_lock (&priv->lock);
2817   if ((result = priv->thread_pool))
2818     g_object_ref (result);
2819   g_mutex_unlock (&priv->lock);
2820
2821   return result;
2822 }
2823
2824 /**
2825  * gst_rtsp_client_set_connection:
2826  * @client: a #GstRTSPClient
2827  * @conn: (transfer full): a #GstRTSPConnection
2828  *
2829  * Set the #GstRTSPConnection of @client. This function takes ownership of
2830  * @conn.
2831  *
2832  * Returns: %TRUE on success.
2833  */
2834 gboolean
2835 gst_rtsp_client_set_connection (GstRTSPClient * client,
2836     GstRTSPConnection * conn)
2837 {
2838   GstRTSPClientPrivate *priv;
2839   GSocket *read_socket;
2840   GSocketAddress *address;
2841   GstRTSPUrl *url;
2842   GError *error = NULL;
2843
2844   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
2845   g_return_val_if_fail (conn != NULL, FALSE);
2846
2847   priv = client->priv;
2848
2849   read_socket = gst_rtsp_connection_get_read_socket (conn);
2850
2851   if (!(address = g_socket_get_local_address (read_socket, &error)))
2852     goto no_address;
2853
2854   g_free (priv->server_ip);
2855   /* keep the original ip that the client connected to */
2856   if (G_IS_INET_SOCKET_ADDRESS (address)) {
2857     GInetAddress *iaddr;
2858
2859     iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
2860
2861     /* socket might be ipv6 but adress still ipv4 */
2862     priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6;
2863     priv->server_ip = g_inet_address_to_string (iaddr);
2864     g_object_unref (address);
2865   } else {
2866     priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
2867     priv->server_ip = g_strdup ("unknown");
2868   }
2869
2870   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
2871       priv->server_ip, priv->is_ipv6);
2872
2873   url = gst_rtsp_connection_get_url (conn);
2874   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
2875
2876   priv->connection = conn;
2877
2878   return TRUE;
2879
2880   /* ERRORS */
2881 no_address:
2882   {
2883     GST_ERROR ("could not get local address %s", error->message);
2884     g_error_free (error);
2885     return FALSE;
2886   }
2887 }
2888
2889 /**
2890  * gst_rtsp_client_get_connection:
2891  * @client: a #GstRTSPClient
2892  *
2893  * Get the #GstRTSPConnection of @client.
2894  *
2895  * Returns: (transfer none): the #GstRTSPConnection of @client.
2896  * The connection object returned remains valid until the client is freed.
2897  */
2898 GstRTSPConnection *
2899 gst_rtsp_client_get_connection (GstRTSPClient * client)
2900 {
2901   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2902
2903   return client->priv->connection;
2904 }
2905
2906 /**
2907  * gst_rtsp_client_set_send_func:
2908  * @client: a #GstRTSPClient
2909  * @func: (scope notified): a #GstRTSPClientSendFunc
2910  * @user_data: (closure): user data passed to @func
2911  * @notify: (allow-none): called when @user_data is no longer in use
2912  *
2913  * Set @func as the callback that will be called when a new message needs to be
2914  * sent to the client. @user_data is passed to @func and @notify is called when
2915  * @user_data is no longer in use.
2916  *
2917  * By default, the client will send the messages on the #GstRTSPConnection that
2918  * was configured with gst_rtsp_client_attach() was called.
2919  */
2920 void
2921 gst_rtsp_client_set_send_func (GstRTSPClient * client,
2922     GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
2923 {
2924   GstRTSPClientPrivate *priv;
2925   GDestroyNotify old_notify;
2926   gpointer old_data;
2927
2928   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2929
2930   priv = client->priv;
2931
2932   g_mutex_lock (&priv->send_lock);
2933   priv->send_func = func;
2934   old_notify = priv->send_notify;
2935   old_data = priv->send_data;
2936   priv->send_notify = notify;
2937   priv->send_data = user_data;
2938   g_mutex_unlock (&priv->send_lock);
2939
2940   if (old_notify)
2941     old_notify (old_data);
2942 }
2943
2944 /**
2945  * gst_rtsp_client_handle_message:
2946  * @client: a #GstRTSPClient
2947  * @message: (transfer none): an #GstRTSPMessage
2948  *
2949  * Let the client handle @message.
2950  *
2951  * Returns: a #GstRTSPResult.
2952  */
2953 GstRTSPResult
2954 gst_rtsp_client_handle_message (GstRTSPClient * client,
2955     GstRTSPMessage * message)
2956 {
2957   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
2958   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2959
2960   switch (message->type) {
2961     case GST_RTSP_MESSAGE_REQUEST:
2962       handle_request (client, message);
2963       break;
2964     case GST_RTSP_MESSAGE_RESPONSE:
2965       handle_response (client, message);
2966       break;
2967     case GST_RTSP_MESSAGE_DATA:
2968       handle_data (client, message);
2969       break;
2970     default:
2971       break;
2972   }
2973   return GST_RTSP_OK;
2974 }
2975
2976 /**
2977  * gst_rtsp_client_send_message:
2978  * @client: a #GstRTSPClient
2979  * @session: (transfer none): a #GstRTSPSession to send the message to or %NULL
2980  * @message: (transfer none): The #GstRTSPMessage to send
2981  *
2982  * Send a message message to the remote end. @message must be a
2983  * #GST_RTSP_MESSAGE_REQUEST or a #GST_RTSP_MESSAGE_RESPONSE.
2984  */
2985 GstRTSPResult
2986 gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session,
2987     GstRTSPMessage * message)
2988 {
2989   GstRTSPContext sctx = { NULL }
2990   , *ctx;
2991   GstRTSPClientPrivate *priv;
2992
2993   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
2994   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2995   g_return_val_if_fail (message->type == GST_RTSP_MESSAGE_REQUEST ||
2996       message->type == GST_RTSP_MESSAGE_RESPONSE, GST_RTSP_EINVAL);
2997
2998   priv = client->priv;
2999
3000   if (!(ctx = gst_rtsp_context_get_current ())) {
3001     ctx = &sctx;
3002     ctx->auth = priv->auth;
3003     gst_rtsp_context_push_current (ctx);
3004   }
3005
3006   ctx->conn = priv->connection;
3007   ctx->client = client;
3008   ctx->session = session;
3009
3010   send_message (client, ctx, message, FALSE);
3011
3012   if (ctx == &sctx)
3013     gst_rtsp_context_pop_current (ctx);
3014
3015   return GST_RTSP_OK;
3016 }
3017
3018 static GstRTSPResult
3019 do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
3020     gboolean close, gpointer user_data)
3021 {
3022   GstRTSPClientPrivate *priv = client->priv;
3023   GstRTSPResult ret;
3024   GTimeVal time;
3025
3026   time.tv_sec = 1;
3027   time.tv_usec = 0;
3028
3029   do {
3030     /* send the response and store the seq number so we can wait until it's
3031      * written to the client to close the connection */
3032     ret =
3033         gst_rtsp_watch_send_message (priv->watch, message,
3034         close ? &priv->close_seq : NULL);
3035     if (ret == GST_RTSP_OK)
3036       break;
3037
3038     if (ret != GST_RTSP_ENOMEM)
3039       goto error;
3040
3041     /* drop backlog */
3042     if (priv->drop_backlog)
3043       break;
3044
3045     /* queue was full, wait for more space */
3046     GST_DEBUG_OBJECT (client, "waiting for backlog");
3047     ret = gst_rtsp_watch_wait_backlog (priv->watch, &time);
3048     GST_DEBUG_OBJECT (client, "Resend due to backlog full");
3049   } while (ret != GST_RTSP_EINTR);
3050
3051   return ret;
3052
3053   /* ERRORS */
3054 error:
3055   {
3056     GST_DEBUG_OBJECT (client, "got error %d", ret);
3057     return ret;
3058   }
3059 }
3060
3061 static GstRTSPResult
3062 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
3063     gpointer user_data)
3064 {
3065   return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
3066 }
3067
3068 static GstRTSPResult
3069 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
3070 {
3071   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3072   GstRTSPClientPrivate *priv = client->priv;
3073
3074   if (priv->close_seq && priv->close_seq == cseq) {
3075     priv->close_seq = 0;
3076     close_connection (client);
3077   }
3078
3079   return GST_RTSP_OK;
3080 }
3081
3082 static GstRTSPResult
3083 closed (GstRTSPWatch * watch, gpointer user_data)
3084 {
3085   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3086   GstRTSPClientPrivate *priv = client->priv;
3087   const gchar *tunnelid;
3088
3089   GST_INFO ("client %p: connection closed", client);
3090
3091   if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
3092     g_mutex_lock (&tunnels_lock);
3093     /* remove from tunnelids */
3094     g_hash_table_remove (tunnels, tunnelid);
3095     g_mutex_unlock (&tunnels_lock);
3096   }
3097
3098   gst_rtsp_watch_set_flushing (watch, TRUE);
3099   gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
3100
3101   return GST_RTSP_OK;
3102 }
3103
3104 static GstRTSPResult
3105 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
3106 {
3107   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3108   gchar *str;
3109
3110   str = gst_rtsp_strresult (result);
3111   GST_INFO ("client %p: received an error %s", client, str);
3112   g_free (str);
3113
3114   return GST_RTSP_OK;
3115 }
3116
3117 static GstRTSPResult
3118 error_full (GstRTSPWatch * watch, GstRTSPResult result,
3119     GstRTSPMessage * message, guint id, gpointer user_data)
3120 {
3121   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3122   gchar *str;
3123
3124   str = gst_rtsp_strresult (result);
3125   GST_INFO
3126       ("client %p: error when handling message %p with id %d: %s",
3127       client, message, id, str);
3128   g_free (str);
3129
3130   return GST_RTSP_OK;
3131 }
3132
3133 static gboolean
3134 remember_tunnel (GstRTSPClient * client)
3135 {
3136   GstRTSPClientPrivate *priv = client->priv;
3137   const gchar *tunnelid;
3138
3139   /* store client in the pending tunnels */
3140   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
3141   if (tunnelid == NULL)
3142     goto no_tunnelid;
3143
3144   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
3145
3146   /* we can't have two clients connecting with the same tunnelid */
3147   g_mutex_lock (&tunnels_lock);
3148   if (g_hash_table_lookup (tunnels, tunnelid))
3149     goto tunnel_existed;
3150
3151   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
3152   g_mutex_unlock (&tunnels_lock);
3153
3154   return TRUE;
3155
3156   /* ERRORS */
3157 no_tunnelid:
3158   {
3159     GST_ERROR ("client %p: no tunnelid provided", client);
3160     return FALSE;
3161   }
3162 tunnel_existed:
3163   {
3164     g_mutex_unlock (&tunnels_lock);
3165     GST_ERROR ("client %p: tunnel session %s already existed", client,
3166         tunnelid);
3167     return FALSE;
3168   }
3169 }
3170
3171 static GstRTSPResult
3172 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
3173 {
3174   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3175   GstRTSPClientPrivate *priv = client->priv;
3176
3177   GST_WARNING ("client %p: tunnel lost (connection %p)", client,
3178       priv->connection);
3179
3180   /* ignore error, it'll only be a problem when the client does a POST again */
3181   remember_tunnel (client);
3182
3183   return GST_RTSP_OK;
3184 }
3185
3186 static gboolean
3187 handle_tunnel (GstRTSPClient * client)
3188 {
3189   GstRTSPClientPrivate *priv = client->priv;
3190   GstRTSPClient *oclient;
3191   GstRTSPClientPrivate *opriv;
3192   const gchar *tunnelid;
3193
3194   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
3195   if (tunnelid == NULL)
3196     goto no_tunnelid;
3197
3198   /* check for previous tunnel */
3199   g_mutex_lock (&tunnels_lock);
3200   oclient = g_hash_table_lookup (tunnels, tunnelid);
3201
3202   if (oclient == NULL) {
3203     /* no previous tunnel, remember tunnel */
3204     g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
3205     g_mutex_unlock (&tunnels_lock);
3206
3207     GST_INFO ("client %p: no previous tunnel found, remembering tunnel (%p)",
3208         client, priv->connection);
3209   } else {
3210     /* merge both tunnels into the first client */
3211     /* remove the old client from the table. ref before because removing it will
3212      * remove the ref to it. */
3213     g_object_ref (oclient);
3214     g_hash_table_remove (tunnels, tunnelid);
3215     g_mutex_unlock (&tunnels_lock);
3216
3217     opriv = oclient->priv;
3218
3219     if (opriv->watch == NULL)
3220       goto tunnel_closed;
3221
3222     GST_INFO ("client %p: found previous tunnel %p (old %p, new %p)", client,
3223         oclient, opriv->connection, priv->connection);
3224
3225     gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
3226     gst_rtsp_watch_reset (priv->watch);
3227     gst_rtsp_watch_reset (opriv->watch);
3228     g_object_unref (oclient);
3229
3230     /* the old client owns the tunnel now, the new one will be freed */
3231     g_source_destroy ((GSource *) priv->watch);
3232     priv->watch = NULL;
3233     gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
3234   }
3235
3236   return TRUE;
3237
3238   /* ERRORS */
3239 no_tunnelid:
3240   {
3241     GST_ERROR ("client %p: no tunnelid provided", client);
3242     return FALSE;
3243   }
3244 tunnel_closed:
3245   {
3246     GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
3247     g_object_unref (oclient);
3248     return FALSE;
3249   }
3250 }
3251
3252 static GstRTSPStatusCode
3253 tunnel_get (GstRTSPWatch * watch, gpointer user_data)
3254 {
3255   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3256
3257   GST_INFO ("client %p: tunnel get (connection %p)", client,
3258       client->priv->connection);
3259
3260   if (!handle_tunnel (client)) {
3261     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
3262   }
3263
3264   return GST_RTSP_STS_OK;
3265 }
3266
3267 static GstRTSPResult
3268 tunnel_post (GstRTSPWatch * watch, gpointer user_data)
3269 {
3270   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3271
3272   GST_INFO ("client %p: tunnel post (connection %p)", client,
3273       client->priv->connection);
3274
3275   if (!handle_tunnel (client)) {
3276     return GST_RTSP_ERROR;
3277   }
3278
3279   return GST_RTSP_OK;
3280 }
3281
3282 static GstRTSPResult
3283 tunnel_http_response (GstRTSPWatch * watch, GstRTSPMessage * request,
3284     GstRTSPMessage * response, gpointer user_data)
3285 {
3286   GstRTSPClientClass *klass;
3287
3288   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
3289   klass = GST_RTSP_CLIENT_GET_CLASS (client);
3290
3291   if (klass->tunnel_http_response) {
3292     klass->tunnel_http_response (client, request, response);
3293   }
3294
3295   return GST_RTSP_OK;
3296 }
3297
3298 static GstRTSPWatchFuncs watch_funcs = {
3299   message_received,
3300   message_sent,
3301   closed,
3302   error,
3303   tunnel_get,
3304   tunnel_post,
3305   error_full,
3306   tunnel_lost,
3307   tunnel_http_response
3308 };
3309
3310 static void
3311 client_watch_notify (GstRTSPClient * client)
3312 {
3313   GstRTSPClientPrivate *priv = client->priv;
3314
3315   GST_INFO ("client %p: watch destroyed", client);
3316   priv->watch = NULL;
3317   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
3318   g_object_unref (client);
3319 }
3320
3321 /**
3322  * gst_rtsp_client_attach:
3323  * @client: a #GstRTSPClient
3324  * @context: (allow-none): a #GMainContext
3325  *
3326  * Attaches @client to @context. When the mainloop for @context is run, the
3327  * client will be dispatched. When @context is %NULL, the default context will be
3328  * used).
3329  *
3330  * This function should be called when the client properties and urls are fully
3331  * configured and the client is ready to start.
3332  *
3333  * Returns: the ID (greater than 0) for the source within the GMainContext.
3334  */
3335 guint
3336 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
3337 {
3338   GstRTSPClientPrivate *priv;
3339   guint res;
3340
3341   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
3342   priv = client->priv;
3343   g_return_val_if_fail (priv->connection != NULL, 0);
3344   g_return_val_if_fail (priv->watch == NULL, 0);
3345
3346   /* create watch for the connection and attach */
3347   priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
3348       g_object_ref (client), (GDestroyNotify) client_watch_notify);
3349   gst_rtsp_client_set_send_func (client, do_send_message, priv->watch,
3350       (GDestroyNotify) gst_rtsp_watch_unref);
3351
3352   /* FIXME make this configurable. We don't want to do this yet because it will
3353    * be superceeded by a cache object later */
3354   gst_rtsp_watch_set_send_backlog (priv->watch, 0, 100);
3355
3356   GST_INFO ("attaching to context %p", context);
3357   res = gst_rtsp_watch_attach (priv->watch, context);
3358
3359   return res;
3360 }
3361
3362 /**
3363  * gst_rtsp_client_session_filter:
3364  * @client: a #GstRTSPClient
3365  * @func: (scope call) (allow-none): a callback
3366  * @user_data: user data passed to @func
3367  *
3368  * Call @func for each session managed by @client. The result value of @func
3369  * determines what happens to the session. @func will be called with @client
3370  * locked so no further actions on @client can be performed from @func.
3371  *
3372  * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from
3373  * @client.
3374  *
3375  * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @client.
3376  *
3377  * If @func returns #GST_RTSP_FILTER_REF, the session will remain in @client but
3378  * will also be added with an additional ref to the result #GList of this
3379  * function..
3380  *
3381  * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each session.
3382  *
3383  * Returns: (element-type GstRTSPSession) (transfer full): a #GList with all
3384  * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each
3385  * element in the #GList should be unreffed before the list is freed.
3386  */
3387 GList *
3388 gst_rtsp_client_session_filter (GstRTSPClient * client,
3389     GstRTSPClientSessionFilterFunc func, gpointer user_data)
3390 {
3391   GstRTSPClientPrivate *priv;
3392   GList *result, *walk, *next;
3393
3394   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3395
3396   priv = client->priv;
3397
3398   result = NULL;
3399
3400   g_mutex_lock (&priv->lock);
3401   for (walk = priv->sessions; walk; walk = next) {
3402     GstRTSPSession *sess = walk->data;
3403     GstRTSPFilterResult res;
3404
3405     next = g_list_next (walk);
3406
3407     if (func)
3408       res = func (client, sess, user_data);
3409     else
3410       res = GST_RTSP_FILTER_REF;
3411
3412     switch (res) {
3413       case GST_RTSP_FILTER_REMOVE:
3414         /* stop watching the session and pretent it went away */
3415         client_cleanup_session (client, sess);
3416         break;
3417       case GST_RTSP_FILTER_REF:
3418         result = g_list_prepend (result, g_object_ref (sess));
3419         break;
3420       case GST_RTSP_FILTER_KEEP:
3421       default:
3422         break;
3423     }
3424   }
3425   g_mutex_unlock (&priv->lock);
3426
3427   return result;
3428 }