gst_plugins_base/gst-libs/gst/rtsp/gstrtspconnection.c
branchRCL_3
changeset 29 567bb019e3e3
parent 0 0e761a78d257
child 30 7e817e7e631c
equal deleted inserted replaced
6:9b2c3c7a1a9c 29:567bb019e3e3
     1 /* GStreamer
     1 /* GStreamer
     2  * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
     2  * Copyright (C) <2005-2009> Wim Taymans <wim.taymans@gmail.com>
     3  *
     3  *
     4  * This library is free software; you can redistribute it and/or
     4  * This library is free software; you can redistribute it and/or
     5  * modify it under the terms of the GNU Library General Public
     5  * modify it under the terms of the GNU Library General Public
     6  * License as published by the Free Software Foundation; either
     6  * License as published by the Free Software Foundation; either
     7  * version 2 of the License, or (at your option) any later version.
     7  * version 2 of the License, or (at your option) any later version.
    67 
    67 
    68 #ifdef HAVE_UNISTD_H
    68 #ifdef HAVE_UNISTD_H
    69 #include <unistd.h>
    69 #include <unistd.h>
    70 #endif
    70 #endif
    71 
    71 
    72 
       
    73 /* we include this here to get the G_OS_* defines */
    72 /* we include this here to get the G_OS_* defines */
    74 #include <glib.h>
    73 #include <glib.h>
    75 #include <gst/gst.h>
    74 #include <gst/gst.h>
    76 
    75 
    77 #ifdef G_OS_WIN32
    76 #ifdef G_OS_WIN32
       
    77 /* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
       
    78  * minwg32 headers check WINVER before allowing the use of these */
       
    79 #ifndef WINVER
       
    80 #define WINVER 0x0501
       
    81 #endif
    78 #include <winsock2.h>
    82 #include <winsock2.h>
       
    83 #include <ws2tcpip.h>
    79 #define EINPROGRESS WSAEINPROGRESS
    84 #define EINPROGRESS WSAEINPROGRESS
    80 #else
    85 #else
    81 #include <sys/ioctl.h>
    86 #include <sys/ioctl.h>
    82 #include <netdb.h>
    87 #include <netdb.h>
    83 #include <sys/socket.h>
    88 #include <sys/socket.h>
       
    89 #include <fcntl.h>
    84 #include <netinet/in.h>
    90 #include <netinet/in.h>
    85 #include <arpa/inet.h>
       
    86 #include <fcntl.h>
       
    87 #endif
    91 #endif
    88 
    92 
    89 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
    93 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
    90 #include <sys/filio.h>
    94 #include <sys/filio.h>
    91 #endif
    95 #endif
    92 
    96 
    93 #include "gstrtspconnection.h"
    97 #include "gstrtspconnection.h"
    94 #include "gstrtspbase64.h"
    98 #include "gstrtspbase64.h"
       
    99 #include "md5.h"
       
   100 
       
   101 union gst_sockaddr
       
   102 {
       
   103   struct sockaddr sa;
       
   104   struct sockaddr_in sa_in;
       
   105   struct sockaddr_in6 sa_in6;
       
   106   struct sockaddr_storage sa_stor;
       
   107 };
       
   108 
       
   109 typedef struct
       
   110 {
       
   111   gint state;
       
   112   guint save;
       
   113   guchar out[3];                /* the size must be evenly divisible by 3 */
       
   114   guint cout;
       
   115   guint coutl;
       
   116 } DecodeCtx;
       
   117 
       
   118 static GstRTSPResult read_line (gint fd, guint8 * buffer, guint * idx,
       
   119     guint size, DecodeCtx * ctxp);
       
   120 static GstRTSPResult parse_key_value (guint8 * buffer, gchar * key,
       
   121     guint keysize, gchar ** value);
       
   122 static void parse_string (gchar * dest, gint size, gchar ** src);
    95 
   123 
    96 #ifdef G_OS_WIN32
   124 #ifdef G_OS_WIN32
    97 #define FIONREAD_TYPE gulong
   125 #define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0)
    98 #define IOCTL_SOCKET ioctlsocket
   126 #define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0)
    99 #define READ_SOCKET(fd, buf, len) recv (fd, buf, len, 0)
   127 #define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, (const char *)val, len)
   100 #define WRITE_SOCKET(fd, buf, len) send (fd, buf, len, 0)
       
   101 #define CLOSE_SOCKET(sock) closesocket (sock)
   128 #define CLOSE_SOCKET(sock) closesocket (sock)
   102 #define ERRNO_IS_NOT_EAGAIN (WSAGetLastError () != WSAEWOULDBLOCK)
   129 #define ERRNO_IS_EAGAIN (WSAGetLastError () == WSAEWOULDBLOCK)
   103 #define ERRNO_IS_NOT_EINTR (WSAGetLastError () != WSAEINTR)
   130 #define ERRNO_IS_EINTR (WSAGetLastError () == WSAEINTR)
   104 /* According to Microsoft's connect() documentation this one returns
   131 /* According to Microsoft's connect() documentation this one returns
   105  * WSAEWOULDBLOCK and not WSAEINPROGRESS. */
   132  * WSAEWOULDBLOCK and not WSAEINPROGRESS. */
   106 #define ERRNO_IS_NOT_EINPROGRESS (WSAGetLastError () != WSAEWOULDBLOCK)
   133 #define ERRNO_IS_EINPROGRESS (WSAGetLastError () == WSAEWOULDBLOCK)
   107 #else
   134 #else
   108 #define FIONREAD_TYPE gint
       
   109 #define IOCTL_SOCKET ioctl
       
   110 #define READ_SOCKET(fd, buf, len) read (fd, buf, len)
   135 #define READ_SOCKET(fd, buf, len) read (fd, buf, len)
   111 #define WRITE_SOCKET(fd, buf, len) write (fd, buf, len)
   136 #define WRITE_SOCKET(fd, buf, len) write (fd, buf, len)
       
   137 #define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, val, len)
   112 #define CLOSE_SOCKET(sock) close (sock)
   138 #define CLOSE_SOCKET(sock) close (sock)
   113 #define ERRNO_IS_NOT_EAGAIN (errno != EAGAIN)
   139 #define ERRNO_IS_EAGAIN (errno == EAGAIN)
   114 #define ERRNO_IS_NOT_EINTR (errno != EINTR)
   140 #define ERRNO_IS_EINTR (errno == EINTR)
   115 #define ERRNO_IS_NOT_EINPROGRESS (errno != EINPROGRESS)
   141 #define ERRNO_IS_EINPROGRESS (errno == EINPROGRESS)
   116 #endif
   142 #endif
   117 
   143 
   118 #ifdef G_OS_WIN32
   144 #define ADD_POLLFD(fdset, pfd, fd)        \
   119 static int
   145 G_STMT_START {                            \
   120 inet_aton (const char *c, struct in_addr *paddr)
   146   (pfd)->fd = fd;                         \
   121 {
   147   gst_poll_add_fd (fdset, pfd);           \
   122   /* note that inet_addr is deprecated on unix because
   148 } G_STMT_END
   123    * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
   149 
   124    * address. */
   150 #define REMOVE_POLLFD(fdset, pfd)          \
   125   paddr->s_addr = inet_addr (c);
   151 G_STMT_START {                             \
   126 
   152   if ((pfd)->fd != -1) {                   \
   127   if (paddr->s_addr == INADDR_NONE)
   153     GST_DEBUG ("remove fd %d", (pfd)->fd); \
   128     return 0;
   154     gst_poll_remove_fd (fdset, pfd);       \
   129 
   155     CLOSE_SOCKET ((pfd)->fd);              \
   130   return 1;
   156     (pfd)->fd = -1;                        \
   131 }
   157   }                                        \
   132 #endif
   158 } G_STMT_END
       
   159 
       
   160 typedef enum
       
   161 {
       
   162   TUNNEL_STATE_NONE,
       
   163   TUNNEL_STATE_GET,
       
   164   TUNNEL_STATE_POST,
       
   165   TUNNEL_STATE_COMPLETE
       
   166 } GstRTSPTunnelState;
       
   167 
       
   168 #define TUNNELID_LEN   24
       
   169 
       
   170 struct _GstRTSPConnection
       
   171 {
       
   172   /*< private > */
       
   173   /* URL for the connection */
       
   174   GstRTSPUrl *url;
       
   175 
       
   176   /* connection state */
       
   177   GstPollFD fd0;
       
   178   GstPollFD fd1;
       
   179 
       
   180   GstPollFD *readfd;
       
   181   GstPollFD *writefd;
       
   182 
       
   183   gchar tunnelid[TUNNELID_LEN];
       
   184   gboolean tunneled;
       
   185   GstRTSPTunnelState tstate;
       
   186 
       
   187   GstPoll *fdset;
       
   188   gchar *ip;
       
   189 
       
   190   /* Session state */
       
   191   gint cseq;                    /* sequence number */
       
   192   gchar session_id[512];        /* session id */
       
   193   gint timeout;                 /* session timeout in seconds */
       
   194   GTimer *timer;                /* timeout timer */
       
   195 
       
   196   /* Authentication */
       
   197   GstRTSPAuthMethod auth_method;
       
   198   gchar *username;
       
   199   gchar *passwd;
       
   200   GHashTable *auth_params;
       
   201 
       
   202   DecodeCtx ctx;
       
   203   DecodeCtx *ctxp;
       
   204 
       
   205   gchar *proxy_host;
       
   206   guint proxy_port;
       
   207 };
       
   208 
       
   209 enum
       
   210 {
       
   211   STATE_START = 0,
       
   212   STATE_DATA_HEADER,
       
   213   STATE_DATA_BODY,
       
   214   STATE_READ_LINES,
       
   215   STATE_END,
       
   216   STATE_LAST
       
   217 };
       
   218 
       
   219 /* a structure for constructing RTSPMessages */
       
   220 typedef struct
       
   221 {
       
   222   gint state;
       
   223   guint8 buffer[4096];
       
   224   guint offset;
       
   225 
       
   226   guint line;
       
   227   guint8 *body_data;
       
   228   glong body_len;
       
   229 } GstRTSPBuilder;
       
   230 
       
   231 static void
       
   232 build_reset (GstRTSPBuilder * builder)
       
   233 {
       
   234   g_free (builder->body_data);
       
   235   memset (builder, 0, sizeof (GstRTSPBuilder));
       
   236 }
   133 
   237 
   134 /**
   238 /**
   135  * gst_rtsp_connection_create:
   239  * gst_rtsp_connection_create:
   136  * @url: a #GstRTSPUrl 
   240  * @url: a #GstRTSPUrl 
   137  * @conn: a #GstRTSPConnection
   241  * @conn: storage for a #GstRTSPConnection
   138  *
   242  *
   139  * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
   243  * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
   140  * The connection will not yet attempt to connect to @url, use
   244  * The connection will not yet attempt to connect to @url, use
   141  * gst_rtsp_connection_connect().
   245  * gst_rtsp_connection_connect().
   142  *
   246  *
       
   247  * A copy of @url will be made.
       
   248  *
   143  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
   249  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
   144  */
   250  */
   145 GstRTSPResult
   251 GstRTSPResult
   146 gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
   252 gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn)
   147 {
   253 {
   148   GstRTSPConnection *newconn;
   254   GstRTSPConnection *newconn;
       
   255 #ifdef G_OS_WIN32
       
   256   WSADATA w;
       
   257   int error;
       
   258 #endif
   149 
   259 
   150   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
   260   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
       
   261 
       
   262 #ifdef G_OS_WIN32
       
   263   error = WSAStartup (0x0202, &w);
       
   264 
       
   265   if (error)
       
   266     goto startup_error;
       
   267 
       
   268   if (w.wVersion != 0x0202)
       
   269     goto version_error;
       
   270 #endif
   151 
   271 
   152   newconn = g_new0 (GstRTSPConnection, 1);
   272   newconn = g_new0 (GstRTSPConnection, 1);
   153 
   273 
   154   if ((newconn->fdset = gst_poll_new (TRUE)) == NULL)
   274   if ((newconn->fdset = gst_poll_new (TRUE)) == NULL)
   155     goto no_fdset;
   275     goto no_fdset;
   156 
   276 
   157   newconn->url = url;
   277   newconn->url = gst_rtsp_url_copy (url);
   158   newconn->fd.fd = -1;
   278   newconn->fd0.fd = -1;
       
   279   newconn->fd1.fd = -1;
   159   newconn->timer = g_timer_new ();
   280   newconn->timer = g_timer_new ();
       
   281   newconn->timeout = 60;
       
   282   newconn->cseq = 1;
   160 
   283 
   161   newconn->auth_method = GST_RTSP_AUTH_NONE;
   284   newconn->auth_method = GST_RTSP_AUTH_NONE;
   162   newconn->username = NULL;
   285   newconn->username = NULL;
   163   newconn->passwd = NULL;
   286   newconn->passwd = NULL;
       
   287   newconn->auth_params = NULL;
   164 
   288 
   165   *conn = newconn;
   289   *conn = newconn;
   166 
   290 
   167   return GST_RTSP_OK;
   291   return GST_RTSP_OK;
   168 
   292 
   169   /* ERRORS */
   293   /* ERRORS */
       
   294 #ifdef G_OS_WIN32
       
   295 startup_error:
       
   296   {
       
   297     g_warning ("Error %d on WSAStartup", error);
       
   298     return GST_RTSP_EWSASTART;
       
   299   }
       
   300 version_error:
       
   301   {
       
   302     g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
       
   303         w.wVersion);
       
   304     WSACleanup ();
       
   305     return GST_RTSP_EWSAVERSION;
       
   306   }
       
   307 #endif
   170 no_fdset:
   308 no_fdset:
   171   {
   309   {
   172     g_free (newconn);
   310     g_free (newconn);
       
   311 #ifdef G_OS_WIN32
       
   312     WSACleanup ();
       
   313 #endif
   173     return GST_RTSP_ESYS;
   314     return GST_RTSP_ESYS;
   174   }
   315   }
   175 }
   316 }
   176 
   317 
   177 /**
   318 /**
   178  * gst_rtsp_connection_connect:
   319  * gst_rtsp_connection_accept:
   179  * @conn: a #GstRTSPConnection 
   320  * @sock: a socket
   180  * @timeout: a #GTimeVal timeout
   321  * @conn: storage for a #GstRTSPConnection
   181  *
   322  *
   182  * Attempt to connect to the url of @conn made with
   323  * Accept a new connection on @sock and create a new #GstRTSPConnection for
   183  * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
   324  * handling communication on new socket.
   184  * forever. If @timeout contains a valid timeout, this function will return
   325  *
   185  * #GST_RTSP_ETIMEOUT after the timeout expired.
   326  * Returns: #GST_RTSP_OK when @conn contains a valid connection.
   186  *
   327  *
   187  * This function can be cancelled with gst_rtsp_connection_flush().
   328  * Since: 0.10.23
   188  *
       
   189  * Returns: #GST_RTSP_OK when a connection could be made.
       
   190  */
   329  */
   191 GstRTSPResult
   330 GstRTSPResult
   192 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
   331 gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn)
       
   332 {
       
   333   int fd;
       
   334   GstRTSPConnection *newconn = NULL;
       
   335   union gst_sockaddr sa;
       
   336   socklen_t slen = sizeof (sa);
       
   337   gchar ip[INET6_ADDRSTRLEN];
       
   338   GstRTSPUrl *url;
       
   339 #ifdef G_OS_WIN32
       
   340   gulong flags = 1;
       
   341 #endif
       
   342 
       
   343   memset (&sa, 0, slen);
       
   344 
       
   345 #ifndef G_OS_WIN32
       
   346   fd = accept (sock, &sa.sa, &slen);
       
   347 #else
       
   348   fd = accept (sock, &sa.sa, (gint *) & slen);
       
   349 #endif /* G_OS_WIN32 */
       
   350   if (fd == -1)
       
   351     goto accept_failed;
       
   352 
       
   353   if (getnameinfo (&sa.sa, slen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0)
       
   354     goto getnameinfo_failed;
       
   355   if (sa.sa.sa_family != AF_INET && sa.sa.sa_family != AF_INET6)
       
   356     goto wrong_family;
       
   357 
       
   358   /* set to non-blocking mode so that we can cancel the communication */
       
   359 #ifndef G_OS_WIN32
       
   360   fcntl (fd, F_SETFL, O_NONBLOCK);
       
   361 #else
       
   362   ioctlsocket (fd, FIONBIO, &flags);
       
   363 #endif /* G_OS_WIN32 */
       
   364 
       
   365   /* create a url for the client address */
       
   366   url = g_new0 (GstRTSPUrl, 1);
       
   367   url->host = g_strdup (ip);
       
   368   if (sa.sa.sa_family == AF_INET)
       
   369     url->port = sa.sa_in.sin_port;
       
   370   else
       
   371     url->port = sa.sa_in6.sin6_port;
       
   372 
       
   373   /* now create the connection object */
       
   374   gst_rtsp_connection_create (url, &newconn);
       
   375   gst_rtsp_url_free (url);
       
   376 
       
   377   ADD_POLLFD (newconn->fdset, &newconn->fd0, fd);
       
   378 
       
   379   /* both read and write initially */
       
   380   newconn->readfd = &newconn->fd0;
       
   381   newconn->writefd = &newconn->fd0;
       
   382 
       
   383   *conn = newconn;
       
   384 
       
   385   return GST_RTSP_OK;
       
   386 
       
   387   /* ERRORS */
       
   388 accept_failed:
       
   389   {
       
   390     return GST_RTSP_ESYS;
       
   391   }
       
   392 getnameinfo_failed:
       
   393 wrong_family:
       
   394   {
       
   395     close (fd);
       
   396     return GST_RTSP_ERROR;
       
   397   }
       
   398 }
       
   399 
       
   400 static gchar *
       
   401 do_resolve (const gchar * host)
       
   402 {
       
   403   static gchar ip[INET6_ADDRSTRLEN];
       
   404   struct addrinfo *aires;
       
   405   struct addrinfo *ai;
       
   406   gint aierr;
       
   407 
       
   408   aierr = getaddrinfo (host, NULL, NULL, &aires);
       
   409   if (aierr != 0)
       
   410     goto no_addrinfo;
       
   411 
       
   412   for (ai = aires; ai; ai = ai->ai_next) {
       
   413     if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
       
   414       break;
       
   415     }
       
   416   }
       
   417   if (ai == NULL)
       
   418     goto no_family;
       
   419 
       
   420   aierr = getnameinfo (ai->ai_addr, ai->ai_addrlen, ip, sizeof (ip), NULL, 0,
       
   421       NI_NUMERICHOST | NI_NUMERICSERV);
       
   422   if (aierr != 0)
       
   423     goto no_address;
       
   424 
       
   425   freeaddrinfo (aires);
       
   426 
       
   427   return g_strdup (ip);
       
   428 
       
   429   /* ERRORS */
       
   430 no_addrinfo:
       
   431   {
       
   432     GST_ERROR ("no addrinfo found for %s: %s", host, gai_strerror (aierr));
       
   433     return NULL;
       
   434   }
       
   435 no_family:
       
   436   {
       
   437     GST_ERROR ("no family found for %s", host);
       
   438     freeaddrinfo (aires);
       
   439     return NULL;
       
   440   }
       
   441 no_address:
       
   442   {
       
   443     GST_ERROR ("no address found for %s: %s", host, gai_strerror (aierr));
       
   444     freeaddrinfo (aires);
       
   445     return NULL;
       
   446   }
       
   447 }
       
   448 
       
   449 static GstRTSPResult
       
   450 do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
       
   451     GstPoll * fdset, GTimeVal * timeout)
   193 {
   452 {
   194   gint fd;
   453   gint fd;
   195   struct sockaddr_in sa_in;
   454   struct addrinfo hints;
   196   struct hostent *hostinfo;
   455   struct addrinfo *aires;
   197   const gchar *ip;
   456   struct addrinfo *ai;
   198   struct in_addr addr;
   457   gint aierr;
       
   458   gchar service[NI_MAXSERV];
   199   gint ret;
   459   gint ret;
   200   guint16 port;
   460 #ifdef G_OS_WIN32
   201   GstRTSPUrl *url;
   461   unsigned long flags = 1;
       
   462 #endif /* G_OS_WIN32 */
   202   GstClockTime to;
   463   GstClockTime to;
   203   gint retval;
   464   gint retval;
   204 
   465 
   205 #ifdef G_OS_WIN32
   466   memset (&hints, 0, sizeof hints);
   206   unsigned long flags = 1;
   467   hints.ai_flags = AI_NUMERICHOST;
   207   struct in_addr *addrp;
   468   hints.ai_family = AF_UNSPEC;
   208 #else
   469   hints.ai_socktype = SOCK_STREAM;
   209   char **addrs;
   470   g_snprintf (service, sizeof (service) - 1, "%hu", port);
   210   gchar ipbuf[INET_ADDRSTRLEN];
   471   service[sizeof (service) - 1] = '\0';
   211 #endif /* G_OS_WIN32 */
   472 
   212 
   473   aierr = getaddrinfo (ip, service, &hints, &aires);
   213   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
   474   if (aierr != 0)
   214   g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
   475     goto no_addrinfo;
   215   g_return_val_if_fail (conn->fd.fd < 0, GST_RTSP_EINVAL);
   476 
   216 
   477   for (ai = aires; ai; ai = ai->ai_next) {
   217   url = conn->url;
   478     if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
   218 
   479       break;
   219   /* first check if it already is an IP address */
   480     }
   220   if (inet_aton (url->host, &addr)) {
   481   }
   221     ip = url->host;
   482   if (ai == NULL)
   222   } else {
   483     goto no_family;
   223     hostinfo = gethostbyname (url->host);
   484 
   224     if (!hostinfo)
   485   fd = socket (ai->ai_family, SOCK_STREAM, 0);
   225       goto not_resolved;        /* h_errno set */
       
   226 
       
   227     if (hostinfo->h_addrtype != AF_INET)
       
   228       goto not_ip;              /* host not an IP host */
       
   229 #ifdef G_OS_WIN32
       
   230     addrp = (struct in_addr *) hostinfo->h_addr_list[0];
       
   231     /* this is not threadsafe */
       
   232     ip = inet_ntoa (*addrp);
       
   233 #else
       
   234     addrs = hostinfo->h_addr_list;
       
   235     ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
       
   236         sizeof (ipbuf));
       
   237 #endif /* G_OS_WIN32 */
       
   238   }
       
   239 
       
   240   /* get the port from the url */
       
   241   gst_rtsp_url_get_port (url, &port);
       
   242 
       
   243   memset (&sa_in, 0, sizeof (sa_in));
       
   244   sa_in.sin_family = AF_INET;   /* network socket */
       
   245   sa_in.sin_port = htons (port);        /* on port */
       
   246   sa_in.sin_addr.s_addr = inet_addr (ip);       /* on host ip */
       
   247 
       
   248   fd = socket (AF_INET, SOCK_STREAM, 0);
       
   249   if (fd == -1)
   486   if (fd == -1)
   250     goto sys_error;
   487     goto no_socket;
   251 
   488 
   252   /* set to non-blocking mode so that we can cancel the connect */
   489   /* set to non-blocking mode so that we can cancel the connect */
   253 #ifndef G_OS_WIN32
   490 #ifndef G_OS_WIN32
   254   fcntl (fd, F_SETFL, O_NONBLOCK);
   491   fcntl (fd, F_SETFL, O_NONBLOCK);
   255 #else
   492 #else
   256   ioctlsocket (fd, FIONBIO, &flags);
   493   ioctlsocket (fd, FIONBIO, &flags);
   257 #endif /* G_OS_WIN32 */
   494 #endif /* G_OS_WIN32 */
   258 
   495 
   259   /* add the socket to our fdset */
   496   /* add the socket to our fdset */
   260   conn->fd.fd = fd;
   497   ADD_POLLFD (fdset, fdout, fd);
   261   gst_poll_add_fd (conn->fdset, &conn->fd);
       
   262 
   498 
   263   /* we are going to connect ASYNC now */
   499   /* we are going to connect ASYNC now */
   264   ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
   500   ret = connect (fd, ai->ai_addr, ai->ai_addrlen);
   265   if (ret == 0)
   501   if (ret == 0)
   266     goto done;
   502     goto done;
   267   if (ERRNO_IS_NOT_EINPROGRESS)
   503   if (!ERRNO_IS_EINPROGRESS)
   268     goto sys_error;
   504     goto sys_error;
   269 
   505 
   270   /* wait for connect to complete up to the specified timeout or until we got
   506   /* wait for connect to complete up to the specified timeout or until we got
   271    * interrupted. */
   507    * interrupted. */
   272   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
   508   gst_poll_fd_ctl_write (fdset, fdout, TRUE);
   273 
   509 
   274   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
   510   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
   275 
   511 
   276   do {
   512   do {
   277     retval = gst_poll_wait (conn->fdset, to);
   513     retval = gst_poll_wait (fdset, to);
   278   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
   514   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
   279 
   515 
   280   if (retval == 0)
   516   if (retval == 0)
   281     goto timeout;
   517     goto timeout;
   282   else if (retval == -1)
   518   else if (retval == -1)
   283     goto sys_error;
   519     goto sys_error;
   284 
   520 
   285   gst_poll_fd_ignored (conn->fdset, &conn->fd);
   521   /* we can still have an error connecting on windows */
       
   522   if (gst_poll_fd_has_error (fdset, fdout)) {
       
   523     socklen_t len = sizeof (errno);
       
   524 #ifndef G_OS_WIN32
       
   525     getsockopt (fd, SOL_SOCKET, SO_ERROR, &errno, &len);
       
   526 #else
       
   527     getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno, &len);
       
   528 #endif
       
   529     goto sys_error;
       
   530   }
       
   531 
       
   532   gst_poll_fd_ignored (fdset, fdout);
   286 
   533 
   287 done:
   534 done:
   288   conn->ip = g_strdup (ip);
   535   freeaddrinfo (aires);
   289 
   536 
   290   return GST_RTSP_OK;
   537   return GST_RTSP_OK;
   291 
   538 
       
   539   /* ERRORS */
       
   540 no_addrinfo:
       
   541   {
       
   542     GST_ERROR ("no addrinfo found for %s: %s", ip, gai_strerror (aierr));
       
   543     return GST_RTSP_ERROR;
       
   544   }
       
   545 no_family:
       
   546   {
       
   547     GST_ERROR ("no family found for %s", ip);
       
   548     freeaddrinfo (aires);
       
   549     return GST_RTSP_ERROR;
       
   550   }
       
   551 no_socket:
       
   552   {
       
   553     GST_ERROR ("no socket %d (%s)", errno, g_strerror (errno));
       
   554     freeaddrinfo (aires);
       
   555     return GST_RTSP_ESYS;
       
   556   }
   292 sys_error:
   557 sys_error:
   293   {
   558   {
   294     if (conn->fd.fd >= 0) {
   559     GST_ERROR ("system error %d (%s)", errno, g_strerror (errno));
   295       gst_poll_remove_fd (conn->fdset, &conn->fd);
   560     REMOVE_POLLFD (fdset, fdout);
   296       conn->fd.fd = -1;
   561     freeaddrinfo (aires);
       
   562     return GST_RTSP_ESYS;
       
   563   }
       
   564 timeout:
       
   565   {
       
   566     GST_ERROR ("timeout");
       
   567     REMOVE_POLLFD (fdset, fdout);
       
   568     freeaddrinfo (aires);
       
   569     return GST_RTSP_ETIMEOUT;
       
   570   }
       
   571 }
       
   572 
       
   573 static GstRTSPResult
       
   574 setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout)
       
   575 {
       
   576   gint i;
       
   577   GstRTSPResult res;
       
   578   gchar *str;
       
   579   guint idx, line;
       
   580   gint retval;
       
   581   GstClockTime to;
       
   582   gchar *ip, *url_port_str;
       
   583   guint16 port, url_port;
       
   584   gchar codestr[4], *resultstr;
       
   585   gint code;
       
   586   GstRTSPUrl *url;
       
   587   gchar *hostparam;
       
   588 
       
   589   /* create a random sessionid */
       
   590   for (i = 0; i < TUNNELID_LEN; i++)
       
   591     conn->tunnelid[i] = g_random_int_range ('a', 'z');
       
   592   conn->tunnelid[TUNNELID_LEN - 1] = '\0';
       
   593 
       
   594   url = conn->url;
       
   595   /* get the port from the url */
       
   596   gst_rtsp_url_get_port (url, &url_port);
       
   597 
       
   598   if (conn->proxy_host) {
       
   599     hostparam = g_strdup_printf ("Host: %s:%d\r\n", url->host, url_port);
       
   600     url_port_str = g_strdup_printf (":%d", url_port);
       
   601     ip = conn->proxy_host;
       
   602     port = conn->proxy_port;
       
   603   } else {
       
   604     hostparam = NULL;
       
   605     url_port_str = NULL;
       
   606     ip = conn->ip;
       
   607     port = url_port;
       
   608   }
       
   609 
       
   610   /* */
       
   611   str = g_strdup_printf ("GET %s%s%s%s%s%s HTTP/1.0\r\n"
       
   612       "%s"
       
   613       "x-sessioncookie: %s\r\n"
       
   614       "Accept: application/x-rtsp-tunnelled\r\n"
       
   615       "Pragma: no-cache\r\n"
       
   616       "Cache-Control: no-cache\r\n" "\r\n",
       
   617       conn->proxy_host ? "http://" : "",
       
   618       conn->proxy_host ? url->host : "",
       
   619       conn->proxy_host ? url_port_str : "",
       
   620       url->abspath, url->query ? "?" : "", url->query ? url->query : "",
       
   621       hostparam ? hostparam : "", conn->tunnelid);
       
   622 
       
   623   /* we start by writing to this fd */
       
   624   conn->writefd = &conn->fd0;
       
   625 
       
   626   res = gst_rtsp_connection_write (conn, (guint8 *) str, strlen (str), timeout);
       
   627   g_free (str);
       
   628   if (res != GST_RTSP_OK)
       
   629     goto write_failed;
       
   630 
       
   631   gst_poll_fd_ctl_write (conn->fdset, &conn->fd0, FALSE);
       
   632   gst_poll_fd_ctl_read (conn->fdset, &conn->fd0, TRUE);
       
   633 
       
   634   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
       
   635 
       
   636   line = 0;
       
   637   while (TRUE) {
       
   638     guint8 buffer[4096];
       
   639 
       
   640     idx = 0;
       
   641     while (TRUE) {
       
   642       res = read_line (conn->fd0.fd, buffer, &idx, sizeof (buffer), NULL);
       
   643       if (res == GST_RTSP_EEOF)
       
   644         goto eof;
       
   645       if (res == GST_RTSP_OK)
       
   646         break;
       
   647       if (res != GST_RTSP_EINTR)
       
   648         goto read_error;
       
   649 
       
   650       do {
       
   651         retval = gst_poll_wait (conn->fdset, to);
       
   652       } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
       
   653 
       
   654       /* check for timeout */
       
   655       if (retval == 0)
       
   656         goto timeout;
       
   657 
       
   658       if (retval == -1) {
       
   659         if (errno == EBUSY)
       
   660           goto stopped;
       
   661         else
       
   662           goto select_error;
       
   663       }
   297     }
   664     }
   298     if (fd >= 0)
   665 
   299       CLOSE_SOCKET (fd);
   666     /* check for last line */
   300     return GST_RTSP_ESYS;
   667     if (buffer[0] == '\r')
       
   668       buffer[0] = '\0';
       
   669     if (buffer[0] == '\0')
       
   670       break;
       
   671 
       
   672     if (line == 0) {
       
   673       /* first line, parse response */
       
   674       gchar versionstr[20];
       
   675       gchar *bptr;
       
   676 
       
   677       bptr = (gchar *) buffer;
       
   678 
       
   679       parse_string (versionstr, sizeof (versionstr), &bptr);
       
   680       parse_string (codestr, sizeof (codestr), &bptr);
       
   681       code = atoi (codestr);
       
   682 
       
   683       while (g_ascii_isspace (*bptr))
       
   684         bptr++;
       
   685 
       
   686       resultstr = bptr;
       
   687 
       
   688       if (code != GST_RTSP_STS_OK)
       
   689         goto wrong_result;
       
   690     } else {
       
   691       gchar key[32];
       
   692       gchar *value;
       
   693 
       
   694       /* other lines, parse key/value */
       
   695       res = parse_key_value (buffer, key, sizeof (key), &value);
       
   696       if (res == GST_RTSP_OK) {
       
   697         /* we got a new ip address */
       
   698         if (g_ascii_strcasecmp (key, "x-server-ip-address") == 0) {
       
   699           if (conn->proxy_host) {
       
   700             /* if we use a proxy we need to change the destination url */
       
   701             g_free (url->host);
       
   702             url->host = g_strdup (value);
       
   703             g_free (hostparam);
       
   704             g_free (url_port_str);
       
   705             hostparam =
       
   706                 g_strdup_printf ("Host: %s:%d\r\n", url->host, url_port);
       
   707             url_port_str = g_strdup_printf (":%d", url_port);
       
   708           } else {
       
   709             /* and resolve the new ip address */
       
   710             if (!(ip = do_resolve (conn->ip)))
       
   711               goto not_resolved;
       
   712             g_free (conn->ip);
       
   713             conn->ip = ip;
       
   714           }
       
   715         }
       
   716       }
       
   717     }
       
   718     line++;
       
   719   }
       
   720 
       
   721   /* connect to the host/port */
       
   722   res = do_connect (ip, port, &conn->fd1, conn->fdset, timeout);
       
   723   if (res != GST_RTSP_OK)
       
   724     goto connect_failed;
       
   725 
       
   726   /* this is now our writing socket */
       
   727   conn->writefd = &conn->fd1;
       
   728 
       
   729   /* */
       
   730   str = g_strdup_printf ("POST %s%s%s%s%s%s HTTP/1.0\r\n"
       
   731       "%s"
       
   732       "x-sessioncookie: %s\r\n"
       
   733       "Content-Type: application/x-rtsp-tunnelled\r\n"
       
   734       "Pragma: no-cache\r\n"
       
   735       "Cache-Control: no-cache\r\n"
       
   736       "Content-Length: 32767\r\n"
       
   737       "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n"
       
   738       "\r\n",
       
   739       conn->proxy_host ? "http://" : "",
       
   740       conn->proxy_host ? url->host : "",
       
   741       conn->proxy_host ? url_port_str : "",
       
   742       url->abspath, url->query ? "?" : "", url->query ? url->query : "",
       
   743       hostparam ? hostparam : "", conn->tunnelid);
       
   744 
       
   745   res = gst_rtsp_connection_write (conn, (guint8 *) str, strlen (str), timeout);
       
   746   g_free (str);
       
   747   if (res != GST_RTSP_OK)
       
   748     goto write_failed;
       
   749 
       
   750 exit:
       
   751   g_free (hostparam);
       
   752   g_free (url_port_str);
       
   753 
       
   754   return res;
       
   755 
       
   756   /* ERRORS */
       
   757 write_failed:
       
   758   {
       
   759     GST_ERROR ("write failed (%d)", res);
       
   760     goto exit;
       
   761   }
       
   762 eof:
       
   763   {
       
   764     res = GST_RTSP_EEOF;
       
   765     goto exit;
       
   766   }
       
   767 read_error:
       
   768   {
       
   769     goto exit;
       
   770   }
       
   771 timeout:
       
   772   {
       
   773     res = GST_RTSP_ETIMEOUT;
       
   774     goto exit;
       
   775   }
       
   776 select_error:
       
   777   {
       
   778     res = GST_RTSP_ESYS;
       
   779     goto exit;
       
   780   }
       
   781 stopped:
       
   782   {
       
   783     res = GST_RTSP_EINTR;
       
   784     goto exit;
       
   785   }
       
   786 wrong_result:
       
   787   {
       
   788     GST_ERROR ("got failure response %d %s", code, resultstr);
       
   789     res = GST_RTSP_ERROR;
       
   790     goto exit;
   301   }
   791   }
   302 not_resolved:
   792 not_resolved:
   303   {
   793   {
       
   794     GST_ERROR ("could not resolve %s", conn->ip);
       
   795     res = GST_RTSP_ENET;
       
   796     goto exit;
       
   797   }
       
   798 connect_failed:
       
   799   {
       
   800     GST_ERROR ("failed to connect");
       
   801     goto exit;
       
   802   }
       
   803 }
       
   804 
       
   805 /**
       
   806  * gst_rtsp_connection_connect:
       
   807  * @conn: a #GstRTSPConnection 
       
   808  * @timeout: a #GTimeVal timeout
       
   809  *
       
   810  * Attempt to connect to the url of @conn made with
       
   811  * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
       
   812  * forever. If @timeout contains a valid timeout, this function will return
       
   813  * #GST_RTSP_ETIMEOUT after the timeout expired.
       
   814  *
       
   815  * This function can be cancelled with gst_rtsp_connection_flush().
       
   816  *
       
   817  * Returns: #GST_RTSP_OK when a connection could be made.
       
   818  */
       
   819 GstRTSPResult
       
   820 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
       
   821 {
       
   822   GstRTSPResult res;
       
   823   gchar *ip;
       
   824   guint16 port;
       
   825   GstRTSPUrl *url;
       
   826 
       
   827   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
       
   828   g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
       
   829   g_return_val_if_fail (conn->fd0.fd < 0, GST_RTSP_EINVAL);
       
   830 
       
   831   url = conn->url;
       
   832 
       
   833   if (conn->proxy_host && conn->tunneled) {
       
   834     if (!(ip = do_resolve (conn->proxy_host))) {
       
   835       GST_ERROR ("could not resolve %s", conn->proxy_host);
       
   836       goto not_resolved;
       
   837     }
       
   838     port = conn->proxy_port;
       
   839     g_free (conn->proxy_host);
       
   840     conn->proxy_host = ip;
       
   841   } else {
       
   842     if (!(ip = do_resolve (url->host))) {
       
   843       GST_ERROR ("could not resolve %s", url->host);
       
   844       goto not_resolved;
       
   845     }
       
   846     /* get the port from the url */
       
   847     gst_rtsp_url_get_port (url, &port);
       
   848 
       
   849     g_free (conn->ip);
       
   850     conn->ip = ip;
       
   851   }
       
   852 
       
   853   /* connect to the host/port */
       
   854   res = do_connect (ip, port, &conn->fd0, conn->fdset, timeout);
       
   855   if (res != GST_RTSP_OK)
       
   856     goto connect_failed;
       
   857 
       
   858   /* this is our read URL */
       
   859   conn->readfd = &conn->fd0;
       
   860 
       
   861   if (conn->tunneled) {
       
   862     res = setup_tunneling (conn, timeout);
       
   863     if (res != GST_RTSP_OK)
       
   864       goto tunneling_failed;
       
   865   } else {
       
   866     conn->writefd = &conn->fd0;
       
   867   }
       
   868 
       
   869   return GST_RTSP_OK;
       
   870 
       
   871 not_resolved:
       
   872   {
   304     return GST_RTSP_ENET;
   873     return GST_RTSP_ENET;
   305   }
   874   }
   306 not_ip:
   875 connect_failed:
   307   {
   876   {
   308     return GST_RTSP_ENOTIP;
   877     GST_ERROR ("failed to connect");
   309   }
   878     return res;
   310 timeout:
   879   }
   311   {
   880 tunneling_failed:
   312     if (conn->fd.fd >= 0) {
   881   {
   313       gst_poll_remove_fd (conn->fdset, &conn->fd);
   882     GST_ERROR ("failed to setup tunneling");
   314       conn->fd.fd = -1;
   883     return res;
   315     }
   884   }
   316     if (fd >= 0)
   885 }
   317       CLOSE_SOCKET (fd);
   886 
   318     return GST_RTSP_ETIMEOUT;
   887 static void
   319   }
   888 md5_digest_to_hex_string (unsigned char digest[16], char string[33])
       
   889 {
       
   890   static const char hexdigits[] = "0123456789abcdef";
       
   891   int i;
       
   892 
       
   893   for (i = 0; i < 16; i++) {
       
   894     string[i * 2] = hexdigits[(digest[i] >> 4) & 0x0f];
       
   895     string[i * 2 + 1] = hexdigits[digest[i] & 0x0f];
       
   896   }
       
   897   string[32] = 0;
       
   898 }
       
   899 
       
   900 static void
       
   901 auth_digest_compute_hex_urp (const gchar * username,
       
   902     const gchar * realm, const gchar * password, gchar hex_urp[33])
       
   903 {
       
   904   struct MD5Context md5_context;
       
   905   unsigned char digest[16];
       
   906 
       
   907   MD5Init (&md5_context);
       
   908   MD5Update (&md5_context, username, strlen (username));
       
   909   MD5Update (&md5_context, ":", 1);
       
   910   MD5Update (&md5_context, realm, strlen (realm));
       
   911   MD5Update (&md5_context, ":", 1);
       
   912   MD5Update (&md5_context, password, strlen (password));
       
   913   MD5Final (digest, &md5_context);
       
   914   md5_digest_to_hex_string (digest, hex_urp);
       
   915 }
       
   916 
       
   917 static void
       
   918 auth_digest_compute_response (const gchar * method,
       
   919     const gchar * uri, const gchar * hex_a1, const gchar * nonce,
       
   920     gchar response[33])
       
   921 {
       
   922   char hex_a2[33];
       
   923   struct MD5Context md5_context;
       
   924   unsigned char digest[16];
       
   925 
       
   926   /* compute A2 */
       
   927   MD5Init (&md5_context);
       
   928   MD5Update (&md5_context, method, strlen (method));
       
   929   MD5Update (&md5_context, ":", 1);
       
   930   MD5Update (&md5_context, uri, strlen (uri));
       
   931   MD5Final (digest, &md5_context);
       
   932   md5_digest_to_hex_string (digest, hex_a2);
       
   933 
       
   934   /* compute KD */
       
   935   MD5Init (&md5_context);
       
   936   MD5Update (&md5_context, hex_a1, strlen (hex_a1));
       
   937   MD5Update (&md5_context, ":", 1);
       
   938   MD5Update (&md5_context, nonce, strlen (nonce));
       
   939   MD5Update (&md5_context, ":", 1);
       
   940 
       
   941   MD5Update (&md5_context, hex_a2, 32);
       
   942   MD5Final (digest, &md5_context);
       
   943   md5_digest_to_hex_string (digest, response);
   320 }
   944 }
   321 
   945 
   322 static void
   946 static void
   323 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
   947 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
   324 {
   948 {
   325   switch (conn->auth_method) {
   949   switch (conn->auth_method) {
   326     case GST_RTSP_AUTH_BASIC:{
   950     case GST_RTSP_AUTH_BASIC:{
   327       gchar *user_pass =
   951       gchar *user_pass;
   328           g_strdup_printf ("%s:%s", conn->username, conn->passwd);
   952       gchar *user_pass64;
   329       gchar *user_pass64 =
   953       gchar *auth_string;
   330           gst_rtsp_base64_encode (user_pass, strlen (user_pass));
   954 
   331       gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
   955       user_pass = g_strdup_printf ("%s:%s", conn->username, conn->passwd);
   332 
   956       user_pass64 = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
   333       gst_rtsp_message_add_header (message, GST_RTSP_HDR_AUTHORIZATION,
   957       auth_string = g_strdup_printf ("Basic %s", user_pass64);
       
   958 
       
   959       gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
   334           auth_string);
   960           auth_string);
   335 
   961 
   336       g_free (user_pass);
   962       g_free (user_pass);
   337       g_free (user_pass64);
   963       g_free (user_pass64);
   338       g_free (auth_string);
   964       break;
       
   965     }
       
   966     case GST_RTSP_AUTH_DIGEST:{
       
   967       gchar response[33], hex_urp[33];
       
   968       gchar *auth_string, *auth_string2;
       
   969       gchar *realm;
       
   970       gchar *nonce;
       
   971       gchar *opaque;
       
   972       const gchar *uri;
       
   973       const gchar *method;
       
   974 
       
   975       /* we need to have some params set */
       
   976       if (conn->auth_params == NULL)
       
   977         break;
       
   978 
       
   979       /* we need the realm and nonce */
       
   980       realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm");
       
   981       nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce");
       
   982       if (realm == NULL || nonce == NULL)
       
   983         break;
       
   984 
       
   985       auth_digest_compute_hex_urp (conn->username, realm, conn->passwd,
       
   986           hex_urp);
       
   987 
       
   988       method = gst_rtsp_method_as_text (message->type_data.request.method);
       
   989       uri = message->type_data.request.uri;
       
   990 
       
   991       /* Assume no qop, algorithm=md5, stale=false */
       
   992       /* For algorithm MD5, a1 = urp. */
       
   993       auth_digest_compute_response (method, uri, hex_urp, nonce, response);
       
   994       auth_string = g_strdup_printf ("Digest username=\"%s\", "
       
   995           "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
       
   996           conn->username, realm, nonce, uri, response);
       
   997 
       
   998       opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
       
   999       if (opaque) {
       
  1000         auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
       
  1001             opaque);
       
  1002         g_free (auth_string);
       
  1003         auth_string = auth_string2;
       
  1004       }
       
  1005       gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
       
  1006           auth_string);
   339       break;
  1007       break;
   340     }
  1008     }
   341     default:
  1009     default:
   342       /* Nothing to do */
  1010       /* Nothing to do */
   343       break;
  1011       break;
   344   }
  1012   }
   345 }
  1013 }
   346 
  1014 
   347 static void
  1015 static void
   348 add_date_header (GstRTSPMessage * message)
  1016 gen_date_string (gchar * date_string, guint len)
   349 {
  1017 {
   350   GTimeVal tv;
  1018   GTimeVal tv;
   351   gchar date_string[100];
       
   352   time_t t;
  1019   time_t t;
   353 
       
   354 #ifdef HAVE_GMTIME_R
  1020 #ifdef HAVE_GMTIME_R
   355   struct tm tm_;
  1021   struct tm tm_;
   356 #endif
  1022 #endif
   357 
  1023 
   358   g_get_current_time (&tv);
  1024   g_get_current_time (&tv);
   359   t = (time_t) tv.tv_sec;
  1025   t = (time_t) tv.tv_sec;
   360 
  1026 
   361 #ifdef HAVE_GMTIME_R
  1027 #ifdef HAVE_GMTIME_R
   362   strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
  1028   strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime_r (&t, &tm_));
   363       gmtime_r (&t, &tm_));
       
   364 #else
  1029 #else
   365   strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
  1030   strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime (&t));
   366       gmtime (&t));
       
   367 #endif
  1031 #endif
   368 
  1032 }
   369   gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
  1033 
       
  1034 static GstRTSPResult
       
  1035 write_bytes (gint fd, const guint8 * buffer, guint * idx, guint size)
       
  1036 {
       
  1037   guint left;
       
  1038 
       
  1039   if (G_UNLIKELY (*idx > size))
       
  1040     return GST_RTSP_ERROR;
       
  1041 
       
  1042   left = size - *idx;
       
  1043 
       
  1044   while (left) {
       
  1045     gint r;
       
  1046 
       
  1047     r = WRITE_SOCKET (fd, &buffer[*idx], left);
       
  1048     if (G_UNLIKELY (r == 0)) {
       
  1049       return GST_RTSP_EINTR;
       
  1050     } else if (G_UNLIKELY (r < 0)) {
       
  1051       if (ERRNO_IS_EAGAIN)
       
  1052         return GST_RTSP_EINTR;
       
  1053       if (!ERRNO_IS_EINTR)
       
  1054         return GST_RTSP_ESYS;
       
  1055     } else {
       
  1056       left -= r;
       
  1057       *idx += r;
       
  1058     }
       
  1059   }
       
  1060   return GST_RTSP_OK;
       
  1061 }
       
  1062 
       
  1063 static gint
       
  1064 fill_bytes (gint fd, guint8 * buffer, guint size, DecodeCtx * ctx)
       
  1065 {
       
  1066   gint out = 0;
       
  1067 
       
  1068   if (ctx) {
       
  1069     while (size > 0) {
       
  1070       guint8 in[sizeof (ctx->out) * 4 / 3];
       
  1071       gint r;
       
  1072 
       
  1073       while (size > 0 && ctx->cout < ctx->coutl) {
       
  1074         /* we have some leftover bytes */
       
  1075         *buffer++ = ctx->out[ctx->cout++];
       
  1076         size--;
       
  1077         out++;
       
  1078       }
       
  1079 
       
  1080       /* got what we needed? */
       
  1081       if (size == 0)
       
  1082         break;
       
  1083 
       
  1084       /* try to read more bytes */
       
  1085       r = READ_SOCKET (fd, in, sizeof (in));
       
  1086       if (r <= 0) {
       
  1087         if (out == 0)
       
  1088           out = r;
       
  1089         break;
       
  1090       }
       
  1091 
       
  1092       ctx->cout = 0;
       
  1093       ctx->coutl =
       
  1094           g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state,
       
  1095           &ctx->save);
       
  1096     }
       
  1097   } else {
       
  1098     out = READ_SOCKET (fd, buffer, size);
       
  1099   }
       
  1100 
       
  1101   return out;
       
  1102 }
       
  1103 
       
  1104 static GstRTSPResult
       
  1105 read_bytes (gint fd, guint8 * buffer, guint * idx, guint size, DecodeCtx * ctx)
       
  1106 {
       
  1107   guint left;
       
  1108 
       
  1109   if (G_UNLIKELY (*idx > size))
       
  1110     return GST_RTSP_ERROR;
       
  1111 
       
  1112   left = size - *idx;
       
  1113 
       
  1114   while (left) {
       
  1115     gint r;
       
  1116 
       
  1117     r = fill_bytes (fd, &buffer[*idx], left, ctx);
       
  1118     if (G_UNLIKELY (r == 0)) {
       
  1119       return GST_RTSP_EEOF;
       
  1120     } else if (G_UNLIKELY (r < 0)) {
       
  1121       if (ERRNO_IS_EAGAIN)
       
  1122         return GST_RTSP_EINTR;
       
  1123       if (!ERRNO_IS_EINTR)
       
  1124         return GST_RTSP_ESYS;
       
  1125     } else {
       
  1126       left -= r;
       
  1127       *idx += r;
       
  1128     }
       
  1129   }
       
  1130   return GST_RTSP_OK;
       
  1131 }
       
  1132 
       
  1133 static GstRTSPResult
       
  1134 read_line (gint fd, guint8 * buffer, guint * idx, guint size, DecodeCtx * ctx)
       
  1135 {
       
  1136   while (TRUE) {
       
  1137     guint8 c;
       
  1138     gint r;
       
  1139 
       
  1140     r = fill_bytes (fd, &c, 1, ctx);
       
  1141     if (G_UNLIKELY (r == 0)) {
       
  1142       return GST_RTSP_EEOF;
       
  1143     } else if (G_UNLIKELY (r < 0)) {
       
  1144       if (ERRNO_IS_EAGAIN)
       
  1145         return GST_RTSP_EINTR;
       
  1146       if (!ERRNO_IS_EINTR)
       
  1147         return GST_RTSP_ESYS;
       
  1148     } else {
       
  1149       if (c == '\n')            /* end on \n */
       
  1150         break;
       
  1151       if (c == '\r')            /* ignore \r */
       
  1152         continue;
       
  1153 
       
  1154       if (G_LIKELY (*idx < size - 1))
       
  1155         buffer[(*idx)++] = c;
       
  1156     }
       
  1157   }
       
  1158   buffer[*idx] = '\0';
       
  1159 
       
  1160   return GST_RTSP_OK;
   370 }
  1161 }
   371 
  1162 
   372 /**
  1163 /**
   373  * gst_rtsp_connection_write:
  1164  * gst_rtsp_connection_write:
   374  * @conn: a #GstRTSPConnection
  1165  * @conn: a #GstRTSPConnection
   386  */
  1177  */
   387 GstRTSPResult
  1178 GstRTSPResult
   388 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
  1179 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
   389     guint size, GTimeVal * timeout)
  1180     guint size, GTimeVal * timeout)
   390 {
  1181 {
   391   guint towrite;
  1182   guint offset;
   392   gint retval;
  1183   gint retval;
   393   GstClockTime to;
  1184   GstClockTime to;
       
  1185   GstRTSPResult res;
   394 
  1186 
   395   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  1187   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
   396   g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
  1188   g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
       
  1189   g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
   397 
  1190 
   398   gst_poll_set_controllable (conn->fdset, TRUE);
  1191   gst_poll_set_controllable (conn->fdset, TRUE);
   399   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
  1192   gst_poll_fd_ctl_write (conn->fdset, conn->writefd, TRUE);
   400   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, FALSE);
  1193   gst_poll_fd_ctl_read (conn->fdset, conn->readfd, FALSE);
       
  1194   /* clear all previous poll results */
       
  1195   gst_poll_fd_ignored (conn->fdset, conn->writefd);
       
  1196   gst_poll_fd_ignored (conn->fdset, conn->readfd);
   401 
  1197 
   402   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
  1198   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
   403 
  1199 
   404   towrite = size;
  1200   offset = 0;
   405 
  1201 
   406   while (towrite > 0) {
  1202   while (TRUE) {
   407     gint written;
  1203     /* try to write */
   408 
  1204     res = write_bytes (conn->writefd->fd, data, &offset, size);
       
  1205     if (G_LIKELY (res == GST_RTSP_OK))
       
  1206       break;
       
  1207     if (G_UNLIKELY (res != GST_RTSP_EINTR))
       
  1208       goto write_error;
       
  1209 
       
  1210     /* not all is written, wait until we can write more */
   409     do {
  1211     do {
   410       retval = gst_poll_wait (conn->fdset, to);
  1212       retval = gst_poll_wait (conn->fdset, to);
   411     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
  1213     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
   412 
  1214 
   413     if (retval == 0)
  1215     if (G_UNLIKELY (retval == 0))
   414       goto timeout;
  1216       goto timeout;
   415 
  1217 
   416     if (retval == -1) {
  1218     if (G_UNLIKELY (retval == -1)) {
   417       if (errno == EBUSY)
  1219       if (errno == EBUSY)
   418         goto stopped;
  1220         goto stopped;
   419       else
  1221       else
   420         goto select_error;
  1222         goto select_error;
   421     }
  1223     }
   422 
       
   423     /* now we can write */
       
   424     written = WRITE_SOCKET (conn->fd.fd, data, towrite);
       
   425     if (written < 0) {
       
   426       if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
       
   427         goto write_error;
       
   428     } else {
       
   429       towrite -= written;
       
   430       data += written;
       
   431     }
       
   432   }
  1224   }
   433   return GST_RTSP_OK;
  1225   return GST_RTSP_OK;
   434 
  1226 
   435   /* ERRORS */
  1227   /* ERRORS */
   436 timeout:
  1228 timeout:
   445   {
  1237   {
   446     return GST_RTSP_EINTR;
  1238     return GST_RTSP_EINTR;
   447   }
  1239   }
   448 write_error:
  1240 write_error:
   449   {
  1241   {
   450     return GST_RTSP_ESYS;
  1242     return res;
   451   }
  1243   }
   452 }
  1244 }
   453 
  1245 
   454 /**
  1246 static GString *
   455  * gst_rtsp_connection_send:
  1247 message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message)
   456  * @conn: a #GstRTSPConnection
       
   457  * @message: the message to send
       
   458  * @timeout: a timeout value or #NULL
       
   459  *
       
   460  * Attempt to send @message to the connected @conn, blocking up to
       
   461  * the specified @timeout. @timeout can be #NULL, in which case this function
       
   462  * might block forever.
       
   463  * 
       
   464  * This function can be cancelled with gst_rtsp_connection_flush().
       
   465  *
       
   466  * Returns: #GST_RTSP_OK on success.
       
   467  */
       
   468 GstRTSPResult
       
   469 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
       
   470     GTimeVal * timeout)
       
   471 {
  1248 {
   472   GString *str = NULL;
  1249   GString *str = NULL;
   473   GstRTSPResult res;
       
   474 
       
   475 #ifdef G_OS_WIN32
       
   476   WSADATA w;
       
   477   int error;
       
   478 #endif
       
   479 
       
   480   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
       
   481   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
       
   482 
       
   483 #ifdef G_OS_WIN32
       
   484   error = WSAStartup (0x0202, &w);
       
   485 
       
   486   if (error)
       
   487     goto startup_error;
       
   488 
       
   489   if (w.wVersion != 0x0202)
       
   490     goto version_error;
       
   491 #endif
       
   492 
  1250 
   493   str = g_string_new ("");
  1251   str = g_string_new ("");
   494 
  1252 
   495   switch (message->type) {
  1253   switch (message->type) {
   496     case GST_RTSP_MESSAGE_REQUEST:
  1254     case GST_RTSP_MESSAGE_REQUEST:
   528           g_string_append_len (str, (gchar *) message->body,
  1286           g_string_append_len (str, (gchar *) message->body,
   529           message->body_size);
  1287           message->body_size);
   530       break;
  1288       break;
   531     }
  1289     }
   532     default:
  1290     default:
   533       g_return_val_if_reached (GST_RTSP_EINVAL);
  1291       g_string_free (str, TRUE);
       
  1292       g_return_val_if_reached (NULL);
   534       break;
  1293       break;
   535   }
  1294   }
   536 
  1295 
   537   /* append headers and body */
  1296   /* append headers and body */
   538   if (message->type != GST_RTSP_MESSAGE_DATA) {
  1297   if (message->type != GST_RTSP_MESSAGE_DATA) {
       
  1298     gchar date_string[100];
       
  1299 
       
  1300     gen_date_string (date_string, sizeof (date_string));
       
  1301 
   539     /* add date header */
  1302     /* add date header */
   540     add_date_header (message);
  1303     gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
   541 
  1304 
   542     /* append headers */
  1305     /* append headers */
   543     gst_rtsp_message_append_headers (message, str);
  1306     gst_rtsp_message_append_headers (message, str);
   544 
  1307 
   545     /* append Content-Length and body if needed */
  1308     /* append Content-Length and body if needed */
   559       /* just end headers */
  1322       /* just end headers */
   560       g_string_append (str, "\r\n");
  1323       g_string_append (str, "\r\n");
   561     }
  1324     }
   562   }
  1325   }
   563 
  1326 
       
  1327   return str;
       
  1328 }
       
  1329 
       
  1330 /**
       
  1331  * gst_rtsp_connection_send:
       
  1332  * @conn: a #GstRTSPConnection
       
  1333  * @message: the message to send
       
  1334  * @timeout: a timeout value or #NULL
       
  1335  *
       
  1336  * Attempt to send @message to the connected @conn, blocking up to
       
  1337  * the specified @timeout. @timeout can be #NULL, in which case this function
       
  1338  * might block forever.
       
  1339  * 
       
  1340  * This function can be cancelled with gst_rtsp_connection_flush().
       
  1341  *
       
  1342  * Returns: #GST_RTSP_OK on success.
       
  1343  */
       
  1344 GstRTSPResult
       
  1345 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
       
  1346     GTimeVal * timeout)
       
  1347 {
       
  1348   GString *string = NULL;
       
  1349   GstRTSPResult res;
       
  1350   gchar *str;
       
  1351   gsize len;
       
  1352 
       
  1353   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
       
  1354   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
       
  1355 
       
  1356   if (G_UNLIKELY (!(string = message_to_string (conn, message))))
       
  1357     goto no_message;
       
  1358 
       
  1359   if (conn->tunneled) {
       
  1360     str = g_base64_encode ((const guchar *) string->str, string->len);
       
  1361     g_string_free (string, TRUE);
       
  1362     len = strlen (str);
       
  1363   } else {
       
  1364     str = string->str;
       
  1365     len = string->len;
       
  1366     g_string_free (string, FALSE);
       
  1367   }
       
  1368 
   564   /* write request */
  1369   /* write request */
   565   res =
  1370   res = gst_rtsp_connection_write (conn, (guint8 *) str, len, timeout);
   566       gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
  1371 
   567 
  1372   g_free (str);
   568   g_string_free (str, TRUE);
       
   569 
  1373 
   570   return res;
  1374   return res;
   571 
  1375 
   572 #ifdef G_OS_WIN32
  1376 no_message:
   573 startup_error:
  1377   {
   574   {
  1378     g_warning ("Wrong message");
   575     g_warning ("Error %d on WSAStartup", error);
  1379     return GST_RTSP_EINVAL;
   576     return GST_RTSP_EWSASTART;
       
   577   }
       
   578 version_error:
       
   579   {
       
   580     g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
       
   581         w.wVersion);
       
   582     WSACleanup ();
       
   583     return GST_RTSP_EWSAVERSION;
       
   584   }
       
   585 #endif
       
   586 }
       
   587 
       
   588 static GstRTSPResult
       
   589 read_line (gint fd, gchar * buffer, guint size)
       
   590 {
       
   591   guint idx;
       
   592   gchar c;
       
   593   gint r;
       
   594 
       
   595   idx = 0;
       
   596   while (TRUE) {
       
   597     r = READ_SOCKET (fd, &c, 1);
       
   598     if (r == 0) {
       
   599       goto eof;
       
   600     } else if (r < 0) {
       
   601       if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
       
   602         goto read_error;
       
   603     } else {
       
   604       if (c == '\n')            /* end on \n */
       
   605         break;
       
   606       if (c == '\r')            /* ignore \r */
       
   607         continue;
       
   608 
       
   609       if (idx < size - 1)
       
   610         buffer[idx++] = c;
       
   611     }
       
   612   }
       
   613   buffer[idx] = '\0';
       
   614 
       
   615   return GST_RTSP_OK;
       
   616 
       
   617 eof:
       
   618   {
       
   619     return GST_RTSP_EEOF;
       
   620   }
       
   621 read_error:
       
   622   {
       
   623     return GST_RTSP_ESYS;
       
   624   }
  1380   }
   625 }
  1381 }
   626 
  1382 
   627 static void
  1383 static void
   628 read_string (gchar * dest, gint size, gchar ** src)
  1384 parse_string (gchar * dest, gint size, gchar ** src)
   629 {
  1385 {
   630   gint idx;
  1386   gint idx;
   631 
  1387 
   632   idx = 0;
  1388   idx = 0;
   633   /* skip spaces */
  1389   /* skip spaces */
   642   if (size > 0)
  1398   if (size > 0)
   643     dest[idx] = '\0';
  1399     dest[idx] = '\0';
   644 }
  1400 }
   645 
  1401 
   646 static void
  1402 static void
   647 read_key (gchar * dest, gint size, gchar ** src)
  1403 parse_key (gchar * dest, gint size, gchar ** src)
   648 {
  1404 {
   649   gint idx;
  1405   gint idx;
   650 
  1406 
   651   idx = 0;
  1407   idx = 0;
   652   while (**src != ':' && **src != '\0') {
  1408   while (**src != ':' && **src != '\0') {
   657   if (size > 0)
  1413   if (size > 0)
   658     dest[idx] = '\0';
  1414     dest[idx] = '\0';
   659 }
  1415 }
   660 
  1416 
   661 static GstRTSPResult
  1417 static GstRTSPResult
   662 parse_response_status (gchar * buffer, GstRTSPMessage * msg)
  1418 parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
   663 {
  1419 {
   664   GstRTSPResult res;
  1420   GstRTSPResult res;
   665   gchar versionstr[20];
  1421   gchar versionstr[20];
   666   gchar codestr[4];
  1422   gchar codestr[4];
   667   gint code;
  1423   gint code;
   668   gchar *bptr;
  1424   gchar *bptr;
   669 
  1425 
   670   bptr = buffer;
  1426   bptr = (gchar *) buffer;
   671 
  1427 
   672   read_string (versionstr, sizeof (versionstr), &bptr);
  1428   parse_string (versionstr, sizeof (versionstr), &bptr);
   673   read_string (codestr, sizeof (codestr), &bptr);
  1429   parse_string (codestr, sizeof (codestr), &bptr);
   674   code = atoi (codestr);
  1430   code = atoi (codestr);
   675 
  1431 
   676   while (g_ascii_isspace (*bptr))
  1432   while (g_ascii_isspace (*bptr))
   677     bptr++;
  1433     bptr++;
   678 
  1434 
   693     return GST_RTSP_EPARSE;
  1449     return GST_RTSP_EPARSE;
   694   }
  1450   }
   695 }
  1451 }
   696 
  1452 
   697 static GstRTSPResult
  1453 static GstRTSPResult
   698 parse_request_line (gchar * buffer, GstRTSPMessage * msg)
  1454 parse_request_line (GstRTSPConnection * conn, guint8 * buffer,
       
  1455     GstRTSPMessage * msg)
   699 {
  1456 {
   700   GstRTSPResult res = GST_RTSP_OK;
  1457   GstRTSPResult res = GST_RTSP_OK;
   701   gchar versionstr[20];
  1458   gchar versionstr[20];
   702   gchar methodstr[20];
  1459   gchar methodstr[20];
   703   gchar urlstr[4096];
  1460   gchar urlstr[4096];
   704   gchar *bptr;
  1461   gchar *bptr;
   705   GstRTSPMethod method;
  1462   GstRTSPMethod method;
   706 
  1463   GstRTSPTunnelState tstate = TUNNEL_STATE_NONE;
   707   bptr = buffer;
  1464 
   708 
  1465   bptr = (gchar *) buffer;
   709   read_string (methodstr, sizeof (methodstr), &bptr);
  1466 
       
  1467   parse_string (methodstr, sizeof (methodstr), &bptr);
   710   method = gst_rtsp_find_method (methodstr);
  1468   method = gst_rtsp_find_method (methodstr);
   711 
  1469   if (method == GST_RTSP_INVALID) {
   712   read_string (urlstr, sizeof (urlstr), &bptr);
  1470     /* a tunnel request is allowed when we don't have one yet */
   713   if (*urlstr == '\0')
  1471     if (conn->tstate != TUNNEL_STATE_NONE)
       
  1472       goto invalid_method;
       
  1473     /* we need GET or POST for a valid tunnel request */
       
  1474     if (!strcmp (methodstr, "GET"))
       
  1475       tstate = TUNNEL_STATE_GET;
       
  1476     else if (!strcmp (methodstr, "POST"))
       
  1477       tstate = TUNNEL_STATE_POST;
       
  1478     else
       
  1479       goto invalid_method;
       
  1480   }
       
  1481 
       
  1482   parse_string (urlstr, sizeof (urlstr), &bptr);
       
  1483   if (G_UNLIKELY (*urlstr == '\0'))
       
  1484     goto invalid_url;
       
  1485 
       
  1486   parse_string (versionstr, sizeof (versionstr), &bptr);
       
  1487 
       
  1488   if (G_UNLIKELY (*bptr != '\0'))
       
  1489     goto invalid_version;
       
  1490 
       
  1491   if (strcmp (versionstr, "RTSP/1.0") == 0) {
       
  1492     res = gst_rtsp_message_init_request (msg, method, urlstr);
       
  1493   } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
       
  1494     res = gst_rtsp_message_init_request (msg, method, urlstr);
       
  1495     msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
       
  1496   } else if (strcmp (versionstr, "HTTP/1.0") == 0) {
       
  1497     /* tunnel request, we need a tunnel method */
       
  1498     if (tstate == TUNNEL_STATE_NONE) {
       
  1499       res = GST_RTSP_EPARSE;
       
  1500     } else {
       
  1501       conn->tstate = tstate;
       
  1502     }
       
  1503   } else {
   714     res = GST_RTSP_EPARSE;
  1504     res = GST_RTSP_EPARSE;
   715 
       
   716   read_string (versionstr, sizeof (versionstr), &bptr);
       
   717 
       
   718   if (*bptr != '\0')
       
   719     res = GST_RTSP_EPARSE;
       
   720 
       
   721   if (strcmp (versionstr, "RTSP/1.0") == 0) {
       
   722     if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
       
   723       res = GST_RTSP_EPARSE;
       
   724   } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
       
   725     if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
       
   726       res = GST_RTSP_EPARSE;
       
   727     msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
       
   728   } else {
       
   729     gst_rtsp_message_init_request (msg, method, urlstr);
       
   730     msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
       
   731     res = GST_RTSP_EPARSE;
       
   732   }
  1505   }
   733 
  1506 
   734   return res;
  1507   return res;
       
  1508 
       
  1509   /* ERRORS */
       
  1510 invalid_method:
       
  1511   {
       
  1512     GST_ERROR ("invalid method %s", methodstr);
       
  1513     return GST_RTSP_EPARSE;
       
  1514   }
       
  1515 invalid_url:
       
  1516   {
       
  1517     GST_ERROR ("invalid url %s", urlstr);
       
  1518     return GST_RTSP_EPARSE;
       
  1519   }
       
  1520 invalid_version:
       
  1521   {
       
  1522     GST_ERROR ("invalid version");
       
  1523     return GST_RTSP_EPARSE;
       
  1524   }
       
  1525 }
       
  1526 
       
  1527 static GstRTSPResult
       
  1528 parse_key_value (guint8 * buffer, gchar * key, guint keysize, gchar ** value)
       
  1529 {
       
  1530   gchar *bptr;
       
  1531 
       
  1532   bptr = (gchar *) buffer;
       
  1533 
       
  1534   /* read key */
       
  1535   parse_key (key, keysize, &bptr);
       
  1536   if (G_UNLIKELY (*bptr != ':'))
       
  1537     goto no_column;
       
  1538 
       
  1539   bptr++;
       
  1540   while (g_ascii_isspace (*bptr))
       
  1541     bptr++;
       
  1542 
       
  1543   *value = bptr;
       
  1544 
       
  1545   return GST_RTSP_OK;
       
  1546 
       
  1547   /* ERRORS */
       
  1548 no_column:
       
  1549   {
       
  1550     return GST_RTSP_EPARSE;
       
  1551   }
   735 }
  1552 }
   736 
  1553 
   737 /* parsing lines means reading a Key: Value pair */
  1554 /* parsing lines means reading a Key: Value pair */
   738 static GstRTSPResult
  1555 static GstRTSPResult
   739 parse_line (gchar * buffer, GstRTSPMessage * msg)
  1556 parse_line (GstRTSPConnection * conn, guint8 * buffer, GstRTSPMessage * msg)
   740 {
  1557 {
       
  1558   GstRTSPResult res;
   741   gchar key[32];
  1559   gchar key[32];
   742   gchar *bptr;
  1560   gchar *value;
   743   GstRTSPHeaderField field;
  1561   GstRTSPHeaderField field;
   744 
  1562 
   745   bptr = buffer;
  1563   res = parse_key_value (buffer, key, sizeof (key), &value);
   746 
  1564   if (G_UNLIKELY (res != GST_RTSP_OK))
   747   /* read key */
  1565     goto parse_error;
   748   read_key (key, sizeof (key), &bptr);
  1566 
   749   if (*bptr != ':')
  1567   if (conn->tstate == TUNNEL_STATE_GET || conn->tstate == TUNNEL_STATE_POST) {
   750     goto no_column;
  1568     /* save the tunnel session in the connection */
   751 
  1569     if (!strcmp (key, "x-sessioncookie")) {
   752   bptr++;
  1570       strncpy (conn->tunnelid, value, TUNNELID_LEN);
   753 
  1571       conn->tunnelid[TUNNELID_LEN - 1] = '\0';
   754   field = gst_rtsp_find_header_field (key);
  1572       conn->tunneled = TRUE;
   755   if (field != GST_RTSP_HDR_INVALID) {
  1573     }
   756     while (g_ascii_isspace (*bptr))
  1574   } else {
   757       bptr++;
  1575     field = gst_rtsp_find_header_field (key);
   758     gst_rtsp_message_add_header (msg, field, bptr);
  1576     if (field != GST_RTSP_HDR_INVALID)
       
  1577       gst_rtsp_message_add_header (msg, field, value);
   759   }
  1578   }
   760 
  1579 
   761   return GST_RTSP_OK;
  1580   return GST_RTSP_OK;
   762 
  1581 
   763 no_column:
  1582   /* ERRORS */
   764   {
  1583 parse_error:
   765     return GST_RTSP_EPARSE;
  1584   {
   766   }
  1585     return res;
   767 }
  1586   }
   768 
  1587 }
   769 /**
  1588 
   770  * gst_rtsp_connection_read_internal:
  1589 /* returns:
       
  1590  *  GST_RTSP_OK when a complete message was read.
       
  1591  *  GST_RTSP_EEOF: when the socket is closed
       
  1592  *  GST_RTSP_EINTR: when more data is needed.
       
  1593  *  GST_RTSP_..: some other error occured.
       
  1594  */
       
  1595 static GstRTSPResult
       
  1596 build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
       
  1597     GstRTSPConnection * conn)
       
  1598 {
       
  1599   GstRTSPResult res;
       
  1600 
       
  1601   while (TRUE) {
       
  1602     switch (builder->state) {
       
  1603       case STATE_START:
       
  1604         builder->offset = 0;
       
  1605         res =
       
  1606             read_bytes (conn->readfd->fd, (guint8 *) builder->buffer,
       
  1607             &builder->offset, 1, conn->ctxp);
       
  1608         if (res != GST_RTSP_OK)
       
  1609           goto done;
       
  1610 
       
  1611         /* we have 1 bytes now and we can see if this is a data message or
       
  1612          * not */
       
  1613         if (builder->buffer[0] == '$') {
       
  1614           /* data message, prepare for the header */
       
  1615           builder->state = STATE_DATA_HEADER;
       
  1616         } else {
       
  1617           builder->line = 0;
       
  1618           builder->state = STATE_READ_LINES;
       
  1619         }
       
  1620         break;
       
  1621       case STATE_DATA_HEADER:
       
  1622       {
       
  1623         res =
       
  1624             read_bytes (conn->readfd->fd, (guint8 *) builder->buffer,
       
  1625             &builder->offset, 4, conn->ctxp);
       
  1626         if (res != GST_RTSP_OK)
       
  1627           goto done;
       
  1628 
       
  1629         gst_rtsp_message_init_data (message, builder->buffer[1]);
       
  1630 
       
  1631         builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
       
  1632         builder->body_data = g_malloc (builder->body_len + 1);
       
  1633         builder->body_data[builder->body_len] = '\0';
       
  1634         builder->offset = 0;
       
  1635         builder->state = STATE_DATA_BODY;
       
  1636         break;
       
  1637       }
       
  1638       case STATE_DATA_BODY:
       
  1639       {
       
  1640         res =
       
  1641             read_bytes (conn->readfd->fd, builder->body_data, &builder->offset,
       
  1642             builder->body_len, conn->ctxp);
       
  1643         if (res != GST_RTSP_OK)
       
  1644           goto done;
       
  1645 
       
  1646         /* we have the complete body now, store in the message adjusting the
       
  1647          * length to include the traling '\0' */
       
  1648         gst_rtsp_message_take_body (message,
       
  1649             (guint8 *) builder->body_data, builder->body_len + 1);
       
  1650         builder->body_data = NULL;
       
  1651         builder->body_len = 0;
       
  1652 
       
  1653         builder->state = STATE_END;
       
  1654         break;
       
  1655       }
       
  1656       case STATE_READ_LINES:
       
  1657       {
       
  1658         res = read_line (conn->readfd->fd, builder->buffer, &builder->offset,
       
  1659             sizeof (builder->buffer), conn->ctxp);
       
  1660         if (res != GST_RTSP_OK)
       
  1661           goto done;
       
  1662 
       
  1663         /* we have a regular response */
       
  1664         if (builder->buffer[0] == '\r') {
       
  1665           builder->buffer[0] = '\0';
       
  1666         }
       
  1667 
       
  1668         if (builder->buffer[0] == '\0') {
       
  1669           gchar *hdrval;
       
  1670 
       
  1671           /* empty line, end of message header */
       
  1672           /* see if there is a Content-Length header */
       
  1673           if (gst_rtsp_message_get_header (message,
       
  1674                   GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK) {
       
  1675             /* there is, prepare to read the body */
       
  1676             builder->body_len = atol (hdrval);
       
  1677             builder->body_data = g_malloc (builder->body_len + 1);
       
  1678             builder->body_data[builder->body_len] = '\0';
       
  1679             builder->offset = 0;
       
  1680             builder->state = STATE_DATA_BODY;
       
  1681           } else {
       
  1682             builder->state = STATE_END;
       
  1683           }
       
  1684           break;
       
  1685         }
       
  1686 
       
  1687         /* we have a line */
       
  1688         if (builder->line == 0) {
       
  1689           /* first line, check for response status */
       
  1690           if (memcmp (builder->buffer, "RTSP", 4) == 0) {
       
  1691             res = parse_response_status (builder->buffer, message);
       
  1692           } else {
       
  1693             res = parse_request_line (conn, builder->buffer, message);
       
  1694           }
       
  1695           /* the first line must parse without errors */
       
  1696           if (res != GST_RTSP_OK)
       
  1697             goto done;
       
  1698         } else {
       
  1699           /* else just parse the line, ignore errors */
       
  1700           parse_line (conn, builder->buffer, message);
       
  1701         }
       
  1702         builder->line++;
       
  1703         builder->offset = 0;
       
  1704         break;
       
  1705       }
       
  1706       case STATE_END:
       
  1707       {
       
  1708         gchar *session_id;
       
  1709 
       
  1710         if (conn->tstate == TUNNEL_STATE_GET) {
       
  1711           res = GST_RTSP_ETGET;
       
  1712           goto done;
       
  1713         } else if (conn->tstate == TUNNEL_STATE_POST) {
       
  1714           res = GST_RTSP_ETPOST;
       
  1715           goto done;
       
  1716         }
       
  1717 
       
  1718         if (message->type == GST_RTSP_MESSAGE_DATA) {
       
  1719           /* data messages don't have headers */
       
  1720           res = GST_RTSP_OK;
       
  1721           goto done;
       
  1722         }
       
  1723 
       
  1724         /* save session id in the connection for further use */
       
  1725         if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
       
  1726             gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
       
  1727                 &session_id, 0) == GST_RTSP_OK) {
       
  1728           gint maxlen, i;
       
  1729 
       
  1730           maxlen = sizeof (conn->session_id) - 1;
       
  1731           /* the sessionid can have attributes marked with ;
       
  1732            * Make sure we strip them */
       
  1733           for (i = 0; session_id[i] != '\0'; i++) {
       
  1734             if (session_id[i] == ';') {
       
  1735               maxlen = i;
       
  1736               /* parse timeout */
       
  1737               do {
       
  1738                 i++;
       
  1739               } while (g_ascii_isspace (session_id[i]));
       
  1740               if (g_str_has_prefix (&session_id[i], "timeout=")) {
       
  1741                 gint to;
       
  1742 
       
  1743                 /* if we parsed something valid, configure */
       
  1744                 if ((to = atoi (&session_id[i + 8])) > 0)
       
  1745                   conn->timeout = to;
       
  1746               }
       
  1747               break;
       
  1748             }
       
  1749           }
       
  1750 
       
  1751           /* make sure to not overflow */
       
  1752           strncpy (conn->session_id, session_id, maxlen);
       
  1753           conn->session_id[maxlen] = '\0';
       
  1754         }
       
  1755         res = GST_RTSP_OK;
       
  1756         goto done;
       
  1757       }
       
  1758       default:
       
  1759         res = GST_RTSP_ERROR;
       
  1760         break;
       
  1761     }
       
  1762   }
       
  1763 done:
       
  1764   return res;
       
  1765 }
       
  1766 
       
  1767 /**
       
  1768  * gst_rtsp_connection_read:
   771  * @conn: a #GstRTSPConnection
  1769  * @conn: a #GstRTSPConnection
   772  * @data: the data to read
  1770  * @data: the data to read
   773  * @size: the size of @data
  1771  * @size: the size of @data
   774  * @timeout: a timeout value or #NULL
  1772  * @timeout: a timeout value or #NULL
   775  * @allow_interrupt: can the pending read be interrupted
       
   776  *
  1773  *
   777  * Attempt to read @size bytes into @data from the connected @conn, blocking up to
  1774  * Attempt to read @size bytes into @data from the connected @conn, blocking up to
   778  * the specified @timeout. @timeout can be #NULL, in which case this function
  1775  * the specified @timeout. @timeout can be #NULL, in which case this function
   779  * might block forever.
  1776  * might block forever.
   780  * 
  1777  *
   781  * This function can be cancelled with gst_rtsp_connection_flush() only if
  1778  * This function can be cancelled with gst_rtsp_connection_flush().
   782  * @allow_interrupt is set.
       
   783  *
  1779  *
   784  * Returns: #GST_RTSP_OK on success.
  1780  * Returns: #GST_RTSP_OK on success.
   785  */
  1781  */
   786 static GstRTSPResult
  1782 GstRTSPResult
   787 gst_rtsp_connection_read_internal (GstRTSPConnection * conn, guint8 * data,
  1783 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
   788     guint size, GTimeVal * timeout, gboolean allow_interrupt)
  1784     GTimeVal * timeout)
   789 {
  1785 {
   790   guint toread;
  1786   guint offset;
   791   gint retval;
  1787   gint retval;
   792   GstClockTime to;
  1788   GstClockTime to;
   793   FIONREAD_TYPE avail;
  1789   GstRTSPResult res;
   794 
  1790 
   795   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  1791   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
   796   g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
  1792   g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
   797 
  1793   g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
   798   if (size == 0)
  1794 
       
  1795   if (G_UNLIKELY (size == 0))
   799     return GST_RTSP_OK;
  1796     return GST_RTSP_OK;
   800 
  1797 
   801   toread = size;
  1798   offset = 0;
   802 
  1799 
   803   /* configure timeout if any */
  1800   /* configure timeout if any */
   804   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
  1801   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
   805 
  1802 
   806   /* if the call fails, just go in the select.. it should not fail. Else if
  1803   gst_poll_set_controllable (conn->fdset, TRUE);
   807    * there is enough data to read, skip the select call al together.*/
  1804   gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE);
   808   if (IOCTL_SOCKET (conn->fd.fd, FIONREAD, &avail) < 0)
  1805   gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE);
   809     avail = 0;
  1806 
   810   else if (avail >= toread)
  1807   while (TRUE) {
   811     goto do_read;
  1808     res = read_bytes (conn->readfd->fd, data, &offset, size, conn->ctxp);
   812 
  1809     if (G_UNLIKELY (res == GST_RTSP_EEOF))
   813   gst_poll_set_controllable (conn->fdset, allow_interrupt);
  1810       goto eof;
   814   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, FALSE);
  1811     if (G_LIKELY (res == GST_RTSP_OK))
   815   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, TRUE);
  1812       break;
   816 
  1813     if (G_UNLIKELY (res != GST_RTSP_EINTR))
   817   while (toread > 0) {
  1814       goto read_error;
   818     gint bytes;
       
   819 
  1815 
   820     do {
  1816     do {
   821       retval = gst_poll_wait (conn->fdset, to);
  1817       retval = gst_poll_wait (conn->fdset, to);
   822     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
  1818     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
   823 
  1819 
   824     if (retval == -1) {
  1820     /* check for timeout */
       
  1821     if (G_UNLIKELY (retval == 0))
       
  1822       goto select_timeout;
       
  1823 
       
  1824     if (G_UNLIKELY (retval == -1)) {
   825       if (errno == EBUSY)
  1825       if (errno == EBUSY)
   826         goto stopped;
  1826         goto stopped;
   827       else
  1827       else
   828         goto select_error;
  1828         goto select_error;
   829     }
  1829     }
   830 
  1830     gst_poll_set_controllable (conn->fdset, FALSE);
   831     /* check for timeout */
       
   832     if (retval == 0)
       
   833       goto select_timeout;
       
   834 
       
   835   do_read:
       
   836     /* if we get here there is activity on the real fd since the select
       
   837      * completed and the control socket was not readable. */
       
   838     bytes = READ_SOCKET (conn->fd.fd, data, toread);
       
   839     if (bytes == 0) {
       
   840       goto eof;
       
   841     } else if (bytes < 0) {
       
   842       if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
       
   843         goto read_error;
       
   844     } else {
       
   845       toread -= bytes;
       
   846       data += bytes;
       
   847     }
       
   848   }
  1831   }
   849   return GST_RTSP_OK;
  1832   return GST_RTSP_OK;
   850 
  1833 
   851   /* ERRORS */
  1834   /* ERRORS */
   852 select_error:
  1835 select_error:
   865   {
  1848   {
   866     return GST_RTSP_EEOF;
  1849     return GST_RTSP_EEOF;
   867   }
  1850   }
   868 read_error:
  1851 read_error:
   869   {
  1852   {
   870     return GST_RTSP_ESYS;
       
   871   }
       
   872 }
       
   873 
       
   874 /**
       
   875  * gst_rtsp_connection_read:
       
   876  * @conn: a #GstRTSPConnection
       
   877  * @data: the data to read
       
   878  * @size: the size of @data
       
   879  * @timeout: a timeout value or #NULL
       
   880  *
       
   881  * Attempt to read @size bytes into @data from the connected @conn, blocking up to
       
   882  * the specified @timeout. @timeout can be #NULL, in which case this function
       
   883  * might block forever.
       
   884  *
       
   885  * This function can be cancelled with gst_rtsp_connection_flush().
       
   886  *
       
   887  * Returns: #GST_RTSP_OK on success.
       
   888  */
       
   889 GstRTSPResult
       
   890 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
       
   891     GTimeVal * timeout)
       
   892 {
       
   893   return gst_rtsp_connection_read_internal (conn, data, size, timeout, TRUE);
       
   894 }
       
   895 
       
   896 
       
   897 static GstRTSPResult
       
   898 read_body (GstRTSPConnection * conn, glong content_length, GstRTSPMessage * msg,
       
   899     GTimeVal * timeout)
       
   900 {
       
   901   guint8 *body;
       
   902   GstRTSPResult res;
       
   903 
       
   904   if (content_length <= 0) {
       
   905     body = NULL;
       
   906     content_length = 0;
       
   907     goto done;
       
   908   }
       
   909 
       
   910   body = g_malloc (content_length + 1);
       
   911   body[content_length] = '\0';
       
   912 
       
   913   GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, body, content_length,
       
   914           timeout, FALSE), read_error);
       
   915 
       
   916   content_length += 1;
       
   917 
       
   918 done:
       
   919   gst_rtsp_message_take_body (msg, (guint8 *) body, content_length);
       
   920 
       
   921   return GST_RTSP_OK;
       
   922 
       
   923   /* ERRORS */
       
   924 read_error:
       
   925   {
       
   926     g_free (body);
       
   927     return res;
  1853     return res;
   928   }
  1854   }
       
  1855 }
       
  1856 
       
  1857 static GString *
       
  1858 gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code)
       
  1859 {
       
  1860   GString *str;
       
  1861   gchar date_string[100];
       
  1862   const gchar *status;
       
  1863 
       
  1864   gen_date_string (date_string, sizeof (date_string));
       
  1865 
       
  1866   status = gst_rtsp_status_as_text (code);
       
  1867   if (status == NULL) {
       
  1868     code = GST_RTSP_STS_INTERNAL_SERVER_ERROR;
       
  1869     status = "Internal Server Error";
       
  1870   }
       
  1871 
       
  1872   str = g_string_new ("");
       
  1873 
       
  1874   /* */
       
  1875   g_string_append_printf (str, "HTTP/1.0 %d %s\r\n", code, status);
       
  1876   g_string_append_printf (str,
       
  1877       "Server: GStreamer RTSP Server\r\n"
       
  1878       "Date: %s\r\n"
       
  1879       "Connection: close\r\n"
       
  1880       "Cache-Control: no-store\r\n" "Pragma: no-cache\r\n", date_string);
       
  1881   if (code == GST_RTSP_STS_OK) {
       
  1882     if (conn->ip)
       
  1883       g_string_append_printf (str, "x-server-ip-address: %s\r\n", conn->ip);
       
  1884     g_string_append_printf (str,
       
  1885         "Content-Type: application/x-rtsp-tunnelled\r\n");
       
  1886   }
       
  1887   g_string_append_printf (str, "\r\n");
       
  1888   return str;
   929 }
  1889 }
   930 
  1890 
   931 /**
  1891 /**
   932  * gst_rtsp_connection_receive:
  1892  * gst_rtsp_connection_receive:
   933  * @conn: a #GstRTSPConnection
  1893  * @conn: a #GstRTSPConnection
   944  */
  1904  */
   945 GstRTSPResult
  1905 GstRTSPResult
   946 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
  1906 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
   947     GTimeVal * timeout)
  1907     GTimeVal * timeout)
   948 {
  1908 {
   949   gchar buffer[4096];
       
   950   gint line;
       
   951   glong content_length;
       
   952   GstRTSPResult res;
  1909   GstRTSPResult res;
   953   gboolean need_body;
  1910   GstRTSPBuilder builder;
       
  1911   gint retval;
       
  1912   GstClockTime to;
   954 
  1913 
   955   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  1914   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
   956   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
  1915   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
   957 
  1916   g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
   958   line = 0;
  1917 
   959 
  1918   /* configure timeout if any */
   960   need_body = TRUE;
  1919   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
   961 
  1920 
   962   res = GST_RTSP_OK;
  1921   gst_poll_set_controllable (conn->fdset, TRUE);
   963   /* parse first line and headers */
  1922   gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE);
   964   while (res == GST_RTSP_OK) {
  1923   gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE);
   965     guint8 c;
  1924 
   966 
  1925   memset (&builder, 0, sizeof (GstRTSPBuilder));
   967     /* read first character, this identifies data messages */
  1926   while (TRUE) {
   968     /* This is the only read() that we allow to be interrupted */
  1927     res = build_next (&builder, message, conn);
   969     GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
  1928     if (G_UNLIKELY (res == GST_RTSP_EEOF))
   970             TRUE), read_error);
  1929       goto eof;
   971 
  1930     if (G_LIKELY (res == GST_RTSP_OK))
   972     /* check for data packet, first character is $ */
       
   973     if (c == '$') {
       
   974       guint16 size;
       
   975 
       
   976       /* data packets are $<1 byte channel><2 bytes length,BE><data bytes> */
       
   977 
       
   978       /* read channel, which is the next char */
       
   979       GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
       
   980               FALSE), read_error);
       
   981 
       
   982       /* now we create a data message */
       
   983       gst_rtsp_message_init_data (message, c);
       
   984 
       
   985       /* next two bytes are the length of the data */
       
   986       GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn,
       
   987               (guint8 *) & size, 2, timeout, FALSE), read_error);
       
   988 
       
   989       size = GUINT16_FROM_BE (size);
       
   990 
       
   991       /* and read the body */
       
   992       res = read_body (conn, size, message, timeout);
       
   993       need_body = FALSE;
       
   994       break;
  1931       break;
   995     } else {
  1932     if (res == GST_RTSP_ETGET) {
   996       gint offset = 0;
  1933       GString *str;
   997 
  1934 
   998       /* we have a regular response */
  1935       /* tunnel GET request, we can reply now */
   999       if (c != '\r') {
  1936       str = gen_tunnel_reply (conn, GST_RTSP_STS_OK);
  1000         buffer[0] = c;
  1937       res =
  1001         offset = 1;
  1938           gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len,
  1002       }
  1939           timeout);
  1003       /* should not happen */
  1940       g_string_free (str, TRUE);
  1004       if (c == '\n')
  1941     } else if (res == GST_RTSP_ETPOST) {
  1005         break;
  1942       /* tunnel POST request, return the value, the caller now has to link the
  1006 
  1943        * two connections. */
  1007       /* read lines */
  1944       break;
  1008       GST_RTSP_CHECK (read_line (conn->fd.fd, buffer + offset,
  1945     } else if (G_UNLIKELY (res != GST_RTSP_EINTR))
  1009               sizeof (buffer) - offset), read_error);
  1946       goto read_error;
  1010 
  1947 
  1011       if (buffer[0] == '\0')
  1948     do {
  1012         break;
  1949       retval = gst_poll_wait (conn->fdset, to);
  1013 
  1950     } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
  1014       if (line == 0) {
  1951 
  1015         /* first line, check for response status */
  1952     /* check for timeout */
  1016         if (g_str_has_prefix (buffer, "RTSP")) {
  1953     if (G_UNLIKELY (retval == 0))
  1017           res = parse_response_status (buffer, message);
  1954       goto select_timeout;
  1018         } else {
  1955 
  1019           res = parse_request_line (buffer, message);
  1956     if (G_UNLIKELY (retval == -1)) {
  1020         }
  1957       if (errno == EBUSY)
  1021       } else {
  1958         goto stopped;
  1022         /* else just parse the line */
  1959       else
  1023         parse_line (buffer, message);
  1960         goto select_error;
  1024       }
       
  1025     }
  1961     }
  1026     line++;
  1962     gst_poll_set_controllable (conn->fdset, FALSE);
  1027   }
  1963   }
  1028 
  1964 
  1029   /* read the rest of the body if needed */
  1965   /* we have a message here */
  1030   if (need_body) {
  1966   build_reset (&builder);
  1031     gchar *session_id;
  1967 
  1032     gchar *hdrval;
  1968   return GST_RTSP_OK;
  1033 
  1969 
  1034     /* see if there is a Content-Length header */
  1970   /* ERRORS */
  1035     if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_CONTENT_LENGTH,
  1971 select_error:
  1036             &hdrval, 0) == GST_RTSP_OK) {
  1972   {
  1037       /* there is, read the body */
  1973     res = GST_RTSP_ESYS;
  1038       content_length = atol (hdrval);
  1974     goto cleanup;
  1039       GST_RTSP_CHECK (read_body (conn, content_length, message, timeout),
  1975   }
  1040           read_error);
  1976 select_timeout:
  1041     }
  1977   {
  1042 
  1978     res = GST_RTSP_ETIMEOUT;
  1043     /* save session id in the connection for further use */
  1979     goto cleanup;
  1044     if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
  1980   }
  1045             &session_id, 0) == GST_RTSP_OK) {
  1981 stopped:
  1046       gint maxlen, i;
  1982   {
  1047 
  1983     res = GST_RTSP_EINTR;
  1048       /* default session timeout */
  1984     goto cleanup;
  1049       conn->timeout = 60;
  1985   }
  1050 
  1986 eof:
  1051       maxlen = sizeof (conn->session_id) - 1;
  1987   {
  1052       /* the sessionid can have attributes marked with ;
  1988     res = GST_RTSP_EEOF;
  1053        * Make sure we strip them */
  1989     goto cleanup;
  1054       for (i = 0; session_id[i] != '\0'; i++) {
  1990   }
  1055         if (session_id[i] == ';') {
       
  1056           maxlen = i;
       
  1057           /* parse timeout */
       
  1058           do {
       
  1059             i++;
       
  1060           } while (g_ascii_isspace (session_id[i]));
       
  1061           if (g_str_has_prefix (&session_id[i], "timeout=")) {
       
  1062             gint to;
       
  1063 
       
  1064             /* if we parsed something valid, configure */
       
  1065             if ((to = atoi (&session_id[i + 9])) > 0)
       
  1066               conn->timeout = to;
       
  1067           }
       
  1068           break;
       
  1069         }
       
  1070       }
       
  1071 
       
  1072       /* make sure to not overflow */
       
  1073       strncpy (conn->session_id, session_id, maxlen);
       
  1074       conn->session_id[maxlen] = '\0';
       
  1075     }
       
  1076   }
       
  1077   return res;
       
  1078 
       
  1079 read_error:
  1991 read_error:
  1080   {
  1992 cleanup:
       
  1993   {
       
  1994     build_reset (&builder);
       
  1995     gst_rtsp_message_unset (message);
  1081     return res;
  1996     return res;
  1082   }
  1997   }
  1083 }
  1998 }
  1084 
  1999 
  1085 /**
  2000 /**
  1086  * gst_rtsp_connection_close:
  2001  * gst_rtsp_connection_close:
  1087  * @conn: a #GstRTSPConnection
  2002  * @conn: a #GstRTSPConnection
  1088  *
  2003  *
  1089  * Close the connected @conn.
  2004  * Close the connected @conn. After this call, the connection is in the same
       
  2005  * state as when it was first created.
  1090  * 
  2006  * 
  1091  * Returns: #GST_RTSP_OK on success.
  2007  * Returns: #GST_RTSP_OK on success.
  1092  */
  2008  */
  1093 GstRTSPResult
  2009 GstRTSPResult
  1094 gst_rtsp_connection_close (GstRTSPConnection * conn)
  2010 gst_rtsp_connection_close (GstRTSPConnection * conn)
  1095 {
  2011 {
  1096   gint res;
       
  1097 
       
  1098   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  2012   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  1099 
  2013 
  1100   g_free (conn->ip);
  2014   g_free (conn->ip);
  1101   conn->ip = NULL;
  2015   conn->ip = NULL;
  1102 
  2016 
  1103   if (conn->fd.fd != -1) {
  2017   REMOVE_POLLFD (conn->fdset, &conn->fd0);
  1104     gst_poll_remove_fd (conn->fdset, &conn->fd);
  2018   REMOVE_POLLFD (conn->fdset, &conn->fd1);
  1105     res = CLOSE_SOCKET (conn->fd.fd);
  2019   conn->writefd = NULL;
  1106     conn->fd.fd = -1;
  2020   conn->readfd = NULL;
  1107 #ifdef G_OS_WIN32
  2021   conn->tunneled = FALSE;
  1108     WSACleanup ();
  2022   conn->tstate = TUNNEL_STATE_NONE;
  1109 #endif
  2023   conn->ctxp = NULL;
  1110     if (res != 0)
  2024   g_free (conn->username);
  1111       goto sys_error;
  2025   conn->username = NULL;
  1112   }
  2026   g_free (conn->passwd);
       
  2027   conn->passwd = NULL;
       
  2028   gst_rtsp_connection_clear_auth_params (conn);
       
  2029   conn->timeout = 60;
       
  2030   conn->cseq = 0;
       
  2031   conn->session_id[0] = '\0';
  1113 
  2032 
  1114   return GST_RTSP_OK;
  2033   return GST_RTSP_OK;
  1115 
       
  1116 sys_error:
       
  1117   {
       
  1118     return GST_RTSP_ESYS;
       
  1119   }
       
  1120 }
  2034 }
  1121 
  2035 
  1122 /**
  2036 /**
  1123  * gst_rtsp_connection_free:
  2037  * gst_rtsp_connection_free:
  1124  * @conn: a #GstRTSPConnection
  2038  * @conn: a #GstRTSPConnection
  1134 
  2048 
  1135   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  2049   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  1136 
  2050 
  1137   res = gst_rtsp_connection_close (conn);
  2051   res = gst_rtsp_connection_close (conn);
  1138   gst_poll_free (conn->fdset);
  2052   gst_poll_free (conn->fdset);
       
  2053   g_timer_destroy (conn->timer);
       
  2054   gst_rtsp_url_free (conn->url);
       
  2055   g_free (conn->proxy_host);
       
  2056   g_free (conn);
  1139 #ifdef G_OS_WIN32
  2057 #ifdef G_OS_WIN32
  1140   WSACleanup ();
  2058   WSACleanup ();
  1141 #endif
  2059 #endif
  1142   g_timer_destroy (conn->timer);
       
  1143   g_free (conn->username);
       
  1144   g_free (conn->passwd);
       
  1145   g_free (conn);
       
  1146 
  2060 
  1147   return res;
  2061   return res;
  1148 }
  2062 }
  1149 
  2063 
  1150 /**
  2064 /**
  1175   gint retval;
  2089   gint retval;
  1176 
  2090 
  1177   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  2091   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  1178   g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
  2092   g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
  1179   g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
  2093   g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
       
  2094   g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
       
  2095   g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
  1180 
  2096 
  1181   gst_poll_set_controllable (conn->fdset, TRUE);
  2097   gst_poll_set_controllable (conn->fdset, TRUE);
  1182 
  2098 
  1183   /* add fd to writer set when asked to */
  2099   /* add fd to writer set when asked to */
  1184   gst_poll_fd_ctl_write (conn->fdset, &conn->fd, events & GST_RTSP_EV_WRITE);
  2100   gst_poll_fd_ctl_write (conn->fdset, conn->writefd,
       
  2101       events & GST_RTSP_EV_WRITE);
  1185 
  2102 
  1186   /* add fd to reader set when asked to */
  2103   /* add fd to reader set when asked to */
  1187   gst_poll_fd_ctl_read (conn->fdset, &conn->fd, events & GST_RTSP_EV_READ);
  2104   gst_poll_fd_ctl_read (conn->fdset, conn->readfd, events & GST_RTSP_EV_READ);
  1188 
  2105 
  1189   /* configure timeout if any */
  2106   /* configure timeout if any */
  1190   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
  2107   to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
  1191 
  2108 
  1192   do {
  2109   do {
  1193     retval = gst_poll_wait (conn->fdset, to);
  2110     retval = gst_poll_wait (conn->fdset, to);
  1194   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
  2111   } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
  1195 
  2112 
  1196   if (retval == 0)
  2113   if (G_UNLIKELY (retval == 0))
  1197     goto select_timeout;
  2114     goto select_timeout;
  1198 
  2115 
  1199   if (retval == -1) {
  2116   if (G_UNLIKELY (retval == -1)) {
  1200     if (errno == EBUSY)
  2117     if (errno == EBUSY)
  1201       goto stopped;
  2118       goto stopped;
  1202     else
  2119     else
  1203       goto select_error;
  2120       goto select_error;
  1204   }
  2121   }
  1205 
  2122 
  1206   *revents = 0;
  2123   *revents = 0;
  1207   if (events & GST_RTSP_EV_READ) {
  2124   if (events & GST_RTSP_EV_READ) {
  1208     if (gst_poll_fd_can_read (conn->fdset, &conn->fd))
  2125     if (gst_poll_fd_can_read (conn->fdset, conn->readfd))
  1209       *revents |= GST_RTSP_EV_READ;
  2126       *revents |= GST_RTSP_EV_READ;
  1210   }
  2127   }
  1211   if (events & GST_RTSP_EV_WRITE) {
  2128   if (events & GST_RTSP_EV_WRITE) {
  1212     if (gst_poll_fd_can_write (conn->fdset, &conn->fd))
  2129     if (gst_poll_fd_can_write (conn->fdset, conn->writefd))
  1213       *revents |= GST_RTSP_EV_WRITE;
  2130       *revents |= GST_RTSP_EV_WRITE;
  1214   }
  2131   }
  1215   return GST_RTSP_OK;
  2132   return GST_RTSP_OK;
  1216 
  2133 
  1217   /* ERRORS */
  2134   /* ERRORS */
  1300 
  2217 
  1301   return GST_RTSP_OK;
  2218   return GST_RTSP_OK;
  1302 }
  2219 }
  1303 
  2220 
  1304 /**
  2221 /**
       
  2222  * gst_rtsp_connection_set_proxy:
       
  2223  * @conn: a #GstRTSPConnection
       
  2224  * @host: the proxy host
       
  2225  * @port: the proxy port
       
  2226  *
       
  2227  * Set the proxy host and port.
       
  2228  * 
       
  2229  * Returns: #GST_RTSP_OK.
       
  2230  *
       
  2231  * Since: 0.10.23
       
  2232  */
       
  2233 GstRTSPResult
       
  2234 gst_rtsp_connection_set_proxy (GstRTSPConnection * conn,
       
  2235     const gchar * host, guint port)
       
  2236 {
       
  2237   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
       
  2238 
       
  2239   g_free (conn->proxy_host);
       
  2240   conn->proxy_host = g_strdup (host);
       
  2241   conn->proxy_port = port;
       
  2242 
       
  2243   return GST_RTSP_OK;
       
  2244 }
       
  2245 
       
  2246 /**
  1305  * gst_rtsp_connection_set_auth:
  2247  * gst_rtsp_connection_set_auth:
  1306  * @conn: a #GstRTSPConnection
  2248  * @conn: a #GstRTSPConnection
  1307  * @method: authentication method
  2249  * @method: authentication method
  1308  * @user: the user
  2250  * @user: the user
  1309  * @pass: the password
  2251  * @pass: the password
  1315  */
  2257  */
  1316 GstRTSPResult
  2258 GstRTSPResult
  1317 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
  2259 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
  1318     GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
  2260     GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
  1319 {
  2261 {
  1320   /* Digest isn't implemented yet */
  2262   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
  1321   if (method == GST_RTSP_AUTH_DIGEST)
  2263 
  1322     return GST_RTSP_ENOTIMPL;
  2264   if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
       
  2265           || g_strrstr (user, ":") != NULL))
       
  2266     return GST_RTSP_EINVAL;
  1323 
  2267 
  1324   /* Make sure the username and passwd are being set for authentication */
  2268   /* Make sure the username and passwd are being set for authentication */
  1325   if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
  2269   if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
  1326     return GST_RTSP_EINVAL;
  2270     return GST_RTSP_EINVAL;
  1327 
  2271 
  1336   conn->username = g_strdup (user);
  2280   conn->username = g_strdup (user);
  1337   conn->passwd = g_strdup (pass);
  2281   conn->passwd = g_strdup (pass);
  1338 
  2282 
  1339   return GST_RTSP_OK;
  2283   return GST_RTSP_OK;
  1340 }
  2284 }
       
  2285 
       
  2286 /**
       
  2287  * str_case_hash:
       
  2288  * @key: ASCII string to hash
       
  2289  *
       
  2290  * Hashes @key in a case-insensitive manner.
       
  2291  *
       
  2292  * Returns: the hash code.
       
  2293  **/
       
  2294 static guint
       
  2295 str_case_hash (gconstpointer key)
       
  2296 {
       
  2297   const char *p = key;
       
  2298   guint h = g_ascii_toupper (*p);
       
  2299 
       
  2300   if (h)
       
  2301     for (p += 1; *p != '\0'; p++)
       
  2302       h = (h << 5) - h + g_ascii_toupper (*p);
       
  2303 
       
  2304   return h;
       
  2305 }
       
  2306 
       
  2307 /**
       
  2308  * str_case_equal:
       
  2309  * @v1: an ASCII string
       
  2310  * @v2: another ASCII string
       
  2311  *
       
  2312  * Compares @v1 and @v2 in a case-insensitive manner
       
  2313  *
       
  2314  * Returns: %TRUE if they are equal (modulo case)
       
  2315  **/
       
  2316 static gboolean
       
  2317 str_case_equal (gconstpointer v1, gconstpointer v2)
       
  2318 {
       
  2319   const char *string1 = v1;
       
  2320   const char *string2 = v2;
       
  2321 
       
  2322   return g_ascii_strcasecmp (string1, string2) == 0;
       
  2323 }
       
  2324 
       
  2325 /**
       
  2326  * gst_rtsp_connection_set_auth_param:
       
  2327  * @conn: a #GstRTSPConnection
       
  2328  * @param: authentication directive
       
  2329  * @value: value
       
  2330  *
       
  2331  * Setup @conn with authentication directives. This is not necesary for
       
  2332  * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
       
  2333  * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
       
  2334  * in the WWW-Authenticate response header and can include realm, domain,
       
  2335  * nonce, opaque, stale, algorithm, qop as per RFC2617.
       
  2336  * 
       
  2337  * Since: 0.10.20
       
  2338  */
       
  2339 void
       
  2340 gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
       
  2341     const gchar * param, const gchar * value)
       
  2342 {
       
  2343   g_return_if_fail (conn != NULL);
       
  2344   g_return_if_fail (param != NULL);
       
  2345 
       
  2346   if (conn->auth_params == NULL) {
       
  2347     conn->auth_params =
       
  2348         g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
       
  2349   }
       
  2350   g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
       
  2351 }
       
  2352 
       
  2353 /**
       
  2354  * gst_rtsp_connection_clear_auth_params:
       
  2355  * @conn: a #GstRTSPConnection
       
  2356  *
       
  2357  * Clear the list of authentication directives stored in @conn.
       
  2358  *
       
  2359  * Since: 0.10.20
       
  2360  */
       
  2361 void
       
  2362 gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
       
  2363 {
       
  2364   g_return_if_fail (conn != NULL);
       
  2365 
       
  2366   if (conn->auth_params != NULL) {
       
  2367     g_hash_table_destroy (conn->auth_params);
       
  2368     conn->auth_params = NULL;
       
  2369   }
       
  2370 }
       
  2371 
       
  2372 static GstRTSPResult
       
  2373 set_qos_dscp (gint fd, guint qos_dscp)
       
  2374 {
       
  2375   union gst_sockaddr sa;
       
  2376   socklen_t slen = sizeof (sa);
       
  2377   gint af;
       
  2378   gint tos;
       
  2379 
       
  2380   if (fd == -1)
       
  2381     return GST_RTSP_OK;
       
  2382 
       
  2383   if (getsockname (fd, &sa.sa, &slen) < 0)
       
  2384     goto no_getsockname;
       
  2385 
       
  2386   af = sa.sa.sa_family;
       
  2387 
       
  2388   /* if this is an IPv4-mapped address then do IPv4 QoS */
       
  2389   if (af == AF_INET6) {
       
  2390     if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr))
       
  2391       af = AF_INET;
       
  2392   }
       
  2393 
       
  2394   /* extract and shift 6 bits of the DSCP */
       
  2395   tos = (qos_dscp & 0x3f) << 2;
       
  2396 
       
  2397   switch (af) {
       
  2398     case AF_INET:
       
  2399       if (SETSOCKOPT (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
       
  2400         goto no_setsockopt;
       
  2401       break;
       
  2402     case AF_INET6:
       
  2403 #ifdef IPV6_TCLASS
       
  2404       if (SETSOCKOPT (fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos)) < 0)
       
  2405         goto no_setsockopt;
       
  2406       break;
       
  2407 #endif
       
  2408     default:
       
  2409       goto wrong_family;
       
  2410   }
       
  2411 
       
  2412   return GST_RTSP_OK;
       
  2413 
       
  2414   /* ERRORS */
       
  2415 no_getsockname:
       
  2416 no_setsockopt:
       
  2417   {
       
  2418     return GST_RTSP_ESYS;
       
  2419   }
       
  2420 
       
  2421 wrong_family:
       
  2422   {
       
  2423     return GST_RTSP_ERROR;
       
  2424   }
       
  2425 }
       
  2426 
       
  2427 /**
       
  2428  * gst_rtsp_connection_set_qos_dscp:
       
  2429  * @conn: a #GstRTSPConnection
       
  2430  * @qos_dscp: DSCP value
       
  2431  *
       
  2432  * Configure @conn to use the specified DSCP value.
       
  2433  *
       
  2434  * Returns: #GST_RTSP_OK on success.
       
  2435  *
       
  2436  * Since: 0.10.20
       
  2437  */
       
  2438 GstRTSPResult
       
  2439 gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
       
  2440 {
       
  2441   GstRTSPResult res;
       
  2442 
       
  2443   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
       
  2444   g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
       
  2445   g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
       
  2446 
       
  2447   res = set_qos_dscp (conn->fd0.fd, qos_dscp);
       
  2448   if (res == GST_RTSP_OK)
       
  2449     res = set_qos_dscp (conn->fd1.fd, qos_dscp);
       
  2450 
       
  2451   return res;
       
  2452 }
       
  2453 
       
  2454 
       
  2455 /**
       
  2456  * gst_rtsp_connection_get_url:
       
  2457  * @conn: a #GstRTSPConnection
       
  2458  *
       
  2459  * Retrieve the URL of the other end of @conn.
       
  2460  *
       
  2461  * Returns: The URL. This value remains valid until the
       
  2462  * connection is freed.
       
  2463  *
       
  2464  * Since: 0.10.23
       
  2465  */
       
  2466 GstRTSPUrl *
       
  2467 gst_rtsp_connection_get_url (const GstRTSPConnection * conn)
       
  2468 {
       
  2469   g_return_val_if_fail (conn != NULL, NULL);
       
  2470 
       
  2471   return conn->url;
       
  2472 }
       
  2473 
       
  2474 /**
       
  2475  * gst_rtsp_connection_get_ip:
       
  2476  * @conn: a #GstRTSPConnection
       
  2477  *
       
  2478  * Retrieve the IP address of the other end of @conn.
       
  2479  *
       
  2480  * Returns: The IP address as a string. this value remains valid until the
       
  2481  * connection is closed.
       
  2482  *
       
  2483  * Since: 0.10.20
       
  2484  */
       
  2485 const gchar *
       
  2486 gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
       
  2487 {
       
  2488   g_return_val_if_fail (conn != NULL, NULL);
       
  2489 
       
  2490   return conn->ip;
       
  2491 }
       
  2492 
       
  2493 /**
       
  2494  * gst_rtsp_connection_set_ip:
       
  2495  * @conn: a #GstRTSPConnection
       
  2496  * @ip: an ip address
       
  2497  *
       
  2498  * Set the IP address of the server.
       
  2499  *
       
  2500  * Since: 0.10.23
       
  2501  */
       
  2502 void
       
  2503 gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip)
       
  2504 {
       
  2505   g_return_if_fail (conn != NULL);
       
  2506 
       
  2507   g_free (conn->ip);
       
  2508   conn->ip = g_strdup (ip);
       
  2509 }
       
  2510 
       
  2511 /**
       
  2512  * gst_rtsp_connection_get_readfd:
       
  2513  * @conn: a #GstRTSPConnection
       
  2514  *
       
  2515  * Get the file descriptor for reading.
       
  2516  *
       
  2517  * Returns: the file descriptor used for reading or -1 on error. The file
       
  2518  * descriptor remains valid until the connection is closed.
       
  2519  *
       
  2520  * Since: 0.10.23
       
  2521  */
       
  2522 gint
       
  2523 gst_rtsp_connection_get_readfd (const GstRTSPConnection * conn)
       
  2524 {
       
  2525   g_return_val_if_fail (conn != NULL, -1);
       
  2526   g_return_val_if_fail (conn->readfd != NULL, -1);
       
  2527 
       
  2528   return conn->readfd->fd;
       
  2529 }
       
  2530 
       
  2531 /**
       
  2532  * gst_rtsp_connection_get_writefd:
       
  2533  * @conn: a #GstRTSPConnection
       
  2534  *
       
  2535  * Get the file descriptor for writing.
       
  2536  *
       
  2537  * Returns: the file descriptor used for writing or -1 on error. The file
       
  2538  * descriptor remains valid until the connection is closed.
       
  2539  *
       
  2540  * Since: 0.10.23
       
  2541  */
       
  2542 gint
       
  2543 gst_rtsp_connection_get_writefd (const GstRTSPConnection * conn)
       
  2544 {
       
  2545   g_return_val_if_fail (conn != NULL, -1);
       
  2546   g_return_val_if_fail (conn->writefd != NULL, -1);
       
  2547 
       
  2548   return conn->writefd->fd;
       
  2549 }
       
  2550 
       
  2551 
       
  2552 /**
       
  2553  * gst_rtsp_connection_set_tunneled:
       
  2554  * @conn: a #GstRTSPConnection
       
  2555  * @tunneled: the new state
       
  2556  *
       
  2557  * Set the HTTP tunneling state of the connection. This must be configured before
       
  2558  * the @conn is connected.
       
  2559  *
       
  2560  * Since: 0.10.23
       
  2561  */
       
  2562 void
       
  2563 gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
       
  2564 {
       
  2565   g_return_if_fail (conn != NULL);
       
  2566   g_return_if_fail (conn->readfd == NULL);
       
  2567   g_return_if_fail (conn->writefd == NULL);
       
  2568 
       
  2569   conn->tunneled = tunneled;
       
  2570 }
       
  2571 
       
  2572 /**
       
  2573  * gst_rtsp_connection_is_tunneled:
       
  2574  * @conn: a #GstRTSPConnection
       
  2575  *
       
  2576  * Get the tunneling state of the connection. 
       
  2577  *
       
  2578  * Returns: if @conn is using HTTP tunneling.
       
  2579  *
       
  2580  * Since: 0.10.23
       
  2581  */
       
  2582 gboolean
       
  2583 gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn)
       
  2584 {
       
  2585   g_return_val_if_fail (conn != NULL, FALSE);
       
  2586 
       
  2587   return conn->tunneled;
       
  2588 }
       
  2589 
       
  2590 /**
       
  2591  * gst_rtsp_connection_get_tunnelid:
       
  2592  * @conn: a #GstRTSPConnection
       
  2593  *
       
  2594  * Get the tunnel session id the connection. 
       
  2595  *
       
  2596  * Returns: returns a non-empty string if @conn is being tunneled over HTTP.
       
  2597  *
       
  2598  * Since: 0.10.23
       
  2599  */
       
  2600 const gchar *
       
  2601 gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn)
       
  2602 {
       
  2603   g_return_val_if_fail (conn != NULL, NULL);
       
  2604 
       
  2605   if (!conn->tunneled)
       
  2606     return NULL;
       
  2607 
       
  2608   return conn->tunnelid;
       
  2609 }
       
  2610 
       
  2611 /**
       
  2612  * gst_rtsp_connection_do_tunnel:
       
  2613  * @conn: a #GstRTSPConnection
       
  2614  * @conn2: a #GstRTSPConnection
       
  2615  *
       
  2616  * If @conn received the first tunnel connection and @conn2 received
       
  2617  * the second tunnel connection, link the two connections together so that
       
  2618  * @conn manages the tunneled connection.
       
  2619  *
       
  2620  * After this call, @conn2 cannot be used anymore and must be freed with
       
  2621  * gst_rtsp_connection_free().
       
  2622  *
       
  2623  * Returns: return GST_RTSP_OK on success.
       
  2624  *
       
  2625  * Since: 0.10.23
       
  2626  */
       
  2627 GstRTSPResult
       
  2628 gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn,
       
  2629     GstRTSPConnection * conn2)
       
  2630 {
       
  2631   g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
       
  2632   g_return_val_if_fail (conn2 != NULL, GST_RTSP_EINVAL);
       
  2633   g_return_val_if_fail (conn->tstate == TUNNEL_STATE_GET, GST_RTSP_EINVAL);
       
  2634   g_return_val_if_fail (conn2->tstate == TUNNEL_STATE_POST, GST_RTSP_EINVAL);
       
  2635   g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid, TUNNELID_LEN),
       
  2636       GST_RTSP_EINVAL);
       
  2637 
       
  2638   /* both connections have fd0 as the read/write socket. start by taking the
       
  2639    * socket from conn2 and set it as the socket in conn */
       
  2640   conn->fd1 = conn2->fd0;
       
  2641 
       
  2642   /* clean up some of the state of conn2 */
       
  2643   gst_poll_remove_fd (conn2->fdset, &conn2->fd0);
       
  2644   conn2->fd0.fd = -1;
       
  2645   conn2->readfd = conn2->writefd = NULL;
       
  2646 
       
  2647   /* We make fd0 the write socket and fd1 the read socket. */
       
  2648   conn->writefd = &conn->fd0;
       
  2649   conn->readfd = &conn->fd1;
       
  2650 
       
  2651   conn->tstate = TUNNEL_STATE_COMPLETE;
       
  2652 
       
  2653   /* we need base64 decoding for the readfd */
       
  2654   conn->ctx.state = 0;
       
  2655   conn->ctx.save = 0;
       
  2656   conn->ctx.cout = 0;
       
  2657   conn->ctx.coutl = 0;
       
  2658   conn->ctxp = &conn->ctx;
       
  2659 
       
  2660   return GST_RTSP_OK;
       
  2661 }
       
  2662 
       
  2663 #define READ_COND   (G_IO_IN | G_IO_HUP | G_IO_ERR)
       
  2664 #define WRITE_COND  (G_IO_OUT | G_IO_ERR)
       
  2665 
       
  2666 typedef struct
       
  2667 {
       
  2668   guint8 *data;
       
  2669   guint size;
       
  2670   guint id;
       
  2671 } GstRTSPRec;
       
  2672 
       
  2673 /* async functions */
       
  2674 struct _GstRTSPWatch
       
  2675 {
       
  2676   GSource source;
       
  2677 
       
  2678   GstRTSPConnection *conn;
       
  2679 
       
  2680   GstRTSPBuilder builder;
       
  2681   GstRTSPMessage message;
       
  2682 
       
  2683   GPollFD readfd;
       
  2684   GPollFD writefd;
       
  2685   gboolean write_added;
       
  2686 
       
  2687   /* queued message for transmission */
       
  2688   guint id;
       
  2689   GAsyncQueue *messages;
       
  2690   guint8 *write_data;
       
  2691   guint write_off;
       
  2692   guint write_size;
       
  2693   guint write_id;
       
  2694 
       
  2695   GstRTSPWatchFuncs funcs;
       
  2696 
       
  2697   gpointer user_data;
       
  2698   GDestroyNotify notify;
       
  2699 };
       
  2700 
       
  2701 static gboolean
       
  2702 gst_rtsp_source_prepare (GSource * source, gint * timeout)
       
  2703 {
       
  2704   GstRTSPWatch *watch = (GstRTSPWatch *) source;
       
  2705 
       
  2706   *timeout = (watch->conn->timeout * 1000);
       
  2707 
       
  2708   return FALSE;
       
  2709 }
       
  2710 
       
  2711 static gboolean
       
  2712 gst_rtsp_source_check (GSource * source)
       
  2713 {
       
  2714   GstRTSPWatch *watch = (GstRTSPWatch *) source;
       
  2715 
       
  2716   if (watch->readfd.revents & READ_COND)
       
  2717     return TRUE;
       
  2718 
       
  2719   if (watch->writefd.revents & WRITE_COND)
       
  2720     return TRUE;
       
  2721 
       
  2722   return FALSE;
       
  2723 }
       
  2724 
       
  2725 static gboolean
       
  2726 gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED,
       
  2727     gpointer user_data G_GNUC_UNUSED)
       
  2728 {
       
  2729   GstRTSPWatch *watch = (GstRTSPWatch *) source;
       
  2730   GstRTSPResult res;
       
  2731 
       
  2732   /* first read as much as we can */
       
  2733   if (watch->readfd.revents & READ_COND) {
       
  2734     do {
       
  2735       res = build_next (&watch->builder, &watch->message, watch->conn);
       
  2736       if (res == GST_RTSP_EINTR)
       
  2737         break;
       
  2738       if (G_UNLIKELY (res == GST_RTSP_EEOF))
       
  2739         goto eof;
       
  2740       if (res == GST_RTSP_ETGET) {
       
  2741         GString *str;
       
  2742         GstRTSPStatusCode code;
       
  2743         guint size;
       
  2744 
       
  2745         if (watch->funcs.tunnel_start)
       
  2746           code = watch->funcs.tunnel_start (watch, watch->user_data);
       
  2747         else
       
  2748           code = GST_RTSP_STS_OK;
       
  2749 
       
  2750         /* queue the response string */
       
  2751         str = gen_tunnel_reply (watch->conn, code);
       
  2752         size = str->len;
       
  2753         gst_rtsp_watch_queue_data (watch, (guint8 *) g_string_free (str, FALSE),
       
  2754             size);
       
  2755       } else if (res == GST_RTSP_ETPOST) {
       
  2756         /* in the callback the connection should be tunneled with the
       
  2757          * GET connection */
       
  2758         if (watch->funcs.tunnel_complete)
       
  2759           watch->funcs.tunnel_complete (watch, watch->user_data);
       
  2760       } else if (G_UNLIKELY (res != GST_RTSP_OK))
       
  2761         goto error;
       
  2762 
       
  2763       if (G_LIKELY (res == GST_RTSP_OK)) {
       
  2764         if (watch->funcs.message_received)
       
  2765           watch->funcs.message_received (watch, &watch->message,
       
  2766               watch->user_data);
       
  2767 
       
  2768         gst_rtsp_message_unset (&watch->message);
       
  2769       }
       
  2770       build_reset (&watch->builder);
       
  2771     } while (FALSE);
       
  2772   }
       
  2773 
       
  2774   if (watch->writefd.revents & WRITE_COND) {
       
  2775     do {
       
  2776       if (watch->write_data == NULL) {
       
  2777         GstRTSPRec *rec;
       
  2778 
       
  2779         /* get a new message from the queue */
       
  2780         rec = g_async_queue_try_pop (watch->messages);
       
  2781         if (rec == NULL)
       
  2782           goto done;
       
  2783 
       
  2784         watch->write_off = 0;
       
  2785         watch->write_data = rec->data;
       
  2786         watch->write_size = rec->size;
       
  2787         watch->write_id = rec->id;
       
  2788 
       
  2789         g_slice_free (GstRTSPRec, rec);
       
  2790       }
       
  2791 
       
  2792       res = write_bytes (watch->writefd.fd, watch->write_data,
       
  2793           &watch->write_off, watch->write_size);
       
  2794       if (res == GST_RTSP_EINTR)
       
  2795         break;
       
  2796       if (G_UNLIKELY (res != GST_RTSP_OK))
       
  2797         goto error;
       
  2798 
       
  2799       if (watch->funcs.message_sent)
       
  2800         watch->funcs.message_sent (watch, watch->write_id, watch->user_data);
       
  2801 
       
  2802     done:
       
  2803       if (g_async_queue_length (watch->messages) == 0 && watch->write_added) {
       
  2804         g_source_remove_poll ((GSource *) watch, &watch->writefd);
       
  2805         watch->write_added = FALSE;
       
  2806         watch->writefd.revents = 0;
       
  2807       }
       
  2808       g_free (watch->write_data);
       
  2809       watch->write_data = NULL;
       
  2810     } while (FALSE);
       
  2811   }
       
  2812 
       
  2813   return TRUE;
       
  2814 
       
  2815   /* ERRORS */
       
  2816 eof:
       
  2817   {
       
  2818     if (watch->funcs.closed)
       
  2819       watch->funcs.closed (watch, watch->user_data);
       
  2820     return FALSE;
       
  2821   }
       
  2822 error:
       
  2823   {
       
  2824     if (watch->funcs.error)
       
  2825       watch->funcs.error (watch, res, watch->user_data);
       
  2826     return FALSE;
       
  2827   }
       
  2828 }
       
  2829 
       
  2830 static void
       
  2831 gst_rtsp_rec_free (gpointer data)
       
  2832 {
       
  2833   GstRTSPRec *rec = data;
       
  2834 
       
  2835   g_free (rec->data);
       
  2836   g_slice_free (GstRTSPRec, rec);
       
  2837 }
       
  2838 
       
  2839 static void
       
  2840 gst_rtsp_source_finalize (GSource * source)
       
  2841 {
       
  2842   GstRTSPWatch *watch = (GstRTSPWatch *) source;
       
  2843 
       
  2844   build_reset (&watch->builder);
       
  2845   gst_rtsp_message_unset (&watch->message);
       
  2846 
       
  2847   g_async_queue_unref (watch->messages);
       
  2848   watch->messages = NULL;
       
  2849 
       
  2850   g_free (watch->write_data);
       
  2851 
       
  2852   if (watch->notify)
       
  2853     watch->notify (watch->user_data);
       
  2854 }
       
  2855 
       
  2856 static GSourceFuncs gst_rtsp_source_funcs = {
       
  2857   gst_rtsp_source_prepare,
       
  2858   gst_rtsp_source_check,
       
  2859   gst_rtsp_source_dispatch,
       
  2860   gst_rtsp_source_finalize,
       
  2861   NULL,
       
  2862   NULL
       
  2863 };
       
  2864 
       
  2865 /**
       
  2866  * gst_rtsp_watch_new:
       
  2867  * @conn: a #GstRTSPConnection
       
  2868  * @funcs: watch functions
       
  2869  * @user_data: user data to pass to @funcs
       
  2870  * @notify: notify when @user_data is not referenced anymore
       
  2871  *
       
  2872  * Create a watch object for @conn. The functions provided in @funcs will be
       
  2873  * called with @user_data when activity happened on the watch.
       
  2874  *
       
  2875  * The new watch is usually created so that it can be attached to a
       
  2876  * maincontext with gst_rtsp_watch_attach(). 
       
  2877  *
       
  2878  * @conn must exist for the entire lifetime of the watch.
       
  2879  *
       
  2880  * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP
       
  2881  * communication. Free with gst_rtsp_watch_unref () after usage.
       
  2882  *
       
  2883  * Since: 0.10.23
       
  2884  */
       
  2885 GstRTSPWatch *
       
  2886 gst_rtsp_watch_new (GstRTSPConnection * conn,
       
  2887     GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify)
       
  2888 {
       
  2889   GstRTSPWatch *result;
       
  2890 
       
  2891   g_return_val_if_fail (conn != NULL, NULL);
       
  2892   g_return_val_if_fail (funcs != NULL, NULL);
       
  2893   g_return_val_if_fail (conn->readfd != NULL, NULL);
       
  2894   g_return_val_if_fail (conn->writefd != NULL, NULL);
       
  2895 
       
  2896   result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs,
       
  2897       sizeof (GstRTSPWatch));
       
  2898 
       
  2899   result->conn = conn;
       
  2900   result->builder.state = STATE_START;
       
  2901 
       
  2902   result->messages = g_async_queue_new_full (gst_rtsp_rec_free);
       
  2903 
       
  2904   result->readfd.fd = -1;
       
  2905   result->writefd.fd = -1;
       
  2906 
       
  2907   gst_rtsp_watch_reset (result);
       
  2908 
       
  2909   result->funcs = *funcs;
       
  2910   result->user_data = user_data;
       
  2911   result->notify = notify;
       
  2912 
       
  2913   /* only add the read fd, the write fd is only added when we have data
       
  2914    * to send. */
       
  2915   g_source_add_poll ((GSource *) result, &result->readfd);
       
  2916 
       
  2917   return result;
       
  2918 }
       
  2919 
       
  2920 /**
       
  2921  * gst_rtsp_watch_reset:
       
  2922  * @watch: a #GstRTSPWatch
       
  2923  *
       
  2924  * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel()
       
  2925  * when the file descriptors of the connection might have changed.
       
  2926  *
       
  2927  * Since: 0.10.23
       
  2928  */
       
  2929 void
       
  2930 gst_rtsp_watch_reset (GstRTSPWatch * watch)
       
  2931 {
       
  2932   if (watch->readfd.fd != -1)
       
  2933     g_source_remove_poll ((GSource *) watch, &watch->readfd);
       
  2934   if (watch->writefd.fd != -1)
       
  2935     g_source_remove_poll ((GSource *) watch, &watch->writefd);
       
  2936 
       
  2937   watch->readfd.fd = watch->conn->readfd->fd;
       
  2938   watch->readfd.events = READ_COND;
       
  2939   watch->readfd.revents = 0;
       
  2940 
       
  2941   watch->writefd.fd = watch->conn->writefd->fd;
       
  2942   watch->writefd.events = WRITE_COND;
       
  2943   watch->writefd.revents = 0;
       
  2944   watch->write_added = FALSE;
       
  2945 
       
  2946   g_source_add_poll ((GSource *) watch, &watch->readfd);
       
  2947 }
       
  2948 
       
  2949 /**
       
  2950  * gst_rtsp_watch_attach:
       
  2951  * @watch: a #GstRTSPWatch
       
  2952  * @context: a GMainContext (if NULL, the default context will be used)
       
  2953  *
       
  2954  * Adds a #GstRTSPWatch to a context so that it will be executed within that context.
       
  2955  *
       
  2956  * Returns: the ID (greater than 0) for the watch within the GMainContext. 
       
  2957  *
       
  2958  * Since: 0.10.23
       
  2959  */
       
  2960 guint
       
  2961 gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
       
  2962 {
       
  2963   g_return_val_if_fail (watch != NULL, 0);
       
  2964 
       
  2965   return g_source_attach ((GSource *) watch, context);
       
  2966 }
       
  2967 
       
  2968 /**
       
  2969  * gst_rtsp_watch_unref:
       
  2970  * @watch: a #GstRTSPWatch
       
  2971  *
       
  2972  * Decreases the reference count of @watch by one. If the resulting reference
       
  2973  * count is zero the watch and associated memory will be destroyed.
       
  2974  *
       
  2975  * Since: 0.10.23
       
  2976  */
       
  2977 void
       
  2978 gst_rtsp_watch_unref (GstRTSPWatch * watch)
       
  2979 {
       
  2980   g_return_if_fail (watch != NULL);
       
  2981 
       
  2982   g_source_unref ((GSource *) watch);
       
  2983 }
       
  2984 
       
  2985 /**
       
  2986  * gst_rtsp_watch_queue_data:
       
  2987  * @watch: a #GstRTSPWatch
       
  2988  * @data: the data to queue
       
  2989  * @size: the size of @data
       
  2990  *
       
  2991  * Queue @data for transmission in @watch. It will be transmitted when the
       
  2992  * connection of the @watch becomes writable.
       
  2993  *
       
  2994  * This function will take ownership of @data and g_free() it after use.
       
  2995  *
       
  2996  * The return value of this function will be used as the id argument in the
       
  2997  * message_sent callback.
       
  2998  *
       
  2999  * Returns: an id.
       
  3000  *
       
  3001  * Since: 0.10.24
       
  3002  */
       
  3003 guint
       
  3004 gst_rtsp_watch_queue_data (GstRTSPWatch * watch, const guint8 * data,
       
  3005     guint size)
       
  3006 {
       
  3007   GstRTSPRec *rec;
       
  3008 
       
  3009   g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
       
  3010   g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
       
  3011   g_return_val_if_fail (size != 0, GST_RTSP_EINVAL);
       
  3012 
       
  3013   /* make a record with the data and id */
       
  3014   rec = g_slice_new (GstRTSPRec);
       
  3015   rec->data = (guint8 *) data;
       
  3016   rec->size = size;
       
  3017   do {
       
  3018     /* make sure rec->id is never 0 */
       
  3019     rec->id = ++watch->id;
       
  3020   } while (G_UNLIKELY (rec->id == 0));
       
  3021 
       
  3022   /* add the record to a queue. FIXME we would like to have an upper limit here */
       
  3023   g_async_queue_push (watch->messages, rec);
       
  3024 
       
  3025   /* FIXME: does the following need to be made thread-safe? (this might be
       
  3026    * called from a streaming thread, like appsink's render function) */
       
  3027   /* make sure the main context will now also check for writability on the
       
  3028    * socket */
       
  3029   if (!watch->write_added) {
       
  3030     g_source_add_poll ((GSource *) watch, &watch->writefd);
       
  3031     watch->write_added = TRUE;
       
  3032   }
       
  3033 
       
  3034   return rec->id;
       
  3035 }
       
  3036 
       
  3037 /**
       
  3038  * gst_rtsp_watch_queue_message:
       
  3039  * @watch: a #GstRTSPWatch
       
  3040  * @message: a #GstRTSPMessage
       
  3041  *
       
  3042  * Queue a @message for transmission in @watch. The contents of this
       
  3043  * message will be serialized and transmitted when the connection of the
       
  3044  * @watch becomes writable.
       
  3045  *
       
  3046  * The return value of this function will be used as the id argument in the
       
  3047  * message_sent callback.
       
  3048  *
       
  3049  * Returns: an id.
       
  3050  *
       
  3051  * Since: 0.10.23
       
  3052  */
       
  3053 guint
       
  3054 gst_rtsp_watch_queue_message (GstRTSPWatch * watch, GstRTSPMessage * message)
       
  3055 {
       
  3056   GString *str;
       
  3057   guint size;
       
  3058 
       
  3059   g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
       
  3060   g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
       
  3061 
       
  3062   /* make a record with the message as a string and id */
       
  3063   str = message_to_string (watch->conn, message);
       
  3064   size = str->len;
       
  3065   return gst_rtsp_watch_queue_data (watch,
       
  3066       (guint8 *) g_string_free (str, FALSE), size);
       
  3067 }