gst/rtsp/: Improves version checking, allowing an RTSP server to reply with "505
authorPeter Kjellerstedt <pkj@axis.com>
Fri, 1 Jun 2007 13:07:11 +0000 (13:07 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 1 Jun 2007 13:07:11 +0000 (13:07 +0000)
Original commit message from CVS:
Patch by: Peter Kjellerstedt  <pkj at axis com>
* gst/rtsp/rtspconnection.c: (rtsp_connection_create),
(rtsp_connection_connect), (add_date_header),
(rtsp_connection_send), (parse_response_status),
(parse_request_line), (parse_line), (rtsp_connection_receive):
* gst/rtsp/rtspdefs.c: (rtsp_version_as_text):
* gst/rtsp/rtspdefs.h:
* gst/rtsp/rtspmessage.c: (key_value_foreach),
(rtsp_message_init_request), (rtsp_message_init_response),
(rtsp_message_remove_header), (rtsp_message_append_headers),
(rtsp_message_dump):
* gst/rtsp/rtspmessage.h:
Improves version checking, allowing an RTSP server to reply with "505
RTSP Version not supported.
Adds a Date header to all messages.
Replies with RTSP_EPARSE rather than RTSP_EINVALID in cases where we
want to be able to send a response even if something in the request was
invalid. EINVAL is only used when passing wrong arguments to functions.
Do not handle an invalid method in parse_request_line(). Defer this to
the caller so it can respond with "405 Method Not Allowed".
Improves parsing of the timeout parameter to the Session header,
allowing whitespace after the semicolon.
Avoids a compiler warning due to variables shadowing a function argument.

ChangeLog
gst/rtsp/rtspconnection.c
gst/rtsp/rtspdefs.c
gst/rtsp/rtspdefs.h
gst/rtsp/rtspmessage.c
gst/rtsp/rtspmessage.h

index 00ed607..b96ad78 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,32 @@
 2007-06-01  Wim Taymans  <wim@fluendo.com>
 
+       Patch by: Peter Kjellerstedt  <pkj at axis com>
+
+       * gst/rtsp/rtspconnection.c: (rtsp_connection_create),
+       (rtsp_connection_connect), (add_date_header),
+       (rtsp_connection_send), (parse_response_status),
+       (parse_request_line), (parse_line), (rtsp_connection_receive):
+       * gst/rtsp/rtspdefs.c: (rtsp_version_as_text):
+       * gst/rtsp/rtspdefs.h:
+       * gst/rtsp/rtspmessage.c: (key_value_foreach),
+       (rtsp_message_init_request), (rtsp_message_init_response),
+       (rtsp_message_remove_header), (rtsp_message_append_headers),
+       (rtsp_message_dump):
+       * gst/rtsp/rtspmessage.h:
+       Improves version checking, allowing an RTSP server to reply with "505
+       RTSP Version not supported.
+       Adds a Date header to all messages.
+       Replies with RTSP_EPARSE rather than RTSP_EINVALID in cases where we
+       want to be able to send a response even if something in the request was
+       invalid. EINVAL is only used when passing wrong arguments to functions.
+       Do not handle an invalid method in parse_request_line(). Defer this to
+       the caller so it can respond with "405 Method Not Allowed".
+       Improves parsing of the timeout parameter to the Session header,
+       allowing whitespace after the semicolon. 
+       Avoids a compiler warning due to variables shadowing a function argument.
+
+2007-06-01  Wim Taymans  <wim@fluendo.com>
+
        Based on Patch by: Daniel Charles <dcharles at ti dot com>
 
        * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_setcaps),
index e20de23..50948f6 100644 (file)
@@ -122,7 +122,7 @@ rtsp_connection_create (RTSPUrl * url, RTSPConnection ** conn)
 
   g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
 
-  newconn = g_new (RTSPConnection, 1);
+  newconn = g_new0 (RTSPConnection, 1);
 
 #ifdef G_OS_WIN32
   /* This should work on UNIX too. PF_UNIX sockets replaced with pipe */
@@ -140,8 +140,6 @@ rtsp_connection_create (RTSPUrl * url, RTSPConnection ** conn)
 
   newconn->url = url;
   newconn->fd = -1;
-  newconn->cseq = 0;
-  newconn->session_id[0] = 0;
   newconn->timer = g_timer_new ();
 
   newconn->auth_method = RTSP_AUTH_NONE;
@@ -164,7 +162,7 @@ RTSPResult
 rtsp_connection_connect (RTSPConnection * conn, GTimeVal * timeout)
 {
   gint fd;
-  struct sockaddr_in sin;
+  struct sockaddr_in sa_in;
   struct hostent *hostinfo;
   char **addrs;
   gchar *ip;
@@ -201,10 +199,10 @@ rtsp_connection_connect (RTSPConnection * conn, GTimeVal * timeout)
   /* get the port from the url */
   rtsp_url_get_port (url, &port);
 
-  memset (&sin, 0, sizeof (sin));
-  sin.sin_family = AF_INET;     /* network socket */
-  sin.sin_port = htons (port);  /* on port */
-  sin.sin_addr.s_addr = inet_addr (ip); /* on host ip */
+  memset (&sa_in, 0, sizeof (sa_in));
+  sa_in.sin_family = AF_INET;   /* network socket */
+  sa_in.sin_port = htons (port);        /* on port */
+  sa_in.sin_addr.s_addr = inet_addr (ip);       /* on host ip */
 
   fd = socket (AF_INET, SOCK_STREAM, 0);
   if (fd == -1)
@@ -214,7 +212,7 @@ rtsp_connection_connect (RTSPConnection * conn, GTimeVal * timeout)
   fcntl (fd, F_SETFL, O_NONBLOCK);
 
   /* we are going to connect ASYNC now */
-  ret = connect (fd, (struct sockaddr *) &sin, sizeof (sin));
+  ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
   if (ret == 0)
     goto done;
   if (errno != EINPROGRESS)
@@ -295,6 +293,19 @@ add_auth_header (RTSPConnection * conn, RTSPMessage * message)
   }
 }
 
+static void
+add_date_header (RTSPMessage * message)
+{
+  GTimeVal tv;
+  gchar date_string[100];
+
+  g_get_current_time (&tv);
+  strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
+      gmtime (&tv.tv_sec));
+
+  rtsp_message_add_header (message, RTSP_HDR_DATE, date_string);
+}
+
 RTSPResult
 rtsp_connection_write (RTSPConnection * conn, const guint8 * data, guint size,
     GTimeVal * timeout)
@@ -389,7 +400,7 @@ RTSPResult
 rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message,
     GTimeVal * timeout)
 {
-  GString *str = NULL;
+  GString *str;
   RTSPResult res;
 
 #ifdef G_OS_WIN32
@@ -455,6 +466,9 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message,
 
   /* append headers and body */
   if (message->type != RTSP_MESSAGE_DATA) {
+    /* add date header */
+    add_date_header (message);
+
     /* append headers */
     rtsp_message_append_headers (message, str);
 
@@ -576,6 +590,7 @@ read_key (gchar * dest, gint size, gchar ** src)
 static RTSPResult
 parse_response_status (gchar * buffer, RTSPMessage * msg)
 {
+  RTSPResult res;
   gchar versionstr[20];
   gchar codestr[4];
   gint code;
@@ -584,28 +599,34 @@ parse_response_status (gchar * buffer, RTSPMessage * msg)
   bptr = buffer;
 
   read_string (versionstr, sizeof (versionstr), &bptr);
-  if (strcmp (versionstr, "RTSP/1.0") != 0)
-    goto wrong_version;
-
   read_string (codestr, sizeof (codestr), &bptr);
   code = atoi (codestr);
 
   while (g_ascii_isspace (*bptr))
     bptr++;
 
-  rtsp_message_init_response (msg, code, bptr, NULL);
+  if (strcmp (versionstr, "RTSP/1.0") == 0)
+    RTSP_CHECK (rtsp_message_init_response (msg, code, bptr, NULL),
+        parse_error);
+  else if (strncmp (versionstr, "RTSP/", 5) == 0) {
+    RTSP_CHECK (rtsp_message_init_response (msg, code, bptr, NULL),
+        parse_error);
+    msg->type_data.response.version = RTSP_VERSION_INVALID;
+  } else
+    goto parse_error;
 
   return RTSP_OK;
 
-wrong_version:
+parse_error:
   {
-    return RTSP_EINVAL;
+    return RTSP_EPARSE;
   }
 }
 
 static RTSPResult
 parse_request_line (gchar * buffer, RTSPMessage * msg)
 {
+  RTSPResult res = RTSP_OK;
   gchar versionstr[20];
   gchar methodstr[20];
   gchar urlstr[4096];
@@ -616,27 +637,30 @@ parse_request_line (gchar * buffer, RTSPMessage * msg)
 
   read_string (methodstr, sizeof (methodstr), &bptr);
   method = rtsp_find_method (methodstr);
-  if (method == RTSP_INVALID)
-    goto wrong_method;
 
   read_string (urlstr, sizeof (urlstr), &bptr);
+  if (*urlstr == '\0')
+    res = RTSP_EPARSE;
 
   read_string (versionstr, sizeof (versionstr), &bptr);
-  if (strcmp (versionstr, "RTSP/1.0") != 0)
-    goto wrong_version;
 
-  rtsp_message_init_request (msg, method, urlstr);
+  if (*bptr != '\0')
+    res = RTSP_EPARSE;
 
-  return RTSP_OK;
-
-wrong_method:
-  {
-    return RTSP_EINVAL;
-  }
-wrong_version:
-  {
-    return RTSP_EINVAL;
+  if (strcmp (versionstr, "RTSP/1.0") == 0) {
+    if (rtsp_message_init_request (msg, method, urlstr) != RTSP_OK)
+      res = RTSP_EPARSE;
+  } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
+    if (rtsp_message_init_request (msg, method, urlstr) != RTSP_OK)
+      res = RTSP_EPARSE;
+    msg->type_data.request.version = RTSP_VERSION_INVALID;
+  } else {
+    rtsp_message_init_request (msg, method, urlstr);
+    msg->type_data.request.version = RTSP_VERSION_INVALID;
+    res = RTSP_EPARSE;
   }
+
+  return res;
 }
 
 /* parsing lines means reading a Key: Value pair */
@@ -667,7 +691,7 @@ parse_line (gchar * buffer, RTSPMessage * msg)
 
 no_column:
   {
-    return RTSP_EINVAL;
+    return RTSP_EPARSE;
   }
 }
 
@@ -821,7 +845,6 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg,
 {
   gchar buffer[4096];
   gint line;
-  gchar *hdrval;
   glong content_length;
   RTSPResult res;
   gboolean need_body;
@@ -899,6 +922,9 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg,
 
   /* read the rest of the body if needed */
   if (need_body) {
+    gchar *session_id;
+    gchar *hdrval;
+
     /* see if there is a Content-Length header */
     if (rtsp_message_get_header (msg, RTSP_HDR_CONTENT_LENGTH,
             &hdrval, 0) == RTSP_OK) {
@@ -908,38 +934,37 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg,
     }
 
     /* save session id in the connection for further use */
-    {
-      gchar *session_id;
-
-      if (rtsp_message_get_header (msg, RTSP_HDR_SESSION,
-              &session_id, 0) == RTSP_OK) {
-        gint sesslen, maxlen, i;
-
-        /* default session timeout */
-        conn->timeout = 60;
-
-        sesslen = strlen (session_id);
-        maxlen = sizeof (conn->session_id) - 1;
-        /* the sessionid can have attributes marked with ;
-         * Make sure we strip them */
-        for (i = 0; i < sesslen; i++) {
-          if (session_id[i] == ';') {
-            maxlen = i;
-            /* parse timeout */
-            if (g_str_has_prefix (&session_id[i], ";timeout=")) {
-              gint timeout;
-
-              /* if we parsed something valid, configure */
-              if ((timeout = atoi (&session_id[i + 9])) > 0)
-                conn->timeout = timeout;
-            }
+    if (rtsp_message_get_header (msg, RTSP_HDR_SESSION,
+            &session_id, 0) == RTSP_OK) {
+      gint maxlen, i;
+
+      /* default session timeout */
+      conn->timeout = 60;
+
+      maxlen = sizeof (conn->session_id) - 1;
+      /* the sessionid can have attributes marked with ;
+       * Make sure we strip them */
+      for (i = 0; session_id[i] != '\0'; i++) {
+        if (session_id[i] == ';') {
+          maxlen = i;
+          /* parse timeout */
+          do {
+            i++;
+          } while (g_ascii_isspace (session_id[i]));
+          if (g_str_has_prefix (&session_id[i], "timeout=")) {
+            gint to;
+
+            /* if we parsed something valid, configure */
+            if ((to = atoi (&session_id[i + 9])) > 0)
+              conn->timeout = to;
           }
+          break;
         }
-
-        /* make sure to not overflow */
-        strncpy (conn->session_id, session_id, maxlen);
-        conn->session_id[maxlen] = '\0';
       }
+
+      /* make sure to not overflow */
+      strncpy (conn->session_id, session_id, maxlen);
+      conn->session_id[maxlen] = '\0';
     }
   }
   return res;
index 2c3f7b7..8f11a5d 100644 (file)
@@ -255,6 +255,18 @@ rtsp_method_as_text (RTSPMethod method)
 }
 
 const gchar *
+rtsp_version_as_text (RTSPVersion version)
+{
+  switch (version) {
+    case RTSP_VERSION_1_0:
+      return "1.0";
+
+    default:
+      return "0.0";
+  }
+}
+
+const gchar *
 rtsp_header_as_text (RTSPHeaderField field)
 {
   if (field == RTSP_HDR_INVALID)
index 8a2182d..2045c1f 100644 (file)
@@ -90,6 +90,11 @@ typedef enum {
 } RTSPState;
 
 typedef enum {
+  RTSP_VERSION_INVALID = 0x00,
+  RTSP_VERSION_1_0     = 0x10,
+} RTSPVersion;
+
+typedef enum {
   RTSP_INVALID          = 0,
   RTSP_DESCRIBE         = (1 <<  0),
   RTSP_ANNOUNCE         = (1 <<  1),
@@ -232,6 +237,7 @@ typedef enum {
 gchar*          rtsp_strresult          (RTSPResult result);
 
 const gchar*    rtsp_method_as_text     (RTSPMethod method);
+const gchar*    rtsp_version_as_text    (RTSPVersion version);
 const gchar*    rtsp_header_as_text     (RTSPHeaderField field);
 const gchar*    rtsp_status_as_text     (RTSPStatusCode code);
 
index 2cb12bf..5dd2faa 100644 (file)
@@ -118,6 +118,7 @@ rtsp_message_init_request (RTSPMessage * msg, RTSPMethod method,
   msg->type = RTSP_MESSAGE_REQUEST;
   msg->type_data.request.method = method;
   msg->type_data.request.uri = g_strdup (uri);
+  msg->type_data.request.version = RTSP_VERSION_1_0;
   msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
 
   return RTSP_OK;
@@ -152,6 +153,7 @@ rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code,
   msg->type = RTSP_MESSAGE_RESPONSE;
   msg->type_data.response.code = code;
   msg->type_data.response.reason = g_strdup (reason);
+  msg->type_data.response.version = RTSP_VERSION_1_0;
   msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
 
   if (request) {
@@ -424,9 +426,11 @@ rtsp_message_dump (RTSPMessage * msg)
     case RTSP_MESSAGE_REQUEST:
       g_print ("RTSP request message %p\n", msg);
       g_print (" request line:\n");
-      g_print ("   method: '%s'\n",
+      g_print ("   method:  '%s'\n",
           rtsp_method_as_text (msg->type_data.request.method));
-      g_print ("   uri:    '%s'\n", msg->type_data.request.uri);
+      g_print ("   uri:     '%s'\n", msg->type_data.request.uri);
+      g_print ("   version: '%s'\n",
+          rtsp_version_as_text (msg->type_data.request.version));
       g_print (" headers:\n");
       key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
       g_print (" body:\n");
@@ -436,8 +440,10 @@ rtsp_message_dump (RTSPMessage * msg)
     case RTSP_MESSAGE_RESPONSE:
       g_print ("RTSP response message %p\n", msg);
       g_print (" status line:\n");
-      g_print ("   code:   '%d'\n", msg->type_data.response.code);
-      g_print ("   reason: '%s'\n", msg->type_data.response.reason);
+      g_print ("   code:    '%d'\n", msg->type_data.response.code);
+      g_print ("   reason:  '%s'\n", msg->type_data.response.reason);
+      g_print ("   version: '%s'\n",
+          rtsp_version_as_text (msg->type_data.response.version));
       g_print (" headers:\n");
       key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
       rtsp_message_get_body (msg, &data, &size);
index 2c099f1..15d173c 100644 (file)
@@ -65,10 +65,12 @@ typedef struct _RTSPMessage
     struct {
       RTSPMethod         method;
       gchar             *uri;
+      RTSPVersion        version;
     } request;
     struct {
       RTSPStatusCode     code;
       gchar             *reason;
+      RTSPVersion        version;
     } response;
     struct {
       guint8             channel;