📄 dialogset.cxx
字号:
#include "resip/stack/Helper.hxx"#include "resip/dum/AppDialog.hxx"#include "resip/dum/AppDialogSet.hxx"#include "resip/dum/BaseCreator.hxx"#include "resip/dum/ClientAuthManager.hxx"#include "resip/dum/ClientOutOfDialogReq.hxx"#include "resip/dum/ClientPublication.hxx"#include "resip/dum/ClientRegistration.hxx"#include "resip/dum/ClientPagerMessage.hxx"#include "resip/dum/ServerPagerMessage.hxx"#include "resip/dum/Dialog.hxx"#include "resip/dum/DialogSet.hxx"#include "resip/dum/DialogSetHandler.hxx"#include "resip/dum/DialogUsageManager.hxx"#include "resip/dum/MasterProfile.hxx"#include "resip/dum/RedirectManager.hxx"#include "resip/dum/UsageUseException.hxx"#include "resip/dum/ServerOutOfDialogReq.hxx"#include "resip/dum/ServerRegistration.hxx"#include "resip/dum/DumHelper.hxx"#include "resip/dum/SubscriptionCreator.hxx"#include "rutil/Logger.hxx"#include "rutil/Inserter.hxx"#include "rutil/WinLeakCheck.hxx"#define RESIPROCATE_SUBSYSTEM Subsystem::DUMusing namespace resip;using namespace std;// UAC DialogSet::DialogSet(BaseCreator* creator, DialogUsageManager& dum) : mMergeKey(), mDialogs(), mCreator(creator), mId(*creator->getLastRequest()), mDum(dum), mAppDialogSet(0), mState(Initial), mClientRegistration(0), mServerRegistration(0), mClientPublication(0), mClientOutOfDialogRequests(), mServerOutOfDialogRequest(0), mClientPagerMessage(0), mServerPagerMessage(0){ setUserProfile(creator->getUserProfile()); assert(!creator->getLastRequest()->isExternal()); DebugLog ( << " ************* Created DialogSet(UAC) -- " << mId << "*************" );}// UAS DialogSet::DialogSet(const SipMessage& request, DialogUsageManager& dum) : mMergeKey(request, dum.getMasterProfile()->checkReqUriInMergeDetectionEnabled()), mDialogs(), mCreator(0), mId(request), mDum(dum), mAppDialogSet(0), mState(Established), mClientRegistration(0), mServerRegistration(0), mClientPublication(0), mClientOutOfDialogRequests(), mServerOutOfDialogRequest(0), mClientPagerMessage(0), mServerPagerMessage(0){ assert(request.isRequest()); assert(request.isExternal()); mDum.mMergedRequests.insert(mMergeKey); if (request.header(h_RequestLine).method() == INVITE) { if(mDum.mCancelMap.count(request.getTransactionId()) != 0) { WarningLog ( << "An endpoint is using the same tid in multiple INVITE requests, ability to match CANCEL requests correctly may be comprimised, tid=" << request.getTransactionId() ); } mCancelKey = request.getTransactionId(); mDum.mCancelMap[mCancelKey] = this; } DebugLog ( << " ************* Created DialogSet(UAS) -- " << mId << "*************" );}DialogSet::~DialogSet(){ if (mDum.mClientAuthManager.get()) { mDum.mClientAuthManager->dialogSetDestroyed(getId()); } if (mMergeKey != MergedRequestKey::Empty) { mDum.requestMergedRequestRemoval(mMergeKey); } if (!mCancelKey.empty()) { mDum.mCancelMap.erase(mCancelKey); } delete mCreator; while(!mDialogs.empty()) { delete mDialogs.begin()->second; } delete mClientRegistration; delete mServerRegistration; delete mClientPublication; delete mServerOutOfDialogRequest; delete mClientPagerMessage; delete mServerPagerMessage; while (!mClientOutOfDialogRequests.empty()) { delete *mClientOutOfDialogRequests.begin(); } DebugLog ( << " ********** DialogSet::~DialogSet: " << mId << "*************" ); //!dcm! -- very delicate code, change the order things go horribly wrong mDum.removeDialogSet(this->getId()); if (mAppDialogSet) { mAppDialogSet->destroy(); }}void DialogSet::possiblyDie(){ if(mState != Destroying && mDialogs.empty() && // The following check ensures we are not a UAC DialogSet in the Initial or // ReceivedProvisional states. // .slg. this check fixes a case where we might receive a short term usuage // request (such as OPTIONS) in the same dialogset as a UAC dialogset // for which we have not created any Dialogs yet - in this case // we don't want the dialogset to die, since the UAC usage is not complete. (mCreator == 0 || (mState != Initial && mState != ReceivedProvisional)) && mClientOutOfDialogRequests.empty() && !(mClientPublication || mServerOutOfDialogRequest || mClientPagerMessage || mServerPagerMessage || mClientRegistration || mServerRegistration)) { mState = Destroying; mDum.destroy(this); }}DialogSetIdDialogSet::getId() const{ return mId;}voidDialogSet::addDialog(Dialog *dialog){ mDialogs[dialog->getId()] = dialog;}BaseCreator*DialogSet::getCreator(){ return mCreator;}Dialog*DialogSet::findDialog(const SipMessage& msg){ if (msg.isResponse() && msg.header(h_StatusLine).statusCode() == 100) { return 0; } return findDialog(DialogId(msg));#if 0 DialogId id(msg); Dialog* dlog = findDialog(id); //vonage/2543 matching here if (dlog) { return dlog; } //match off transaction ID else if (msg.isResponse() && !msg.header(h_To).exists(p_tag)) { for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) { if (it->second->matches(msg)) { return it->second; } } } else if (msg.exists(h_Contacts) && !msg.header(h_Contacts).empty() && msg.isResponse() && mDum.getProfile()->looseToTagMatching() && msg.header(h_To).exists(p_tag)) { const Uri& contact = msg.header(h_Contacts).front().uri(); //match by contact for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) { if (it->second->mRemoteTarget.uri() == msg.header(h_Contacts).front().uri()) { //!dcm! in the vonage case, the to tag should be updated to match the fake //vonage tag introduced in the 200 which is also used for the BYE. //find out how deep this rabbit hole goes, may just have a pugabble //filter api that can be added for dialog matching if things get any //more specific--this is the VonageKludgeFilter Dialog* dialog = it->second; DialogId old = dialog->getId(); dialog->mId = DialogId(old.getCallId(), old.getLocalTag(), msg.header(h_To).param(p_tag)); dialog->mRemoteNameAddr.param(p_tag) = msg.header(h_To).param(p_tag); mDialogs.erase(it); mDialogs[dialog->getId()] = dialog; return dialog; } } } return 0;#endif}boolDialogSet::empty() const{ return mDialogs.empty();}boolDialogSet::handledByAuthOrRedirect(const SipMessage& msg){ if (msg.isResponse() && !(mState == Terminating || mState == WaitingToEnd || mState == Destroying)) { //!dcm! -- multiple usage grief...only one of each method type allowed if (getCreator() && msg.header(h_CSeq) == getCreator()->getLastRequest()->header(h_CSeq)) { if (mDum.mClientAuthManager.get()) { if (mDum.mClientAuthManager->handle(*getUserProfile().get(), *getCreator()->getLastRequest(), msg)) { // Note: ClientAuthManager->handle will end up incrementing the CSeq sequence of getLastRequest DebugLog( << "about to re-send request with digest credentials" ); StackLog( << getCreator()->getLastRequest() ); mDum.send(getCreator()->getLastRequest()); return true; } } //!dcm! -- need to protect against 3xx highjacking a dialogset which //has a fully established dialog. also could case strange behaviour //by sending 401/407 at the wrong time. if (mDum.mRedirectManager.get() && mState != Established) // !slg! for now don't handle redirect in established dialogs - alternatively we could treat as a target referesh (using 1st Contact) and reissue request { if (mDum.mRedirectManager->handle(*this, *getCreator()->getLastRequest(), msg)) { //terminating existing dialogs(branches) as this is a final //response--?dcm?--merge w/ forking logic somehow? //!dcm! -- really, really horrible. Should make a don't die //scoped guard mState = Initial; for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); ++it) { it->second->redirected(msg); } InfoLog( << "about to re-send request to redirect destination" ); DebugLog( << getCreator()->getLastRequest() ); mDum.send(getCreator()->getLastRequest()); return true; } // Check if a 422 response to initial Invite (RFC4028) if(msg.header(h_StatusLine).statusCode() == 422 && msg.exists(h_MinSE)) { // Change interval to min from 422 response getCreator()->getLastRequest()->header(h_SessionExpires).value() = msg.header(h_MinSE).value(); getCreator()->getLastRequest()->header(h_MinSE).value() = msg.header(h_MinSE).value(); getCreator()->getLastRequest()->header(h_CSeq).sequence()++; InfoLog( << "about to re-send request with new session expiration time" ); DebugLog( << getCreator()->getLastRequest() ); mDum.send(getCreator()->getLastRequest()); return true; } } } } return false;}voidDialogSet::dispatch(const SipMessage& msg){ if(!mAppDialogSet) { // !bwc! There are conditions where reuse of the AppDialogSet will cause // us to hit this code. This is because the teardown of DialogSets is not // atomic, causing the DialogSet to hang around for a short time after it // has given up its AppDialogSet. Also, if we have multiple Usages in // this DialogSet, one of the Usages may decide to re-establish itself in // a new Dialog, and take the AppDialogSet with it, leaving all the others // high and dry. This is a design issue that will take some real effort to // fix properly. This is a band-aid for now. // TODO fix this properly if(msg.isRequest()) { if(msg.method() != ACK) { SipMessage err; Helper::makeResponse(err, msg, 500, "DialogSet: My AppDialogSet is " "missing!"); mDum.sendResponse(err); } } else { ErrLog(<<"Response came in, but no AppDialogSet! Dropping this is very" "likely to cause leaks, but continuing to process it is " "likely to cause a core. Taking the lesser of two evils..."); } return; } assert(msg.isRequest() || msg.isResponse()); if (mState == WaitingToEnd) { assert(mDialogs.empty()); if (msg.isResponse()) { int code = msg.header(h_StatusLine).statusCode(); switch(mCreator->getLastRequest()->header(h_CSeq).method()) { case INVITE: if (code / 100 == 1) { mState = ReceivedProvisional; end(); } else if (code / 100 == 2) { Dialog dialog(mDum, msg, *this); SharedPtr<SipMessage> ack(new SipMessage); dialog.makeRequest(*ack, ACK); ack->header(h_CSeq).sequence() = msg.header(h_CSeq).sequence(); dialog.send(ack); SharedPtr<SipMessage> bye(new SipMessage); dialog.makeRequest(*bye, BYE); dialog.send(bye); // Note: Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -