parse_fline.c

Go to the documentation of this file.
00001 /*
00002  * $Id: parse_fline.c 4750 2008-08-27 14:22:55Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 /*!
00024  * \file
00025  * \brief SIP first line parsing automaton
00026  * \ingroup parser
00027  */
00028 
00029 #include "../dprint.h"
00030 #include "msg_parser.h"
00031 #include "parser_f.h"
00032 #include "parse_methods.h"
00033 #include "../mem/mem.h"
00034 #include "../ut.h"
00035 
00036 /* grammar:
00037    request  =  method SP uri SP version CRLF
00038    response =  version SP status  SP reason  CRLF
00039    (version = "SIP/2.0")
00040 */
00041 
00042 /*known methods: INVITE, ACK, CANCEL, BYE*/
00043 
00044 enum { START,
00045        INVITE1, INVITE2, INVITE3, INVITE4, INVITE5,
00046        ACK1, ACK2,
00047        CANCEL1, CANCEL2, CANCEL3, CANCEL4, CANCEL5,
00048        BYE1, BYE2,
00049        SIP1, SIP2, SIP3, SIP4, SIP5, SIP6,
00050        FIN_INVITE = 100, FIN_ACK, FIN_CANCEL, FIN_BYE, FIN_SIP,
00051        P_METHOD = 200, L_URI, P_URI, L_VER, 
00052        VER1, VER2, VER3, VER4, VER5, VER6, FIN_VER,
00053        L_STATUS, P_STATUS, L_REASON, P_REASON,
00054        L_LF, F_CR, F_LF
00055 };
00056 
00057 /* parses the first line, returns pointer to  next line  & fills fl;
00058    also  modifies buffer (to avoid extra copy ops) */
00059 char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
00060 {
00061    
00062    char *tmp;
00063    char* second;
00064    char* third;
00065    char* nl;
00066    unsigned int offset;
00067    /* int l; */
00068    char* end;
00069    char s1,s2,s3;
00070    char *prn;
00071    unsigned int t;
00072 
00073    /* grammar:
00074       request  =  method SP uri SP version CRLF
00075       response =  version SP status  SP reason  CRLF
00076       (version = "SIP/2.0")
00077    */
00078    
00079 
00080    end=buffer+len;
00081    /* see if it's a reply (status) */
00082 
00083    /* jku  -- parse well-known methods */
00084 
00085    /* drop messages which are so short they are for sure useless;
00086            utilize knowledge of minimum size in parsing the first
00087       token 
00088         */
00089    if (len <=16 ) {
00090       LM_INFO("message too short: %d\n", len);
00091       goto error1;
00092    }
00093 
00094    tmp=buffer;
00095    /* is it perhaps a reply, ie does it start with "SIP...." ? */
00096    if (  (*tmp=='S' || *tmp=='s') && 
00097       strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
00098       (*(tmp+SIP_VERSION_LEN)==' ')) {
00099          fl->type=SIP_REPLY;
00100          fl->u.reply.version.len=SIP_VERSION_LEN;
00101          tmp=buffer+SIP_VERSION_LEN;
00102    } else IFISMETHOD( INVITE, 'I' )
00103    else IFISMETHOD( CANCEL, 'C')
00104    else IFISMETHOD( ACK, 'A' )
00105    else IFISMETHOD( BYE, 'B' ) 
00106    else IFISMETHOD( INFO, 'I' )
00107    /* if you want to add another method XXX, include METHOD_XXX in
00108            H-file (this is the value which you will take later in
00109            processing and define XXX_LEN as length of method name;
00110       then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
00111       latter; everything must be capitals
00112    */
00113    else {
00114       /* neither reply, nor any of known method requests, 
00115          let's believe it is an unknown method request
00116          */
00117       tmp=eat_token_end(buffer,buffer+len);
00118       if ((tmp==buffer)||(tmp>=end)){
00119          LM_INFO("empty  or bad first line\n");
00120          goto error1;
00121       }
00122       if (*tmp!=' ') {
00123          LM_INFO("method not followed by SP\n");
00124          goto error1;
00125       }
00126       fl->type=SIP_REQUEST;
00127       /* see if it is another known method */
00128       /* fl->u.request.method_value=METHOD_OTHER; */
00129       if(parse_method(buffer, tmp,
00130             (unsigned int*)&fl->u.request.method_value)==0)
00131       {
00132          LM_INFO("failed to parse the method\n");
00133          goto error1;
00134       }
00135       fl->u.request.method.len=tmp-buffer;
00136    }
00137    
00138 
00139    /* identifying type of message over now; 
00140       tmp points at space after; go ahead */
00141 
00142    fl->u.request.method.s=buffer;  /* store ptr to first token */
00143    second=tmp+1;        /* jump to second token */
00144    offset=second-buffer;
00145 
00146 /* EoJku */
00147    
00148    /* next element */
00149    tmp=eat_token_end(second, second+len-offset);
00150    if (tmp>=end){
00151       goto error;
00152    }
00153    offset+=tmp-second;
00154    third=eat_space_end(tmp, tmp+len-offset);
00155    offset+=third-tmp;
00156    if ((third==tmp)||(tmp>=end)){
00157       goto error;
00158    }
00159    fl->u.request.uri.s=second;
00160    fl->u.request.uri.len=tmp-second;
00161 
00162    /* jku: parse status code */
00163    if (fl->type==SIP_REPLY) {
00164       if (fl->u.request.uri.len!=3) {
00165          LM_INFO("len(status code)!=3: %.*s\n",
00166             fl->u.request.uri.len, ZSW(second) );
00167          goto error;
00168       }
00169       s1=*second; s2=*(second+1);s3=*(second+2);
00170       if (s1>='0' && s1<='9' && 
00171           s2>='0' && s2<='9' &&
00172           s3>='0' && s3<='9' ) {
00173          fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
00174       } else {
00175          LM_INFO("status_code non-numerical: %.*s\n",
00176             fl->u.request.uri.len, ZSW(second) );
00177          goto error;
00178       }
00179    }
00180    /* EoJku */
00181 
00182    /*  last part: for a request it must be the version, for a reply
00183     *  it can contain almost anything, including spaces, so we don't care
00184     *  about it*/
00185    if (fl->type==SIP_REQUEST){
00186       tmp=eat_token_end(third,third+len-offset);
00187       offset+=tmp-third;
00188       if ((tmp==third)||(tmp>=end)){
00189          goto error;
00190       }
00191       if (! is_empty_end(tmp, tmp+len-offset)){
00192          goto error;
00193       }
00194    }else{
00195       tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
00196                                       ('\n' or '\r') */
00197       if (tmp>=end){ /* no crlf in packet => invalid */
00198          goto error;
00199       }
00200       offset+=tmp-third;
00201    }
00202    nl=eat_line(tmp,len-offset);
00203    if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
00204       goto error;
00205    }
00206    fl->u.request.version.s=third;
00207    fl->u.request.version.len=tmp-third;
00208    fl->len=nl-buffer;
00209 
00210    return nl;
00211 
00212 error:
00213    LM_ERR("bad %s first line\n",
00214       (fl->type==SIP_REPLY)?"reply(status)":"request");
00215 
00216    LM_ERR("at line 0 char %d: \n", offset );
00217    prn=pkg_malloc( offset );
00218    if (prn) {
00219       for (t=0; t<offset; t++)
00220          if (*(buffer+t)) *(prn+t)=*(buffer+t);
00221          else *(prn+t)='°';
00222       LM_ERR("parsed so far: %.*s\n", offset, ZSW(prn) );
00223       pkg_free( prn );
00224    };
00225 error1:
00226    fl->type=SIP_INVALID;
00227    LM_INFO("bad message\n");
00228    /* skip  line */
00229    nl=eat_line(buffer,len);
00230    return nl;
00231 }

Generated on Thu May 24 00:00:28 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6