reSIProcate/repro  9694
Public Member Functions | Static Public Member Functions | Static Public Attributes | Protected Member Functions | Private Member Functions | Private Attributes
repro::Proxy Class Reference

#include <Proxy.hxx>

Inheritance diagram for repro::Proxy:
Inheritance graph
[legend]
Collaboration diagram for repro::Proxy:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 Proxy (resip::SipStack &, ProxyConfig &config, ProcessorChain &requestP, ProcessorChain &responseP, ProcessorChain &targetP)
virtual ~Proxy ()
void setOptionsHandler (OptionsHandler *handler)
void setRequestContextFactory (std::auto_ptr< RequestContextFactory > requestContextFactory)
virtual bool isShutDown () const
virtual void thread ()
bool isMyUri (const resip::Uri &uri) const
const resip::NameAddrgetRecordRoute (const resip::Transport *transport) const
bool getRecordRouteForced () const
void setAssumePath (bool f)
bool getAssumePath () const
bool isPAssertedIdentityProcessingEnabled ()
UserStoregetUserStore ()
resip::SipStackgetStack ()
ProxyConfiggetConfig ()
void send (const resip::SipMessage &msg)
void addClientTransaction (const resip::Data &transactionId, RequestContext *rc)
void postTimerC (std::auto_ptr< TimerCMessage > tc)
void postMS (std::auto_ptr< resip::ApplicationMessage > msg, int msec)
bool compressionEnabled () const
void addSupportedOption (const resip::Data &option)
void removeSupportedOption (const resip::Data &option)
void setServerText (const resip::Data &text)
const resip::DatagetServerText () const
resip::KeyValueStoregetKeyValueStore ()

Static Public Member Functions

static
resip::KeyValueStore::KeyValueStoreKeyAllocator
getGlobalKeyValueStoreKeyAllocator ()
static
resip::KeyValueStore::KeyValueStoreKeyAllocator
getRequestKeyValueStoreKeyAllocator ()
static
resip::KeyValueStore::KeyValueStoreKeyAllocator
getTargetKeyValueStoreKeyAllocator ()
static resip::KeyValueStore::Key allocateGlobalKeyValueStoreKey ()
static resip::KeyValueStore::Key allocateRequestKeyValueStoreKey ()
static resip::KeyValueStore::Key allocateTargetKeyValueStoreKey ()

Static Public Attributes

static resip::Data FlowTokenSalt

Protected Member Functions

virtual const resip::Dataname () const

Private Member Functions

 Proxy ()

Private Attributes

resip::SipStackmStack
ProxyConfigmConfig
resip::NameAddr mRecordRoute
bool mRecordRouteForced
bool mAssumePath
bool mPAssertedIdentityProcessing
resip::Data mServerText
int mTimerC
resip::KeyValueStore mKeyValueStore
ProcessorChainmRequestProcessorChain
ProcessorChainmResponseProcessorChain
ProcessorChainmTargetProcessorChain
HashMap< resip::Data,
RequestContext * > 
mClientRequestContexts
 a map from transaction id to RequestContext.
HashMap< resip::Data,
RequestContext * > 
mServerRequestContexts
UserStoremUserStore
std::set< resip::DatamSupportedOptions
OptionsHandlermOptionsHandler
std::auto_ptr
< RequestContextFactory
mRequestContextFactory

Detailed Description

Definition at line 47 of file Proxy.hxx.


Constructor & Destructor Documentation

Proxy::Proxy ( resip::SipStack stack,
ProxyConfig config,
ProcessorChain requestP,
ProcessorChain responseP,
ProcessorChain targetP 
)

Definition at line 74 of file Proxy.cxx.

   : TransactionUser(TransactionUser::RegisterForTransactionTermination),
     mStack(stack), 
     mConfig(config),
     mRecordRoute(config.getConfigUri("RecordRouteUri", Uri())),
     mRecordRouteForced(config.getConfigBool("ForceRecordRouting", false)),
     mAssumePath(config.getConfigBool("AssumePath", false)),
     mPAssertedIdentityProcessing(config.getConfigBool("EnablePAssertedIdentityProcessing", false)),
     mServerText(config.getConfigData("ServerText", "")),
     mTimerC(config.getConfigInt("TimerC", 180)),
     mKeyValueStore(*Proxy::getGlobalKeyValueStoreKeyAllocator()),
     mRequestProcessorChain(requestP), 
     mResponseProcessorChain(responseP),
     mTargetProcessorChain(targetP),
     mUserStore(config.getDataStore()->mUserStore),
     mOptionsHandler(0),
     mRequestContextFactory(new RequestContextFactory)
{
   FlowTokenSalt = Random::getCryptoRandom(20);   // 20-octet Crypto Random Key for Salting Flow Token HMACs

   mFifo.setDescription("Proxy::mFifo");

   if(InteropHelper::getOutboundSupported())
   {
      addSupportedOption("outbound");
   }
}
Proxy::~Proxy ( ) [virtual]

Definition at line 107 of file Proxy.cxx.

{
   shutdown();
   join();
   InfoLog (<< "Proxy::thread shutdown with " << mServerRequestContexts.size() << " ServerRequestContexts and " << mClientRequestContexts.size() << " ClientRequestContexts.");
}
repro::Proxy::Proxy ( ) [private]

Member Function Documentation

void Proxy::addClientTransaction ( const resip::Data transactionId,
RequestContext rc 
)

Definition at line 523 of file Proxy.cxx.

{
   if(mClientRequestContexts.count(transactionId) == 0)
   {
      InfoLog (<< "add client transaction tid=" << transactionId << " " << rc);
      mClientRequestContexts[transactionId] = rc;
   }
   else
   {
      ErrLog(<< "Received a client request context whose transaction id matches that of an existing request context. Ignoring.");
   }
}
void Proxy::addSupportedOption ( const resip::Data option)

Definition at line 613 of file Proxy.cxx.

{
   mSupportedOptions.insert(option);
}
KeyValueStore::Key Proxy::allocateGlobalKeyValueStoreKey ( ) [static]

Definition at line 50 of file Proxy.cxx.

KeyValueStore::Key Proxy::allocateRequestKeyValueStoreKey ( ) [static]

Definition at line 55 of file Proxy.cxx.

KeyValueStore::Key Proxy::allocateTargetKeyValueStoreKey ( ) [static]

Definition at line 60 of file Proxy.cxx.

bool Proxy::compressionEnabled ( ) const

Definition at line 607 of file Proxy.cxx.

bool repro::Proxy::getAssumePath ( ) const [inline]

Definition at line 78 of file Proxy.hxx.

{ return mAssumePath; }
ProxyConfig& repro::Proxy::getConfig ( ) [inline]

Definition at line 84 of file Proxy.hxx.

{return mConfig;}
KeyValueStore::KeyValueStoreKeyAllocator * Proxy::getGlobalKeyValueStoreKeyAllocator ( ) [static]

Definition at line 32 of file Proxy.cxx.

{
   static KeyValueStore::KeyValueStoreKeyAllocator* globalAllocator = new KeyValueStore::KeyValueStoreKeyAllocator();
   return globalAllocator;
}
resip::KeyValueStore& repro::Proxy::getKeyValueStore ( ) [inline]

Definition at line 101 of file Proxy.hxx.

{ return mKeyValueStore; }
const resip::NameAddr & Proxy::getRecordRoute ( const resip::Transport transport) const

Definition at line 589 of file Proxy.cxx.

{
   assert(transport);
   if(transport->hasRecordRoute())
   {
      // Transport specific record-route found
      return transport->getRecordRoute();
   }
   return mRecordRoute;
}
bool Proxy::getRecordRouteForced ( ) const

Definition at line 601 of file Proxy.cxx.

{
   return mRecordRouteForced;
}
KeyValueStore::KeyValueStoreKeyAllocator * Proxy::getRequestKeyValueStoreKeyAllocator ( ) [static]

Definition at line 38 of file Proxy.cxx.

{
   static KeyValueStore::KeyValueStoreKeyAllocator* requestAllocator = new KeyValueStore::KeyValueStoreKeyAllocator();
   return requestAllocator;
}
const resip::Data& repro::Proxy::getServerText ( ) const [inline]

Definition at line 98 of file Proxy.hxx.

{ return mServerText; }
resip::SipStack& repro::Proxy::getStack ( ) [inline]

Definition at line 83 of file Proxy.hxx.

{return mStack;}
KeyValueStore::KeyValueStoreKeyAllocator * Proxy::getTargetKeyValueStoreKeyAllocator ( ) [static]

Definition at line 44 of file Proxy.cxx.

{
   static KeyValueStore::KeyValueStoreKeyAllocator* targetAllocator = new KeyValueStore::KeyValueStoreKeyAllocator();
   return targetAllocator;
}
UserStore & Proxy::getUserStore ( )

Definition at line 134 of file Proxy.cxx.

{
   return mUserStore;
}
bool Proxy::isMyUri ( const resip::Uri uri) const

Definition at line 562 of file Proxy.cxx.

{
   bool ret = mStack.isMyDomain(uri.host(), uri.port());
   if(!ret)
   {
      ret = isMyDomain(uri.host());

      if(ret) 
      {
         // check if we are listening on the specified port
         // .slg. this is not perfect, but it will allow us to operate in most environments
         //       where the repro proxy and a UA are running on the same machine.
         //       Note:  There is a scenario that we cannot correctly handle - when a UA and 
         //       repro are running on the same machine, and they are using the same port but on 
         //       different transports types or interfaces.  In this case we cannot tell, by looking
         //       at a requestUri or From header if the uri is ours or the UA's, and things will break.
         if(uri.port() != 0)
         {
            ret = mStack.isMyPort(uri.port());
         }
      }
   }
   DebugLog( << "Proxy::isMyUri " << uri << " " << ret);
   return ret;
}
bool repro::Proxy::isPAssertedIdentityProcessingEnabled ( ) [inline]

Definition at line 80 of file Proxy.hxx.

bool Proxy::isShutDown ( ) const [virtual]

Definition at line 127 of file Proxy.cxx.

{
  return false;
}
const Data & Proxy::name ( ) const [protected, virtual]

Implements resip::TransactionUser.

Definition at line 555 of file Proxy.cxx.

{
   static Data n("Proxy");
   return n;
}
void Proxy::postMS ( std::auto_ptr< resip::ApplicationMessage msg,
int  msec 
)

Definition at line 548 of file Proxy.cxx.

{
   mStack.postMS(*msg,msec,this);
}
void Proxy::postTimerC ( std::auto_ptr< TimerCMessage tc)

Definition at line 537 of file Proxy.cxx.

{
   if(mTimerC > 0)
   {
      InfoLog(<<"Posting timer C");
      mStack.post(*tc,mTimerC,this);
   }
}
void Proxy::removeSupportedOption ( const resip::Data option)

Definition at line 619 of file Proxy.cxx.

{
   mSupportedOptions.erase(option);
}
void Proxy::send ( const resip::SipMessage msg)

Definition at line 517 of file Proxy.cxx.

{
   mStack.send(msg, this);
}
void repro::Proxy::setAssumePath ( bool  f) [inline]

Definition at line 77 of file Proxy.hxx.

{ mAssumePath = f; }
void Proxy::setOptionsHandler ( OptionsHandler handler)

Definition at line 115 of file Proxy.cxx.

{
   mOptionsHandler = handler;
}
void Proxy::setRequestContextFactory ( std::auto_ptr< RequestContextFactory requestContextFactory)

Definition at line 121 of file Proxy.cxx.

{
   mRequestContextFactory = requestContextFactory;
}
void repro::Proxy::setServerText ( const resip::Data text) [inline]

Definition at line 97 of file Proxy.hxx.

{ mServerText = text; }
void Proxy::thread ( ) [virtual]

Implements resip::ThreadIf.

Definition at line 141 of file Proxy.cxx.

{
   InfoLog (<< "Proxy::thread start");

   while (!isShutdown())
   {
      Message* msg=0;
      //DebugLog (<< "TransactionUser::postToTransactionUser " << " &=" << &mFifo << " size=" << mFifo.size());

      try
      {
         if ((msg = mFifo.getNext(100)) != 0)
         {
            DebugLog (<< "Got: " << *msg);
         
            SipMessage* sip = dynamic_cast<SipMessage*>(msg);
            ApplicationMessage* app = dynamic_cast<ApplicationMessage*>(msg);
            TransactionTerminated* term = dynamic_cast<TransactionTerminated*>(msg);
         
            if (sip)
            {
               Data tid(sip->getTransactionId());
               tid.lowercase();
               if (sip->isRequest())
               {
                  // Verify that the request has all the mandatory headers
                  // (To, From, Call-ID, CSeq)  Via is already checked by stack.  
                  // See RFC 3261 Section 16.3 Step 1
                  if (!sip->exists(h_To)     ||
                      !sip->exists(h_From)   ||
                      !sip->exists(h_CallID) ||
                      !sip->exists(h_CSeq)     )
                  {
                     // skip this message and move on to the next one
                     delete sip;
                     continue;  
                  }

                  // The TU selector already checks the URI scheme for us (Sect 16.3, Step 2)
                  if(sip->method()==OPTIONS && 
                     isMyUri(sip->header(h_RequestLine).uri()))
                  {
                     if(mOptionsHandler)
                     {
                        std::auto_ptr<SipMessage> resp(new SipMessage);
                        Helper::makeResponse(*resp,*sip,200);
                        if(mOptionsHandler->onOptionsRequest(*sip, *resp))
                        {
                           mStack.send(*resp,this);
                           delete sip;
                           continue;
                        }
                     }
                     else if(sip->header(h_RequestLine).uri().user().empty())
                     {
                        std::auto_ptr<SipMessage> resp(new SipMessage);
                        Helper::makeResponse(*resp,*sip,200);

                        if(resip::InteropHelper::getOutboundSupported())
                        {
                           resp->header(h_Supporteds).push_back(Token("outbound"));
                        }
                        mStack.send(*resp,this);
                        delete sip;
                        continue;
                     }
                  }

                  // check the MaxForwards isn't too low
                  if (!sip->exists(h_MaxForwards))
                  {
                     // .bwc. Add Max-Forwards header if not found.
                     sip->header(h_MaxForwards).value()=20;
                  }
                  
                  if(!sip->header(h_MaxForwards).isWellFormed())
                  {
                     //Malformed Max-Forwards! (Maybe we can be lenient and set
                     // it to 70...)
                     std::auto_ptr<SipMessage> response(Helper::makeResponse(*sip,400));
                     response->header(h_StatusLine).reason()="Malformed Max-Forwards";
                     mStack.send(*response,this);
                     delete sip;
                     continue;                     
                  }
                  
                  // .bwc. Unacceptable values for Max-Forwards
                  // !bwc! TODO make this ceiling configurable
                  if(sip->header(h_MaxForwards).value() > 255)
                  {
                     sip->header(h_MaxForwards).value() = 20;                     
                  }
                  else if(sip->header(h_MaxForwards).value() <= 0)
                  {
                     if (sip->header(h_RequestLine).method() != OPTIONS)
                     {
                     std::auto_ptr<SipMessage> response(Helper::makeResponse(*sip, 483));
                     mStack.send(*response, this);
                     }
                     else  // If the request is an OPTIONS, send an appropriate response
                     {
                        std::auto_ptr<SipMessage> response(Helper::makeResponse(*sip, 200));
                        mStack.send(*response, this);                        
                     }
                     // in either case get rid of the request and process the next one
                     delete sip;
                     continue;
                  }

                  if(!sip->empty(h_ProxyRequires))
                  {
                     std::auto_ptr<SipMessage> response(0);

                     for(Tokens::iterator i=sip->header(h_ProxyRequires).begin();
                           i!=sip->header(h_ProxyRequires).end();
                           ++i)
                     {
                        if(!i->isWellFormed() || 
                           !mSupportedOptions.count(i->value()) )
                        {
                           if(!response.get())
                           {
                              response.reset(Helper::makeResponse(*sip, 420, "Bad extension"));
                           }
                           response->header(h_Unsupporteds).push_back(*i);
                        }
                     }

                     if(response.get())
                     {
                        mStack.send(*response, this);
                        delete sip;
                        continue;
                     }
                  }
                  
                  
                  if (sip->method() == CANCEL)
                  {
                     HashMap<Data,RequestContext*>::iterator i = mServerRequestContexts.find(tid);

                     if(i == mServerRequestContexts.end())
                     {
                        SipMessage response;
                        Helper::makeResponse(response,*sip,481);
                        mStack.send(response,this);
                        delete sip;
                     }
                     else
                     {
                        try
                        {
                           i->second->process(std::auto_ptr<resip::SipMessage>(sip));
                        }
                        catch(resip::BaseException& e)
                        {
                           // .bwc. Some sort of unhandled error in process.
                           // This is very bad; we cannot form a response 
                           // at this point because we do not know
                           // whether the original request still exists.
                           ErrLog(<<"Uncaught exception in process on a CANCEL "
                                    "request: " << e);
                           mStack.abandonServerTransaction(tid);
                        }
                     }
                  }
                  else if (sip->method() == ACK)
                  {
                     // .bwc. This is going to be treated as a new transaction.
                     // The stack is maintaining no state whatsoever for this.
                     // We should treat this exactly like a new transaction.
                     if(sip->mIsBadAck200)
                     {
                        static Data ack("ack");
                        tid+=ack;
                     }
                     
                     RequestContext* context=0;

                     HashMap<Data,RequestContext*>::iterator i = mServerRequestContexts.find(tid);
                     
                     // .bwc. This might be an ACK/200, or a stray ACK/failure
                     if(i == mServerRequestContexts.end())
                     {
                        context = mRequestContextFactory->createRequestContext(*this, 
                                                     mRequestProcessorChain, 
                                                     mResponseProcessorChain, 
                                                     mTargetProcessorChain);
                        mServerRequestContexts[tid] = context;
                     }
                     else // .bwc. ACK/failure
                     {
                        context = i->second;
                     }

                     // The stack will send TransactionTerminated messages for
                     // client and server transaction which will clean up this
                     // RequestContext 
                     try
                     {
                        context->process(std::auto_ptr<resip::SipMessage>(sip));
                     }
                     catch(resip::BaseException& e)
                     {
                        // .bwc. Some sort of unhandled error in process.
                        ErrLog(<<"Uncaught exception in process on an ACK "
                                 "request: " << e);
                     }
                  }
                  else
                  {
                     // This is a new request, so create a Request Context for it
                     InfoLog (<< "New RequestContext tid=" << tid << " : " << sip->brief());
                     

                     if(mServerRequestContexts.count(tid) == 0)
                     {
                        RequestContext* context = mRequestContextFactory->createRequestContext(*this,
                                                                     mRequestProcessorChain, 
                                                                     mResponseProcessorChain, 
                                                                     mTargetProcessorChain);
                        InfoLog (<< "Inserting new RequestContext tid=" << tid
                                  << " -> " << *context);
                        mServerRequestContexts[tid] = context;
                        DebugLog (<< "RequestContexts: " << InserterP(mServerRequestContexts));
                        try
                        {
                           context->process(std::auto_ptr<resip::SipMessage>(sip));
                        }
                        catch(resip::BaseException& e)
                        {
                           // .bwc. Some sort of unhandled error in process.
                           // This is very bad; we cannot form a response 
                           // at this point because we do not know
                           // whether the original request still exists.
                           ErrLog(<<"Uncaught exception in process on a new "
                                    "request: " << e);
                           mStack.abandonServerTransaction(tid);
                        }
                     }
                     else
                     {
                        InfoLog(<<"Got a new non-ACK request "
                        "with an already existing transaction ID. This can "
                        "happen if a new request collides with a previously "
                        "received ACK/200.");
                        SipMessage response;
                        Helper::makeResponse(response,*sip,400,"Transaction-id "
                                                         "collision");
                        mStack.send(response,this);
                        delete sip;
                     }
                  }
               }
               else if (sip->isResponse())
               {
                  InfoLog (<< "Looking up RequestContext tid=" << tid);
               
                  // TODO  is there a problem with a stray 200?
                  HashMap<Data,RequestContext*>::iterator i = mClientRequestContexts.find(tid);
                  if (i != mClientRequestContexts.end())
                  {
                     try
                     {
                        i->second->process(std::auto_ptr<resip::SipMessage>(sip));
                     }
                     catch(resip::BaseException& e)
                     {
                        // .bwc. Some sort of unhandled error in process.
                        ErrLog(<<"Uncaught exception in process on a response: " << e);
                     }
                  }
                  else
                  {
                     // throw away stray responses
                     InfoLog (<< "Unmatched response (stray?) : " << endl << *msg);
                     delete sip;  
                  }
               }
            }
            else if (app)
            {
               Data tid(app->getTransactionId());
               tid.lowercase();
               DebugLog(<< "Trying to dispatch : " << *app );
               HashMap<Data,RequestContext*>::iterator i=mServerRequestContexts.find(tid);
               // the underlying RequestContext may not exist
               if (i != mServerRequestContexts.end())
               {
                  DebugLog(<< "Sending " << *app << " to " << *(i->second));
                  // This goes in as a Message and not an ApplicationMessage
                  // so that we have one peice of code doing dispatch to Monkeys
                  // (the intent is that Monkeys may eventually handle non-SIP
                  //  application messages).
                  bool eraseThisTid =  (dynamic_cast<Ack200DoneMessage*>(app)!=0);
                  try
                  {
                     i->second->process(std::auto_ptr<resip::ApplicationMessage>(app));
                  }
                  catch(resip::BaseException& e)
                  {
                     ErrLog(<<"Uncaught exception in process: " << e);
                  }
                  
                  if (eraseThisTid)
                  {
                     mServerRequestContexts.erase(i);
                  }
               }
               else
               {
                  InfoLog (<< "No matching request context...ignoring " << *app);
                  delete app;
               }
            }
            else if (term)
            {
               Data tid(term->getTransactionId());
               tid.lowercase();
               if (term->isClientTransaction())
               {
                  HashMap<Data,RequestContext*>::iterator i=mClientRequestContexts.find(tid);
                  if (i != mClientRequestContexts.end())
                  {
                     try
                     {
                        i->second->process(*term);
                     }
                     catch(resip::BaseException& e)
                     {
                        ErrLog(<<"Uncaught exception in process: " << e);
                     }
                     mClientRequestContexts.erase(i);
                  }
                  else
                  {
                     InfoLog (<< "No matching request context...ignoring " << *term);
                  }
               }
               else 
               {
                  HashMap<Data,RequestContext*>::iterator i=mServerRequestContexts.find(tid);
                  if (i != mServerRequestContexts.end())
                  {
                     try
                     {
                        i->second->process(*term);
                     }
                     catch(resip::BaseException& e)
                     {
                        ErrLog(<<"Uncaught exception in process: " << e);
                     }
                     mServerRequestContexts.erase(i);
                  }
                  else
                  {
                     InfoLog (<< "No matching request context...ignoring " << *term);
                  }
               }
               delete term;
            }
         }
      }
      catch (BaseException& e)
      {
         ErrLog (<< "Caught: " << e);
      }
      catch (...)
      {
         ErrLog (<< "Caught unknown exception");
      }
   }
   InfoLog (<< "Proxy::thread exit");
}

Member Data Documentation

Data Proxy::FlowTokenSalt [static]

Definition at line 58 of file Proxy.hxx.

bool repro::Proxy::mAssumePath [private]

Definition at line 111 of file Proxy.hxx.

a map from transaction id to RequestContext.

Store the server transaction and client transactions in this map. The TransactionTerminated events from the stack will be passed to the RequestContext

Definition at line 127 of file Proxy.hxx.

Definition at line 108 of file Proxy.hxx.

Definition at line 115 of file Proxy.hxx.

Definition at line 132 of file Proxy.hxx.

Definition at line 112 of file Proxy.hxx.

Definition at line 109 of file Proxy.hxx.

Definition at line 110 of file Proxy.hxx.

Definition at line 133 of file Proxy.hxx.

Definition at line 118 of file Proxy.hxx.

Definition at line 119 of file Proxy.hxx.

Definition at line 128 of file Proxy.hxx.

Definition at line 113 of file Proxy.hxx.

Definition at line 107 of file Proxy.hxx.

Definition at line 131 of file Proxy.hxx.

Definition at line 120 of file Proxy.hxx.

int repro::Proxy::mTimerC [private]

Definition at line 114 of file Proxy.hxx.

Definition at line 130 of file Proxy.hxx.


The documentation for this class was generated from the following files: