rtsp-client: free transport on no_stream in SETUP handler
[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     gst_rtsp_transport_free (ct);
1022     return FALSE;
1023   }
1024 no_transport:
1025   {
1026     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1027     return FALSE;
1028   }
1029 unsupported_transports:
1030   {
1031     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1032     gst_rtsp_transport_free (ct);
1033     return FALSE;
1034   }
1035 no_pool:
1036   {
1037     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1038     return FALSE;
1039   }
1040 service_unavailable:
1041   {
1042     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1043     return FALSE;
1044   }
1045 }
1046
1047 static GstSDPMessage *
1048 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
1049 {
1050   GstSDPMessage *sdp;
1051   GstSDPInfo info;
1052   const gchar *proto;
1053   GstRTSPLowerTrans protocols;
1054
1055   gst_sdp_message_new (&sdp);
1056
1057   /* some standard things first */
1058   gst_sdp_message_set_version (sdp, "0");
1059
1060   if (client->is_ipv6)
1061     proto = "IP6";
1062   else
1063     proto = "IP4";
1064
1065   gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
1066       client->server_ip);
1067
1068   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
1069   gst_sdp_message_set_information (sdp, "rtsp-server");
1070   gst_sdp_message_add_time (sdp, "0", "0", NULL);
1071   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
1072   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
1073   gst_sdp_message_add_attribute (sdp, "control", "*");
1074
1075   info.server_proto = proto;
1076   protocols = gst_rtsp_media_get_protocols (media);
1077   if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)
1078     info.server_ip = gst_rtsp_media_get_multicast_group (media);
1079   else
1080     info.server_ip = g_strdup (client->server_ip);
1081
1082   /* create an SDP for the media object */
1083   if (!gst_rtsp_sdp_from_media (sdp, &info, media))
1084     goto no_sdp;
1085
1086   g_free (info.server_ip);
1087
1088   return sdp;
1089
1090   /* ERRORS */
1091 no_sdp:
1092   {
1093     g_free (info.server_ip);
1094     gst_sdp_message_free (sdp);
1095     return NULL;
1096   }
1097 }
1098
1099 /* for the describe we must generate an SDP */
1100 static gboolean
1101 handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state)
1102 {
1103   GstRTSPResult res;
1104   GstSDPMessage *sdp;
1105   guint i, str_len;
1106   gchar *str, *content_base;
1107   GstRTSPMedia *media;
1108
1109   /* check what kind of format is accepted, we don't really do anything with it
1110    * and always return SDP for now. */
1111   for (i = 0; i++;) {
1112     gchar *accept;
1113
1114     res =
1115         gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT,
1116         &accept, i);
1117     if (res == GST_RTSP_ENOTIMPL)
1118       break;
1119
1120     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
1121       break;
1122   }
1123
1124   /* find the media object for the uri */
1125   if (!(media = find_media (client, state)))
1126     goto no_media;
1127
1128   /* create an SDP for the media object on this client */
1129   if (!(sdp = create_sdp (client, media)))
1130     goto no_sdp;
1131
1132   g_object_unref (media);
1133
1134   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1135       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1136
1137   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE,
1138       "application/sdp");
1139
1140   /* content base for some clients that might screw up creating the setup uri */
1141   str = gst_rtsp_url_get_request_uri (state->uri);
1142   str_len = strlen (str);
1143
1144   /* check for trailing '/' and append one */
1145   if (str[str_len - 1] != '/') {
1146     content_base = g_malloc (str_len + 2);
1147     memcpy (content_base, str, str_len);
1148     content_base[str_len] = '/';
1149     content_base[str_len + 1] = '\0';
1150     g_free (str);
1151   } else {
1152     content_base = str;
1153   }
1154
1155   GST_INFO ("adding content-base: %s", content_base);
1156
1157   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE,
1158       content_base);
1159   g_free (content_base);
1160
1161   /* add SDP to the response body */
1162   str = gst_sdp_message_as_text (sdp);
1163   gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str));
1164   gst_sdp_message_free (sdp);
1165
1166   send_response (client, state->session, state->response);
1167
1168   return TRUE;
1169
1170   /* ERRORS */
1171 no_media:
1172   {
1173     /* error reply is already sent */
1174     return FALSE;
1175   }
1176 no_sdp:
1177   {
1178     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1179     g_object_unref (media);
1180     return FALSE;
1181   }
1182 }
1183
1184 static gboolean
1185 handle_options_request (GstRTSPClient * client, GstRTSPClientState * state)
1186 {
1187   GstRTSPMethod options;
1188   gchar *str;
1189
1190   options = GST_RTSP_DESCRIBE |
1191       GST_RTSP_OPTIONS |
1192       GST_RTSP_PAUSE |
1193       GST_RTSP_PLAY |
1194       GST_RTSP_SETUP |
1195       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1196
1197   str = gst_rtsp_options_as_text (options);
1198
1199   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1200       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1201
1202   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str);
1203   g_free (str);
1204
1205   send_response (client, state->session, state->response);
1206
1207   return TRUE;
1208 }
1209
1210 /* remove duplicate and trailing '/' */
1211 static void
1212 sanitize_uri (GstRTSPUrl * uri)
1213 {
1214   gint i, len;
1215   gchar *s, *d;
1216   gboolean have_slash, prev_slash;
1217
1218   s = d = uri->abspath;
1219   len = strlen (uri->abspath);
1220
1221   prev_slash = FALSE;
1222
1223   for (i = 0; i < len; i++) {
1224     have_slash = s[i] == '/';
1225     *d = s[i];
1226     if (!have_slash || !prev_slash)
1227       d++;
1228     prev_slash = have_slash;
1229   }
1230   len = d - uri->abspath;
1231   /* don't remove the first slash if that's the only thing left */
1232   if (len > 1 && *(d - 1) == '/')
1233     d--;
1234   *d = '\0';
1235 }
1236
1237 static void
1238 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
1239 {
1240   GST_INFO ("client %p: session %p finished", client, session);
1241
1242   /* unlink all media managed in this session */
1243   client_unlink_session (client, session);
1244
1245   /* remove the session */
1246   if (!(client->sessions = g_list_remove (client->sessions, session))) {
1247     GST_INFO ("client %p: all sessions finalized, close the connection",
1248         client);
1249     close_connection (client);
1250   }
1251 }
1252
1253 static void
1254 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
1255 {
1256   GList *walk;
1257
1258   for (walk = client->sessions; walk; walk = g_list_next (walk)) {
1259     GstRTSPSession *msession = (GstRTSPSession *) walk->data;
1260
1261     /* we already know about this session */
1262     if (msession == session)
1263       return;
1264   }
1265
1266   GST_INFO ("watching session %p", session);
1267
1268   g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
1269       client);
1270   client->sessions = g_list_prepend (client->sessions, session);
1271 }
1272
1273 static void
1274 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
1275 {
1276   GstRTSPMethod method;
1277   const gchar *uristr;
1278   GstRTSPUrl *uri;
1279   GstRTSPVersion version;
1280   GstRTSPResult res;
1281   GstRTSPSession *session;
1282   GstRTSPClientState state = { NULL };
1283   GstRTSPMessage response = { 0 };
1284   gchar *sessid;
1285
1286   state.request = request;
1287   state.response = &response;
1288
1289   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1290     gst_rtsp_message_dump (request);
1291   }
1292
1293   GST_INFO ("client %p: received a request", client);
1294
1295   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
1296
1297   if (version != GST_RTSP_VERSION_1_0) {
1298     /* we can only handle 1.0 requests */
1299     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
1300         &state);
1301     return;
1302   }
1303   state.method = method;
1304
1305   /* we always try to parse the url first */
1306   if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
1307     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1308     return;
1309   }
1310
1311   /* sanitize the uri */
1312   sanitize_uri (uri);
1313   state.uri = uri;
1314
1315   /* get the session if there is any */
1316   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
1317   if (res == GST_RTSP_OK) {
1318     if (client->session_pool == NULL)
1319       goto no_pool;
1320
1321     /* we had a session in the request, find it again */
1322     if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
1323       goto session_not_found;
1324
1325     /* we add the session to the client list of watched sessions. When a session
1326      * disappears because it times out, we will be notified. If all sessions are
1327      * gone, we will close the connection */
1328     client_watch_session (client, session);
1329   } else
1330     session = NULL;
1331
1332   state.session = session;
1333
1334   if (client->auth) {
1335     if (!gst_rtsp_auth_check (client->auth, client, 0, &state))
1336       goto not_authorized;
1337   }
1338
1339   /* now see what is asked and dispatch to a dedicated handler */
1340   switch (method) {
1341     case GST_RTSP_OPTIONS:
1342       handle_options_request (client, &state);
1343       break;
1344     case GST_RTSP_DESCRIBE:
1345       handle_describe_request (client, &state);
1346       break;
1347     case GST_RTSP_SETUP:
1348       handle_setup_request (client, &state);
1349       break;
1350     case GST_RTSP_PLAY:
1351       handle_play_request (client, &state);
1352       break;
1353     case GST_RTSP_PAUSE:
1354       handle_pause_request (client, &state);
1355       break;
1356     case GST_RTSP_TEARDOWN:
1357       handle_teardown_request (client, &state);
1358       break;
1359     case GST_RTSP_SET_PARAMETER:
1360       handle_set_param_request (client, &state);
1361       break;
1362     case GST_RTSP_GET_PARAMETER:
1363       handle_get_param_request (client, &state);
1364       break;
1365     case GST_RTSP_ANNOUNCE:
1366     case GST_RTSP_RECORD:
1367     case GST_RTSP_REDIRECT:
1368       send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state);
1369       break;
1370     case GST_RTSP_INVALID:
1371     default:
1372       send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1373       break;
1374   }
1375   if (session)
1376     g_object_unref (session);
1377
1378   gst_rtsp_url_free (uri);
1379   return;
1380
1381   /* ERRORS */
1382 no_pool:
1383   {
1384     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, &state);
1385     return;
1386   }
1387 session_not_found:
1388   {
1389     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1390     return;
1391   }
1392 not_authorized:
1393   {
1394     handle_unauthorized_request (client, client->auth, &state);
1395     return;
1396   }
1397 }
1398
1399 static void
1400 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
1401 {
1402   GstRTSPResult res;
1403   guint8 channel;
1404   GList *walk;
1405   guint8 *data;
1406   guint size;
1407   GstBuffer *buffer;
1408   gboolean handled;
1409
1410   /* find the stream for this message */
1411   res = gst_rtsp_message_parse_data (message, &channel);
1412   if (res != GST_RTSP_OK)
1413     return;
1414
1415   gst_rtsp_message_steal_body (message, &data, &size);
1416
1417   buffer = gst_buffer_new_wrapped (data, size);
1418
1419   handled = FALSE;
1420   for (walk = client->streams; walk; walk = g_list_next (walk)) {
1421     GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
1422     GstRTSPMediaStream *mstream;
1423     GstRTSPTransport *tr;
1424
1425     /* get the transport, if there is no transport configured, skip this stream */
1426     if (!(tr = stream->trans.transport))
1427       continue;
1428
1429     /* we also need a media stream */
1430     if (!(mstream = stream->media_stream))
1431       continue;
1432
1433     /* check for TCP transport */
1434     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1435       /* dispatch to the stream based on the channel number */
1436       if (tr->interleaved.min == channel) {
1437         gst_rtsp_media_stream_rtp (mstream, buffer);
1438         handled = TRUE;
1439         break;
1440       } else if (tr->interleaved.max == channel) {
1441         gst_rtsp_media_stream_rtcp (mstream, buffer);
1442         handled = TRUE;
1443         break;
1444       }
1445     }
1446   }
1447   if (!handled)
1448     gst_buffer_unref (buffer);
1449 }
1450
1451 /**
1452  * gst_rtsp_client_set_session_pool:
1453  * @client: a #GstRTSPClient
1454  * @pool: a #GstRTSPSessionPool
1455  *
1456  * Set @pool as the sessionpool for @client which it will use to find
1457  * or allocate sessions. the sessionpool is usually inherited from the server
1458  * that created the client but can be overridden later.
1459  */
1460 void
1461 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
1462     GstRTSPSessionPool * pool)
1463 {
1464   GstRTSPSessionPool *old;
1465
1466   old = client->session_pool;
1467   if (old != pool) {
1468     if (pool)
1469       g_object_ref (pool);
1470     client->session_pool = pool;
1471     if (old)
1472       g_object_unref (old);
1473   }
1474 }
1475
1476 /**
1477  * gst_rtsp_client_get_session_pool:
1478  * @client: a #GstRTSPClient
1479  *
1480  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1481  *
1482  * Returns: a #GstRTSPSessionPool, unref after usage.
1483  */
1484 GstRTSPSessionPool *
1485 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
1486 {
1487   GstRTSPSessionPool *result;
1488
1489   if ((result = client->session_pool))
1490     g_object_ref (result);
1491
1492   return result;
1493 }
1494
1495 /**
1496  * gst_rtsp_client_set_server:
1497  * @client: a #GstRTSPClient
1498  * @server: a #GstRTSPServer
1499  *
1500  * Set @server as the server that created @client.
1501  */
1502 void
1503 gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server)
1504 {
1505   GstRTSPServer *old;
1506
1507   old = client->server;
1508   if (old != server) {
1509     if (server)
1510       g_object_ref (server);
1511     client->server = server;
1512     if (old)
1513       g_object_unref (old);
1514   }
1515 }
1516
1517 /**
1518  * gst_rtsp_client_get_server:
1519  * @client: a #GstRTSPClient
1520  *
1521  * Get the #GstRTSPServer object that @client was created from.
1522  *
1523  * Returns: a #GstRTSPServer, unref after usage.
1524  */
1525 GstRTSPServer *
1526 gst_rtsp_client_get_server (GstRTSPClient * client)
1527 {
1528   GstRTSPServer *result;
1529
1530   if ((result = client->server))
1531     g_object_ref (result);
1532
1533   return result;
1534 }
1535
1536 /**
1537  * gst_rtsp_client_set_media_mapping:
1538  * @client: a #GstRTSPClient
1539  * @mapping: a #GstRTSPMediaMapping
1540  *
1541  * Set @mapping as the media mapping for @client which it will use to map urls
1542  * to media streams. These mapping is usually inherited from the server that
1543  * created the client but can be overriden later.
1544  */
1545 void
1546 gst_rtsp_client_set_media_mapping (GstRTSPClient * client,
1547     GstRTSPMediaMapping * mapping)
1548 {
1549   GstRTSPMediaMapping *old;
1550
1551   old = client->media_mapping;
1552
1553   if (old != mapping) {
1554     if (mapping)
1555       g_object_ref (mapping);
1556     client->media_mapping = mapping;
1557     if (old)
1558       g_object_unref (old);
1559   }
1560 }
1561
1562 /**
1563  * gst_rtsp_client_get_media_mapping:
1564  * @client: a #GstRTSPClient
1565  *
1566  * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
1567  *
1568  * Returns: a #GstRTSPMediaMapping, unref after usage.
1569  */
1570 GstRTSPMediaMapping *
1571 gst_rtsp_client_get_media_mapping (GstRTSPClient * client)
1572 {
1573   GstRTSPMediaMapping *result;
1574
1575   if ((result = client->media_mapping))
1576     g_object_ref (result);
1577
1578   return result;
1579 }
1580
1581 /**
1582  * gst_rtsp_client_set_auth:
1583  * @client: a #GstRTSPClient
1584  * @auth: a #GstRTSPAuth
1585  *
1586  * configure @auth to be used as the authentication manager of @client.
1587  */
1588 void
1589 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
1590 {
1591   GstRTSPAuth *old;
1592
1593   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1594
1595   old = client->auth;
1596
1597   if (old != auth) {
1598     if (auth)
1599       g_object_ref (auth);
1600     client->auth = auth;
1601     if (old)
1602       g_object_unref (old);
1603   }
1604 }
1605
1606
1607 /**
1608  * gst_rtsp_client_get_auth:
1609  * @client: a #GstRTSPClient
1610  *
1611  * Get the #GstRTSPAuth used as the authentication manager of @client.
1612  *
1613  * Returns: the #GstRTSPAuth of @client. g_object_unref() after
1614  * usage.
1615  */
1616 GstRTSPAuth *
1617 gst_rtsp_client_get_auth (GstRTSPClient * client)
1618 {
1619   GstRTSPAuth *result;
1620
1621   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1622
1623   if ((result = client->auth))
1624     g_object_ref (result);
1625
1626   return result;
1627 }
1628
1629 static GstRTSPResult
1630 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
1631     gpointer user_data)
1632 {
1633   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1634
1635   switch (message->type) {
1636     case GST_RTSP_MESSAGE_REQUEST:
1637       handle_request (client, message);
1638       break;
1639     case GST_RTSP_MESSAGE_RESPONSE:
1640       break;
1641     case GST_RTSP_MESSAGE_DATA:
1642       handle_data (client, message);
1643       break;
1644     default:
1645       break;
1646   }
1647   return GST_RTSP_OK;
1648 }
1649
1650 static GstRTSPResult
1651 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
1652 {
1653   /* GstRTSPClient *client; */
1654
1655   /* client = GST_RTSP_CLIENT (user_data); */
1656
1657   /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */
1658
1659   return GST_RTSP_OK;
1660 }
1661
1662 static GstRTSPResult
1663 closed (GstRTSPWatch * watch, gpointer user_data)
1664 {
1665   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1666   const gchar *tunnelid;
1667
1668   GST_INFO ("client %p: connection closed", client);
1669
1670   if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
1671     g_mutex_lock (&tunnels_lock);
1672     /* remove from tunnelids */
1673     g_hash_table_remove (tunnels, tunnelid);
1674     g_mutex_unlock (&tunnels_lock);
1675   }
1676
1677   return GST_RTSP_OK;
1678 }
1679
1680 static GstRTSPResult
1681 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
1682 {
1683   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1684   gchar *str;
1685
1686   str = gst_rtsp_strresult (result);
1687   GST_INFO ("client %p: received an error %s", client, str);
1688   g_free (str);
1689
1690   return GST_RTSP_OK;
1691 }
1692
1693 static GstRTSPResult
1694 error_full (GstRTSPWatch * watch, GstRTSPResult result,
1695     GstRTSPMessage * message, guint id, gpointer user_data)
1696 {
1697   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1698   gchar *str;
1699
1700   str = gst_rtsp_strresult (result);
1701   GST_INFO
1702       ("client %p: received an error %s when handling message %p with id %d",
1703       client, str, message, id);
1704   g_free (str);
1705
1706   return GST_RTSP_OK;
1707 }
1708
1709 static gboolean
1710 remember_tunnel (GstRTSPClient * client)
1711 {
1712   const gchar *tunnelid;
1713
1714   /* store client in the pending tunnels */
1715   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1716   if (tunnelid == NULL)
1717     goto no_tunnelid;
1718
1719   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
1720
1721   /* we can't have two clients connecting with the same tunnelid */
1722   g_mutex_lock (&tunnels_lock);
1723   if (g_hash_table_lookup (tunnels, tunnelid))
1724     goto tunnel_existed;
1725
1726   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
1727   g_mutex_unlock (&tunnels_lock);
1728
1729   return TRUE;
1730
1731   /* ERRORS */
1732 no_tunnelid:
1733   {
1734     GST_ERROR ("client %p: no tunnelid provided", client);
1735     return FALSE;
1736   }
1737 tunnel_existed:
1738   {
1739     g_mutex_unlock (&tunnels_lock);
1740     GST_ERROR ("client %p: tunnel session %s already existed", client,
1741         tunnelid);
1742     return FALSE;
1743   }
1744 }
1745
1746 static GstRTSPStatusCode
1747 tunnel_start (GstRTSPWatch * watch, gpointer user_data)
1748 {
1749   GstRTSPClient *client;
1750
1751   client = GST_RTSP_CLIENT (user_data);
1752
1753   GST_INFO ("client %p: tunnel start (connection %p)", client,
1754       client->connection);
1755
1756   if (!remember_tunnel (client))
1757     goto tunnel_error;
1758
1759   return GST_RTSP_STS_OK;
1760
1761   /* ERRORS */
1762 tunnel_error:
1763   {
1764     GST_ERROR ("client %p: error starting tunnel", client);
1765     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1766   }
1767 }
1768
1769 static GstRTSPResult
1770 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
1771 {
1772   GstRTSPClient *client;
1773
1774   client = GST_RTSP_CLIENT (user_data);
1775
1776   GST_INFO ("client %p: tunnel lost (connection %p)", client,
1777       client->connection);
1778
1779   /* ignore error, it'll only be a problem when the client does a POST again */
1780   remember_tunnel (client);
1781
1782   return GST_RTSP_OK;
1783 }
1784
1785 static GstRTSPResult
1786 tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
1787 {
1788   const gchar *tunnelid;
1789   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1790   GstRTSPClient *oclient;
1791
1792   GST_INFO ("client %p: tunnel complete", client);
1793
1794   /* find previous tunnel */
1795   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1796   if (tunnelid == NULL)
1797     goto no_tunnelid;
1798
1799   g_mutex_lock (&tunnels_lock);
1800   if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
1801     goto no_tunnel;
1802
1803   /* remove the old client from the table. ref before because removing it will
1804    * remove the ref to it. */
1805   g_object_ref (oclient);
1806   g_hash_table_remove (tunnels, tunnelid);
1807
1808   if (oclient->watch == NULL)
1809     goto tunnel_closed;
1810   g_mutex_unlock (&tunnels_lock);
1811
1812   GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
1813       oclient->connection, client->connection);
1814
1815   /* merge the tunnels into the first client */
1816   gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
1817   gst_rtsp_watch_reset (oclient->watch);
1818   g_object_unref (oclient);
1819
1820   /* we don't need this watch anymore */
1821   g_source_destroy ((GSource *) client->watch);
1822   client->watchid = 0;
1823   client->watch = NULL;
1824
1825   return GST_RTSP_OK;
1826
1827   /* ERRORS */
1828 no_tunnelid:
1829   {
1830     GST_INFO ("client %p: no tunnelid provided", client);
1831     return GST_RTSP_ERROR;
1832   }
1833 no_tunnel:
1834   {
1835     g_mutex_unlock (&tunnels_lock);
1836     GST_INFO ("client %p: tunnel session %s not found", client, tunnelid);
1837     return GST_RTSP_ERROR;
1838   }
1839 tunnel_closed:
1840   {
1841     g_mutex_unlock (&tunnels_lock);
1842     GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid);
1843     g_object_unref (oclient);
1844     return GST_RTSP_ERROR;
1845   }
1846 }
1847
1848 static GstRTSPWatchFuncs watch_funcs = {
1849   message_received,
1850   message_sent,
1851   closed,
1852   error,
1853   tunnel_start,
1854   tunnel_complete,
1855   error_full,
1856   tunnel_lost
1857 };
1858
1859 static void
1860 client_watch_notify (GstRTSPClient * client)
1861 {
1862   GST_INFO ("client %p: watch destroyed", client);
1863   client->watchid = 0;
1864   client->watch = NULL;
1865   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
1866   g_object_unref (client);
1867 }
1868
1869 /**
1870  * gst_rtsp_client_attach:
1871  * @client: a #GstRTSPClient
1872  * @socket: a #GSocket
1873  * @cancellable: a #GCancellable
1874  * @error: a #GError
1875  *
1876  * Accept a new connection for @client on @socket.
1877  *
1878  * This function should be called when the client properties and urls are fully
1879  * configured and the client is ready to start.
1880  *
1881  * Returns: %TRUE if the client could be accepted.
1882  */
1883 gboolean
1884 gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket,
1885     GCancellable * cancellable, GError ** error)
1886 {
1887   GstRTSPConnection *conn;
1888   GstRTSPResult res;
1889   GSocket *read_socket;
1890   GSocketAddress *addres;
1891   GSource *source;
1892   GMainContext *context;
1893   GstRTSPUrl *url;
1894   struct sockaddr_storage addr;
1895   socklen_t addrlen;
1896   gchar ip[INET6_ADDRSTRLEN];
1897
1898   /* a new client connected. */
1899   GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable),
1900       accept_failed);
1901
1902   read_socket = gst_rtsp_connection_get_read_socket (conn);
1903   client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6;
1904
1905   if (!(addres = g_socket_get_remote_address (read_socket, error)))
1906     goto no_address;
1907
1908   addrlen = sizeof (addr);
1909   if (!g_socket_address_to_native (addres, &addr, addrlen, error))
1910     goto native_failed;
1911   g_object_unref (addres);
1912
1913   if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0,
1914           NI_NUMERICHOST) != 0)
1915     goto getnameinfo_failed;
1916
1917   /* keep the original ip that the client connected to */
1918   g_free (client->server_ip);
1919   client->server_ip = g_strndup (ip, sizeof (ip));
1920
1921   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
1922       client->server_ip, client->is_ipv6);
1923
1924   url = gst_rtsp_connection_get_url (conn);
1925   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
1926
1927   client->connection = conn;
1928
1929   /* create watch for the connection and attach */
1930   client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
1931       g_object_ref (client), (GDestroyNotify) client_watch_notify);
1932
1933   /* find the context to add the watch */
1934   if ((source = g_main_current_source ()))
1935     context = g_source_get_context (source);
1936   else
1937     context = NULL;
1938
1939   GST_INFO ("attaching to context %p", context);
1940
1941   client->watchid = gst_rtsp_watch_attach (client->watch, context);
1942   gst_rtsp_watch_unref (client->watch);
1943
1944   return TRUE;
1945
1946   /* ERRORS */
1947 accept_failed:
1948   {
1949     gchar *str = gst_rtsp_strresult (res);
1950
1951     GST_ERROR ("Could not accept client on server socket %p: %s", socket, str);
1952     g_free (str);
1953     return FALSE;
1954   }
1955 no_address:
1956   {
1957     GST_ERROR ("could not get remote address %s", (*error)->message);
1958     return FALSE;
1959   }
1960 native_failed:
1961   {
1962     g_object_unref (addres);
1963     GST_ERROR ("could not get native address %s", (*error)->message);
1964     return FALSE;
1965   }
1966 getnameinfo_failed:
1967   {
1968     GST_ERROR ("getnameinfo failed: %s", g_strerror (errno));
1969     return FALSE;
1970   }
1971 }