server: separate create and accept
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-server.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <sys/ioctl.h>
21
22 #include "rtsp-server.h"
23 #include "rtsp-client.h"
24
25 #define DEFAULT_ADDRESS         "0.0.0.0"
26 /* #define DEFAULT_ADDRESS         "::0" */
27 #define DEFAULT_SERVICE         "8554"
28 #define DEFAULT_BACKLOG         5
29
30 /* Define to use the SO_LINGER option so that the server sockets can be resused
31  * sooner. Disabled for now because it is not very well implemented by various
32  * OSes and it causes clients to fail to read the TEARDOWN response. */
33 #undef USE_SOLINGER
34
35 enum
36 {
37   PROP_0,
38   PROP_ADDRESS,
39   PROP_SERVICE,
40   PROP_BACKLOG,
41
42   PROP_SESSION_POOL,
43   PROP_MEDIA_MAPPING,
44   PROP_LAST
45 };
46
47 G_DEFINE_TYPE (GstRTSPServer, gst_rtsp_server, G_TYPE_OBJECT);
48
49 GST_DEBUG_CATEGORY_STATIC (rtsp_server_debug);
50 #define GST_CAT_DEFAULT rtsp_server_debug
51
52 static void gst_rtsp_server_get_property (GObject * object, guint propid,
53     GValue * value, GParamSpec * pspec);
54 static void gst_rtsp_server_set_property (GObject * object, guint propid,
55     const GValue * value, GParamSpec * pspec);
56 static void gst_rtsp_server_finalize (GObject * object);
57
58 static GstRTSPClient *default_create_client (GstRTSPServer * server);
59 static gboolean default_accept_client (GstRTSPServer * server,
60     GstRTSPClient * client, GIOChannel * channel);
61
62 static void
63 gst_rtsp_server_class_init (GstRTSPServerClass * klass)
64 {
65   GObjectClass *gobject_class;
66
67   gobject_class = G_OBJECT_CLASS (klass);
68
69   gobject_class->get_property = gst_rtsp_server_get_property;
70   gobject_class->set_property = gst_rtsp_server_set_property;
71   gobject_class->finalize = gst_rtsp_server_finalize;
72
73   /**
74    * GstRTSPServer::address
75    *
76    * The address of the server. This is the address where the server will
77    * listen on.
78    */
79   g_object_class_install_property (gobject_class, PROP_ADDRESS,
80       g_param_spec_string ("address", "Address",
81           "The address the server uses to listen on", DEFAULT_ADDRESS,
82           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
83   /**
84    * GstRTSPServer::service
85    *
86    * The service of the server. This is either a string with the service name or
87    * a port number (as a string) the server will listen on.
88    */
89   g_object_class_install_property (gobject_class, PROP_SERVICE,
90       g_param_spec_string ("service", "Service",
91           "The service or port number the server uses to listen on",
92           DEFAULT_SERVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
93   /**
94    * GstRTSPServer::backlog
95    *
96    * The backlog argument defines the maximum length to which the queue of
97    * pending connections for the server may grow. If a connection request arrives
98    * when the queue is full, the client may receive an error with an indication of
99    * ECONNREFUSED or, if the underlying protocol supports retransmission, the
100    * request may be ignored so that a later reattempt at  connection succeeds.
101    */
102   g_object_class_install_property (gobject_class, PROP_BACKLOG,
103       g_param_spec_int ("backlog", "Backlog",
104           "The maximum length to which the queue "
105           "of pending connections may grow", 0, G_MAXINT, DEFAULT_BACKLOG,
106           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
107   /**
108    * GstRTSPServer::session-pool
109    *
110    * The session pool of the server. By default each server has a separate
111    * session pool but sessions can be shared between servers by setting the same
112    * session pool on multiple servers.
113    */
114   g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
115       g_param_spec_object ("session-pool", "Session Pool",
116           "The session pool to use for client session",
117           GST_TYPE_RTSP_SESSION_POOL,
118           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
119   /**
120    * GstRTSPServer::media-mapping
121    *
122    * The media mapping to use for this server. By default the server has no
123    * media mapping and thus cannot map urls to media streams.
124    */
125   g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING,
126       g_param_spec_object ("media-mapping", "Media Mapping",
127           "The media mapping to use for client session",
128           GST_TYPE_RTSP_MEDIA_MAPPING,
129           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
130
131   klass->create_client = default_create_client;
132   klass->accept_client = default_accept_client;
133
134   GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer");
135 }
136
137 static void
138 gst_rtsp_server_init (GstRTSPServer * server)
139 {
140   server->lock = g_mutex_new ();
141   server->address = g_strdup (DEFAULT_ADDRESS);
142   server->service = g_strdup (DEFAULT_SERVICE);
143   server->backlog = DEFAULT_BACKLOG;
144   server->session_pool = gst_rtsp_session_pool_new ();
145   server->media_mapping = gst_rtsp_media_mapping_new ();
146 }
147
148 static void
149 gst_rtsp_server_finalize (GObject * object)
150 {
151   GstRTSPServer *server = GST_RTSP_SERVER (object);
152
153   g_mutex_free (server->lock);
154   g_free (server->address);
155   g_free (server->service);
156
157   g_object_unref (server->session_pool);
158   g_object_unref (server->media_mapping);
159 }
160
161 /**
162  * gst_rtsp_server_new:
163  *
164  * Create a new #GstRTSPServer instance.
165  */
166 GstRTSPServer *
167 gst_rtsp_server_new (void)
168 {
169   GstRTSPServer *result;
170
171   result = g_object_new (GST_TYPE_RTSP_SERVER, NULL);
172
173   return result;
174 }
175
176 /**
177  * gst_rtsp_server_set_address:
178  * @server: a #GstRTSPServer
179  * @address: the address
180  *
181  * Configure @server to accept connections on the given address.
182  *
183  * This function must be called before the server is bound.
184  */
185 void
186 gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address)
187 {
188   g_return_if_fail (GST_IS_RTSP_SERVER (server));
189   g_return_if_fail (address != NULL);
190
191   g_free (server->address);
192   server->address = g_strdup (address);
193 }
194
195 /**
196  * gst_rtsp_server_get_address:
197  * @server: a #GstRTSPServer
198  *
199  * Get the address on which the server will accept connections.
200  *
201  * Returns: the server address. g_free() after usage.
202  */
203 gchar *
204 gst_rtsp_server_get_address (GstRTSPServer * server)
205 {
206   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
207
208   return g_strdup (server->address);
209 }
210
211 /**
212  * gst_rtsp_server_set_service:
213  * @server: a #GstRTSPServer
214  * @service: the service
215  *
216  * Configure @server to accept connections on the given service.
217  * @service should be a string containing the service name (see services(5)) or
218  * a string containing a port number between 1 and 65535.
219  *
220  * This function must be called before the server is bound.
221  */
222 void
223 gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service)
224 {
225   g_return_if_fail (GST_IS_RTSP_SERVER (server));
226   g_return_if_fail (service != NULL);
227
228   g_free (server->service);
229   server->service = g_strdup (service);
230 }
231
232 /**
233  * gst_rtsp_server_get_service:
234  * @server: a #GstRTSPServer
235  *
236  * Get the service on which the server will accept connections.
237  *
238  * Returns: the service. use g_free() after usage.
239  */
240 gchar *
241 gst_rtsp_server_get_service (GstRTSPServer * server)
242 {
243   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
244
245   return g_strdup (server->service);
246 }
247
248 /**
249  * gst_rtsp_server_set_backlog:
250  * @server: a #GstRTSPServer
251  * @backlog: the backlog
252  *
253  * configure the maximum amount of requests that may be queued for the
254  * server.
255  *
256  * This function must be called before the server is bound.
257  */
258 void
259 gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog)
260 {
261   g_return_if_fail (GST_IS_RTSP_SERVER (server));
262
263   server->backlog = backlog;
264 }
265
266 /**
267  * gst_rtsp_server_get_backlog:
268  * @server: a #GstRTSPServer
269  *
270  * The maximum amount of queued requests for the server.
271  *
272  * Returns: the server backlog.
273  */
274 gint
275 gst_rtsp_server_get_backlog (GstRTSPServer * server)
276 {
277   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1);
278
279   return server->backlog;
280 }
281
282 /**
283  * gst_rtsp_server_set_session_pool:
284  * @server: a #GstRTSPServer
285  * @pool: a #GstRTSPSessionPool
286  *
287  * configure @pool to be used as the session pool of @server.
288  */
289 void
290 gst_rtsp_server_set_session_pool (GstRTSPServer * server,
291     GstRTSPSessionPool * pool)
292 {
293   GstRTSPSessionPool *old;
294
295   g_return_if_fail (GST_IS_RTSP_SERVER (server));
296
297   old = server->session_pool;
298
299   if (old != pool) {
300     if (pool)
301       g_object_ref (pool);
302     server->session_pool = pool;
303     if (old)
304       g_object_unref (old);
305   }
306 }
307
308 /**
309  * gst_rtsp_server_get_session_pool:
310  * @server: a #GstRTSPServer
311  *
312  * Get the #GstRTSPSessionPool used as the session pool of @server.
313  *
314  * Returns: the #GstRTSPSessionPool used for sessions. g_object_unref() after
315  * usage.
316  */
317 GstRTSPSessionPool *
318 gst_rtsp_server_get_session_pool (GstRTSPServer * server)
319 {
320   GstRTSPSessionPool *result;
321
322   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
323
324   if ((result = server->session_pool))
325     g_object_ref (result);
326
327   return result;
328 }
329
330 /**
331  * gst_rtsp_server_set_media_mapping:
332  * @server: a #GstRTSPServer
333  * @mapping: a #GstRTSPMediaMapping
334  *
335  * configure @mapping to be used as the media mapping of @server.
336  */
337 void
338 gst_rtsp_server_set_media_mapping (GstRTSPServer * server,
339     GstRTSPMediaMapping * mapping)
340 {
341   GstRTSPMediaMapping *old;
342
343   g_return_if_fail (GST_IS_RTSP_SERVER (server));
344
345   old = server->media_mapping;
346
347   if (old != mapping) {
348     if (mapping)
349       g_object_ref (mapping);
350     server->media_mapping = mapping;
351     if (old)
352       g_object_unref (old);
353   }
354 }
355
356
357 /**
358  * gst_rtsp_server_get_media_mapping:
359  * @server: a #GstRTSPServer
360  *
361  * Get the #GstRTSPMediaMapping used as the media mapping of @server.
362  *
363  * Returns: the #GstRTSPMediaMapping of @server. g_object_unref() after
364  * usage.
365  */
366 GstRTSPMediaMapping *
367 gst_rtsp_server_get_media_mapping (GstRTSPServer * server)
368 {
369   GstRTSPMediaMapping *result;
370
371   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
372
373   if ((result = server->media_mapping))
374     g_object_ref (result);
375
376   return result;
377 }
378
379 /**
380  * gst_rtsp_server_set_auth:
381  * @server: a #GstRTSPServer
382  * @auth: a #GstRTSPAuth
383  *
384  * configure @auth to be used as the authentication manager of @server.
385  */
386 void
387 gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth)
388 {
389   GstRTSPAuth *old;
390
391   g_return_if_fail (GST_IS_RTSP_SERVER (server));
392
393   old = server->auth;
394
395   if (old != auth) {
396     if (auth)
397       g_object_ref (auth);
398     server->auth = auth;
399     if (old)
400       g_object_unref (old);
401   }
402 }
403
404
405 /**
406  * gst_rtsp_server_get_auth:
407  * @server: a #GstRTSPServer
408  *
409  * Get the #GstRTSPAuth used as the authentication manager of @server.
410  *
411  * Returns: the #GstRTSPAuth of @server. g_object_unref() after
412  * usage.
413  */
414 GstRTSPAuth *
415 gst_rtsp_server_get_auth (GstRTSPServer * server)
416 {
417   GstRTSPAuth *result;
418
419   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
420
421   if ((result = server->auth))
422     g_object_ref (result);
423
424   return result;
425 }
426
427 static void
428 gst_rtsp_server_get_property (GObject * object, guint propid,
429     GValue * value, GParamSpec * pspec)
430 {
431   GstRTSPServer *server = GST_RTSP_SERVER (object);
432
433   switch (propid) {
434     case PROP_ADDRESS:
435       g_value_take_string (value, gst_rtsp_server_get_address (server));
436       break;
437     case PROP_SERVICE:
438       g_value_take_string (value, gst_rtsp_server_get_service (server));
439       break;
440     case PROP_BACKLOG:
441       g_value_set_int (value, gst_rtsp_server_get_backlog (server));
442       break;
443     case PROP_SESSION_POOL:
444       g_value_take_object (value, gst_rtsp_server_get_session_pool (server));
445       break;
446     case PROP_MEDIA_MAPPING:
447       g_value_take_object (value, gst_rtsp_server_get_media_mapping (server));
448       break;
449     default:
450       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
451   }
452 }
453
454 static void
455 gst_rtsp_server_set_property (GObject * object, guint propid,
456     const GValue * value, GParamSpec * pspec)
457 {
458   GstRTSPServer *server = GST_RTSP_SERVER (object);
459
460   switch (propid) {
461     case PROP_ADDRESS:
462       gst_rtsp_server_set_address (server, g_value_get_string (value));
463       break;
464     case PROP_SERVICE:
465       gst_rtsp_server_set_service (server, g_value_get_string (value));
466       break;
467     case PROP_BACKLOG:
468       gst_rtsp_server_set_backlog (server, g_value_get_int (value));
469       break;
470     case PROP_SESSION_POOL:
471       gst_rtsp_server_set_session_pool (server, g_value_get_object (value));
472       break;
473     case PROP_MEDIA_MAPPING:
474       gst_rtsp_server_set_media_mapping (server, g_value_get_object (value));
475       break;
476     default:
477       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
478   }
479 }
480
481 /* Prepare a server socket for @server and make it listen on the configured port */
482 static gboolean
483 gst_rtsp_server_sink_init_send (GstRTSPServer * server)
484 {
485   int ret, sockfd;
486   struct addrinfo hints;
487   struct addrinfo *result, *rp;
488 #ifdef USE_SOLINGER
489   struct linger linger;
490 #endif
491
492   memset (&hints, 0, sizeof (struct addrinfo));
493   hints.ai_family = AF_UNSPEC;  /* Allow IPv4 or IPv6 */
494   hints.ai_socktype = SOCK_STREAM;      /* stream socket */
495   hints.ai_flags = AI_PASSIVE | AI_CANONNAME;   /* For wildcard IP address */
496   hints.ai_protocol = 0;        /* Any protocol */
497   hints.ai_canonname = NULL;
498   hints.ai_addr = NULL;
499   hints.ai_next = NULL;
500
501   GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address,
502       server->service);
503
504   /* resolve the server IP address */
505   if ((ret =
506           getaddrinfo (server->address, server->service, &hints, &result)) != 0)
507     goto no_address;
508
509   /* create server socket, we loop through all the addresses until we manage to
510    * create a socket and bind. */
511   for (rp = result; rp; rp = rp->ai_next) {
512     sockfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
513     if (sockfd == -1) {
514       GST_DEBUG_OBJECT (server, "failed to make socket (%s), try next",
515           g_strerror (errno));
516       continue;
517     }
518
519     /* make address reusable */
520     ret = 1;
521     if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR,
522             (void *) &ret, sizeof (ret)) < 0) {
523       /* warn but try to bind anyway */
524       GST_WARNING_OBJECT (server, "failed to reuse socker (%s)",
525           g_strerror (errno));
526     }
527
528     if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) {
529       GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname);
530       break;
531     }
532
533     GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next",
534         g_strerror (errno));
535     close (sockfd);
536   }
537   freeaddrinfo (result);
538
539   if (rp == NULL)
540     goto no_socket;
541
542   server->server_sock.fd = sockfd;
543
544   GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d",
545       server->server_sock.fd);
546
547   /* keep connection alive; avoids SIGPIPE during write */
548   ret = 1;
549   if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE,
550           (void *) &ret, sizeof (ret)) < 0)
551     goto keepalive_failed;
552
553 #ifdef USE_SOLINGER
554   /* make sure socket is reset 5 seconds after close. This ensure that we can
555    * reuse the socket quickly while still having a chance to send data to the
556    * client. */
557   linger.l_onoff = 1;
558   linger.l_linger = 5;
559   if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_LINGER,
560           (void *) &linger, sizeof (linger)) < 0)
561     goto linger_failed;
562 #endif
563
564   /* set the server socket to nonblocking */
565   fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK);
566
567   GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d",
568       server->server_sock.fd, server->backlog);
569   if (listen (server->server_sock.fd, server->backlog) == -1)
570     goto listen_failed;
571
572   GST_DEBUG_OBJECT (server,
573       "listened on server socket %d, returning from connection setup",
574       server->server_sock.fd);
575
576   GST_INFO_OBJECT (server, "listening on service %s", server->service);
577
578   return TRUE;
579
580   /* ERRORS */
581 no_address:
582   {
583     GST_ERROR_OBJECT (server, "failed to resolve address: %s",
584         gai_strerror (ret));
585     return FALSE;
586   }
587 no_socket:
588   {
589     GST_ERROR_OBJECT (server, "failed to create socket: %s",
590         g_strerror (errno));
591     return FALSE;
592   }
593 keepalive_failed:
594   {
595     GST_ERROR_OBJECT (server, "failed to configure keepalive socket: %s",
596         g_strerror (errno));
597     goto close_error;
598   }
599 #ifdef USE_SOLINGER
600 linger_failed:
601   {
602     GST_ERROR_OBJECT (server, "failed to no linger socket: %s",
603         g_strerror (errno));
604     goto close_error;
605   }
606 #endif
607 listen_failed:
608   {
609     GST_ERROR_OBJECT (server, "failed to listen on socket: %s",
610         g_strerror (errno));
611     goto close_error;
612   }
613 close_error:
614   {
615     if (server->server_sock.fd >= 0) {
616       close (server->server_sock.fd);
617       server->server_sock.fd = -1;
618     }
619     return FALSE;
620   }
621 }
622
623 /* add the client to the active list of clients, takes ownership of
624  * the client */
625 static void
626 manage_client (GstRTSPServer * server, GstRTSPClient * client)
627 {
628   gst_rtsp_client_set_server (client, server);
629
630   /* can unref the client now, when the request is finished, it will be
631    * unreffed async. */
632   gst_object_unref (client);
633 }
634
635 static GstRTSPClient *
636 default_create_client (GstRTSPServer * server)
637 {
638   GstRTSPClient *client;
639
640   /* a new client connected, create a session to handle the client. */
641   client = gst_rtsp_client_new ();
642
643   /* set the session pool that this client should use */
644   gst_rtsp_client_set_session_pool (client, server->session_pool);
645   /* set the media mapping that this client should use */
646   gst_rtsp_client_set_media_mapping (client, server->media_mapping);
647   /* set authentication manager */
648   gst_rtsp_client_set_auth (client, server->auth);
649
650   return client;
651 }
652
653 /* default method for creating a new client object in the server to accept and
654  * handle a client connection on this server */
655 static gboolean
656 default_accept_client (GstRTSPServer * server, GstRTSPClient * client,
657     GIOChannel * channel)
658 {
659   /* accept connections for that client, this function returns after accepting
660    * the connection and will run the remainder of the communication with the
661    * client asyncronously. */
662   if (!gst_rtsp_client_accept (client, channel))
663     goto accept_failed;
664
665   return TRUE;
666
667   /* ERRORS */
668 accept_failed:
669   {
670     GST_ERROR_OBJECT (server,
671         "Could not accept client on server socket %d: %s (%d)",
672         server->server_sock.fd, g_strerror (errno), errno);
673     return FALSE;
674   }
675 }
676
677 /**
678  * gst_rtsp_server_io_func:
679  * @channel: a #GIOChannel
680  * @condition: the condition on @source
681  *
682  * A default #GIOFunc that creates a new #GstRTSPClient to accept and handle a
683  * new connection on @channel or @server.
684  *
685  * Returns: TRUE if the source could be connected, FALSE if an error occured.
686  */
687 gboolean
688 gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition,
689     GstRTSPServer * server)
690 {
691   gboolean result;
692   GstRTSPClient *client = NULL;
693   GstRTSPServerClass *klass;
694
695   if (condition & G_IO_IN) {
696     klass = GST_RTSP_SERVER_GET_CLASS (server);
697
698     if (klass->create_client)
699       client = klass->create_client (server);
700     if (client == NULL)
701       goto client_failed;
702
703     /* a new client connected, create a client object to handle the client. */
704     if (klass->accept_client)
705       result = klass->accept_client (server, client, channel);
706     if (!result)
707       goto accept_failed;
708
709     /* manage the client connection */
710     manage_client (server, client);
711   } else {
712     GST_WARNING_OBJECT (server, "received unknown event %08x", condition);
713   }
714   return TRUE;
715
716   /* ERRORS */
717 client_failed:
718   {
719     GST_ERROR_OBJECT (server, "failed to create a client");
720     return FALSE;
721   }
722 accept_failed:
723   {
724     GST_ERROR_OBJECT (server, "failed to accept client");
725     gst_object_unref (client);
726     return FALSE;
727   }
728 }
729
730 /**
731  * gst_rtsp_server_get_io_channel:
732  * @server: a #GstRTSPServer
733  *
734  * Create a #GIOChannel for @server.
735  *
736  * Returns: the GIOChannel for @server or NULL when an error occured.
737  */
738 GIOChannel *
739 gst_rtsp_server_get_io_channel (GstRTSPServer * server)
740 {
741   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
742
743   if (server->io_channel == NULL) {
744     if (!gst_rtsp_server_sink_init_send (server))
745       goto init_failed;
746
747     /* create IO channel for the socket */
748     server->io_channel = g_io_channel_unix_new (server->server_sock.fd);
749   }
750   return server->io_channel;
751
752 init_failed:
753   {
754     GST_ERROR_OBJECT (server, "failed to initialize server");
755     return NULL;
756   }
757 }
758
759 /**
760  * gst_rtsp_server_create_watch:
761  * @server: a #GstRTSPServer
762  *
763  * Create a #GSource for @server. The new source will have a default
764  * #GIOFunc of gst_rtsp_server_io_func().
765  *
766  * Returns: the #GSource for @server or NULL when an error occured.
767  */
768 GSource *
769 gst_rtsp_server_create_watch (GstRTSPServer * server)
770 {
771   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
772
773   if (server->io_watch == NULL) {
774     GIOChannel *channel;
775
776     channel = gst_rtsp_server_get_io_channel (server);
777     if (channel == NULL)
778       goto no_channel;
779
780     /* create a watch for reads (new connections) and possible errors */
781     server->io_watch = g_io_create_watch (channel, G_IO_IN |
782         G_IO_ERR | G_IO_HUP | G_IO_NVAL);
783
784     /* configure the callback */
785     g_source_set_callback (server->io_watch,
786         (GSourceFunc) gst_rtsp_server_io_func, server, NULL);
787   }
788   return server->io_watch;
789
790 no_channel:
791   {
792     GST_ERROR_OBJECT (server, "failed to create IO channel");
793     return NULL;
794   }
795 }
796
797 /**
798  * gst_rtsp_server_attach:
799  * @server: a #GstRTSPServer
800  * @context: a #GMainContext
801  *
802  * Attaches @server to @context. When the mainloop for @context is run, the
803  * server will be dispatched.
804  *
805  * This function should be called when the server properties and urls are fully
806  * configured and the server is ready to start.
807  *
808  * Returns: the ID (greater than 0) for the source within the GMainContext.
809  */
810 guint
811 gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context)
812 {
813   guint res;
814   GSource *source;
815
816   g_return_val_if_fail (GST_IS_RTSP_SERVER (server), 0);
817
818   source = gst_rtsp_server_create_watch (server);
819   if (source == NULL)
820     goto no_source;
821
822   res = g_source_attach (source, context);
823
824   return res;
825
826   /* ERRORS */
827 no_source:
828   {
829     GST_ERROR_OBJECT (server, "failed to create watch");
830     return 0;
831   }
832 }