Initial revision
[sip-router] / msg_parser.c
1 /*
2  * $Id$
3  *
4  * sip msg. header proxy parser 
5  *
6  */
7
8 #include "msg_parser.h"
9 #include "string.h"
10
11 #include "parser_f.h"
12 #include "dprint.h"
13
14
15
16 /* parses the first line, returns pointer to  next line  & fills fl;
17    also  modifies buffer (to avoid extra copy ops) */
18 char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
19 {
20         
21         char *tmp;
22         char* second;
23         char* third;
24         char* nl;
25         int offset;
26         
27         /* grammar:
28                 request  =  method SP uri SP version CRLF
29                 response =  version SP status  SP reason  CRLF
30                 (version = "SIP/2.0")
31         */
32         
33
34         /* see if it's a reply (status) */
35         tmp=eat_token(buffer, len);
36         if (tmp==buffer){
37                 DPrint("ERROR: empty  or bad first line\n");
38                 goto error1;
39         }
40         if ((strlen(SIP_VERSION)==(tmp-buffer)) &&
41                 (memcmp(buffer,SIP_VERSION,tmp-buffer)==0)){
42                 
43                 fl->type=SIP_REPLY;
44         }else{
45                 fl->type=SIP_REQUEST;
46         }
47         
48         offset=tmp-buffer;
49         second=eat_space(tmp, len-offset);
50         offset+=second-tmp;
51         if (second==tmp){
52                 goto error;
53         }
54         *tmp=0; /* mark the end of the token */
55         fl->u.request.method=buffer;
56         
57         /* next element */
58         tmp=eat_token(second, len-offset);
59         offset+=tmp-second;
60         third=eat_space(tmp, len-offset);
61         offset+=third-tmp;
62         if(third==tmp){
63                 goto error;
64         }
65         *tmp=0; /* mark the end of the token */
66         fl->u.request.uri=second;
67         /*  last part */
68         tmp=eat_token(third,len-offset);
69         offset+=tmp-third;
70         if (tmp==third){
71                 goto error;
72         }
73         if (! is_empty(tmp, len-offset)){               
74                 goto error;
75         }
76         nl=eat_line(tmp,len-offset);
77         *tmp=0;
78         fl->u.request.version=third;
79         
80         return nl;
81
82 error:
83         DPrint("ERROR: bad %s first line\n", 
84                 (fl->type==SIP_REPLY)?"reply(status)":"request");
85 error1:
86         fl->type=SIP_INVALID;
87         DPrint("ERROR: at line 0 char %d\n", offset);
88         /* skip  line */
89         nl=eat_line(buffer,len);
90         return nl;
91 }
92
93
94 /* returns integer field name type */
95 int field_name(char *s)
96 {
97         if ((strcmp(s, "Via")==0 )||(strcmp(s,"v")==0))
98                 return  HDR_VIA;
99         if ((strcmp(s, "To")==0)||(strcmp(s,"t")==0))
100                 return HDR_TO;
101         return HDR_OTHER;
102 }
103
104
105
106
107 /* returns pointer to next header line, and fill hdr_f */
108 char* get_hdr_field(char *buffer, unsigned int len, struct hdr_field*  hdr_f)
109 {
110         /* grammar (rfc822):
111                 field = field-name ":" field-body CRLF
112                 field-body = text [ CRLF SP field-body ]
113            (CRLF in the field body must be removed)
114         */
115
116         char* tmp;
117         char* nl;
118         char* body;
119         int offset;
120
121         if ((*buffer=='\n')||(*buffer=='\r')){
122                 /* double crlf */
123                 tmp=eat_line(buffer,len);
124                 hdr_f->type=HDR_EOH;
125                 return tmp;
126         }
127         
128         tmp=eat_token2(buffer, len, ':');
129         if ((tmp==buffer) || (tmp-buffer==len) ||
130                 (is_empty(buffer, tmp-buffer-1))|| (*tmp!=':')){
131                 hdr_f->type=HDR_ERROR;
132                 goto error;
133         }
134         *tmp=0;
135         hdr_f->type=field_name(buffer);
136         body= ++tmp;
137         hdr_f->name=buffer;
138         offset=tmp-buffer;
139         /* get all the lines in this field  body */
140         do{
141                 nl=eat_line(tmp, len-offset);
142                 offset+=nl-tmp;
143                 tmp=nl;
144         
145         }while( (*tmp==' ' ||  *tmp=='\t') && (offset<len) );
146         if (offset==len){
147                 hdr_f->type=HDR_ERROR;
148                 DPrint("ERROR: field body too  long\n");
149                 goto error;
150         }
151         *(tmp-1)=0; /* should be an LF */
152         hdr_f->body=body;
153 error:
154         return tmp;
155 }
156
157
158
159 char* parse_hostport(char* buf, char** host, short int* port)
160 {
161         char *tmp;
162         char *invalid;
163         
164         *host=buf;
165         for(tmp=buf;(*tmp)&&(*tmp!=':');tmp++);
166         if (*tmp==0){
167                 *port=0;
168         }else{
169                 *tmp=0;
170                 invalid=0;
171                 *port=strtol(tmp+1, &invalid, 10);
172                 if ((invalid!=0)&&(*invalid)){
173                         DPrint("ERROR: hostport: trailing chars in port number: %s(%x)\n",
174                                         invalid, invalid);
175                         /* report error? */
176                 }
177         }
178         return *host;
179 }
180
181
182
183 /* parses a via body, returns next via (for compact vias) & fills vb,
184  * the buffer should be null terminated! */
185 char* parse_via_body(char* buffer,unsigned int len, struct via_body * vb)
186 {
187         /* format: sent-proto sent-by  *(";" params) [comment] 
188
189                    sent-proto = name"/"version"/"transport
190                    sent-by    = host [":" port]
191                    
192         */
193
194         char* tmp;
195         char *name,*version, *transport, *comment, *params, *hostport;
196         char * next_via;
197         char * host;
198         short int port;
199         int offset;
200         
201
202         name=version=transport=comment=params=hostport=next_via=host=0;
203         name=eat_space(buffer, len);
204         if (name-buffer==len) goto error;
205         offset=name-buffer;
206         tmp=name;
207
208         version=eat_token2(tmp,len-offset,'/');
209         if (version+1-buffer>=len) goto error;
210         *version=0;
211         version++;
212         offset+=version-tmp;
213         
214         transport=eat_token2(tmp,len-offset,'/');
215         if (transport+1-buffer>=len) goto error;
216         *transport=0;
217         transport++;
218         offset+=transport-tmp;
219         
220         tmp=eat_token(transport,len-offset);
221         if (tmp+1-buffer>=len) goto error;
222         *tmp=0;
223         tmp++;
224         offset+=tmp-transport;
225         
226         hostport=eat_space(tmp,len-offset);
227         if (hostport+1-buffer>=len) goto error;
228         offset+=hostport-tmp;
229
230         /* find end of hostport */
231         for(tmp=hostport; (tmp-buffer)<len &&
232                         (*tmp!=' ')&&(*tmp!=';')&&(*tmp!=','); tmp++);
233         if (tmp-buffer<len){
234                 switch (*tmp){
235                         case ' ':
236                                 *tmp=0;
237                                 /*the rest is comment? */
238                                 if (tmp+1-buffer<len){
239                                         tmp++;
240                                         comment=tmp;
241                                         /* eat the comment */
242                                         for(;((tmp-buffer)<len)&&
243                                                 (*tmp!=',');tmp++);
244                                         /* mark end of compact via (also end of comment)*/
245                                         if (tmp-buffer<len){
246                                                 *tmp=0;
247                                         }else break;
248                                         /* eat space & ',' */
249                                         for(tmp=tmp+1;((tmp-buffer)<len)&&
250                                                 (*tmp==' '|| *tmp==',');tmp++);
251                                         
252                                 }
253                                 break;
254
255                         case ';':
256                                 *tmp=0;
257                                 if (tmp+1-buffer>=len) goto error;
258                                 tmp++;
259                                 params=tmp;
260                                 /* eat till end, first space  or ',' */
261                                 for(;((tmp-buffer)<len)&&
262                                         (*tmp!=' '&& *tmp!=',');tmp++);
263                                 if (tmp-buffer==len)  break;
264                                 if (*tmp==' '){
265                                         /* eat comment */
266                                         *tmp=0;
267                                         tmp++;
268                                         comment=tmp;
269                                         for(;((tmp-buffer)<len)&&
270                                                 (*tmp!=',');tmp++);
271                                         if (tmp-buffer==len)  break;
272                                 }
273                                 /* mark end of via*/
274                                 *tmp=0;
275                                 /* eat space & ',' */
276                                 for(tmp=tmp+1;((tmp-buffer)<len)&&
277                                         (*tmp==' '|| *tmp==',');tmp++);
278                                 break;
279
280                         case ',':
281                                 *tmp=0;
282                                 if (tmp+1-buffer<len){
283                                         /* eat space and ',' */
284                                         for(tmp=tmp+1; 
285                                                 ((tmp-buffer)<len)&&
286                                                 (*tmp==' '|| *tmp==',');
287                                            tmp++);
288                                 }
289                 }
290         }
291         /* if we are not at the end of the body => we found another compact via */
292         if (tmp-buffer<len) next_via=tmp;
293         
294         /* parse hostport */
295         parse_hostport(hostport, &host, &port);
296         vb->name=name;
297         vb->version=version;
298         vb->transport=transport;
299         vb->host=host;
300         vb->port=port;
301         vb->params=params;
302         vb->comment=comment;
303         vb->next=next_via;
304         vb->error=VIA_PARSE_OK;
305
306         
307         /* tmp points to end of body or to next via (if compact)*/
308         
309         return tmp;
310
311 error:
312         vb->error=VIA_PARSE_ERROR;
313         return tmp;
314 }
315