Add RTSP channel object for async io
[platform/upstream/gstreamer.git] / gst-libs / gst / rtsp / gstrtspconnection.c
1 /* GStreamer
2  * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.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  * <refsect2>
49  * <para>
50  * This object manages the RTSP connection to the server. It provides function
51  * to receive and send bytes and messages.
52  * </para>
53  * </refsect2>
54  *  
55  * Last reviewed on 2007-07-24 (0.10.14)
56  */
57
58 #ifdef HAVE_CONFIG_H
59 #  include <config.h>
60 #endif
61
62 #include <stdio.h>
63 #include <errno.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <time.h>
67
68 #ifdef HAVE_UNISTD_H
69 #include <unistd.h>
70 #endif
71
72
73 /* we include this here to get the G_OS_* defines */
74 #include <glib.h>
75 #include <gst/gst.h>
76
77 #ifdef G_OS_WIN32
78 #include <winsock2.h>
79 #include <ws2tcpip.h>
80 #define EINPROGRESS WSAEINPROGRESS
81 #else
82 #include <sys/ioctl.h>
83 #include <netdb.h>
84 #include <sys/socket.h>
85 #include <netinet/in.h>
86 #include <arpa/inet.h>
87 #include <fcntl.h>
88 #endif
89
90 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
91 #include <sys/filio.h>
92 #endif
93
94 #include "gstrtspconnection.h"
95 #include "gstrtspbase64.h"
96 #include "md5.h"
97
98 #ifdef G_OS_WIN32
99 #define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0)
100 #define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0)
101 #define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, (const char *)val, len)
102 #define CLOSE_SOCKET(sock) closesocket (sock)
103 #define ERRNO_IS_EAGAIN (WSAGetLastError () == WSAEWOULDBLOCK)
104 #define ERRNO_IS_EINTR (WSAGetLastError () == WSAEINTR)
105 /* According to Microsoft's connect() documentation this one returns
106  * WSAEWOULDBLOCK and not WSAEINPROGRESS. */
107 #define ERRNO_IS_EINPROGRESS (WSAGetLastError () == WSAEWOULDBLOCK)
108 #else
109 #define READ_SOCKET(fd, buf, len) read (fd, buf, len)
110 #define WRITE_SOCKET(fd, buf, len) write (fd, buf, len)
111 #define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, val, len)
112 #define CLOSE_SOCKET(sock) close (sock)
113 #define ERRNO_IS_EAGAIN (errno == EAGAIN)
114 #define ERRNO_IS_EINTR (errno == EINTR)
115 #define ERRNO_IS_EINPROGRESS (errno == EINPROGRESS)
116 #endif
117
118 #ifdef G_OS_WIN32
119 static int
120 inet_aton (const char *c, struct in_addr *paddr)
121 {
122   /* note that inet_addr is deprecated on unix because
123    * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
124    * address. */
125   paddr->s_addr = inet_addr (c);
126
127   if (paddr->s_addr == INADDR_NONE)
128     return 0;
129
130   return 1;
131 }
132 #endif
133
134 enum
135 {
136   STATE_START = 0,
137   STATE_DATA_HEADER,
138   STATE_DATA_BODY,
139   STATE_READ_LINES,
140   STATE_END,
141   STATE_LAST
142 };
143
144 /* a structure for constructing RTSPMessages */
145 typedef struct
146 {
147   gint state;
148   guint8 buffer[4096];
149   guint offset;
150
151   guint line;
152   guint8 *body_data;
153   glong body_len;
154 } GstRTSPBuilder;
155
156 static void
157 build_reset (GstRTSPBuilder * builder)
158 {
159   g_free (builder->body_data);
160   memset (builder, 0, sizeof (builder));
161 }
162
163 /**
164  * gst_rtsp_connection_create:
165  * @url: a #GstRTSPUrl 
166  * @conn: a #GstRTSPConnection
167  *
168  * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
169  * The connection will not yet attempt to connect to @url, use
170  * gst_rtsp_connection_connect().
171  *
172  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
173  */
174 GstRTSPResult
175 gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
176 {
177   GstRTSPConnection *newconn;
178
179   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
180
181   newconn = g_new0 (GstRTSPConnection, 1);
182
183   if ((newconn->fdset = gst_poll_new (TRUE)) == NULL)
184     goto no_fdset;
185
186   newconn->url = url;
187   newconn->fd.fd = -1;
188   newconn->timer = g_timer_new ();
189   newconn->timeout = 60;
190
191   newconn->auth_method = GST_RTSP_AUTH_NONE;
192   newconn->username = NULL;
193   newconn->passwd = NULL;
194   newconn->auth_params = NULL;
195
196   *conn = newconn;
197
198   return GST_RTSP_OK;
199
200   /* ERRORS */
201 no_fdset:
202   {
203     g_free (newconn);
204     return GST_RTSP_ESYS;
205   }
206 }
207
208 /**
209  * gst_rtsp_connection_connect:
210  * @conn: a #GstRTSPConnection 
211  * @timeout: a #GTimeVal timeout
212  *
213  * Attempt to connect to the url of @conn made with
214  * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
215  * forever. If @timeout contains a valid timeout, this function will return
216  * #GST_RTSP_ETIMEOUT after the timeout expired.
217  *
218  * This function can be cancelled with gst_rtsp_connection_flush().
219  *
220  * Returns: #GST_RTSP_OK when a connection could be made.
221  */
222 GstRTSPResult
223 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
224 {
225   gint fd;
226   struct sockaddr_in sa_in;
227   struct hostent *hostinfo;
228   const gchar *ip;
229   struct in_addr addr;
230   gint ret;
231   guint16 port;
232   GstRTSPUrl *url;
233   GstClockTime to;
234   gint retval;
235
236 #ifdef G_OS_WIN32
237   unsigned long flags = 1;
238   struct in_addr *addrp;
239 #else
240   char **addrs;
241   gchar ipbuf[INET_ADDRSTRLEN];
242 #endif /* G_OS_WIN32 */
243
244   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
245   g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
246   g_return_val_if_fail (conn->fd.fd < 0, GST_RTSP_EINVAL);
247
248   url = conn->url;
249
250   /* first check if it already is an IP address */
251   if (inet_aton (url->host, &addr)) {
252     ip = url->host;
253   } else {
254     hostinfo = gethostbyname (url->host);
255     if (!hostinfo)
256       goto not_resolved;        /* h_errno set */
257
258     if (hostinfo->h_addrtype != AF_INET)
259       goto not_ip;              /* host not an IP host */
260 #ifdef G_OS_WIN32
261     addrp = (struct in_addr *) hostinfo->h_addr_list[0];
262     /* this is not threadsafe */
263     ip = inet_ntoa (*addrp);
264 #else
265     addrs = hostinfo->h_addr_list;
266     ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
267         sizeof (ipbuf));
268 #endif /* G_OS_WIN32 */
269   }
270
271   /* get the port from the url */
272   gst_rtsp_url_get_port (url, &port);
273
274   memset (&sa_in, 0, sizeof (sa_in));
275   sa_in.sin_family = AF_INET;   /* network socket */
276   sa_in.sin_port = htons (port);        /* on port */
277   sa_in.sin_addr.s_addr = inet_addr (ip);       /* on host ip */
278
279   fd = socket (AF_INET, SOCK_STREAM, 0);
280   if (fd == -1)
281     goto sys_error;
282
283   /* set to non-blocking mode so that we can cancel the connect */
284 #ifndef G_OS_WIN32
285   fcntl (fd, F_SETFL, O_NONBLOCK);
286 #else
287   ioctlsocket (fd, FIONBIO, &flags);
288 #endif /* G_OS_WIN32 */
289
290   /* add the socket to our fdset */
291   conn->fd.fd = fd;
292   gst_poll_add_fd (conn->fdset, &conn->fd);
293
294   /* we are going to connect ASYNC now */
295   ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
296   if (ret == 0)
297     goto done;
298   if (!ERRNO_IS_EINPROGRESS)
299     goto sys_error;
300
301   /* wait for connect to complete up to the specified timeout or until we got
302    * interrupted. */
303   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
304
305   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
306
307   do {
308     retval = gst_poll_wait (conn->fdset, to);
309   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
310
311   if (retval == 0)
312     goto timeout;
313   else if (retval == -1)
314     goto sys_error;
315
316   /* we can still have an error connecting on windows */
317   if (gst_poll_fd_has_error (conn->fdset, &conn->fd)) {
318     socklen_t len = sizeof (errno);
319     getsockopt (conn->fd.fd, SOL_SOCKET, SO_ERROR, &errno, &len);
320     goto sys_error;
321   }
322
323   gst_poll_fd_ignored (conn->fdset, &conn->fd);
324
325 done:
326   conn->ip = g_strdup (ip);
327
328   return GST_RTSP_OK;
329
330 sys_error:
331   {
332     GST_ERROR ("system error %d (%s)", errno, g_strerror (errno));
333     if (conn->fd.fd >= 0) {
334       GST_DEBUG ("remove fd %d", conn->fd.fd);
335       gst_poll_remove_fd (conn->fdset, &conn->fd);
336       conn->fd.fd = -1;
337     }
338     if (fd >= 0)
339       CLOSE_SOCKET (fd);
340     return GST_RTSP_ESYS;
341   }
342 not_resolved:
343   {
344     GST_ERROR ("could not resolve %s", url->host);
345     return GST_RTSP_ENET;
346   }
347 not_ip:
348   {
349     GST_ERROR ("not an IP address");
350     return GST_RTSP_ENOTIP;
351   }
352 timeout:
353   {
354     GST_ERROR ("timeout");
355     if (conn->fd.fd >= 0) {
356       GST_DEBUG ("remove fd %d", conn->fd.fd);
357       gst_poll_remove_fd (conn->fdset, &conn->fd);
358       conn->fd.fd = -1;
359     }
360     if (fd >= 0)
361       CLOSE_SOCKET (fd);
362     return GST_RTSP_ETIMEOUT;
363   }
364 }
365
366 static void
367 md5_digest_to_hex_string (unsigned char digest[16], char string[33])
368 {
369   static const char hexdigits[] = "0123456789abcdef";
370   int i;
371
372   for (i = 0; i < 16; i++) {
373     string[i * 2] = hexdigits[(digest[i] >> 4) & 0x0f];
374     string[i * 2 + 1] = hexdigits[digest[i] & 0x0f];
375   }
376   string[32] = 0;
377 }
378
379 static void
380 auth_digest_compute_hex_urp (const gchar * username,
381     const gchar * realm, const gchar * password, gchar hex_urp[33])
382 {
383   struct MD5Context md5_context;
384   unsigned char digest[16];
385
386   MD5Init (&md5_context);
387   MD5Update (&md5_context, username, strlen (username));
388   MD5Update (&md5_context, ":", 1);
389   MD5Update (&md5_context, realm, strlen (realm));
390   MD5Update (&md5_context, ":", 1);
391   MD5Update (&md5_context, password, strlen (password));
392   MD5Final (digest, &md5_context);
393   md5_digest_to_hex_string (digest, hex_urp);
394 }
395
396 static void
397 auth_digest_compute_response (const gchar * method,
398     const gchar * uri, const gchar * hex_a1, const gchar * nonce,
399     gchar response[33])
400 {
401   char hex_a2[33];
402   struct MD5Context md5_context;
403   unsigned char digest[16];
404
405   /* compute A2 */
406   MD5Init (&md5_context);
407   MD5Update (&md5_context, method, strlen (method));
408   MD5Update (&md5_context, ":", 1);
409   MD5Update (&md5_context, uri, strlen (uri));
410   MD5Final (digest, &md5_context);
411   md5_digest_to_hex_string (digest, hex_a2);
412
413   /* compute KD */
414   MD5Init (&md5_context);
415   MD5Update (&md5_context, hex_a1, strlen (hex_a1));
416   MD5Update (&md5_context, ":", 1);
417   MD5Update (&md5_context, nonce, strlen (nonce));
418   MD5Update (&md5_context, ":", 1);
419
420   MD5Update (&md5_context, hex_a2, 32);
421   MD5Final (digest, &md5_context);
422   md5_digest_to_hex_string (digest, response);
423 }
424
425 static void
426 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
427 {
428   switch (conn->auth_method) {
429     case GST_RTSP_AUTH_BASIC:{
430       gchar *user_pass =
431           g_strdup_printf ("%s:%s", conn->username, conn->passwd);
432       gchar *user_pass64 =
433           gst_rtsp_base64_encode (user_pass, strlen (user_pass));
434       gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
435
436       gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
437           auth_string);
438
439       g_free (user_pass);
440       g_free (user_pass64);
441       break;
442     }
443     case GST_RTSP_AUTH_DIGEST:{
444       gchar response[33], hex_urp[33];
445       gchar *auth_string, *auth_string2;
446       gchar *realm;
447       gchar *nonce;
448       gchar *opaque;
449       const gchar *uri;
450       const gchar *method;
451
452       /* we need to have some params set */
453       if (conn->auth_params == NULL)
454         break;
455
456       /* we need the realm and nonce */
457       realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm");
458       nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce");
459       if (realm == NULL || nonce == NULL)
460         break;
461
462       auth_digest_compute_hex_urp (conn->username, realm, conn->passwd,
463           hex_urp);
464
465       method = gst_rtsp_method_as_text (message->type_data.request.method);
466       uri = message->type_data.request.uri;
467
468       /* Assume no qop, algorithm=md5, stale=false */
469       /* For algorithm MD5, a1 = urp. */
470       auth_digest_compute_response (method, uri, hex_urp, nonce, response);
471       auth_string = g_strdup_printf ("Digest username=\"%s\", "
472           "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
473           conn->username, realm, nonce, uri, response);
474
475       opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
476       if (opaque) {
477         auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
478             opaque);
479         g_free (auth_string);
480         auth_string = auth_string2;
481       }
482       gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
483           auth_string);
484       break;
485     }
486     default:
487       /* Nothing to do */
488       break;
489   }
490 }
491
492 static void
493 add_date_header (GstRTSPMessage * message)
494 {
495   GTimeVal tv;
496   gchar date_string[100];
497   time_t t;
498
499 #ifdef HAVE_GMTIME_R
500   struct tm tm_;
501 #endif
502
503   g_get_current_time (&tv);
504   t = (time_t) tv.tv_sec;
505
506 #ifdef HAVE_GMTIME_R
507   strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
508       gmtime_r (&t, &tm_));
509 #else
510   strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
511       gmtime (&t));
512 #endif
513
514   gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
515 }
516
517 static GstRTSPResult
518 write_bytes (gint fd, const guint8 * buffer, guint * idx, guint size)
519 {
520   guint left;
521
522   if (*idx > size)
523     return GST_RTSP_ERROR;
524
525   left = size - *idx;
526
527   while (left) {
528     gint r;
529
530     r = WRITE_SOCKET (fd, &buffer[*idx], left);
531     if (r == 0) {
532       return GST_RTSP_EINTR;
533     } else if (r < 0) {
534       if (ERRNO_IS_EAGAIN)
535         return GST_RTSP_EINTR;
536       if (!ERRNO_IS_EINTR)
537         return GST_RTSP_ESYS;
538     } else {
539       left -= r;
540       *idx += r;
541     }
542   }
543   return GST_RTSP_OK;
544 }
545
546 static GstRTSPResult
547 read_bytes (gint fd, guint8 * buffer, guint * idx, guint size)
548 {
549   guint left;
550
551   if (*idx > size)
552     return GST_RTSP_ERROR;
553
554   left = size - *idx;
555
556   while (left) {
557     gint r;
558
559     r = READ_SOCKET (fd, &buffer[*idx], left);
560     if (r == 0) {
561       return GST_RTSP_EEOF;
562     } else if (r < 0) {
563       if (ERRNO_IS_EAGAIN)
564         return GST_RTSP_EINTR;
565       if (!ERRNO_IS_EINTR)
566         return GST_RTSP_ESYS;
567     } else {
568       left -= r;
569       *idx += r;
570     }
571   }
572   return GST_RTSP_OK;
573 }
574
575 static GstRTSPResult
576 read_line (gint fd, guint8 * buffer, guint * idx, guint size)
577 {
578   while (TRUE) {
579     guint8 c;
580     gint r;
581
582     r = READ_SOCKET (fd, &c, 1);
583     if (r == 0) {
584       return GST_RTSP_EEOF;
585     } else if (r < 0) {
586       if (ERRNO_IS_EAGAIN)
587         return GST_RTSP_EINTR;
588       if (!ERRNO_IS_EINTR)
589         return GST_RTSP_ESYS;
590     } else {
591       if (c == '\n')            /* end on \n */
592         break;
593       if (c == '\r')            /* ignore \r */
594         continue;
595
596       if (*idx < size - 1)
597         buffer[(*idx)++] = c;
598     }
599   }
600   buffer[*idx] = '\0';
601
602   return GST_RTSP_OK;
603 }
604
605 /**
606  * gst_rtsp_connection_write:
607  * @conn: a #GstRTSPConnection
608  * @data: the data to write
609  * @size: the size of @data
610  * @timeout: a timeout value or #NULL
611  *
612  * Attempt to write @size bytes of @data to the connected @conn, blocking up to
613  * the specified @timeout. @timeout can be #NULL, in which case this function
614  * might block forever.
615  * 
616  * This function can be cancelled with gst_rtsp_connection_flush().
617  *
618  * Returns: #GST_RTSP_OK on success.
619  */
620 GstRTSPResult
621 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
622     guint size, GTimeVal * timeout)
623 {
624   guint offset;
625   gint retval;
626   GstClockTime to;
627   GstRTSPResult res;
628
629   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
630   g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
631   g_return_val_if_fail (conn->fd.fd >= 0, GST_RTSP_EINVAL);
632
633   gst_poll_set_controllable (conn->fdset, TRUE);
634   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
635   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, FALSE);
636   /* clear all previous poll results */
637   gst_poll_fd_ignored (conn->fdset, &conn->fd);
638
639   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
640
641   offset = 0;
642
643   while (TRUE) {
644     /* try to write */
645     res = write_bytes (conn->fd.fd, data, &offset, size);
646     if (res == GST_RTSP_OK)
647       break;
648     if (res != GST_RTSP_EINTR)
649       goto write_error;
650
651     /* not all is written, wait until we can write more */
652     do {
653       retval = gst_poll_wait (conn->fdset, to);
654     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
655
656     if (retval == 0)
657       goto timeout;
658
659     if (retval == -1) {
660       if (errno == EBUSY)
661         goto stopped;
662       else
663         goto select_error;
664     }
665   }
666   return GST_RTSP_OK;
667
668   /* ERRORS */
669 timeout:
670   {
671     return GST_RTSP_ETIMEOUT;
672   }
673 select_error:
674   {
675     return GST_RTSP_ESYS;
676   }
677 stopped:
678   {
679     return GST_RTSP_EINTR;
680   }
681 write_error:
682   {
683     return res;
684   }
685 }
686
687 static GString *
688 message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message)
689 {
690   GString *str = NULL;
691
692   str = g_string_new ("");
693
694   switch (message->type) {
695     case GST_RTSP_MESSAGE_REQUEST:
696       /* create request string, add CSeq */
697       g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
698           "CSeq: %d\r\n",
699           gst_rtsp_method_as_text (message->type_data.request.method),
700           message->type_data.request.uri, conn->cseq++);
701       /* add session id if we have one */
702       if (conn->session_id[0] != '\0') {
703         gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
704             conn->session_id);
705       }
706       /* add any authentication headers */
707       add_auth_header (conn, message);
708       break;
709     case GST_RTSP_MESSAGE_RESPONSE:
710       /* create response string */
711       g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
712           message->type_data.response.code, message->type_data.response.reason);
713       break;
714     case GST_RTSP_MESSAGE_DATA:
715     {
716       guint8 data_header[4];
717
718       /* prepare data header */
719       data_header[0] = '$';
720       data_header[1] = message->type_data.data.channel;
721       data_header[2] = (message->body_size >> 8) & 0xff;
722       data_header[3] = message->body_size & 0xff;
723
724       /* create string with header and data */
725       str = g_string_append_len (str, (gchar *) data_header, 4);
726       str =
727           g_string_append_len (str, (gchar *) message->body,
728           message->body_size);
729       break;
730     }
731     default:
732       g_string_free (str, TRUE);
733       g_return_val_if_reached (NULL);
734       break;
735   }
736
737   /* append headers and body */
738   if (message->type != GST_RTSP_MESSAGE_DATA) {
739     /* add date header */
740     add_date_header (message);
741
742     /* append headers */
743     gst_rtsp_message_append_headers (message, str);
744
745     /* append Content-Length and body if needed */
746     if (message->body != NULL && message->body_size > 0) {
747       gchar *len;
748
749       len = g_strdup_printf ("%d", message->body_size);
750       g_string_append_printf (str, "%s: %s\r\n",
751           gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
752       g_free (len);
753       /* header ends here */
754       g_string_append (str, "\r\n");
755       str =
756           g_string_append_len (str, (gchar *) message->body,
757           message->body_size);
758     } else {
759       /* just end headers */
760       g_string_append (str, "\r\n");
761     }
762   }
763
764   return str;
765 }
766
767 /**
768  * gst_rtsp_connection_send:
769  * @conn: a #GstRTSPConnection
770  * @message: the message to send
771  * @timeout: a timeout value or #NULL
772  *
773  * Attempt to send @message to the connected @conn, blocking up to
774  * the specified @timeout. @timeout can be #NULL, in which case this function
775  * might block forever.
776  * 
777  * This function can be cancelled with gst_rtsp_connection_flush().
778  *
779  * Returns: #GST_RTSP_OK on success.
780  */
781 GstRTSPResult
782 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
783     GTimeVal * timeout)
784 {
785   GString *str = NULL;
786   GstRTSPResult res;
787
788 #ifdef G_OS_WIN32
789   WSADATA w;
790   int error;
791 #endif
792
793   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
794   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
795
796 #ifdef G_OS_WIN32
797   error = WSAStartup (0x0202, &w);
798
799   if (error)
800     goto startup_error;
801
802   if (w.wVersion != 0x0202)
803     goto version_error;
804 #endif
805
806   if (!(str = message_to_string (conn, message)))
807     goto no_message;
808
809   /* write request */
810   res =
811       gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
812
813   g_string_free (str, TRUE);
814
815   return res;
816
817 no_message:
818   {
819     g_warning ("Wrong message");
820     return GST_RTSP_EINVAL;
821   }
822 #ifdef G_OS_WIN32
823 startup_error:
824   {
825     g_warning ("Error %d on WSAStartup", error);
826     return GST_RTSP_EWSASTART;
827   }
828 version_error:
829   {
830     g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
831         w.wVersion);
832     WSACleanup ();
833     return GST_RTSP_EWSAVERSION;
834   }
835 #endif
836 }
837
838 static void
839 parse_string (gchar * dest, gint size, gchar ** src)
840 {
841   gint idx;
842
843   idx = 0;
844   /* skip spaces */
845   while (g_ascii_isspace (**src))
846     (*src)++;
847
848   while (!g_ascii_isspace (**src) && **src != '\0') {
849     if (idx < size - 1)
850       dest[idx++] = **src;
851     (*src)++;
852   }
853   if (size > 0)
854     dest[idx] = '\0';
855 }
856
857 static void
858 parse_key (gchar * dest, gint size, gchar ** src)
859 {
860   gint idx;
861
862   idx = 0;
863   while (**src != ':' && **src != '\0') {
864     if (idx < size - 1)
865       dest[idx++] = **src;
866     (*src)++;
867   }
868   if (size > 0)
869     dest[idx] = '\0';
870 }
871
872 static GstRTSPResult
873 parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
874 {
875   GstRTSPResult res;
876   gchar versionstr[20];
877   gchar codestr[4];
878   gint code;
879   gchar *bptr;
880
881   bptr = (gchar *) buffer;
882
883   parse_string (versionstr, sizeof (versionstr), &bptr);
884   parse_string (codestr, sizeof (codestr), &bptr);
885   code = atoi (codestr);
886
887   while (g_ascii_isspace (*bptr))
888     bptr++;
889
890   if (strcmp (versionstr, "RTSP/1.0") == 0)
891     GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
892         parse_error);
893   else if (strncmp (versionstr, "RTSP/", 5) == 0) {
894     GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
895         parse_error);
896     msg->type_data.response.version = GST_RTSP_VERSION_INVALID;
897   } else
898     goto parse_error;
899
900   return GST_RTSP_OK;
901
902 parse_error:
903   {
904     return GST_RTSP_EPARSE;
905   }
906 }
907
908 static GstRTSPResult
909 parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
910 {
911   GstRTSPResult res = GST_RTSP_OK;
912   gchar versionstr[20];
913   gchar methodstr[20];
914   gchar urlstr[4096];
915   gchar *bptr;
916   GstRTSPMethod method;
917
918   bptr = (gchar *) buffer;
919
920   parse_string (methodstr, sizeof (methodstr), &bptr);
921   method = gst_rtsp_find_method (methodstr);
922
923   parse_string (urlstr, sizeof (urlstr), &bptr);
924   if (*urlstr == '\0')
925     res = GST_RTSP_EPARSE;
926
927   parse_string (versionstr, sizeof (versionstr), &bptr);
928
929   if (*bptr != '\0')
930     res = GST_RTSP_EPARSE;
931
932   if (strcmp (versionstr, "RTSP/1.0") == 0) {
933     if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
934       res = GST_RTSP_EPARSE;
935   } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
936     if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
937       res = GST_RTSP_EPARSE;
938     msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
939   } else {
940     gst_rtsp_message_init_request (msg, method, urlstr);
941     msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
942     res = GST_RTSP_EPARSE;
943   }
944
945   return res;
946 }
947
948 /* parsing lines means reading a Key: Value pair */
949 static GstRTSPResult
950 parse_line (guint8 * buffer, GstRTSPMessage * msg)
951 {
952   gchar key[32];
953   gchar *bptr;
954   GstRTSPHeaderField field;
955
956   bptr = (gchar *) buffer;
957
958   /* read key */
959   parse_key (key, sizeof (key), &bptr);
960   if (*bptr != ':')
961     goto no_column;
962
963   bptr++;
964
965   field = gst_rtsp_find_header_field (key);
966   if (field != GST_RTSP_HDR_INVALID) {
967     while (g_ascii_isspace (*bptr))
968       bptr++;
969     gst_rtsp_message_add_header (msg, field, bptr);
970   }
971
972   return GST_RTSP_OK;
973
974 no_column:
975   {
976     return GST_RTSP_EPARSE;
977   }
978 }
979
980 /* returns:
981  *  GST_RTSP_OK when a complete message was read.
982  *  GST_RTSP_EEOF: when the socket is closed
983  *  GST_RTSP_EINTR: when more data is needed.
984  *  GST_RTSP_..: some other error occured.
985  */
986 static GstRTSPResult
987 build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
988     GstRTSPConnection * conn)
989 {
990   GstRTSPResult res;
991
992   while (TRUE) {
993     switch (builder->state) {
994       case STATE_START:
995         builder->offset = 0;
996         res =
997             read_bytes (conn->fd.fd, (guint8 *) builder->buffer,
998             &builder->offset, 1);
999         if (res != GST_RTSP_OK)
1000           goto done;
1001
1002         /* we have 1 bytes now and we can see if this is a data message or
1003          * not */
1004         if (builder->buffer[0] == '$') {
1005           /* data message, prepare for the header */
1006           builder->state = STATE_DATA_HEADER;
1007         } else {
1008           builder->line = 0;
1009           builder->state = STATE_READ_LINES;
1010         }
1011         break;
1012       case STATE_DATA_HEADER:
1013       {
1014         res =
1015             read_bytes (conn->fd.fd, (guint8 *) builder->buffer,
1016             &builder->offset, 4);
1017         if (res != GST_RTSP_OK)
1018           goto done;
1019
1020         gst_rtsp_message_init_data (message, builder->buffer[1]);
1021
1022         builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
1023         builder->body_data = g_malloc (builder->body_len + 1);
1024         builder->body_data[builder->body_len] = '\0';
1025         builder->offset = 0;
1026         builder->state = STATE_DATA_BODY;
1027         break;
1028       }
1029       case STATE_DATA_BODY:
1030       {
1031         res = read_bytes (conn->fd.fd, builder->body_data, &builder->offset,
1032             builder->body_len);
1033         if (res != GST_RTSP_OK)
1034           goto done;
1035
1036         /* we have the complete body now */
1037         gst_rtsp_message_take_body (message,
1038             (guint8 *) builder->body_data, builder->body_len);
1039         builder->body_data = NULL;
1040         builder->body_len = 0;
1041
1042         builder->state = STATE_END;
1043         break;
1044       }
1045       case STATE_READ_LINES:
1046       {
1047         res = read_line (conn->fd.fd, builder->buffer, &builder->offset,
1048             sizeof (builder->buffer));
1049         if (res != GST_RTSP_OK)
1050           goto done;
1051
1052         /* we have a regular response */
1053         if (builder->buffer[0] == '\r') {
1054           builder->buffer[0] = '\0';
1055         }
1056
1057         if (builder->buffer[0] == '\0') {
1058           gchar *hdrval;
1059
1060           /* empty line, end of message header */
1061           /* see if there is a Content-Length header */
1062           if (gst_rtsp_message_get_header (message,
1063                   GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK) {
1064             /* there is, prepare to read the body */
1065             builder->body_len = atol (hdrval);
1066             builder->body_data = g_malloc (builder->body_len + 1);
1067             builder->body_data[builder->body_len] = '\0';
1068             builder->offset = 0;
1069             builder->state = STATE_DATA_BODY;
1070           } else {
1071             builder->state = STATE_END;
1072           }
1073           break;
1074         }
1075
1076         /* we have a line */
1077         if (builder->line == 0) {
1078           /* first line, check for response status */
1079           if (memcmp (builder->buffer, "RTSP", 4) == 0) {
1080             res = parse_response_status (builder->buffer, message);
1081           } else {
1082             res = parse_request_line (builder->buffer, message);
1083           }
1084         } else {
1085           /* else just parse the line */
1086           parse_line (builder->buffer, message);
1087         }
1088         builder->line++;
1089         builder->offset = 0;
1090         break;
1091       }
1092       case STATE_END:
1093       {
1094         gchar *session_id;
1095
1096         /* save session id in the connection for further use */
1097         if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
1098                 &session_id, 0) == GST_RTSP_OK) {
1099           gint maxlen, i;
1100
1101           maxlen = sizeof (conn->session_id) - 1;
1102           /* the sessionid can have attributes marked with ;
1103            * Make sure we strip them */
1104           for (i = 0; session_id[i] != '\0'; i++) {
1105             if (session_id[i] == ';') {
1106               maxlen = i;
1107               /* parse timeout */
1108               do {
1109                 i++;
1110               } while (g_ascii_isspace (session_id[i]));
1111               if (g_str_has_prefix (&session_id[i], "timeout=")) {
1112                 gint to;
1113
1114                 /* if we parsed something valid, configure */
1115                 if ((to = atoi (&session_id[i + 9])) > 0)
1116                   conn->timeout = to;
1117               }
1118               break;
1119             }
1120           }
1121
1122           /* make sure to not overflow */
1123           strncpy (conn->session_id, session_id, maxlen);
1124           conn->session_id[maxlen] = '\0';
1125         }
1126         res = GST_RTSP_OK;
1127         goto done;
1128       }
1129       default:
1130         res = GST_RTSP_ERROR;
1131         break;
1132     }
1133   }
1134 done:
1135   return res;
1136 }
1137
1138 /**
1139  * gst_rtsp_connection_read:
1140  * @conn: a #GstRTSPConnection
1141  * @data: the data to read
1142  * @size: the size of @data
1143  * @timeout: a timeout value or #NULL
1144  *
1145  * Attempt to read @size bytes into @data from the connected @conn, blocking up to
1146  * the specified @timeout. @timeout can be #NULL, in which case this function
1147  * might block forever.
1148  *
1149  * This function can be cancelled with gst_rtsp_connection_flush().
1150  *
1151  * Returns: #GST_RTSP_OK on success.
1152  */
1153 GstRTSPResult
1154 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
1155     GTimeVal * timeout)
1156 {
1157   guint offset;
1158   gint retval;
1159   GstClockTime to;
1160   GstRTSPResult res;
1161
1162   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1163   g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
1164   g_return_val_if_fail (conn->fd.fd >= 0, GST_RTSP_EINVAL);
1165
1166   if (size == 0)
1167     return GST_RTSP_OK;
1168
1169   offset = 0;
1170
1171   /* configure timeout if any */
1172   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
1173
1174   gst_poll_set_controllable (conn->fdset, TRUE);
1175   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, FALSE);
1176   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, TRUE);
1177
1178   while (TRUE) {
1179     res = read_bytes (conn->fd.fd, data, &offset, size);
1180     if (res == GST_RTSP_EEOF)
1181       goto eof;
1182     if (res == GST_RTSP_OK)
1183       break;
1184     if (res != GST_RTSP_EINTR)
1185       goto read_error;
1186
1187     do {
1188       retval = gst_poll_wait (conn->fdset, to);
1189     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
1190
1191     /* check for timeout */
1192     if (retval == 0)
1193       goto select_timeout;
1194
1195     if (retval == -1) {
1196       if (errno == EBUSY)
1197         goto stopped;
1198       else
1199         goto select_error;
1200     }
1201     gst_poll_set_controllable (conn->fdset, FALSE);
1202   }
1203   return GST_RTSP_OK;
1204
1205   /* ERRORS */
1206 select_error:
1207   {
1208     return GST_RTSP_ESYS;
1209   }
1210 select_timeout:
1211   {
1212     return GST_RTSP_ETIMEOUT;
1213   }
1214 stopped:
1215   {
1216     return GST_RTSP_EINTR;
1217   }
1218 eof:
1219   {
1220     return GST_RTSP_EEOF;
1221   }
1222 read_error:
1223   {
1224     return res;
1225   }
1226 }
1227
1228
1229 /**
1230  * gst_rtsp_connection_receive:
1231  * @conn: a #GstRTSPConnection
1232  * @message: the message to read
1233  * @timeout: a timeout value or #NULL
1234  *
1235  * Attempt to read into @message from the connected @conn, blocking up to
1236  * the specified @timeout. @timeout can be #NULL, in which case this function
1237  * might block forever.
1238  * 
1239  * This function can be cancelled with gst_rtsp_connection_flush().
1240  *
1241  * Returns: #GST_RTSP_OK on success.
1242  */
1243 GstRTSPResult
1244 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
1245     GTimeVal * timeout)
1246 {
1247   GstRTSPResult res;
1248   GstRTSPBuilder builder = { 0 };
1249   gint retval;
1250   GstClockTime to;
1251
1252   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1253   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
1254
1255   /* configure timeout if any */
1256   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
1257
1258   gst_poll_set_controllable (conn->fdset, TRUE);
1259   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, FALSE);
1260   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, TRUE);
1261
1262   while (TRUE) {
1263     res = build_next (&builder, message, conn);
1264     if (res == GST_RTSP_EEOF)
1265       goto eof;
1266     if (res == GST_RTSP_OK)
1267       break;
1268     if (res != GST_RTSP_EINTR)
1269       goto read_error;
1270
1271     do {
1272       retval = gst_poll_wait (conn->fdset, to);
1273     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
1274
1275     /* check for timeout */
1276     if (retval == 0)
1277       goto select_timeout;
1278
1279     if (retval == -1) {
1280       if (errno == EBUSY)
1281         goto stopped;
1282       else
1283         goto select_error;
1284     }
1285     gst_poll_set_controllable (conn->fdset, FALSE);
1286   }
1287
1288   /* we have a message here */
1289   build_reset (&builder);
1290
1291   return GST_RTSP_OK;
1292
1293   /* ERRORS */
1294 select_error:
1295   {
1296     res = GST_RTSP_ESYS;
1297     goto cleanup;
1298   }
1299 select_timeout:
1300   {
1301     res = GST_RTSP_ETIMEOUT;
1302     goto cleanup;
1303   }
1304 stopped:
1305   {
1306     res = GST_RTSP_EINTR;
1307     goto cleanup;
1308   }
1309 eof:
1310   {
1311     res = GST_RTSP_EEOF;
1312     goto cleanup;
1313   }
1314 read_error:
1315 cleanup:
1316   {
1317     build_reset (&builder);
1318     gst_rtsp_message_unset (message);
1319     return res;
1320   }
1321 }
1322
1323 /**
1324  * gst_rtsp_connection_close:
1325  * @conn: a #GstRTSPConnection
1326  *
1327  * Close the connected @conn.
1328  * 
1329  * Returns: #GST_RTSP_OK on success.
1330  */
1331 GstRTSPResult
1332 gst_rtsp_connection_close (GstRTSPConnection * conn)
1333 {
1334   gint res;
1335
1336   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1337
1338   g_free (conn->ip);
1339   conn->ip = NULL;
1340
1341   if (conn->fd.fd != -1) {
1342     gst_poll_remove_fd (conn->fdset, &conn->fd);
1343     res = CLOSE_SOCKET (conn->fd.fd);
1344     conn->fd.fd = -1;
1345 #ifdef G_OS_WIN32
1346     WSACleanup ();
1347 #endif
1348     if (res != 0)
1349       goto sys_error;
1350   }
1351
1352   return GST_RTSP_OK;
1353
1354 sys_error:
1355   {
1356     return GST_RTSP_ESYS;
1357   }
1358 }
1359
1360 /**
1361  * gst_rtsp_connection_free:
1362  * @conn: a #GstRTSPConnection
1363  *
1364  * Close and free @conn.
1365  * 
1366  * Returns: #GST_RTSP_OK on success.
1367  */
1368 GstRTSPResult
1369 gst_rtsp_connection_free (GstRTSPConnection * conn)
1370 {
1371   GstRTSPResult res;
1372
1373   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1374
1375   res = gst_rtsp_connection_close (conn);
1376   gst_poll_free (conn->fdset);
1377 #ifdef G_OS_WIN32
1378   WSACleanup ();
1379 #endif
1380   g_timer_destroy (conn->timer);
1381   g_free (conn->username);
1382   g_free (conn->passwd);
1383   gst_rtsp_connection_clear_auth_params (conn);
1384   g_free (conn);
1385
1386   return res;
1387 }
1388
1389 /**
1390  * gst_rtsp_connection_poll:
1391  * @conn: a #GstRTSPConnection
1392  * @events: a bitmask of #GstRTSPEvent flags to check
1393  * @revents: location for result flags 
1394  * @timeout: a timeout
1395  *
1396  * Wait up to the specified @timeout for the connection to become available for
1397  * at least one of the operations specified in @events. When the function returns
1398  * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
1399  * @conn.
1400  *
1401  * @timeout can be #NULL, in which case this function might block forever.
1402  *
1403  * This function can be cancelled with gst_rtsp_connection_flush().
1404  * 
1405  * Returns: #GST_RTSP_OK on success.
1406  *
1407  * Since: 0.10.15
1408  */
1409 GstRTSPResult
1410 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
1411     GstRTSPEvent * revents, GTimeVal * timeout)
1412 {
1413   GstClockTime to;
1414   gint retval;
1415
1416   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1417   g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
1418   g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
1419   g_return_val_if_fail (conn->fd.fd >= 0, GST_RTSP_EINVAL);
1420
1421   gst_poll_set_controllable (conn->fdset, TRUE);
1422
1423   /* add fd to writer set when asked to */
1424   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, events & GST_RTSP_EV_WRITE);
1425
1426   /* add fd to reader set when asked to */
1427   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, events & GST_RTSP_EV_READ);
1428
1429   /* configure timeout if any */
1430   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
1431
1432   do {
1433     retval = gst_poll_wait (conn->fdset, to);
1434   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
1435
1436   if (retval == 0)
1437     goto select_timeout;
1438
1439   if (retval == -1) {
1440     if (errno == EBUSY)
1441       goto stopped;
1442     else
1443       goto select_error;
1444   }
1445
1446   *revents = 0;
1447   if (events & GST_RTSP_EV_READ) {
1448     if (gst_poll_fd_can_read (conn->fdset, &conn->fd))
1449       *revents |= GST_RTSP_EV_READ;
1450   }
1451   if (events & GST_RTSP_EV_WRITE) {
1452     if (gst_poll_fd_can_write (conn->fdset, &conn->fd))
1453       *revents |= GST_RTSP_EV_WRITE;
1454   }
1455   return GST_RTSP_OK;
1456
1457   /* ERRORS */
1458 select_timeout:
1459   {
1460     return GST_RTSP_ETIMEOUT;
1461   }
1462 select_error:
1463   {
1464     return GST_RTSP_ESYS;
1465   }
1466 stopped:
1467   {
1468     return GST_RTSP_EINTR;
1469   }
1470 }
1471
1472 /**
1473  * gst_rtsp_connection_next_timeout:
1474  * @conn: a #GstRTSPConnection
1475  * @timeout: a timeout
1476  *
1477  * Calculate the next timeout for @conn, storing the result in @timeout.
1478  * 
1479  * Returns: #GST_RTSP_OK.
1480  */
1481 GstRTSPResult
1482 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
1483 {
1484   gdouble elapsed;
1485   glong sec;
1486   gulong usec;
1487
1488   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1489   g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
1490
1491   elapsed = g_timer_elapsed (conn->timer, &usec);
1492   if (elapsed >= conn->timeout) {
1493     sec = 0;
1494     usec = 0;
1495   } else {
1496     sec = conn->timeout - elapsed;
1497   }
1498
1499   timeout->tv_sec = sec;
1500   timeout->tv_usec = usec;
1501
1502   return GST_RTSP_OK;
1503 }
1504
1505 /**
1506  * gst_rtsp_connection_reset_timeout:
1507  * @conn: a #GstRTSPConnection
1508  *
1509  * Reset the timeout of @conn.
1510  * 
1511  * Returns: #GST_RTSP_OK.
1512  */
1513 GstRTSPResult
1514 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
1515 {
1516   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1517
1518   g_timer_start (conn->timer);
1519
1520   return GST_RTSP_OK;
1521 }
1522
1523 /**
1524  * gst_rtsp_connection_flush:
1525  * @conn: a #GstRTSPConnection
1526  * @flush: start or stop the flush
1527  *
1528  * Start or stop the flushing action on @conn. When flushing, all current
1529  * and future actions on @conn will return #GST_RTSP_EINTR until the connection
1530  * is set to non-flushing mode again.
1531  * 
1532  * Returns: #GST_RTSP_OK.
1533  */
1534 GstRTSPResult
1535 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
1536 {
1537   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1538
1539   gst_poll_set_flushing (conn->fdset, flush);
1540
1541   return GST_RTSP_OK;
1542 }
1543
1544 /**
1545  * gst_rtsp_connection_set_auth:
1546  * @conn: a #GstRTSPConnection
1547  * @method: authentication method
1548  * @user: the user
1549  * @pass: the password
1550  *
1551  * Configure @conn for authentication mode @method with @user and @pass as the
1552  * user and password respectively.
1553  * 
1554  * Returns: #GST_RTSP_OK.
1555  */
1556 GstRTSPResult
1557 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
1558     GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
1559 {
1560   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1561
1562   if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
1563           || g_strrstr (user, ":") != NULL))
1564     return GST_RTSP_EINVAL;
1565
1566   /* Make sure the username and passwd are being set for authentication */
1567   if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
1568     return GST_RTSP_EINVAL;
1569
1570   /* ":" chars are not allowed in usernames for basic auth */
1571   if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
1572     return GST_RTSP_EINVAL;
1573
1574   g_free (conn->username);
1575   g_free (conn->passwd);
1576
1577   conn->auth_method = method;
1578   conn->username = g_strdup (user);
1579   conn->passwd = g_strdup (pass);
1580
1581   return GST_RTSP_OK;
1582 }
1583
1584 /**
1585  * str_case_hash:
1586  * @key: ASCII string to hash
1587  *
1588  * Hashes @key in a case-insensitive manner.
1589  *
1590  * Returns: the hash code.
1591  **/
1592 static guint
1593 str_case_hash (gconstpointer key)
1594 {
1595   const char *p = key;
1596   guint h = g_ascii_toupper (*p);
1597
1598   if (h)
1599     for (p += 1; *p != '\0'; p++)
1600       h = (h << 5) - h + g_ascii_toupper (*p);
1601
1602   return h;
1603 }
1604
1605 /**
1606  * str_case_equal:
1607  * @v1: an ASCII string
1608  * @v2: another ASCII string
1609  *
1610  * Compares @v1 and @v2 in a case-insensitive manner
1611  *
1612  * Returns: %TRUE if they are equal (modulo case)
1613  **/
1614 static gboolean
1615 str_case_equal (gconstpointer v1, gconstpointer v2)
1616 {
1617   const char *string1 = v1;
1618   const char *string2 = v2;
1619
1620   return g_ascii_strcasecmp (string1, string2) == 0;
1621 }
1622
1623 /**
1624  * gst_rtsp_connection_set_auth_param:
1625  * @conn: a #GstRTSPConnection
1626  * @param: authentication directive
1627  * @value: value
1628  *
1629  * Setup @conn with authentication directives. This is not necesary for
1630  * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
1631  * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
1632  * in the WWW-Authenticate response header and can include realm, domain,
1633  * nonce, opaque, stale, algorithm, qop as per RFC2617.
1634  * 
1635  * Since: 0.10.20
1636  */
1637 void
1638 gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
1639     const gchar * param, const gchar * value)
1640 {
1641   g_return_if_fail (conn != NULL);
1642   g_return_if_fail (param != NULL);
1643
1644   if (conn->auth_params == NULL) {
1645     conn->auth_params =
1646         g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
1647   }
1648   g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
1649 }
1650
1651 /**
1652  * gst_rtsp_connection_clear_auth_params:
1653  * @conn: a #GstRTSPConnection
1654  *
1655  * Clear the list of authentication directives stored in @conn.
1656  *
1657  * Since: 0.10.20
1658  */
1659 void
1660 gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
1661 {
1662   g_return_if_fail (conn != NULL);
1663
1664   if (conn->auth_params != NULL) {
1665     g_hash_table_destroy (conn->auth_params);
1666     conn->auth_params = NULL;
1667   }
1668 }
1669
1670 /**
1671  * gst_rtsp_connection_set_qos_dscp:
1672  * @conn: a #GstRTSPConnection
1673  * @qos_dscp: DSCP value
1674  *
1675  * Configure @conn to use the specified DSCP value.
1676  *
1677  * Returns: #GST_RTSP_OK on success.
1678  *
1679  * Since: 0.10.20
1680  */
1681 GstRTSPResult
1682 gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
1683 {
1684   struct sockaddr_storage sa_s;
1685   socklen_t sa_sl = sizeof (sa_s);
1686   gint af;
1687   gint tos;
1688
1689   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1690   g_return_val_if_fail (conn->fd.fd >= 0, GST_RTSP_EINVAL);
1691
1692   if (getsockname (conn->fd.fd, (struct sockaddr *) &sa_s, &sa_sl) < 0)
1693     goto no_getsockname;
1694
1695   af = sa_s.ss_family;
1696
1697   /* if this is an IPv4-mapped address then do IPv4 QoS */
1698   if (af == AF_INET6) {
1699     struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) &sa_s;
1700
1701     if (IN6_IS_ADDR_V4MAPPED (&saddr6->sin6_addr))
1702       af = AF_INET;
1703   }
1704
1705   /* extract and shift 6 bits of the DSCP */
1706   tos = (qos_dscp & 0x3f) << 2;
1707
1708   switch (af) {
1709     case AF_INET:
1710       if (SETSOCKOPT (conn->fd.fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
1711         goto no_setsockopt;
1712       break;
1713     case AF_INET6:
1714 #ifdef IPV6_TCLASS
1715       if (SETSOCKOPT (conn->fd.fd, IPPROTO_IPV6, IPV6_TCLASS, &tos,
1716               sizeof (tos)) < 0)
1717         goto no_setsockopt;
1718       break;
1719 #endif
1720     default:
1721       goto wrong_family;
1722   }
1723
1724   return GST_RTSP_OK;
1725
1726   /* ERRORS */
1727 no_getsockname:
1728 no_setsockopt:
1729   {
1730     return GST_RTSP_ESYS;
1731   }
1732
1733 wrong_family:
1734   {
1735     return GST_RTSP_ERROR;
1736   }
1737 }
1738
1739 /**
1740  * gst_rtsp_connection_get_ip:
1741  * @conn: a #GstRTSPConnection
1742  *
1743  * Retrieve the IP address of the other end of @conn.
1744  *
1745  * Returns: The IP address as a string. this value remains valid until the
1746  * connection is closed.
1747  *
1748  * Since: 0.10.20
1749  */
1750 const gchar *
1751 gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
1752 {
1753   g_return_val_if_fail (conn != NULL, NULL);
1754
1755   return conn->ip;
1756 }
1757
1758 #define READ_COND   (G_IO_IN | G_IO_HUP | G_IO_ERR)
1759 #define WRITE_COND  (G_IO_OUT | G_IO_ERR)
1760
1761 typedef struct
1762 {
1763   GString *str;
1764   guint cseq;
1765 } GstRTSPRec;
1766
1767 /* async functions */
1768 struct _GstRTSPChannel
1769 {
1770   GSource source;
1771
1772   GstRTSPConnection *conn;
1773
1774   GstRTSPBuilder builder;
1775   GstRTSPMessage message;
1776
1777   GPollFD readfd;
1778   GPollFD writefd;
1779   gboolean write_added;
1780
1781   /* queued message for transmission */
1782   GList *messages;
1783   guint8 *write_data;
1784   guint write_off;
1785   guint write_len;
1786   guint write_cseq;
1787
1788   GstRTSPChannelFuncs funcs;
1789
1790   gpointer user_data;
1791   GDestroyNotify notify;
1792 };
1793
1794 static gboolean
1795 gst_rtsp_source_prepare (GSource * source, gint * timeout)
1796 {
1797   GstRTSPChannel *channel = (GstRTSPChannel *) source;
1798
1799   *timeout = (channel->conn->timeout * 1000);
1800
1801   return FALSE;
1802 }
1803
1804 static gboolean
1805 gst_rtsp_source_check (GSource * source)
1806 {
1807   GstRTSPChannel *channel = (GstRTSPChannel *) source;
1808
1809   if (channel->readfd.revents & READ_COND)
1810     return TRUE;
1811
1812   if (channel->writefd.revents & WRITE_COND)
1813     return TRUE;
1814
1815   return FALSE;
1816 }
1817
1818 static gboolean
1819 gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback,
1820     gpointer user_data)
1821 {
1822   GstRTSPChannel *channel = (GstRTSPChannel *) source;
1823   GstRTSPResult res;
1824
1825   /* first read as much as we can */
1826   if (channel->readfd.revents & READ_COND) {
1827     do {
1828       res = build_next (&channel->builder, &channel->message, channel->conn);
1829       if (res == GST_RTSP_EINTR)
1830         break;
1831       if (res == GST_RTSP_EEOF)
1832         goto eof;
1833       if (res != GST_RTSP_OK)
1834         goto error;
1835
1836       if (channel->funcs.message_received)
1837         channel->funcs.message_received (channel, &channel->message,
1838             channel->user_data);
1839
1840       gst_rtsp_message_unset (&channel->message);
1841       build_reset (&channel->builder);
1842     } while (FALSE);
1843   }
1844
1845   if (channel->writefd.revents & WRITE_COND) {
1846     do {
1847       if (channel->write_data == NULL) {
1848         GstRTSPRec *data;
1849
1850         if (!channel->messages)
1851           goto done;
1852
1853         /* no data, get a new message from the queue */
1854         data = channel->messages->data;
1855         channel->messages =
1856             g_list_delete_link (channel->messages, channel->messages);
1857
1858         channel->write_off = 0;
1859         channel->write_len = data->str->len;
1860         channel->write_data = (guint8 *) g_string_free (data->str, FALSE);
1861         channel->write_cseq = data->cseq;
1862
1863         g_slice_free (GstRTSPRec, data);
1864       }
1865
1866       res = write_bytes (channel->writefd.fd, channel->write_data,
1867           &channel->write_off, channel->write_len);
1868       if (res == GST_RTSP_EINTR)
1869         break;
1870       if (res != GST_RTSP_OK)
1871         goto error;
1872
1873       if (channel->funcs.message_sent)
1874         channel->funcs.message_sent (channel, channel->write_cseq,
1875             channel->user_data);
1876
1877     done:
1878       if (channel->messages == NULL && channel->write_added) {
1879         g_source_remove_poll ((GSource *) channel, &channel->writefd);
1880         channel->write_added = FALSE;
1881         channel->writefd.revents = 0;
1882       }
1883       g_free (channel->write_data);
1884       channel->write_data = NULL;
1885     } while (FALSE);
1886   }
1887
1888   return TRUE;
1889
1890   /* ERRORS */
1891 eof:
1892   {
1893     if (channel->funcs.closed)
1894       channel->funcs.closed (channel, channel->user_data);
1895     return FALSE;
1896   }
1897 error:
1898   {
1899     if (channel->funcs.error)
1900       channel->funcs.error (channel, res, channel->user_data);
1901     return FALSE;
1902   }
1903 }
1904
1905 static void
1906 gst_rtsp_source_finalize (GSource * source)
1907 {
1908   GstRTSPChannel *channel = (GstRTSPChannel *) source;
1909   GList *walk;
1910
1911   build_reset (&channel->builder);
1912
1913   for (walk = channel->messages; walk; walk = g_list_next (walk)) {
1914     GstRTSPRec *data = walk->data;
1915
1916     g_string_free (data->str, TRUE);
1917     g_slice_free (GstRTSPRec, data);
1918   }
1919   g_list_free (channel->messages);
1920   g_free (channel->write_data);
1921
1922   if (channel->notify)
1923     channel->notify (channel->user_data);
1924 }
1925
1926 static GSourceFuncs gst_rtsp_source_funcs = {
1927   gst_rtsp_source_prepare,
1928   gst_rtsp_source_check,
1929   gst_rtsp_source_dispatch,
1930   gst_rtsp_source_finalize
1931 };
1932
1933 /**
1934  * gst_rtsp_channel_new:
1935  * @conn: a #GstRTSPConnection
1936  * @funcs: channel functions
1937  * @user_data: user data to pass to @funcs
1938  *
1939  * Create a channel object for @conn. The functions provided in @funcs will be
1940  * called with @user_data when activity happened on the channel.
1941  *
1942  * The new channel is usually created so that it can be attached to a
1943  * maincontext with gst_rtsp_channel_attach(). 
1944  *
1945  * @conn must exist for the entire lifetime of the channel.
1946  *
1947  * Returns: a #GstRTSPChannel that can be used for asynchronous RTSP
1948  * communication. Free with gst_rtsp_channel_unref () after usage.
1949  *
1950  * Since: 0.10.23
1951  */
1952 GstRTSPChannel *
1953 gst_rtsp_channel_new (GstRTSPConnection * conn,
1954     GstRTSPChannelFuncs * funcs, gpointer user_data, GDestroyNotify notify)
1955 {
1956   GstRTSPChannel *result;
1957
1958   g_return_val_if_fail (conn != NULL, NULL);
1959   g_return_val_if_fail (funcs != NULL, NULL);
1960
1961   result = (GstRTSPChannel *) g_source_new (&gst_rtsp_source_funcs,
1962       sizeof (GstRTSPChannel));
1963
1964   result->conn = conn;
1965   result->builder.state = STATE_START;
1966
1967   result->readfd.fd = conn->fd.fd;
1968   result->readfd.events = READ_COND;
1969   result->readfd.revents = 0;
1970
1971   result->writefd.fd = conn->fd.fd;
1972   result->writefd.events = WRITE_COND;
1973   result->writefd.revents = 0;
1974   result->write_added = FALSE;
1975
1976   result->funcs = *funcs;
1977   result->user_data = user_data;
1978   result->notify = notify;
1979
1980   /* only add the read fd, the write fd is only added when we have data
1981    * to send. */
1982   g_source_add_poll ((GSource *) result, &result->readfd);
1983
1984   return result;
1985 }
1986
1987 /**
1988  * gst_rtsp_channel_attach:
1989  * @channel: a #GstRTSPChannel
1990  * @context: a GMainContext (if NULL, the default context will be used)
1991  *
1992  * Adds a #GstRTSPChannel to a context so that it will be executed within that context.
1993  *
1994  * Returns: the ID (greater than 0) for the channel within the GMainContext. 
1995  *
1996  * Since: 0.10.23
1997  */
1998 guint
1999 gst_rtsp_channel_attach (GstRTSPChannel * channel, GMainContext * context)
2000 {
2001   g_return_val_if_fail (channel != NULL, 0);
2002
2003   return g_source_attach ((GSource *) channel, context);
2004 }
2005
2006 /**
2007  * gst_rtsp_channel_free:
2008  * @channel: a #GstRTSPChannel
2009  *
2010  * Decreases the reference count of @channel by one. If the resulting reference
2011  * count is zero the channel and associated memory will be destroyed.
2012  *
2013  * Since: 0.10.23
2014  */
2015 void
2016 gst_rtsp_channel_unref (GstRTSPChannel * channel)
2017 {
2018   g_return_if_fail (channel != NULL);
2019
2020   g_source_unref ((GSource *) channel);
2021 }
2022
2023 /**
2024  * gst_rtsp_channel_queue_message:
2025  * @channel: a #GstRTSPChannel
2026  * @message: a #GstRTSPMessage
2027  *
2028  * Queue a @message for transmission in @channel. The contents of this 
2029  * message will be serialized and transmitted when the connection of the
2030  * channel becomes writable.
2031  *
2032  * The return value of this function will be returned as the cseq argument in
2033  * the message_sent callback.
2034  *
2035  * Returns: the sequence number of the message or -1 if the cseq could not be
2036  * determined.
2037  *
2038  * Since: 0.10.23
2039  */
2040 guint
2041 gst_rtsp_channel_queue_message (GstRTSPChannel * channel,
2042     GstRTSPMessage * message)
2043 {
2044   GstRTSPRec *data;
2045   gchar *header;
2046   guint cseq;
2047
2048   g_return_val_if_fail (channel != NULL, GST_RTSP_EINVAL);
2049   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2050
2051   /* get the cseq from the message, when we finish writing this message on the
2052    * socket we will have to pass the cseq to the callback. */
2053   if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_CSEQ, &header,
2054           0) == GST_RTSP_OK) {
2055     cseq = atoi (header);
2056   } else {
2057     cseq = -1;
2058   }
2059
2060   /* make a record with the message as a string ans cseq */
2061   data = g_slice_new (GstRTSPRec);
2062   data->str = message_to_string (channel->conn, message);
2063   data->cseq = cseq;
2064
2065   /* add the record to a queue */
2066   channel->messages = g_list_append (channel->messages, data);
2067
2068   /* make sure the main context will now also check for writability on the
2069    * socket */
2070   if (!channel->write_added) {
2071     g_source_add_poll ((GSource *) channel, &channel->writefd);
2072     channel->write_added = TRUE;
2073   }
2074   return cseq;
2075 }