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