/src/opensips/parser/parse_fline.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * sip first line parsing automaton |
3 | | * |
4 | | * Copyright (C) 2001-2003 FhG Fokus |
5 | | * |
6 | | * This file is part of opensips, a free SIP server. |
7 | | * |
8 | | * opensips is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * opensips is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | * |
22 | | * History: |
23 | | * --------- |
24 | | * 2003-02-28 scratchpad compatibility abandoned (jiri) |
25 | | * 2003-01-28: removed 0-terminators from first line (jiri) |
26 | | * 2003-04-26 ZSW (jiri) |
27 | | */ |
28 | | |
29 | | |
30 | | #include "../dprint.h" |
31 | | #include "msg_parser.h" |
32 | | #include "parser_f.h" |
33 | | #include "parse_methods.h" |
34 | | #include "../mem/mem.h" |
35 | | #include "../ut.h" |
36 | | |
37 | | /* grammar: |
38 | | request = method SP uri SP version CRLF |
39 | | response = version SP status SP reason CRLF |
40 | | (version = "SIP/2.0") |
41 | | */ |
42 | | |
43 | | /*known methods: INVITE, ACK, CANCEL, BYE*/ |
44 | | |
45 | | enum { START, |
46 | | INVITE1, INVITE2, INVITE3, INVITE4, INVITE5, |
47 | | ACK1, ACK2, |
48 | | CANCEL1, CANCEL2, CANCEL3, CANCEL4, CANCEL5, |
49 | | BYE1, BYE2, |
50 | | SIP1, SIP2, SIP3, SIP4, SIP5, SIP6, |
51 | | FIN_INVITE = 100, FIN_ACK, FIN_CANCEL, FIN_BYE, FIN_SIP, |
52 | | P_METHOD = 200, L_URI, P_URI, L_VER, |
53 | | VER1, VER2, VER3, VER4, VER5, VER6, FIN_VER, |
54 | | L_STATUS, P_STATUS, L_REASON, P_REASON, |
55 | | L_LF, F_CR, F_LF |
56 | | }; |
57 | | |
58 | | |
59 | | #ifdef _CURRENTLY_UNUSED |
60 | | char* parse_fline(char* buffer, char* end, struct msg_start* fl) |
61 | | { |
62 | | char* tmp; |
63 | | register int state; |
64 | | unsigned short stat; |
65 | | |
66 | | stat=0; |
67 | | fl->type=SIP_REQUEST; |
68 | | state=START; |
69 | | for(tmp=buffer;tmp<end;tmp++){ |
70 | | switch(*tmp){ |
71 | | case ' ': |
72 | | case '\t': |
73 | | switch(state){ |
74 | | case START: /*allow space at the beginning, although not |
75 | | legal*/ |
76 | | break; |
77 | | case L_URI: |
78 | | case L_VER: |
79 | | case L_STATUS: |
80 | | case L_REASON: |
81 | | case L_LF: |
82 | | /*eat space*/ |
83 | | break; |
84 | | case FIN_INVITE: |
85 | | *tmp=0; |
86 | | fl->u.request.method.len=tmp-fl->u.request.method.s; |
87 | | fl->u.request.method_value=METHOD_INVITE; |
88 | | state=L_URI; |
89 | | break; |
90 | | case FIN_ACK: |
91 | | *tmp=0; |
92 | | fl->u.request.method.len=tmp-fl->u.request.method.s; |
93 | | fl->u.request.method_value=METHOD_ACK; |
94 | | state=L_URI; |
95 | | break; |
96 | | case FIN_CANCEL: |
97 | | *tmp=0; |
98 | | fl->u.request.method.len=tmp-fl->u.request.method.s; |
99 | | fl->u.request.method_value=METHOD_CANCEL; |
100 | | state=L_URI; |
101 | | break; |
102 | | case FIN_BYE: |
103 | | *tmp=0; |
104 | | fl->u.request.method.len=tmp-fl->u.request.method.s; |
105 | | fl->u.request.method_value=METHOD_BYE; |
106 | | state=L_URI; |
107 | | break; |
108 | | case FIN_SIP: |
109 | | *tmp=0; |
110 | | fl->u.reply.version.len=tmp-fl->u.reply.version.s; |
111 | | state=L_STATUS; |
112 | | fl->type=SIP_REPLY; |
113 | | break; |
114 | | case P_URI: |
115 | | *tmp=0; |
116 | | fl->u.request.uri.len=tmp-fl->u.request.uri.s; |
117 | | state=L_VER; |
118 | | break; |
119 | | case FIN_VER: |
120 | | *tmp=0; |
121 | | fl->u.request.version.len=tmp-fl->u.request.version.s; |
122 | | state=L_LF; |
123 | | break; |
124 | | case P_STATUS: |
125 | | *tmp=0; |
126 | | fl->u.reply.status.len=tmp-fl->u.reply.status.s; |
127 | | state=L_REASON; |
128 | | break; |
129 | | case P_REASON: |
130 | | /* *tmp=0; |
131 | | fl->u.reply.reason.len=tmp-fl->u.reply.reason.s; |
132 | | */ |
133 | | break; |
134 | | case VER1: |
135 | | case VER2: |
136 | | case VER3: |
137 | | case VER4: |
138 | | case VER5: |
139 | | case VER6: |
140 | | LM_ERR("invalid version in request\n"); |
141 | | goto error; |
142 | | case P_METHOD: |
143 | | default: |
144 | | *tmp=0; |
145 | | fl->u.request.method.len=tmp-fl->u.request.method.s; |
146 | | fl->u.request.method_value=METHOD_OTHER; |
147 | | state=L_URI; |
148 | | } |
149 | | break; |
150 | | case 's': |
151 | | case 'S': |
152 | | switch(state){ |
153 | | case START: |
154 | | state=SIP1; |
155 | | fl->u.reply.version.s=tmp; |
156 | | break; |
157 | | case P_URI: |
158 | | case P_REASON: |
159 | | case P_METHOD: |
160 | | break; |
161 | | case L_REASON: |
162 | | fl->u.reply.reason.s=tmp; |
163 | | state=P_REASON; |
164 | | break; |
165 | | case P_STATUS: |
166 | | case L_STATUS: |
167 | | LM_ERR("non-number character <%c> in request" |
168 | | "status\n", *tmp); |
169 | | goto error; |
170 | | case L_LF: |
171 | | LM_ERR("invalid character <%c> in request\n", *tmp); |
172 | | goto error; |
173 | | case L_URI: |
174 | | fl->u.request.uri.s=tmp; |
175 | | state=P_URI; |
176 | | break; |
177 | | case L_VER: |
178 | | fl->u.request.version.s=tmp; |
179 | | state=VER1; |
180 | | break; |
181 | | case VER1: |
182 | | case VER2: |
183 | | case VER3: |
184 | | case VER4: |
185 | | case VER5: |
186 | | case VER6: |
187 | | case FIN_VER: |
188 | | LM_ERR("invalid version in request\n"); |
189 | | goto error; |
190 | | default: |
191 | | state=P_METHOD; |
192 | | } |
193 | | break; |
194 | | |
195 | | case 'i': |
196 | | case 'I': |
197 | | switch(state){ |
198 | | case START: |
199 | | state=INVITE1; |
200 | | fl->u.request.method.s=tmp; |
201 | | break; |
202 | | case INVITE3: |
203 | | state=INVITE4; |
204 | | break; |
205 | | case SIP1: |
206 | | state=SIP2; |
207 | | break; |
208 | | case P_URI: |
209 | | case P_REASON: |
210 | | case P_METHOD: |
211 | | break; |
212 | | case L_REASON: |
213 | | fl->u.reply.reason.s=tmp; |
214 | | state=P_REASON; |
215 | | break; |
216 | | case P_STATUS: |
217 | | case L_STATUS: |
218 | | LM_ERR("non-number " |
219 | | "character <%c> in request status\n", *tmp); |
220 | | goto error; |
221 | | case L_LF: |
222 | | LM_ERR("invalid " |
223 | | "character <%c> in request\n", *tmp); |
224 | | goto error; |
225 | | case L_URI: |
226 | | fl->u.request.uri.s=tmp; |
227 | | state=P_URI; |
228 | | break; |
229 | | case VER1: |
230 | | state=VER2; |
231 | | break; |
232 | | case L_VER: |
233 | | case VER2: |
234 | | case VER3: |
235 | | case VER4: |
236 | | case VER5: |
237 | | case VER6: |
238 | | case FIN_VER: |
239 | | LM_ERR("invalid version in request\n"); |
240 | | goto error; |
241 | | default: |
242 | | state=P_METHOD; |
243 | | } |
244 | | break; |
245 | | |
246 | | case 'p': |
247 | | case 'P': |
248 | | switch(state){ |
249 | | case START: |
250 | | state=P_METHOD; |
251 | | fl->u.request.method.s=tmp; |
252 | | break; |
253 | | case SIP2: |
254 | | state=SIP3; |
255 | | break; |
256 | | case P_URI: |
257 | | case P_REASON: |
258 | | case P_METHOD: |
259 | | break; |
260 | | case L_REASON: |
261 | | fl->u.reply.reason.s=tmp; |
262 | | state=P_REASON; |
263 | | break; |
264 | | case P_STATUS: |
265 | | case L_STATUS: |
266 | | LM_ERR("non-number " |
267 | | "character <%c> in request status\n", *tmp); |
268 | | goto error; |
269 | | case L_LF: |
270 | | LM_ERR("invalid " |
271 | | "character <%c> in request\n", *tmp); |
272 | | goto error; |
273 | | case L_URI: |
274 | | fl->u.request.uri.s=tmp; |
275 | | state=P_URI; |
276 | | break; |
277 | | case VER2: |
278 | | state=VER3; |
279 | | break; |
280 | | case L_VER: |
281 | | case VER1: |
282 | | case VER3: |
283 | | case VER4: |
284 | | case VER5: |
285 | | case VER6: |
286 | | case FIN_VER: |
287 | | LM_ERR("invalid version in request\n"); |
288 | | goto error; |
289 | | default: |
290 | | state=P_METHOD; |
291 | | } |
292 | | break; |
293 | | |
294 | | |
295 | | case '/': |
296 | | switch(state){ |
297 | | case START: |
298 | | state=P_METHOD; |
299 | | fl->u.request.method.s=tmp; |
300 | | break; |
301 | | case SIP3: |
302 | | state=SIP4; |
303 | | break; |
304 | | case P_URI: |
305 | | case P_REASON: |
306 | | case P_METHOD: |
307 | | break; |
308 | | case L_REASON: |
309 | | fl->u.reply.reason.s=tmp; |
310 | | state=P_REASON; |
311 | | break; |
312 | | case P_STATUS: |
313 | | case L_STATUS: |
314 | | LM_ERR("non-number " |
315 | | "character <%c> in request status\n", *tmp); |
316 | | goto error; |
317 | | case L_LF: |
318 | | LM_ERR("invalid " |
319 | | "character <%c> in request\n", *tmp); |
320 | | goto error; |
321 | | case L_URI: |
322 | | fl->u.request.uri.s=tmp; |
323 | | state=P_URI; |
324 | | break; |
325 | | case VER3: |
326 | | state=VER4; |
327 | | break; |
328 | | case L_VER: |
329 | | case VER1: |
330 | | case VER2: |
331 | | case VER4: |
332 | | case VER5: |
333 | | case VER6: |
334 | | case FIN_VER: |
335 | | LM_ERR("invalid version in request\n"); |
336 | | goto error; |
337 | | default: |
338 | | state=P_METHOD; |
339 | | } |
340 | | break; |
341 | | |
342 | | case '2': |
343 | | switch(state){ |
344 | | case START: |
345 | | state=P_METHOD; |
346 | | fl->u.request.method.s=tmp; |
347 | | break; |
348 | | case SIP4: |
349 | | state=SIP5; |
350 | | break; |
351 | | case P_URI: |
352 | | case P_REASON: |
353 | | case P_METHOD: |
354 | | break; |
355 | | case L_REASON: |
356 | | fl->u.reply.reason.s=tmp; |
357 | | state=P_REASON; |
358 | | break; |
359 | | case P_STATUS: |
360 | | stat=stat*10+*tmp-'0'; |
361 | | break; |
362 | | case L_STATUS: |
363 | | stat=*tmp-'0'; |
364 | | fl->u.reply.status.s=tmp; |
365 | | break; |
366 | | case L_LF: |
367 | | LM_ERR("invalid " |
368 | | "character <%c> in request\n", *tmp); |
369 | | goto error; |
370 | | case L_URI: |
371 | | fl->u.request.uri.s=tmp; |
372 | | state=P_URI; |
373 | | break; |
374 | | case VER4: |
375 | | state=VER5; |
376 | | break; |
377 | | case L_VER: |
378 | | case VER1: |
379 | | case VER2: |
380 | | case VER3: |
381 | | case VER5: |
382 | | case VER6: |
383 | | case FIN_VER: |
384 | | LM_ERR("invalid version in request\n"); |
385 | | goto error; |
386 | | default: |
387 | | state=P_METHOD; |
388 | | } |
389 | | break; |
390 | | |
391 | | case '.': |
392 | | switch(state){ |
393 | | case START: |
394 | | state=P_METHOD; |
395 | | fl->u.request.method.s=tmp; |
396 | | break; |
397 | | case SIP5: |
398 | | state=SIP6; |
399 | | break; |
400 | | case P_URI: |
401 | | case P_REASON: |
402 | | case P_METHOD: |
403 | | break; |
404 | | case L_REASON: |
405 | | fl->u.reply.reason.s=tmp; |
406 | | state=P_REASON; |
407 | | break; |
408 | | case P_STATUS: |
409 | | case L_STATUS: |
410 | | LM_ERR("non-number " |
411 | | "character <%c> in request status\n", *tmp); |
412 | | goto error; |
413 | | case L_LF: |
414 | | LM_ERR("invalid " |
415 | | "character <%c> in request\n", *tmp); |
416 | | goto error; |
417 | | case L_URI: |
418 | | fl->u.request.uri.s=tmp; |
419 | | state=P_URI; |
420 | | break; |
421 | | case VER5: |
422 | | state=VER6; |
423 | | break; |
424 | | case L_VER: |
425 | | case VER1: |
426 | | case VER2: |
427 | | case VER3: |
428 | | case VER4: |
429 | | case VER6: |
430 | | case FIN_VER: |
431 | | LM_ERR("invalid version in request\n"); |
432 | | goto error; |
433 | | default: |
434 | | state=P_METHOD; |
435 | | } |
436 | | break; |
437 | | |
438 | | case '0': |
439 | | switch(state){ |
440 | | case START: |
441 | | state=P_METHOD; |
442 | | fl->u.request.method.s=tmp; |
443 | | break; |
444 | | case SIP6: |
445 | | state=FIN_SIP; |
446 | | break; |
447 | | case P_URI: |
448 | | case P_REASON: |
449 | | case P_METHOD: |
450 | | break; |
451 | | case L_REASON: |
452 | | fl->u.reply.reason.s=tmp; |
453 | | state=P_REASON; |
454 | | break; |
455 | | case P_STATUS: |
456 | | stat=stat*10; |
457 | | break; |
458 | | case L_STATUS: |
459 | | stat=0; |
460 | | fl->u.reply.status.s=tmp; |
461 | | break; |
462 | | case L_LF: |
463 | | LM_ERR("invalid " |
464 | | "character <%c> in request\n", *tmp); |
465 | | goto error; |
466 | | case L_URI: |
467 | | fl->u.request.uri.s=tmp; |
468 | | state=P_URI; |
469 | | break; |
470 | | case VER6: |
471 | | state=FIN_VER; |
472 | | break; |
473 | | case L_VER: |
474 | | case VER1: |
475 | | case VER2: |
476 | | case VER3: |
477 | | case VER4: |
478 | | case VER5: |
479 | | case FIN_VER: |
480 | | LM_ERR("invalid version " |
481 | | " in request\n"); |
482 | | goto error; |
483 | | default: |
484 | | state=P_METHOD; |
485 | | } |
486 | | break; |
487 | | |
488 | | case 'n': |
489 | | case 'N': |
490 | | switch(state){ |
491 | | case START: |
492 | | state=P_METHOD; |
493 | | fl->u.request.method.s=tmp; |
494 | | break; |
495 | | case INVITE1: |
496 | | state=INVITE2; |
497 | | break; |
498 | | case CANCEL2: |
499 | | state=CANCEL3; |
500 | | break; |
501 | | case P_URI: |
502 | | case P_REASON: |
503 | | case P_METHOD: |
504 | | break; |
505 | | case L_REASON: |
506 | | fl->u.reply.reason.s=tmp; |
507 | | state=P_REASON; |
508 | | break; |
509 | | case P_STATUS: |
510 | | case L_STATUS: |
511 | | LM_ERR("non-number " |
512 | | "character <%c> in request status\n", *tmp); |
513 | | goto error; |
514 | | case L_LF: |
515 | | LM_ERR("invalid " |
516 | | "character <%c> in request\n", *tmp); |
517 | | goto error; |
518 | | case L_URI: |
519 | | fl->u.request.uri.s=tmp; |
520 | | state=P_URI; |
521 | | break; |
522 | | case L_VER: |
523 | | case VER1: |
524 | | case VER2: |
525 | | case VER3: |
526 | | case VER4: |
527 | | case VER5: |
528 | | case VER6: |
529 | | case FIN_VER: |
530 | | LM_ERR("invalid version in request\n"); |
531 | | goto error; |
532 | | default: |
533 | | state=P_METHOD; |
534 | | } |
535 | | break; |
536 | | |
537 | | case 'v': |
538 | | case 'V': |
539 | | switch(state){ |
540 | | case START: |
541 | | state=P_METHOD; |
542 | | fl->u.request.method.s=tmp; |
543 | | break; |
544 | | case INVITE2: |
545 | | state=INVITE3; |
546 | | break; |
547 | | case P_URI: |
548 | | case P_REASON: |
549 | | case P_METHOD: |
550 | | break; |
551 | | case L_REASON: |
552 | | fl->u.reply.reason.s=tmp; |
553 | | state=P_REASON; |
554 | | break; |
555 | | case P_STATUS: |
556 | | case L_STATUS: |
557 | | LM_ERR("non-number " |
558 | | "character <%c> in request status\n", *tmp); |
559 | | goto error; |
560 | | case L_LF: |
561 | | LM_ERR("invalid " |
562 | | "character <%c> in request\n", *tmp); |
563 | | goto error; |
564 | | case L_URI: |
565 | | fl->u.request.uri.s=tmp; |
566 | | state=P_URI; |
567 | | break; |
568 | | case L_VER: |
569 | | case VER1: |
570 | | case VER2: |
571 | | case VER3: |
572 | | case VER4: |
573 | | case VER5: |
574 | | case VER6: |
575 | | case FIN_VER: |
576 | | LM_ERR("invalid version in request\n"); |
577 | | goto error; |
578 | | default: |
579 | | state=P_METHOD; |
580 | | } |
581 | | break; |
582 | | |
583 | | case 't': |
584 | | case 'T': |
585 | | switch(state){ |
586 | | case START: |
587 | | state=P_METHOD; |
588 | | fl->u.request.method.s=tmp; |
589 | | break; |
590 | | case INVITE4: |
591 | | state=INVITE5; |
592 | | break; |
593 | | case P_URI: |
594 | | case P_REASON: |
595 | | case P_METHOD: |
596 | | break; |
597 | | case L_REASON: |
598 | | fl->u.reply.reason.s=tmp; |
599 | | state=P_REASON; |
600 | | break; |
601 | | case P_STATUS: |
602 | | case L_STATUS: |
603 | | LM_ERR("non-number " |
604 | | "character <%c> in request status\n", *tmp); |
605 | | goto error; |
606 | | case L_LF: |
607 | | LM_ERR("invalid " |
608 | | "character <%c> in request\n", *tmp); |
609 | | goto error; |
610 | | case L_URI: |
611 | | fl->u.request.uri.s=tmp; |
612 | | state=P_URI; |
613 | | break; |
614 | | case L_VER: |
615 | | case VER1: |
616 | | case VER2: |
617 | | case VER3: |
618 | | case VER4: |
619 | | case VER5: |
620 | | case VER6: |
621 | | case FIN_VER: |
622 | | LM_ERR("invalid version in request\n"); |
623 | | goto error; |
624 | | default: |
625 | | state=P_METHOD; |
626 | | } |
627 | | break; |
628 | | |
629 | | case 'e': |
630 | | case 'E': |
631 | | switch(state){ |
632 | | case START: |
633 | | state=P_METHOD; |
634 | | fl->u.request.method.s=tmp; |
635 | | break; |
636 | | case INVITE5: |
637 | | state=FIN_INVITE; |
638 | | break; |
639 | | case CANCEL4: |
640 | | state=CANCEL5; |
641 | | break; |
642 | | case BYE2: |
643 | | state=FIN_BYE; |
644 | | break; |
645 | | case P_URI: |
646 | | case P_REASON: |
647 | | case P_METHOD: |
648 | | break; |
649 | | case L_REASON: |
650 | | fl->u.reply.reason.s=tmp; |
651 | | state=P_REASON; |
652 | | break; |
653 | | case P_STATUS: |
654 | | case L_STATUS: |
655 | | LM_ERR("non-number " |
656 | | "character <%c> in request status\n", *tmp); |
657 | | goto error; |
658 | | case L_LF: |
659 | | LM_ERR("invalid " |
660 | | "character <%c> in request\n", *tmp); |
661 | | goto error; |
662 | | case L_URI: |
663 | | fl->u.request.uri.s=tmp; |
664 | | state=P_URI; |
665 | | break; |
666 | | case L_VER: |
667 | | case VER1: |
668 | | case VER2: |
669 | | case VER3: |
670 | | case VER4: |
671 | | case VER5: |
672 | | case VER6: |
673 | | case FIN_VER: |
674 | | LM_ERR("invalid version in request\n"); |
675 | | goto error; |
676 | | default: |
677 | | state=P_METHOD; |
678 | | } |
679 | | break; |
680 | | |
681 | | case 'a': |
682 | | case 'A': |
683 | | switch(state){ |
684 | | case START: |
685 | | state=ACK1; |
686 | | fl->u.request.method.s=tmp; |
687 | | break; |
688 | | case CANCEL1: |
689 | | state=CANCEL2; |
690 | | break; |
691 | | case BYE2: |
692 | | state=FIN_BYE; |
693 | | break; |
694 | | case P_URI: |
695 | | case P_REASON: |
696 | | case P_METHOD: |
697 | | break; |
698 | | case L_REASON: |
699 | | fl->u.reply.reason.s=tmp; |
700 | | state=P_REASON; |
701 | | break; |
702 | | case P_STATUS: |
703 | | case L_STATUS: |
704 | | LM_ERR("non-number " |
705 | | "character <%c> in request status\n", *tmp); |
706 | | goto error; |
707 | | case L_LF: |
708 | | LM_ERR("invalid " |
709 | | "character <%c> in request\n", *tmp); |
710 | | goto error; |
711 | | case L_URI: |
712 | | fl->u.request.uri.s=tmp; |
713 | | state=P_URI; |
714 | | break; |
715 | | case L_VER: |
716 | | case VER1: |
717 | | case VER2: |
718 | | case VER3: |
719 | | case VER4: |
720 | | case VER5: |
721 | | case VER6: |
722 | | case FIN_VER: |
723 | | LM_ERR("invalid version in request\n"); |
724 | | goto error; |
725 | | default: |
726 | | state=P_METHOD; |
727 | | } |
728 | | break; |
729 | | |
730 | | case 'c': |
731 | | case 'C': |
732 | | switch(state){ |
733 | | case START: |
734 | | state=CANCEL1; |
735 | | fl->u.request.method.s=tmp; |
736 | | break; |
737 | | case CANCEL3: |
738 | | state=CANCEL4; |
739 | | break; |
740 | | case ACK1: |
741 | | state=ACK2; |
742 | | break; |
743 | | case P_URI: |
744 | | case P_REASON: |
745 | | case P_METHOD: |
746 | | break; |
747 | | case L_REASON: |
748 | | fl->u.reply.reason.s=tmp; |
749 | | state=P_REASON; |
750 | | break; |
751 | | case P_STATUS: |
752 | | case L_STATUS: |
753 | | LM_ERR("non-number " |
754 | | "character <%c> in request status\n", *tmp); |
755 | | goto error; |
756 | | case L_LF: |
757 | | LM_ERR("invalid " |
758 | | "character <%c> in request\n", *tmp); |
759 | | goto error; |
760 | | case L_URI: |
761 | | fl->u.request.uri.s=tmp; |
762 | | state=P_URI; |
763 | | break; |
764 | | case L_VER: |
765 | | case VER1: |
766 | | case VER2: |
767 | | case VER3: |
768 | | case VER4: |
769 | | case VER5: |
770 | | case VER6: |
771 | | case FIN_VER: |
772 | | LM_ERR("invalid version in request\n"); |
773 | | goto error; |
774 | | default: |
775 | | state=P_METHOD; |
776 | | } |
777 | | break; |
778 | | |
779 | | case 'k': |
780 | | case 'K': |
781 | | switch(state){ |
782 | | case START: |
783 | | state=P_METHOD; |
784 | | fl->u.request.method.s=tmp; |
785 | | break; |
786 | | case ACK2: |
787 | | state=FIN_ACK; |
788 | | break; |
789 | | case P_URI: |
790 | | case P_REASON: |
791 | | case P_METHOD: |
792 | | break; |
793 | | case L_REASON: |
794 | | fl->u.reply.reason.s=tmp; |
795 | | state=P_REASON; |
796 | | break; |
797 | | case P_STATUS: |
798 | | case L_STATUS: |
799 | | LM_ERR("non-number " |
800 | | "character <%c> in request status\n", *tmp); |
801 | | goto error; |
802 | | case L_LF: |
803 | | LM_ERR("invalid " |
804 | | "character <%c> in request\n", *tmp); |
805 | | goto error; |
806 | | case L_URI: |
807 | | fl->u.request.uri.s=tmp; |
808 | | state=P_URI; |
809 | | break; |
810 | | case L_VER: |
811 | | case VER1: |
812 | | case VER2: |
813 | | case VER3: |
814 | | case VER4: |
815 | | case VER5: |
816 | | case VER6: |
817 | | case FIN_VER: |
818 | | LM_ERR("invalid version in request\n"); |
819 | | goto error; |
820 | | default: |
821 | | state=P_METHOD; |
822 | | } |
823 | | break; |
824 | | |
825 | | case 'l': |
826 | | case 'L': |
827 | | switch(state){ |
828 | | case START: |
829 | | state=P_METHOD; |
830 | | fl->u.request.method.s=tmp; |
831 | | break; |
832 | | case CANCEL5: |
833 | | state=FIN_CANCEL; |
834 | | break; |
835 | | case P_URI: |
836 | | case P_REASON: |
837 | | case P_METHOD: |
838 | | break; |
839 | | case L_REASON: |
840 | | fl->u.reply.reason.s=tmp; |
841 | | state=P_REASON; |
842 | | break; |
843 | | case P_STATUS: |
844 | | case L_STATUS: |
845 | | LM_ERR("non-number " |
846 | | "character <%c> in request status\n", *tmp); |
847 | | goto error; |
848 | | case L_LF: |
849 | | LM_ERR("invalid " |
850 | | "character <%c> in request\n", *tmp); |
851 | | goto error; |
852 | | case L_URI: |
853 | | fl->u.request.uri.s=tmp; |
854 | | state=P_URI; |
855 | | break; |
856 | | case L_VER: |
857 | | case VER1: |
858 | | case VER2: |
859 | | case VER3: |
860 | | case VER4: |
861 | | case VER5: |
862 | | case VER6: |
863 | | case FIN_VER: |
864 | | LM_ERR("invalid version in request\n"); |
865 | | goto error; |
866 | | default: |
867 | | state=P_METHOD; |
868 | | } |
869 | | break; |
870 | | |
871 | | case 'b': |
872 | | case 'B': |
873 | | switch(state){ |
874 | | case START: |
875 | | state=BYE1; |
876 | | fl->u.request.method.s=tmp; |
877 | | break; |
878 | | case P_URI: |
879 | | case P_REASON: |
880 | | case P_METHOD: |
881 | | break; |
882 | | case L_REASON: |
883 | | fl->u.reply.reason.s=tmp; |
884 | | state=P_REASON; |
885 | | break; |
886 | | case P_STATUS: |
887 | | case L_STATUS: |
888 | | LM_ERR("non-number " |
889 | | "character <%c> in request status\n", *tmp); |
890 | | goto error; |
891 | | case L_LF: |
892 | | LM_ERR("invalid " |
893 | | "character <%c> in request\n", *tmp); |
894 | | goto error; |
895 | | case L_URI: |
896 | | fl->u.request.uri.s=tmp; |
897 | | state=P_URI; |
898 | | break; |
899 | | case L_VER: |
900 | | case VER1: |
901 | | case VER2: |
902 | | case VER3: |
903 | | case VER4: |
904 | | case VER5: |
905 | | case VER6: |
906 | | case FIN_VER: |
907 | | LM_ERR("invalid version in request\n"); |
908 | | goto error; |
909 | | default: |
910 | | state=P_METHOD; |
911 | | } |
912 | | break; |
913 | | |
914 | | case 'y': |
915 | | case 'Y': |
916 | | switch(state){ |
917 | | case START: |
918 | | state=P_METHOD; |
919 | | fl->u.request.method.s=tmp; |
920 | | break; |
921 | | case BYE1: |
922 | | state=BYE2; |
923 | | break; |
924 | | case P_URI: |
925 | | case P_REASON: |
926 | | case P_METHOD: |
927 | | break; |
928 | | case L_REASON: |
929 | | fl->u.reply.reason.s=tmp; |
930 | | state=P_REASON; |
931 | | break; |
932 | | case P_STATUS: |
933 | | case L_STATUS: |
934 | | LM_ERR("non-number " |
935 | | "character <%c> in request status\n", *tmp); |
936 | | goto error; |
937 | | case L_LF: |
938 | | LM_ERR("invalid " |
939 | | "character <%c> in request\n", *tmp); |
940 | | goto error; |
941 | | case L_URI: |
942 | | fl->u.request.uri.s=tmp; |
943 | | state=P_URI; |
944 | | break; |
945 | | case L_VER: |
946 | | case VER1: |
947 | | case VER2: |
948 | | case VER3: |
949 | | case VER4: |
950 | | case VER5: |
951 | | case VER6: |
952 | | case FIN_VER: |
953 | | LM_ERR("invalid version in request\n"); |
954 | | goto error; |
955 | | default: |
956 | | state=P_METHOD; |
957 | | } |
958 | | break; |
959 | | |
960 | | case '\r': |
961 | | switch(state){ |
962 | | case P_REASON: |
963 | | *tmp=0; |
964 | | fl->u.reply.reason.len=tmp-fl->u.reply.reason.s; |
965 | | state=F_CR; |
966 | | break; |
967 | | case L_LF: |
968 | | state=F_CR; |
969 | | break; |
970 | | case FIN_VER: |
971 | | *tmp=0; |
972 | | fl->u.request.version.len=tmp-fl->u.request.version.s; |
973 | | state=F_CR; |
974 | | break; |
975 | | case L_REASON: |
976 | | state=F_CR; |
977 | | break; |
978 | | default: |
979 | | LM_ERR("invalid message\n"); |
980 | | goto error; |
981 | | } |
982 | | break; |
983 | | |
984 | | case '\n': |
985 | | switch(state){ |
986 | | case P_REASON: |
987 | | *tmp=0; |
988 | | fl->u.reply.reason.len=tmp-fl->u.reply.reason.s; |
989 | | state=F_LF; |
990 | | goto skip; |
991 | | case FIN_VER: |
992 | | *tmp=0; |
993 | | fl->u.request.version.len=tmp-fl->u.request.version.s; |
994 | | state=F_LF; |
995 | | goto skip; |
996 | | case L_REASON: |
997 | | case L_LF: |
998 | | case F_CR: |
999 | | state=F_LF; |
1000 | | goto skip; |
1001 | | default: |
1002 | | LM_ERR("invalid message\n"); |
1003 | | goto error; |
1004 | | } |
1005 | | break; |
1006 | | |
1007 | | case '1': |
1008 | | case '3': |
1009 | | case '4': |
1010 | | case '5': |
1011 | | case '6': |
1012 | | case '7': |
1013 | | case '8': |
1014 | | case '9': |
1015 | | switch(state){ |
1016 | | case START: |
1017 | | state=P_METHOD; |
1018 | | fl->u.request.method.s=tmp; |
1019 | | break; |
1020 | | case P_URI: |
1021 | | case P_REASON: |
1022 | | case P_METHOD: |
1023 | | break; |
1024 | | case L_REASON: |
1025 | | fl->u.reply.reason.s=tmp; |
1026 | | state=P_REASON; |
1027 | | break; |
1028 | | case P_STATUS: |
1029 | | stat=stat*10+*tmp-'0'; |
1030 | | break; |
1031 | | case L_STATUS: |
1032 | | stat=*tmp-'0'; |
1033 | | state=P_STATUS; |
1034 | | fl->u.reply.status.s=tmp; |
1035 | | break; |
1036 | | case L_LF: |
1037 | | LM_ERR("invalid character <%c> in request\n", *tmp); |
1038 | | goto error; |
1039 | | case L_URI: |
1040 | | fl->u.request.uri.s=tmp; |
1041 | | state=P_URI; |
1042 | | break; |
1043 | | case L_VER: |
1044 | | case VER1: |
1045 | | case VER2: |
1046 | | case VER3: |
1047 | | case VER4: |
1048 | | case VER5: |
1049 | | case VER6: |
1050 | | case FIN_VER: |
1051 | | LM_ERR("invalid version in request\n"); |
1052 | | goto error; |
1053 | | default: |
1054 | | state=P_METHOD; |
1055 | | } |
1056 | | |
1057 | | default: |
1058 | | switch(state){ |
1059 | | case START: |
1060 | | state=P_METHOD; |
1061 | | fl->u.request.method.s=tmp; |
1062 | | break; |
1063 | | case P_URI: |
1064 | | case P_REASON: |
1065 | | case P_METHOD: |
1066 | | break; |
1067 | | case L_REASON: |
1068 | | fl->u.reply.reason.s=tmp; |
1069 | | state=P_REASON; |
1070 | | break; |
1071 | | case P_STATUS: |
1072 | | case L_STATUS: |
1073 | | LM_ERR("non-number " |
1074 | | "character <%c> in request status\n", *tmp); |
1075 | | goto error; |
1076 | | case L_LF: |
1077 | | LM_ERR("invalid character <%c> in request\n", *tmp); |
1078 | | goto error; |
1079 | | case L_URI: |
1080 | | fl->u.request.uri.s=tmp; |
1081 | | state=P_URI; |
1082 | | break; |
1083 | | case L_VER: |
1084 | | case VER1: |
1085 | | case VER2: |
1086 | | case VER3: |
1087 | | case VER4: |
1088 | | case VER5: |
1089 | | case VER6: |
1090 | | case FIN_VER: |
1091 | | LM_ERR("invalid version in request\n"); |
1092 | | goto error; |
1093 | | default: |
1094 | | state=P_METHOD; |
1095 | | } |
1096 | | } |
1097 | | } |
1098 | | skip: |
1099 | | fl->len=tmp-buf; |
1100 | | if (fl->type==SIP_REPLY){ |
1101 | | fl->u.reply.statuscode=stat; |
1102 | | /* fl->u.reply.statusclass=stat/100; */ |
1103 | | } |
1104 | | return tmp; |
1105 | | |
1106 | | error: |
1107 | | LM_ERR("while parsing first line (state=%d)\n", state); |
1108 | | fl->type=SIP_INVALID; |
1109 | | return tmp; |
1110 | | } |
1111 | | |
1112 | | #endif /* currently unused */ |
1113 | | |
1114 | | /* parses the first line, returns pointer to next line & fills fl; |
1115 | | also modifies buffer (to avoid extra copy ops) */ |
1116 | | char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) |
1117 | 0 | { |
1118 | |
|
1119 | 0 | char *tmp; |
1120 | 0 | char* second; |
1121 | 0 | char* third; |
1122 | 0 | char* nl; |
1123 | 0 | unsigned int offset; |
1124 | | /* int l; */ |
1125 | 0 | char* end; |
1126 | 0 | char s1,s2,s3; |
1127 | 0 | char *prn; |
1128 | 0 | unsigned int t; |
1129 | | |
1130 | | /* grammar: |
1131 | | request = method SP uri SP version CRLF |
1132 | | response = version SP status SP reason CRLF |
1133 | | (version = "SIP/2.0") |
1134 | | */ |
1135 | | |
1136 | |
|
1137 | 0 | end=buffer+len; |
1138 | | /* see if it's a reply (status) */ |
1139 | | |
1140 | | /* jku -- parse well-known methods */ |
1141 | | |
1142 | | /* drop messages which are so short they are for sure useless; |
1143 | | utilize knowledge of minimum size in parsing the first |
1144 | | token |
1145 | | */ |
1146 | 0 | if (len <=16 ) { |
1147 | 0 | LM_INFO("message too short: %d\n", len); |
1148 | 0 | goto error1; |
1149 | 0 | } |
1150 | | |
1151 | 0 | tmp=buffer; |
1152 | | /* is it perhaps a reply, ie does it start with "SIP...." ? */ |
1153 | 0 | if ( (*tmp=='S' || *tmp=='s') && |
1154 | 0 | strncasecmp( tmp+1, (char *)SIP_VERSION+1, SIP_VERSION_LEN-1)==0 && |
1155 | 0 | (*(tmp+SIP_VERSION_LEN)==' ')) { |
1156 | 0 | fl->type=SIP_REPLY; |
1157 | 0 | fl->u.reply.version.len=SIP_VERSION_LEN; |
1158 | 0 | tmp=buffer+SIP_VERSION_LEN; |
1159 | 0 | } else IFISMETHOD( INVITE, 'I' ) |
1160 | 0 | else IFISMETHOD( CANCEL, 'C') |
1161 | 0 | else IFISMETHOD( ACK, 'A' ) |
1162 | 0 | else IFISMETHOD( BYE, 'B' ) |
1163 | 0 | else IFISMETHOD( INFO, 'I' ) |
1164 | | /* if you want to add another method XXX, include METHOD_XXX in |
1165 | | H-file (this is the value which you will take later in |
1166 | | processing and define XXX_LEN as length of method name; |
1167 | | then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first |
1168 | | latter; everything must be capitals |
1169 | | */ |
1170 | 0 | else { |
1171 | | /* neither reply, nor any of known method requests, |
1172 | | let's believe it is an unknown method request |
1173 | | */ |
1174 | 0 | tmp=eat_token_end(buffer,buffer+len); |
1175 | 0 | if ((tmp==buffer)||(tmp>=end)){ |
1176 | 0 | LM_INFO("empty or bad first line\n"); |
1177 | 0 | goto error1; |
1178 | 0 | } |
1179 | 0 | if (*tmp!=' ') { |
1180 | 0 | LM_INFO("method not followed by SP\n"); |
1181 | 0 | goto error1; |
1182 | 0 | } |
1183 | 0 | fl->type=SIP_REQUEST; |
1184 | | /* see if it is another known method */ |
1185 | | /* fl->u.request.method_value=METHOD_OTHER; */ |
1186 | 0 | if(parse_method(buffer, tmp, |
1187 | 0 | (unsigned int*)&fl->u.request.method_value)==0) |
1188 | 0 | { |
1189 | 0 | LM_INFO("failed to parse the method\n"); |
1190 | 0 | goto error1; |
1191 | 0 | } |
1192 | 0 | fl->u.request.method.len=tmp-buffer; |
1193 | 0 | } |
1194 | | |
1195 | | |
1196 | | /* identifying type of message over now; |
1197 | | tmp points at space after; go ahead */ |
1198 | | |
1199 | 0 | fl->u.request.method.s=buffer; /* store ptr to first token */ |
1200 | 0 | second=tmp+1; /* jump to second token */ |
1201 | 0 | offset=second-buffer; |
1202 | | |
1203 | | /* EoJku */ |
1204 | | |
1205 | | /* next element */ |
1206 | 0 | tmp=eat_token_end(second, second+len-offset); |
1207 | 0 | if (tmp>=end){ |
1208 | 0 | goto error; |
1209 | 0 | } |
1210 | 0 | offset+=tmp-second; |
1211 | 0 | third=eat_space_end(tmp, tmp+len-offset); |
1212 | 0 | offset+=third-tmp; |
1213 | 0 | if ((third==tmp)||(tmp>=end)){ |
1214 | 0 | goto error; |
1215 | 0 | } |
1216 | 0 | fl->u.request.uri.s=second; |
1217 | 0 | fl->u.request.uri.len=tmp-second; |
1218 | | |
1219 | | /* jku: parse status code */ |
1220 | 0 | if (fl->type==SIP_REPLY) { |
1221 | 0 | if (fl->u.request.uri.len!=3) { |
1222 | 0 | LM_INFO("len(status code)!=3: %.*s\n", |
1223 | 0 | fl->u.request.uri.len, ZSW(second) ); |
1224 | 0 | goto error; |
1225 | 0 | } |
1226 | 0 | s1=*second; s2=*(second+1);s3=*(second+2); |
1227 | 0 | if (s1>='0' && s1<='9' && |
1228 | 0 | s2>='0' && s2<='9' && |
1229 | 0 | s3>='0' && s3<='9' ) { |
1230 | 0 | fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0'); |
1231 | 0 | } else { |
1232 | 0 | LM_INFO("status_code non-numerical: %.*s\n", |
1233 | 0 | fl->u.request.uri.len, ZSW(second) ); |
1234 | 0 | goto error; |
1235 | 0 | } |
1236 | 0 | } |
1237 | | /* EoJku */ |
1238 | | |
1239 | | /* last part: for a request it must be the version, for a reply |
1240 | | * it can contain almost anything, including spaces, so we don't care |
1241 | | * about it*/ |
1242 | 0 | if (fl->type==SIP_REQUEST){ |
1243 | 0 | tmp=eat_token_end(third,third+len-offset); |
1244 | 0 | offset+=tmp-third; |
1245 | 0 | if ((tmp==third)||(tmp>=end)){ |
1246 | 0 | goto error; |
1247 | 0 | } |
1248 | 0 | if (! is_empty_end(tmp, tmp+len-offset)){ |
1249 | 0 | goto error; |
1250 | 0 | } |
1251 | 0 | }else{ |
1252 | 0 | tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line |
1253 | | ('\n' or '\r') */ |
1254 | 0 | if (tmp>=end){ /* no crlf in packet => invalid */ |
1255 | 0 | goto error; |
1256 | 0 | } |
1257 | 0 | offset+=tmp-third; |
1258 | 0 | } |
1259 | 0 | nl=eat_line(tmp,len-offset); |
1260 | 0 | if (nl>=end){ /* no crlf in packet or only 1 line > invalid */ |
1261 | 0 | goto error; |
1262 | 0 | } |
1263 | 0 | fl->u.request.version.s=third; |
1264 | 0 | fl->u.request.version.len=tmp-third; |
1265 | 0 | fl->len=nl-buffer; |
1266 | |
|
1267 | 0 | return nl; |
1268 | | |
1269 | 0 | error: |
1270 | 0 | LM_ERR("bad %s first line\n", |
1271 | 0 | (fl->type==SIP_REPLY)?"reply(status)":"request"); |
1272 | |
|
1273 | 0 | LM_ERR("at line 0 char %d: \n", offset ); |
1274 | 0 | prn=pkg_malloc( offset ); |
1275 | 0 | if (prn) { |
1276 | 0 | for (t=0; t<offset; t++) |
1277 | 0 | if (*(buffer+t)) *(prn+t)=*(buffer+t); |
1278 | 0 | else *(prn+t)=248U; |
1279 | 0 | LM_ERR("parsed so far: %.*s\n", offset, ZSW(prn) ); |
1280 | 0 | pkg_free( prn ); |
1281 | 0 | }; |
1282 | 0 | error1: |
1283 | 0 | fl->type=SIP_INVALID; |
1284 | 0 | LM_INFO("bad message\n"); |
1285 | | /* skip line */ |
1286 | 0 | nl=eat_line(buffer,len); |
1287 | 0 | return nl; |
1288 | 0 | } |