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