allow pause requests for now.
[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 <sys/ioctl.h>
21
22 #include "rtsp-client.h"
23 #include "rtsp-sdp.h"
24
25 #define DEBUG
26
27 static GMutex *tunnels_lock;
28 static GHashTable *tunnels;
29
30 enum
31 {
32   PROP_0,
33   PROP_SESSION_POOL,
34   PROP_MEDIA_MAPPING,
35   PROP_LAST
36 };
37
38 static void gst_rtsp_client_get_property (GObject *object, guint propid,
39     GValue *value, GParamSpec *pspec);
40 static void gst_rtsp_client_set_property (GObject *object, guint propid,
41     const GValue *value, GParamSpec *pspec);
42 static void gst_rtsp_client_finalize (GObject * obj);
43
44 static void client_session_finalized (GstRTSPClient *client, GstRTSPSession *session);
45
46 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
47
48 static void
49 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
50 {
51   GObjectClass *gobject_class;
52
53   gobject_class = G_OBJECT_CLASS (klass);
54
55   gobject_class->get_property = gst_rtsp_client_get_property;
56   gobject_class->set_property = gst_rtsp_client_set_property;
57   gobject_class->finalize = gst_rtsp_client_finalize;
58
59   g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
60       g_param_spec_object ("session-pool", "Session Pool",
61           "The session pool to use for client session",
62           GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
63
64   g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING,
65       g_param_spec_object ("media-mapping", "Media Mapping",
66           "The media mapping to use for client session",
67           GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
68
69   tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
70   tunnels_lock = g_mutex_new ();
71 }
72
73 static void
74 gst_rtsp_client_init (GstRTSPClient * client)
75 {
76 }
77
78 /* A client is finalized when the connection is broken */
79 static void
80 gst_rtsp_client_finalize (GObject * obj)
81 {
82   GstRTSPClient *client = GST_RTSP_CLIENT (obj);
83   GList *walk;
84
85   g_message ("finalize client %p", client);
86
87   for (walk = client->sessions; walk; walk = g_list_next (walk))
88     g_object_weak_unref (G_OBJECT (walk->data), (GWeakNotify) client_session_finalized, client);
89   g_list_free (client->sessions);
90
91   gst_rtsp_connection_free (client->connection);
92   if (client->session_pool)
93     g_object_unref (client->session_pool);
94   if (client->media_mapping)
95     g_object_unref (client->media_mapping);
96
97   if (client->uri)
98     gst_rtsp_url_free (client->uri);
99   if (client->media)
100     g_object_unref (client->media);
101
102   G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
103 }
104
105 static void
106 gst_rtsp_client_get_property (GObject *object, guint propid,
107     GValue *value, GParamSpec *pspec)
108 {
109   GstRTSPClient *client = GST_RTSP_CLIENT (object);
110
111   switch (propid) {
112     case PROP_SESSION_POOL:
113       g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
114       break;
115     case PROP_MEDIA_MAPPING:
116       g_value_take_object (value, gst_rtsp_client_get_media_mapping (client));
117       break;
118     default:
119       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
120   }
121 }
122
123 static void
124 gst_rtsp_client_set_property (GObject *object, guint propid,
125     const GValue *value, GParamSpec *pspec)
126 {
127   GstRTSPClient *client = GST_RTSP_CLIENT (object);
128
129   switch (propid) {
130     case PROP_SESSION_POOL:
131       gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
132       break;
133     case PROP_MEDIA_MAPPING:
134       gst_rtsp_client_set_media_mapping (client, g_value_get_object (value));
135       break;
136     default:
137       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
138   }
139 }
140
141 /**
142  * gst_rtsp_client_new:
143  *
144  * Create a new #GstRTSPClient instance.
145  */
146 GstRTSPClient *
147 gst_rtsp_client_new (void)
148 {
149   GstRTSPClient *result;
150
151   result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
152
153   return result;
154 }
155
156 static void
157 send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *response)
158 {
159   gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server");
160
161   /* remove any previous header */
162   gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1);
163
164   /* add the new session header for new session ids */
165   if (session) {
166     gchar *str;
167
168     if (session->timeout != 60)
169       str = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout);
170     else
171       str = g_strdup (session->sessionid);
172
173     gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str);
174   }
175
176 #ifdef DEBUG
177   gst_rtsp_message_dump (response);
178 #endif
179
180   gst_rtsp_watch_queue_message (client->watch, response);
181   gst_rtsp_message_unset (response);
182 }
183
184 static void
185 send_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, 
186     GstRTSPMessage *request)
187 {
188   GstRTSPMessage response = { 0 };
189
190   gst_rtsp_message_init_response (&response, code, 
191         gst_rtsp_status_as_text (code), request);
192
193   send_response (client, NULL, &response);
194 }
195
196 static gboolean
197 compare_uri (const GstRTSPUrl *uri1, const GstRTSPUrl *uri2)
198 {
199   if (uri1 == NULL || uri2 == NULL)
200     return FALSE;
201
202   if (strcmp (uri1->abspath, uri2->abspath))
203     return FALSE;
204
205   return TRUE;
206 }
207
208 /* this function is called to initially find the media for the DESCRIBE request
209  * but is cached for when the same client (without breaking the connection) is
210  * doing a setup for the exact same url. */
211 static GstRTSPMedia *
212 find_media (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request)
213 {
214   GstRTSPMediaFactory *factory;
215   GstRTSPMedia *media;
216
217   if (!compare_uri (client->uri, uri)) {
218     /* remove any previously cached values before we try to construct a new
219      * media for uri */
220     if (client->uri)
221       gst_rtsp_url_free (client->uri);
222     client->uri = NULL;
223     if (client->media)
224       g_object_unref (client->media);
225     client->media = NULL;
226
227     if (!client->media_mapping)
228       goto no_mapping;
229
230     /* find the factory for the uri first */
231     if (!(factory = gst_rtsp_media_mapping_find_factory (client->media_mapping, uri)))
232       goto no_factory;
233
234     /* prepare the media and add it to the pipeline */
235     if (!(media = gst_rtsp_media_factory_construct (factory, uri)))
236       goto no_media;
237
238     /* prepare the media */
239     if (!(gst_rtsp_media_prepare (media)))
240       goto no_prepare;
241
242     /* now keep track of the uri and the media */
243     client->uri = gst_rtsp_url_copy (uri);
244     client->media = media;
245   }
246   else {
247     /* we have seen this uri before, used cached media */
248     media = client->media;
249     g_message ("reusing cached media %p", media); 
250   }
251
252   if (media)
253     g_object_ref (media);
254
255   return media;
256
257   /* ERRORS */
258 no_mapping:
259   {
260     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
261     return NULL;
262   }
263 no_factory:
264   {
265     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
266     return NULL;
267   }
268 no_media:
269   {
270     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
271     g_object_unref (factory);
272     return NULL;
273   }
274 no_prepare:
275   {
276     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
277     g_object_unref (media);
278     g_object_unref (factory);
279     return NULL;
280   }
281 }
282
283 static gboolean
284 do_send_data (GstBuffer *buffer, guint8 channel, GstRTSPClient *client)
285 {
286   GstRTSPMessage message = { 0 };
287   guint8 *data;
288   guint size;
289
290   gst_rtsp_message_init_data (&message, channel);
291
292   data = GST_BUFFER_DATA (buffer);
293   size = GST_BUFFER_SIZE (buffer);
294   gst_rtsp_message_take_body (&message, data, size);
295
296   gst_rtsp_watch_queue_message (client->watch, &message);
297
298   gst_rtsp_message_steal_body (&message, &data, &size);
299   gst_rtsp_message_unset (&message);
300
301   return TRUE;
302 }
303
304 static void
305 link_stream (GstRTSPClient *client, GstRTSPSessionStream *stream)
306 {
307   gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data,
308        (GstRTSPSendFunc) do_send_data, client, NULL);
309   client->streams = g_list_prepend (client->streams, stream);
310 }
311
312 static void
313 unlink_stream (GstRTSPClient *client, GstRTSPSessionStream *stream)
314 {
315   gst_rtsp_session_stream_set_callbacks (stream, NULL,
316        NULL, client, g_object_unref);
317   client->streams = g_list_remove (client->streams, stream);
318 }
319
320 static void
321 unlink_streams (GstRTSPClient *client)
322 {
323   GList *walk;
324
325   for (walk = client->streams; walk; walk = g_list_next (walk)) {
326     GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
327
328     gst_rtsp_session_stream_set_callbacks (stream, NULL,
329          NULL, NULL, NULL);
330   }
331   g_list_free (client->streams);
332   client->streams = NULL;
333 }
334
335 static void
336 unlink_session_streams (GstRTSPClient *client, GstRTSPSessionMedia *media)
337 {
338   guint n_streams, i;
339
340   n_streams = gst_rtsp_media_n_streams (media->media);
341   for (i = 0; i < n_streams; i++) {
342     GstRTSPSessionStream *sstream;
343     GstRTSPTransport *tr;
344
345     /* get the stream as configured in the session */
346     sstream = gst_rtsp_session_media_get_stream (media, i);
347     /* get the transport, if there is no transport configured, skip this stream */
348     if (!(tr = sstream->trans.transport))
349       continue;
350
351     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
352       /* for TCP, unlink the stream from the TCP connection of the client */
353       unlink_stream (client, sstream);
354     }
355   }
356 }
357
358 static gboolean
359 handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
360 {
361   GstRTSPSessionMedia *media;
362   GstRTSPMessage response = { 0 };
363   GstRTSPStatusCode code;
364
365   if (!session)
366     goto no_session;
367
368   /* get a handle to the configuration of the media in the session */
369   media = gst_rtsp_session_get_media (session, uri);
370   if (!media)
371     goto not_found;
372
373   /* unlink the all TCP callbacks */
374   unlink_session_streams (client, media);
375
376   /* remove the session from the watched sessions */
377   g_object_weak_unref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client);
378   client->sessions = g_list_remove (client->sessions, session);
379
380   gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
381
382   /* unmanage the media in the session, returns false if all media session
383    * are torn down. */
384   if (!gst_rtsp_session_release_media (session, media)) {
385     /* remove the session */
386     gst_rtsp_session_pool_remove (client->session_pool, session);
387   }
388   /* construct the response now */
389   code = GST_RTSP_STS_OK;
390   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
391
392   send_response (client, session, &response);
393
394   return FALSE;
395
396   /* ERRORS */
397 no_session:
398   {
399     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
400     return FALSE;
401   }
402 not_found:
403   {
404     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
405     return FALSE;
406   }
407 }
408
409 static gboolean
410 handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
411 {
412   GstRTSPSessionMedia *media;
413   GstRTSPMessage response = { 0 };
414   GstRTSPStatusCode code;
415
416   if (!session)
417     goto no_session;
418
419   /* get a handle to the configuration of the media in the session */
420   media = gst_rtsp_session_get_media (session, uri);
421   if (!media)
422     goto not_found;
423
424   /* the session state must be playing or recording */
425   if (media->state != GST_RTSP_STATE_PLAYING &&
426       media->state != GST_RTSP_STATE_RECORDING)
427     goto invalid_state;
428
429   /* unlink the all TCP callbacks */
430   unlink_session_streams (client, media);
431
432   /* then pause sending */
433   gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
434
435   /* construct the response now */
436   code = GST_RTSP_STS_OK;
437   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
438
439   send_response (client, session, &response);
440
441   /* the state is now READY */
442   media->state = GST_RTSP_STATE_READY;
443
444   return FALSE;
445
446   /* ERRORS */
447 no_session:
448   {
449     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
450     return FALSE;
451   }
452 not_found:
453   {
454     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
455     return FALSE;
456   }
457 invalid_state:
458   {
459     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
460     return FALSE;
461   }
462 }
463
464 static gboolean
465 handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
466 {
467   GstRTSPSessionMedia *media;
468   GstRTSPMessage response = { 0 };
469   GstRTSPStatusCode code;
470   GString *rtpinfo;
471   guint n_streams, i;
472   guint timestamp, seqnum;
473   gchar *str;
474
475   if (!session)
476     goto no_session;
477
478   /* get a handle to the configuration of the media in the session */
479   media = gst_rtsp_session_get_media (session, uri);
480   if (!media)
481     goto not_found;
482
483   /* the session state must be playing or ready */
484   if (media->state != GST_RTSP_STATE_PLAYING &&
485       media->state != GST_RTSP_STATE_READY)
486     goto invalid_state;
487
488   /* grab RTPInfo from the payloaders now */
489   rtpinfo = g_string_new ("");
490
491   n_streams = gst_rtsp_media_n_streams (media->media);
492   for (i = 0; i < n_streams; i++) {
493     GstRTSPSessionStream *sstream;
494     GstRTSPMediaStream *stream;
495     GstRTSPTransport *tr;
496     gchar *uristr;
497
498     /* get the stream as configured in the session */
499     sstream = gst_rtsp_session_media_get_stream (media, i);
500     /* get the transport, if there is no transport configured, skip this stream */
501     if (!(tr = sstream->trans.transport))
502       continue;
503
504     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
505       /* for TCP, link the stream to the TCP connection of the client */
506       link_stream (client, sstream);
507     }
508
509     stream = sstream->media_stream;
510
511     g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL);
512     g_object_get (G_OBJECT (stream->payloader), "timestamp", &timestamp, NULL);
513
514     if (i > 0)
515       g_string_append (rtpinfo, ", ");
516
517     uristr = gst_rtsp_url_get_request_uri (uri);
518     g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp);
519     g_free (uristr);
520   }
521
522   /* construct the response now */
523   code = GST_RTSP_STS_OK;
524   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
525
526   /* add the RTP-Info header */
527   str = g_string_free (rtpinfo, FALSE);
528   gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str);
529
530   /* add the range */
531   str = gst_rtsp_range_to_string (&media->media->range);
532   gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str);
533
534   send_response (client, session, &response);
535
536   /* start playing after sending the request */
537   gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
538
539   media->state = GST_RTSP_STATE_PLAYING;
540
541   return FALSE;
542
543   /* ERRORS */
544 no_session:
545   {
546     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
547     return FALSE;
548   }
549 not_found:
550   {
551     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
552     return FALSE;
553   }
554 invalid_state:
555   {
556     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
557     return FALSE;
558   }
559 }
560
561 static gboolean
562 handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
563 {
564   GstRTSPResult res;
565   gchar *transport;
566   gchar **transports;
567   gboolean have_transport;
568   GstRTSPTransport *ct, *st;
569   gint i;
570   GstRTSPLowerTrans supported;
571   GstRTSPMessage response = { 0 };
572   GstRTSPStatusCode code;
573   GstRTSPSessionStream *stream;
574   gchar *trans_str, *pos;
575   guint streamid;
576   GstRTSPSessionMedia *media;
577   gboolean need_session;
578   GstRTSPUrl *url;
579
580   /* the uri contains the stream number we added in the SDP config, which is
581    * always /stream=%d so we need to strip that off 
582    * parse the stream we need to configure, look for the stream in the abspath
583    * first and then in the query. */
584   if (!(pos = strstr (uri->abspath, "/stream="))) {
585     if (!(pos = strstr (uri->query, "/stream=")))
586       goto bad_request;
587   }
588
589   /* we can mofify the parse uri in place */
590   *pos = '\0';
591
592   pos += strlen ("/stream=");
593   if (sscanf (pos, "%u", &streamid) != 1)
594     goto bad_request;
595
596   /* parse the transport */
597   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, 0);
598   if (res != GST_RTSP_OK)
599     goto no_transport;
600
601   transports = g_strsplit (transport, ",", 0);
602   gst_rtsp_transport_new (&ct);  
603
604   /* loop through the transports, try to parse */
605   have_transport = FALSE;
606   for (i = 0; transports[i]; i++) {
607
608     gst_rtsp_transport_init (ct);  
609     res = gst_rtsp_transport_parse (transports[i], ct);
610     if (res == GST_RTSP_OK) {
611       have_transport = TRUE;
612       break;
613     }
614   }
615   g_strfreev (transports);
616
617   /* we have not found anything usable, error out */
618   if (!have_transport) 
619     goto unsupported_transports;
620
621   /* we have a valid transport, check if we can handle it */
622   if (ct->trans != GST_RTSP_TRANS_RTP)
623     goto unsupported_transports;
624   if (ct->profile != GST_RTSP_PROFILE_AVP)
625     goto unsupported_transports;
626
627   supported = GST_RTSP_LOWER_TRANS_UDP |
628         GST_RTSP_LOWER_TRANS_UDP_MCAST |
629         GST_RTSP_LOWER_TRANS_TCP;
630   if (!(ct->lower_transport & supported))
631     goto unsupported_transports;
632
633   if (client->session_pool == NULL)
634     goto no_pool;
635
636   /* we have a valid transport now, set the destination of the client. */
637   g_free (ct->destination);
638   url = gst_rtsp_connection_get_url (client->connection);
639   ct->destination = g_strdup (url->host);
640
641   if (session) {
642     g_object_ref (session);
643     /* get a handle to the configuration of the media in the session, this can
644      * return NULL if this is a new url to manage in this session. */
645     media = gst_rtsp_session_get_media (session, uri);
646
647     need_session = FALSE;
648   }
649   else {
650     /* create a session if this fails we probably reached our session limit or
651      * something. */
652     if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
653       goto service_unavailable;
654
655     /* we need a new media configuration in this session */
656     media = NULL;
657
658     need_session = TRUE;
659   }
660
661   /* we have no media, find one and manage it */
662   if (media == NULL) {
663     GstRTSPMedia *m;
664
665     /* get a handle to the configuration of the media in the session */
666     if ((m = find_media (client, uri, request))) {
667       /* manage the media in our session now */
668       media = gst_rtsp_session_manage_media (session, uri, m);
669     }
670   }
671
672   /* if we stil have no media, error */
673   if (media == NULL)
674     goto not_found;
675
676   /* get a handle to the stream in the media */
677   if (!(stream = gst_rtsp_session_media_get_stream (media, streamid)))
678     goto no_stream;
679
680   st = gst_rtsp_session_stream_set_transport (stream, ct);
681
682   /* serialize the server transport */
683   trans_str = gst_rtsp_transport_as_text (st);
684   gst_rtsp_transport_free (st);
685
686   /* construct the response now */
687   code = GST_RTSP_STS_OK;
688   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
689
690   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str);
691   g_free (trans_str);
692
693   send_response (client, session, &response);
694
695   /* update the state */
696   switch (media->state) {
697     case GST_RTSP_STATE_PLAYING:
698     case GST_RTSP_STATE_RECORDING:
699     case GST_RTSP_STATE_READY:
700       /* no state change */
701       break;
702     default:
703       media->state = GST_RTSP_STATE_READY;
704       break;
705   }
706   g_object_unref (session);
707
708   return TRUE;
709
710   /* ERRORS */
711 bad_request:
712   {
713     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
714     return FALSE;
715   }
716 not_found:
717   {
718     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
719     g_object_unref (session);
720     return FALSE;
721   }
722 no_stream:
723   {
724     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
725     g_object_unref (media);
726     g_object_unref (session);
727     return FALSE;
728   }
729 no_transport:
730   {
731     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
732     return FALSE;
733   }
734 unsupported_transports:
735   {
736     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
737     gst_rtsp_transport_free (ct);  
738     return FALSE;
739   }
740 no_pool:
741   {
742     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
743     return FALSE;
744   }
745 service_unavailable:
746   {
747     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
748     return FALSE;
749   }
750 }
751
752 /* for the describe we must generate an SDP */
753 static gboolean
754 handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
755 {
756   GstRTSPMessage response = { 0 };
757   GstRTSPResult res;
758   GstSDPMessage *sdp;
759   guint i;
760   gchar *str;
761   GstRTSPMedia *media;
762
763   /* check what kind of format is accepted, we don't really do anything with it
764    * and always return SDP for now. */
765   for (i = 0; i++; ) {
766     gchar *accept;
767
768     res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i);
769     if (res == GST_RTSP_ENOTIMPL)
770       break;
771
772     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
773       break;
774   }
775
776   /* find the media object for the uri */
777   if (!(media = find_media (client, uri, request)))
778     goto no_media;
779
780   /* create an SDP for the media object */
781   if (!(sdp = gst_rtsp_sdp_from_media (media)))
782     goto no_sdp;
783
784   g_object_unref (media);
785
786   gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, 
787         gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
788
789   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp");
790
791   /* content base for some clients that might screw up creating the setup uri */
792   str = g_strdup_printf ("rtsp://%s:%u%s/", uri->host, uri->port, uri->abspath);
793   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, str);
794   g_free (str);
795
796   /* add SDP to the response body */
797   str = gst_sdp_message_as_text (sdp);
798   gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str));
799   gst_sdp_message_free (sdp);
800
801   send_response (client, session, &response);
802
803   return TRUE;
804
805   /* ERRORS */
806 no_media:
807   {
808     /* error reply is already sent */
809     return FALSE;
810   }
811 no_sdp:
812   {
813     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
814     g_object_unref (media);
815     return FALSE;
816   }
817 }
818
819 static void
820 handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
821 {
822   GstRTSPMessage response = { 0 };
823   GstRTSPMethod options;
824   gchar *str;
825
826   options = GST_RTSP_DESCRIBE |
827             GST_RTSP_OPTIONS |
828             GST_RTSP_PAUSE |
829             GST_RTSP_PLAY |
830             GST_RTSP_SETUP |
831             GST_RTSP_TEARDOWN;
832
833   str = gst_rtsp_options_as_text (options);
834
835   gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, 
836         gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
837
838   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str);
839   g_free (str);
840
841   send_response (client, session, &response);
842 }
843
844 /* remove duplicate and trailing '/' */
845 static void
846 santize_uri (GstRTSPUrl *uri)
847 {
848   gint i, len;
849   gchar *s, *d;
850   gboolean have_slash, prev_slash;
851
852   s = d = uri->abspath;
853   len = strlen (uri->abspath);
854
855   prev_slash = FALSE;
856
857   for (i = 0; i < len; i++) {
858     have_slash = s[i] == '/';
859     *d = s[i];
860     if (!have_slash || !prev_slash)
861       d++;
862     prev_slash = have_slash;
863   }
864   len = d - uri->abspath;
865   /* don't remove the first slash if that's the only thing left */
866   if (len > 1 && *(d-1) == '/')
867     d--;
868   *d = '\0';
869 }
870
871 static void
872 client_session_finalized (GstRTSPClient *client, GstRTSPSession *session)
873 {
874   if (!(client->sessions = g_list_remove (client->sessions, session))) {
875     g_message ("all sessions finalized, close the connection");
876     g_source_destroy ((GSource*)client->watch);
877   }
878 }
879
880 static void
881 client_watch_session (GstRTSPClient *client, GstRTSPSession *session)
882 {
883   GList *walk;
884
885   for (walk = client->sessions; walk; walk = g_list_next (walk)) {
886     GstRTSPSession *msession = (GstRTSPSession *) walk->data;
887
888     /* we already know about this session */
889     if (msession == session)
890       return;
891   }
892
893   g_message ("watching session %p", session);
894
895   g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client);
896   client->sessions = g_list_prepend (client->sessions, session);
897 }
898
899 static void
900 handle_request (GstRTSPClient *client, GstRTSPMessage *request)
901 {
902   GstRTSPMethod method;
903   const gchar *uristr;
904   GstRTSPUrl *uri;
905   GstRTSPVersion version;
906   GstRTSPResult res;
907   GstRTSPSession *session;
908   gchar *sessid;
909
910 #ifdef DEBUG
911   gst_rtsp_message_dump (request);
912 #endif
913
914   g_message ("client %p: received a request", client);
915
916   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
917
918   if (version != GST_RTSP_VERSION_1_0) {
919     /* we can only handle 1.0 requests */
920     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, request);
921     return;
922   }
923
924   /* we always try to parse the url first */
925   if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) {
926     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
927     return;
928   }
929
930   /* sanitize the uri */
931   santize_uri (uri);
932
933   /* get the session if there is any */
934   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
935   if (res == GST_RTSP_OK) {
936     if (client->session_pool == NULL)
937       goto no_pool;
938
939     /* we had a session in the request, find it again */
940     if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
941       goto session_not_found;
942
943     /* we add the session to the client list of watched sessions. When a session
944      * disappears because it times out, we will be notified. If all sessions are
945      * gone, we will close the connection */
946     client_watch_session (client, session);
947   }
948   else
949     session = NULL;
950
951   /* now see what is asked and dispatch to a dedicated handler */
952   switch (method) {
953     case GST_RTSP_OPTIONS:
954       handle_options_request (client, uri, session, request);
955       break;
956     case GST_RTSP_DESCRIBE:
957       handle_describe_request (client, uri, session, request);
958       break;
959     case GST_RTSP_SETUP:
960       handle_setup_request (client, uri, session, request);
961       break;
962     case GST_RTSP_PLAY:
963       handle_play_request (client, uri, session, request);
964       break;
965     case GST_RTSP_PAUSE:
966       handle_pause_request (client, uri, session, request);
967       break;
968     case GST_RTSP_TEARDOWN:
969       handle_teardown_request (client, uri, session, request);
970       break;
971     case GST_RTSP_ANNOUNCE:
972     case GST_RTSP_GET_PARAMETER:
973     case GST_RTSP_RECORD:
974     case GST_RTSP_REDIRECT:
975     case GST_RTSP_SET_PARAMETER:
976       send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, request);
977       break;
978     case GST_RTSP_INVALID:
979     default:
980       send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
981       break;
982   }
983   if (session)
984     g_object_unref (session);
985
986   gst_rtsp_url_free (uri);
987   return;
988
989   /* ERRORS */
990 no_pool:
991   {
992     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
993     return;
994   }
995 session_not_found:
996   {
997     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
998     return;
999   }
1000 }
1001
1002 static void
1003 handle_data (GstRTSPClient *client, GstRTSPMessage *message)
1004 {
1005   GstRTSPResult res;
1006   guint8 channel;
1007   GList *walk;
1008   guint8 *data;
1009   guint size;
1010   GstBuffer *buffer;
1011
1012   /* find the stream for this message */ 
1013   res = gst_rtsp_message_parse_data (message, &channel);
1014   if (res != GST_RTSP_OK)
1015     return;
1016
1017   gst_rtsp_message_steal_body (message, &data, &size);
1018
1019   buffer = gst_buffer_new ();
1020   GST_BUFFER_DATA (buffer) = data;
1021   GST_BUFFER_MALLOCDATA (buffer) = data;
1022   GST_BUFFER_SIZE (buffer) = size;
1023
1024   for (walk = client->streams; walk; walk = g_list_next (walk)) {
1025     GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
1026     GstRTSPMediaStream *mstream;
1027     GstRTSPTransport *tr;
1028
1029     /* get the transport, if there is no transport configured, skip this stream */
1030     if (!(tr = stream->trans.transport))
1031       continue;
1032
1033     /* we also need a media stream */
1034     if (!(mstream = stream->media_stream))
1035       continue;
1036
1037     /* check for TCP transport */
1038     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1039       /* dispatch to the stream based on the channel number */
1040       if (tr->interleaved.min == channel) {
1041         gst_rtsp_media_stream_rtp (mstream, buffer);
1042       } else if (tr->interleaved.max == channel) {
1043         gst_rtsp_media_stream_rtcp (mstream, buffer);
1044       }
1045     }
1046   }
1047   gst_buffer_unref (buffer);
1048 }
1049
1050 /**
1051  * gst_rtsp_client_set_session_pool:
1052  * @client: a #GstRTSPClient
1053  * @pool: a #GstRTSPSessionPool
1054  *
1055  * Set @pool as the sessionpool for @client which it will use to find
1056  * or allocate sessions. the sessionpool is usually inherited from the server
1057  * that created the client but can be overridden later.
1058  */
1059 void
1060 gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool)
1061 {
1062   GstRTSPSessionPool *old;
1063
1064   old = client->session_pool;
1065   if (old != pool) {
1066     if (pool)
1067       g_object_ref (pool);
1068     client->session_pool = pool;
1069     if (old)
1070       g_object_unref (old);
1071   }
1072 }
1073
1074 /**
1075  * gst_rtsp_client_get_session_pool:
1076  * @client: a #GstRTSPClient
1077  *
1078  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1079  *
1080  * Returns: a #GstRTSPSessionPool, unref after usage.
1081  */
1082 GstRTSPSessionPool *
1083 gst_rtsp_client_get_session_pool (GstRTSPClient *client)
1084 {
1085   GstRTSPSessionPool *result;
1086
1087   if ((result = client->session_pool))
1088     g_object_ref (result);
1089
1090   return result;
1091 }
1092
1093 /**
1094  * gst_rtsp_client_set_media_mapping:
1095  * @client: a #GstRTSPClient
1096  * @mapping: a #GstRTSPMediaMapping
1097  *
1098  * Set @mapping as the media mapping for @client which it will use to map urls
1099  * to media streams. These mapping is usually inherited from the server that
1100  * created the client but can be overriden later.
1101  */
1102 void
1103 gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping)
1104 {
1105   GstRTSPMediaMapping *old;
1106
1107   old = client->media_mapping;
1108
1109   if (old != mapping) {
1110     if (mapping)
1111       g_object_ref (mapping);
1112     client->media_mapping = mapping;
1113     if (old)
1114       g_object_unref (old);
1115   }
1116 }
1117
1118 /**
1119  * gst_rtsp_client_get_media_mapping:
1120  * @client: a #GstRTSPClient
1121  *
1122  * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
1123  *
1124  * Returns: a #GstRTSPMediaMapping, unref after usage.
1125  */
1126 GstRTSPMediaMapping *
1127 gst_rtsp_client_get_media_mapping (GstRTSPClient *client)
1128 {
1129   GstRTSPMediaMapping *result;
1130
1131   if ((result = client->media_mapping))
1132     g_object_ref (result);
1133
1134   return result;
1135 }
1136
1137 static GstRTSPResult
1138 message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_data)
1139 {
1140   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1141
1142   switch (message->type) {
1143     case GST_RTSP_MESSAGE_REQUEST:
1144       handle_request (client, message);
1145       break;
1146     case GST_RTSP_MESSAGE_RESPONSE:
1147       break;
1148     case GST_RTSP_MESSAGE_DATA:
1149       handle_data (client, message);
1150       break;
1151     default:
1152       break;
1153   }
1154   return GST_RTSP_OK;
1155 }
1156
1157 static GstRTSPResult
1158 message_sent (GstRTSPWatch *watch, guint cseq, gpointer user_data)
1159 {
1160   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1161
1162   g_message ("client %p: sent a message with cseq %d", client, cseq);
1163
1164   return GST_RTSP_OK;
1165 }
1166
1167 static GstRTSPResult
1168 closed (GstRTSPWatch *watch, gpointer user_data)
1169 {
1170   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1171   const gchar *tunnelid;
1172
1173   g_message ("client %p: connection closed", client);
1174
1175   if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
1176     g_mutex_lock (tunnels_lock);
1177     g_hash_table_remove (tunnels, tunnelid);
1178     g_mutex_unlock (tunnels_lock);
1179   }
1180
1181   /* remove all streams that are streaming over this client connection */
1182   unlink_streams (client);
1183
1184   return GST_RTSP_OK;
1185 }
1186
1187 static GstRTSPResult
1188 error (GstRTSPWatch *watch, GstRTSPResult result, gpointer user_data)
1189 {
1190   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1191   gchar *str;
1192
1193   str = gst_rtsp_strresult (result);
1194   g_message ("client %p: received an error %s", client, str);
1195   g_free (str);
1196
1197   return GST_RTSP_OK;
1198 }
1199
1200 static GstRTSPStatusCode
1201 tunnel_start (GstRTSPWatch *watch, gpointer user_data)
1202 {
1203   GstRTSPClient *client;
1204   const gchar *tunnelid;
1205
1206   client = GST_RTSP_CLIENT (user_data);
1207
1208   g_message ("client %p: tunnel start", client);
1209
1210   /* store client in the pending tunnels */
1211   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1212
1213   g_message ("client %p: inserting %s", client, tunnelid);
1214
1215   /* we can't have two clients connecting with the same tunnelid */
1216   g_mutex_lock (tunnels_lock);
1217   if (g_hash_table_lookup (tunnels, tunnelid))
1218     goto tunnel_existed;
1219
1220   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
1221   g_mutex_unlock (tunnels_lock);
1222
1223   return GST_RTSP_STS_OK;
1224
1225   /* ERRORS */
1226 tunnel_existed:
1227   {
1228     g_mutex_unlock (tunnels_lock);
1229     g_message ("client %p: tunnel session %s existed", client, tunnelid);
1230     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1231   }
1232 }
1233
1234 static GstRTSPResult
1235 tunnel_complete (GstRTSPWatch *watch, gpointer user_data)
1236 {
1237   const gchar *tunnelid;
1238   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1239   GstRTSPClient *oclient;
1240
1241   g_message ("client %p: tunnel complete", client);
1242
1243   /* find previous tunnel */
1244   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1245
1246   g_mutex_lock (tunnels_lock);
1247   if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
1248     goto no_tunnel;
1249
1250   /* remove the old client from the table. ref before because removing it will
1251    * remove the ref to it. */
1252   g_object_ref (oclient);
1253   g_hash_table_remove (tunnels, tunnelid);
1254   g_mutex_unlock (tunnels_lock);
1255
1256   g_message ("client %p: found tunnel %p", client, oclient);
1257
1258   /* merge the tunnels into the first client */
1259   gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
1260   gst_rtsp_watch_reset (oclient->watch);
1261   g_object_unref (oclient);
1262
1263   /* we don't need this watch anymore */
1264   g_source_remove (client->watchid);
1265
1266   return GST_RTSP_OK;
1267
1268   /* ERRORS */
1269 no_tunnel:
1270   {
1271     g_mutex_unlock (tunnels_lock);
1272     g_message ("client %p: tunnel session %s not found", client, tunnelid);
1273     return GST_RTSP_OK;
1274   }
1275 }
1276
1277 static GstRTSPWatchFuncs watch_funcs = {
1278   message_received,
1279   message_sent,
1280   closed,
1281   error,
1282   tunnel_start,
1283   tunnel_complete
1284 };
1285
1286 /**
1287  * gst_rtsp_client_attach:
1288  * @client: a #GstRTSPClient
1289  * @channel: a #GIOChannel
1290  *
1291  * Accept a new connection for @client on the socket in @source. 
1292  *
1293  * This function should be called when the client properties and urls are fully
1294  * configured and the client is ready to start.
1295  *
1296  * Returns: %TRUE if the client could be accepted.
1297  */
1298 gboolean
1299 gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel)
1300 {
1301   int sock;
1302   GstRTSPConnection *conn;
1303   GstRTSPResult res;
1304   GSource *source;
1305   GMainContext *context;
1306   GstRTSPUrl *url;
1307
1308   /* a new client connected. */
1309   sock = g_io_channel_unix_get_fd (channel);
1310
1311   GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed);
1312
1313   url = gst_rtsp_connection_get_url (conn);
1314   g_message ("added new client %p ip %s:%d", client,
1315                 url->host, url->port);
1316
1317   client->connection = conn;
1318
1319   /* create watch for the connection and attach */
1320   client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
1321                   g_object_ref (client), g_object_unref);
1322
1323   /* find the context to add the watch */
1324   if ((source = g_main_current_source ()))
1325     context = g_source_get_context (source);
1326   else
1327     context = NULL;
1328
1329   g_message ("attaching to context %p", context);
1330
1331   client->watchid = gst_rtsp_watch_attach (client->watch, context);
1332   gst_rtsp_watch_unref (client->watch);
1333
1334   return TRUE;
1335
1336   /* ERRORS */
1337 accept_failed:
1338   {
1339     gchar *str = gst_rtsp_strresult (res);
1340
1341     g_error ("Could not accept client on server socket %d: %s",
1342             sock, str);
1343     g_free (str);
1344     return FALSE;
1345   }
1346 }