49ad173c14a50417a55f9241da5d9fd403e8947f
[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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <netdb.h>
29 #include <sys/socket.h>
30 #include <sys/wait.h>
31 #include <fcntl.h>
32 #include <arpa/inet.h>
33 #include <sys/ioctl.h>
34
35 #include "rtsp-client.h"
36 #include "rtsp-sdp.h"
37 #include "rtsp-params.h"
38
39 static GMutex tunnels_lock;
40 static GHashTable *tunnels;
41
42 enum
43 {
44   PROP_0,
45   PROP_SESSION_POOL,
46   PROP_MEDIA_MAPPING,
47   PROP_LAST
48 };
49
50 enum
51 {
52   SIGNAL_CLOSED,
53   SIGNAL_LAST
54 };
55
56 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
57 #define GST_CAT_DEFAULT rtsp_client_debug
58
59 static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 };
60
61 static void gst_rtsp_client_get_property (GObject * object, guint propid,
62     GValue * value, GParamSpec * pspec);
63 static void gst_rtsp_client_set_property (GObject * object, guint propid,
64     const GValue * value, GParamSpec * pspec);
65 static void gst_rtsp_client_finalize (GObject * obj);
66
67 static void client_session_finalized (GstRTSPClient * client,
68     GstRTSPSession * session);
69 static void unlink_session_streams (GstRTSPClient * client,
70     GstRTSPSession * session, GstRTSPSessionMedia * media);
71
72 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
73
74 static void
75 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
76 {
77   GObjectClass *gobject_class;
78
79   gobject_class = G_OBJECT_CLASS (klass);
80
81   gobject_class->get_property = gst_rtsp_client_get_property;
82   gobject_class->set_property = gst_rtsp_client_set_property;
83   gobject_class->finalize = gst_rtsp_client_finalize;
84
85   g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
86       g_param_spec_object ("session-pool", "Session Pool",
87           "The session pool to use for client session",
88           GST_TYPE_RTSP_SESSION_POOL,
89           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
90
91   g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING,
92       g_param_spec_object ("media-mapping", "Media Mapping",
93           "The media mapping to use for client session",
94           GST_TYPE_RTSP_MEDIA_MAPPING,
95           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
96
97   gst_rtsp_client_signals[SIGNAL_CLOSED] =
98       g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
99       G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL,
100       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
101
102   tunnels =
103       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
104   g_mutex_init (&tunnels_lock);
105
106   GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
107 }
108
109 static void
110 gst_rtsp_client_init (GstRTSPClient * client)
111 {
112 }
113
114 static void
115 client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
116 {
117   /* unlink all media managed in this session */
118   while (g_list_length (session->medias) > 0) {
119     GstRTSPSessionMedia *media = g_list_first (session->medias)->data;
120
121     gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
122     unlink_session_streams (client, session, media);
123     /* unmanage the media in the session. this will modify session->medias */
124     gst_rtsp_session_release_media (session, media);
125   }
126 }
127
128 static void
129 client_cleanup_sessions (GstRTSPClient * client)
130 {
131   GList *sessions;
132
133   /* remove weak-ref from sessions */
134   for (sessions = client->sessions; sessions; sessions = g_list_next (sessions)) {
135     GstRTSPSession *session = (GstRTSPSession *) sessions->data;
136     g_object_weak_unref (G_OBJECT (session),
137         (GWeakNotify) client_session_finalized, client);
138     client_unlink_session (client, session);
139   }
140   g_list_free (client->sessions);
141   client->sessions = NULL;
142 }
143
144 /* A client is finalized when the connection is broken */
145 static void
146 gst_rtsp_client_finalize (GObject * obj)
147 {
148   GstRTSPClient *client = GST_RTSP_CLIENT (obj);
149
150   GST_INFO ("finalize client %p", client);
151
152   client_cleanup_sessions (client);
153
154   gst_rtsp_connection_free (client->connection);
155   if (client->session_pool)
156     g_object_unref (client->session_pool);
157   if (client->media_mapping)
158     g_object_unref (client->media_mapping);
159   if (client->auth)
160     g_object_unref (client->auth);
161
162   if (client->uri)
163     gst_rtsp_url_free (client->uri);
164   if (client->media)
165     g_object_unref (client->media);
166
167   g_free (client->server_ip);
168
169   G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
170 }
171
172 static void
173 gst_rtsp_client_get_property (GObject * object, guint propid,
174     GValue * value, GParamSpec * pspec)
175 {
176   GstRTSPClient *client = GST_RTSP_CLIENT (object);
177
178   switch (propid) {
179     case PROP_SESSION_POOL:
180       g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
181       break;
182     case PROP_MEDIA_MAPPING:
183       g_value_take_object (value, gst_rtsp_client_get_media_mapping (client));
184       break;
185     default:
186       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
187   }
188 }
189
190 static void
191 gst_rtsp_client_set_property (GObject * object, guint propid,
192     const GValue * value, GParamSpec * pspec)
193 {
194   GstRTSPClient *client = GST_RTSP_CLIENT (object);
195
196   switch (propid) {
197     case PROP_SESSION_POOL:
198       gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
199       break;
200     case PROP_MEDIA_MAPPING:
201       gst_rtsp_client_set_media_mapping (client, g_value_get_object (value));
202       break;
203     default:
204       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
205   }
206 }
207
208 /**
209  * gst_rtsp_client_new:
210  *
211  * Create a new #GstRTSPClient instance.
212  *
213  * Returns: a new #GstRTSPClient
214  */
215 GstRTSPClient *
216 gst_rtsp_client_new (void)
217 {
218   GstRTSPClient *result;
219
220   result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
221
222   return result;
223 }
224
225 static void
226 send_response (GstRTSPClient * client, GstRTSPSession * session,
227     GstRTSPMessage * response)
228 {
229   gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER,
230       "GStreamer RTSP server");
231
232   /* remove any previous header */
233   gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1);
234
235   /* add the new session header for new session ids */
236   if (session) {
237     gchar *str;
238
239     if (session->timeout != 60)
240       str =
241           g_strdup_printf ("%s; timeout=%d", session->sessionid,
242           session->timeout);
243     else
244       str = g_strdup (session->sessionid);
245
246     gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str);
247   }
248
249   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
250     gst_rtsp_message_dump (response);
251   }
252
253   gst_rtsp_watch_send_message (client->watch, response, NULL);
254   gst_rtsp_message_unset (response);
255 }
256
257 static void
258 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
259     GstRTSPClientState * state)
260 {
261   gst_rtsp_message_init_response (state->response, code,
262       gst_rtsp_status_as_text (code), state->request);
263
264   send_response (client, NULL, state->response);
265 }
266
267 static void
268 handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth,
269     GstRTSPClientState * state)
270 {
271   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_UNAUTHORIZED,
272       gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request);
273
274   if (auth) {
275     /* and let the authentication manager setup the auth tokens */
276     gst_rtsp_auth_setup_auth (auth, client, 0, state);
277   }
278
279   send_response (client, state->session, state->response);
280 }
281
282
283 static gboolean
284 compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2)
285 {
286   if (uri1 == NULL || uri2 == NULL)
287     return FALSE;
288
289   if (strcmp (uri1->abspath, uri2->abspath))
290     return FALSE;
291
292   return TRUE;
293 }
294
295 /* this function is called to initially find the media for the DESCRIBE request
296  * but is cached for when the same client (without breaking the connection) is
297  * doing a setup for the exact same url. */
298 static GstRTSPMedia *
299 find_media (GstRTSPClient * client, GstRTSPClientState * state)
300 {
301   GstRTSPMediaFactory *factory;
302   GstRTSPMedia *media;
303   GstRTSPAuth *auth;
304
305   if (!compare_uri (client->uri, state->uri)) {
306     /* remove any previously cached values before we try to construct a new
307      * media for uri */
308     if (client->uri)
309       gst_rtsp_url_free (client->uri);
310     client->uri = NULL;
311     if (client->media)
312       g_object_unref (client->media);
313     client->media = NULL;
314
315     if (!client->media_mapping)
316       goto no_mapping;
317
318     /* find the factory for the uri first */
319     if (!(factory =
320             gst_rtsp_media_mapping_find_factory (client->media_mapping,
321                 state->uri)))
322       goto no_factory;
323
324     state->factory = factory;
325
326     /* check if we have access to the factory */
327     if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
328       if (!gst_rtsp_auth_check (auth, client, 0, state))
329         goto not_allowed;
330
331       g_object_unref (auth);
332     }
333
334     /* prepare the media and add it to the pipeline */
335     if (!(media = gst_rtsp_media_factory_construct (factory, state->uri)))
336       goto no_media;
337
338     g_object_unref (factory);
339     factory = NULL;
340     state->factory = NULL;
341
342     /* set ipv6 on the media before preparing */
343     media->is_ipv6 = client->is_ipv6;
344     state->media = media;
345
346     /* prepare the media */
347     if (!(gst_rtsp_media_prepare (media)))
348       goto no_prepare;
349
350     /* now keep track of the uri and the media */
351     client->uri = gst_rtsp_url_copy (state->uri);
352     client->media = media;
353   } else {
354     /* we have seen this uri before, used cached media */
355     media = client->media;
356     state->media = media;
357     GST_INFO ("reusing cached media %p", media);
358   }
359
360   if (media)
361     g_object_ref (media);
362
363   return media;
364
365   /* ERRORS */
366 no_mapping:
367   {
368     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
369     return NULL;
370   }
371 no_factory:
372   {
373     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
374     return NULL;
375   }
376 not_allowed:
377   {
378     handle_unauthorized_request (client, auth, state);
379     g_object_unref (factory);
380     g_object_unref (auth);
381     return NULL;
382   }
383 no_media:
384   {
385     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
386     g_object_unref (factory);
387     return NULL;
388   }
389 no_prepare:
390   {
391     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
392     g_object_unref (media);
393     return NULL;
394   }
395 }
396
397 static gboolean
398 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
399 {
400   GstRTSPMessage message = { 0 };
401   GstMapInfo map_info;
402   guint8 *data;
403   guint usize;
404
405   gst_rtsp_message_init_data (&message, channel);
406
407   if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ))
408     return FALSE;
409
410   gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
411
412   /* FIXME, client->watch could have been finalized here, we need to keep an
413    * extra refcount to the watch.  */
414   gst_rtsp_watch_send_message (client->watch, &message, NULL);
415
416   gst_rtsp_message_steal_body (&message, &data, &usize);
417   gst_buffer_unmap (buffer, &map_info);
418
419   gst_rtsp_message_unset (&message);
420
421   return TRUE;
422 }
423
424 static void
425 link_stream (GstRTSPClient * client, GstRTSPSession * session,
426     GstRTSPSessionStream * stream)
427 {
428   GST_DEBUG ("client %p: linking stream %p", client, stream);
429   gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data,
430       (GstRTSPSendFunc) do_send_data, client, NULL);
431   client->streams = g_list_prepend (client->streams, stream);
432   /* make sure our session can't expire */
433   gst_rtsp_session_prevent_expire (session);
434 }
435
436 static void
437 unlink_stream (GstRTSPClient * client, GstRTSPSession * session,
438     GstRTSPSessionStream * stream)
439 {
440   GST_DEBUG ("client %p: unlinking stream %p", client, stream);
441   gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL);
442   client->streams = g_list_remove (client->streams, stream);
443   /* our session can now expire */
444   gst_rtsp_session_allow_expire (session);
445 }
446
447 static void
448 unlink_session_streams (GstRTSPClient * client, GstRTSPSession * session,
449     GstRTSPSessionMedia * media)
450 {
451   guint n_streams, i;
452
453   n_streams = gst_rtsp_media_n_streams (media->media);
454   for (i = 0; i < n_streams; i++) {
455     GstRTSPSessionStream *sstream;
456     GstRTSPTransport *tr;
457
458     /* get the stream as configured in the session */
459     sstream = gst_rtsp_session_media_get_stream (media, i);
460     /* get the transport, if there is no transport configured, skip this stream */
461     if (!(tr = sstream->trans.transport))
462       continue;
463
464     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
465       /* for TCP, unlink the stream from the TCP connection of the client */
466       unlink_stream (client, session, sstream);
467     }
468   }
469 }
470
471 static void
472 close_connection (GstRTSPClient * client)
473 {
474   const gchar *tunnelid;
475
476   GST_DEBUG ("client %p: closing connection", client);
477
478   if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
479     g_mutex_lock (&tunnels_lock);
480     /* remove from tunnelids */
481     g_hash_table_remove (tunnels, tunnelid);
482     g_mutex_unlock (&tunnels_lock);
483   }
484
485   gst_rtsp_connection_close (client->connection);
486   if (client->watchid) {
487     g_source_destroy ((GSource *) client->watch);
488     client->watchid = 0;
489     client->watch = NULL;
490   }
491 }
492
493 static gboolean
494 handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state)
495 {
496   GstRTSPSession *session;
497   GstRTSPSessionMedia *media;
498   GstRTSPStatusCode code;
499
500   if (!state->session)
501     goto no_session;
502
503   session = state->session;
504
505   /* get a handle to the configuration of the media in the session */
506   media = gst_rtsp_session_get_media (session, state->uri);
507   if (!media)
508     goto not_found;
509
510   state->sessmedia = media;
511
512   /* unlink the all TCP callbacks */
513   unlink_session_streams (client, session, media);
514
515   /* remove the session from the watched sessions */
516   g_object_weak_unref (G_OBJECT (session),
517       (GWeakNotify) client_session_finalized, client);
518   client->sessions = g_list_remove (client->sessions, session);
519
520   gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
521
522   /* unmanage the media in the session, returns false if all media session
523    * are torn down. */
524   if (!gst_rtsp_session_release_media (session, media)) {
525     /* remove the session */
526     gst_rtsp_session_pool_remove (client->session_pool, session);
527   }
528   /* construct the response now */
529   code = GST_RTSP_STS_OK;
530   gst_rtsp_message_init_response (state->response, code,
531       gst_rtsp_status_as_text (code), state->request);
532
533   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION,
534       "close");
535
536   send_response (client, session, state->response);
537
538   close_connection (client);
539
540   return TRUE;
541
542   /* ERRORS */
543 no_session:
544   {
545     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
546     return FALSE;
547   }
548 not_found:
549   {
550     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
551     return FALSE;
552   }
553 }
554
555 static gboolean
556 handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state)
557 {
558   GstRTSPResult res;
559   guint8 *data;
560   guint size;
561
562   res = gst_rtsp_message_get_body (state->request, &data, &size);
563   if (res != GST_RTSP_OK)
564     goto bad_request;
565
566   if (size == 0) {
567     /* no body, keep-alive request */
568     send_generic_response (client, GST_RTSP_STS_OK, state);
569   } else {
570     /* there is a body, handle the params */
571     res = gst_rtsp_params_get (client, state);
572     if (res != GST_RTSP_OK)
573       goto bad_request;
574
575     send_response (client, state->session, state->response);
576   }
577   return TRUE;
578
579   /* ERRORS */
580 bad_request:
581   {
582     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
583     return FALSE;
584   }
585 }
586
587 static gboolean
588 handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state)
589 {
590   GstRTSPResult res;
591   guint8 *data;
592   guint size;
593
594   res = gst_rtsp_message_get_body (state->request, &data, &size);
595   if (res != GST_RTSP_OK)
596     goto bad_request;
597
598   if (size == 0) {
599     /* no body, keep-alive request */
600     send_generic_response (client, GST_RTSP_STS_OK, state);
601   } else {
602     /* there is a body, handle the params */
603     res = gst_rtsp_params_set (client, state);
604     if (res != GST_RTSP_OK)
605       goto bad_request;
606
607     send_response (client, state->session, state->response);
608   }
609   return TRUE;
610
611   /* ERRORS */
612 bad_request:
613   {
614     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
615     return FALSE;
616   }
617 }
618
619 static gboolean
620 handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state)
621 {
622   GstRTSPSession *session;
623   GstRTSPSessionMedia *media;
624   GstRTSPStatusCode code;
625
626   if (!(session = state->session))
627     goto no_session;
628
629   /* get a handle to the configuration of the media in the session */
630   media = gst_rtsp_session_get_media (session, state->uri);
631   if (!media)
632     goto not_found;
633
634   state->sessmedia = media;
635
636   /* the session state must be playing or recording */
637   if (media->state != GST_RTSP_STATE_PLAYING &&
638       media->state != GST_RTSP_STATE_RECORDING)
639     goto invalid_state;
640
641   /* unlink the all TCP callbacks */
642   unlink_session_streams (client, session, media);
643
644   /* then pause sending */
645   gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
646
647   /* construct the response now */
648   code = GST_RTSP_STS_OK;
649   gst_rtsp_message_init_response (state->response, code,
650       gst_rtsp_status_as_text (code), state->request);
651
652   send_response (client, session, state->response);
653
654   /* the state is now READY */
655   media->state = GST_RTSP_STATE_READY;
656
657   return TRUE;
658
659   /* ERRORS */
660 no_session:
661   {
662     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
663     return FALSE;
664   }
665 not_found:
666   {
667     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
668     return FALSE;
669   }
670 invalid_state:
671   {
672     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
673         state);
674     return FALSE;
675   }
676 }
677
678 static gboolean
679 handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
680 {
681   GstRTSPSession *session;
682   GstRTSPSessionMedia *media;
683   GstRTSPStatusCode code;
684   GString *rtpinfo;
685   guint n_streams, i, infocount;
686   guint timestamp, seqnum;
687   gchar *str;
688   GstRTSPTimeRange *range;
689   GstRTSPResult res;
690
691   if (!(session = state->session))
692     goto no_session;
693
694   /* get a handle to the configuration of the media in the session */
695   media = gst_rtsp_session_get_media (session, state->uri);
696   if (!media)
697     goto not_found;
698
699   state->sessmedia = media;
700
701   /* the session state must be playing or ready */
702   if (media->state != GST_RTSP_STATE_PLAYING &&
703       media->state != GST_RTSP_STATE_READY)
704     goto invalid_state;
705
706   /* parse the range header if we have one */
707   res =
708       gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_RANGE, &str, 0);
709   if (res == GST_RTSP_OK) {
710     if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
711       /* we have a range, seek to the position */
712       gst_rtsp_media_seek (media->media, range);
713       gst_rtsp_range_free (range);
714     }
715   }
716
717   /* grab RTPInfo from the payloaders now */
718   rtpinfo = g_string_new ("");
719
720   n_streams = gst_rtsp_media_n_streams (media->media);
721   for (i = 0, infocount = 0; i < n_streams; i++) {
722     GstRTSPSessionStream *sstream;
723     GstRTSPMediaStream *stream;
724     GstRTSPTransport *tr;
725     GObjectClass *payobjclass;
726     gchar *uristr;
727
728     /* get the stream as configured in the session */
729     sstream = gst_rtsp_session_media_get_stream (media, i);
730     /* get the transport, if there is no transport configured, skip this stream */
731     if (!(tr = sstream->trans.transport)) {
732       GST_INFO ("stream %d is not configured", i);
733       continue;
734     }
735
736     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
737       /* for TCP, link the stream to the TCP connection of the client */
738       link_stream (client, session, sstream);
739     }
740
741     stream = sstream->media_stream;
742
743     payobjclass = G_OBJECT_GET_CLASS (stream->payloader);
744
745     if (g_object_class_find_property (payobjclass, "seqnum") &&
746         g_object_class_find_property (payobjclass, "timestamp")) {
747       GObject *payobj;
748
749       payobj = G_OBJECT (stream->payloader);
750
751       /* only add RTP-Info for streams with seqnum and timestamp */
752       g_object_get (payobj, "seqnum", &seqnum, "timestamp", &timestamp, NULL);
753
754       if (infocount > 0)
755         g_string_append (rtpinfo, ", ");
756
757       uristr = gst_rtsp_url_get_request_uri (state->uri);
758       g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u",
759           uristr, i, seqnum, timestamp);
760       g_free (uristr);
761
762       infocount++;
763     } else {
764       GST_WARNING ("RTP-Info cannot be determined for stream %d", i);
765     }
766   }
767
768   /* construct the response now */
769   code = GST_RTSP_STS_OK;
770   gst_rtsp_message_init_response (state->response, code,
771       gst_rtsp_status_as_text (code), state->request);
772
773   /* add the RTP-Info header */
774   if (infocount > 0) {
775     str = g_string_free (rtpinfo, FALSE);
776     gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RTP_INFO, str);
777   } else {
778     g_string_free (rtpinfo, TRUE);
779   }
780
781   /* add the range */
782   str = gst_rtsp_media_get_range_string (media->media, TRUE);
783   gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str);
784
785   send_response (client, session, state->response);
786
787   /* start playing after sending the request */
788   gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
789
790   media->state = GST_RTSP_STATE_PLAYING;
791
792   return TRUE;
793
794   /* ERRORS */
795 no_session:
796   {
797     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
798     return FALSE;
799   }
800 not_found:
801   {
802     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
803     return FALSE;
804   }
805 invalid_state:
806   {
807     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
808         state);
809     return FALSE;
810   }
811 }
812
813 static void
814 do_keepalive (GstRTSPSession * session)
815 {
816   GST_INFO ("keep session %p alive", session);
817   gst_rtsp_session_touch (session);
818 }
819
820 static gboolean
821 handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
822 {
823   GstRTSPResult res;
824   GstRTSPUrl *uri;
825   gchar *transport;
826   gchar **transports;
827   gboolean have_transport;
828   GstRTSPTransport *ct, *st;
829   gint i;
830   GstRTSPLowerTrans supported;
831   GstRTSPStatusCode code;
832   GstRTSPSession *session;
833   GstRTSPSessionStream *stream;
834   gchar *trans_str, *pos;
835   guint streamid;
836   GstRTSPSessionMedia *media;
837
838   uri = state->uri;
839
840   /* the uri contains the stream number we added in the SDP config, which is
841    * always /stream=%d so we need to strip that off 
842    * parse the stream we need to configure, look for the stream in the abspath
843    * first and then in the query. */
844   if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) {
845     if (uri->query == NULL || !(pos = strstr (uri->query, "/stream=")))
846       goto bad_request;
847   }
848
849   /* we can mofify the parse uri in place */
850   *pos = '\0';
851
852   pos += strlen ("/stream=");
853   if (sscanf (pos, "%u", &streamid) != 1)
854     goto bad_request;
855
856   /* parse the transport */
857   res =
858       gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_TRANSPORT,
859       &transport, 0);
860   if (res != GST_RTSP_OK)
861     goto no_transport;
862
863   transports = g_strsplit (transport, ",", 0);
864   gst_rtsp_transport_new (&ct);
865
866   /* init transports */
867   have_transport = FALSE;
868   gst_rtsp_transport_init (ct);
869
870   /* our supported transports */
871   supported = GST_RTSP_LOWER_TRANS_UDP |
872       GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP;
873
874   /* loop through the transports, try to parse */
875   for (i = 0; transports[i]; i++) {
876     res = gst_rtsp_transport_parse (transports[i], ct);
877     if (res != GST_RTSP_OK) {
878       /* no valid transport, search some more */
879       GST_WARNING ("could not parse transport %s", transports[i]);
880       goto next;
881     }
882
883     /* we have a transport, see if it's RTP/AVP */
884     if (ct->trans != GST_RTSP_TRANS_RTP || ct->profile != GST_RTSP_PROFILE_AVP) {
885       GST_WARNING ("invalid transport %s", transports[i]);
886       goto next;
887     }
888
889     if (!(ct->lower_transport & supported)) {
890       GST_WARNING ("unsupported transport %s", transports[i]);
891       goto next;
892     }
893
894     /* we have a valid transport */
895     GST_INFO ("found valid transport %s", transports[i]);
896     have_transport = TRUE;
897     break;
898
899   next:
900     gst_rtsp_transport_init (ct);
901   }
902   g_strfreev (transports);
903
904   /* we have not found anything usable, error out */
905   if (!have_transport)
906     goto unsupported_transports;
907
908   if (client->session_pool == NULL)
909     goto no_pool;
910
911   session = state->session;
912
913   if (session) {
914     g_object_ref (session);
915     /* get a handle to the configuration of the media in the session, this can
916      * return NULL if this is a new url to manage in this session. */
917     media = gst_rtsp_session_get_media (session, uri);
918   } else {
919     /* create a session if this fails we probably reached our session limit or
920      * something. */
921     if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
922       goto service_unavailable;
923
924     state->session = session;
925
926     /* we need a new media configuration in this session */
927     media = NULL;
928   }
929
930   /* we have no media, find one and manage it */
931   if (media == NULL) {
932     GstRTSPMedia *m;
933
934     /* get a handle to the configuration of the media in the session */
935     if ((m = find_media (client, state))) {
936       /* manage the media in our session now */
937       media = gst_rtsp_session_manage_media (session, uri, m);
938     }
939   }
940
941   /* if we stil have no media, error */
942   if (media == NULL)
943     goto not_found;
944
945   state->sessmedia = media;
946
947   /* we have a valid transport now, set the destination of the client. */
948   g_free (ct->destination);
949   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
950     ct->destination = gst_rtsp_media_get_multicast_group (media->media);
951   } else {
952     GstRTSPUrl *url;
953
954     url = gst_rtsp_connection_get_url (client->connection);
955     ct->destination = g_strdup (url->host);
956
957     if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
958       /* check if the client selected channels for TCP */
959       if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
960         gst_rtsp_session_media_alloc_channels (media, &ct->interleaved);
961       }
962     }
963   }
964
965   /* get a handle to the stream in the media */
966   if (!(stream = gst_rtsp_session_media_get_stream (media, streamid)))
967     goto no_stream;
968
969   st = gst_rtsp_session_stream_set_transport (stream, ct);
970
971   /* configure keepalive for this transport */
972   gst_rtsp_session_stream_set_keepalive (stream,
973       (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
974
975   /* serialize the server transport */
976   trans_str = gst_rtsp_transport_as_text (st);
977   gst_rtsp_transport_free (st);
978
979   /* construct the response now */
980   code = GST_RTSP_STS_OK;
981   gst_rtsp_message_init_response (state->response, code,
982       gst_rtsp_status_as_text (code), state->request);
983
984   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_TRANSPORT,
985       trans_str);
986   g_free (trans_str);
987
988   send_response (client, session, state->response);
989
990   /* update the state */
991   switch (media->state) {
992     case GST_RTSP_STATE_PLAYING:
993     case GST_RTSP_STATE_RECORDING:
994     case GST_RTSP_STATE_READY:
995       /* no state change */
996       break;
997     default:
998       media->state = GST_RTSP_STATE_READY;
999       break;
1000   }
1001   g_object_unref (session);
1002
1003   return TRUE;
1004
1005   /* ERRORS */
1006 bad_request:
1007   {
1008     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1009     return FALSE;
1010   }
1011 not_found:
1012   {
1013     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1014     g_object_unref (session);
1015     return FALSE;
1016   }
1017 no_stream:
1018   {
1019     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1020     g_object_unref (session);
1021     return FALSE;
1022   }
1023 no_transport:
1024   {
1025     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1026     return FALSE;
1027   }
1028 unsupported_transports:
1029   {
1030     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1031     gst_rtsp_transport_free (ct);
1032     return FALSE;
1033   }
1034 no_pool:
1035   {
1036     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1037     return FALSE;
1038   }
1039 service_unavailable:
1040   {
1041     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1042     return FALSE;
1043   }
1044 }
1045
1046 static GstSDPMessage *
1047 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
1048 {
1049   GstSDPMessage *sdp;
1050   GstSDPInfo info;
1051   const gchar *proto;
1052   GstRTSPLowerTrans protocols;
1053
1054   gst_sdp_message_new (&sdp);
1055
1056   /* some standard things first */
1057   gst_sdp_message_set_version (sdp, "0");
1058
1059   if (client->is_ipv6)
1060     proto = "IP6";
1061   else
1062     proto = "IP4";
1063
1064   gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
1065       client->server_ip);
1066
1067   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
1068   gst_sdp_message_set_information (sdp, "rtsp-server");
1069   gst_sdp_message_add_time (sdp, "0", "0", NULL);
1070   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
1071   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
1072   gst_sdp_message_add_attribute (sdp, "control", "*");
1073
1074   info.server_proto = proto;
1075   protocols = gst_rtsp_media_get_protocols (media);
1076   if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)
1077     info.server_ip = gst_rtsp_media_get_multicast_group (media);
1078   else
1079     info.server_ip = g_strdup (client->server_ip);
1080
1081   /* create an SDP for the media object */
1082   if (!gst_rtsp_sdp_from_media (sdp, &info, media))
1083     goto no_sdp;
1084
1085   g_free (info.server_ip);
1086
1087   return sdp;
1088
1089   /* ERRORS */
1090 no_sdp:
1091   {
1092     g_free (info.server_ip);
1093     gst_sdp_message_free (sdp);
1094     return NULL;
1095   }
1096 }
1097
1098 /* for the describe we must generate an SDP */
1099 static gboolean
1100 handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state)
1101 {
1102   GstRTSPResult res;
1103   GstSDPMessage *sdp;
1104   guint i, str_len;
1105   gchar *str, *content_base;
1106   GstRTSPMedia *media;
1107
1108   /* check what kind of format is accepted, we don't really do anything with it
1109    * and always return SDP for now. */
1110   for (i = 0; i++;) {
1111     gchar *accept;
1112
1113     res =
1114         gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT,
1115         &accept, i);
1116     if (res == GST_RTSP_ENOTIMPL)
1117       break;
1118
1119     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
1120       break;
1121   }
1122
1123   /* find the media object for the uri */
1124   if (!(media = find_media (client, state)))
1125     goto no_media;
1126
1127   /* create an SDP for the media object on this client */
1128   if (!(sdp = create_sdp (client, media)))
1129     goto no_sdp;
1130
1131   g_object_unref (media);
1132
1133   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1134       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1135
1136   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE,
1137       "application/sdp");
1138
1139   /* content base for some clients that might screw up creating the setup uri */
1140   str = gst_rtsp_url_get_request_uri (state->uri);
1141   str_len = strlen (str);
1142
1143   /* check for trailing '/' and append one */
1144   if (str[str_len - 1] != '/') {
1145     content_base = g_malloc (str_len + 2);
1146     memcpy (content_base, str, str_len);
1147     content_base[str_len] = '/';
1148     content_base[str_len + 1] = '\0';
1149     g_free (str);
1150   } else {
1151     content_base = str;
1152   }
1153
1154   GST_INFO ("adding content-base: %s", content_base);
1155
1156   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE,
1157       content_base);
1158   g_free (content_base);
1159
1160   /* add SDP to the response body */
1161   str = gst_sdp_message_as_text (sdp);
1162   gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str));
1163   gst_sdp_message_free (sdp);
1164
1165   send_response (client, state->session, state->response);
1166
1167   return TRUE;
1168
1169   /* ERRORS */
1170 no_media:
1171   {
1172     /* error reply is already sent */
1173     return FALSE;
1174   }
1175 no_sdp:
1176   {
1177     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1178     g_object_unref (media);
1179     return FALSE;
1180   }
1181 }
1182
1183 static gboolean
1184 handle_options_request (GstRTSPClient * client, GstRTSPClientState * state)
1185 {
1186   GstRTSPMethod options;
1187   gchar *str;
1188
1189   options = GST_RTSP_DESCRIBE |
1190       GST_RTSP_OPTIONS |
1191       GST_RTSP_PAUSE |
1192       GST_RTSP_PLAY |
1193       GST_RTSP_SETUP |
1194       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1195
1196   str = gst_rtsp_options_as_text (options);
1197
1198   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1199       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1200
1201   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str);
1202   g_free (str);
1203
1204   send_response (client, state->session, state->response);
1205
1206   return TRUE;
1207 }
1208
1209 /* remove duplicate and trailing '/' */
1210 static void
1211 sanitize_uri (GstRTSPUrl * uri)
1212 {
1213   gint i, len;
1214   gchar *s, *d;
1215   gboolean have_slash, prev_slash;
1216
1217   s = d = uri->abspath;
1218   len = strlen (uri->abspath);
1219
1220   prev_slash = FALSE;
1221
1222   for (i = 0; i < len; i++) {
1223     have_slash = s[i] == '/';
1224     *d = s[i];
1225     if (!have_slash || !prev_slash)
1226       d++;
1227     prev_slash = have_slash;
1228   }
1229   len = d - uri->abspath;
1230   /* don't remove the first slash if that's the only thing left */
1231   if (len > 1 && *(d - 1) == '/')
1232     d--;
1233   *d = '\0';
1234 }
1235
1236 static void
1237 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
1238 {
1239   GST_INFO ("client %p: session %p finished", client, session);
1240
1241   /* unlink all media managed in this session */
1242   client_unlink_session (client, session);
1243
1244   /* remove the session */
1245   if (!(client->sessions = g_list_remove (client->sessions, session))) {
1246     GST_INFO ("client %p: all sessions finalized, close the connection",
1247         client);
1248     close_connection (client);
1249   }
1250 }
1251
1252 static void
1253 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
1254 {
1255   GList *walk;
1256
1257   for (walk = client->sessions; walk; walk = g_list_next (walk)) {
1258     GstRTSPSession *msession = (GstRTSPSession *) walk->data;
1259
1260     /* we already know about this session */
1261     if (msession == session)
1262       return;
1263   }
1264
1265   GST_INFO ("watching session %p", session);
1266
1267   g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
1268       client);
1269   client->sessions = g_list_prepend (client->sessions, session);
1270 }
1271
1272 static void
1273 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
1274 {
1275   GstRTSPMethod method;
1276   const gchar *uristr;
1277   GstRTSPUrl *uri;
1278   GstRTSPVersion version;
1279   GstRTSPResult res;
1280   GstRTSPSession *session;
1281   GstRTSPClientState state = { NULL };
1282   GstRTSPMessage response = { 0 };
1283   gchar *sessid;
1284
1285   state.request = request;
1286   state.response = &response;
1287
1288   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1289     gst_rtsp_message_dump (request);
1290   }
1291
1292   GST_INFO ("client %p: received a request", client);
1293
1294   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
1295
1296   if (version != GST_RTSP_VERSION_1_0) {
1297     /* we can only handle 1.0 requests */
1298     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
1299         &state);
1300     return;
1301   }
1302   state.method = method;
1303
1304   /* we always try to parse the url first */
1305   if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
1306     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1307     return;
1308   }
1309
1310   /* sanitize the uri */
1311   sanitize_uri (uri);
1312   state.uri = uri;
1313
1314   /* get the session if there is any */
1315   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
1316   if (res == GST_RTSP_OK) {
1317     if (client->session_pool == NULL)
1318       goto no_pool;
1319
1320     /* we had a session in the request, find it again */
1321     if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
1322       goto session_not_found;
1323
1324     /* we add the session to the client list of watched sessions. When a session
1325      * disappears because it times out, we will be notified. If all sessions are
1326      * gone, we will close the connection */
1327     client_watch_session (client, session);
1328   } else
1329     session = NULL;
1330
1331   state.session = session;
1332
1333   if (client->auth) {
1334     if (!gst_rtsp_auth_check (client->auth, client, 0, &state))
1335       goto not_authorized;
1336   }
1337
1338   /* now see what is asked and dispatch to a dedicated handler */
1339   switch (method) {
1340     case GST_RTSP_OPTIONS:
1341       handle_options_request (client, &state);
1342       break;
1343     case GST_RTSP_DESCRIBE:
1344       handle_describe_request (client, &state);
1345       break;
1346     case GST_RTSP_SETUP:
1347       handle_setup_request (client, &state);
1348       break;
1349     case GST_RTSP_PLAY:
1350       handle_play_request (client, &state);
1351       break;
1352     case GST_RTSP_PAUSE:
1353       handle_pause_request (client, &state);
1354       break;
1355     case GST_RTSP_TEARDOWN:
1356       handle_teardown_request (client, &state);
1357       break;
1358     case GST_RTSP_SET_PARAMETER:
1359       handle_set_param_request (client, &state);
1360       break;
1361     case GST_RTSP_GET_PARAMETER:
1362       handle_get_param_request (client, &state);
1363       break;
1364     case GST_RTSP_ANNOUNCE:
1365     case GST_RTSP_RECORD:
1366     case GST_RTSP_REDIRECT:
1367       send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state);
1368       break;
1369     case GST_RTSP_INVALID:
1370     default:
1371       send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1372       break;
1373   }
1374   if (session)
1375     g_object_unref (session);
1376
1377   gst_rtsp_url_free (uri);
1378   return;
1379
1380   /* ERRORS */
1381 no_pool:
1382   {
1383     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, &state);
1384     return;
1385   }
1386 session_not_found:
1387   {
1388     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1389     return;
1390   }
1391 not_authorized:
1392   {
1393     handle_unauthorized_request (client, client->auth, &state);
1394     return;
1395   }
1396 }
1397
1398 static void
1399 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
1400 {
1401   GstRTSPResult res;
1402   guint8 channel;
1403   GList *walk;
1404   guint8 *data;
1405   guint size;
1406   GstBuffer *buffer;
1407   gboolean handled;
1408
1409   /* find the stream for this message */
1410   res = gst_rtsp_message_parse_data (message, &channel);
1411   if (res != GST_RTSP_OK)
1412     return;
1413
1414   gst_rtsp_message_steal_body (message, &data, &size);
1415
1416   buffer = gst_buffer_new_wrapped (data, size);
1417
1418   handled = FALSE;
1419   for (walk = client->streams; walk; walk = g_list_next (walk)) {
1420     GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
1421     GstRTSPMediaStream *mstream;
1422     GstRTSPTransport *tr;
1423
1424     /* get the transport, if there is no transport configured, skip this stream */
1425     if (!(tr = stream->trans.transport))
1426       continue;
1427
1428     /* we also need a media stream */
1429     if (!(mstream = stream->media_stream))
1430       continue;
1431
1432     /* check for TCP transport */
1433     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1434       /* dispatch to the stream based on the channel number */
1435       if (tr->interleaved.min == channel) {
1436         gst_rtsp_media_stream_rtp (mstream, buffer);
1437         handled = TRUE;
1438         break;
1439       } else if (tr->interleaved.max == channel) {
1440         gst_rtsp_media_stream_rtcp (mstream, buffer);
1441         handled = TRUE;
1442         break;
1443       }
1444     }
1445   }
1446   if (!handled)
1447     gst_buffer_unref (buffer);
1448 }
1449
1450 /**
1451  * gst_rtsp_client_set_session_pool:
1452  * @client: a #GstRTSPClient
1453  * @pool: a #GstRTSPSessionPool
1454  *
1455  * Set @pool as the sessionpool for @client which it will use to find
1456  * or allocate sessions. the sessionpool is usually inherited from the server
1457  * that created the client but can be overridden later.
1458  */
1459 void
1460 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
1461     GstRTSPSessionPool * pool)
1462 {
1463   GstRTSPSessionPool *old;
1464
1465   old = client->session_pool;
1466   if (old != pool) {
1467     if (pool)
1468       g_object_ref (pool);
1469     client->session_pool = pool;
1470     if (old)
1471       g_object_unref (old);
1472   }
1473 }
1474
1475 /**
1476  * gst_rtsp_client_get_session_pool:
1477  * @client: a #GstRTSPClient
1478  *
1479  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1480  *
1481  * Returns: a #GstRTSPSessionPool, unref after usage.
1482  */
1483 GstRTSPSessionPool *
1484 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
1485 {
1486   GstRTSPSessionPool *result;
1487
1488   if ((result = client->session_pool))
1489     g_object_ref (result);
1490
1491   return result;
1492 }
1493
1494 /**
1495  * gst_rtsp_client_set_server:
1496  * @client: a #GstRTSPClient
1497  * @server: a #GstRTSPServer
1498  *
1499  * Set @server as the server that created @client.
1500  */
1501 void
1502 gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server)
1503 {
1504   GstRTSPServer *old;
1505
1506   old = client->server;
1507   if (old != server) {
1508     if (server)
1509       g_object_ref (server);
1510     client->server = server;
1511     if (old)
1512       g_object_unref (old);
1513   }
1514 }
1515
1516 /**
1517  * gst_rtsp_client_get_server:
1518  * @client: a #GstRTSPClient
1519  *
1520  * Get the #GstRTSPServer object that @client was created from.
1521  *
1522  * Returns: a #GstRTSPServer, unref after usage.
1523  */
1524 GstRTSPServer *
1525 gst_rtsp_client_get_server (GstRTSPClient * client)
1526 {
1527   GstRTSPServer *result;
1528
1529   if ((result = client->server))
1530     g_object_ref (result);
1531
1532   return result;
1533 }
1534
1535 /**
1536  * gst_rtsp_client_set_media_mapping:
1537  * @client: a #GstRTSPClient
1538  * @mapping: a #GstRTSPMediaMapping
1539  *
1540  * Set @mapping as the media mapping for @client which it will use to map urls
1541  * to media streams. These mapping is usually inherited from the server that
1542  * created the client but can be overriden later.
1543  */
1544 void
1545 gst_rtsp_client_set_media_mapping (GstRTSPClient * client,
1546     GstRTSPMediaMapping * mapping)
1547 {
1548   GstRTSPMediaMapping *old;
1549
1550   old = client->media_mapping;
1551
1552   if (old != mapping) {
1553     if (mapping)
1554       g_object_ref (mapping);
1555     client->media_mapping = mapping;
1556     if (old)
1557       g_object_unref (old);
1558   }
1559 }
1560
1561 /**
1562  * gst_rtsp_client_get_media_mapping:
1563  * @client: a #GstRTSPClient
1564  *
1565  * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
1566  *
1567  * Returns: a #GstRTSPMediaMapping, unref after usage.
1568  */
1569 GstRTSPMediaMapping *
1570 gst_rtsp_client_get_media_mapping (GstRTSPClient * client)
1571 {
1572   GstRTSPMediaMapping *result;
1573
1574   if ((result = client->media_mapping))
1575     g_object_ref (result);
1576
1577   return result;
1578 }
1579
1580 /**
1581  * gst_rtsp_client_set_auth:
1582  * @client: a #GstRTSPClient
1583  * @auth: a #GstRTSPAuth
1584  *
1585  * configure @auth to be used as the authentication manager of @client.
1586  */
1587 void
1588 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
1589 {
1590   GstRTSPAuth *old;
1591
1592   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1593
1594   old = client->auth;
1595
1596   if (old != auth) {
1597     if (auth)
1598       g_object_ref (auth);
1599     client->auth = auth;
1600     if (old)
1601       g_object_unref (old);
1602   }
1603 }
1604
1605
1606 /**
1607  * gst_rtsp_client_get_auth:
1608  * @client: a #GstRTSPClient
1609  *
1610  * Get the #GstRTSPAuth used as the authentication manager of @client.
1611  *
1612  * Returns: the #GstRTSPAuth of @client. g_object_unref() after
1613  * usage.
1614  */
1615 GstRTSPAuth *
1616 gst_rtsp_client_get_auth (GstRTSPClient * client)
1617 {
1618   GstRTSPAuth *result;
1619
1620   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1621
1622   if ((result = client->auth))
1623     g_object_ref (result);
1624
1625   return result;
1626 }
1627
1628 static GstRTSPResult
1629 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
1630     gpointer user_data)
1631 {
1632   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1633
1634   switch (message->type) {
1635     case GST_RTSP_MESSAGE_REQUEST:
1636       handle_request (client, message);
1637       break;
1638     case GST_RTSP_MESSAGE_RESPONSE:
1639       break;
1640     case GST_RTSP_MESSAGE_DATA:
1641       handle_data (client, message);
1642       break;
1643     default:
1644       break;
1645   }
1646   return GST_RTSP_OK;
1647 }
1648
1649 static GstRTSPResult
1650 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
1651 {
1652   /* GstRTSPClient *client; */
1653
1654   /* client = GST_RTSP_CLIENT (user_data); */
1655
1656   /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */
1657
1658   return GST_RTSP_OK;
1659 }
1660
1661 static GstRTSPResult
1662 closed (GstRTSPWatch * watch, gpointer user_data)
1663 {
1664   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1665   const gchar *tunnelid;
1666
1667   GST_INFO ("client %p: connection closed", client);
1668
1669   if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
1670     g_mutex_lock (&tunnels_lock);
1671     /* remove from tunnelids */
1672     g_hash_table_remove (tunnels, tunnelid);
1673     g_mutex_unlock (&tunnels_lock);
1674   }
1675
1676   return GST_RTSP_OK;
1677 }
1678
1679 static GstRTSPResult
1680 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
1681 {
1682   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1683   gchar *str;
1684
1685   str = gst_rtsp_strresult (result);
1686   GST_INFO ("client %p: received an error %s", client, str);
1687   g_free (str);
1688
1689   return GST_RTSP_OK;
1690 }
1691
1692 static GstRTSPResult
1693 error_full (GstRTSPWatch * watch, GstRTSPResult result,
1694     GstRTSPMessage * message, guint id, gpointer user_data)
1695 {
1696   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1697   gchar *str;
1698
1699   str = gst_rtsp_strresult (result);
1700   GST_INFO
1701       ("client %p: received an error %s when handling message %p with id %d",
1702       client, str, message, id);
1703   g_free (str);
1704
1705   return GST_RTSP_OK;
1706 }
1707
1708 static gboolean
1709 remember_tunnel (GstRTSPClient * client)
1710 {
1711   const gchar *tunnelid;
1712
1713   /* store client in the pending tunnels */
1714   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1715   if (tunnelid == NULL)
1716     goto no_tunnelid;
1717
1718   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
1719
1720   /* we can't have two clients connecting with the same tunnelid */
1721   g_mutex_lock (&tunnels_lock);
1722   if (g_hash_table_lookup (tunnels, tunnelid))
1723     goto tunnel_existed;
1724
1725   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
1726   g_mutex_unlock (&tunnels_lock);
1727
1728   return TRUE;
1729
1730   /* ERRORS */
1731 no_tunnelid:
1732   {
1733     GST_ERROR ("client %p: no tunnelid provided", client);
1734     return FALSE;
1735   }
1736 tunnel_existed:
1737   {
1738     g_mutex_unlock (&tunnels_lock);
1739     GST_ERROR ("client %p: tunnel session %s already existed", client,
1740         tunnelid);
1741     return FALSE;
1742   }
1743 }
1744
1745 static GstRTSPStatusCode
1746 tunnel_start (GstRTSPWatch * watch, gpointer user_data)
1747 {
1748   GstRTSPClient *client;
1749
1750   client = GST_RTSP_CLIENT (user_data);
1751
1752   GST_INFO ("client %p: tunnel start (connection %p)", client,
1753       client->connection);
1754
1755   if (!remember_tunnel (client))
1756     goto tunnel_error;
1757
1758   return GST_RTSP_STS_OK;
1759
1760   /* ERRORS */
1761 tunnel_error:
1762   {
1763     GST_ERROR ("client %p: error starting tunnel", client);
1764     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1765   }
1766 }
1767
1768 static GstRTSPResult
1769 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
1770 {
1771   GstRTSPClient *client;
1772
1773   client = GST_RTSP_CLIENT (user_data);
1774
1775   GST_INFO ("client %p: tunnel lost (connection %p)", client,
1776       client->connection);
1777
1778   /* ignore error, it'll only be a problem when the client does a POST again */
1779   remember_tunnel (client);
1780
1781   return GST_RTSP_OK;
1782 }
1783
1784 static GstRTSPResult
1785 tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
1786 {
1787   const gchar *tunnelid;
1788   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1789   GstRTSPClient *oclient;
1790
1791   GST_INFO ("client %p: tunnel complete", client);
1792
1793   /* find previous tunnel */
1794   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1795   if (tunnelid == NULL)
1796     goto no_tunnelid;
1797
1798   g_mutex_lock (&tunnels_lock);
1799   if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
1800     goto no_tunnel;
1801
1802   /* remove the old client from the table. ref before because removing it will
1803    * remove the ref to it. */
1804   g_object_ref (oclient);
1805   g_hash_table_remove (tunnels, tunnelid);
1806
1807   if (oclient->watch == NULL)
1808     goto tunnel_closed;
1809   g_mutex_unlock (&tunnels_lock);
1810
1811   GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
1812       oclient->connection, client->connection);
1813
1814   /* merge the tunnels into the first client */
1815   gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
1816   gst_rtsp_watch_reset (oclient->watch);
1817   g_object_unref (oclient);
1818
1819   /* we don't need this watch anymore */
1820   g_source_destroy ((GSource *) client->watch);
1821   client->watchid = 0;
1822   client->watch = NULL;
1823
1824   return GST_RTSP_OK;
1825
1826   /* ERRORS */
1827 no_tunnelid:
1828   {
1829     GST_INFO ("client %p: no tunnelid provided", client);
1830     return GST_RTSP_ERROR;
1831   }
1832 no_tunnel:
1833   {
1834     g_mutex_unlock (&tunnels_lock);
1835     GST_INFO ("client %p: tunnel session %s not found", client, tunnelid);
1836     return GST_RTSP_ERROR;
1837   }
1838 tunnel_closed:
1839   {
1840     g_mutex_unlock (&tunnels_lock);
1841     GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid);
1842     g_object_unref (oclient);
1843     return GST_RTSP_ERROR;
1844   }
1845 }
1846
1847 static GstRTSPWatchFuncs watch_funcs = {
1848   message_received,
1849   message_sent,
1850   closed,
1851   error,
1852   tunnel_start,
1853   tunnel_complete,
1854   error_full,
1855   tunnel_lost
1856 };
1857
1858 static void
1859 client_watch_notify (GstRTSPClient * client)
1860 {
1861   GST_INFO ("client %p: watch destroyed", client);
1862   client->watchid = 0;
1863   client->watch = NULL;
1864   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
1865   g_object_unref (client);
1866 }
1867
1868 /**
1869  * gst_rtsp_client_attach:
1870  * @client: a #GstRTSPClient
1871  * @socket: a #GSocket
1872  * @cancellable: a #GCancellable
1873  * @error: a #GError
1874  *
1875  * Accept a new connection for @client on @socket.
1876  *
1877  * This function should be called when the client properties and urls are fully
1878  * configured and the client is ready to start.
1879  *
1880  * Returns: %TRUE if the client could be accepted.
1881  */
1882 gboolean
1883 gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket,
1884     GCancellable * cancellable, GError ** error)
1885 {
1886   GstRTSPConnection *conn;
1887   GstRTSPResult res;
1888   GSocket *read_socket;
1889   GSocketAddress *addres;
1890   GSource *source;
1891   GMainContext *context;
1892   GstRTSPUrl *url;
1893   struct sockaddr_storage addr;
1894   socklen_t addrlen;
1895   gchar ip[INET6_ADDRSTRLEN];
1896
1897   /* a new client connected. */
1898   GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable),
1899       accept_failed);
1900
1901   read_socket = gst_rtsp_connection_get_read_socket (conn);
1902   client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6;
1903
1904   if (!(addres = g_socket_get_remote_address (read_socket, error)))
1905     goto no_address;
1906
1907   addrlen = sizeof (addr);
1908   if (!g_socket_address_to_native (addres, &addr, addrlen, error))
1909     goto native_failed;
1910   g_object_unref (addres);
1911
1912   if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0,
1913           NI_NUMERICHOST) != 0)
1914     goto getnameinfo_failed;
1915
1916   /* keep the original ip that the client connected to */
1917   g_free (client->server_ip);
1918   client->server_ip = g_strndup (ip, sizeof (ip));
1919
1920   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
1921       client->server_ip, client->is_ipv6);
1922
1923   url = gst_rtsp_connection_get_url (conn);
1924   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
1925
1926   client->connection = conn;
1927
1928   /* create watch for the connection and attach */
1929   client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
1930       g_object_ref (client), (GDestroyNotify) client_watch_notify);
1931
1932   /* find the context to add the watch */
1933   if ((source = g_main_current_source ()))
1934     context = g_source_get_context (source);
1935   else
1936     context = NULL;
1937
1938   GST_INFO ("attaching to context %p", context);
1939
1940   client->watchid = gst_rtsp_watch_attach (client->watch, context);
1941   gst_rtsp_watch_unref (client->watch);
1942
1943   return TRUE;
1944
1945   /* ERRORS */
1946 accept_failed:
1947   {
1948     gchar *str = gst_rtsp_strresult (res);
1949
1950     GST_ERROR ("Could not accept client on server socket %p: %s", socket, str);
1951     g_free (str);
1952     return FALSE;
1953   }
1954 no_address:
1955   {
1956     GST_ERROR ("could not get remote address %s", (*error)->message);
1957     return FALSE;
1958   }
1959 native_failed:
1960   {
1961     g_object_unref (addres);
1962     GST_ERROR ("could not get native address %s", (*error)->message);
1963     return FALSE;
1964   }
1965 getnameinfo_failed:
1966   {
1967     GST_ERROR ("getnameinfo failed: %s", g_strerror (errno));
1968     return FALSE;
1969   }
1970 }