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