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