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