|
reSIProcate/repro
9694
|
#include <Proxy.hxx>


| 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] |
| 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.
{
return getGlobalKeyValueStoreKeyAllocator()->allocateNewKey();
}
| KeyValueStore::Key Proxy::allocateRequestKeyValueStoreKey | ( | ) | [static] |
Definition at line 55 of file Proxy.cxx.
{
return getRequestKeyValueStoreKeyAllocator()->allocateNewKey();
}
| KeyValueStore::Key Proxy::allocateTargetKeyValueStoreKey | ( | ) | [static] |
Definition at line 60 of file Proxy.cxx.
{
return getTargetKeyValueStoreKeyAllocator()->allocateNewKey();
}
| bool Proxy::compressionEnabled | ( | ) | const |
Definition at line 607 of file Proxy.cxx.
{
return mStack.getCompression().getAlgorithm() != resip::Compression::NONE;
}
| bool repro::Proxy::getAssumePath | ( | ) | const [inline] |
Definition at line 78 of file Proxy.hxx.
{ return mAssumePath; }
| ProxyConfig& repro::Proxy::getConfig | ( | ) | [inline] |
| 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] |
| 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.
{ return mPAssertedIdentityProcessing; }
| bool Proxy::isShutDown | ( | ) | const [virtual] |
| 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 | ||
| ) |
| void Proxy::postTimerC | ( | std::auto_ptr< TimerCMessage > | tc | ) |
| 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 | ) |
| 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");
}
Data Proxy::FlowTokenSalt [static] |
bool repro::Proxy::mAssumePath [private] |
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
ProxyConfig& repro::Proxy::mConfig [private] |
OptionsHandler* repro::Proxy::mOptionsHandler [private] |
bool repro::Proxy::mPAssertedIdentityProcessing [private] |
resip::NameAddr repro::Proxy::mRecordRoute [private] |
bool repro::Proxy::mRecordRouteForced [private] |
std::auto_ptr<RequestContextFactory> repro::Proxy::mRequestContextFactory [private] |
resip::Data repro::Proxy::mServerText [private] |
resip::SipStack& repro::Proxy::mStack [private] |
std::set<resip::Data> repro::Proxy::mSupportedOptions [private] |
int repro::Proxy::mTimerC [private] |
UserStore& repro::Proxy::mUserStore [private] |
1.7.5.1