diff options
author | Guy Harris <guy@alum.mit.edu> | 2000-12-02 06:05:29 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2000-12-02 06:05:29 +0000 |
commit | 75acffe70c5a17c20324094c15397ff60a8641de (patch) | |
tree | b338f4cae97152aa20425c112e19718fd5d28e6c /packet-rtsp.c | |
parent | 70d52fa4e8270c829ccea59cc52c4387b2d63db8 (diff) |
Clean up the handling of MIME headers.
Handle the Content-Length: MIME header, so that, if there's a
Content-Length: header, we only process as RTSP payload the amount of
data specified by that header.
Handle frames with more than one RTSP message in them (the previous
change allows us to do so).
svn path=/trunk/; revision=2729
Diffstat (limited to 'packet-rtsp.c')
-rw-r--r-- | packet-rtsp.c | 234 |
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) { |