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