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