gst-libs/gst/rtsp/gstrtspconnection.c: Don't error when poll_wait returns EAGAIN.
[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 #define EINPROGRESS WSAEINPROGRESS
80 #else
81 #include <sys/ioctl.h>
82 #include <netdb.h>
83 #include <sys/socket.h>
84 #include <netinet/in.h>
85 #include <arpa/inet.h>
86 #include <fcntl.h>
87 #endif
88
89 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
90 #include <sys/filio.h>
91 #endif
92
93 #include "gstrtspconnection.h"
94 #include "gstrtspbase64.h"
95
96 #ifdef G_OS_WIN32
97 #define FIONREAD_TYPE gulong
98 #define IOCTL_SOCKET ioctlsocket
99 #define READ_SOCKET(fd, buf, len) recv (fd, buf, len, 0)
100 #define WRITE_SOCKET(fd, buf, len) send (fd, buf, len, 0)
101 #define CLOSE_SOCKET(sock) closesocket (sock)
102 #define ERRNO_IS_NOT_EAGAIN (WSAGetLastError () != WSAEWOULDBLOCK)
103 #define ERRNO_IS_NOT_EINTR (WSAGetLastError () != WSAEINTR)
104 /* According to Microsoft's connect() documentation this one returns
105  * WSAEWOULDBLOCK and not WSAEINPROGRESS. */
106 #define ERRNO_IS_NOT_EINPROGRESS (WSAGetLastError () != WSAEWOULDBLOCK)
107 #else
108 #define FIONREAD_TYPE gint
109 #define IOCTL_SOCKET ioctl
110 #define READ_SOCKET(fd, buf, len) read (fd, buf, len)
111 #define WRITE_SOCKET(fd, buf, len) write (fd, buf, len)
112 #define CLOSE_SOCKET(sock) close (sock)
113 #define ERRNO_IS_NOT_EAGAIN (errno != EAGAIN)
114 #define ERRNO_IS_NOT_EINTR (errno != EINTR)
115 #define ERRNO_IS_NOT_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 /**
135  * gst_rtsp_connection_create:
136  * @url: a #GstRTSPUrl 
137  * @conn: a #GstRTSPConnection
138  *
139  * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
140  * The connection will not yet attempt to connect to @url, use
141  * gst_rtsp_connection_connect().
142  *
143  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
144  */
145 GstRTSPResult
146 gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
147 {
148   GstRTSPConnection *newconn;
149
150   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
151
152   newconn = g_new0 (GstRTSPConnection, 1);
153
154   if ((newconn->fdset = gst_poll_new (TRUE)) == NULL)
155     goto no_fdset;
156
157   newconn->url = url;
158   newconn->fd.fd = -1;
159   newconn->timer = g_timer_new ();
160
161   newconn->auth_method = GST_RTSP_AUTH_NONE;
162   newconn->username = NULL;
163   newconn->passwd = NULL;
164
165   *conn = newconn;
166
167   return GST_RTSP_OK;
168
169   /* ERRORS */
170 no_fdset:
171   {
172     g_free (newconn);
173     return GST_RTSP_ESYS;
174   }
175 }
176
177 /**
178  * gst_rtsp_connection_connect:
179  * @conn: a #GstRTSPConnection 
180  * @timeout: a #GTimeVal timeout
181  *
182  * Attempt to connect to the url of @conn made with
183  * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
184  * forever. If @timeout contains a valid timeout, this function will return
185  * #GST_RTSP_ETIMEOUT after the timeout expired.
186  *
187  * This function can be cancelled with gst_rtsp_connection_flush().
188  *
189  * Returns: #GST_RTSP_OK when a connection could be made.
190  */
191 GstRTSPResult
192 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
193 {
194   gint fd;
195   struct sockaddr_in sa_in;
196   struct hostent *hostinfo;
197   const gchar *ip;
198   struct in_addr addr;
199   gint ret;
200   guint16 port;
201   GstRTSPUrl *url;
202   GstClockTime to;
203   gint retval;
204
205 #ifdef G_OS_WIN32
206   unsigned long flags = 1;
207   struct in_addr *addrp;
208 #else
209   char **addrs;
210   gchar ipbuf[INET_ADDRSTRLEN];
211 #endif /* G_OS_WIN32 */
212
213   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
214   g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
215   g_return_val_if_fail (conn->fd.fd < 0, GST_RTSP_EINVAL);
216
217   url = conn->url;
218
219   /* first check if it already is an IP address */
220   if (inet_aton (url->host, &addr)) {
221     ip = url->host;
222   } else {
223     hostinfo = gethostbyname (url->host);
224     if (!hostinfo)
225       goto not_resolved;        /* h_errno set */
226
227     if (hostinfo->h_addrtype != AF_INET)
228       goto not_ip;              /* host not an IP host */
229 #ifdef G_OS_WIN32
230     addrp = (struct in_addr *) hostinfo->h_addr_list[0];
231     /* this is not threadsafe */
232     ip = inet_ntoa (*addrp);
233 #else
234     addrs = hostinfo->h_addr_list;
235     ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
236         sizeof (ipbuf));
237 #endif /* G_OS_WIN32 */
238   }
239
240   /* get the port from the url */
241   gst_rtsp_url_get_port (url, &port);
242
243   memset (&sa_in, 0, sizeof (sa_in));
244   sa_in.sin_family = AF_INET;   /* network socket */
245   sa_in.sin_port = htons (port);        /* on port */
246   sa_in.sin_addr.s_addr = inet_addr (ip);       /* on host ip */
247
248   fd = socket (AF_INET, SOCK_STREAM, 0);
249   if (fd == -1)
250     goto sys_error;
251
252   /* set to non-blocking mode so that we can cancel the connect */
253 #ifndef G_OS_WIN32
254   fcntl (fd, F_SETFL, O_NONBLOCK);
255 #else
256   ioctlsocket (fd, FIONBIO, &flags);
257 #endif /* G_OS_WIN32 */
258
259   /* add the socket to our fdset */
260   conn->fd.fd = fd;
261   gst_poll_add_fd (conn->fdset, &conn->fd);
262
263   /* we are going to connect ASYNC now */
264   ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
265   if (ret == 0)
266     goto done;
267   if (ERRNO_IS_NOT_EINPROGRESS)
268     goto sys_error;
269
270   /* wait for connect to complete up to the specified timeout or until we got
271    * interrupted. */
272   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
273
274   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
275
276   do {
277     retval = gst_poll_wait (conn->fdset, to);
278   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
279
280   if (retval == 0)
281     goto timeout;
282   else if (retval == -1)
283     goto sys_error;
284
285   gst_poll_fd_ignored (conn->fdset, &conn->fd);
286
287 done:
288   conn->ip = g_strdup (ip);
289
290   return GST_RTSP_OK;
291
292 sys_error:
293   {
294     if (conn->fd.fd >= 0) {
295       gst_poll_remove_fd (conn->fdset, &conn->fd);
296       conn->fd.fd = -1;
297     }
298     if (fd >= 0)
299       CLOSE_SOCKET (fd);
300     return GST_RTSP_ESYS;
301   }
302 not_resolved:
303   {
304     return GST_RTSP_ENET;
305   }
306 not_ip:
307   {
308     return GST_RTSP_ENOTIP;
309   }
310 timeout:
311   {
312     if (conn->fd.fd >= 0) {
313       gst_poll_remove_fd (conn->fdset, &conn->fd);
314       conn->fd.fd = -1;
315     }
316     if (fd >= 0)
317       CLOSE_SOCKET (fd);
318     return GST_RTSP_ETIMEOUT;
319   }
320 }
321
322 static void
323 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
324 {
325   switch (conn->auth_method) {
326     case GST_RTSP_AUTH_BASIC:{
327       gchar *user_pass =
328           g_strdup_printf ("%s:%s", conn->username, conn->passwd);
329       gchar *user_pass64 =
330           gst_rtsp_base64_encode (user_pass, strlen (user_pass));
331       gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
332
333       gst_rtsp_message_add_header (message, GST_RTSP_HDR_AUTHORIZATION,
334           auth_string);
335
336       g_free (user_pass);
337       g_free (user_pass64);
338       g_free (auth_string);
339       break;
340     }
341     default:
342       /* Nothing to do */
343       break;
344   }
345 }
346
347 static void
348 add_date_header (GstRTSPMessage * message)
349 {
350   GTimeVal tv;
351   gchar date_string[100];
352   time_t t;
353
354 #ifdef HAVE_GMTIME_R
355   struct tm tm_;
356 #endif
357
358   g_get_current_time (&tv);
359   t = (time_t) tv.tv_sec;
360
361 #ifdef HAVE_GMTIME_R
362   strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
363       gmtime_r (&t, &tm_));
364 #else
365   strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
366       gmtime (&t));
367 #endif
368
369   gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
370 }
371
372 /**
373  * gst_rtsp_connection_write:
374  * @conn: a #GstRTSPConnection
375  * @data: the data to write
376  * @size: the size of @data
377  * @timeout: a timeout value or #NULL
378  *
379  * Attempt to write @size bytes of @data to the connected @conn, blocking up to
380  * the specified @timeout. @timeout can be #NULL, in which case this function
381  * might block forever.
382  * 
383  * This function can be cancelled with gst_rtsp_connection_flush().
384  *
385  * Returns: #GST_RTSP_OK on success.
386  */
387 GstRTSPResult
388 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
389     guint size, GTimeVal * timeout)
390 {
391   guint towrite;
392   gint retval;
393   GstClockTime to;
394
395   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
396   g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
397
398   gst_poll_set_controllable (conn->fdset, TRUE);
399   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
400   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, FALSE);
401
402   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
403
404   towrite = size;
405
406   while (towrite > 0) {
407     gint written;
408
409     do {
410       retval = gst_poll_wait (conn->fdset, to);
411     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
412
413     if (retval == 0)
414       goto timeout;
415
416     if (retval == -1) {
417       if (errno == EBUSY)
418         goto stopped;
419       else
420         goto select_error;
421     }
422
423     /* now we can write */
424     written = WRITE_SOCKET (conn->fd.fd, data, towrite);
425     if (written < 0) {
426       if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
427         goto write_error;
428     } else {
429       towrite -= written;
430       data += written;
431     }
432   }
433   return GST_RTSP_OK;
434
435   /* ERRORS */
436 timeout:
437   {
438     return GST_RTSP_ETIMEOUT;
439   }
440 select_error:
441   {
442     return GST_RTSP_ESYS;
443   }
444 stopped:
445   {
446     return GST_RTSP_EINTR;
447   }
448 write_error:
449   {
450     return GST_RTSP_ESYS;
451   }
452 }
453
454 /**
455  * gst_rtsp_connection_send:
456  * @conn: a #GstRTSPConnection
457  * @message: the message to send
458  * @timeout: a timeout value or #NULL
459  *
460  * Attempt to send @message to the connected @conn, blocking up to
461  * the specified @timeout. @timeout can be #NULL, in which case this function
462  * might block forever.
463  * 
464  * This function can be cancelled with gst_rtsp_connection_flush().
465  *
466  * Returns: #GST_RTSP_OK on success.
467  */
468 GstRTSPResult
469 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
470     GTimeVal * timeout)
471 {
472   GString *str = NULL;
473   GstRTSPResult res;
474
475 #ifdef G_OS_WIN32
476   WSADATA w;
477   int error;
478 #endif
479
480   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
481   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
482
483 #ifdef G_OS_WIN32
484   error = WSAStartup (0x0202, &w);
485
486   if (error)
487     goto startup_error;
488
489   if (w.wVersion != 0x0202)
490     goto version_error;
491 #endif
492
493   str = g_string_new ("");
494
495   switch (message->type) {
496     case GST_RTSP_MESSAGE_REQUEST:
497       /* create request string, add CSeq */
498       g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
499           "CSeq: %d\r\n",
500           gst_rtsp_method_as_text (message->type_data.request.method),
501           message->type_data.request.uri, conn->cseq++);
502       /* add session id if we have one */
503       if (conn->session_id[0] != '\0') {
504         gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
505             conn->session_id);
506       }
507       /* add any authentication headers */
508       add_auth_header (conn, message);
509       break;
510     case GST_RTSP_MESSAGE_RESPONSE:
511       /* create response string */
512       g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
513           message->type_data.response.code, message->type_data.response.reason);
514       break;
515     case GST_RTSP_MESSAGE_DATA:
516     {
517       guint8 data_header[4];
518
519       /* prepare data header */
520       data_header[0] = '$';
521       data_header[1] = message->type_data.data.channel;
522       data_header[2] = (message->body_size >> 8) & 0xff;
523       data_header[3] = message->body_size & 0xff;
524
525       /* create string with header and data */
526       str = g_string_append_len (str, (gchar *) data_header, 4);
527       str =
528           g_string_append_len (str, (gchar *) message->body,
529           message->body_size);
530       break;
531     }
532     default:
533       g_return_val_if_reached (GST_RTSP_EINVAL);
534       break;
535   }
536
537   /* append headers and body */
538   if (message->type != GST_RTSP_MESSAGE_DATA) {
539     /* add date header */
540     add_date_header (message);
541
542     /* append headers */
543     gst_rtsp_message_append_headers (message, str);
544
545     /* append Content-Length and body if needed */
546     if (message->body != NULL && message->body_size > 0) {
547       gchar *len;
548
549       len = g_strdup_printf ("%d", message->body_size);
550       g_string_append_printf (str, "%s: %s\r\n",
551           gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
552       g_free (len);
553       /* header ends here */
554       g_string_append (str, "\r\n");
555       str =
556           g_string_append_len (str, (gchar *) message->body,
557           message->body_size);
558     } else {
559       /* just end headers */
560       g_string_append (str, "\r\n");
561     }
562   }
563
564   /* write request */
565   res =
566       gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
567
568   g_string_free (str, TRUE);
569
570   return res;
571
572 #ifdef G_OS_WIN32
573 startup_error:
574   {
575     g_warning ("Error %d on WSAStartup", error);
576     return GST_RTSP_EWSASTART;
577   }
578 version_error:
579   {
580     g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
581         w.wVersion);
582     WSACleanup ();
583     return GST_RTSP_EWSAVERSION;
584   }
585 #endif
586 }
587
588 static GstRTSPResult
589 read_line (gint fd, gchar * buffer, guint size)
590 {
591   guint idx;
592   gchar c;
593   gint r;
594
595   idx = 0;
596   while (TRUE) {
597     r = READ_SOCKET (fd, &c, 1);
598     if (r == 0) {
599       goto eof;
600     } else if (r < 0) {
601       if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
602         goto read_error;
603     } else {
604       if (c == '\n')            /* end on \n */
605         break;
606       if (c == '\r')            /* ignore \r */
607         continue;
608
609       if (idx < size - 1)
610         buffer[idx++] = c;
611     }
612   }
613   buffer[idx] = '\0';
614
615   return GST_RTSP_OK;
616
617 eof:
618   {
619     return GST_RTSP_EEOF;
620   }
621 read_error:
622   {
623     return GST_RTSP_ESYS;
624   }
625 }
626
627 static void
628 read_string (gchar * dest, gint size, gchar ** src)
629 {
630   gint idx;
631
632   idx = 0;
633   /* skip spaces */
634   while (g_ascii_isspace (**src))
635     (*src)++;
636
637   while (!g_ascii_isspace (**src) && **src != '\0') {
638     if (idx < size - 1)
639       dest[idx++] = **src;
640     (*src)++;
641   }
642   if (size > 0)
643     dest[idx] = '\0';
644 }
645
646 static void
647 read_key (gchar * dest, gint size, gchar ** src)
648 {
649   gint idx;
650
651   idx = 0;
652   while (**src != ':' && **src != '\0') {
653     if (idx < size - 1)
654       dest[idx++] = **src;
655     (*src)++;
656   }
657   if (size > 0)
658     dest[idx] = '\0';
659 }
660
661 static GstRTSPResult
662 parse_response_status (gchar * buffer, GstRTSPMessage * msg)
663 {
664   GstRTSPResult res;
665   gchar versionstr[20];
666   gchar codestr[4];
667   gint code;
668   gchar *bptr;
669
670   bptr = buffer;
671
672   read_string (versionstr, sizeof (versionstr), &bptr);
673   read_string (codestr, sizeof (codestr), &bptr);
674   code = atoi (codestr);
675
676   while (g_ascii_isspace (*bptr))
677     bptr++;
678
679   if (strcmp (versionstr, "RTSP/1.0") == 0)
680     GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
681         parse_error);
682   else if (strncmp (versionstr, "RTSP/", 5) == 0) {
683     GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
684         parse_error);
685     msg->type_data.response.version = GST_RTSP_VERSION_INVALID;
686   } else
687     goto parse_error;
688
689   return GST_RTSP_OK;
690
691 parse_error:
692   {
693     return GST_RTSP_EPARSE;
694   }
695 }
696
697 static GstRTSPResult
698 parse_request_line (gchar * buffer, GstRTSPMessage * msg)
699 {
700   GstRTSPResult res = GST_RTSP_OK;
701   gchar versionstr[20];
702   gchar methodstr[20];
703   gchar urlstr[4096];
704   gchar *bptr;
705   GstRTSPMethod method;
706
707   bptr = buffer;
708
709   read_string (methodstr, sizeof (methodstr), &bptr);
710   method = gst_rtsp_find_method (methodstr);
711
712   read_string (urlstr, sizeof (urlstr), &bptr);
713   if (*urlstr == '\0')
714     res = GST_RTSP_EPARSE;
715
716   read_string (versionstr, sizeof (versionstr), &bptr);
717
718   if (*bptr != '\0')
719     res = GST_RTSP_EPARSE;
720
721   if (strcmp (versionstr, "RTSP/1.0") == 0) {
722     if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
723       res = GST_RTSP_EPARSE;
724   } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
725     if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
726       res = GST_RTSP_EPARSE;
727     msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
728   } else {
729     gst_rtsp_message_init_request (msg, method, urlstr);
730     msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
731     res = GST_RTSP_EPARSE;
732   }
733
734   return res;
735 }
736
737 /* parsing lines means reading a Key: Value pair */
738 static GstRTSPResult
739 parse_line (gchar * buffer, GstRTSPMessage * msg)
740 {
741   gchar key[32];
742   gchar *bptr;
743   GstRTSPHeaderField field;
744
745   bptr = buffer;
746
747   /* read key */
748   read_key (key, sizeof (key), &bptr);
749   if (*bptr != ':')
750     goto no_column;
751
752   bptr++;
753
754   field = gst_rtsp_find_header_field (key);
755   if (field != GST_RTSP_HDR_INVALID) {
756     while (g_ascii_isspace (*bptr))
757       bptr++;
758     gst_rtsp_message_add_header (msg, field, bptr);
759   }
760
761   return GST_RTSP_OK;
762
763 no_column:
764   {
765     return GST_RTSP_EPARSE;
766   }
767 }
768
769 /**
770  * gst_rtsp_connection_read_internal:
771  * @conn: a #GstRTSPConnection
772  * @data: the data to read
773  * @size: the size of @data
774  * @timeout: a timeout value or #NULL
775  * @allow_interrupt: can the pending read be interrupted
776  *
777  * Attempt to read @size bytes into @data from the connected @conn, blocking up to
778  * the specified @timeout. @timeout can be #NULL, in which case this function
779  * might block forever.
780  * 
781  * This function can be cancelled with gst_rtsp_connection_flush() only if
782  * @allow_interrupt is set.
783  *
784  * Returns: #GST_RTSP_OK on success.
785  */
786 static GstRTSPResult
787 gst_rtsp_connection_read_internal (GstRTSPConnection * conn, guint8 * data,
788     guint size, GTimeVal * timeout, gboolean allow_interrupt)
789 {
790   guint toread;
791   gint retval;
792   GstClockTime to;
793   FIONREAD_TYPE avail;
794
795   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
796   g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
797
798   if (size == 0)
799     return GST_RTSP_OK;
800
801   toread = size;
802
803   /* configure timeout if any */
804   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
805
806   /* if the call fails, just go in the select.. it should not fail. Else if
807    * there is enough data to read, skip the select call al together.*/
808   if (IOCTL_SOCKET (conn->fd.fd, FIONREAD, &avail) < 0)
809     avail = 0;
810   else if (avail >= toread)
811     goto do_read;
812
813   gst_poll_set_controllable (conn->fdset, allow_interrupt);
814   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, FALSE);
815   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, TRUE);
816
817   while (toread > 0) {
818     gint bytes;
819
820     do {
821       retval = gst_poll_wait (conn->fdset, to);
822     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
823
824     if (retval == -1) {
825       if (errno == EBUSY)
826         goto stopped;
827       else
828         goto select_error;
829     }
830
831     /* check for timeout */
832     if (retval == 0)
833       goto select_timeout;
834
835   do_read:
836     /* if we get here there is activity on the real fd since the select
837      * completed and the control socket was not readable. */
838     bytes = READ_SOCKET (conn->fd.fd, data, toread);
839     if (bytes == 0) {
840       goto eof;
841     } else if (bytes < 0) {
842       if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
843         goto read_error;
844     } else {
845       toread -= bytes;
846       data += bytes;
847     }
848   }
849   return GST_RTSP_OK;
850
851   /* ERRORS */
852 select_error:
853   {
854     return GST_RTSP_ESYS;
855   }
856 select_timeout:
857   {
858     return GST_RTSP_ETIMEOUT;
859   }
860 stopped:
861   {
862     return GST_RTSP_EINTR;
863   }
864 eof:
865   {
866     return GST_RTSP_EEOF;
867   }
868 read_error:
869   {
870     return GST_RTSP_ESYS;
871   }
872 }
873
874 /**
875  * gst_rtsp_connection_read:
876  * @conn: a #GstRTSPConnection
877  * @data: the data to read
878  * @size: the size of @data
879  * @timeout: a timeout value or #NULL
880  *
881  * Attempt to read @size bytes into @data from the connected @conn, blocking up to
882  * the specified @timeout. @timeout can be #NULL, in which case this function
883  * might block forever.
884  *
885  * This function can be cancelled with gst_rtsp_connection_flush().
886  *
887  * Returns: #GST_RTSP_OK on success.
888  */
889 GstRTSPResult
890 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
891     GTimeVal * timeout)
892 {
893   return gst_rtsp_connection_read_internal (conn, data, size, timeout, TRUE);
894 }
895
896
897 static GstRTSPResult
898 read_body (GstRTSPConnection * conn, glong content_length, GstRTSPMessage * msg,
899     GTimeVal * timeout)
900 {
901   guint8 *body;
902   GstRTSPResult res;
903
904   if (content_length <= 0) {
905     body = NULL;
906     content_length = 0;
907     goto done;
908   }
909
910   body = g_malloc (content_length + 1);
911   body[content_length] = '\0';
912
913   GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, body, content_length,
914           timeout, FALSE), read_error);
915
916   content_length += 1;
917
918 done:
919   gst_rtsp_message_take_body (msg, (guint8 *) body, content_length);
920
921   return GST_RTSP_OK;
922
923   /* ERRORS */
924 read_error:
925   {
926     g_free (body);
927     return res;
928   }
929 }
930
931 /**
932  * gst_rtsp_connection_receive:
933  * @conn: a #GstRTSPConnection
934  * @message: the message to read
935  * @timeout: a timeout value or #NULL
936  *
937  * Attempt to read into @message from the connected @conn, blocking up to
938  * the specified @timeout. @timeout can be #NULL, in which case this function
939  * might block forever.
940  * 
941  * This function can be cancelled with gst_rtsp_connection_flush().
942  *
943  * Returns: #GST_RTSP_OK on success.
944  */
945 GstRTSPResult
946 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
947     GTimeVal * timeout)
948 {
949   gchar buffer[4096];
950   gint line;
951   glong content_length;
952   GstRTSPResult res;
953   gboolean need_body;
954
955   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
956   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
957
958   line = 0;
959
960   need_body = TRUE;
961
962   res = GST_RTSP_OK;
963   /* parse first line and headers */
964   while (res == GST_RTSP_OK) {
965     guint8 c;
966
967     /* read first character, this identifies data messages */
968     /* This is the only read() that we allow to be interrupted */
969     GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
970             TRUE), read_error);
971
972     /* check for data packet, first character is $ */
973     if (c == '$') {
974       guint16 size;
975
976       /* data packets are $<1 byte channel><2 bytes length,BE><data bytes> */
977
978       /* read channel, which is the next char */
979       GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
980               FALSE), read_error);
981
982       /* now we create a data message */
983       gst_rtsp_message_init_data (message, c);
984
985       /* next two bytes are the length of the data */
986       GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn,
987               (guint8 *) & size, 2, timeout, FALSE), read_error);
988
989       size = GUINT16_FROM_BE (size);
990
991       /* and read the body */
992       res = read_body (conn, size, message, timeout);
993       need_body = FALSE;
994       break;
995     } else {
996       gint offset = 0;
997
998       /* we have a regular response */
999       if (c != '\r') {
1000         buffer[0] = c;
1001         offset = 1;
1002       }
1003       /* should not happen */
1004       if (c == '\n')
1005         break;
1006
1007       /* read lines */
1008       GST_RTSP_CHECK (read_line (conn->fd.fd, buffer + offset,
1009               sizeof (buffer) - offset), read_error);
1010
1011       if (buffer[0] == '\0')
1012         break;
1013
1014       if (line == 0) {
1015         /* first line, check for response status */
1016         if (g_str_has_prefix (buffer, "RTSP")) {
1017           res = parse_response_status (buffer, message);
1018         } else {
1019           res = parse_request_line (buffer, message);
1020         }
1021       } else {
1022         /* else just parse the line */
1023         parse_line (buffer, message);
1024       }
1025     }
1026     line++;
1027   }
1028
1029   /* read the rest of the body if needed */
1030   if (need_body) {
1031     gchar *session_id;
1032     gchar *hdrval;
1033
1034     /* see if there is a Content-Length header */
1035     if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_CONTENT_LENGTH,
1036             &hdrval, 0) == GST_RTSP_OK) {
1037       /* there is, read the body */
1038       content_length = atol (hdrval);
1039       GST_RTSP_CHECK (read_body (conn, content_length, message, timeout),
1040           read_error);
1041     }
1042
1043     /* save session id in the connection for further use */
1044     if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
1045             &session_id, 0) == GST_RTSP_OK) {
1046       gint maxlen, i;
1047
1048       /* default session timeout */
1049       conn->timeout = 60;
1050
1051       maxlen = sizeof (conn->session_id) - 1;
1052       /* the sessionid can have attributes marked with ;
1053        * Make sure we strip them */
1054       for (i = 0; session_id[i] != '\0'; i++) {
1055         if (session_id[i] == ';') {
1056           maxlen = i;
1057           /* parse timeout */
1058           do {
1059             i++;
1060           } while (g_ascii_isspace (session_id[i]));
1061           if (g_str_has_prefix (&session_id[i], "timeout=")) {
1062             gint to;
1063
1064             /* if we parsed something valid, configure */
1065             if ((to = atoi (&session_id[i + 9])) > 0)
1066               conn->timeout = to;
1067           }
1068           break;
1069         }
1070       }
1071
1072       /* make sure to not overflow */
1073       strncpy (conn->session_id, session_id, maxlen);
1074       conn->session_id[maxlen] = '\0';
1075     }
1076   }
1077   return res;
1078
1079 read_error:
1080   {
1081     return res;
1082   }
1083 }
1084
1085 /**
1086  * gst_rtsp_connection_close:
1087  * @conn: a #GstRTSPConnection
1088  *
1089  * Close the connected @conn.
1090  * 
1091  * Returns: #GST_RTSP_OK on success.
1092  */
1093 GstRTSPResult
1094 gst_rtsp_connection_close (GstRTSPConnection * conn)
1095 {
1096   gint res;
1097
1098   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1099
1100   g_free (conn->ip);
1101   conn->ip = NULL;
1102
1103   if (conn->fd.fd != -1) {
1104     gst_poll_remove_fd (conn->fdset, &conn->fd);
1105     res = CLOSE_SOCKET (conn->fd.fd);
1106     conn->fd.fd = -1;
1107 #ifdef G_OS_WIN32
1108     WSACleanup ();
1109 #endif
1110     if (res != 0)
1111       goto sys_error;
1112   }
1113
1114   return GST_RTSP_OK;
1115
1116 sys_error:
1117   {
1118     return GST_RTSP_ESYS;
1119   }
1120 }
1121
1122 /**
1123  * gst_rtsp_connection_free:
1124  * @conn: a #GstRTSPConnection
1125  *
1126  * Close and free @conn.
1127  * 
1128  * Returns: #GST_RTSP_OK on success.
1129  */
1130 GstRTSPResult
1131 gst_rtsp_connection_free (GstRTSPConnection * conn)
1132 {
1133   GstRTSPResult res;
1134
1135   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1136
1137   res = gst_rtsp_connection_close (conn);
1138   gst_poll_free (conn->fdset);
1139 #ifdef G_OS_WIN32
1140   WSACleanup ();
1141 #endif
1142   g_timer_destroy (conn->timer);
1143   g_free (conn->username);
1144   g_free (conn->passwd);
1145   g_free (conn);
1146
1147   return res;
1148 }
1149
1150 /**
1151  * gst_rtsp_connection_poll:
1152  * @conn: a #GstRTSPConnection
1153  * @events: a bitmask of #GstRTSPEvent flags to check
1154  * @revents: location for result flags 
1155  * @timeout: a timeout
1156  *
1157  * Wait up to the specified @timeout for the connection to become available for
1158  * at least one of the operations specified in @events. When the function returns
1159  * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
1160  * @conn.
1161  *
1162  * @timeout can be #NULL, in which case this function might block forever.
1163  *
1164  * This function can be cancelled with gst_rtsp_connection_flush().
1165  * 
1166  * Returns: #GST_RTSP_OK on success.
1167  *
1168  * Since: 0.10.15
1169  */
1170 GstRTSPResult
1171 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
1172     GstRTSPEvent * revents, GTimeVal * timeout)
1173 {
1174   GstClockTime to;
1175   gint retval;
1176
1177   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1178   g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
1179   g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
1180
1181   gst_poll_set_controllable (conn->fdset, TRUE);
1182
1183   /* add fd to writer set when asked to */
1184   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, events & GST_RTSP_EV_WRITE);
1185
1186   /* add fd to reader set when asked to */
1187   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, events & GST_RTSP_EV_READ);
1188
1189   /* configure timeout if any */
1190   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
1191
1192   do {
1193     retval = gst_poll_wait (conn->fdset, to);
1194   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
1195
1196   if (retval == 0)
1197     goto select_timeout;
1198
1199   if (retval == -1) {
1200     if (errno == EBUSY)
1201       goto stopped;
1202     else
1203       goto select_error;
1204   }
1205
1206   *revents = 0;
1207   if (events & GST_RTSP_EV_READ) {
1208     if (gst_poll_fd_can_read (conn->fdset, &conn->fd))
1209       *revents |= GST_RTSP_EV_READ;
1210   }
1211   if (events & GST_RTSP_EV_WRITE) {
1212     if (gst_poll_fd_can_write (conn->fdset, &conn->fd))
1213       *revents |= GST_RTSP_EV_WRITE;
1214   }
1215   return GST_RTSP_OK;
1216
1217   /* ERRORS */
1218 select_timeout:
1219   {
1220     return GST_RTSP_ETIMEOUT;
1221   }
1222 select_error:
1223   {
1224     return GST_RTSP_ESYS;
1225   }
1226 stopped:
1227   {
1228     return GST_RTSP_EINTR;
1229   }
1230 }
1231
1232 /**
1233  * gst_rtsp_connection_next_timeout:
1234  * @conn: a #GstRTSPConnection
1235  * @timeout: a timeout
1236  *
1237  * Calculate the next timeout for @conn, storing the result in @timeout.
1238  * 
1239  * Returns: #GST_RTSP_OK.
1240  */
1241 GstRTSPResult
1242 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
1243 {
1244   gdouble elapsed;
1245   glong sec;
1246   gulong usec;
1247
1248   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1249   g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
1250
1251   elapsed = g_timer_elapsed (conn->timer, &usec);
1252   if (elapsed >= conn->timeout) {
1253     sec = 0;
1254     usec = 0;
1255   } else {
1256     sec = conn->timeout - elapsed;
1257   }
1258
1259   timeout->tv_sec = sec;
1260   timeout->tv_usec = usec;
1261
1262   return GST_RTSP_OK;
1263 }
1264
1265 /**
1266  * gst_rtsp_connection_reset_timeout:
1267  * @conn: a #GstRTSPConnection
1268  *
1269  * Reset the timeout of @conn.
1270  * 
1271  * Returns: #GST_RTSP_OK.
1272  */
1273 GstRTSPResult
1274 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
1275 {
1276   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1277
1278   g_timer_start (conn->timer);
1279
1280   return GST_RTSP_OK;
1281 }
1282
1283 /**
1284  * gst_rtsp_connection_flush:
1285  * @conn: a #GstRTSPConnection
1286  * @flush: start or stop the flush
1287  *
1288  * Start or stop the flushing action on @conn. When flushing, all current
1289  * and future actions on @conn will return #GST_RTSP_EINTR until the connection
1290  * is set to non-flushing mode again.
1291  * 
1292  * Returns: #GST_RTSP_OK.
1293  */
1294 GstRTSPResult
1295 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
1296 {
1297   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1298
1299   gst_poll_set_flushing (conn->fdset, flush);
1300
1301   return GST_RTSP_OK;
1302 }
1303
1304 /**
1305  * gst_rtsp_connection_set_auth:
1306  * @conn: a #GstRTSPConnection
1307  * @method: authentication method
1308  * @user: the user
1309  * @pass: the password
1310  *
1311  * Configure @conn for authentication mode @method with @user and @pass as the
1312  * user and password respectively.
1313  * 
1314  * Returns: #GST_RTSP_OK.
1315  */
1316 GstRTSPResult
1317 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
1318     GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
1319 {
1320   /* Digest isn't implemented yet */
1321   if (method == GST_RTSP_AUTH_DIGEST)
1322     return GST_RTSP_ENOTIMPL;
1323
1324   /* Make sure the username and passwd are being set for authentication */
1325   if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
1326     return GST_RTSP_EINVAL;
1327
1328   /* ":" chars are not allowed in usernames for basic auth */
1329   if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
1330     return GST_RTSP_EINVAL;
1331
1332   g_free (conn->username);
1333   g_free (conn->passwd);
1334
1335   conn->auth_method = method;
1336   conn->username = g_strdup (user);
1337   conn->passwd = g_strdup (pass);
1338
1339   return GST_RTSP_OK;
1340 }