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