rtsp-client:Error handling when equal http session cookie
[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   GstRTSPResult res = GST_RTSP_OK;
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     res = 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 res == GST_RTSP_OK;
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_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
1830           &blocksize_str, 0) == GST_RTSP_OK) {
1831     guint64 blocksize;
1832     gchar *end;
1833
1834     blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
1835     if (end == blocksize_str)
1836       goto parse_failed;
1837
1838     /* we don't want to change the mtu when this media
1839      * can be shared because it impacts other clients */
1840     if (gst_rtsp_media_is_shared (media))
1841       goto done;
1842
1843     if (blocksize > G_MAXUINT)
1844       blocksize = G_MAXUINT;
1845
1846     gst_rtsp_stream_set_mtu (stream, blocksize);
1847   }
1848 done:
1849   return TRUE;
1850
1851   /* ERRORS */
1852 parse_failed:
1853   {
1854     GST_ERROR_OBJECT (client, "failed to parse blocksize");
1855     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1856     return FALSE;
1857   }
1858 }
1859
1860 static gboolean
1861 default_configure_client_transport (GstRTSPClient * client,
1862     GstRTSPContext * ctx, GstRTSPTransport * ct)
1863 {
1864   GstRTSPClientPrivate *priv = client->priv;
1865
1866   /* we have a valid transport now, set the destination of the client. */
1867   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST ||
1868       ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP) {
1869
1870     /* allocate UDP ports */
1871     GSocketFamily family;
1872     gboolean use_client_settings = FALSE;
1873
1874     family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4;
1875     if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) &&
1876         gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) &&
1877         (ct->destination != NULL))
1878       use_client_settings = TRUE;
1879
1880     if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, family, ct,
1881             use_client_settings))
1882       goto error_allocating_ports;
1883
1884     if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1885       GstRTSPAddress *addr = NULL;
1886
1887       if (use_client_settings) {
1888         /* the address has been successfully allocated, let's check if it's
1889          * the one requested by the client */
1890         addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination,
1891             ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
1892
1893         if (addr == NULL)
1894           goto no_address;
1895       } else {
1896         g_free (ct->destination);
1897         addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family);
1898         if (addr == NULL)
1899           goto no_address;
1900         ct->destination = g_strdup (addr->address);
1901         ct->port.min = addr->port;
1902         ct->port.max = addr->port + addr->n_ports - 1;
1903         ct->ttl = addr->ttl;
1904       }
1905
1906       gst_rtsp_address_free (addr);
1907     } else {
1908       GstRTSPUrl *url;
1909
1910       url = gst_rtsp_connection_get_url (priv->connection);
1911       g_free (ct->destination);
1912       ct->destination = g_strdup (url->host);
1913     }
1914   } else {
1915     GstRTSPUrl *url;
1916
1917     url = gst_rtsp_connection_get_url (priv->connection);
1918     g_free (ct->destination);
1919     ct->destination = g_strdup (url->host);
1920
1921     if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1922       GSocket *sock;
1923       GSocketAddress *addr;
1924
1925       sock = gst_rtsp_connection_get_read_socket (priv->connection);
1926       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1927         /* our read port is the sender port of client */
1928         ct->client_port.min =
1929             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1930         g_object_unref (addr);
1931       }
1932       if ((addr = g_socket_get_local_address (sock, NULL))) {
1933         ct->server_port.max =
1934             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1935         g_object_unref (addr);
1936       }
1937       sock = gst_rtsp_connection_get_write_socket (priv->connection);
1938       if ((addr = g_socket_get_remote_address (sock, NULL))) {
1939         /* our write port is the receiver port of client */
1940         ct->client_port.max =
1941             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1942         g_object_unref (addr);
1943       }
1944       if ((addr = g_socket_get_local_address (sock, NULL))) {
1945         ct->server_port.min =
1946             g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1947         g_object_unref (addr);
1948       }
1949       /* check if the client selected channels for TCP */
1950       if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1951         gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
1952             &ct->interleaved);
1953       }
1954     }
1955   }
1956   return TRUE;
1957
1958   /* ERRORS */
1959 error_allocating_ports:
1960   {
1961     GST_ERROR_OBJECT (client, "Failed to allocate UDP ports");
1962     return FALSE;
1963   }
1964 no_address:
1965   {
1966     GST_ERROR_OBJECT (client, "Failed to acquire address for stream");
1967     return FALSE;
1968   }
1969 }
1970
1971 static GstRTSPTransport *
1972 make_server_transport (GstRTSPClient * client, GstRTSPMedia * media,
1973     GstRTSPContext * ctx, GstRTSPTransport * ct)
1974 {
1975   GstRTSPTransport *st;
1976   GInetAddress *addr;
1977   GSocketFamily family;
1978
1979   /* prepare the server transport */
1980   gst_rtsp_transport_new (&st);
1981
1982   st->trans = ct->trans;
1983   st->profile = ct->profile;
1984   st->lower_transport = ct->lower_transport;
1985   st->mode_play = ct->mode_play;
1986   st->mode_record = ct->mode_record;
1987
1988   addr = g_inet_address_new_from_string (ct->destination);
1989
1990   if (!addr) {
1991     GST_ERROR ("failed to get inet addr from client destination");
1992     family = G_SOCKET_FAMILY_IPV4;
1993   } else {
1994     family = g_inet_address_get_family (addr);
1995     g_object_unref (addr);
1996     addr = NULL;
1997   }
1998
1999   switch (st->lower_transport) {
2000     case GST_RTSP_LOWER_TRANS_UDP:
2001       st->client_port = ct->client_port;
2002       gst_rtsp_stream_get_server_port (ctx->stream, &st->server_port, family);
2003       break;
2004     case GST_RTSP_LOWER_TRANS_UDP_MCAST:
2005       st->port = ct->port;
2006       st->destination = g_strdup (ct->destination);
2007       st->ttl = ct->ttl;
2008       break;
2009     case GST_RTSP_LOWER_TRANS_TCP:
2010       st->interleaved = ct->interleaved;
2011       st->client_port = ct->client_port;
2012       st->server_port = ct->server_port;
2013     default:
2014       break;
2015   }
2016
2017   if ((gst_rtsp_media_get_transport_mode (media) &
2018           GST_RTSP_TRANSPORT_MODE_PLAY))
2019     gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc);
2020
2021   return st;
2022 }
2023
2024 #define AES_128_KEY_LEN 16
2025 #define AES_256_KEY_LEN 32
2026
2027 #define HMAC_32_KEY_LEN 4
2028 #define HMAC_80_KEY_LEN 10
2029
2030 static gboolean
2031 mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy)
2032 {
2033   const gchar *srtp_cipher;
2034   const gchar *srtp_auth;
2035   const GstMIKEYPayload *sp;
2036   guint i;
2037
2038   /* loop over Security policy until we find one containing policy */
2039   for (i = 0;; i++) {
2040     if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL)
2041       break;
2042
2043     if (((GstMIKEYPayloadSP *) sp)->policy == policy)
2044       break;
2045   }
2046
2047   /* the default ciphers */
2048   srtp_cipher = "aes-128-icm";
2049   srtp_auth = "hmac-sha1-80";
2050
2051   /* now override the defaults with what is in the Security Policy */
2052   if (sp != NULL) {
2053     guint len;
2054
2055     /* collect all the params and go over them */
2056     len = gst_mikey_payload_sp_get_n_params (sp);
2057     for (i = 0; i < len; i++) {
2058       const GstMIKEYPayloadSPParam *param =
2059           gst_mikey_payload_sp_get_param (sp, i);
2060
2061       switch (param->type) {
2062         case GST_MIKEY_SP_SRTP_ENC_ALG:
2063           switch (param->val[0]) {
2064             case 0:
2065               srtp_cipher = "null";
2066               break;
2067             case 2:
2068             case 1:
2069               srtp_cipher = "aes-128-icm";
2070               break;
2071             default:
2072               break;
2073           }
2074           break;
2075         case GST_MIKEY_SP_SRTP_ENC_KEY_LEN:
2076           switch (param->val[0]) {
2077             case AES_128_KEY_LEN:
2078               srtp_cipher = "aes-128-icm";
2079               break;
2080             case AES_256_KEY_LEN:
2081               srtp_cipher = "aes-256-icm";
2082               break;
2083             default:
2084               break;
2085           }
2086           break;
2087         case GST_MIKEY_SP_SRTP_AUTH_ALG:
2088           switch (param->val[0]) {
2089             case 0:
2090               srtp_auth = "null";
2091               break;
2092             case 2:
2093             case 1:
2094               srtp_auth = "hmac-sha1-80";
2095               break;
2096             default:
2097               break;
2098           }
2099           break;
2100         case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN:
2101           switch (param->val[0]) {
2102             case HMAC_32_KEY_LEN:
2103               srtp_auth = "hmac-sha1-32";
2104               break;
2105             case HMAC_80_KEY_LEN:
2106               srtp_auth = "hmac-sha1-80";
2107               break;
2108             default:
2109               break;
2110           }
2111           break;
2112         case GST_MIKEY_SP_SRTP_SRTP_ENC:
2113           break;
2114         case GST_MIKEY_SP_SRTP_SRTCP_ENC:
2115           break;
2116         default:
2117           break;
2118       }
2119     }
2120   }
2121   /* now configure the SRTP parameters */
2122   gst_caps_set_simple (caps,
2123       "srtp-cipher", G_TYPE_STRING, srtp_cipher,
2124       "srtp-auth", G_TYPE_STRING, srtp_auth,
2125       "srtcp-cipher", G_TYPE_STRING, srtp_cipher,
2126       "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
2127
2128   return TRUE;
2129 }
2130
2131 static gboolean
2132 handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx,
2133     guint8 * data, gsize size)
2134 {
2135   GstMIKEYMessage *msg;
2136   guint i, n_cs;
2137   GstCaps *caps = NULL;
2138   GstMIKEYPayloadKEMAC *kemac;
2139   const GstMIKEYPayloadKeyData *pkd;
2140   GstBuffer *key;
2141
2142   /* the MIKEY message contains a CSB or crypto session bundle. It is a
2143    * set of Crypto Sessions protected with the same master key.
2144    * In the context of SRTP, an RTP and its RTCP stream is part of a
2145    * crypto session */
2146   if ((msg = gst_mikey_message_new_from_data (data, size, NULL, NULL)) == NULL)
2147     goto parse_failed;
2148
2149   /* we can only handle SRTP crypto sessions for now */
2150   if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP)
2151     goto invalid_map_type;
2152
2153   /* get the number of crypto sessions. This maps SSRC to its
2154    * security parameters */
2155   n_cs = gst_mikey_message_get_n_cs (msg);
2156   if (n_cs == 0)
2157     goto no_crypto_sessions;
2158
2159   /* we also need keys */
2160   if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload
2161           (msg, GST_MIKEY_PT_KEMAC, 0)))
2162     goto no_keys;
2163
2164   /* we don't support encrypted keys */
2165   if (kemac->enc_alg != GST_MIKEY_ENC_NULL
2166       || kemac->mac_alg != GST_MIKEY_MAC_NULL)
2167     goto unsupported_encryption;
2168
2169   /* get Key data sub-payload */
2170   pkd = (const GstMIKEYPayloadKeyData *)
2171       gst_mikey_payload_kemac_get_sub (&kemac->pt, 0);
2172
2173   key =
2174       gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
2175       pkd->key_len);
2176
2177   /* go over all crypto sessions and create the security policy for each
2178    * SSRC */
2179   for (i = 0; i < n_cs; i++) {
2180     const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i);
2181
2182     caps = gst_caps_new_simple ("application/x-srtp",
2183         "ssrc", G_TYPE_UINT, map->ssrc,
2184         "roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL);
2185     mikey_apply_policy (caps, msg, map->policy);
2186
2187     gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps);
2188     gst_caps_unref (caps);
2189   }
2190   gst_mikey_message_unref (msg);
2191   gst_buffer_unref (key);
2192
2193   return TRUE;
2194
2195   /* ERRORS */
2196 parse_failed:
2197   {
2198     GST_DEBUG_OBJECT (client, "failed to parse MIKEY message");
2199     return FALSE;
2200   }
2201 invalid_map_type:
2202   {
2203     GST_DEBUG_OBJECT (client, "invalid map type %d", msg->map_type);
2204     goto cleanup_message;
2205   }
2206 no_crypto_sessions:
2207   {
2208     GST_DEBUG_OBJECT (client, "no crypto sessions");
2209     goto cleanup_message;
2210   }
2211 no_keys:
2212   {
2213     GST_DEBUG_OBJECT (client, "no keys found");
2214     goto cleanup_message;
2215   }
2216 unsupported_encryption:
2217   {
2218     GST_DEBUG_OBJECT (client, "unsupported key encryption");
2219     goto cleanup_message;
2220   }
2221 cleanup_message:
2222   {
2223     gst_mikey_message_unref (msg);
2224     return FALSE;
2225   }
2226 }
2227
2228 #define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"'))
2229
2230 static void
2231 strip_chars (gchar * str)
2232 {
2233   gchar *s;
2234   gsize len;
2235
2236   len = strlen (str);
2237   while (len--) {
2238     if (!IS_STRIP_CHAR (str[len]))
2239       break;
2240     str[len] = '\0';
2241   }
2242   for (s = str; *s && IS_STRIP_CHAR (*s); s++);
2243   memmove (str, s, len + 1);
2244 }
2245
2246 /* KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec)
2247  * key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"]
2248  */
2249 static gboolean
2250 handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt)
2251 {
2252   gchar **specs;
2253   gint i, j;
2254
2255   specs = g_strsplit (keymgmt, ",", 0);
2256   for (i = 0; specs[i]; i++) {
2257     gchar **split;
2258
2259     split = g_strsplit (specs[i], ";", 0);
2260     for (j = 0; split[j]; j++) {
2261       g_strstrip (split[j]);
2262       if (g_str_has_prefix (split[j], "prot=")) {
2263         g_strstrip (split[j] + 5);
2264         if (!g_str_equal (split[j] + 5, "mikey"))
2265           break;
2266         GST_DEBUG ("found mikey");
2267       } else if (g_str_has_prefix (split[j], "uri=")) {
2268         strip_chars (split[j] + 4);
2269         GST_DEBUG ("found uri '%s'", split[j] + 4);
2270       } else if (g_str_has_prefix (split[j], "data=")) {
2271         guchar *data;
2272         gsize size;
2273         strip_chars (split[j] + 5);
2274         GST_DEBUG ("found data '%s'", split[j] + 5);
2275         data = g_base64_decode_inplace (split[j] + 5, &size);
2276         handle_mikey_data (client, ctx, data, size);
2277       }
2278     }
2279     g_strfreev (split);
2280   }
2281   g_strfreev (specs);
2282   return TRUE;
2283 }
2284
2285 static gboolean
2286 rtsp_ctrl_timeout_cb (gpointer user_data)
2287 {
2288   gboolean res = G_SOURCE_CONTINUE;
2289   GstRTSPClient *client = (GstRTSPClient *) user_data;
2290   GstRTSPClientPrivate *priv = client->priv;
2291
2292   priv->rtsp_ctrl_timeout_cnt += RTSP_CTRL_CB_INTERVAL;
2293
2294   if (priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE) {
2295     GST_DEBUG ("rtsp control session timeout id=%u expired, closing client.",
2296         priv->rtsp_ctrl_timeout_id);
2297     g_mutex_lock (&priv->lock);
2298     priv->rtsp_ctrl_timeout_id = 0;
2299     priv->rtsp_ctrl_timeout_cnt = 0;
2300     g_mutex_unlock (&priv->lock);
2301     gst_rtsp_client_close (client);
2302
2303     res = G_SOURCE_REMOVE;
2304   }
2305
2306   return res;
2307 }
2308
2309 static void
2310 rtsp_ctrl_timeout_remove (GstRTSPClientPrivate * priv)
2311 {
2312   g_mutex_lock (&priv->lock);
2313
2314   if (priv->rtsp_ctrl_timeout_id != 0) {
2315     g_source_destroy (g_main_context_find_source_by_id (priv->watch_context,
2316             priv->rtsp_ctrl_timeout_id));
2317     GST_DEBUG ("rtsp control session removed timeout id=%u.",
2318         priv->rtsp_ctrl_timeout_id);
2319     priv->rtsp_ctrl_timeout_id = 0;
2320     priv->rtsp_ctrl_timeout_cnt = 0;
2321   }
2322
2323   g_mutex_unlock (&priv->lock);
2324 }
2325
2326 static gboolean
2327 handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
2328 {
2329   GstRTSPClientPrivate *priv = client->priv;
2330   GstRTSPResult res;
2331   GstRTSPUrl *uri;
2332   gchar *transport, *keymgmt;
2333   GstRTSPTransport *ct, *st;
2334   GstRTSPStatusCode code;
2335   GstRTSPSession *session;
2336   GstRTSPStreamTransport *trans;
2337   gchar *trans_str;
2338   GstRTSPSessionMedia *sessmedia;
2339   GstRTSPMedia *media;
2340   GstRTSPStream *stream;
2341   GstRTSPState rtspstate;
2342   GstRTSPClientClass *klass;
2343   gchar *path, *control = NULL;
2344   gint matched;
2345   gboolean new_session = FALSE;
2346   GstRTSPStatusCode sig_result;
2347   gchar *pipelined_request_id = NULL, *accept_range = NULL;
2348
2349   if (!ctx->uri)
2350     goto no_uri;
2351
2352   uri = ctx->uri;
2353   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2354   path = klass->make_path_from_uri (client, uri);
2355
2356   /* parse the transport */
2357   res =
2358       gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_TRANSPORT,
2359       &transport, 0);
2360   if (res != GST_RTSP_OK)
2361     goto no_transport;
2362
2363   /* Handle Pipelined-requests if using >= 2.0 */
2364   if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0)
2365     gst_rtsp_message_get_header (ctx->request,
2366         GST_RTSP_HDR_PIPELINED_REQUESTS, &pipelined_request_id, 0);
2367
2368   /* we create the session after parsing stuff so that we don't make
2369    * a session for malformed requests */
2370   if (priv->session_pool == NULL)
2371     goto no_pool;
2372
2373   session = ctx->session;
2374
2375   if (session) {
2376     g_object_ref (session);
2377     /* get a handle to the configuration of the media in the session, this can
2378      * return NULL if this is a new url to manage in this session. */
2379     sessmedia = gst_rtsp_session_get_media (session, path, &matched);
2380   } else {
2381     /* we need a new media configuration in this session */
2382     sessmedia = NULL;
2383   }
2384
2385   /* we have no session media, find one and manage it */
2386   if (sessmedia == NULL) {
2387     /* get a handle to the configuration of the media in the session */
2388     media = find_media (client, ctx, path, &matched);
2389     /* need to suspend the media, if the protocol has changed */
2390     if (media != NULL)
2391       gst_rtsp_media_suspend (media);
2392   } else {
2393     if ((media = gst_rtsp_session_media_get_media (sessmedia)))
2394       g_object_ref (media);
2395     else
2396       goto media_not_found;
2397   }
2398   /* no media, not found then */
2399   if (media == NULL)
2400     goto media_not_found_no_reply;
2401
2402   if (path[matched] == '\0') {
2403     if (gst_rtsp_media_n_streams (media) == 1) {
2404       stream = gst_rtsp_media_get_stream (media, 0);
2405     } else {
2406       goto control_not_found;
2407     }
2408   } else {
2409     /* path is what matched. */
2410     path[matched] = '\0';
2411     /* control is remainder */
2412     control = &path[matched + 1];
2413
2414     /* find the stream now using the control part */
2415     stream = gst_rtsp_media_find_stream (media, control);
2416   }
2417
2418   if (stream == NULL)
2419     goto stream_not_found;
2420
2421   /* now we have a uri identifying a valid media and stream */
2422   ctx->stream = stream;
2423   ctx->media = media;
2424
2425   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST], 0,
2426       ctx, &sig_result);
2427   if (sig_result != GST_RTSP_STS_OK) {
2428     goto sig_failed;
2429   }
2430
2431   if (session == NULL) {
2432     /* create a session if this fails we probably reached our session limit or
2433      * something. */
2434     if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
2435       goto service_unavailable;
2436
2437     /* Pipelined requests should be cleared between sessions */
2438     g_hash_table_remove_all (priv->pipelined_requests);
2439
2440     /* make sure this client is closed when the session is closed */
2441     client_watch_session (client, session);
2442
2443     new_session = TRUE;
2444     /* signal new session */
2445     g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
2446         session);
2447
2448     ctx->session = session;
2449   }
2450
2451   if (pipelined_request_id) {
2452     g_hash_table_insert (client->priv->pipelined_requests,
2453         g_strdup (pipelined_request_id),
2454         g_strdup (gst_rtsp_session_get_sessionid (session)));
2455   }
2456   rtsp_ctrl_timeout_remove (priv);
2457
2458   if (!klass->configure_client_media (client, media, stream, ctx))
2459     goto configure_media_failed_no_reply;
2460
2461   gst_rtsp_transport_new (&ct);
2462
2463   /* parse and find a usable supported transport */
2464   if (!parse_transport (transport, stream, ct))
2465     goto unsupported_transports;
2466
2467   if ((ct->mode_play
2468           && !(gst_rtsp_media_get_transport_mode (media) &
2469               GST_RTSP_TRANSPORT_MODE_PLAY)) || (ct->mode_record
2470           && !(gst_rtsp_media_get_transport_mode (media) &
2471               GST_RTSP_TRANSPORT_MODE_RECORD)))
2472     goto unsupported_mode;
2473
2474   /* parse the keymgmt */
2475   if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT,
2476           &keymgmt, 0) == GST_RTSP_OK) {
2477     if (!handle_keymgmt (client, ctx, keymgmt))
2478       goto keymgmt_error;
2479   }
2480
2481   if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
2482           &accept_range, 0) == GST_RTSP_OK) {
2483     GEnumValue *runit = NULL;
2484     gint i;
2485     gchar **valid_ranges;
2486     GEnumClass *runit_class = g_type_class_ref (GST_TYPE_RTSP_RANGE_UNIT);
2487
2488     gst_rtsp_message_dump (ctx->request);
2489     valid_ranges = g_strsplit (accept_range, ",", -1);
2490
2491     for (i = 0; valid_ranges[i]; i++) {
2492       gchar *range = valid_ranges[i];
2493
2494       while (*range == ' ')
2495         range++;
2496
2497       runit = g_enum_get_value_by_nick (runit_class, range);
2498       if (runit)
2499         break;
2500     }
2501     g_strfreev (valid_ranges);
2502     g_type_class_unref (runit_class);
2503
2504     if (!runit)
2505       goto unsupported_range_unit;
2506   }
2507
2508   if (sessmedia == NULL) {
2509     /* manage the media in our session now, if not done already  */
2510     sessmedia =
2511         gst_rtsp_session_manage_media (session, path, g_object_ref (media));
2512     /* if we stil have no media, error */
2513     if (sessmedia == NULL)
2514       goto sessmedia_unavailable;
2515
2516     /* don't cache media anymore */
2517     clean_cached_media (client, FALSE);
2518   }
2519
2520   ctx->sessmedia = sessmedia;
2521
2522   /* update the client transport */
2523   if (!klass->configure_client_transport (client, ctx, ct))
2524     goto unsupported_client_transport;
2525
2526   /* set in the session media transport */
2527   trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
2528
2529   ctx->trans = trans;
2530
2531   /* configure the url used to set this transport, this we will use when
2532    * generating the response for the PLAY request */
2533   gst_rtsp_stream_transport_set_url (trans, uri);
2534   /* configure keepalive for this transport */
2535   gst_rtsp_stream_transport_set_keepalive (trans,
2536       (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
2537
2538   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
2539     /* our callbacks to send data on this TCP connection */
2540     gst_rtsp_stream_transport_set_callbacks (trans,
2541         (GstRTSPSendFunc) do_send_data,
2542         (GstRTSPSendFunc) do_send_data, client, NULL);
2543
2544     g_hash_table_insert (priv->transports,
2545         GINT_TO_POINTER (ct->interleaved.min), trans);
2546     g_object_ref (trans);
2547     g_hash_table_insert (priv->transports,
2548         GINT_TO_POINTER (ct->interleaved.max), trans);
2549     g_object_ref (trans);
2550   }
2551
2552   /* create and serialize the server transport */
2553   st = make_server_transport (client, media, ctx, ct);
2554   trans_str = gst_rtsp_transport_as_text (st);
2555   gst_rtsp_transport_free (st);
2556
2557   /* construct the response now */
2558   code = GST_RTSP_STS_OK;
2559   gst_rtsp_message_init_response (ctx->response, code,
2560       gst_rtsp_status_as_text (code), ctx->request);
2561
2562   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_TRANSPORT,
2563       trans_str);
2564   g_free (trans_str);
2565
2566   if (pipelined_request_id)
2567     gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PIPELINED_REQUESTS,
2568         pipelined_request_id);
2569
2570   if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) {
2571     GstClockTimeDiff seekable = gst_rtsp_media_seekable (media);
2572     GString *media_properties = g_string_new (NULL);
2573
2574     if (seekable == -1)
2575       g_string_append (media_properties,
2576           "No-Seeking,Time-Progressing,Time-Duration=0.0");
2577     else if (seekable == 0)
2578       g_string_append (media_properties, "Beginning-Only");
2579     else if (seekable == G_MAXINT64)
2580       g_string_append (media_properties, "Random-Access");
2581     else
2582       g_string_append_printf (media_properties,
2583           "Random-Access=%f, Unlimited, Immutable",
2584           (gdouble) seekable / GST_SECOND);
2585
2586     gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_MEDIA_PROPERTIES,
2587         g_string_free (media_properties, FALSE));
2588     /* TODO Check how Accept-Ranges should be filled */
2589     gst_rtsp_message_add_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
2590         "npt, clock, smpte, clock");
2591   }
2592
2593   send_message (client, ctx, ctx->response, FALSE);
2594
2595   /* update the state */
2596   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
2597   switch (rtspstate) {
2598     case GST_RTSP_STATE_PLAYING:
2599     case GST_RTSP_STATE_RECORDING:
2600     case GST_RTSP_STATE_READY:
2601       /* no state change */
2602       break;
2603     default:
2604       gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
2605       break;
2606   }
2607   g_object_unref (media);
2608   g_object_unref (session);
2609   g_free (path);
2610
2611   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx);
2612
2613   return TRUE;
2614
2615   /* ERRORS */
2616 no_uri:
2617   {
2618     GST_ERROR ("client %p: no uri", client);
2619     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2620     return FALSE;
2621   }
2622 no_transport:
2623   {
2624     GST_ERROR ("client %p: no transport", client);
2625     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2626     goto cleanup_path;
2627   }
2628 no_pool:
2629   {
2630     GST_ERROR ("client %p: no session pool configured", client);
2631     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2632     goto cleanup_path;
2633   }
2634 media_not_found_no_reply:
2635   {
2636     GST_ERROR ("client %p: media '%s' not found", client, path);
2637     /* error reply is already sent */
2638     goto cleanup_session;
2639   }
2640 media_not_found:
2641   {
2642     GST_ERROR ("client %p: media '%s' not found", client, path);
2643     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2644     goto cleanup_session;
2645   }
2646 control_not_found:
2647   {
2648     GST_ERROR ("client %p: no control in path '%s'", client, path);
2649     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2650     g_object_unref (media);
2651     goto cleanup_session;
2652   }
2653 stream_not_found:
2654   {
2655     GST_ERROR ("client %p: stream '%s' not found", client,
2656         GST_STR_NULL (control));
2657     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2658     g_object_unref (media);
2659     goto cleanup_session;
2660   }
2661 sig_failed:
2662   {
2663     GST_ERROR ("client %p: pre signal returned error: %s", client,
2664         gst_rtsp_status_as_text (sig_result));
2665     send_generic_response (client, sig_result, ctx);
2666     g_object_unref (media);
2667     goto cleanup_path;
2668   }
2669 service_unavailable:
2670   {
2671     GST_ERROR ("client %p: can't create session", client);
2672     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2673     g_object_unref (media);
2674     goto cleanup_session;
2675   }
2676 sessmedia_unavailable:
2677   {
2678     GST_ERROR ("client %p: can't create session media", client);
2679     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2680     goto cleanup_transport;
2681   }
2682 configure_media_failed_no_reply:
2683   {
2684     GST_ERROR ("client %p: configure_media failed", client);
2685     g_object_unref (media);
2686     /* error reply is already sent */
2687     goto cleanup_session;
2688   }
2689 unsupported_transports:
2690   {
2691     GST_ERROR ("client %p: unsupported transports", client);
2692     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2693     goto cleanup_transport;
2694   }
2695 unsupported_client_transport:
2696   {
2697     GST_ERROR ("client %p: unsupported client transport", client);
2698     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2699     goto cleanup_transport;
2700   }
2701 unsupported_mode:
2702   {
2703     GST_ERROR ("client %p: unsupported mode (media play: %d, media record: %d, "
2704         "mode play: %d, mode record: %d)", client,
2705         ! !(gst_rtsp_media_get_transport_mode (media) &
2706             GST_RTSP_TRANSPORT_MODE_PLAY),
2707         ! !(gst_rtsp_media_get_transport_mode (media) &
2708             GST_RTSP_TRANSPORT_MODE_RECORD), ct->mode_play, ct->mode_record);
2709     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
2710     goto cleanup_transport;
2711   }
2712 unsupported_range_unit:
2713   {
2714     GST_ERROR ("Client %p: does not support any range format we support",
2715         client);
2716     send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
2717     goto cleanup_transport;
2718   }
2719 keymgmt_error:
2720   {
2721     GST_ERROR ("client %p: keymgmt error", client);
2722     send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx);
2723     goto cleanup_transport;
2724   }
2725   {
2726   cleanup_transport:
2727     gst_rtsp_transport_free (ct);
2728     if (media)
2729       g_object_unref (media);
2730   cleanup_session:
2731     if (new_session)
2732       gst_rtsp_session_pool_remove (priv->session_pool, session);
2733     if (session)
2734       g_object_unref (session);
2735   cleanup_path:
2736     g_free (path);
2737     return FALSE;
2738   }
2739 }
2740
2741 static GstSDPMessage *
2742 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
2743 {
2744   GstRTSPClientPrivate *priv = client->priv;
2745   GstSDPMessage *sdp;
2746   GstSDPInfo info;
2747   const gchar *proto;
2748   guint64 session_id_tmp;
2749   gchar session_id[21];
2750
2751   gst_sdp_message_new (&sdp);
2752
2753   /* some standard things first */
2754   gst_sdp_message_set_version (sdp, "0");
2755
2756   if (priv->is_ipv6)
2757     proto = "IP6";
2758   else
2759     proto = "IP4";
2760
2761   session_id_tmp = (((guint64) g_random_int ()) << 32) | g_random_int ();
2762   g_snprintf (session_id, sizeof (session_id), "%" G_GUINT64_FORMAT,
2763       session_id_tmp);
2764
2765   gst_sdp_message_set_origin (sdp, "-", session_id, "1", "IN", proto,
2766       priv->server_ip);
2767
2768   gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
2769   gst_sdp_message_set_information (sdp, "rtsp-server");
2770   gst_sdp_message_add_time (sdp, "0", "0", NULL);
2771   gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
2772   gst_sdp_message_add_attribute (sdp, "type", "broadcast");
2773   gst_sdp_message_add_attribute (sdp, "control", "*");
2774
2775   info.is_ipv6 = priv->is_ipv6;
2776   info.server_ip = priv->server_ip;
2777
2778   /* create an SDP for the media object */
2779   if (!gst_rtsp_media_setup_sdp (media, sdp, &info))
2780     goto no_sdp;
2781
2782   return sdp;
2783
2784   /* ERRORS */
2785 no_sdp:
2786   {
2787     GST_ERROR ("client %p: could not create SDP", client);
2788     gst_sdp_message_free (sdp);
2789     return NULL;
2790   }
2791 }
2792
2793 /* for the describe we must generate an SDP */
2794 static gboolean
2795 handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx)
2796 {
2797   GstRTSPClientPrivate *priv = client->priv;
2798   GstRTSPResult res;
2799   GstSDPMessage *sdp;
2800   guint i;
2801   gchar *path, *str;
2802   GstRTSPMedia *media;
2803   GstRTSPClientClass *klass;
2804   GstRTSPStatusCode sig_result;
2805
2806   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2807
2808   if (!ctx->uri)
2809     goto no_uri;
2810
2811   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST],
2812       0, ctx, &sig_result);
2813   if (sig_result != GST_RTSP_STS_OK) {
2814     goto sig_failed;
2815   }
2816
2817   /* check what kind of format is accepted, we don't really do anything with it
2818    * and always return SDP for now. */
2819   for (i = 0;; i++) {
2820     gchar *accept;
2821
2822     res =
2823         gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT,
2824         &accept, i);
2825     if (res == GST_RTSP_ENOTIMPL)
2826       break;
2827
2828     if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
2829       break;
2830   }
2831
2832   if (!priv->mount_points)
2833     goto no_mount_points;
2834
2835   if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
2836     goto no_path;
2837
2838   /* find the media object for the uri */
2839   if (!(media = find_media (client, ctx, path, NULL)))
2840     goto no_media;
2841
2842   if (!(gst_rtsp_media_get_transport_mode (media) &
2843           GST_RTSP_TRANSPORT_MODE_PLAY))
2844     goto unsupported_mode;
2845
2846   /* create an SDP for the media object on this client */
2847   if (!(sdp = klass->create_sdp (client, media)))
2848     goto no_sdp;
2849
2850   /* we suspend after the describe */
2851   gst_rtsp_media_suspend (media);
2852   g_object_unref (media);
2853
2854   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
2855       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
2856
2857   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_TYPE,
2858       "application/sdp");
2859
2860   /* content base for some clients that might screw up creating the setup uri */
2861   str = make_base_url (client, ctx->uri, path);
2862   g_free (path);
2863
2864   GST_INFO ("adding content-base: %s", str);
2865   gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, str);
2866
2867   /* add SDP to the response body */
2868   str = gst_sdp_message_as_text (sdp);
2869   gst_rtsp_message_take_body (ctx->response, (guint8 *) str, strlen (str));
2870   gst_sdp_message_free (sdp);
2871
2872   send_message (client, ctx, ctx->response, FALSE);
2873
2874   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
2875       0, ctx);
2876
2877   return TRUE;
2878
2879   /* ERRORS */
2880 sig_failed:
2881   {
2882     GST_ERROR ("client %p: pre signal returned error: %s", client,
2883         gst_rtsp_status_as_text (sig_result));
2884     send_generic_response (client, sig_result, ctx);
2885     return FALSE;
2886   }
2887 no_uri:
2888   {
2889     GST_ERROR ("client %p: no uri", client);
2890     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2891     return FALSE;
2892   }
2893 no_mount_points:
2894   {
2895     GST_ERROR ("client %p: no mount points configured", client);
2896     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2897     return FALSE;
2898   }
2899 no_path:
2900   {
2901     GST_ERROR ("client %p: can't find path for url", client);
2902     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2903     return FALSE;
2904   }
2905 no_media:
2906   {
2907     GST_ERROR ("client %p: no media", client);
2908     g_free (path);
2909     /* error reply is already sent */
2910     return FALSE;
2911   }
2912 unsupported_mode:
2913   {
2914     GST_ERROR ("client %p: media does not support DESCRIBE", client);
2915     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
2916     g_free (path);
2917     g_object_unref (media);
2918     return FALSE;
2919   }
2920 no_sdp:
2921   {
2922     GST_ERROR ("client %p: can't create SDP", client);
2923     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2924     g_free (path);
2925     g_object_unref (media);
2926     return FALSE;
2927   }
2928 }
2929
2930 static gboolean
2931 handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPMedia * media,
2932     GstSDPMessage * sdp)
2933 {
2934   GstRTSPClientPrivate *priv = client->priv;
2935   GstRTSPThread *thread;
2936
2937   /* create an SDP for the media object */
2938   if (!gst_rtsp_media_handle_sdp (media, sdp))
2939     goto unhandled_sdp;
2940
2941   thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool,
2942       GST_RTSP_THREAD_TYPE_MEDIA, ctx);
2943   if (thread == NULL)
2944     goto no_thread;
2945
2946   /* prepare the media */
2947   if (!gst_rtsp_media_prepare (media, thread))
2948     goto no_prepare;
2949
2950   return TRUE;
2951
2952   /* ERRORS */
2953 unhandled_sdp:
2954   {
2955     GST_ERROR ("client %p: could not handle SDP", client);
2956     return FALSE;
2957   }
2958 no_thread:
2959   {
2960     GST_ERROR ("client %p: can't create thread", client);
2961     return FALSE;
2962   }
2963 no_prepare:
2964   {
2965     GST_ERROR ("client %p: can't prepare media", client);
2966     return FALSE;
2967   }
2968 }
2969
2970 static gboolean
2971 handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx)
2972 {
2973   GstRTSPClientPrivate *priv = client->priv;
2974   GstRTSPClientClass *klass;
2975   GstSDPResult sres;
2976   GstSDPMessage *sdp;
2977   GstRTSPMedia *media;
2978   gchar *path, *cont = NULL;
2979   guint8 *data;
2980   guint size;
2981   GstRTSPStatusCode sig_result;
2982
2983   klass = GST_RTSP_CLIENT_GET_CLASS (client);
2984
2985   if (!ctx->uri)
2986     goto no_uri;
2987
2988   if (!priv->mount_points)
2989     goto no_mount_points;
2990
2991   /* check if reply is SDP */
2992   gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_CONTENT_TYPE, &cont,
2993       0);
2994   /* could not be set but since the request returned OK, we assume it
2995    * was SDP, else check it. */
2996   if (cont) {
2997     if (g_ascii_strcasecmp (cont, "application/sdp") != 0)
2998       goto wrong_content_type;
2999   }
3000
3001   /* get message body and parse as SDP */
3002   gst_rtsp_message_get_body (ctx->request, &data, &size);
3003   if (data == NULL || size == 0)
3004     goto no_message;
3005
3006   GST_DEBUG ("client %p: parse SDP...", client);
3007   gst_sdp_message_new (&sdp);
3008   sres = gst_sdp_message_parse_buffer (data, size, sdp);
3009   if (sres != GST_SDP_OK)
3010     goto sdp_parse_failed;
3011
3012   if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
3013     goto no_path;
3014
3015   /* find the media object for the uri */
3016   if (!(media = find_media (client, ctx, path, NULL)))
3017     goto no_media;
3018
3019   ctx->media = media;
3020
3021   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST],
3022       0, ctx, &sig_result);
3023   if (sig_result != GST_RTSP_STS_OK) {
3024     goto sig_failed;
3025   }
3026
3027   if (!(gst_rtsp_media_get_transport_mode (media) &
3028           GST_RTSP_TRANSPORT_MODE_RECORD))
3029     goto unsupported_mode;
3030
3031   /* Tell client subclass about the media */
3032   if (!klass->handle_sdp (client, ctx, media, sdp))
3033     goto unhandled_sdp;
3034
3035   /* we suspend after the announce */
3036   gst_rtsp_media_suspend (media);
3037   g_object_unref (media);
3038
3039   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3040       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3041
3042   send_message (client, ctx, ctx->response, FALSE);
3043
3044   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST],
3045       0, ctx);
3046
3047   gst_sdp_message_free (sdp);
3048   g_free (path);
3049   return TRUE;
3050
3051 no_uri:
3052   {
3053     GST_ERROR ("client %p: no uri", client);
3054     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3055     return FALSE;
3056   }
3057 no_mount_points:
3058   {
3059     GST_ERROR ("client %p: no mount points configured", client);
3060     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3061     return FALSE;
3062   }
3063 no_path:
3064   {
3065     GST_ERROR ("client %p: can't find path for url", client);
3066     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3067     gst_sdp_message_free (sdp);
3068     return FALSE;
3069   }
3070 wrong_content_type:
3071   {
3072     GST_ERROR ("client %p: unknown content type", client);
3073     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3074     return FALSE;
3075   }
3076 no_message:
3077   {
3078     GST_ERROR ("client %p: can't find SDP message", client);
3079     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3080     return FALSE;
3081   }
3082 sdp_parse_failed:
3083   {
3084     GST_ERROR ("client %p: failed to parse SDP message", client);
3085     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3086     gst_sdp_message_free (sdp);
3087     return FALSE;
3088   }
3089 no_media:
3090   {
3091     GST_ERROR ("client %p: no media", client);
3092     g_free (path);
3093     /* error reply is already sent */
3094     gst_sdp_message_free (sdp);
3095     return FALSE;
3096   }
3097 sig_failed:
3098   {
3099     GST_ERROR ("client %p: pre signal returned error: %s", client,
3100         gst_rtsp_status_as_text (sig_result));
3101     send_generic_response (client, sig_result, ctx);
3102     gst_sdp_message_free (sdp);
3103     return FALSE;
3104   }
3105 unsupported_mode:
3106   {
3107     GST_ERROR ("client %p: media does not support ANNOUNCE", client);
3108     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
3109     g_free (path);
3110     g_object_unref (media);
3111     gst_sdp_message_free (sdp);
3112     return FALSE;
3113   }
3114 unhandled_sdp:
3115   {
3116     GST_ERROR ("client %p: can't handle SDP", client);
3117     send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx);
3118     g_free (path);
3119     g_object_unref (media);
3120     gst_sdp_message_free (sdp);
3121     return FALSE;
3122   }
3123 }
3124
3125 static gboolean
3126 handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx)
3127 {
3128   GstRTSPSession *session;
3129   GstRTSPClientClass *klass;
3130   GstRTSPSessionMedia *sessmedia;
3131   GstRTSPMedia *media;
3132   GstRTSPUrl *uri;
3133   GstRTSPState rtspstate;
3134   gchar *path;
3135   gint matched;
3136   GstRTSPStatusCode sig_result;
3137   GPtrArray *transports;
3138
3139   if (!(session = ctx->session))
3140     goto no_session;
3141
3142   if (!(uri = ctx->uri))
3143     goto no_uri;
3144
3145   klass = GST_RTSP_CLIENT_GET_CLASS (client);
3146   path = klass->make_path_from_uri (client, uri);
3147
3148   /* get a handle to the configuration of the media in the session */
3149   sessmedia = gst_rtsp_session_get_media (session, path, &matched);
3150   if (!sessmedia)
3151     goto not_found;
3152
3153   if (path[matched] != '\0')
3154     goto no_aggregate;
3155
3156   g_free (path);
3157
3158   ctx->sessmedia = sessmedia;
3159   ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
3160
3161   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST], 0,
3162       ctx, &sig_result);
3163   if (sig_result != GST_RTSP_STS_OK) {
3164     goto sig_failed;
3165   }
3166
3167   if (!(gst_rtsp_media_get_transport_mode (media) &
3168           GST_RTSP_TRANSPORT_MODE_RECORD))
3169     goto unsupported_mode;
3170
3171   /* the session state must be playing or ready */
3172   rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
3173   if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
3174     goto invalid_state;
3175
3176   /* update the pipeline */
3177   transports = gst_rtsp_session_media_get_transports (sessmedia);
3178   if (!gst_rtsp_media_complete_pipeline (media, transports)) {
3179     g_ptr_array_unref (transports);
3180     goto pipeline_error;
3181   }
3182   g_ptr_array_unref (transports);
3183
3184   /* in record we first unsuspend, media could be suspended from SDP or PAUSED */
3185   if (!gst_rtsp_media_unsuspend (media))
3186     goto unsuspend_failed;
3187
3188   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3189       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3190
3191   send_message (client, ctx, ctx->response, FALSE);
3192
3193   /* start playing after sending the response */
3194   gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
3195
3196   gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
3197
3198   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST], 0,
3199       ctx);
3200
3201   return TRUE;
3202
3203   /* ERRORS */
3204 no_session:
3205   {
3206     GST_ERROR ("client %p: no session", client);
3207     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3208     return FALSE;
3209   }
3210 no_uri:
3211   {
3212     GST_ERROR ("client %p: no uri supplied", client);
3213     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3214     return FALSE;
3215   }
3216 not_found:
3217   {
3218     GST_ERROR ("client %p: media not found", client);
3219     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3220     return FALSE;
3221   }
3222 no_aggregate:
3223   {
3224     GST_ERROR ("client %p: no aggregate path %s", client, path);
3225     send_generic_response (client,
3226         GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
3227     g_free (path);
3228     return FALSE;
3229   }
3230 sig_failed:
3231   {
3232     GST_ERROR ("client %p: pre signal returned error: %s", client,
3233         gst_rtsp_status_as_text (sig_result));
3234     send_generic_response (client, sig_result, ctx);
3235     return FALSE;
3236   }
3237 unsupported_mode:
3238   {
3239     GST_ERROR ("client %p: media does not support RECORD", client);
3240     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
3241     return FALSE;
3242   }
3243 invalid_state:
3244   {
3245     GST_ERROR ("client %p: not PLAYING or READY", client);
3246     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
3247         ctx);
3248     return FALSE;
3249   }
3250 pipeline_error:
3251   {
3252     GST_ERROR ("client %p: failed to configure the pipeline", client);
3253     send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
3254         ctx);
3255     return FALSE;
3256   }
3257 unsuspend_failed:
3258   {
3259     GST_ERROR ("client %p: unsuspend failed", client);
3260     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
3261     return FALSE;
3262   }
3263 }
3264
3265 static gboolean
3266 handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx,
3267     GstRTSPVersion version)
3268 {
3269   GstRTSPMethod options;
3270   gchar *str;
3271   GstRTSPStatusCode sig_result;
3272
3273   options = GST_RTSP_DESCRIBE |
3274       GST_RTSP_OPTIONS |
3275       GST_RTSP_PAUSE |
3276       GST_RTSP_PLAY |
3277       GST_RTSP_SETUP |
3278       GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
3279
3280   if (version < GST_RTSP_VERSION_2_0) {
3281     options |= GST_RTSP_RECORD;
3282     options |= GST_RTSP_ANNOUNCE;
3283   }
3284
3285   str = gst_rtsp_options_as_text (options);
3286
3287   gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3288       gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3289
3290   gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str);
3291   g_free (str);
3292
3293   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST], 0,
3294       ctx, &sig_result);
3295   if (sig_result != GST_RTSP_STS_OK) {
3296     goto sig_failed;
3297   }
3298
3299   send_message (client, ctx, ctx->response, FALSE);
3300
3301   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
3302       0, ctx);
3303
3304   return TRUE;
3305
3306 /* ERRORS */
3307 sig_failed:
3308   {
3309     GST_ERROR ("client %p: pre signal returned error: %s", client,
3310         gst_rtsp_status_as_text (sig_result));
3311     send_generic_response (client, sig_result, ctx);
3312     gst_rtsp_message_free (ctx->response);
3313     return FALSE;
3314   }
3315 }
3316
3317 /* remove duplicate and trailing '/' */
3318 static void
3319 sanitize_uri (GstRTSPUrl * uri)
3320 {
3321   gint i, len;
3322   gchar *s, *d;
3323   gboolean have_slash, prev_slash;
3324
3325   s = d = uri->abspath;
3326   len = strlen (uri->abspath);
3327
3328   prev_slash = FALSE;
3329
3330   for (i = 0; i < len; i++) {
3331     have_slash = s[i] == '/';
3332     *d = s[i];
3333     if (!have_slash || !prev_slash)
3334       d++;
3335     prev_slash = have_slash;
3336   }
3337   len = d - uri->abspath;
3338   /* don't remove the first slash if that's the only thing left */
3339   if (len > 1 && *(d - 1) == '/')
3340     d--;
3341   *d = '\0';
3342 }
3343
3344 /* is called when the session is removed from its session pool. */
3345 static void
3346 client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session,
3347     GstRTSPClient * client)
3348 {
3349   GstRTSPClientPrivate *priv = client->priv;
3350
3351   GST_INFO ("client %p: session %p removed", client, session);
3352
3353   g_mutex_lock (&priv->lock);
3354   if (priv->watch != NULL)
3355     gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0);
3356   client_unwatch_session (client, session, NULL);
3357   if (priv->watch != NULL)
3358     gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3359   g_mutex_unlock (&priv->lock);
3360 }
3361
3362 /* Check for Require headers. Returns TRUE if there are no Require headers,
3363  * otherwise lets the application decide which headers are supported.
3364  * By default all headers are unsupported.
3365  * If there are unsupported options, FALSE will be returned together with
3366  * a newly-allocated string of (comma-separated) unsupported options in
3367  * the unsupported_reqs variable.
3368  *
3369  * There may be multiple Require headers, but we must send one single
3370  * Unsupported header with all the unsupported options as response. If
3371  * an incoming Require header contained a comma-separated list of options
3372  * GstRtspConnection will already have split that list up into multiple
3373  * headers.
3374  */
3375 static gboolean
3376 check_request_requirements (GstRTSPContext * ctx, gchar ** unsupported_reqs)
3377 {
3378   GstRTSPResult res;
3379   GPtrArray *arr = NULL;
3380   GstRTSPMessage *msg = ctx->request;
3381   gchar *reqs = NULL;
3382   gint i;
3383   gchar *sig_result = NULL;
3384   gboolean result = TRUE;
3385
3386   i = 0;
3387   do {
3388     res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++);
3389
3390     if (res == GST_RTSP_ENOTIMPL)
3391       break;
3392
3393     if (arr == NULL)
3394       arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
3395
3396     g_ptr_array_add (arr, g_strdup (reqs));
3397   }
3398   while (TRUE);
3399
3400   /* if we don't have any Require headers at all, all is fine */
3401   if (i == 1)
3402     return TRUE;
3403
3404   /* otherwise we've now processed at all the Require headers */
3405   g_ptr_array_add (arr, NULL);
3406
3407   g_signal_emit (ctx->client,
3408       gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS], 0, ctx,
3409       (gchar **) arr->pdata, &sig_result);
3410
3411   if (sig_result == NULL) {
3412     /* no supported options, just report all of the required ones as
3413      * unsupported */
3414     *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata);
3415     result = FALSE;
3416     goto done;
3417   }
3418
3419   if (strlen (sig_result) == 0)
3420     g_free (sig_result);
3421   else {
3422     *unsupported_reqs = sig_result;
3423     result = FALSE;
3424   }
3425
3426 done:
3427   g_ptr_array_unref (arr);
3428   return result;
3429 }
3430
3431 static void
3432 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
3433 {
3434   GstRTSPClientPrivate *priv = client->priv;
3435   GstRTSPMethod method;
3436   const gchar *uristr;
3437   GstRTSPUrl *uri = NULL;
3438   GstRTSPVersion version;
3439   GstRTSPResult res;
3440   GstRTSPSession *session = NULL;
3441   GstRTSPContext sctx = { NULL }, *ctx;
3442   GstRTSPMessage response = { 0 };
3443   gchar *unsupported_reqs = NULL;
3444   gchar *sessid = NULL, *pipelined_request_id = NULL;
3445
3446   if (!(ctx = gst_rtsp_context_get_current ())) {
3447     ctx = &sctx;
3448     ctx->auth = priv->auth;
3449     gst_rtsp_context_push_current (ctx);
3450   }
3451
3452   ctx->conn = priv->connection;
3453   ctx->client = client;
3454   ctx->request = request;
3455   ctx->response = &response;
3456
3457   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3458     gst_rtsp_message_dump (request);
3459   }
3460
3461   gst_rtsp_message_parse_request (request, &method, &uristr, &version);
3462
3463   GST_INFO ("client %p: received a request %s %s %s", client,
3464       gst_rtsp_method_as_text (method), uristr,
3465       gst_rtsp_version_as_text (version));
3466
3467   /* we can only handle 1.0 requests */
3468   if (version != GST_RTSP_VERSION_1_0 && version != GST_RTSP_VERSION_2_0)
3469     goto not_supported;
3470
3471   ctx->method = method;
3472
3473   /* we always try to parse the url first */
3474   if (strcmp (uristr, "*") == 0) {
3475     /* special case where we have * as uri, keep uri = NULL */
3476   } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
3477     /* check if the uristr is an absolute path <=> scheme and host information
3478      * is missing */
3479     gchar *scheme;
3480
3481     scheme = g_uri_parse_scheme (uristr);
3482     if (scheme == NULL && g_str_has_prefix (uristr, "/")) {
3483       gchar *absolute_uristr = NULL;
3484
3485       GST_WARNING_OBJECT (client, "request doesn't contain absolute url");
3486       if (priv->server_ip == NULL) {
3487         GST_WARNING_OBJECT (client, "host information missing");
3488         goto bad_request;
3489       }
3490
3491       absolute_uristr =
3492           g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr);
3493
3494       GST_DEBUG_OBJECT (client, "absolute url: %s", absolute_uristr);
3495       if (gst_rtsp_url_parse (absolute_uristr, &uri) != GST_RTSP_OK) {
3496         g_free (absolute_uristr);
3497         goto bad_request;
3498       }
3499       g_free (absolute_uristr);
3500     } else {
3501       g_free (scheme);
3502       goto bad_request;
3503     }
3504   }
3505
3506   /* get the session if there is any */
3507   res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_PIPELINED_REQUESTS,
3508       &pipelined_request_id, 0);
3509   if (res == GST_RTSP_OK) {
3510     sessid = g_hash_table_lookup (client->priv->pipelined_requests,
3511         pipelined_request_id);
3512
3513     if (!sessid)
3514       res = GST_RTSP_ERROR;
3515   }
3516
3517   if (res != GST_RTSP_OK)
3518     res =
3519         gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
3520
3521   if (res == GST_RTSP_OK) {
3522     if (priv->session_pool == NULL)
3523       goto no_pool;
3524
3525     /* we had a session in the request, find it again */
3526     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
3527       goto session_not_found;
3528
3529     /* we add the session to the client list of watched sessions. When a session
3530      * disappears because it times out, we will be notified. If all sessions are
3531      * gone, we will close the connection */
3532     client_watch_session (client, session);
3533   }
3534
3535   /* sanitize the uri */
3536   if (uri)
3537     sanitize_uri (uri);
3538   ctx->uri = uri;
3539   ctx->session = session;
3540
3541   if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL))
3542     goto not_authorized;
3543
3544   /* handle any 'Require' headers */
3545   if (!check_request_requirements (ctx, &unsupported_reqs))
3546     goto unsupported_requirement;
3547
3548   /* the backlog must be unlimited while processing requests.
3549    * the causes of this are two cases of deadlocks while streaming over TCP:
3550    *
3551    * 1. consider the scenario where the media pipeline's streaming thread
3552    * is blocking in the appsink (taking the appsink's preroll lock) because
3553    * the backlog is full. when a PAUSE request is received by the RTSP
3554    * client thread then the the state of the session media ought to change
3555    * to PAUSED. while most elements in the pipeline can change state this
3556    * can never happen for the appsink since its preroll lock is taken by
3557    * another thread.
3558    *
3559    * 2. consider the scenario where the media pipeline's streaming thread
3560    * is blocking in the appsink new_sample callback (taking the send lock
3561    * in RTSP client) because the backlog is full. when e.g. a GET request
3562    * is received by the RTSP client thread then a response ought to be sent
3563    * but this can never happen since it requires taking the send lock
3564    * already taken by another thread.
3565    *
3566    * the reason that the backlog is never emptied is that the source used
3567    * for dequeing messages from the backlog is never dispatched because it
3568    * is attached to the same mainloop as the source receving RTSP requests and
3569    * therefore run by the RTSP client thread which is alreayd blocking.
3570    *
3571    * without significant changes the easiest way to cope with this is to
3572    * not block indefinitely when the backlog is full, but rather let the
3573    * backlog grow in size. this in effect means that there can not be any
3574    * upper boundary on its size.
3575    */
3576   if (priv->watch != NULL)
3577     gst_rtsp_watch_set_send_backlog (priv->watch, 0, 0);
3578
3579   /* now see what is asked and dispatch to a dedicated handler */
3580   switch (method) {
3581     case GST_RTSP_OPTIONS:
3582       priv->version = version;
3583       handle_options_request (client, ctx, version);
3584       break;
3585     case GST_RTSP_DESCRIBE:
3586       handle_describe_request (client, ctx);
3587       break;
3588     case GST_RTSP_SETUP:
3589       handle_setup_request (client, ctx);
3590       break;
3591     case GST_RTSP_PLAY:
3592       handle_play_request (client, ctx);
3593       break;
3594     case GST_RTSP_PAUSE:
3595       handle_pause_request (client, ctx);
3596       break;
3597     case GST_RTSP_TEARDOWN:
3598       handle_teardown_request (client, ctx);
3599       break;
3600     case GST_RTSP_SET_PARAMETER:
3601       handle_set_param_request (client, ctx);
3602       break;
3603     case GST_RTSP_GET_PARAMETER:
3604       handle_get_param_request (client, ctx);
3605       break;
3606     case GST_RTSP_ANNOUNCE:
3607       if (version >= GST_RTSP_VERSION_2_0)
3608         goto invalid_command_for_version;
3609       handle_announce_request (client, ctx);
3610       break;
3611     case GST_RTSP_RECORD:
3612       if (version >= GST_RTSP_VERSION_2_0)
3613         goto invalid_command_for_version;
3614       handle_record_request (client, ctx);
3615       break;
3616     case GST_RTSP_REDIRECT:
3617       if (priv->watch != NULL)
3618         gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3619       goto not_implemented;
3620     case GST_RTSP_INVALID:
3621     default:
3622       if (priv->watch != NULL)
3623         gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3624       goto bad_request;
3625   }
3626
3627   if (priv->watch != NULL)
3628     gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3629
3630 done:
3631   if (ctx == &sctx)
3632     gst_rtsp_context_pop_current (ctx);
3633   if (session)
3634     g_object_unref (session);
3635   if (uri)
3636     gst_rtsp_url_free (uri);
3637   return;
3638
3639   /* ERRORS */
3640 not_supported:
3641   {
3642     GST_ERROR ("client %p: version %d not supported", client, version);
3643     send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
3644         ctx);
3645     goto done;
3646   }
3647 invalid_command_for_version:
3648   {
3649     if (priv->watch != NULL)
3650       gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
3651
3652     GST_ERROR ("client %p: invalid command for version", client);
3653     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3654     goto done;
3655   }
3656 bad_request:
3657   {
3658     GST_ERROR ("client %p: bad request", client);
3659     send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3660     goto done;
3661   }
3662 no_pool:
3663   {
3664     GST_ERROR ("client %p: no pool configured", client);
3665     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3666     goto done;
3667   }
3668 session_not_found:
3669   {
3670     GST_ERROR ("client %p: session not found", client);
3671     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3672     goto done;
3673   }
3674 not_authorized:
3675   {
3676     GST_ERROR ("client %p: not allowed", client);
3677     /* error reply is already sent */
3678     goto done;
3679   }
3680 unsupported_requirement:
3681   {
3682     GST_ERROR ("client %p: Required option is not supported (%s)", client,
3683         unsupported_reqs);
3684     send_option_not_supported_response (client, ctx, unsupported_reqs);
3685     g_free (unsupported_reqs);
3686     goto done;
3687   }
3688 not_implemented:
3689   {
3690     GST_ERROR ("client %p: method %d not implemented", client, method);
3691     send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
3692     goto done;
3693   }
3694 }
3695
3696
3697 static void
3698 handle_response (GstRTSPClient * client, GstRTSPMessage * response)
3699 {
3700   GstRTSPClientPrivate *priv = client->priv;
3701   GstRTSPResult res;
3702   GstRTSPSession *session = NULL;
3703   GstRTSPContext sctx = { NULL }, *ctx;
3704   gchar *sessid;
3705
3706   if (!(ctx = gst_rtsp_context_get_current ())) {
3707     ctx = &sctx;
3708     ctx->auth = priv->auth;
3709     gst_rtsp_context_push_current (ctx);
3710   }
3711
3712   ctx->conn = priv->connection;
3713   ctx->client = client;
3714   ctx->request = NULL;
3715   ctx->uri = NULL;
3716   ctx->method = GST_RTSP_INVALID;
3717   ctx->response = response;
3718
3719   if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3720     gst_rtsp_message_dump (response);
3721   }
3722
3723   GST_INFO ("client %p: received a response", client);
3724
3725   /* get the session if there is any */
3726   res =
3727       gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &sessid, 0);
3728   if (res == GST_RTSP_OK) {
3729     if (priv->session_pool == NULL)
3730       goto no_pool;
3731
3732     /* we had a session in the request, find it again */
3733     if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
3734       goto session_not_found;
3735
3736     /* we add the session to the client list of watched sessions. When a session
3737      * disappears because it times out, we will be notified. If all sessions are
3738      * gone, we will close the connection */
3739     client_watch_session (client, session);
3740   }
3741
3742   ctx->session = session;
3743
3744   g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE],
3745       0, ctx);
3746
3747 done:
3748   if (ctx == &sctx)
3749     gst_rtsp_context_pop_current (ctx);
3750   if (session)
3751     g_object_unref (session);
3752   return;
3753
3754 no_pool:
3755   {
3756     GST_ERROR ("client %p: no pool configured", client);
3757     goto done;
3758   }
3759 session_not_found:
3760   {
3761     GST_ERROR ("client %p: session not found", client);
3762     goto done;
3763   }
3764 }
3765
3766 static void
3767 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
3768 {
3769   GstRTSPClientPrivate *priv = client->priv;
3770   GstRTSPResult res;
3771   guint8 channel;
3772   guint8 *data;
3773   guint size;
3774   GstBuffer *buffer;
3775   GstRTSPStreamTransport *trans;
3776
3777   /* find the stream for this message */
3778   res = gst_rtsp_message_parse_data (message, &channel);
3779   if (res != GST_RTSP_OK)
3780     return;
3781
3782   gst_rtsp_message_get_body (message, &data, &size);
3783   if (size < 2)
3784     goto invalid_length;
3785
3786   gst_rtsp_message_steal_body (message, &data, &size);
3787
3788   /* Strip trailing \0 (which GstRTSPConnection adds) */
3789   --size;
3790
3791   buffer = gst_buffer_new_wrapped (data, size);
3792
3793   trans =
3794       g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel));
3795   if (trans) {
3796     GSocketAddress *addr;
3797
3798     /* Only create the socket address once for the transport, we don't really
3799      * want to do that for every single packet.
3800      *
3801      * The netaddress meta is later used by the RTP stack to know where
3802      * packets came from and allows us to match it again to a stream transport
3803      *
3804      * In theory we could use the remote socket address of the RTSP connection
3805      * here, but this would fail with a custom configure_client_transport()
3806      * implementation.
3807      */
3808     if (!(addr =
3809             g_object_get_data (G_OBJECT (trans), "rtsp-client.remote-addr"))) {
3810       const GstRTSPTransport *tr;
3811       GInetAddress *iaddr;
3812
3813       tr = gst_rtsp_stream_transport_get_transport (trans);
3814       iaddr = g_inet_address_new_from_string (tr->destination);
3815       if (iaddr) {
3816         addr = g_inet_socket_address_new (iaddr, tr->client_port.min);
3817         g_object_unref (iaddr);
3818         g_object_set_data_full (G_OBJECT (trans), "rtsp-client.remote-addr",
3819             addr, (GDestroyNotify) g_object_unref);
3820       }
3821     }
3822
3823     if (addr) {
3824       gst_buffer_add_net_address_meta (buffer, addr);
3825     }
3826
3827     /* dispatch to the stream based on the channel number */
3828     GST_LOG_OBJECT (client, "%u bytes of data on channel %u", size, channel);
3829     gst_rtsp_stream_transport_recv_data (trans, channel, buffer);
3830   } else {
3831     GST_DEBUG_OBJECT (client, "received %u bytes of data for "
3832         "unknown channel %u", size, channel);
3833     gst_buffer_unref (buffer);
3834   }
3835
3836   return;
3837
3838 /* ERRORS */
3839 invalid_length:
3840   {
3841     GST_DEBUG ("client %p: Short message received, ignoring", client);
3842     return;
3843   }
3844 }
3845
3846 /**
3847  * gst_rtsp_client_set_session_pool:
3848  * @client: a #GstRTSPClient
3849  * @pool: (transfer none) (nullable): a #GstRTSPSessionPool
3850  *
3851  * Set @pool as the sessionpool for @client which it will use to find
3852  * or allocate sessions. the sessionpool is usually inherited from the server
3853  * that created the client but can be overridden later.
3854  */
3855 void
3856 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
3857     GstRTSPSessionPool * pool)
3858 {
3859   GstRTSPSessionPool *old;
3860   GstRTSPClientPrivate *priv;
3861
3862   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3863
3864   priv = client->priv;
3865
3866   if (pool)
3867     g_object_ref (pool);
3868
3869   g_mutex_lock (&priv->lock);
3870   old = priv->session_pool;
3871   priv->session_pool = pool;
3872
3873   if (priv->session_removed_id) {
3874     g_signal_handler_disconnect (old, priv->session_removed_id);
3875     priv->session_removed_id = 0;
3876   }
3877   g_mutex_unlock (&priv->lock);
3878
3879   /* FIXME, should remove all sessions from the old pool for this client */
3880   if (old)
3881     g_object_unref (old);
3882 }
3883
3884 /**
3885  * gst_rtsp_client_get_session_pool:
3886  * @client: a #GstRTSPClient
3887  *
3888  * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
3889  *
3890  * Returns: (transfer full) (nullable): a #GstRTSPSessionPool, unref after usage.
3891  */
3892 GstRTSPSessionPool *
3893 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
3894 {
3895   GstRTSPClientPrivate *priv;
3896   GstRTSPSessionPool *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->session_pool))
3904     g_object_ref (result);
3905   g_mutex_unlock (&priv->lock);
3906
3907   return result;
3908 }
3909
3910 /**
3911  * gst_rtsp_client_set_mount_points:
3912  * @client: a #GstRTSPClient
3913  * @mounts: (transfer none) (nullable): a #GstRTSPMountPoints
3914  *
3915  * Set @mounts as the mount points for @client which it will use to map urls
3916  * to media streams. These mount points are usually inherited from the server that
3917  * created the client but can be overriden later.
3918  */
3919 void
3920 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
3921     GstRTSPMountPoints * mounts)
3922 {
3923   GstRTSPClientPrivate *priv;
3924   GstRTSPMountPoints *old;
3925
3926   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3927
3928   priv = client->priv;
3929
3930   if (mounts)
3931     g_object_ref (mounts);
3932
3933   g_mutex_lock (&priv->lock);
3934   old = priv->mount_points;
3935   priv->mount_points = mounts;
3936   g_mutex_unlock (&priv->lock);
3937
3938   if (old)
3939     g_object_unref (old);
3940 }
3941
3942 /**
3943  * gst_rtsp_client_get_mount_points:
3944  * @client: a #GstRTSPClient
3945  *
3946  * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
3947  *
3948  * Returns: (transfer full) (nullable): a #GstRTSPMountPoints, unref after usage.
3949  */
3950 GstRTSPMountPoints *
3951 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
3952 {
3953   GstRTSPClientPrivate *priv;
3954   GstRTSPMountPoints *result;
3955
3956   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
3957
3958   priv = client->priv;
3959
3960   g_mutex_lock (&priv->lock);
3961   if ((result = priv->mount_points))
3962     g_object_ref (result);
3963   g_mutex_unlock (&priv->lock);
3964
3965   return result;
3966 }
3967
3968 /**
3969  * gst_rtsp_client_set_auth:
3970  * @client: a #GstRTSPClient
3971  * @auth: (transfer none) (nullable): a #GstRTSPAuth
3972  *
3973  * configure @auth to be used as the authentication manager of @client.
3974  */
3975 void
3976 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
3977 {
3978   GstRTSPClientPrivate *priv;
3979   GstRTSPAuth *old;
3980
3981   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
3982
3983   priv = client->priv;
3984
3985   if (auth)
3986     g_object_ref (auth);
3987
3988   g_mutex_lock (&priv->lock);
3989   old = priv->auth;
3990   priv->auth = auth;
3991   g_mutex_unlock (&priv->lock);
3992
3993   if (old)
3994     g_object_unref (old);
3995 }
3996
3997
3998 /**
3999  * gst_rtsp_client_get_auth:
4000  * @client: a #GstRTSPClient
4001  *
4002  * Get the #GstRTSPAuth used as the authentication manager of @client.
4003  *
4004  * Returns: (transfer full) (nullable): the #GstRTSPAuth of @client.
4005  * g_object_unref() after usage.
4006  */
4007 GstRTSPAuth *
4008 gst_rtsp_client_get_auth (GstRTSPClient * client)
4009 {
4010   GstRTSPClientPrivate *priv;
4011   GstRTSPAuth *result;
4012
4013   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4014
4015   priv = client->priv;
4016
4017   g_mutex_lock (&priv->lock);
4018   if ((result = priv->auth))
4019     g_object_ref (result);
4020   g_mutex_unlock (&priv->lock);
4021
4022   return result;
4023 }
4024
4025 /**
4026  * gst_rtsp_client_set_thread_pool:
4027  * @client: a #GstRTSPClient
4028  * @pool: (transfer none) (nullable): a #GstRTSPThreadPool
4029  *
4030  * configure @pool to be used as the thread pool of @client.
4031  */
4032 void
4033 gst_rtsp_client_set_thread_pool (GstRTSPClient * client,
4034     GstRTSPThreadPool * pool)
4035 {
4036   GstRTSPClientPrivate *priv;
4037   GstRTSPThreadPool *old;
4038
4039   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4040
4041   priv = client->priv;
4042
4043   if (pool)
4044     g_object_ref (pool);
4045
4046   g_mutex_lock (&priv->lock);
4047   old = priv->thread_pool;
4048   priv->thread_pool = pool;
4049   g_mutex_unlock (&priv->lock);
4050
4051   if (old)
4052     g_object_unref (old);
4053 }
4054
4055 /**
4056  * gst_rtsp_client_get_thread_pool:
4057  * @client: a #GstRTSPClient
4058  *
4059  * Get the #GstRTSPThreadPool used as the thread pool of @client.
4060  *
4061  * Returns: (transfer full) (nullable): the #GstRTSPThreadPool of @client. g_object_unref() after
4062  * usage.
4063  */
4064 GstRTSPThreadPool *
4065 gst_rtsp_client_get_thread_pool (GstRTSPClient * client)
4066 {
4067   GstRTSPClientPrivate *priv;
4068   GstRTSPThreadPool *result;
4069
4070   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4071
4072   priv = client->priv;
4073
4074   g_mutex_lock (&priv->lock);
4075   if ((result = priv->thread_pool))
4076     g_object_ref (result);
4077   g_mutex_unlock (&priv->lock);
4078
4079   return result;
4080 }
4081
4082 /**
4083  * gst_rtsp_client_set_connection:
4084  * @client: a #GstRTSPClient
4085  * @conn: (transfer full): a #GstRTSPConnection
4086  *
4087  * Set the #GstRTSPConnection of @client. This function takes ownership of
4088  * @conn.
4089  *
4090  * Returns: %TRUE on success.
4091  */
4092 gboolean
4093 gst_rtsp_client_set_connection (GstRTSPClient * client,
4094     GstRTSPConnection * conn)
4095 {
4096   GstRTSPClientPrivate *priv;
4097   GSocket *read_socket;
4098   GSocketAddress *address;
4099   GstRTSPUrl *url;
4100   GError *error = NULL;
4101
4102   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
4103   g_return_val_if_fail (conn != NULL, FALSE);
4104
4105   priv = client->priv;
4106
4107   read_socket = gst_rtsp_connection_get_read_socket (conn);
4108
4109   if (!(address = g_socket_get_local_address (read_socket, &error)))
4110     goto no_address;
4111
4112   g_free (priv->server_ip);
4113   /* keep the original ip that the client connected to */
4114   if (G_IS_INET_SOCKET_ADDRESS (address)) {
4115     GInetAddress *iaddr;
4116
4117     iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
4118
4119     /* socket might be ipv6 but adress still ipv4 */
4120     priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6;
4121     priv->server_ip = g_inet_address_to_string (iaddr);
4122     g_object_unref (address);
4123   } else {
4124     priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
4125     priv->server_ip = g_strdup ("unknown");
4126   }
4127
4128   GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
4129       priv->server_ip, priv->is_ipv6);
4130
4131   url = gst_rtsp_connection_get_url (conn);
4132   GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
4133
4134   priv->connection = conn;
4135
4136   return TRUE;
4137
4138   /* ERRORS */
4139 no_address:
4140   {
4141     GST_ERROR ("could not get local address %s", error->message);
4142     g_error_free (error);
4143     return FALSE;
4144   }
4145 }
4146
4147 /**
4148  * gst_rtsp_client_get_connection:
4149  * @client: a #GstRTSPClient
4150  *
4151  * Get the #GstRTSPConnection of @client.
4152  *
4153  * Returns: (transfer none) (nullable): the #GstRTSPConnection of @client.
4154  * The connection object returned remains valid until the client is freed.
4155  */
4156 GstRTSPConnection *
4157 gst_rtsp_client_get_connection (GstRTSPClient * client)
4158 {
4159   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4160
4161   return client->priv->connection;
4162 }
4163
4164 /**
4165  * gst_rtsp_client_set_send_func:
4166  * @client: a #GstRTSPClient
4167  * @func: (scope notified): a #GstRTSPClientSendFunc
4168  * @user_data: (closure): user data passed to @func
4169  * @notify: (allow-none): called when @user_data is no longer in use
4170  *
4171  * Set @func as the callback that will be called when a new message needs to be
4172  * sent to the client. @user_data is passed to @func and @notify is called when
4173  * @user_data is no longer in use.
4174  *
4175  * By default, the client will send the messages on the #GstRTSPConnection that
4176  * was configured with gst_rtsp_client_attach() was called.
4177  */
4178 void
4179 gst_rtsp_client_set_send_func (GstRTSPClient * client,
4180     GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
4181 {
4182   GstRTSPClientPrivate *priv;
4183   GDestroyNotify old_notify;
4184   gpointer old_data;
4185
4186   g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4187
4188   priv = client->priv;
4189
4190   g_mutex_lock (&priv->send_lock);
4191   priv->send_func = func;
4192   old_notify = priv->send_notify;
4193   old_data = priv->send_data;
4194   priv->send_notify = notify;
4195   priv->send_data = user_data;
4196   g_mutex_unlock (&priv->send_lock);
4197
4198   if (old_notify)
4199     old_notify (old_data);
4200 }
4201
4202 /**
4203  * gst_rtsp_client_handle_message:
4204  * @client: a #GstRTSPClient
4205  * @message: (transfer none): an #GstRTSPMessage
4206  *
4207  * Let the client handle @message.
4208  *
4209  * Returns: a #GstRTSPResult.
4210  */
4211 GstRTSPResult
4212 gst_rtsp_client_handle_message (GstRTSPClient * client,
4213     GstRTSPMessage * message)
4214 {
4215   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
4216   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4217
4218   switch (message->type) {
4219     case GST_RTSP_MESSAGE_REQUEST:
4220       handle_request (client, message);
4221       break;
4222     case GST_RTSP_MESSAGE_RESPONSE:
4223       handle_response (client, message);
4224       break;
4225     case GST_RTSP_MESSAGE_DATA:
4226       handle_data (client, message);
4227       break;
4228     default:
4229       break;
4230   }
4231   return GST_RTSP_OK;
4232 }
4233
4234 /**
4235  * gst_rtsp_client_send_message:
4236  * @client: a #GstRTSPClient
4237  * @session: (allow-none) (transfer none): a #GstRTSPSession to send
4238  *   the message to or %NULL
4239  * @message: (transfer none): The #GstRTSPMessage to send
4240  *
4241  * Send a message message to the remote end. @message must be a
4242  * #GST_RTSP_MESSAGE_REQUEST or a #GST_RTSP_MESSAGE_RESPONSE.
4243  */
4244 GstRTSPResult
4245 gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session,
4246     GstRTSPMessage * message)
4247 {
4248   GstRTSPContext sctx = { NULL }
4249   , *ctx;
4250   GstRTSPClientPrivate *priv;
4251
4252   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
4253   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4254   g_return_val_if_fail (message->type == GST_RTSP_MESSAGE_REQUEST ||
4255       message->type == GST_RTSP_MESSAGE_RESPONSE, GST_RTSP_EINVAL);
4256
4257   priv = client->priv;
4258
4259   if (!(ctx = gst_rtsp_context_get_current ())) {
4260     ctx = &sctx;
4261     ctx->auth = priv->auth;
4262     gst_rtsp_context_push_current (ctx);
4263   }
4264
4265   ctx->conn = priv->connection;
4266   ctx->client = client;
4267   ctx->session = session;
4268
4269   send_message (client, ctx, message, FALSE);
4270
4271   if (ctx == &sctx)
4272     gst_rtsp_context_pop_current (ctx);
4273
4274   return GST_RTSP_OK;
4275 }
4276
4277 static gboolean
4278 do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
4279     gboolean close, gpointer user_data)
4280 {
4281   GstRTSPClientPrivate *priv = client->priv;
4282   GstRTSPResult ret;
4283   GTimeVal time;
4284
4285   time.tv_sec = 1;
4286   time.tv_usec = 0;
4287
4288   do {
4289     /* send the response and store the seq number so we can wait until it's
4290      * written to the client to close the connection */
4291     ret =
4292         gst_rtsp_watch_send_message (priv->watch, message,
4293         close ? &priv->close_seq : NULL);
4294     if (ret == GST_RTSP_OK)
4295       break;
4296
4297     if (ret != GST_RTSP_ENOMEM)
4298       goto error;
4299
4300     /* drop backlog */
4301     if (priv->drop_backlog)
4302       break;
4303
4304     /* queue was full, wait for more space */
4305     GST_DEBUG_OBJECT (client, "waiting for backlog");
4306     ret = gst_rtsp_watch_wait_backlog (priv->watch, &time);
4307     GST_DEBUG_OBJECT (client, "Resend due to backlog full");
4308   } while (ret != GST_RTSP_EINTR);
4309
4310   return ret == GST_RTSP_OK;
4311
4312   /* ERRORS */
4313 error:
4314   {
4315     GST_DEBUG_OBJECT (client, "got error %d", ret);
4316     return ret == GST_RTSP_OK;
4317   }
4318 }
4319
4320 static GstRTSPResult
4321 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
4322     gpointer user_data)
4323 {
4324   return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
4325 }
4326
4327 static GstRTSPResult
4328 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
4329 {
4330   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4331   GstRTSPClientPrivate *priv = client->priv;
4332
4333   if (priv->close_seq && priv->close_seq == cseq) {
4334     GST_INFO ("client %p: send close message", client);
4335     priv->close_seq = 0;
4336     gst_rtsp_client_close (client);
4337   }
4338
4339   return GST_RTSP_OK;
4340 }
4341
4342 static GstRTSPResult
4343 closed (GstRTSPWatch * watch, gpointer user_data)
4344 {
4345   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4346   GstRTSPClientPrivate *priv = client->priv;
4347   const gchar *tunnelid;
4348
4349   GST_INFO ("client %p: connection closed", client);
4350
4351   if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
4352     g_mutex_lock (&tunnels_lock);
4353     /* remove from tunnelids */
4354     g_hash_table_remove (tunnels, tunnelid);
4355     g_mutex_unlock (&tunnels_lock);
4356   }
4357
4358   gst_rtsp_watch_set_flushing (watch, TRUE);
4359   g_mutex_lock (&priv->watch_lock);
4360   gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
4361   g_mutex_unlock (&priv->watch_lock);
4362
4363   return GST_RTSP_OK;
4364 }
4365
4366 static GstRTSPResult
4367 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
4368 {
4369   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4370   gchar *str;
4371
4372   str = gst_rtsp_strresult (result);
4373   GST_INFO ("client %p: received an error %s", client, str);
4374   g_free (str);
4375
4376   return GST_RTSP_OK;
4377 }
4378
4379 static GstRTSPResult
4380 error_full (GstRTSPWatch * watch, GstRTSPResult result,
4381     GstRTSPMessage * message, guint id, gpointer user_data)
4382 {
4383   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4384   gchar *str;
4385
4386   str = gst_rtsp_strresult (result);
4387   GST_INFO
4388       ("client %p: error when handling message %p with id %d: %s",
4389       client, message, id, str);
4390   g_free (str);
4391
4392   return GST_RTSP_OK;
4393 }
4394
4395 static gboolean
4396 remember_tunnel (GstRTSPClient * client)
4397 {
4398   GstRTSPClientPrivate *priv = client->priv;
4399   const gchar *tunnelid;
4400
4401   /* store client in the pending tunnels */
4402   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
4403   if (tunnelid == NULL)
4404     goto no_tunnelid;
4405
4406   GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
4407
4408   /* we can't have two clients connecting with the same tunnelid */
4409   g_mutex_lock (&tunnels_lock);
4410   if (g_hash_table_lookup (tunnels, tunnelid))
4411     goto tunnel_existed;
4412
4413   g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
4414   g_mutex_unlock (&tunnels_lock);
4415
4416   return TRUE;
4417
4418   /* ERRORS */
4419 no_tunnelid:
4420   {
4421     GST_ERROR ("client %p: no tunnelid provided", client);
4422     return FALSE;
4423   }
4424 tunnel_existed:
4425   {
4426     g_mutex_unlock (&tunnels_lock);
4427     GST_ERROR ("client %p: tunnel session %s already existed", client,
4428         tunnelid);
4429     return FALSE;
4430   }
4431 }
4432
4433 static GstRTSPResult
4434 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
4435 {
4436   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4437   GstRTSPClientPrivate *priv = client->priv;
4438
4439   GST_WARNING ("client %p: tunnel lost (connection %p)", client,
4440       priv->connection);
4441
4442   /* ignore error, it'll only be a problem when the client does a POST again */
4443   remember_tunnel (client);
4444
4445   return GST_RTSP_OK;
4446 }
4447
4448 static GstRTSPStatusCode
4449 handle_tunnel (GstRTSPClient * client)
4450 {
4451   GstRTSPClientPrivate *priv = client->priv;
4452   GstRTSPClient *oclient;
4453   GstRTSPClientPrivate *opriv;
4454   const gchar *tunnelid;
4455
4456   tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
4457   if (tunnelid == NULL)
4458     goto no_tunnelid;
4459
4460   /* check for previous tunnel */
4461   g_mutex_lock (&tunnels_lock);
4462   oclient = g_hash_table_lookup (tunnels, tunnelid);
4463
4464   if (oclient == NULL) {
4465     /* no previous tunnel, remember tunnel */
4466     g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
4467     g_mutex_unlock (&tunnels_lock);
4468
4469     GST_INFO ("client %p: no previous tunnel found, remembering tunnel (%p)",
4470         client, priv->connection);
4471   } else {
4472     /* merge both tunnels into the first client */
4473     /* remove the old client from the table. ref before because removing it will
4474      * remove the ref to it. */
4475     g_object_ref (oclient);
4476     g_hash_table_remove (tunnels, tunnelid);
4477     g_mutex_unlock (&tunnels_lock);
4478
4479     opriv = oclient->priv;
4480
4481     g_mutex_lock (&opriv->watch_lock);
4482     if (opriv->watch == NULL)
4483       goto tunnel_closed;
4484     if (opriv->tstate == priv->tstate)
4485       goto tunnel_duplicate_id;
4486
4487     GST_INFO ("client %p: found previous tunnel %p (old %p, new %p)", client,
4488         oclient, opriv->connection, priv->connection);
4489
4490     gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
4491     gst_rtsp_watch_reset (priv->watch);
4492     gst_rtsp_watch_reset (opriv->watch);
4493     g_mutex_unlock (&opriv->watch_lock);
4494     g_object_unref (oclient);
4495
4496     /* the old client owns the tunnel now, the new one will be freed */
4497     g_source_destroy ((GSource *) priv->watch);
4498     priv->watch = NULL;
4499     gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
4500   }
4501
4502   return GST_RTSP_STS_OK;
4503
4504   /* ERRORS */
4505 no_tunnelid:
4506   {
4507     GST_ERROR ("client %p: no tunnelid provided", client);
4508     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
4509   }
4510 tunnel_closed:
4511   {
4512     GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
4513     g_mutex_unlock (&opriv->watch_lock);
4514     g_object_unref (oclient);
4515     return GST_RTSP_STS_SERVICE_UNAVAILABLE;
4516   }
4517 tunnel_duplicate_id:
4518   {
4519     GST_ERROR ("client %p: tunnel session %s was duplicate", client, tunnelid);
4520     g_mutex_unlock (&opriv->watch_lock);
4521     g_object_unref (oclient);
4522     return GST_RTSP_STS_BAD_REQUEST;
4523   }
4524 }
4525
4526 static GstRTSPStatusCode
4527 tunnel_get (GstRTSPWatch * watch, gpointer user_data)
4528 {
4529   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4530
4531   GST_INFO ("client %p: tunnel get (connection %p)", client,
4532       client->priv->connection);
4533
4534   g_mutex_lock (&client->priv->lock);
4535   client->priv->tstate = TUNNEL_STATE_GET;
4536   g_mutex_unlock (&client->priv->lock);
4537
4538   return handle_tunnel (client);
4539 }
4540
4541 static GstRTSPResult
4542 tunnel_post (GstRTSPWatch * watch, gpointer user_data)
4543 {
4544   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4545
4546   GST_INFO ("client %p: tunnel post (connection %p)", client,
4547       client->priv->connection);
4548
4549   g_mutex_lock (&client->priv->lock);
4550   client->priv->tstate = TUNNEL_STATE_POST;
4551   g_mutex_unlock (&client->priv->lock);
4552
4553   if (handle_tunnel (client) != GST_RTSP_STS_OK)
4554     return GST_RTSP_ERROR;
4555
4556   return GST_RTSP_OK;
4557 }
4558
4559 static GstRTSPResult
4560 tunnel_http_response (GstRTSPWatch * watch, GstRTSPMessage * request,
4561     GstRTSPMessage * response, gpointer user_data)
4562 {
4563   GstRTSPClientClass *klass;
4564
4565   GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
4566   klass = GST_RTSP_CLIENT_GET_CLASS (client);
4567
4568   if (klass->tunnel_http_response) {
4569     klass->tunnel_http_response (client, request, response);
4570   }
4571
4572   return GST_RTSP_OK;
4573 }
4574
4575 static GstRTSPWatchFuncs watch_funcs = {
4576   message_received,
4577   message_sent,
4578   closed,
4579   error,
4580   tunnel_get,
4581   tunnel_post,
4582   error_full,
4583   tunnel_lost,
4584   tunnel_http_response
4585 };
4586
4587 static void
4588 client_watch_notify (GstRTSPClient * client)
4589 {
4590   GstRTSPClientPrivate *priv = client->priv;
4591   gboolean closed = TRUE;
4592
4593   GST_INFO ("client %p: watch destroyed", client);
4594   priv->watch = NULL;
4595   /* remove all sessions if the media says so and so drop the extra client ref */
4596   rtsp_ctrl_timeout_remove (priv);
4597   gst_rtsp_client_session_filter (client, cleanup_session, &closed);
4598   if (closed)
4599     g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
4600   g_object_unref (client);
4601 }
4602
4603 /**
4604  * gst_rtsp_client_attach:
4605  * @client: a #GstRTSPClient
4606  * @context: (allow-none): a #GMainContext
4607  *
4608  * Attaches @client to @context. When the mainloop for @context is run, the
4609  * client will be dispatched. When @context is %NULL, the default context will be
4610  * used).
4611  *
4612  * This function should be called when the client properties and urls are fully
4613  * configured and the client is ready to start.
4614  *
4615  * Returns: the ID (greater than 0) for the source within the GMainContext.
4616  */
4617 guint
4618 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
4619 {
4620   GstRTSPClientPrivate *priv;
4621   GSource *timer_src;
4622   guint res;
4623
4624   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
4625   priv = client->priv;
4626   g_return_val_if_fail (priv->connection != NULL, 0);
4627   g_return_val_if_fail (priv->watch == NULL, 0);
4628
4629   /* make sure noone will free the context before the watch is destroyed */
4630   priv->watch_context = g_main_context_ref (context);
4631
4632   /* create watch for the connection and attach */
4633   priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
4634       g_object_ref (client), (GDestroyNotify) client_watch_notify);
4635   gst_rtsp_client_set_send_func (client, do_send_message, priv->watch,
4636       (GDestroyNotify) gst_rtsp_watch_unref);
4637
4638   gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
4639
4640   GST_INFO ("client %p: attaching to context %p", client, context);
4641   res = gst_rtsp_watch_attach (priv->watch, context);
4642
4643   /* Setting up a timeout for the RTSP control channel until a session
4644    * is up where it is handling timeouts. */
4645   rtsp_ctrl_timeout_remove (priv);      /* removing old if any */
4646   g_mutex_lock (&priv->lock);
4647
4648   timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL);
4649   g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client, NULL);
4650   priv->rtsp_ctrl_timeout_id = g_source_attach (timer_src, priv->watch_context);
4651   g_source_unref (timer_src);
4652   GST_DEBUG ("rtsp control setting up session timeout id=%u.",
4653       priv->rtsp_ctrl_timeout_id);
4654
4655   g_mutex_unlock (&priv->lock);
4656
4657   return res;
4658 }
4659
4660 /**
4661  * gst_rtsp_client_session_filter:
4662  * @client: a #GstRTSPClient
4663  * @func: (scope call) (allow-none): a callback
4664  * @user_data: user data passed to @func
4665  *
4666  * Call @func for each session managed by @client. The result value of @func
4667  * determines what happens to the session. @func will be called with @client
4668  * locked so no further actions on @client can be performed from @func.
4669  *
4670  * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from
4671  * @client.
4672  *
4673  * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @client.
4674  *
4675  * If @func returns #GST_RTSP_FILTER_REF, the session will remain in @client but
4676  * will also be added with an additional ref to the result #GList of this
4677  * function..
4678  *
4679  * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each session.
4680  *
4681  * Returns: (element-type GstRTSPSession) (transfer full): a #GList with all
4682  * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each
4683  * element in the #GList should be unreffed before the list is freed.
4684  */
4685 GList *
4686 gst_rtsp_client_session_filter (GstRTSPClient * client,
4687     GstRTSPClientSessionFilterFunc func, gpointer user_data)
4688 {
4689   GstRTSPClientPrivate *priv;
4690   GList *result, *walk, *next;
4691   GHashTable *visited;
4692   guint cookie;
4693
4694   g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4695
4696   priv = client->priv;
4697
4698   result = NULL;
4699   if (func)
4700     visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
4701
4702   g_mutex_lock (&priv->lock);
4703 restart:
4704   cookie = priv->sessions_cookie;
4705   for (walk = priv->sessions; walk; walk = next) {
4706     GstRTSPSession *sess = walk->data;
4707     GstRTSPFilterResult res;
4708     gboolean changed;
4709
4710     next = g_list_next (walk);
4711
4712     if (func) {
4713       /* only visit each session once */
4714       if (g_hash_table_contains (visited, sess))
4715         continue;
4716
4717       g_hash_table_add (visited, g_object_ref (sess));
4718       g_mutex_unlock (&priv->lock);
4719
4720       res = func (client, sess, user_data);
4721
4722       g_mutex_lock (&priv->lock);
4723     } else
4724       res = GST_RTSP_FILTER_REF;
4725
4726     changed = (cookie != priv->sessions_cookie);
4727
4728     switch (res) {
4729       case GST_RTSP_FILTER_REMOVE:
4730         /* stop watching the session and pretend it went away, if the list was
4731          * changed, we can't use the current list position, try to see if we
4732          * still have the session */
4733         client_unwatch_session (client, sess, changed ? NULL : walk);
4734         cookie = priv->sessions_cookie;
4735         break;
4736       case GST_RTSP_FILTER_REF:
4737         result = g_list_prepend (result, g_object_ref (sess));
4738         break;
4739       case GST_RTSP_FILTER_KEEP:
4740       default:
4741         break;
4742     }
4743     if (changed)
4744       goto restart;
4745   }
4746   g_mutex_unlock (&priv->lock);
4747
4748   if (func)
4749     g_hash_table_unref (visited);
4750
4751   return result;
4752 }