parse_methods.c

Go to the documentation of this file.
00001 /*
00002  * $Id: parse_methods.c 4720 2008-08-23 10:56:15Z henningw $
00003  *
00004  * Copyright (c) 2004 Juha Heinanen
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  * History:
00023  * --------
00024  *  2005-07-05 - moved and merged method types in msg_parser.h (ramona)
00025  *             - changed and exported parse_method() to use it from other
00026  *               files (ramona)
00027  */
00028 
00029 /*!
00030  * \file
00031  * \brief Method parser
00032  * \ingroup parser
00033  */
00034 
00035 #include <strings.h>
00036 #include "../dprint.h"
00037 #include "../trim.h"
00038 #include "../core_stats.h"
00039 #include "parse_methods.h"
00040 #include "msg_parser.h"
00041 
00042 
00043 /*!
00044  * Check if argument is valid RFC3261 token character.
00045  */
00046 static inline int method_char(char _c)
00047 {
00048    return (_c >= 65 && _c <= 90)    /* upper alpha */
00049       || (_c >= 97 && _c <= 122)   /* lower aplha */
00050       || (_c >= 48 && _c <= 57)    /* digits */
00051       || (_c == '-') || (_c == '.') || (_c == '%') || (_c == '*')
00052       || (_c == '_') || (_c == '+') || (_c == '~') || (_c == '+');
00053  }
00054  
00055  
00056 /*!
00057  * Parse a method pointed by start, end is the last character to check (if NULL
00058  * assume that start is a zero terminated string)
00059  * => assign enum bit to method.
00060  * \return pointer to next char if parse succeeded, NULL otherwise
00061  */
00062 char* parse_method(char* start, char* end, unsigned int* method)
00063 {
00064    int len=0;
00065    int max=0;
00066       
00067     if (!start || !method) {
00068        LM_ERR("invalid parameter value\n");
00069        return NULL;
00070     }
00071 
00072     if(end)
00073        max = end - start;
00074     *method = METHOD_UNDEF;
00075 
00076     switch (start[0]) {
00077        case 'A':
00078        case 'a':
00079          if(end && max<3)
00080             goto unknown;
00081 
00082          if ((start[1]=='c' || start[1]=='C')
00083                && (start[2]=='k' || start[2]=='K'))
00084          {
00085             *method = METHOD_ACK;
00086             len = 3;
00087             goto done;
00088          }
00089          goto unknown;
00090 
00091       case 'B':
00092       case 'b':
00093          if(end && max<3)
00094             goto unknown;
00095           
00096          if ((start[1]=='y' || start[1]=='Y')
00097                && (start[2]=='e' || start[2]=='E'))
00098          {
00099             *method = METHOD_BYE;
00100             len = 3;
00101             goto done;
00102          }
00103          goto unknown;
00104 
00105       case 'C':
00106       case 'c':
00107          if(end && max<6)
00108             goto unknown;
00109          if ((start[1]=='a' || start[1]=='A')
00110                && (start[2]=='n' || start[2]=='N')
00111                && (start[3]=='c' || start[3]=='C')
00112                && (start[4]=='e' || start[4]=='E')
00113                && (start[5]=='l' || start[5]=='L'))
00114          {
00115             *method = METHOD_CANCEL;
00116             len = 6;
00117             goto done;
00118          }
00119          goto unknown;
00120 
00121       case 'I':
00122       case 'i':
00123          if(end && max<4)
00124             goto unknown;
00125          if(start[1]=='n' && start[1]=='N')
00126             goto unknown;
00127          
00128          if ((start[2]=='f' || start[2]=='F')
00129                && (start[3]=='o' || start[3]=='O'))
00130          {
00131             *method = METHOD_INFO;
00132             len = 4;
00133             goto done;
00134          }
00135    
00136          if(end && max<6)
00137             goto unknown;
00138          if ((start[2]=='v' || start[2]=='V')
00139                && (start[3]=='i' || start[3]=='I')
00140                && (start[4]=='t' || start[4]=='T')
00141                && (start[5]=='e' || start[5]=='E'))
00142          {
00143             *method = METHOD_INVITE;
00144             len = 6;
00145             goto done;
00146          }
00147          goto unknown;
00148 
00149       case 'M':
00150       case 'm':
00151          if(end && max<7)
00152             goto unknown;
00153          if ((start[1]=='e' || start[1]=='E')
00154                && (start[2]=='s' || start[2]=='S')
00155                && (start[3]=='s' || start[3]=='S')
00156                && (start[4]=='a' || start[4]=='A')
00157                && (start[5]=='g' || start[5]=='G')
00158                && (start[6]=='e' || start[6]=='E')) {
00159             *method = METHOD_MESSAGE;
00160             len = 7;
00161             goto done;
00162          }
00163          goto unknown;
00164 
00165       case 'N':
00166       case 'n':
00167          if(end && max<6)
00168             goto unknown;
00169          if ((start[1]=='o' || start[1]=='O')
00170                && (start[2]=='t' || start[2]=='T')
00171                && (start[3]=='i' || start[3]=='I')
00172                && (start[4]=='f' || start[4]=='F')
00173                && (start[5]=='y' || start[5]=='Y'))
00174          {
00175             *method = METHOD_NOTIFY;
00176             len = 6;
00177             goto done;
00178          }
00179          goto unknown;
00180 
00181       case 'O':
00182       case 'o':
00183          if(end && max<7)
00184             goto unknown;
00185          if((start[1]=='p' || start[1]=='P')
00186                && (start[2]=='t' || start[2]=='T')
00187                && (start[3]=='i' || start[3]=='I')
00188                && (start[4]=='o' || start[4]=='O')
00189                && (start[5]=='n' || start[5]=='N')
00190                && (start[6]=='s' || start[6]=='S'))
00191          {
00192             *method = METHOD_OPTIONS;
00193             len = 7;
00194             goto done;
00195          }
00196          goto unknown;
00197 
00198       case 'P':
00199       case 'p':
00200          if(end && max<5)
00201             goto unknown;
00202          if((start[1]=='r' || start[1]=='R')
00203                && (start[2]=='a' || start[2]=='A')
00204                && (start[3]=='c' || start[3]=='C')
00205                && (start[4]=='k' || start[4]=='K'))
00206          {
00207             *method = METHOD_PRACK;
00208             len = 5;
00209             goto done;
00210          }
00211          
00212          if(end && max<7)
00213             goto unknown;
00214          
00215          if ((start[1]=='u' || start[1]=='U')
00216                 && (start[2]=='b' || start[2]=='B')
00217                 && (start[3]=='l' || start[3]=='L')
00218                 && (start[4]=='i' || start[4]=='I')
00219                 && (start[5]=='s' || start[5]=='S')
00220                 && (start[6]=='h' || start[6]=='H'))
00221          {
00222             *method = METHOD_PUBLISH;
00223             len = 7;
00224             goto done;
00225          }
00226          goto unknown;
00227 
00228       case 'R':
00229       case 'r':
00230          if(end && max<5)
00231             goto unknown;
00232          if(start[1]!='e' && start[1]!='E')
00233             goto unknown;
00234          
00235          if((start[2]=='f' || start[2]=='F')
00236                 && (start[3]=='e' || start[3]=='E')
00237                 && (start[4]=='R' || start[4]=='R'))
00238          {
00239             *method = METHOD_REFER;
00240             len = 5;
00241             goto done;
00242          }
00243 
00244          if(end && max<8)
00245             goto unknown;
00246          
00247          if ((start[2]=='g' || start[2]=='G')
00248                 && (start[3]=='i' || start[3]=='I')
00249                 && (start[4]=='s' || start[4]=='S')
00250                 && (start[5]=='t' || start[5]=='T')
00251                 && (start[6]=='e' || start[6]=='E')
00252                 && (start[7]=='r' || start[7]=='R'))
00253          {
00254             *method = METHOD_REGISTER;
00255             len = 8;
00256             goto done;
00257          }
00258          goto unknown;
00259 
00260       case 'S':
00261       case 's':
00262          if(end && max<9)
00263             goto unknown;
00264          if ((start[1]=='u' || start[1]=='U')
00265                 && (start[2]=='b' || start[2]=='B')
00266                 && (start[3]=='s' || start[3]=='S')
00267                 && (start[4]=='c' || start[4]=='C')
00268                 && (start[5]=='r' || start[5]=='R')
00269                 && (start[6]=='i' || start[6]=='I')
00270                 && (start[7]=='b' || start[7]=='B')
00271                 && (start[8]=='e' || start[8]=='E'))
00272          {
00273             *method = METHOD_SUBSCRIBE;
00274             len = 9;
00275             goto done;
00276          }
00277          goto unknown;
00278 
00279       case 'U':
00280       case 'u':
00281          if(end && max<6)
00282             goto unknown;
00283          if ((start[1]=='p' || start[1]=='P')
00284                && (start[2]=='d' || start[2]=='D')
00285                && (start[3]=='a' || start[3]=='A')
00286                && (start[4]=='t' || start[4]=='T')
00287                && (start[5]=='e' || start[5]=='E')) {
00288             *method = METHOD_UPDATE;
00289             len = 6;
00290             goto done;
00291          }
00292          goto unknown;
00293 
00294       default:
00295          goto unknown;
00296       }
00297  
00298 done:
00299    if(!end || (end && len < max))
00300    {
00301       if(start[len]!='\0' && start[len]!=',' && start[len]!=' '
00302             && start[len]!='\t' && start[len]!='\r' && start[len]!='\n')
00303          goto unknown;
00304    }
00305    
00306    return (start+len);
00307 
00308 unknown:
00309    update_stat(unsupported_methods, 1);
00310    *method = METHOD_OTHER;
00311    if(end)
00312    {
00313       while(len < max)
00314       {
00315          if((start[len]=='\0' || start[len]==',' || start[len]==' '
00316                   || start[len]=='\t' || start[len]=='\r'
00317                   || start[len]=='\n'))
00318             return (start+len);
00319          
00320          if(!method_char(start[len]))
00321          {
00322             LM_ERR("invalid character %c\n", start[len]);
00323             return NULL;
00324          }
00325          
00326          len++;
00327       }
00328       return end;
00329    }
00330    
00331    while(start[len]!='\0' && start[len]!=',' && start[len]!=' '
00332          && start[len]!='\t' && start[len]!='\r' && start[len]!='\n')
00333    {
00334       if(!method_char(start[len]))
00335       {
00336          LM_ERR("invalid character %c!\n", start[len]);
00337          return NULL;
00338       }
00339       len++;
00340    }
00341 
00342    return (start+len);
00343 }
00344  
00345  
00346 /*!
00347  * Parse comma separated list of methods pointed by _body and assign their
00348  * enum bits to _methods.
00349  * \return 0 on success, -1 on failure
00350  */
00351 int parse_methods(str* _body, unsigned int* _methods)
00352 {
00353    str next;
00354    char *p;
00355    char *p0;
00356    unsigned int method;
00357 
00358    if (!_body || !_methods) {
00359       LM_ERR("invalid parameter value\n");
00360       return -1;
00361    }
00362 
00363    next.len = _body->len;
00364    next.s = _body->s;
00365 
00366    trim_leading(&next);
00367 
00368    *_methods = 0;
00369    if (next.len == 0) {
00370       goto done;
00371    }
00372 
00373    method = 0;
00374    p = next.s;
00375    
00376    while (p<next.s+next.len) {
00377       if((p0=parse_method(p, next.s+next.len, &method))!=NULL) {
00378          *_methods |= method;
00379          p = p0;
00380       } else {
00381          LM_ERR("invalid method [%.*s]\n", next.len, next.s);
00382          return -1;
00383       }
00384       
00385       while(p<next.s+next.len && (*p==' ' || *p=='\t'
00386                || *p=='\r' || *p=='\n'))
00387          p++;
00388       if(p>=next.s+next.len || *p == '\0')
00389          goto done;
00390       
00391       
00392       if (*p == ',')
00393       {
00394          p++;
00395          while(p<next.s+next.len && (*p==' ' || *p=='\t'
00396                || *p=='\r' || *p=='\n'))
00397             p++;
00398          if(p>=next.s+next.len)
00399             goto done;
00400       } else {
00401          LM_ERR("comma expected\n");
00402          return -1;
00403       }
00404    }
00405 
00406 done:
00407    LM_DBG("methods 0x%X\n", *_methods);
00408    return 0;
00409 }

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