Start support for RTSP 2.0
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-client.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  * Copyright (C) 2015 Centricular Ltd
4  *     Author: Sebastian Dröge <sebastian@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 /**
22  * SECTION:rtsp-client
23  * @short_description: A client connection state
24  * @see_also: #GstRTSPServer, #GstRTSPThreadPool
25  *
26  * The client object handles the connection with a client for as long as a TCP
27  * connection is open.
28  *
29  * A #GstRTSPClient is created by #GstRTSPServer when a new connection is
30  * accepted and it inherits the #GstRTSPMountPoints, #GstRTSPSessionPool,
31  * #GstRTSPAuth and #GstRTSPThreadPool from the server.
32  *
33  * The client connection should be configured with the #GstRTSPConnection using
34  * gst_rtsp_client_set_connection() before it can be attached to a #GMainContext
35  * using gst_rtsp_client_attach(). From then on the client will handle requests
36  * on the connection.
37  *
38  * Use gst_rtsp_client_session_filter() to iterate or modify all the
39  * #GstRTSPSession objects managed by the client object.
40  *
41  * Last reviewed on 2013-07-11 (1.0.0)
42  */
43
44 #include <stdio.h>
45 #include <string.h>
46
47 #include <gst/sdp/gstmikey.h>
48 #include <gst/rtsp/gstrtsp-enumtypes.h>
49
50 #include "rtsp-client.h"
51 #include "rtsp-sdp.h"
52 #include "rtsp-params.h"
53
54 #define GST_RTSP_CLIENT_GET_PRIVATE(obj)  \
55    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate))
56
57 /* locking order:
58  * send_lock, lock, tunnels_lock
59  */
60
61 struct _GstRTSPClientPrivate
62 {
63   GMutex lock;                  /* protects everything else */
64   GMutex send_lock;
65   GMutex watch_lock;
66   GstRTSPConnection *connection;
67   GstRTSPWatch *watch;
68   GMainContext *watch_context;
69   guint close_seq;
70   gchar *server_ip;
71   gboolean is_ipv6;
72
73   GstRTSPClientSendFunc send_func;      /* protected by send_lock */
74   gpointer send_data;           /* protected by send_lock */
75   GDestroyNotify send_notify;   /* protected by send_lock */
76
77   GstRTSPSessionPool *session_pool;
78   gulong session_removed_id;
79   GstRTSPMountPoints *mount_points;
80   GstRTSPAuth *auth;
81   GstRTSPThreadPool *thread_pool;
82
83   /* used to cache the media in the last requested DESCRIBE so that
84    * we can pick it up in the next SETUP immediately */
85   gchar *path;
86   GstRTSPMedia *media;
87
88   GHashTable *transports;
89   GList *sessions;
90   guint sessions_cookie;
91
92   gboolean drop_backlog;
93
94   guint rtsp_ctrl_timeout_id;
95   guint rtsp_ctrl_timeout_cnt;
96
97   /* The version currently being used */
98   GstRTSPVersion version;
99
100   GHashTable *pipelined_requests;       /* pipelined_request_id -> session_id */
101 };
102
103 static GMutex tunnels_lock;
104 static GHashTable *tunnels;     /* protected by tunnels_lock */
105
106 /* FIXME make this configurable. We don't want to do this yet because it will
107  * be superceeded by a cache object later */
108 #define WATCH_BACKLOG_SIZE              100
109
110 #define DEFAULT_SESSION_POOL            NULL
111 #define DEFAULT_MOUNT_POINTS            NULL
112 #define DEFAULT_DROP_BACKLOG            TRUE
113
114 #define RTSP_CTRL_CB_INTERVAL           1
115 #define RTSP_CTRL_TIMEOUT_VALUE         60
116
117 enum
118 {
119   PROP_0,
120   PROP_SESSION_POOL,
121   PROP_MOUNT_POINTS,
122   PROP_DROP_BACKLOG,
123   PROP_LAST
124 };
125
126 enum
127 {
128   SIGNAL_CLOSED,
129   SIGNAL_NEW_SESSION,
130   SIGNAL_PRE_OPTIONS_REQUEST,
131   SIGNAL_OPTIONS_REQUEST,
132   SIGNAL_PRE_DESCRIBE_REQUEST,
133   SIGNAL_DESCRIBE_REQUEST,
134   SIGNAL_PRE_SETUP_REQUEST,
135   SIGNAL_SETUP_REQUEST,
136   SIGNAL_PRE_PLAY_REQUEST,
137   SIGNAL_PLAY_REQUEST,
138   SIGNAL_PRE_PAUSE_REQUEST,
139   SIGNAL_PAUSE_REQUEST,
140   SIGNAL_PRE_TEARDOWN_REQUEST,
141   SIGNAL_TEARDOWN_REQUEST,
142   SIGNAL_PRE_SET_PARAMETER_REQUEST,
143   SIGNAL_SET_PARAMETER_REQUEST,
144   SIGNAL_PRE_GET_PARAMETER_REQUEST,
145   SIGNAL_GET_PARAMETER_REQUEST,
146   SIGNAL_HANDLE_RESPONSE,
147   SIGNAL_SEND_MESSAGE,
148   SIGNAL_PRE_ANNOUNCE_REQUEST,
149   SIGNAL_ANNOUNCE_REQUEST,
150   SIGNAL_PRE_RECORD_REQUEST,
151   SIGNAL_RECORD_REQUEST,
152   SIGNAL_CHECK_REQUIREMENTS,
153   SIGNAL_LAST
154 };
155
156 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
157 #define GST_CAT_DEFAULT rtsp_client_debug
158
159 static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 };
160
161 static void gst_rtsp_client_get_property (GObject * object, guint propid,
162     GValue * value, GParamSpec * pspec);
163 static void gst_rtsp_client_set_property (GObject * object, guint propid,
164     const GValue * value, GParamSpec * pspec);
165 static void gst_rtsp_client_finalize (GObject * obj);
166
167 static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
168 static gboolean handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx,
169     GstRTSPMedia * media, GstSDPMessage * sdp);
170 static gboolean default_configure_client_media (GstRTSPClient * client,
171     GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx);
172 static gboolean default_configure_client_transport (GstRTSPClient * client,
173     GstRTSPContext * ctx, GstRTSPTransport * ct);
174 static GstRTSPResult default_params_set (GstRTSPClient * client,
175     GstRTSPContext * ctx);
176 static GstRTSPResult default_params_get (GstRTSPClient * client,
177     GstRTSPContext * ctx);
178 static gchar *default_make_path_from_uri (GstRTSPClient * client,
179     const GstRTSPUrl * uri);
180 static void client_session_removed (GstRTSPSessionPool * pool,
181     GstRTSPSession * session, GstRTSPClient * client);
182 static GstRTSPStatusCode default_pre_signal_handler (GstRTSPClient * client,
183     GstRTSPContext * ctx);
184 static gboolean pre_signal_accumulator (GSignalInvocationHint * ihint,
185     GValue * return_accu, const GValue * handler_return, gpointer data);
186
187 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
188
189 static void
190 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
191 {
192   GObjectClass *gobject_class;
193
194   g_type_class_add_private (klass, sizeof (GstRTSPClientPrivate));
195
196   gobject_class = G_OBJECT_CLASS (klass);
197
198   gobject_class->get_property = gst_rtsp_client_get_property;
199   gobject_class->set_property = gst_rtsp_client_set_property;
200   gobject_class->finalize = gst_rtsp_client_finalize;
201
202   klass->create_sdp = create_sdp;
203   klass->handle_sdp = handle_sdp;
204   klass->configure_client_media = default_configure_client_media;
205   klass->configure_client_transport = default_configure_client_transport;
206   klass->params_set = default_params_set;
207   klass->params_get = default_params_get;
208   klass->make_path_from_uri = default_make_path_from_uri;
209
210   klass->pre_options_request = default_pre_signal_handler;
211   klass->pre_describe_request = default_pre_signal_handler;
212   klass->pre_setup_request = default_pre_signal_handler;
213   klass->pre_play_request = default_pre_signal_handler;
214   klass->pre_pause_request = default_pre_signal_handler;
215   klass->pre_teardown_request = default_pre_signal_handler;
216   klass->pre_set_parameter_request = default_pre_signal_handler;
217   klass->pre_get_parameter_request = default_pre_signal_handler;
218   klass->pre_announce_request = default_pre_signal_handler;
219   klass->pre_record_request = default_pre_signal_handler;
220
221   g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
222       g_param_spec_object ("session-pool", "Session Pool",
223           "The session pool to use for client session",
224           GST_TYPE_RTSP_SESSION_POOL,
225           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
226
227   g_object_class_install_property (gobject_class, PROP_MOUNT_POINTS,
228       g_param_spec_object ("mount-points", "Mount Points",
229           "The mount points to use for client session",
230           GST_TYPE_RTSP_MOUNT_POINTS,
231           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
232
233   g_object_class_install_property (gobject_class, PROP_DROP_BACKLOG,
234       g_param_spec_boolean ("drop-backlog", "Drop Backlog",
235           "Drop data when the backlog queue is full",
236           DEFAULT_DROP_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
237
238   gst_rtsp_client_signals[SIGNAL_CLOSED] =
239       g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
240       G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL,
241       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
242
243   gst_rtsp_client_signals[SIGNAL_NEW_SESSION] =
244       g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
245       G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL,
246       g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION);
247
248   /**
249    * GstRTSPClient::pre-options-request:
250    * @client: a #GstRTSPClient
251    * @ctx: a #GstRTSPContext
252    *
253    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
254    *          otherwise an appropriate return code
255    *
256    * Since: 1.12
257    */
258   gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST] =
259       g_signal_new ("pre-options-request", G_TYPE_FROM_CLASS (klass),
260       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
261           pre_options_request), pre_signal_accumulator, NULL,
262       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
263       GST_TYPE_RTSP_CONTEXT);
264
265   gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] =
266       g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass),
267       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request),
268       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
269       GST_TYPE_RTSP_CONTEXT);
270
271   /**
272    * GstRTSPClient::pre-describe-request:
273    * @client: a #GstRTSPClient
274    * @ctx: a #GstRTSPContext
275    *
276    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
277    *          otherwise an appropriate return code
278    *
279    * Since: 1.12
280    */
281   gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST] =
282       g_signal_new ("pre-describe-request", G_TYPE_FROM_CLASS (klass),
283       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
284           pre_describe_request), pre_signal_accumulator, NULL,
285       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
286       GST_TYPE_RTSP_CONTEXT);
287
288   gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] =
289       g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass),
290       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request),
291       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
292       GST_TYPE_RTSP_CONTEXT);
293
294   /**
295    * GstRTSPClient::pre-setup-request:
296    * @client: a #GstRTSPClient
297    * @ctx: a #GstRTSPContext
298    *
299    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
300    *          otherwise an appropriate return code
301    *
302    * Since: 1.12
303    */
304   gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST] =
305       g_signal_new ("pre-setup-request", G_TYPE_FROM_CLASS (klass),
306       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
307           pre_setup_request), pre_signal_accumulator, NULL,
308       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
309       GST_TYPE_RTSP_CONTEXT);
310
311   gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] =
312       g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass),
313       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request),
314       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
315       GST_TYPE_RTSP_CONTEXT);
316
317   /**
318    * GstRTSPClient::pre-play-request:
319    * @client: a #GstRTSPClient
320    * @ctx: a #GstRTSPContext
321    *
322    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
323    *          otherwise an appropriate return code
324    *
325    * Since: 1.12
326    */
327   gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST] =
328       g_signal_new ("pre-play-request", G_TYPE_FROM_CLASS (klass),
329       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
330           pre_play_request), pre_signal_accumulator, NULL,
331       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
332       GST_TYPE_RTSP_CONTEXT);
333
334   gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] =
335       g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass),
336       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request),
337       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
338       GST_TYPE_RTSP_CONTEXT);
339
340   /**
341    * GstRTSPClient::pre-pause-request:
342    * @client: a #GstRTSPClient
343    * @ctx: a #GstRTSPContext
344    *
345    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
346    *          otherwise an appropriate return code
347    *
348    * Since: 1.12
349    */
350   gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST] =
351       g_signal_new ("pre-pause-request", G_TYPE_FROM_CLASS (klass),
352       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
353           pre_pause_request), pre_signal_accumulator, NULL,
354       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
355       GST_TYPE_RTSP_CONTEXT);
356
357   gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] =
358       g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass),
359       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request),
360       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
361       GST_TYPE_RTSP_CONTEXT);
362
363   /**
364    * GstRTSPClient::pre-teardown-request:
365    * @client: a #GstRTSPClient
366    * @ctx: a #GstRTSPContext
367    *
368    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
369    *          otherwise an appropriate return code
370    *
371    * Since: 1.12
372    */
373   gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST] =
374       g_signal_new ("pre-teardown-request", G_TYPE_FROM_CLASS (klass),
375       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
376           pre_teardown_request), pre_signal_accumulator, NULL,
377       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
378       GST_TYPE_RTSP_CONTEXT);
379
380   gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] =
381       g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass),
382       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request),
383       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
384       GST_TYPE_RTSP_CONTEXT);
385
386   /**
387    * GstRTSPClient::pre-set-parameter-request:
388    * @client: a #GstRTSPClient
389    * @ctx: a #GstRTSPContext
390    *
391    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
392    *          otherwise an appropriate return code
393    *
394    * Since: 1.12
395    */
396   gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST] =
397       g_signal_new ("pre-set-parameter-request", G_TYPE_FROM_CLASS (klass),
398       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
399           pre_set_parameter_request), pre_signal_accumulator, NULL,
400       g_cclosure_marshal_generic,
401       GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
402
403   gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] =
404       g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass),
405       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
406           set_parameter_request), NULL, NULL, g_cclosure_marshal_generic,
407       G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
408
409   /**
410    * GstRTSPClient::pre-get-parameter-request:
411    * @client: a #GstRTSPClient
412    * @ctx: a #GstRTSPContext
413    *
414    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
415    *          otherwise an appropriate return code
416    *
417    * Since: 1.12
418    */
419   gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST] =
420       g_signal_new ("pre-get-parameter-request", G_TYPE_FROM_CLASS (klass),
421       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
422           pre_get_parameter_request), pre_signal_accumulator, NULL,
423       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
424       GST_TYPE_RTSP_CONTEXT);
425
426   gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] =
427       g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass),
428       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
429           get_parameter_request), NULL, NULL, g_cclosure_marshal_generic,
430       G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
431
432   gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE] =
433       g_signal_new ("handle-response", G_TYPE_FROM_CLASS (klass),
434       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
435           handle_response), NULL, NULL, g_cclosure_marshal_generic,
436       G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
437
438   /**
439    * GstRTSPClient::send-message:
440    * @client: The RTSP client
441    * @session: (type GstRtspServer.RTSPSession): The session
442    * @message: (type GstRtsp.RTSPMessage): The message
443    */
444   gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] =
445       g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass),
446       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
447           send_message), NULL, NULL, g_cclosure_marshal_generic,
448       G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER);
449
450   /**
451    * GstRTSPClient::pre-announce-request:
452    * @client: a #GstRTSPClient
453    * @ctx: a #GstRTSPContext
454    *
455    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
456    *          otherwise an appropriate return code
457    *
458    * Since: 1.12
459    */
460   gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST] =
461       g_signal_new ("pre-announce-request", G_TYPE_FROM_CLASS (klass),
462       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
463           pre_announce_request), pre_signal_accumulator, NULL,
464       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
465       GST_TYPE_RTSP_CONTEXT);
466
467   gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] =
468       g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass),
469       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request),
470       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
471       GST_TYPE_RTSP_CONTEXT);
472
473   /**
474    * GstRTSPClient::pre-record-request:
475    * @client: a #GstRTSPClient
476    * @ctx: a #GstRTSPContext
477    *
478    * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
479    *          otherwise an appropriate return code
480    *
481    * Since: 1.12
482    */
483   gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST] =
484       g_signal_new ("pre-record-request", G_TYPE_FROM_CLASS (klass),
485       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
486           pre_record_request), pre_signal_accumulator, NULL,
487       g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1,
488       GST_TYPE_RTSP_CONTEXT);
489
490   gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] =
491       g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass),
492       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request),
493       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
494       GST_TYPE_RTSP_CONTEXT);
495
496   /**
497    * GstRTSPClient::check-requirements:
498    * @client: a #GstRTSPClient
499    * @ctx: a #GstRTSPContext
500    * @arr: a NULL-terminated array of strings
501    *
502    * Returns: a newly allocated string with comma-separated list of
503    *          unsupported options. An empty string must be returned if
504    *          all options are supported.
505    *
506    * Since: 1.6
507    */
508   gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS] =
509       g_signal_new ("check-requirements", G_TYPE_FROM_CLASS (klass),
510       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
511           check_requirements), NULL, NULL, g_cclosure_marshal_generic,
512       G_TYPE_STRING, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_STRV);
513
514   tunnels =
515       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
516   g_mutex_init (&tunnels_lock);
517
518   GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
519 }
520
521 static void
522 gst_rtsp_client_init (GstRTSPClient * client)
523 {
524   GstRTSPClientPrivate *priv = GST_RTSP_CLIENT_GET_PRIVATE (client);
525
526   client->priv = priv;
527
528   g_mutex_init (&priv->lock);
529   g_mutex_init (&priv->send_lock);
530   g_mutex_init (&priv->watch_lock);
531   priv->close_seq = 0;
532   priv->drop_backlog = DEFAULT_DROP_BACKLOG;
533   priv->transports =
534       g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
535       g_object_unref);
536   priv->pipelined_requests = g_hash_table_new_full (g_str_hash,
537       g_str_equal, g_free, g_free);
538 }
539
540 static GstRTSPFilterResult
541 filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
542     gpointer user_data)
543 {
544   gboolean *closed = user_data;
545   GstRTSPMedia *media;
546   guint i, n_streams;
547   gboolean is_all_udp = TRUE;
548
549   media = gst_rtsp_session_media_get_media (sessmedia);
550   n_streams = gst_rtsp_media_n_streams (media);
551
552   for (i = 0; i < n_streams; i++) {
553     GstRTSPStreamTransport *transport =
554         gst_rtsp_session_media_get_transport (sessmedia, i);
555     const GstRTSPTransport *rtsp_transport;
556
557     if (!transport)
558       continue;
559
560     rtsp_transport = gst_rtsp_stream_transport_get_transport (transport);
561     if (rtsp_transport
562         && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP
563         && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP_MCAST) {
564       is_all_udp = FALSE;
565       break;
566     }
567   }
568
569   if (!is_all_udp || gst_rtsp_media_is_stop_on_disconnect (media)) {
570     gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
571     return GST_RTSP_FILTER_REMOVE;
572   } else {
573     *closed = FALSE;
574     return GST_RTSP_FILTER_KEEP;
575   }
576 }
577
578 static void
579 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
580 {
581   GstRTSPClientPrivate *priv = client->priv;
582
583   g_mutex_lock (&priv->lock);
584   /* check if we already know about this session */
585   if (g_list_find (priv->sessions, session) == NULL) {
586     GST_INFO ("watching session %p", session);
587
588     priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session));
589     priv->sessions_cookie++;
590
591     /* connect removed session handler, it will be disconnected when the last
592      * session gets removed  */
593     if (priv->session_removed_id == 0)
594       priv->session_removed_id = g_signal_connect_data (priv->session_pool,
595           "session-removed", G_CALLBACK (client_session_removed),
596           g_object_ref (client), (GClosureNotify) g_object_unref, 0);
597   }
598   g_mutex_unlock (&priv->lock);
599
600   return;
601 }
602
603 /* should be called with lock */
604 static void
605 client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session,
606     GList * link)
607 {
608   GstRTSPClientPrivate *priv = client->priv;
609
610   GST_INFO ("client %p: unwatch session %p", client, session);
611
612   if (link == NULL) {
613     link = g_list_find (priv->sessions, session);
614     if (link == NULL)
615       return;
616   }
617
618   priv->sessions = g_list_delete_link (priv->sessions, link);
619   priv->sessions_cookie++;
620
621   /* if this was the last session, disconnect the handler.
622    * This will also drop the extra client ref */
623   if (!priv->sessions) {
624     g_signal_handler_disconnect (priv->session_pool, priv->session_removed_id);
625     priv->session_removed_id = 0;
626   }
627
628   if (!priv->drop_backlog) {
629     /* unlink all media managed in this session */
630     gst_rtsp_session_filter (session, filter_session_media, client);
631   }
632
633   /* remove the session */
634   g_object_unref (session);
635 }
636
637 static GstRTSPFilterResult
638 cleanup_session (GstRTSPClient * client, GstRTSPSession * sess,
639     gpointer user_data)
640 {
641   gboolean *closed = user_data;
642   GstRTSPClientPrivate *priv = client->priv;
643
644   if (priv->drop_backlog) {
645     /* unlink all media managed in this session. This needs to happen
646      * without the client lock, so we really want to do it here. */
647     gst_rtsp_session_filter (sess, filter_session_media, user_data);
648   }
649
650   if (*closed)
651     return GST_RTSP_FILTER_REMOVE;
652   else
653     return GST_RTSP_FILTER_KEEP;
654 }
655
656 static void
657 clean_cached_media (GstRTSPClient * client, gboolean unprepare)
658 {
659   GstRTSPClientPrivate *priv = client->priv;
660
661   if (priv->path) {
662     g_free (priv->path);
663     priv->path = NULL;
664   }
665   if (priv->media) {
666     if (unprepare)
667       gst_rtsp_media_unprepare (priv->media);
668     g_object_unref (priv->media);
669     priv->media = NULL;
670   }
671 }
672
673 /* A client is finalized when the connection is broken */
674 static void
675 gst_rtsp_client_finalize (GObject * obj)
676 {
677   GstRTSPClient *client = GST_RTSP_CLIENT (obj);
678   GstRTSPClientPrivate *priv = client->priv;
679
680   GST_INFO ("finalize client %p", client);
681
682   if (priv->watch)
683     gst_rtsp_watch_set_flushing (priv->watch, TRUE);
684   gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
685
686   if (priv->watch)
687     g_source_destroy ((GSource *) priv->watch);
688
689   if (priv->watch_context)
690     g_main_context_unref (priv->watch_context);
691
692   /* all sessions should have been removed by now. We keep a ref to
693    * the client object for the session removed handler. The ref is
694    * dropped when the last session is removed from the list. */
695   g_assert (priv->sessions == NULL);
696   g_assert (priv->session_removed_id == 0);
697
698   g_hash_table_unref (priv->transports);
699
700   if (priv->connection)
701     gst_rtsp_connection_free (priv->connection);
702   if (priv->session_pool) {
703     g_object_unref (priv->session_pool);
704   }
705   if (priv->mount_points)
706     g_object_unref (priv->mount_points);
707   if (priv->auth)
708     g_object_unref (priv->auth);
709   if (priv->thread_pool)
710     g_object_unref (priv->thread_pool);
711
712   clean_cached_media (client, TRUE);
713
714   g_free (priv->server_ip);
715   g_mutex_clear (&priv->lock);
716   g_mutex_clear (&priv->send_lock);
717   g_mutex_clear (&priv->watch_lock);
718
719   G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
720 }
721
722 static void
723 gst_rtsp_client_get_property (GObject * object, guint propid,
724     GValue * value, GParamSpec * pspec)
725 {
726   GstRTSPClient *client = GST_RTSP_CLIENT (object);
727   GstRTSPClientPrivate *priv = client->priv;
728
729   switch (propid) {
730     case PROP_SESSION_POOL:
731       g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
732       break;
733     case PROP_MOUNT_POINTS:
734       g_value_take_object (value, gst_rtsp_client_get_mount_points (client));
735       break;
736     case PROP_DROP_BACKLOG:
737       g_value_set_boolean (value, priv->drop_backlog);
738       break;
739     default:
740       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
741   }
742 }
743
744 static void
745 gst_rtsp_client_set_property (GObject * object, guint propid,
746     const GValue * value, GParamSpec * pspec)
747 {
748   GstRTSPClient *client = GST_RTSP_CLIENT (object);
749   GstRTSPClientPrivate *priv = client->priv;
750
751   switch (propid) {
752     case PROP_SESSION_POOL:
753       gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
754       break;
755     case PROP_MOUNT_POINTS:
756       gst_rtsp_client_set_mount_points (client, g_value_get_object (value));
757       break;
758     case PROP_DROP_BACKLOG:
759       g_mutex_lock (&priv->lock);
760       priv->drop_backlog = g_value_get_boolean (value);
761       g_mutex_unlock (&priv->lock);
762       break;
763     default:
764       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
765   }
766 }
767
768 /**
769  * gst_rtsp_client_new:
770  *
771  * Create a new #GstRTSPClient instance.
772  *
773  * Returns: (transfer full): a new #GstRTSPClient
774  */
775 GstRTSPClient *
776 gst_rtsp_client_new (void)
777 {
778   GstRTSPClient *result;
779
780   result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
781
782   return result;
783 }
784
785 static void
786 send_message (GstRTSPClient * client, GstRTSPContext * ctx,
787     GstRTSPMessage * message, gboolean close)
788 {
789   GstRTSPClientPrivate *priv = client->priv;
790
791   gst_rtsp_message_add_header (message, GST_RTSP_HDR_SERVER,
792       "GStreamer RTSP server");
793
794   /* remove any previous header */
795   gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
796
797   /* add the new session header for new session ids */
798   if (ctx->session) {
799     gst_rtsp_message_take_header (message, GST_RTSP_HDR_SESSION,
800         gst_rtsp_session_get_header (ctx->session));
801   }
802
803   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
804     gst_rtsp_message_dump (message);
805   }
806
807   if (close)
808     gst_rtsp_message_add_header (message, GST_RTSP_HDR_CONNECTION, "close");
809
810   if (ctx->request)
811     message->type_data.response.version =
812         ctx->request->type_data.request.version;
813
814   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE],
815       0, ctx, message);
816
817   g_mutex_lock (&priv->send_lock);
818   if (priv->send_func)
819     priv->send_func (client, message, close, priv->send_data);
820   g_mutex_unlock (&priv->send_lock);
821
822   gst_rtsp_message_unset (message);
823 }
824
825 static void
826 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
827     GstRTSPContext * ctx)
828 {
829   gst_rtsp_message_init_response (ctx->response, code,
830       gst_rtsp_status_as_text (code), ctx->request);
831
832   ctx->session = NULL;
833
834   send_message (client, ctx, ctx->response, FALSE);
835 }
836
837 static void
838 send_option_not_supported_response (GstRTSPClient * client,
839     GstRTSPContext * ctx, const gchar * unsupported_options)
840 {
841   GstRTSPStatusCode code = GST_RTSP_STS_OPTION_NOT_SUPPORTED;
842
843   gst_rtsp_message_init_response (ctx->response, code,
844       gst_rtsp_status_as_text (code), ctx->request);
845
846   if (unsupported_options != NULL) {
847     gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_UNSUPPORTED,
848         unsupported_options);
849   }
850
851   ctx->session = NULL;
852
853   send_message (client, ctx, ctx->response, FALSE);
854 }
855
856 static gboolean
857 paths_are_equal (const gchar * path1, const gchar * path2, gint len2)
858 {
859   if (path1 == NULL || path2 == NULL)
860     return FALSE;
861
862   if (strlen (path1) != len2)
863     return FALSE;
864
865   if (strncmp (path1, path2, len2))
866     return FALSE;
867
868   return TRUE;
869 }
870
871 /* this function is called to initially find the media for the DESCRIBE request
872  * but is cached for when the same client (without breaking the connection) is
873  * doing a setup for the exact same url. */
874 static GstRTSPMedia *
875 find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path,
876     gint * matched)
877 {
878   GstRTSPClientPrivate *priv = client->priv;
879   GstRTSPMediaFactory *factory;
880   GstRTSPMedia *media;
881   gint path_len;
882
883   /* find the longest matching factory for the uri first */
884   if (!(factory = gst_rtsp_mount_points_match (priv->mount_points,
885               path, matched)))
886     goto no_factory;
887
888   ctx->factory = factory;
889
890   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS))
891     goto no_factory_access;
892
893   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT))
894     goto not_authorized;
895
896   if (matched)
897     path_len = *matched;
898   else
899     path_len = strlen (path);
900
901   if (!paths_are_equal (priv->path, path, path_len)) {
902     /* remove any previously cached values before we try to construct a new
903      * media for uri */
904     clean_cached_media (client, TRUE);
905
906     /* prepare the media and add it to the pipeline */
907     if (!(media = gst_rtsp_media_factory_construct (factory, ctx->uri)))
908       goto no_media;
909
910     ctx->media = media;
911
912     if (!(gst_rtsp_media_get_transport_mode (media) &
913             GST_RTSP_TRANSPORT_MODE_RECORD)) {
914       GstRTSPThread *thread;
915
916       thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool,
917           GST_RTSP_THREAD_TYPE_MEDIA, ctx);
918       if (thread == NULL)
919         goto no_thread;
920
921       /* prepare the media */
922       if (!gst_rtsp_media_prepare (media, thread))
923         goto no_prepare;
924     }
925
926     /* now keep track of the uri and the media */
927     priv->path = g_strndup (path, path_len);
928     priv->media = media;
929   } else {
930     /* we have seen this path before, used cached media */
931     media = priv->media;
932     ctx->media = media;
933     GST_INFO ("reusing cached media %p for path %s", media, priv->path);
934   }
935
936   g_object_unref (factory);
937   ctx->factory = NULL;
938
939   if (media)
940     g_object_ref (media);
941
942   return media;
943
944   /* ERRORS */
945 no_factory:
946   {
947     GST_ERROR ("client %p: no factory for path %s", client, path);
948     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
949     return NULL;
950   }
951 no_factory_access:
952   {
953     g_object_unref (factory);
954     ctx->factory = NULL;
955     GST_ERROR ("client %p: not authorized to see factory path %s", client,
956         path);
957     /* error reply is already sent */
958     return NULL;
959   }
960 not_authorized:
961   {
962     g_object_unref (factory);
963     ctx->factory = NULL;
964     GST_ERROR ("client %p: not authorized for factory path %s", client, path);
965     /* error reply is already sent */
966     return NULL;
967   }
968 no_media:
969   {
970     GST_ERROR ("client %p: can't create media", client);
971     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
972     g_object_unref (factory);
973     ctx->factory = NULL;
974     return NULL;
975   }
976 no_thread:
977   {
978     GST_ERROR ("client %p: can't create thread", client);
979     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
980     g_object_unref (media);
981     ctx->media = NULL;
982     g_object_unref (factory);
983     ctx->factory = NULL;
984     return NULL;
985   }
986 no_prepare:
987   {
988     GST_ERROR ("client %p: can't prepare media", client);
989     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
990     g_object_unref (media);
991     ctx->media = NULL;
992     g_object_unref (factory);
993     ctx->factory = NULL;
994     return NULL;
995   }
996 }
997
998 static gboolean
999 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
1000 {
1001   GstRTSPClientPrivate *priv = client->priv;
1002   GstRTSPMessage message = { 0 };
1003   GstRTSPResult res = GST_RTSP_OK;
1004   GstMapInfo map_info;
1005   guint8 *data;
1006   guint usize;
1007
1008   gst_rtsp_message_init_data (&message, channel);
1009
1010   /* FIXME, need some sort of iovec RTSPMessage here */
1011   if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ))
1012     return FALSE;
1013
1014   gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
1015
1016   g_mutex_lock (&priv->send_lock);
1017   if (priv->send_func)
1018     res = priv->send_func (client, &message, FALSE, priv->send_data);
1019   g_mutex_unlock (&priv->send_lock);
1020
1021   gst_rtsp_message_steal_body (&message, &data, &usize);
1022   gst_buffer_unmap (buffer, &map_info);
1023
1024   gst_rtsp_message_unset (&message);
1025
1026   return res == GST_RTSP_OK;
1027 }
1028
1029 /**
1030  * gst_rtsp_client_close:
1031  * @client: a #GstRTSPClient
1032  *
1033  * Close the connection of @client and remove all media it was managing.
1034  *
1035  * Since: 1.4
1036  */
1037 void
1038 gst_rtsp_client_close (GstRTSPClient * client)
1039 {
1040   GstRTSPClientPrivate *priv = client->priv;
1041   const gchar *tunnelid;
1042
1043   GST_DEBUG ("client %p: closing connection", client);
1044
1045   if (priv->connection) {
1046     if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
1047       g_mutex_lock (&tunnels_lock);
1048       /* remove from tunnelids */
1049       g_hash_table_remove (tunnels, tunnelid);
1050       g_mutex_unlock (&tunnels_lock);
1051     }
1052     gst_rtsp_connection_close (priv->connection);
1053   }
1054
1055   /* connection is now closed, destroy the watch which will also cause the
1056    * closed signal to be emitted */
1057   if (priv->watch) {
1058     GST_DEBUG ("client %p: destroying watch", client);
1059     g_source_destroy ((GSource *) priv->watch);
1060     priv->watch = NULL;
1061     gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
1062     g_main_context_unref (priv->watch_context);
1063     priv->watch_context = NULL;
1064   }
1065 }
1066
1067 static gchar *
1068 default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
1069 {
1070   gchar *path;
1071
1072   if (uri->query)
1073     path = g_strconcat (uri->abspath, "?", uri->query, NULL);
1074   else
1075     path = g_strdup (uri->abspath);
1076
1077   return path;
1078 }
1079
1080 /* Default signal handler function for all "pre-command" signals, like
1081  * pre-options-request. It just returns the RTSP return code 200.
1082  * Subclasses can override this to get another default behaviour.
1083  */
1084 static GstRTSPStatusCode
1085 default_pre_signal_handler (GstRTSPClient * client, GstRTSPContext * ctx)
1086 {
1087   GST_LOG_OBJECT (client, "returning GST_RTSP_STS_OK");
1088   return GST_RTSP_STS_OK;
1089 }
1090
1091 /* The pre-signal accumulator function checks the return value of the signal
1092  * handlers. If any of them returns an RTSP status code that does not start
1093  * with 2 it will return FALSE, no more signal handlers will be called, and
1094  * this last RTSP status code will be the result of the signal emission.
1095  */
1096 static gboolean
1097 pre_signal_accumulator (GSignalInvocationHint * ihint, GValue * return_accu,
1098     const GValue * handler_return, gpointer data)
1099 {
1100   GstRTSPStatusCode handler_value = g_value_get_enum (handler_return);
1101   GstRTSPStatusCode accumulated_value = g_value_get_enum (return_accu);
1102
1103   if (handler_value < 200 || handler_value > 299) {
1104     GST_DEBUG ("handler_value : %d, returning FALSE", handler_value);
1105     g_value_set_enum (return_accu, handler_value);
1106     return FALSE;
1107   }
1108
1109   /* the accumulated value is initiated to 0 by GLib. if current handler value is
1110    * bigger then use that instead
1111    *
1112    * FIXME: Should we prioritize the 2xx codes in a smarter way?
1113    *        Like, "201 Created" > "250 Low On Storage Space" > "200 OK"?
1114    */
1115   if (handler_value > accumulated_value)
1116     g_value_set_enum (return_accu, handler_value);
1117
1118   return TRUE;
1119 }
1120
1121 static gboolean
1122 handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
1123 {
1124   GstRTSPClientPrivate *priv = client->priv;
1125   GstRTSPClientClass *klass;
1126   GstRTSPSession *session;
1127   GstRTSPSessionMedia *sessmedia;
1128   GstRTSPStatusCode code;
1129   gchar *path;
1130   gint matched;
1131   gboolean keep_session;
1132   GstRTSPStatusCode sig_result;
1133
1134   if (!ctx->session)
1135     goto no_session;
1136
1137   session = ctx->session;
1138
1139   if (!ctx->uri)
1140     goto no_uri;
1141
1142   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1143   path = klass->make_path_from_uri (client, ctx->uri);
1144
1145   /* get a handle to the configuration of the media in the session */
1146   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1147   if (!sessmedia)
1148     goto not_found;
1149
1150   /* only aggregate control for now.. */
1151   if (path[matched] != '\0')
1152     goto no_aggregate;
1153
1154   g_free (path);
1155
1156   ctx->sessmedia = sessmedia;
1157
1158   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST],
1159       0, ctx, &sig_result);
1160   if (sig_result != GST_RTSP_STS_OK) {
1161     goto sig_failed;
1162   }
1163
1164   /* we emit the signal before closing the connection */
1165   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
1166       0, ctx);
1167
1168   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
1169
1170   /* unmanage the media in the session, returns false if all media session
1171    * are torn down. */
1172   keep_session = gst_rtsp_session_release_media (session, sessmedia);
1173
1174   /* construct the response now */
1175   code = GST_RTSP_STS_OK;
1176   gst_rtsp_message_init_response (ctx->response, code,
1177       gst_rtsp_status_as_text (code), ctx->request);
1178
1179   send_message (client, ctx, ctx->response, TRUE);
1180
1181   if (!keep_session) {
1182     /* remove the session */
1183     gst_rtsp_session_pool_remove (priv->session_pool, session);
1184   }
1185
1186   return TRUE;
1187
1188   /* ERRORS */
1189 no_session:
1190   {
1191     GST_ERROR ("client %p: no session", client);
1192     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1193     return FALSE;
1194   }
1195 no_uri:
1196   {
1197     GST_ERROR ("client %p: no uri supplied", client);
1198     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1199     return FALSE;
1200   }
1201 not_found:
1202   {
1203     GST_ERROR ("client %p: no media for uri", client);
1204     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1205     g_free (path);
1206     return FALSE;
1207   }
1208 no_aggregate:
1209   {
1210     GST_ERROR ("client %p: no aggregate path %s", client, path);
1211     send_generic_response (client,
1212         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1213     g_free (path);
1214     return FALSE;
1215   }
1216 sig_failed:
1217   {
1218     GST_ERROR ("client %p: pre signal returned error: %s", client,
1219         gst_rtsp_status_as_text (sig_result));
1220     send_generic_response (client, sig_result, ctx);
1221     return FALSE;
1222   }
1223 }
1224
1225 static GstRTSPResult
1226 default_params_set (GstRTSPClient * client, GstRTSPContext * ctx)
1227 {
1228   GstRTSPResult res;
1229
1230   res = gst_rtsp_params_set (client, ctx);
1231
1232   return res;
1233 }
1234
1235 static GstRTSPResult
1236 default_params_get (GstRTSPClient * client, GstRTSPContext * ctx)
1237 {
1238   GstRTSPResult res;
1239
1240   res = gst_rtsp_params_get (client, ctx);
1241
1242   return res;
1243 }
1244
1245 static gboolean
1246 handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
1247 {
1248   GstRTSPResult res;
1249   guint8 *data;
1250   guint size;
1251   GstRTSPStatusCode sig_result;
1252
1253   g_signal_emit (client,
1254       gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST], 0, ctx,
1255       &sig_result);
1256   if (sig_result != GST_RTSP_STS_OK) {
1257     goto sig_failed;
1258   }
1259
1260   res = gst_rtsp_message_get_body (ctx->request, &data, &size);
1261   if (res != GST_RTSP_OK)
1262     goto bad_request;
1263
1264   if (size == 0 || !data || strlen ((char *) data) == 0) {
1265     if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) {
1266       GST_ERROR_OBJECT (client, "Using PLAY request for keep-alive is forbidden"
1267           " in RTSP 2.0");
1268       goto bad_request;
1269     }
1270
1271     /* no body (or only '\0'), keep-alive request */
1272     send_generic_response (client, GST_RTSP_STS_OK, ctx);
1273   } else {
1274     /* there is a body, handle the params */
1275     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, ctx);
1276     if (res != GST_RTSP_OK)
1277       goto bad_request;
1278
1279     send_message (client, ctx, ctx->response, FALSE);
1280   }
1281
1282   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
1283       0, ctx);
1284
1285   return TRUE;
1286
1287   /* ERRORS */
1288 sig_failed:
1289   {
1290     GST_ERROR ("client %p: pre signal returned error: %s", client,
1291         gst_rtsp_status_as_text (sig_result));
1292     send_generic_response (client, sig_result, ctx);
1293     return FALSE;
1294   }
1295 bad_request:
1296   {
1297     GST_ERROR ("client %p: bad request", client);
1298     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1299     return FALSE;
1300   }
1301 }
1302
1303 static gboolean
1304 handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
1305 {
1306   GstRTSPResult res;
1307   guint8 *data;
1308   guint size;
1309   GstRTSPStatusCode sig_result;
1310
1311   g_signal_emit (client,
1312       gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST], 0, ctx,
1313       &sig_result);
1314   if (sig_result != GST_RTSP_STS_OK) {
1315     goto sig_failed;
1316   }
1317
1318   res = gst_rtsp_message_get_body (ctx->request, &data, &size);
1319   if (res != GST_RTSP_OK)
1320     goto bad_request;
1321
1322   if (size == 0 || !data || strlen ((char *) data) == 0) {
1323     /* no body (or only '\0'), keep-alive request */
1324     send_generic_response (client, GST_RTSP_STS_OK, ctx);
1325   } else {
1326     /* there is a body, handle the params */
1327     res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, ctx);
1328     if (res != GST_RTSP_OK)
1329       goto bad_request;
1330
1331     send_message (client, ctx, ctx->response, FALSE);
1332   }
1333
1334   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
1335       0, ctx);
1336
1337   return TRUE;
1338
1339   /* ERRORS */
1340 sig_failed:
1341   {
1342     GST_ERROR ("client %p: pre signal returned error: %s", client,
1343         gst_rtsp_status_as_text (sig_result));
1344     send_generic_response (client, sig_result, ctx);
1345     return FALSE;
1346   }
1347 bad_request:
1348   {
1349     GST_ERROR ("client %p: bad request", client);
1350     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1351     return FALSE;
1352   }
1353 }
1354
1355 static gboolean
1356 handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
1357 {
1358   GstRTSPSession *session;
1359   GstRTSPClientClass *klass;
1360   GstRTSPSessionMedia *sessmedia;
1361   GstRTSPMedia *media;
1362   GstRTSPStatusCode code;
1363   GstRTSPState rtspstate;
1364   gchar *path;
1365   gint matched;
1366   GstRTSPStatusCode sig_result;
1367   guint i, n;
1368
1369   if (!(session = ctx->session))
1370     goto no_session;
1371
1372   if (!ctx->uri)
1373     goto no_uri;
1374
1375   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1376   path = klass->make_path_from_uri (client, ctx->uri);
1377
1378   /* get a handle to the configuration of the media in the session */
1379   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1380   if (!sessmedia)
1381     goto not_found;
1382
1383   if (path[matched] != '\0')
1384     goto no_aggregate;
1385
1386   g_free (path);
1387
1388   media = gst_rtsp_session_media_get_media (sessmedia);
1389   n = gst_rtsp_media_n_streams (media);
1390   for (i = 0; i < n; i++) {
1391     GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i);
1392
1393     if (gst_rtsp_stream_get_publish_clock_mode (stream) ==
1394         GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET)
1395       goto not_supported;
1396   }
1397
1398   ctx->sessmedia = sessmedia;
1399
1400   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST], 0,
1401       ctx, &sig_result);
1402   if (sig_result != GST_RTSP_STS_OK) {
1403     goto sig_failed;
1404   }
1405
1406   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1407   /* the session state must be playing or recording */
1408   if (rtspstate != GST_RTSP_STATE_PLAYING &&
1409       rtspstate != GST_RTSP_STATE_RECORDING)
1410     goto invalid_state;
1411
1412   /* then pause sending */
1413   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED);
1414
1415   /* construct the response now */
1416   code = GST_RTSP_STS_OK;
1417   gst_rtsp_message_init_response (ctx->response, code,
1418       gst_rtsp_status_as_text (code), ctx->request);
1419
1420   send_message (client, ctx, ctx->response, FALSE);
1421
1422   /* the state is now READY */
1423   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1424
1425   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx);
1426
1427   return TRUE;
1428
1429   /* ERRORS */
1430 no_session:
1431   {
1432     GST_ERROR ("client %p: no session", client);
1433     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1434     return FALSE;
1435   }
1436 no_uri:
1437   {
1438     GST_ERROR ("client %p: no uri supplied", client);
1439     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1440     return FALSE;
1441   }
1442 not_found:
1443   {
1444     GST_ERROR ("client %p: no media for uri", client);
1445     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1446     g_free (path);
1447     return FALSE;
1448   }
1449 no_aggregate:
1450   {
1451     GST_ERROR ("client %p: no aggregate path %s", client, path);
1452     send_generic_response (client,
1453         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1454     g_free (path);
1455     return FALSE;
1456   }
1457 sig_failed:
1458   {
1459     GST_ERROR ("client %p: pre signal returned error: %s", client,
1460         gst_rtsp_status_as_text (sig_result));
1461     send_generic_response (client, sig_result, ctx);
1462     return FALSE;
1463   }
1464 invalid_state:
1465   {
1466     GST_ERROR ("client %p: not PLAYING or RECORDING", client);
1467     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1468         ctx);
1469     return FALSE;
1470   }
1471 not_supported:
1472   {
1473     GST_ERROR ("client %p: pausing not supported", client);
1474     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1475     return FALSE;
1476   }
1477 }
1478
1479 /* convert @url and @path to a URL used as a content base for the factory
1480  * located at @path */
1481 static gchar *
1482 make_base_url (GstRTSPClient * client, GstRTSPUrl * url, const gchar * path)
1483 {
1484   GstRTSPUrl tmp;
1485   gchar *result;
1486   const gchar *trail;
1487
1488   /* check for trailing '/' and append one */
1489   trail = (path[strlen (path) - 1] != '/' ? "/" : "");
1490
1491   tmp = *url;
1492   tmp.user = NULL;
1493   tmp.passwd = NULL;
1494   tmp.abspath = g_strdup_printf ("%s%s", path, trail);
1495   tmp.query = NULL;
1496   result = gst_rtsp_url_get_request_uri (&tmp);
1497   g_free (tmp.abspath);
1498
1499   return result;
1500 }
1501
1502 static gboolean
1503 handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
1504 {
1505   GstRTSPSession *session;
1506   GstRTSPClientClass *klass;
1507   GstRTSPSessionMedia *sessmedia;
1508   GstRTSPMedia *media;
1509   GstRTSPStatusCode code;
1510   GstRTSPUrl *uri;
1511   gchar *str;
1512   GstRTSPTimeRange *range;
1513   GstRTSPResult res;
1514   GstRTSPState rtspstate;
1515   GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
1516   gchar *path, *rtpinfo;
1517   gint matched;
1518   gchar *seek_style = NULL;
1519   GstRTSPStatusCode sig_result;
1520
1521   if (!(session = ctx->session))
1522     goto no_session;
1523
1524   if (!(uri = ctx->uri))
1525     goto no_uri;
1526
1527   klass = GST_RTSP_CLIENT_GET_CLASS (client);
1528   path = klass->make_path_from_uri (client, uri);
1529
1530   /* get a handle to the configuration of the media in the session */
1531   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
1532   if (!sessmedia)
1533     goto not_found;
1534
1535   if (path[matched] != '\0')
1536     goto no_aggregate;
1537
1538   g_free (path);
1539
1540   ctx->sessmedia = sessmedia;
1541   ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
1542
1543   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST], 0,
1544       ctx, &sig_result);
1545   if (sig_result != GST_RTSP_STS_OK) {
1546     goto sig_failed;
1547   }
1548
1549   if (!(gst_rtsp_media_get_transport_mode (media) &
1550           GST_RTSP_TRANSPORT_MODE_PLAY))
1551     goto unsupported_mode;
1552
1553   /* the session state must be playing or ready */
1554   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1555   if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
1556     goto invalid_state;
1557
1558   /* in play we first unsuspend, media could be suspended from SDP or PAUSED */
1559   if (!gst_rtsp_media_unsuspend (media))
1560     goto unsuspend_failed;
1561
1562   /* parse the range header if we have one */
1563   res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0);
1564   if (res == GST_RTSP_OK) {
1565     if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
1566       GstRTSPMediaStatus media_status;
1567       GstSeekFlags flags = 0;
1568
1569       if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_SEEK_STYLE,
1570               &seek_style, 0)) {
1571         if (g_strcmp0 (seek_style, "RAP") == 0)
1572           flags = GST_SEEK_FLAG_ACCURATE;
1573         else if (g_strcmp0 (seek_style, "CoRAP") == 0)
1574           flags = GST_SEEK_FLAG_KEY_UNIT;
1575         else if (g_strcmp0 (seek_style, "First-Prior") == 0)
1576           flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_BEFORE;
1577         else if (g_strcmp0 (seek_style, "Next") == 0)
1578           flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_AFTER;
1579         else
1580           GST_FIXME_OBJECT (client, "Add support for seek style %s",
1581               seek_style);
1582       }
1583
1584       /* we have a range, seek to the position */
1585       unit = range->unit;
1586       gst_rtsp_media_seek_full (media, range, flags);
1587       gst_rtsp_range_free (range);
1588
1589       media_status = gst_rtsp_media_get_status (media);
1590       if (media_status == GST_RTSP_MEDIA_STATUS_ERROR)
1591         goto seek_failed;
1592     }
1593   }
1594
1595   /* grab RTPInfo from the media now */
1596   rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia);
1597
1598   /* construct the response now */
1599   code = GST_RTSP_STS_OK;
1600   gst_rtsp_message_init_response (ctx->response, code,
1601       gst_rtsp_status_as_text (code), ctx->request);
1602
1603   /* add the RTP-Info header */
1604   if (rtpinfo)
1605     gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO,
1606         rtpinfo);
1607   if (seek_style)
1608     gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE,
1609         seek_style);
1610
1611   /* add the range */
1612   str = gst_rtsp_media_get_range_string (media, TRUE, unit);
1613   if (str)
1614     gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str);
1615
1616   send_message (client, ctx, ctx->response, FALSE);
1617
1618   /* start playing after sending the response */
1619   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
1620
1621   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
1622
1623   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx);
1624
1625   return TRUE;
1626
1627   /* ERRORS */
1628 no_session:
1629   {
1630     GST_ERROR ("client %p: no session", client);
1631     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1632     return FALSE;
1633   }
1634 no_uri:
1635   {
1636     GST_ERROR ("client %p: no uri supplied", client);
1637     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1638     return FALSE;
1639   }
1640 not_found:
1641   {
1642     GST_ERROR ("client %p: media not found", client);
1643     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1644     return FALSE;
1645   }
1646 no_aggregate:
1647   {
1648     GST_ERROR ("client %p: no aggregate path %s", client, path);
1649     send_generic_response (client,
1650         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1651     g_free (path);
1652     return FALSE;
1653   }
1654 sig_failed:
1655   {
1656     GST_ERROR ("client %p: pre signal returned error: %s", client,
1657         gst_rtsp_status_as_text (sig_result));
1658     send_generic_response (client, sig_result, ctx);
1659     return FALSE;
1660   }
1661 invalid_state:
1662   {
1663     GST_ERROR ("client %p: not PLAYING or READY", client);
1664     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1665         ctx);
1666     return FALSE;
1667   }
1668 unsuspend_failed:
1669   {
1670     GST_ERROR ("client %p: unsuspend failed", client);
1671     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1672     return FALSE;
1673   }
1674 seek_failed:
1675   {
1676     GST_ERROR ("client %p: seek failed", client);
1677     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1678     return FALSE;
1679   }
1680 unsupported_mode:
1681   {
1682     GST_ERROR ("client %p: media does not support PLAY", client);
1683     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
1684     return FALSE;
1685   }
1686 }
1687
1688 static void
1689 do_keepalive (GstRTSPSession * session)
1690 {
1691   GST_INFO ("keep session %p alive", session);
1692   gst_rtsp_session_touch (session);
1693 }
1694
1695 /* parse @transport and return a valid transport in @tr. only transports
1696  * supported by @stream are returned. Returns FALSE if no valid transport
1697  * was found. */
1698 static gboolean
1699 parse_transport (const char *transport, GstRTSPStream * stream,
1700     GstRTSPTransport * tr)
1701 {
1702   gint i;
1703   gboolean res;
1704   gchar **transports;
1705
1706   res = FALSE;
1707   gst_rtsp_transport_init (tr);
1708
1709   GST_DEBUG ("parsing transports %s", transport);
1710
1711   transports = g_strsplit (transport, ",", 0);
1712
1713   /* loop through the transports, try to parse */
1714   for (i = 0; transports[i]; i++) {
1715     res = gst_rtsp_transport_parse (transports[i], tr);
1716     if (res != GST_RTSP_OK) {
1717       /* no valid transport, search some more */
1718       GST_WARNING ("could not parse transport %s", transports[i]);
1719       goto next;
1720     }
1721
1722     /* we have a transport, see if it's supported */
1723     if (!gst_rtsp_stream_is_transport_supported (stream, tr)) {
1724       GST_WARNING ("unsupported transport %s", transports[i]);
1725       goto next;
1726     }
1727
1728     /* we have a valid transport */
1729     GST_INFO ("found valid transport %s", transports[i]);
1730     res = TRUE;
1731     break;
1732
1733   next:
1734     gst_rtsp_transport_init (tr);
1735   }
1736   g_strfreev (transports);
1737
1738   return res;
1739 }
1740
1741 static gboolean
1742 default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
1743     GstRTSPStream * stream, GstRTSPContext * ctx)
1744 {
1745   GstRTSPMessage *request = ctx->request;
1746   gchar *blocksize_str;
1747
1748   if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
1749           &blocksize_str, 0) == GST_RTSP_OK) {
1750     guint64 blocksize;
1751     gchar *end;
1752
1753     blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
1754     if (end == blocksize_str)
1755       goto parse_failed;
1756
1757     /* we don't want to change the mtu when this media
1758      * can be shared because it impacts other clients */
1759     if (gst_rtsp_media_is_shared (media))
1760       goto done;
1761
1762     if (blocksize > G_MAXUINT)
1763       blocksize = G_MAXUINT;
1764
1765     gst_rtsp_stream_set_mtu (stream, blocksize);
1766   }
1767 done:
1768   return TRUE;
1769
1770   /* ERRORS */
1771 parse_failed:
1772   {
1773     GST_ERROR_OBJECT (client, "failed to parse blocksize");
1774     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1775     return FALSE;
1776   }
1777 }
1778
1779 static gboolean
1780 default_configure_client_transport (GstRTSPClient * client,
1781     GstRTSPContext * ctx, GstRTSPTransport * ct)
1782 {
1783   GstRTSPClientPrivate *priv = client->priv;
1784
1785   /* we have a valid transport now, set the destination of the client. */
1786   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1787     gboolean use_client_settings;
1788
1789     use_client_settings =
1790         gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS);
1791
1792     if (ct->destination && use_client_settings) {
1793       GstRTSPAddress *addr;
1794
1795       addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination,
1796           ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
1797
1798       if (addr == NULL)
1799         goto no_address;
1800
1801       gst_rtsp_address_free (addr);
1802     } else {
1803       GstRTSPAddress *addr;
1804       GSocketFamily family;
1805
1806       family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4;
1807
1808       addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family);
1809       if (addr == NULL)
1810         goto no_address;
1811
1812       g_free (ct->destination);
1813       ct->destination = g_strdup (addr->address);
1814       ct->port.min = addr->port;
1815       ct->port.max = addr->port + addr->n_ports - 1;
1816       ct->ttl = addr->ttl;
1817
1818       gst_rtsp_address_free (addr);
1819     }
1820   } else {
1821     GstRTSPUrl *url;
1822
1823     url = gst_rtsp_connection_get_url (priv->connection);
1824     g_free (ct->destination);
1825     ct->destination = g_strdup (url->host);
1826
1827     if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1828       GSocket *sock;
1829       GSocketAddress *addr;
1830
1831       sock = gst_rtsp_connection_get_read_socket (priv->connection);
1832       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1833         /* our read port is the sender port of client */
1834         ct->client_port.min =
1835             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1836         g_object_unref (addr);
1837       }
1838       if ((addr = g_socket_get_local_address (sock, NULL))) {
1839         ct->server_port.max =
1840             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1841         g_object_unref (addr);
1842       }
1843       sock = gst_rtsp_connection_get_write_socket (priv->connection);
1844       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1845         /* our write port is the receiver port of client */
1846         ct->client_port.max =
1847             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1848         g_object_unref (addr);
1849       }
1850       if ((addr = g_socket_get_local_address (sock, NULL))) {
1851         ct->server_port.min =
1852             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1853         g_object_unref (addr);
1854       }
1855       /* check if the client selected channels for TCP */
1856       if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1857         gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
1858             &ct->interleaved);
1859       }
1860     }
1861   }
1862   return TRUE;
1863
1864   /* ERRORS */
1865 no_address:
1866   {
1867     GST_ERROR_OBJECT (client, "failed to acquire address for stream");
1868     return FALSE;
1869   }
1870 }
1871
1872 static GstRTSPTransport *
1873 make_server_transport (GstRTSPClient * client, GstRTSPMedia * media,
1874     GstRTSPContext * ctx, GstRTSPTransport * ct)
1875 {
1876   GstRTSPTransport *st;
1877   GInetAddress *addr;
1878   GSocketFamily family;
1879
1880   /* prepare the server transport */
1881   gst_rtsp_transport_new (&st);
1882
1883   st->trans = ct->trans;
1884   st->profile = ct->profile;
1885   st->lower_transport = ct->lower_transport;
1886   st->mode_play = ct->mode_play;
1887   st->mode_record = ct->mode_record;
1888
1889   addr = g_inet_address_new_from_string (ct->destination);
1890
1891   if (!addr) {
1892     GST_ERROR ("failed to get inet addr from client destination");
1893     family = G_SOCKET_FAMILY_IPV4;
1894   } else {
1895     family = g_inet_address_get_family (addr);
1896     g_object_unref (addr);
1897     addr = NULL;
1898   }
1899
1900   switch (st->lower_transport) {
1901     case GST_RTSP_LOWER_TRANS_UDP:
1902       st->client_port = ct->client_port;
1903       gst_rtsp_stream_get_server_port (ctx->stream, &st->server_port, family);
1904       break;
1905     case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1906       st->port = ct->port;
1907       st->destination = g_strdup (ct->destination);
1908       st->ttl = ct->ttl;
1909       break;
1910     case GST_RTSP_LOWER_TRANS_TCP:
1911       st->interleaved = ct->interleaved;
1912       st->client_port = ct->client_port;
1913       st->server_port = ct->server_port;
1914     default:
1915       break;
1916   }
1917
1918   if ((gst_rtsp_media_get_transport_mode (media) &
1919           GST_RTSP_TRANSPORT_MODE_PLAY))
1920     gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc);
1921
1922   return st;
1923 }
1924
1925 #define AES_128_KEY_LEN 16
1926 #define AES_256_KEY_LEN 32
1927
1928 #define HMAC_32_KEY_LEN 4
1929 #define HMAC_80_KEY_LEN 10
1930
1931 static gboolean
1932 mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy)
1933 {
1934   const gchar *srtp_cipher;
1935   const gchar *srtp_auth;
1936   const GstMIKEYPayload *sp;
1937   guint i;
1938
1939   /* loop over Security policy until we find one containing policy */
1940   for (i = 0;; i++) {
1941     if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL)
1942       break;
1943
1944     if (((GstMIKEYPayloadSP *) sp)->policy == policy)
1945       break;
1946   }
1947
1948   /* the default ciphers */
1949   srtp_cipher = "aes-128-icm";
1950   srtp_auth = "hmac-sha1-80";
1951
1952   /* now override the defaults with what is in the Security Policy */
1953   if (sp != NULL) {
1954     guint len;
1955
1956     /* collect all the params and go over them */
1957     len = gst_mikey_payload_sp_get_n_params (sp);
1958     for (i = 0; i < len; i++) {
1959       const GstMIKEYPayloadSPParam *param =
1960           gst_mikey_payload_sp_get_param (sp, i);
1961
1962       switch (param->type) {
1963         case GST_MIKEY_SP_SRTP_ENC_ALG:
1964           switch (param->val[0]) {
1965             case 0:
1966               srtp_cipher = "null";
1967               break;
1968             case 2:
1969             case 1:
1970               srtp_cipher = "aes-128-icm";
1971               break;
1972             default:
1973               break;
1974           }
1975           break;
1976         case GST_MIKEY_SP_SRTP_ENC_KEY_LEN:
1977           switch (param->val[0]) {
1978             case AES_128_KEY_LEN:
1979               srtp_cipher = "aes-128-icm";
1980               break;
1981             case AES_256_KEY_LEN:
1982               srtp_cipher = "aes-256-icm";
1983               break;
1984             default:
1985               break;
1986           }
1987           break;
1988         case GST_MIKEY_SP_SRTP_AUTH_ALG:
1989           switch (param->val[0]) {
1990             case 0:
1991               srtp_auth = "null";
1992               break;
1993             case 2:
1994             case 1:
1995               srtp_auth = "hmac-sha1-80";
1996               break;
1997             default:
1998               break;
1999           }
2000           break;
2001         case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN:
2002           switch (param->val[0]) {
2003             case HMAC_32_KEY_LEN:
2004               srtp_auth = "hmac-sha1-32";
2005               break;
2006             case HMAC_80_KEY_LEN:
2007               srtp_auth = "hmac-sha1-80";
2008               break;
2009             default:
2010               break;
2011           }
2012           break;
2013         case GST_MIKEY_SP_SRTP_SRTP_ENC:
2014           break;
2015         case GST_MIKEY_SP_SRTP_SRTCP_ENC:
2016           break;
2017         default:
2018           break;
2019       }
2020     }
2021   }
2022   /* now configure the SRTP parameters */
2023   gst_caps_set_simple (caps,
2024       "srtp-cipher", G_TYPE_STRING, srtp_cipher,
2025       "srtp-auth", G_TYPE_STRING, srtp_auth,
2026       "srtcp-cipher", G_TYPE_STRING, srtp_cipher,
2027       "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
2028
2029   return TRUE;
2030 }
2031
2032 static gboolean
2033 handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx,
2034     guint8 * data, gsize size)
2035 {
2036   GstMIKEYMessage *msg;
2037   guint i, n_cs;
2038   GstCaps *caps = NULL;
2039   GstMIKEYPayloadKEMAC *kemac;
2040   const GstMIKEYPayloadKeyData *pkd;
2041   GstBuffer *key;
2042
2043   /* the MIKEY message contains a CSB or crypto session bundle. It is a
2044    * set of Crypto Sessions protected with the same master key.
2045    * In the context of SRTP, an RTP and its RTCP stream is part of a
2046    * crypto session */
2047   if ((msg = gst_mikey_message_new_from_data (data, size, NULL, NULL)) == NULL)
2048     goto parse_failed;
2049
2050   /* we can only handle SRTP crypto sessions for now */
2051   if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP)
2052     goto invalid_map_type;
2053
2054   /* get the number of crypto sessions. This maps SSRC to its
2055    * security parameters */
2056   n_cs = gst_mikey_message_get_n_cs (msg);
2057   if (n_cs == 0)
2058     goto no_crypto_sessions;
2059
2060   /* we also need keys */
2061   if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload
2062           (msg, GST_MIKEY_PT_KEMAC, 0)))
2063     goto no_keys;
2064
2065   /* we don't support encrypted keys */
2066   if (kemac->enc_alg != GST_MIKEY_ENC_NULL
2067       || kemac->mac_alg != GST_MIKEY_MAC_NULL)
2068     goto unsupported_encryption;
2069
2070   /* get Key data sub-payload */
2071   pkd = (const GstMIKEYPayloadKeyData *)
2072       gst_mikey_payload_kemac_get_sub (&kemac->pt, 0);
2073
2074   key =
2075       gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
2076       pkd->key_len);
2077
2078   /* go over all crypto sessions and create the security policy for each
2079    * SSRC */
2080   for (i = 0; i < n_cs; i++) {
2081     const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i);
2082
2083     caps = gst_caps_new_simple ("application/x-srtp",
2084         "ssrc", G_TYPE_UINT, map->ssrc,
2085         "roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL);
2086     mikey_apply_policy (caps, msg, map->policy);
2087
2088     gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps);
2089     gst_caps_unref (caps);
2090   }
2091   gst_mikey_message_unref (msg);
2092   gst_buffer_unref (key);
2093
2094   return TRUE;
2095
2096   /* ERRORS */
2097 parse_failed:
2098   {
2099     GST_DEBUG_OBJECT (client, "failed to parse MIKEY message");
2100     return FALSE;
2101   }
2102 invalid_map_type:
2103   {
2104     GST_DEBUG_OBJECT (client, "invalid map type %d", msg->map_type);
2105     goto cleanup_message;
2106   }
2107 no_crypto_sessions:
2108   {
2109     GST_DEBUG_OBJECT (client, "no crypto sessions");
2110     goto cleanup_message;
2111   }
2112 no_keys:
2113   {
2114     GST_DEBUG_OBJECT (client, "no keys found");
2115     goto cleanup_message;
2116   }
2117 unsupported_encryption:
2118   {
2119     GST_DEBUG_OBJECT (client, "unsupported key encryption");
2120     goto cleanup_message;
2121   }
2122 cleanup_message:
2123   {
2124     gst_mikey_message_unref (msg);
2125     return FALSE;
2126   }
2127 }
2128
2129 #define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"'))
2130
2131 static void
2132 strip_chars (gchar * str)
2133 {
2134   gchar *s;
2135   gsize len;
2136
2137   len = strlen (str);
2138   while (len--) {
2139     if (!IS_STRIP_CHAR (str[len]))
2140       break;
2141     str[len] = '\0';
2142   }
2143   for (s = str; *s && IS_STRIP_CHAR (*s); s++);
2144   memmove (str, s, len + 1);
2145 }
2146
2147 /* KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec)
2148  * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"]
2149  */
2150 static gboolean
2151 handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt)
2152 {
2153   gchar **specs;
2154   gint i, j;
2155
2156   specs = g_strsplit (keymgmt, ",", 0);
2157   for (i = 0; specs[i]; i++) {
2158     gchar **split;
2159
2160     split = g_strsplit (specs[i], ";", 0);
2161     for (j = 0; split[j]; j++) {
2162       g_strstrip (split[j]);
2163       if (g_str_has_prefix (split[j], "prot=")) {
2164         g_strstrip (split[j] + 5);
2165         if (!g_str_equal (split[j] + 5, "mikey"))
2166           break;
2167         GST_DEBUG ("found mikey");
2168       } else if (g_str_has_prefix (split[j], "uri=")) {
2169         strip_chars (split[j] + 4);
2170         GST_DEBUG ("found uri '%s'", split[j] + 4);
2171       } else if (g_str_has_prefix (split[j], "data=")) {
2172         guchar *data;
2173         gsize size;
2174         strip_chars (split[j] + 5);
2175         GST_DEBUG ("found data '%s'", split[j] + 5);
2176         data = g_base64_decode_inplace (split[j] + 5, &size);
2177         handle_mikey_data (client, ctx, data, size);
2178       }
2179     }
2180     g_strfreev (split);
2181   }
2182   g_strfreev (specs);
2183   return TRUE;
2184 }
2185
2186 static gboolean
2187 rtsp_ctrl_timeout_cb (gpointer user_data)
2188 {
2189   gboolean res = G_SOURCE_CONTINUE;
2190   GstRTSPClient *client = (GstRTSPClient *) user_data;
2191   GstRTSPClientPrivate *priv = client->priv;
2192
2193   priv->rtsp_ctrl_timeout_cnt += RTSP_CTRL_CB_INTERVAL;
2194
2195   if (priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) {
2196     GST_DEBUG ("rtsp control session timeout id=%u expired, closing client.",
2197         priv->rtsp_ctrl_timeout_id);
2198     g_mutex_lock (&priv->lock);
2199     priv->rtsp_ctrl_timeout_id = 0;
2200     priv->rtsp_ctrl_timeout_cnt = 0;
2201     g_mutex_unlock (&priv->lock);
2202     gst_rtsp_client_close (client);
2203
2204     res = G_SOURCE_REMOVE;
2205   }
2206
2207   return res;
2208 }
2209
2210 static void
2211 rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv)
2212 {
2213   g_mutex_lock (&priv->lock);
2214
2215   if (priv->rtsp_ctrl_timeout_id != 0) {
2216     g_source_destroy (g_main_context_find_source_by_id (priv->watch_context,
2217             priv->rtsp_ctrl_timeout_id));
2218     GST_DEBUG ("rtsp control session removed timeout id=%u.",
2219         priv->rtsp_ctrl_timeout_id);
2220     priv->rtsp_ctrl_timeout_id = 0;
2221     priv->rtsp_ctrl_timeout_cnt = 0;
2222   }
2223
2224   g_mutex_unlock (&priv->lock);
2225 }
2226
2227 static gboolean
2228 handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
2229 {
2230   GstRTSPClientPrivate *priv = client->priv;
2231   GstRTSPResult res;
2232   GstRTSPUrl *uri;
2233   gchar *transport, *keymgmt;
2234   GstRTSPTransport *ct, *st;
2235   GstRTSPStatusCode code;
2236   GstRTSPSession *session;
2237   GstRTSPStreamTransport *trans;
2238   gchar *trans_str;
2239   GstRTSPSessionMedia *sessmedia;
2240   GstRTSPMedia *media;
2241   GstRTSPStream *stream;
2242   GstRTSPState rtspstate;
2243   GstRTSPClientClass *klass;
2244   gchar *path, *control = NULL;
2245   gint matched;
2246   gboolean new_session = FALSE;
2247   GstRTSPStatusCode sig_result;
2248   gchar *pipelined_request_id = NULL, *accept_range = NULL;
2249
2250   if (!ctx->uri)
2251     goto no_uri;
2252
2253   uri = ctx->uri;
2254   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2255   path = klass->make_path_from_uri (client, uri);
2256
2257   /* parse the transport */
2258   res =
2259       gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_TRANSPORT,
2260       &transport, 0);
2261   if (res != GST_RTSP_OK)
2262     goto no_transport;
2263
2264   /* Handle Pipelined-requests if using >= 2.0 */
2265   if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0)
2266     gst_rtsp_message_get_header (ctx->request,
2267         GST_RTSP_HDR_PIPELINED_REQUESTS, &pipelined_request_id, 0);
2268
2269   /* we create the session after parsing stuff so that we don't make
2270    * a session for malformed requests */
2271   if (priv->session_pool == NULL)
2272     goto no_pool;
2273
2274   session = ctx->session;
2275
2276   if (session) {
2277     g_object_ref (session);
2278     /* get a handle to the configuration of the media in the session, this can
2279      * return NULL if this is a new url to manage in this session. */
2280     sessmedia = gst_rtsp_session_get_media (session, path, &matched);
2281   } else {
2282     /* we need a new media configuration in this session */
2283     sessmedia = NULL;
2284   }
2285
2286   /* we have no session media, find one and manage it */
2287   if (sessmedia == NULL) {
2288     /* get a handle to the configuration of the media in the session */
2289     media = find_media (client, ctx, path, &matched);
2290     /* need to suspend the media, if the protocol has changed */
2291     if (media != NULL)
2292       gst_rtsp_media_suspend (media);
2293   } else {
2294     if ((media = gst_rtsp_session_media_get_media (sessmedia)))
2295       g_object_ref (media);
2296     else
2297       goto media_not_found;
2298   }
2299   /* no media, not found then */
2300   if (media == NULL)
2301     goto media_not_found_no_reply;
2302
2303   if (path[matched] == '\0') {
2304     if (gst_rtsp_media_n_streams (media) == 1) {
2305       stream = gst_rtsp_media_get_stream (media, 0);
2306     } else {
2307       goto control_not_found;
2308     }
2309   } else {
2310     /* path is what matched. */
2311     path[matched] = '\0';
2312     /* control is remainder */
2313     control = &path[matched + 1];
2314
2315     /* find the stream now using the control part */
2316     stream = gst_rtsp_media_find_stream (media, control);
2317   }
2318
2319   if (stream == NULL)
2320     goto stream_not_found;
2321
2322   /* now we have a uri identifying a valid media and stream */
2323   ctx->stream = stream;
2324   ctx->media = media;
2325
2326   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST], 0,
2327       ctx, &sig_result);
2328   if (sig_result != GST_RTSP_STS_OK) {
2329     goto sig_failed;
2330   }
2331
2332   if (session == NULL) {
2333     /* create a session if this fails we probably reached our session limit or
2334      * something. */
2335     if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
2336       goto service_unavailable;
2337
2338     /* Pipelined requests should be cleared between sessions */
2339     g_hash_table_remove_all (priv->pipelined_requests);
2340
2341     /* make sure this client is closed when the session is closed */
2342     client_watch_session (client, session);
2343
2344     new_session = TRUE;
2345     /* signal new session */
2346     g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
2347         session);
2348
2349     ctx->session = session;
2350   }
2351
2352   if (pipelined_request_id) {
2353     g_hash_table_insert (client->priv->pipelined_requests,
2354         g_strdup (pipelined_request_id),
2355         g_strdup (gst_rtsp_session_get_sessionid (session)));
2356   }
2357   rtsp_ctrl_timeout_remove (priv);
2358
2359   if (!klass->configure_client_media (client, media, stream, ctx))
2360     goto configure_media_failed_no_reply;
2361
2362   gst_rtsp_transport_new (&ct);
2363
2364   /* parse and find a usable supported transport */
2365   if (!parse_transport (transport, stream, ct))
2366     goto unsupported_transports;
2367
2368   if ((ct->mode_play
2369           && !(gst_rtsp_media_get_transport_mode (media) &
2370               GST_RTSP_TRANSPORT_MODE_PLAY)) || (ct->mode_record
2371           && !(gst_rtsp_media_get_transport_mode (media) &
2372               GST_RTSP_TRANSPORT_MODE_RECORD)))
2373     goto unsupported_mode;
2374
2375   /* parse the keymgmt */
2376   if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT,
2377           &keymgmt, 0) == GST_RTSP_OK) {
2378     if (!handle_keymgmt (client, ctx, keymgmt))
2379       goto keymgmt_error;
2380   }
2381
2382   if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
2383           &accept_range, 0) == GST_RTSP_OK) {
2384     GEnumValue *runit = NULL;
2385     gint i;
2386     gchar **valid_ranges;
2387     GEnumClass *runit_class = g_type_class_ref (GST_TYPE_RTSP_RANGE_UNIT);
2388
2389     gst_rtsp_message_dump (ctx->request);
2390     valid_ranges = g_strsplit (accept_range, ",", -1);
2391
2392     for (i = 0; valid_ranges[i]; i++) {
2393       gchar *range = valid_ranges[i];
2394
2395       while (*range == ' ')
2396         range++;
2397
2398       runit = g_enum_get_value_by_nick (runit_class, range);
2399       if (runit)
2400         break;
2401     }
2402     g_strfreev (valid_ranges);
2403     g_type_class_unref (runit_class);
2404
2405     if (!runit)
2406       goto unsupported_range_unit;
2407   }
2408
2409   if (sessmedia == NULL) {
2410     /* manage the media in our session now, if not done already  */
2411     sessmedia =
2412         gst_rtsp_session_manage_media (session, path, g_object_ref (media));
2413     /* if we stil have no media, error */
2414     if (sessmedia == NULL)
2415       goto sessmedia_unavailable;
2416
2417     /* don't cache media anymore */
2418     clean_cached_media (client, FALSE);
2419   }
2420
2421   ctx->sessmedia = sessmedia;
2422
2423   /* update the client transport */
2424   if (!klass->configure_client_transport (client, ctx, ct))
2425     goto unsupported_client_transport;
2426
2427   /* set in the session media transport */
2428   trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
2429
2430   ctx->trans = trans;
2431
2432   /* configure the url used to set this transport, this we will use when
2433    * generating the response for the PLAY request */
2434   gst_rtsp_stream_transport_set_url (trans, uri);
2435   /* configure keepalive for this transport */
2436   gst_rtsp_stream_transport_set_keepalive (trans,
2437       (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
2438
2439   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
2440     /* our callbacks to send data on this TCP connection */
2441     gst_rtsp_stream_transport_set_callbacks (trans,
2442         (GstRTSPSendFunc) do_send_data,
2443         (GstRTSPSendFunc) do_send_data, client, NULL);
2444
2445     g_hash_table_insert (priv->transports,
2446         GINT_TO_POINTER (ct->interleaved.min), trans);
2447     g_object_ref (trans);
2448     g_hash_table_insert (priv->transports,
2449         GINT_TO_POINTER (ct->interleaved.max), trans);
2450     g_object_ref (trans);
2451   }
2452
2453   /* create and serialize the server transport */
2454   st = make_server_transport (client, media, ctx, ct);
2455   trans_str = gst_rtsp_transport_as_text (st);
2456   gst_rtsp_transport_free (st);
2457
2458   /* construct the response now */
2459   code = GST_RTSP_STS_OK;
2460   gst_rtsp_message_init_response (ctx->response, code,
2461       gst_rtsp_status_as_text (code), ctx->request);
2462
2463   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_TRANSPORT,
2464       trans_str);
2465   g_free (trans_str);
2466
2467   if (pipelined_request_id)
2468     gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PIPELINED_REQUESTS,
2469         pipelined_request_id);
2470
2471   if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) {
2472     GstClockTimeDiff seekable = gst_rtsp_media_seekable (media);
2473     GString *media_properties = g_string_new (NULL);
2474
2475     if (seekable == -1)
2476       g_string_append (media_properties,
2477           "No-Seeking,Time-Progressing,Time-Duration=0.0");
2478     else if (seekable == 0)
2479       g_string_append (media_properties, "Beginning-Only");
2480     else if (seekable == G_MAXINT64)
2481       g_string_append (media_properties, "Random-Access");
2482     else
2483       g_string_append_printf (media_properties,
2484           "Random-Access=%f, Unlimited, Immutable",
2485           (gdouble) seekable / GST_SECOND);
2486
2487     gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_MEDIA_PROPERTIES,
2488         g_string_free (media_properties, FALSE));
2489     /* TODO Check how Accept-Ranges should be filled */
2490     gst_rtsp_message_add_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
2491         "npt, clock, smpte, clock");
2492   }
2493
2494   send_message (client, ctx, ctx->response, FALSE);
2495
2496   /* update the state */
2497   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
2498   switch (rtspstate) {
2499     case GST_RTSP_STATE_PLAYING:
2500     case GST_RTSP_STATE_RECORDING:
2501     case GST_RTSP_STATE_READY:
2502       /* no state change */
2503       break;
2504     default:
2505       gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
2506       break;
2507   }
2508   g_object_unref (media);
2509   g_object_unref (session);
2510   g_free (path);
2511
2512   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx);
2513
2514   return TRUE;
2515
2516   /* ERRORS */
2517 no_uri:
2518   {
2519     GST_ERROR ("client %p: no uri", client);
2520     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2521     return FALSE;
2522   }
2523 no_transport:
2524   {
2525     GST_ERROR ("client %p: no transport", client);
2526     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2527     goto cleanup_path;
2528   }
2529 no_pool:
2530   {
2531     GST_ERROR ("client %p: no session pool configured", client);
2532     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2533     goto cleanup_path;
2534   }
2535 media_not_found_no_reply:
2536   {
2537     GST_ERROR ("client %p: media '%s' not found", client, path);
2538     /* error reply is already sent */
2539     goto cleanup_session;
2540   }
2541 media_not_found:
2542   {
2543     GST_ERROR ("client %p: media '%s' not found", client, path);
2544     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2545     goto cleanup_session;
2546   }
2547 control_not_found:
2548   {
2549     GST_ERROR ("client %p: no control in path '%s'", client, path);
2550     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2551     g_object_unref (media);
2552     goto cleanup_session;
2553   }
2554 stream_not_found:
2555   {
2556     GST_ERROR ("client %p: stream '%s' not found", client,
2557         GST_STR_NULL (control));
2558     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2559     g_object_unref (media);
2560     goto cleanup_session;
2561   }
2562 sig_failed:
2563   {
2564     GST_ERROR ("client %p: pre signal returned error: %s", client,
2565         gst_rtsp_status_as_text (sig_result));
2566     send_generic_response (client, sig_result, ctx);
2567     g_object_unref (media);
2568     goto cleanup_path;
2569   }
2570 service_unavailable:
2571   {
2572     GST_ERROR ("client %p: can't create session", client);
2573     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2574     g_object_unref (media);
2575     goto cleanup_session;
2576   }
2577 sessmedia_unavailable:
2578   {
2579     GST_ERROR ("client %p: can't create session media", client);
2580     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2581     goto cleanup_transport;
2582   }
2583 configure_media_failed_no_reply:
2584   {
2585     GST_ERROR ("client %p: configure_media failed", client);
2586     g_object_unref (media);
2587     /* error reply is already sent */
2588     goto cleanup_session;
2589   }
2590 unsupported_transports:
2591   {
2592     GST_ERROR ("client %p: unsupported transports", client);
2593     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2594     goto cleanup_transport;
2595   }
2596 unsupported_client_transport:
2597   {
2598     GST_ERROR ("client %p: unsupported client transport", client);
2599     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2600     goto cleanup_transport;
2601   }
2602 unsupported_mode:
2603   {
2604     GST_ERROR ("client %p: unsupported mode (media play: %d, media record: %d, "
2605         "mode play: %d, mode record: %d)", client,
2606         ! !(gst_rtsp_media_get_transport_mode (media) &
2607             GST_RTSP_TRANSPORT_MODE_PLAY),
2608         ! !(gst_rtsp_media_get_transport_mode (media) &
2609             GST_RTSP_TRANSPORT_MODE_RECORD), ct->mode_play, ct->mode_record);
2610     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2611     goto cleanup_transport;
2612   }
2613 unsupported_range_unit:
2614   {
2615     GST_ERROR ("Client %p: does not support any range format we support",
2616         client);
2617     send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
2618     goto cleanup_transport;
2619   }
2620 keymgmt_error:
2621   {
2622     GST_ERROR ("client %p: keymgmt error", client);
2623     send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx);
2624     goto cleanup_transport;
2625   }
2626   {
2627   cleanup_transport:
2628     gst_rtsp_transport_free (ct);
2629     if (media)
2630       g_object_unref (media);
2631   cleanup_session:
2632     if (new_session)
2633       gst_rtsp_session_pool_remove (priv->session_pool, session);
2634     if (session)
2635       g_object_unref (session);
2636   cleanup_path:
2637     g_free (path);
2638     return FALSE;
2639   }
2640 }
2641
2642 static GstSDPMessage *
2643 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
2644 {
2645   GstRTSPClientPrivate *priv = client->priv;
2646   GstSDPMessage *sdp;
2647   GstSDPInfo info;
2648   const gchar *proto;
2649   guint64 session_id_tmp;
2650   gchar session_id[21];
2651
2652   gst_sdp_message_new (&sdp);
2653
2654   /* some standard things first */
2655   gst_sdp_message_set_version (sdp, "0");
2656
2657   if (priv->is_ipv6)
2658     proto = "IP6";
2659   else
2660     proto = "IP4";
2661
2662   session_id_tmp = (((guint64) g_random_int ()) << 32) | g_random_int ();
2663   g_snprintf (session_id, sizeof (session_id), "%" G_GUINT64_FORMAT,
2664       session_id_tmp);
2665
2666   gst_sdp_message_set_origin (sdp, "-", session_id, "1", "IN", proto,
2667       priv->server_ip);
2668
2669   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
2670   gst_sdp_message_set_information (sdp, "rtsp-server");
2671   gst_sdp_message_add_time (sdp, "0", "0", NULL);
2672   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
2673   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
2674   gst_sdp_message_add_attribute (sdp, "control", "*");
2675
2676   info.is_ipv6 = priv->is_ipv6;
2677   info.server_ip = priv->server_ip;
2678
2679   /* create an SDP for the media object */
2680   if (!gst_rtsp_media_setup_sdp (media, sdp, &info))
2681     goto no_sdp;
2682
2683   return sdp;
2684
2685   /* ERRORS */
2686 no_sdp:
2687   {
2688     GST_ERROR ("client %p: could not create SDP", client);
2689     gst_sdp_message_free (sdp);
2690     return NULL;
2691   }
2692 }
2693
2694 /* for the describe we must generate an SDP */
2695 static gboolean
2696 handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx)
2697 {
2698   GstRTSPClientPrivate *priv = client->priv;
2699   GstRTSPResult res;
2700   GstSDPMessage *sdp;
2701   guint i;
2702   gchar *path, *str;
2703   GstRTSPMedia *media;
2704   GstRTSPClientClass *klass;
2705   GstRTSPStatusCode sig_result;
2706
2707   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2708
2709   if (!ctx->uri)
2710     goto no_uri;
2711
2712   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST],
2713       0, ctx, &sig_result);
2714   if (sig_result != GST_RTSP_STS_OK) {
2715     goto sig_failed;
2716   }
2717
2718   /* check what kind of format is accepted, we don't really do anything with it
2719    * and always return SDP for now. */
2720   for (i = 0;; i++) {
2721     gchar *accept;
2722
2723     res =
2724         gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT,
2725         &accept, i);
2726     if (res == GST_RTSP_ENOTIMPL)
2727       break;
2728
2729     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
2730       break;
2731   }
2732
2733   if (!priv->mount_points)
2734     goto no_mount_points;
2735
2736   if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
2737     goto no_path;
2738
2739   /* find the media object for the uri */
2740   if (!(media = find_media (client, ctx, path, NULL)))
2741     goto no_media;
2742
2743   if (!(gst_rtsp_media_get_transport_mode (media) &
2744           GST_RTSP_TRANSPORT_MODE_PLAY))
2745     goto unsupported_mode;
2746
2747   /* create an SDP for the media object on this client */
2748   if (!(sdp = klass->create_sdp (client, media)))
2749     goto no_sdp;
2750
2751   /* we suspend after the describe */
2752   gst_rtsp_media_suspend (media);
2753   g_object_unref (media);
2754
2755   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2756       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2757
2758   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_TYPE,
2759       "application/sdp");
2760
2761   /* content base for some clients that might screw up creating the setup uri */
2762   str = make_base_url (client, ctx->uri, path);
2763   g_free (path);
2764
2765   GST_INFO ("adding content-base: %s", str);
2766   gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, str);
2767
2768   /* add SDP to the response body */
2769   str = gst_sdp_message_as_text (sdp);
2770   gst_rtsp_message_take_body (ctx->response, (guint8 *) str, strlen (str));
2771   gst_sdp_message_free (sdp);
2772
2773   send_message (client, ctx, ctx->response, FALSE);
2774
2775   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
2776       0, ctx);
2777
2778   return TRUE;
2779
2780   /* ERRORS */
2781 sig_failed:
2782   {
2783     GST_ERROR ("client %p: pre signal returned error: %s", client,
2784         gst_rtsp_status_as_text (sig_result));
2785     send_generic_response (client, sig_result, ctx);
2786     return FALSE;
2787   }
2788 no_uri:
2789   {
2790     GST_ERROR ("client %p: no uri", client);
2791     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2792     return FALSE;
2793   }
2794 no_mount_points:
2795   {
2796     GST_ERROR ("client %p: no mount points configured", client);
2797     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2798     return FALSE;
2799   }
2800 no_path:
2801   {
2802     GST_ERROR ("client %p: can't find path for url", client);
2803     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2804     return FALSE;
2805   }
2806 no_media:
2807   {
2808     GST_ERROR ("client %p: no media", client);
2809     g_free (path);
2810     /* error reply is already sent */
2811     return FALSE;
2812   }
2813 unsupported_mode:
2814   {
2815     GST_ERROR ("client %p: media does not support DESCRIBE", client);
2816     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
2817     g_free (path);
2818     g_object_unref (media);
2819     return FALSE;
2820   }
2821 no_sdp:
2822   {
2823     GST_ERROR ("client %p: can't create SDP", client);
2824     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2825     g_free (path);
2826     g_object_unref (media);
2827     return FALSE;
2828   }
2829 }
2830
2831 static gboolean
2832 handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPMedia * media,
2833     GstSDPMessage * sdp)
2834 {
2835   GstRTSPClientPrivate *priv = client->priv;
2836   GstRTSPThread *thread;
2837
2838   /* create an SDP for the media object */
2839   if (!gst_rtsp_media_handle_sdp (media, sdp))
2840     goto unhandled_sdp;
2841
2842   thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool,
2843       GST_RTSP_THREAD_TYPE_MEDIA, ctx);
2844   if (thread == NULL)
2845     goto no_thread;
2846
2847   /* prepare the media */
2848   if (!gst_rtsp_media_prepare (media, thread))
2849     goto no_prepare;
2850
2851   return TRUE;
2852
2853   /* ERRORS */
2854 unhandled_sdp:
2855   {
2856     GST_ERROR ("client %p: could not handle SDP", client);
2857     return FALSE;
2858   }
2859 no_thread:
2860   {
2861     GST_ERROR ("client %p: can't create thread", client);
2862     return FALSE;
2863   }
2864 no_prepare:
2865   {
2866     GST_ERROR ("client %p: can't prepare media", client);
2867     return FALSE;
2868   }
2869 }
2870
2871 static gboolean
2872 handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx)
2873 {
2874   GstRTSPClientPrivate *priv = client->priv;
2875   GstRTSPClientClass *klass;
2876   GstSDPResult sres;
2877   GstSDPMessage *sdp;
2878   GstRTSPMedia *media;
2879   gchar *path, *cont = NULL;
2880   guint8 *data;
2881   guint size;
2882   GstRTSPStatusCode sig_result;
2883
2884   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2885
2886   if (!ctx->uri)
2887     goto no_uri;
2888
2889   if (!priv->mount_points)
2890     goto no_mount_points;
2891
2892   /* check if reply is SDP */
2893   gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_CONTENT_TYPE, &cont,
2894       0);
2895   /* could not be set but since the request returned OK, we assume it
2896    * was SDP, else check it. */
2897   if (cont) {
2898     if (g_ascii_strcasecmp (cont, "application/sdp") != 0)
2899       goto wrong_content_type;
2900   }
2901
2902   /* get message body and parse as SDP */
2903   gst_rtsp_message_get_body (ctx->request, &data, &size);
2904   if (data == NULL || size == 0)
2905     goto no_message;
2906
2907   GST_DEBUG ("client %p: parse SDP...", client);
2908   gst_sdp_message_new (&sdp);
2909   sres = gst_sdp_message_parse_buffer (data, size, sdp);
2910   if (sres != GST_SDP_OK)
2911     goto sdp_parse_failed;
2912
2913   if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
2914     goto no_path;
2915
2916   /* find the media object for the uri */
2917   if (!(media = find_media (client, ctx, path, NULL)))
2918     goto no_media;
2919
2920   ctx->media = media;
2921
2922   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST],
2923       0, ctx, &sig_result);
2924   if (sig_result != GST_RTSP_STS_OK) {
2925     goto sig_failed;
2926   }
2927
2928   if (!(gst_rtsp_media_get_transport_mode (media) &
2929           GST_RTSP_TRANSPORT_MODE_RECORD))
2930     goto unsupported_mode;
2931
2932   /* Tell client subclass about the media */
2933   if (!klass->handle_sdp (client, ctx, media, sdp))
2934     goto unhandled_sdp;
2935
2936   /* we suspend after the announce */
2937   gst_rtsp_media_suspend (media);
2938   g_object_unref (media);
2939
2940   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2941       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2942
2943   send_message (client, ctx, ctx->response, FALSE);
2944
2945   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST],
2946       0, ctx);
2947
2948   gst_sdp_message_free (sdp);
2949   g_free (path);
2950   return TRUE;
2951
2952 no_uri:
2953   {
2954     GST_ERROR ("client %p: no uri", client);
2955     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2956     return FALSE;
2957   }
2958 no_mount_points:
2959   {
2960     GST_ERROR ("client %p: no mount points configured", client);
2961     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2962     return FALSE;
2963   }
2964 no_path:
2965   {
2966     GST_ERROR ("client %p: can't find path for url", client);
2967     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2968     gst_sdp_message_free (sdp);
2969     return FALSE;
2970   }
2971 wrong_content_type:
2972   {
2973     GST_ERROR ("client %p: unknown content type", client);
2974     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2975     return FALSE;
2976   }
2977 no_message:
2978   {
2979     GST_ERROR ("client %p: can't find SDP message", client);
2980     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2981     return FALSE;
2982   }
2983 sdp_parse_failed:
2984   {
2985     GST_ERROR ("client %p: failed to parse SDP message", client);
2986     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2987     gst_sdp_message_free (sdp);
2988     return FALSE;
2989   }
2990 no_media:
2991   {
2992     GST_ERROR ("client %p: no media", client);
2993     g_free (path);
2994     /* error reply is already sent */
2995     gst_sdp_message_free (sdp);
2996     return FALSE;
2997   }
2998 sig_failed:
2999   {
3000     GST_ERROR ("client %p: pre signal returned error: %s", client,
3001         gst_rtsp_status_as_text (sig_result));
3002     send_generic_response (client, sig_result, ctx);
3003     gst_sdp_message_free (sdp);
3004     return FALSE;
3005   }
3006 unsupported_mode:
3007   {
3008     GST_ERROR ("client %p: media does not support ANNOUNCE", client);
3009     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
3010     g_free (path);
3011     g_object_unref (media);
3012     gst_sdp_message_free (sdp);
3013     return FALSE;
3014   }
3015 unhandled_sdp:
3016   {
3017     GST_ERROR ("client %p: can't handle SDP", client);
3018     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx);
3019     g_free (path);
3020     g_object_unref (media);
3021     gst_sdp_message_free (sdp);
3022     return FALSE;
3023   }
3024 }
3025
3026 static gboolean
3027 handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx)
3028 {
3029   GstRTSPSession *session;
3030   GstRTSPClientClass *klass;
3031   GstRTSPSessionMedia *sessmedia;
3032   GstRTSPMedia *media;
3033   GstRTSPUrl *uri;
3034   GstRTSPState rtspstate;
3035   gchar *path;
3036   gint matched;
3037   GstRTSPStatusCode sig_result;
3038
3039   if (!(session = ctx->session))
3040     goto no_session;
3041
3042   if (!(uri = ctx->uri))
3043     goto no_uri;
3044
3045   klass = GST_RTSP_CLIENT_GET_CLASS (client);
3046   path = klass->make_path_from_uri (client, uri);
3047
3048   /* get a handle to the configuration of the media in the session */
3049   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
3050   if (!sessmedia)
3051     goto not_found;
3052
3053   if (path[matched] != '\0')
3054     goto no_aggregate;
3055
3056   g_free (path);
3057
3058   ctx->sessmedia = sessmedia;
3059   ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
3060
3061   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST], 0,
3062       ctx, &sig_result);
3063   if (sig_result != GST_RTSP_STS_OK) {
3064     goto sig_failed;
3065   }
3066
3067   if (!(gst_rtsp_media_get_transport_mode (media) &
3068           GST_RTSP_TRANSPORT_MODE_RECORD))
3069     goto unsupported_mode;
3070
3071   /* the session state must be playing or ready */
3072   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
3073   if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
3074     goto invalid_state;
3075
3076   /* in play we first unsuspend, media could be suspended from SDP or PAUSED */
3077   if (!gst_rtsp_media_unsuspend (media))
3078     goto unsuspend_failed;
3079
3080   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3081       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3082
3083   send_message (client, ctx, ctx->response, FALSE);
3084
3085   /* start playing after sending the response */
3086   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
3087
3088   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
3089
3090   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST], 0,
3091       ctx);
3092
3093   return TRUE;
3094
3095   /* ERRORS */
3096 no_session:
3097   {
3098     GST_ERROR ("client %p: no session", client);
3099     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3100     return FALSE;
3101   }
3102 no_uri:
3103   {
3104     GST_ERROR ("client %p: no uri supplied", client);
3105     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3106     return FALSE;
3107   }
3108 not_found:
3109   {
3110     GST_ERROR ("client %p: media not found", client);
3111     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3112     return FALSE;
3113   }
3114 no_aggregate:
3115   {
3116     GST_ERROR ("client %p: no aggregate path %s", client, path);
3117     send_generic_response (client,
3118         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
3119     g_free (path);
3120     return FALSE;
3121   }
3122 sig_failed:
3123   {
3124     GST_ERROR ("client %p: pre signal returned error: %s", client,
3125         gst_rtsp_status_as_text (sig_result));
3126     send_generic_response (client, sig_result, ctx);
3127     return FALSE;
3128   }
3129 unsupported_mode:
3130   {
3131     GST_ERROR ("client %p: media does not support RECORD", client);
3132     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
3133     return FALSE;
3134   }
3135 invalid_state:
3136   {
3137     GST_ERROR ("client %p: not PLAYING or READY", client);
3138     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
3139         ctx);
3140     return FALSE;
3141   }
3142 unsuspend_failed:
3143   {
3144     GST_ERROR ("client %p: unsuspend failed", client);
3145     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
3146     return FALSE;
3147   }
3148 }
3149
3150 static gboolean
3151 handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx,
3152     GstRTSPVersion version)
3153 {
3154   GstRTSPMethod options;
3155   gchar *str;
3156   GstRTSPStatusCode sig_result;
3157
3158   options = GST_RTSP_DESCRIBE |
3159       GST_RTSP_OPTIONS |
3160       GST_RTSP_PAUSE |
3161       GST_RTSP_PLAY |
3162       GST_RTSP_SETUP |
3163       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
3164
3165   if (version < GST_RTSP_VERSION_2_0) {
3166     options |= GST_RTSP_RECORD;
3167     options |= GST_RTSP_ANNOUNCE;
3168   }
3169
3170   str = gst_rtsp_options_as_text (options);
3171
3172   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3173       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3174
3175   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str);
3176   g_free (str);
3177
3178   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST], 0,
3179       ctx, &sig_result);
3180   if (sig_result != GST_RTSP_STS_OK) {
3181     goto sig_failed;
3182   }
3183
3184   send_message (client, ctx, ctx->response, FALSE);
3185
3186   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
3187       0, ctx);
3188
3189   return TRUE;
3190
3191 /* ERRORS */
3192 sig_failed:
3193   {
3194     GST_ERROR ("client %p: pre signal returned error: %s", client,
3195         gst_rtsp_status_as_text (sig_result));
3196     send_generic_response (client, sig_result, ctx);
3197     gst_rtsp_message_free (ctx->response);
3198     return FALSE;
3199   }
3200 }
3201
3202 /* remove duplicate and trailing '/' */
3203 static void
3204 sanitize_uri (GstRTSPUrl * uri)
3205 {
3206   gint i, len;
3207   gchar *s, *d;
3208   gboolean have_slash, prev_slash;
3209
3210   s = d = uri->abspath;
3211   len = strlen (uri->abspath);
3212
3213   prev_slash = FALSE;
3214
3215   for (i = 0; i < len; i++) {
3216     have_slash = s[i] == '/';
3217     *d = s[i];
3218     if (!have_slash || !prev_slash)
3219       d++;
3220     prev_slash = have_slash;
3221   }
3222   len = d - uri->abspath;
3223   /* don't remove the first slash if that's the only thing left */
3224   if (len > 1 && *(d - 1) == '/')
3225     d--;
3226   *d = '\0';
3227 }
3228
3229 /* is called when the session is removed from its session pool. */
3230 static void
3231 client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session,
3232     GstRTSPClient * client)
3233 {
3234   GstRTSPClientPrivate *priv = client->priv;
3235
3236   GST_INFO ("client %p: session %p removed", client, session);
3237
3238   g_mutex_lock (&priv->lock);
3239   if (priv->watch != NULL)
3240     gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0);
3241   client_unwatch_session (client, session, NULL);
3242   if (priv->watch != NULL)
3243     gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3244   g_mutex_unlock (&priv->lock);
3245 }
3246
3247 /* Check for Require headers. Returns TRUE if there are no Require headers,
3248  * otherwise lets the application decide which headers are supported.
3249  * By default all headers are unsupported.
3250  * If there are unsupported options, FALSE will be returned together with
3251  * a newly-allocated string of (comma-separated) unsupported options in
3252  * the unsupported_reqs variable.
3253  *
3254  * There may be multiple Require headers, but we must send one single
3255  * Unsupported header with all the unsupported options as response. If
3256  * an incoming Require header contained a comma-separated list of options
3257  * GstRtspConnection will already have split that list up into multiple
3258  * headers.
3259  */
3260 static gboolean
3261 check_request_requirements (GstRTSPContext * ctx, gchar ** unsupported_reqs)
3262 {
3263   GstRTSPResult res;
3264   GPtrArray *arr = NULL;
3265   GstRTSPMessage *msg = ctx->request;
3266   gchar *reqs = NULL;
3267   gint i;
3268   gchar *sig_result = NULL;
3269   gboolean result = TRUE;
3270
3271   i = 0;
3272   do {
3273     res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++);
3274
3275     if (res == GST_RTSP_ENOTIMPL)
3276       break;
3277
3278     if (arr == NULL)
3279       arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
3280
3281     g_ptr_array_add (arr, g_strdup (reqs));
3282   }
3283   while (TRUE);
3284
3285   /* if we don't have any Require headers at all, all is fine */
3286   if (i == 1)
3287     return TRUE;
3288
3289   /* otherwise we've now processed at all the Require headers */
3290   g_ptr_array_add (arr, NULL);
3291
3292   g_signal_emit (ctx->client,
3293       gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS], 0, ctx,
3294       (gchar **) arr->pdata, &sig_result);
3295
3296   if (sig_result == NULL) {
3297     /* no supported options, just report all of the required ones as
3298      * unsupported */
3299     *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata);
3300     result = FALSE;
3301     goto done;
3302   }
3303
3304   if (strlen (sig_result) == 0)
3305     g_free (sig_result);
3306   else {
3307     *unsupported_reqs = sig_result;
3308     result = FALSE;
3309   }
3310
3311 done:
3312   g_ptr_array_unref (arr);
3313   return result;
3314 }
3315
3316 static void
3317 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
3318 {
3319   GstRTSPClientPrivate *priv = client->priv;
3320   GstRTSPMethod method;
3321   const gchar *uristr;
3322   GstRTSPUrl *uri = NULL;
3323   GstRTSPVersion version;
3324   GstRTSPResult res;
3325   GstRTSPSession *session = NULL;
3326   GstRTSPContext sctx = { NULL }, *ctx;
3327   GstRTSPMessage response = { 0 };
3328   gchar *unsupported_reqs = NULL;
3329   gchar *sessid = NULL, *pipelined_request_id = NULL;
3330
3331   if (!(ctx = gst_rtsp_context_get_current ())) {
3332     ctx = &sctx;
3333     ctx->auth = priv->auth;
3334     gst_rtsp_context_push_current (ctx);
3335   }
3336
3337   ctx->conn = priv->connection;
3338   ctx->client = client;
3339   ctx->request = request;
3340   ctx->response = &response;
3341
3342   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3343     gst_rtsp_message_dump (request);
3344   }
3345
3346   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
3347
3348   GST_INFO ("client %p: received a request %s %s %s", client,
3349       gst_rtsp_method_as_text (method), uristr,
3350       gst_rtsp_version_as_text (version));
3351
3352   /* we can only handle 1.0 requests */
3353   if (version != GST_RTSP_VERSION_1_0 && version != GST_RTSP_VERSION_2_0)
3354     goto not_supported;
3355
3356   ctx->method = method;
3357
3358   /* we always try to parse the url first */
3359   if (strcmp (uristr, "*") == 0) {
3360     /* special case where we have * as uri, keep uri = NULL */
3361   } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
3362     /* check if the uristr is an absolute path <=> scheme and host information
3363      * is missing */
3364     gchar *scheme;
3365
3366     scheme = g_uri_parse_scheme (uristr);
3367     if (scheme == NULL && g_str_has_prefix (uristr, "/")) {
3368       gchar *absolute_uristr = NULL;
3369
3370       GST_WARNING_OBJECT (client, "request doesn't contain absolute url");
3371       if (priv->server_ip == NULL) {
3372         GST_WARNING_OBJECT (client, "host information missing");
3373         goto bad_request;
3374       }
3375
3376       absolute_uristr =
3377           g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr);
3378
3379       GST_DEBUG_OBJECT (client, "absolute url: %s", absolute_uristr);
3380       if (gst_rtsp_url_parse (absolute_uristr, &uri) != GST_RTSP_OK) {
3381         g_free (absolute_uristr);
3382         goto bad_request;
3383       }
3384       g_free (absolute_uristr);
3385     } else {
3386       g_free (scheme);
3387       goto bad_request;
3388     }
3389   }
3390
3391   /* get the session if there is any */
3392   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_PIPELINED_REQUESTS,
3393       &pipelined_request_id, 0);
3394   if (res == GST_RTSP_OK) {
3395     sessid = g_hash_table_lookup (client->priv->pipelined_requests,
3396         pipelined_request_id);
3397
3398     if (!sessid)
3399       res = GST_RTSP_ERROR;
3400   }
3401
3402   if (res != GST_RTSP_OK)
3403     res =
3404         gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
3405
3406   if (res == GST_RTSP_OK) {
3407     if (priv->session_pool == NULL)
3408       goto no_pool;
3409
3410     /* we had a session in the request, find it again */
3411     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
3412       goto session_not_found;
3413
3414     /* we add the session to the client list of watched sessions. When a session
3415      * disappears because it times out, we will be notified. If all sessions are
3416      * gone, we will close the connection */
3417     client_watch_session (client, session);
3418   }
3419
3420   /* sanitize the uri */
3421   if (uri)
3422     sanitize_uri (uri);
3423   ctx->uri = uri;
3424   ctx->session = session;
3425
3426   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL))
3427     goto not_authorized;
3428
3429   /* handle any 'Require' headers */
3430   if (!check_request_requirements (ctx, &unsupported_reqs))
3431     goto unsupported_requirement;
3432
3433   /* the backlog must be unlimited while processing requests.
3434    * the causes of this are two cases of deadlocks while streaming over TCP:
3435    *
3436    * 1. consider the scenario where the media pipeline's streaming thread
3437    * is blocking in the appsink (taking the appsink's preroll lock) because
3438    * the backlog is full. when a PAUSE request is received by the RTSP
3439    * client thread then the the state of the session media ought to change
3440    * to PAUSED. while most elements in the pipeline can change state this
3441    * can never happen for the appsink since its preroll lock is taken by
3442    * another thread.
3443    *
3444    * 2. consider the scenario where the media pipeline's streaming thread
3445    * is blocking in the appsink new_sample callback (taking the send lock
3446    * in RTSP client) because the backlog is full. when e.g. a GET request
3447    * is received by the RTSP client thread then a response ought to be sent
3448    * but this can never happen since it requires taking the send lock
3449    * already taken by another thread.
3450    *
3451    * the reason that the backlog is never emptied is that the source used
3452    * for dequeing messages from the backlog is never dispatched because it
3453    * is attached to the same mainloop as the source receving RTSP requests and
3454    * therefore run by the RTSP client thread which is alreayd blocking.
3455    *
3456    * without significant changes the easiest way to cope with this is to
3457    * not block indefinitely when the backlog is full, but rather let the
3458    * backlog grow in size. this in effect means that there can not be any
3459    * upper boundary on its size.
3460    */
3461   if (priv->watch != NULL)
3462     gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0);
3463
3464   /* now see what is asked and dispatch to a dedicated handler */
3465   switch (method) {
3466     case GST_RTSP_OPTIONS:
3467       priv->version = version;
3468       handle_options_request (client, ctx, version);
3469       break;
3470     case GST_RTSP_DESCRIBE:
3471       handle_describe_request (client, ctx);
3472       break;
3473     case GST_RTSP_SETUP:
3474       handle_setup_request (client, ctx);
3475       break;
3476     case GST_RTSP_PLAY:
3477       handle_play_request (client, ctx);
3478       break;
3479     case GST_RTSP_PAUSE:
3480       handle_pause_request (client, ctx);
3481       break;
3482     case GST_RTSP_TEARDOWN:
3483       handle_teardown_request (client, ctx);
3484       break;
3485     case GST_RTSP_SET_PARAMETER:
3486       handle_set_param_request (client, ctx);
3487       break;
3488     case GST_RTSP_GET_PARAMETER:
3489       handle_get_param_request (client, ctx);
3490       break;
3491     case GST_RTSP_ANNOUNCE:
3492       if (version >= GST_RTSP_VERSION_2_0)
3493         goto invalid_command_for_version;
3494       handle_announce_request (client, ctx);
3495       break;
3496     case GST_RTSP_RECORD:
3497       if (version >= GST_RTSP_VERSION_2_0)
3498         goto invalid_command_for_version;
3499       handle_record_request (client, ctx);
3500       break;
3501     case GST_RTSP_REDIRECT:
3502       if (priv->watch != NULL)
3503         gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3504       goto not_implemented;
3505     case GST_RTSP_INVALID:
3506     default:
3507       if (priv->watch != NULL)
3508         gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3509       goto bad_request;
3510   }
3511
3512   if (priv->watch != NULL)
3513     gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3514
3515 done:
3516   if (ctx == &sctx)
3517     gst_rtsp_context_pop_current (ctx);
3518   if (session)
3519     g_object_unref (session);
3520   if (uri)
3521     gst_rtsp_url_free (uri);
3522   return;
3523
3524   /* ERRORS */
3525 not_supported:
3526   {
3527     GST_ERROR ("client %p: version %d not supported", client, version);
3528     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
3529         ctx);
3530     goto done;
3531   }
3532 invalid_command_for_version:
3533   {
3534     if (priv->watch != NULL)
3535       gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3536
3537     GST_ERROR ("client %p: invalid command for version", client);
3538     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3539     goto done;
3540   }
3541 bad_request:
3542   {
3543     GST_ERROR ("client %p: bad request", client);
3544     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3545     goto done;
3546   }
3547 no_pool:
3548   {
3549     GST_ERROR ("client %p: no pool configured", client);
3550     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3551     goto done;
3552   }
3553 session_not_found:
3554   {
3555     GST_ERROR ("client %p: session not found", client);
3556     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3557     goto done;
3558   }
3559 not_authorized:
3560   {
3561     GST_ERROR ("client %p: not allowed", client);
3562     /* error reply is already sent */
3563     goto done;
3564   }
3565 unsupported_requirement:
3566   {
3567     GST_ERROR ("client %p: Required option is not supported (%s)", client,
3568         unsupported_reqs);
3569     send_option_not_supported_response (client, ctx, unsupported_reqs);
3570     g_free (unsupported_reqs);
3571     goto done;
3572   }
3573 not_implemented:
3574   {
3575     GST_ERROR ("client %p: method %d not implemented", client, method);
3576     send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
3577     goto done;
3578   }
3579 }
3580
3581
3582 static void
3583 handle_response (GstRTSPClient * client, GstRTSPMessage * response)
3584 {
3585   GstRTSPClientPrivate *priv = client->priv;
3586   GstRTSPResult res;
3587   GstRTSPSession *session = NULL;
3588   GstRTSPContext sctx = { NULL }, *ctx;
3589   gchar *sessid;
3590
3591   if (!(ctx = gst_rtsp_context_get_current ())) {
3592     ctx = &sctx;
3593     ctx->auth = priv->auth;
3594     gst_rtsp_context_push_current (ctx);
3595   }
3596
3597   ctx->conn = priv->connection;
3598   ctx->client = client;
3599   ctx->request = NULL;
3600   ctx->uri = NULL;
3601   ctx->method = GST_RTSP_INVALID;
3602   ctx->response = response;
3603
3604   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3605     gst_rtsp_message_dump (response);
3606   }
3607
3608   GST_INFO ("client %p: received a response", client);
3609
3610   /* get the session if there is any */
3611   res =
3612       gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &sessid, 0);
3613   if (res == GST_RTSP_OK) {
3614     if (priv->session_pool == NULL)
3615       goto no_pool;
3616
3617     /* we had a session in the request, find it again */
3618     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
3619       goto session_not_found;
3620
3621     /* we add the session to the client list of watched sessions. When a session
3622      * disappears because it times out, we will be notified. If all sessions are
3623      * gone, we will close the connection */
3624     client_watch_session (client, session);
3625   }
3626
3627   ctx->session = session;
3628
3629   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE],
3630       0, ctx);
3631
3632 done:
3633   if (ctx == &sctx)
3634     gst_rtsp_context_pop_current (ctx);
3635   if (session)
3636     g_object_unref (session);
3637   return;
3638
3639 no_pool:
3640   {
3641     GST_ERROR ("client %p: no pool configured", client);
3642     goto done;
3643   }
3644 session_not_found:
3645   {
3646     GST_ERROR ("client %p: session not found", client);
3647     goto done;
3648   }
3649 }
3650
3651 static void
3652 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
3653 {
3654   GstRTSPClientPrivate *priv = client->priv;
3655   GstRTSPResult res;
3656   guint8 channel;
3657   guint8 *data;
3658   guint size;
3659   GstBuffer *buffer;
3660   GstRTSPStreamTransport *trans;
3661
3662   /* find the stream for this message */
3663   res = gst_rtsp_message_parse_data (message, &channel);
3664   if (res != GST_RTSP_OK)
3665     return;
3666
3667   gst_rtsp_message_get_body (message, &data, &size);
3668   if (size < 2)
3669     goto invalid_length;
3670
3671   gst_rtsp_message_steal_body (message, &data, &size);
3672
3673   /* Strip trailing \0 (which GstRTSPConnection adds) */
3674   --size;
3675
3676   buffer = gst_buffer_new_wrapped (data, size);
3677
3678   trans =
3679       g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel));
3680   if (trans) {
3681     /* dispatch to the stream based on the channel number */
3682     GST_LOG_OBJECT (client, "%u bytes of data on channel %u", size, channel);
3683     gst_rtsp_stream_transport_recv_data (trans, channel, buffer);
3684   } else {
3685     GST_DEBUG_OBJECT (client, "received %u bytes of data for "
3686         "unknown channel %u", size, channel);
3687     gst_buffer_unref (buffer);
3688   }
3689
3690   return;
3691
3692 /* ERRORS */
3693 invalid_length:
3694   {
3695     GST_DEBUG ("client %p: Short message received, ignoring", client);
3696     return;
3697   }
3698 }
3699
3700 /**
3701  * gst_rtsp_client_set_session_pool:
3702  * @client: a #GstRTSPClient
3703  * @pool: (transfer none): a #GstRTSPSessionPool
3704  *
3705  * Set @pool as the sessionpool for @client which it will use to find
3706  * or allocate sessions. the sessionpool is usually inherited from the server
3707  * that created the client but can be overridden later.
3708  */
3709 void
3710 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
3711     GstRTSPSessionPool * pool)
3712 {
3713   GstRTSPSessionPool *old;
3714   GstRTSPClientPrivate *priv;
3715
3716   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3717
3718   priv = client->priv;
3719
3720   if (pool)
3721     g_object_ref (pool);
3722
3723   g_mutex_lock (&priv->lock);
3724   old = priv->session_pool;
3725   priv->session_pool = pool;
3726
3727   if (priv->session_removed_id) {
3728     g_signal_handler_disconnect (old, priv->session_removed_id);
3729     priv->session_removed_id = 0;
3730   }
3731   g_mutex_unlock (&priv->lock);
3732
3733   /* FIXME, should remove all sessions from the old pool for this client */
3734   if (old)
3735     g_object_unref (old);
3736 }
3737
3738 /**
3739  * gst_rtsp_client_get_session_pool:
3740  * @client: a #GstRTSPClient
3741  *
3742  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
3743  *
3744  * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage.
3745  */
3746 GstRTSPSessionPool *
3747 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
3748 {
3749   GstRTSPClientPrivate *priv;
3750   GstRTSPSessionPool *result;
3751
3752   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3753
3754   priv = client->priv;
3755
3756   g_mutex_lock (&priv->lock);
3757   if ((result = priv->session_pool))
3758     g_object_ref (result);
3759   g_mutex_unlock (&priv->lock);
3760
3761   return result;
3762 }
3763
3764 /**
3765  * gst_rtsp_client_set_mount_points:
3766  * @client: a #GstRTSPClient
3767  * @mounts: (transfer none): a #GstRTSPMountPoints
3768  *
3769  * Set @mounts as the mount points for @client which it will use to map urls
3770  * to media streams. These mount points are usually inherited from the server that
3771  * created the client but can be overriden later.
3772  */
3773 void
3774 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
3775     GstRTSPMountPoints * mounts)
3776 {
3777   GstRTSPClientPrivate *priv;
3778   GstRTSPMountPoints *old;
3779
3780   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3781
3782   priv = client->priv;
3783
3784   if (mounts)
3785     g_object_ref (mounts);
3786
3787   g_mutex_lock (&priv->lock);
3788   old = priv->mount_points;
3789   priv->mount_points = mounts;
3790   g_mutex_unlock (&priv->lock);
3791
3792   if (old)
3793     g_object_unref (old);
3794 }
3795
3796 /**
3797  * gst_rtsp_client_get_mount_points:
3798  * @client: a #GstRTSPClient
3799  *
3800  * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
3801  *
3802  * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage.
3803  */
3804 GstRTSPMountPoints *
3805 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
3806 {
3807   GstRTSPClientPrivate *priv;
3808   GstRTSPMountPoints *result;
3809
3810   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3811
3812   priv = client->priv;
3813
3814   g_mutex_lock (&priv->lock);
3815   if ((result = priv->mount_points))
3816     g_object_ref (result);
3817   g_mutex_unlock (&priv->lock);
3818
3819   return result;
3820 }
3821
3822 /**
3823  * gst_rtsp_client_set_auth:
3824  * @client: a #GstRTSPClient
3825  * @auth: (transfer none): a #GstRTSPAuth
3826  *
3827  * configure @auth to be used as the authentication manager of @client.
3828  */
3829 void
3830 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
3831 {
3832   GstRTSPClientPrivate *priv;
3833   GstRTSPAuth *old;
3834
3835   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3836
3837   priv = client->priv;
3838
3839   if (auth)
3840     g_object_ref (auth);
3841
3842   g_mutex_lock (&priv->lock);
3843   old = priv->auth;
3844   priv->auth = auth;
3845   g_mutex_unlock (&priv->lock);
3846
3847   if (old)
3848     g_object_unref (old);
3849 }
3850
3851
3852 /**
3853  * gst_rtsp_client_get_auth:
3854  * @client: a #GstRTSPClient
3855  *
3856  * Get the #GstRTSPAuth used as the authentication manager of @client.
3857  *
3858  * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after
3859  * usage.
3860  */
3861 GstRTSPAuth *
3862 gst_rtsp_client_get_auth (GstRTSPClient * client)
3863 {
3864   GstRTSPClientPrivate *priv;
3865   GstRTSPAuth *result;
3866
3867   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3868
3869   priv = client->priv;
3870
3871   g_mutex_lock (&priv->lock);
3872   if ((result = priv->auth))
3873     g_object_ref (result);
3874   g_mutex_unlock (&priv->lock);
3875
3876   return result;
3877 }
3878
3879 /**
3880  * gst_rtsp_client_set_thread_pool:
3881  * @client: a #GstRTSPClient
3882  * @pool: (transfer none): a #GstRTSPThreadPool
3883  *
3884  * configure @pool to be used as the thread pool of @client.
3885  */
3886 void
3887 gst_rtsp_client_set_thread_pool (GstRTSPClient * client,
3888     GstRTSPThreadPool * pool)
3889 {
3890   GstRTSPClientPrivate *priv;
3891   GstRTSPThreadPool *old;
3892
3893   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3894
3895   priv = client->priv;
3896
3897   if (pool)
3898     g_object_ref (pool);
3899
3900   g_mutex_lock (&priv->lock);
3901   old = priv->thread_pool;
3902   priv->thread_pool = pool;
3903   g_mutex_unlock (&priv->lock);
3904
3905   if (old)
3906     g_object_unref (old);
3907 }
3908
3909 /**
3910  * gst_rtsp_client_get_thread_pool:
3911  * @client: a #GstRTSPClient
3912  *
3913  * Get the #GstRTSPThreadPool used as the thread pool of @client.
3914  *
3915  * Returns: (transfer full): the #GstRTSPThreadPool of @client. g_object_unref() after
3916  * usage.
3917  */
3918 GstRTSPThreadPool *
3919 gst_rtsp_client_get_thread_pool (GstRTSPClient * client)
3920 {
3921   GstRTSPClientPrivate *priv;
3922   GstRTSPThreadPool *result;
3923
3924   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3925
3926   priv = client->priv;
3927
3928   g_mutex_lock (&priv->lock);
3929   if ((result = priv->thread_pool))
3930     g_object_ref (result);
3931   g_mutex_unlock (&priv->lock);
3932
3933   return result;
3934 }
3935
3936 /**
3937  * gst_rtsp_client_set_connection:
3938  * @client: a #GstRTSPClient
3939  * @conn: (transfer full): a #GstRTSPConnection
3940  *
3941  * Set the #GstRTSPConnection of @client. This function takes ownership of
3942  * @conn.
3943  *
3944  * Returns: %TRUE on success.
3945  */
3946 gboolean
3947 gst_rtsp_client_set_connection (GstRTSPClient * client,
3948     GstRTSPConnection * conn)
3949 {
3950   GstRTSPClientPrivate *priv;
3951   GSocket *read_socket;
3952   GSocketAddress *address;
3953   GstRTSPUrl *url;
3954   GError *error = NULL;
3955
3956   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
3957   g_return_val_if_fail (conn != NULL, FALSE);
3958
3959   priv = client->priv;
3960
3961   read_socket = gst_rtsp_connection_get_read_socket (conn);
3962
3963   if (!(address = g_socket_get_local_address (read_socket, &error)))
3964     goto no_address;
3965
3966   g_free (priv->server_ip);
3967   /* keep the original ip that the client connected to */
3968   if (G_IS_INET_SOCKET_ADDRESS (address)) {
3969     GInetAddress *iaddr;
3970
3971     iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
3972
3973     /* socket might be ipv6 but adress still ipv4 */
3974     priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6;
3975     priv->server_ip = g_inet_address_to_string (iaddr);
3976     g_object_unref (address);
3977   } else {
3978     priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
3979     priv->server_ip = g_strdup ("unknown");
3980   }
3981
3982   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
3983       priv->server_ip, priv->is_ipv6);
3984
3985   url = gst_rtsp_connection_get_url (conn);
3986   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
3987
3988   priv->connection = conn;
3989
3990   return TRUE;
3991
3992   /* ERRORS */
3993 no_address:
3994   {
3995     GST_ERROR ("could not get local address %s", error->message);
3996     g_error_free (error);
3997     return FALSE;
3998   }
3999 }
4000
4001 /**
4002  * gst_rtsp_client_get_connection:
4003  * @client: a #GstRTSPClient
4004  *
4005  * Get the #GstRTSPConnection of @client.
4006  *
4007  * Returns: (transfer none): the #GstRTSPConnection of @client.
4008  * The connection object returned remains valid until the client is freed.
4009  */
4010 GstRTSPConnection *
4011 gst_rtsp_client_get_connection (GstRTSPClient * client)
4012 {
4013   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4014
4015   return client->priv->connection;
4016 }
4017
4018 /**
4019  * gst_rtsp_client_set_send_func:
4020  * @client: a #GstRTSPClient
4021  * @func: (scope notified): a #GstRTSPClientSendFunc
4022  * @user_data: (closure): user data passed to @func
4023  * @notify: (allow-none): called when @user_data is no longer in use
4024  *
4025  * Set @func as the callback that will be called when a new message needs to be
4026  * sent to the client. @user_data is passed to @func and @notify is called when
4027  * @user_data is no longer in use.
4028  *
4029  * By default, the client will send the messages on the #GstRTSPConnection that
4030  * was configured with gst_rtsp_client_attach() was called.
4031  */
4032 void
4033 gst_rtsp_client_set_send_func (GstRTSPClient * client,
4034     GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
4035 {
4036   GstRTSPClientPrivate *priv;
4037   GDestroyNotify old_notify;
4038   gpointer old_data;
4039
4040   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4041
4042   priv = client->priv;
4043
4044   g_mutex_lock (&priv->send_lock);
4045   priv->send_func = func;
4046   old_notify = priv->send_notify;
4047   old_data = priv->send_data;
4048   priv->send_notify = notify;
4049   priv->send_data = user_data;
4050   g_mutex_unlock (&priv->send_lock);
4051
4052   if (old_notify)
4053     old_notify (old_data);
4054 }
4055
4056 /**
4057  * gst_rtsp_client_handle_message:
4058  * @client: a #GstRTSPClient
4059  * @message: (transfer none): an #GstRTSPMessage
4060  *
4061  * Let the client handle @message.
4062  *
4063  * Returns: a #GstRTSPResult.
4064  */
4065 GstRTSPResult
4066 gst_rtsp_client_handle_message (GstRTSPClient * client,
4067     GstRTSPMessage * message)
4068 {
4069   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
4070   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4071
4072   switch (message->type) {
4073     case GST_RTSP_MESSAGE_REQUEST:
4074       handle_request (client, message);
4075       break;
4076     case GST_RTSP_MESSAGE_RESPONSE:
4077       handle_response (client, message);
4078       break;
4079     case GST_RTSP_MESSAGE_DATA:
4080       handle_data (client, message);
4081       break;
4082     default:
4083       break;
4084   }
4085   return GST_RTSP_OK;
4086 }
4087
4088 /**
4089  * gst_rtsp_client_send_message:
4090  * @client: a #GstRTSPClient
4091  * @session: (allow-none) (transfer none): a #GstRTSPSession to send
4092  *   the message to or %NULL
4093  * @message: (transfer none): The #GstRTSPMessage to send
4094  *
4095  * Send a message message to the remote end. @message must be a
4096  * #GST_RTSP_MESSAGE_REQUEST or a #GST_RTSP_MESSAGE_RESPONSE.
4097  */
4098 GstRTSPResult
4099 gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session,
4100     GstRTSPMessage * message)
4101 {
4102   GstRTSPContext sctx = { NULL }
4103   , *ctx;
4104   GstRTSPClientPrivate *priv;
4105
4106   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
4107   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4108   g_return_val_if_fail (message->type == GST_RTSP_MESSAGE_REQUEST ||
4109       message->type == GST_RTSP_MESSAGE_RESPONSE, GST_RTSP_EINVAL);
4110
4111   priv = client->priv;
4112
4113   if (!(ctx = gst_rtsp_context_get_current ())) {
4114     ctx = &sctx;
4115     ctx->auth = priv->auth;
4116     gst_rtsp_context_push_current (ctx);
4117   }
4118
4119   ctx->conn = priv->connection;
4120   ctx->client = client;
4121   ctx->session = session;
4122
4123   send_message (client, ctx, message, FALSE);
4124
4125   if (ctx == &sctx)
4126     gst_rtsp_context_pop_current (ctx);
4127
4128   return GST_RTSP_OK;
4129 }
4130
4131 static gboolean
4132 do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
4133     gboolean close, gpointer user_data)
4134 {
4135   GstRTSPClientPrivate *priv = client->priv;
4136   GstRTSPResult ret;
4137   GTimeVal time;
4138
4139   time.tv_sec = 1;
4140   time.tv_usec = 0;
4141
4142   do {
4143     /* send the response and store the seq number so we can wait until it's
4144      * written to the client to close the connection */
4145     ret =
4146         gst_rtsp_watch_send_message (priv->watch, message,
4147         close ? &priv->close_seq : NULL);
4148     if (ret == GST_RTSP_OK)
4149       break;
4150
4151     if (ret != GST_RTSP_ENOMEM)
4152       goto error;
4153
4154     /* drop backlog */
4155     if (priv->drop_backlog)
4156       break;
4157
4158     /* queue was full, wait for more space */
4159     GST_DEBUG_OBJECT (client, "waiting for backlog");
4160     ret = gst_rtsp_watch_wait_backlog (priv->watch, &time);
4161     GST_DEBUG_OBJECT (client, "Resend due to backlog full");
4162   } while (ret != GST_RTSP_EINTR);
4163
4164   return ret == GST_RTSP_OK;
4165
4166   /* ERRORS */
4167 error:
4168   {
4169     GST_DEBUG_OBJECT (client, "got error %d", ret);
4170     return ret == GST_RTSP_OK;
4171   }
4172 }
4173
4174 static GstRTSPResult
4175 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
4176     gpointer user_data)
4177 {
4178   return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
4179 }
4180
4181 static GstRTSPResult
4182 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
4183 {
4184   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4185   GstRTSPClientPrivate *priv = client->priv;
4186
4187   if (priv->close_seq && priv->close_seq == cseq) {
4188     GST_INFO ("client %p: send close message", client);
4189     priv->close_seq = 0;
4190     gst_rtsp_client_close (client);
4191   }
4192
4193   return GST_RTSP_OK;
4194 }
4195
4196 static GstRTSPResult
4197 closed (GstRTSPWatch * watch, gpointer user_data)
4198 {
4199   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4200   GstRTSPClientPrivate *priv = client->priv;
4201   const gchar *tunnelid;
4202
4203   GST_INFO ("client %p: connection closed", client);
4204
4205   if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
4206     g_mutex_lock (&tunnels_lock);
4207     /* remove from tunnelids */
4208     g_hash_table_remove (tunnels, tunnelid);
4209     g_mutex_unlock (&tunnels_lock);
4210   }
4211
4212   gst_rtsp_watch_set_flushing (watch, TRUE);
4213   g_mutex_lock (&priv->watch_lock);
4214   gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
4215   g_mutex_unlock (&priv->watch_lock);
4216
4217   return GST_RTSP_OK;
4218 }
4219
4220 static GstRTSPResult
4221 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
4222 {
4223   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4224   gchar *str;
4225
4226   str = gst_rtsp_strresult (result);
4227   GST_INFO ("client %p: received an error %s", client, str);
4228   g_free (str);
4229
4230   return GST_RTSP_OK;
4231 }
4232
4233 static GstRTSPResult
4234 error_full (GstRTSPWatch * watch, GstRTSPResult result,
4235     GstRTSPMessage * message, guint id, gpointer user_data)
4236 {
4237   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4238   gchar *str;
4239
4240   str = gst_rtsp_strresult (result);
4241   GST_INFO
4242       ("client %p: error when handling message %p with id %d: %s",
4243       client, message, id, str);
4244   g_free (str);
4245
4246   return GST_RTSP_OK;
4247 }
4248
4249 static gboolean
4250 remember_tunnel (GstRTSPClient * client)
4251 {
4252   GstRTSPClientPrivate *priv = client->priv;
4253   const gchar *tunnelid;
4254
4255   /* store client in the pending tunnels */
4256   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
4257   if (tunnelid == NULL)
4258     goto no_tunnelid;
4259
4260   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
4261
4262   /* we can't have two clients connecting with the same tunnelid */
4263   g_mutex_lock (&tunnels_lock);
4264   if (g_hash_table_lookup (tunnels, tunnelid))
4265     goto tunnel_existed;
4266
4267   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
4268   g_mutex_unlock (&tunnels_lock);
4269
4270   return TRUE;
4271
4272   /* ERRORS */
4273 no_tunnelid:
4274   {
4275     GST_ERROR ("client %p: no tunnelid provided", client);
4276     return FALSE;
4277   }
4278 tunnel_existed:
4279   {
4280     g_mutex_unlock (&tunnels_lock);
4281     GST_ERROR ("client %p: tunnel session %s already existed", client,
4282         tunnelid);
4283     return FALSE;
4284   }
4285 }
4286
4287 static GstRTSPResult
4288 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
4289 {
4290   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4291   GstRTSPClientPrivate *priv = client->priv;
4292
4293   GST_WARNING ("client %p: tunnel lost (connection %p)", client,
4294       priv->connection);
4295
4296   /* ignore error, it'll only be a problem when the client does a POST again */
4297   remember_tunnel (client);
4298
4299   return GST_RTSP_OK;
4300 }
4301
4302 static gboolean
4303 handle_tunnel (GstRTSPClient * client)
4304 {
4305   GstRTSPClientPrivate *priv = client->priv;
4306   GstRTSPClient *oclient;
4307   GstRTSPClientPrivate *opriv;
4308   const gchar *tunnelid;
4309
4310   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
4311   if (tunnelid == NULL)
4312     goto no_tunnelid;
4313
4314   /* check for previous tunnel */
4315   g_mutex_lock (&tunnels_lock);
4316   oclient = g_hash_table_lookup (tunnels, tunnelid);
4317
4318   if (oclient == NULL) {
4319     /* no previous tunnel, remember tunnel */
4320     g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
4321     g_mutex_unlock (&tunnels_lock);
4322
4323     GST_INFO ("client %p: no previous tunnel found, remembering tunnel (%p)",
4324         client, priv->connection);
4325   } else {
4326     /* merge both tunnels into the first client */
4327     /* remove the old client from the table. ref before because removing it will
4328      * remove the ref to it. */
4329     g_object_ref (oclient);
4330     g_hash_table_remove (tunnels, tunnelid);
4331     g_mutex_unlock (&tunnels_lock);
4332
4333     opriv = oclient->priv;
4334
4335     g_mutex_lock (&opriv->watch_lock);
4336     if (opriv->watch == NULL)
4337       goto tunnel_closed;
4338
4339     GST_INFO ("client %p: found previous tunnel %p (old %p, new %p)", client,
4340         oclient, opriv->connection, priv->connection);
4341
4342     gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
4343     gst_rtsp_watch_reset (priv->watch);
4344     gst_rtsp_watch_reset (opriv->watch);
4345     g_mutex_unlock (&opriv->watch_lock);
4346     g_object_unref (oclient);
4347
4348     /* the old client owns the tunnel now, the new one will be freed */
4349     g_source_destroy ((GSource *) priv->watch);
4350     priv->watch = NULL;
4351     gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
4352   }
4353
4354   return TRUE;
4355
4356   /* ERRORS */
4357 no_tunnelid:
4358   {
4359     GST_ERROR ("client %p: no tunnelid provided", client);
4360     return FALSE;
4361   }
4362 tunnel_closed:
4363   {
4364     GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
4365     g_mutex_unlock (&opriv->watch_lock);
4366     g_object_unref (oclient);
4367     return FALSE;
4368   }
4369 }
4370
4371 static GstRTSPStatusCode
4372 tunnel_get (GstRTSPWatch * watch, gpointer user_data)
4373 {
4374   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4375
4376   GST_INFO ("client %p: tunnel get (connection %p)", client,
4377       client->priv->connection);
4378
4379   if (!handle_tunnel (client)) {
4380     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
4381   }
4382
4383   return GST_RTSP_STS_OK;
4384 }
4385
4386 static GstRTSPResult
4387 tunnel_post (GstRTSPWatch * watch, gpointer user_data)
4388 {
4389   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4390
4391   GST_INFO ("client %p: tunnel post (connection %p)", client,
4392       client->priv->connection);
4393
4394   if (!handle_tunnel (client)) {
4395     return GST_RTSP_ERROR;
4396   }
4397
4398   return GST_RTSP_OK;
4399 }
4400
4401 static GstRTSPResult
4402 tunnel_http_response (GstRTSPWatch * watch, GstRTSPMessage * request,
4403     GstRTSPMessage * response, gpointer user_data)
4404 {
4405   GstRTSPClientClass *klass;
4406
4407   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4408   klass = GST_RTSP_CLIENT_GET_CLASS (client);
4409
4410   if (klass->tunnel_http_response) {
4411     klass->tunnel_http_response (client, request, response);
4412   }
4413
4414   return GST_RTSP_OK;
4415 }
4416
4417 static GstRTSPWatchFuncs watch_funcs = {
4418   message_received,
4419   message_sent,
4420   closed,
4421   error,
4422   tunnel_get,
4423   tunnel_post,
4424   error_full,
4425   tunnel_lost,
4426   tunnel_http_response
4427 };
4428
4429 static void
4430 client_watch_notify (GstRTSPClient * client)
4431 {
4432   GstRTSPClientPrivate *priv = client->priv;
4433   gboolean closed = TRUE;
4434
4435   GST_INFO ("client %p: watch destroyed", client);
4436   priv->watch = NULL;
4437   /* remove all sessions if the media says so and so drop the extra client ref */
4438   rtsp_ctrl_timeout_remove (priv);
4439   gst_rtsp_client_session_filter (client, cleanup_session, &closed);
4440   if (closed)
4441     g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
4442   g_object_unref (client);
4443 }
4444
4445 /**
4446  * gst_rtsp_client_attach:
4447  * @client: a #GstRTSPClient
4448  * @context: (allow-none): a #GMainContext
4449  *
4450  * Attaches @client to @context. When the mainloop for @context is run, the
4451  * client will be dispatched. When @context is %NULL, the default context will be
4452  * used).
4453  *
4454  * This function should be called when the client properties and urls are fully
4455  * configured and the client is ready to start.
4456  *
4457  * Returns: the ID (greater than 0) for the source within the GMainContext.
4458  */
4459 guint
4460 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
4461 {
4462   GstRTSPClientPrivate *priv;
4463   GSource *timer_src;
4464   guint res;
4465
4466   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
4467   priv = client->priv;
4468   g_return_val_if_fail (priv->connection != NULL, 0);
4469   g_return_val_if_fail (priv->watch == NULL, 0);
4470
4471   /* make sure noone will free the context before the watch is destroyed */
4472   priv->watch_context = g_main_context_ref (context);
4473
4474   /* create watch for the connection and attach */
4475   priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
4476       g_object_ref (client), (GDestroyNotify) client_watch_notify);
4477   gst_rtsp_client_set_send_func (client, do_send_message, priv->watch,
4478       (GDestroyNotify) gst_rtsp_watch_unref);
4479
4480   gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
4481
4482   GST_INFO ("client %p: attaching to context %p", client, context);
4483   res = gst_rtsp_watch_attach (priv->watch, context);
4484
4485   /* Setting up a timeout for the RTSP control channel until a session
4486    * is up where it is handling timeouts. */
4487   rtsp_ctrl_timeout_remove (priv);      /* removing old if any */
4488   g_mutex_lock (&priv->lock);
4489
4490   timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL);
4491   g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL);
4492   priv->rtsp_ctrl_timeout_id = g_source_attach (timer_src, priv->watch_context);
4493   g_source_unref (timer_src);
4494   GST_DEBUG ("rtsp control setting up session timeout id=%u.",
4495       priv->rtsp_ctrl_timeout_id);
4496
4497   g_mutex_unlock (&priv->lock);
4498
4499   return res;
4500 }
4501
4502 /**
4503  * gst_rtsp_client_session_filter:
4504  * @client: a #GstRTSPClient
4505  * @func: (scope call) (allow-none): a callback
4506  * @user_data: user data passed to @func
4507  *
4508  * Call @func for each session managed by @client. The result value of @func
4509  * determines what happens to the session. @func will be called with @client
4510  * locked so no further actions on @client can be performed from @func.
4511  *
4512  * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from
4513  * @client.
4514  *
4515  * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @client.
4516  *
4517  * If @func returns #GST_RTSP_FILTER_REF, the session will remain in @client but
4518  * will also be added with an additional ref to the result #GList of this
4519  * function..
4520  *
4521  * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each session.
4522  *
4523  * Returns: (element-type GstRTSPSession) (transfer full): a #GList with all
4524  * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each
4525  * element in the #GList should be unreffed before the list is freed.
4526  */
4527 GList *
4528 gst_rtsp_client_session_filter (GstRTSPClient * client,
4529     GstRTSPClientSessionFilterFunc func, gpointer user_data)
4530 {
4531   GstRTSPClientPrivate *priv;
4532   GList *result, *walk, *next;
4533   GHashTable *visited;
4534   guint cookie;
4535
4536   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4537
4538   priv = client->priv;
4539
4540   result = NULL;
4541   if (func)
4542     visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
4543
4544   g_mutex_lock (&priv->lock);
4545 restart:
4546   cookie = priv->sessions_cookie;
4547   for (walk = priv->sessions; walk; walk = next) {
4548     GstRTSPSession *sess = walk->data;
4549     GstRTSPFilterResult res;
4550     gboolean changed;
4551
4552     next = g_list_next (walk);
4553
4554     if (func) {
4555       /* only visit each session once */
4556       if (g_hash_table_contains (visited, sess))
4557         continue;
4558
4559       g_hash_table_add (visited, g_object_ref (sess));
4560       g_mutex_unlock (&priv->lock);
4561
4562       res = func (client, sess, user_data);
4563
4564       g_mutex_lock (&priv->lock);
4565     } else
4566       res = GST_RTSP_FILTER_REF;
4567
4568     changed = (cookie != priv->sessions_cookie);
4569
4570     switch (res) {
4571       case GST_RTSP_FILTER_REMOVE:
4572         /* stop watching the session and pretend it went away, if the list was
4573          * changed, we can't use the current list position, try to see if we
4574          * still have the session */
4575         client_unwatch_session (client, sess, changed ? NULL : walk);
4576         cookie = priv->sessions_cookie;
4577         break;
4578       case GST_RTSP_FILTER_REF:
4579         result = g_list_prepend (result, g_object_ref (sess));
4580         break;
4581       case GST_RTSP_FILTER_KEEP:
4582       default:
4583         break;
4584     }
4585     if (changed)
4586       goto restart;
4587   }
4588   g_mutex_unlock (&priv->lock);
4589
4590   if (func)
4591     g_hash_table_unref (visited);
4592
4593   return result;
4594 }