Created a new protocol tree implementation and a new display filter
[obnox/wireshark/wip.git] / packet-rtsp.c
1 /* packet-rtsp.c
2  * Routines for RTSP packet disassembly
3  *
4  * Jason Lango <jal@netapp.com>
5  * Liberally copied from packet-http.c, by Guy Harris <guy@netapp.com>
6  *
7  * $Id: packet-rtsp.c,v 1.2 1999/07/07 22:51:53 gram Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@zing.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * 
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  * 
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  *
28  *
29  */
30
31 #include "config.h"
32
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
35 #endif
36
37 #include <string.h>
38 #include <ctype.h>
39
40 #include <glib.h>
41 #include "packet.h"
42
43 static int is_rtsp_request_or_reply(const u_char *data, int linelen);
44
45 static int
46 is_content_sdp(const u_char *line, int linelen)
47 {
48         const char      *hdr = "Content-Type:";
49         size_t          hdrlen = strlen(hdr);
50         const char      *type = "application/sdp";
51         size_t          typelen = strlen(type);
52
53         if (linelen < hdrlen || strncasecmp(hdr, line, hdrlen))
54                 return 0;
55
56         line += hdrlen;
57         linelen -= hdrlen;
58         while (linelen > 0 && (*line == ' ' || *line == '\t')) {
59                 line++;
60                 linelen--;
61         }
62
63         if (linelen < typelen || strncasecmp(type, line, typelen))
64                 return 0;
65
66         line += typelen;
67         linelen -= typelen;
68         if (linelen > 0 && !isspace(*line))
69                 return 0;
70
71         return 1;
72 }
73
74 void dissect_rtsp(const u_char *pd, int offset, frame_data *fd,
75         proto_tree *tree)
76 {
77         proto_tree      *rtsp_tree;
78         proto_item      *ti;
79         const u_char    *data, *dataend;
80         const u_char    *linep, *lineend, *eol;
81         int             linelen;
82         u_char          c;
83         int             is_sdp = 0;
84
85         data = &pd[offset];
86         dataend = data + END_OF_FRAME;
87
88         if (check_col(fd, COL_PROTOCOL))
89                 col_add_str(fd, COL_PROTOCOL, "RTSP");
90         if (check_col(fd, COL_INFO)) {
91                 /*
92                  * Put the first line from the buffer into the summary,
93                  * if it's an RTSP request or reply.
94                  * Otherwise, just call it a continuation.
95                  */
96                 lineend = find_line_end(data, dataend, &eol);
97                 linelen = lineend - data;
98                 if (is_rtsp_request_or_reply(data, linelen))
99                         col_add_str(fd, COL_INFO, format_text(data, linelen));
100                 else
101                         col_add_str(fd, COL_INFO, "Continuation");
102         }
103
104         rtsp_tree = NULL;
105
106         if (tree) {
107                 ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
108                         "Real Time Streaming Protocol");
109                 rtsp_tree = proto_item_add_subtree(ti, ETT_RTSP);
110         }
111
112         while (data < dataend) {
113                 /*
114                  * Find the end of the line.
115                  */
116                 lineend = find_line_end(data, dataend, &eol);
117                 linelen = lineend - data;
118
119                 /*
120                  * OK, does it look like an RTSP request or
121                  * response?
122                  */
123                 if (is_rtsp_request_or_reply(data, linelen))
124                         goto is_rtsp;
125
126                 /*
127                  * No.  Does it look like a blank line (as would
128                  * appear at the end of an RTSP request)?
129                  */
130                 if (linelen == 1) {
131                         if (*data == '\n')
132                                 goto is_rtsp;
133                 }
134                 if (linelen == 2) {
135                         if (strncmp(data, "\r\n", 2) == 0 ||
136                             strncmp(data, "\n\r", 2) == 0)
137                                 goto is_rtsp;
138                 }
139
140                 /*
141                  * No.  Does it look like a MIME header?
142                  */
143                 linep = data;
144                 while (linep < lineend) {
145                         c = *linep++;
146                         if (!isprint(c))
147                                 break;  /* not printable, not a MIME header */
148                         switch (c) {
149
150                         case '(':
151                         case ')':
152                         case '<':
153                         case '>':
154                         case '@':
155                         case ',':
156                         case ';':
157                         case '\\':
158                         case '"':
159                         case '/':
160                         case '[':
161                         case ']':
162                         case '?':
163                         case '=':
164                         case '{':
165                         case '}':
166                                 /*
167                                  * It's a tspecial, so it's not
168                                  * part of a token, so it's not
169                                  * a field name for the beginning
170                                  * of a MIME header.
171                                  */
172                                 goto not_rtsp;
173
174                         case ':':
175                                 /*
176                                  * This ends the token; we consider
177                                  * this to be a MIME header.
178                                  */
179                                 if (is_content_sdp(data, linelen))
180                                         is_sdp = 1;
181                                 goto is_rtsp;
182                         }
183                 }
184
185         not_rtsp:
186                 /*
187                  * We don't consider this part of an RTSP request or
188                  * reply, so we don't display it.
189                  */
190                 break;
191
192         is_rtsp:
193                 /*
194                  * Put this line.
195                  */
196                 if (rtsp_tree) {
197                         proto_tree_add_text(rtsp_tree, offset, linelen, "%s",
198                             format_text(data, linelen));
199                 }
200                 offset += linelen;
201                 data = lineend;
202         }
203
204         if (is_sdp) {
205                 dissect_sdp(pd, offset, fd, tree);
206                 if (check_col(fd, COL_PROTOCOL))
207                         col_add_str(fd, COL_PROTOCOL, "RTSP/SDP");
208         }
209         else if (rtsp_tree && data < dataend) {
210                 proto_tree_add_text(rtsp_tree, offset, END_OF_FRAME,
211                     "Data (%d bytes)", END_OF_FRAME);
212         }
213 }
214
215 const char *rtsp_methods[] = {
216         "DESCRIBE", "ANNOUNCE", "GET_PARAMETER", "OPTIONS",
217         "PAUSE", "PLAY", "RECORD", "REDIRECT", "SETUP",
218         "SET_PARAMETER", "TEARDOWN"
219 };
220 const int rtsp_nmethods = sizeof(rtsp_methods) / sizeof(*rtsp_methods);
221
222 static int
223 is_rtsp_request_or_reply(const u_char *data, int linelen)
224 {
225         int             ii;
226         size_t          len;
227
228         /* Reply */
229         if (linelen >= 5 && !strncasecmp("RTSP/", data, 5))
230                 return TRUE;
231
232         /* Request Methods */
233         for (ii = 0; ii < rtsp_nmethods; ii++) {
234                 len = strlen(rtsp_methods[ii]);
235                 if (linelen >= len && !strncasecmp(rtsp_methods[ii], data, len))
236                         return TRUE;
237         }
238
239         return FALSE;
240 }