082af4142d78b38d181ad7fc4405db0969884353
[sip-router] / parser / parse_via.c
1 /*
2  * $Id$ 
3  *
4  * via 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 /* parsing:           compact form:
33  */
34
35 /* 
36  * still TODO/test:
37  *  x parse next via
38  *  - return a list of header structs
39  *  - return list of params
40  */
41
42
43
44 #include <stdlib.h>
45 #include <string.h>
46 #include "../dprint.h"
47 #include "../ut.h"
48 #include "../mem/mem.h"
49 #include "parse_via.h"
50 #include "parse_def.h"
51
52
53
54 /* main via states (uri:port ...) */
55 enum {           
56         F_HOST, P_HOST,
57         L_PORT, F_PORT, P_PORT,
58         L_PARAM, F_PARAM, P_PARAM,
59         L_VIA, F_VIA,
60         F_COMMENT, P_COMMENT,
61         F_IP6HOST, P_IP6HOST,
62         F_CRLF,
63         F_LF,
64         F_CR,
65         END_OF_HEADER
66 };
67
68
69 /* first via part state */
70 enum {
71         F_SIP = 100,
72         SIP1, SIP2, FIN_SIP,
73         L_VER, F_VER,
74         VER1, VER2, FIN_VER,
75         L_PROTO, F_PROTO, P_PROTO
76 };
77
78
79 /* param related states
80  * WARNING: keep the FIN*, GEN_PARAM & PARAM_ERROR in sync w/ PARAM_* from
81  * msg_parser.h !*/
82 enum {  
83         L_VALUE = 200, F_VALUE, P_VALUE, P_STRING,
84         HIDDEN1, HIDDEN2, HIDDEN3, HIDDEN4, HIDDEN5,
85         TTL1, TTL2,
86         BRANCH1, BRANCH2, BRANCH3, BRANCH4, BRANCH5,
87         MADDR1, MADDR2, MADDR3, MADDR4,
88         RECEIVED1, RECEIVED2, RECEIVED3, RECEIVED4, RECEIVED5, RECEIVED6,
89         RECEIVED7,
90              /* fin states (227-...)*/
91         FIN_HIDDEN = 230, FIN_TTL, FIN_BRANCH, FIN_MADDR, FIN_RECEIVED,
92              /*GEN_PARAM,
93                PARAM_ERROR*/ /* declared in msg_parser.h*/
94 };
95
96
97 /* entry state must be F_PARAM, or saved_state=F_PARAM and
98  * state=F_{LF,CR,CRLF}!
99  * output state = L_PARAM or F_PARAM or END_OF_HEADER
100  * (and saved_state= last state); everything else => error 
101  */
102 static /*inline*/ char* parse_via_param(char* p, char* end, int* pstate, 
103                                     int* psaved_state, struct via_param* param)
104 {
105         char* tmp;
106         register int state;
107         int saved_state;
108
109         state=*pstate;
110         saved_state=*psaved_state;
111         param->type=PARAM_ERROR;
112
113         for (tmp=p;tmp<end;tmp++){
114                 switch(*tmp){
115                         case ' ':
116                         case '\t':
117                                 switch(state){
118                                         case FIN_HIDDEN:
119                                                 *tmp=0;
120                                                 param->type=state;
121                                                 param->name.len=tmp-param->name.s;
122                                                 state=L_PARAM;
123                                                 goto endofparam;
124                                         case FIN_BRANCH:
125                                         case FIN_TTL:
126                                         case FIN_MADDR:
127                                         case FIN_RECEIVED:
128                                                 *tmp=0;
129                                                 param->type=state;
130                                                 param->name.len=tmp-param->name.s;
131                                                 state=L_VALUE;
132                                                 goto find_value;
133                                         case F_PARAM:
134                                                 break;
135                                         case F_LF:
136                                         case F_CR:
137                                         case F_CRLF:
138                                                 state=saved_state;
139                                                 break;
140                                         case GEN_PARAM:
141                                         default:
142                                                 *tmp=0;
143                                                 param->type=GEN_PARAM;
144                                                 param->name.len=tmp-param->name.s;
145                                                 state=L_VALUE;
146                                                 goto find_value;
147                                 }
148                                 break;
149                         /* \n and \r*/
150                         case '\n':
151                                 switch(state){
152                                         case FIN_HIDDEN:
153                                                 *tmp=0;
154                                                 param->type=state;
155                                                 param->name.len=tmp-param->name.s;
156                                                 saved_state=L_PARAM;
157                                                 state=F_LF;
158                                                 goto endofparam;
159                                         case FIN_BRANCH:
160                                         case FIN_TTL:
161                                         case FIN_MADDR:
162                                         case FIN_RECEIVED:
163                                                 *tmp=0;
164                                                 param->type=state;
165                                                 param->name.len=tmp-param->name.s;
166                                                 saved_state=L_VALUE;
167                                                 state=F_LF;
168                                                 goto find_value;
169                                         case F_PARAM:
170                                                 saved_state=state;
171                                                 state=F_LF;
172                                                 break;
173                                         case F_LF:
174                                         case F_CRLF:
175                                                 state=END_OF_HEADER;
176                                                 goto end_via;
177                                         case F_CR:
178                                                 state=F_CRLF;
179                                                 break;
180                                         case GEN_PARAM:
181                                         default:
182                                                 *tmp=0;
183                                                 param->type=GEN_PARAM;
184                                                 saved_state=L_VALUE;
185                                                 param->name.len=tmp-param->name.s;
186                                                 state=F_LF;
187                                                 goto find_value;
188                                 }
189                                 break;
190                         case '\r':
191                                 switch(state){
192                                         case FIN_HIDDEN:
193                                                 *tmp=0;
194                                                 param->type=state;
195                                                 param->name.len=tmp-param->name.s;
196                                                 saved_state=L_PARAM;
197                                                 state=F_CR;
198                                                 goto endofparam;
199                                         case FIN_BRANCH:
200                                         case FIN_TTL:
201                                         case FIN_MADDR:
202                                         case FIN_RECEIVED:
203                                                 *tmp=0;
204                                                 param->type=state;
205                                                 param->name.len=tmp-param->name.s;
206                                                 saved_state=L_VALUE;
207                                                 state=F_CR;
208                                                 goto find_value;
209                                         case F_PARAM:
210                                                 saved_state=state;
211                                                 state=F_CR;
212                                                 break;
213                                         case F_CR:
214                                         case F_CRLF:
215                                                 state=END_OF_HEADER;
216                                                 goto end_via;
217                                         case GEN_PARAM:
218                                         default:
219                                                 *tmp=0;
220                                                 param->type=GEN_PARAM;
221                                                 param->name.len=tmp-param->name.s;
222                                                 saved_state=L_VALUE;
223                                                 state=F_CR;
224                                                 goto find_value;
225                                 }
226                                 break;
227
228                         case '=':
229                                 switch(state){
230                                         case FIN_BRANCH:
231                                         case FIN_TTL:
232                                         case FIN_MADDR:
233                                         case FIN_RECEIVED:
234                                                 *tmp=0;
235                                                 param->type=state;
236                                                 param->name.len=tmp-param->name.s;
237                                                 state=F_VALUE;
238                                                 goto find_value;
239                                         case F_PARAM:
240                                         case FIN_HIDDEN:
241                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c> in"
242                                                                 " state %d\n", *tmp, state);
243                                                 goto error;
244                                         case F_CR:
245                                         case F_LF:
246                                         case F_CRLF:
247                                                 state=END_OF_HEADER;
248                                                 goto end_via;
249                                         case GEN_PARAM:
250                                         default:
251                                                 *tmp=0;
252                                                 param->type=GEN_PARAM;
253                                                 param->name.len=tmp-param->name.s;
254                                                 state=F_VALUE;
255                                                 goto find_value;
256                                 }
257                                 break;
258                         case ';':
259                                 switch(state){
260                                         case FIN_HIDDEN:
261                                                 *tmp=0;
262                                                 param->type=state;
263                                                 param->name.len=tmp-param->name.s;
264                                                 state=F_PARAM;
265                                                 goto endofparam;
266                                         case FIN_BRANCH:
267                                         case FIN_MADDR:
268                                         case FIN_TTL:
269                                         case FIN_RECEIVED:
270                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c> in"
271                                                                 " state %d\n", *tmp, state);
272                                                 goto error;
273                                         case F_CR:
274                                         case F_LF:
275                                         case F_CRLF:
276                                                 state=END_OF_HEADER;
277                                                 goto end_via;
278                                         case GEN_PARAM:
279                                         default:
280                                                 *tmp=0;
281                                                 param->type=GEN_PARAM;
282                                                 param->name.len=tmp-param->name.s;
283                                                 state=F_PARAM;
284                                                 goto endofparam;
285                                 }
286                                 break;
287                         case ',':
288                                 switch(state){
289                                         case FIN_HIDDEN:
290                                                 *tmp=0;
291                                                 param->type=state;
292                                                 param->name.len=tmp-param->name.s;
293                                                 state=F_VIA;
294                                                 goto endofvalue;
295                                         case FIN_BRANCH:
296                                         case FIN_MADDR:
297                                         case FIN_TTL:
298                                         case FIN_RECEIVED:
299                                                 LOG(L_ERR, "ERROR: parse_via_param: new via found" 
300                                                                 "(',') when '=' expected (state %d=)\n",
301                                                                 state);
302                                                 goto error; /* or we could ignore this bad param*/
303                                         case F_CR:
304                                         case F_LF:
305                                         case F_CRLF:
306                                                 state=END_OF_HEADER;
307                                                 goto end_via;
308                                         case GEN_PARAM:
309                                         default:
310                                                 *tmp=0;
311                                                 param->type=GEN_PARAM;
312                                                 param->name.len=tmp-param->name.s;
313                                                 state=F_VIA;
314                                                 goto endofvalue;
315                                 }
316                                 break; 
317
318                                 /* param names */
319                         case 'h':
320                         case 'H':
321                                 switch(state){
322                                         case F_PARAM:
323                                                 state=HIDDEN1;
324                                                 param->name.s=tmp;
325                                                 break;
326                                         case BRANCH5:
327                                                 state=FIN_BRANCH;
328                                                 break;
329                                         case GEN_PARAM:
330                                                 break;
331                                         case F_CR:
332                                         case F_LF:
333                                         case F_CRLF:
334                                                 state=END_OF_HEADER;
335                                                 goto end_via;
336                                         default:
337                                                 state=GEN_PARAM;
338                                 }
339                                 break;
340                         case 'i':
341                         case 'I':
342                                 switch(state){
343                                         case F_PARAM:
344                                                 state=GEN_PARAM;
345                                                 param->name.s=tmp;
346                                                 break;
347                                         case HIDDEN1:
348                                                 state=HIDDEN2;
349                                                 break;
350                                         case RECEIVED4:
351                                                 state=RECEIVED5;
352                                                 break;
353                                         case GEN_PARAM:
354                                                 break;
355                                         case F_CR:
356                                         case F_LF:
357                                         case F_CRLF:
358                                                 state=END_OF_HEADER;
359                                                 goto end_via;
360                                         default:
361                                                 state=GEN_PARAM;
362                                 }
363                                 break;
364                         case 'd':
365                         case 'D':
366                                 switch(state){
367                                         case F_PARAM:
368                                                 state=GEN_PARAM;
369                                                 param->name.s=tmp;
370                                                 break;
371                                         case HIDDEN2:
372                                                 state=HIDDEN3;
373                                                 break;
374                                         case HIDDEN3:
375                                                 state=HIDDEN4;
376                                                 break;
377                                         case MADDR2:
378                                                 state=MADDR3;
379                                                 break;
380                                         case MADDR3:
381                                                 state=MADDR4;
382                                                 break;
383                                         case RECEIVED7:
384                                                 state=FIN_RECEIVED;
385                                                 break;
386                                         case GEN_PARAM:
387                                                 break;
388                                         case F_CR:
389                                         case F_LF:
390                                         case F_CRLF:
391                                                 state=END_OF_HEADER;
392                                                 goto end_via;
393                                         default:
394                                                 state=GEN_PARAM;
395                                 }
396                                 break;
397                         case 'e':
398                         case 'E':
399                                 switch(state){
400                                         case F_PARAM:
401                                                 state=GEN_PARAM;
402                                                 param->name.s=tmp;
403                                                 break;
404                                         case HIDDEN4:
405                                                 state=HIDDEN5;
406                                                 break;
407                                         case RECEIVED1:
408                                                 state=RECEIVED2;
409                                                 break;
410                                         case RECEIVED3:
411                                                 state=RECEIVED4;
412                                                 break;
413                                         case RECEIVED6:
414                                                 state=RECEIVED7;
415                                                 break;
416                                         case GEN_PARAM:
417                                                 break;
418                                         case F_CR:
419                                         case F_LF:
420                                         case F_CRLF:
421                                                 state=END_OF_HEADER;
422                                                 goto end_via;
423                                         default:
424                                                 state=GEN_PARAM;
425                                 }
426                                 break;
427                         case 'n':
428                         case 'N':
429                                 switch(state){
430                                         case F_PARAM:
431                                                 state=GEN_PARAM;
432                                                 param->name.s=tmp;
433                                                 break;
434                                         case HIDDEN5:
435                                                 state=FIN_HIDDEN;
436                                                 break;
437                                         case BRANCH3:
438                                                 state=BRANCH4;
439                                                 break;
440                                         case GEN_PARAM:
441                                                 break;
442                                         case F_CR:
443                                         case F_LF:
444                                         case F_CRLF:
445                                                 state=END_OF_HEADER;
446                                                 goto end_via;
447                                         default:
448                                                 state=GEN_PARAM;
449                                 }
450                                 break;
451                         case 't':
452                         case 'T':
453                                 switch(state){
454                                         case F_PARAM:
455                                                 state=TTL1;
456                                                 param->name.s=tmp;
457                                                 break;
458                                         case TTL1:
459                                                 state=TTL2;
460                                                 break;
461                                         case GEN_PARAM:
462                                                 break;
463                                         case F_CR:
464                                         case F_LF:
465                                         case F_CRLF:
466                                                 state=END_OF_HEADER;
467                                                 goto end_via;
468                                         default:
469                                                 state=GEN_PARAM;
470                                 }
471                                 break;
472                         case 'l':
473                         case 'L':
474                                 switch(state){
475                                         case F_PARAM:
476                                                 state=GEN_PARAM;
477                                                 param->name.s=tmp;
478                                                 break;
479                                         case TTL2:
480                                                 state=FIN_TTL;
481                                                 break;
482                                         case GEN_PARAM:
483                                                 break;
484                                         case F_CR:
485                                         case F_LF:
486                                         case F_CRLF:
487                                                 state=END_OF_HEADER;
488                                                 goto end_via;
489                                         default:
490                                                 state=GEN_PARAM;
491                                 }
492                                 break;
493                         case 'm':
494                         case 'M':
495                                 switch(state){
496                                         case F_PARAM:
497                                                 state=MADDR1;
498                                                 param->name.s=tmp;
499                                                 break;
500                                         case GEN_PARAM:
501                                                 break;
502                                         case F_CR:
503                                         case F_LF:
504                                         case F_CRLF:
505                                                 state=END_OF_HEADER;
506                                                 goto end_via;
507                                         default:
508                                                 state=GEN_PARAM;
509                                 }
510                                 break;
511                         case 'a':
512                         case 'A':
513                                 switch(state){
514                                         case F_PARAM:
515                                                 state=GEN_PARAM;
516                                                 param->name.s=tmp;
517                                                 break;
518                                         case MADDR1:
519                                                 state=MADDR2;
520                                                 break;
521                                         case BRANCH2:
522                                                 state=BRANCH3;
523                                                 break;
524                                         case GEN_PARAM:
525                                                 break;
526                                         case F_CR:
527                                         case F_LF:
528                                         case F_CRLF:
529                                                 state=END_OF_HEADER;
530                                                 goto end_via;
531                                         default:
532                                                 state=GEN_PARAM;
533                                 }
534                                 break;
535                         case 'r':
536                         case 'R':
537                                 switch(state){
538                                         case MADDR4:
539                                                 state=FIN_MADDR;
540                                                 break;
541                                         case F_PARAM:
542                                                 state=RECEIVED1;
543                                                 param->name.s=tmp;
544                                                 break;
545                                         case BRANCH1:
546                                                 state=BRANCH2;
547                                                 break;
548                                         case GEN_PARAM:
549                                                 break;
550                                         case F_CR:
551                                         case F_LF:
552                                         case F_CRLF:
553                                                 state=END_OF_HEADER;
554                                                 goto end_via;
555                                         default:
556                                                 state=GEN_PARAM;
557                                 }
558                                 break;
559                         case 'c':
560                         case 'C':
561                                 switch(state){
562                                         case F_PARAM:
563                                                 state=GEN_PARAM;
564                                                 param->name.s=tmp;
565                                                 break;
566                                         case RECEIVED2:
567                                                 state=RECEIVED3;
568                                                 break;
569                                         case BRANCH4:
570                                                 state=BRANCH5;
571                                                 break;
572                                         case GEN_PARAM:
573                                                 break;
574                                         case F_CR:
575                                         case F_LF:
576                                         case F_CRLF:
577                                                 state=END_OF_HEADER;
578                                                 goto end_via;
579                                         default:
580                                                 state=GEN_PARAM;
581                                 }
582                                 break;
583                         case 'v':
584                         case 'V':
585                                 switch(state){
586                                         case F_PARAM:
587                                                 state=GEN_PARAM;
588                                                 param->name.s=tmp;
589                                                 break;
590                                         case RECEIVED5:
591                                                 state=RECEIVED6;
592                                                 break;
593                                         case GEN_PARAM:
594                                                 break;
595                                         case F_CR:
596                                         case F_LF:
597                                         case F_CRLF:
598                                                 state=END_OF_HEADER;
599                                                 goto end_via;
600                                         default:
601                                                 state=GEN_PARAM;
602                                 }
603                                 break;
604                         case 'b':
605                         case 'B':
606                                 switch(state){
607                                         case F_PARAM:
608                                                 state=BRANCH1;
609                                                 param->name.s=tmp;
610                                                 break;
611                                         case GEN_PARAM:
612                                                 break;
613                                         case F_CR:
614                                         case F_LF:
615                                         case F_CRLF:
616                                                 state=END_OF_HEADER;
617                                                 goto end_via;
618                                         default:
619                                                 state=GEN_PARAM;
620                                 }
621                                 break;
622
623                         default:
624                                 switch(state){
625                                         case F_PARAM:
626                                                 state=GEN_PARAM;
627                                                 param->name.s=tmp;
628                                                 break;
629                                         case  GEN_PARAM:
630                                                 break;
631                                         case F_CR:
632                                         case F_LF:
633                                         case F_CRLF:
634                                                 state=END_OF_HEADER;
635                                                 goto end_via;
636                                         default:
637                                                 state=GEN_PARAM;
638                                 }
639                 }
640         }/* for tmp*/
641
642         /* end of packet? => error, no cr/lf,',' found!!!*/
643         saved_state=state;
644         state=END_OF_HEADER;
645         goto error;
646         
647  find_value:
648         tmp++;
649         for(;*tmp;tmp++){
650                 switch(*tmp){
651                         case ' ':
652                         case '\t':
653                                 switch(state){
654                                         case L_VALUE:
655                                         case F_VALUE: /*eat space*/
656                                                 break; 
657                                         case P_VALUE:
658                                                 *tmp=0;
659                                                 state=L_PARAM;
660                                                 param->value.len=tmp-param->value.s;
661                                                 goto endofvalue;
662                                         case P_STRING:
663                                                 break;
664                                         case F_CR:
665                                         case F_LF:
666                                         case F_CRLF:
667                                                 state=saved_state;
668                                                 break;
669                                         default:
670                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
671                                                                 " in state %d\n", *tmp, state);
672                                                 goto error;
673                                 }
674                                 break;
675                         case '\n':
676                                 switch(state){
677                                         case L_VALUE:
678                                         case F_VALUE: /*eat space*/
679                                         case P_STRING:
680                                                 saved_state=state;
681                                                 state=F_LF;
682                                                 break;
683                                         case P_VALUE:
684                                                 *tmp=0;
685                                                 saved_state=L_PARAM;
686                                                 state=F_LF;
687                                                 param->value.len=tmp-param->value.s;
688                                                 goto endofvalue;
689                                         case F_LF:
690                                         case F_CRLF:
691                                                 state=END_OF_HEADER;
692                                                 goto end_via;
693                                         case F_CR:
694                                                 state=F_CRLF;
695                                                 break;
696                                         default:
697                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
698                                                                 " in state %d\n", *tmp, state);
699                                                 goto error;
700                                 }
701                                 break;
702                         case '\r':
703                                 switch(state){
704                                         case L_VALUE:
705                                         case F_VALUE: /*eat space*/
706                                         case P_STRING:
707                                                 saved_state=state;
708                                                 state=F_CR;
709                                                 break;
710                                         case P_VALUE:
711                                                 *tmp=0;
712                                                 param->value.len=tmp-param->value.s;
713                                                 saved_state=L_PARAM;
714                                                 state=F_CR;
715                                                 goto endofvalue;
716                                         case F_LF:
717                                         case F_CR:
718                                         case F_CRLF:
719                                                 state=END_OF_HEADER;
720                                                 goto end_via;
721                                         default:
722                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
723                                                                 " in state %d\n", *tmp, state);
724                                                 goto error;
725                                 }
726                                 break;
727
728                         case '=':
729                                 switch(state){
730                                         case L_VALUE:
731                                                 state=F_VALUE;
732                                                 break;
733                                         case P_STRING:
734                                                 break;
735                                         case F_LF:
736                                         case F_CR:
737                                         case F_CRLF:
738                                                 state=END_OF_HEADER;
739                                                 goto end_via;
740                                         default:
741                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
742                                                                 " in state %d\n", *tmp, state);
743                                                 goto error;
744                                 }
745                                 break;
746                         case ';':
747                                 switch(state){
748                                         case P_VALUE:
749                                                 *tmp=0;
750                                                 param->value.len=tmp-param->value.s;
751                                                 state=F_PARAM;
752                                                 goto endofvalue;
753                                         case P_STRING:
754                                                 break; /* what to do? */
755                                         case F_LF:
756                                         case F_CR:
757                                         case F_CRLF:
758                                                 state=END_OF_HEADER;
759                                                 goto end_via;
760                                         default:
761                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
762                                                                 " in state %d\n", *tmp, state);
763                                                 goto error;
764                                 }
765                                 break;
766                         case ',':
767                                 switch(state){
768                                         case P_VALUE:
769                                                 *tmp=0;
770                                                 param->value.len=tmp-param->value.s;
771                                                 state=F_VIA;
772                                                 goto endofvalue;
773                                         case P_STRING:
774                                                 case F_LF:
775                                         case F_CR:
776                                         case F_CRLF:
777                                                 state=END_OF_HEADER;
778                                                 goto end_via;
779                                         default:
780                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
781                                                                 " in state %d\n", *tmp, state);
782                                                 goto error;
783                                 }
784                                 break; /* what to do? */
785                         case '"':
786                                 switch(state){
787                                         case F_VALUE:
788                                                 state=P_STRING;
789                                                 param->value.s=tmp+1;
790                                                 break;
791                                         case P_STRING:
792                                                 *tmp=0;
793                                                 state=L_PARAM;
794                                                 param->value.len=tmp-param->value.s;
795                                                 goto endofvalue;
796                                         case F_LF:
797                                         case F_CR:
798                                         case F_CRLF:
799                                                 state=END_OF_HEADER;
800                                                 goto end_via;
801                                         default:
802                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
803                                                                 " in state %d\n", *tmp, state);
804                                                 goto error;
805                                 }
806                                 break;
807                         default:
808                                 switch(state){
809                                         case F_VALUE:
810                                                 state=P_VALUE;
811                                                 param->value.s=tmp;
812                                                 break;
813                                         case P_VALUE:
814                                         case P_STRING:
815                                                 break;
816                                         case F_LF:
817                                         case F_CR:
818                                         case F_CRLF:
819                                                 state=END_OF_HEADER;
820                                                 goto end_via;
821                                         default:
822                                                 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
823                                                                 " in state %d\n", *tmp, state);
824                                                 goto error;
825                                 }
826                 }
827         } /* for2 tmp*/
828
829         /* end of buff and no CR/LF =>error*/
830         saved_state=state;
831         state=END_OF_HEADER;
832         goto error;
833         
834  endofparam:
835  endofvalue:
836         param->size=tmp-p;
837         *pstate=state;
838         *psaved_state=saved_state;
839         DBG("Found param type %d, <%s> = <%s>; state=%d\n", param->type,
840                         param->name.s, param->value.s, state);
841         return tmp;
842         
843  end_via:
844              /* if we are here we found an "unexpected" end of via
845               *  (cr/lf). This is valid only if the param type is GEN_PARAM*/
846         if (param->type==GEN_PARAM){
847                 saved_state=L_PARAM; /* change the saved_state, we have an unknown
848                                         param. w/o a value */
849                 goto endofparam;
850         }
851         *pstate=state;
852         *psaved_state=saved_state;
853         DBG("Error on  param type %d, <%s>, state=%d, saved_state=%d\n",
854                 param->type, param->name.s, state, saved_state);
855
856  error:
857         LOG(L_ERR, "error: parse_via_param\n");
858         param->type=PARAM_ERROR;
859         *pstate=PARAM_ERROR;
860         *psaved_state=state;
861         return tmp;
862 }
863
864
865
866 char* parse_via(char* buffer, char* end, struct via_body *vb)
867 {
868         char* tmp;
869         int state;
870         int saved_state;
871         int c_nest;
872         int err;
873
874         struct via_param* param;
875
876 parse_again:
877         vb->error=PARSE_ERROR;
878         /* parse start of via ( SIP/2.0/UDP    )*/
879         state=F_SIP;
880         for(tmp=buffer;tmp<end;tmp++){
881                 switch(*tmp){
882                         case ' ':
883                         case'\t':
884                                 switch(state){
885                                         case L_VER: /* eat space */
886                                         case L_PROTO:
887                                         case F_SIP:
888                                         case F_VER:
889                                         case F_PROTO:
890                                                 break;
891                                         case P_PROTO:
892                                                 *tmp=0;  /* finished proto parsing */
893                                                 vb->transport.len=tmp-vb->transport.s;
894                                                 state=F_HOST; /* start looking for host*/
895                                                 goto main_via;
896                                         case FIN_SIP:
897                                                 *tmp=0;
898                                                 vb->name.len=tmp-vb->name.s;
899                                                 state=L_VER;
900                                                 break;
901                                         case FIN_VER:
902                                                 *tmp=0;
903                                                 vb->version.len=tmp-vb->version.s;
904                                                 state=L_PROTO;
905                                                 break;
906                                         case F_LF:
907                                         case F_CRLF:
908                                         case F_CR: /* header continues on this line */
909                                                 state=saved_state;
910                                                 break;
911                                         default:
912                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
913                                                                 " state %d\n", *tmp, state);
914                                                 goto error;
915                                 }
916                                 break;
917                         case '\n':
918                                 switch(state){
919                                         case L_VER:
920                                         case F_SIP:
921                                         case F_VER:
922                                         case F_PROTO:
923                                         case L_PROTO:
924                                                 saved_state=state;
925                                                 state=F_LF;
926                                                 break;
927                                         case P_PROTO:
928                                                 *tmp=0;
929                                                 vb->transport.len=tmp-vb->transport.s;
930                                                 state=F_LF;
931                                                 saved_state=F_HOST; /* start looking for host*/
932                                                 goto main_via;
933                                         case FIN_SIP:
934                                                 *tmp=0;
935                                                 vb->name.len=tmp-vb->name.s;
936                                                 state=F_LF;
937                                                 saved_state=L_VER;
938                                                 break;
939                                         case FIN_VER:
940                                                 *tmp=0;
941                                                 vb->version.len=tmp-vb->version.s;
942                                                 state=F_LF;
943                                                 saved_state=L_PROTO;
944                                                 break;
945                                         case F_CR:
946                                                 state=F_CRLF;
947                                                 break;
948                                         case F_LF:
949                                         case F_CRLF:
950                                                 state=saved_state;
951                                                 goto endofheader;
952                                         default:
953                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
954                                                                 " state %d\n", *tmp, state);
955                                                 goto error;
956                                 }
957                                 break;
958                         case '\r':
959                                 switch(state){
960                                         case L_VER:
961                                         case F_SIP:
962                                         case F_VER:
963                                         case F_PROTO:
964                                         case L_PROTO:
965                                                 saved_state=state;
966                                                 state=F_CR;
967                                                 break;
968                                         case P_PROTO:
969                                                 *tmp=0;
970                                                 vb->transport.len=tmp-vb->transport.s;
971                                                 state=F_CR;
972                                                 saved_state=F_HOST;
973                                                 goto main_via;
974                                         case FIN_SIP:
975                                                 *tmp=0;
976                                                 vb->name.len=tmp-vb->name.s;
977                                                 state=F_CR;
978                                                 saved_state=L_VER;
979                                                 break;
980                                         case FIN_VER:
981                                                 *tmp=0;
982                                                 vb->version.len=tmp-vb->version.s;
983                                                 state=F_CR;
984                                                 saved_state=L_PROTO;
985                                                 break;
986                                         case F_LF: /*end of line ?next header?*/
987                                         case F_CR:
988                                         case F_CRLF:
989                                                 state=saved_state;
990                                                 goto endofheader;
991                                         default:
992                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
993                                                                 " state %d\n", *tmp, state);
994                                                 goto error;
995                                 }
996                                 break;
997                         
998                         case '/':
999                                 switch(state){
1000                                         case FIN_SIP:
1001                                                 *tmp=0;
1002                                                 vb->name.len=tmp-vb->name.s;
1003                                                 state=F_VER;
1004                                                 break;
1005                                         case FIN_VER:
1006                                                 *tmp=0;
1007                                                 vb->version.len=tmp-vb->version.s;
1008                                                 state=F_PROTO;
1009                                                 break;
1010                                         case L_VER:
1011                                                 state=F_VER;
1012                                                 break;
1013                                         case L_PROTO:
1014                                                 state=F_PROTO;
1015                                                 break;
1016                                         default:
1017                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1018                                                                 " state %d\n", *tmp, state);
1019                                                 goto error;
1020                                 }
1021                                 break;
1022                                 /* match SIP*/
1023                         case 'S':
1024                         case 's':
1025                                 switch(state){
1026                                         case F_SIP:
1027                                                 state=SIP1;
1028                                                 vb->name.s=tmp;
1029                                                 break;
1030                                         /* allow S in PROTO */
1031                                         case F_PROTO:
1032                                                 state=P_PROTO;
1033                                                 vb->transport.s=tmp;
1034                                                 break;
1035                                         case P_PROTO:
1036                                                 break;
1037                                         default:
1038                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1039                                                                 " state %d\n", *tmp, state);
1040                                                 goto error;
1041                                 }
1042                                 break;
1043                         case 'I':
1044                         case 'i':
1045                                 switch(state){
1046                                         case SIP1:
1047                                                 state=SIP2;
1048                                                 break;
1049                                         /* allow i in PROTO */
1050                                         case F_PROTO:
1051                                                 vb->transport.s=tmp;
1052                                                 state=P_PROTO;
1053                                                 break;
1054                                         case P_PROTO:
1055                                                 break;
1056                                         default:
1057                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1058                                                                 " state %d\n", *tmp, state);
1059                                                 goto error;
1060                                 }
1061                                 break;
1062                         case 'p':
1063                         case 'P':
1064                                 switch(state){
1065                                         case SIP2:
1066                                                 state=FIN_SIP;
1067                                                 break;
1068                                         /* allow p in PROTO */
1069                                         case F_PROTO:
1070                                                 state=P_PROTO;
1071                                                 vb->transport.s=tmp;
1072                                                 break;
1073                                         case P_PROTO:
1074                                                 break;
1075                                         default:
1076                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1077                                                                 " state %d\n", *tmp, state);
1078                                                 goto error;
1079                                 }
1080                                 break;
1081                         /*match 2.0*/
1082                         case '2':
1083                                 switch(state){
1084                                         case F_VER:
1085                                                 state=VER1;
1086                                                 vb->version.s=tmp;
1087                                                 break;
1088                                         /* allow 2 in PROTO*/
1089                                         case F_PROTO:
1090                                                 vb->transport.s=tmp;
1091                                                 state=P_PROTO;
1092                                                 break;
1093                                         case P_PROTO:
1094                                                 break;
1095                                         default:
1096                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1097                                                                 " state %d\n", *tmp, state);
1098                                                 goto error;
1099                                 }
1100                                 break;
1101                         case '.':
1102                                 switch(state){
1103                                         case VER1:
1104                                                 state=VER2;
1105                                                 break;
1106                                         /* allow . in PROTO */
1107                                         case F_PROTO:
1108                                                 vb->transport.s=tmp;
1109                                                 state=P_PROTO;
1110                                                 break;
1111                                         case P_PROTO:
1112                                                 break;
1113                                         default:
1114                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1115                                                                 " state %d\n", *tmp, state);
1116                                                 goto error;
1117                                 }
1118                                  break;
1119                         case '0':
1120                                 switch(state){
1121                                         case VER2:
1122                                                 state=FIN_VER;
1123                                                 break;
1124                                         /* allow 0 in PROTO*/
1125                                         case F_PROTO:
1126                                                 vb->transport.s=tmp;
1127                                                 state=P_PROTO;
1128                                                 break;
1129                                         case P_PROTO:
1130                                                 break;
1131                                         default:
1132                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1133                                                                 " state %d\n", *tmp, state);
1134                                                 goto error;
1135                                 }
1136                                 break;
1137                         
1138                         default:
1139                                 switch(state){
1140                                         case F_PROTO:
1141                                                 vb->transport.s=tmp;
1142                                                 state=P_PROTO;
1143                                                 break;
1144                                         case P_PROTO:
1145                                                 break;
1146                                         default:
1147                                                 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1148                                                                 " state %d\n", *tmp, state);
1149                                                 goto error;
1150                                 }
1151                                 break;
1152                 }
1153         } /* for tmp*/
1154
1155         /* we should not be here! if everything is ok > main_via*/
1156         LOG(L_ERR, "ERROR: parse_via: bad via: end of packet on state=%d\n",
1157                         state);
1158         goto error;
1159
1160  main_via:
1161         /* inc tmp to point to the next char*/
1162         tmp++;
1163         c_nest=0;
1164         /*state should always be F_HOST here*/;
1165         for(;*tmp;tmp++){
1166                 switch(*tmp){
1167                 case ' ':
1168                 case '\t':
1169                         switch(state){
1170                                         case F_HOST:/*eat the spaces*/
1171                                                 break;
1172                                         case P_HOST:
1173                                                  *tmp=0;/*mark end of host*/
1174                                                  vb->host.len=tmp-vb->host.s;
1175                                                  state=L_PORT;
1176                                                  break;
1177                                         case L_PORT: /*eat the spaces*/
1178                                         case F_PORT:
1179                                                 break;
1180                                         case P_PORT:
1181                                                 *tmp=0; /*end of port */
1182                                                 vb->port_str.len=tmp-vb->port_str.s;
1183                                                 state=L_PARAM;
1184                                                 break;
1185                                         case L_PARAM: /* eat the space */
1186                                         case F_PARAM:
1187                                                 break;
1188                                         case P_PARAM:
1189                                         /*      *tmp=0;*/ /*!?end of param*/
1190                                                 state=L_PARAM;
1191                                                 break;
1192                                         case L_VIA:
1193                                         case F_VIA: /* eat the space */
1194                                                 break;
1195                                         case F_COMMENT:
1196                                         case P_COMMENT:
1197                                                 break;
1198                                         case F_IP6HOST: /*eat the spaces*/
1199                                                 break;
1200                                         case P_IP6HOST:
1201                                                 *tmp=0; /*mark end of host*/
1202                                                 vb->host.len=tmp-vb->host.s;
1203                                                 state=L_PORT; 
1204                                                 break;
1205                                         case F_CRLF:
1206                                         case F_LF:
1207                                         case F_CR:
1208                                                 /*previous=crlf and now =' '*/
1209                                                 state=saved_state;
1210                                                 break;
1211                                         default:
1212                                                 LOG(L_CRIT,"BUG: parse_via"
1213                                                         " on <%c>, state=%d\n",*tmp, state);
1214                                                 goto  error;
1215                                 }
1216                         break;
1217                         case '\n':
1218                                 switch(state){
1219                                         case F_HOST:/*eat the spaces*/
1220                                         case L_PORT: /*eat the spaces*/
1221                                         case F_PORT:
1222                                         case L_PARAM: /* eat the space */
1223                                         case F_PARAM:
1224                                         case F_VIA: /* eat the space */
1225                                         case L_VIA:
1226                                         case F_COMMENT:
1227                                         case P_COMMENT:
1228                                         case F_IP6HOST:
1229                                         case P_IP6HOST:
1230                                                 saved_state=state;
1231                                                 state=F_LF;
1232                                                 break;
1233                                         case P_HOST:
1234                                                  *tmp=0;/*mark end of host*/
1235                                                  vb->host.len=tmp-vb->host.s;
1236                                                  saved_state=L_PORT;
1237                                                  state=F_LF;
1238                                                  break;
1239                                         case P_PORT:
1240                                                 *tmp=0; /*end of port */
1241                                                 vb->port_str.len=tmp-vb->port_str.s;
1242                                                 saved_state=L_PARAM;
1243                                                 state=F_LF;
1244                                                 break;
1245                                         case P_PARAM:
1246                                         /*      *tmp=0;*/ /*!?end of param*/
1247                                                 saved_state=L_PARAM;
1248                                                 state=F_LF;
1249                                                 break;
1250                                         case F_CR:
1251                                                 state=F_CRLF;
1252                                                 break;
1253                                         case F_CRLF:
1254                                         case F_LF:
1255                                                 state=saved_state;
1256                                                 goto endofheader;
1257                                         default:
1258                                                 LOG(L_CRIT,"BUG: parse_via"
1259                                                         " on <%c>\n",*tmp);
1260                                                 goto  error;
1261                                 }
1262                         break;
1263                 case '\r':
1264                                 switch(state){
1265                                         case F_HOST:/*eat the spaces*/
1266                                         case L_PORT: /*eat the spaces*/
1267                                         case F_PORT:
1268                                         case L_PARAM: /* eat the space */
1269                                         case F_PARAM:
1270                                         case F_VIA: /* eat the space */
1271                                         case L_VIA:
1272                                         case F_COMMENT:
1273                                         case P_COMMENT:
1274                                         case F_IP6HOST:
1275                                         case P_IP6HOST:
1276                                                 saved_state=state;
1277                                                 state=F_CR;
1278                                                 break;
1279                                         case P_HOST:
1280                                                  *tmp=0;/*mark end of host*/
1281                                                  vb->host.len=tmp-vb->host.s;
1282                                                  saved_state=L_PORT;
1283                                                  state=F_CR;
1284                                                  break;
1285                                         case P_PORT:
1286                                                 *tmp=0; /*end of port */
1287                                                 vb->port_str.len=tmp-vb->port_str.s;
1288                                                 saved_state=L_PARAM;
1289                                                 state=F_CR;
1290                                                 break;
1291                                         case P_PARAM:
1292                                         /*      *tmp=0;*/ /*!?end of param*/
1293                                                 saved_state=L_PARAM;
1294                                                 state=F_CR;
1295                                                 break;
1296                                         case F_CRLF:
1297                                         case F_CR:
1298                                         case F_LF:
1299                                                 state=saved_state;
1300                                                 goto endofheader;
1301                                         default:
1302                                                 LOG(L_CRIT,"BUG: parse_via"
1303                                                         " on <%c>\n",*tmp);
1304                                                 goto  error;
1305                                 }
1306                         break;
1307                         
1308                         case ':':
1309                                 switch(state){
1310                                         case F_HOST:
1311                                         case F_IP6HOST:
1312                                                 LOG(L_ERR,"ERROR:parse_via:"
1313                                                         " no host found\n");
1314                                                 goto error;
1315                                         case P_IP6HOST:
1316                                                 break;
1317                                         case P_HOST:
1318                                                 *tmp=0; /*mark  end of host*/
1319                                                 vb->host.len=tmp-vb->host.s;
1320                                                 state=F_PORT;
1321                                                 break;
1322                                         case L_PORT:
1323                                                 state=F_PORT;
1324                                                 break;
1325                                         case P_PORT:
1326                                                 LOG(L_ERR, "ERROR:parse_via:"
1327                                                         " bad port\n");
1328                                                 goto error;
1329                                         case L_PARAM:
1330                                         case F_PARAM:
1331                                         case P_PARAM:
1332                                                 LOG(L_ERR, "ERROR:parse_via:"
1333                                                 " bad char <%c> in state %d\n",
1334                                                         *tmp,state);
1335                                                 goto error;
1336                                         case L_VIA:
1337                                         case F_VIA:
1338                                                 LOG(L_ERR, "ERROR:parse_via:"
1339                                                 " bad char in compact via\n");
1340                                                 goto error;
1341                                         case F_CRLF:
1342                                         case F_LF:
1343                                         case F_CR:
1344                                                 /*previous=crlf and now !=' '*/
1345                                                 goto endofheader;
1346                                         case F_COMMENT:/*everything is allowed in a comment*/
1347                                                 vb->comment.s=tmp;
1348                                                 state=P_COMMENT;
1349                                                 break;
1350                                         case P_COMMENT: /*everything is allowed in a comment*/
1351                                                 break;
1352                                         default:
1353                                                 LOG(L_CRIT,"BUG: parse_via"
1354                                                         " on <%c> state %d\n",
1355                                                         *tmp, state);
1356                                                 goto error;
1357                                 }
1358                                 break;
1359                         case ';':
1360                                 switch(state){
1361                                         case F_HOST:
1362                                         case F_IP6HOST:
1363                                                 LOG(L_ERR,"ERROR:parse_via:"
1364                                                         " no host found\n");
1365                                                 goto error;
1366                                         case P_IP6HOST:
1367                                                 LOG(L_ERR, "ERROR:parse_via: bad ipv6 reference\n");
1368                                                 goto error;
1369                                         case P_HOST:
1370                                                 *tmp=0;
1371                                                 vb->host.len=tmp-vb->host.s;
1372                                                 state=F_PARAM;
1373                                                 break;
1374                                         case P_PORT:
1375                                                 *tmp=0; /*mark the end*/
1376                                                 vb->port_str.len=tmp-vb->port_str.s;
1377                                         case L_PORT:
1378                                         case L_PARAM:
1379                                                 state=F_PARAM;
1380                                                 break;
1381                                         case F_PORT:
1382                                                 LOG(L_ERR, "ERROR:parse_via:"
1383                                                 " bad char <%c> in state %d\n",
1384                                                         *tmp,state);
1385                                                 goto error;
1386                                         case F_PARAM:
1387                                                 LOG(L_ERR,  "ERROR:parse_via:"
1388                                                         " null param?\n");
1389                                                 goto error;
1390                                         case P_PARAM:
1391                                                 /*hmm next, param?*/
1392                                                 state=F_PARAM;
1393                                                 break;
1394                                         case L_VIA:
1395                                         case F_VIA:
1396                                                 LOG(L_ERR, "ERROR:parse_via:"
1397                                                 " bad char <%c> in next via\n",
1398                                                         *tmp);
1399                                                 goto error;
1400                                         case F_CRLF:
1401                                         case F_LF:
1402                                         case F_CR:
1403                                                 /*previous=crlf and now !=' '*/
1404                                                 goto endofheader;
1405                                         case F_COMMENT:/*everything is allowed in a comment*/
1406                                                 vb->comment.s=tmp;
1407                                                 state=P_COMMENT;
1408                                                 break;
1409                                         case P_COMMENT: /*everything is allowed in a comment*/
1410                                                 break;
1411                                         
1412                                         default:
1413                                                 LOG(L_CRIT,"BUG: parse_via"
1414                                                         " on <%c> state %d\n",
1415                                                         *tmp, state);
1416                                                 goto  error;
1417                                 }
1418                         break;
1419                         case ',':
1420                                 switch(state){
1421                                         case F_HOST:
1422                                         case F_IP6HOST:
1423                                                 LOG(L_ERR,"ERROR:parse_via:"
1424                                                         " no host found\n");
1425                                                 goto error;
1426                                         case P_IP6HOST:
1427                                                 LOG(L_ERR, "ERROR:parse_via: bad ipv6 reference\n");
1428                                                 goto error;
1429                                         case P_HOST:
1430                                                 *tmp=0; /*mark the end*/
1431                                                 vb->host.len=tmp-vb->host.s;
1432                                                 state=F_VIA;
1433                                                 break;
1434                                         case P_PORT:
1435                                                 *tmp=0; /*mark the end*/
1436                                                 vb->port_str.len=tmp-vb->port_str.s;
1437                                                 state=F_VIA;
1438                                                 break;
1439                                         case L_PORT:
1440                                         case L_PARAM:
1441                                         case P_PARAM:
1442                                         case L_VIA:
1443                                                 state=F_VIA;
1444                                                 break;
1445                                         case F_PORT:
1446                                         case F_PARAM:
1447                                                 LOG(L_ERR, "ERROR:parse_via:"
1448                                                 " invalid char <%c> in state"
1449                                                 " %d\n", *tmp,state);
1450                                                 goto error;
1451                                         case F_VIA:
1452                                                 /* do  nothing,  eat ","*/
1453                                                 break;  
1454                                         case F_CRLF:
1455                                         case F_LF:
1456                                         case F_CR:
1457                                                 /*previous=crlf and now !=' '*/
1458                                                 goto endofheader;
1459                                         case F_COMMENT:/*everything is allowed in a comment*/
1460                                                 vb->comment.s=tmp;
1461                                                 state=P_COMMENT;
1462                                                 break;
1463                                         case P_COMMENT: /*everything is allowed in a comment*/
1464                                                 break;
1465                                         default:
1466                                                 LOG(L_CRIT,"BUG: parse_via"
1467                                                         " on <%c> state %d\n",
1468                                                         *tmp, state);
1469                                                 goto  error;
1470                                 }
1471                         break;
1472                         case '(':
1473                                 switch(state){
1474                                         case F_HOST:
1475                                         case F_PORT:
1476                                         case F_PARAM:
1477                                         case F_VIA:
1478                                         case F_IP6HOST:
1479                                         case P_IP6HOST: /*must be terminated in ']'*/
1480                                                 LOG(L_ERR,"ERROR:parse_via"
1481                                                         " on <%c> state %d\n",
1482                                                         *tmp, state);
1483                                                 goto  error;
1484                                         case P_HOST:
1485                                                 *tmp=0; /*mark the end*/
1486                                                 vb->host.len=tmp-vb->host.s;
1487                                                 state=F_COMMENT;
1488                                                 c_nest++;
1489                                                 break;
1490                                         case P_PORT:
1491                                                 *tmp=0; /*mark the end*/
1492                                                 vb->port_str.len=tmp-vb->port_str.s;
1493                                                 state=F_COMMENT;
1494                                                 c_nest++;
1495                                                 break;
1496                                         case P_PARAM:
1497                                                 *tmp=0; /*mark the end*/
1498                                                 vb->params.len=tmp-vb->params.s;
1499                                                 state=F_COMMENT;
1500                                                 c_nest++;
1501                                                 break;
1502                                         case L_PORT:
1503                                         case L_PARAM:
1504                                         case L_VIA:
1505                                                 state=F_COMMENT;
1506                                                 vb->params.len=tmp-vb->params.s;
1507                                                 c_nest++;
1508                                                 *tmp=0;
1509                                                 break;
1510                                         case P_COMMENT:
1511                                         case F_COMMENT:
1512                                                 c_nest++;
1513                                                 break;
1514                                         case F_CRLF:
1515                                         case F_LF:
1516                                         case F_CR:
1517                                                 /*previous=crlf and now !=' '*/
1518                                                 goto endofheader;
1519                                         default:
1520                                                 LOG(L_CRIT,"BUG: parse_via"
1521                                                         " on <%c> state %d\n",
1522                                                         *tmp, state);
1523                                                 goto  error;
1524                                 }
1525                         break;
1526                         case ')':
1527                                 switch(state){
1528                                         case F_COMMENT:
1529                                         case P_COMMENT:
1530                                                 if (c_nest){
1531                                                         c_nest--;
1532                                                         if(c_nest==0){
1533                                                                 state=L_VIA;
1534                                                                 *tmp=0;
1535                                                                 vb->comment.len=tmp-vb->comment.s;
1536                                                                 break;
1537                                                         }
1538                                                 }else{
1539                                                         LOG(L_ERR,"ERROR:"
1540                                                             "parse_via: "
1541                                                             "missing '(' - "
1542                                                             "nesting = %d\n",
1543                                                             c_nest);
1544                                                          goto error;
1545                                                 }
1546                                                 break;
1547                                         case F_HOST:
1548                                         case F_PORT:
1549                                         case F_PARAM:
1550                                         case F_VIA:
1551                                         case P_HOST:
1552                                         case P_PORT:
1553                                         case P_PARAM:
1554                                         case L_PORT:
1555                                         case L_PARAM:
1556                                         case L_VIA:
1557                                         case F_IP6HOST:
1558                                         case P_IP6HOST:
1559                                                 LOG(L_ERR,"ERROR:parse_via"
1560                                                         " on <%c> state %d\n",
1561                                                         *tmp, state);
1562                                                 goto  error;
1563                                         case F_CRLF:
1564                                         case F_LF:
1565                                         case F_CR:
1566                                                 /*previous=crlf and now !=' '*/
1567                                                 goto endofheader;
1568                                         default:
1569                                                 LOG(L_CRIT,"BUG: parse_via"
1570                                                         " on <%c> state %d\n",
1571                                                         *tmp, state);
1572                                                 goto  error;
1573                                 }
1574                                 break;
1575                         case '[':
1576                                 switch(state){
1577                                         case F_HOST:
1578                                                 state=F_IP6HOST;
1579                                                 break;
1580                                         case F_COMMENT:/*everything is allowed in a comment*/
1581                                                 vb->comment.s=tmp;
1582                                                 state=P_COMMENT;
1583                                                 break;
1584                                         case P_COMMENT:
1585                                                 break;
1586                                         case F_CRLF:
1587                                         case F_LF:
1588                                         case F_CR:
1589                                                 /*previous=crlf and now !=' '*/
1590                                                 goto endofheader;
1591                                         default:
1592                                                 LOG(L_ERR,"ERROR:parse_via"
1593                                                         " on <%c> state %d\n",
1594                                                         *tmp, state);
1595                                                 goto  error;
1596                                 }
1597                                 break;
1598                         case ']':
1599                                 switch(state){
1600                                         case P_IP6HOST:
1601                                                 *tmp=0; /*mark the end*/
1602                                                 vb->host.len=tmp-vb->host.s;
1603                                                 state=L_PORT;
1604                                                 break;
1605                                         case F_CRLF:
1606                                         case F_LF:
1607                                         case F_CR:
1608                                                 /*previous=crlf and now !=' '*/
1609                                                 goto endofheader;
1610                                         case F_COMMENT:/*everything is allowed in a comment*/
1611                                                 vb->comment.s=tmp;
1612                                                 state=P_COMMENT;
1613                                                 break;
1614                                         case P_COMMENT:
1615                                                 break;
1616                                         default:
1617                                                 LOG(L_ERR,"ERROR:parse_via"
1618                                                         " on <%c> state %d\n",
1619                                                         *tmp, state);
1620                                                 goto  error;
1621                                 }
1622                                 break;
1623                                                 
1624                         default:
1625                                 switch(state){
1626                                         case F_HOST:
1627                                                 state=P_HOST;
1628                                                 vb->host.s=tmp;
1629                                                 break;
1630                                         case P_HOST:
1631                                                 break;
1632                                         case F_PORT:
1633                                                 state=P_PORT;
1634                                                 vb->port_str.s=tmp;
1635                                                 break;
1636                                         case P_PORT:
1637                                                 /*check if number?*/
1638                                                 break;
1639                                         case F_PARAM:
1640                                                 /*state=P_PARAM*/;
1641                                                 if(vb->params.s==0) vb->params.s=tmp;
1642                                                 param=pkg_malloc(sizeof(struct via_param));
1643                                                 if (param==0){
1644                                                         LOG(L_ERR, "ERROR:parse_via: mem. allocation"
1645                                                                         " error\n");
1646                                                         goto error;
1647                                                 }
1648                                                 memset(param,0, sizeof(struct via_param));
1649                                                 tmp=parse_via_param(tmp, end, &state, &saved_state,
1650                                                                                         param);
1651
1652                                                 switch(state){
1653                                                         case L_PARAM:
1654                                                         case F_PARAM:
1655                                                         case F_LF:
1656                                                         case F_CR:
1657                                                                 break;
1658                                                         case F_VIA:
1659                                                                 vb->params.len=tmp-vb->params.s;
1660                                                                 *tmp=0;
1661                                                                 break;
1662                                                         case END_OF_HEADER:
1663                                                                 vb->params.len=tmp-vb->params.s;
1664                                                                 state=saved_state;
1665                                                                 goto endofheader;
1666                                                         case PARAM_ERROR:
1667                                                                 pkg_free(param);
1668                                                                 goto error;
1669                                                         default:
1670                                                                 LOG(L_ERR, "ERROR: parse_via after"
1671                                                                                 " parse_via_param: invalid"
1672                                                                                 " char <%c> on state %d\n",
1673                                                                                 *tmp, state);
1674                                                                 goto error;
1675                                                 }
1676                                                 /*add param to the list*/
1677                                                 if (vb->last_param)     vb->last_param->next=param;
1678                                                 else                            vb->param_lst=param;
1679                                                 vb->last_param=param;
1680                                                 if (param->type==PARAM_BRANCH)
1681                                                         vb->branch=param;
1682                                                 else if (param->type==PARAM_RECEIVED)
1683                                                         vb->received=param;
1684                                                 break;
1685                                         case P_PARAM:
1686                                                 break;
1687                                         case F_VIA:
1688                                                 /*vb->next=tmp;*/ /*???*/
1689                                                 goto nextvia;
1690                                         case L_PORT:
1691                                         case L_PARAM:
1692                                         case L_VIA:
1693                                                 LOG(L_ERR,"ERROR:parse_via"
1694                                                         " on <%c> state %d (default)\n",
1695                                                         *tmp, state);
1696                                                 goto  error;
1697                                         case F_COMMENT:
1698                                                 state=P_COMMENT;
1699                                                 vb->comment.s=tmp;
1700                                                 break;
1701                                         case P_COMMENT:
1702                                                 break;
1703                                         case F_IP6HOST:
1704                                                 state=P_IP6HOST;
1705                                                 vb->host.s=tmp;
1706                                                 break;
1707                                         case P_IP6HOST:
1708                                                 break;
1709                                         case F_CRLF:
1710                                         case F_LF:
1711                                         case F_CR:
1712                                                 /*previous=crlf and now !=' '*/
1713                                                 goto endofheader;
1714                                         default:
1715                                                 LOG(L_ERR, "BUG:parse_via:"
1716                                                         " invalid char <%c>"
1717                                                         " in state %d\n",
1718                                                         *tmp, state);
1719                                                 goto error;
1720                                 }
1721
1722
1723                 }
1724         }
1725
1726         DBG("end of packet reached, state=%d\n", state);
1727         goto endofpacket; /*end of packet, probably should be goto error*/
1728         
1729 endofheader:
1730         state=saved_state;
1731         DBG("end of header reached, state=%d\n", state);
1732 endofpacket:
1733         /* check if error*/
1734         switch(state){
1735                 case P_HOST:
1736                 case L_PORT:
1737                 case P_PORT:
1738                 case L_PARAM:
1739                 case P_PARAM:
1740                 case P_VALUE:
1741                 case GEN_PARAM:
1742                 case FIN_HIDDEN:
1743                 case L_VIA:
1744                         break;
1745                 default:
1746                         LOG(L_ERR, "ERROR: parse_via: invalid via - end of header in"
1747                                         " state %d\n", state);
1748                         goto error;
1749         }
1750
1751
1752         /*
1753         if (proto) printf("<SIP/2.0/%s>\n", proto);
1754         if (host) printf("host= <%s>\n", host);
1755         if (port_str) printf("port= <%s>\n", port_str);
1756         if (param) printf("params= <%s>\n", param);
1757         if (comment) printf("comment= <%s>\n", comment);
1758         if(next_via) printf("next_via= <%s>\n", next_via);
1759         */
1760         /*DBG("parse_via: rest=<%s>\n", tmp);*/
1761
1762         vb->error=PARSE_OK;
1763         vb->bsize=tmp-buffer;
1764         if (vb->port_str.s){
1765                 vb->port=str2s((unsigned char*)vb->port_str.s, vb->port_str.len, &err);
1766                 if (err){
1767                                         LOG(L_ERR, "ERROR: parse_via: invalid port number <%s>\n",
1768                                                 vb->port_str.s);
1769                                         goto error;
1770                 }
1771         }
1772         return tmp;
1773 nextvia:
1774         DBG("parse_via: next_via\n");
1775         vb->error=PARSE_OK;
1776         vb->bsize=tmp-buffer;
1777         if (vb->port_str.s){
1778                 vb->port=str2s((unsigned char*)vb->port_str.s, vb->port_str.len, &err);
1779                 if (err){
1780                                         LOG(L_ERR, "ERROR: parse_via: invalid port number <%s>\n",
1781                                                 vb->port_str.s);
1782                                         goto error;
1783                 }
1784         }
1785         vb->next=pkg_malloc(sizeof(struct via_body));
1786         if (vb->next==0){
1787                 LOG(L_ERR, "ERROR: parse_via: out of memory\n");
1788                 goto error;
1789         }
1790         vb=vb->next;
1791         memset(vb, 0, sizeof(struct via_body));
1792         buffer=tmp;
1793         goto parse_again;
1794
1795 error:
1796         if (end>buffer){
1797                 LOG(L_ERR, "ERROR: parse_via on: <%.*s>\n", (int)(end-buffer), buffer);
1798         }
1799         if ((tmp>buffer)&&(tmp<end)){
1800                 LOG(L_ERR, "ERROR: parse_via parse error, parsed so far:<%.*s>\n",
1801                                 (int)(tmp-buffer), buffer );
1802         }else{
1803                 LOG(L_ERR, "ERROR: parse_via: via parse error\n");
1804         }
1805         vb->error=PARSE_ERROR;
1806         return tmp;
1807 }
1808
1809
1810 static inline void free_via_param_list(struct via_param* vp)
1811 {
1812         struct via_param* foo;
1813         while(vp){
1814                 foo=vp;
1815                 vp=vp->next;
1816                 pkg_free(foo);
1817         }
1818 }
1819
1820
1821 void free_via_list(struct via_body* vb)
1822 {
1823         struct via_body* foo;
1824         while(vb){
1825                 foo=vb;
1826                 vb=vb->next;
1827                 if (foo->param_lst) free_via_param_list(foo->param_lst);
1828                 pkg_free(foo);
1829         }
1830 }