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