summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorPeter Kjellerstedt <pkj@axis.com>2007-06-01 13:07:11 +0000
committerWim Taymans <wim.taymans@gmail.com>2007-06-01 13:07:11 +0000
commitf12fb76f70cbc7ecb088fa9ca00b33b3079c9d8e (patch)
treec051ea88aa8b4d42eaf9ea6169f75cd983ef2084 /gst
parent89ae9b40f9c32d3e8aac4c7c9aafb83d64fa2497 (diff)
gst/rtsp/: Improves version checking, allowing an RTSP server to reply with "505
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.
Diffstat (limited to 'gst')
-rw-r--r--gst/rtsp/rtspconnection.c147
-rw-r--r--gst/rtsp/rtspdefs.c12
-rw-r--r--gst/rtsp/rtspdefs.h6
-rw-r--r--gst/rtsp/rtspmessage.c14
-rw-r--r--gst/rtsp/rtspmessage.h2
5 files changed, 116 insertions, 65 deletions
diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c
index e20de231..50948f6c 100644
--- a/gst/rtsp/rtspconnection.c
+++ b/gst/rtsp/rtspconnection.c
@@ -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;
diff --git a/gst/rtsp/rtspdefs.c b/gst/rtsp/rtspdefs.c
index 2c3f7b73..8f11a5d9 100644
--- a/gst/rtsp/rtspdefs.c
+++ b/gst/rtsp/rtspdefs.c
@@ -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)
diff --git a/gst/rtsp/rtspdefs.h b/gst/rtsp/rtspdefs.h
index 8a2182db..2045c1fc 100644
--- a/gst/rtsp/rtspdefs.h
+++ b/gst/rtsp/rtspdefs.h
@@ -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);
diff --git a/gst/rtsp/rtspmessage.c b/gst/rtsp/rtspmessage.c
index 2cb12bf3..5dd2faab 100644
--- a/gst/rtsp/rtspmessage.c
+++ b/gst/rtsp/rtspmessage.c
@@ -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);
diff --git a/gst/rtsp/rtspmessage.h b/gst/rtsp/rtspmessage.h
index 2c099f17..15d173c3 100644
--- a/gst/rtsp/rtspmessage.h
+++ b/gst/rtsp/rtspmessage.h
@@ -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;