123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- /*
- * sip first line parsing automaton
- *
- * 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:
- * [email protected]
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * History:
- * ---------
- * 2003-02-28 scratchpad compatibility abandoned (jiri)
- * 2003-01-28: removed 0-terminators from first line (jiri)
- * 2003-04-26 ZSW (jiri)
- */
- /*! \file
- * \brief Parser :: SIP first line parsing automaton
- *
- * \ingroup parser
- */
- #include "../comp_defs.h"
- #include "../dprint.h"
- #include "msg_parser.h"
- #include "parser_f.h"
- #include "../mem/mem.h"
- #include "../ut.h"
- int http_reply_parse = 0;
- /* grammar:
- request = method SP uri SP version CRLF
- response = version SP status SP reason CRLF
- (version = "SIP/2.0")
- */
- /* 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")
- */
-
- offset = 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 if (http_reply_parse != 0 &&
- (*tmp=='H' || *tmp=='h') &&
- /* 'HTTP/1.' */
- strncasecmp( tmp+1, HTTP_VERSION+1, HTTP_VERSION_LEN-1)==0 &&
- /* [0|1] */
- ((*(tmp+HTTP_VERSION_LEN)=='0') || (*(tmp+HTTP_VERSION_LEN)=='1')) &&
- (*(tmp+HTTP_VERSION_LEN+1)==' ') ){
- /* ugly hack to be able to route http replies
- * Note: - the http reply must have a via
- * - the message is marked as SIP_REPLY (ugly)
- */
- fl->type=SIP_REPLY;
- fl->u.reply.version.len=HTTP_VERSION_LEN+1 /*include last digit*/;
- tmp=buffer+HTTP_VERSION_LEN+1 /* last digit */;
- } else IFISMETHOD( INVITE, 'I' )
- else IFISMETHOD( CANCEL, 'C')
- else IFISMETHOD( ACK, 'A' )
- else IFISMETHOD( BYE, 'B' )
- else IFISMETHOD( INFO, 'I' )
- else IFISMETHOD( REGISTER, 'R')
- else IFISMETHOD( SUBSCRIBE, 'S')
- else IFISMETHOD( NOTIFY, 'N')
- else IFISMETHOD( MESSAGE, 'M')
- else IFISMETHOD( OPTIONS, 'O')
- else IFISMETHOD( PRACK, 'P')
- else IFISMETHOD( UPDATE, 'U')
- else IFISMETHOD( REFER, 'R')
- else IFISMETHOD( PUBLISH, 'P')
- /* 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 */
- 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;
- }
- 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) {
- LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %.*s\n",
- fl->u.request.uri.len, ZSW(second) );
- 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 {
- LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %.*s\n",
- fl->u.request.uri.len, ZSW(second) );
- 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;
- }
- fl->u.request.version.s=third;
- fl->u.request.version.len=tmp-third;
- fl->len=nl-buffer;
- return nl;
- error:
- LOG(L_DBG, "parse_first_line: bad %s first line\n",
- (fl->type==SIP_REPLY)?"reply(status)":"request");
- LOG(L_DBG, "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)=176; /* '°' */
- LOG(L_DBG, "parsed so far: %.*s\n", offset, ZSW(prn) );
- pkg_free( prn );
- };
- error1:
- fl->type=SIP_INVALID;
- LOG(L_ERR, "parse_first_line: bad message (offset: %d)\n", offset);
- /* skip line */
- nl=eat_line(buffer,len);
- return nl;
- }
|