parse_methods.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (c) 2004 Juha Heinanen
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser 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  * ser 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 
00029 #include <strings.h>
00030 #include "../dprint.h"
00031 #include "../trim.h"
00032 #include "parse_methods.h"
00033 
00034 
00038 static int token_char(char _c)
00039 {
00040         return  (_c >= 65 && _c <= 90) ||        /* upper alpha */
00041                 (_c >= 97 && _c <= 122) ||       /* lower aplha */
00042                 (_c >= 48 && _c <= 57) ||        /* digits */
00043                 (_c == '-') || (_c == '.') || (_c == '!') || (_c == '%') ||
00044                 (_c == '*') || (_c == '_') || (_c == '+') || (_c == '`') ||
00045                 (_c == '\'') || (_c == '~') || (_c == '+') || (_c == '`');
00046  }
00047 
00048 
00049 
00056 int parse_method_name(str* s, enum request_method* method)
00057  {
00058         if (unlikely(!s || !method)) {
00059                 LOG(L_ERR, "Invalid parameter value\n");
00060                 return -1;
00061         }
00062         
00063         if (unlikely(!s->len || (s->s==0))) {
00064                 DBG("No input\n");
00065                 *method = METHOD_OTHER;
00066                 return 0;
00067         }
00068         
00069         switch ((s->s)[0]) {
00070                 /* ordered after probability of aparition on a normal proxy */
00071                 case 'R':
00072                 case 'r':
00073                         if (likely((s->len == 8) &&
00074                                         !strncasecmp(s->s + 1, "egister", 7))) {
00075                                 *method = METHOD_REGISTER;
00076                                 return 0;
00077                         }
00078                         if (likely((s->len==5) && !strncasecmp(s->s + 1, "efer", 4))) {
00079                                 *method = METHOD_REFER;
00080                                 return 0;
00081                         }
00082                         break;
00083                 case 'A':
00084                 case 'a':
00085                         if (likely((s->len==3) && !strncasecmp(s->s + 1, "ck", 2))) {
00086                                 *method = METHOD_ACK;
00087                                 return 0;
00088                         }
00089                         break;
00090                 case 'I':
00091                 case 'i':
00092                         if (likely((s->len==6) && !strncasecmp(s->s + 1, "nvite", 5))){
00093                                 *method = METHOD_INVITE;
00094                                 return 0;
00095                         }
00096                         if (likely((s->len==4) && !strncasecmp(s->s + 1, "nfo", 3))) {
00097                                 *method = METHOD_INFO;
00098                                 return 0;
00099                         }
00100                         break;
00101                 case 'P':
00102                 case 'p':
00103                         if (likely((s->len==5) && !strncasecmp(s->s + 1, "rack", 4))) {
00104                                 *method = METHOD_PRACK;
00105                                 return 0;
00106                         }
00107                         if (likely((s->len==7) && !strncasecmp(s->s + 1, "ublish", 6))) {
00108                                 *method = METHOD_PUBLISH;
00109                                 return 0;
00110                         }
00111                         break;
00112                 case 'C':
00113                 case 'c':
00114                         if (likely((s->len==6) && !strncasecmp(s->s + 1, "ancel", 5))) {
00115                                 *method = METHOD_CANCEL;
00116                                 return 0;
00117                         }
00118                         break;
00119                 case 'B':
00120                 case 'b':
00121                         if (likely((s->len==3) && !strncasecmp(s->s + 1, "ye", 2))) {
00122                                 *method = METHOD_BYE;
00123                                 return 0;
00124                         }
00125                         break;
00126                 case 'M':
00127                 case 'm':
00128                         if (likely((s->len==7) && !strncasecmp(s->s + 1, "essage", 6))) {
00129                                 *method = METHOD_MESSAGE;
00130                                 return 0;
00131                         }
00132                         break;
00133                 case 'O':
00134                 case 'o':
00135                         if (likely((s->len==7) && !strncasecmp(s->s + 1, "ptions", 6))) {
00136                                 *method = METHOD_OPTIONS;
00137                                 return 0;
00138                         }
00139                         break;
00140                 case 'S':
00141                 case 's':
00142                         if (likely((s->len==9) && !strncasecmp(s->s + 1, "ubscribe", 8))) {
00143                                 *method = METHOD_SUBSCRIBE;
00144                                 return 0;
00145                         }
00146                         break;
00147                 case 'N':
00148                 case 'n':
00149                         if (likely((s->len==6) && !strncasecmp(s->s + 1, "otify", 5))){
00150                                 *method = METHOD_NOTIFY;
00151                                 return 0;
00152                         }
00153                         break;
00154                 case 'U':
00155                 case 'u':
00156                         if (likely((s->len==6) && !strncasecmp(s->s + 1, "pdate", 5))){
00157                                 *method = METHOD_UPDATE;
00158                                 return 0;
00159                         }
00160                         break;
00161                 default:
00162                         break;
00163         }
00164         /* unknown method */
00165         *method = METHOD_OTHER;
00166         return 0;
00167 }
00168 
00169 
00170 
00175 static int parse_method_advance(str* _next, enum request_method* _method)
00176  {
00177         char* end;
00178         
00179          if (unlikely(!_next || !_method)) {
00180                  LOG(L_ERR, "Invalid parameter value\n");
00181                  return 0;
00182          }
00183          
00184          if (unlikely(!_next->len || !_next->s)) {
00185                  DBG("No input\n");
00186                 *_method = METHOD_OTHER;
00187                  return 1;
00188          }
00189         end=_next->s+_next->len;
00190         
00191          switch ((_next->s)[0]) {
00192          case 'A':
00193          case 'a':
00194                  if ((_next->len > 2) && !strncasecmp(_next->s + 1, "ck", 2)) {
00195                         *_method = METHOD_ACK;
00196                         _next->len -= 3;
00197                         _next->s += 3;
00198                         goto found;
00199                 } else {
00200                         goto unknown;
00201                 }
00202 
00203         case 'B':
00204         case 'b':
00205                 if ((_next->len > 2) && !strncasecmp(_next->s + 1, "ye", 2)) {
00206                         *_method = METHOD_BYE;
00207                         _next->len -= 3;
00208                         _next->s += 3;
00209                         goto found;
00210                 } else {
00211                         goto unknown;
00212                 }
00213 
00214         case 'C':
00215         case 'c':
00216                 if ((_next->len > 5) && !strncasecmp(_next->s + 1, "ancel", 5)) {
00217                         *_method = METHOD_CANCEL;
00218                         _next->len -= 6;
00219                         _next->s += 6;
00220                         goto found;
00221                 } else {
00222                         goto unknown;
00223                 }
00224 
00225         case 'I':
00226         case 'i':
00227                 if ((_next->len > 3) &&
00228                     ((*(_next->s + 1) == 'N') || (*(_next->s + 1) == 'n'))) {
00229                         if (!strncasecmp(_next->s + 2, "fo", 2)) {
00230                                 *_method = METHOD_INFO;
00231                                 _next->len -= 4;
00232                                 _next->s += 4;
00233                                 goto found;
00234                         }
00235 
00236                         if ((_next->len > 5) && !strncasecmp(_next->s + 2, "vite", 4)) {
00237                                 *_method = METHOD_INVITE;
00238                                 _next->len -= 6;
00239                                 _next->s += 6;
00240                                 goto found;
00241                         }
00242                 }
00243                 goto unknown;
00244 
00245         case 'M':
00246         case 'm':
00247                 if ((_next->len > 6) && !strncasecmp(_next->s + 1, "essage", 6)) {
00248                         *_method = METHOD_MESSAGE;
00249                         _next->len -= 7;
00250                         _next->s += 7;
00251                         goto found;
00252                 } else {
00253                         goto unknown;
00254                 }
00255 
00256         case 'N':
00257         case 'n':
00258                 if ((_next->len > 5) && !strncasecmp(_next->s + 1, "otify", 5)) {
00259                         *_method = METHOD_NOTIFY;
00260                         _next->len -= 6;
00261                         _next->s += 6;
00262                         goto found;
00263                 } else {
00264                         goto unknown;
00265                 }
00266 
00267         case 'O':
00268         case 'o':
00269                 if ((_next->len > 6) && !strncasecmp(_next->s + 1, "ptions", 6)) {
00270                         *_method = METHOD_OPTIONS;
00271                         _next->len -= 7;
00272                         _next->s += 7;
00273                         goto found;
00274                 } else {
00275                         goto unknown;
00276                 }
00277 
00278         case 'P':
00279         case 'p':
00280                 if ((_next->len > 4) && !strncasecmp(_next->s + 1, "rack", 4)) {
00281                         *_method = METHOD_PRACK;
00282                         _next->len -= 5;
00283                         _next->s += 5;
00284                         goto found;
00285                 }
00286                 if ((_next->len > 6) && !strncasecmp(_next->s + 1, "ublish", 6)) {
00287                         *_method = METHOD_PUBLISH;
00288                         _next->len -= 7;
00289                         _next->s += 7;
00290                         goto found;
00291                 }
00292                 goto unknown;
00293 
00294         case 'R':
00295         case 'r':
00296                 if ((_next->len > 4) &&
00297                     ((*(_next->s + 1) == 'E') || (*(_next->s + 1) == 'e'))) {
00298                         if (!strncasecmp(_next->s + 2, "fer", 3)) {
00299                                 *_method = METHOD_REFER;
00300                                 _next->len -= 5;
00301                                 _next->s += 5;
00302                                 goto found;
00303                         }
00304 
00305                         if ((_next->len > 7) && !strncasecmp(_next->s + 2, "gister", 6)) {
00306                                 *_method = METHOD_REGISTER;
00307                                 _next->len -= 8;
00308                                 _next->s += 8;
00309                                 goto found;
00310                         }
00311                 }
00312                 goto unknown;
00313 
00314         case 'S':
00315         case 's':
00316                 if ((_next->len > 8) && !strncasecmp(_next->s + 1, "ubscribe", 8)) {
00317                         *_method = METHOD_SUBSCRIBE;
00318                         _next->len -= 9;
00319                         _next->s += 9;
00320                         goto found;
00321                 } else {
00322                         goto unknown;
00323                 }
00324 
00325         case 'U':
00326         case 'u':
00327                 if ((_next->len > 5) && !strncasecmp(_next->s + 1, "pdate", 5)) {
00328                         *_method = METHOD_UPDATE;
00329                         _next->len -= 6;
00330                         _next->s += 6;
00331                         goto found;
00332                 } else {
00333                         goto unknown;
00334                 }
00335 
00336         default:
00337                 goto unknown;
00338         }
00339 
00340  unknown:
00341         if (token_char(*(_next->s))) {
00342                 do { 
00343                         _next->s++;
00344                         _next->len--;
00345                 } while (_next->len && token_char(*(_next->s)));
00346                 *_method = METHOD_OTHER;
00347                 return 1;
00348         } else {
00349                 return 0;
00350         }
00351 found:
00352         /* check if the method really ends here (if not return 0) */
00353         return (_next->s>=end) || (!token_char(*(_next->s)));
00354  }
00355  
00356  
00361  int parse_methods(str* _body, unsigned int* _methods)
00362  {
00363         str next;
00364         unsigned int method;
00365         
00366         method=0; /* fixes silly gcc 4.x warning */
00367  
00368         if (!_body || !_methods) {
00369                 LOG(L_ERR, "parse_methods: Invalid parameter value\n");
00370                 return -1;
00371         }
00372 
00373         next.len = _body->len;
00374         next.s = _body->s;
00375  
00376         trim_leading(&next);
00377  
00378         *_methods = 0;
00379  
00380         if (next.len == 0) {
00381                 return 0;
00382         }
00383 
00384         while (1) {
00385                 if (parse_method_advance(&next, &method)) {
00386                         *_methods |= method;
00387                 } else {
00388                         LOG(L_ERR, "ERROR: parse_methods: Invalid method\n");
00389                         return -1;
00390                 }
00391                 
00392                 trim_leading(&next);
00393                 if (next.len) {
00394                         if (next.s[0] == ',') {
00395                                 next.len--;
00396                                 next.s++;
00397                                 trim_leading(&next);
00398                                 if (next.len == 0) {
00399                                         LOG(L_ERR, "ERROR: parse_methods: Method expected\n");
00400                                         return 0;
00401                                 }
00402                         } else {
00403                                 LOG(L_ERR, "ERROR: parse_methods: Comma expected\n");
00404                                 return -1;
00405                         }
00406                 } else {
00407                         break;
00408                 }
00409         }
00410 
00411         return 0;
00412  }