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