- added special callbacks for non-sip msg (e.g http), They are called every
[sip-router] / parser / parse_fline.c
1 /*
2  * $Id$
3  * 
4  * sip first line parsing automaton
5  * 
6  *
7  * Copyright (C) 2001-2003 FhG Fokus
8  *
9  * This file is part of ser, a free SIP server.
10  *
11  * ser is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * For a license to use the ser software under conditions
17  * other than those described here, or to purchase support for this
18  * software, please contact iptel.org by e-mail at the following addresses:
19  *    info@iptel.org
20  *
21  * ser is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License 
27  * along with this program; if not, write to the Free Software 
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  *
30  * History:
31  * ---------
32  * 2003-02-28 scratchpad compatibility abandoned (jiri)
33  * 2003-01-28: removed 0-terminators from first line (jiri)
34  * 2003-04-26 ZSW (jiri)
35  */
36
37
38 #include "../comp_defs.h"
39 #include "../dprint.h"
40 #include "msg_parser.h"
41 #include "parser_f.h"
42 #include "../mem/mem.h"
43 #include "../ut.h"
44
45 #define HTTP_REPLY_HACK /* allow HTTP replies */
46
47 /* grammar:
48         request  =  method SP uri SP version CRLF
49         response =  version SP status  SP reason  CRLF
50         (version = "SIP/2.0")
51 */
52
53
54 /* parses the first line, returns pointer to  next line  & fills fl;
55    also  modifies buffer (to avoid extra copy ops) */
56 char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
57 {
58         
59         char *tmp;
60         char* second;
61         char* third;
62         char* nl;
63         int offset;
64         /* int l; */
65         char* end;
66         char s1,s2,s3;
67         char *prn;
68         unsigned int t;
69
70         /* grammar:
71                 request  =  method SP uri SP version CRLF
72                 response =  version SP status  SP reason  CRLF
73                 (version = "SIP/2.0")
74         */
75         
76
77         end=buffer+len;
78         /* see if it's a reply (status) */
79
80         /* jku  -- parse well-known methods */
81
82         /* drop messages which are so short they are for sure useless;
83            utilize knowledge of minimum size in parsing the first
84            token 
85         */
86         if (len <=16 ) {
87                 LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
88                 goto error1;
89         }
90
91         tmp=buffer;
92         /* is it perhaps a reply, ie does it start with "SIP...." ? */
93         if (    (*tmp=='S' || *tmp=='s') && 
94                 strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
95                 (*(tmp+SIP_VERSION_LEN)==' ')) {
96                         fl->type=SIP_REPLY;
97                         fl->u.reply.version.len=SIP_VERSION_LEN;
98                         tmp=buffer+SIP_VERSION_LEN;
99         } else IFISMETHOD( INVITE, 'I' )
100         else IFISMETHOD( CANCEL, 'C')
101         else IFISMETHOD( ACK, 'A' )
102         else IFISMETHOD( BYE, 'B' ) 
103         else IFISMETHOD( INFO, 'I' )
104         else IFISMETHOD( REGISTER, 'R')
105         else IFISMETHOD( SUBSCRIBE, 'S')
106         else IFISMETHOD( NOTIFY, 'N')
107         /* if you want to add another method XXX, include METHOD_XXX in
108            H-file (this is the value which you will take later in
109            processing and define XXX_LEN as length of method name;
110            then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
111            latter; everything must be capitals
112         */
113         else {
114                 /* neither reply, nor any of known method requests, 
115                    let's believe it is an unknown method request
116                 */
117                 tmp=eat_token_end(buffer,buffer+len);
118                 if ((tmp==buffer)||(tmp>=end)){
119                         LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
120                         goto error1;
121                 }
122                 if (*tmp!=' ') {
123                         LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
124                         goto error1;
125                 }
126                 fl->type=SIP_REQUEST;
127                 fl->u.request.method_value=METHOD_OTHER;
128                 fl->u.request.method.len=tmp-buffer;
129         }
130
131
132         /* identifying type of message over now; 
133            tmp points at space after; go ahead */
134
135         fl->u.request.method.s=buffer;  /* store ptr to first token */
136         second=tmp+1;                   /* jump to second token */
137         offset=second-buffer;
138
139 /* EoJku */
140         
141         /* next element */
142         tmp=eat_token_end(second, second+len-offset);
143         if (tmp>=end){
144                 goto error;
145         }
146         offset+=tmp-second;
147         third=eat_space_end(tmp, tmp+len-offset);
148         offset+=third-tmp;
149         if ((third==tmp)||(tmp>=end)){
150                 goto error;
151         }
152         fl->u.request.uri.s=second;
153         fl->u.request.uri.len=tmp-second;
154
155         /* jku: parse status code */
156         if (fl->type==SIP_REPLY) {
157                 if (fl->u.request.uri.len!=3) {
158                         LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %.*s\n",
159                                 fl->u.request.uri.len, ZSW(second) );
160                         goto error;
161                 }
162                 s1=*second; s2=*(second+1);s3=*(second+2);
163                 if (s1>='0' && s1<='9' && 
164                     s2>='0' && s2<='9' &&
165                     s3>='0' && s3<='9' ) {
166                         fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
167                 } else {
168                         LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %.*s\n",
169                                 fl->u.request.uri.len, ZSW(second) );
170                         goto error;
171                 }
172         }
173         /* EoJku */
174
175         /*  last part: for a request it must be the version, for a reply
176          *  it can contain almost anything, including spaces, so we don't care
177          *  about it*/
178         if (fl->type==SIP_REQUEST){
179                 tmp=eat_token_end(third,third+len-offset);
180                 offset+=tmp-third;
181                 if ((tmp==third)||(tmp>=end)){
182                         goto error;
183                 }
184                 if (! is_empty_end(tmp, tmp+len-offset)){
185                         goto error;
186                 }
187         }else{
188                 tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
189                                                                                                   ('\n' or '\r') */
190                 if (tmp>=end){ /* no crlf in packet => invalid */
191                         goto error;
192                 }
193                 offset+=tmp-third;
194         }
195         nl=eat_line(tmp,len-offset);
196         if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
197                 goto error;
198         }
199         fl->u.request.version.s=third;
200         fl->u.request.version.len=tmp-third;
201         fl->len=nl-buffer;
202
203         return nl;
204
205 error:
206         LOG(L_INFO, "ERROR:parse_first_line: bad %s first line\n",
207                 (fl->type==SIP_REPLY)?"reply(status)":"request");
208
209         LOG(L_INFO, "ERROR: at line 0 char %d: \n", offset );
210         prn=pkg_malloc( offset );
211         if (prn) {
212                 for (t=0; t<offset; t++)
213                         if (*(buffer+t)) *(prn+t)=*(buffer+t);
214                         else *(prn+t)='°';
215                 LOG(L_INFO, "ERROR: parsed so far: %.*s\n", offset, ZSW(prn) );
216                 pkg_free( prn );
217         };
218 error1:
219         fl->type=SIP_INVALID;
220         LOG(L_INFO, "ERROR:parse_first_line: bad message\n");
221         /* skip  line */
222         nl=eat_line(buffer,len);
223         return nl;
224 }