client: small cleanup
[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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "rtsp-client.h"
24 #include "rtsp-sdp.h"
25 #include "rtsp-params.h"
26
27 static GMutex tunnels_lock;
28 static GHashTable *tunnels;
29
30 #define DEFAULT_SESSION_POOL            NULL
31 #define DEFAULT_MOUNT_POINTS            NULL
32 #define DEFAULT_USE_CLIENT_SETTINGS     FALSE
33
34 enum
35 {
36   PROP_0,
37   PROP_SESSION_POOL,
38   PROP_MOUNT_POINTS,
39   PROP_USE_CLIENT_SETTINGS,
40   PROP_LAST
41 };
42
43 enum
44 {
45   SIGNAL_CLOSED,
46   SIGNAL_NEW_SESSION,
47   SIGNAL_OPTIONS_REQUEST,
48   SIGNAL_DESCRIBE_REQUEST,
49   SIGNAL_SETUP_REQUEST,
50   SIGNAL_PLAY_REQUEST,
51   SIGNAL_PAUSE_REQUEST,
52   SIGNAL_TEARDOWN_REQUEST,
53   SIGNAL_SET_PARAMETER_REQUEST,
54   SIGNAL_GET_PARAMETER_REQUEST,
55   SIGNAL_LAST
56 };
57
58 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
59 #define GST_CAT_DEFAULT rtsp_client_debug
60
61 static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 };
62
63 static void gst_rtsp_client_get_property (GObject * object, guint propid,
64     GValue * value, GParamSpec * pspec);
65 static void gst_rtsp_client_set_property (GObject * object, guint propid,
66     const GValue * value, GParamSpec * pspec);
67 static void gst_rtsp_client_finalize (GObject * obj);
68
69 static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
70 static void client_session_finalized (GstRTSPClient * client,
71     GstRTSPSession * session);
72 static void unlink_session_transports (GstRTSPClient * client,
73     GstRTSPSession * session, GstRTSPSessionMedia * media);
74
75 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
76
77 static void
78 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
79 {
80   GObjectClass *gobject_class;
81
82   gobject_class = G_OBJECT_CLASS (klass);
83
84   gobject_class->get_property = gst_rtsp_client_get_property;
85   gobject_class->set_property = gst_rtsp_client_set_property;
86   gobject_class->finalize = gst_rtsp_client_finalize;
87
88   klass->create_sdp = create_sdp;
89
90   g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
91       g_param_spec_object ("session-pool", "Session Pool",
92           "The session pool to use for client session",
93           GST_TYPE_RTSP_SESSION_POOL,
94           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
95
96   g_object_class_install_property (gobject_class, PROP_MOUNT_POINTS,
97       g_param_spec_object ("mount-points", "Mount Points",
98           "The mount points to use for client session",
99           GST_TYPE_RTSP_MOUNT_POINTS,
100           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
101
102   g_object_class_install_property (gobject_class, PROP_USE_CLIENT_SETTINGS,
103       g_param_spec_boolean ("use-client-settings", "Use Client Settings",
104           "Use client settings for ttl and destination in multicast",
105           DEFAULT_USE_CLIENT_SETTINGS,
106           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
107
108   gst_rtsp_client_signals[SIGNAL_CLOSED] =
109       g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
110       G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL,
111       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
112
113   gst_rtsp_client_signals[SIGNAL_NEW_SESSION] =
114       g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
115       G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL,
116       g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION);
117
118   gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] =
119       g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass),
120       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request),
121       NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
122       G_TYPE_POINTER);
123
124   gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] =
125       g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass),
126       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request),
127       NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
128       G_TYPE_POINTER);
129
130   gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] =
131       g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass),
132       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request),
133       NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
134       G_TYPE_POINTER);
135
136   gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] =
137       g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass),
138       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request),
139       NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
140       G_TYPE_POINTER);
141
142   gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] =
143       g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass),
144       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request),
145       NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
146       G_TYPE_POINTER);
147
148   gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] =
149       g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass),
150       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request),
151       NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
152       G_TYPE_POINTER);
153
154   gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] =
155       g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass),
156       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
157           set_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
158       G_TYPE_NONE, 1, G_TYPE_POINTER);
159
160   gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] =
161       g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass),
162       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
163           get_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
164       G_TYPE_NONE, 1, G_TYPE_POINTER);
165
166   tunnels =
167       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
168   g_mutex_init (&tunnels_lock);
169
170   GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
171 }
172
173 static void
174 gst_rtsp_client_init (GstRTSPClient * client)
175 {
176   g_mutex_init (&client->lock);
177   client->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS;
178   client->close_seq = 0;
179 }
180
181 static void
182 client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
183 {
184   /* unlink all media managed in this session */
185   while (session->medias) {
186     GstRTSPSessionMedia *media = session->medias->data;
187
188     gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
189     unlink_session_transports (client, session, media);
190     /* unmanage the media in the session. this will modify session->medias */
191     gst_rtsp_session_release_media (session, media);
192   }
193 }
194
195 static void
196 client_cleanup_sessions (GstRTSPClient * client)
197 {
198   GList *sessions;
199
200   /* remove weak-ref from sessions */
201   for (sessions = client->sessions; sessions; sessions = g_list_next (sessions)) {
202     GstRTSPSession *session = (GstRTSPSession *) sessions->data;
203     g_object_weak_unref (G_OBJECT (session),
204         (GWeakNotify) client_session_finalized, client);
205     client_unlink_session (client, session);
206   }
207   g_list_free (client->sessions);
208   client->sessions = NULL;
209 }
210
211 /* A client is finalized when the connection is broken */
212 static void
213 gst_rtsp_client_finalize (GObject * obj)
214 {
215   GstRTSPClient *client = GST_RTSP_CLIENT (obj);
216
217   GST_INFO ("finalize client %p", client);
218
219   if (client->watch)
220     g_source_destroy ((GSource *) client->watch);
221
222   if (client->send_notify)
223     client->send_notify (client->send_data);
224
225   client_cleanup_sessions (client);
226
227   gst_rtsp_connection_free (client->connection);
228   if (client->session_pool)
229     g_object_unref (client->session_pool);
230   if (client->mount_points)
231     g_object_unref (client->mount_points);
232   if (client->auth)
233     g_object_unref (client->auth);
234
235   if (client->uri)
236     gst_rtsp_url_free (client->uri);
237   if (client->media) {
238     gst_rtsp_media_unprepare (client->media);
239     g_object_unref (client->media);
240   }
241
242   g_free (client->server_ip);
243   g_mutex_clear (&client->lock);
244
245   G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
246 }
247
248 static void
249 gst_rtsp_client_get_property (GObject * object, guint propid,
250     GValue * value, GParamSpec * pspec)
251 {
252   GstRTSPClient *client = GST_RTSP_CLIENT (object);
253
254   switch (propid) {
255     case PROP_SESSION_POOL:
256       g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
257       break;
258     case PROP_MOUNT_POINTS:
259       g_value_take_object (value, gst_rtsp_client_get_mount_points (client));
260       break;
261     case PROP_USE_CLIENT_SETTINGS:
262       g_value_set_boolean (value,
263           gst_rtsp_client_get_use_client_settings (client));
264       break;
265     default:
266       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
267   }
268 }
269
270 static void
271 gst_rtsp_client_set_property (GObject * object, guint propid,
272     const GValue * value, GParamSpec * pspec)
273 {
274   GstRTSPClient *client = GST_RTSP_CLIENT (object);
275
276   switch (propid) {
277     case PROP_SESSION_POOL:
278       gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
279       break;
280     case PROP_MOUNT_POINTS:
281       gst_rtsp_client_set_mount_points (client, g_value_get_object (value));
282       break;
283     case PROP_USE_CLIENT_SETTINGS:
284       gst_rtsp_client_set_use_client_settings (client,
285           g_value_get_boolean (value));
286       break;
287     default:
288       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
289   }
290 }
291
292 /**
293  * gst_rtsp_client_new:
294  *
295  * Create a new #GstRTSPClient instance.
296  *
297  * Returns: a new #GstRTSPClient
298  */
299 GstRTSPClient *
300 gst_rtsp_client_new (void)
301 {
302   GstRTSPClient *result;
303
304   result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
305
306   return result;
307 }
308
309 static void
310 send_response (GstRTSPClient * client, GstRTSPSession * session,
311     GstRTSPMessage * response, gboolean close)
312 {
313   gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER,
314       "GStreamer RTSP server");
315
316   /* remove any previous header */
317   gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1);
318
319   /* add the new session header for new session ids */
320   if (session) {
321     gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION,
322         gst_rtsp_session_get_header (session));
323   }
324
325   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
326     gst_rtsp_message_dump (response);
327   }
328
329   if (close)
330     gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close");
331
332   if (client->send_func)
333     client->send_func (client, response, close, client->send_data);
334
335   gst_rtsp_message_unset (response);
336 }
337
338 static void
339 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
340     GstRTSPClientState * state)
341 {
342   gst_rtsp_message_init_response (state->response, code,
343       gst_rtsp_status_as_text (code), state->request);
344
345   send_response (client, NULL, state->response, FALSE);
346 }
347
348 static void
349 handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth,
350     GstRTSPClientState * state)
351 {
352   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_UNAUTHORIZED,
353       gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request);
354
355   if (auth) {
356     /* and let the authentication manager setup the auth tokens */
357     gst_rtsp_auth_setup_auth (auth, client, 0, state);
358   }
359
360   send_response (client, state->session, state->response, FALSE);
361 }
362
363
364 static gboolean
365 compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2)
366 {
367   if (uri1 == NULL || uri2 == NULL)
368     return FALSE;
369
370   if (strcmp (uri1->abspath, uri2->abspath))
371     return FALSE;
372
373   return TRUE;
374 }
375
376 /* this function is called to initially find the media for the DESCRIBE request
377  * but is cached for when the same client (without breaking the connection) is
378  * doing a setup for the exact same url. */
379 static GstRTSPMedia *
380 find_media (GstRTSPClient * client, GstRTSPClientState * state)
381 {
382   GstRTSPMediaFactory *factory;
383   GstRTSPMedia *media;
384   GstRTSPAuth *auth;
385
386   if (!compare_uri (client->uri, state->uri)) {
387     /* remove any previously cached values before we try to construct a new
388      * media for uri */
389     if (client->uri)
390       gst_rtsp_url_free (client->uri);
391     client->uri = NULL;
392     if (client->media) {
393       gst_rtsp_media_unprepare (client->media);
394       g_object_unref (client->media);
395     }
396     client->media = NULL;
397
398     if (!client->mount_points)
399       goto no_mount_points;
400
401     /* find the factory for the uri first */
402     if (!(factory =
403             gst_rtsp_mount_points_find_factory (client->mount_points,
404                 state->uri)))
405       goto no_factory;
406
407     state->factory = factory;
408
409     /* check if we have access to the factory */
410     if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
411       if (!gst_rtsp_auth_check (auth, client, 0, state))
412         goto not_allowed;
413
414       g_object_unref (auth);
415     }
416
417     /* prepare the media and add it to the pipeline */
418     if (!(media = gst_rtsp_media_factory_construct (factory, state->uri)))
419       goto no_media;
420
421     g_object_unref (factory);
422     factory = NULL;
423     state->factory = NULL;
424
425     /* set ipv6 on the media before preparing */
426     media->is_ipv6 = client->is_ipv6;
427     state->media = media;
428
429     /* prepare the media */
430     if (!(gst_rtsp_media_prepare (media)))
431       goto no_prepare;
432
433     /* now keep track of the uri and the media */
434     client->uri = gst_rtsp_url_copy (state->uri);
435     client->media = media;
436   } else {
437     /* we have seen this uri before, used cached media */
438     media = client->media;
439     state->media = media;
440     GST_INFO ("reusing cached media %p", media);
441   }
442
443   if (media)
444     g_object_ref (media);
445
446   return media;
447
448   /* ERRORS */
449 no_mount_points:
450   {
451     GST_ERROR ("client %p: no mount points configured", client);
452     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
453     return NULL;
454   }
455 no_factory:
456   {
457     GST_ERROR ("client %p: no factory for uri", client);
458     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
459     return NULL;
460   }
461 not_allowed:
462   {
463     GST_ERROR ("client %p: unauthorized request", client);
464     handle_unauthorized_request (client, auth, state);
465     g_object_unref (factory);
466     g_object_unref (auth);
467     return NULL;
468   }
469 no_media:
470   {
471     GST_ERROR ("client %p: can't create media", client);
472     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
473     g_object_unref (factory);
474     return NULL;
475   }
476 no_prepare:
477   {
478     GST_ERROR ("client %p: can't prepare media", client);
479     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
480     g_object_unref (media);
481     return NULL;
482   }
483 }
484
485 static gboolean
486 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
487 {
488   GstRTSPMessage message = { 0 };
489   GstMapInfo map_info;
490   guint8 *data;
491   guint usize;
492
493   gst_rtsp_message_init_data (&message, channel);
494
495   /* FIXME, need some sort of iovec RTSPMessage here */
496   if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ))
497     return FALSE;
498
499   gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
500
501   if (client->send_func)
502     client->send_func (client, &message, FALSE, client->send_data);
503
504   gst_rtsp_message_steal_body (&message, &data, &usize);
505   gst_buffer_unmap (buffer, &map_info);
506
507   gst_rtsp_message_unset (&message);
508
509   return TRUE;
510 }
511
512 static void
513 link_transport (GstRTSPClient * client, GstRTSPSession * session,
514     GstRTSPStreamTransport * trans)
515 {
516   GST_DEBUG ("client %p: linking transport %p", client, trans);
517   gst_rtsp_stream_transport_set_callbacks (trans,
518       (GstRTSPSendFunc) do_send_data,
519       (GstRTSPSendFunc) do_send_data, client, NULL);
520
521   client->transports = g_list_prepend (client->transports, trans);
522
523   /* make sure our session can't expire */
524   gst_rtsp_session_prevent_expire (session);
525 }
526
527 static void
528 unlink_transport (GstRTSPClient * client, GstRTSPSession * session,
529     GstRTSPStreamTransport * trans)
530 {
531   GST_DEBUG ("client %p: unlinking transport %p", client, trans);
532   gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL);
533
534   client->transports = g_list_remove (client->transports, trans);
535
536   /* our session can now expire */
537   gst_rtsp_session_allow_expire (session);
538 }
539
540 static void
541 unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session,
542     GstRTSPSessionMedia * media)
543 {
544   guint n_streams, i;
545
546   n_streams = gst_rtsp_media_n_streams (media->media);
547   for (i = 0; i < n_streams; i++) {
548     GstRTSPStreamTransport *trans;
549     GstRTSPTransport *tr;
550
551     /* get the transport, if there is no transport configured, skip this stream */
552     trans = gst_rtsp_session_media_get_transport (media, i);
553     if (trans == NULL)
554       continue;
555
556     tr = trans->transport;
557
558     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
559       /* for TCP, unlink the stream from the TCP connection of the client */
560       unlink_transport (client, session, trans);
561     }
562   }
563 }
564
565 static void
566 close_connection (GstRTSPClient * client)
567 {
568   const gchar *tunnelid;
569
570   GST_DEBUG ("client %p: closing connection", client);
571
572   if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
573     g_mutex_lock (&tunnels_lock);
574     /* remove from tunnelids */
575     g_hash_table_remove (tunnels, tunnelid);
576     g_mutex_unlock (&tunnels_lock);
577   }
578
579   gst_rtsp_connection_close (client->connection);
580 }
581
582 static gboolean
583 handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state)
584 {
585   GstRTSPSession *session;
586   GstRTSPSessionMedia *media;
587   GstRTSPStatusCode code;
588
589   if (!state->session)
590     goto no_session;
591
592   session = state->session;
593
594   /* get a handle to the configuration of the media in the session */
595   media = gst_rtsp_session_get_media (session, state->uri);
596   if (!media)
597     goto not_found;
598
599   state->sessmedia = media;
600
601   /* unlink the all TCP callbacks */
602   unlink_session_transports (client, session, media);
603
604   /* remove the session from the watched sessions */
605   g_object_weak_unref (G_OBJECT (session),
606       (GWeakNotify) client_session_finalized, client);
607   client->sessions = g_list_remove (client->sessions, session);
608
609   gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
610
611   /* unmanage the media in the session, returns false if all media session
612    * are torn down. */
613   if (!gst_rtsp_session_release_media (session, media)) {
614     /* remove the session */
615     gst_rtsp_session_pool_remove (client->session_pool, session);
616   }
617   /* construct the response now */
618   code = GST_RTSP_STS_OK;
619   gst_rtsp_message_init_response (state->response, code,
620       gst_rtsp_status_as_text (code), state->request);
621
622   send_response (client, session, state->response, TRUE);
623
624   /* we emit the signal before closing the connection */
625   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
626       0, state);
627
628   return TRUE;
629
630   /* ERRORS */
631 no_session:
632   {
633     GST_ERROR ("client %p: no session", client);
634     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
635     return FALSE;
636   }
637 not_found:
638   {
639     GST_ERROR ("client %p: no media for uri", client);
640     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
641     return FALSE;
642   }
643 }
644
645 static gboolean
646 handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state)
647 {
648   GstRTSPResult res;
649   guint8 *data;
650   guint size;
651
652   res = gst_rtsp_message_get_body (state->request, &data, &size);
653   if (res != GST_RTSP_OK)
654     goto bad_request;
655
656   if (size == 0) {
657     /* no body, keep-alive request */
658     send_generic_response (client, GST_RTSP_STS_OK, state);
659   } else {
660     /* there is a body, handle the params */
661     res = gst_rtsp_params_get (client, state);
662     if (res != GST_RTSP_OK)
663       goto bad_request;
664
665     send_response (client, state->session, state->response, FALSE);
666   }
667
668   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
669       0, state);
670
671   return TRUE;
672
673   /* ERRORS */
674 bad_request:
675   {
676     GST_ERROR ("client %p: bad request", client);
677     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
678     return FALSE;
679   }
680 }
681
682 static gboolean
683 handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state)
684 {
685   GstRTSPResult res;
686   guint8 *data;
687   guint size;
688
689   res = gst_rtsp_message_get_body (state->request, &data, &size);
690   if (res != GST_RTSP_OK)
691     goto bad_request;
692
693   if (size == 0) {
694     /* no body, keep-alive request */
695     send_generic_response (client, GST_RTSP_STS_OK, state);
696   } else {
697     /* there is a body, handle the params */
698     res = gst_rtsp_params_set (client, state);
699     if (res != GST_RTSP_OK)
700       goto bad_request;
701
702     send_response (client, state->session, state->response, FALSE);
703   }
704
705   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
706       0, state);
707
708   return TRUE;
709
710   /* ERRORS */
711 bad_request:
712   {
713     GST_ERROR ("client %p: bad request", client);
714     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
715     return FALSE;
716   }
717 }
718
719 static gboolean
720 handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state)
721 {
722   GstRTSPSession *session;
723   GstRTSPSessionMedia *media;
724   GstRTSPStatusCode code;
725
726   if (!(session = state->session))
727     goto no_session;
728
729   /* get a handle to the configuration of the media in the session */
730   media = gst_rtsp_session_get_media (session, state->uri);
731   if (!media)
732     goto not_found;
733
734   state->sessmedia = media;
735
736   /* the session state must be playing or recording */
737   if (media->state != GST_RTSP_STATE_PLAYING &&
738       media->state != GST_RTSP_STATE_RECORDING)
739     goto invalid_state;
740
741   /* unlink the all TCP callbacks */
742   unlink_session_transports (client, session, media);
743
744   /* then pause sending */
745   gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
746
747   /* construct the response now */
748   code = GST_RTSP_STS_OK;
749   gst_rtsp_message_init_response (state->response, code,
750       gst_rtsp_status_as_text (code), state->request);
751
752   send_response (client, session, state->response, FALSE);
753
754   /* the state is now READY */
755   media->state = GST_RTSP_STATE_READY;
756
757   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST],
758       0, state);
759
760   return TRUE;
761
762   /* ERRORS */
763 no_session:
764   {
765     GST_ERROR ("client %p: no seesion", client);
766     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
767     return FALSE;
768   }
769 not_found:
770   {
771     GST_ERROR ("client %p: no media for uri", client);
772     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
773     return FALSE;
774   }
775 invalid_state:
776   {
777     GST_ERROR ("client %p: not PLAYING or RECORDING", client);
778     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
779         state);
780     return FALSE;
781   }
782 }
783
784 static gboolean
785 handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
786 {
787   GstRTSPSession *session;
788   GstRTSPSessionMedia *media;
789   GstRTSPStatusCode code;
790   GString *rtpinfo;
791   guint n_streams, i, infocount;
792   gchar *str;
793   GstRTSPTimeRange *range;
794   GstRTSPResult res;
795
796   if (!(session = state->session))
797     goto no_session;
798
799   /* get a handle to the configuration of the media in the session */
800   media = gst_rtsp_session_get_media (session, state->uri);
801   if (!media)
802     goto not_found;
803
804   state->sessmedia = media;
805
806   /* the session state must be playing or ready */
807   if (media->state != GST_RTSP_STATE_PLAYING &&
808       media->state != GST_RTSP_STATE_READY)
809     goto invalid_state;
810
811   /* parse the range header if we have one */
812   res =
813       gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_RANGE, &str, 0);
814   if (res == GST_RTSP_OK) {
815     if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
816       /* we have a range, seek to the position */
817       gst_rtsp_media_seek (media->media, range);
818       gst_rtsp_range_free (range);
819     }
820   }
821
822   /* grab RTPInfo from the payloaders now */
823   rtpinfo = g_string_new ("");
824
825   n_streams = gst_rtsp_media_n_streams (media->media);
826   for (i = 0, infocount = 0; i < n_streams; i++) {
827     GstRTSPStreamTransport *trans;
828     GstRTSPTransport *tr;
829     gchar *uristr;
830     guint rtptime, seq;
831
832     /* get the transport, if there is no transport configured, skip this stream */
833     trans = gst_rtsp_session_media_get_transport (media, i);
834     if (trans == NULL) {
835       GST_INFO ("stream %d is not configured", i);
836       continue;
837     }
838     tr = trans->transport;
839
840     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
841       /* for TCP, link the stream to the TCP connection of the client */
842       link_transport (client, session, trans);
843     }
844
845     if (gst_rtsp_stream_get_rtpinfo (trans->stream, &rtptime, &seq)) {
846       if (infocount > 0)
847         g_string_append (rtpinfo, ", ");
848
849       uristr = gst_rtsp_url_get_request_uri (state->uri);
850       g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u",
851           uristr, i, seq, rtptime);
852       g_free (uristr);
853
854       infocount++;
855     } else {
856       GST_WARNING ("RTP-Info cannot be determined for stream %d", i);
857     }
858   }
859
860   /* construct the response now */
861   code = GST_RTSP_STS_OK;
862   gst_rtsp_message_init_response (state->response, code,
863       gst_rtsp_status_as_text (code), state->request);
864
865   /* add the RTP-Info header */
866   if (infocount > 0) {
867     str = g_string_free (rtpinfo, FALSE);
868     gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RTP_INFO, str);
869   } else {
870     g_string_free (rtpinfo, TRUE);
871   }
872
873   /* add the range */
874   str = gst_rtsp_media_get_range_string (media->media, TRUE);
875   gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str);
876
877   send_response (client, session, state->response, FALSE);
878
879   /* start playing after sending the request */
880   gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
881
882   media->state = GST_RTSP_STATE_PLAYING;
883
884   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST],
885       0, state);
886
887   return TRUE;
888
889   /* ERRORS */
890 no_session:
891   {
892     GST_ERROR ("client %p: no session", client);
893     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
894     return FALSE;
895   }
896 not_found:
897   {
898     GST_ERROR ("client %p: media not found", client);
899     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
900     return FALSE;
901   }
902 invalid_state:
903   {
904     GST_ERROR ("client %p: not PLAYING or READY", client);
905     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
906         state);
907     return FALSE;
908   }
909 }
910
911 static void
912 do_keepalive (GstRTSPSession * session)
913 {
914   GST_INFO ("keep session %p alive", session);
915   gst_rtsp_session_touch (session);
916 }
917
918 /* parse @transport and return a valid transport in @tr. only transports
919  * from @supported are returned. Returns FALSE if no valid transport
920  * was found. */
921 static gboolean
922 parse_transport (const char *transport, GstRTSPLowerTrans supported,
923     GstRTSPTransport * tr)
924 {
925   gint i;
926   gboolean res;
927   gchar **transports;
928
929   res = FALSE;
930   gst_rtsp_transport_init (tr);
931
932   GST_DEBUG ("parsing transports %s", transport);
933
934   transports = g_strsplit (transport, ",", 0);
935
936   /* loop through the transports, try to parse */
937   for (i = 0; transports[i]; i++) {
938     res = gst_rtsp_transport_parse (transports[i], tr);
939     if (res != GST_RTSP_OK) {
940       /* no valid transport, search some more */
941       GST_WARNING ("could not parse transport %s", transports[i]);
942       goto next;
943     }
944
945     /* we have a transport, see if it's RTP/AVP */
946     if (tr->trans != GST_RTSP_TRANS_RTP || tr->profile != GST_RTSP_PROFILE_AVP) {
947       GST_WARNING ("invalid transport %s", transports[i]);
948       goto next;
949     }
950
951     if (!(tr->lower_transport & supported)) {
952       GST_WARNING ("unsupported transport %s", transports[i]);
953       goto next;
954     }
955
956     /* we have a valid transport */
957     GST_INFO ("found valid transport %s", transports[i]);
958     res = TRUE;
959     break;
960
961   next:
962     gst_rtsp_transport_init (tr);
963   }
964   g_strfreev (transports);
965
966   return res;
967 }
968
969 static gboolean
970 handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream,
971     GstRTSPMessage * request)
972 {
973   gchar *blocksize_str;
974   gboolean ret = TRUE;
975
976   if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
977           &blocksize_str, 0) == GST_RTSP_OK) {
978     guint64 blocksize;
979     gchar *end;
980
981     blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
982     if (end == blocksize_str) {
983       GST_ERROR ("failed to parse blocksize");
984       ret = FALSE;
985     } else {
986       /* we don't want to change the mtu when this media
987        * can be shared because it impacts other clients */
988       if (gst_rtsp_media_is_shared (media))
989         return TRUE;
990
991       if (blocksize > G_MAXUINT)
992         blocksize = G_MAXUINT;
993       gst_rtsp_stream_set_mtu (stream, blocksize);
994     }
995   }
996   return ret;
997 }
998
999 static gboolean
1000 configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
1001     GstRTSPTransport * ct)
1002 {
1003   /* we have a valid transport now, set the destination of the client. */
1004   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1005     if (ct->destination == NULL || !client->use_client_settings) {
1006       GstRTSPAddress *addr;
1007
1008       addr = gst_rtsp_stream_get_address (state->stream);
1009       if (addr == NULL)
1010         goto no_address;
1011
1012       g_free (ct->destination);
1013       ct->destination = g_strdup (addr->address);
1014       ct->port.min = addr->port;
1015       ct->port.max = addr->port + addr->n_ports - 1;
1016       ct->ttl = addr->ttl;
1017     }
1018   } else {
1019     GstRTSPUrl *url;
1020
1021     url = gst_rtsp_connection_get_url (client->connection);
1022     g_free (ct->destination);
1023     ct->destination = g_strdup (url->host);
1024
1025     if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1026       /* check if the client selected channels for TCP */
1027       if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1028         gst_rtsp_session_media_alloc_channels (state->sessmedia,
1029             &ct->interleaved);
1030       }
1031     }
1032   }
1033   return TRUE;
1034
1035   /* ERRORS */
1036 no_address:
1037   {
1038     GST_ERROR_OBJECT (client, "failed to acquire address for stream");
1039     return FALSE;
1040   }
1041 }
1042
1043 static GstRTSPTransport *
1044 make_server_transport (GstRTSPClient * client, GstRTSPClientState * state,
1045     GstRTSPTransport * ct)
1046 {
1047   GstRTSPTransport *st;
1048
1049   /* prepare the server transport */
1050   gst_rtsp_transport_new (&st);
1051
1052   st->trans = ct->trans;
1053   st->profile = ct->profile;
1054   st->lower_transport = ct->lower_transport;
1055
1056   switch (st->lower_transport) {
1057     case GST_RTSP_LOWER_TRANS_UDP:
1058       st->client_port = ct->client_port;
1059       st->server_port = state->stream->server_port;
1060       break;
1061     case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1062       st->port = ct->port;
1063       st->destination = g_strdup (ct->destination);
1064       st->ttl = ct->ttl;
1065       break;
1066     case GST_RTSP_LOWER_TRANS_TCP:
1067       st->interleaved = ct->interleaved;
1068     default:
1069       break;
1070   }
1071
1072   if (state->stream->session)
1073     g_object_get (state->stream->session, "internal-ssrc", &st->ssrc, NULL);
1074
1075   return st;
1076 }
1077
1078 static gboolean
1079 handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
1080 {
1081   GstRTSPResult res;
1082   GstRTSPUrl *uri;
1083   gchar *transport;
1084   GstRTSPTransport *ct, *st;
1085   GstRTSPLowerTrans supported;
1086   GstRTSPStatusCode code;
1087   GstRTSPSession *session;
1088   GstRTSPStreamTransport *trans;
1089   gchar *trans_str, *pos;
1090   guint streamid;
1091   GstRTSPSessionMedia *sessmedia;
1092   GstRTSPMedia *media;
1093   GstRTSPStream *stream;
1094
1095   uri = state->uri;
1096
1097   /* the uri contains the stream number we added in the SDP config, which is
1098    * always /stream=%d so we need to strip that off
1099    * parse the stream we need to configure, look for the stream in the abspath
1100    * first and then in the query. */
1101   if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) {
1102     if (uri->query == NULL || !(pos = strstr (uri->query, "/stream=")))
1103       goto bad_request;
1104   }
1105
1106   /* we can mofify the parsed uri in place */
1107   *pos = '\0';
1108
1109   pos += strlen ("/stream=");
1110   if (sscanf (pos, "%u", &streamid) != 1)
1111     goto bad_request;
1112
1113   /* parse the transport */
1114   res =
1115       gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_TRANSPORT,
1116       &transport, 0);
1117   if (res != GST_RTSP_OK)
1118     goto no_transport;
1119
1120   gst_rtsp_transport_new (&ct);
1121
1122   /* our supported transports */
1123   supported = GST_RTSP_LOWER_TRANS_UDP |
1124       GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP;
1125
1126   /* parse and find a usable supported transport */
1127   if (!parse_transport (transport, supported, ct))
1128     goto unsupported_transports;
1129
1130   /* we create the session after parsing stuff so that we don't make
1131    * a session for malformed requests */
1132   if (client->session_pool == NULL)
1133     goto no_pool;
1134
1135   session = state->session;
1136
1137   if (session) {
1138     g_object_ref (session);
1139     /* get a handle to the configuration of the media in the session, this can
1140      * return NULL if this is a new url to manage in this session. */
1141     sessmedia = gst_rtsp_session_get_media (session, uri);
1142   } else {
1143     /* create a session if this fails we probably reached our session limit or
1144      * something. */
1145     if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
1146       goto service_unavailable;
1147
1148     state->session = session;
1149
1150     /* we need a new media configuration in this session */
1151     sessmedia = NULL;
1152   }
1153
1154   /* we have no media, find one and manage it */
1155   if (sessmedia == NULL) {
1156     /* get a handle to the configuration of the media in the session */
1157     if ((media = find_media (client, state))) {
1158       /* manage the media in our session now */
1159       sessmedia = gst_rtsp_session_manage_media (session, uri, media);
1160     }
1161   }
1162
1163   /* if we stil have no media, error */
1164   if (sessmedia == NULL)
1165     goto not_found;
1166
1167   state->sessmedia = sessmedia;
1168   state->media = media = sessmedia->media;
1169
1170   /* now get the stream */
1171   stream = gst_rtsp_media_get_stream (media, streamid);
1172   if (stream == NULL)
1173     goto not_found;
1174
1175   state->stream = stream;
1176
1177   /* set blocksize on this stream */
1178   if (!handle_blocksize (media, stream, state->request))
1179     goto invalid_blocksize;
1180
1181   /* update the client transport */
1182   if (!configure_client_transport (client, state, ct))
1183     goto unsupported_client_transport;
1184
1185   /* set in the session media transport */
1186   trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
1187
1188   /* configure keepalive for this transport */
1189   gst_rtsp_stream_transport_set_keepalive (trans,
1190       (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
1191
1192   /* create and serialize the server transport */
1193   st = make_server_transport (client, state, ct);
1194   trans_str = gst_rtsp_transport_as_text (st);
1195   gst_rtsp_transport_free (st);
1196
1197   /* construct the response now */
1198   code = GST_RTSP_STS_OK;
1199   gst_rtsp_message_init_response (state->response, code,
1200       gst_rtsp_status_as_text (code), state->request);
1201
1202   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_TRANSPORT,
1203       trans_str);
1204   g_free (trans_str);
1205
1206   send_response (client, session, state->response, FALSE);
1207
1208   /* update the state */
1209   switch (sessmedia->state) {
1210     case GST_RTSP_STATE_PLAYING:
1211     case GST_RTSP_STATE_RECORDING:
1212     case GST_RTSP_STATE_READY:
1213       /* no state change */
1214       break;
1215     default:
1216       sessmedia->state = GST_RTSP_STATE_READY;
1217       break;
1218   }
1219   g_object_unref (session);
1220
1221   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST],
1222       0, state);
1223
1224   return TRUE;
1225
1226   /* ERRORS */
1227 bad_request:
1228   {
1229     GST_ERROR ("client %p: bad request", client);
1230     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1231     return FALSE;
1232   }
1233 not_found:
1234   {
1235     GST_ERROR ("client %p: media not found", client);
1236     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1237     g_object_unref (session);
1238     gst_rtsp_transport_free (ct);
1239     return FALSE;
1240   }
1241 invalid_blocksize:
1242   {
1243     GST_ERROR ("client %p: invalid blocksize", client);
1244     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1245     g_object_unref (session);
1246     gst_rtsp_transport_free (ct);
1247     return FALSE;
1248   }
1249 unsupported_client_transport:
1250   {
1251     GST_ERROR ("client %p: unsupported client transport", client);
1252     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1253     g_object_unref (session);
1254     gst_rtsp_transport_free (ct);
1255     return FALSE;
1256   }
1257 no_transport:
1258   {
1259     GST_ERROR ("client %p: no transport", client);
1260     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1261     return FALSE;
1262   }
1263 unsupported_transports:
1264   {
1265     GST_ERROR ("client %p: unsupported transports", client);
1266     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1267     gst_rtsp_transport_free (ct);
1268     return FALSE;
1269   }
1270 no_pool:
1271   {
1272     GST_ERROR ("client %p: no session pool configured", client);
1273     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1274     gst_rtsp_transport_free (ct);
1275     return FALSE;
1276   }
1277 service_unavailable:
1278   {
1279     GST_ERROR ("client %p: can't create session", client);
1280     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1281     gst_rtsp_transport_free (ct);
1282     return FALSE;
1283   }
1284 }
1285
1286 static GstSDPMessage *
1287 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
1288 {
1289   GstSDPMessage *sdp;
1290   GstSDPInfo info;
1291   const gchar *proto;
1292
1293   gst_sdp_message_new (&sdp);
1294
1295   /* some standard things first */
1296   gst_sdp_message_set_version (sdp, "0");
1297
1298   if (client->is_ipv6)
1299     proto = "IP6";
1300   else
1301     proto = "IP4";
1302
1303   gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
1304       client->server_ip);
1305
1306   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
1307   gst_sdp_message_set_information (sdp, "rtsp-server");
1308   gst_sdp_message_add_time (sdp, "0", "0", NULL);
1309   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
1310   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
1311   gst_sdp_message_add_attribute (sdp, "control", "*");
1312
1313   info.server_proto = proto;
1314   info.server_ip = g_strdup (client->server_ip);
1315
1316   /* create an SDP for the media object */
1317   if (!gst_rtsp_sdp_from_media (sdp, &info, media))
1318     goto no_sdp;
1319
1320   g_free (info.server_ip);
1321
1322   return sdp;
1323
1324   /* ERRORS */
1325 no_sdp:
1326   {
1327     GST_ERROR ("client %p: could not create SDP", client);
1328     g_free (info.server_ip);
1329     gst_sdp_message_free (sdp);
1330     return NULL;
1331   }
1332 }
1333
1334 /* for the describe we must generate an SDP */
1335 static gboolean
1336 handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state)
1337 {
1338   GstRTSPResult res;
1339   GstSDPMessage *sdp;
1340   guint i, str_len;
1341   gchar *str, *content_base;
1342   GstRTSPMedia *media;
1343   GstRTSPClientClass *klass;
1344
1345   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1346
1347   /* check what kind of format is accepted, we don't really do anything with it
1348    * and always return SDP for now. */
1349   for (i = 0; i++;) {
1350     gchar *accept;
1351
1352     res =
1353         gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT,
1354         &accept, i);
1355     if (res == GST_RTSP_ENOTIMPL)
1356       break;
1357
1358     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
1359       break;
1360   }
1361
1362   /* find the media object for the uri */
1363   if (!(media = find_media (client, state)))
1364     goto no_media;
1365
1366   /* create an SDP for the media object on this client */
1367   if (!(sdp = klass->create_sdp (client, media)))
1368     goto no_sdp;
1369
1370   g_object_unref (media);
1371
1372   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1373       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1374
1375   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE,
1376       "application/sdp");
1377
1378   /* content base for some clients that might screw up creating the setup uri */
1379   str = gst_rtsp_url_get_request_uri (state->uri);
1380   str_len = strlen (str);
1381
1382   /* check for trailing '/' and append one */
1383   if (str[str_len - 1] != '/') {
1384     content_base = g_malloc (str_len + 2);
1385     memcpy (content_base, str, str_len);
1386     content_base[str_len] = '/';
1387     content_base[str_len + 1] = '\0';
1388     g_free (str);
1389   } else {
1390     content_base = str;
1391   }
1392
1393   GST_INFO ("adding content-base: %s", content_base);
1394
1395   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE,
1396       content_base);
1397   g_free (content_base);
1398
1399   /* add SDP to the response body */
1400   str = gst_sdp_message_as_text (sdp);
1401   gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str));
1402   gst_sdp_message_free (sdp);
1403
1404   send_response (client, state->session, state->response, FALSE);
1405
1406   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
1407       0, state);
1408
1409   return TRUE;
1410
1411   /* ERRORS */
1412 no_media:
1413   {
1414     GST_ERROR ("client %p: no media", client);
1415     /* error reply is already sent */
1416     return FALSE;
1417   }
1418 no_sdp:
1419   {
1420     GST_ERROR ("client %p: can't create SDP", client);
1421     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1422     g_object_unref (media);
1423     return FALSE;
1424   }
1425 }
1426
1427 static gboolean
1428 handle_options_request (GstRTSPClient * client, GstRTSPClientState * state)
1429 {
1430   GstRTSPMethod options;
1431   gchar *str;
1432
1433   options = GST_RTSP_DESCRIBE |
1434       GST_RTSP_OPTIONS |
1435       GST_RTSP_PAUSE |
1436       GST_RTSP_PLAY |
1437       GST_RTSP_SETUP |
1438       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1439
1440   str = gst_rtsp_options_as_text (options);
1441
1442   gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1443       gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1444
1445   gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str);
1446   g_free (str);
1447
1448   send_response (client, state->session, state->response, FALSE);
1449
1450   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
1451       0, state);
1452
1453   return TRUE;
1454 }
1455
1456 /* remove duplicate and trailing '/' */
1457 static void
1458 sanitize_uri (GstRTSPUrl * uri)
1459 {
1460   gint i, len;
1461   gchar *s, *d;
1462   gboolean have_slash, prev_slash;
1463
1464   s = d = uri->abspath;
1465   len = strlen (uri->abspath);
1466
1467   prev_slash = FALSE;
1468
1469   for (i = 0; i < len; i++) {
1470     have_slash = s[i] == '/';
1471     *d = s[i];
1472     if (!have_slash || !prev_slash)
1473       d++;
1474     prev_slash = have_slash;
1475   }
1476   len = d - uri->abspath;
1477   /* don't remove the first slash if that's the only thing left */
1478   if (len > 1 && *(d - 1) == '/')
1479     d--;
1480   *d = '\0';
1481 }
1482
1483 static void
1484 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
1485 {
1486   GST_INFO ("client %p: session %p finished", client, session);
1487
1488   /* unlink all media managed in this session */
1489   client_unlink_session (client, session);
1490
1491   /* remove the session */
1492   if (!(client->sessions = g_list_remove (client->sessions, session))) {
1493     GST_INFO ("client %p: all sessions finalized, close the connection",
1494         client);
1495     close_connection (client);
1496   }
1497 }
1498
1499 static void
1500 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
1501 {
1502   GList *walk;
1503
1504   for (walk = client->sessions; walk; walk = g_list_next (walk)) {
1505     GstRTSPSession *msession = (GstRTSPSession *) walk->data;
1506
1507     /* we already know about this session */
1508     if (msession == session)
1509       return;
1510   }
1511
1512   GST_INFO ("watching session %p", session);
1513
1514   g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
1515       client);
1516   client->sessions = g_list_prepend (client->sessions, session);
1517
1518   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
1519       session);
1520 }
1521
1522 static void
1523 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
1524 {
1525   GstRTSPMethod method;
1526   const gchar *uristr;
1527   GstRTSPUrl *uri;
1528   GstRTSPVersion version;
1529   GstRTSPResult res;
1530   GstRTSPSession *session;
1531   GstRTSPClientState state = { NULL };
1532   GstRTSPMessage response = { 0 };
1533   gchar *sessid;
1534
1535   state.request = request;
1536   state.response = &response;
1537
1538   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1539     gst_rtsp_message_dump (request);
1540   }
1541
1542   GST_INFO ("client %p: received a request", client);
1543
1544   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
1545
1546   if (version != GST_RTSP_VERSION_1_0) {
1547     /* we can only handle 1.0 requests */
1548     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
1549         &state);
1550     return;
1551   }
1552   state.method = method;
1553
1554   /* we always try to parse the url first */
1555   if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
1556     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1557     return;
1558   }
1559
1560   /* sanitize the uri */
1561   sanitize_uri (uri);
1562   state.uri = uri;
1563
1564   /* get the session if there is any */
1565   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
1566   if (res == GST_RTSP_OK) {
1567     if (client->session_pool == NULL)
1568       goto no_pool;
1569
1570     /* we had a session in the request, find it again */
1571     if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
1572       goto session_not_found;
1573
1574     /* we add the session to the client list of watched sessions. When a session
1575      * disappears because it times out, we will be notified. If all sessions are
1576      * gone, we will close the connection */
1577     client_watch_session (client, session);
1578   } else
1579     session = NULL;
1580
1581   state.session = session;
1582
1583   if (client->auth) {
1584     if (!gst_rtsp_auth_check (client->auth, client, 0, &state))
1585       goto not_authorized;
1586   }
1587
1588   /* now see what is asked and dispatch to a dedicated handler */
1589   switch (method) {
1590     case GST_RTSP_OPTIONS:
1591       handle_options_request (client, &state);
1592       break;
1593     case GST_RTSP_DESCRIBE:
1594       handle_describe_request (client, &state);
1595       break;
1596     case GST_RTSP_SETUP:
1597       handle_setup_request (client, &state);
1598       break;
1599     case GST_RTSP_PLAY:
1600       handle_play_request (client, &state);
1601       break;
1602     case GST_RTSP_PAUSE:
1603       handle_pause_request (client, &state);
1604       break;
1605     case GST_RTSP_TEARDOWN:
1606       handle_teardown_request (client, &state);
1607       break;
1608     case GST_RTSP_SET_PARAMETER:
1609       handle_set_param_request (client, &state);
1610       break;
1611     case GST_RTSP_GET_PARAMETER:
1612       handle_get_param_request (client, &state);
1613       break;
1614     case GST_RTSP_ANNOUNCE:
1615     case GST_RTSP_RECORD:
1616     case GST_RTSP_REDIRECT:
1617       send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state);
1618       break;
1619     case GST_RTSP_INVALID:
1620     default:
1621       send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1622       break;
1623   }
1624   if (session)
1625     g_object_unref (session);
1626
1627   gst_rtsp_url_free (uri);
1628   return;
1629
1630   /* ERRORS */
1631 no_pool:
1632   {
1633     GST_ERROR ("client %p: no pool configured", client);
1634     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, &state);
1635     return;
1636   }
1637 session_not_found:
1638   {
1639     GST_ERROR ("client %p: session not found", client);
1640     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1641     return;
1642   }
1643 not_authorized:
1644   {
1645     GST_ERROR ("client %p: not allowed", client);
1646     handle_unauthorized_request (client, client->auth, &state);
1647     return;
1648   }
1649 }
1650
1651 static void
1652 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
1653 {
1654   GstRTSPResult res;
1655   guint8 channel;
1656   GList *walk;
1657   guint8 *data;
1658   guint size;
1659   GstBuffer *buffer;
1660   gboolean handled;
1661
1662   /* find the stream for this message */
1663   res = gst_rtsp_message_parse_data (message, &channel);
1664   if (res != GST_RTSP_OK)
1665     return;
1666
1667   gst_rtsp_message_steal_body (message, &data, &size);
1668
1669   buffer = gst_buffer_new_wrapped (data, size);
1670
1671   handled = FALSE;
1672   for (walk = client->transports; walk; walk = g_list_next (walk)) {
1673     GstRTSPStreamTransport *trans;
1674     GstRTSPStream *stream;
1675     GstRTSPTransport *tr;
1676
1677     trans = walk->data;
1678
1679     /* we only add clients with a transport to the list */
1680     tr = trans->transport;
1681     stream = trans->stream;
1682
1683     /* check for TCP transport */
1684     if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1685       /* dispatch to the stream based on the channel number */
1686       if (tr->interleaved.min == channel) {
1687         gst_rtsp_stream_recv_rtp (stream, buffer);
1688         handled = TRUE;
1689         break;
1690       } else if (tr->interleaved.max == channel) {
1691         gst_rtsp_stream_recv_rtcp (stream, buffer);
1692         handled = TRUE;
1693         break;
1694       }
1695     }
1696   }
1697   if (!handled)
1698     gst_buffer_unref (buffer);
1699 }
1700
1701 /**
1702  * gst_rtsp_client_set_session_pool:
1703  * @client: a #GstRTSPClient
1704  * @pool: a #GstRTSPSessionPool
1705  *
1706  * Set @pool as the sessionpool for @client which it will use to find
1707  * or allocate sessions. the sessionpool is usually inherited from the server
1708  * that created the client but can be overridden later.
1709  */
1710 void
1711 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
1712     GstRTSPSessionPool * pool)
1713 {
1714   GstRTSPSessionPool *old;
1715
1716   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1717
1718   if (pool)
1719     g_object_ref (pool);
1720
1721   g_mutex_lock (&client->lock);
1722   old = client->session_pool;
1723   client->session_pool = pool;
1724   g_mutex_unlock (&client->lock);
1725
1726   if (old)
1727     g_object_unref (old);
1728 }
1729
1730 /**
1731  * gst_rtsp_client_get_session_pool:
1732  * @client: a #GstRTSPClient
1733  *
1734  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1735  *
1736  * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage.
1737  */
1738 GstRTSPSessionPool *
1739 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
1740 {
1741   GstRTSPSessionPool *result;
1742
1743   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1744
1745   g_mutex_lock (&client->lock);
1746   if ((result = client->session_pool))
1747     g_object_ref (result);
1748   g_mutex_unlock (&client->lock);
1749
1750   return result;
1751 }
1752
1753 /**
1754  * gst_rtsp_client_set_mount_points:
1755  * @client: a #GstRTSPClient
1756  * @mounts: a #GstRTSPMountPoints
1757  *
1758  * Set @mounts as the mount points for @client which it will use to map urls
1759  * to media streams. These mount points are usually inherited from the server that
1760  * created the client but can be overriden later.
1761  */
1762 void
1763 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
1764     GstRTSPMountPoints * mounts)
1765 {
1766   GstRTSPMountPoints *old;
1767
1768   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1769
1770   if (mounts)
1771     g_object_ref (mounts);
1772
1773   g_mutex_lock (&client->lock);
1774   old = client->mount_points;
1775   client->mount_points = mounts;
1776   g_mutex_unlock (&client->lock);
1777
1778   if (old)
1779     g_object_unref (old);
1780 }
1781
1782 /**
1783  * gst_rtsp_client_get_mount_points:
1784  * @client: a #GstRTSPClient
1785  *
1786  * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
1787  *
1788  * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage.
1789  */
1790 GstRTSPMountPoints *
1791 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
1792 {
1793   GstRTSPMountPoints *result;
1794
1795   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1796
1797   g_mutex_lock (&client->lock);
1798   if ((result = client->mount_points))
1799     g_object_ref (result);
1800   g_mutex_unlock (&client->lock);
1801
1802   return result;
1803 }
1804
1805 /**
1806  * gst_rtsp_client_set_use_client_settings:
1807  * @client: a #GstRTSPClient
1808  * @use_client_settings: whether to use client settings for multicast
1809  *
1810  * Use client transport settings (destination and ttl) for multicast.
1811  * When @use_client_settings is %FALSE, the server settings will be
1812  * used.
1813  */
1814 void
1815 gst_rtsp_client_set_use_client_settings (GstRTSPClient * client,
1816     gboolean use_client_settings)
1817 {
1818   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1819
1820   g_mutex_lock (&client->lock);
1821   client->use_client_settings = use_client_settings;
1822   g_mutex_unlock (&client->lock);
1823 }
1824
1825 /**
1826  * gst_rtsp_client_get_use_client_settings:
1827  * @client: a #GstRTSPClient
1828  *
1829  * Check if client transport settings (destination and ttl) for multicast
1830  * will be used.
1831  */
1832 gboolean
1833 gst_rtsp_client_get_use_client_settings (GstRTSPClient * client)
1834 {
1835   gboolean res;
1836
1837   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
1838
1839   g_mutex_lock (&client->lock);
1840   res = client->use_client_settings;
1841   g_mutex_unlock (&client->lock);
1842
1843   return res;
1844 }
1845
1846 /**
1847  * gst_rtsp_client_set_auth:
1848  * @client: a #GstRTSPClient
1849  * @auth: a #GstRTSPAuth
1850  *
1851  * configure @auth to be used as the authentication manager of @client.
1852  */
1853 void
1854 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
1855 {
1856   GstRTSPAuth *old;
1857
1858   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1859
1860   if (auth)
1861     g_object_ref (auth);
1862
1863   g_mutex_lock (&client->lock);
1864   old = client->auth;
1865   client->auth = auth;
1866   g_mutex_unlock (&client->lock);
1867
1868   if (old)
1869     g_object_unref (old);
1870 }
1871
1872
1873 /**
1874  * gst_rtsp_client_get_auth:
1875  * @client: a #GstRTSPClient
1876  *
1877  * Get the #GstRTSPAuth used as the authentication manager of @client.
1878  *
1879  * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after
1880  * usage.
1881  */
1882 GstRTSPAuth *
1883 gst_rtsp_client_get_auth (GstRTSPClient * client)
1884 {
1885   GstRTSPAuth *result;
1886
1887   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1888
1889   g_mutex_lock (&client->lock);
1890   if ((result = client->auth))
1891     g_object_ref (result);
1892   g_mutex_unlock (&client->lock);
1893
1894   return result;
1895 }
1896
1897 /**
1898  * gst_rtsp_client_set_send_func:
1899  * @client: a #GstRTSPClient
1900  * @func: a #GstRTSPClientSendFunc
1901  * @user_data: user data passed to @func
1902  * @notify: called when @user_data is no longer in use
1903  *
1904  * Set @func as the callback that will be called when a new message needs to be
1905  * sent to the client. @user_data is passed to @func and @notify is called when
1906  * @user_data is no longer in use.
1907  */
1908 void
1909 gst_rtsp_client_set_send_func (GstRTSPClient * client,
1910     GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
1911 {
1912   GDestroyNotify old_notify;
1913   gpointer old_data;
1914
1915   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1916
1917   g_mutex_lock (&client->lock);
1918   client->send_func = func;
1919   old_notify = client->send_notify;
1920   old_data = client->send_data;
1921   client->send_notify = notify;
1922   client->send_data = user_data;
1923   g_mutex_unlock (&client->lock);
1924
1925   if (old_notify)
1926     old_notify (old_data);
1927 }
1928
1929 /**
1930  * gst_rtsp_client_handle_message:
1931  * @client: a #GstRTSPClient
1932  * @message: an #GstRTSPMessage
1933  *
1934  * Let the client handle @message.
1935  *
1936  * Returns: a #GstRTSPResult.
1937  */
1938 GstRTSPResult
1939 gst_rtsp_client_handle_message (GstRTSPClient * client,
1940     GstRTSPMessage * message)
1941 {
1942   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
1943   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
1944
1945   switch (message->type) {
1946     case GST_RTSP_MESSAGE_REQUEST:
1947       handle_request (client, message);
1948       break;
1949     case GST_RTSP_MESSAGE_RESPONSE:
1950       break;
1951     case GST_RTSP_MESSAGE_DATA:
1952       handle_data (client, message);
1953       break;
1954     default:
1955       break;
1956   }
1957   return GST_RTSP_OK;
1958 }
1959
1960 static GstRTSPResult
1961 do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
1962     gboolean close, gpointer user_data)
1963 {
1964   /* send the response and store the seq number so we can wait until it's
1965    * written to the client to close the connection */
1966   return gst_rtsp_watch_send_message (client->watch, message, close ?
1967       &client->close_seq : NULL);
1968 }
1969
1970 static GstRTSPResult
1971 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
1972     gpointer user_data)
1973 {
1974   return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
1975 }
1976
1977 static GstRTSPResult
1978 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
1979 {
1980   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1981
1982   if (client->close_seq && client->close_seq == cseq) {
1983     client->close_seq = 0;
1984     close_connection (client);
1985   }
1986
1987   return GST_RTSP_OK;
1988 }
1989
1990 static GstRTSPResult
1991 closed (GstRTSPWatch * watch, gpointer user_data)
1992 {
1993   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1994   const gchar *tunnelid;
1995
1996   GST_INFO ("client %p: connection closed", client);
1997
1998   if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
1999     g_mutex_lock (&tunnels_lock);
2000     /* remove from tunnelids */
2001     g_hash_table_remove (tunnels, tunnelid);
2002     g_mutex_unlock (&tunnels_lock);
2003   }
2004
2005   return GST_RTSP_OK;
2006 }
2007
2008 static GstRTSPResult
2009 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
2010 {
2011   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2012   gchar *str;
2013
2014   str = gst_rtsp_strresult (result);
2015   GST_INFO ("client %p: received an error %s", client, str);
2016   g_free (str);
2017
2018   return GST_RTSP_OK;
2019 }
2020
2021 static GstRTSPResult
2022 error_full (GstRTSPWatch * watch, GstRTSPResult result,
2023     GstRTSPMessage * message, guint id, gpointer user_data)
2024 {
2025   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2026   gchar *str;
2027
2028   str = gst_rtsp_strresult (result);
2029   GST_INFO
2030       ("client %p: received an error %s when handling message %p with id %d",
2031       client, str, message, id);
2032   g_free (str);
2033
2034   return GST_RTSP_OK;
2035 }
2036
2037 static gboolean
2038 remember_tunnel (GstRTSPClient * client)
2039 {
2040   const gchar *tunnelid;
2041
2042   /* store client in the pending tunnels */
2043   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
2044   if (tunnelid == NULL)
2045     goto no_tunnelid;
2046
2047   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
2048
2049   /* we can't have two clients connecting with the same tunnelid */
2050   g_mutex_lock (&tunnels_lock);
2051   if (g_hash_table_lookup (tunnels, tunnelid))
2052     goto tunnel_existed;
2053
2054   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
2055   g_mutex_unlock (&tunnels_lock);
2056
2057   return TRUE;
2058
2059   /* ERRORS */
2060 no_tunnelid:
2061   {
2062     GST_ERROR ("client %p: no tunnelid provided", client);
2063     return FALSE;
2064   }
2065 tunnel_existed:
2066   {
2067     g_mutex_unlock (&tunnels_lock);
2068     GST_ERROR ("client %p: tunnel session %s already existed", client,
2069         tunnelid);
2070     return FALSE;
2071   }
2072 }
2073
2074 static GstRTSPStatusCode
2075 tunnel_start (GstRTSPWatch * watch, gpointer user_data)
2076 {
2077   GstRTSPClient *client;
2078
2079   client = GST_RTSP_CLIENT (user_data);
2080
2081   GST_INFO ("client %p: tunnel start (connection %p)", client,
2082       client->connection);
2083
2084   if (!remember_tunnel (client))
2085     goto tunnel_error;
2086
2087   return GST_RTSP_STS_OK;
2088
2089   /* ERRORS */
2090 tunnel_error:
2091   {
2092     GST_ERROR ("client %p: error starting tunnel", client);
2093     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2094   }
2095 }
2096
2097 static GstRTSPResult
2098 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
2099 {
2100   GstRTSPClient *client;
2101
2102   client = GST_RTSP_CLIENT (user_data);
2103
2104   GST_WARNING ("client %p: tunnel lost (connection %p)", client,
2105       client->connection);
2106
2107   /* ignore error, it'll only be a problem when the client does a POST again */
2108   remember_tunnel (client);
2109
2110   return GST_RTSP_OK;
2111 }
2112
2113 static GstRTSPResult
2114 tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
2115 {
2116   const gchar *tunnelid;
2117   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2118   GstRTSPClient *oclient;
2119
2120   GST_INFO ("client %p: tunnel complete", client);
2121
2122   /* find previous tunnel */
2123   tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
2124   if (tunnelid == NULL)
2125     goto no_tunnelid;
2126
2127   g_mutex_lock (&tunnels_lock);
2128   if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
2129     goto no_tunnel;
2130
2131   /* remove the old client from the table. ref before because removing it will
2132    * remove the ref to it. */
2133   g_object_ref (oclient);
2134   g_hash_table_remove (tunnels, tunnelid);
2135
2136   if (oclient->watch == NULL)
2137     goto tunnel_closed;
2138   g_mutex_unlock (&tunnels_lock);
2139
2140   GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
2141       oclient->connection, client->connection);
2142
2143   /* merge the tunnels into the first client */
2144   gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
2145   gst_rtsp_watch_reset (oclient->watch);
2146   g_object_unref (oclient);
2147
2148   return GST_RTSP_OK;
2149
2150   /* ERRORS */
2151 no_tunnelid:
2152   {
2153     GST_ERROR ("client %p: no tunnelid provided", client);
2154     return GST_RTSP_ERROR;
2155   }
2156 no_tunnel:
2157   {
2158     g_mutex_unlock (&tunnels_lock);
2159     GST_ERROR ("client %p: tunnel session %s not found", client, tunnelid);
2160     return GST_RTSP_ERROR;
2161   }
2162 tunnel_closed:
2163   {
2164     g_mutex_unlock (&tunnels_lock);
2165     GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
2166     g_object_unref (oclient);
2167     return GST_RTSP_ERROR;
2168   }
2169 }
2170
2171 static GstRTSPWatchFuncs watch_funcs = {
2172   message_received,
2173   message_sent,
2174   closed,
2175   error,
2176   tunnel_start,
2177   tunnel_complete,
2178   error_full,
2179   tunnel_lost
2180 };
2181
2182 static void
2183 client_watch_notify (GstRTSPClient * client)
2184 {
2185   GST_INFO ("client %p: watch destroyed", client);
2186   client->watch = NULL;
2187   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
2188   g_object_unref (client);
2189 }
2190
2191 static gboolean
2192 setup_client (GstRTSPClient * client, GSocket * socket,
2193     GstRTSPConnection * conn, GError ** error)
2194 {
2195   GSocket *read_socket;
2196   GSocketAddress *address;
2197   GstRTSPUrl *url;
2198
2199   read_socket = gst_rtsp_connection_get_read_socket (conn);
2200   client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6;
2201
2202   if (!(address = g_socket_get_remote_address (read_socket, error)))
2203     goto no_address;
2204
2205   g_free (client->server_ip);
2206   /* keep the original ip that the client connected to */
2207   if (G_IS_INET_SOCKET_ADDRESS (address)) {
2208     GInetAddress *iaddr;
2209
2210     iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
2211
2212     client->server_ip = g_inet_address_to_string (iaddr);
2213     g_object_unref (address);
2214   } else {
2215     client->server_ip = g_strdup ("unknown");
2216   }
2217
2218   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
2219       client->server_ip, client->is_ipv6);
2220
2221   url = gst_rtsp_connection_get_url (conn);
2222   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
2223
2224   client->connection = conn;
2225
2226   return TRUE;
2227
2228   /* ERRORS */
2229 no_address:
2230   {
2231     GST_ERROR ("could not get remote address %s", (*error)->message);
2232     return FALSE;
2233   }
2234 }
2235
2236 /**
2237  * gst_rtsp_client_use_socket:
2238  * @client: a #GstRTSPClient
2239  * @socket: a #GSocket
2240  * @ip: the IP address of the remote client
2241  * @port: the port used by the other end
2242  * @initial_buffer: any zero terminated initial data that was already read from
2243  *     the socket
2244  * @error: a #GError
2245  *
2246  * Take an existing network socket and use it for an RTSP connection.
2247  *
2248  * Returns: %TRUE on success.
2249  */
2250 gboolean
2251 gst_rtsp_client_use_socket (GstRTSPClient * client, GSocket * socket,
2252     const gchar * ip, gint port, const gchar * initial_buffer, GError ** error)
2253 {
2254   GstRTSPConnection *conn;
2255   GstRTSPResult res;
2256
2257   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
2258   g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
2259
2260   GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port,
2261           initial_buffer, &conn), no_connection);
2262
2263   return setup_client (client, socket, conn, error);
2264
2265   /* ERRORS */
2266 no_connection:
2267   {
2268     gchar *str = gst_rtsp_strresult (res);
2269
2270     GST_ERROR ("could not create connection from socket %p: %s", socket, str);
2271     g_free (str);
2272     return FALSE;
2273   }
2274 }
2275
2276 /**
2277  * gst_rtsp_client_accept:
2278  * @client: a #GstRTSPClient
2279  * @socket: a #GSocket
2280  * @context: the context to run in
2281  * @cancellable: a #GCancellable
2282  * @error: a #GError
2283  *
2284  * Accept a new connection for @client on @socket.
2285  *
2286  * Returns: %TRUE if the client could be accepted.
2287  */
2288 gboolean
2289 gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket,
2290     GCancellable * cancellable, GError ** error)
2291 {
2292   GstRTSPConnection *conn;
2293   GstRTSPResult res;
2294
2295   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
2296   g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
2297
2298   /* a new client connected. */
2299   GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable),
2300       accept_failed);
2301
2302   return setup_client (client, socket, conn, error);
2303
2304   /* ERRORS */
2305 accept_failed:
2306   {
2307     gchar *str = gst_rtsp_strresult (res);
2308
2309     GST_ERROR ("Could not accept client on server socket %p: %s", socket, str);
2310     g_free (str);
2311     return FALSE;
2312   }
2313 }
2314
2315 /**
2316  * gst_rtsp_client_attach:
2317  * @client: a #GstRTSPClient
2318  * @context: (allow-none): a #GMainContext
2319  *
2320  * Attaches @client to @context. When the mainloop for @context is run, the
2321  * client will be dispatched. When @context is NULL, the default context will be
2322  * used).
2323  *
2324  * This function should be called when the client properties and urls are fully
2325  * configured and the client is ready to start.
2326  *
2327  * Returns: the ID (greater than 0) for the source within the GMainContext.
2328  */
2329 guint
2330 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
2331 {
2332   guint res;
2333
2334   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
2335   g_return_val_if_fail (client->watch == NULL, 0);
2336
2337   /* create watch for the connection and attach */
2338   client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
2339       g_object_ref (client), (GDestroyNotify) client_watch_notify);
2340   gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL);
2341
2342   GST_INFO ("attaching to context %p", context);
2343   res = gst_rtsp_watch_attach (client->watch, context);
2344   gst_rtsp_watch_unref (client->watch);
2345
2346   return res;
2347 }