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