diff --git a/resip/dum/MasterProfile.cxx b/resip/dum/MasterProfile.cxx index f4d3ad6baa..fda67c24cb 100644 --- a/resip/dum/MasterProfile.cxx +++ b/resip/dum/MasterProfile.cxx @@ -2,6 +2,7 @@ #include "resip/dum/Profile.hxx" #include "resip/dum/MasterProfile.hxx" #include "resip/stack/HeaderTypes.hxx" +#include "rutil/Logger.hxx" using namespace resip; #define RESIPROCATE_SUBSYSTEM Subsystem::DUM @@ -22,7 +23,8 @@ MasterProfile::MasterProfile() : mUasReliableProvisionalMode(Never), mServerRegistrationMinExpires(0), mServerRegistrationMaxExpires(UINT_MAX), - mServerRegistrationDefaultExpires(3600) + mServerRegistrationDefaultExpires(3600), + mAdditionalTransationTerminatingResponsesEnabled(false) { // Default settings addSupportedMimeType(INVITE, Mime("application", "sdp")); @@ -432,6 +434,40 @@ MasterProfile::clone() const return new MasterProfile(*this); } +bool& MasterProfile::additionalTransationTerminatingResponsesEnabled() +{ + return mAdditionalTransationTerminatingResponsesEnabled; +} + +bool MasterProfile::additionalTransationTerminatingResponsesEnabled() const +{ + return mAdditionalTransationTerminatingResponsesEnabled; +} + +void MasterProfile::addAdditionalTransationTerminatingResponses(int code) +{ + DebugLog(<< "MasterProfile::addAdditionalTransationTerminatingResponses" << "added code: " << code); + mAdditionalTransationTerminatingResponsess.insert(code); +} + +bool MasterProfile::isAdditionalTransationTerminatingResponse(int code) const +{ + bool isAllowed = (mAdditionalTransationTerminatingResponsess.end() != mAdditionalTransationTerminatingResponsess.find(code)); + + DebugLog(<< "MasterProfile::isAdditionalTransationTerminatingResponse" << "is code " << code << " allowed: " << isAllowed); + return isAllowed; +} + +const std::set& MasterProfile::getAdditionalTransationTerminatingResponses() const +{ + return mAdditionalTransationTerminatingResponsess; +} + +void MasterProfile::clearAdditionalTransationTerminatingResponses(void) +{ + mAdditionalTransationTerminatingResponsess.clear(); +} + /* ==================================================================== * The Vovida Software License, Version 1.0 * diff --git a/resip/dum/MasterProfile.hxx b/resip/dum/MasterProfile.hxx index 018aa6420f..49ad27827c 100644 --- a/resip/dum/MasterProfile.hxx +++ b/resip/dum/MasterProfile.hxx @@ -163,6 +163,29 @@ class MasterProfile : public UserProfile virtual bool& checkReqUriInMergeDetectionEnabled(); virtual bool checkReqUriInMergeDetectionEnabled() const; + /// Enabling this setting will allow the application layer to provide additional SIP responses, from class 4xx, 5xx, 6xx, + /// that will lead to transaction termination instead of other failure effects like dialog termination, as defined by + /// method Helper::determineFailureMessageEffect. (See header Helper.hxx for all transaction failure effects). + /// A scenarui when this is useful is when, for a server subscription, a NOTIFY is responded with an error response due to a timeout + /// condition, but the application needs the subscription to be continued. Even though RFC 3265 prescribes the + /// notifier should remove the subscription in such cases, timeouts may occur for transient conditions like a + /// overloaded proxy, a slow network connection, eventually nobody would benefit if the subscription is terminated by the server. + /// With this setting enabled the subscription will be continued, but only until the subscription expires. + /// Currently, it is only used by ServerSubscriptions. + /// Default is to not allow additional transaction terminating responses + /// To enable it: + /// 1. Set additionalTransationTerminatingResponsesEnabled() = true on master profile + /// 2. Call method addAdditionalTransationTerminatingResponses(code) to provide SIP responses for which the application + /// need the transaction to be terminated + virtual bool& additionalTransationTerminatingResponsesEnabled(); + virtual bool additionalTransationTerminatingResponsesEnabled() const; + + virtual void addAdditionalTransationTerminatingResponses(int code); + virtual bool isAdditionalTransationTerminatingResponse(int code) const; + + virtual const std::set& getAdditionalTransationTerminatingResponses() const; + virtual void clearAdditionalTransationTerminatingResponses(void); + private: virtual UserProfile* clone() const; std::set mSupportedSchemes; @@ -185,6 +208,9 @@ class MasterProfile : public UserProfile UInt32 mServerRegistrationMinExpires; UInt32 mServerRegistrationMaxExpires; UInt32 mServerRegistrationDefaultExpires; + + bool mAdditionalTransationTerminatingResponsesEnabled; + std::set mAdditionalTransationTerminatingResponsess; }; } diff --git a/resip/dum/ServerSubscription.cxx b/resip/dum/ServerSubscription.cxx index 49b29fd882..ddb072db57 100644 --- a/resip/dum/ServerSubscription.cxx +++ b/resip/dum/ServerSubscription.cxx @@ -4,6 +4,7 @@ #include "resip/dum/ServerSubscription.hxx" #include "resip/dum/SubscriptionHandler.hxx" #include "resip/dum/UsageUseException.hxx" +#include "resip/dum/MasterProfile.hxx" #include "resip/stack/Helper.hxx" #include "rutil/Logger.hxx" @@ -25,7 +26,8 @@ ServerSubscription::ServerSubscription(DialogUsageManager& dum, : BaseSubscription(dum, dialog, req), mSubscriber(req.header(h_From).uri().getAor()), mExpires(60), - mAbsoluteExpiry(0) + mAbsoluteExpiry(0), + mDeleteSubscription(true) { if (req.header(h_RequestLine).method() == REFER && req.header(h_To).exists(p_tag)) { @@ -89,6 +91,15 @@ ServerSubscription::reject(int statusCode) return mLastResponse; } +void ServerSubscription::terminateSubscription(ServerSubscriptionHandler* handler) +{ + if (mDeleteSubscription) + { + handler->onTerminated(getHandle()); + delete this; + } +} + void ServerSubscription::send(SharedPtr msg) @@ -119,8 +130,7 @@ ServerSubscription::send(SharedPtr msg) else if (code < 400) { DialogUsage::send(msg); - handler->onTerminated(getHandle()); - delete this; + terminateSubscription(handler); return; } else @@ -128,8 +138,7 @@ ServerSubscription::send(SharedPtr msg) if (shouldDestroyAfterSendingFailure(*msg)) { DialogUsage::send(msg); - handler->onTerminated(getHandle()); - delete this; + terminateSubscription(handler); return; } else @@ -143,8 +152,7 @@ ServerSubscription::send(SharedPtr msg) DialogUsage::send(msg); if (mSubscriptionState == Terminated) { - handler->onTerminated(getHandle()); - delete this; + terminateSubscription(handler); } } } @@ -245,6 +253,8 @@ ServerSubscription::dispatch(const SipMessage& msg) if (mSubscriptionState == Invalid) { mSubscriptionState = Terminated; + mDeleteSubscription = false; + if (mEventType != "refer" ) { handler->onNewSubscription(getHandle(), msg); @@ -253,11 +263,19 @@ ServerSubscription::dispatch(const SipMessage& msg) { handler->onNewSubscriptionFromRefer(getHandle(), msg); } + + mDeleteSubscription = true; + + if (mLastResponse->header(h_StatusLine).statusCode() >= 300) + { + send(mLastResponse); + return; + } } makeNotifyExpires(); handler->onExpiredByClient(getHandle(), msg, *mLastRequest); - + mDialog.makeResponse(*mLastResponse, mLastSubscribe, 200); mLastResponse->header(h_Expires).value() = mExpires; send(mLastResponse); @@ -305,12 +323,13 @@ ServerSubscription::dispatch(const SipMessage& msg) { //in dialog NOTIFY got redirected? Bizarre... handler->onError(getHandle(), msg); - handler->onTerminated(getHandle()); - delete this; + terminateSubscription(handler); } else { - switch(Helper::determineFailureMessageEffect(msg)) + switch(Helper::determineFailureMessageEffect(msg, + (mDum.getMasterProfile()->additionalTransationTerminatingResponsesEnabled()) ? + &mDum.getMasterProfile()->getAdditionalTransationTerminatingResponses() : NULL)) { case Helper::TransactionTermination: DebugLog( << "ServerSubscription::TransactionTermination: " << msg.brief()); @@ -323,8 +342,7 @@ ServerSubscription::dispatch(const SipMessage& msg) case Helper::DialogTermination: DebugLog( << "ServerSubscription::UsageTermination: " << msg.brief()); handler->onError(getHandle(), msg); - handler->onTerminated(getHandle()); - delete this; + terminateSubscription(handler); break; } } @@ -420,8 +438,7 @@ ServerSubscription::dialogDestroyed(const SipMessage& msg) ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType); assert(handler); handler->onError(getHandle(), msg); - handler->onTerminated(getHandle()); - delete this; + terminateSubscription(handler); } void @@ -448,7 +465,6 @@ ServerSubscription::dump(EncodeStream& strm) const return strm; } - /* ==================================================================== * The Vovida Software License, Version 1.0 * diff --git a/resip/dum/ServerSubscription.hxx b/resip/dum/ServerSubscription.hxx index c0860c0664..8292b8aa60 100644 --- a/resip/dum/ServerSubscription.hxx +++ b/resip/dum/ServerSubscription.hxx @@ -1,12 +1,14 @@ #if !defined(RESIP_SERVERSUBSCRIPTION_HXX) #define RESIP_SERVERSUBSCRIPTION_HXX +#include "resip/stack/Helper.hxx" #include "resip/dum/BaseSubscription.hxx" namespace resip { class DialogUsageManager; +class ServerSubscriptionHandler; //!dcm! -- no Subscription State expires parameter generation yet. class ServerSubscription : public BaseSubscription @@ -63,6 +65,8 @@ class ServerSubscription : public BaseSubscription bool shouldDestroyAfterSendingFailure(const SipMessage& msg); + void terminateSubscription(ServerSubscriptionHandler* handler); + Data mSubscriber; // const Contents* mCurrentEventDocument; @@ -74,6 +78,8 @@ class ServerSubscription : public BaseSubscription ServerSubscription(const ServerSubscription&); ServerSubscription& operator=(const ServerSubscription&); UInt64 mAbsoluteExpiry; + + bool mDeleteSubscription; }; } diff --git a/resip/stack/Helper.cxx b/resip/stack/Helper.cxx index cdc3064333..c34fc32efe 100644 --- a/resip/stack/Helper.cxx +++ b/resip/stack/Helper.cxx @@ -1995,12 +1995,19 @@ Helper::extractFromPkcs7(const SipMessage& message, } Helper::FailureMessageEffect -Helper::determineFailureMessageEffect(const SipMessage& response) +Helper::determineFailureMessageEffect(const SipMessage& response, + const std::set* additionalTransationTerminatingResponses) { assert(response.isResponse()); int code = response.header(h_StatusLine).statusCode(); assert(code >= 400); + if (additionalTransationTerminatingResponses && + (additionalTransationTerminatingResponses->end() != additionalTransationTerminatingResponses->find(code))) + { + return Helper::TransactionTermination; + } + switch(code) { case 404: diff --git a/resip/stack/Helper.hxx b/resip/stack/Helper.hxx index 2a3c7ac15b..cd695ddaf5 100644 --- a/resip/stack/Helper.hxx +++ b/resip/stack/Helper.hxx @@ -540,7 +540,8 @@ class Helper enum FailureMessageEffect{ DialogTermination, TransactionTermination, UsageTermination, RetryAfter, OptionalRetryAfter, ApplicationDependant }; - static FailureMessageEffect determineFailureMessageEffect(const SipMessage& response); + static FailureMessageEffect determineFailureMessageEffect(const SipMessage& response, + const std::set* additionalTransationTerminatingResponses = NULL); // Just simply walk the contents tree and return the first SdpContents in // the tree.