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