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