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