reSIProcate/repro  9694
RouteStore.cxx
Go to the documentation of this file.
00001 
00002 #include "rutil/Logger.hxx"
00003 #include "rutil/ParseBuffer.hxx"
00004 #include "rutil/Lock.hxx"
00005 #include "resip/stack/Uri.hxx"
00006 
00007 #include "repro/RouteStore.hxx"
00008 #include "rutil/WinLeakCheck.hxx"
00009 
00010 
00011 using namespace resip;
00012 using namespace repro;
00013 using namespace std;
00014 
00015 
00016 #define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
00017 
00018 bool RouteStore::RouteOp::operator<(const RouteOp& rhs) const
00019 {
00020    return routeRecord.mOrder < rhs.routeRecord.mOrder;
00021 }
00022 
00023 
00024 RouteStore::RouteStore(AbstractDb& db):
00025    mDb(db)
00026 {  
00027    Key key = mDb.firstRouteKey();
00028    while ( !key.empty() )
00029    {
00030       RouteOp route;
00031       route.routeRecord =  mDb.getRoute(key);
00032       route.key = key;
00033       route.preq = 0;
00034       
00035       if(!route.routeRecord.mMatchingPattern.empty())
00036       {
00037          int flags = REG_EXTENDED;
00038          if(route.routeRecord.mRewriteExpression.find("$") == Data::npos)
00039          {
00040             flags |= REG_NOSUB;
00041          }
00042          route.preq = new regex_t;
00043          int ret = regcomp(route.preq, route.routeRecord.mMatchingPattern.c_str(), flags);
00044          if(ret != 0)
00045          {
00046             delete route.preq;
00047             ErrLog(<< "Routing rule has invalid match expression: "
00048                    << route.routeRecord.mMatchingPattern);
00049             route.preq = 0;
00050          }
00051       }
00052 
00053       mRouteOperators.insert( route );
00054 
00055       key = mDb.nextRouteKey();
00056    } 
00057    mCursor = mRouteOperators.begin();
00058 }
00059 
00060 
00061 RouteStore::~RouteStore()
00062 {
00063    for(RouteOpList::iterator i = mRouteOperators.begin(); i != mRouteOperators.end(); i++)
00064    {
00065       if ( i->preq )
00066       {
00067          regfree ( i->preq );
00068          delete i->preq;
00069 
00070          // !abr! Can't modify elements in a set
00071          // i->preq = 0;
00072 
00073       }
00074    }
00075    mRouteOperators.clear();
00076 }
00077 
00078       
00079 bool
00080 RouteStore::addRoute(const resip::Data& method,
00081                      const resip::Data& event,
00082                      const resip::Data& matchingPattern,
00083                      const resip::Data& rewriteExpression,
00084                      const int order )
00085 { 
00086    InfoLog( << "Add route" );
00087    
00088    RouteOp route;
00089 
00090    Key key = buildKey(method, event, matchingPattern);
00091    
00092    if(findKey(key)) return false;
00093 
00094    route.routeRecord.mMethod = method;
00095    route.routeRecord.mEvent = event;
00096    route.routeRecord.mMatchingPattern = matchingPattern;
00097    route.routeRecord.mRewriteExpression =  rewriteExpression;
00098    route.routeRecord.mOrder = order;
00099 
00100    if(!mDb.addRoute(key , route.routeRecord))
00101    {
00102       return false;
00103    }
00104 
00105    route.key = key;
00106    route.preq = 0;
00107    if( !route.routeRecord.mMatchingPattern.empty() )
00108    {
00109      int flags = REG_EXTENDED;
00110      if( route.routeRecord.mRewriteExpression.find("$") == Data::npos )
00111      {
00112        flags |= REG_NOSUB;
00113      }
00114      route.preq = new regex_t;
00115      int ret = regcomp( route.preq, route.routeRecord.mMatchingPattern.c_str(), flags );
00116      if( ret != 0 )
00117      {
00118        delete route.preq;
00119        route.preq = 0;
00120      }
00121    }
00122 
00123    {
00124       WriteLock lock(mMutex);
00125       mRouteOperators.insert( route );
00126    }
00127    mCursor = mRouteOperators.begin(); 
00128 
00129    return true;
00130 }
00131 
00132       
00133 /*
00134 AbstractDb::RouteRecordList 
00135 RouteStore::getRoutes() const
00136 { 
00137    AbstractDb::RouteRecordList result;
00138    result.reserve(mRouteOperators.size());
00139    
00140    for (RouteOpList::const_iterator it = mRouteOperators.begin();
00141         it != mRouteOperators.end(); it++)
00142    {
00143       result.push_back(it->routeRecord);
00144    }
00145    return result;   
00146 }
00147 */
00148 
00149 
00150 void 
00151 RouteStore::eraseRoute(const resip::Data& method,
00152                        const resip::Data& event,
00153                        const resip::Data& matchingPattern)
00154 {
00155    Key key = buildKey(method, event, matchingPattern);
00156    eraseRoute(key);
00157 }
00158 
00159 
00160 void 
00161 RouteStore::eraseRoute(const resip::Data& key )
00162 {  
00163    mDb.eraseRoute(key);
00164 
00165    {
00166       WriteLock lock(mMutex);
00167 
00168       RouteOpList::iterator it = mRouteOperators.begin();
00169       while ( it != mRouteOperators.end() )
00170       {
00171          if (it->key == key )
00172          {
00173             RouteOpList::iterator i = it;
00174             it++;
00175             if ( i->preq )
00176             {
00177                regfree ( i->preq );
00178                delete i->preq;
00179 
00180                // !abr! Can't modify elements in a set
00181                //i->preq = 0;
00182 
00183             }
00184             mRouteOperators.erase(i);
00185          }
00186          else
00187          {
00188             it++;
00189          }
00190       }
00191    }
00192    mCursor = mRouteOperators.begin();  // reset the cursor since it may have been on deleted route
00193 }
00194 
00195 
00196 bool
00197 RouteStore::updateRoute( const resip::Data& originalKey, 
00198                          const resip::Data& method,
00199                          const resip::Data& event,
00200                          const resip::Data& matchingPattern,
00201                          const resip::Data& rewriteExpression,
00202                          const int order )
00203 {
00204    eraseRoute(originalKey);
00205    return addRoute(method, event, matchingPattern, rewriteExpression, order);
00206 }
00207 
00208 
00209 RouteStore::Key 
00210 RouteStore::getFirstKey()
00211 {
00212    ReadLock lock(mMutex);
00213 
00214    mCursor = mRouteOperators.begin();
00215    if ( mCursor == mRouteOperators.end() )
00216    {
00217       return Key( Data::Empty );
00218    }
00219    
00220    return mCursor->key;
00221 }
00222 
00223 bool 
00224 RouteStore::findKey(const Key& key)
00225 { 
00226    // check if cursor happens to be at the key
00227    if ( mCursor != mRouteOperators.end() )
00228    {
00229       if ( mCursor->key == key )
00230       {
00231          return true;
00232       }
00233    }
00234    
00235    // search for the key 
00236    mCursor = mRouteOperators.begin();
00237    while (  mCursor != mRouteOperators.end() )
00238    {
00239       if ( mCursor->key == key )
00240       {
00241          return true; // found the key 
00242       }
00243       mCursor++;
00244    }
00245    return false; // key was not found 
00246 }
00247 
00248 RouteStore::Key 
00249 RouteStore::getNextKey(Key& key)
00250 {  
00251    ReadLock lock(mMutex);
00252 
00253    if ( !findKey(key) )
00254    {
00255       return Key(Data::Empty);
00256    }
00257       
00258    mCursor++;
00259    
00260    if ( mCursor == mRouteOperators.end() )
00261    {
00262       return Key( Data::Empty );
00263    }
00264    
00265    return mCursor->key;
00266 }
00267 
00268 
00269 AbstractDb::RouteRecord 
00270 RouteStore::getRouteRecord(const resip::Data& key)
00271 {
00272    ReadLock lock(mMutex);
00273 
00274    if (!findKey(key))
00275    {
00276       return AbstractDb::RouteRecord();
00277    }
00278    return mCursor->routeRecord;
00279 }
00280 
00281 
00282 RouteStore::UriList 
00283 RouteStore::process(const resip::Uri& ruri, 
00284                     const resip::Data& method, 
00285                     const resip::Data& event )
00286 {
00287    RouteStore::UriList targetSet;
00288    if(mRouteOperators.empty()) return targetSet;  // If there are no routes bail early to save a few cycles (size check is atomic enough, we don't need a lock)
00289 
00290    ReadLock lock(mMutex);
00291 
00292    for (RouteOpList::iterator it = mRouteOperators.begin();
00293         it != mRouteOperators.end(); it++)
00294    {
00295       DebugLog( << "Consider route " // << *it
00296                 << " reqUri=" << ruri
00297                 << " method=" << method 
00298                 << " event=" << event );
00299 
00300       const AbstractDb::RouteRecord& rec = it->routeRecord;
00301       
00302       if(!rec.mMethod.empty())
00303       {
00304          if(!isEqualNoCase(rec.mMethod,method))
00305          {
00306             DebugLog( << "  Skipped - method did not match" );
00307             continue;
00308          }
00309          
00310       }
00311       if(!rec.mEvent.empty())
00312       {
00313          if(!isEqualNoCase(rec.mEvent, event))
00314          {
00315             DebugLog( << "  Skipped - event did not match" );
00316             continue;
00317          }
00318       }
00319       const Data& rewrite = rec.mRewriteExpression;
00320       const Data& match = rec.mMatchingPattern;
00321       if ( it->preq ) 
00322       {
00323          int ret;
00324          // TODO - !cj! www.pcre.org looks like it has better performance
00325          // !mbg! is this true now that the compiled regexp is used?
00326          Data uri;
00327          {
00328             DataStream s(uri);
00329             s << ruri;
00330             s.flush();
00331          }
00332          
00333          const int nmatch=10;
00334          regmatch_t pmatch[nmatch];
00335          
00336          ret = regexec(it->preq, uri.c_str(), nmatch, pmatch, 0/*eflags*/);
00337          if ( ret != 0 )
00338          {
00339             // did not match 
00340             DebugLog( << "  Skipped - request URI "<< uri << " did not match " << match );
00341             continue;
00342          }
00343 
00344          DebugLog( << "  Route matched" );
00345          Data target = rewrite;
00346          
00347          if ( rewrite.find("$") != Data::npos )
00348          {
00349             for ( int i=1; i<nmatch; i++)
00350             {
00351                if ( pmatch[i].rm_so != -1 )
00352                {
00353                   Data subExp(uri.substr(pmatch[i].rm_so,
00354                                          pmatch[i].rm_eo-pmatch[i].rm_so));
00355                   DebugLog( << "  subExpression[" <<i <<"]="<< subExp );
00356 
00357                   Data result;
00358                   {
00359                      DataStream s(result);
00360 
00361                      ParseBuffer pb(target);
00362                      
00363                      while (true)
00364                      {
00365                         const char* a = pb.position();
00366                         pb.skipToChars( Data("$") + char('0'+i) );
00367                         if ( pb.eof() )
00368                         {
00369                            s << pb.data(a);
00370                            break;
00371                         }
00372                         else
00373                         {
00374                            s << pb.data(a);
00375                            pb.skipN(2);
00376                            s <<  subExp;
00377                         }
00378                      }
00379                      s.flush();
00380                   }
00381                   target = result;
00382                }
00383             }
00384          }
00385          
00386          Uri targetUri;
00387          try
00388          {
00389             targetUri = Uri(target);
00390          }
00391          catch( BaseException& )
00392          {
00393             ErrLog( << "Routing rule transform " << rewrite << " gave invalid URI " << target );
00394             try
00395             {
00396                targetUri = Uri( Data("sip:")+target);
00397             }
00398             catch( BaseException& )
00399             {
00400                ErrLog( << "Routing rule transform " << rewrite << " gave invalid URI sip:" << target );
00401                continue;
00402             }
00403          }
00404          targetSet.push_back( targetUri );
00405       }
00406    }
00407 
00408    return targetSet;
00409 }
00410   
00411 
00412 RouteStore::Key 
00413 RouteStore::buildKey(const resip::Data& method,
00414                      const resip::Data& event,
00415                      const resip::Data& matchingPattern ) const
00416 {  
00417    // missing mOrder
00418    // Data pKey = Data(order) + ":" + method + ":" + event + ":" + matchingPattern;
00419    Data pKey = method+":"+event+":"+matchingPattern; 
00420    return pKey;
00421 }
00422 
00423 
00424 /* ====================================================================
00425  * The Vovida Software License, Version 1.0 
00426  * 
00427  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00428  * 
00429  * Redistribution and use in source and binary forms, with or without
00430  * modification, are permitted provided that the following conditions
00431  * are met:
00432  * 
00433  * 1. Redistributions of source code must retain the above copyright
00434  *    notice, this list of conditions and the following disclaimer.
00435  * 
00436  * 2. Redistributions in binary form must reproduce the above copyright
00437  *    notice, this list of conditions and the following disclaimer in
00438  *    the documentation and/or other materials provided with the
00439  *    distribution.
00440  * 
00441  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00442  *    and "Vovida Open Communication Application Library (VOCAL)" must
00443  *    not be used to endorse or promote products derived from this
00444  *    software without prior written permission. For written
00445  *    permission, please contact vocal@vovida.org.
00446  *
00447  * 4. Products derived from this software may not be called "VOCAL", nor
00448  *    may "VOCAL" appear in their name, without prior written
00449  *    permission of Vovida Networks, Inc.
00450  * 
00451  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00452  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00453  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00454  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00455  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00456  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00457  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00458  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00459  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00460  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00461  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00462  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00463  * DAMAGE.
00464  * 
00465  * ====================================================================
00466  */