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