Initial import
[platform/upstream/gst-rtsp-server.git] / src / 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
402   /* check what kind of format is accepted */
403
404
405   /* for the describe we must generate an SDP */
406   if (!(media = gst_rtsp_media_new (uri)))
407     goto no_media;
408
409   /* create a pipeline if we have to */
410   if (client->pipeline == NULL) {
411     client->pipeline = gst_pipeline_new ("client-pipeline");
412   }
413
414   /* prepare the media into the pipeline */
415   if (!gst_rtsp_media_prepare (media, GST_BIN (client->pipeline)))
416     goto no_media;
417
418   /* link fakesink to all stream pads and set the pipeline to PLAYING */
419   n_streams = gst_rtsp_media_n_streams (media);
420   for (i = 0; i < n_streams; i++) {
421     GstRTSPMediaStream *stream;
422     GstElement *sink;
423     GstPad *sinkpad;
424
425     stream = gst_rtsp_media_get_stream (media, i);
426
427     sink = gst_element_factory_make ("fakesink", NULL);
428     gst_bin_add (GST_BIN (client->pipeline), sink);
429
430     sinkpad = gst_element_get_static_pad (sink, "sink");
431     gst_pad_link (stream->srcpad, sinkpad);
432     gst_object_unref (sinkpad);
433   }
434
435   /* now play and wait till we get the pads blocked. At that time the pipeline
436    * is prerolled and we have the caps on the streams too. */
437   gst_element_set_state (client->pipeline, GST_STATE_PLAYING);
438
439   /* wait for state change to complete */
440   gst_element_get_state (client->pipeline, NULL, NULL, -1);
441
442   /* we should now be able to construct the SDP message */
443   gst_sdp_message_new (&sdp);
444
445   /* some standard things first */
446   gst_sdp_message_set_version (sdp, "0");
447   gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", "IP4", "127.0.0.1");
448   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
449   gst_sdp_message_set_information (sdp, "rtsp-server");
450   gst_sdp_message_add_time (sdp, "0", "0", NULL);
451   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
452   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
453
454   for (i = 0; i < n_streams; i++) {
455     GstRTSPMediaStream *stream;
456     GstSDPMedia *smedia;
457     GstStructure *s;
458     const gchar *caps_str, *caps_enc, *caps_params;
459     gchar *tmp;
460     gint caps_pt, caps_rate;
461     guint n_fields, j;
462     gboolean first;
463     GString *fmtp;
464
465     stream = gst_rtsp_media_get_stream (media, i);
466     gst_sdp_media_new (&smedia);
467
468     s = gst_caps_get_structure (stream->caps, 0);
469
470     /* get media type and payload for the m= line */
471     caps_str = gst_structure_get_string (s, "media");
472     gst_sdp_media_set_media (smedia, caps_str);
473
474     gst_structure_get_int (s, "payload", &caps_pt);
475     tmp = g_strdup_printf ("%d", caps_pt);
476     gst_sdp_media_add_format (smedia, tmp);
477     g_free (tmp);
478
479     gst_sdp_media_set_port_info (smedia, 0, 1);
480     gst_sdp_media_set_proto (smedia, "RTP/AVP");
481
482     /* for the c= line */
483     gst_sdp_media_add_connection (smedia, "IN", "IP4", "127.0.0.1", 0, 0);
484
485     /* get clock-rate, media type and params for the rtpmap attribute */
486     gst_structure_get_int (s, "clock-rate", &caps_rate);
487     caps_enc = gst_structure_get_string (s, "encoding-name");
488     caps_params = gst_structure_get_string (s, "encoding-params");
489
490     if (caps_params)
491       tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate,
492                       caps_params);
493     else
494       tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate);
495
496     gst_sdp_media_add_attribute (smedia, "rtpmap", tmp);
497     g_free (tmp);
498
499     /* the config uri */
500     tmp = g_strdup_printf ("stream=%d", i);
501     gst_sdp_media_add_attribute (smedia, "control", tmp);
502     g_free (tmp);
503
504     /* collect all other properties and add them to fmtp */
505     fmtp = g_string_new ("");
506     g_string_append_printf (fmtp, "%d ", caps_pt);
507     first = TRUE;
508     n_fields = gst_structure_n_fields (s);
509     for (j = 0; j < n_fields; j++) {
510       const gchar *fname, *fval;
511
512       fname = gst_structure_nth_field_name (s, j);
513
514       /* filter out standard properties */
515       if (!strcmp (fname, "media")) 
516         continue;
517       if (!strcmp (fname, "payload")) 
518         continue;
519       if (!strcmp (fname, "clock-rate")) 
520         continue;
521       if (!strcmp (fname, "encoding-name")) 
522         continue;
523       if (!strcmp (fname, "encoding-params")) 
524         continue;
525       if (!strcmp (fname, "ssrc")) 
526         continue;
527       if (!strcmp (fname, "clock-base")) 
528         continue;
529       if (!strcmp (fname, "seqnum-base")) 
530         continue;
531
532       if ((fval = gst_structure_get_string (s, fname))) {
533         g_string_append_printf (fmtp, "%s%s=%s", first ? "":";", fname, fval);
534         first = FALSE;
535       }
536     }
537     if (!first) {
538       tmp = g_string_free (fmtp, FALSE);
539       gst_sdp_media_add_attribute (smedia, "fmtp", tmp);
540       g_free (tmp);
541     }
542     else {
543       g_string_free (fmtp, TRUE);
544     }
545     gst_sdp_message_add_media (sdp, smedia);
546   }
547   /* go back to NULL */
548   gst_element_set_state (client->pipeline, GST_STATE_NULL);
549
550   g_object_unref (media);
551
552   gst_object_unref (client->pipeline);
553   client->pipeline = NULL;
554
555   gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, 
556         gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
557
558   /* add SDP to the response body */
559   sdptext = gst_sdp_message_as_text (sdp);
560   gst_rtsp_message_take_body (&response, (guint8 *)sdptext, strlen (sdptext));
561   gst_sdp_message_free (sdp);
562
563   gst_rtsp_connection_send (client->connection, &response, NULL);
564
565   return TRUE;
566
567   /* ERRORS */
568 no_media:
569   {
570     handle_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
571     return FALSE;
572   }
573 }
574
575 static void
576 handle_options_response (GstRTSPClient *client, const gchar *uri, GstRTSPMessage *request)
577 {
578   GstRTSPMessage response = { 0 };
579   GstRTSPMethod options;
580   GString *str;
581
582   gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, 
583         gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
584
585   options = GST_RTSP_DESCRIBE |
586             GST_RTSP_OPTIONS |
587     //        GST_RTSP_PAUSE |
588             GST_RTSP_PLAY |
589             GST_RTSP_SETUP |
590             GST_RTSP_TEARDOWN;
591
592   /* always return options.. */
593   str = g_string_new ("OPTIONS");
594
595   if (options & GST_RTSP_DESCRIBE)
596     g_string_append (str, ", DESCRIBE");
597   if (options & GST_RTSP_ANNOUNCE)
598     g_string_append (str, ", ANNOUNCE");
599   if (options & GST_RTSP_GET_PARAMETER)
600     g_string_append (str, ", GET_PARAMETER");
601   if (options & GST_RTSP_PAUSE)
602     g_string_append (str, ", PAUSE");
603   if (options & GST_RTSP_PLAY)
604     g_string_append (str, ", PLAY");
605   if (options & GST_RTSP_RECORD)
606     g_string_append (str, ", RECORD");
607   if (options & GST_RTSP_REDIRECT)
608     g_string_append (str, ", REDIRECT");
609   if (options & GST_RTSP_SETUP)
610     g_string_append (str, ", SETUP");
611   if (options & GST_RTSP_SET_PARAMETER)
612     g_string_append (str, ", SET_PARAMETER");
613   if (options & GST_RTSP_TEARDOWN)
614     g_string_append (str, ", TEARDOWN");
615
616   gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str->str);
617
618   g_string_free (str, TRUE);
619
620   gst_rtsp_connection_send (client->connection, &response, NULL);
621 }
622
623 /* this function runs in a client specific thread and handles all rtsp messages
624  * with the client */
625 static gpointer
626 handle_client (GstRTSPClient *client)
627 {
628   GstRTSPMessage request = { 0 };
629   GstRTSPResult res;
630   GstRTSPMethod method;
631   const gchar *uri;
632   GstRTSPVersion version;
633
634   while (TRUE) {
635     /* start by waiting for a message from the client */
636     res = gst_rtsp_connection_receive (client->connection, &request, NULL);
637     if (res < 0)
638       goto receive_failed;
639
640 #ifdef DEBUG
641     gst_rtsp_message_dump (&request);
642 #endif
643
644     gst_rtsp_message_parse_request (&request, &method, &uri, &version);
645
646     if (version != GST_RTSP_VERSION_1_0) {
647       /* we can only handle 1.0 requests */
648       handle_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, &request);
649       continue;
650     }
651
652     /* now see what is asked and dispatch to a dedicated handler */
653     switch (method) {
654       case GST_RTSP_OPTIONS:
655         handle_options_response (client, uri, &request);
656         break;
657       case GST_RTSP_DESCRIBE:
658         handle_describe_response (client, uri, &request);
659         break;
660       case GST_RTSP_SETUP:
661         handle_setup_response (client, uri, &request);
662         break;
663       case GST_RTSP_PLAY:
664         handle_play_response (client, uri, &request);
665         break;
666       case GST_RTSP_PAUSE:
667         handle_pause_response (client, uri, &request);
668         break;
669       case GST_RTSP_TEARDOWN:
670         handle_teardown_response (client, uri, &request);
671         break;
672       case GST_RTSP_ANNOUNCE:
673       case GST_RTSP_GET_PARAMETER:
674       case GST_RTSP_RECORD:
675       case GST_RTSP_REDIRECT:
676       case GST_RTSP_SET_PARAMETER:
677         handle_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &request);
678         break;
679       case GST_RTSP_INVALID:
680       default:
681         handle_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &request);
682         break;
683     }
684   }
685   g_object_unref (client);
686   return NULL;
687
688   /* ERRORS */
689 receive_failed:
690   {
691     g_print ("receive failed, disconnect client %p\n", client);
692     gst_rtsp_connection_close (client->connection);
693     g_object_unref (client);
694     return NULL;
695   }
696 }
697
698 /* called when we need to accept a new request from a client */
699 static gboolean
700 client_accept (GstRTSPClient *client, GIOChannel *source)
701 {
702   /* a new client connected. */
703   int server_sock_fd;
704   unsigned int address_len;
705   GstRTSPConnection *conn;
706
707   conn = client->connection;
708
709   server_sock_fd = g_io_channel_unix_get_fd (source);
710
711   address_len = sizeof (client->address);
712   memset (&client->address, 0, address_len);
713
714   conn->fd.fd = accept (server_sock_fd, (struct sockaddr *) &client->address,
715       &address_len);
716   if (conn->fd.fd == -1)
717     goto accept_failed;
718
719   g_print ("added new client %p ip %s with fd %d\n", client,
720                 inet_ntoa (client->address.sin_addr), conn->fd.fd);
721
722   /* FIXME some hackery, we need to have a connection method to accept server
723    * connections */
724   gst_poll_add_fd (conn->fdset, &conn->fd);
725
726   return TRUE;
727
728   /* ERRORS */
729 accept_failed:
730   {
731     g_error ("Could not accept client on server socket %d: %s (%d)",
732             server_sock_fd, g_strerror (errno), errno);
733     return FALSE;
734   }
735 }
736
737 /**
738  * gst_rtsp_client_set_session_pool:
739  * @client: a #GstRTSPClient
740  * @pool: a #GstRTSPSessionPool
741  *
742  * Set @pool as the sessionpool for @client which it will use to find
743  * or allocate sessions.
744  */
745 void
746 gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool)
747 {
748   GstRTSPSessionPool *old;
749
750   old = client->pool;
751   if (pool)
752     g_object_ref (pool);
753   client->pool = pool;
754   if (old)
755     g_object_unref (old);
756 }
757
758 /**
759  * gst_rtsp_client_get_session_pool:
760  * @client: a #GstRTSPClient
761  *
762  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
763  *
764  * Returns: a #GstRTSPSessionPool, unref after usage.
765  */
766 GstRTSPSessionPool *
767 gst_rtsp_client_get_session_pool (GstRTSPClient *client)
768 {
769   GstRTSPSessionPool *result;
770
771   if ((result = client->pool))
772     g_object_ref (result);
773
774   return result;
775 }
776
777
778 /**
779  * gst_rtsp_client_attach:
780  * @client: a #GstRTSPClient
781  * @context: a #GMainContext
782  *
783  * Attaches @client to @context. When the mainloop for @context is run, the
784  * client will be dispatched.
785  *
786  * This function should be called when the client properties and urls are fully
787  * configured and the client is ready to start.
788  *
789  * Returns: %TRUE if the client could be accepted.
790  */
791 gboolean
792 gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *source)
793 {
794   gst_rtsp_connection_create (NULL, &client->connection);
795
796   if (!client_accept (client, source))
797     goto accept_failed;
798
799   /* client accepted, spawn a thread for the client */
800   g_object_ref (client);
801   client->thread = g_thread_create ((GThreadFunc)handle_client, client, TRUE, NULL);
802
803   return TRUE;
804
805   /* ERRORS */
806 accept_failed:
807   {
808     gst_rtsp_connection_close (client->connection);
809     return FALSE;
810   }
811 }