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