Split in library and example program
[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 <gst/sdp/gstsdpmessage.h>
23
24 #include "rtsp-client.h"
25
26 #undef DEBUG
27
28 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
29
30 static void
31 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
32 {
33   GObjectClass *gobject_class;
34
35   gobject_class = G_OBJECT_CLASS (klass);
36 }
37
38 static void
39 gst_rtsp_client_init (GstRTSPClient * client)
40 {
41 }
42
43 /**
44  * gst_rtsp_client_new:
45  *
46  * Create a new #GstRTSPClient instance.
47  */
48 GstRTSPClient *
49 gst_rtsp_client_new (void)
50 {
51   GstRTSPClient *result;
52
53   result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
54
55   return result;
56 }
57
58 static void
59 handle_generic_response (GstRTSPClient *client, GstRTSPStatusCode code, 
60     GstRTSPMessage *request)
61 {
62   GstRTSPMessage response = { 0 };
63
64   gst_rtsp_message_init_response (&response, code, 
65         gst_rtsp_status_as_text (code), request);
66
67   gst_rtsp_connection_send (client->connection, &response, NULL);
68 }
69
70 static gboolean
71 handle_teardown_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
72 {
73   GstRTSPResult res;
74   GstRTSPSessionMedia *media;
75   GstRTSPSession *session;
76   gchar *sessid;
77   GstRTSPMessage response = { 0 };
78   GstRTSPStatusCode code;
79
80   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
81   if (res == GST_RTSP_OK) {
82     /* we had a session in the request, find it again */
83     if (!(session = gst_rtsp_session_pool_find (client->pool, sessid)))
84       goto session_not_found;
85   }
86   else
87     goto service_unavailable;
88
89   /* get a handle to the configuration of the media in the session */
90   media = gst_rtsp_session_get_media (session, client->media);
91
92   gst_rtsp_session_media_stop (media);
93
94   gst_rtsp_session_pool_remove (client->pool, session);
95   g_object_unref (session);
96
97   /* remove the session id from the request, which will also remove it from the
98    * response */
99   gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1);
100
101   /* construct the response now */
102   code = GST_RTSP_STS_OK;
103   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
104
105   gst_rtsp_connection_send (client->connection, &response, NULL);
106
107   return FALSE;
108
109   /* ERRORS */
110 session_not_found:
111   {
112     handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
113     return FALSE;
114   }
115 service_unavailable:
116   {
117     return FALSE;
118   }
119 }
120
121 static gboolean
122 handle_pause_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
123 {
124   GstRTSPResult res;
125   GstRTSPSessionMedia *media;
126   GstRTSPSession *session;
127   gchar *sessid;
128   GstRTSPMessage response = { 0 };
129   GstRTSPStatusCode code;
130
131   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
132   if (res == GST_RTSP_OK) {
133     /* we had a session in the request, find it again */
134     if (!(session = gst_rtsp_session_pool_find (client->pool, sessid)))
135       goto session_not_found;
136   }
137   else
138     goto service_unavailable;
139
140   /* get a handle to the configuration of the media in the session */
141   media = gst_rtsp_session_get_media (session, client->media);
142
143   gst_rtsp_session_media_pause (media);
144   g_object_unref (session);
145
146   /* construct the response now */
147   code = GST_RTSP_STS_OK;
148   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
149
150   gst_rtsp_connection_send (client->connection, &response, NULL);
151
152   return FALSE;
153
154   /* ERRORS */
155 session_not_found:
156   {
157     handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
158     return FALSE;
159   }
160 service_unavailable:
161   {
162     return FALSE;
163   }
164 }
165
166 static gboolean
167 handle_play_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
168 {
169   GstRTSPResult res;
170   GstRTSPSessionMedia *media;
171   GstRTSPSession *session;
172   gchar *sessid;
173   GstRTSPMessage response = { 0 };
174   GstRTSPStatusCode code;
175   GstStateChangeReturn ret;
176   GString *rtpinfo;
177   guint n_streams, i;
178   guint timestamp, seqnum;
179
180   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
181   if (res == GST_RTSP_OK) {
182     /* we had a session in the request, find it again */
183     if (!(session = gst_rtsp_session_pool_find (client->pool, sessid)))
184       goto session_not_found;
185   }
186   else
187     goto service_unavailable;
188
189   /* get a handle to the configuration of the media in the session */
190   media = gst_rtsp_session_get_media (session, client->media);
191
192   /* wait for paused to get the caps */
193   ret = gst_rtsp_session_media_pause (media);
194   switch (ret) {
195     case GST_STATE_CHANGE_NO_PREROLL:
196       break;
197     case GST_STATE_CHANGE_SUCCESS:
198       break;
199     case GST_STATE_CHANGE_FAILURE:
200       goto service_unavailable;
201     case GST_STATE_CHANGE_ASYNC:
202       ret = gst_element_get_state (media->pipeline, NULL, NULL, -1);
203       break;
204   }
205
206   /* grab RTPInfo from the payloaders now */
207   rtpinfo = g_string_new ("");
208   n_streams = gst_rtsp_media_n_streams (client->media);
209   for (i = 0; i < n_streams; i++) {
210     GstRTSPMediaStream *stream;
211
212     stream = gst_rtsp_media_get_stream (client->media, i);
213
214     g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL);
215     g_object_get (G_OBJECT (stream->payloader), "timestamp", &timestamp, NULL);
216
217     if (i > 0)
218       g_string_append (rtpinfo, ", ");
219     g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uri, i, seqnum, timestamp);
220   }
221
222   /* construct the response now */
223   code = GST_RTSP_STS_OK;
224   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
225
226   /* add the RTP-Info header */
227   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_RTP_INFO, rtpinfo->str);
228   g_string_free (rtpinfo, TRUE);
229
230   gst_rtsp_connection_send (client->connection, &response, NULL);
231
232   /* start playing after sending the request */
233   gst_rtsp_session_media_play (media);
234   g_object_unref (session);
235
236   return FALSE;
237
238   /* ERRORS */
239 session_not_found:
240   {
241     handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
242     return FALSE;
243   }
244 service_unavailable:
245   {
246     handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
247     return FALSE;
248   }
249 }
250
251 static gboolean
252 handle_setup_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
253 {
254   GstRTSPResult res;
255   gchar *sessid;
256   gchar *transport;
257   gchar **transports;
258   gboolean have_transport;
259   GstRTSPTransport *ct, *st;
260   GstRTSPSession *session;
261   gint i;
262   GstRTSPLowerTrans supported;
263   GstRTSPMessage response = { 0 };
264   GstRTSPStatusCode code;
265   GstRTSPSessionStream *stream;
266   gchar *trans_str, *pos;
267   guint streamid;
268   GstRTSPSessionMedia *media;
269   gboolean need_session;
270
271   /* find the media associated with the uri */
272   if (client->media == NULL) {
273     if ((client->media = gst_rtsp_media_new (uri)) == NULL)
274       goto not_found;
275   }
276
277   /* parse the transport */
278   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, 0);
279   if (res != GST_RTSP_OK)
280     goto unsupported_transports;
281
282   transports = g_strsplit (transport, ",", 0);
283   gst_rtsp_transport_new (&ct);  
284
285   /* loop through the transports, try to parse */
286   have_transport = FALSE;
287   for (i = 0; transports[i]; i++) {
288
289     gst_rtsp_transport_init (ct);  
290     res = gst_rtsp_transport_parse (transports[i], ct);
291     if (res == GST_RTSP_OK) {
292       have_transport = TRUE;
293       break;
294     }
295   }
296   g_strfreev (transports);
297
298   /* we have not found anything usable, error out */
299   if (!have_transport) {
300     gst_rtsp_transport_free (ct);  
301     goto unsupported_transports;
302   }
303
304   /* we have a valid transport, check if we can handle it */
305   if (ct->trans != GST_RTSP_TRANS_RTP)
306     goto unsupported_transports;
307   if (ct->profile != GST_RTSP_PROFILE_AVP)
308     goto unsupported_transports;
309   supported = GST_RTSP_LOWER_TRANS_UDP |
310         GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP;
311   if (!(ct->lower_transport & supported))
312     goto unsupported_transports;
313
314   /* a setup request creates a session for a client, check if the client already
315    * sent a session id to us */
316   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
317   if (res == GST_RTSP_OK) {
318     /* we had a session in the request, find it again */
319     if (!(session = gst_rtsp_session_pool_find (client->pool, sessid)))
320       goto session_not_found;
321     need_session = FALSE;
322   }
323   else {
324     /* create a session if this fails we probably reached our session limit or
325      * something. */
326     if (!(session = gst_rtsp_session_pool_create (client->pool)))
327       goto service_unavailable;
328     need_session = TRUE;
329   }
330
331   /* get a handle to the configuration of the media in the session */
332   media = gst_rtsp_session_get_media (session, client->media);
333
334   /* parse the stream we need to configure */
335   if (!(pos = strstr (uri, "stream=")))
336     goto bad_request;
337
338   pos += strlen ("stream=");
339   if (sscanf (pos, "%u", &streamid) != 1)
340     goto bad_request;
341
342   /* get a handle to the stream in the media */
343   stream = gst_rtsp_session_get_stream (media, streamid);
344
345   /* setup the server transport from the client transport */
346   st = gst_rtsp_session_stream_set_transport (stream, inet_ntoa (client->address.sin_addr), ct);
347
348   /* serialize the server transport */
349   trans_str = gst_rtsp_transport_as_text (st);
350
351   /* construct the response now */
352   code = GST_RTSP_STS_OK;
353   gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
354
355   if (need_session)
356     gst_rtsp_message_add_header (&response, GST_RTSP_HDR_SESSION, session->sessionid);
357   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str);
358   g_free (trans_str);
359   g_object_unref (session);
360
361   gst_rtsp_connection_send (client->connection, &response, NULL);
362
363   return TRUE;
364
365   /* ERRORS */
366 not_found:
367   {
368     handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
369     return FALSE;
370   }
371 bad_request:
372   {
373     handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
374     return FALSE;
375   }
376 session_not_found:
377   {
378     handle_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
379     return FALSE;
380   }
381 unsupported_transports:
382   {
383     handle_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
384     return FALSE;
385   }
386 service_unavailable:
387   {
388     handle_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
389     return FALSE;
390   }
391 }
392
393 static gboolean
394 handle_describe_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
395 {
396   GstRTSPMessage response = { 0 };
397   GstSDPMessage *sdp;
398   guint n_streams, i;
399   gchar *sdptext;
400   GstRTSPMedia *media;
401   GstElement *pipeline = NULL;
402
403   /* check what kind of format is accepted */
404
405
406   /* for the describe we must generate an SDP */
407   if (!(media = gst_rtsp_media_new (uri)))
408     goto no_media;
409
410   /* create a pipeline if we have to */
411   if (pipeline == NULL) {
412     pipeline = gst_pipeline_new ("client-pipeline");
413   }
414
415   /* prepare the media into the pipeline */
416   if (!gst_rtsp_media_prepare (media, GST_BIN (pipeline)))
417     goto no_media;
418
419   /* link fakesink to all stream pads and set the pipeline to PLAYING */
420   n_streams = gst_rtsp_media_n_streams (media);
421   for (i = 0; i < n_streams; i++) {
422     GstRTSPMediaStream *stream;
423     GstElement *sink;
424     GstPad *sinkpad;
425
426     stream = gst_rtsp_media_get_stream (media, i);
427
428     sink = gst_element_factory_make ("fakesink", NULL);
429     gst_bin_add (GST_BIN (pipeline), sink);
430
431     sinkpad = gst_element_get_static_pad (sink, "sink");
432     gst_pad_link (stream->srcpad, sinkpad);
433     gst_object_unref (sinkpad);
434   }
435
436   /* now play and wait till we get the pads blocked. At that time the pipeline
437    * is prerolled and we have the caps on the streams too. */
438   gst_element_set_state (pipeline, GST_STATE_PLAYING);
439
440   /* wait for state change to complete */
441   gst_element_get_state (pipeline, NULL, NULL, -1);
442
443   /* we should now be able to construct the SDP message */
444   gst_sdp_message_new (&sdp);
445
446   /* some standard things first */
447   gst_sdp_message_set_version (sdp, "0");
448   gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", "127.0.0.1");
449   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
450   gst_sdp_message_set_information (sdp, "rtsp-server");
451   gst_sdp_message_add_time (sdp, "0", "0", NULL);
452   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
453   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
454
455   for (i = 0; i < n_streams; i++) {
456     GstRTSPMediaStream *stream;
457     GstSDPMedia *smedia;
458     GstStructure *s;
459     const gchar *caps_str, *caps_enc, *caps_params;
460     gchar *tmp;
461     gint caps_pt, caps_rate;
462     guint n_fields, j;
463     gboolean first;
464     GString *fmtp;
465
466     stream = gst_rtsp_media_get_stream (media, i);
467     gst_sdp_media_new (&smedia);
468
469     s = gst_caps_get_structure (stream->caps, 0);
470
471     /* get media type and payload for the m= line */
472     caps_str = gst_structure_get_string (s, "media");
473     gst_sdp_media_set_media (smedia, caps_str);
474
475     gst_structure_get_int (s, "payload", &caps_pt);
476     tmp = g_strdup_printf ("%d", caps_pt);
477     gst_sdp_media_add_format (smedia, tmp);
478     g_free (tmp);
479
480     gst_sdp_media_set_port_info (smedia, 0, 1);
481     gst_sdp_media_set_proto (smedia, "RTP/AVP");
482
483     /* for the c= line */
484     gst_sdp_media_add_connection (smedia, "IN", "IP4", "127.0.0.1", 0, 0);
485
486     /* get clock-rate, media type and params for the rtpmap attribute */
487     gst_structure_get_int (s, "clock-rate", &caps_rate);
488     caps_enc = gst_structure_get_string (s, "encoding-name");
489     caps_params = gst_structure_get_string (s, "encoding-params");
490
491     if (caps_params)
492       tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate,
493                       caps_params);
494     else
495       tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate);
496
497     gst_sdp_media_add_attribute (smedia, "rtpmap", tmp);
498     g_free (tmp);
499
500     /* the config uri */
501     tmp = g_strdup_printf ("stream=%d", i);
502     gst_sdp_media_add_attribute (smedia, "control", tmp);
503     g_free (tmp);
504
505     /* collect all other properties and add them to fmtp */
506     fmtp = g_string_new ("");
507     g_string_append_printf (fmtp, "%d ", caps_pt);
508     first = TRUE;
509     n_fields = gst_structure_n_fields (s);
510     for (j = 0; j < n_fields; j++) {
511       const gchar *fname, *fval;
512
513       fname = gst_structure_nth_field_name (s, j);
514
515       /* filter out standard properties */
516       if (!strcmp (fname, "media")) 
517         continue;
518       if (!strcmp (fname, "payload")) 
519         continue;
520       if (!strcmp (fname, "clock-rate")) 
521         continue;
522       if (!strcmp (fname, "encoding-name")) 
523         continue;
524       if (!strcmp (fname, "encoding-params")) 
525         continue;
526       if (!strcmp (fname, "ssrc")) 
527         continue;
528       if (!strcmp (fname, "clock-base")) 
529         continue;
530       if (!strcmp (fname, "seqnum-base")) 
531         continue;
532
533       if ((fval = gst_structure_get_string (s, fname))) {
534         g_string_append_printf (fmtp, "%s%s=%s", first ? "":";", fname, fval);
535         first = FALSE;
536       }
537     }
538     if (!first) {
539       tmp = g_string_free (fmtp, FALSE);
540       gst_sdp_media_add_attribute (smedia, "fmtp", tmp);
541       g_free (tmp);
542     }
543     else {
544       g_string_free (fmtp, TRUE);
545     }
546     gst_sdp_message_add_media (sdp, smedia);
547   }
548   /* go back to NULL */
549   gst_element_set_state (pipeline, GST_STATE_NULL);
550
551   g_object_unref (media);
552
553   gst_object_unref (pipeline);
554   pipeline = NULL;
555
556   gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, 
557         gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
558
559   /* add SDP to the response body */
560   sdptext = gst_sdp_message_as_text (sdp);
561   gst_rtsp_message_take_body (&response, (guint8 *)sdptext, strlen (sdptext));
562   gst_sdp_message_free (sdp);
563
564   gst_rtsp_connection_send (client->connection, &response, NULL);
565
566   return TRUE;
567
568   /* ERRORS */
569 no_media:
570   {
571     handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
572     return FALSE;
573   }
574 }
575
576 static void
577 handle_options_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
578 {
579   GstRTSPMessage response = { 0 };
580   GstRTSPMethod options;
581   GString *str;
582
583   gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, 
584         gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
585
586   options = GST_RTSP_DESCRIBE |
587             GST_RTSP_OPTIONS |
588     //        GST_RTSP_PAUSE |
589             GST_RTSP_PLAY |
590             GST_RTSP_SETUP |
591             GST_RTSP_TEARDOWN;
592
593   /* always return options.. */
594   str = g_string_new ("OPTIONS");
595
596   if (options & GST_RTSP_DESCRIBE)
597     g_string_append (str, ", DESCRIBE");
598   if (options & GST_RTSP_ANNOUNCE)
599     g_string_append (str, ", ANNOUNCE");
600   if (options & GST_RTSP_GET_PARAMETER)
601     g_string_append (str, ", GET_PARAMETER");
602   if (options & GST_RTSP_PAUSE)
603     g_string_append (str, ", PAUSE");
604   if (options & GST_RTSP_PLAY)
605     g_string_append (str, ", PLAY");
606   if (options & GST_RTSP_RECORD)
607     g_string_append (str, ", RECORD");
608   if (options & GST_RTSP_REDIRECT)
609     g_string_append (str, ", REDIRECT");
610   if (options & GST_RTSP_SETUP)
611     g_string_append (str, ", SETUP");
612   if (options & GST_RTSP_SET_PARAMETER)
613     g_string_append (str, ", SET_PARAMETER");
614   if (options & GST_RTSP_TEARDOWN)
615     g_string_append (str, ", TEARDOWN");
616
617   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str->str);
618
619   g_string_free (str, TRUE);
620
621   gst_rtsp_connection_send (client->connection, &response, NULL);
622 }
623
624 /* this function runs in a client specific thread and handles all rtsp messages
625  * with the client */
626 static gpointer
627 handle_client (GstRTSPClient *client)
628 {
629   GstRTSPMessage request = { 0 };
630   GstRTSPResult res;
631   GstRTSPMethod method;
632   const gchar *uri;
633   GstRTSPVersion version;
634
635   while (TRUE) {
636     /* start by waiting for a message from the client */
637     res = gst_rtsp_connection_receive (client->connection, &request, NULL);
638     if (res < 0)
639       goto receive_failed;
640
641 #ifdef DEBUG
642     gst_rtsp_message_dump (&request);
643 #endif
644
645     gst_rtsp_message_parse_request (&request, &method, &uri, &version);
646
647     if (version != GST_RTSP_VERSION_1_0) {
648       /* we can only handle 1.0 requests */
649       handle_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, &request);
650       continue;
651     }
652
653     /* now see what is asked and dispatch to a dedicated handler */
654     switch (method) {
655       case GST_RTSP_OPTIONS:
656         handle_options_response (client, uri, &request);
657         break;
658       case GST_RTSP_DESCRIBE:
659         handle_describe_response (client, uri, &request);
660         break;
661       case GST_RTSP_SETUP:
662         handle_setup_response (client, uri, &request);
663         break;
664       case GST_RTSP_PLAY:
665         handle_play_response (client, uri, &request);
666         break;
667       case GST_RTSP_PAUSE:
668         handle_pause_response (client, uri, &request);
669         break;
670       case GST_RTSP_TEARDOWN:
671         handle_teardown_response (client, uri, &request);
672         break;
673       case GST_RTSP_ANNOUNCE:
674       case GST_RTSP_GET_PARAMETER:
675       case GST_RTSP_RECORD:
676       case GST_RTSP_REDIRECT:
677       case GST_RTSP_SET_PARAMETER:
678         handle_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &request);
679         break;
680       case GST_RTSP_INVALID:
681       default:
682         handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request);
683         break;
684     }
685   }
686   g_object_unref (client);
687   return NULL;
688
689   /* ERRORS */
690 receive_failed:
691   {
692     g_print ("receive failed, disconnect client %p\n", client);
693     gst_rtsp_connection_close (client->connection);
694     g_object_unref (client);
695     return NULL;
696   }
697 }
698
699 /* called when we need to accept a new request from a client */
700 static gboolean
701 client_accept (GstRTSPClient *client, GIOChannel *source)
702 {
703   /* a new client connected. */
704   int server_sock_fd;
705   unsigned int address_len;
706   GstRTSPConnection *conn;
707
708   conn = client->connection;
709
710   server_sock_fd = g_io_channel_unix_get_fd (source);
711
712   address_len = sizeof (client->address);
713   memset (&client->address, 0, address_len);
714
715   conn->fd.fd = accept (server_sock_fd, (struct sockaddr *) &client->address,
716       &address_len);
717   if (conn->fd.fd == -1)
718     goto accept_failed;
719
720   g_print ("added new client %p ip %s with fd %d\n", client,
721                 inet_ntoa (client->address.sin_addr), conn->fd.fd);
722
723   /* FIXME some hackery, we need to have a connection method to accept server
724    * connections */
725   gst_poll_add_fd (conn->fdset, &conn->fd);
726
727   return TRUE;
728
729   /* ERRORS */
730 accept_failed:
731   {
732     g_error ("Could not accept client on server socket %d: %s (%d)",
733             server_sock_fd, g_strerror (errno), errno);
734     return FALSE;
735   }
736 }
737
738 /**
739  * gst_rtsp_client_set_session_pool:
740  * @client: a #GstRTSPClient
741  * @pool: a #GstRTSPSessionPool
742  *
743  * Set @pool as the sessionpool for @client which it will use to find
744  * or allocate sessions.
745  */
746 void
747 gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool)
748 {
749   GstRTSPSessionPool *old;
750
751   old = client->pool;
752   if (pool)
753     g_object_ref (pool);
754   client->pool = pool;
755   if (old)
756     g_object_unref (old);
757 }
758
759 /**
760  * gst_rtsp_client_get_session_pool:
761  * @client: a #GstRTSPClient
762  *
763  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
764  *
765  * Returns: a #GstRTSPSessionPool, unref after usage.
766  */
767 GstRTSPSessionPool *
768 gst_rtsp_client_get_session_pool (GstRTSPClient *client)
769 {
770   GstRTSPSessionPool *result;
771
772   if ((result = client->pool))
773     g_object_ref (result);
774
775   return result;
776 }
777
778
779 /**
780  * gst_rtsp_client_attach:
781  * @client: a #GstRTSPClient
782  * @context: a #GMainContext
783  *
784  * Attaches @client to @context. When the mainloop for @context is run, the
785  * client will be dispatched.
786  *
787  * This function should be called when the client properties and urls are fully
788  * configured and the client is ready to start.
789  *
790  * Returns: %TRUE if the client could be accepted.
791  */
792 gboolean
793 gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *source)
794 {
795   gst_rtsp_connection_create (NULL, &client->connection);
796
797   if (!client_accept (client, source))
798     goto accept_failed;
799
800   /* client accepted, spawn a thread for the client */
801   g_object_ref (client);
802   client->thread = g_thread_create ((GThreadFunc)handle_client, client, TRUE, NULL);
803
804   return TRUE;
805
806   /* ERRORS */
807 accept_failed:
808   {
809     gst_rtsp_connection_close (client->connection);
810     return FALSE;
811   }
812 }