Add a comment.
[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.3 1999/07/29 05:47:03 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 proto_rtsp = -1;
44
45 static int is_rtsp_request_or_reply(const u_char *data, int linelen);
46
47 static int
48 is_content_sdp(const u_char *line, int linelen)
49 {
50         const char      *hdr = "Content-Type:";
51         size_t          hdrlen = strlen(hdr);
52         const char      *type = "application/sdp";
53         size_t          typelen = strlen(type);
54
55         if (linelen < hdrlen || strncasecmp(hdr, line, hdrlen))
56                 return 0;
57
58         line += hdrlen;
59         linelen -= hdrlen;
60         while (linelen > 0 && (*line == ' ' || *line == '\t')) {
61                 line++;
62                 linelen--;
63         }
64
65         if (linelen < typelen || strncasecmp(type, line, typelen))
66                 return 0;
67
68         line += typelen;
69         linelen -= typelen;
70         if (linelen > 0 && !isspace(*line))
71                 return 0;
72
73         return 1;
74 }
75
76 void dissect_rtsp(const u_char *pd, int offset, frame_data *fd,
77         proto_tree *tree)
78 {
79         proto_tree      *rtsp_tree;
80         proto_item      *ti;
81         const u_char    *data, *dataend;
82         const u_char    *linep, *lineend, *eol;
83         int             linelen;
84         u_char          c;
85         int             is_sdp = 0;
86
87         data = &pd[offset];
88         dataend = data + END_OF_FRAME;
89
90         if (check_col(fd, COL_PROTOCOL))
91                 col_add_str(fd, COL_PROTOCOL, "RTSP");
92         if (check_col(fd, COL_INFO)) {
93                 /*
94                  * Put the first line from the buffer into the summary,
95                  * if it's an RTSP request or reply.
96                  * Otherwise, just call it a continuation.
97                  */
98                 lineend = find_line_end(data, dataend, &eol);
99                 linelen = lineend - data;
100                 if (is_rtsp_request_or_reply(data, linelen))
101                         col_add_str(fd, COL_INFO, format_text(data, linelen));
102                 else
103                         col_add_str(fd, COL_INFO, "Continuation");
104         }
105
106         rtsp_tree = NULL;
107
108         if (tree) {
109                 ti = proto_tree_add_item(tree, proto_rtsp, offset, END_OF_FRAME, NULL);
110                 rtsp_tree = proto_item_add_subtree(ti, ETT_RTSP);
111         }
112
113         while (data < dataend) {
114                 /*
115                  * Find the end of the line.
116                  */
117                 lineend = find_line_end(data, dataend, &eol);
118                 linelen = lineend - data;
119
120                 /*
121                  * OK, does it look like an RTSP request or
122                  * response?
123                  */
124                 if (is_rtsp_request_or_reply(data, linelen))
125                         goto is_rtsp;
126
127                 /*
128                  * No.  Does it look like a blank line (as would
129                  * appear at the end of an RTSP request)?
130                  */
131                 if (linelen == 1) {
132                         if (*data == '\n')
133                                 goto is_rtsp;
134                 }
135                 if (linelen == 2) {
136                         if (strncmp(data, "\r\n", 2) == 0 ||
137                             strncmp(data, "\n\r", 2) == 0)
138                                 goto is_rtsp;
139                 }
140
141                 /*
142                  * No.  Does it look like a MIME header?
143                  */
144                 linep = data;
145                 while (linep < lineend) {
146                         c = *linep++;
147                         if (!isprint(c))
148                                 break;  /* not printable, not a MIME header */
149                         switch (c) {
150
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                         case '}':
167                                 /*
168                                  * It's a tspecial, so it's not
169                                  * part of a token, so it's not
170                                  * a field name for the beginning
171                                  * of a MIME header.
172                                  */
173                                 goto not_rtsp;
174
175                         case ':':
176                                 /*
177                                  * This ends the token; we consider
178                                  * this to be a MIME header.
179                                  */
180                                 if (is_content_sdp(data, linelen))
181                                         is_sdp = 1;
182                                 goto is_rtsp;
183                         }
184                 }
185
186         not_rtsp:
187                 /*
188                  * We don't consider this part of an RTSP request or
189                  * reply, so we don't display it.
190                  */
191                 break;
192
193         is_rtsp:
194                 /*
195                  * Put this line.
196                  */
197                 if (rtsp_tree) {
198                         proto_tree_add_text(rtsp_tree, offset, linelen, "%s",
199                             format_text(data, linelen));
200                 }
201                 offset += linelen;
202                 data = lineend;
203         }
204
205         if (is_sdp) {
206                 dissect_sdp(pd, offset, fd, tree);
207                 if (check_col(fd, COL_PROTOCOL))
208                         col_add_str(fd, COL_PROTOCOL, "RTSP/SDP");
209         }
210         else if (rtsp_tree && data < dataend) {
211                 proto_tree_add_text(rtsp_tree, offset, END_OF_FRAME,
212                     "Data (%d bytes)", END_OF_FRAME);
213         }
214 }
215
216 const char *rtsp_methods[] = {
217         "DESCRIBE", "ANNOUNCE", "GET_PARAMETER", "OPTIONS",
218         "PAUSE", "PLAY", "RECORD", "REDIRECT", "SETUP",
219         "SET_PARAMETER", "TEARDOWN"
220 };
221 const int rtsp_nmethods = sizeof(rtsp_methods) / sizeof(*rtsp_methods);
222
223 static int
224 is_rtsp_request_or_reply(const u_char *data, int linelen)
225 {
226         int             ii;
227         size_t          len;
228
229         /* Reply */
230         if (linelen >= 5 && !strncasecmp("RTSP/", data, 5))
231                 return TRUE;
232
233         /* Request Methods */
234         for (ii = 0; ii < rtsp_nmethods; ii++) {
235                 len = strlen(rtsp_methods[ii]);
236                 if (linelen >= len && !strncasecmp(rtsp_methods[ii], data, len))
237                         return TRUE;
238         }
239
240         return FALSE;
241 }
242
243 void
244 proto_register_rtsp(void)
245 {
246 /*        static hf_register_info hf[] = {
247                 { &variable,
248                 { "Name",           "rtsp.abbreviation", TYPE, VALS_POINTER }},
249         };*/
250
251         proto_rtsp = proto_register_protocol("Real Time Streaming Protocol", "rtsp");
252  /*       proto_register_field_array(proto_rtsp, hf, array_length(hf));*/
253 }