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