b6f4c1df |
/*
* $Id$
*
* sip first line parsing automaton
*
|
7dd0b342 |
*
* Copyright (C) 2001-2003 Fhg Fokus
*
* This file is part of ser, a free SIP server.
*
* ser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
049f64c2 |
*
* History:
* ---------
* 2003-01-28: removed 0-terminators from first line (jiri)
|
b6f4c1df |
*/
|
7dd0b342 |
|
049f64c2 |
#include "../comp_defs.h"
|
3881f12c |
#include "../dprint.h"
|
b6f4c1df |
#include "msg_parser.h"
|
2bb60634 |
#include "parser_f.h"
#include "../mem/mem.h"
|
b6f4c1df |
/* grammar:
request = method SP uri SP version CRLF
response = version SP status SP reason CRLF
(version = "SIP/2.0")
*/
/*known methods: INVITE, ACK, CANCEL, BYE*/
|
2bb60634 |
enum { START,
INVITE1, INVITE2, INVITE3, INVITE4, INVITE5,
ACK1, ACK2,
CANCEL1, CANCEL2, CANCEL3, CANCEL4, CANCEL5,
BYE1, BYE2,
SIP1, SIP2, SIP3, SIP4, SIP5, SIP6,
FIN_INVITE = 100, FIN_ACK, FIN_CANCEL, FIN_BYE, FIN_SIP,
P_METHOD = 200, L_URI, P_URI, L_VER,
VER1, VER2, VER3, VER4, VER5, VER6, FIN_VER,
L_STATUS, P_STATUS, L_REASON, P_REASON,
L_LF, F_CR, F_LF
|
b6f4c1df |
};
|
049f64c2 |
#ifdef _CURRENTLY_UNUSED
|
b6f4c1df |
char* parse_fline(char* buffer, char* end, struct msg_start* fl)
{
char* tmp;
register int state;
unsigned short stat;
stat=0;
fl->type=SIP_REQUEST;
state=START;
for(tmp=buffer;tmp<end;tmp++){
switch(*tmp){
case ' ':
case '\t':
switch(state){
case START: /*allow space at the beginnig, althoug not
legal*/
break;
case L_URI:
case L_VER:
case L_STATUS:
case L_REASON:
case L_LF:
/*eat space*/
break;
case FIN_INVITE:
*tmp=0;
fl->u.request.method.len=tmp-fl->u.request.method.s;
fl->u.request.method_value=METHOD_INVITE;
state=L_URI;
break;
case FIN_ACK:
*tmp=0;
fl->u.request.method.len=tmp-fl->u.request.method.s;
fl->u.request.method_value=METHOD_ACK;
state=L_URI;
break;
case FIN_CANCEL:
*tmp=0;
fl->u.request.method.len=tmp-fl->u.request.method.s;
fl->u.request.method_value=METHOD_CANCEL;
state=L_URI;
break;
case FIN_BYE:
*tmp=0;
fl->u.request.method.len=tmp-fl->u.request.method.s;
fl->u.request.method_value=METHOD_BYE;
state=L_URI;
break;
case FIN_SIP:
*tmp=0;
fl->u.reply.version.len=tmp-fl->u.reply.version.s;
state=L_STATUS;
fl->type=SIP_REPLY;
break;
case P_URI:
*tmp=0;
fl->u.request.uri.len=tmp-fl->u.request.uri.s;
state=L_VER;
break;
case FIN_VER:
*tmp=0;
fl->u.request.version.len=tmp-fl->u.request.version.s;
state=L_LF;
break;
case P_STATUS:
*tmp=0;
fl->u.reply.status.len=tmp-fl->u.reply.status.s;
state=L_REASON;
break;
case P_REASON:
/* *tmp=0;
fl->u.reply.reason.len=tmp-fl->u.reply.reason.s;
*/
break;
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
case P_METHOD:
default:
*tmp=0;
fl->u.request.method.len=tmp-fl->u.request.method.s;
fl->u.request.method_value=METHOD_OTHER;
state=L_URI;
}
break;
case 's':
case 'S':
switch(state){
case START:
state=SIP1;
fl->u.reply.version.s=tmp;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
fl->u.request.version.s=tmp;
state=VER1;
break;
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'i':
case 'I':
switch(state){
case START:
state=INVITE1;
fl->u.request.method.s=tmp;
break;
case INVITE3:
state=INVITE4;
break;
case SIP1:
state=SIP2;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case VER1:
state=VER2;
break;
case L_VER:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'p':
case 'P':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case SIP2:
state=SIP3;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case VER2:
state=VER3;
break;
case L_VER:
case VER1:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case '/':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case SIP3:
state=SIP4;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case VER3:
state=VER4;
break;
case L_VER:
case VER1:
case VER2:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case '2':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case SIP4:
state=SIP5;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
stat=stat*10+*tmp-'0';
break;
case L_STATUS:
stat=*tmp-'0';
fl->u.reply.status.s=tmp;
break;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case VER4:
state=VER5;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case '.':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case SIP5:
state=SIP6;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case VER5:
state=VER6;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case '0':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case SIP6:
state=FIN_SIP;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
stat=stat*10;
break;
case L_STATUS:
stat=0;
fl->u.reply.status.s=tmp;
break;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case VER6:
state=FIN_VER;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'n':
case 'N':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case INVITE1:
state=INVITE2;
break;
case CANCEL2:
state=CANCEL3;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'v':
case 'V':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case INVITE2:
state=INVITE3;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 't':
case 'T':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case INVITE4:
state=INVITE5;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'e':
case 'E':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case INVITE5:
state=FIN_INVITE;
break;
case CANCEL4:
state=CANCEL5;
break;
case BYE2:
state=FIN_BYE;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'a':
case 'A':
switch(state){
case START:
state=ACK1;
fl->u.request.method.s=tmp;
break;
case CANCEL1:
state=CANCEL2;
break;
case BYE2:
state=FIN_BYE;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'c':
case 'C':
switch(state){
case START:
state=CANCEL1;
fl->u.request.method.s=tmp;
break;
case CANCEL3:
state=CANCEL4;
break;
case ACK1:
state=ACK2;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'k':
case 'K':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case ACK2:
state=FIN_ACK;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'l':
case 'L':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case CANCEL5:
state=FIN_CANCEL;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'b':
case 'B':
switch(state){
case START:
state=BYE1;
fl->u.request.method.s=tmp;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case 'y':
case 'Y':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case BYE1:
state=BYE2;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
break;
case '\r':
switch(state){
case P_REASON:
*tmp=0;
fl->u.reply.reason.len=tmp-fl->u.reply.reason.s;
state=F_CR;
break;
case L_LF:
state=F_CR;
break;
case FIN_VER:
*tmp=0;
fl->u.request.version.len=tmp-fl->u.request.version.s;
state=F_CR;
break;
case L_REASON:
state=F_CR;
break;
default:
|
b2dec9c6 |
LOG(L_ERR, "ERROR: parse_first_line: invalid"
"message\n");
|
b6f4c1df |
goto error;
}
break;
case '\n':
switch(state){
case P_REASON:
*tmp=0;
fl->u.reply.reason.len=tmp-fl->u.reply.reason.s;
state=F_LF;
goto skip;
case FIN_VER:
*tmp=0;
fl->u.request.version.len=tmp-fl->u.request.version.s;
state=F_LF;
goto skip;
case L_REASON:
case L_LF:
case F_CR:
state=F_LF;
goto skip;
default:
|
b2dec9c6 |
LOG(L_ERR, "ERROR: parse_first_line: invalid"
" message\n");
|
b6f4c1df |
goto error;
}
break;
case '1':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
stat=stat*10+*tmp-'0';
break;
case L_STATUS:
stat=*tmp-'0';
state=P_STATUS;
fl->u.reply.status.s=tmp;
break;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
default:
switch(state){
case START:
state=P_METHOD;
fl->u.request.method.s=tmp;
break;
case P_URI:
case P_REASON:
case P_METHOD:
break;
case L_REASON:
fl->u.reply.reason.s=tmp;
state=P_REASON;
break;
case P_STATUS:
case L_STATUS:
LOG(L_ERR, "ERROR: parse_first_line: non-number "
"character <%c> in request status\n", *tmp);
goto error;
case L_LF:
LOG(L_ERR, "ERROR: parse_first_line: invalid "
"character <%c> in request\n", *tmp);
goto error;
case L_URI:
fl->u.request.uri.s=tmp;
state=P_URI;
break;
case L_VER:
case VER1:
case VER2:
case VER3:
case VER4:
case VER5:
case VER6:
case FIN_VER:
LOG(L_ERR, "ERROR: parse_first_line: invalid version "
" in request\n");
goto error;
default:
state=P_METHOD;
}
}
}
skip:
|
049f64c2 |
fl->len=tmp-buf;
|
b6f4c1df |
if (fl->type==SIP_REPLY){
fl->u.reply.statuscode=stat;
|
dda9dab1 |
/* fl->u.reply.statusclass=stat/100; */
|
b6f4c1df |
}
return tmp;
error:
LOG(L_ERR, "ERROR: while parsing first line (state=%d)\n", state);
fl->type=SIP_INVALID;
return tmp;
}
|
2bb60634 |
|
049f64c2 |
#endif /* currently unused */
|
2bb60634 |
/* parses the first line, returns pointer to next line & fills fl;
also modifies buffer (to avoid extra copy ops) */
char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
{
char *tmp;
char* second;
char* third;
char* nl;
int offset;
/* int l; */
char* end;
char s1,s2,s3;
char *prn;
unsigned int t;
/* grammar:
request = method SP uri SP version CRLF
response = version SP status SP reason CRLF
(version = "SIP/2.0")
*/
end=buffer+len;
/* see if it's a reply (status) */
/* jku -- parse well-known methods */
/* drop messages which are so short they are for sure useless;
utilize knowledge of minimum size in parsing the first
token
*/
if (len <=16 ) {
LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
goto error1;
}
tmp=buffer;
/* is it perhaps a reply, ie does it start with "SIP...." ? */
if ( (*tmp=='S' || *tmp=='s') &&
strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
(*(tmp+SIP_VERSION_LEN)==' ')) {
fl->type=SIP_REPLY;
fl->u.reply.version.len=SIP_VERSION_LEN;
tmp=buffer+SIP_VERSION_LEN;
} else IFISMETHOD( INVITE, 'I' )
else IFISMETHOD( CANCEL, 'C')
else IFISMETHOD( ACK, 'A' )
else IFISMETHOD( BYE, 'B' )
/* if you want to add another method XXX, include METHOD_XXX in
H-file (this is the value which you will take later in
processing and define XXX_LEN as length of method name;
then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
latter; everything must be capitals
*/
else {
/* neither reply, nor any of known method requests,
let's believe it is an unknown method request
*/
tmp=eat_token_end(buffer,buffer+len);
if ((tmp==buffer)||(tmp>=end)){
LOG(L_INFO, "ERROR:parse_first_line: empty or bad first line\n");
goto error1;
}
if (*tmp!=' ') {
LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
goto error1;
}
fl->type=SIP_REQUEST;
fl->u.request.method_value=METHOD_OTHER;
fl->u.request.method.len=tmp-buffer;
}
/* identifying type of message over now;
tmp points at space after; go ahead */
fl->u.request.method.s=buffer; /* store ptr to first token */
|
049f64c2 |
#ifdef DONT_REMOVE_ZT
|
2bb60634 |
(*tmp)=0; /* mark the 1st token end */
|
049f64c2 |
#endif
|
2bb60634 |
second=tmp+1; /* jump to second token */
offset=second-buffer;
/* EoJku */
/* next element */
tmp=eat_token_end(second, second+len-offset);
if (tmp>=end){
goto error;
}
offset+=tmp-second;
third=eat_space_end(tmp, tmp+len-offset);
offset+=third-tmp;
if ((third==tmp)||(tmp>=end)){
goto error;
}
|
049f64c2 |
#ifdef DONT_REMOVE_ZT
|
2bb60634 |
*tmp=0; /* mark the end of the token */
|
049f64c2 |
#endif
|
2bb60634 |
fl->u.request.uri.s=second;
fl->u.request.uri.len=tmp-second;
/* jku: parse status code */
if (fl->type==SIP_REPLY) {
if (fl->u.request.uri.len!=3) {
|
049f64c2 |
LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %.*s\n",
fl->u.request.uri.len, second );
|
2bb60634 |
goto error;
}
s1=*second; s2=*(second+1);s3=*(second+2);
if (s1>='0' && s1<='9' &&
s2>='0' && s2<='9' &&
s3>='0' && s3<='9' ) {
fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
} else {
|
049f64c2 |
LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %.*s\n",
fl->u.request.uri.len, second );
|
2bb60634 |
goto error;
}
}
/* EoJku */
/* last part: for a request it must be the version, for a reply
* it can contain almost anything, including spaces, so we don't care
* about it*/
if (fl->type==SIP_REQUEST){
tmp=eat_token_end(third,third+len-offset);
offset+=tmp-third;
if ((tmp==third)||(tmp>=end)){
goto error;
}
if (! is_empty_end(tmp, tmp+len-offset)){
goto error;
}
}else{
tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line
('\n' or '\r') */
if (tmp>=end){ /* no crlf in packet => invalid */
goto error;
}
offset+=tmp-third;
}
nl=eat_line(tmp,len-offset);
if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
goto error;
}
|
049f64c2 |
#ifdef DONT_REMOVE_ZT
|
2bb60634 |
*tmp=0;
|
049f64c2 |
#endif
|
2bb60634 |
fl->u.request.version.s=third;
fl->u.request.version.len=tmp-third;
|
049f64c2 |
fl->len=nl-buffer;
|
2bb60634 |
return nl;
error:
LOG(L_INFO, "ERROR:parse_first_line: bad %s first line\n",
(fl->type==SIP_REPLY)?"reply(status)":"request");
LOG(L_INFO, "ERROR: at line 0 char %d: \n", offset );
prn=pkg_malloc( offset );
if (prn) {
for (t=0; t<offset; t++)
if (*(buffer+t)) *(prn+t)=*(buffer+t);
else *(prn+t)='�';
LOG(L_INFO, "ERROR: parsed so far: %.*s\n", offset, prn );
pkg_free( prn );
};
error1:
fl->type=SIP_INVALID;
LOG(L_INFO, "ERROR:parse_first_line: bad message\n");
/* skip line */
nl=eat_line(buffer,len);
return nl;
}
|