mi_datagram_parser.c

Go to the documentation of this file.
00001 /*
00002  * $Id: mi_datagram.h 1133 2007-04-02 17:31:13Z ancuta_onofrei $
00003  *
00004  * Copyright (C) 2007 Voice Sistem SRL
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  * History:
00024  * ---------
00025  *  2007-06-25  first version (ancuta)
00026  */
00027 
00028 /*!
00029  * \file
00030  * \brief MI_DATAGRAM :: Command parser
00031  * \ingroup mi
00032  */
00033 
00034 
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <ctype.h>
00038 
00039 #include "../../str.h"
00040 #include "../../dprint.h"
00041 #include "../../mi/mi.h"
00042 #include "../../mem/mem.h"
00043 #include "../../mem/shm_mem.h"
00044 #include "datagram_fnc.h"
00045 #include "mi_datagram.h"
00046 #include "mi_datagram_parser.h"
00047 
00048 /*static unsigned int mi_parse_buffer_len = 0;
00049 
00050 int mi_datagram_parser_init( unsigned int size )
00051 {
00052    mi_parse_buffer_len = size;
00053 
00054    return 0;
00055 }*/
00056 
00057 
00058 
00059 /*! \brief Parse MI command
00060       example: mi_parse_node(datagram, &buf, &name, &value)
00061  * returns -1 = error
00062  *          0 = ok
00063  *          1 = end of input
00064  */
00065 static inline int mi_datagram_parse_node(datagram_stream * data, str *name, str *value)
00066 {
00067    char *p, *pmax;
00068    char *start, *start1;
00069    char *mark_nsp;
00070    int newline_found = 0;
00071 
00072    LM_DBG("the remaining datagram to be parsed is %s and %i in length \n",
00073          data->current,data->len);
00074 
00075    p =data->current;
00076    start1 = start = p;
00077    if(data->len > DATAGRAM_SOCK_BUF_SIZE) {
00078       LM_ERR("overflow while parsing the received datagram\n");
00079       goto parse_err;
00080    }
00081    pmax  = start + data->len ;
00082 
00083    /* remove leading spaces */
00084    for( ; start<pmax && isspace((int)*start) ; start++ );
00085    /*no valuable data---end of input*/
00086    if(start == pmax)
00087       return 1;
00088 
00089    /* init */
00090    name->s = value->s = 0;
00091    name->len = value->len = 0;
00092 
00093    mark_nsp = 0;
00094 
00095    /* start parsing */
00096    if (*start!='"') {
00097       LM_DBG("the string is not just a quoted string\n");
00098       /* look for the atribute name */
00099 
00100       p = mark_nsp = start;
00101       while ( p!=pmax && (( *p!=MI_ATTR_VAL_SEP1) || p+1==pmax ||*(p+1)!=MI_ATTR_VAL_SEP2) ) {
00102          if (!isspace((int)*p)) {
00103             if (*p=='"') {
00104                LM_DBG("found \" before attr_separator\n");
00105                goto parse_err;
00106             }
00107             mark_nsp = p;
00108          }
00109          if(*p=='\n' && p!=(pmax -1)) {
00110             LM_DBG("found newline before attr_separator--we have just the "
00111                "attribute's value\n");
00112             mark_nsp++;
00113             pmax = ++p;
00114             break;
00115          }else if (p == (pmax-1)){
00116             mark_nsp++;
00117             pmax = ++p;
00118             LM_DBG("just a value, no new line");
00119             break;
00120          }
00121          p++;
00122       }
00123 
00124       if (p!=pmax) {
00125          /* we have found the separator */
00126          LM_DBG("we've found the attr_separator\n");
00127          if (p==start) {
00128             /* empty attr name */
00129             LM_DBG("empty attr_name\n");
00130          } else {
00131             name->s = start;
00132             name->len = mark_nsp - start+1;
00133             LM_DBG("attr name <%.*s> found\n",name->len, name->s);
00134          }
00135 
00136          p += 2; /* for separator */
00137             
00138          /* consume the trailing spaces */
00139          for( ; p!=pmax && isspace((int)*p) ; p++) {
00140             if(*p=='\n') {
00141                LM_DBG("empty value\n");
00142                /* empty value.....we are done */
00143                goto done;
00144             }
00145          }
00146          /*LM_DBG("p is %s case2\n",p);*/
00147 
00148          if(p==pmax && *p=='\n') {
00149             LM_DBG("empty value\n");
00150                /* empty value.....we are done */
00151             goto done;
00152          }
00153          /*LM_DBG("p is %s case1\n",p);*/
00154          /* value (only if not quoted ) */
00155          if (*p!='"') {
00156             LM_DBG("not quoted value, p is %c \n", *p);
00157             for( start=p ; p!=pmax ; p++ ) {
00158                if (!isspace((int)*p)) {
00159                   if (*p=='"') {
00160                      goto parse_err;
00161                   }
00162                   mark_nsp = p;
00163                   LM_DBG("nsp is %p ,p is %p, pmax is %p and *p is %c\n",
00164                      mark_nsp, p, pmax,*p);
00165                }
00166                if(*p=='\n') { /*end of the node*/
00167                   pmax = p;
00168                   break;
00169                }
00170             }
00171          
00172             value->s = start;
00173             value->len = mark_nsp - start+1;
00174             LM_DBG("*start is %c and start is %p\n",*start, start);
00175             LM_DBG("attr value <%s> found\n"/*,value->len*/, value->s);
00176             goto done;
00177          }
00178          /* quoted value....continue */
00179       } else {
00180          /* we have an empty name ... and we read a non-quoted value */
00181          value->s = start;
00182          value->len = mark_nsp  - start;
00183          LM_DBG("empty name, attr not quoted value <%.*s> found\n",
00184                value->len, value->s);
00185          goto done;
00186       }
00187    } else {
00188       p = start; /*send the value only: as a quoted string*/
00189    }
00190    /*we have a quoted value*/
00191    LM_DBG("we have a  quoted value, %s\n", p);
00192    start = p+1; /*skip the first "*/
00193    value->s = start;
00194 
00195    p = start;
00196    /* parse the buffer and look for " */
00197    while (p<pmax) {
00198       if (*p=='"' && start!=p) { /*search the closing "*/
00199 
00200          LM_DBG("\" found p is %s\n",p);
00201 
00202          if (start+1!=p && *(p-1)=='\\') {
00203             LM_DBG("skipping %c",*p);
00204             /* skip current char */
00205             memmove( p-1, p, pmax-p);
00206             pmax--; 
00207          } else {
00208             LM_DBG("we have reached the end of attr value, p is %s\n", p);
00209             /* end of value */
00210             value->len = p - value->s;
00211             LM_DBG("attr value <%.*s> found\n",value->len, value->s);
00212             
00213             /* is the line ending propely (only spaces) ? */
00214             p++;
00215             for(; p!=pmax && isspace((int)*p) ; p++)
00216             {
00217                if(*p=='\n') {
00218                   /*case : ""quoted string"  \n on a line */
00219                   LM_DBG("line ended properly case1\n");
00220                   pmax = p;
00221                   break;
00222                }
00223             }
00224             if (p!=pmax )/*didn't find the second " on the current line*/
00225             {
00226                LM_ERR("didn't find newline case1 \n");
00227                goto parse_err;
00228             }
00229             newline_found = 1;
00230             /* found! */
00231             goto done;
00232          }
00233       } else {
00234          p++;
00235       }
00236    }
00237 
00238    if(p== pmax && !newline_found) {
00239       LM_ERR("didn't find newline case2\n");
00240       goto parse_err;
00241    }
00242 
00243 done:
00244    /*set the current datagram's offset */
00245    LM_DBG("1 data->len is %i\n",data->len);
00246    data->len -= p-start1;
00247    LM_DBG("2 data->len is %i\n",data->len);
00248    data->current = p;
00249    return 0;
00250 parse_err:
00251    LM_ERR("parse error around %c\n",*p);
00252    return -1;
00253 }
00254 
00255 
00256 
00257 /*! \brief parsing the datagram buffer*/
00258 struct mi_root * mi_datagram_parse_tree(datagram_stream * datagram) {
00259    struct mi_root *root;
00260    struct mi_node *node;
00261    str name;
00262    str value;
00263    int ret;
00264 
00265    root = init_mi_tree(0,0,0);
00266    if (!root) {
00267       LM_ERR("the MI tree cannot be initialized!\n");
00268       goto error;
00269    }
00270    if(!datagram || datagram->current[0] == '\0')
00271    {
00272       LM_DBG("no data in the datagram\n");
00273       return root;
00274    }
00275 
00276    node = &root->node;
00277 
00278    name.s = value.s = 0;
00279    name.len = value.len = 0;
00280 
00281    /* every tree for a command ends with a \n that is alone on its line */
00282    while ((ret=mi_datagram_parse_node(datagram, &name, &value))>=0 ) {
00283       
00284       if(ret == 1)
00285          return root;
00286       LM_DBG("adding node <%.*s> ; val <%.*s>\n",
00287             name.len,name.s, value.len,value.s);
00288 
00289       if(!add_mi_node_child(node,0,name.s,name.len,value.s,value.len)){
00290          LM_ERR("cannot add the child node to the tree\n");
00291          goto error;
00292       }
00293       LM_DBG("the remaining datagram has %i bytes\n",datagram->len);
00294       /*end condition*/
00295       if(datagram->len == 0) {
00296          LM_DBG("found end of input\n");
00297          return root;
00298       }
00299    }
00300 
00301    LM_ERR("parse error!\n");
00302 error:
00303    if (root)
00304       free_mi_tree(root);
00305    return 0;
00306 }
00307 
00308 

Generated on Wed May 23 20:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6