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