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