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