Commit 9c4b018b authored by Simon Morlat's avatar Simon Morlat

rewrite fork contexts.

parent 9e88cfe4
......@@ -746,14 +746,6 @@ void Agent::injectResponseEvent(shared_ptr<ResponseSipEvent> ev) {
doSendEvent(ev, it, mModules.end());
}
void Agent::sendTransactionEvent(shared_ptr<TransactionEvent> ev) {
SLOGD << "Propagating new Transaction Event " << ev->transaction.get()
<< " " << ev->getKindName();
list<Module*>::iterator it;
for (it = mModules.begin(); it != mModules.end(); ++it) {
(*it)->processTransactionEvent(ev);
}
}
/**
* This is a dangerous function when called at the wrong time.
......
......@@ -156,8 +156,6 @@ class Agent: public IncomingAgent, public OutgoingAgent, public std::enable_shar
Module *findModule(const std::string &modname) const;
int onIncomingMessage(msg_t *msg, const sip_t *sip);
nth_engine_t* getHttpEngine() {return mHttpEngine; }
protected:
void sendTransactionEvent(std::shared_ptr<TransactionEvent> ev);
private:
virtual void send(const std::shared_ptr<MsgSip> &msg, url_string_t const *u, tag_type_t tag, tag_value_t value, ...);
virtual void reply(const std::shared_ptr<MsgSip> &msg, int status, char const *phrase, tag_type_t tag, tag_value_t value, ...);
......
......@@ -133,6 +133,14 @@ void SipEvent::restartProcessing() {
}
}
std::shared_ptr<IncomingTransaction> SipEvent::getIncomingTransaction(){
return dynamic_pointer_cast<IncomingTransaction>(getIncomingAgent());
}
std::shared_ptr<OutgoingTransaction> SipEvent::getOutgoingTransaction(){
return dynamic_pointer_cast<OutgoingTransaction>(getOutgoingAgent());
}
RequestSipEvent::RequestSipEvent(shared_ptr<IncomingAgent> incomingAgent,
const shared_ptr<MsgSip> &msgSip,
shared_ptr<tport_t> inTport
......
......@@ -147,6 +147,8 @@ public:
}
void setEventLog(const std::shared_ptr<EventLog> & log);
void flushLog();/*to be used exceptionally when an eventlog needs to be flushed immediately, for example because you need to submit a new one.*/
std::shared_ptr<IncomingTransaction> getIncomingTransaction();
std::shared_ptr<OutgoingTransaction> getOutgoingTransaction();
protected:
Module *mCurrModule;
std::shared_ptr<MsgSip> mMsgSip;
......
......@@ -24,9 +24,12 @@
using namespace ::std;
ForkBasicContext::ForkBasicContext(Agent *agent, const std::shared_ptr<RequestSipEvent> &event, shared_ptr<ForkContextConfig> cfg, ForkContextListener* listener) :
ForkContext(agent, event,cfg,listener), mDeliveredCount(0) {
ForkContext(agent, event,cfg,listener) {
LOGD("New ForkBasicContext %p", this);
mDecisionTimer=NULL;
//start the acceptance timer immediately
mDecisionTimer=su_timer_create(su_root_task(mAgent->getRoot()), 0);
su_timer_set_interval(mDecisionTimer, &ForkBasicContext::sOnDecisionTimer, this, (su_duration_t)20000);
}
ForkBasicContext::~ForkBasicContext() {
......@@ -35,78 +38,39 @@ ForkBasicContext::~ForkBasicContext() {
LOGD("Destroy ForkBasicContext %p", this);
}
void ForkBasicContext::forward(const shared_ptr<ResponseSipEvent> &ev) {
sip_t *sip = ev->getMsgSip()->getSip();
if (sip->sip_status->st_status >= 200 ) {
if (mDeliveredCount>1){
/*should only transfer one response*/
ev->setIncomingAgent(shared_ptr<IncomingAgent>());
}
mDeliveredCount++;
checkFinished();
}
}
void ForkBasicContext::checkFinished(){
return ForkContext::checkFinished();
}
void ForkBasicContext::onRequest(const shared_ptr<IncomingTransaction> &transaction, shared_ptr<RequestSipEvent> &event) {
}
void ForkBasicContext::store(shared_ptr<ResponseSipEvent> &event) {
bool best = true;
if (mBestResponse != NULL) {
if (mBestResponse->getMsgSip()->getSip()->sip_status->st_status < event->getMsgSip()->getSip()->sip_status->st_status) {
best = false;
}
}
// Save
if (best) {
mBestResponse = make_shared<ResponseSipEvent>(event); // Copy event
mBestResponse->suspendProcessing();
}
// Don't forward
event->setIncomingAgent(shared_ptr<IncomingAgent>());
}
void ForkBasicContext::onResponse(const shared_ptr<OutgoingTransaction> &transaction, shared_ptr<ResponseSipEvent> &event) {
event->setIncomingAgent(mIncoming);
const shared_ptr<MsgSip> &ms = event->getMsgSip();
sip_t *sip = ms->getSip();
if (sip != NULL && sip->sip_status != NULL) {
LOGD("Fork: outgoingCallback %d", sip->sip_status->st_status);
if (sip->sip_status->st_status > 100 && sip->sip_status->st_status < 300) {
forward(event);
} else {
store(event);
void ForkBasicContext::onResponse(const shared_ptr<BranchInfo> &br, const shared_ptr<ResponseSipEvent> &event) {
int code=br->getStatus();
if (code>=200){
if (code<300){
forwardResponse(br);
if (mDecisionTimer){
su_timer_destroy(mDecisionTimer);
mDecisionTimer=NULL;
}
setFinished();
}else{
if (allBranchesAnswered()){
finishIncomingTransaction();
}
}
}
}
void ForkBasicContext::finishIncomingTransaction(){
if (mIncoming != NULL && mDeliveredCount==0) {
if (mBestResponse == NULL) {
// Create response
shared_ptr<MsgSip> msgsip(mIncoming->createResponse(SIP_408_REQUEST_TIMEOUT));
shared_ptr<ResponseSipEvent> ev(new ResponseSipEvent(dynamic_pointer_cast<OutgoingAgent>(mAgent->shared_from_this()), msgsip));
ev->setIncomingAgent(mIncoming);
mAgent->sendResponseEvent(ev);
} else {
mAgent->injectResponseEvent(mBestResponse);
}
}
if (mDecisionTimer){
su_timer_destroy(mDecisionTimer);
mDecisionTimer=NULL;
}
mBestResponse.reset();
mIncoming.reset();
shared_ptr<BranchInfo> best=findBestBranch(sUrgentCodes);
if (best==NULL) {
// Create response
shared_ptr<MsgSip> msgsip(mIncoming->createResponse(SIP_408_REQUEST_TIMEOUT));
shared_ptr<ResponseSipEvent> ev(new ResponseSipEvent(dynamic_pointer_cast<OutgoingAgent>(mAgent->shared_from_this()), msgsip));
forwardResponse(ev);
}else{
forwardResponse(best);
}
setFinished();
}
void ForkBasicContext::onDecisionTimer(){
......@@ -118,30 +82,7 @@ void ForkBasicContext::sOnDecisionTimer(su_root_magic_t* magic, su_timer_t* t, s
static_cast<ForkBasicContext*>(arg)->onDecisionTimer();
}
void ForkBasicContext::onNew(const shared_ptr<IncomingTransaction> &transaction) {
ForkContext::onNew(transaction);
//start the acceptance timer immediately
mDecisionTimer=su_timer_create(su_root_task(mAgent->getRoot()), 0);
su_timer_set_interval(mDecisionTimer, &ForkBasicContext::sOnDecisionTimer, this, (su_duration_t)20000);
}
void ForkBasicContext::onDestroy(const shared_ptr<IncomingTransaction> &transaction) {
ForkContext::onDestroy(transaction);
}
void ForkBasicContext::onNew(const shared_ptr<OutgoingTransaction> &transaction) {
ForkContext::onNew(transaction);
}
void ForkBasicContext::onDestroy(const shared_ptr<OutgoingTransaction> &transaction) {
if (mOutgoings.size() == 1) {
finishIncomingTransaction();
}
ForkContext::onDestroy(transaction);
}
bool ForkBasicContext::onNewRegister(const sip_contact_t *ctt){
bool ForkBasicContext::onNewRegister(const url_t *url, const string &uid){
return false;
}
......@@ -28,22 +28,13 @@
class ForkBasicContext: public ForkContext {
private:
int mDeliveredCount;
std::shared_ptr<ResponseSipEvent> mBestResponse;
void forward(const std::shared_ptr<ResponseSipEvent> &ev);
void store(std::shared_ptr<ResponseSipEvent> &event);
su_timer_t *mDecisionTimer; /*timeout after which an answer must be sent through the incoming transaction even if no success response was received on the outgoing transactions*/
public:
ForkBasicContext(Agent *agent, const std::shared_ptr<RequestSipEvent> &event, std::shared_ptr<ForkContextConfig> cfg, ForkContextListener* listener);
virtual ~ForkBasicContext();
virtual void onNew(const std::shared_ptr<IncomingTransaction> &transaction);
virtual void onRequest(const std::shared_ptr<IncomingTransaction> &transaction, std::shared_ptr<RequestSipEvent> &event);
virtual void onDestroy(const std::shared_ptr<IncomingTransaction> &transaction);
virtual void onNew(const std::shared_ptr<OutgoingTransaction> &transaction);
virtual void onResponse(const std::shared_ptr<OutgoingTransaction> &transaction, std::shared_ptr<ResponseSipEvent> &event);
virtual void onDestroy(const std::shared_ptr<OutgoingTransaction> &transaction);
virtual bool onNewRegister(const sip_contact_t *ctt);
virtual void checkFinished();
protected:
virtual void onResponse(const std::shared_ptr<BranchInfo> &br, const std::shared_ptr<ResponseSipEvent> &event);
virtual bool onNewRegister(const url_t *url, const std::string &uid);
private:
void finishIncomingTransaction();
static void sOnDecisionTimer(su_root_magic_t *magic, su_timer_t *t, su_timer_arg_t *arg);
......
......@@ -29,7 +29,7 @@ static bool contains(const list<T> &l, T value) {
}
ForkCallContext::ForkCallContext(Agent *agent, const std::shared_ptr<RequestSipEvent> &event, shared_ptr<ForkContextConfig> cfg, ForkContextListener* listener) :
ForkContext(agent, event,cfg, listener), mShortTimer(NULL), mPushTimer(NULL), mLastResponseCodeSent(100), mCancelled(false) {
ForkContext(agent, event,cfg, listener), mShortTimer(NULL), mPushTimer(NULL), mCancelled(false) {
LOGD("New ForkCallContext %p", this);
mLog=event->getEventLog<CallLog>();
mActivePushes = 0;
......@@ -51,55 +51,15 @@ void ForkCallContext::cancel() {
mLog->setCancelled();
mLog->setCompleted();
mCancelled=true;
cancelOthers();
cancelOthers(NULL);
}
void ForkCallContext::forward(const shared_ptr<ResponseSipEvent> &ev, bool force) {
sip_t *sip = ev->getMsgSip()->getSip();
bool fakeSipEvent = ((mLastResponseCodeSent >= 200) && !force) || mIncoming == NULL;
const int status = sip->sip_status->st_status;
if (mCfg->mForkOneResponse) { // TODO: respect RFC 3261 16.7.5
if (status == 183 || status == 180 || status == 101) {
auto it = find(mForwardResponses.begin(), mForwardResponses.end(), status);
if (it != mForwardResponses.end()) {
fakeSipEvent = true;
} else {
mForwardResponses.push_back(status);
}
}
}
if (fakeSipEvent) {
ev->setIncomingAgent(shared_ptr<IncomingAgent>());
}else{
if (mCfg->mRemoveToTag && (status == 183 || status == 180 || status == 101)) {
SLOGD << "Removing 'to tag' ";
msg_header_remove_param((msg_common_t *)sip->sip_to, "tag");
}
logResponse(ev);
}
mLastResponseCodeSent=status;
}
void ForkCallContext::decline(const shared_ptr<OutgoingTransaction> &transaction, shared_ptr<ResponseSipEvent> &ev) {
if (!mCfg->mForkNoGlobalDecline) {
cancelOthers(transaction);
forward(ev);
} else {
if (mOutgoings.size() != 1) {
store(ev);
} else {
forward(ev);
}
}
}
void ForkCallContext::cancelOthers(const shared_ptr<OutgoingTransaction> &transaction) {
for (list<shared_ptr<OutgoingTransaction>>::iterator it = mOutgoings.begin(); it != mOutgoings.end();) {
if (*it != transaction) {
shared_ptr<OutgoingTransaction> tr = (*it);
it = mOutgoings.erase(it);
void ForkCallContext::cancelOthers(const shared_ptr<BranchInfo> & br) {
auto branches=getBranches();
for (auto it = branches.begin(); it != branches.end();) {
if (*it != br) {
shared_ptr<OutgoingTransaction> tr = (*it)->mTransaction;
removeBranch(*it);
tr->cancel();
} else {
++it;
......@@ -107,109 +67,48 @@ void ForkCallContext::cancelOthers(const shared_ptr<OutgoingTransaction> &transa
}
}
void ForkCallContext::onRequest(const shared_ptr<IncomingTransaction> &transaction, shared_ptr<RequestSipEvent> &event) {
event->setOutgoingAgent(shared_ptr<OutgoingAgent>());
const shared_ptr<MsgSip> &ms = event->getMsgSip();
sip_t *sip = ms->getSip();
if (sip != NULL && sip->sip_request != NULL) {
if (sip->sip_request->rq_method == sip_method_cancel) {
LOGD("Fork: incomingCallback cancel");
cancel();
/*
* let the event go through the list of modules for notification purpose, but do not send the cancel at the end since it is handled here.
* Indeed there might not be generated cancels for non-responded branches of the fork, letting other modules unnotified.
**/
event->setOutgoingAgent(shared_ptr<OutgoingAgent>());
}
}
}
const int ForkCallContext::sUrgentCodesWithout603[]={401,407,415,420,484,488,606,0};
bool ForkCallContext::isRetryableOrUrgent(int code){
switch(code){
case 401:
case 407:
case 415:
case 420:
case 484:
case 488:
case 606:
return true;
case 603:
if (mCfg->mTreatDeclineAsUrgent)
return true;
default:
return false;
}
return false;
const int * ForkCallContext::getUrgentCodes(){
return mCfg->mTreatDeclineAsUrgent ? ForkContext::sUrgentCodes : sUrgentCodesWithout603;
}
void ForkCallContext::store(shared_ptr<ResponseSipEvent> &event) {
bool best = false;
int code=event->getMsgSip()->getSip()->sip_status->st_status;
if (mBestResponse != NULL) {
//we must give priority to 401, 407, 415, 420, 484 because they will trigger a request retry.
int prev_resp_code=mBestResponse->getMsgSip()->getSip()->sip_status->st_status;
int code_class=code/100;
int prev_code_class=prev_resp_code/100;
if (code_class < prev_code_class) {
best = true;
}
}else best=true;
void ForkCallContext::onResponse(const shared_ptr<BranchInfo> & br, const shared_ptr<ResponseSipEvent> &event) {
const shared_ptr<MsgSip> &ms = event->getMsgSip();
sip_t *sip = ms->getSip();
int code=sip->sip_status->st_status;
if (best && isRetryableOrUrgent(code)){
if (mShortTimer==NULL){
if (code>=300){
if (allBranchesAnswered()){
shared_ptr<BranchInfo> best=findBestBranch(getUrgentCodes());
if (best) logResponse(forwardResponse(best));
return;
}
if (isUrgent(code,getUrgentCodes()) && mShortTimer==NULL){
mShortTimer=su_timer_create(su_root_task(mAgent->getRoot()), 0);
su_timer_set_interval(mShortTimer, &ForkCallContext::sOnShortTimer, this, (su_duration_t)mCfg->mUrgentTimeout*1000);
return;
}
}
// Save
if (best) {
mBestResponse = make_shared<ResponseSipEvent>(event); // Copy event
mBestResponse->suspendProcessing();
}
// Don't forward
event->setIncomingAgent(shared_ptr<IncomingAgent>());
}
void ForkCallContext::onResponse(const shared_ptr<OutgoingTransaction> &transaction, shared_ptr<ResponseSipEvent> &event) {
event->setIncomingAgent(mIncoming);
const shared_ptr<MsgSip> &ms = event->getMsgSip();
sip_t *sip = ms->getSip();
if (sip != NULL && sip->sip_status != NULL) {
int code=sip->sip_status->st_status;
LOGD("Fork: outgoingCallback %d", code);
if (code > 100 && code < 200) {
forward(event);
} else if (code >= 200 && code < 300) {
if (mCfg->mForkOneResponse) // TODO: respect RFC 3261 16.7.5
cancelOthers(transaction);
forward(event, true);
} else if (code >= 600 && code < 700) {
decline(transaction, event);
} else if (code!=503 && code!=408){ //ignore 503 and 408
if (mOutgoings.size()<2){
//optimization: when there is a single branch in the fork, send all the response immediately.
forward(event,true);
}else if (!mCancelled){
store(event);
}else{
forward(event,true);
if (code>=600){
/*6xx response are normally treated as global faillures */
if (!mCfg->mForkNoGlobalDecline){
logResponse(forwardResponse(br));
cancelOthers(br);
}
} else {// Don't forward
event->setIncomingAgent(shared_ptr<IncomingAgent>());
SLOGW << "ForkCallContext::onResponse " << this << " Outgoing transaction: ignore message " << code;
}
}else if (code>=200){
logResponse(forwardResponse(br));
cancelOthers(br);
}else if (code>=100){
logResponse(forwardResponse(br));
}
}
//This is actually called when we want to simulate a ringing event, for example when a push notification is sent to a device.
void ForkCallContext::sendRinging(){
// Create response
if (mIncoming && mLastResponseCodeSent<180){
int code=getLastResponseCode();
if (code<180){
shared_ptr<MsgSip> msgsip(mIncoming->createResponse(SIP_180_RINGING));
shared_ptr<ResponseSipEvent> ev(new ResponseSipEvent(dynamic_pointer_cast<OutgoingAgent>(mAgent->shared_from_this()), msgsip));
//add a to tag, no set by sofia here.
......@@ -222,81 +121,28 @@ void ForkCallContext::sendRinging(){
mPushTimer=su_timer_create(su_root_task(mAgent->getRoot()), 0);
su_timer_set_interval(mPushTimer, &ForkCallContext::sOnPushTimer, this, (su_duration_t)mCfg->mPushResponseTimeout*1000);
}
ev->setIncomingAgent(mIncoming);
sendResponse(ev,false);
forwardResponse(ev);
}
}
void ForkCallContext::onNew(const shared_ptr<IncomingTransaction> &transaction) {
ForkContext::onNew(transaction);
}
void ForkCallContext::onDestroy(const shared_ptr<IncomingTransaction> &transaction) {
return ForkContext::onDestroy(transaction);
}
void ForkCallContext::onNew(const shared_ptr<OutgoingTransaction> &transaction) {
ForkContext::onNew(transaction);
}
void ForkCallContext::logResponse(const shared_ptr<ResponseSipEvent> &ev){
sip_t *sip=ev->getMsgSip()->getSip();
mLog->setStatusCode(sip->sip_status->st_status,sip->sip_status->st_phrase);
if (sip->sip_status->st_status>=200)
mLog->setCompleted();
ev->setEventLog(mLog);
}
void ForkCallContext::sendResponse(shared_ptr<ResponseSipEvent> ev, bool inject){
logResponse(ev);
if (inject)
mAgent->injectResponseEvent(ev);
else
mAgent->sendResponseEvent(ev);
mLastResponseCodeSent=ev->getMsgSip()->getSip()->sip_status->st_status;
}
void ForkCallContext::checkFinished(){
if (mOutgoings.size() == 0){
if (!isCompleted() && mBestResponse){
/* no more outgoing transactions, but one of them replied with an explicit answer (not 503 or 408).
* In this case, forward this response now.
**/
sendResponse(mBestResponse,true);
mBestResponse.reset();
setFinished();
return;
}
if ((mLateTimerExpired || mLateTimer==NULL)) {
if (mIncoming != NULL && !isCompleted()) {
if (mBestResponse == NULL) {
// Create response
shared_ptr<MsgSip> msgsip(mIncoming->createResponse(SIP_408_REQUEST_TIMEOUT));
shared_ptr<ResponseSipEvent> ev(new ResponseSipEvent(dynamic_pointer_cast<OutgoingAgent>(mAgent->shared_from_this()), msgsip));
ev->setIncomingAgent(mIncoming);
sendResponse(ev,false);
} else {
sendResponse(mBestResponse,true);
}
}
mBestResponse.reset();
setFinished();
}
if (ev){
sip_t *sip=ev->getMsgSip()->getSip();
mLog->setStatusCode(sip->sip_status->st_status,sip->sip_status->st_phrase);
if (sip->sip_status->st_status>=200)
mLog->setCompleted();
ev->setEventLog(mLog);
}
}
void ForkCallContext::onDestroy(const shared_ptr<OutgoingTransaction> &transaction) {
ForkContext::onDestroy(transaction);
}
bool ForkCallContext::onNewRegister(const sip_contact_t *ctt){
bool ForkCallContext::onNewRegister(const url_t *url, const string &uid){
if (isCompleted()) return false;
return ForkContext::onNewRegister(ctt);
return ForkContext::onNewRegister(url,uid);
}
bool ForkCallContext::isCompleted()const{
return mLastResponseCodeSent>=200 || mCancelled || mIncoming==NULL;
if (getLastResponseCode()>=200 || mCancelled) return true;
return false;
}
void ForkCallContext::onShortTimer(){
......@@ -304,15 +150,25 @@ void ForkCallContext::onShortTimer(){
su_timer_destroy(mShortTimer);
mShortTimer=NULL;
if (mCancelled || mLastResponseCodeSent>=180) return; /*it's ringing somewhere*/
if (isRetryableOrUrgent(mBestResponse->getMsgSip()->getSip()->sip_status->st_status)){
cancelOthers(static_pointer_cast<OutgoingTransaction>(mBestResponse->getOutgoingAgent()));
sendResponse(mBestResponse,true);// send urgent reply immediately
mBestResponse.reset();
if (getLastResponseCode()>=180) return; /*it's ringing somewhere*/
auto br=findBestBranch(getUrgentCodes());
if (br){
logResponse(forwardResponse(br));
}
}
void ForkCallContext::onLateTimeout() {
auto br=findBestBranch(getUrgentCodes());
if (!br || br->getStatus()==0 || br->getStatus()==503){
shared_ptr<MsgSip> msgsip(mIncoming->createResponse(SIP_408_REQUEST_TIMEOUT));
shared_ptr<ResponseSipEvent> ev(new ResponseSipEvent(dynamic_pointer_cast<OutgoingAgent>(mAgent->shared_from_this()), msgsip));
logResponse(forwardResponse(ev));
}else{
logResponse(forwardResponse(br));
}
}
void ForkCallContext::sOnShortTimer(su_root_magic_t *magic, su_timer_t *t, su_timer_arg_t *arg){
ForkCallContext *zis=static_cast<ForkCallContext*>(arg);
zis->onShortTimer();
......@@ -320,7 +176,7 @@ void ForkCallContext::sOnShortTimer(su_root_magic_t *magic, su_timer_t *t, su_ti
void ForkCallContext::onPushTimer(){
if (!isCompleted() && !mBestResponse && !contains(mForwardResponses, 180) && !contains(mForwardResponses, 183)) {
if (!isCompleted() && getLastResponseCode()<180) {
SLOGD << "ForkCallContext " << this << " push timer : no uac response";
}
su_timer_destroy(mPushTimer);
......
......@@ -27,42 +27,34 @@
class ForkCallContext: public ForkContext {
private:
std::shared_ptr<ResponseSipEvent> mBestResponse;
su_timer_t *mShortTimer; //optionaly used to send retryable responses
su_timer_t *mPushTimer; //used to track push responses
int mLastResponseCodeSent;
bool mCancelled;
std::list<int> mForwardResponses;
std::shared_ptr<CallLog> mLog;
bool mCancelled;
public:
ForkCallContext(Agent *agent, const std::shared_ptr<RequestSipEvent> &event, std::shared_ptr<ForkContextConfig> cfg, ForkContextListener* listener);
~ForkCallContext();
virtual void onNew(const std::shared_ptr<IncomingTransaction> &transaction);
virtual void onRequest(const std::shared_ptr<IncomingTransaction> &transaction, std::shared_ptr<RequestSipEvent> &event);
virtual void onDestroy(const std::shared_ptr<IncomingTransaction> &transaction);
virtual void onNew(const std::shared_ptr<OutgoingTransaction> &transaction);
virtual void onResponse(const std::shared_ptr<OutgoingTransaction> &transaction, std::shared_ptr<ResponseSipEvent> &event);
virtual void onDestroy(const std::shared_ptr<OutgoingTransaction> &transaction);
virtual void checkFinished();
virtual bool onNewRegister(const sip_contact_t *ctt);
void sendRinging();
bool isCompleted()const;
void onPushInitiated(const std::string &key);
void onPushError(const std::string &key, const std::string &errormsg);
protected:
virtual void onResponse(const std::shared_ptr<BranchInfo> &br, const std::shared_ptr<ResponseSipEvent> &event);
virtual bool onNewRegister(const url_t *url, const std::string &uid);
virtual void cancel();
private:
bool isRetryableOrUrgent(int code);
const int *getUrgentCodes();
void onShortTimer();
void onPushTimer();
void cancel();
void cancelOthers(const std::shared_ptr<OutgoingTransaction> &transaction = std::shared_ptr<OutgoingTransaction>());
void decline(const std::shared_ptr<OutgoingTransaction> &transaction, std::shared_ptr<ResponseSipEvent> &ev);
void forward(const std::shared_ptr<ResponseSipEvent> &ev, bool force = false);
void store(std::shared_ptr<ResponseSipEvent> &ev);
void sendResponse(std::shared_ptr<ResponseSipEvent> ev, bool inject);
void onLateTimeout();
void cancelOthers(const std::shared_ptr<BranchInfo> &br);
void logResponse(const std::shared_ptr<ResponseSipEvent> &ev);
static void sOnShortTimer(su_root_magic_t *magic, su_timer_t *t, su_timer_arg_t *arg);
static void sOnPushTimer(su_root_magic_t *magic, su_timer_t *t, su_timer_arg_t *arg);
int mActivePushes;
static const int sUrgentCodesWithout603[];
};
#endif //forkcallcontext_hh
......@@ -21,6 +21,7 @@
using namespace ::std;
const int ForkContext::sUrgentCodes[]={401,407,415,420,484,488,606,603,0};
ForkContextConfig::ForkContextConfig() : mDeliveryTimeout(0),mUrgentTimeout(5),
mForkLate(false),mForkOneResponse(false), mForkNoGlobalDecline(false),
......@@ -28,49 +29,39 @@ ForkContextConfig::ForkContextConfig() : mDeliveryTimeout(0),mUrgentTimeout(5),
}
void ForkContext::__timer_callback(su_root_magic_t *magic, su_timer_t *t, su_timer_arg_t *arg){
(static_cast<ForkContext*>(arg))->onLateTimeout();
(static_cast<ForkContext*>(arg))->processLateTimeout();
}
ForkContext::ForkContext(Agent *agent, const std::shared_ptr<RequestSipEvent> &event, shared_ptr<ForkContextConfig> cfg, ForkContextListener* listener) :
mListener(listener),
mAgent(agent),
mEvent(make_shared<RequestSipEvent>(event)),
mIncoming(),
mOutgoings(),
mDestinationUris(),
mCfg(cfg),
mLateTimer(NULL),
mLateTimerExpired(false) {
su_home_init(&mHome);
init();
}
void ForkContext::checkFinished(){
bool finished=false;
if (!mIncoming && mOutgoings.empty()){
if (mLateTimer){
finished=mLateTimerExpired;
}else finished=true;
}
if (finished)
setFinished();
void ForkContext::onLateTimeout(){
}
void ForkContext::onLateTimeout(){
LOGD("ForkContext: late timer expired.");
shared_ptr<ForkContext> me(shared_from_this()); //this is to keep the object alive at least the time of the timer callback.
//Indeed sofia does not hold a refcount to the ForkContext. During checkFinished() the refcount my drop to zero, but we need to the object
//to be kept alive until checkFinished() returns.
void ForkContext::processLateTimeout() {
su_timer_destroy(mLateTimer);
mLateTimerExpired=true;
checkFinished();
onLateTimeout();
setFinished();
}
struct dest_finder{
dest_finder(const url_t *ctt) {
cttport = url_port(ctt);
ctthost = ctt->url_host;
// don't care about transport
}
bool operator()(const url_t *dest){
bool operator()(const shared_ptr<BranchInfo> &br){
const url_t *dest=br->mTransaction->getRequestUri();
return 0 == strcmp(url_port(dest), cttport)
&& 0 == strcmp(dest->url_host, ctthost);
}
......@@ -78,11 +69,81 @@ struct dest_finder{
const char *cttport;
};
struct uid_finder{
uid_finder(const std::string &uid) : mUid(uid){};
bool operator()(const shared_ptr<BranchInfo> &br){
return mUid==br->mUid;
}
const string mUid;
};
std::shared_ptr<BranchInfo> ForkContext::findBranchByUid(const std::string &uid){
auto it=find_if(mBranches.begin(),mBranches.end(),uid_finder(uid));
if (it!=mBranches.end()) return *it;
return shared_ptr<BranchInfo>();
}