aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packet-rtsp.c234
1 files changed, 195 insertions, 39 deletions
diff --git a/packet-rtsp.c b/packet-rtsp.c
index 4f0c09b879..c889203e81 100644
--- a/packet-rtsp.c
+++ b/packet-rtsp.c
@@ -4,7 +4,7 @@
* Jason Lango <jal@netapp.com>
* Liberally copied from packet-http.c, by Guy Harris <guy@alum.mit.edu>
*
- * $Id: packet-rtsp.c,v 1.28 2000/11/30 02:06:30 guy Exp $
+ * $Id: packet-rtsp.c,v 1.29 2000/12/02 06:05:29 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -36,6 +36,7 @@
#include <string.h>
#include <ctype.h>
+#include <stdlib.h>
#include <glib.h>
#include "packet.h"
@@ -53,6 +54,13 @@ static int hf_rtsp_status = -1;
#define TCP_PORT_RTSP 554
+/*
+ * Takes an array of bytes, assumed to contain a null-terminated
+ * string, as an argument, and returns the length of the string -
+ * i.e., the size of the array, minus 1 for the null terminator.
+ */
+#define STRLEN_CONST(str) (sizeof (str) - 1)
+
static void process_rtsp_request(tvbuff_t *tvb, int offset, const u_char *data,
int linelen, proto_tree *tree);
@@ -102,33 +110,30 @@ is_rtsp_request_or_reply(const u_char *line, int linelen)
return NOT_RTSP;
}
+static const char rtsp_content_type[] = "Content-Type:";
+
static int
is_content_sdp(const u_char *line, int linelen)
{
- const char *hdr = "Content-Type:";
- size_t hdrlen = strlen(hdr);
- const char *type = "application/sdp";
- size_t typelen = strlen(type);
+ static const char type[] = "application/sdp";
+ size_t typelen = STRLEN_CONST(type);
- if (linelen < hdrlen || strncasecmp(hdr, line, hdrlen))
- return 0;
-
- line += hdrlen;
- linelen -= hdrlen;
+ line += STRLEN_CONST(rtsp_content_type);
+ linelen -= STRLEN_CONST(rtsp_content_type);
while (linelen > 0 && (*line == ' ' || *line == '\t')) {
line++;
linelen--;
}
if (linelen < typelen || strncasecmp(type, line, typelen))
- return 0;
+ return FALSE;
line += typelen;
linelen -= typelen;
if (linelen > 0 && !isspace(*line))
- return 0;
+ return FALSE;
- return 1;
+ return TRUE;
}
static const char rtsp_transport[] = "Transport:";
@@ -137,31 +142,37 @@ static const char rtsp_cps[] = "client_port=";
static const char rtsp_rtp[] = "rtp/avp";
static void
-rtsp_create_conversation(const u_char *trans_begin, const u_char *trans_end)
+rtsp_create_conversation(const u_char *line_begin, int line_len)
{
conversation_t *conv;
- u_char tbuf[256];
+ u_char buf[256];
u_char *tmp;
int c_data_port, c_mon_port;
int s_data_port, s_mon_port;
- strncpy(tbuf, trans_begin, trans_end - trans_begin);
- tbuf[sizeof(tbuf)-1] = 0;
+ if (line_len > sizeof(buf) - 1) {
+ /*
+ * Don't overflow the buffer.
+ */
+ line_len = sizeof(buf) - 1;
+ }
+ memcpy(buf, line_begin, line_len);
+ buf[line_len] = '\0';
- tmp = tbuf + strlen(rtsp_transport);
+ tmp = buf + STRLEN_CONST(rtsp_transport);
while (*tmp && isspace(*tmp))
tmp++;
if (strncasecmp(tmp, rtsp_rtp, strlen(rtsp_rtp)) != 0)
- return;
+ return; /* we don't know this transport */
c_data_port = c_mon_port = 0;
s_data_port = s_mon_port = 0;
- if ((tmp = strstr(tbuf, rtsp_sps))) {
+ if ((tmp = strstr(buf, rtsp_sps))) {
tmp += strlen(rtsp_sps);
if (sscanf(tmp, "%u-%u", &s_data_port, &s_mon_port) < 1)
g_warning("rtsp: failed to parse server_port");
}
- if ((tmp = strstr(tbuf, rtsp_cps))) {
+ if ((tmp = strstr(buf, rtsp_cps))) {
tmp += strlen(rtsp_cps);
if (sscanf(tmp, "%u-%u", &c_data_port, &c_mon_port) < 1)
g_warning("rtsp: failed to parse client_port");
@@ -181,24 +192,54 @@ rtsp_create_conversation(const u_char *trans_begin, const u_char *trans_end)
conversation_set_dissector(conv, dissect_rtcp);
}
-static void
-dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static const char rtsp_content_length[] = "Content-Length:";
+
+static int
+rtsp_get_content_length(const u_char *line_begin, int line_len)
+{
+ u_char buf[256];
+ u_char *tmp;
+ long content_length;
+ char *p;
+ u_char *up;
+
+ if (line_len > sizeof(buf) - 1) {
+ /*
+ * Don't overflow the buffer.
+ */
+ line_len = sizeof(buf) - 1;
+ }
+ memcpy(buf, line_begin, line_len);
+ buf[line_len] = '\0';
+
+ tmp = buf + STRLEN_CONST(rtsp_content_length);
+ while (*tmp && isspace(*tmp))
+ tmp++;
+ content_length = strtol(tmp, &p, 10);
+ up = p;
+ if (up == tmp || (*up != '\0' && !isspace(*up)))
+ return -1; /* not a valid number */
+ return content_length;
+}
+
+static int
+dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree)
{
proto_tree *rtsp_tree;
proto_item *ti = NULL;
- gint offset = 0;
const u_char *line;
gint next_offset;
const u_char *linep, *lineend;
- int linelen;
+ int orig_offset, linelen;
u_char c;
+ gboolean is_mime_header;
int is_sdp = FALSE;
int datalen;
+ int content_length;
+ int reported_datalen;
- CHECK_DISPLAY_AS_DATA(proto_rtsp, tvb, pinfo, tree);
-
- pinfo->current_proto = "RTSP";
-
+ orig_offset = offset;
rtsp_tree = NULL;
if (tree) {
ti = proto_tree_add_item(tree, proto_rtsp, tvb, offset,
@@ -206,8 +247,6 @@ dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
rtsp_tree = proto_item_add_subtree(ti, ett_rtsp);
}
- if (check_col(pinfo->fd, COL_PROTOCOL))
- col_set_str(pinfo->fd, COL_PROTOCOL, "RTSP");
if (check_col(pinfo->fd, COL_INFO)) {
/*
* Put the first line from the buffer into the summary
@@ -232,10 +271,20 @@ dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
/*
+ * We haven't yet seen a Content-Length header.
+ */
+ content_length = -1;
+
+ /*
* Process the packet data, a line at a time.
*/
while (tvb_offset_exists(tvb, offset)) {
/*
+ * We haven't yet concluded that this is a MIME header.
+ */
+ is_mime_header = FALSE;
+
+ /*
* Find the end of the line.
*/
linelen = tvb_find_line_end(tvb, offset, -1, &next_offset);
@@ -314,8 +363,7 @@ dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
* This ends the token; we consider
* this to be a MIME header.
*/
- if (is_content_sdp(line, linelen))
- is_sdp = TRUE;
+ is_mime_header = TRUE;
goto is_rtsp;
}
}
@@ -336,14 +384,73 @@ dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
next_offset - offset, "%s",
tvb_format_text(tvb, offset, next_offset - offset));
}
- if (linelen > strlen(rtsp_transport) &&
- strncasecmp(line, rtsp_transport,
- strlen(rtsp_transport)) == 0)
- rtsp_create_conversation(line, line + linelen);
+ if (is_mime_header) {
+ /*
+ * Process some MIME headers specially.
+ */
+#define MIME_HDR_MATCHES(header) \
+ (linelen > STRLEN_CONST(header) && \
+ strncasecmp(line, (header), STRLEN_CONST(header)) == 0)
+
+ if (MIME_HDR_MATCHES(rtsp_transport)) {
+ /*
+ * Based on the port numbers specified
+ * in the Transport: header, set up
+ * a conversation that will be dissected
+ * with the appropriate dissector.
+ */
+ rtsp_create_conversation(line, linelen);
+ } else if (MIME_HDR_MATCHES(rtsp_content_type)) {
+ /*
+ * If the Content-Type: header says this
+ * is SDP, dissect the payload as SDP.
+ */
+ if (is_content_sdp(line, linelen))
+ is_sdp = TRUE;
+ } else if (MIME_HDR_MATCHES(rtsp_content_length)) {
+ /*
+ * Only the amount specified by the
+ * Content-Length: header should be treated
+ * as payload.
+ */
+ content_length = rtsp_get_content_length(line,
+ linelen);
+ }
+ }
offset = next_offset;
}
+ /*
+ * If a content length was supplied, the amount of data to be
+ * processed as RTSP payload is the minimum of the content
+ * length and the amount of data remaining in the frame.
+ *
+ * If no content length was supplied, the amount of data to be
+ * processed is the amount of data remaining in the frame.
+ */
datalen = tvb_length_remaining(tvb, offset);
+ if (content_length != -1) {
+ if (datalen > content_length)
+ datalen = content_length;
+
+ /*
+ * XXX - for now, if the content length is greater
+ * than the amount of data left in this frame (not
+ * the amount of *captured* data left in the frame
+ * minus the current offset, but the amount of *actual*
+ * data that was reported to be in the frame minus
+ * the current offset), limit it to the amount
+ * of data left in this frame.
+ *
+ * If we ever handle data that crosses frame
+ * boundaries, we'll need to remember the actual
+ * content length.
+ */
+ reported_datalen = tvb_reported_length(tvb) - offset;
+ if (content_length > reported_datalen)
+ content_length = reported_datalen;
+ }
+
if (datalen > 0) {
/*
* There's stuff left over; process it.
@@ -359,16 +466,37 @@ dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item_set_len(ti, offset);
/*
- * Now creat a tvbuff for the SDP stuff and
+ * Now create a tvbuff for the SDP stuff and
* dissect it.
+ *
+ * The amount of data to be processed that's
+ * available in the tvbuff is "datalen", which
+ * is the minimum of the amount of data left in
+ * the tvbuff and any specified content length.
+ *
+ * The amount of data to be processed that's in
+ * this frame, regardless of whether it was
+ * captured or not, is "content_length",
+ * which, if no content length was specified,
+ * is -1, i.e. "to the end of the frame.
*/
- new_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ new_tvb = tvb_new_subset(tvb, offset, datalen,
+ content_length);
call_dissector(sdp_handle, new_tvb, pinfo, tree);
} else {
proto_tree_add_text(rtsp_tree, tvb, offset, datalen,
"Data (%d bytes)", datalen);
}
+
+ /*
+ * We've processed "datalen" bytes worth of data
+ * (which may be no data at all); advance the
+ * offset past whatever data we've processed, so they
+ * don't process it.
+ */
+ offset += datalen;
}
+ return offset - orig_offset;
}
static void
@@ -440,6 +568,34 @@ process_rtsp_reply(tvbuff_t *tvb, int offset, const u_char *data,
status - status_start, status_i);
}
+static void
+dissect_rtsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ int offset = 0;
+ int len;
+
+ CHECK_DISPLAY_AS_DATA(proto_rtsp, tvb, pinfo, tree);
+
+ pinfo->current_proto = "RTSP";
+
+ if (check_col(pinfo->fd, COL_PROTOCOL))
+ col_set_str(pinfo->fd, COL_PROTOCOL, "RTSP");
+
+ while (tvb_offset_exists(tvb, offset)) {
+ len = dissect_rtspmessage(tvb, offset, pinfo, tree);
+ if (len == -1)
+ break;
+ offset += len;
+
+ /*
+ * OK, we've set the Protocol and Info columns for the
+ * first RTSP message; make the columns non-writable,
+ * so that we don't change it for subsequent RTSP messages.
+ */
+ col_set_writable(pinfo->fd, FALSE);
+ }
+}
+
void
proto_register_rtsp(void)
{