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