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