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