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