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