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