parse_sst.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  * 
00004  * Copyright (c) 2006 SOMA Networks, Inc. <http://www.somanetworks.com/>
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  * 2006-02-17 Initial revision (dhsueh@somanetworks.com)
00025  */
00026 
00033 #include "parse_sst.h"
00034 
00035 #include "../../error.h"
00036 #include "../../dprint.h"
00037 #include "../../mem/mem.h"
00038 
00039 
00040 inline int/*bool*/  is_space( char c ) { return (c == ' ' || c == '\t'); }
00041 inline int/*bool*/  is_num( char c ) { return (c >= '0' && c <= '9'); }
00042 
00043 inline unsigned  lower_byte( char b ) { return b | 0x20; }
00044 inline unsigned  lower_4bytes( unsigned d ) { return d | 0x20202020; }
00045 inline unsigned  lower_3bytes( unsigned d ) { return d |   0x202020; }
00046 inline unsigned  read_4bytes( char *val ) {
00047         return (*(val + 0) + (*(val + 1) << 8)
00048                 + (*(val + 2) << 16) + (*(val + 3) << 24));
00049 }
00050 inline unsigned  read_3bytes( char *val ) {
00051         return (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16));
00052 }
00053 
00054 /* compile-time constants if called with constants */
00055 #define  MAKE_4BYTES( a, b, c, d ) \
00056         ( ((a)&0xFF) | (((b)&0xFF)<<8) | (((c)&0xFF)<<16) | (((d)&0xFF)<<24) )
00057 #define  MAKE_3BYTES( a, b, c ) \
00058         ( ((a)&0xFF) | (((b)&0xFF)<<8) | (((c)&0xFF)<<16) )
00059 
00060 
00061 struct session_expires *
00062 malloc_session_expires( void )
00063 {
00064         struct session_expires *se = (struct session_expires *)
00065                 pkg_malloc( sizeof(struct session_expires) );
00066         if ( se )
00067                 memset( se, 0, sizeof(struct session_expires) );
00068         return se;
00069 }
00070 
00074 void hf_free_session_expires(void *parsed)
00075 {
00076         struct session_expires *se;
00077         se = (struct session_expires*)parsed;
00078         free_session_expires(se);
00079 }
00080 
00081 
00082 void
00083 free_session_expires( struct session_expires *se )
00084 {
00085         if ( se )
00086                 pkg_free( se );
00087 }
00088 
00089 
00090 enum parse_sst_result
00091 parse_session_expires_body( struct hdr_field *hf )
00092 {
00093         register char *p = hf->body.s;
00094         int pos = 0;
00095         int len = hf->body.len;
00096         char *q;
00097         struct session_expires se = { 0, 0, sst_refresher_unspecified };
00098         unsigned tok;
00099 
00100         if ( !p || len <= 0 ) {
00101                 LM_ERR(" no body for header field\n" );
00102                 return parse_sst_header_not_found;
00103         }
00104 
00105         /* skip whitespace */
00106         for ( ; pos < len && is_space(*p); ++pos, ++p )
00107                 /*nothing*/;
00108 
00109         /* collect a number */
00110         for ( q = p; pos < len && is_num(*q); ++pos, ++q )
00111                 se.interval = se.interval*10/*radix*/ + (*q - '0');
00112 
00113         if ( q == p ) /*nothing parsed */ {
00114                 LM_ERR(" no expiry interval\n" );
00115                 return parse_sst_no_value;
00116         }
00117         p = q;
00118 
00119         /* continue on with params */
00120         while ( pos < len ) {
00121 
00122                 if ( *p == ';' ) {
00123                         ++p; ++pos;
00124 
00125                         if ( pos + 4 < len ) {
00126                                 switch ( lower_4bytes(read_4bytes(p)) ) {
00127                                         case /*refr*/MAKE_4BYTES('r','e','f','r'):
00128                                                 if ( pos + 9 <= len
00129                                                          && lower_4bytes(read_4bytes(p+4))
00130                                                                 == /*eshe*/MAKE_4BYTES('e','s','h','e')
00131                                                          && lower_byte(*(p+8)) == 'r'
00132                                                          && *(p+9) == '=' ) {
00133                                                         tok = lower_3bytes( read_3bytes(p+10) );
00134                                                         if ( tok == MAKE_3BYTES('u','a','c') ) {
00135                                                                 se.refresher = sst_refresher_uac;
00136                                                                 p += 13; pos += 13;
00137                                                         }
00138                                                         else if ( tok == MAKE_3BYTES('u','a','s') ) {
00139                                                                 se.refresher = sst_refresher_uas;
00140                                                                 p += 13; pos += 13;
00141                                                         }
00142                                                         else /* unrecognized refresher-param */ {
00143                                                                 LM_ERR(" unrecognized refresher\n" );
00144                                                                 return parse_sst_parse_error;
00145                                                         }
00146                                                 }
00147                                                 else /* not "esher=" */ {
00148                                                         /* there are no other se-params 
00149                                                            that start with "refr" */
00150                                                         for ( ; pos < len && *p != ';'; ++pos, ++p )
00151                                                                 /*skip to ';'*/;
00152                                                 }
00153                                                 break;
00154                                         default:
00155                                                 /* unrecognized se-param */
00156                                                 for ( ; pos < len && *p != ';'; ++pos, ++p )
00157                                                         /*skip to ';'*/;
00158                                                 break;
00159                                 } /*switch*/
00160                         } /* exist 4 bytes to check */
00161                         else /* less than 4 bytes left */ {
00162                                 /* not enough text left for any of the recognized se-params */
00163                                 /* no other recognized se-param */
00164                                 for ( ; pos < len && *p != ';'; ++pos, ++p ) /*skip to ';'*/;
00165                         }
00166                 }
00167                 else /* not ';' */ {
00168                         LM_ERR("no semicolon separating se-params\n");
00169                         return parse_sst_parse_error;
00170                 } /* if ';' */
00171         } /* while */
00172 
00173         hf->parsed = malloc_session_expires();
00174         if ( !hf->parsed ) {
00175                 LM_ERR(" out of pkg memory\n" );
00176                 return parse_sst_out_of_mem;
00177         }
00178         se.hfree = hf_free_session_expires;
00179         *((struct session_expires *)hf->parsed) = se;
00180 
00181         return parse_sst_success;
00182 }
00183 
00184 
00185 enum parse_sst_result
00186 parse_session_expires( struct sip_msg *msg, struct session_expires *se )
00187 {
00188         enum parse_sst_result result;
00189 
00190         if ( msg->session_expires ) {
00191                 if ( msg->session_expires->parsed == 0
00192                          && (result = parse_session_expires_body(msg->session_expires))
00193                                 != parse_sst_success ) {
00194                         return result;
00195                 }
00196                 if ( se ) {
00197                         *se = *((struct session_expires *)msg->session_expires->parsed);
00198                 }
00199                 return parse_sst_success;
00200         }
00201         else {
00202                 return parse_sst_header_not_found;
00203         }
00204 }
00205 
00206 
00207 enum parse_sst_result
00208 parse_min_se_body( struct hdr_field *hf )
00209 {
00210         int len = hf->body.len;
00211         char *p = hf->body.s;
00212         int pos = 0;
00213         unsigned int interval = 0;
00214 
00215         /* skip whitespace */
00216         for ( ; pos < len && is_space(*p); ++pos, ++p )
00217                 /*nothing*/;
00218         if ( pos == len )
00219                 return parse_sst_no_value;
00220         /* collect a number */
00221         for ( ; pos < len && is_num(*p); ++pos, ++p )
00222                 interval = interval*10/*radix*/ + (*p - '0');
00223         /* skip whitespace */
00224         for ( ; pos < len && is_space(*p); ++pos, ++p )
00225                 /*nothing*/;
00226         if ( pos != len ) /* shouldn't be any more junk */
00227                 return parse_sst_parse_error;
00228         hf->parsed=(void*)(long)interval;
00229         return parse_sst_success;
00230 }
00231 
00232 
00233 enum parse_sst_result
00234 parse_min_se( struct sip_msg *msg, unsigned int *min_se )
00235 {
00236         enum parse_sst_result result;
00237 
00238         if ( msg->min_se ) {
00239                 if ( msg->min_se->parsed == 0
00240                          && (result = parse_min_se_body(msg->min_se))
00241                                 != parse_sst_success ) {
00242                         return result;
00243                 }
00244                 if ( min_se ) {
00245                         *min_se = (unsigned int)(long)msg->min_se->parsed;
00246                 }
00247                 return parse_sst_success;
00248         }
00249         else {
00250                 return parse_sst_header_not_found;
00251         }
00252 }