Merge remote-tracking branch 'origin/0.10'
[platform/upstream/gstreamer.git] / gst-libs / gst / rtsp / gstrtspconnection.c
1 /* GStreamer
2  * Copyright (C) <2005-2009> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 /*
20  * Unless otherwise indicated, Source Code is licensed under MIT license.
21  * See further explanation attached in License Statement (distributed in the file
22  * LICENSE).
23  *
24  * Permission is hereby granted, free of charge, to any person obtaining a copy of
25  * this software and associated documentation files (the "Software"), to deal in
26  * the Software without restriction, including without limitation the rights to
27  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28  * of the Software, and to permit persons to whom the Software is furnished to do
29  * so, subject to the following conditions:
30  *
31  * The above copyright notice and this permission notice shall be included in all
32  * copies or substantial portions of the Software.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40  * SOFTWARE.
41  */
42
43 /**
44  * SECTION:gstrtspconnection
45  * @short_description: manage RTSP connections
46  * @see_also: gstrtspurl
47  *  
48  * This object manages the RTSP connection to the server. It provides function
49  * to receive and send bytes and messages.
50  *  
51  * Last reviewed on 2007-07-24 (0.10.14)
52  */
53
54 #ifdef HAVE_CONFIG_H
55 #  include <config.h>
56 #endif
57
58 #include <stdio.h>
59 #include <errno.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <time.h>
63
64 /* we include this here to get the G_OS_* defines */
65 #include <glib.h>
66 #include <gst/gst.h>
67
68 #include "gstrtspconnection.h"
69
70 #include "gst/glib-compat-private.h"
71
72 #ifdef IP_TOS
73 union gst_sockaddr
74 {
75   struct sockaddr sa;
76   struct sockaddr_in sa_in;
77   struct sockaddr_in6 sa_in6;
78   struct sockaddr_storage sa_stor;
79 };
80 #endif
81
82 typedef struct
83 {
84   gint state;
85   guint save;
86   guchar out[3];                /* the size must be evenly divisible by 3 */
87   guint cout;
88   guint coutl;
89 } DecodeCtx;
90
91 #ifdef MSG_NOSIGNAL
92 #define SEND_FLAGS MSG_NOSIGNAL
93 #else
94 #define SEND_FLAGS 0
95 #endif
96
97 typedef enum
98 {
99   TUNNEL_STATE_NONE,
100   TUNNEL_STATE_GET,
101   TUNNEL_STATE_POST,
102   TUNNEL_STATE_COMPLETE
103 } GstRTSPTunnelState;
104
105 #define TUNNELID_LEN   24
106
107 struct _GstRTSPConnection
108 {
109   /*< private > */
110   /* URL for the connection */
111   GstRTSPUrl *url;
112
113   /* connection state */
114   GSocket *read_socket;
115   GSocket *write_socket;
116   gboolean manual_http;
117   GSocket *socket0, *socket1;
118   GCancellable *cancellable;
119
120   gchar tunnelid[TUNNELID_LEN];
121   gboolean tunneled;
122   GstRTSPTunnelState tstate;
123
124   gchar *ip;
125
126   gint read_ahead;
127
128   gchar *initial_buffer;
129   gsize initial_buffer_offset;
130
131   /* Session state */
132   gint cseq;                    /* sequence number */
133   gchar session_id[512];        /* session id */
134   gint timeout;                 /* session timeout in seconds */
135   GTimer *timer;                /* timeout timer */
136
137   /* Authentication */
138   GstRTSPAuthMethod auth_method;
139   gchar *username;
140   gchar *passwd;
141   GHashTable *auth_params;
142
143   DecodeCtx ctx;
144   DecodeCtx *ctxp;
145
146   gchar *proxy_host;
147   guint proxy_port;
148 };
149
150 enum
151 {
152   STATE_START = 0,
153   STATE_DATA_HEADER,
154   STATE_DATA_BODY,
155   STATE_READ_LINES,
156   STATE_END,
157   STATE_LAST
158 };
159
160 enum
161 {
162   READ_AHEAD_EOH = -1,          /* end of headers */
163   READ_AHEAD_CRLF = -2,
164   READ_AHEAD_CRLFCR = -3
165 };
166
167 /* a structure for constructing RTSPMessages */
168 typedef struct
169 {
170   gint state;
171   GstRTSPResult status;
172   guint8 buffer[4096];
173   guint offset;
174
175   guint line;
176   guint8 *body_data;
177   glong body_len;
178 } GstRTSPBuilder;
179
180 static void
181 build_reset (GstRTSPBuilder * builder)
182 {
183   g_free (builder->body_data);
184   memset (builder, 0, sizeof (GstRTSPBuilder));
185 }
186
187 /**
188  * gst_rtsp_connection_create:
189  * @url: a #GstRTSPUrl 
190  * @conn: storage for a #GstRTSPConnection
191  *
192  * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
193  * The connection will not yet attempt to connect to @url, use
194  * gst_rtsp_connection_connect().
195  *
196  * A copy of @url will be made.
197  *
198  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
199  */
200 GstRTSPResult
201 gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn)
202 {
203   GstRTSPConnection *newconn;
204
205   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
206
207   newconn = g_new0 (GstRTSPConnection, 1);
208
209   newconn->cancellable = g_cancellable_new ();
210
211   newconn->url = gst_rtsp_url_copy (url);
212   newconn->timer = g_timer_new ();
213   newconn->timeout = 60;
214   newconn->cseq = 1;
215
216   newconn->auth_method = GST_RTSP_AUTH_NONE;
217   newconn->username = NULL;
218   newconn->passwd = NULL;
219   newconn->auth_params = NULL;
220
221   *conn = newconn;
222
223   return GST_RTSP_OK;
224 }
225
226 /**
227  * gst_rtsp_connection_create_from_socket:
228  * @socket: a #GSocket
229  * @ip: the IP address of the other end
230  * @port: the port used by the other end
231  * @initial_buffer: data already read from @fd
232  * @conn: storage for a #GstRTSPConnection
233  *
234  * Create a new #GstRTSPConnection for handling communication on the existing
235  * socket @socket. The @initial_buffer contains any data already read from
236  * @socket which should be used before starting to read new data.
237  *
238  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
239  *
240  * Since: 0.10.25
241  */
242 GstRTSPResult
243 gst_rtsp_connection_create_from_socket (GSocket * socket, const gchar * ip,
244     guint16 port, const gchar * initial_buffer, GstRTSPConnection ** conn)
245 {
246   GstRTSPConnection *newconn = NULL;
247   GstRTSPUrl *url;
248   GstRTSPResult res;
249
250   g_return_val_if_fail (G_IS_SOCKET (socket), GST_RTSP_EINVAL);
251   g_return_val_if_fail (ip != NULL, GST_RTSP_EINVAL);
252   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
253
254   /* set to non-blocking mode so that we can cancel the communication */
255   g_socket_set_blocking (socket, FALSE);
256
257   /* create a url for the client address */
258   url = g_new0 (GstRTSPUrl, 1);
259   url->host = g_strdup (ip);
260   url->port = port;
261
262   /* now create the connection object */
263   GST_RTSP_CHECK (gst_rtsp_connection_create (url, &newconn), newconn_failed);
264   gst_rtsp_url_free (url);
265
266   /* both read and write initially */
267   newconn->socket0 = G_SOCKET (g_object_ref (socket));
268   newconn->socket1 = G_SOCKET (g_object_ref (socket));
269   newconn->write_socket = newconn->read_socket = newconn->socket0;
270
271   newconn->ip = g_strdup (ip);
272
273   newconn->initial_buffer = g_strdup (initial_buffer);
274
275   *conn = newconn;
276
277   return GST_RTSP_OK;
278
279   /* ERRORS */
280 newconn_failed:
281   {
282     gst_rtsp_url_free (url);
283     return res;
284   }
285 }
286
287 /**
288  * gst_rtsp_connection_accept:
289  * @socket: a socket
290  * @conn: storage for a #GstRTSPConnection
291  * @cancellable: a #GCancellable to cancel the operation
292  *
293  * Accept a new connection on @socket and create a new #GstRTSPConnection for
294  * handling communication on new socket.
295  *
296  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
297  *
298  * Since: 0.10.23
299  */
300 GstRTSPResult
301 gst_rtsp_connection_accept (GSocket * socket, GstRTSPConnection ** conn,
302     GCancellable * cancellable)
303 {
304   GError *err = NULL;
305   gchar *ip;
306   guint16 port;
307   GSocket *client_sock;
308   GSocketAddress *addr;
309   GstRTSPResult ret;
310
311   g_return_val_if_fail (G_IS_SOCKET (socket), GST_RTSP_EINVAL);
312   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
313
314   client_sock = g_socket_accept (socket, cancellable, &err);
315   if (!client_sock)
316     goto accept_failed;
317
318   addr = g_socket_get_remote_address (client_sock, &err);
319   if (!addr)
320     goto getnameinfo_failed;
321
322   ip = g_inet_address_to_string (g_inet_socket_address_get_address
323       (G_INET_SOCKET_ADDRESS (addr)));
324   port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
325
326   ret =
327       gst_rtsp_connection_create_from_socket (client_sock, ip, port, NULL,
328       conn);
329   g_free (ip);
330
331   return ret;
332
333   /* ERRORS */
334 accept_failed:
335   {
336     GST_DEBUG ("Accepting client failed: %s", err->message);
337     g_clear_error (&err);
338     return GST_RTSP_ESYS;
339   }
340 getnameinfo_failed:
341   {
342     if (!g_socket_close (client_sock, &err)) {
343       GST_DEBUG ("Closing socket failed: %s", err->message);
344       g_clear_error (&err);
345     }
346     g_object_unref (client_sock);
347     return GST_RTSP_ERROR;
348   }
349 }
350
351 static gchar *
352 do_resolve (const gchar * host, GCancellable * cancellable)
353 {
354   GResolver *resolver;
355   GInetAddress *addr;
356   GError *err = NULL;
357   gchar *ip;
358
359   addr = g_inet_address_new_from_string (host);
360   if (!addr) {
361     GList *results, *l;
362
363     resolver = g_resolver_get_default ();
364
365     results = g_resolver_lookup_by_name (resolver, host, cancellable, &err);
366     if (!results)
367       goto name_resolve;
368
369     for (l = results; l; l = l->next) {
370       GInetAddress *tmp = l->data;
371
372       if (g_inet_address_get_family (tmp) == G_SOCKET_FAMILY_IPV4 ||
373           g_inet_address_get_family (tmp) == G_SOCKET_FAMILY_IPV6) {
374         addr = G_INET_ADDRESS (g_object_ref (tmp));
375         break;
376       }
377     }
378
379     g_resolver_free_addresses (results);
380     g_object_unref (resolver);
381   }
382
383   if (!addr)
384     return NULL;
385
386   ip = g_inet_address_to_string (addr);
387   g_object_unref (addr);
388
389   return ip;
390
391   /* ERRORS */
392 name_resolve:
393   {
394     GST_ERROR ("failed to resolve %s: %s", host, err->message);
395     g_clear_error (&err);
396     g_object_unref (resolver);
397     return NULL;
398   }
399 }
400
401 static GstRTSPResult
402 do_connect (const gchar * ip, guint16 port, GSocket ** socket_out,
403     GTimeVal * timeout, GCancellable * cancellable)
404 {
405   GSocket *socket;
406   GstClockTime to;
407   GInetAddress *addr;
408   GSocketAddress *saddr;
409   GError *err = NULL;
410
411   addr = g_inet_address_new_from_string (ip);
412   g_assert (addr);
413   saddr = g_inet_socket_address_new (addr, port);
414   g_object_unref (addr);
415
416   socket =
417       g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM,
418       G_SOCKET_PROTOCOL_TCP, &err);
419   if (socket == NULL)
420     goto no_socket;
421
422   /* set to non-blocking mode so that we can cancel the connect */
423   g_socket_set_blocking (socket, FALSE);
424
425   /* we are going to connect ASYNC now */
426   if (!g_socket_connect (socket, saddr, cancellable, &err)) {
427     if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_PENDING))
428       goto sys_error;
429   } else {
430     goto done;
431   }
432
433   /* wait for connect to complete up to the specified timeout or until we got
434    * interrupted. */
435   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
436
437   g_socket_set_timeout (socket, (to + GST_SECOND - 1) / GST_SECOND);
438   if (!g_socket_condition_wait (socket, G_IO_OUT, cancellable, &err)) {
439     g_socket_set_timeout (socket, 0);
440     if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT))
441       goto timeout;
442     else
443       goto sys_error;
444   }
445   g_socket_set_timeout (socket, 0);
446
447   if (!g_socket_check_connect_result (socket, &err))
448     goto sys_error;
449
450 done:
451   g_object_unref (saddr);
452
453   *socket_out = socket;
454
455   return GST_RTSP_OK;
456
457   /* ERRORS */
458 no_socket:
459   {
460     GST_ERROR ("no socket: %s", err->message);
461     g_clear_error (&err);
462     g_object_unref (saddr);
463     return GST_RTSP_ESYS;
464   }
465 sys_error:
466   {
467     GST_ERROR ("system error: %s", err->message);
468     g_clear_error (&err);
469     g_object_unref (saddr);
470     g_object_unref (socket);
471     return GST_RTSP_ESYS;
472   }
473 timeout:
474   {
475     GST_ERROR ("timeout");
476     g_clear_error (&err);
477     g_object_unref (saddr);
478     g_object_unref (socket);
479     return GST_RTSP_ETIMEOUT;
480   }
481 }
482
483 static GstRTSPResult
484 setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout)
485 {
486   gint i;
487   GstRTSPResult res;
488   gchar *ip;
489   gchar *uri;
490   gchar *value;
491   guint16 port, url_port;
492   GstRTSPUrl *url;
493   gchar *hostparam;
494   GstRTSPMessage *msg;
495   GstRTSPMessage response;
496   gboolean old_http;
497
498   memset (&response, 0, sizeof (response));
499   gst_rtsp_message_init (&response);
500
501   /* create a random sessionid */
502   for (i = 0; i < TUNNELID_LEN; i++)
503     conn->tunnelid[i] = g_random_int_range ('a', 'z');
504   conn->tunnelid[TUNNELID_LEN - 1] = '\0';
505
506   url = conn->url;
507   /* get the port from the url */
508   gst_rtsp_url_get_port (url, &url_port);
509
510   if (conn->proxy_host) {
511     uri = g_strdup_printf ("http://%s:%d%s%s%s", url->host, url_port,
512         url->abspath, url->query ? "?" : "", url->query ? url->query : "");
513     hostparam = g_strdup_printf ("%s:%d", url->host, url_port);
514     ip = conn->proxy_host;
515     port = conn->proxy_port;
516   } else {
517     uri = g_strdup_printf ("%s%s%s", url->abspath, url->query ? "?" : "",
518         url->query ? url->query : "");
519     hostparam = NULL;
520     ip = conn->ip;
521     port = url_port;
522   }
523
524   /* create the GET request for the read connection */
525   GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_GET, uri),
526       no_message);
527   msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
528
529   if (hostparam != NULL)
530     gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam);
531   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
532       conn->tunnelid);
533   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
534       "application/x-rtsp-tunnelled");
535   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
536   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
537
538   /* we start by writing to this fd */
539   conn->write_socket = conn->socket0;
540
541   /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
542    * request from being base64 encoded */
543   conn->tunneled = FALSE;
544   GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed);
545   gst_rtsp_message_free (msg);
546   conn->tunneled = TRUE;
547
548   /* receive the response to the GET request */
549   /* we need to temporarily set manual_http to TRUE since
550    * gst_rtsp_connection_receive() will treat the HTTP response as a parsing
551    * failure otherwise */
552   old_http = conn->manual_http;
553   conn->manual_http = TRUE;
554   GST_RTSP_CHECK (gst_rtsp_connection_receive (conn, &response, timeout),
555       read_failed);
556   conn->manual_http = old_http;
557
558   if (response.type != GST_RTSP_MESSAGE_HTTP_RESPONSE ||
559       response.type_data.response.code != GST_RTSP_STS_OK)
560     goto wrong_result;
561
562   if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
563           &value, 0) == GST_RTSP_OK) {
564     if (conn->proxy_host) {
565       /* if we use a proxy we need to change the destination url */
566       g_free (url->host);
567       url->host = g_strdup (value);
568       g_free (hostparam);
569       hostparam = g_strdup_printf ("%s:%d", url->host, url_port);
570     } else {
571       /* and resolve the new ip address */
572       if (!(ip = do_resolve (value, conn->cancellable)))
573         goto not_resolved;
574       g_free (conn->ip);
575       conn->ip = ip;
576     }
577   }
578
579   /* connect to the host/port */
580   res = do_connect (ip, port, &conn->socket1, timeout, conn->cancellable);
581   if (res != GST_RTSP_OK)
582     goto connect_failed;
583
584   /* this is now our writing socket */
585   conn->write_socket = conn->socket1;
586
587   /* create the POST request for the write connection */
588   GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_POST, uri),
589       no_message);
590   msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
591
592   if (hostparam != NULL)
593     gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam);
594   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
595       conn->tunnelid);
596   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
597       "application/x-rtsp-tunnelled");
598   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
599   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
600   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_EXPIRES,
601       "Sun, 9 Jan 1972 00:00:00 GMT");
602   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "32767");
603
604   /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
605    * request from being base64 encoded */
606   conn->tunneled = FALSE;
607   GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed);
608   gst_rtsp_message_free (msg);
609   conn->tunneled = TRUE;
610
611 exit:
612   gst_rtsp_message_unset (&response);
613   g_free (hostparam);
614   g_free (uri);
615
616   return res;
617
618   /* ERRORS */
619 no_message:
620   {
621     GST_ERROR ("failed to create request (%d)", res);
622     goto exit;
623   }
624 write_failed:
625   {
626     GST_ERROR ("write failed (%d)", res);
627     gst_rtsp_message_free (msg);
628     conn->tunneled = TRUE;
629     goto exit;
630   }
631 read_failed:
632   {
633     GST_ERROR ("read failed (%d)", res);
634     conn->manual_http = FALSE;
635     goto exit;
636   }
637 wrong_result:
638   {
639     GST_ERROR ("got failure response %d %s", response.type_data.response.code,
640         response.type_data.response.reason);
641     res = GST_RTSP_ERROR;
642     goto exit;
643   }
644 not_resolved:
645   {
646     GST_ERROR ("could not resolve %s", conn->ip);
647     res = GST_RTSP_ENET;
648     goto exit;
649   }
650 connect_failed:
651   {
652     GST_ERROR ("failed to connect");
653     goto exit;
654   }
655 }
656
657 /**
658  * gst_rtsp_connection_connect:
659  * @conn: a #GstRTSPConnection 
660  * @timeout: a #GTimeVal timeout
661  *
662  * Attempt to connect to the url of @conn made with
663  * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
664  * forever. If @timeout contains a valid timeout, this function will return
665  * #GST_RTSP_ETIMEOUT after the timeout expired.
666  *
667  * This function can be cancelled with gst_rtsp_connection_flush().
668  *
669  * Returns: #GST_RTSP_OK when a connection could be made.
670  */
671 GstRTSPResult
672 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
673 {
674   GstRTSPResult res;
675   gchar *ip;
676   guint16 port;
677   GstRTSPUrl *url;
678
679   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
680   g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
681   g_return_val_if_fail (conn->socket0 == NULL, GST_RTSP_EINVAL);
682
683   url = conn->url;
684
685   if (conn->proxy_host && conn->tunneled) {
686     if (!(ip = do_resolve (conn->proxy_host, conn->cancellable))) {
687       GST_ERROR ("could not resolve %s", conn->proxy_host);
688       goto not_resolved;
689     }
690     port = conn->proxy_port;
691     g_free (conn->proxy_host);
692     conn->proxy_host = ip;
693   } else {
694     if (!(ip = do_resolve (url->host, conn->cancellable))) {
695       GST_ERROR ("could not resolve %s", url->host);
696       goto not_resolved;
697     }
698     /* get the port from the url */
699     gst_rtsp_url_get_port (url, &port);
700
701     g_free (conn->ip);
702     conn->ip = ip;
703   }
704
705   /* connect to the host/port */
706   res = do_connect (ip, port, &conn->socket0, timeout, conn->cancellable);
707   if (res != GST_RTSP_OK)
708     goto connect_failed;
709
710   /* this is our read URL */
711   conn->read_socket = conn->socket0;
712
713   if (conn->tunneled) {
714     res = setup_tunneling (conn, timeout);
715     if (res != GST_RTSP_OK)
716       goto tunneling_failed;
717   } else {
718     conn->write_socket = conn->socket0;
719   }
720
721   return GST_RTSP_OK;
722
723 not_resolved:
724   {
725     return GST_RTSP_ENET;
726   }
727 connect_failed:
728   {
729     GST_ERROR ("failed to connect");
730     return res;
731   }
732 tunneling_failed:
733   {
734     GST_ERROR ("failed to setup tunneling");
735     return res;
736   }
737 }
738
739 static void
740 auth_digest_compute_hex_urp (const gchar * username,
741     const gchar * realm, const gchar * password, gchar hex_urp[33])
742 {
743   GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
744   const gchar *digest_string;
745
746   g_checksum_update (md5_context, (const guchar *) username, strlen (username));
747   g_checksum_update (md5_context, (const guchar *) ":", 1);
748   g_checksum_update (md5_context, (const guchar *) realm, strlen (realm));
749   g_checksum_update (md5_context, (const guchar *) ":", 1);
750   g_checksum_update (md5_context, (const guchar *) password, strlen (password));
751   digest_string = g_checksum_get_string (md5_context);
752
753   memset (hex_urp, 0, 33);
754   memcpy (hex_urp, digest_string, strlen (digest_string));
755
756   g_checksum_free (md5_context);
757 }
758
759 static void
760 auth_digest_compute_response (const gchar * method,
761     const gchar * uri, const gchar * hex_a1, const gchar * nonce,
762     gchar response[33])
763 {
764   char hex_a2[33] = { 0, };
765   GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
766   const gchar *digest_string;
767
768   /* compute A2 */
769   g_checksum_update (md5_context, (const guchar *) method, strlen (method));
770   g_checksum_update (md5_context, (const guchar *) ":", 1);
771   g_checksum_update (md5_context, (const guchar *) uri, strlen (uri));
772   digest_string = g_checksum_get_string (md5_context);
773   memcpy (hex_a2, digest_string, strlen (digest_string));
774
775   /* compute KD */
776   g_checksum_reset (md5_context);
777   g_checksum_update (md5_context, (const guchar *) hex_a1, strlen (hex_a1));
778   g_checksum_update (md5_context, (const guchar *) ":", 1);
779   g_checksum_update (md5_context, (const guchar *) nonce, strlen (nonce));
780   g_checksum_update (md5_context, (const guchar *) ":", 1);
781
782   g_checksum_update (md5_context, (const guchar *) hex_a2, 32);
783   digest_string = g_checksum_get_string (md5_context);
784   memset (response, 0, 33);
785   memcpy (response, digest_string, strlen (digest_string));
786
787   g_checksum_free (md5_context);
788 }
789
790 static void
791 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
792 {
793   switch (conn->auth_method) {
794     case GST_RTSP_AUTH_BASIC:{
795       gchar *user_pass;
796       gchar *user_pass64;
797       gchar *auth_string;
798
799       if (conn->username == NULL || conn->passwd == NULL)
800         break;
801
802       user_pass = g_strdup_printf ("%s:%s", conn->username, conn->passwd);
803       user_pass64 = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
804       auth_string = g_strdup_printf ("Basic %s", user_pass64);
805
806       gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
807           auth_string);
808
809       g_free (user_pass);
810       g_free (user_pass64);
811       break;
812     }
813     case GST_RTSP_AUTH_DIGEST:{
814       gchar response[33], hex_urp[33];
815       gchar *auth_string, *auth_string2;
816       gchar *realm;
817       gchar *nonce;
818       gchar *opaque;
819       const gchar *uri;
820       const gchar *method;
821
822       /* we need to have some params set */
823       if (conn->auth_params == NULL || conn->username == NULL ||
824           conn->passwd == NULL)
825         break;
826
827       /* we need the realm and nonce */
828       realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm");
829       nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce");
830       if (realm == NULL || nonce == NULL)
831         break;
832
833       auth_digest_compute_hex_urp (conn->username, realm, conn->passwd,
834           hex_urp);
835
836       method = gst_rtsp_method_as_text (message->type_data.request.method);
837       uri = message->type_data.request.uri;
838
839       /* Assume no qop, algorithm=md5, stale=false */
840       /* For algorithm MD5, a1 = urp. */
841       auth_digest_compute_response (method, uri, hex_urp, nonce, response);
842       auth_string = g_strdup_printf ("Digest username=\"%s\", "
843           "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
844           conn->username, realm, nonce, uri, response);
845
846       opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
847       if (opaque) {
848         auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
849             opaque);
850         g_free (auth_string);
851         auth_string = auth_string2;
852       }
853       gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
854           auth_string);
855       break;
856     }
857     default:
858       /* Nothing to do */
859       break;
860   }
861 }
862
863 static void
864 gen_date_string (gchar * date_string, guint len)
865 {
866   static const char wkdays[7][4] =
867       { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
868   static const char months[12][4] =
869       { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
870     "Nov", "Dec"
871   };
872   struct tm tm;
873   time_t t;
874
875   time (&t);
876
877 #ifdef HAVE_GMTIME_R
878   gmtime_r (&t, &tm);
879 #else
880   tm = *gmtime (&t);
881 #endif
882
883   g_snprintf (date_string, len, "%s, %02d %s %04d %02d:%02d:%02d GMT",
884       wkdays[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], tm.tm_year + 1900,
885       tm.tm_hour, tm.tm_min, tm.tm_sec);
886 }
887
888 static GstRTSPResult
889 write_bytes (GSocket * socket, const guint8 * buffer, guint * idx, guint size,
890     GCancellable * cancellable)
891 {
892   guint left;
893
894   if (G_UNLIKELY (*idx > size))
895     return GST_RTSP_ERROR;
896
897   left = size - *idx;
898
899   while (left) {
900     GError *err = NULL;
901     gssize r;
902
903     r = g_socket_send (socket, (gchar *) & buffer[*idx], left, cancellable,
904         &err);
905     if (G_UNLIKELY (r == 0)) {
906       return GST_RTSP_EINTR;
907     } else if (G_UNLIKELY (r < 0)) {
908       if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
909         g_clear_error (&err);
910         return GST_RTSP_EINTR;
911       }
912       g_clear_error (&err);
913       return GST_RTSP_ESYS;
914     } else {
915       left -= r;
916       *idx += r;
917     }
918   }
919   return GST_RTSP_OK;
920 }
921
922 static gint
923 fill_raw_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
924     GError ** err)
925 {
926   gint out = 0;
927
928   if (G_UNLIKELY (conn->initial_buffer != NULL)) {
929     gsize left = strlen (&conn->initial_buffer[conn->initial_buffer_offset]);
930
931     out = MIN (left, size);
932     memcpy (buffer, &conn->initial_buffer[conn->initial_buffer_offset], out);
933
934     if (left == (gsize) out) {
935       g_free (conn->initial_buffer);
936       conn->initial_buffer = NULL;
937       conn->initial_buffer_offset = 0;
938     } else
939       conn->initial_buffer_offset += out;
940   }
941
942   if (G_LIKELY (size > (guint) out)) {
943     gssize r;
944
945     r = g_socket_receive (conn->read_socket, (gchar *) & buffer[out],
946         size - out, conn->cancellable, err);
947     if (r <= 0) {
948       if (out == 0)
949         out = r;
950     } else
951       out += r;
952   }
953
954   return out;
955 }
956
957 static gint
958 fill_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
959     GError ** err)
960 {
961   DecodeCtx *ctx = conn->ctxp;
962   gint out = 0;
963
964   if (ctx) {
965     while (size > 0) {
966       guint8 in[sizeof (ctx->out) * 4 / 3];
967       gint r;
968
969       while (size > 0 && ctx->cout < ctx->coutl) {
970         /* we have some leftover bytes */
971         *buffer++ = ctx->out[ctx->cout++];
972         size--;
973         out++;
974       }
975
976       /* got what we needed? */
977       if (size == 0)
978         break;
979
980       /* try to read more bytes */
981       r = fill_raw_bytes (conn, in, sizeof (in), err);
982       if (r <= 0) {
983         if (out == 0)
984           out = r;
985         break;
986       }
987
988       ctx->cout = 0;
989       ctx->coutl =
990           g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state,
991           &ctx->save);
992     }
993   } else {
994     out = fill_raw_bytes (conn, buffer, size, err);
995   }
996
997   return out;
998 }
999
1000 static GstRTSPResult
1001 read_bytes (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size)
1002 {
1003   guint left;
1004   GError *err = NULL;
1005
1006   if (G_UNLIKELY (*idx > size))
1007     return GST_RTSP_ERROR;
1008
1009   left = size - *idx;
1010
1011   while (left) {
1012     gint r;
1013
1014     r = fill_bytes (conn, &buffer[*idx], left, &err);
1015     if (G_UNLIKELY (r == 0)) {
1016       return GST_RTSP_EEOF;
1017     } else if (G_UNLIKELY (r < 0)) {
1018       if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
1019         g_clear_error (&err);
1020         return GST_RTSP_EINTR;
1021       }
1022       g_clear_error (&err);
1023       return GST_RTSP_ESYS;
1024     } else {
1025       left -= r;
1026       *idx += r;
1027     }
1028   }
1029   return GST_RTSP_OK;
1030 }
1031
1032 /* The code below tries to handle clients using \r, \n or \r\n to indicate the
1033  * end of a line. It even does its best to handle clients which mix them (even
1034  * though this is a really stupid idea (tm).) It also handles Line White Space
1035  * (LWS), where a line end followed by whitespace is considered LWS. This is
1036  * the method used in RTSP (and HTTP) to break long lines.
1037  */
1038 static GstRTSPResult
1039 read_line (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size)
1040 {
1041   GError *err = NULL;
1042
1043   while (TRUE) {
1044     guint8 c;
1045     gint r;
1046
1047     if (conn->read_ahead == READ_AHEAD_EOH) {
1048       /* the last call to read_line() already determined that we have reached
1049        * the end of the headers, so convey that information now */
1050       conn->read_ahead = 0;
1051       break;
1052     } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1053       /* the last call to read_line() left off after having read \r\n */
1054       c = '\n';
1055     } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1056       /* the last call to read_line() left off after having read \r\n\r */
1057       c = '\r';
1058     } else if (conn->read_ahead != 0) {
1059       /* the last call to read_line() left us with a character to start with */
1060       c = (guint8) conn->read_ahead;
1061       conn->read_ahead = 0;
1062     } else {
1063       /* read the next character */
1064       r = fill_bytes (conn, &c, 1, &err);
1065       if (G_UNLIKELY (r == 0)) {
1066         return GST_RTSP_EEOF;
1067       } else if (G_UNLIKELY (r < 0)) {
1068         if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
1069           g_clear_error (&err);
1070           return GST_RTSP_EINTR;
1071         }
1072
1073         g_clear_error (&err);
1074         return GST_RTSP_ESYS;
1075       }
1076     }
1077
1078     /* special treatment of line endings */
1079     if (c == '\r' || c == '\n') {
1080       guint8 read_ahead;
1081
1082     retry:
1083       /* need to read ahead one more character to know what to do... */
1084       r = fill_bytes (conn, &read_ahead, 1, &err);
1085       if (G_UNLIKELY (r == 0)) {
1086         return GST_RTSP_EEOF;
1087       } else if (G_UNLIKELY (r < 0)) {
1088         if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
1089           /* remember the original character we read and try again next time */
1090           if (conn->read_ahead == 0)
1091             conn->read_ahead = c;
1092           return GST_RTSP_EINTR;
1093           g_clear_error (&err);
1094           return GST_RTSP_EINTR;
1095         }
1096
1097         g_clear_error (&err);
1098         return GST_RTSP_ESYS;
1099       }
1100
1101       if (read_ahead == ' ' || read_ahead == '\t') {
1102         if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1103           /* got \r\n\r followed by whitespace, treat it as a normal line
1104            * followed by one starting with LWS */
1105           conn->read_ahead = read_ahead;
1106           break;
1107         } else {
1108           /* got LWS, change the line ending to a space and continue */
1109           c = ' ';
1110           conn->read_ahead = read_ahead;
1111         }
1112       } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1113         if (read_ahead == '\r' || read_ahead == '\n') {
1114           /* got \r\n\r\r or \r\n\r\n, treat it as the end of the headers */
1115           conn->read_ahead = READ_AHEAD_EOH;
1116           break;
1117         } else {
1118           /* got \r\n\r followed by something else, this is not really
1119            * supported since we have probably just eaten the first character
1120            * of the body or the next message, so just ignore the second \r
1121            * and live with it... */
1122           conn->read_ahead = read_ahead;
1123           break;
1124         }
1125       } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1126         if (read_ahead == '\r') {
1127           /* got \r\n\r so far, need one more character... */
1128           conn->read_ahead = READ_AHEAD_CRLFCR;
1129           goto retry;
1130         } else if (read_ahead == '\n') {
1131           /* got \r\n\n, treat it as the end of the headers */
1132           conn->read_ahead = READ_AHEAD_EOH;
1133           break;
1134         } else {
1135           /* found the end of a line, keep read_ahead for the next line */
1136           conn->read_ahead = read_ahead;
1137           break;
1138         }
1139       } else if (c == read_ahead) {
1140         /* got double \r or \n, treat it as the end of the headers */
1141         conn->read_ahead = READ_AHEAD_EOH;
1142         break;
1143       } else if (c == '\r' && read_ahead == '\n') {
1144         /* got \r\n so far, still need more to know what to do... */
1145         conn->read_ahead = READ_AHEAD_CRLF;
1146         goto retry;
1147       } else {
1148         /* found the end of a line, keep read_ahead for the next line */
1149         conn->read_ahead = read_ahead;
1150         break;
1151       }
1152     }
1153
1154     if (G_LIKELY (*idx < size - 1))
1155       buffer[(*idx)++] = c;
1156   }
1157   buffer[*idx] = '\0';
1158
1159   return GST_RTSP_OK;
1160 }
1161
1162 /**
1163  * gst_rtsp_connection_write:
1164  * @conn: a #GstRTSPConnection
1165  * @data: the data to write
1166  * @size: the size of @data
1167  * @timeout: a timeout value or #NULL
1168  *
1169  * Attempt to write @size bytes of @data to the connected @conn, blocking up to
1170  * the specified @timeout. @timeout can be #NULL, in which case this function
1171  * might block forever.
1172  * 
1173  * This function can be cancelled with gst_rtsp_connection_flush().
1174  *
1175  * Returns: #GST_RTSP_OK on success.
1176  */
1177 GstRTSPResult
1178 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
1179     guint size, GTimeVal * timeout)
1180 {
1181   guint offset;
1182   GstClockTime to;
1183   GstRTSPResult res;
1184   GError *err = NULL;
1185
1186   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1187   g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
1188   g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
1189
1190   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
1191
1192   offset = 0;
1193
1194   while (TRUE) {
1195     /* try to write */
1196     res =
1197         write_bytes (conn->write_socket, data, &offset, size,
1198         conn->cancellable);
1199     if (G_LIKELY (res == GST_RTSP_OK))
1200       break;
1201     if (G_UNLIKELY (res != GST_RTSP_EINTR))
1202       goto write_error;
1203
1204     /* not all is written, wait until we can write more */
1205     g_socket_set_timeout (conn->write_socket,
1206         (to + GST_SECOND - 1) / GST_SECOND);
1207     if (!g_socket_condition_wait (conn->write_socket,
1208             G_IO_OUT | G_IO_ERR | G_IO_HUP, conn->cancellable, &err)) {
1209       g_socket_set_timeout (conn->write_socket, 0);
1210       if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)) {
1211         g_clear_error (&err);
1212         goto stopped;
1213       } else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
1214         g_clear_error (&err);
1215         goto timeout;
1216       }
1217       g_clear_error (&err);
1218       goto select_error;
1219     }
1220     g_socket_set_timeout (conn->write_socket, 0);
1221   }
1222   return GST_RTSP_OK;
1223
1224   /* ERRORS */
1225 timeout:
1226   {
1227     return GST_RTSP_ETIMEOUT;
1228   }
1229 select_error:
1230   {
1231     return GST_RTSP_ESYS;
1232   }
1233 stopped:
1234   {
1235     return GST_RTSP_EINTR;
1236   }
1237 write_error:
1238   {
1239     return res;
1240   }
1241 }
1242
1243 static GString *
1244 message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message)
1245 {
1246   GString *str = NULL;
1247
1248   str = g_string_new ("");
1249
1250   switch (message->type) {
1251     case GST_RTSP_MESSAGE_REQUEST:
1252       /* create request string, add CSeq */
1253       g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
1254           "CSeq: %d\r\n",
1255           gst_rtsp_method_as_text (message->type_data.request.method),
1256           message->type_data.request.uri, conn->cseq++);
1257       /* add session id if we have one */
1258       if (conn->session_id[0] != '\0') {
1259         gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
1260         gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
1261             conn->session_id);
1262       }
1263       /* add any authentication headers */
1264       add_auth_header (conn, message);
1265       break;
1266     case GST_RTSP_MESSAGE_RESPONSE:
1267       /* create response string */
1268       g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
1269           message->type_data.response.code, message->type_data.response.reason);
1270       break;
1271     case GST_RTSP_MESSAGE_HTTP_REQUEST:
1272       /* create request string */
1273       g_string_append_printf (str, "%s %s HTTP/%s\r\n",
1274           gst_rtsp_method_as_text (message->type_data.request.method),
1275           message->type_data.request.uri,
1276           gst_rtsp_version_as_text (message->type_data.request.version));
1277       /* add any authentication headers */
1278       add_auth_header (conn, message);
1279       break;
1280     case GST_RTSP_MESSAGE_HTTP_RESPONSE:
1281       /* create response string */
1282       g_string_append_printf (str, "HTTP/%s %d %s\r\n",
1283           gst_rtsp_version_as_text (message->type_data.request.version),
1284           message->type_data.response.code, message->type_data.response.reason);
1285       break;
1286     case GST_RTSP_MESSAGE_DATA:
1287     {
1288       guint8 data_header[4];
1289
1290       /* prepare data header */
1291       data_header[0] = '$';
1292       data_header[1] = message->type_data.data.channel;
1293       data_header[2] = (message->body_size >> 8) & 0xff;
1294       data_header[3] = message->body_size & 0xff;
1295
1296       /* create string with header and data */
1297       str = g_string_append_len (str, (gchar *) data_header, 4);
1298       str =
1299           g_string_append_len (str, (gchar *) message->body,
1300           message->body_size);
1301       break;
1302     }
1303     default:
1304       g_string_free (str, TRUE);
1305       g_return_val_if_reached (NULL);
1306       break;
1307   }
1308
1309   /* append headers and body */
1310   if (message->type != GST_RTSP_MESSAGE_DATA) {
1311     gchar date_string[100];
1312
1313     gen_date_string (date_string, sizeof (date_string));
1314
1315     /* add date header */
1316     gst_rtsp_message_remove_header (message, GST_RTSP_HDR_DATE, -1);
1317     gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
1318
1319     /* append headers */
1320     gst_rtsp_message_append_headers (message, str);
1321
1322     /* append Content-Length and body if needed */
1323     if (message->body != NULL && message->body_size > 0) {
1324       gchar *len;
1325
1326       len = g_strdup_printf ("%d", message->body_size);
1327       g_string_append_printf (str, "%s: %s\r\n",
1328           gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
1329       g_free (len);
1330       /* header ends here */
1331       g_string_append (str, "\r\n");
1332       str =
1333           g_string_append_len (str, (gchar *) message->body,
1334           message->body_size);
1335     } else {
1336       /* just end headers */
1337       g_string_append (str, "\r\n");
1338     }
1339   }
1340
1341   return str;
1342 }
1343
1344 /**
1345  * gst_rtsp_connection_send:
1346  * @conn: a #GstRTSPConnection
1347  * @message: the message to send
1348  * @timeout: a timeout value or #NULL
1349  *
1350  * Attempt to send @message to the connected @conn, blocking up to
1351  * the specified @timeout. @timeout can be #NULL, in which case this function
1352  * might block forever.
1353  * 
1354  * This function can be cancelled with gst_rtsp_connection_flush().
1355  *
1356  * Returns: #GST_RTSP_OK on success.
1357  */
1358 GstRTSPResult
1359 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
1360     GTimeVal * timeout)
1361 {
1362   GString *string = NULL;
1363   GstRTSPResult res;
1364   gchar *str;
1365   gsize len;
1366
1367   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1368   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
1369
1370   if (G_UNLIKELY (!(string = message_to_string (conn, message))))
1371     goto no_message;
1372
1373   if (conn->tunneled) {
1374     str = g_base64_encode ((const guchar *) string->str, string->len);
1375     g_string_free (string, TRUE);
1376     len = strlen (str);
1377   } else {
1378     str = string->str;
1379     len = string->len;
1380     g_string_free (string, FALSE);
1381   }
1382
1383   /* write request */
1384   res = gst_rtsp_connection_write (conn, (guint8 *) str, len, timeout);
1385
1386   g_free (str);
1387
1388   return res;
1389
1390 no_message:
1391   {
1392     g_warning ("Wrong message");
1393     return GST_RTSP_EINVAL;
1394   }
1395 }
1396
1397 static GstRTSPResult
1398 parse_string (gchar * dest, gint size, gchar ** src)
1399 {
1400   GstRTSPResult res = GST_RTSP_OK;
1401   gint idx;
1402
1403   idx = 0;
1404   /* skip spaces */
1405   while (g_ascii_isspace (**src))
1406     (*src)++;
1407
1408   while (!g_ascii_isspace (**src) && **src != '\0') {
1409     if (idx < size - 1)
1410       dest[idx++] = **src;
1411     else
1412       res = GST_RTSP_EPARSE;
1413     (*src)++;
1414   }
1415   if (size > 0)
1416     dest[idx] = '\0';
1417
1418   return res;
1419 }
1420
1421 static GstRTSPResult
1422 parse_protocol_version (gchar * protocol, GstRTSPMsgType * type,
1423     GstRTSPVersion * version)
1424 {
1425   GstRTSPResult res = GST_RTSP_OK;
1426   gchar *ver;
1427
1428   if (G_LIKELY ((ver = strchr (protocol, '/')) != NULL)) {
1429     guint major;
1430     guint minor;
1431     gchar dummychar;
1432
1433     *ver++ = '\0';
1434
1435     /* the version number must be formatted as X.Y with nothing following */
1436     if (sscanf (ver, "%u.%u%c", &major, &minor, &dummychar) != 2)
1437       res = GST_RTSP_EPARSE;
1438
1439     if (g_ascii_strcasecmp (protocol, "RTSP") == 0) {
1440       if (major != 1 || minor != 0) {
1441         *version = GST_RTSP_VERSION_INVALID;
1442         res = GST_RTSP_ERROR;
1443       }
1444     } else if (g_ascii_strcasecmp (protocol, "HTTP") == 0) {
1445       if (*type == GST_RTSP_MESSAGE_REQUEST)
1446         *type = GST_RTSP_MESSAGE_HTTP_REQUEST;
1447       else if (*type == GST_RTSP_MESSAGE_RESPONSE)
1448         *type = GST_RTSP_MESSAGE_HTTP_RESPONSE;
1449
1450       if (major == 1 && minor == 1) {
1451         *version = GST_RTSP_VERSION_1_1;
1452       } else if (major != 1 || minor != 0) {
1453         *version = GST_RTSP_VERSION_INVALID;
1454         res = GST_RTSP_ERROR;
1455       }
1456     } else
1457       res = GST_RTSP_EPARSE;
1458   } else
1459     res = GST_RTSP_EPARSE;
1460
1461   return res;
1462 }
1463
1464 static GstRTSPResult
1465 parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
1466 {
1467   GstRTSPResult res = GST_RTSP_OK;
1468   GstRTSPResult res2;
1469   gchar versionstr[20];
1470   gchar codestr[4];
1471   gint code;
1472   gchar *bptr;
1473
1474   bptr = (gchar *) buffer;
1475
1476   if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
1477     res = GST_RTSP_EPARSE;
1478
1479   if (parse_string (codestr, sizeof (codestr), &bptr) != GST_RTSP_OK)
1480     res = GST_RTSP_EPARSE;
1481   code = atoi (codestr);
1482   if (G_UNLIKELY (*codestr == '\0' || code < 0 || code >= 600))
1483     res = GST_RTSP_EPARSE;
1484
1485   while (g_ascii_isspace (*bptr))
1486     bptr++;
1487
1488   if (G_UNLIKELY (gst_rtsp_message_init_response (msg, code, bptr,
1489               NULL) != GST_RTSP_OK))
1490     res = GST_RTSP_EPARSE;
1491
1492   res2 = parse_protocol_version (versionstr, &msg->type,
1493       &msg->type_data.response.version);
1494   if (G_LIKELY (res == GST_RTSP_OK))
1495     res = res2;
1496
1497   return res;
1498 }
1499
1500 static GstRTSPResult
1501 parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
1502 {
1503   GstRTSPResult res = GST_RTSP_OK;
1504   GstRTSPResult res2;
1505   gchar versionstr[20];
1506   gchar methodstr[20];
1507   gchar urlstr[4096];
1508   gchar *bptr;
1509   GstRTSPMethod method;
1510
1511   bptr = (gchar *) buffer;
1512
1513   if (parse_string (methodstr, sizeof (methodstr), &bptr) != GST_RTSP_OK)
1514     res = GST_RTSP_EPARSE;
1515   method = gst_rtsp_find_method (methodstr);
1516
1517   if (parse_string (urlstr, sizeof (urlstr), &bptr) != GST_RTSP_OK)
1518     res = GST_RTSP_EPARSE;
1519   if (G_UNLIKELY (*urlstr == '\0'))
1520     res = GST_RTSP_EPARSE;
1521
1522   if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
1523     res = GST_RTSP_EPARSE;
1524
1525   if (G_UNLIKELY (*bptr != '\0'))
1526     res = GST_RTSP_EPARSE;
1527
1528   if (G_UNLIKELY (gst_rtsp_message_init_request (msg, method,
1529               urlstr) != GST_RTSP_OK))
1530     res = GST_RTSP_EPARSE;
1531
1532   res2 = parse_protocol_version (versionstr, &msg->type,
1533       &msg->type_data.request.version);
1534   if (G_LIKELY (res == GST_RTSP_OK))
1535     res = res2;
1536
1537   if (G_LIKELY (msg->type == GST_RTSP_MESSAGE_REQUEST)) {
1538     /* GET and POST are not allowed as RTSP methods */
1539     if (msg->type_data.request.method == GST_RTSP_GET ||
1540         msg->type_data.request.method == GST_RTSP_POST) {
1541       msg->type_data.request.method = GST_RTSP_INVALID;
1542       if (res == GST_RTSP_OK)
1543         res = GST_RTSP_ERROR;
1544     }
1545   } else if (msg->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
1546     /* only GET and POST are allowed as HTTP methods */
1547     if (msg->type_data.request.method != GST_RTSP_GET &&
1548         msg->type_data.request.method != GST_RTSP_POST) {
1549       msg->type_data.request.method = GST_RTSP_INVALID;
1550       if (res == GST_RTSP_OK)
1551         res = GST_RTSP_ERROR;
1552     }
1553   }
1554
1555   return res;
1556 }
1557
1558 /* parsing lines means reading a Key: Value pair */
1559 static GstRTSPResult
1560 parse_line (guint8 * buffer, GstRTSPMessage * msg)
1561 {
1562   GstRTSPHeaderField field;
1563   gchar *line = (gchar *) buffer;
1564   gchar *value;
1565
1566   if ((value = strchr (line, ':')) == NULL || value == line)
1567     goto parse_error;
1568
1569   /* trim space before the colon */
1570   if (value[-1] == ' ')
1571     value[-1] = '\0';
1572
1573   /* replace the colon with a NUL */
1574   *value++ = '\0';
1575
1576   /* find the header */
1577   field = gst_rtsp_find_header_field (line);
1578   if (field == GST_RTSP_HDR_INVALID)
1579     goto done;
1580
1581   /* split up the value in multiple key:value pairs if it contains comma(s) */
1582   while (*value != '\0') {
1583     gchar *next_value;
1584     gchar *comma = NULL;
1585     gboolean quoted = FALSE;
1586     guint comment = 0;
1587
1588     /* trim leading space */
1589     if (*value == ' ')
1590       value++;
1591
1592     /* for headers which may not appear multiple times, and thus may not
1593      * contain multiple values on the same line, we can short-circuit the loop
1594      * below and the entire value results in just one key:value pair*/
1595     if (!gst_rtsp_header_allow_multiple (field))
1596       next_value = value + strlen (value);
1597     else
1598       next_value = value;
1599
1600     /* find the next value, taking special care of quotes and comments */
1601     while (*next_value != '\0') {
1602       if ((quoted || comment != 0) && *next_value == '\\' &&
1603           next_value[1] != '\0')
1604         next_value++;
1605       else if (comment == 0 && *next_value == '"')
1606         quoted = !quoted;
1607       else if (!quoted && *next_value == '(')
1608         comment++;
1609       else if (comment != 0 && *next_value == ')')
1610         comment--;
1611       else if (!quoted && comment == 0) {
1612         /* To quote RFC 2068: "User agents MUST take special care in parsing
1613          * the WWW-Authenticate field value if it contains more than one
1614          * challenge, or if more than one WWW-Authenticate header field is
1615          * provided, since the contents of a challenge may itself contain a
1616          * comma-separated list of authentication parameters."
1617          *
1618          * What this means is that we cannot just look for an unquoted comma
1619          * when looking for multiple values in Proxy-Authenticate and
1620          * WWW-Authenticate headers. Instead we need to look for the sequence
1621          * "comma [space] token space token" before we can split after the
1622          * comma...
1623          */
1624         if (field == GST_RTSP_HDR_PROXY_AUTHENTICATE ||
1625             field == GST_RTSP_HDR_WWW_AUTHENTICATE) {
1626           if (*next_value == ',') {
1627             if (next_value[1] == ' ') {
1628               /* skip any space following the comma so we do not mistake it for
1629                * separating between two tokens */
1630               next_value++;
1631             }
1632             comma = next_value;
1633           } else if (*next_value == ' ' && next_value[1] != ',' &&
1634               next_value[1] != '=' && comma != NULL) {
1635             next_value = comma;
1636             comma = NULL;
1637             break;
1638           }
1639         } else if (*next_value == ',')
1640           break;
1641       }
1642
1643       next_value++;
1644     }
1645
1646     /* trim space */
1647     if (value != next_value && next_value[-1] == ' ')
1648       next_value[-1] = '\0';
1649
1650     if (*next_value != '\0')
1651       *next_value++ = '\0';
1652
1653     /* add the key:value pair */
1654     if (*value != '\0')
1655       gst_rtsp_message_add_header (msg, field, value);
1656
1657     value = next_value;
1658   }
1659
1660 done:
1661   return GST_RTSP_OK;
1662
1663   /* ERRORS */
1664 parse_error:
1665   {
1666     return GST_RTSP_EPARSE;
1667   }
1668 }
1669
1670 /* convert all consecutive whitespace to a single space */
1671 static void
1672 normalize_line (guint8 * buffer)
1673 {
1674   while (*buffer) {
1675     if (g_ascii_isspace (*buffer)) {
1676       guint8 *tmp;
1677
1678       *buffer++ = ' ';
1679       for (tmp = buffer; g_ascii_isspace (*tmp); tmp++) {
1680       }
1681       if (buffer != tmp)
1682         memmove (buffer, tmp, strlen ((gchar *) tmp) + 1);
1683     } else {
1684       buffer++;
1685     }
1686   }
1687 }
1688
1689 /* returns:
1690  *  GST_RTSP_OK when a complete message was read.
1691  *  GST_RTSP_EEOF: when the read socket is closed
1692  *  GST_RTSP_EINTR: when more data is needed.
1693  *  GST_RTSP_..: some other error occured.
1694  */
1695 static GstRTSPResult
1696 build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
1697     GstRTSPConnection * conn)
1698 {
1699   GstRTSPResult res;
1700
1701   while (TRUE) {
1702     switch (builder->state) {
1703       case STATE_START:
1704       {
1705         guint8 c;
1706
1707         builder->offset = 0;
1708         res =
1709             read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 1);
1710         if (res != GST_RTSP_OK)
1711           goto done;
1712
1713         c = builder->buffer[0];
1714
1715         /* we have 1 bytes now and we can see if this is a data message or
1716          * not */
1717         if (c == '$') {
1718           /* data message, prepare for the header */
1719           builder->state = STATE_DATA_HEADER;
1720         } else if (c == '\n' || c == '\r') {
1721           /* skip \n and \r */
1722           builder->offset = 0;
1723         } else {
1724           builder->line = 0;
1725           builder->state = STATE_READ_LINES;
1726         }
1727         break;
1728       }
1729       case STATE_DATA_HEADER:
1730       {
1731         res =
1732             read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 4);
1733         if (res != GST_RTSP_OK)
1734           goto done;
1735
1736         gst_rtsp_message_init_data (message, builder->buffer[1]);
1737
1738         builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
1739         builder->body_data = g_malloc (builder->body_len + 1);
1740         builder->body_data[builder->body_len] = '\0';
1741         builder->offset = 0;
1742         builder->state = STATE_DATA_BODY;
1743         break;
1744       }
1745       case STATE_DATA_BODY:
1746       {
1747         res =
1748             read_bytes (conn, builder->body_data, &builder->offset,
1749             builder->body_len);
1750         if (res != GST_RTSP_OK)
1751           goto done;
1752
1753         /* we have the complete body now, store in the message adjusting the
1754          * length to include the trailing '\0' */
1755         gst_rtsp_message_take_body (message,
1756             (guint8 *) builder->body_data, builder->body_len + 1);
1757         builder->body_data = NULL;
1758         builder->body_len = 0;
1759
1760         builder->state = STATE_END;
1761         break;
1762       }
1763       case STATE_READ_LINES:
1764       {
1765         res = read_line (conn, builder->buffer, &builder->offset,
1766             sizeof (builder->buffer));
1767         if (res != GST_RTSP_OK)
1768           goto done;
1769
1770         /* we have a regular response */
1771         if (builder->buffer[0] == '\0') {
1772           gchar *hdrval;
1773
1774           /* empty line, end of message header */
1775           /* see if there is a Content-Length header, but ignore it if this
1776            * is a POST request with an x-sessioncookie header */
1777           if (gst_rtsp_message_get_header (message,
1778                   GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK &&
1779               (message->type != GST_RTSP_MESSAGE_HTTP_REQUEST ||
1780                   message->type_data.request.method != GST_RTSP_POST ||
1781                   gst_rtsp_message_get_header (message,
1782                       GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) {
1783             /* there is, prepare to read the body */
1784             builder->body_len = atol (hdrval);
1785             builder->body_data = g_try_malloc (builder->body_len + 1);
1786             /* we can't do much here, we need the length to know how many bytes
1787              * we need to read next and when allocation fails, something is
1788              * probably wrong with the length. */
1789             if (builder->body_data == NULL)
1790               goto invalid_body_len;
1791
1792             builder->body_data[builder->body_len] = '\0';
1793             builder->offset = 0;
1794             builder->state = STATE_DATA_BODY;
1795           } else {
1796             builder->state = STATE_END;
1797           }
1798           break;
1799         }
1800
1801         /* we have a line */
1802         normalize_line (builder->buffer);
1803         if (builder->line == 0) {
1804           /* first line, check for response status */
1805           if (memcmp (builder->buffer, "RTSP", 4) == 0 ||
1806               memcmp (builder->buffer, "HTTP", 4) == 0) {
1807             builder->status = parse_response_status (builder->buffer, message);
1808           } else {
1809             builder->status = parse_request_line (builder->buffer, message);
1810           }
1811         } else {
1812           /* else just parse the line */
1813           res = parse_line (builder->buffer, message);
1814           if (res != GST_RTSP_OK)
1815             builder->status = res;
1816         }
1817         builder->line++;
1818         builder->offset = 0;
1819         break;
1820       }
1821       case STATE_END:
1822       {
1823         gchar *session_cookie;
1824         gchar *session_id;
1825
1826         if (message->type == GST_RTSP_MESSAGE_DATA) {
1827           /* data messages don't have headers */
1828           res = GST_RTSP_OK;
1829           goto done;
1830         }
1831
1832         /* save the tunnel session in the connection */
1833         if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST &&
1834             !conn->manual_http &&
1835             conn->tstate == TUNNEL_STATE_NONE &&
1836             gst_rtsp_message_get_header (message, GST_RTSP_HDR_X_SESSIONCOOKIE,
1837                 &session_cookie, 0) == GST_RTSP_OK) {
1838           strncpy (conn->tunnelid, session_cookie, TUNNELID_LEN);
1839           conn->tunnelid[TUNNELID_LEN - 1] = '\0';
1840           conn->tunneled = TRUE;
1841         }
1842
1843         /* save session id in the connection for further use */
1844         if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
1845             gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
1846                 &session_id, 0) == GST_RTSP_OK) {
1847           gint maxlen, i;
1848
1849           maxlen = sizeof (conn->session_id) - 1;
1850           /* the sessionid can have attributes marked with ;
1851            * Make sure we strip them */
1852           for (i = 0; session_id[i] != '\0'; i++) {
1853             if (session_id[i] == ';') {
1854               maxlen = i;
1855               /* parse timeout */
1856               do {
1857                 i++;
1858               } while (g_ascii_isspace (session_id[i]));
1859               if (g_str_has_prefix (&session_id[i], "timeout=")) {
1860                 gint to;
1861
1862                 /* if we parsed something valid, configure */
1863                 if ((to = atoi (&session_id[i + 8])) > 0)
1864                   conn->timeout = to;
1865               }
1866               break;
1867             }
1868           }
1869
1870           /* make sure to not overflow */
1871           strncpy (conn->session_id, session_id, maxlen);
1872           conn->session_id[maxlen] = '\0';
1873         }
1874         res = builder->status;
1875         goto done;
1876       }
1877       default:
1878         res = GST_RTSP_ERROR;
1879         break;
1880     }
1881   }
1882 done:
1883   return res;
1884
1885   /* ERRORS */
1886 invalid_body_len:
1887   {
1888     GST_DEBUG ("could not allocate body");
1889     return GST_RTSP_ERROR;
1890   }
1891 }
1892
1893 /**
1894  * gst_rtsp_connection_read:
1895  * @conn: a #GstRTSPConnection
1896  * @data: the data to read
1897  * @size: the size of @data
1898  * @timeout: a timeout value or #NULL
1899  *
1900  * Attempt to read @size bytes into @data from the connected @conn, blocking up to
1901  * the specified @timeout. @timeout can be #NULL, in which case this function
1902  * might block forever.
1903  *
1904  * This function can be cancelled with gst_rtsp_connection_flush().
1905  *
1906  * Returns: #GST_RTSP_OK on success.
1907  */
1908 GstRTSPResult
1909 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
1910     GTimeVal * timeout)
1911 {
1912   guint offset;
1913   GstClockTime to;
1914   GstRTSPResult res;
1915   GError *err = NULL;
1916
1917   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1918   g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
1919   g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
1920
1921   if (G_UNLIKELY (size == 0))
1922     return GST_RTSP_OK;
1923
1924   offset = 0;
1925
1926   /* configure timeout if any */
1927   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
1928
1929   while (TRUE) {
1930     res = read_bytes (conn, data, &offset, size);
1931     if (G_UNLIKELY (res == GST_RTSP_EEOF))
1932       goto eof;
1933     if (G_LIKELY (res == GST_RTSP_OK))
1934       break;
1935     if (G_UNLIKELY (res != GST_RTSP_EINTR))
1936       goto read_error;
1937
1938     g_socket_set_timeout (conn->read_socket,
1939         (to + GST_SECOND - 1) / GST_SECOND);
1940     if (!g_socket_condition_wait (conn->read_socket,
1941             G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, conn->cancellable,
1942             &err)) {
1943       g_socket_set_timeout (conn->read_socket, 0);
1944       if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)) {
1945         g_clear_error (&err);
1946         goto stopped;
1947       } else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
1948         g_clear_error (&err);
1949         goto select_timeout;
1950       }
1951       g_clear_error (&err);
1952       goto select_error;
1953     }
1954     g_socket_set_timeout (conn->read_socket, 0);
1955   }
1956   return GST_RTSP_OK;
1957
1958   /* ERRORS */
1959 select_error:
1960   {
1961     return GST_RTSP_ESYS;
1962   }
1963 select_timeout:
1964   {
1965     return GST_RTSP_ETIMEOUT;
1966   }
1967 stopped:
1968   {
1969     return GST_RTSP_EINTR;
1970   }
1971 eof:
1972   {
1973     return GST_RTSP_EEOF;
1974   }
1975 read_error:
1976   {
1977     return res;
1978   }
1979 }
1980
1981 static GstRTSPMessage *
1982 gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code,
1983     const GstRTSPMessage * request)
1984 {
1985   GstRTSPMessage *msg;
1986   GstRTSPResult res;
1987
1988   if (gst_rtsp_status_as_text (code) == NULL)
1989     code = GST_RTSP_STS_INTERNAL_SERVER_ERROR;
1990
1991   GST_RTSP_CHECK (gst_rtsp_message_new_response (&msg, code, NULL, request),
1992       no_message);
1993
1994   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SERVER,
1995       "GStreamer RTSP Server");
1996   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONNECTION, "close");
1997   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-store");
1998   gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
1999
2000   if (code == GST_RTSP_STS_OK) {
2001     if (conn->ip)
2002       gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
2003           conn->ip);
2004     gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
2005         "application/x-rtsp-tunnelled");
2006   }
2007
2008   return msg;
2009
2010   /* ERRORS */
2011 no_message:
2012   {
2013     return NULL;
2014   }
2015 }
2016
2017 /**
2018  * gst_rtsp_connection_receive:
2019  * @conn: a #GstRTSPConnection
2020  * @message: the message to read
2021  * @timeout: a timeout value or #NULL
2022  *
2023  * Attempt to read into @message from the connected @conn, blocking up to
2024  * the specified @timeout. @timeout can be #NULL, in which case this function
2025  * might block forever.
2026  * 
2027  * This function can be cancelled with gst_rtsp_connection_flush().
2028  *
2029  * Returns: #GST_RTSP_OK on success.
2030  */
2031 GstRTSPResult
2032 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
2033     GTimeVal * timeout)
2034 {
2035   GstRTSPResult res;
2036   GstRTSPBuilder builder;
2037   GstClockTime to;
2038   GError *err = NULL;
2039
2040   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2041   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2042   g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2043
2044   /* configure timeout if any */
2045   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
2046
2047   memset (&builder, 0, sizeof (GstRTSPBuilder));
2048   while (TRUE) {
2049     res = build_next (&builder, message, conn);
2050     if (G_UNLIKELY (res == GST_RTSP_EEOF))
2051       goto eof;
2052     else if (G_LIKELY (res == GST_RTSP_OK)) {
2053       if (!conn->manual_http) {
2054         if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2055           if (conn->tstate == TUNNEL_STATE_NONE &&
2056               message->type_data.request.method == GST_RTSP_GET) {
2057             GstRTSPMessage *response;
2058
2059             conn->tstate = TUNNEL_STATE_GET;
2060
2061             /* tunnel GET request, we can reply now */
2062             response = gen_tunnel_reply (conn, GST_RTSP_STS_OK, message);
2063             res = gst_rtsp_connection_send (conn, response, timeout);
2064             gst_rtsp_message_free (response);
2065             if (res == GST_RTSP_OK)
2066               res = GST_RTSP_ETGET;
2067             goto cleanup;
2068           } else if (conn->tstate == TUNNEL_STATE_NONE &&
2069               message->type_data.request.method == GST_RTSP_POST) {
2070             conn->tstate = TUNNEL_STATE_POST;
2071
2072             /* tunnel POST request, the caller now has to link the two
2073              * connections. */
2074             res = GST_RTSP_ETPOST;
2075             goto cleanup;
2076           } else {
2077             res = GST_RTSP_EPARSE;
2078             goto cleanup;
2079           }
2080         } else if (message->type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
2081           res = GST_RTSP_EPARSE;
2082           goto cleanup;
2083         }
2084       }
2085
2086       break;
2087     } else if (G_UNLIKELY (res != GST_RTSP_EINTR))
2088       goto read_error;
2089
2090     g_socket_set_timeout (conn->read_socket,
2091         (to + GST_SECOND - 1) / GST_SECOND);
2092     if (!g_socket_condition_wait (conn->read_socket,
2093             G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, conn->cancellable,
2094             &err)) {
2095       g_socket_set_timeout (conn->read_socket, 0);
2096       if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)) {
2097         g_clear_error (&err);
2098         goto stopped;
2099       } else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
2100         g_clear_error (&err);
2101         goto select_timeout;
2102       }
2103       g_clear_error (&err);
2104       goto select_error;
2105     }
2106     g_socket_set_timeout (conn->read_socket, 0);
2107   }
2108
2109   /* we have a message here */
2110   build_reset (&builder);
2111
2112   return GST_RTSP_OK;
2113
2114   /* ERRORS */
2115 select_error:
2116   {
2117     res = GST_RTSP_ESYS;
2118     goto cleanup;
2119   }
2120 select_timeout:
2121   {
2122     res = GST_RTSP_ETIMEOUT;
2123     goto cleanup;
2124   }
2125 stopped:
2126   {
2127     res = GST_RTSP_EINTR;
2128     goto cleanup;
2129   }
2130 eof:
2131   {
2132     res = GST_RTSP_EEOF;
2133     goto cleanup;
2134   }
2135 read_error:
2136 cleanup:
2137   {
2138     build_reset (&builder);
2139     gst_rtsp_message_unset (message);
2140     return res;
2141   }
2142 }
2143
2144 /**
2145  * gst_rtsp_connection_close:
2146  * @conn: a #GstRTSPConnection
2147  *
2148  * Close the connected @conn. After this call, the connection is in the same
2149  * state as when it was first created.
2150  * 
2151  * Returns: #GST_RTSP_OK on success.
2152  */
2153 GstRTSPResult
2154 gst_rtsp_connection_close (GstRTSPConnection * conn)
2155 {
2156   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2157
2158   g_free (conn->ip);
2159   conn->ip = NULL;
2160
2161   conn->read_ahead = 0;
2162
2163   g_free (conn->initial_buffer);
2164   conn->initial_buffer = NULL;
2165   conn->initial_buffer_offset = 0;
2166
2167   conn->write_socket = NULL;
2168   conn->read_socket = NULL;
2169   conn->tunneled = FALSE;
2170   conn->tstate = TUNNEL_STATE_NONE;
2171   conn->ctxp = NULL;
2172   g_free (conn->username);
2173   conn->username = NULL;
2174   g_free (conn->passwd);
2175   conn->passwd = NULL;
2176   gst_rtsp_connection_clear_auth_params (conn);
2177   conn->timeout = 60;
2178   conn->cseq = 0;
2179   conn->session_id[0] = '\0';
2180
2181   return GST_RTSP_OK;
2182 }
2183
2184 /**
2185  * gst_rtsp_connection_free:
2186  * @conn: a #GstRTSPConnection
2187  *
2188  * Close and free @conn.
2189  * 
2190  * Returns: #GST_RTSP_OK on success.
2191  */
2192 GstRTSPResult
2193 gst_rtsp_connection_free (GstRTSPConnection * conn)
2194 {
2195   GstRTSPResult res;
2196
2197   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2198
2199   res = gst_rtsp_connection_close (conn);
2200   if (conn->socket0)
2201     g_object_unref (conn->socket0);
2202   if (conn->socket1)
2203     g_object_unref (conn->socket1);
2204
2205   if (conn->cancellable)
2206     g_object_unref (conn->cancellable);
2207
2208   g_timer_destroy (conn->timer);
2209   gst_rtsp_url_free (conn->url);
2210   g_free (conn->proxy_host);
2211   g_free (conn);
2212
2213   return res;
2214 }
2215
2216 /**
2217  * gst_rtsp_connection_poll:
2218  * @conn: a #GstRTSPConnection
2219  * @events: a bitmask of #GstRTSPEvent flags to check
2220  * @revents: location for result flags 
2221  * @timeout: a timeout
2222  *
2223  * Wait up to the specified @timeout for the connection to become available for
2224  * at least one of the operations specified in @events. When the function returns
2225  * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
2226  * @conn.
2227  *
2228  * @timeout can be #NULL, in which case this function might block forever.
2229  *
2230  * This function can be cancelled with gst_rtsp_connection_flush().
2231  * 
2232  * Returns: #GST_RTSP_OK on success.
2233  *
2234  * Since: 0.10.15
2235  */
2236 GstRTSPResult
2237 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
2238     GstRTSPEvent * revents, GTimeVal * timeout)
2239 {
2240   GstClockTime to;
2241   GMainContext *ctx;
2242   GSource *rs, *ws, *ts;
2243   GIOCondition condition;
2244
2245   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2246   g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
2247   g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
2248   g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2249   g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
2250
2251   ctx = g_main_context_new ();
2252
2253   /* configure timeout if any */
2254   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
2255
2256   if (timeout) {
2257     ts = g_timeout_source_new (to / GST_MSECOND);
2258     g_source_set_dummy_callback (ts);
2259     g_source_attach (ts, ctx);
2260     g_source_unref (ts);
2261   }
2262
2263   rs = g_socket_create_source (conn->read_socket,
2264       G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, conn->cancellable);
2265   g_source_set_dummy_callback (rs);
2266   g_source_attach (rs, ctx);
2267   g_source_unref (rs);
2268
2269   ws = g_socket_create_source (conn->write_socket,
2270       G_IO_OUT | G_IO_ERR | G_IO_HUP, conn->cancellable);
2271   g_source_set_dummy_callback (ws);
2272   g_source_attach (ws, ctx);
2273   g_source_unref (ws);
2274
2275   /* Returns after handling all pending events */
2276   g_main_context_iteration (ctx, TRUE);
2277
2278   g_main_context_unref (ctx);
2279
2280   condition =
2281       g_socket_condition_check (conn->read_socket,
2282       G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP);
2283   condition |=
2284       g_socket_condition_check (conn->write_socket,
2285       G_IO_OUT | G_IO_ERR | G_IO_HUP);
2286
2287   *revents = 0;
2288   if (events & GST_RTSP_EV_READ) {
2289     if ((condition & G_IO_IN) || (condition & G_IO_PRI))
2290       *revents |= GST_RTSP_EV_READ;
2291   }
2292   if (events & GST_RTSP_EV_WRITE) {
2293     if ((condition & G_IO_OUT))
2294       *revents |= GST_RTSP_EV_WRITE;
2295   }
2296
2297   if (*revents == 0)
2298     return GST_RTSP_ETIMEOUT;
2299
2300   return GST_RTSP_OK;
2301 }
2302
2303 /**
2304  * gst_rtsp_connection_next_timeout:
2305  * @conn: a #GstRTSPConnection
2306  * @timeout: a timeout
2307  *
2308  * Calculate the next timeout for @conn, storing the result in @timeout.
2309  *
2310  * Returns: #GST_RTSP_OK.
2311  */
2312 GstRTSPResult
2313 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
2314 {
2315   gdouble elapsed;
2316   glong sec;
2317   gulong usec;
2318   gint ctimeout;
2319
2320   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2321   g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
2322
2323   ctimeout = conn->timeout;
2324   if (ctimeout >= 20) {
2325     /* Because we should act before the timeout we timeout 5
2326      * seconds in advance. */
2327     ctimeout -= 5;
2328   } else if (ctimeout >= 5) {
2329     /* else timeout 20% earlier */
2330     ctimeout -= ctimeout / 5;
2331   } else if (ctimeout >= 1) {
2332     /* else timeout 1 second earlier */
2333     ctimeout -= 1;
2334   }
2335
2336   elapsed = g_timer_elapsed (conn->timer, &usec);
2337   if (elapsed >= ctimeout) {
2338     sec = 0;
2339     usec = 0;
2340   } else {
2341     sec = ctimeout - elapsed;
2342     if (usec <= G_USEC_PER_SEC)
2343       usec = G_USEC_PER_SEC - usec;
2344     else
2345       usec = 0;
2346   }
2347
2348   timeout->tv_sec = sec;
2349   timeout->tv_usec = usec;
2350
2351   return GST_RTSP_OK;
2352 }
2353
2354 /**
2355  * gst_rtsp_connection_reset_timeout:
2356  * @conn: a #GstRTSPConnection
2357  *
2358  * Reset the timeout of @conn.
2359  *
2360  * Returns: #GST_RTSP_OK.
2361  */
2362 GstRTSPResult
2363 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
2364 {
2365   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2366
2367   g_timer_start (conn->timer);
2368
2369   return GST_RTSP_OK;
2370 }
2371
2372 /**
2373  * gst_rtsp_connection_flush:
2374  * @conn: a #GstRTSPConnection
2375  * @flush: start or stop the flush
2376  *
2377  * Start or stop the flushing action on @conn. When flushing, all current
2378  * and future actions on @conn will return #GST_RTSP_EINTR until the connection
2379  * is set to non-flushing mode again.
2380  * 
2381  * Returns: #GST_RTSP_OK.
2382  */
2383 GstRTSPResult
2384 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
2385 {
2386   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2387
2388   if (flush)
2389     g_cancellable_cancel (conn->cancellable);
2390   else
2391     g_cancellable_reset (conn->cancellable);
2392
2393   return GST_RTSP_OK;
2394 }
2395
2396 /**
2397  * gst_rtsp_connection_set_proxy:
2398  * @conn: a #GstRTSPConnection
2399  * @host: the proxy host
2400  * @port: the proxy port
2401  *
2402  * Set the proxy host and port.
2403  * 
2404  * Returns: #GST_RTSP_OK.
2405  *
2406  * Since: 0.10.23
2407  */
2408 GstRTSPResult
2409 gst_rtsp_connection_set_proxy (GstRTSPConnection * conn,
2410     const gchar * host, guint port)
2411 {
2412   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2413
2414   g_free (conn->proxy_host);
2415   conn->proxy_host = g_strdup (host);
2416   conn->proxy_port = port;
2417
2418   return GST_RTSP_OK;
2419 }
2420
2421 /**
2422  * gst_rtsp_connection_set_auth:
2423  * @conn: a #GstRTSPConnection
2424  * @method: authentication method
2425  * @user: the user
2426  * @pass: the password
2427  *
2428  * Configure @conn for authentication mode @method with @user and @pass as the
2429  * user and password respectively.
2430  * 
2431  * Returns: #GST_RTSP_OK.
2432  */
2433 GstRTSPResult
2434 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
2435     GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
2436 {
2437   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2438
2439   if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
2440           || g_strrstr (user, ":") != NULL))
2441     return GST_RTSP_EINVAL;
2442
2443   /* Make sure the username and passwd are being set for authentication */
2444   if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
2445     return GST_RTSP_EINVAL;
2446
2447   /* ":" chars are not allowed in usernames for basic auth */
2448   if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
2449     return GST_RTSP_EINVAL;
2450
2451   g_free (conn->username);
2452   g_free (conn->passwd);
2453
2454   conn->auth_method = method;
2455   conn->username = g_strdup (user);
2456   conn->passwd = g_strdup (pass);
2457
2458   return GST_RTSP_OK;
2459 }
2460
2461 /**
2462  * str_case_hash:
2463  * @key: ASCII string to hash
2464  *
2465  * Hashes @key in a case-insensitive manner.
2466  *
2467  * Returns: the hash code.
2468  **/
2469 static guint
2470 str_case_hash (gconstpointer key)
2471 {
2472   const char *p = key;
2473   guint h = g_ascii_toupper (*p);
2474
2475   if (h)
2476     for (p += 1; *p != '\0'; p++)
2477       h = (h << 5) - h + g_ascii_toupper (*p);
2478
2479   return h;
2480 }
2481
2482 /**
2483  * str_case_equal:
2484  * @v1: an ASCII string
2485  * @v2: another ASCII string
2486  *
2487  * Compares @v1 and @v2 in a case-insensitive manner
2488  *
2489  * Returns: %TRUE if they are equal (modulo case)
2490  **/
2491 static gboolean
2492 str_case_equal (gconstpointer v1, gconstpointer v2)
2493 {
2494   const char *string1 = v1;
2495   const char *string2 = v2;
2496
2497   return g_ascii_strcasecmp (string1, string2) == 0;
2498 }
2499
2500 /**
2501  * gst_rtsp_connection_set_auth_param:
2502  * @conn: a #GstRTSPConnection
2503  * @param: authentication directive
2504  * @value: value
2505  *
2506  * Setup @conn with authentication directives. This is not necesary for
2507  * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
2508  * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
2509  * in the WWW-Authenticate response header and can include realm, domain,
2510  * nonce, opaque, stale, algorithm, qop as per RFC2617.
2511  * 
2512  * Since: 0.10.20
2513  */
2514 void
2515 gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
2516     const gchar * param, const gchar * value)
2517 {
2518   g_return_if_fail (conn != NULL);
2519   g_return_if_fail (param != NULL);
2520
2521   if (conn->auth_params == NULL) {
2522     conn->auth_params =
2523         g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
2524   }
2525   g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
2526 }
2527
2528 /**
2529  * gst_rtsp_connection_clear_auth_params:
2530  * @conn: a #GstRTSPConnection
2531  *
2532  * Clear the list of authentication directives stored in @conn.
2533  *
2534  * Since: 0.10.20
2535  */
2536 void
2537 gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
2538 {
2539   g_return_if_fail (conn != NULL);
2540
2541   if (conn->auth_params != NULL) {
2542     g_hash_table_destroy (conn->auth_params);
2543     conn->auth_params = NULL;
2544   }
2545 }
2546
2547 static GstRTSPResult
2548 set_qos_dscp (GSocket * socket, guint qos_dscp)
2549 {
2550 #ifndef IP_TOS
2551   return GST_RTSP_OK;
2552 #else
2553   gint fd;
2554   union gst_sockaddr sa;
2555   socklen_t slen = sizeof (sa);
2556   gint af;
2557   gint tos;
2558
2559   if (!socket)
2560     return GST_RTSP_OK;
2561
2562   fd = g_socket_get_fd (socket);
2563   if (getsockname (fd, &sa.sa, &slen) < 0)
2564     goto no_getsockname;
2565
2566   af = sa.sa.sa_family;
2567
2568   /* if this is an IPv4-mapped address then do IPv4 QoS */
2569   if (af == AF_INET6) {
2570     if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr))
2571       af = AF_INET;
2572   }
2573
2574   /* extract and shift 6 bits of the DSCP */
2575   tos = (qos_dscp & 0x3f) << 2;
2576
2577   switch (af) {
2578     case AF_INET:
2579       if (setsockopt (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
2580         goto no_setsockopt;
2581       break;
2582     case AF_INET6:
2583 #ifdef IPV6_TCLASS
2584       if (setsockopt (fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos)) < 0)
2585         goto no_setsockopt;
2586       break;
2587 #endif
2588     default:
2589       goto wrong_family;
2590   }
2591
2592   return GST_RTSP_OK;
2593
2594   /* ERRORS */
2595 no_getsockname:
2596 no_setsockopt:
2597   {
2598     return GST_RTSP_ESYS;
2599   }
2600 wrong_family:
2601   {
2602     return GST_RTSP_ERROR;
2603   }
2604 #endif
2605 }
2606
2607 /**
2608  * gst_rtsp_connection_set_qos_dscp:
2609  * @conn: a #GstRTSPConnection
2610  * @qos_dscp: DSCP value
2611  *
2612  * Configure @conn to use the specified DSCP value.
2613  *
2614  * Returns: #GST_RTSP_OK on success.
2615  *
2616  * Since: 0.10.20
2617  */
2618 GstRTSPResult
2619 gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
2620 {
2621   GstRTSPResult res;
2622
2623   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2624   g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2625   g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
2626
2627   res = set_qos_dscp (conn->socket0, qos_dscp);
2628   if (res == GST_RTSP_OK)
2629     res = set_qos_dscp (conn->socket1, qos_dscp);
2630
2631   return res;
2632 }
2633
2634
2635 /**
2636  * gst_rtsp_connection_get_url:
2637  * @conn: a #GstRTSPConnection
2638  *
2639  * Retrieve the URL of the other end of @conn.
2640  *
2641  * Returns: The URL. This value remains valid until the
2642  * connection is freed.
2643  *
2644  * Since: 0.10.23
2645  */
2646 GstRTSPUrl *
2647 gst_rtsp_connection_get_url (const GstRTSPConnection * conn)
2648 {
2649   g_return_val_if_fail (conn != NULL, NULL);
2650
2651   return conn->url;
2652 }
2653
2654 /**
2655  * gst_rtsp_connection_get_ip:
2656  * @conn: a #GstRTSPConnection
2657  *
2658  * Retrieve the IP address of the other end of @conn.
2659  *
2660  * Returns: The IP address as a string. this value remains valid until the
2661  * connection is closed.
2662  *
2663  * Since: 0.10.20
2664  */
2665 const gchar *
2666 gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
2667 {
2668   g_return_val_if_fail (conn != NULL, NULL);
2669
2670   return conn->ip;
2671 }
2672
2673 /**
2674  * gst_rtsp_connection_set_ip:
2675  * @conn: a #GstRTSPConnection
2676  * @ip: an ip address
2677  *
2678  * Set the IP address of the server.
2679  *
2680  * Since: 0.10.23
2681  */
2682 void
2683 gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip)
2684 {
2685   g_return_if_fail (conn != NULL);
2686
2687   g_free (conn->ip);
2688   conn->ip = g_strdup (ip);
2689 }
2690
2691 /**
2692  * gst_rtsp_connection_get_readfd:
2693  * @conn: a #GstRTSPConnection
2694  *
2695  * Get the file descriptor for reading.
2696  *
2697  * Returns: the file descriptor used for reading or %NULL on error. The file
2698  * descriptor remains valid until the connection is closed.
2699  *
2700  * Since: 0.10.23
2701  */
2702 GSocket *
2703 gst_rtsp_connection_get_read_socket (const GstRTSPConnection * conn)
2704 {
2705   g_return_val_if_fail (conn != NULL, NULL);
2706   g_return_val_if_fail (conn->read_socket != NULL, NULL);
2707
2708   return conn->read_socket;
2709 }
2710
2711 /**
2712  * gst_rtsp_connection_get_write_socket:
2713  * @conn: a #GstRTSPConnection
2714  *
2715  * Get the file descriptor for writing.
2716  *
2717  * Returns: the file descriptor used for writing or NULL on error. The file
2718  * descriptor remains valid until the connection is closed.
2719  *
2720  * Since: 0.10.23
2721  */
2722 GSocket *
2723 gst_rtsp_connection_get_write_socket (const GstRTSPConnection * conn)
2724 {
2725   g_return_val_if_fail (conn != NULL, NULL);
2726   g_return_val_if_fail (conn->write_socket != NULL, NULL);
2727
2728   return conn->write_socket;
2729 }
2730
2731 /**
2732  * gst_rtsp_connection_set_http_mode:
2733  * @conn: a #GstRTSPConnection
2734  * @enable: %TRUE to enable manual HTTP mode
2735  *
2736  * By setting the HTTP mode to %TRUE the message parsing will support HTTP
2737  * messages in addition to the RTSP messages. It will also disable the
2738  * automatic handling of setting up an HTTP tunnel.
2739  *
2740  * Since: 0.10.25
2741  */
2742 void
2743 gst_rtsp_connection_set_http_mode (GstRTSPConnection * conn, gboolean enable)
2744 {
2745   g_return_if_fail (conn != NULL);
2746
2747   conn->manual_http = enable;
2748 }
2749
2750 /**
2751  * gst_rtsp_connection_set_tunneled:
2752  * @conn: a #GstRTSPConnection
2753  * @tunneled: the new state
2754  *
2755  * Set the HTTP tunneling state of the connection. This must be configured before
2756  * the @conn is connected.
2757  *
2758  * Since: 0.10.23
2759  */
2760 void
2761 gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
2762 {
2763   g_return_if_fail (conn != NULL);
2764   g_return_if_fail (conn->read_socket == NULL);
2765   g_return_if_fail (conn->write_socket == NULL);
2766
2767   conn->tunneled = tunneled;
2768 }
2769
2770 /**
2771  * gst_rtsp_connection_is_tunneled:
2772  * @conn: a #GstRTSPConnection
2773  *
2774  * Get the tunneling state of the connection. 
2775  *
2776  * Returns: if @conn is using HTTP tunneling.
2777  *
2778  * Since: 0.10.23
2779  */
2780 gboolean
2781 gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn)
2782 {
2783   g_return_val_if_fail (conn != NULL, FALSE);
2784
2785   return conn->tunneled;
2786 }
2787
2788 /**
2789  * gst_rtsp_connection_get_tunnelid:
2790  * @conn: a #GstRTSPConnection
2791  *
2792  * Get the tunnel session id the connection. 
2793  *
2794  * Returns: returns a non-empty string if @conn is being tunneled over HTTP.
2795  *
2796  * Since: 0.10.23
2797  */
2798 const gchar *
2799 gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn)
2800 {
2801   g_return_val_if_fail (conn != NULL, NULL);
2802
2803   if (!conn->tunneled)
2804     return NULL;
2805
2806   return conn->tunnelid;
2807 }
2808
2809 /**
2810  * gst_rtsp_connection_do_tunnel:
2811  * @conn: a #GstRTSPConnection
2812  * @conn2: a #GstRTSPConnection or %NULL
2813  *
2814  * If @conn received the first tunnel connection and @conn2 received
2815  * the second tunnel connection, link the two connections together so that
2816  * @conn manages the tunneled connection.
2817  *
2818  * After this call, @conn2 cannot be used anymore and must be freed with
2819  * gst_rtsp_connection_free().
2820  *
2821  * If @conn2 is %NULL then only the base64 decoding context will be setup for
2822  * @conn.
2823  *
2824  * Returns: return GST_RTSP_OK on success.
2825  *
2826  * Since: 0.10.23
2827  */
2828 GstRTSPResult
2829 gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn,
2830     GstRTSPConnection * conn2)
2831 {
2832   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2833
2834   if (conn2 != NULL) {
2835     g_return_val_if_fail (conn->tstate == TUNNEL_STATE_GET, GST_RTSP_EINVAL);
2836     g_return_val_if_fail (conn2->tstate == TUNNEL_STATE_POST, GST_RTSP_EINVAL);
2837     g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid,
2838             TUNNELID_LEN), GST_RTSP_EINVAL);
2839
2840     /* both connections have socket0 as the read/write socket. start by taking the
2841      * socket from conn2 and set it as the socket in conn */
2842     conn->socket1 = conn2->socket0;
2843
2844     /* clean up some of the state of conn2 */
2845     g_cancellable_cancel (conn2->cancellable);
2846     conn2->socket0 = 0;
2847     g_object_unref (conn2->socket1);
2848     conn2->socket1 = NULL;
2849     conn2->write_socket = conn2->read_socket = NULL;
2850     g_cancellable_reset (conn2->cancellable);
2851
2852     /* We make socket0 the write socket and socket1 the read socket. */
2853     conn->write_socket = conn->socket0;
2854     conn->read_socket = conn->socket1;
2855
2856     conn->tstate = TUNNEL_STATE_COMPLETE;
2857   }
2858
2859   /* we need base64 decoding for the readfd */
2860   conn->ctx.state = 0;
2861   conn->ctx.save = 0;
2862   conn->ctx.cout = 0;
2863   conn->ctx.coutl = 0;
2864   conn->ctxp = &conn->ctx;
2865
2866   return GST_RTSP_OK;
2867 }
2868
2869 #define READ_ERR    (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
2870 #define READ_COND   (G_IO_IN | READ_ERR)
2871 #define WRITE_ERR   (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
2872 #define WRITE_COND  (G_IO_OUT | WRITE_ERR)
2873
2874 typedef struct
2875 {
2876   guint8 *data;
2877   guint size;
2878   guint id;
2879 } GstRTSPRec;
2880
2881 /* async functions */
2882 struct _GstRTSPWatch
2883 {
2884   GSource source;
2885
2886   GstRTSPConnection *conn;
2887
2888   GstRTSPBuilder builder;
2889   GstRTSPMessage message;
2890
2891   GPollFD readfd;
2892   GPollFD writefd;
2893
2894   /* queued message for transmission */
2895   guint id;
2896   GMutex *mutex;
2897   GQueue *messages;
2898   guint8 *write_data;
2899   guint write_off;
2900   guint write_size;
2901   guint write_id;
2902
2903   GstRTSPWatchFuncs funcs;
2904
2905   gpointer user_data;
2906   GDestroyNotify notify;
2907 };
2908
2909 static gboolean
2910 gst_rtsp_source_prepare (GSource * source, gint * timeout)
2911 {
2912   GstRTSPWatch *watch = (GstRTSPWatch *) source;
2913
2914   if (watch->conn->initial_buffer != NULL)
2915     return TRUE;
2916
2917   *timeout = (watch->conn->timeout * 1000);
2918
2919   return FALSE;
2920 }
2921
2922 static gboolean
2923 gst_rtsp_source_check (GSource * source)
2924 {
2925   GstRTSPWatch *watch = (GstRTSPWatch *) source;
2926
2927   if (watch->readfd.revents & READ_COND)
2928     return TRUE;
2929
2930   if (watch->writefd.revents & WRITE_COND)
2931     return TRUE;
2932
2933   return FALSE;
2934 }
2935
2936 static gboolean
2937 gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED,
2938     gpointer user_data G_GNUC_UNUSED)
2939 {
2940   GstRTSPWatch *watch = (GstRTSPWatch *) source;
2941   GstRTSPResult res = GST_RTSP_ERROR;
2942   gboolean keep_running = TRUE;
2943
2944   /* first read as much as we can */
2945   if (watch->readfd.revents & READ_COND || watch->conn->initial_buffer != NULL) {
2946     do {
2947       if (watch->readfd.revents & READ_ERR)
2948         goto read_error;
2949
2950       res = build_next (&watch->builder, &watch->message, watch->conn);
2951       if (res == GST_RTSP_EINTR)
2952         break;
2953       else if (G_UNLIKELY (res == GST_RTSP_EEOF)) {
2954         watch->readfd.events = 0;
2955         watch->readfd.revents = 0;
2956         g_source_remove_poll ((GSource *) watch, &watch->readfd);
2957         /* When we are in tunnelled mode, the read socket can be closed and we
2958          * should be prepared for a new POST method to reopen it */
2959         if (watch->conn->tstate == TUNNEL_STATE_COMPLETE) {
2960           /* remove the read connection for the tunnel */
2961           /* we accept a new POST request */
2962           watch->conn->tstate = TUNNEL_STATE_GET;
2963           /* and signal that we lost our tunnel */
2964           if (watch->funcs.tunnel_lost)
2965             res = watch->funcs.tunnel_lost (watch, watch->user_data);
2966           goto read_done;
2967         } else
2968           goto eof;
2969       } else if (G_LIKELY (res == GST_RTSP_OK)) {
2970         if (!watch->conn->manual_http &&
2971             watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2972           if (watch->conn->tstate == TUNNEL_STATE_NONE &&
2973               watch->message.type_data.request.method == GST_RTSP_GET) {
2974             GstRTSPMessage *response;
2975             GstRTSPStatusCode code;
2976
2977             watch->conn->tstate = TUNNEL_STATE_GET;
2978
2979             if (watch->funcs.tunnel_start)
2980               code = watch->funcs.tunnel_start (watch, watch->user_data);
2981             else
2982               code = GST_RTSP_STS_OK;
2983
2984             /* queue the response */
2985             response = gen_tunnel_reply (watch->conn, code, &watch->message);
2986             gst_rtsp_watch_send_message (watch, response, NULL);
2987             gst_rtsp_message_free (response);
2988             goto read_done;
2989           } else if (watch->conn->tstate == TUNNEL_STATE_NONE &&
2990               watch->message.type_data.request.method == GST_RTSP_POST) {
2991             watch->conn->tstate = TUNNEL_STATE_POST;
2992
2993             /* in the callback the connection should be tunneled with the
2994              * GET connection */
2995             if (watch->funcs.tunnel_complete)
2996               watch->funcs.tunnel_complete (watch, watch->user_data);
2997             goto read_done;
2998           }
2999         }
3000       }
3001
3002       if (!watch->conn->manual_http) {
3003         /* if manual HTTP support is not enabled, then restore the message to
3004          * what it would have looked like without the support for parsing HTTP
3005          * messages being present */
3006         if (watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
3007           watch->message.type = GST_RTSP_MESSAGE_REQUEST;
3008           watch->message.type_data.request.method = GST_RTSP_INVALID;
3009           if (watch->message.type_data.request.version != GST_RTSP_VERSION_1_0)
3010             watch->message.type_data.request.version = GST_RTSP_VERSION_INVALID;
3011           res = GST_RTSP_EPARSE;
3012         } else if (watch->message.type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
3013           watch->message.type = GST_RTSP_MESSAGE_RESPONSE;
3014           if (watch->message.type_data.response.version != GST_RTSP_VERSION_1_0)
3015             watch->message.type_data.response.version =
3016                 GST_RTSP_VERSION_INVALID;
3017           res = GST_RTSP_EPARSE;
3018         }
3019       }
3020
3021       if (G_LIKELY (res == GST_RTSP_OK)) {
3022         if (watch->funcs.message_received)
3023           watch->funcs.message_received (watch, &watch->message,
3024               watch->user_data);
3025       } else {
3026         goto read_error;
3027       }
3028
3029     read_done:
3030       gst_rtsp_message_unset (&watch->message);
3031       build_reset (&watch->builder);
3032     } while (FALSE);
3033   }
3034
3035   if (watch->writefd.revents & WRITE_COND) {
3036     if (watch->writefd.revents & WRITE_ERR)
3037       goto write_error;
3038
3039     g_mutex_lock (watch->mutex);
3040     do {
3041       if (watch->write_data == NULL) {
3042         GstRTSPRec *rec;
3043
3044         /* get a new message from the queue */
3045         rec = g_queue_pop_tail (watch->messages);
3046         if (rec == NULL)
3047           break;
3048
3049         watch->write_off = 0;
3050         watch->write_data = rec->data;
3051         watch->write_size = rec->size;
3052         watch->write_id = rec->id;
3053
3054         g_slice_free (GstRTSPRec, rec);
3055       }
3056
3057       res = write_bytes (watch->conn->write_socket, watch->write_data,
3058           &watch->write_off, watch->write_size, watch->conn->cancellable);
3059       g_mutex_unlock (watch->mutex);
3060
3061       if (res == GST_RTSP_EINTR)
3062         goto write_blocked;
3063       else if (G_LIKELY (res == GST_RTSP_OK)) {
3064         if (watch->funcs.message_sent)
3065           watch->funcs.message_sent (watch, watch->write_id, watch->user_data);
3066       } else {
3067         goto write_error;
3068       }
3069       g_mutex_lock (watch->mutex);
3070
3071       g_free (watch->write_data);
3072       watch->write_data = NULL;
3073     } while (TRUE);
3074
3075     watch->writefd.events = WRITE_ERR;
3076
3077     g_mutex_unlock (watch->mutex);
3078   }
3079
3080 write_blocked:
3081   return keep_running;
3082
3083   /* ERRORS */
3084 eof:
3085   {
3086     if (watch->funcs.closed)
3087       watch->funcs.closed (watch, watch->user_data);
3088
3089     /* always stop when the readfd returns EOF in non-tunneled mode */
3090     return FALSE;
3091   }
3092 read_error:
3093   {
3094     watch->readfd.events = 0;
3095     watch->readfd.revents = 0;
3096     g_source_remove_poll ((GSource *) watch, &watch->readfd);
3097     keep_running = (watch->writefd.events != 0);
3098
3099     if (keep_running) {
3100       if (watch->funcs.error_full)
3101         GST_RTSP_CHECK (watch->funcs.error_full (watch, res, &watch->message,
3102                 0, watch->user_data), error);
3103       else
3104         goto error;
3105     } else
3106       goto eof;
3107   }
3108 write_error:
3109   {
3110     watch->writefd.events = 0;
3111     watch->writefd.revents = 0;
3112     g_source_remove_poll ((GSource *) watch, &watch->writefd);
3113     keep_running = (watch->readfd.events != 0);
3114
3115     if (keep_running) {
3116       if (watch->funcs.error_full)
3117         GST_RTSP_CHECK (watch->funcs.error_full (watch, res, NULL,
3118                 watch->write_id, watch->user_data), error);
3119       else
3120         goto error;
3121     } else
3122       goto eof;
3123   }
3124 error:
3125   {
3126     if (watch->funcs.error)
3127       watch->funcs.error (watch, res, watch->user_data);
3128
3129     return keep_running;
3130   }
3131 }
3132
3133 static void
3134 gst_rtsp_rec_free (gpointer data)
3135 {
3136   GstRTSPRec *rec = data;
3137
3138   g_free (rec->data);
3139   g_slice_free (GstRTSPRec, rec);
3140 }
3141
3142 static void
3143 gst_rtsp_source_finalize (GSource * source)
3144 {
3145   GstRTSPWatch *watch = (GstRTSPWatch *) source;
3146
3147   build_reset (&watch->builder);
3148   gst_rtsp_message_unset (&watch->message);
3149
3150   g_queue_foreach (watch->messages, (GFunc) gst_rtsp_rec_free, NULL);
3151   g_queue_free (watch->messages);
3152   watch->messages = NULL;
3153   g_free (watch->write_data);
3154
3155   g_mutex_free (watch->mutex);
3156
3157   if (watch->notify)
3158     watch->notify (watch->user_data);
3159 }
3160
3161 static GSourceFuncs gst_rtsp_source_funcs = {
3162   gst_rtsp_source_prepare,
3163   gst_rtsp_source_check,
3164   gst_rtsp_source_dispatch,
3165   gst_rtsp_source_finalize,
3166   NULL,
3167   NULL
3168 };
3169
3170 /**
3171  * gst_rtsp_watch_new:
3172  * @conn: a #GstRTSPConnection
3173  * @funcs: watch functions
3174  * @user_data: user data to pass to @funcs
3175  * @notify: notify when @user_data is not referenced anymore
3176  *
3177  * Create a watch object for @conn. The functions provided in @funcs will be
3178  * called with @user_data when activity happened on the watch.
3179  *
3180  * The new watch is usually created so that it can be attached to a
3181  * maincontext with gst_rtsp_watch_attach(). 
3182  *
3183  * @conn must exist for the entire lifetime of the watch.
3184  *
3185  * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP
3186  * communication. Free with gst_rtsp_watch_unref () after usage.
3187  *
3188  * Since: 0.10.23
3189  */
3190 GstRTSPWatch *
3191 gst_rtsp_watch_new (GstRTSPConnection * conn,
3192     GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify)
3193 {
3194   GstRTSPWatch *result;
3195
3196   g_return_val_if_fail (conn != NULL, NULL);
3197   g_return_val_if_fail (funcs != NULL, NULL);
3198   g_return_val_if_fail (conn->read_socket != NULL, NULL);
3199   g_return_val_if_fail (conn->write_socket != NULL, NULL);
3200
3201   result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs,
3202       sizeof (GstRTSPWatch));
3203
3204   result->conn = conn;
3205   result->builder.state = STATE_START;
3206
3207   result->mutex = g_mutex_new ();
3208   result->messages = g_queue_new ();
3209
3210   result->readfd.fd = -1;
3211   result->writefd.fd = -1;
3212
3213   gst_rtsp_watch_reset (result);
3214
3215   result->funcs = *funcs;
3216   result->user_data = user_data;
3217   result->notify = notify;
3218
3219   return result;
3220 }
3221
3222 /**
3223  * gst_rtsp_watch_reset:
3224  * @watch: a #GstRTSPWatch
3225  *
3226  * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel()
3227  * when the file descriptors of the connection might have changed.
3228  *
3229  * Since: 0.10.23
3230  */
3231 void
3232 gst_rtsp_watch_reset (GstRTSPWatch * watch)
3233 {
3234   if (watch->readfd.fd != -1)
3235     g_source_remove_poll ((GSource *) watch, &watch->readfd);
3236   if (watch->writefd.fd != -1)
3237     g_source_remove_poll ((GSource *) watch, &watch->writefd);
3238
3239   watch->readfd.fd = g_socket_get_fd (watch->conn->read_socket);
3240   watch->readfd.events = READ_COND;
3241   watch->readfd.revents = 0;
3242
3243   watch->writefd.fd = g_socket_get_fd (watch->conn->write_socket);
3244   watch->writefd.events = WRITE_ERR;
3245   watch->writefd.revents = 0;
3246
3247   if (watch->readfd.fd != -1)
3248     g_source_add_poll ((GSource *) watch, &watch->readfd);
3249   if (watch->writefd.fd != -1)
3250     g_source_add_poll ((GSource *) watch, &watch->writefd);
3251 }
3252
3253 /**
3254  * gst_rtsp_watch_attach:
3255  * @watch: a #GstRTSPWatch
3256  * @context: a GMainContext (if NULL, the default context will be used)
3257  *
3258  * Adds a #GstRTSPWatch to a context so that it will be executed within that context.
3259  *
3260  * Returns: the ID (greater than 0) for the watch within the GMainContext. 
3261  *
3262  * Since: 0.10.23
3263  */
3264 guint
3265 gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
3266 {
3267   g_return_val_if_fail (watch != NULL, 0);
3268
3269   return g_source_attach ((GSource *) watch, context);
3270 }
3271
3272 /**
3273  * gst_rtsp_watch_unref:
3274  * @watch: a #GstRTSPWatch
3275  *
3276  * Decreases the reference count of @watch by one. If the resulting reference
3277  * count is zero the watch and associated memory will be destroyed.
3278  *
3279  * Since: 0.10.23
3280  */
3281 void
3282 gst_rtsp_watch_unref (GstRTSPWatch * watch)
3283 {
3284   g_return_if_fail (watch != NULL);
3285
3286   g_source_unref ((GSource *) watch);
3287 }
3288
3289 /**
3290  * gst_rtsp_watch_write_data:
3291  * @watch: a #GstRTSPWatch
3292  * @data: the data to queue
3293  * @size: the size of @data
3294  * @id: location for a message ID or %NULL
3295  *
3296  * Write @data using the connection of the @watch. If it cannot be sent
3297  * immediately, it will be queued for transmission in @watch. The contents of
3298  * @message will then be serialized and transmitted when the connection of the
3299  * @watch becomes writable. In case the @message is queued, the ID returned in
3300  * @id will be non-zero and used as the ID argument in the message_sent
3301  * callback.
3302  *
3303  * This function will take ownership of @data and g_free() it after use.
3304  *
3305  * Returns: #GST_RTSP_OK on success.
3306  *
3307  * Since: 0.10.25
3308  */
3309 GstRTSPResult
3310 gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data,
3311     guint size, guint * id)
3312 {
3313   GstRTSPResult res;
3314   GstRTSPRec *rec;
3315   guint off = 0;
3316   GMainContext *context = NULL;
3317
3318   g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
3319   g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
3320   g_return_val_if_fail (size != 0, GST_RTSP_EINVAL);
3321
3322   g_mutex_lock (watch->mutex);
3323
3324   /* try to send the message synchronously first */
3325   if (watch->messages->length == 0 && watch->write_data == NULL) {
3326     res =
3327         write_bytes (watch->conn->write_socket, data, &off, size,
3328         watch->conn->cancellable);
3329     if (res != GST_RTSP_EINTR) {
3330       if (id != NULL)
3331         *id = 0;
3332       g_free ((gpointer) data);
3333       goto done;
3334     }
3335   }
3336
3337   /* make a record with the data and id for sending async */
3338   rec = g_slice_new (GstRTSPRec);
3339   if (off == 0) {
3340     rec->data = (guint8 *) data;
3341     rec->size = size;
3342   } else {
3343     rec->data = g_memdup (data + off, size - off);
3344     rec->size = size - off;
3345     g_free ((gpointer) data);
3346   }
3347
3348   do {
3349     /* make sure rec->id is never 0 */
3350     rec->id = ++watch->id;
3351   } while (G_UNLIKELY (rec->id == 0));
3352
3353   /* add the record to a queue. FIXME we would like to have an upper limit here */
3354   g_queue_push_head (watch->messages, rec);
3355
3356   /* make sure the main context will now also check for writability on the
3357    * socket */
3358   if (watch->writefd.events != WRITE_COND) {
3359     watch->writefd.events = WRITE_COND;
3360     context = ((GSource *) watch)->context;
3361   }
3362
3363   if (id != NULL)
3364     *id = rec->id;
3365   res = GST_RTSP_OK;
3366
3367 done:
3368   g_mutex_unlock (watch->mutex);
3369
3370   if (context)
3371     g_main_context_wakeup (context);
3372
3373   return res;
3374 }
3375
3376 /**
3377  * gst_rtsp_watch_send_message:
3378  * @watch: a #GstRTSPWatch
3379  * @message: a #GstRTSPMessage
3380  * @id: location for a message ID or %NULL
3381  *
3382  * Send a @message using the connection of the @watch. If it cannot be sent
3383  * immediately, it will be queued for transmission in @watch. The contents of
3384  * @message will then be serialized and transmitted when the connection of the
3385  * @watch becomes writable. In case the @message is queued, the ID returned in
3386  * @id will be non-zero and used as the ID argument in the message_sent
3387  * callback.
3388  *
3389  * Returns: #GST_RTSP_OK on success.
3390  *
3391  * Since: 0.10.25
3392  */
3393 GstRTSPResult
3394 gst_rtsp_watch_send_message (GstRTSPWatch * watch, GstRTSPMessage * message,
3395     guint * id)
3396 {
3397   GString *str;
3398   guint size;
3399
3400   g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
3401   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
3402
3403   /* make a record with the message as a string and id */
3404   str = message_to_string (watch->conn, message);
3405   size = str->len;
3406   return gst_rtsp_watch_write_data (watch,
3407       (guint8 *) g_string_free (str, FALSE), size, id);
3408 }