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