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