rtsp-client: Make configure_client_transport 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 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   /* get a handle to the configuration of the media in the session */
668   media = gst_rtsp_session_get_media (session, state->uri);
669   if (!media)
670     goto not_found;
671
672   state->sessmedia = media;
673
674   /* we emit the signal before closing the connection */
675   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
676       0, state);
677
678   /* unlink the all TCP callbacks */
679   unlink_session_transports (client, session, media);
680
681   /* remove the session from the watched sessions */
682   g_object_weak_unref (G_OBJECT (session),
683       (GWeakNotify) client_session_finalized, client);
684   priv->sessions = g_list_remove (priv->sessions, session);
685
686   gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
687
688   /* unmanage the media in the session, returns false if all media session
689    * are torn down. */
690   if (!gst_rtsp_session_release_media (session, media)) {
691     /* remove the session */
692     gst_rtsp_session_pool_remove (priv->session_pool, session);
693   }
694   /* construct the response now */
695   code = GST_RTSP_STS_OK;
696   gst_rtsp_message_init_response (state->response, code,
697       gst_rtsp_status_as_text (code), state->request);
698
699   send_response (client, session, state->response, TRUE);
700
701   return TRUE;
702
703   /* ERRORS */
704 no_session:
705   {
706     GST_ERROR ("client %p: no session", client);
707     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
708     return FALSE;
709   }
710 not_found:
711   {
712     GST_ERROR ("client %p: no media for uri", client);
713     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
714     return FALSE;
715   }
716 }
717
718 static GstRTSPResult
719 default_params_set (GstRTSPClient * client, GstRTSPClientState * state)
720 {
721   GstRTSPResult res;
722
723   res = gst_rtsp_params_set (client, state);
724
725   return res;
726 }
727
728 static GstRTSPResult
729 default_params_get (GstRTSPClient * client, GstRTSPClientState * state)
730 {
731   GstRTSPResult res;
732
733   res = gst_rtsp_params_get (client, state);
734
735   return res;
736 }
737
738 static gboolean
739 handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state)
740 {
741   GstRTSPResult res;
742   guint8 *data;
743   guint size;
744
745   res = gst_rtsp_message_get_body (state->request, &data, &size);
746   if (res != GST_RTSP_OK)
747     goto bad_request;
748
749   if (size == 0) {
750     /* no body, keep-alive request */
751     send_generic_response (client, GST_RTSP_STS_OK, state);
752   } else {
753     /* there is a body, handle the params */
754     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, state);
755     if (res != GST_RTSP_OK)
756       goto bad_request;
757
758     send_response (client, state->session, state->response, FALSE);
759   }
760
761   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
762       0, state);
763
764   return TRUE;
765
766   /* ERRORS */
767 bad_request:
768   {
769     GST_ERROR ("client %p: bad request", client);
770     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
771     return FALSE;
772   }
773 }
774
775 static gboolean
776 handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state)
777 {
778   GstRTSPResult res;
779   guint8 *data;
780   guint size;
781
782   res = gst_rtsp_message_get_body (state->request, &data, &size);
783   if (res != GST_RTSP_OK)
784     goto bad_request;
785
786   if (size == 0) {
787     /* no body, keep-alive request */
788     send_generic_response (client, GST_RTSP_STS_OK, state);
789   } else {
790     /* there is a body, handle the params */
791     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, state);
792     if (res != GST_RTSP_OK)
793       goto bad_request;
794
795     send_response (client, state->session, state->response, FALSE);
796   }
797
798   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
799       0, state);
800
801   return TRUE;
802
803   /* ERRORS */
804 bad_request:
805   {
806     GST_ERROR ("client %p: bad request", client);
807     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
808     return FALSE;
809   }
810 }
811
812 static gboolean
813 handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state)
814 {
815   GstRTSPSession *session;
816   GstRTSPSessionMedia *media;
817   GstRTSPStatusCode code;
818   GstRTSPState rtspstate;
819
820   if (!(session = state->session))
821     goto no_session;
822
823   /* get a handle to the configuration of the media in the session */
824   media = gst_rtsp_session_get_media (session, state->uri);
825   if (!media)
826     goto not_found;
827
828   state->sessmedia = media;
829
830   rtspstate = gst_rtsp_session_media_get_rtsp_state (media);
831   /* the session state must be playing or recording */
832   if (rtspstate != GST_RTSP_STATE_PLAYING &&
833       rtspstate != GST_RTSP_STATE_RECORDING)
834     goto invalid_state;
835
836   /* unlink the all TCP callbacks */
837   unlink_session_transports (client, session, media);
838
839   /* then pause sending */
840   gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
841
842   /* construct the response now */
843   code = GST_RTSP_STS_OK;
844   gst_rtsp_message_init_response (state->response, code,
845       gst_rtsp_status_as_text (code), state->request);
846
847   send_response (client, session, state->response, FALSE);
848
849   /* the state is now READY */
850   gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_READY);
851
852   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST],
853       0, state);
854
855   return TRUE;
856
857   /* ERRORS */
858 no_session:
859   {
860     GST_ERROR ("client %p: no seesion", client);
861     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
862     return FALSE;
863   }
864 not_found:
865   {
866     GST_ERROR ("client %p: no media for uri", client);
867     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
868     return FALSE;
869   }
870 invalid_state:
871   {
872     GST_ERROR ("client %p: not PLAYING or RECORDING", client);
873     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
874         state);
875     return FALSE;
876   }
877 }
878
879 static gboolean
880 handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
881 {
882   GstRTSPSession *session;
883   GstRTSPSessionMedia *media;
884   GstRTSPStatusCode code;
885   GString *rtpinfo;
886   guint n_streams, i, infocount;
887   gchar *str;
888   GstRTSPTimeRange *range;
889   GstRTSPResult res;
890   GstRTSPState rtspstate;
891   GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
892
893   if (!(session = state->session))
894     goto no_session;
895
896   /* get a handle to the configuration of the media in the session */
897   media = gst_rtsp_session_get_media (session, state->uri);
898   if (!media)
899     goto not_found;
900
901   state->sessmedia = media;
902
903   /* the session state must be playing or ready */
904   rtspstate = gst_rtsp_session_media_get_rtsp_state (media);
905   if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
906     goto invalid_state;
907
908   /* parse the range header if we have one */
909   res =
910       gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_RANGE, &str, 0);
911   if (res == GST_RTSP_OK) {
912     if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
913       /* we have a range, seek to the position */
914       unit = range->unit;
915       gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range);
916       gst_rtsp_range_free (range);
917     }
918   }
919
920   /* grab RTPInfo from the payloaders now */
921   rtpinfo = g_string_new ("");
922
923   n_streams =
924       gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media));
925   for (i = 0, infocount = 0; i < n_streams; i++) {
926     GstRTSPStreamTransport *trans;
927     GstRTSPStream *stream;
928     const GstRTSPTransport *tr;
929     gchar *uristr;
930     guint rtptime, seq;
931
932     /* get the transport, if there is no transport configured, skip this stream */
933     trans = gst_rtsp_session_media_get_transport (media, i);
934     if (trans == NULL) {
935       GST_INFO ("stream %d is not configured", i);
936       continue;
937     }
938     tr = gst_rtsp_stream_transport_get_transport (trans);
939
940     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
941       /* for TCP, link the stream to the TCP connection of the client */
942       link_transport (client, session, trans);
943     }
944
945     stream = gst_rtsp_stream_transport_get_stream (trans);
946     if (gst_rtsp_stream_get_rtpinfo (stream, &rtptime, &seq)) {
947       if (infocount > 0)
948         g_string_append (rtpinfo, ", ");
949
950       uristr = gst_rtsp_url_get_request_uri (state->uri);
951       g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u",
952           uristr, i, seq, rtptime);
953       g_free (uristr);
954
955       infocount++;
956     } else {
957       GST_WARNING ("RTP-Info cannot be determined for stream %d", i);
958     }
959   }
960
961   /* construct the response now */
962   code = GST_RTSP_STS_OK;
963   gst_rtsp_message_init_response (state->response, code,
964       gst_rtsp_status_as_text (code), state->request);
965
966   /* add the RTP-Info header */
967   if (infocount > 0) {
968     str = g_string_free (rtpinfo, FALSE);
969     gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RTP_INFO, str);
970   } else {
971     g_string_free (rtpinfo, TRUE);
972   }
973
974   /* add the range */
975   str =
976       gst_rtsp_media_get_range_string (gst_rtsp_session_media_get_media (media),
977       TRUE, unit);
978   gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str);
979
980   send_response (client, session, state->response, FALSE);
981
982   /* start playing after sending the request */
983   gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
984
985   gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_PLAYING);
986
987   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST],
988       0, state);
989
990   return TRUE;
991
992   /* ERRORS */
993 no_session:
994   {
995     GST_ERROR ("client %p: no session", client);
996     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
997     return FALSE;
998   }
999 not_found:
1000   {
1001     GST_ERROR ("client %p: media not found", client);
1002     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1003     return FALSE;
1004   }
1005 invalid_state:
1006   {
1007     GST_ERROR ("client %p: not PLAYING or READY", client);
1008     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1009         state);
1010     return FALSE;
1011   }
1012 }
1013
1014 static void
1015 do_keepalive (GstRTSPSession * session)
1016 {
1017   GST_INFO ("keep session %p alive", session);
1018   gst_rtsp_session_touch (session);
1019 }
1020
1021 /* parse @transport and return a valid transport in @tr. only transports
1022  * from @supported are returned. Returns FALSE if no valid transport
1023  * was found. */
1024 static gboolean
1025 parse_transport (const char *transport, GstRTSPLowerTrans supported,
1026     GstRTSPTransport * tr)
1027 {
1028   gint i;
1029   gboolean res;
1030   gchar **transports;
1031
1032   res = FALSE;
1033   gst_rtsp_transport_init (tr);
1034
1035   GST_DEBUG ("parsing transports %s", transport);
1036
1037   transports = g_strsplit (transport, ",", 0);
1038
1039   /* loop through the transports, try to parse */
1040   for (i = 0; transports[i]; i++) {
1041     res = gst_rtsp_transport_parse (transports[i], tr);
1042     if (res != GST_RTSP_OK) {
1043       /* no valid transport, search some more */
1044       GST_WARNING ("could not parse transport %s", transports[i]);
1045       goto next;
1046     }
1047
1048     /* we have a transport, see if it's RTP/AVP */
1049     if (tr->trans != GST_RTSP_TRANS_RTP || tr->profile != GST_RTSP_PROFILE_AVP) {
1050       GST_WARNING ("invalid transport %s", transports[i]);
1051       goto next;
1052     }
1053
1054     if (!(tr->lower_transport & supported)) {
1055       GST_WARNING ("unsupported transport %s", transports[i]);
1056       goto next;
1057     }
1058
1059     /* we have a valid transport */
1060     GST_INFO ("found valid transport %s", transports[i]);
1061     res = TRUE;
1062     break;
1063
1064   next:
1065     gst_rtsp_transport_init (tr);
1066   }
1067   g_strfreev (transports);
1068
1069   return res;
1070 }
1071
1072 static gboolean
1073 handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream,
1074     GstRTSPMessage * request)
1075 {
1076   gchar *blocksize_str;
1077   gboolean ret = TRUE;
1078
1079   if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
1080           &blocksize_str, 0) == GST_RTSP_OK) {
1081     guint64 blocksize;
1082     gchar *end;
1083
1084     blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
1085     if (end == blocksize_str) {
1086       GST_ERROR ("failed to parse blocksize");
1087       ret = FALSE;
1088     } else {
1089       /* we don't want to change the mtu when this media
1090        * can be shared because it impacts other clients */
1091       if (gst_rtsp_media_is_shared (media))
1092         return TRUE;
1093
1094       if (blocksize > G_MAXUINT)
1095         blocksize = G_MAXUINT;
1096       gst_rtsp_stream_set_mtu (stream, blocksize);
1097     }
1098   }
1099   return ret;
1100 }
1101
1102 static gboolean
1103 default_configure_client_transport (GstRTSPClient * client,
1104     GstRTSPClientState * state, GstRTSPTransport * ct)
1105 {
1106   GstRTSPClientPrivate *priv = client->priv;
1107
1108   /* we have a valid transport now, set the destination of the client. */
1109   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1110     if (ct->destination && priv->use_client_settings) {
1111       GstRTSPAddress *addr;
1112
1113       addr = gst_rtsp_stream_reserve_address (state->stream, ct->destination,
1114           ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
1115
1116       if (addr == NULL)
1117         goto no_address;
1118
1119       gst_rtsp_address_free (addr);
1120     } else {
1121       GstRTSPAddress *addr;
1122
1123       addr = gst_rtsp_stream_get_address (state->stream);
1124       if (addr == NULL)
1125         goto no_address;
1126
1127       g_free (ct->destination);
1128       ct->destination = g_strdup (addr->address);
1129       ct->port.min = addr->port;
1130       ct->port.max = addr->port + addr->n_ports - 1;
1131       ct->ttl = addr->ttl;
1132
1133       gst_rtsp_address_free (addr);
1134     }
1135   } else {
1136     GstRTSPUrl *url;
1137
1138     url = gst_rtsp_connection_get_url (priv->connection);
1139     g_free (ct->destination);
1140     ct->destination = g_strdup (url->host);
1141
1142     if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1143       /* check if the client selected channels for TCP */
1144       if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1145         gst_rtsp_session_media_alloc_channels (state->sessmedia,
1146             &ct->interleaved);
1147       }
1148     }
1149   }
1150   return TRUE;
1151
1152   /* ERRORS */
1153 no_address:
1154   {
1155     GST_ERROR_OBJECT (client, "failed to acquire address for stream");
1156     return FALSE;
1157   }
1158 }
1159
1160 static GstRTSPTransport *
1161 make_server_transport (GstRTSPClient * client, GstRTSPClientState * state,
1162     GstRTSPTransport * ct)
1163 {
1164   GstRTSPTransport *st;
1165   GInetAddress *addr;
1166   GSocketFamily family;
1167
1168   /* prepare the server transport */
1169   gst_rtsp_transport_new (&st);
1170
1171   st->trans = ct->trans;
1172   st->profile = ct->profile;
1173   st->lower_transport = ct->lower_transport;
1174
1175   addr = g_inet_address_new_from_string (ct->destination);
1176
1177   if (!addr) {
1178     GST_ERROR ("failed to get inet addr from client destination");
1179     family = G_SOCKET_FAMILY_IPV4;
1180   } else {
1181     family = g_inet_address_get_family (addr);
1182     g_object_unref (addr);
1183     addr = NULL;
1184   }
1185
1186   switch (st->lower_transport) {
1187     case GST_RTSP_LOWER_TRANS_UDP:
1188       st->client_port = ct->client_port;
1189       gst_rtsp_stream_get_server_port (state->stream, &st->server_port, family);
1190       break;
1191     case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1192       st->port = ct->port;
1193       st->destination = g_strdup (ct->destination);
1194       st->ttl = ct->ttl;
1195       break;
1196     case GST_RTSP_LOWER_TRANS_TCP:
1197       st->interleaved = ct->interleaved;
1198     default:
1199       break;
1200   }
1201
1202   gst_rtsp_stream_get_ssrc (state->stream, &st->ssrc);
1203
1204   return st;
1205 }
1206
1207 static gboolean
1208 handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
1209 {
1210   GstRTSPClientPrivate *priv = client->priv;
1211   GstRTSPResult res;
1212   GstRTSPUrl *uri;
1213   gchar *transport;
1214   GstRTSPTransport *ct, *st;
1215   GstRTSPLowerTrans supported;
1216   GstRTSPStatusCode code;
1217   GstRTSPSession *session;
1218   GstRTSPStreamTransport *trans;
1219   gchar *trans_str, *pos;
1220   guint streamid;
1221   GstRTSPSessionMedia *sessmedia;
1222   GstRTSPMedia *media;
1223   GstRTSPStream *stream;
1224   GstRTSPState rtspstate;
1225   GstRTSPClientClass *klass;
1226
1227   uri = state->uri;
1228
1229   /* the uri contains the stream number we added in the SDP config, which is
1230    * always /stream=%d so we need to strip that off
1231    * parse the stream we need to configure, look for the stream in the abspath
1232    * first and then in the query. */
1233   if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) {
1234     if (uri->query == NULL || !(pos = strstr (uri->query, "/stream=")))
1235       goto bad_request;
1236   }
1237
1238   /* we can mofify the parsed uri in place */
1239   *pos = '\0';
1240
1241   pos += strlen ("/stream=");
1242   if (sscanf (pos, "%u", &streamid) != 1)
1243     goto bad_request;
1244
1245   /* parse the transport */
1246   res =
1247       gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_TRANSPORT,
1248       &transport, 0);
1249   if (res != GST_RTSP_OK)
1250     goto no_transport;
1251
1252   gst_rtsp_transport_new (&ct);
1253
1254   /* our supported transports */
1255   supported = GST_RTSP_LOWER_TRANS_UDP |
1256       GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP;
1257
1258   /* parse and find a usable supported transport */
1259   if (!parse_transport (transport, supported, ct))
1260     goto unsupported_transports;
1261
1262   /* we create the session after parsing stuff so that we don't make
1263    * a session for malformed requests */
1264   if (priv->session_pool == NULL)
1265     goto no_pool;
1266
1267   session = state->session;
1268
1269   if (session) {
1270     g_object_ref (session);
1271     /* get a handle to the configuration of the media in the session, this can
1272      * return NULL if this is a new url to manage in this session. */
1273     sessmedia = gst_rtsp_session_get_media (session, uri);
1274   } else {
1275     /* create a session if this fails we probably reached our session limit or
1276      * something. */
1277     if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
1278       goto service_unavailable;
1279
1280     state->session = session;
1281
1282     /* we need a new media configuration in this session */
1283     sessmedia = NULL;
1284   }
1285
1286   /* we have no media, find one and manage it */
1287   if (sessmedia == NULL) {
1288     /* get a handle to the configuration of the media in the session */
1289     if ((media = find_media (client, state))) {
1290       /* manage the media in our session now */
1291       sessmedia = gst_rtsp_session_manage_media (session, uri, media);
1292     }
1293   }
1294
1295   /* if we stil have no media, error */
1296   if (sessmedia == NULL)
1297     goto not_found;
1298
1299   state->sessmedia = sessmedia;
1300   state->media = media = gst_rtsp_session_media_get_media (sessmedia);
1301
1302   /* now get the stream */
1303   stream = gst_rtsp_media_get_stream (media, streamid);
1304   if (stream == NULL)
1305     goto not_found;
1306
1307   state->stream = stream;
1308
1309   /* set blocksize on this stream */
1310   if (!handle_blocksize (media, stream, state->request))
1311     goto invalid_blocksize;
1312
1313   /* update the client transport */
1314   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1315   if (!klass->configure_client_transport (client, state, ct))
1316     goto unsupported_client_transport;
1317
1318   /* set in the session media transport */
1319   trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
1320
1321   /* configure keepalive for this transport */
1322   gst_rtsp_stream_transport_set_keepalive (trans,
1323       (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
1324
1325   /* create and serialize the server transport */
1326   st = make_server_transport (client, state, ct);
1327   trans_str = gst_rtsp_transport_as_text (st);
1328   gst_rtsp_transport_free (st);
1329
1330   /* construct the response now */
1331   code = GST_RTSP_STS_OK;
1332   gst_rtsp_message_init_response (state->response, code,
1333       gst_rtsp_status_as_text (code), state->request);
1334
1335   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_TRANSPORT,
1336       trans_str);
1337   g_free (trans_str);
1338
1339   send_response (client, session, state->response, FALSE);
1340
1341   /* update the state */
1342   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1343   switch (rtspstate) {
1344     case GST_RTSP_STATE_PLAYING:
1345     case GST_RTSP_STATE_RECORDING:
1346     case GST_RTSP_STATE_READY:
1347       /* no state change */
1348       break;
1349     default:
1350       gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1351       break;
1352   }
1353   g_object_unref (session);
1354
1355   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST],
1356       0, state);
1357
1358   return TRUE;
1359
1360   /* ERRORS */
1361 bad_request:
1362   {
1363     GST_ERROR ("client %p: bad request", client);
1364     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1365     return FALSE;
1366   }
1367 not_found:
1368   {
1369     GST_ERROR ("client %p: media not found", client);
1370     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1371     g_object_unref (session);
1372     gst_rtsp_transport_free (ct);
1373     return FALSE;
1374   }
1375 invalid_blocksize:
1376   {
1377     GST_ERROR ("client %p: invalid blocksize", client);
1378     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1379     g_object_unref (session);
1380     gst_rtsp_transport_free (ct);
1381     return FALSE;
1382   }
1383 unsupported_client_transport:
1384   {
1385     GST_ERROR ("client %p: unsupported client transport", client);
1386     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1387     g_object_unref (session);
1388     gst_rtsp_transport_free (ct);
1389     return FALSE;
1390   }
1391 no_transport:
1392   {
1393     GST_ERROR ("client %p: no transport", client);
1394     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1395     return FALSE;
1396   }
1397 unsupported_transports:
1398   {
1399     GST_ERROR ("client %p: unsupported transports", client);
1400     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1401     gst_rtsp_transport_free (ct);
1402     return FALSE;
1403   }
1404 no_pool:
1405   {
1406     GST_ERROR ("client %p: no session pool configured", client);
1407     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
1408     gst_rtsp_transport_free (ct);
1409     return FALSE;
1410   }
1411 service_unavailable:
1412   {
1413     GST_ERROR ("client %p: can't create session", client);
1414     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1415     gst_rtsp_transport_free (ct);
1416     return FALSE;
1417   }
1418 }
1419
1420 static GstSDPMessage *
1421 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
1422 {
1423   GstRTSPClientPrivate *priv = client->priv;
1424   GstSDPMessage *sdp;
1425   GstSDPInfo info;
1426   const gchar *proto;
1427
1428   gst_sdp_message_new (&sdp);
1429
1430   /* some standard things first */
1431   gst_sdp_message_set_version (sdp, "0");
1432
1433   if (priv->is_ipv6)
1434     proto = "IP6";
1435   else
1436     proto = "IP4";
1437
1438   gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
1439       priv->server_ip);
1440
1441   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
1442   gst_sdp_message_set_information (sdp, "rtsp-server");
1443   gst_sdp_message_add_time (sdp, "0", "0", NULL);
1444   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
1445   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
1446   gst_sdp_message_add_attribute (sdp, "control", "*");
1447
1448   info.is_ipv6 = priv->is_ipv6;
1449   info.server_ip = priv->server_ip;
1450
1451   /* create an SDP for the media object */
1452   if (!gst_rtsp_sdp_from_media (sdp, &info, media))
1453     goto no_sdp;
1454
1455   return sdp;
1456
1457   /* ERRORS */
1458 no_sdp:
1459   {
1460     GST_ERROR ("client %p: could not create SDP", client);
1461     gst_sdp_message_free (sdp);
1462     return NULL;
1463   }
1464 }
1465
1466 /* for the describe we must generate an SDP */
1467 static gboolean
1468 handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state)
1469 {
1470   GstRTSPResult res;
1471   GstSDPMessage *sdp;
1472   guint i, str_len;
1473   gchar *str, *content_base;
1474   GstRTSPMedia *media;
1475   GstRTSPClientClass *klass;
1476
1477   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1478
1479   /* check what kind of format is accepted, we don't really do anything with it
1480    * and always return SDP for now. */
1481   for (i = 0; i++;) {
1482     gchar *accept;
1483
1484     res =
1485         gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT,
1486         &accept, i);
1487     if (res == GST_RTSP_ENOTIMPL)
1488       break;
1489
1490     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
1491       break;
1492   }
1493
1494   /* find the media object for the uri */
1495   if (!(media = find_media (client, state)))
1496     goto no_media;
1497
1498   /* create an SDP for the media object on this client */
1499   if (!(sdp = klass->create_sdp (client, media)))
1500     goto no_sdp;
1501
1502   g_object_unref (media);
1503
1504   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1505       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1506
1507   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE,
1508       "application/sdp");
1509
1510   /* content base for some clients that might screw up creating the setup uri */
1511   str = gst_rtsp_url_get_request_uri (state->uri);
1512   str_len = strlen (str);
1513
1514   /* check for trailing '/' and append one */
1515   if (str[str_len - 1] != '/') {
1516     content_base = g_malloc (str_len + 2);
1517     memcpy (content_base, str, str_len);
1518     content_base[str_len] = '/';
1519     content_base[str_len + 1] = '\0';
1520     g_free (str);
1521   } else {
1522     content_base = str;
1523   }
1524
1525   GST_INFO ("adding content-base: %s", content_base);
1526
1527   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE,
1528       content_base);
1529   g_free (content_base);
1530
1531   /* add SDP to the response body */
1532   str = gst_sdp_message_as_text (sdp);
1533   gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str));
1534   gst_sdp_message_free (sdp);
1535
1536   send_response (client, state->session, state->response, FALSE);
1537
1538   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
1539       0, state);
1540
1541   return TRUE;
1542
1543   /* ERRORS */
1544 no_media:
1545   {
1546     GST_ERROR ("client %p: no media", client);
1547     /* error reply is already sent */
1548     return FALSE;
1549   }
1550 no_sdp:
1551   {
1552     GST_ERROR ("client %p: can't create SDP", client);
1553     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1554     g_object_unref (media);
1555     return FALSE;
1556   }
1557 }
1558
1559 static gboolean
1560 handle_options_request (GstRTSPClient * client, GstRTSPClientState * state)
1561 {
1562   GstRTSPMethod options;
1563   gchar *str;
1564
1565   options = GST_RTSP_DESCRIBE |
1566       GST_RTSP_OPTIONS |
1567       GST_RTSP_PAUSE |
1568       GST_RTSP_PLAY |
1569       GST_RTSP_SETUP |
1570       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1571
1572   str = gst_rtsp_options_as_text (options);
1573
1574   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1575       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1576
1577   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str);
1578   g_free (str);
1579
1580   send_response (client, state->session, state->response, FALSE);
1581
1582   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
1583       0, state);
1584
1585   return TRUE;
1586 }
1587
1588 /* remove duplicate and trailing '/' */
1589 static void
1590 sanitize_uri (GstRTSPUrl * uri)
1591 {
1592   gint i, len;
1593   gchar *s, *d;
1594   gboolean have_slash, prev_slash;
1595
1596   s = d = uri->abspath;
1597   len = strlen (uri->abspath);
1598
1599   prev_slash = FALSE;
1600
1601   for (i = 0; i < len; i++) {
1602     have_slash = s[i] == '/';
1603     *d = s[i];
1604     if (!have_slash || !prev_slash)
1605       d++;
1606     prev_slash = have_slash;
1607   }
1608   len = d - uri->abspath;
1609   /* don't remove the first slash if that's the only thing left */
1610   if (len > 1 && *(d - 1) == '/')
1611     d--;
1612   *d = '\0';
1613 }
1614
1615 static void
1616 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
1617 {
1618   GstRTSPClientPrivate *priv = client->priv;
1619
1620   GST_INFO ("client %p: session %p finished", client, session);
1621
1622   /* unlink all media managed in this session */
1623   client_unlink_session (client, session);
1624
1625   /* remove the session */
1626   if (!(priv->sessions = g_list_remove (priv->sessions, session))) {
1627     GST_INFO ("client %p: all sessions finalized, close the connection",
1628         client);
1629     close_connection (client);
1630   }
1631 }
1632
1633 static void
1634 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
1635 {
1636   GstRTSPClientPrivate *priv = client->priv;
1637   GList *walk;
1638
1639   for (walk = priv->sessions; walk; walk = g_list_next (walk)) {
1640     GstRTSPSession *msession = (GstRTSPSession *) walk->data;
1641
1642     /* we already know about this session */
1643     if (msession == session)
1644       return;
1645   }
1646
1647   GST_INFO ("watching session %p", session);
1648
1649   g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
1650       client);
1651   priv->sessions = g_list_prepend (priv->sessions, session);
1652
1653   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
1654       session);
1655 }
1656
1657 static void
1658 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
1659 {
1660   GstRTSPClientPrivate *priv = client->priv;
1661   GstRTSPMethod method;
1662   const gchar *uristr;
1663   GstRTSPUrl *uri = NULL;
1664   GstRTSPVersion version;
1665   GstRTSPResult res;
1666   GstRTSPSession *session = NULL;
1667   GstRTSPClientState state = { NULL };
1668   GstRTSPMessage response = { 0 };
1669   gchar *sessid;
1670
1671   state.request = request;
1672   state.response = &response;
1673
1674   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1675     gst_rtsp_message_dump (request);
1676   }
1677
1678   GST_INFO ("client %p: received a request", client);
1679
1680   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
1681
1682   /* we can only handle 1.0 requests */
1683   if (version != GST_RTSP_VERSION_1_0)
1684     goto not_supported;
1685
1686   state.method = method;
1687
1688   /* we always try to parse the url first */
1689   if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK)
1690     goto bad_request;
1691
1692   /* get the session if there is any */
1693   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
1694   if (res == GST_RTSP_OK) {
1695     if (priv->session_pool == NULL)
1696       goto no_pool;
1697
1698     /* we had a session in the request, find it again */
1699     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
1700       goto session_not_found;
1701
1702     /* we add the session to the client list of watched sessions. When a session
1703      * disappears because it times out, we will be notified. If all sessions are
1704      * gone, we will close the connection */
1705     client_watch_session (client, session);
1706   }
1707
1708   /* sanitize the uri */
1709   sanitize_uri (uri);
1710   state.uri = uri;
1711   state.session = session;
1712
1713   if (priv->auth) {
1714     if (!gst_rtsp_auth_check (priv->auth, client, 0, &state))
1715       goto not_authorized;
1716   }
1717
1718   /* now see what is asked and dispatch to a dedicated handler */
1719   switch (method) {
1720     case GST_RTSP_OPTIONS:
1721       handle_options_request (client, &state);
1722       break;
1723     case GST_RTSP_DESCRIBE:
1724       handle_describe_request (client, &state);
1725       break;
1726     case GST_RTSP_SETUP:
1727       handle_setup_request (client, &state);
1728       break;
1729     case GST_RTSP_PLAY:
1730       handle_play_request (client, &state);
1731       break;
1732     case GST_RTSP_PAUSE:
1733       handle_pause_request (client, &state);
1734       break;
1735     case GST_RTSP_TEARDOWN:
1736       handle_teardown_request (client, &state);
1737       break;
1738     case GST_RTSP_SET_PARAMETER:
1739       handle_set_param_request (client, &state);
1740       break;
1741     case GST_RTSP_GET_PARAMETER:
1742       handle_get_param_request (client, &state);
1743       break;
1744     case GST_RTSP_ANNOUNCE:
1745     case GST_RTSP_RECORD:
1746     case GST_RTSP_REDIRECT:
1747       goto not_implemented;
1748     case GST_RTSP_INVALID:
1749     default:
1750       goto bad_request;
1751   }
1752
1753 done:
1754   if (session)
1755     g_object_unref (session);
1756   if (uri)
1757     gst_rtsp_url_free (uri);
1758   return;
1759
1760   /* ERRORS */
1761 not_supported:
1762   {
1763     GST_ERROR ("client %p: version %d not supported", client, version);
1764     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
1765         &state);
1766     goto done;
1767   }
1768 bad_request:
1769   {
1770     GST_ERROR ("client %p: bad request", client);
1771     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1772     goto done;
1773   }
1774 no_pool:
1775   {
1776     GST_ERROR ("client %p: no pool configured", client);
1777     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1778     goto done;
1779   }
1780 session_not_found:
1781   {
1782     GST_ERROR ("client %p: session not found", client);
1783     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1784     goto done;
1785   }
1786 not_authorized:
1787   {
1788     GST_ERROR ("client %p: not allowed", client);
1789     handle_unauthorized_request (client, priv->auth, &state);
1790     goto done;
1791   }
1792 not_implemented:
1793   {
1794     GST_ERROR ("client %p: method %d not implemented", client, method);
1795     send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state);
1796     goto done;
1797   }
1798 }
1799
1800 static void
1801 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
1802 {
1803   GstRTSPClientPrivate *priv = client->priv;
1804   GstRTSPResult res;
1805   guint8 channel;
1806   GList *walk;
1807   guint8 *data;
1808   guint size;
1809   GstBuffer *buffer;
1810   gboolean handled;
1811
1812   /* find the stream for this message */
1813   res = gst_rtsp_message_parse_data (message, &channel);
1814   if (res != GST_RTSP_OK)
1815     return;
1816
1817   gst_rtsp_message_steal_body (message, &data, &size);
1818
1819   buffer = gst_buffer_new_wrapped (data, size);
1820
1821   handled = FALSE;
1822   for (walk = priv->transports; walk; walk = g_list_next (walk)) {
1823     GstRTSPStreamTransport *trans;
1824     GstRTSPStream *stream;
1825     const GstRTSPTransport *tr;
1826
1827     trans = walk->data;
1828
1829     tr = gst_rtsp_stream_transport_get_transport (trans);
1830     stream = gst_rtsp_stream_transport_get_stream (trans);
1831
1832     /* check for TCP transport */
1833     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1834       /* dispatch to the stream based on the channel number */
1835       if (tr->interleaved.min == channel) {
1836         gst_rtsp_stream_recv_rtp (stream, buffer);
1837         handled = TRUE;
1838         break;
1839       } else if (tr->interleaved.max == channel) {
1840         gst_rtsp_stream_recv_rtcp (stream, buffer);
1841         handled = TRUE;
1842         break;
1843       }
1844     }
1845   }
1846   if (!handled)
1847     gst_buffer_unref (buffer);
1848 }
1849
1850 /**
1851  * gst_rtsp_client_set_session_pool:
1852  * @client: a #GstRTSPClient
1853  * @pool: a #GstRTSPSessionPool
1854  *
1855  * Set @pool as the sessionpool for @client which it will use to find
1856  * or allocate sessions. the sessionpool is usually inherited from the server
1857  * that created the client but can be overridden later.
1858  */
1859 void
1860 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
1861     GstRTSPSessionPool * pool)
1862 {
1863   GstRTSPSessionPool *old;
1864   GstRTSPClientPrivate *priv;
1865
1866   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1867
1868   priv = client->priv;
1869
1870   if (pool)
1871     g_object_ref (pool);
1872
1873   g_mutex_lock (&priv->lock);
1874   old = priv->session_pool;
1875   priv->session_pool = pool;
1876   g_mutex_unlock (&priv->lock);
1877
1878   if (old)
1879     g_object_unref (old);
1880 }
1881
1882 /**
1883  * gst_rtsp_client_get_session_pool:
1884  * @client: a #GstRTSPClient
1885  *
1886  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1887  *
1888  * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage.
1889  */
1890 GstRTSPSessionPool *
1891 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
1892 {
1893   GstRTSPClientPrivate *priv;
1894   GstRTSPSessionPool *result;
1895
1896   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1897
1898   priv = client->priv;
1899
1900   g_mutex_lock (&priv->lock);
1901   if ((result = priv->session_pool))
1902     g_object_ref (result);
1903   g_mutex_unlock (&priv->lock);
1904
1905   return result;
1906 }
1907
1908 /**
1909  * gst_rtsp_client_set_mount_points:
1910  * @client: a #GstRTSPClient
1911  * @mounts: a #GstRTSPMountPoints
1912  *
1913  * Set @mounts as the mount points for @client which it will use to map urls
1914  * to media streams. These mount points are usually inherited from the server that
1915  * created the client but can be overriden later.
1916  */
1917 void
1918 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
1919     GstRTSPMountPoints * mounts)
1920 {
1921   GstRTSPClientPrivate *priv;
1922   GstRTSPMountPoints *old;
1923
1924   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1925
1926   priv = client->priv;
1927
1928   if (mounts)
1929     g_object_ref (mounts);
1930
1931   g_mutex_lock (&priv->lock);
1932   old = priv->mount_points;
1933   priv->mount_points = mounts;
1934   g_mutex_unlock (&priv->lock);
1935
1936   if (old)
1937     g_object_unref (old);
1938 }
1939
1940 /**
1941  * gst_rtsp_client_get_mount_points:
1942  * @client: a #GstRTSPClient
1943  *
1944  * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
1945  *
1946  * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage.
1947  */
1948 GstRTSPMountPoints *
1949 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
1950 {
1951   GstRTSPClientPrivate *priv;
1952   GstRTSPMountPoints *result;
1953
1954   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1955
1956   priv = client->priv;
1957
1958   g_mutex_lock (&priv->lock);
1959   if ((result = priv->mount_points))
1960     g_object_ref (result);
1961   g_mutex_unlock (&priv->lock);
1962
1963   return result;
1964 }
1965
1966 /**
1967  * gst_rtsp_client_set_use_client_settings:
1968  * @client: a #GstRTSPClient
1969  * @use_client_settings: whether to use client settings for multicast
1970  *
1971  * Use client transport settings (destination and ttl) for multicast.
1972  * When @use_client_settings is %FALSE, the server settings will be
1973  * used.
1974  */
1975 void
1976 gst_rtsp_client_set_use_client_settings (GstRTSPClient * client,
1977     gboolean use_client_settings)
1978 {
1979   GstRTSPClientPrivate *priv;
1980
1981   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1982
1983   priv = client->priv;
1984
1985   g_mutex_lock (&priv->lock);
1986   priv->use_client_settings = use_client_settings;
1987   g_mutex_unlock (&priv->lock);
1988 }
1989
1990 /**
1991  * gst_rtsp_client_get_use_client_settings:
1992  * @client: a #GstRTSPClient
1993  *
1994  * Check if client transport settings (destination and ttl) for multicast
1995  * will be used.
1996  */
1997 gboolean
1998 gst_rtsp_client_get_use_client_settings (GstRTSPClient * client)
1999 {
2000   GstRTSPClientPrivate *priv;
2001   gboolean res;
2002
2003   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
2004
2005   priv = client->priv;
2006
2007   g_mutex_lock (&priv->lock);
2008   res = priv->use_client_settings;
2009   g_mutex_unlock (&priv->lock);
2010
2011   return res;
2012 }
2013
2014 /**
2015  * gst_rtsp_client_set_auth:
2016  * @client: a #GstRTSPClient
2017  * @auth: a #GstRTSPAuth
2018  *
2019  * configure @auth to be used as the authentication manager of @client.
2020  */
2021 void
2022 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
2023 {
2024   GstRTSPClientPrivate *priv;
2025   GstRTSPAuth *old;
2026
2027   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2028
2029   priv = client->priv;
2030
2031   if (auth)
2032     g_object_ref (auth);
2033
2034   g_mutex_lock (&priv->lock);
2035   old = priv->auth;
2036   priv->auth = auth;
2037   g_mutex_unlock (&priv->lock);
2038
2039   if (old)
2040     g_object_unref (old);
2041 }
2042
2043
2044 /**
2045  * gst_rtsp_client_get_auth:
2046  * @client: a #GstRTSPClient
2047  *
2048  * Get the #GstRTSPAuth used as the authentication manager of @client.
2049  *
2050  * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after
2051  * usage.
2052  */
2053 GstRTSPAuth *
2054 gst_rtsp_client_get_auth (GstRTSPClient * client)
2055 {
2056   GstRTSPClientPrivate *priv;
2057   GstRTSPAuth *result;
2058
2059   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2060
2061   priv = client->priv;
2062
2063   g_mutex_lock (&priv->lock);
2064   if ((result = priv->auth))
2065     g_object_ref (result);
2066   g_mutex_unlock (&priv->lock);
2067
2068   return result;
2069 }
2070
2071 /**
2072  * gst_rtsp_client_get_uri:
2073  * @client: a #GstRTSPClient
2074  *
2075  * Get the #GstRTSPUrl of @client.
2076  *
2077  * Returns: (transfer full): the #GstRTSPUrl of @client. Free with
2078  * gst_rtsp_url_free () after usage.
2079  */
2080 GstRTSPUrl *
2081 gst_rtsp_client_get_uri (GstRTSPClient * client)
2082 {
2083   GstRTSPClientPrivate *priv;
2084   GstRTSPUrl *result = NULL;
2085
2086   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2087
2088   priv = client->priv;
2089
2090   g_mutex_lock (&priv->lock);
2091   if (priv->uri != NULL)
2092     result = gst_rtsp_url_copy (priv->uri);
2093   g_mutex_unlock (&priv->lock);
2094
2095   return result;
2096 }
2097
2098 /**
2099  * gst_rtsp_client_set_connection:
2100  * @client: a #GstRTSPClient
2101  * @conn: (transfer full): a #GstRTSPConnection
2102  *
2103  * Set the #GstRTSPConnection of @client. This function takes ownership of
2104  * @conn.
2105  *
2106  * Returns: %TRUE on success.
2107  */
2108 gboolean
2109 gst_rtsp_client_set_connection (GstRTSPClient * client,
2110     GstRTSPConnection * conn)
2111 {
2112   GstRTSPClientPrivate *priv;
2113   GSocket *read_socket;
2114   GSocketAddress *address;
2115   GstRTSPUrl *url;
2116   GError *error = NULL;
2117
2118   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
2119   g_return_val_if_fail (conn != NULL, FALSE);
2120
2121   priv = client->priv;
2122
2123   read_socket = gst_rtsp_connection_get_read_socket (conn);
2124
2125   if (!(address = g_socket_get_local_address (read_socket, &error)))
2126     goto no_address;
2127
2128   g_free (priv->server_ip);
2129   /* keep the original ip that the client connected to */
2130   if (G_IS_INET_SOCKET_ADDRESS (address)) {
2131     GInetAddress *iaddr;
2132
2133     iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
2134
2135     /* socket might be ipv6 but adress still ipv4 */
2136     priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6;
2137     priv->server_ip = g_inet_address_to_string (iaddr);
2138     g_object_unref (address);
2139   } else {
2140     priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
2141     priv->server_ip = g_strdup ("unknown");
2142   }
2143
2144   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
2145       priv->server_ip, priv->is_ipv6);
2146
2147   url = gst_rtsp_connection_get_url (conn);
2148   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
2149
2150   priv->connection = conn;
2151
2152   return TRUE;
2153
2154   /* ERRORS */
2155 no_address:
2156   {
2157     GST_ERROR ("could not get remote address %s", error->message);
2158     g_error_free (error);
2159     return FALSE;
2160   }
2161 }
2162
2163 /**
2164  * gst_rtsp_client_get_connection:
2165  * @client: a #GstRTSPClient
2166  *
2167  * Get the #GstRTSPConnection of @client.
2168  *
2169  * Returns: (transfer none): the #GstRTSPConnection of @client.
2170  * The connection object returned remains valid until the client is freed.
2171  */
2172 GstRTSPConnection *
2173 gst_rtsp_client_get_connection (GstRTSPClient * client)
2174 {
2175   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2176
2177   return client->priv->connection;
2178 }
2179
2180 /**
2181  * gst_rtsp_client_set_send_func:
2182  * @client: a #GstRTSPClient
2183  * @func: a #GstRTSPClientSendFunc
2184  * @user_data: user data passed to @func
2185  * @notify: called when @user_data is no longer in use
2186  *
2187  * Set @func as the callback that will be called when a new message needs to be
2188  * sent to the client. @user_data is passed to @func and @notify is called when
2189  * @user_data is no longer in use.
2190  */
2191 void
2192 gst_rtsp_client_set_send_func (GstRTSPClient * client,
2193     GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
2194 {
2195   GstRTSPClientPrivate *priv;
2196   GDestroyNotify old_notify;
2197   gpointer old_data;
2198
2199   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2200
2201   priv = client->priv;
2202
2203   g_mutex_lock (&priv->send_lock);
2204   priv->send_func = func;
2205   old_notify = priv->send_notify;
2206   old_data = priv->send_data;
2207   priv->send_notify = notify;
2208   priv->send_data = user_data;
2209   g_mutex_unlock (&priv->send_lock);
2210
2211   if (old_notify)
2212     old_notify (old_data);
2213 }
2214
2215 /**
2216  * gst_rtsp_client_handle_message:
2217  * @client: a #GstRTSPClient
2218  * @message: an #GstRTSPMessage
2219  *
2220  * Let the client handle @message.
2221  *
2222  * Returns: a #GstRTSPResult.
2223  */
2224 GstRTSPResult
2225 gst_rtsp_client_handle_message (GstRTSPClient * client,
2226     GstRTSPMessage * message)
2227 {
2228   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
2229   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2230
2231   switch (message->type) {
2232     case GST_RTSP_MESSAGE_REQUEST:
2233       handle_request (client, message);
2234       break;
2235     case GST_RTSP_MESSAGE_RESPONSE:
2236       break;
2237     case GST_RTSP_MESSAGE_DATA:
2238       handle_data (client, message);
2239       break;
2240     default:
2241       break;
2242   }
2243   return GST_RTSP_OK;
2244 }
2245
2246 static GstRTSPResult
2247 do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
2248     gboolean close, gpointer user_data)
2249 {
2250   GstRTSPClientPrivate *priv = client->priv;
2251
2252   /* send the response and store the seq number so we can wait until it's
2253    * written to the client to close the connection */
2254   return gst_rtsp_watch_send_message (priv->watch, message, close ?
2255       &priv->close_seq : NULL);
2256 }
2257
2258 static GstRTSPResult
2259 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
2260     gpointer user_data)
2261 {
2262   return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
2263 }
2264
2265 static GstRTSPResult
2266 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
2267 {
2268   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2269   GstRTSPClientPrivate *priv = client->priv;
2270
2271   if (priv->close_seq && priv->close_seq == cseq) {
2272     priv->close_seq = 0;
2273     close_connection (client);
2274   }
2275
2276   return GST_RTSP_OK;
2277 }
2278
2279 static GstRTSPResult
2280 closed (GstRTSPWatch * watch, gpointer user_data)
2281 {
2282   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2283   GstRTSPClientPrivate *priv = client->priv;
2284   const gchar *tunnelid;
2285
2286   GST_INFO ("client %p: connection closed", client);
2287
2288   if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
2289     g_mutex_lock (&tunnels_lock);
2290     /* remove from tunnelids */
2291     g_hash_table_remove (tunnels, tunnelid);
2292     g_mutex_unlock (&tunnels_lock);
2293   }
2294
2295   gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
2296
2297   return GST_RTSP_OK;
2298 }
2299
2300 static GstRTSPResult
2301 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
2302 {
2303   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2304   gchar *str;
2305
2306   str = gst_rtsp_strresult (result);
2307   GST_INFO ("client %p: received an error %s", client, str);
2308   g_free (str);
2309
2310   return GST_RTSP_OK;
2311 }
2312
2313 static GstRTSPResult
2314 error_full (GstRTSPWatch * watch, GstRTSPResult result,
2315     GstRTSPMessage * message, guint id, gpointer user_data)
2316 {
2317   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2318   gchar *str;
2319
2320   str = gst_rtsp_strresult (result);
2321   GST_INFO
2322       ("client %p: error when handling message %p with id %d: %s",
2323       client, message, id, str);
2324   g_free (str);
2325
2326   return GST_RTSP_OK;
2327 }
2328
2329 static gboolean
2330 remember_tunnel (GstRTSPClient * client)
2331 {
2332   GstRTSPClientPrivate *priv = client->priv;
2333   const gchar *tunnelid;
2334
2335   /* store client in the pending tunnels */
2336   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
2337   if (tunnelid == NULL)
2338     goto no_tunnelid;
2339
2340   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
2341
2342   /* we can't have two clients connecting with the same tunnelid */
2343   g_mutex_lock (&tunnels_lock);
2344   if (g_hash_table_lookup (tunnels, tunnelid))
2345     goto tunnel_existed;
2346
2347   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
2348   g_mutex_unlock (&tunnels_lock);
2349
2350   return TRUE;
2351
2352   /* ERRORS */
2353 no_tunnelid:
2354   {
2355     GST_ERROR ("client %p: no tunnelid provided", client);
2356     return FALSE;
2357   }
2358 tunnel_existed:
2359   {
2360     g_mutex_unlock (&tunnels_lock);
2361     GST_ERROR ("client %p: tunnel session %s already existed", client,
2362         tunnelid);
2363     return FALSE;
2364   }
2365 }
2366
2367 static GstRTSPStatusCode
2368 tunnel_start (GstRTSPWatch * watch, gpointer user_data)
2369 {
2370   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2371   GstRTSPClientPrivate *priv = client->priv;
2372
2373   GST_INFO ("client %p: tunnel start (connection %p)", client,
2374       priv->connection);
2375
2376   if (!remember_tunnel (client))
2377     goto tunnel_error;
2378
2379   return GST_RTSP_STS_OK;
2380
2381   /* ERRORS */
2382 tunnel_error:
2383   {
2384     GST_ERROR ("client %p: error starting tunnel", client);
2385     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2386   }
2387 }
2388
2389 static GstRTSPResult
2390 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
2391 {
2392   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2393   GstRTSPClientPrivate *priv = client->priv;
2394
2395   GST_WARNING ("client %p: tunnel lost (connection %p)", client,
2396       priv->connection);
2397
2398   /* ignore error, it'll only be a problem when the client does a POST again */
2399   remember_tunnel (client);
2400
2401   return GST_RTSP_OK;
2402 }
2403
2404 static GstRTSPResult
2405 tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
2406 {
2407   const gchar *tunnelid;
2408   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2409   GstRTSPClientPrivate *priv = client->priv;
2410   GstRTSPClient *oclient;
2411   GstRTSPClientPrivate *opriv;
2412
2413   GST_INFO ("client %p: tunnel complete", client);
2414
2415   /* find previous tunnel */
2416   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
2417   if (tunnelid == NULL)
2418     goto no_tunnelid;
2419
2420   g_mutex_lock (&tunnels_lock);
2421   if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
2422     goto no_tunnel;
2423
2424   /* remove the old client from the table. ref before because removing it will
2425    * remove the ref to it. */
2426   g_object_ref (oclient);
2427   g_hash_table_remove (tunnels, tunnelid);
2428
2429   opriv = oclient->priv;
2430
2431   if (opriv->watch == NULL)
2432     goto tunnel_closed;
2433   g_mutex_unlock (&tunnels_lock);
2434
2435   GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
2436       opriv->connection, priv->connection);
2437
2438   /* merge the tunnels into the first client */
2439   gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
2440   gst_rtsp_watch_reset (opriv->watch);
2441   g_object_unref (oclient);
2442
2443   return GST_RTSP_OK;
2444
2445   /* ERRORS */
2446 no_tunnelid:
2447   {
2448     GST_ERROR ("client %p: no tunnelid provided", client);
2449     return GST_RTSP_ERROR;
2450   }
2451 no_tunnel:
2452   {
2453     g_mutex_unlock (&tunnels_lock);
2454     GST_ERROR ("client %p: tunnel session %s not found", client, tunnelid);
2455     return GST_RTSP_ERROR;
2456   }
2457 tunnel_closed:
2458   {
2459     g_mutex_unlock (&tunnels_lock);
2460     GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
2461     g_object_unref (oclient);
2462     return GST_RTSP_ERROR;
2463   }
2464 }
2465
2466 static GstRTSPWatchFuncs watch_funcs = {
2467   message_received,
2468   message_sent,
2469   closed,
2470   error,
2471   tunnel_start,
2472   tunnel_complete,
2473   error_full,
2474   tunnel_lost
2475 };
2476
2477 static void
2478 client_watch_notify (GstRTSPClient * client)
2479 {
2480   GstRTSPClientPrivate *priv = client->priv;
2481
2482   GST_INFO ("client %p: watch destroyed", client);
2483   priv->watch = NULL;
2484   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
2485   g_object_unref (client);
2486 }
2487
2488 /**
2489  * gst_rtsp_client_attach:
2490  * @client: a #GstRTSPClient
2491  * @context: (allow-none): a #GMainContext
2492  *
2493  * Attaches @client to @context. When the mainloop for @context is run, the
2494  * client will be dispatched. When @context is NULL, the default context will be
2495  * used).
2496  *
2497  * This function should be called when the client properties and urls are fully
2498  * configured and the client is ready to start.
2499  *
2500  * Returns: the ID (greater than 0) for the source within the GMainContext.
2501  */
2502 guint
2503 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
2504 {
2505   GstRTSPClientPrivate *priv;
2506   guint res;
2507
2508   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
2509   priv = client->priv;
2510   g_return_val_if_fail (priv->watch == NULL, 0);
2511
2512   /* create watch for the connection and attach */
2513   priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
2514       g_object_ref (client), (GDestroyNotify) client_watch_notify);
2515   gst_rtsp_client_set_send_func (client, do_send_message, priv->watch,
2516       (GDestroyNotify) gst_rtsp_watch_unref);
2517
2518   /* FIXME make this configurable. We don't want to do this yet because it will
2519    * be superceeded by a cache object later */
2520   gst_rtsp_watch_set_send_backlog (priv->watch, 0, 100);
2521
2522   GST_INFO ("attaching to context %p", context);
2523   res = gst_rtsp_watch_attach (priv->watch, context);
2524
2525   return res;
2526 }