- start upgrade to resiprocate 1.12

This commit is contained in:
Dmytro Bogovych 2021-12-27 11:02:19 +02:00
parent aeedeb0626
commit 0c4bf77a67
468 changed files with 37035 additions and 35842 deletions

View File

@ -58,7 +58,6 @@ set (STACK_SOURCES
resip/stack/DeprecatedDialog.cxx resip/stack/DeprecatedDialog.cxx
resip/stack/GenericUri.cxx resip/stack/GenericUri.cxx
resip/stack/GenericContents.cxx resip/stack/GenericContents.cxx
resip/stack/FloatParameter.cxx
resip/stack/ExternalBodyContents.cxx resip/stack/ExternalBodyContents.cxx
resip/stack/ExtensionParameter.cxx resip/stack/ExtensionParameter.cxx
resip/stack/ExtensionHeader.cxx resip/stack/ExtensionHeader.cxx
@ -68,13 +67,13 @@ set (STACK_SOURCES
resip/stack/EventStackThread.cxx resip/stack/EventStackThread.cxx
resip/stack/Embedded.cxx resip/stack/Embedded.cxx
resip/stack/DtlsMessage.cxx resip/stack/DtlsMessage.cxx
resip/stack/HeaderHash.cxx # resip/stack/HeaderHash.cxx
resip/stack/HeaderFieldValueList.cxx resip/stack/HeaderFieldValueList.cxx
resip/stack/HeaderFieldValue.cxx resip/stack/HeaderFieldValue.cxx
resip/stack/MsgHeaderScanner.cxx resip/stack/MsgHeaderScanner.cxx
resip/stack/Mime.cxx resip/stack/Mime.cxx
resip/stack/MethodTypes.cxx resip/stack/MethodTypes.cxx
resip/stack/MethodHash.cxx # resip/stack/MethodHash.cxx
resip/stack/MessageWaitingContents.cxx resip/stack/MessageWaitingContents.cxx
resip/stack/MessageFilterRule.cxx resip/stack/MessageFilterRule.cxx
resip/stack/Message.cxx resip/stack/Message.cxx
@ -89,7 +88,7 @@ set (STACK_SOURCES
resip/stack/Helper.cxx resip/stack/Helper.cxx
resip/stack/HeaderTypes.cxx resip/stack/HeaderTypes.cxx
resip/stack/Headers.cxx resip/stack/Headers.cxx
resip/stack/ParameterHash.cxx # resip/stack/ParameterHash.cxx
resip/stack/Parameter.cxx resip/stack/Parameter.cxx
resip/stack/OctetContents.cxx resip/stack/OctetContents.cxx
resip/stack/NonceHelper.cxx resip/stack/NonceHelper.cxx
@ -305,7 +304,6 @@ SET (RUTIL_SOURCES
rutil/KeyValueStore.cxx rutil/KeyValueStore.cxx
rutil/HeapInstanceCounter.cxx rutil/HeapInstanceCounter.cxx
rutil/GeneralCongestionManager.cxx rutil/GeneralCongestionManager.cxx
rutil/AtomicCounter.cxx
rutil/WinCompat.cxx rutil/WinCompat.cxx
) )

View File

@ -1,19 +0,0 @@
*.ncb
*.suo
.DS_Store
.make_prefs
Makefile.in
autom4te*.cache
autoscan.log
config.log
config.status
configure.scan
lib.debug.Linux.i686
lib.opt.Linux.i686
lib.prof.Linux.i686
libtool
resiprocate-old-junk
depcomp
install-sh
compile
proj

View File

@ -1,5 +1,5 @@
#include "resip/dum/Dialog.hxx"
#include "resip/dum/AppDialog.hxx" #include "resip/dum/AppDialog.hxx"
#include "resip/dum/Dialog.hxx"
using namespace resip; using namespace resip;
using namespace std; using namespace std;

View File

@ -86,7 +86,7 @@ AppDialogSet::getDialogSetId()
AppDialogSet* AppDialogSet*
AppDialogSet::reuse() AppDialogSet::reuse()
{ {
assert(mDialogSet); resip_assert(mDialogSet);
mDialogSet->appDissociate(); mDialogSet->appDissociate();
mDialogSet = 0; mDialogSet = 0;

View File

@ -1,5 +1,5 @@
#include "resip/dum/DialogUsageManager.hxx"
#include "resip/dum/AppDialogSetFactory.hxx" #include "resip/dum/AppDialogSetFactory.hxx"
#include "resip/dum/DialogUsageManager.hxx"
#include "resip/stack/SipMessage.hxx" #include "resip/stack/SipMessage.hxx"
#include "resip/dum/AppDialogSet.hxx" #include "resip/dum/AppDialogSet.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"

View File

@ -1,5 +1,5 @@
#include "rutil/Logger.hxx"
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "rutil/Logger.hxx"
#include "resip/dum/DialogUsageManager.hxx" #include "resip/dum/DialogUsageManager.hxx"
#include "resip/dum/MasterProfile.hxx" #include "resip/dum/MasterProfile.hxx"
#include "resip/dum/BaseCreator.hxx" #include "resip/dum/BaseCreator.hxx"
@ -43,7 +43,7 @@ BaseCreator::getUserProfile()
void void
BaseCreator::makeInitialRequest(const NameAddr& target, MethodTypes method) BaseCreator::makeInitialRequest(const NameAddr& target, MethodTypes method)
{ {
assert(mUserProfile.get()); resip_assert(mUserProfile.get());
makeInitialRequest(target, mUserProfile->getDefaultFrom(), method); makeInitialRequest(target, mUserProfile->getDefaultFrom(), method);
} }
@ -63,7 +63,7 @@ BaseCreator::makeInitialRequest(const NameAddr& target, const NameAddr& from, Me
mLastRequest->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize); mLastRequest->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
mLastRequest->header(h_CallId).value() = Helper::computeCallId(); mLastRequest->header(h_CallId).value() = Helper::computeCallId();
assert(mUserProfile.get()); resip_assert(mUserProfile.get());
if (!mUserProfile->getImsAuthUserName().empty()) if (!mUserProfile->getImsAuthUserName().empty())
{ {
Auth auth; Auth auth;
@ -137,33 +137,15 @@ BaseCreator::makeInitialRequest(const NameAddr& target, const NameAddr& from, Me
Via via; Via via;
mLastRequest->header(h_Vias).push_front(via); mLastRequest->header(h_Vias).push_front(via);
if(mUserProfile->isAdvertisedCapability(Headers::Allow)) // Add Advertised Capabilities to initial request
{ mDum.setAdvertisedCapabilities(*mLastRequest.get(), mUserProfile);
mLastRequest->header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
}
if(mUserProfile->isAdvertisedCapability(Headers::AcceptEncoding))
{
mLastRequest->header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
}
if(mUserProfile->isAdvertisedCapability(Headers::AcceptLanguage))
{
mLastRequest->header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
}
if(mUserProfile->isAdvertisedCapability(Headers::AllowEvents))
{
mLastRequest->header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
}
if(mUserProfile->isAdvertisedCapability(Headers::Supported))
{
mLastRequest->header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
}
// Merge Embedded parameters // Merge Embedded parameters
mLastRequest->mergeUri(target.uri()); mLastRequest->mergeUri(target.uri());
//DumHelper::setOutgoingEncryptionLevel(mLastRequest, mEncryptionLevel); //DumHelper::setOutgoingEncryptionLevel(mLastRequest, mEncryptionLevel);
DebugLog ( << "BaseCreator::makeInitialRequest: " << std::endl << std::endl << mLastRequest); DebugLog ( << "BaseCreator::makeInitialRequest: " << std::endl << std::endl << *mLastRequest);
} }

View File

@ -15,7 +15,6 @@ BaseSubscription::BaseSubscription(DialogUsageManager& dum, Dialog& dialog, cons
mSubscriptionId(Data::Empty), mSubscriptionId(Data::Empty),
mTimerSeq(0), mTimerSeq(0),
mSubscriptionState(Invalid) mSubscriptionState(Invalid)
{ {
if (request.exists(h_Event)) if (request.exists(h_Event))
{ {
@ -37,7 +36,7 @@ BaseSubscription::BaseSubscription(DialogUsageManager& dum, Dialog& dialog, cons
bool bool
BaseSubscription::matches(const SipMessage& msg) BaseSubscription::matches(const SipMessage& msg)
{ {
if (msg.isResponse() && msg.header(h_CSeq) == mLastRequest->header(h_CSeq)) if (msg.isResponse() && mLastRequest.get() != 0 && msg.header(h_CSeq) == mLastRequest->header(h_CSeq))
{ {
return true; return true;
} }
@ -48,7 +47,6 @@ BaseSubscription::matches(const SipMessage& msg)
return msg.header(h_Event).value() == mEventType return msg.header(h_Event).value() == mEventType
&& ( !msg.header(h_Event).exists(p_id) || && ( !msg.header(h_Event).exists(p_id) ||
msg.header(h_Event).param(p_id) == mSubscriptionId); msg.header(h_Event).param(p_id) == mSubscriptionId);
} }
else else
{ {
@ -58,7 +56,6 @@ BaseSubscription::matches(const SipMessage& msg)
} }
} }
BaseSubscription::~BaseSubscription() BaseSubscription::~BaseSubscription()
{ {
} }

View File

@ -38,6 +38,11 @@ BaseUsage::getBaseHandle()
return mHandle; return mHandle;
} }
void BaseUsage::postDum(Message* messageForDum)
{
mDum.post(messageForDum);
}
#if 0 #if 0
EncodeStream& EncodeStream&
BaseUsage::dump(EncodeStream& strm) const BaseUsage::dump(EncodeStream& strm) const

View File

@ -8,11 +8,12 @@
namespace resip namespace resip
{ {
class DialogUsageManager;
class Dialog; class Dialog;
class DialogUsageManager;
class DumTimeout; class DumTimeout;
class SipMessage; class Message;
class NameAddr; class NameAddr;
class SipMessage;
class BaseUsage : public Handled class BaseUsage : public Handled
{ {
@ -24,6 +25,9 @@ class BaseUsage : public Handled
virtual const char* name() const; virtual const char* name() const;
}; };
/// @brief posts a message on dum
virtual void postDum(Message* messageForDum);
virtual void end()=0; virtual void end()=0;
virtual EncodeStream& dump(EncodeStream& strm) const=0; virtual EncodeStream& dump(EncodeStream& strm) const=0;

View File

@ -1,5 +1,5 @@
#include <cassert> #include "rutil/ResipAssert.h"
#include "resip/dum/ChallengeInfo.hxx" #include "resip/dum/ChallengeInfo.hxx"
#include "rutil/Data.hxx" #include "rutil/Data.hxx"
@ -49,7 +49,7 @@ ChallengeInfo::brief() const
resip::Message* resip::Message*
ChallengeInfo::clone() const ChallengeInfo::clone() const
{ {
assert(false); return NULL; resip_assert(false); return NULL;
} }
std::ostream& std::ostream&

View File

@ -2,12 +2,12 @@
using namespace resip; using namespace resip;
std::unique_ptr<ClientAuthExtension> ClientAuthExtension::mInstance = std::unique_ptr<ClientAuthExtension>(new ClientAuthExtension()); std::auto_ptr<ClientAuthExtension> ClientAuthExtension::mInstance = std::auto_ptr<ClientAuthExtension>(new ClientAuthExtension());
void void
ClientAuthExtension::setInstance(std::unique_ptr<ClientAuthExtension> ext) ClientAuthExtension::setInstance(std::auto_ptr<ClientAuthExtension> ext)
{ {
mInstance = std::move(ext); mInstance = ext;
} }
@ -21,7 +21,7 @@ ClientAuthExtension::makeChallengeResponseAuth(const SipMessage& request,
const Data& nonceCountString, const Data& nonceCountString,
Auth& auth) Auth& auth)
{ {
assert(0); resip_assert(0);
} }
void void
@ -34,7 +34,7 @@ ClientAuthExtension::makeChallengeResponseAuthWithA1(const SipMessage& request,
const Data& nonceCountString, const Data& nonceCountString,
Auth& auth) Auth& auth)
{ {
assert(0); resip_assert(0);
} }

View File

@ -45,7 +45,7 @@ class ClientAuthExtension
virtual bool algorithmAndQopSupported(const Auth& challenge); virtual bool algorithmAndQopSupported(const Auth& challenge);
static void setInstance(std::unique_ptr<ClientAuthExtension> ext); static void setInstance(std::auto_ptr<ClientAuthExtension> ext);
static ClientAuthExtension& instance() static ClientAuthExtension& instance()
{ {
return *mInstance; return *mInstance;
@ -54,7 +54,7 @@ class ClientAuthExtension
ClientAuthExtension() {} ClientAuthExtension() {}
static std::unique_ptr<ClientAuthExtension> mInstance; static std::auto_ptr<ClientAuthExtension> mInstance;
}; };

View File

@ -1,4 +1,4 @@
#include <cassert> #include "rutil/ResipAssert.h"
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "resip/stack/SipMessage.hxx" #include "resip/stack/SipMessage.hxx"
@ -100,18 +100,18 @@ private:
Data mNonceCountString; Data mNonceCountString;
}; };
ClientAuthManager::ClientAuthManager() ClientAuthManager::ClientAuthManager()
{ {
} }
bool bool
ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, const SipMessage& response) ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, const SipMessage& response)
{ {
try try
{ {
assert( response.isResponse() ); resip_assert( response.isResponse() );
assert( origRequest.isRequest() ); resip_assert( origRequest.isRequest() );
DialogSetId id(origRequest); DialogSetId id(origRequest);
@ -133,6 +133,7 @@ ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, con
return false; return false;
} }
// 401 or 407...
if (!(response.exists(h_WWWAuthenticates) || response.exists(h_ProxyAuthenticates))) if (!(response.exists(h_WWWAuthenticates) || response.exists(h_ProxyAuthenticates)))
{ {
DebugLog (<< "Invalid challenge for " << id << ", nothing to respond to; fail"); DebugLog (<< "Invalid challenge for " << id << ", nothing to respond to; fail");
@ -145,7 +146,7 @@ ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, con
// AuthState associated with this DialogSet if the algorithm is supported // AuthState associated with this DialogSet if the algorithm is supported
if (authState.handleChallenge(userProfile, response)) if (authState.handleChallenge(userProfile, response))
{ {
assert(origRequest.header(h_Vias).size() == 1); resip_assert(origRequest.header(h_Vias).size() == 1);
origRequest.header(h_CSeq).sequence()++; origRequest.header(h_CSeq).sequence()++;
DebugLog (<< "Produced response to digest challenge for " << userProfile ); DebugLog (<< "Produced response to digest challenge for " << userProfile );
return true; return true;
@ -157,7 +158,7 @@ ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, con
} }
catch(BaseException& e) catch(BaseException& e)
{ {
assert(0); resip_assert(0);
ErrLog(<< "Unexpected exception in ClientAuthManager::handle " << e); ErrLog(<< "Unexpected exception in ClientAuthManager::handle " << e);
return false; return false;
} }
@ -176,15 +177,26 @@ ClientAuthManager::addAuthentication(SipMessage& request)
void void
ClientAuthManager::clearAuthenticationState(const DialogSetId& dsId) ClientAuthManager::clearAuthenticationState(const DialogSetId& dsId)
{ {
dialogSetDestroyed(dsId); AttemptedAuthMap::iterator it = mAttemptedAuths.find(dsId);
if (it != mAttemptedAuths.end())
{
mAttemptedAuths.erase(it);
}
}
void
ClientAuthManager::dialogSetDestroyed(const DialogSetId& id)
{
clearAuthenticationState(id);
} }
ClientAuthManager::AuthState::AuthState() : ClientAuthManager::AuthState::AuthState() :
mFailed(false) mFailed(false),
mCacheUseLimit(0),
mCacheUseCount(0)
{ {
} }
bool bool
ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const SipMessage& challenge) ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const SipMessage& challenge)
{ {
@ -192,11 +204,11 @@ ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const Si
{ {
return false; return false;
} }
bool handled = true; bool handled = true;
if (challenge.exists(h_WWWAuthenticates)) if (challenge.exists(h_WWWAuthenticates))
{ {
for (Auths::const_iterator i = challenge.header(h_WWWAuthenticates).begin(); for (Auths::const_iterator i = challenge.header(h_WWWAuthenticates).begin();
i != challenge.header(h_WWWAuthenticates).end(); ++i) i != challenge.header(h_WWWAuthenticates).end(); ++i)
{ {
if (i->exists(p_realm)) if (i->exists(p_realm))
{ {
@ -214,8 +226,8 @@ ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const Si
} }
if (challenge.exists(h_ProxyAuthenticates)) if (challenge.exists(h_ProxyAuthenticates))
{ {
for (Auths::const_iterator i = challenge.header(h_ProxyAuthenticates).begin(); for(Auths::const_iterator i = challenge.header(h_ProxyAuthenticates).begin();
i != challenge.header(h_ProxyAuthenticates).end(); ++i) i != challenge.header(h_ProxyAuthenticates).end(); ++i)
{ {
if (i->exists(p_realm)) if (i->exists(p_realm))
{ {
@ -225,16 +237,20 @@ ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const Si
break; break;
} }
} }
else else
{ {
return false; return false;
} }
}
if(!handled)
{
InfoLog( << "ClientAuthManager::AuthState::handleChallenge failed for: " << challenge);
} }
} }
if(!handled)
{
InfoLog( << "ClientAuthManager::AuthState::handleChallenge failed for: " << challenge);
}
else
{
mCacheUseLimit = userProfile.getDigestCacheUseLimit();
}
return handled; return handled;
} }
@ -245,6 +261,13 @@ ClientAuthManager::AuthState::authSucceeded()
{ {
i->second.authSucceeded(); i->second.authSucceeded();
} }
mCacheUseCount++;
if(mCacheUseLimit != 0 && mCacheUseCount >= mCacheUseLimit)
{
// Cache use limit reached - clear auth state
mRealms.clear();
mCacheUseCount = 0;
}
} }
void void
@ -265,8 +288,7 @@ ClientAuthManager::AuthState::addAuthentication(SipMessage& request)
ClientAuthManager::RealmState::RealmState() : ClientAuthManager::RealmState::RealmState() :
mIsProxyCredential(false), mIsProxyCredential(false),
mState(Invalid), mState(Invalid),
mNonceCount(0), mNonceCount(0)
mAuthPtr(NULL)
{ {
} }
@ -298,7 +320,7 @@ ClientAuthManager::RealmState::authSucceeded()
switch(mState) switch(mState)
{ {
case Invalid: case Invalid:
assert(0); resip_assert(0);
break; break;
case Current: case Current:
case Cached: case Cached:
@ -306,7 +328,7 @@ ClientAuthManager::RealmState::authSucceeded()
transition(Cached); transition(Cached);
break; break;
case Failed: case Failed:
assert(0); resip_assert(0);
break; break;
}; };
} }
@ -388,11 +410,11 @@ ClientAuthManager::RealmState::findCredential(UserProfile& userProfile, const Au
const Data& realm = auth.param(p_realm); const Data& realm = auth.param(p_realm);
//!dcm! -- icky, expose static empty soon...ptr instead of reference? //!dcm! -- icky, expose static empty soon...ptr instead of reference?
mCredential = userProfile.getDigestCredential(realm); mCredential = userProfile.getDigestCredential(realm);
if ( mCredential.realm.empty() ) if (mCredential.realm.empty())
{ {
DebugLog( << "Got a 401 or 407 but could not find credentials for realm: " << realm); DebugLog( << "Got a 401 or 407 but could not find credentials for realm: " << realm);
// DebugLog (<< auth); // DebugLog (<< auth);
// DebugLog (<< response); // DebugLog (<< response);
return false; return false;
} }
return true; return true;
@ -401,7 +423,7 @@ ClientAuthManager::RealmState::findCredential(UserProfile& userProfile, const Au
void void
ClientAuthManager::RealmState::addAuthentication(SipMessage& request) ClientAuthManager::RealmState::addAuthentication(SipMessage& request)
{ {
assert(mState != Failed); resip_assert(mState != Failed);
if (mState == Failed) return; if (mState == Failed) return;
Data nonceCountString; Data nonceCountString;
@ -413,16 +435,8 @@ ClientAuthManager::RealmState::addAuthentication(SipMessage& request)
// Add client auth decorator so that we ensure any body hashes are calcuated after user defined outbound decorators that // Add client auth decorator so that we ensure any body hashes are calcuated after user defined outbound decorators that
// may be modifying the message body // may be modifying the message body
std::unique_ptr<MessageDecorator> clientAuthDecorator(new ClientAuthDecorator(mIsProxyCredential, mAuth, mCredential, authQop, nonceCountString)); std::auto_ptr<MessageDecorator> clientAuthDecorator(new ClientAuthDecorator(mIsProxyCredential, mAuth, mCredential, authQop, nonceCountString));
request.addOutboundDecorator(std::move(clientAuthDecorator)); request.addOutboundDecorator(clientAuthDecorator);
}
void ClientAuthManager::dialogSetDestroyed(const DialogSetId& id)
{
if ( mAttemptedAuths.find(id) != mAttemptedAuths.end())
{
mAttemptedAuths.erase(id);
}
} }
// bool // bool
@ -443,7 +457,6 @@ void ClientAuthManager::dialogSetDestroyed(const DialogSetId& id)
// } // }
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0
* *

View File

@ -42,7 +42,6 @@ class ClientAuthManager
// bool operator()(const Auth& lhs, const Auth& rhs) const; // bool operator()(const Auth& lhs, const Auth& rhs) const;
// }; // };
class RealmState class RealmState
{ {
public: public:
@ -74,13 +73,10 @@ class ClientAuthManager
unsigned int mNonceCount; unsigned int mNonceCount;
Auth mAuth; Auth mAuth;
// FH add the realm state so it can change // .dcm. only one credential per realm per challenge supported
Auth *mAuthPtr; // typedef std::map<Auth, UserProfile::DigestCredential, CompareAuth > CredentialMap;
// CredentialMap proxyCredentials;
// .dcm. only one credential per realm per challenge supported // CredentialMap wwwCredentials;
// typedef std::map<Auth, UserProfile::DigestCredential, CompareAuth > CredentialMap;
// CredentialMap proxyCredentials;
// CredentialMap wwwCredentials;
}; };
class AuthState class AuthState
@ -95,6 +91,8 @@ class ClientAuthManager
typedef std::map<Data, RealmState> RealmStates; typedef std::map<Data, RealmState> RealmStates;
RealmStates mRealms; RealmStates mRealms;
bool mFailed; bool mFailed;
unsigned long mCacheUseLimit;
unsigned long mCacheUseCount;
}; };
typedef std::map<DialogSetId, AuthState> AttemptedAuthMap; typedef std::map<DialogSetId, AuthState> AttemptedAuthMap;

View File

@ -1,5 +1,6 @@
#include "resip/stack/Contents.hxx" #include "resip/stack/Contents.hxx"
#include "resip/dum/BaseCreator.hxx"
#include "resip/dum/ClientInviteSession.hxx" #include "resip/dum/ClientInviteSession.hxx"
#include "resip/dum/Dialog.hxx" #include "resip/dum/Dialog.hxx"
#include "resip/dum/DialogEventStateManager.hxx" #include "resip/dum/DialogEventStateManager.hxx"
@ -31,12 +32,13 @@ ClientInviteSession::ClientInviteSession(DialogUsageManager& dum,
InviteSession(dum, dialog), InviteSession(dum, dialog),
mStaleCallTimerSeq(1), mStaleCallTimerSeq(1),
mCancelledTimerSeq(1), mCancelledTimerSeq(1),
mServerSub(serverSub) mServerSub(serverSub),
mAllowOfferInPrack(false)
{ {
assert(request->isRequest()); resip_assert(request->isRequest());
if(initialOffer) if(initialOffer)
{ {
mProposedLocalOfferAnswer = unique_ptr<Contents>(initialOffer->clone()); mProposedLocalOfferAnswer = auto_ptr<Contents>(initialOffer->clone());
mProposedEncryptionLevel = level; mProposedEncryptionLevel = level;
} }
*mLastLocalSessionModification = *request; // Copy message, so that modifications to mLastLocalSessionModification don't effect creator->getLastRequest *mLastLocalSessionModification = *request; // Copy message, so that modifications to mLastLocalSessionModification don't effect creator->getLastRequest
@ -64,22 +66,32 @@ ClientInviteSession::provideOffer(const Contents& offer, DialogUsageManager::Enc
switch(mState) switch(mState)
{ {
case UAC_EarlyWithAnswer: case UAC_EarlyWithAnswer:
{ if(mAllowOfferInPrack)
transition(UAC_SentUpdateEarly); {
// This flag is enabled when we are about to send our first PRACK. We are
// allowed to send an offer in our first PRACK request, so don't use UPDATE in
// this case.
// Remember proposed local offferAnswer.
mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
mProposedEncryptionLevel = level;
}
else
{
transition(UAC_SentUpdateEarly);
// Creates an UPDATE request with application supplied offer. // Creates an UPDATE request with application supplied offer.
mDialog.makeRequest(*mLastLocalSessionModification, UPDATE); mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
InviteSession::setOfferAnswer(*mLastLocalSessionModification, offer); InviteSession::setOfferAnswer(*mLastLocalSessionModification, offer);
// Remember proposed local offferAnswer. // Remember proposed local offferAnswer.
mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative); mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
mProposedEncryptionLevel = level; mProposedEncryptionLevel = level;
// Send the req and do state transition. // Send the req and do state transition.
DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel); DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
send(mLastLocalSessionModification); send(mLastLocalSessionModification);
}
break; break;
}
case UAC_SentAnswer: case UAC_SentAnswer:
// just queue it for later // just queue it for later
@ -97,7 +109,8 @@ ClientInviteSession::provideOffer(const Contents& offer, DialogUsageManager::Enc
case UAC_Cancelled: case UAC_Cancelled:
case UAC_QueuedUpdate: case UAC_QueuedUpdate:
case Terminated: case Terminated:
assert(0); WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
break; break;
default: default:
@ -124,11 +137,11 @@ ClientInviteSession::provideAnswer (const Contents& answer)
transition(UAC_SentAnswer); transition(UAC_SentAnswer);
// Remember proposed local offerAnswer. // Remember proposed local offerAnswer.
mCurrentRemoteOfferAnswer = std::move(mProposedRemoteOfferAnswer); mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer); mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
// Creates an PRACK request with application supplied offer. // Creates a PRACK request with application supplied answer
sendPrack(answer); sendPrack(answer, mCurrentEncryptionLevel);
break; break;
} }
@ -137,9 +150,8 @@ ClientInviteSession::provideAnswer (const Contents& answer)
transition(Connected); transition(Connected);
sendAck(&answer); sendAck(&answer);
mCurrentRemoteOfferAnswer = std::move(mProposedRemoteOfferAnswer); mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer); mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
// mLastSessionModification = ack; // ?slg? is this needed?
break; break;
} }
case UAC_ReceivedUpdateEarly: case UAC_ReceivedUpdateEarly:
@ -154,7 +166,7 @@ ClientInviteSession::provideAnswer (const Contents& answer)
mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200); mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
InviteSession::setOfferAnswer(*response, answer, 0); InviteSession::setOfferAnswer(*response, answer, 0);
mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer); mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
mCurrentRemoteOfferAnswer = std::move(mProposedRemoteOfferAnswer); mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
InfoLog (<< "Sending " << response->brief()); InfoLog (<< "Sending " << response->brief());
DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel); DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
send(response); send(response);
@ -169,7 +181,8 @@ ClientInviteSession::provideAnswer (const Contents& answer)
case UAC_Cancelled: case UAC_Cancelled:
case UAC_QueuedUpdate: case UAC_QueuedUpdate:
case Terminated: case Terminated:
assert(0); WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
break; break;
default: default:
@ -220,7 +233,7 @@ ClientInviteSession::end(EndReason reason)
case UAC_Start: case UAC_Start:
WarningLog (<< "Try to end when in state=" << toData(mState)); WarningLog (<< "Try to end when in state=" << toData(mState));
assert(0); resip_assert(0);
break; break;
case Terminated: case Terminated:
@ -255,7 +268,8 @@ ClientInviteSession::reject (int statusCode, WarningCategory *warning)
break; break;
} }
case UAC_Answered:{ case UAC_Answered:
{
// We received an offer in a 2xx response, and we want to reject it // We received an offer in a 2xx response, and we want to reject it
// ACK with no body, then send bye // ACK with no body, then send bye
sendAck(); sendAck();
@ -273,7 +287,7 @@ ClientInviteSession::reject (int statusCode, WarningCategory *warning)
case UAC_SentAnswer: case UAC_SentAnswer:
case UAC_Cancelled: case UAC_Cancelled:
WarningLog (<< "Try to reject when in state=" << toData(mState)); WarningLog (<< "Try to reject when in state=" << toData(mState));
assert(0); resip_assert(0);
break; break;
default: default:
@ -304,7 +318,7 @@ ClientInviteSession::cancel()
break; break;
default: default:
assert(0); resip_assert(0);
break; break;
} }
} }
@ -344,7 +358,6 @@ ClientInviteSession::startStaleCallTimer()
{ {
InfoLog (<< toData(mState) << ": startStaleCallTimer"); InfoLog (<< toData(mState) << ": startStaleCallTimer");
unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleCallTime(); unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleCallTime();
when += Random::getRandom() % 120;
mDum.addTimer(DumTimeout::StaleCall, mDum.addTimer(DumTimeout::StaleCall,
when, when,
@ -405,7 +418,7 @@ ClientInviteSession::dispatch(const SipMessage& msg)
} }
} }
if (checkRseq(msg)) if (isBadRseq(msg))
{ {
return; return;
} }
@ -529,15 +542,16 @@ ClientInviteSession::handleRedirect (const SipMessage& msg)
void void
ClientInviteSession::handleProvisional(const SipMessage& msg) ClientInviteSession::handleProvisional(const SipMessage& msg)
{ {
assert(msg.isResponse()); resip_assert(msg.isResponse());
assert(msg.header(h_StatusLine).statusCode() < 200); resip_assert(msg.header(h_StatusLine).statusCode() < 200);
assert(msg.header(h_StatusLine).statusCode() > 100); resip_assert(msg.header(h_StatusLine).statusCode() > 100);
//.dcm. Kept the following checks here rather than discardMessage as the //.dcm. Kept the following checks here rather than discardMessage as the
// state machine can be affected(termination). // state machine can be affected(termination).
// !dcm! should we really end the InviteSession or should be discard the 1xx instead? // !dcm! should we really end the InviteSession or should be discard the 1xx instead?
if (msg.header(h_CSeq).sequence() != mLastLocalSessionModification->header(h_CSeq).sequence()) // Check CSeq in 1xx against original INVITE request
if (msg.header(h_CSeq).sequence() != mDialog.mDialogSet.getCreator()->getLastRequest()->header(h_CSeq).sequence())
{ {
InfoLog (<< "Failure: CSeq doesn't match invite: " << msg.brief()); InfoLog (<< "Failure: CSeq doesn't match invite: " << msg.brief());
onFailureAspect(getHandle(), msg); onFailureAspect(getHandle(), msg);
@ -562,9 +576,9 @@ ClientInviteSession::handleProvisional(const SipMessage& msg)
void void
ClientInviteSession::handleFinalResponse(const SipMessage& msg) ClientInviteSession::handleFinalResponse(const SipMessage& msg)
{ {
assert(msg.isResponse()); resip_assert(msg.isResponse());
assert(msg.header(h_StatusLine).statusCode() >= 200); resip_assert(msg.header(h_StatusLine).statusCode() >= 200);
assert(msg.header(h_StatusLine).statusCode() < 300); resip_assert(msg.header(h_StatusLine).statusCode() < 300);
handleSessionTimerResponse(msg); handleSessionTimerResponse(msg);
storePeerCapabilities(msg); storePeerCapabilities(msg);
@ -572,7 +586,7 @@ ClientInviteSession::handleFinalResponse(const SipMessage& msg)
} }
void void
ClientInviteSession::handleOffer (const SipMessage& msg, const Contents& offer) ClientInviteSession::handle1xxOffer(const SipMessage& msg, const Contents& offer)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
@ -583,27 +597,44 @@ ClientInviteSession::handleOffer (const SipMessage& msg, const Contents& offer)
} }
void void
ClientInviteSession::handleAnswer(const SipMessage& msg, const Contents& answer) ClientInviteSession::handle1xxAnswer(const SipMessage& msg, const Contents& answer)
{ {
//mCurrentLocalOfferAnswer = mProposedLocalOfferAnswer;
setCurrentLocalOfferAnswer(msg); setCurrentLocalOfferAnswer(msg);
mCurrentEncryptionLevel = getEncryptionLevel(msg); mCurrentEncryptionLevel = getEncryptionLevel(msg);
mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(answer); mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(answer);
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
handleProvisional(msg); handleProvisional(msg);
// flag to let handle1xxAnswer know that it is OK to send an offer in the
// first PRACK (for a provisional with SDP answer) and to let providerOffer know
// that the offer will be going in an PRACK and not in an update. Flag is not
// needed after handle1xxAnswer is called so it is reset.
mAllowOfferInPrack = true;
handler->onAnswer(getSessionHandle(), msg, answer); handler->onAnswer(getSessionHandle(), msg, answer);
sendPrackIfNeeded(msg); // Reset flag - no longer needed
mAllowOfferInPrack = false;
// If offer is provided in onAnswer callback then send offer in PRACK
if(mProposedLocalOfferAnswer.get())
{
sendPrack(*mProposedLocalOfferAnswer.get(), mProposedEncryptionLevel);
}
else
{
sendPrackIfNeeded(msg);
}
} }
// will not include SDP (this is a subsequent 1xx) // will not include SDP (this is a subsequent 1xx)
void void
ClientInviteSession::sendPrackIfNeeded(const SipMessage& msg) ClientInviteSession::sendPrackIfNeeded(const SipMessage& msg)
{ {
assert(msg.isResponse()); resip_assert(msg.isResponse());
assert(msg.header(h_StatusLine).statusCode() < 200); resip_assert(msg.header(h_StatusLine).statusCode() < 200);
assert(msg.header(h_StatusLine).statusCode() > 100); resip_assert(msg.header(h_StatusLine).statusCode() > 100);
if (isReliable(msg)) if (isReliable(msg))
{ {
@ -614,11 +645,12 @@ ClientInviteSession::sendPrackIfNeeded(const SipMessage& msg)
} }
} }
// This version is used to send an answer to the UAS in PRACK // This version is used to send an answer to the UAS in PRACK from EarlyWithOffer
// from EarlyWithOffer state. Assumes that it is the first PRACK. Subsequent // state. Assumes that it is the first PRACK. Subsequent PRACK will not have SDP
// PRACK will not have SDP // Also used to send an offer in the first PRACK if the 18x included an
// answer.
void void
ClientInviteSession::sendPrack(const Contents& offerAnswer) ClientInviteSession::sendPrack(const Contents& offerAnswer, DialogUsageManager::EncryptionLevel encryptionLevel)
{ {
SharedPtr<SipMessage> prack(new SipMessage); SharedPtr<SipMessage> prack(new SipMessage);
mDialog.makeRequest(*prack, PRACK); mDialog.makeRequest(*prack, PRACK);
@ -626,44 +658,19 @@ ClientInviteSession::sendPrack(const Contents& offerAnswer)
InviteSession::setOfferAnswer(*prack, offerAnswer); InviteSession::setOfferAnswer(*prack, offerAnswer);
// Remember last session modification. DumHelper::setOutgoingEncryptionLevel(*prack, encryptionLevel);
// mLastSessionModification = prack; // ?slg? is this needed?
DumHelper::setOutgoingEncryptionLevel(*prack, mCurrentEncryptionLevel);
send(prack); send(prack);
} }
/*
bool
ClientInviteSession::isNextProvisional(const SipMessage& msg)
{
}
bool
ClientInviteSession::isRetransmission(const SipMessage& msg)
{
if ( mLastReceivedRSeq == 0 ||
msg.header(h_RSeq).value() <= mLastReceivedRSeq)
{
return false;
}
else
{
return true;
}
}
*/
void void
ClientInviteSession::dispatchStart (const SipMessage& msg) ClientInviteSession::dispatchStart (const SipMessage& msg)
{ {
assert(msg.isResponse()); resip_assert(msg.isResponse());
assert(msg.header(h_StatusLine).statusCode() > 100); resip_assert(msg.header(h_StatusLine).statusCode() > 100);
assert(msg.header(h_CSeq).method() == INVITE); resip_assert(msg.header(h_CSeq).method() == INVITE);
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
InviteSession::Event event = toEvent(msg, offerAnswer.get()); InviteSession::Event event = toEvent(msg, offerAnswer.get());
@ -675,12 +682,12 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
if(!isTerminated()) if(!isTerminated())
{ {
handleProvisional(msg); handleProvisional(msg);
sendPrackIfNeeded(msg); //may wish to move emprty PRACK handling sendPrackIfNeeded(msg); // may wish to move emprty PRACK handling
//outside the state machine // outside the state machine
} }
break; break;
case On1xxEarly: case On1xxEarly: // only unreliable
//!dcm! according to draft-ietf-sipping-offeranswer there can be a non //!dcm! according to draft-ietf-sipping-offeranswer there can be a non
// reliable 1xx followed by a reliable 1xx. Also, the intial 1xx // reliable 1xx followed by a reliable 1xx. Also, the intial 1xx
// doesn't have to have an offer. However, DUM will only generate // doesn't have to have an offer. However, DUM will only generate
@ -704,7 +711,7 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
handler->onNewSession(getHandle(), InviteSession::Offer, msg); handler->onNewSession(getHandle(), InviteSession::Offer, msg);
if(!isTerminated()) if(!isTerminated())
{ {
handleOffer(msg, *offerAnswer); handle1xxOffer(msg, *offerAnswer);
} }
break; break;
@ -713,7 +720,7 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
handler->onNewSession(getHandle(), InviteSession::Answer, msg); handler->onNewSession(getHandle(), InviteSession::Answer, msg);
if(!isTerminated()) if(!isTerminated())
{ {
handleAnswer(msg, *offerAnswer); handle1xxAnswer(msg, *offerAnswer);
} }
break; break;
@ -722,7 +729,7 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
handleFinalResponse(msg); handleFinalResponse(msg);
mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer); mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
handler->onNewSession(getHandle(), InviteSession::Offer, msg); handler->onNewSession(getHandle(), InviteSession::Offer, msg);
assert(mProposedLocalOfferAnswer.get() == 0); resip_assert(mProposedLocalOfferAnswer.get() == 0);
mCurrentEncryptionLevel = getEncryptionLevel(msg); mCurrentEncryptionLevel = getEncryptionLevel(msg);
if(!isTerminated()) if(!isTerminated())
{ {
@ -738,7 +745,6 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
transition(Connected); transition(Connected);
sendAck(); sendAck();
handleFinalResponse(msg); handleFinalResponse(msg);
//mCurrentLocalOfferAnswer = mProposedLocalOfferAnswer;
setCurrentLocalOfferAnswer(msg); setCurrentLocalOfferAnswer(msg);
mCurrentEncryptionLevel = getEncryptionLevel(msg); mCurrentEncryptionLevel = getEncryptionLevel(msg);
mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer); mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
@ -793,13 +799,14 @@ void
ClientInviteSession::dispatchEarly (const SipMessage& msg) ClientInviteSession::dispatchEarly (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
case On1xx: case On1xx:
transition(UAC_Early); transition(UAC_Early);
handleProvisional(msg); handleProvisional(msg);
sendPrackIfNeeded(msg);
break; break;
case On1xxEarly: // only unreliable case On1xxEarly: // only unreliable
@ -814,19 +821,19 @@ ClientInviteSession::dispatchEarly (const SipMessage& msg)
case On1xxOffer: case On1xxOffer:
transition(UAC_EarlyWithOffer); transition(UAC_EarlyWithOffer);
handleOffer(msg, *offerAnswer); handle1xxOffer(msg, *offerAnswer);
break; break;
case On1xxAnswer: case On1xxAnswer:
transition(UAC_EarlyWithAnswer); transition(UAC_EarlyWithAnswer);
handleAnswer(msg, *offerAnswer); handle1xxAnswer(msg, *offerAnswer);
break; break;
case On2xxOffer: case On2xxOffer:
transition(UAC_Answered); transition(UAC_Answered);
handleFinalResponse(msg); handleFinalResponse(msg);
assert(mProposedLocalOfferAnswer.get() == 0); resip_assert(mProposedLocalOfferAnswer.get() == 0);
mCurrentEncryptionLevel = getEncryptionLevel(msg); mCurrentEncryptionLevel = getEncryptionLevel(msg);
mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer); mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
@ -841,7 +848,6 @@ ClientInviteSession::dispatchEarly (const SipMessage& msg)
transition(Connected); transition(Connected);
sendAck(); sendAck();
handleFinalResponse(msg); handleFinalResponse(msg);
//mCurrentLocalOfferAnswer = mProposedLocalOfferAnswer;
setCurrentLocalOfferAnswer(msg); setCurrentLocalOfferAnswer(msg);
mCurrentEncryptionLevel = getEncryptionLevel(msg); mCurrentEncryptionLevel = getEncryptionLevel(msg);
mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer); mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
@ -902,11 +908,13 @@ ClientInviteSession::dispatchEarly (const SipMessage& msg)
{ {
// ?slg? no offerAnswer in update - just respond immediately - do we need a callback? // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
SharedPtr<SipMessage> response(new SipMessage); SharedPtr<SipMessage> response(new SipMessage);
*mLastRemoteSessionModification = msg;
mDialog.makeResponse(*response, msg, 200); mDialog.makeResponse(*response, msg, 200);
send(response); send(response);
break; break;
} }
case On200Prack:
break;
default: default:
// !kh! // !kh!
@ -920,7 +928,7 @@ void
ClientInviteSession::dispatchAnswered (const SipMessage& msg) ClientInviteSession::dispatchAnswered (const SipMessage& msg)
{ {
//InviteSessionHandler* handler = mDum.mInviteSessionHandler; //InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
@ -972,7 +980,7 @@ void
ClientInviteSession::dispatchEarlyWithOffer (const SipMessage& msg) ClientInviteSession::dispatchEarlyWithOffer (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
@ -1022,7 +1030,6 @@ ClientInviteSession::dispatchEarlyWithOffer (const SipMessage& msg)
{ {
// ?slg? no offerAnswer in update - just respond immediately - do we need a callback? // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
SharedPtr<SipMessage> response(new SipMessage); SharedPtr<SipMessage> response(new SipMessage);
*mLastRemoteSessionModification = msg;
mDialog.makeResponse(*response, msg, 200); mDialog.makeResponse(*response, msg, 200);
send(response); send(response);
break; break;
@ -1040,7 +1047,7 @@ void
ClientInviteSession::dispatchSentAnswer (const SipMessage& msg) ClientInviteSession::dispatchSentAnswer (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
@ -1055,18 +1062,29 @@ ClientInviteSession::dispatchSentAnswer (const SipMessage& msg)
onConnectedAspect(getHandle(), msg); onConnectedAspect(getHandle(), msg);
break; break;
case On2xxAnswer:
case On2xxOffer: case On2xxOffer:
// RFC6337 section 3.1.2 recommends we ignore any illegal SDP here to be more interoperable
WarningLog(<< "Ignoring illegal SDP offer in 2xx: " << msg.brief());
transition(Connected);
sendAck();
handleFinalResponse(msg);
onConnectedAspect(getHandle(), msg);
break;
case On2xxAnswer:
case On1xxAnswer: case On1xxAnswer:
case On1xxOffer:
sendAck(); sendAck();
sendBye(); sendBye();
InfoLog (<< "Failure: illegal offer/answer: " << msg.brief()); WarningLog(<< "Failure: illegal offer/answer: " << msg.brief());
transition(Terminated); transition(Terminated);
onFailureAspect(getHandle(), msg); onFailureAspect(getHandle(), msg);
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg); handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
break; break;
case On1xxOffer:
// RFC6337 section 3.1.2 recommends we ignore any illegal SDP here to be more interoperable
WarningLog(<< "Ignoring illegal SDP offer in 1xx: " << msg.brief());
// No break is itentional
case On1xx: case On1xx:
handleProvisional(msg); handleProvisional(msg);
sendPrackIfNeeded(msg); sendPrackIfNeeded(msg);
@ -1101,7 +1119,7 @@ void
ClientInviteSession::dispatchQueuedUpdate (const SipMessage& msg) ClientInviteSession::dispatchQueuedUpdate (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
@ -1131,18 +1149,29 @@ ClientInviteSession::dispatchQueuedUpdate (const SipMessage& msg)
onConnectedAspect(getHandle(), msg); onConnectedAspect(getHandle(), msg);
break; break;
case On2xxAnswer:
case On2xxOffer: case On2xxOffer:
// RFC6337 section 3.1.2 recommends we ignore any illegal SDP here to be more interoperable
WarningLog(<< "Ignoring illegal SDP offer in 2xx: " << msg.brief());
transition(Connected);
sendAck();
handleFinalResponse(msg);
onConnectedAspect(getHandle(), msg);
break;
case On2xxAnswer:
case On1xxAnswer: case On1xxAnswer:
case On1xxOffer:
sendAck(); sendAck();
sendBye(); sendBye();
InfoLog (<< "Failure: illegal offer/answer: " << msg.brief()); WarningLog(<< "Failure: illegal offer/answer: " << msg.brief());
transition(Terminated); transition(Terminated);
onFailureAspect(getHandle(), msg); onFailureAspect(getHandle(), msg);
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg); handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
break; break;
case On1xxOffer:
// RFC6337 section 3.1.2 recommends we ignore any illegal SDP here to be more interoperable
WarningLog(<< "Ignoring illegal SDP offer in 1xx: " << msg.brief());
// No break is itentional
case On1xx: case On1xx:
handleProvisional(msg); handleProvisional(msg);
sendPrackIfNeeded(msg); sendPrackIfNeeded(msg);
@ -1179,21 +1208,19 @@ void
ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg) ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
case On1xxOffer:
// RFC6337 section 3.1.1 recommends we ignore any illegal SDP here to be more interoperable
WarningLog(<< "Ignoring illegal SDP offer in 1xx: " << msg.brief());
// No break is itentional
case On1xx: case On1xx:
handleProvisional(msg); handleProvisional(msg);
sendPrackIfNeeded(msg); sendPrackIfNeeded(msg);
break; break;
case On1xxOffer:
if(!isTerminated())
{
transition(UAC_EarlyWithOffer);
handleOffer(msg, *offerAnswer);
}
break;
case On2xx: case On2xx:
transition(Connected); transition(Connected);
sendAck(); sendAck();
@ -1201,11 +1228,19 @@ ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
onConnectedAspect(getHandle(), msg); onConnectedAspect(getHandle(), msg);
break; break;
case On2xxAnswer:
case On2xxOffer: case On2xxOffer:
// RFC6337 section 3.1.1 recommends we ignore any illegal SDP here to be more interoperable
WarningLog(<< "Ignoring illegal SDP offer in 2xx: " << msg.brief());
transition(Connected);
sendAck();
handleFinalResponse(msg);
onConnectedAspect(getHandle(), msg);
break;
case On2xxAnswer:
sendAck(); sendAck();
sendBye(); sendBye();
InfoLog (<< "Failure: illegal offer/answer: " << msg.brief()); WarningLog(<< "Failure: illegal offer/answer: " << msg.brief());
transition(Terminated); transition(Terminated);
onFailureAspect(getHandle(), msg); onFailureAspect(getHandle(), msg);
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg); handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
@ -1223,7 +1258,6 @@ ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
{ {
// ?slg? no offerAnswer in update - just respond immediately - do we need a callback? // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
SharedPtr<SipMessage> response(new SipMessage); SharedPtr<SipMessage> response(new SipMessage);
*mLastRemoteSessionModification = msg;
mDialog.makeResponse(*response, msg, 200); mDialog.makeResponse(*response, msg, 200);
send(response); send(response);
break; break;
@ -1246,6 +1280,18 @@ ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
dispatchBye(msg); dispatchBye(msg);
break; break;
case On200Prack:
// We may have sent a PRACK with an offer (if provideOffer was called from onAnswer
// from the first reliable provisional) - if so this will have SDP we need to call onAnswer
if(offerAnswer.get() && mProposedLocalOfferAnswer.get())
{
setCurrentLocalOfferAnswer(msg);
mCurrentEncryptionLevel = getEncryptionLevel(msg);
mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
}
break;
default: default:
// !kh! // !kh!
// should not assert here for peer sent us garbage. // should not assert here for peer sent us garbage.
@ -1258,7 +1304,7 @@ void
ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg) ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
@ -1282,7 +1328,6 @@ ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg)
{ {
// ?slg? no offerAnswer in update - just respond immediately - do we need a callback? // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
SharedPtr<SipMessage> response(new SipMessage); SharedPtr<SipMessage> response(new SipMessage);
*mLastRemoteSessionModification = msg;
mDialog.makeResponse(*response, msg, 200); mDialog.makeResponse(*response, msg, 200);
send(response); send(response);
break; break;
@ -1312,6 +1357,9 @@ ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg)
mDum.destroy(this); mDum.destroy(this);
break; break;
case On200Prack:
break;
default: default:
WarningLog (<< "Don't know what this is : " << msg); WarningLog (<< "Don't know what this is : " << msg);
break; break;
@ -1322,7 +1370,7 @@ void
ClientInviteSession::dispatchSentUpdateEarlyGlare (const SipMessage& msg) ClientInviteSession::dispatchSentUpdateEarlyGlare (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
@ -1360,21 +1408,28 @@ ClientInviteSession::dispatchSentUpdateEarlyGlare (const SipMessage& msg)
} }
void void
ClientInviteSession::dispatchReceivedUpdateEarly (const SipMessage& msg) ClientInviteSession::dispatchReceivedUpdateEarly(const SipMessage& msg)
{ {
/* std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
case OnUpdate:
case OnUpdateOffer:
// If we receive an UPDATE before we have generated a final response to a previous UPDATE on the
// same dialog, then we MUST return a 500 response with a Retry-After header (random duration 0-10 seconds)
{
SharedPtr<SipMessage> u500(new SipMessage);
mDialog.makeResponse(*u500, msg, 500);
u500->header(h_RetryAfter).value() = Random::getRandom() % 10;
send(u500);
}
break;
default: default:
// !kh!
// should not assert here for peer sent us garbage.
WarningLog (<< "Don't know what this is : " << msg); WarningLog (<< "Don't know what this is : " << msg);
break; break;
} }
*/
WarningLog (<< "Ignoring message received in ReceivedUpdateEarly: " << msg); WarningLog (<< "Ignoring message received in ReceivedUpdateEarly: " << msg);
} }
@ -1382,7 +1437,7 @@ void
ClientInviteSession::dispatchCancelled (const SipMessage& msg) ClientInviteSession::dispatchCancelled (const SipMessage& msg)
{ {
InviteSessionHandler* handler = mDum.mInviteSessionHandler; InviteSessionHandler* handler = mDum.mInviteSessionHandler;
std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg); std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
switch (toEvent(msg, offerAnswer.get())) switch (toEvent(msg, offerAnswer.get()))
{ {
@ -1422,7 +1477,7 @@ ClientInviteSession::dispatchCancelled (const SipMessage& msg)
//true if 180rel should be ignored. Saves rseq as a side effect. //true if 180rel should be ignored. Saves rseq as a side effect.
bool bool
ClientInviteSession::checkRseq(const SipMessage& msg) ClientInviteSession::isBadRseq(const SipMessage& msg)
{ {
int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0; int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
if (msg.method() == INVITE && code > 100 && code < 200) if (msg.method() == INVITE && code > 100 && code < 200)

View File

@ -64,10 +64,10 @@ class ClientInviteSession : public InviteSession
void handleRedirect (const SipMessage& msg); void handleRedirect (const SipMessage& msg);
void handleProvisional (const SipMessage& msg); void handleProvisional (const SipMessage& msg);
void handleFinalResponse (const SipMessage& msg); void handleFinalResponse (const SipMessage& msg);
void handleOffer (const SipMessage& msg, const Contents& offer); void handle1xxOffer (const SipMessage& msg, const Contents& offer);
void handleAnswer (const SipMessage& msg, const Contents& answer); void handle1xxAnswer (const SipMessage& msg, const Contents& answer);
void sendPrackIfNeeded(const SipMessage& msg); void sendPrackIfNeeded(const SipMessage& msg);
void sendPrack(const Contents& offerAnswer); void sendPrack(const Contents& offerAnswer, DialogUsageManager::EncryptionLevel encryptionLevel);
// Called by the DialogSet (friend) when the app has CANCELed the request // Called by the DialogSet (friend) when the app has CANCELed the request
void cancel(); void cancel();
@ -75,7 +75,7 @@ class ClientInviteSession : public InviteSession
// Called by the DialogSet when it receives a 2xx response // Called by the DialogSet when it receives a 2xx response
void onForkAccepted(); void onForkAccepted();
bool checkRseq(const SipMessage& msg); bool isBadRseq(const SipMessage& msg);
private: private:
void startCancelTimer(); void startCancelTimer();
void startStaleCallTimer(); void startStaleCallTimer();
@ -85,12 +85,13 @@ class ClientInviteSession : public InviteSession
void onProvisionalAspect(ClientInviteSessionHandle c, const SipMessage& msg); void onProvisionalAspect(ClientInviteSessionHandle c, const SipMessage& msg);
void onFailureAspect(ClientInviteSessionHandle c, const SipMessage& msg); void onFailureAspect(ClientInviteSessionHandle c, const SipMessage& msg);
std::unique_ptr<Contents> mEarlyMedia; std::auto_ptr<Contents> mEarlyMedia;
RAckCategory mRelRespInfo; RAckCategory mRelRespInfo;
unsigned int mStaleCallTimerSeq; unsigned int mStaleCallTimerSeq;
unsigned int mCancelledTimerSeq; unsigned int mCancelledTimerSeq;
ServerSubscriptionHandle mServerSub; ServerSubscriptionHandle mServerSub;
bool mAllowOfferInPrack;
// disabled // disabled
ClientInviteSession(const ClientInviteSession&); ClientInviteSession(const ClientInviteSession&);

View File

@ -38,7 +38,7 @@ ClientOutOfDialogReq::end()
void void
ClientOutOfDialogReq::dispatch(const SipMessage& msg) ClientOutOfDialogReq::dispatch(const SipMessage& msg)
{ {
assert(msg.isResponse()); resip_assert(msg.isResponse());
if (msg.header(h_StatusLine).statusCode() >= 200) if (msg.header(h_StatusLine).statusCode() >= 200)
{ {

View File

@ -113,10 +113,9 @@ ClientPagerMessage::getMessageRequest()
} }
void void
ClientPagerMessage::page(std::unique_ptr<Contents> contents, ClientPagerMessage::page(std::auto_ptr<Contents> contents, DialogUsageManager::EncryptionLevel level)
DialogUsageManager::EncryptionLevel level)
{ {
assert(contents.get() != 0); resip_assert(contents.get() != 0);
bool do_page = mMsgQueue.empty(); bool do_page = mMsgQueue.empty();
Item item; Item item;
item.contents = contents.release(); item.contents = contents.release();
@ -124,89 +123,129 @@ ClientPagerMessage::page(std::unique_ptr<Contents> contents,
mMsgQueue.push_back(item); mMsgQueue.push_back(item);
if(do_page) if(do_page)
{ {
this->pageFirstMsgQueued(); pageFirstMsgQueued();
} }
} }
class ClientPagerMessagePageCommand : public DumCommandAdapter class ClientPagerMessagePageCommand : public DumCommandAdapter
{ {
public: public:
ClientPagerMessagePageCommand(ClientPagerMessage& clientPagerMessage, ClientPagerMessagePageCommand(const ClientPagerMessageHandle& clientPagerMessageHandle,
std::unique_ptr<Contents> contents, std::auto_ptr<Contents> contents,
DialogUsageManager::EncryptionLevel level) DialogUsageManager::EncryptionLevel level)
: mClientPagerMessage(clientPagerMessage), : mClientPagerMessageHandle(clientPagerMessageHandle),
mContents(std::move(contents)), mContents(contents),
mLevel(level) mLevel(level)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientPagerMessage.page(std::move(mContents), mLevel); if(mClientPagerMessageHandle.isValid())
{
mClientPagerMessageHandle->page(mContents, mLevel);
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
{ {
return strm << "ClientPagerMessagePageCommand"; return strm << "ClientPagerMessagePageCommand";
} }
private: private:
ClientPagerMessage& mClientPagerMessage; ClientPagerMessageHandle mClientPagerMessageHandle;
std::unique_ptr<Contents> mContents; std::auto_ptr<Contents> mContents;
DialogUsageManager::EncryptionLevel mLevel; DialogUsageManager::EncryptionLevel mLevel;
}; };
void void
ClientPagerMessage::pageCommand(std::unique_ptr<Contents> contents, ClientPagerMessage::pageCommand(std::auto_ptr<Contents> contents,
DialogUsageManager::EncryptionLevel level) DialogUsageManager::EncryptionLevel level)
{ {
mDum.post(new ClientPagerMessagePageCommand(*this, std::move(contents), level)); mDum.post(new ClientPagerMessagePageCommand(getHandle(), contents, level));
}
// Use this API if the application has ongoing pending messages and it is using
// getMessageRequest to modify the target routing information for messsages (ie:
// requestUri or Route headers). This will cause the current pending message to
// be re-sent immediately using the new information that the application just set.
// Any onSuccess or onFailure callbacks that might result from the active pending
// message at the time this is called will be supressed. Any messages queued
// behind that message will be dispatched sequentially to the new target.
void
ClientPagerMessage::newTargetInfoSet()
{
if (mMsgQueue.empty() == false)
{
// Note: calling this will cause mRequest->header(h_CSeq) to get a new value
// and the responses to the currently pending MESSAGE will be ignored
pageFirstMsgQueued();
}
} }
void void
ClientPagerMessage::dispatch(const SipMessage& msg) ClientPagerMessage::dispatch(const SipMessage& msg)
{ {
assert(msg.isResponse()); resip_assert(msg.isResponse());
ClientPagerMessageHandler* handler = mDum.mClientPagerMessageHandler; ClientPagerMessageHandler* handler = mDum.mClientPagerMessageHandler;
assert(handler); resip_assert(handler);
int code = msg.header(h_StatusLine).statusCode(); int code = msg.header(h_StatusLine).statusCode();
DebugLog ( << "ClientPagerMessageReq::dispatch(msg)" << msg.brief() ); DebugLog ( << "ClientPagerMessageReq::dispatch(msg)" << msg.brief());
{ {
assert(mMsgQueue.empty() == false);
if (code < 200) if (code < 200)
{ {
DebugLog ( << "ClientPagerMessageReq::dispatch - encountered provisional response" << msg.brief() ); DebugLog ( << "ClientPagerMessageReq::dispatch - encountered provisional response" << msg.brief() );
} }
else if (code < 300) else if (code < 300)
{ {
if(mMsgQueue.empty() == false) // if cseq doesn't match last message paged then someone must have called newTargetInfoSet
{ // we want to supress the onSuccess callback and logic, since we re-sent this first queued
delete mMsgQueue.front().contents; // item to a new target
mMsgQueue.pop_front(); if (msg.header(h_CSeq).sequence() == mRequest->header(h_CSeq).sequence())
if(mMsgQueue.empty() == false) {
{ if (mMsgQueue.empty() == false)
this->pageFirstMsgQueued(); {
} delete mMsgQueue.front().contents;
mMsgQueue.pop_front();
handler->onSuccess(getHandle(), msg); if (mMsgQueue.empty() == false)
} {
this->pageFirstMsgQueued();
}
}
handler->onSuccess(getHandle(), msg);
}
} }
else else
{ {
SipMessage errResponse; // if cseq doesn't match last message paged then someone must have called newTargetInfoSet
MsgQueue::iterator contents; // we want to supress the onFailure callback and logic, since we re-sent this first queued
for(contents = mMsgQueue.begin(); contents != mMsgQueue.end(); ++contents) // item to a new target
{ if (msg.header(h_CSeq).sequence() == mRequest->header(h_CSeq).sequence())
Contents* p = contents->contents; {
WarningLog ( << "Paging failed " << *p ); if (!mMsgQueue.empty())
Helper::makeResponse(errResponse, *mRequest, code); {
handler->onFailure(getHandle(), errResponse, std::unique_ptr<Contents>(p)); // if cseq doesn't match first queued element - someone must have called newTargetInfoSet
contents->contents = 0; // we want to supress the onFailure callback and logic, since we re-sent this first queued item to a new target
} SipMessage errResponse;
mMsgQueue.clear(); MsgQueue::iterator contents;
for (contents = mMsgQueue.begin(); contents != mMsgQueue.end(); ++contents)
{
Contents* p = contents->contents;
WarningLog(<< "Paging failed " << *p);
Helper::makeResponse(errResponse, *mRequest, code);
handler->onFailure(getHandle(), errResponse, std::auto_ptr<Contents>(p));
contents->contents = 0;
}
mMsgQueue.clear();
}
else
{
handler->onFailure(getHandle(), msg, std::auto_ptr<Contents>(mRequest->releaseContents()));
}
}
} }
} }
} }
@ -254,15 +293,15 @@ ClientPagerMessage::endCommand()
} }
size_t size_t
ClientPagerMessage::msgQueued () const ClientPagerMessage::msgQueued() const
{ {
return mMsgQueue.size(); return mMsgQueue.size();
} }
void void
ClientPagerMessage::pageFirstMsgQueued () ClientPagerMessage::pageFirstMsgQueued()
{ {
assert(mMsgQueue.empty() == false); resip_assert(mMsgQueue.empty() == false);
mRequest->header(h_CSeq).sequence()++; mRequest->header(h_CSeq).sequence()++;
mRequest->setContents(mMsgQueue.front().contents); mRequest->setContents(mMsgQueue.front().contents);
DumHelper::setOutgoingEncryptionLevel(*mRequest, mMsgQueue.front().encryptionLevel); DumHelper::setOutgoingEncryptionLevel(*mRequest, mMsgQueue.front().encryptionLevel);
@ -271,7 +310,7 @@ ClientPagerMessage::pageFirstMsgQueued ()
} }
void void
ClientPagerMessage::clearMsgQueued () ClientPagerMessage::clearMsgQueued()
{ {
MsgQueue::iterator contents; MsgQueue::iterator contents;
for(contents = mMsgQueue.begin(); contents != mMsgQueue.end(); ++contents) for(contents = mMsgQueue.begin(); contents != mMsgQueue.end(); ++contents)

View File

@ -23,24 +23,34 @@ class ClientPagerMessage : public NonDialogUsage
//I don't know how this would interact with the queuing mechanism. //I don't know how this would interact with the queuing mechanism.
//Will come back to re-visit this in the future. //Will come back to re-visit this in the future.
SipMessage& getMessageRequest(); SipMessage& getMessageRequest();
SharedPtr<SipMessage> getMessageRequestSharedPtr() { return mRequest; }
//!kh! //!kh!
//queues the message if there is one sent but not yet received a response //queues the message if there is one sent but not yet received a response
//for it. //for it.
//asserts if contents->get() is NULL. //asserts if contents->get() is NULL.
virtual void page(std::unique_ptr<Contents> contents, DialogUsageManager::EncryptionLevel level=DialogUsageManager::None); virtual void page(std::auto_ptr<Contents> contents, DialogUsageManager::EncryptionLevel level=DialogUsageManager::None);
virtual void end(); virtual void end();
// Use this API if the application has ongoing pending messages and it is using
// getMessageRequest to modify the target routing information for messages (ie:
// requestUri or Route headers). This will cause the current pending message to
// be re-sent immediately using the new information that the application just set.
// Any onSuccess or onFailure callbacks that might result from the active pending
// message at the time this is called will be suppressed. Any messages queued
// behind that message will be dispatched sequentially to the new target.
void newTargetInfoSet();
/** /**
* Provide asynchronous method access by using command * Provide asynchronous method access by using command
*/ */
virtual void endCommand(); virtual void endCommand();
virtual void pageCommand(std::unique_ptr<Contents> contents, DialogUsageManager::EncryptionLevel level=DialogUsageManager::None); virtual void pageCommand(std::auto_ptr<Contents> contents, DialogUsageManager::EncryptionLevel level=DialogUsageManager::None);
virtual void dispatch(const SipMessage& msg); virtual void dispatch(const SipMessage& msg);
virtual void dispatch(const DumTimeout& timer); virtual void dispatch(const DumTimeout& timer);
size_t msgQueued () const; size_t msgQueued() const;
virtual EncodeStream& dump(EncodeStream& strm) const; virtual EncodeStream& dump(EncodeStream& strm) const;
@ -68,8 +78,8 @@ class ClientPagerMessage : public NonDialogUsage
ClientPagerMessage(const ClientPagerMessage&); ClientPagerMessage(const ClientPagerMessage&);
ClientPagerMessage& operator=(const ClientPagerMessage&); ClientPagerMessage& operator=(const ClientPagerMessage&);
void pageFirstMsgQueued (); void pageFirstMsgQueued();
void clearMsgQueued (); void clearMsgQueued();
}; };
} }

View File

@ -1,4 +1,4 @@
#include <cassert> #include "rutil/ResipAssert.h"
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "resip/stack/SipMessage.hxx" #include "resip/stack/SipMessage.hxx"
@ -24,8 +24,10 @@ ClientPublication::ClientPublication(DialogUsageManager& dum,
DialogSet& dialogSet, DialogSet& dialogSet,
SharedPtr<SipMessage> req) SharedPtr<SipMessage> req)
: NonDialogUsage(dum, dialogSet), : NonDialogUsage(dum, dialogSet),
mPublished(false),
mWaitingForResponse(false), mWaitingForResponse(false),
mPendingPublish(false), mPendingPublish(false),
mPendingEnd(false),
mPublish(req), mPublish(req),
mEventType(req->header(h_Event).value()), mEventType(req->header(h_Event).value()),
mTimerSeq(0), mTimerSeq(0),
@ -50,14 +52,28 @@ ClientPublication::end()
void void
ClientPublication::end(bool immediate) ClientPublication::end(bool immediate)
{ {
InfoLog (<< "End client publication to " << mPublish->header(h_RequestLine).uri()); if (immediate)
if(!immediate)
{ {
InfoLog(<< "End client publication immediately to " << mPublish->header(h_RequestLine).uri());
delete this;
return;
}
if (mWaitingForResponse)
{
InfoLog(<< "Waiting for response, pending End of client publication to " << mPublish->header(h_RequestLine).uri());
mPendingEnd = true;
return;
}
if (mPublished)
{
InfoLog(<< "End client publication to " << mPublish->header(h_RequestLine).uri());
mPublish->header(h_Expires).value() = 0; mPublish->header(h_Expires).value() = 0;
mPublish->releaseContents();
send(mPublish); send(mPublish);
} }
else else
{ {
InfoLog(<< "End client publication immediately (not published) to " << mPublish->header(h_RequestLine).uri());
delete this; delete this;
} }
} }
@ -65,15 +81,17 @@ ClientPublication::end(bool immediate)
class ClientPublicationEndCommand : public DumCommandAdapter class ClientPublicationEndCommand : public DumCommandAdapter
{ {
public: public:
ClientPublicationEndCommand(ClientPublication& clientPublication, bool immediate) ClientPublicationEndCommand(const ClientPublicationHandle& clientPublicationHandle, bool immediate)
: mClientPublication(clientPublication), mImmediate(immediate) : mClientPublicationHandle(clientPublicationHandle), mImmediate(immediate)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientPublication.end(mImmediate); if(mClientPublicationHandle.isValid())
{
mClientPublicationHandle->end(mImmediate);
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -81,21 +99,21 @@ public:
return strm << "ClientPublicationEndCommand"; return strm << "ClientPublicationEndCommand";
} }
private: private:
ClientPublication& mClientPublication; ClientPublicationHandle mClientPublicationHandle;
bool mImmediate; bool mImmediate;
}; };
void void
ClientPublication::endCommand(bool immediate) ClientPublication::endCommand(bool immediate)
{ {
mDum.post(new ClientPublicationEndCommand(*this, immediate)); mDum.post(new ClientPublicationEndCommand(getHandle(), immediate));
} }
void void
ClientPublication::dispatch(const SipMessage& msg) ClientPublication::dispatch(const SipMessage& msg)
{ {
ClientPublicationHandler* handler = mDum.getClientPublicationHandler(mEventType); ClientPublicationHandler* handler = mDum.getClientPublicationHandler(mEventType);
assert(handler); resip_assert(handler);
if (msg.isRequest()) if (msg.isRequest())
{ {
@ -109,11 +127,12 @@ ClientPublication::dispatch(const SipMessage& msg)
return; return;
} }
assert(code >= 200); resip_assert(code >= 200);
mWaitingForResponse = false; mWaitingForResponse = false;
if (code < 300) if (code < 300)
{ {
mPublished = true;
if (mPublish->exists(h_Expires) && mPublish->header(h_Expires).value() == 0) if (mPublish->exists(h_Expires) && mPublish->header(h_Expires).value() == 0)
{ {
handler->onRemove(getHandle(), msg); handler->onRemove(getHandle(), msg);
@ -125,7 +144,7 @@ ClientPublication::dispatch(const SipMessage& msg)
mPublish->header(h_SIPIfMatch) = msg.header(h_SIPETag); mPublish->header(h_SIPIfMatch) = msg.header(h_SIPETag);
if(!mPendingPublish) if(!mPendingPublish)
{ {
mPublish->releaseContents(); mPublish->releaseContents();
} }
mDum.addTimer(DumTimeout::Publication, mDum.addTimer(DumTimeout::Publication,
Helper::aBitSmallerThan(msg.header(h_Expires).value()), Helper::aBitSmallerThan(msg.header(h_Expires).value()),
@ -167,7 +186,7 @@ ClientPublication::dispatch(const SipMessage& msg)
} }
} }
else if (code == 408 || else if (code == 408 ||
(code == 503 && msg.getReceivedTransport() == 0) || (code == 503 && !msg.isFromWire()) ||
((code == 404 || ((code == 404 ||
code == 413 || code == 413 ||
code == 480 || code == 480 ||
@ -208,7 +227,6 @@ ClientPublication::dispatch(const SipMessage& msg)
getBaseHandle(), getBaseHandle(),
++mTimerSeq); ++mTimerSeq);
return; return;
} }
} }
else else
@ -217,10 +235,26 @@ ClientPublication::dispatch(const SipMessage& msg)
delete this; delete this;
return; return;
} }
} }
if (mPendingPublish) if (mPendingEnd)
{
mPendingEnd = false;
if (mPublished)
{
mPublish->header(h_Expires).value() = 0;
mPublish->releaseContents();
InfoLog(<< "Sending pending end PUBLISH: " << mPublish->brief());
send(mPublish);
}
else
{
InfoLog(<< "Pending end PUBLISH, but not published, so ending immediately: " << mPublish->brief());
delete this;
return;
}
}
else if (mPendingPublish)
{ {
InfoLog (<< "Sending pending PUBLISH: " << mPublish->brief()); InfoLog (<< "Sending pending PUBLISH: " << mPublish->brief());
send(mPublish); send(mPublish);
@ -240,9 +274,9 @@ ClientPublication::dispatch(const DumTimeout& timer)
void void
ClientPublication::refresh(unsigned int expiration) ClientPublication::refresh(unsigned int expiration)
{ {
if (expiration == 0 && mPublish->exists(h_Expires)) if (expiration != 0)
{ {
expiration = mPublish->header(h_Expires).value(); mPublish->header(h_Expires).value() = expiration;
} }
send(mPublish); send(mPublish);
} }
@ -250,16 +284,18 @@ ClientPublication::refresh(unsigned int expiration)
class ClientPublicationRefreshCommand : public DumCommandAdapter class ClientPublicationRefreshCommand : public DumCommandAdapter
{ {
public: public:
ClientPublicationRefreshCommand(ClientPublication& clientPublication, unsigned int expiration) ClientPublicationRefreshCommand(const ClientPublicationHandle& clientPublicationHandle, unsigned int expiration)
: mClientPublication(clientPublication), : mClientPublicationHandle(clientPublicationHandle),
mExpiration(expiration) mExpiration(expiration)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientPublication.refresh(mExpiration); if(mClientPublicationHandle.isValid())
{
mClientPublicationHandle->refresh(mExpiration);
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -268,14 +304,14 @@ public:
} }
private: private:
ClientPublication& mClientPublication; ClientPublicationHandle mClientPublicationHandle;
unsigned int mExpiration; unsigned int mExpiration;
}; };
void void
ClientPublication::refreshCommand(unsigned int expiration) ClientPublication::refreshCommand(unsigned int expiration)
{ {
mDum.post(new ClientPublicationRefreshCommand(*this, expiration)); mDum.post(new ClientPublicationRefreshCommand(getHandle(), expiration));
} }
void void
@ -303,16 +339,18 @@ ClientPublication::update(const Contents* body)
class ClientPublicationUpdateCommand : public DumCommandAdapter class ClientPublicationUpdateCommand : public DumCommandAdapter
{ {
public: public:
ClientPublicationUpdateCommand(ClientPublication& clientPublication, const Contents* body) ClientPublicationUpdateCommand(const ClientPublicationHandle& clientPublicationHandle, const Contents* body)
: mClientPublication(clientPublication), : mClientPublicationHandle(clientPublicationHandle),
mBody(body?body->clone():0) mBody(body?body->clone():0)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientPublication.update(mBody.get()); if(mClientPublicationHandle.isValid())
{
mClientPublicationHandle->update(mBody.get());
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -321,14 +359,14 @@ public:
} }
private: private:
ClientPublication& mClientPublication; ClientPublicationHandle mClientPublicationHandle;
std::unique_ptr<Contents> mBody; std::auto_ptr<Contents> mBody;
}; };
void void
ClientPublication::updateCommand(const Contents* body) ClientPublication::updateCommand(const Contents* body)
{ {
mDum.post(new ClientPublicationUpdateCommand(*this, body)); mDum.post(new ClientPublicationUpdateCommand(getHandle(), body));
} }
void void

View File

@ -41,8 +41,10 @@ class ClientPublication : public NonDialogUsage
private: private:
friend class DialogSet; friend class DialogSet;
bool mPublished;
bool mWaitingForResponse; bool mWaitingForResponse;
bool mPendingPublish; bool mPendingPublish;
bool mPendingEnd;
SharedPtr<SipMessage> mPublish; SharedPtr<SipMessage> mPublish;
Data mEventType; Data mEventType;

View File

@ -2,7 +2,6 @@
#include <iterator> #include <iterator>
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "resip/stack/ExtensionHeader.hxx"
#include "resip/dum/BaseCreator.hxx" #include "resip/dum/BaseCreator.hxx"
#include "resip/dum/ClientAuthManager.hxx" #include "resip/dum/ClientAuthManager.hxx"
#include "resip/dum/ClientRegistration.hxx" #include "resip/dum/ClientRegistration.hxx"
@ -15,20 +14,21 @@
#include "rutil/Inserter.hxx" #include "rutil/Inserter.hxx"
#include "rutil/Random.hxx" #include "rutil/Random.hxx"
#include "rutil/ParseBuffer.hxx" #include "rutil/ParseBuffer.hxx"
#include "rutil/TransportType.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"
#include "rutil/AtomicCounter.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
using namespace resip; using namespace resip;
static const UInt32 UnreasonablyLowExpirationThreshold = 7; // The threshold before which we consider a contacts expiry to be unreasonably low
ClientRegistrationHandle ClientRegistrationHandle
ClientRegistration::getHandle() ClientRegistration::getHandle()
{ {
return ClientRegistrationHandle(mDum, getBaseHandle().getId()); return ClientRegistrationHandle(mDum, getBaseHandle().getId());
} }
AtomicCounter ClientRegistration::InstanceCounter;
ClientRegistration::ClientRegistration(DialogUsageManager& dum, ClientRegistration::ClientRegistration(DialogUsageManager& dum,
DialogSet& dialogSet, DialogSet& dialogSet,
SharedPtr<SipMessage> request) SharedPtr<SipMessage> request)
@ -36,19 +36,25 @@ ClientRegistration::ClientRegistration(DialogUsageManager& dum,
mLastRequest(request), mLastRequest(request),
mTimerSeq(0), mTimerSeq(0),
mState(mLastRequest->exists(h_Contacts) ? Adding : Querying), mState(mLastRequest->exists(h_Contacts) ? Adding : Querying),
mEnding(false),
mEndWhenDone(false), mEndWhenDone(false),
mUserRefresh(false), mUserRefresh(false),
mRegistrationTime(mDialogSet.mUserProfile->getDefaultRegistrationTime()), mRegistrationTime(mDialogSet.mUserProfile->getDefaultRegistrationTime()),
mExpires(0), mExpires(0),
mRefreshTime(0),
mQueuedState(None), mQueuedState(None),
mQueuedRequest(new SipMessage), mQueuedRequest(new SipMessage)
mCustomHeader(false)
{ {
InstanceCounter.increment();
// If no Contacts header, this is a query // If no Contacts header, this is a query
if (mLastRequest->exists(h_Contacts)) if (mLastRequest->exists(h_Contacts))
{ {
mMyContacts = mLastRequest->header(h_Contacts); NameAddr all;
all.setAllContacts();
if(!(mLastRequest->header(h_Contacts).front() == all))
{
// store if not special all contacts header
mMyContacts = mLastRequest->header(h_Contacts);
}
} }
if(mLastRequest->exists(h_Expires) && if(mLastRequest->exists(h_Expires) &&
@ -67,7 +73,6 @@ ClientRegistration::~ClientRegistration()
// !dcm! Will not interact well with multiple registrations from the same AOR // !dcm! Will not interact well with multiple registrations from the same AOR
mDialogSet.mUserProfile->setServiceRoute(NameAddrs()); mDialogSet.mUserProfile->setServiceRoute(NameAddrs());
InstanceCounter.decrement();
} }
void void
@ -100,7 +105,7 @@ ClientRegistration::tryModification(ClientRegistration::State state)
} }
} }
assert(mQueuedState == None); resip_assert(mQueuedState == None);
mState = state; mState = state;
return mLastRequest; return mLastRequest;
@ -117,8 +122,6 @@ ClientRegistration::addBinding(const NameAddr& contact, UInt32 registrationTime)
mRegistrationTime = registrationTime; mRegistrationTime = registrationTime;
next->header(h_Expires).value() = mRegistrationTime; next->header(h_Expires).value() = mRegistrationTime;
next->header(h_CSeq).sequence()++; next->header(h_CSeq).sequence()++;
updateWithCustomHeader(next);
// caller prefs // caller prefs
if (mQueuedState == None) if (mQueuedState == None)
@ -145,7 +148,6 @@ ClientRegistration::removeBinding(const NameAddr& contact)
next->header(h_Contacts).push_back(*i); next->header(h_Contacts).push_back(*i);
next->header(h_Expires).value() = 0; next->header(h_Expires).value() = 0;
next->header(h_CSeq).sequence()++; next->header(h_CSeq).sequence()++;
updateWithCustomHeader(next);
if (mQueuedState == None) if (mQueuedState == None)
{ {
@ -182,7 +184,7 @@ ClientRegistration::removeAll(bool stopRegisteringWhenDone)
next->header(h_Expires).value() = 0; next->header(h_Expires).value() = 0;
next->header(h_CSeq).sequence()++; next->header(h_CSeq).sequence()++;
mEndWhenDone = stopRegisteringWhenDone; mEndWhenDone = stopRegisteringWhenDone;
updateWithCustomHeader(next);
if (mQueuedState == None) if (mQueuedState == None)
{ {
send(next); send(next);
@ -226,6 +228,13 @@ ClientRegistration::removeMyBindings(bool stopRegisteringWhenDone)
if (mQueuedState == None) if (mQueuedState == None)
{ {
if(mEnding && whenExpires() == 0)
{
resip_assert(mEndWhenDone); // will always be true when mEnding is true
// We are not actually registered, and we are ending - no need to send un-register - just terminate now
stopRegistering();
return;
}
send(next); send(next);
} }
} }
@ -233,15 +242,18 @@ ClientRegistration::removeMyBindings(bool stopRegisteringWhenDone)
class ClientRegistrationRemoveMyBindings : public DumCommandAdapter class ClientRegistrationRemoveMyBindings : public DumCommandAdapter
{ {
public: public:
ClientRegistrationRemoveMyBindings(ClientRegistration& clientRegistration, bool stopRegisteringWhenDone) ClientRegistrationRemoveMyBindings(const ClientRegistrationHandle& clientRegistrationHandle, bool stopRegisteringWhenDone)
: mClientRegistration(clientRegistration), : mClientRegistrationHandle(clientRegistrationHandle),
mStopRegisteringWhenDone(stopRegisteringWhenDone) mStopRegisteringWhenDone(stopRegisteringWhenDone)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientRegistration.removeMyBindings(mStopRegisteringWhenDone); if(mClientRegistrationHandle.isValid())
{
mClientRegistrationHandle->removeMyBindings(mStopRegisteringWhenDone);
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -249,14 +261,14 @@ public:
return strm << "ClientRegistrationRemoveMyBindings"; return strm << "ClientRegistrationRemoveMyBindings";
} }
private: private:
ClientRegistration& mClientRegistration; ClientRegistrationHandle mClientRegistrationHandle;
bool mStopRegisteringWhenDone; bool mStopRegisteringWhenDone;
}; };
void void
ClientRegistration::removeMyBindingsCommand(bool stopRegisteringWhenDone) ClientRegistration::removeMyBindingsCommand(bool stopRegisteringWhenDone)
{ {
mDum.post(new ClientRegistrationRemoveMyBindings(*this, stopRegisteringWhenDone)); mDum.post(new ClientRegistrationRemoveMyBindings(getHandle(), stopRegisteringWhenDone));
} }
void void
@ -277,7 +289,7 @@ ClientRegistration::requestRefresh(UInt32 expires)
void void
ClientRegistration::internalRequestRefresh(UInt32 expires) ClientRegistration::internalRequestRefresh(UInt32 expires)
{ {
if(mState == RetryAdding && mState == RetryRefreshing) if(mState == RetryAdding || mState == RetryRefreshing)
{ {
// disable retry time and try refresh immediately // disable retry time and try refresh immediately
++mTimerSeq; ++mTimerSeq;
@ -288,14 +300,19 @@ ClientRegistration::internalRequestRefresh(UInt32 expires)
return; return;
} }
// check if refresh really required
if(!mDum.mClientRegistrationHandler->onRefreshRequired(getHandle(), *mLastRequest))
{
InfoLog (<< "application doesn't want to refresh " << *this);
end();
return;
}
InfoLog (<< "requesting refresh of " << *this); InfoLog (<< "requesting refresh of " << *this);
mState = Refreshing; mState = Refreshing;
mLastRequest->header(h_CSeq).sequence()++; mLastRequest->header(h_CSeq).sequence()++;
mLastRequest->header(h_Contacts)=mMyContacts; mLastRequest->header(h_Contacts)=mMyContacts;
updateWithCustomHeader(mLastRequest);
if(expires > 0) if(expires > 0)
{ {
mRegistrationTime = expires; mRegistrationTime = expires;
@ -320,30 +337,41 @@ ClientRegistration::allContacts()
UInt32 UInt32
ClientRegistration::whenExpires() const ClientRegistration::whenExpires() const
{ {
// !cj! - TODO - I'm suspisious these time are getting confused on what units they are in
UInt64 now = Timer::getTimeSecs(); UInt64 now = Timer::getTimeSecs();
UInt64 ret = mExpires - now; if(mExpires > now)
return (UInt32)ret; {
return (UInt32)(mExpires - now);
}
else
{
return 0;
}
} }
void void
ClientRegistration::end() ClientRegistration::end()
{ {
removeMyBindings(true); if(!mEnding)
{
mEnding = true;
removeMyBindings(true);
}
} }
class ClientRegistrationEndCommand : public DumCommandAdapter class ClientRegistrationEndCommand : public DumCommandAdapter
{ {
public: public:
ClientRegistrationEndCommand(ClientRegistration& clientRegistration) ClientRegistrationEndCommand(const ClientRegistrationHandle& clientRegistrationHandle)
: mClientRegistration(clientRegistration) : mClientRegistrationHandle(clientRegistrationHandle)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientRegistration.end(); if(mClientRegistrationHandle.isValid())
{
mClientRegistrationHandle->end();
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -351,13 +379,13 @@ public:
return strm << "ClientRegistrationEndCommand"; return strm << "ClientRegistrationEndCommand";
} }
private: private:
ClientRegistration& mClientRegistration; ClientRegistrationHandle mClientRegistrationHandle;
}; };
void void
ClientRegistration::endCommand() ClientRegistration::endCommand()
{ {
mDum.post(new ClientRegistrationEndCommand(*this)); mDum.post(new ClientRegistrationEndCommand(getHandle()));
} }
EncodeStream& EncodeStream&
@ -373,7 +401,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
try try
{ {
// !jf! there may be repairable errors that we can handle here // !jf! there may be repairable errors that we can handle here
assert(msg.isResponse()); resip_assert(msg.isResponse());
const int& code = msg.header(h_StatusLine).statusCode(); const int& code = msg.header(h_StatusLine).statusCode();
bool nextHopSupportsOutbound = false; bool nextHopSupportsOutbound = false;
int keepAliveTime = 0; int keepAliveTime = 0;
@ -405,14 +433,13 @@ ClientRegistration::dispatch(const SipMessage& msg)
} }
} }
if(msg.isExternal()) if(msg.isFromWire())
{ {
const Data& receivedTransport = msg.header(h_Vias).front().transport(); resip::TransportType receivedTransport = toTransportType(
msg.header(h_Vias).front().transport());
if(keepAliveTime == 0) if(keepAliveTime == 0)
{ {
if(receivedTransport == Symbols::TCP || if(isReliable(receivedTransport))
receivedTransport == Symbols::TLS ||
receivedTransport == Symbols::SCTP)
{ {
keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream(); keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream();
} }
@ -485,7 +512,9 @@ ClientRegistration::dispatch(const SipMessage& msg)
// !ah! take list of ctcs and push into mMy or mOther as required. // !ah! take list of ctcs and push into mMy or mOther as required.
// make timers to re-register // make timers to re-register
UInt64 nowSecs = Timer::getTimeSecs();
UInt32 expiry = calculateExpiry(msg); UInt32 expiry = calculateExpiry(msg);
mExpires = nowSecs + expiry;
if(msg.exists(h_Contacts)) if(msg.exists(h_Contacts))
{ {
mAllContacts = msg.header(h_Contacts); mAllContacts = msg.header(h_Contacts);
@ -497,10 +526,10 @@ ClientRegistration::dispatch(const SipMessage& msg)
if (expiry != 0 && expiry != UINT_MAX) if (expiry != 0 && expiry != UINT_MAX)
{ {
if(expiry>=7) if(expiry >= UnreasonablyLowExpirationThreshold)
{ {
int exp = Helper::aBitSmallerThan(expiry); int exp = Helper::aBitSmallerThan(expiry);
mExpires = exp + Timer::getTimeSecs(); mRefreshTime = exp + nowSecs;
mDum.addTimer(DumTimeout::Registration, mDum.addTimer(DumTimeout::Registration,
exp, exp,
getBaseHandle(), getBaseHandle(),
@ -571,6 +600,13 @@ ClientRegistration::dispatch(const SipMessage& msg)
if (mQueuedState != None) if (mQueuedState != None)
{ {
if(mQueuedState == Removing && mEnding && whenExpires() == 0)
{
resip_assert(mEndWhenDone); // will always be true when mEnding is true
// We are not actually registered, and we are ending - no need to send un-register - just terminate now
stopRegistering();
return;
}
InfoLog (<< "Sending queued request: " << *mQueuedRequest); InfoLog (<< "Sending queued request: " << *mQueuedRequest);
mState = mQueuedState; mState = mQueuedState;
mQueuedState = None; mQueuedState = None;
@ -595,7 +631,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
return; return;
} }
} }
else if (code == 408 || (code == 503 && msg.getReceivedTransport() == 0)) else if (code == 408 || (code == 503 && !msg.isFromWire()))
{ {
int retry = mDum.mClientRegistrationHandler->onRequestRetry(getHandle(), 0, msg); int retry = mDum.mClientRegistrationHandler->onRequestRetry(getHandle(), 0, msg);
@ -615,7 +651,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
else else
{ {
DebugLog(<< "Application requested delayed retry on 408 or internal 503: " << retry); DebugLog(<< "Application requested delayed retry on 408 or internal 503: " << retry);
mExpires = 0; mRefreshTime = 0;
switch(mState) switch(mState)
{ {
case Adding: case Adding:
@ -625,7 +661,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
mState = RetryRefreshing; mState = RetryRefreshing;
break; break;
default: default:
assert(false); resip_assert(false);
break; break;
} }
if(mDum.mClientAuthManager.get()) mDum.mClientAuthManager.get()->clearAuthenticationState(DialogSetId(*mLastRequest)); if(mDum.mClientAuthManager.get()) mDum.mClientAuthManager.get()->clearAuthenticationState(DialogSetId(*mLastRequest));
@ -777,20 +813,55 @@ ClientRegistration::calculateExpiry(const SipMessage& reg200) const
const NameAddrs& contacts(reg200.header(h_Contacts)); const NameAddrs& contacts(reg200.header(h_Contacts));
// We are going to track two things here:
// 1. expiry - the lowest expiration value of all of our contacts
// 2. reasonableExpiry - the lowest expiration value of all of our contacts
// that is above the UnreasonablyLowExpirationThreshold (7 seconds)
// Before we return, if expiry is less than UnreasonablyLowExpirationThreshold
// but we had another contact that had a reasonable expiry value, then return
// that value instead. This logic covers a very interesting scenario:
//
// Consider the case where we are registered over TCP due to DNS SRV record
// configuration. Let's say an administrator reconfigures the DNS records to
// now make UDP the preferred transport. When we re-register we will now
// send the re-registration message over UDP. This will cause our contact
// address to be changed (ie: ;tranport=tcp will no longer exist). So for a
// short period of time the registrar will return two contacts to us, both
// belonging to us, one for TCP and one for UDP. The TCP one will expire in
// a short amount of time, and if we return this expiry to the dispatch()
// method then it will cause the ClientRegistration to end (see logic in
// dispatch() that prints out the error "Server is using an unreasonably low
// expiry: "...
unsigned long reasonableExpiry = 0xFFFFFFFF;
for(NameAddrs::const_iterator c=contacts.begin();c!=contacts.end();++c) for(NameAddrs::const_iterator c=contacts.begin();c!=contacts.end();++c)
{ {
// Our expiry is never going to increase if we find one of our contacts, // Our expiry is never going to increase if we find one of our contacts,
// so if the expiry is not lower, we just ignore it. For registrars that // so if the expiry is not lower, we just ignore it. For registrars that
// leave our requested expiry alone, this code ends up being pretty quick, // leave our requested expiry alone, this code ends up being pretty quick,
// especially if there aren't contacts from other endpoints laying around. // especially if there aren't contacts from other endpoints laying around.
if(c->isWellFormed() && if(c->isWellFormed() && c->exists(p_expires))
c->exists(p_expires) &&
c->param(p_expires) < expiry &&
contactIsMine(*c))
{ {
expiry=c->param(p_expires); unsigned long contactExpires = c->param(p_expires);
if((contactExpires < expiry ||
contactExpires < reasonableExpiry) &&
contactIsMine(*c))
{
expiry = contactExpires;
if(contactExpires >= UnreasonablyLowExpirationThreshold)
{
reasonableExpiry = contactExpires;
}
}
} }
} }
// If expiry is less than UnreasonablyLowExpirationThreshold and we have another
// contact that has a reasonable expiry value, then return that value instead.
// See large comment above for more details.
if(expiry < UnreasonablyLowExpirationThreshold && reasonableExpiry != 0xFFFFFFFF)
{
expiry = reasonableExpiry;
}
return expiry; return expiry;
} }
@ -863,7 +934,7 @@ ClientRegistration::checkProfileRetry(const SipMessage& msg)
// Use retry interval from error response // Use retry interval from error response
retryInterval = msg.header(h_RetryAfter).value(); retryInterval = msg.header(h_RetryAfter).value();
} }
mExpires = 0; mRefreshTime = 0;
switch(mState) switch(mState)
{ {
case Adding: case Adding:
@ -873,7 +944,7 @@ ClientRegistration::checkProfileRetry(const SipMessage& msg)
mState = RetryRefreshing; mState = RetryRefreshing;
break; break;
default: default:
assert(false); resip_assert(false);
break; break;
} }
@ -916,7 +987,7 @@ ClientRegistration::dispatch(const DumTimeout& timer)
mState = Refreshing; mState = Refreshing;
break; break;
default: default:
assert(false); resip_assert(false);
break; break;
} }
@ -943,31 +1014,6 @@ ClientRegistration::flowTerminated()
mDum.mClientRegistrationHandler->onFlowTerminated(getHandle()); mDum.mClientRegistrationHandler->onFlowTerminated(getHandle());
} }
void
ClientRegistration::setCustomHeader(const resip::Data& name, const resip::Data& value)
{
mCustomHeader = true;
mCustomHeaderName = name;
mCustomHeaderValue = value;
}
void
ClientRegistration::unsetCustomHeader()
{
mCustomHeader = false;
}
void
ClientRegistration::updateWithCustomHeader(SharedPtr<SipMessage> msg)
{
if (mCustomHeader)
{
ExtensionHeader hdr(mCustomHeaderName);
msg->header(hdr).clear();
StringCategory sc(mCustomHeaderValue);
msg->header(hdr).push_back(sc);
}
}
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0
@ -1019,4 +1065,3 @@ ClientRegistration::updateWithCustomHeader(SharedPtr<SipMessage> msg)
* <http://www.vovida.org/>. * <http://www.vovida.org/>.
* *
*/ */

View File

@ -11,14 +11,11 @@ namespace resip
class SipMessage; class SipMessage;
class BaseCreator; class BaseCreator;
class AtomicCounter;
//!dcm! -- shutdown/deletion API -- end? //!dcm! -- shutdown/deletion API -- end?
class ClientRegistration: public NonDialogUsage class ClientRegistration: public NonDialogUsage
{ {
public: public:
static AtomicCounter InstanceCounter;
//ClientRegistration(DialogUsageManager& dum, DialogSet& dialog, //ClientRegistration(DialogUsageManager& dum, DialogSet& dialog,
//SipMessage& req); //SipMessage& req);
ClientRegistration(DialogUsageManager& dum, DialogSet& dialog, SharedPtr<SipMessage> req); ClientRegistration(DialogUsageManager& dum, DialogSet& dialog, SharedPtr<SipMessage> req);
@ -42,7 +39,6 @@ class ClientRegistration: public NonDialogUsage
when complete */ when complete */
void removeMyBindings(bool stopRegisteringWhenDone=false); void removeMyBindings(bool stopRegisteringWhenDone=false);
/** Request a manual refresh of the registration. If 0 then default to using original /** Request a manual refresh of the registration. If 0 then default to using original
expires value (to remove use removeXXX() instead) */ expires value (to remove use removeXXX() instead) */
void requestRefresh(UInt32 expires = 0); void requestRefresh(UInt32 expires = 0);
@ -56,12 +52,15 @@ class ClientRegistration: public NonDialogUsage
/** returns a list of all contacts for this AOR - may include those added by other UA's */ /** returns a list of all contacts for this AOR - may include those added by other UA's */
const NameAddrs& allContacts(); const NameAddrs& allContacts();
/** returns the number of seconds until the registration expires - relative */ /** returns the number of seconds until the registration expires - relative, returns 0 if already expired */
UInt32 whenExpires() const; UInt32 whenExpires() const;
/** Calls removeMyBindings and ends usage when complete */ /** Calls removeMyBindings and ends usage when complete */
virtual void end(); virtual void end();
/** Returns true if a REGISTER request is currently pending and we are waiting for the SIP Response */
bool isRequestPending() { return mState != Registered && mState != RetryAdding && mState != RetryRefreshing; }
/** /**
* Provide asynchronous method access by using command * Provide asynchronous method access by using command
*/ */
@ -73,8 +72,6 @@ class ClientRegistration: public NonDialogUsage
virtual void dispatch(const DumTimeout& timer); virtual void dispatch(const DumTimeout& timer);
virtual EncodeStream& dump(EncodeStream& strm) const; virtual EncodeStream& dump(EncodeStream& strm) const;
void setCustomHeader(const resip::Data& name, const resip::Data& value);
void unsetCustomHeader();
static void tagContact(NameAddr& contact, DialogUsageManager& dum, SharedPtr<UserProfile>& userProfile); static void tagContact(NameAddr& contact, DialogUsageManager& dum, SharedPtr<UserProfile>& userProfile);
@ -102,7 +99,6 @@ class ClientRegistration: public NonDialogUsage
bool contactIsMine(const NameAddr& contact) const; bool contactIsMine(const NameAddr& contact) const;
bool rinstanceIsMine(const Data& rinstance) const; bool rinstanceIsMine(const Data& rinstance) const;
bool searchByUri(const Uri& cUri) const; bool searchByUri(const Uri& cUri) const;
void updateWithCustomHeader(SharedPtr<SipMessage> msg);
friend class DialogSet; friend class DialogSet;
void flowTerminated(); void flowTerminated();
@ -114,16 +110,17 @@ class ClientRegistration: public NonDialogUsage
unsigned int mTimerSeq; // expected timer seq (all < are stale) unsigned int mTimerSeq; // expected timer seq (all < are stale)
State mState; State mState;
bool mEnding;
bool mEndWhenDone; bool mEndWhenDone;
bool mUserRefresh; bool mUserRefresh;
UInt32 mRegistrationTime; UInt32 mRegistrationTime;
UInt64 mExpires; UInt64 mExpires;
UInt64 mRefreshTime;
State mQueuedState; State mQueuedState;
SharedPtr<SipMessage> mQueuedRequest; SharedPtr<SipMessage> mQueuedRequest;
resip::Data mCustomHeaderName, mCustomHeaderValue;
bool mCustomHeader;
NetworkAssociation mNetworkAssociation;
NetworkAssociation mNetworkAssociation;
// disabled // disabled
ClientRegistration(const ClientRegistration&); ClientRegistration(const ClientRegistration&);
ClientRegistration& operator=(const ClientRegistration&); ClientRegistration& operator=(const ClientRegistration&);

View File

@ -18,27 +18,22 @@ using namespace resip;
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
ClientSubscription::ClientSubscription(DialogUsageManager& dum, Dialog& dialog, ClientSubscription::ClientSubscription(DialogUsageManager& dum, Dialog& dialog, const SipMessage& request)
const SipMessage& request, UInt32 defaultSubExpiration)
: BaseSubscription(dum, dialog, request), : BaseSubscription(dum, dialog, request),
mOnNewSubscriptionCalled(mEventType == "refer"), // don't call onNewSubscription for Refer subscriptions mOnNewSubscriptionCalled(mEventType == "refer"), // don't call onNewSubscription for Refer subscriptions
mEnded(false), mEnded(false),
mNextRefreshSecs(0), mNextRefreshSecs(0),
mLastSubSecs(Timer::getTimeSecs()), // Not exactly, but more forgiving mLastSubSecs(Timer::getTimeSecs()), // Not exactly, but more forgiving
mDefaultExpires(defaultSubExpiration), mSubscribed(false),
mRefreshing(false), mRefreshing(false),
mHaveQueuedRefresh(false), mHaveQueuedRefresh(false),
mQueuedRefreshInterval(-1), mQueuedRefreshInterval(-1),
mLargestNotifyCSeq(0) mLargestNotifyCSeq(0)
{ {
DebugLog (<< "ClientSubscription::ClientSubscription from " << request.brief()); DebugLog (<< "ClientSubscription::ClientSubscription from " << request.brief() << ": " << this);
if(request.method() == SUBSCRIBE) if(request.method() == SUBSCRIBE)
{ {
*mLastRequest = request; *mLastRequest = request;
if (defaultSubExpiration > 0)
{
mLastRequest->header(h_Expires).value() = defaultSubExpiration;
}
} }
else else
{ {
@ -59,6 +54,7 @@ ClientSubscription::~ClientSubscription()
} }
clearDustbin(); clearDustbin();
DebugLog(<< "ClientSubscription::~ClientSubscription: " << this);
} }
ClientSubscriptionHandle ClientSubscriptionHandle
@ -73,37 +69,46 @@ ClientSubscription::dispatch(const SipMessage& msg)
DebugLog (<< "ClientSubscription::dispatch " << msg.brief()); DebugLog (<< "ClientSubscription::dispatch " << msg.brief());
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
clearDustbin(); clearDustbin();
// asserts are checks the correctness of Dialog::dispatch // asserts are checks the correctness of Dialog::dispatch
if (msg.isRequest() ) if (msg.isRequest() )
{ {
assert( msg.header(h_RequestLine).getMethod() == NOTIFY ); resip_assert( msg.header(h_RequestLine).getMethod() == NOTIFY );
mRefreshing = false; mRefreshing = false;
mSubscribed = true; // If we got a NOTIFY then we are subscribed
// !dlb! 481 NOTIFY iff state is dead? // !dlb! 481 NOTIFY iff state is dead?
//!dcm! -- heavy, should just store enough information to make response //!dcm! -- heavy, should just store enough information to make response
//mLastNotify = msg; //mLastNotify = msg;
//!fj! There is a bug that prevents onNewSubscription from being called
// when, for example, the UAS sends a 408 back and
// ClientSubscriptionHandler::onRequestRetry returns 0. A fix was
// attempted in revision 10128 but it created a more important
// regression. See
// http://list.resiprocate.org/archive/resiprocate-devel/thrd83.html#08362
// for more details.
if (!mOnNewSubscriptionCalled && !getAppDialogSet()->isReUsed()) if (!mOnNewSubscriptionCalled && !getAppDialogSet()->isReUsed())
{ {
InfoLog (<< "[ClientSubscription] " << mLastRequest->header(h_To));
if (msg.exists(h_Contacts))
{
mDialog.mRemoteTarget = msg.header(h_Contacts).front();
}
handler->onNewSubscription(getHandle(), msg);
mOnNewSubscriptionCalled = true; mOnNewSubscriptionCalled = true;
} InfoLog(<< "[ClientSubscription] " << mLastRequest->header(h_To));
handler->onNewSubscription(getHandle(), msg);
if (mEnded) return;
}
bool outOfOrder = mLargestNotifyCSeq > msg.header(h_CSeq).sequence(); bool outOfOrder = mLargestNotifyCSeq > msg.header(h_CSeq).sequence();
if (!outOfOrder) if (!outOfOrder)
{ {
mLargestNotifyCSeq = msg.header(h_CSeq).sequence(); mLargestNotifyCSeq = msg.header(h_CSeq).sequence();
// If not out of order, then allow NOTIFY to do a target refresh - RFC6665
if (msg.exists(h_Contacts))
{
mDialog.mRemoteTarget = msg.header(h_Contacts).front();
}
} }
else else
{ {
@ -133,13 +138,14 @@ void
ClientSubscription::processResponse(const SipMessage& msg) ClientSubscription::processResponse(const SipMessage& msg)
{ {
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
mRefreshing = false; mRefreshing = false;
int statusCode = msg.header(h_StatusLine).statusCode(); int statusCode = msg.header(h_StatusLine).statusCode();
if (statusCode >= 200 && statusCode <300) if (statusCode >= 200 && statusCode <300)
{ {
mSubscribed = true; // If we got a 200 response then we are subscribed
if (msg.exists(h_Expires)) if (msg.exists(h_Expires))
{ {
// grab the expires from the 2xx in case there is not one on the NOTIFY .mjf. // grab the expires from the 2xx in case there is not one on the NOTIFY .mjf.
@ -153,22 +159,30 @@ ClientSubscription::processResponse(const SipMessage& msg)
if(!mOnNewSubscriptionCalled) if(!mOnNewSubscriptionCalled)
{ {
// Timer for initial NOTIFY; since we don't know when the initial mOnNewSubscriptionCalled = true;
// SUBSRIBE is sent, we have to set the timer when the 200 comes in, if handler->onNewSubscription(getHandle(), msg);
// it beat the NOTIFY. if (!mEnded)
mDum.addTimer(DumTimeout::WaitForNotify, {
64*Timer::T1, // Timer for initial NOTIFY; since we don't know when the initial
getBaseHandle(), // SUBSCRIBE is sent, we have to set the timer when the 200 comes in, if
++mTimerSeq); // it beats the NOTIFY.
mDum.addTimerMs(DumTimeout::WaitForNotify,
64 * Timer::T1,
getBaseHandle(),
++mTimerSeq);
}
}
else if (!mEnded)
{
sendQueuedRefreshRequest();
} }
sendQueuedRefreshRequest();
} }
else if (!mEnded && else if (!mEnded &&
statusCode == 481 && statusCode == 481 &&
msg.header(h_To).exists(p_tag) && // Only do this if we were re-subscribing
msg.exists(h_Expires) && msg.header(h_Expires).value() > 0) msg.exists(h_Expires) && msg.header(h_Expires).value() > 0)
{ {
InfoLog (<< "Received 481 to SUBSCRIBE, reSUBSCRIBEing (presence server probably restarted) " InfoLog (<< "Received 481 to SUBSCRIBE, reSUBSCRIBEing (subscription server probably restarted) "
<< mLastRequest->header(h_To)); << mLastRequest->header(h_To));
reSubscribe(); // will delete "this" reSubscribe(); // will delete "this"
@ -176,7 +190,7 @@ ClientSubscription::processResponse(const SipMessage& msg)
} }
else if (!mEnded && else if (!mEnded &&
(statusCode == 408 || (statusCode == 408 ||
(statusCode == 503 && msg.getReceivedTransport() == 0) || (statusCode == 503 && !msg.isFromWire()) ||
((statusCode == 413 || ((statusCode == 413 ||
statusCode == 480 || statusCode == 480 ||
statusCode == 486 || statusCode == 486 ||
@ -263,7 +277,7 @@ ClientSubscription::processNextNotify()
QueuedNotify* qn = mQueuedNotifies.front(); QueuedNotify* qn = mQueuedNotifies.front();
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
unsigned long refreshInterval = 0; unsigned long refreshInterval = 0;
bool setRefreshTimer=false; bool setRefreshTimer=false;
@ -279,18 +293,13 @@ ClientSubscription::processNextNotify()
{ {
expires = mLastRequest->header(h_Expires).value(); expires = mLastRequest->header(h_Expires).value();
} }
else if (mDefaultExpires) else
{ {
/* if we haven't gotten an expires value from: /* if we haven't gotten an expires value from:
1. the subscription state from this notify 1. the subscription state from this notify
2. the last request 2. the last request (may have came from the 2xx in response)
then use the default expires (meaning it came from the 2xx in response then use some reasonable value.
to the initial SUBSCRIBE). .mjf.
*/ */
expires = mDefaultExpires;
}
else
{
expires = 3600; expires = 3600;
} }
@ -386,7 +395,7 @@ ClientSubscription::processNextNotify()
} }
else if (isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated)) else if (isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated))
{ {
if(mLastRequest->header(h_Expires).value()!=0 && if (mLastRequest->header(h_Expires).value() != 0 &&
isEqualNoCase(qn->notify().header(h_SubscriptionState).param(p_reason), "timeout")) isEqualNoCase(qn->notify().header(h_SubscriptionState).param(p_reason), "timeout"))
{ {
// Unexpected timeout of some sort. Look closer. // Unexpected timeout of some sort. Look closer.
@ -396,8 +405,7 @@ ClientSubscription::processNextNotify()
// NOT loop here? // NOT loop here?
if(Helper::aBitSmallerThan((signed long)(Timer::getTimeSecs() - mLastSubSecs)) < 2) if(Helper::aBitSmallerThan((signed long)(Timer::getTimeSecs() - mLastSubSecs)) < 2)
{ {
acceptUpdate(200, "I just sent a refresh, what more do you want " acceptUpdate(200, "I just sent a refresh, what more do you want from me?");
"from me?");
} }
else else
{ {
@ -406,8 +414,7 @@ ClientSubscription::processNextNotify()
} }
else else
{ {
acceptUpdate(200, "You terminated my subscription early! What " acceptUpdate(200, "You terminated my subscription early! What gives?");
"gives?");
} }
} }
else else
@ -422,6 +429,11 @@ ClientSubscription::processNextNotify()
} }
else if (!mEnded) else if (!mEnded)
{ {
if (setRefreshTimer)
{
scheduleRefresh(refreshInterval);
}
handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder()); handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder());
} }
else if (mEnded) else if (mEnded)
@ -451,8 +463,9 @@ ClientSubscription::dispatch(const DumTimeout& timer)
if(timer.type() == DumTimeout::WaitForNotify) if(timer.type() == DumTimeout::WaitForNotify)
{ {
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
if(mOnNewSubscriptionCalled && mEnded) if(mEnded)
{ {
InfoLog(<< "ClientSubscription: received NOTIFY timeout when trying to end, terminating...");
// NOTIFY terminated didn't come in // NOTIFY terminated didn't come in
handler->onTerminated(getHandle(),0); handler->onTerminated(getHandle(),0);
delete this; delete this;
@ -464,17 +477,21 @@ ClientSubscription::dispatch(const DumTimeout& timer)
} }
else if (timer.type() == DumTimeout::SubscriptionRetry) else if (timer.type() == DumTimeout::SubscriptionRetry)
{ {
// this indicates that the ClientSubscription was created by a 408 // Ensure someone hasn't called end() while we were waiting
if (mOnNewSubscriptionCalled) if (!mEnded)
{ {
InfoLog(<< "ClientSubscription: application retry refresh"); // this indicates that the ClientSubscription was created by a 408
requestRefresh(); if (mOnNewSubscriptionCalled)
} {
else InfoLog(<< "ClientSubscription: application retry refresh");
{ requestRefresh();
InfoLog(<< "ClientSubscription: application retry new request"); }
reSubscribe(); // will delete "this" else
return; {
InfoLog(<< "ClientSubscription: application retry new request");
reSubscribe(); // will delete "this"
return;
}
} }
} }
else if(timer.type() == DumTimeout::Subscription) else if(timer.type() == DumTimeout::Subscription)
@ -515,7 +532,7 @@ ClientSubscription::requestRefresh(UInt32 expires)
mLastSubSecs = Timer::getTimeSecs(); mLastSubSecs = Timer::getTimeSecs();
send(mLastRequest); send(mLastRequest);
// Timer for reSUB NOTIFY. // Timer for reSUB NOTIFY.
mDum.addTimer(DumTimeout::WaitForNotify, mDum.addTimerMs(DumTimeout::WaitForNotify,
64*Timer::T1, 64*Timer::T1,
getBaseHandle(), getBaseHandle(),
++mTimerSeq); ++mTimerSeq);
@ -525,15 +542,18 @@ ClientSubscription::requestRefresh(UInt32 expires)
class ClientSubscriptionRefreshCommand : public DumCommandAdapter class ClientSubscriptionRefreshCommand : public DumCommandAdapter
{ {
public: public:
ClientSubscriptionRefreshCommand(ClientSubscription& clientSubscription, UInt32 expires) ClientSubscriptionRefreshCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, UInt32 expires)
: mClientSubscription(clientSubscription), : mClientSubscriptionHandle(clientSubscriptionHandle),
mExpires(expires) mExpires(expires)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientSubscription.requestRefresh(mExpires); if(mClientSubscriptionHandle.isValid())
{
mClientSubscriptionHandle->requestRefresh(mExpires);
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -541,14 +561,14 @@ public:
return strm << "ClientSubscriptionRefreshCommand"; return strm << "ClientSubscriptionRefreshCommand";
} }
private: private:
ClientSubscription& mClientSubscription; ClientSubscriptionHandle mClientSubscriptionHandle;
UInt32 mExpires; UInt32 mExpires;
}; };
void void
ClientSubscription::requestRefreshCommand(UInt32 expires) ClientSubscription::requestRefreshCommand(UInt32 expires)
{ {
mDum.post(new ClientSubscriptionRefreshCommand(*this, expires)); mDum.post(new ClientSubscriptionRefreshCommand(getHandle(), expires));
} }
void void
@ -560,41 +580,49 @@ ClientSubscription::end()
void void
ClientSubscription::end(bool immediate) ClientSubscription::end(bool immediate)
{ {
InfoLog (<< "End subscription: " << mLastRequest->header(h_RequestLine).uri());
if (!mEnded) if (!mEnded)
{ {
if(!immediate) if(!immediate && mSubscribed)
{ {
InfoLog(<< "End subscription: " << mLastRequest->header(h_RequestLine).uri());
mDialog.makeRequest(*mLastRequest, SUBSCRIBE); mDialog.makeRequest(*mLastRequest, SUBSCRIBE);
mLastRequest->header(h_Expires).value() = 0; mLastRequest->header(h_Expires).value() = 0;
mEnded = true; mEnded = true;
send(mLastRequest); send(mLastRequest);
// Timer for NOTIFY terminated // Timer for NOTIFY terminated
mDum.addTimer(DumTimeout::WaitForNotify, mDum.addTimerMs(DumTimeout::WaitForNotify,
64*Timer::T1, 64*Timer::T1,
getBaseHandle(), getBaseHandle(),
++mTimerSeq); ++mTimerSeq);
} }
else else
{ {
InfoLog(<< "End subscription immediately: " << mLastRequest->header(h_RequestLine).uri());
delete this; delete this;
return;
} }
} }
else
{
InfoLog(<< "End subscription called but already ended: " << mLastRequest->header(h_RequestLine).uri());
}
} }
class ClientSubscriptionEndCommand : public DumCommandAdapter class ClientSubscriptionEndCommand : public DumCommandAdapter
{ {
public: public:
ClientSubscriptionEndCommand(ClientSubscription& clientSubscription, bool immediate) ClientSubscriptionEndCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, bool immediate)
:mClientSubscription(clientSubscription), mImmediate(immediate) :mClientSubscriptionHandle(clientSubscriptionHandle), mImmediate(immediate)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mClientSubscription.end(mImmediate); if(mClientSubscriptionHandle.isValid())
{
mClientSubscriptionHandle->end(mImmediate);
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -602,20 +630,20 @@ public:
return strm << "ClientSubscriptionEndCommand"; return strm << "ClientSubscriptionEndCommand";
} }
private: private:
ClientSubscription& mClientSubscription; ClientSubscriptionHandle mClientSubscriptionHandle;
bool mImmediate; bool mImmediate;
}; };
void void
ClientSubscription::endCommand(bool immediate) ClientSubscription::endCommand(bool immediate)
{ {
mDum.post(new ClientSubscriptionEndCommand(*this, immediate)); mDum.post(new ClientSubscriptionEndCommand(getHandle(), immediate));
} }
void void
ClientSubscription::acceptUpdate(int statusCode, const char* reason) ClientSubscription::acceptUpdate(int statusCode, const char* reason)
{ {
assert(!mQueuedNotifies.empty()); resip_assert(!mQueuedNotifies.empty());
if (mQueuedNotifies.empty()) if (mQueuedNotifies.empty())
{ {
InfoLog(<< "No queued notify to accept"); InfoLog(<< "No queued notify to accept");
@ -636,8 +664,8 @@ ClientSubscription::acceptUpdate(int statusCode, const char* reason)
class ClientSubscriptionAcceptUpdateCommand : public DumCommandAdapter class ClientSubscriptionAcceptUpdateCommand : public DumCommandAdapter
{ {
public: public:
ClientSubscriptionAcceptUpdateCommand(ClientSubscription& clientSubscription, int statusCode, const char* reason) ClientSubscriptionAcceptUpdateCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, int statusCode, const char* reason)
: mClientSubscription(clientSubscription), : mClientSubscriptionHandle(clientSubscriptionHandle),
mStatusCode(statusCode), mStatusCode(statusCode),
mReason(reason ? Data(reason) : Data::Empty) mReason(reason ? Data(reason) : Data::Empty)
{ {
@ -646,7 +674,10 @@ public:
virtual void executeCommand() virtual void executeCommand()
{ {
mClientSubscription.acceptUpdate(mStatusCode, mReason.c_str()); if(mClientSubscriptionHandle.isValid())
{
mClientSubscriptionHandle->acceptUpdate(mStatusCode, mReason.c_str());
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -654,7 +685,7 @@ public:
return strm << "ClientSubscriptionAcceptUpdateCommand"; return strm << "ClientSubscriptionAcceptUpdateCommand";
} }
private: private:
ClientSubscription& mClientSubscription; ClientSubscriptionHandle mClientSubscriptionHandle;
int mStatusCode; int mStatusCode;
Data mReason; Data mReason;
}; };
@ -662,7 +693,7 @@ private:
void void
ClientSubscription::acceptUpdateCommand(int statusCode, const char* reason) ClientSubscription::acceptUpdateCommand(int statusCode, const char* reason)
{ {
mDum.post(new ClientSubscriptionAcceptUpdateCommand(*this, statusCode, reason)); mDum.post(new ClientSubscriptionAcceptUpdateCommand(getHandle(), statusCode, reason));
} }
void void
@ -698,8 +729,8 @@ void
ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase) ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase)
{ {
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
assert(!mQueuedNotifies.empty()); resip_assert(!mQueuedNotifies.empty());
if (mQueuedNotifies.empty()) if (mQueuedNotifies.empty())
{ {
InfoLog(<< "No queued notify to reject"); InfoLog(<< "No queued notify to reject");
@ -729,9 +760,15 @@ ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase)
break; break;
case Helper::DialogTermination: //?dcm? -- throw or destroy this? case Helper::DialogTermination: //?dcm? -- throw or destroy this?
case Helper::UsageTermination: case Helper::UsageTermination:
mEnded = true; // If we are already "ended" then we are likely here because we are rejecting an inbound
handler->onTerminated(getHandle(), mLastResponse.get()); // NOTIFY with a 481 that crossed with our un-subscribe request (due to end()). In this case we don't
delete this; // want to call onTerminated or delete this - we wait for end() request to run it's course.
if (!mEnded)
{
mEnded = true;
handler->onTerminated(getHandle(), mLastResponse.get());
delete this;
}
break; break;
} }
} }
@ -739,8 +776,8 @@ ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase)
class ClientSubscriptionRejectUpdateCommand : public DumCommandAdapter class ClientSubscriptionRejectUpdateCommand : public DumCommandAdapter
{ {
public: public:
ClientSubscriptionRejectUpdateCommand(ClientSubscription& clientSubscription, int statusCode, const Data& reasonPhrase) ClientSubscriptionRejectUpdateCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, int statusCode, const Data& reasonPhrase)
: mClientSubscription(clientSubscription), : mClientSubscriptionHandle(clientSubscriptionHandle),
mStatusCode(statusCode), mStatusCode(statusCode),
mReasonPhrase(reasonPhrase) mReasonPhrase(reasonPhrase)
{ {
@ -748,7 +785,10 @@ public:
virtual void executeCommand() virtual void executeCommand()
{ {
mClientSubscription.rejectUpdate(mStatusCode, mReasonPhrase); if(mClientSubscriptionHandle.isValid())
{
mClientSubscriptionHandle->rejectUpdate(mStatusCode, mReasonPhrase);
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -756,7 +796,7 @@ public:
return strm << "ClientSubscriptionRejectUpdateCommand"; return strm << "ClientSubscriptionRejectUpdateCommand";
} }
private: private:
ClientSubscription& mClientSubscription; ClientSubscriptionHandle mClientSubscriptionHandle;
int mStatusCode; int mStatusCode;
Data mReasonPhrase; Data mReasonPhrase;
}; };
@ -764,16 +804,7 @@ private:
void void
ClientSubscription::rejectUpdateCommand(int statusCode, const Data& reasonPhrase) ClientSubscription::rejectUpdateCommand(int statusCode, const Data& reasonPhrase)
{ {
mDum.post(new ClientSubscriptionRejectUpdateCommand(*this, statusCode, reasonPhrase)); mDum.post(new ClientSubscriptionRejectUpdateCommand(getHandle(), statusCode, reasonPhrase));
}
void ClientSubscription::dialogDestroyed(const SipMessage& msg)
{
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
mEnded = true;
handler->onTerminated(getHandle(), &msg);
delete this;
} }
EncodeStream& EncodeStream&
@ -787,7 +818,7 @@ void
ClientSubscription::onReadyToSend(SipMessage& msg) ClientSubscription::onReadyToSend(SipMessage& msg)
{ {
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
handler->onReadyToSend(getHandle(), msg); handler->onReadyToSend(getHandle(), msg);
} }
@ -796,14 +827,14 @@ ClientSubscription::flowTerminated()
{ {
// notify handler // notify handler
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
handler->onFlowTerminated(getHandle()); handler->onFlowTerminated(getHandle());
} }
void void
ClientSubscription::sendQueuedRefreshRequest() ClientSubscription::sendQueuedRefreshRequest()
{ {
assert(!mRefreshing); resip_assert(!mRefreshing);
if (mHaveQueuedRefresh) if (mHaveQueuedRefresh)
{ {

View File

@ -14,8 +14,7 @@ class DialogUsageManager;
class ClientSubscription: public BaseSubscription class ClientSubscription: public BaseSubscription
{ {
public: public:
ClientSubscription(DialogUsageManager& dum, Dialog& dialog, ClientSubscription(DialogUsageManager& dum, Dialog& dialog, const SipMessage& request);
const SipMessage& request, UInt32 defaultSubExpiration);
typedef Handle<ClientSubscription> ClientSubscriptionHandle; typedef Handle<ClientSubscription> ClientSubscriptionHandle;
ClientSubscriptionHandle getHandle(); ClientSubscriptionHandle getHandle();
@ -39,7 +38,6 @@ class ClientSubscription: public BaseSubscription
protected: protected:
virtual ~ClientSubscription(); virtual ~ClientSubscription();
virtual void dialogDestroyed(const SipMessage& msg);
virtual void onReadyToSend(SipMessage& msg); virtual void onReadyToSend(SipMessage& msg);
virtual void send(SharedPtr<SipMessage> msg); virtual void send(SharedPtr<SipMessage> msg);
virtual void flowTerminated(); virtual void flowTerminated();
@ -69,15 +67,12 @@ class ClientSubscription: public BaseSubscription
Dustbin mDustbin; Dustbin mDustbin;
bool mOnNewSubscriptionCalled; bool mOnNewSubscriptionCalled;
//SipMessage mLastNotify;
bool mEnded; bool mEnded;
// .bwc. This is when our next reSUB is scheduled to happen. // .bwc. This is when our next reSUB is scheduled to happen.
UInt64 mNextRefreshSecs; UInt64 mNextRefreshSecs;
UInt64 mLastSubSecs; UInt64 mLastSubSecs;
// this is the expires value from the 2xx coming from the SUB message bool mSubscribed;
UInt32 mDefaultExpires;
bool mRefreshing; bool mRefreshing;
bool mHaveQueuedRefresh; bool mHaveQueuedRefresh;
int mQueuedRefreshInterval; int mQueuedRefreshInterval;

View File

@ -1,7 +1,10 @@
#include <sstream>
#include "resip/dum/ContactInstanceRecord.hxx" #include "resip/dum/ContactInstanceRecord.hxx"
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "rutil/Timer.hxx"
#include "resip/stack/SipMessage.hxx" #include "resip/stack/SipMessage.hxx"
#include "rutil/XMLCursor.hxx"
#include "rutil/Timer.hxx"
using namespace resip; using namespace resip;
@ -11,10 +14,58 @@ ContactInstanceRecord::ContactInstanceRecord() :
mRegId(0), mRegId(0),
mSyncContact(false), mSyncContact(false),
mUseFlowRouting(false), mUseFlowRouting(false),
mUserInfo(0) mUserInfo(0),
mUserData(0)
{ {
} }
ContactInstanceRecord::ContactInstanceRecord(const ContactInstanceRecord& rhs) :
mUserData(0)
{
*this = rhs;
}
ContactInstanceRecord& ContactInstanceRecord::operator=(const ContactInstanceRecord& rhs)
{
mContact = rhs.mContact;
mRegExpires = rhs.mRegExpires;
mLastUpdated = rhs.mLastUpdated;
mReceivedFrom = rhs.mReceivedFrom;
mPublicAddress = rhs.mPublicAddress;
mSipPath = rhs.mSipPath;
mInstance = rhs.mInstance;
mUserAgent = rhs.mUserAgent;
mRegId = rhs.mRegId;
mSyncContact = rhs.mSyncContact;
mUseFlowRouting = rhs.mUseFlowRouting;
mUserInfo = rhs.mUserInfo;
if(mUserData && rhs.mUserData == 0)
{
delete mUserData;
mUserData = 0;
}
else if(mUserData == 0 && rhs.mUserData)
{
mUserData = new Data(*rhs.mUserData);
}
else if(rhs.mUserData)
{
*mUserData = *rhs.mUserData;
}
// else both are already NULL
return(*this);
}
ContactInstanceRecord::~ContactInstanceRecord()
{
if(mUserData)
{
delete mUserData;
mUserData = 0;
}
}
bool bool
ContactInstanceRecord::operator==(const ContactInstanceRecord& rhs) const ContactInstanceRecord::operator==(const ContactInstanceRecord& rhs) const
{ {
@ -26,6 +77,13 @@ ContactInstanceRecord::operator==(const ContactInstanceRecord& rhs) const
return mInstance == rhs.mInstance && return mInstance == rhs.mInstance &&
mRegId == rhs.mRegId; mRegId == rhs.mRegId;
} }
else if (mRegId == 0 && rhs.mRegId == 0 &&
!mInstance.empty() && !rhs.mInstance.empty())
{
// If RegId is not specified on either but instance Id is, then look for instanceId
// match only - RFC5627 matching (even though we don't fully support GRUU yet)
return mInstance == rhs.mInstance;
}
else else
{ {
// otherwise both instance (if specified) and contact must match // otherwise both instance (if specified) and contact must match
@ -34,6 +92,173 @@ ContactInstanceRecord::operator==(const ContactInstanceRecord& rhs) const
} }
} }
void ContactInstanceRecord::stream(std::iostream& ss) const
{
UInt64 now = Timer::getTimeSecs();
ss << " <contactinfo>" << Symbols::CRLF;
ss << " <contacturi>" << Data::from(mContact).xmlCharDataEncode() << "</contacturi>" << Symbols::CRLF;
// If contact is expired or removed, then pass expires time as 0, otherwise send number of seconds until expirey
ss << " <expires>" << (((mRegExpires == 0) || (mRegExpires <= now)) ? 0 : (mRegExpires-now)) << "</expires>" << Symbols::CRLF;
ss << " <lastupdate>" << now-mLastUpdated << "</lastupdate>" << Symbols::CRLF;
if(mReceivedFrom.getPort() != 0)
{
resip::Data binaryFlowToken;
Tuple::writeBinaryToken(mReceivedFrom,binaryFlowToken);
ss << " <receivedfrom>" << binaryFlowToken.base64encode() << "</receivedfrom>" << Symbols::CRLF;
}
if(mPublicAddress.getType() != UNKNOWN_TRANSPORT)
{
resip::Data binaryFlowToken;
Tuple::writeBinaryToken(mPublicAddress,binaryFlowToken);
ss << " <publicaddress>" << binaryFlowToken.base64encode() << "</publicaddress>" << Symbols::CRLF;
}
NameAddrs::const_iterator naIt = mSipPath.begin();
for(; naIt != mSipPath.end(); naIt++)
{
ss << " <sippath>" << Data::from(naIt->uri()).xmlCharDataEncode() << "</sippath>" << Symbols::CRLF;
}
if(!mInstance.empty())
{
ss << " <instance>" << mInstance.xmlCharDataEncode() << "</instance>" << Symbols::CRLF;
}
if(mRegId != 0)
{
ss << " <regid>" << mRegId << "</regid>" << Symbols::CRLF;
}
if (!mUserAgent.empty())
{
ss << " <useragent>" << mUserAgent.xmlCharDataEncode() << "</useragent>" << Symbols::CRLF;
}
if(mUserData != 0 && mUserData->size())
{
ss << " <userdata>" << *mUserData << "</userdata>" << Symbols::CRLF;
}
ss << " </contactinfo>" << Symbols::CRLF;
}
bool ContactInstanceRecord::deserialize(resip::XMLCursor& xml, UInt64 now)
{
bool success = false;
// Reset this members
*this = ContactInstanceRecord();
if(now <= 0)
{
now = Timer::getTimeSecs();
}
if(isEqualNoCase(xml.getTag(), "contactinfo"))
{
if(xml.firstChild())
{
do
{
if(isEqualNoCase(xml.getTag(), "contacturi"))
{
if(xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: contacturi=" << xml.getValue());
mContact = NameAddr(xml.getValue().xmlCharDataDecode());
xml.parent();
success = true;
}
}
else if(isEqualNoCase(xml.getTag(), "expires"))
{
if(xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: expires=" << xml.getValue());
UInt64 expires = xml.getValue().convertUInt64();
mRegExpires = (expires == 0 ? 0 : now+expires);
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "lastupdate"))
{
if(xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: lastupdate=" << xml.getValue());
mLastUpdated = now-xml.getValue().convertUInt64();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "receivedfrom"))
{
if(xml.firstChild())
{
mReceivedFrom = Tuple::makeTupleFromBinaryToken(xml.getValue().base64decode());
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: receivedfrom=" << xml.getValue() << " tuple=" << mReceivedFrom);
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "publicaddress"))
{
if(xml.firstChild())
{
mPublicAddress = Tuple::makeTupleFromBinaryToken(xml.getValue().base64decode());
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: publicaddress=" << xml.getValue() << " tuple=" << mPublicAddress);
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "sippath"))
{
if(xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: sippath=" << xml.getValue());
mSipPath.push_back(NameAddr(xml.getValue().xmlCharDataDecode()));
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "instance"))
{
if(xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: instance=" << xml.getValue());
mInstance = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "regid"))
{
if(xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: regid=" << xml.getValue());
mRegId = xml.getValue().convertUnsignedLong();
xml.parent();
}
}
else if (isEqualNoCase(xml.getTag(), "useragent"))
{
if (xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: useragent=" << xml.getValue());
mUserAgent = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "userdata"))
{
if(xml.firstChild())
{
//InfoLog(<< "RegSyncClient::handleRegInfoEvent: userdata=" << xml.getValue());
if(mUserData == 0)
{
mUserData = new Data("");
}
*mUserData = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
} while(xml.nextSibling());
xml.parent();
}
}
return(success);
}
ContactInstanceRecord ContactInstanceRecord
ContactInstanceRecord::makeRemoveDelta(const NameAddr& contact) ContactInstanceRecord::makeRemoveDelta(const NameAddr& contact)
{ {

View File

@ -12,6 +12,9 @@
namespace resip namespace resip
{ {
class XMLCursor;
static const UInt64 NeverExpire = 0xFFFFFFFFFFFFFFFFULL; static const UInt64 NeverExpire = 0xFFFFFFFFFFFFFFFFULL;
/** A single contact record, bound to an Aor during registration. /** A single contact record, bound to an Aor during registration.
@ -20,10 +23,22 @@ class ContactInstanceRecord
{ {
public: public:
ContactInstanceRecord(); ContactInstanceRecord();
ContactInstanceRecord(const ContactInstanceRecord& rhs);
ContactInstanceRecord& operator=(const ContactInstanceRecord& rhs);
virtual ~ContactInstanceRecord();
static ContactInstanceRecord makeRemoveDelta(const NameAddr& contact); static ContactInstanceRecord makeRemoveDelta(const NameAddr& contact);
static ContactInstanceRecord makeUpdateDelta(const NameAddr& contact, static ContactInstanceRecord makeUpdateDelta(const NameAddr& contact,
UInt64 expires, // absolute time in secs UInt64 expires, // absolute time in secs
const SipMessage& msg); const SipMessage& msg);
// Stream ContactInstanceRecord in XML format
void stream(std::iostream& ss) const;
// Deserialize off xml tree
bool deserialize(resip::XMLCursor& xml, UInt64 now = 0);
/* @returns true if successfully deserialized
*/
NameAddr mContact; // can contain callee caps and q-values NameAddr mContact; // can contain callee caps and q-values
UInt64 mRegExpires; // in seconds UInt64 mRegExpires; // in seconds
@ -33,6 +48,7 @@ class ContactInstanceRecord
NameAddrs mSipPath; // Value of SIP Path header from the request NameAddrs mSipPath; // Value of SIP Path header from the request
Data mInstance; // From the instance parameter; usually a UUID URI Data mInstance; // From the instance parameter; usually a UUID URI
UInt32 mRegId; // From regid parameter of Contact header UInt32 mRegId; // From regid parameter of Contact header
Data mUserAgent; // From User-Agent header
bool mSyncContact; // This contact came from registration sync process, instead of direct SIP registration bool mSyncContact; // This contact came from registration sync process, instead of direct SIP registration
bool mUseFlowRouting; // Set to true when routing to this contact should use flow routing bool mUseFlowRouting; // Set to true when routing to this contact should use flow routing
// Note: There is no need to regsync this field, since such records will also have // Note: There is no need to regsync this field, since such records will also have
@ -40,8 +56,10 @@ class ContactInstanceRecord
// Data mServerSessionId;// if there is no SIP Path header, the connection/session identifier // Data mServerSessionId;// if there is no SIP Path header, the connection/session identifier
// Uri gruu; (GRUU is currently derived) // Uri gruu; (GRUU is currently derived)
void *mUserInfo; //!< can be used to map user record information (database record id for faster updates?) void *mUserInfo; //!< can be used to map user record information (database record id for faster updates?)
Data* mUserData; // Optional user/application specific string
bool operator==(const ContactInstanceRecord& rhs) const; bool operator==(const ContactInstanceRecord& rhs) const;
}; };
typedef std::list<ContactInstanceRecord> ContactList; typedef std::list<ContactInstanceRecord> ContactList;

View File

@ -1,5 +1,5 @@
#if !defined(RESIP_DEFAULTSERVERREFERHANDLER_HXX) #if !defined(RESIP_DEFAULTSERVERREFERHANDLER_HXX)
#define RESIP__DEFAULTSERVERREFERHANDLER_HXX #define RESIP_DEFAULTSERVERREFERHANDLER_HXX
#include "resip/dum/SubscriptionHandler.hxx" #include "resip/dum/SubscriptionHandler.hxx"

View File

@ -4,7 +4,7 @@
#include "resip/dum/DialogSet.hxx" #include "resip/dum/DialogSet.hxx"
#include "resip/dum/Dialog.hxx" #include "resip/dum/Dialog.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"
#include <cassert> #include "rutil/ResipAssert.h"
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM

View File

@ -15,8 +15,10 @@
#include "resip/dum/ServerSubscription.hxx" #include "resip/dum/ServerSubscription.hxx"
#include "resip/dum/SubscriptionHandler.hxx" #include "resip/dum/SubscriptionHandler.hxx"
#include "resip/dum/UsageUseException.hxx" #include "resip/dum/UsageUseException.hxx"
#include "rutil/ResipAssert.h"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
#include "rutil/Inserter.hxx" #include "rutil/Inserter.hxx"
#include "rutil/TransportType.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
@ -40,16 +42,15 @@ Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
mLocalNameAddr(), mLocalNameAddr(),
mRemoteNameAddr(), mRemoteNameAddr(),
mCallId(msg.header(h_CallID)), mCallId(msg.header(h_CallID)),
mDefaultSubExpiration(0),
mAppDialog(0), mAppDialog(0),
mDestroying(false), mDestroying(false),
mReUseDialogSet(false) mReUseDialogSet(false)
{ {
assert(msg.isExternal()); resip_assert(msg.isExternal());
assert(msg.header(h_CSeq).method() != MESSAGE); resip_assert(msg.header(h_CSeq).method() != MESSAGE);
assert(msg.header(h_CSeq).method() != REGISTER); resip_assert(msg.header(h_CSeq).method() != REGISTER);
assert(msg.header(h_CSeq).method() != PUBLISH); resip_assert(msg.header(h_CSeq).method() != PUBLISH);
mNetworkAssociation.setDum(&dum); mNetworkAssociation.setDum(&dum);
@ -239,7 +240,7 @@ Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
InfoLog(<< response); InfoLog(<< response);
throw Exception("lastRequest does not contain a valid contact.", __FILE__, __LINE__); throw Exception("lastRequest does not contain a valid contact.", __FILE__, __LINE__);
} }
mLocalContact = creator->getLastRequest()->header(h_Contacts).front(); mLocalContact = lastRequest->header(h_Contacts).front();
mRemoteTarget = contact; mRemoteTarget = contact;
} }
else else
@ -337,9 +338,9 @@ Dialog::getRouteSet() const
void void
Dialog::cancel() Dialog::cancel()
{ {
assert(mType == Invitation); resip_assert(mType == Invitation);
ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession); ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
assert (uac); resip_assert (uac);
uac->cancel(); uac->cancel();
} }
@ -378,6 +379,8 @@ Dialog::handleTargetRefresh(const SipMessage& msg)
{ {
case INVITE: case INVITE:
case UPDATE: case UPDATE:
case SUBSCRIBE: // RFC6665 - Note: target refreshes via NOTIFY requests are handled via
// ClientSubscription usage after NOTIFY ordering is confirmed
if (msg.isRequest() || (msg.isResponse() && msg.header(h_StatusLine).statusCode()/100 == 2)) if (msg.isRequest() || (msg.isResponse() && msg.header(h_StatusLine).statusCode()/100 == 2))
{ {
//?dcm? modify local target; 12.2.2 of 3261 implies that the remote //?dcm? modify local target; 12.2.2 of 3261 implies that the remote
@ -403,13 +406,12 @@ Dialog::dispatch(const SipMessage& msg)
DebugLog ( << "Dialog::dispatch: " << msg.brief()); DebugLog ( << "Dialog::dispatch: " << msg.brief());
if(msg.isExternal()) if(msg.isFromWire())
{ {
const Data& receivedTransport = msg.header(h_Vias).front().transport(); TransportType receivedTransport = toTransportType(
msg.header(h_Vias).front().transport());
int keepAliveTime = 0; int keepAliveTime = 0;
if(receivedTransport == Symbols::TCP || if(isReliable(receivedTransport))
receivedTransport == Symbols::TLS ||
receivedTransport == Symbols::SCTP)
{ {
keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream(); keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream();
} }
@ -483,6 +485,17 @@ Dialog::dispatch(const SipMessage& msg)
mInviteSession->dispatch(request); mInviteSession->dispatch(request);
} }
break; break;
case PRACK:
if (mInviteSession == 0)
{
InfoLog ( << "Spurious PRACK" );
return;
}
else
{
mInviteSession->dispatch(request);
}
break;
case ACK: case ACK:
case CANCEL: case CANCEL:
if (mInviteSession == 0) if (mInviteSession == 0)
@ -552,7 +565,7 @@ Dialog::dispatch(const SipMessage& msg)
(request.exists(h_Requires) && (request.exists(h_Requires) &&
request.header(h_Requires).find(Token("norefersub")))) request.header(h_Requires).find(Token("norefersub"))))
{ {
assert(mInviteSession); resip_assert(mInviteSession);
mInviteSession->referNoSub(msg); mInviteSession->referNoSub(msg);
} }
else else
@ -622,7 +635,7 @@ Dialog::dispatch(const SipMessage& msg)
} }
break; break;
default: default:
assert(0); resip_assert(0);
return; return;
} }
} }
@ -642,7 +655,7 @@ Dialog::dispatch(const SipMessage& msg)
{ {
InfoLog( << "about to re-send request with digest credentials" << r->second->brief()); InfoLog( << "about to re-send request with digest credentials" << r->second->brief());
assert (r->second->isRequest()); resip_assert (r->second->isRequest());
mLocalCSeq++; mLocalCSeq++;
send(r->second); send(r->second);
@ -665,8 +678,21 @@ Dialog::dispatch(const SipMessage& msg)
} }
else else
{ {
// Ensure that if the route-set in the 200 is empty, then we overwrite any existing route-sets // Note: This is code to facilitate Dialog recovery, and works in conjunction with the
mRouteSet.clear(); // makeInviteSession API that takes a DialogSetId parameter.
// If our original outbound request contained a to tag, then we are attempting to restore a previously
// existing (outside this process) dialog. Some clients will send the routeset to use as Record-Routes
// in the response, in which case the code above will store them. However clients are not mandated to
// do so, so if our outbound INVITE had routes on it, then store these as the routeset for the dialog.
if (creator->getLastRequest()->header(h_To).exists(p_tag) && creator->getLastRequest()->exists(h_Routes))
{
mRouteSet = creator->getLastRequest()->header(h_Routes);
}
else
{
// Ensure that if the route-set in the 200 is empty, then we overwrite any existing route-sets
mRouteSet.clear();
}
} }
} }
@ -700,6 +726,7 @@ Dialog::dispatch(const SipMessage& msg)
case INFO: case INFO:
case MESSAGE: case MESSAGE:
case UPDATE: case UPDATE:
case PRACK:
if (mInviteSession) if (mInviteSession)
{ {
mInviteSession->dispatch(response); mInviteSession->dispatch(response);
@ -707,7 +734,7 @@ Dialog::dispatch(const SipMessage& msg)
// else drop on the floor // else drop on the floor
break; break;
case REFER: case REFER:
if(mInviteSession) if(mInviteSession)
{ {
if (code >= 300) if (code >= 300)
@ -733,39 +760,11 @@ Dialog::dispatch(const SipMessage& msg)
case SUBSCRIBE: case SUBSCRIBE:
{ {
int code = response.header(h_StatusLine).statusCode();
ClientSubscription* client = findMatchingClientSub(response); ClientSubscription* client = findMatchingClientSub(response);
if (client) if (client)
{ {
client->dispatch(response); client->dispatch(response);
} }
else if (code < 300)
{
/*
we're capturing the value from the expires header off
the 2xx because the ClientSubscription is only created
after receiving the NOTIFY that comes (usually) after
this 2xx. We really should be creating the
ClientSubscription at either the 2xx or the NOTIFY
whichever arrives first. .mjf.
Note: we're capturing a duration here (not the
absolute time because all the inputs to
ClientSubscription desling with the expiration are expecting
duration type values from the headers. .mjf.
*/
if(response.exists(h_Expires))
{
mDefaultSubExpiration = response.header(h_Expires).value();
}
else
{
//?dcm? defaults to 3600 in ClientSubscription if no expires value
//is provided anywhere...should we assume the value from the
//sub in the basecreator if it exists?
mDefaultSubExpiration = 0;
}
return;
}
else else
{ {
//!dcm! -- can't subscribe in an existing Dialog, this is all //!dcm! -- can't subscribe in an existing Dialog, this is all
@ -792,9 +791,8 @@ Dialog::dispatch(const SipMessage& msg)
break; break;
case NOTIFY: case NOTIFY:
{ {
//2xx responses are treated as retransmission quenchers(handled by //Failures are dispatched to all ServerSubsscriptions,
//the stack). Failures are dispatched to all ServerSubsscriptions, //which may not be correct as per RFC 5057.
//which may not be correct.
int code = msg.header(h_StatusLine).statusCode(); int code = msg.header(h_StatusLine).statusCode();
if (code >= 300) if (code >= 300)
@ -811,49 +809,20 @@ Dialog::dispatch(const SipMessage& msg)
mDestroying = false; mDestroying = false;
possiblyDie(); possiblyDie();
} }
// ServerSubscription* server = findMatchingServerSub(response); else if (code >= 200)
// if (server) {
// { ServerSubscription* server = findMatchingServerSub(response);
// server->dispatch(response); if (server)
// } {
server->dispatch(response);
}
}
} }
break; break;
default: default:
assert(0); resip_assert(0);
return; return;
} }
#if 0 // merged from head back to teltel-branch
if (msg.header(h_StatusLine).statusCode() >= 400
&& Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)
{
//kill all usages
mDestroying = true;
for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
it != mServerSubscriptions.end(); )
{
ServerSubscription* s = *it;
it++;
s->dialogDestroyed(msg);
}
for (list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();
it != mClientSubscriptions.end(); )
{
ClientSubscription* s = *it;
it++;
s->dialogDestroyed(msg);
}
if (mInviteSession)
{
mInviteSession->dialogDestroyed(msg);
}
mDestroying = false;
possiblyDie(); //should aways result in destruction of this
return;
}
#endif
} }
} }
@ -978,7 +947,7 @@ Dialog::redirected(const SipMessage& msg)
} }
void void
Dialog::makeRequest(SipMessage& request, MethodTypes method) Dialog::makeRequest(SipMessage& request, MethodTypes method, bool incrementCSeq)
{ {
RequestLine rLine(method); RequestLine rLine(method);
@ -1012,13 +981,16 @@ Dialog::makeRequest(SipMessage& request, MethodTypes method)
} }
else else
{ {
assert(request.exists(h_Vias)); resip_assert(request.exists(h_Vias));
} }
//don't increment CSeq for ACK or CANCEL //don't increment CSeq for ACK or CANCEL
if (method != ACK && method != CANCEL) if (method != ACK && method != CANCEL)
{ {
request.header(h_CSeq).sequence() = ++mLocalCSeq; if(incrementCSeq)
{
setRequestNextCSeq(request);
}
} }
else else
{ {
@ -1036,31 +1008,28 @@ Dialog::makeRequest(SipMessage& request, MethodTypes method)
// If method is INVITE then advertise required headers // If method is INVITE then advertise required headers
if(method == INVITE || method == UPDATE) if(method == INVITE || method == UPDATE)
{ {
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods(); // Add Advertised Capabilities
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings(); mDum.setAdvertisedCapabilities(request, mDialogSet.mUserProfile);
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptLanguage)) request.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AllowEvents)) request.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Supported)) request.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
} }
if (mDialogSet.mUserProfile->isAnonymous()) if (mDialogSet.mUserProfile->isAnonymous())
{ {
request.remove(h_Privacys);
request.header(h_Privacys).push_back(PrivacyCategory(Symbols::id)); request.header(h_Privacys).push_back(PrivacyCategory(Symbols::id));
} }
DebugLog ( << "Dialog::makeRequest: " << std::endl << std::endl << request ); DebugLog ( << "Dialog::makeRequest: " << std::endl << std::endl << request );
} }
void void
Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code) Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
{ {
assert( code >= 100 ); resip_assert( code >= 100 );
response.remove(h_Contacts); response.remove(h_Contacts);
if (code < 300 && code > 100) if (code < 300 && code > 100)
{ {
assert(request.isRequest()); resip_assert(request.isRequest());
assert(request.header(h_RequestLine).getMethod() == INVITE || resip_assert(request.header(h_RequestLine).getMethod() == INVITE ||
request.header(h_RequestLine).getMethod() == SUBSCRIBE || request.header(h_RequestLine).getMethod() == SUBSCRIBE ||
request.header(h_RequestLine).getMethod() == BYE || request.header(h_RequestLine).getMethod() == BYE ||
request.header(h_RequestLine).getMethod() == CANCEL || request.header(h_RequestLine).getMethod() == CANCEL ||
@ -1069,6 +1038,7 @@ Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
request.header(h_RequestLine).getMethod() == NOTIFY || request.header(h_RequestLine).getMethod() == NOTIFY ||
request.header(h_RequestLine).getMethod() == INFO || request.header(h_RequestLine).getMethod() == INFO ||
request.header(h_RequestLine).getMethod() == OPTIONS || request.header(h_RequestLine).getMethod() == OPTIONS ||
request.header(h_RequestLine).getMethod() == PRACK ||
request.header(h_RequestLine).getMethod() == UPDATE request.header(h_RequestLine).getMethod() == UPDATE
); );
@ -1079,30 +1049,12 @@ Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
response.header(h_To).param(p_tag) = mId.getLocalTag(); response.header(h_To).param(p_tag) = mId.getLocalTag();
if((request.header(h_RequestLine).getMethod() == INVITE || if((request.header(h_RequestLine).getMethod() == INVITE ||
request.header(h_RequestLine).getMethod() == PRACK ||
request.header(h_RequestLine).getMethod() == UPDATE) request.header(h_RequestLine).getMethod() == UPDATE)
&& code >= 200 && code < 300) && code >= 200 && code < 300)
{ {
// Check if we should add our capabilites to the invite success response // Add Advertised Capabilities
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Allow)) mDum.setAdvertisedCapabilities(response, mDialogSet.mUserProfile);
{
response.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
}
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptEncoding))
{
response.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
}
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptLanguage))
{
response.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
}
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AllowEvents))
{
response.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
}
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Supported))
{
response.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
}
} }
} }
else else
@ -1114,6 +1066,12 @@ Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
DebugLog ( << "Dialog::makeResponse: " << std::endl << std::endl << response); DebugLog ( << "Dialog::makeResponse: " << std::endl << std::endl << response);
} }
void
Dialog::setRequestNextCSeq(SipMessage& request)
{
resip_assert(request.isRequest() && request.method() != ACK && request.method() != CANCEL);
request.header(h_CSeq).sequence() = ++mLocalCSeq;
}
ClientInviteSession* ClientInviteSession*
Dialog::makeClientInviteSession(const SipMessage& response) Dialog::makeClientInviteSession(const SipMessage& response)
@ -1121,7 +1079,7 @@ Dialog::makeClientInviteSession(const SipMessage& response)
InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator()); InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
if (!creator) if (!creator)
{ {
assert(0); // !jf! this maybe can assert by evil UAS resip_assert(0); // !jf! this maybe can assert by evil UAS
return 0; return 0;
} }
//return mDum.createAppClientInviteSession(*this, *creator); //return mDum.createAppClientInviteSession(*this, *creator);
@ -1129,15 +1087,12 @@ Dialog::makeClientInviteSession(const SipMessage& response)
creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription()); creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription());
} }
ClientSubscription* ClientSubscription*
Dialog::makeClientSubscription(const SipMessage& request) Dialog::makeClientSubscription(const SipMessage& request)
{ {
return new ClientSubscription(mDum, *this, request, mDefaultSubExpiration); return new ClientSubscription(mDum, *this, request);
} }
ServerInviteSession* ServerInviteSession*
Dialog::makeServerInviteSession(const SipMessage& request) Dialog::makeServerInviteSession(const SipMessage& request)
{ {

View File

@ -51,8 +51,9 @@ class Dialog
void send(SharedPtr<SipMessage> msg); void send(SharedPtr<SipMessage> msg);
//void send(SipMessage& msg); //void send(SipMessage& msg);
void makeRequest(SipMessage& request, MethodTypes method); void makeRequest(SipMessage& request, MethodTypes method, bool incrementCSeq = true);
void makeResponse(SipMessage& response, const SipMessage& request, int responseCode); void makeResponse(SipMessage& response, const SipMessage& request, int responseCode);
void setRequestNextCSeq(SipMessage& request);
//void setLocalContact(const NameAddr& localContact); //void setLocalContact(const NameAddr& localContact);
//void setRemoteTarget(const NameAddr& remoteTarget); //void setRemoteTarget(const NameAddr& remoteTarget);
@ -145,9 +146,6 @@ class Dialog
NameAddr mLocalNameAddr; NameAddr mLocalNameAddr;
NameAddr mRemoteNameAddr; NameAddr mRemoteNameAddr;
CallID mCallId; CallID mCallId;
// used to capture the 2xx expiration value for the initial subscription response
UInt32 mDefaultSubExpiration;
// store until we get a response (non-401/407) // store until we get a response (non-401/407)
// !jf! this shouldn't be necessary // !jf! this shouldn't be necessary

View File

@ -31,17 +31,17 @@ DialogEventInfo::DialogEventInfo(const DialogEventInfo& rhs)
{ {
if (rhs.mReplacesId.get()) if (rhs.mReplacesId.get())
{ {
mReplacesId = std::unique_ptr<DialogId>(new DialogId(rhs.mReplacesId->getCallId(), mReplacesId = std::auto_ptr<DialogId>(new DialogId(rhs.mReplacesId->getCallId(),
rhs.mReplacesId->getLocalTag(), rhs.mReplacesId->getLocalTag(),
rhs.mReplacesId->getRemoteTag())); rhs.mReplacesId->getRemoteTag()));
} }
if (rhs.mLocalOfferAnswer.get()) if (rhs.mLocalOfferAnswer.get())
{ {
mLocalOfferAnswer = std::unique_ptr<Contents>(rhs.mLocalOfferAnswer->clone()); mLocalOfferAnswer = std::auto_ptr<Contents>(rhs.mLocalOfferAnswer->clone());
} }
if (rhs.mRemoteOfferAnswer.get()) if (rhs.mRemoteOfferAnswer.get())
{ {
mRemoteOfferAnswer = std::unique_ptr<Contents>(rhs.mRemoteOfferAnswer->clone()); mRemoteOfferAnswer = std::auto_ptr<Contents>(rhs.mRemoteOfferAnswer->clone());
} }
} }
@ -217,7 +217,7 @@ DialogEventInfo::getLocalOfferAnswer() const
return mInviteSession->getLocalOfferAnswer(); return mInviteSession->getLocalOfferAnswer();
} }
} }
assert(mLocalOfferAnswer.get() != NULL); resip_assert(mLocalOfferAnswer.get() != NULL);
return *mLocalOfferAnswer; return *mLocalOfferAnswer;
} }
@ -231,7 +231,7 @@ DialogEventInfo::getRemoteOfferAnswer() const
return mInviteSession->getRemoteOfferAnswer(); return mInviteSession->getRemoteOfferAnswer();
} }
} }
assert(mRemoteOfferAnswer.get() != NULL); resip_assert(mRemoteOfferAnswer.get() != NULL);
return *mRemoteOfferAnswer; return *mRemoteOfferAnswer;
} }

View File

@ -83,22 +83,22 @@ class DialogEventInfo
DialogId mDialogId; DialogId mDialogId;
Direction mDirection; Direction mDirection;
//ID of the dialog this dialog replaced. //ID of the dialog this dialog replaced.
std::unique_ptr<DialogId> mReplacesId; std::auto_ptr<DialogId> mReplacesId;
InviteSessionHandle mInviteSession; InviteSessionHandle mInviteSession;
std::unique_ptr<NameAddr> mReferredBy; std::auto_ptr<NameAddr> mReferredBy;
//could back-point to dialog for this information to save space //could back-point to dialog for this information to save space
NameAddrs mRouteSet; NameAddrs mRouteSet;
NameAddr mLocalIdentity; NameAddr mLocalIdentity;
NameAddr mRemoteIdentity; NameAddr mRemoteIdentity;
Uri mLocalTarget; Uri mLocalTarget;
std::unique_ptr<Uri> mRemoteTarget; std::auto_ptr<Uri> mRemoteTarget;
UInt64 mCreationTimeSeconds; UInt64 mCreationTimeSeconds;
std::unique_ptr<Contents> mLocalOfferAnswer; std::auto_ptr<Contents> mLocalOfferAnswer;
std::unique_ptr<Contents> mRemoteOfferAnswer; std::auto_ptr<Contents> mRemoteOfferAnswer;
private: private:
bool mReplaced; bool mReplaced;

View File

@ -26,11 +26,11 @@ DialogEventStateManager::onTryingUas(Dialog& dialog, const SipMessage& invite)
eventInfo->mDirection = DialogEventInfo::Recipient; eventInfo->mDirection = DialogEventInfo::Recipient;
eventInfo->mCreationTimeSeconds = Timer::getTimeSecs(); eventInfo->mCreationTimeSeconds = Timer::getTimeSecs();
eventInfo->mInviteSession = InviteSessionHandle::NotValid(); eventInfo->mInviteSession = InviteSessionHandle::NotValid();
eventInfo->mRemoteOfferAnswer = (invite.getContents() != NULL ? std::unique_ptr<Contents>(invite.getContents()->clone()) : std::unique_ptr<Contents>()); eventInfo->mRemoteOfferAnswer = (invite.getContents() != NULL ? std::auto_ptr<Contents>(invite.getContents()->clone()) : std::auto_ptr<Contents>());
eventInfo->mLocalIdentity = dialog.getLocalNameAddr(); eventInfo->mLocalIdentity = dialog.getLocalNameAddr();
eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in
eventInfo->mRemoteIdentity = dialog.getRemoteNameAddr(); eventInfo->mRemoteIdentity = dialog.getRemoteNameAddr();
eventInfo->mRemoteTarget = std::unique_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
eventInfo->mRouteSet = dialog.getRouteSet(); eventInfo->mRouteSet = dialog.getRouteSet();
eventInfo->mState = DialogEventInfo::Trying; eventInfo->mState = DialogEventInfo::Trying;
@ -40,20 +40,25 @@ DialogEventStateManager::onTryingUas(Dialog& dialog, const SipMessage& invite)
Data replacesToTag = invite.header(h_Replaces).exists(p_toTag) ? invite.header(h_Replaces).param(p_toTag) : Data::Empty; Data replacesToTag = invite.header(h_Replaces).exists(p_toTag) ? invite.header(h_Replaces).param(p_toTag) : Data::Empty;
Data replacesFromTag = invite.header(h_Replaces).exists(p_fromTag) ? invite.header(h_Replaces).param(p_fromTag) : Data::Empty; Data replacesFromTag = invite.header(h_Replaces).exists(p_fromTag) ? invite.header(h_Replaces).param(p_fromTag) : Data::Empty;
eventInfo->mReplacesId = std::unique_ptr<DialogId>(new DialogId(invite.header(h_Replaces).value(), eventInfo->mReplacesId = std::auto_ptr<DialogId>(new DialogId(invite.header(h_Replaces).value(),
replacesToTag, replacesToTag,
replacesFromTag)); replacesFromTag));
std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(*(eventInfo->mReplacesId)); std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(*(eventInfo->mReplacesId));
if (it != mDialogIdToEventInfo.end()) if (it != mDialogIdToEventInfo.end())
{ {
it->second->mReplaced = true; // If the call to be replaced is early and it is a recipient, then it cannot get replaced (according to RFC3891)
// so we don't want to set the flag in this case. Using inverted logic statement.
if (it->second->getState() != DialogEventInfo::Early || it->second->getDirection() != DialogEventInfo::Recipient)
{
it->second->mReplaced = true;
}
} }
} }
if (invite.exists(h_ReferredBy) && if (invite.exists(h_ReferredBy) &&
invite.header(h_ReferredBy).isWellFormed()) invite.header(h_ReferredBy).isWellFormed())
{ {
eventInfo->mReferredBy = std::unique_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy))); eventInfo->mReferredBy = std::auto_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy)));
} }
mDialogIdToEventInfo[dialog.getId()] = eventInfo; mDialogIdToEventInfo[dialog.getId()] = eventInfo;
@ -94,17 +99,17 @@ DialogEventStateManager::onTryingUac(DialogSet& dialogSet, const SipMessage& inv
// ?bwc? Has something already checked for well-formedness here? // ?bwc? Has something already checked for well-formedness here?
// Maybe DialogSet? We need to be absolutely certain that this exists and is // Maybe DialogSet? We need to be absolutely certain that this exists and is
// well-formed. Assert for now. // well-formed. Assert for now.
assert(!invite.empty(h_Contacts)); resip_assert(!invite.empty(h_Contacts));
assert(invite.header(h_Contacts).front().isWellFormed()); resip_assert(invite.header(h_Contacts).front().isWellFormed());
eventInfo->mLocalTarget = invite.header(h_Contacts).front().uri(); eventInfo->mLocalTarget = invite.header(h_Contacts).front().uri();
eventInfo->mRemoteIdentity = invite.header(h_To); eventInfo->mRemoteIdentity = invite.header(h_To);
eventInfo->mLocalOfferAnswer = (invite.getContents() != NULL ? std::unique_ptr<Contents>(invite.getContents()->clone()) : std::unique_ptr<Contents>()); eventInfo->mLocalOfferAnswer = (invite.getContents() != NULL ? std::auto_ptr<Contents>(invite.getContents()->clone()) : std::auto_ptr<Contents>());
eventInfo->mState = DialogEventInfo::Trying; eventInfo->mState = DialogEventInfo::Trying;
if (invite.exists(h_ReferredBy) && if (invite.exists(h_ReferredBy) &&
invite.header(h_ReferredBy).isWellFormed()) invite.header(h_ReferredBy).isWellFormed())
{ {
eventInfo->mReferredBy = std::unique_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy))); eventInfo->mReferredBy = std::auto_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy)));
} }
mDialogIdToEventInfo[eventInfo->mDialogId] = eventInfo; mDialogIdToEventInfo[eventInfo->mDialogId] = eventInfo;
@ -131,8 +136,8 @@ DialogEventStateManager::onProceedingUac(const DialogSet& dialogSet, const SipMe
{ {
// ?bwc? Has something already checked for well-formedness here? // ?bwc? Has something already checked for well-formedness here?
// Maybe DialogSet? Assert for now. // Maybe DialogSet? Assert for now.
assert(response.header(h_Contacts).front().isWellFormed()); resip_assert(response.header(h_Contacts).front().isWellFormed());
eventInfo->mRemoteTarget = std::unique_ptr<Uri>(new Uri(response.header(h_Contacts).front().uri())); eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(response.header(h_Contacts).front().uri()));
} }
ProceedingDialogEvent evt(*eventInfo); ProceedingDialogEvent evt(*eventInfo);
mDialogEventHandler->onProceeding(evt); mDialogEventHandler->onProceeding(evt);
@ -162,7 +167,7 @@ DialogEventStateManager::onEarly(const Dialog& dialog, InviteSessionHandle is)
// local or remote target might change due to an UPDATE or re-INVITE // local or remote target might change due to an UPDATE or re-INVITE
eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in
eventInfo->mRemoteTarget = std::unique_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
EarlyDialogEvent evt(*eventInfo); EarlyDialogEvent evt(*eventInfo);
mDialogEventHandler->onEarly(evt); mDialogEventHandler->onEarly(evt);
@ -183,7 +188,11 @@ DialogEventStateManager::onConfirmed(const Dialog& dialog, InviteSessionHandle i
// local or remote target might change due to an UPDATE or re-INVITE // local or remote target might change due to an UPDATE or re-INVITE
eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in
eventInfo->mRemoteTarget = std::unique_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
// Set the latest sdp
eventInfo->mLocalOfferAnswer = (is->hasLocalOfferAnswer() ? std::auto_ptr<Contents>(is->getLocalOfferAnswer().clone()) : std::auto_ptr<Contents>());
eventInfo->mRemoteOfferAnswer = (is->hasRemoteOfferAnswer() ? std::auto_ptr<Contents>(is->getRemoteOfferAnswer().clone()) : std::auto_ptr<Contents>());
// for the dialog that got the 200 OK // for the dialog that got the 200 OK
SharedPtr<ConfirmedDialogEvent> confirmedEvt(new ConfirmedDialogEvent(*eventInfo)); SharedPtr<ConfirmedDialogEvent> confirmedEvt(new ConfirmedDialogEvent(*eventInfo));
@ -239,7 +248,7 @@ DialogEventStateManager::onTerminated(const Dialog& dialog, const SipMessage& ms
{ {
// .jjg. we're killing a *specific* dialog *after* the successful completion of the initial INVITE transaction; // .jjg. we're killing a *specific* dialog *after* the successful completion of the initial INVITE transaction;
// so just elminate this dialog, not the entire dialogset // so just elminate this dialog, not the entire dialogset
std::unique_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(it->second, reason, getResponseCode(msg), getFrontContact(msg))); std::auto_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(it->second, reason, getResponseCode(msg), getFrontContact(msg)));
mDialogEventHandler->onTerminated(*evt); mDialogEventHandler->onTerminated(*evt);
delete it->second; delete it->second;
mDialogIdToEventInfo.erase(it++); mDialogIdToEventInfo.erase(it++);
@ -283,7 +292,7 @@ DialogEventStateManager::onDialogSetTerminatedImpl(const DialogSetId& dialogSetI
it->first.getDialogSetId() == dialogSetId) it->first.getDialogSetId() == dialogSetId)
{ {
eventInfo = it->second; eventInfo = it->second;
std::unique_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(eventInfo, reason, getResponseCode(msg), getFrontContact(msg))); std::auto_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(eventInfo, reason, getResponseCode(msg), getFrontContact(msg)));
mDialogEventHandler->onTerminated(*evt); mDialogEventHandler->onTerminated(*evt);
delete it->second; delete it->second;
mDialogIdToEventInfo.erase(it++); mDialogIdToEventInfo.erase(it++);
@ -311,7 +320,7 @@ DialogEventStateManager::onDialogTerminatedImpl(DialogEventInfo* eventInfo,
if (remoteTarget) if (remoteTarget)
{ {
eventInfo->mRemoteTarget = std::unique_ptr<Uri>(remoteTarget); eventInfo->mRemoteTarget = std::auto_ptr<Uri>(remoteTarget);
} }
TerminatedDialogEvent* evt = new TerminatedDialogEvent(*eventInfo, actualReason, responseCode); TerminatedDialogEvent* evt = new TerminatedDialogEvent(*eventInfo, actualReason, responseCode);
@ -340,7 +349,7 @@ DialogEventStateManager::getFrontContact(const SipMessage& msg)
{ {
// ?bwc? Has something already checked for well-formedness here? // ?bwc? Has something already checked for well-formedness here?
// Maybe DialogSet? Assert for now. // Maybe DialogSet? Assert for now.
assert(msg.header(h_Contacts).front().isWellFormed()); resip_assert(msg.header(h_Contacts).front().isWellFormed());
pContact = new Uri(msg.header(h_Contacts).front().uri()); pContact = new Uri(msg.header(h_Contacts).front().uri());
} }
} }
@ -359,6 +368,34 @@ DialogEventStateManager::getDialogEventInfo() const
return infos; return infos;
} }
DialogEventStateManager::DialogEventInfos
DialogEventStateManager::getDialogEventInfo(const Uri& entityUri, bool bMatchRemoteIdentityOnly) const
{
DialogEventStateManager::DialogEventInfos infos;
std::map<DialogId, DialogEventInfo*, DialogIdComparator>::const_iterator it = mDialogIdToEventInfo.begin();
for (; it != mDialogIdToEventInfo.end(); it++)
{
if (!bMatchRemoteIdentityOnly)
{
// Return all calls to or from the requested entity
if (it->second->getLocalIdentity().uri().getAOR(false) == entityUri.getAOR(false) ||
it->second->getRemoteIdentity().uri().getAOR(false) == entityUri.getAOR(false))
{
infos.push_back(*(it->second));
}
}
else
{
// Return only those dialogs whose remote identity matches the requested entity
if (it->second->getRemoteIdentity().uri().getAOR(false) == entityUri.getAOR(false))
{
infos.push_back(*(it->second));
}
}
}
return infos;
}
DialogEventInfo* DialogEventInfo*
DialogEventStateManager::findOrCreateDialogInfo(const Dialog& dialog) DialogEventStateManager::findOrCreateDialogInfo(const Dialog& dialog)
{ {
@ -403,7 +440,7 @@ DialogEventStateManager::findOrCreateDialogInfo(const Dialog& dialog)
newForkInfo->mCreationTimeSeconds = Timer::getTimeSecs(); newForkInfo->mCreationTimeSeconds = Timer::getTimeSecs();
newForkInfo->mDialogId = dialog.getId(); newForkInfo->mDialogId = dialog.getId();
newForkInfo->mRemoteIdentity = dialog.getRemoteNameAddr(); newForkInfo->mRemoteIdentity = dialog.getRemoteNameAddr();
newForkInfo->mRemoteTarget = std::unique_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); newForkInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
newForkInfo->mRouteSet = dialog.getRouteSet(); newForkInfo->mRouteSet = dialog.getRouteSet();
eventInfo = newForkInfo; eventInfo = newForkInfo;
} }

View File

@ -19,6 +19,7 @@ class DialogEventStateManager
public: public:
typedef std::vector<DialogEventInfo> DialogEventInfos; typedef std::vector<DialogEventInfo> DialogEventInfos;
DialogEventInfos getDialogEventInfo() const; DialogEventInfos getDialogEventInfo() const;
DialogEventInfos getDialogEventInfo(const Uri& entityUri, bool bMatchRemoteIdentityOnly = false) const;
virtual ~DialogEventStateManager(); virtual ~DialogEventStateManager();

View File

@ -48,7 +48,7 @@ DialogSet::DialogSet(BaseCreator* creator, DialogUsageManager& dum) :
mServerPagerMessage(0) mServerPagerMessage(0)
{ {
setUserProfile(creator->getUserProfile()); setUserProfile(creator->getUserProfile());
assert(!creator->getLastRequest()->isExternal()); resip_assert(!creator->getLastRequest()->isExternal());
DebugLog ( << " ************* Created DialogSet(UAC) -- " << mId << "*************" ); DebugLog ( << " ************* Created DialogSet(UAC) -- " << mId << "*************" );
} }
@ -69,8 +69,8 @@ DialogSet::DialogSet(const SipMessage& request, DialogUsageManager& dum) :
mClientPagerMessage(0), mClientPagerMessage(0),
mServerPagerMessage(0) mServerPagerMessage(0)
{ {
assert(request.isRequest()); resip_assert(request.isRequest());
assert(request.isExternal()); resip_assert(request.isExternal());
mDum.mMergedRequests.insert(mMergeKey); mDum.mMergedRequests.insert(mMergeKey);
if (request.header(h_RequestLine).method() == INVITE) if (request.header(h_RequestLine).method() == INVITE)
{ {
@ -338,18 +338,18 @@ DialogSet::dispatch(const SipMessage& msg)
} }
else else
{ {
ErrLog(<<"Response came in, but no AppDialogSet! Dropping this is very" ErrLog(<<"Response came in, but no AppDialogSet! Dropping this is very "
"likely to cause leaks, but continuing to process it is " "likely to cause leaks, but continuing to process it is "
"likely to cause a core. Taking the lesser of two evils..."); "likely to cause a core. Taking the lesser of two evils...");
} }
return; return;
} }
assert(msg.isRequest() || msg.isResponse()); resip_assert(msg.isRequest() || msg.isResponse());
if (mState == WaitingToEnd) if (mState == WaitingToEnd)
{ {
assert(mDialogs.empty()); resip_assert(mDialogs.empty());
if (msg.isResponse()) if (msg.isResponse())
{ {
int code = msg.header(h_StatusLine).statusCode(); int code = msg.header(h_StatusLine).statusCode();
@ -451,7 +451,7 @@ DialogSet::dispatch(const SipMessage& msg)
} }
else if(mState == Cancelling) else if(mState == Cancelling)
{ {
assert(mDialogs.empty()); resip_assert(mDialogs.empty());
if (msg.isResponse()) if (msg.isResponse())
{ {
int code = msg.header(h_StatusLine).statusCode(); int code = msg.header(h_StatusLine).statusCode();
@ -520,7 +520,7 @@ DialogSet::dispatch(const SipMessage& msg)
} }
else else
{ {
StackLog (<< "Matching dialog is destroying, dropping response message " << endl << msg); StackLog (<< "Matching dialog is destroying, dropping response message " << endl << msg);
} }
return; return;
} }
@ -547,6 +547,7 @@ DialogSet::dispatch(const SipMessage& msg)
case BYE: case BYE:
case INFO: case INFO:
case ACK: case ACK:
case PRACK:
case UPDATE: case UPDATE:
if(!dialog) if(!dialog)
{ {
@ -570,7 +571,7 @@ DialogSet::dispatch(const SipMessage& msg)
request.header(h_Requires).find(Token("norefersub"))))// out of dialog & noReferSub=true request.header(h_Requires).find(Token("norefersub"))))// out of dialog & noReferSub=true
{ {
DebugLog(<< "out of dialog refer request with norefersub"); DebugLog(<< "out of dialog refer request with norefersub");
assert(mServerOutOfDialogRequest == 0); resip_assert(mServerOutOfDialogRequest == 0);
mServerOutOfDialogRequest = makeServerOutOfDialog(request); mServerOutOfDialogRequest = makeServerOutOfDialog(request);
mServerOutOfDialogRequest->dispatch(request); mServerOutOfDialogRequest->dispatch(request);
return; return;
@ -592,7 +593,7 @@ DialogSet::dispatch(const SipMessage& msg)
{ {
// unsolicited - not allowed but commonly implemented // unsolicited - not allowed but commonly implemented
// by large companies with a bridge as their logo // by large companies with a bridge as their logo
assert(mServerOutOfDialogRequest == 0); resip_assert(mServerOutOfDialogRequest == 0);
mServerOutOfDialogRequest = makeServerOutOfDialog(request); mServerOutOfDialogRequest = makeServerOutOfDialog(request);
mServerOutOfDialogRequest->dispatch(request); mServerOutOfDialogRequest->dispatch(request);
return; return;
@ -600,7 +601,7 @@ DialogSet::dispatch(const SipMessage& msg)
break; break;
case PUBLISH: case PUBLISH:
assert(false); // handled in DialogUsageManager resip_assert(false); // handled in DialogUsageManager
return; return;
case REGISTER: case REGISTER:
@ -626,7 +627,7 @@ DialogSet::dispatch(const SipMessage& msg)
// !jf! move this to DialogUsageManager // !jf! move this to DialogUsageManager
DebugLog ( << "In DialogSet::dispatch, default(ServerOutOfDialogRequest), msg: " << msg ); DebugLog ( << "In DialogSet::dispatch, default(ServerOutOfDialogRequest), msg: " << msg );
// only can be one ServerOutOfDialogReq at a time // only can be one ServerOutOfDialogReq at a time
assert(mServerOutOfDialogRequest == 0); resip_assert(mServerOutOfDialogRequest == 0);
mServerOutOfDialogRequest = makeServerOutOfDialog(request); mServerOutOfDialogRequest = makeServerOutOfDialog(request);
mServerOutOfDialogRequest->dispatch(request); mServerOutOfDialogRequest->dispatch(request);
return; return;
@ -742,7 +743,7 @@ DialogSet::dispatch(const SipMessage& msg)
return; return;
case MESSAGE: case MESSAGE:
if (dialog) if (dialog)
{ {
break; break;
} }
@ -754,6 +755,7 @@ DialogSet::dispatch(const SipMessage& msg)
case INFO: case INFO:
case UPDATE: case UPDATE:
case PRACK:
if (dialog) if (dialog)
{ {
break; break;
@ -791,7 +793,19 @@ DialogSet::dispatch(const SipMessage& msg)
{ {
if (msg.isRequest() && msg.header(h_RequestLine).method() == CANCEL) if (msg.isRequest() && msg.header(h_RequestLine).method() == CANCEL)
{ {
dispatchToAllDialogs(msg); if(!mDialogs.empty())
{
dispatchToAllDialogs(msg);
}
else
{
DebugLog ( << "In DialogSet::dispatch, CANCEL received but no dialogs to dispatch to - respond with 481, msg: " << msg );
// Race condition - Dialogset is still around, but dialog is gone (potentially BYE'd).
// Need to respond to CANCEL in order for transaction in stack to go away
SharedPtr<SipMessage> response(new SipMessage);
mDum.makeResponse(*response, msg, 481);
mDum.send(response);
}
return; return;
} }
@ -883,7 +897,7 @@ DialogSet::dispatch(const SipMessage& msg)
return; return;
} }
assert(mState != WaitingToEnd); resip_assert(mState != WaitingToEnd);
DebugLog ( << "### Calling CreateAppDialog ###: " << std::endl << std::endl <<msg); DebugLog ( << "### Calling CreateAppDialog ###: " << std::endl << std::endl <<msg);
AppDialog* appDialog = mAppDialogSet->createAppDialog(msg); AppDialog* appDialog = mAppDialogSet->createAppDialog(msg);
dialog->mAppDialog = appDialog; dialog->mAppDialog = appDialog;
@ -946,38 +960,63 @@ DialogSet::end()
break; break;
case ReceivedProvisional: case ReceivedProvisional:
{ {
assert (mCreator->getLastRequest()->header(h_CSeq).method() == INVITE); if (mCreator->getLastRequest()->header(h_CSeq).method() == INVITE)
mState = Terminating; {
// !jf! this should be made exception safe mState = Terminating;
SharedPtr<SipMessage> cancel(Helper::makeCancel(*getCreator()->getLastRequest())); // !jf! this should be made exception safe
mDum.send(cancel); SharedPtr<SipMessage> cancel(Helper::makeCancel(*getCreator()->getLastRequest()));
mDum.send(cancel);
if (mDum.mDialogEventStateManager) if (mDum.mDialogEventStateManager)
{
mDum.mDialogEventStateManager->onTerminated(*this, *cancel, InviteSessionHandler::LocalCancel);
}
if (mDialogs.empty())
{
mState = Cancelling;
}
else
{
//need to lag and do last element ouside of look as this DialogSet will be
//deleted if all dialogs are destroyed
for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
{ {
try mDum.mDialogEventStateManager->onTerminated(*this, *cancel, InviteSessionHandler::LocalCancel);
}
if (mDialogs.empty())
{
mState = Cancelling;
}
else
{
//need to lag and do last element ouside of look as this DialogSet will be
//deleted if all dialogs are destroyed
for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
{ {
it->second->cancel(); try
} {
catch(UsageUseException& e) it->second->cancel();
{ }
InfoLog (<< "Caught: " << e); catch (UsageUseException& e)
{
InfoLog(<< "Caught: " << e);
}
} }
} }
} }
} else
{
// Non-Invite Dialogset
if (mDialogs.empty())
{
mState = WaitingToEnd;
}
else
{
for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); ++it)
{
try
{
it->second->end();
}
catch (UsageUseException& e)
{
InfoLog(<< "Caught: " << e);
}
}
mState = Terminating;
}
}
}
break; break;
case Established: case Established:
{ {
@ -1047,7 +1086,7 @@ ClientRegistration*
DialogSet::makeClientRegistration(const SipMessage& response) DialogSet::makeClientRegistration(const SipMessage& response)
{ {
BaseCreator* creator = getCreator(); BaseCreator* creator = getCreator();
assert(creator); resip_assert(creator);
return new ClientRegistration(mDum, *this, creator->getLastRequest()); return new ClientRegistration(mDum, *this, creator->getLastRequest());
} }
@ -1055,7 +1094,7 @@ ClientPublication*
DialogSet::makeClientPublication(const SipMessage& response) DialogSet::makeClientPublication(const SipMessage& response)
{ {
BaseCreator* creator = getCreator(); BaseCreator* creator = getCreator();
assert(creator); resip_assert(creator);
return new ClientPublication(mDum, *this, creator->getLastRequest()); return new ClientPublication(mDum, *this, creator->getLastRequest());
} }
@ -1063,7 +1102,7 @@ ClientOutOfDialogReq*
DialogSet::makeClientOutOfDialogReq(const SipMessage& response) DialogSet::makeClientOutOfDialogReq(const SipMessage& response)
{ {
BaseCreator* creator = getCreator(); BaseCreator* creator = getCreator();
assert(creator); resip_assert(creator);
return new ClientOutOfDialogReq(mDum, *this, *creator->getLastRequest()); return new ClientOutOfDialogReq(mDum, *this, *creator->getLastRequest());
} }
@ -1126,7 +1165,7 @@ DialogSet::getUserProfile() const
void void
DialogSet::setUserProfile(SharedPtr<UserProfile> userProfile) DialogSet::setUserProfile(SharedPtr<UserProfile> userProfile)
{ {
assert(userProfile.get()); resip_assert(userProfile.get());
mUserProfile = userProfile; mUserProfile = userProfile;
} }

View File

@ -81,7 +81,7 @@ class DialogSet
/// Abandon this dialog set, but keep the AppDialogSet around /// Abandon this dialog set, but keep the AppDialogSet around
void appDissociate() void appDissociate()
{ {
assert(mAppDialogSet); resip_assert(mAppDialogSet);
mAppDialogSet = 0; mAppDialogSet = 0;
} }
friend class AppDialogSet; friend class AppDialogSet;

View File

@ -40,12 +40,12 @@ DialogSetId::DialogSetId(const SipMessage& msg) :
{ {
if(msg.isRequest()) if(msg.isRequest())
{ {
assert(msg.header(h_From).exists(p_tag)); resip_assert(msg.header(h_From).exists(p_tag));
mTag = msg.header(h_From).param(p_tag); mTag = msg.header(h_From).param(p_tag);
} }
else else
{ {
assert(msg.header(h_To).exists(p_tag)); resip_assert(msg.header(h_To).exists(p_tag));
mTag = msg.header(h_To).param(p_tag); mTag = msg.header(h_To).param(p_tag);
} }
} }

View File

@ -4,26 +4,13 @@
#include "resip/dum/Dialog.hxx" #include "resip/dum/Dialog.hxx"
#include "resip/dum/DialogSet.hxx" #include "resip/dum/DialogSet.hxx"
#include "resip/dum/DialogUsageManager.hxx" #include "resip/dum/DialogUsageManager.hxx"
#include "resip/stack/ExtensionHeader.hxx" #include "rutil/ResipAssert.h"
#include "resip/stack/ExtensionParameter.hxx"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
using namespace resip; using namespace resip;
static void putUserHeaders(const std::map<std::string, std::string>& hdr, SipMessage& msg)
{
for (std::map<std::string, std::string>::const_iterator iter = hdr.begin(); iter != hdr.end(); iter++)
{
const std::string& name = iter->first;
const std::string& value = iter->second;
msg.header(ExtensionHeader(name.c_str())).push_back(StringCategory(value.c_str()));
}
}
DialogUsage::Exception::Exception(const Data& msg,const Data& file,int line) DialogUsage::Exception::Exception(const Data& msg,const Data& file,int line)
: BaseException(msg, file, line) : BaseException(msg, file, line)
{ {
@ -49,6 +36,11 @@ DialogUsage::~DialogUsage()
AppDialogSetHandle AppDialogSetHandle
DialogUsage::getAppDialogSet() DialogUsage::getAppDialogSet()
{ {
if (mDialog.mDialogSet.mAppDialogSet == 0)
{
ErrLog(<< "mDialog.mDialogSet.mAppDialogSet is NULL!!!");
return AppDialogSetHandle();
}
return mDialog.mDialogSet.mAppDialogSet->getHandle(); return mDialog.mDialogSet.mAppDialogSet->getHandle();
} }
@ -76,6 +68,12 @@ DialogUsage::remoteTarget() const
return mDialog.mRemoteTarget; return mDialog.mRemoteTarget;
} }
const NameAddrs&
DialogUsage::getRouteSet() const
{
return mDialog.mRouteSet;
}
const DialogId& const DialogId&
DialogUsage::getDialogId() const DialogUsage::getDialogId() const
{ {
@ -99,9 +97,6 @@ DialogUsage::send(SharedPtr<SipMessage> msg)
{ {
// give app an chance to adorn the message. // give app an chance to adorn the message.
onReadyToSend(*msg); onReadyToSend(*msg);
putUserHeaders(mUserHeaders, *msg);
mDialog.send(msg); mDialog.send(msg);
} }
@ -111,17 +106,12 @@ DialogUsage::sendCommand(SharedPtr<SipMessage> message)
mDum.post(new DialogUsageSendCommand(*this, message)); mDum.post(new DialogUsageSendCommand(*this, message));
} }
void
DialogUsage::setUserHeaders(const std::map<std::string, std::string> &headers)
{
mUserHeaders = headers;
}
/* /*
void void
DialogUsage::send(SipMessage& msg) DialogUsage::send(SipMessage& msg)
{ {
assert(msg.isResponse() || msg.header(h_RequestLine).method() == ACK); resip_assert(msg.isResponse() || msg.header(h_RequestLine).method() == ACK);
mDialog.send(msg); mDialog.send(msg);
} }
*/ */

View File

@ -7,8 +7,6 @@
#include "resip/dum/UserProfile.hxx" #include "resip/dum/UserProfile.hxx"
#include "resip/dum/BaseUsage.hxx" #include "resip/dum/BaseUsage.hxx"
#include "resip/dum/Handles.hxx" #include "resip/dum/Handles.hxx"
#include <map>
#include <string>
namespace resip namespace resip
{ {
@ -37,11 +35,11 @@ class DialogUsage : public BaseUsage
const NameAddr& myAddr() const; const NameAddr& myAddr() const;
const NameAddr& peerAddr() const; const NameAddr& peerAddr() const;
const NameAddr& remoteTarget() const; const NameAddr& remoteTarget() const;
const NameAddrs& getRouteSet() const;
const DialogId& getDialogId() const; const DialogId& getDialogId() const;
const Data& getCallId() const; const Data& getCallId() const;
SharedPtr<UserProfile> getUserProfile(); SharedPtr<UserProfile> getUserProfile();
void setUserHeaders(const std::map<std::string, std::string>& headers);
protected: protected:
friend class DialogSet; friend class DialogSet;
friend class DialogUsageManager; friend class DialogUsageManager;
@ -82,14 +80,7 @@ class DialogUsage : public BaseUsage
DialogUsage(DialogUsageManager& dum, Dialog& dialog); DialogUsage(DialogUsageManager& dum, Dialog& dialog);
virtual ~DialogUsage(); virtual ~DialogUsage();
//virtual void sendToDialog(SharedPtr<SipMessage> msg);
virtual void dialogDestroyed(const SipMessage& msg) = 0;
Dialog& mDialog; Dialog& mDialog;
// Custom headers
std::map<std::string, std::string> mUserHeaders;
}; };
} }

View File

@ -60,12 +60,14 @@
#include "resip/dum/OutgoingEvent.hxx" #include "resip/dum/OutgoingEvent.hxx"
#include "resip/dum/DumHelper.hxx" #include "resip/dum/DumHelper.hxx"
#include "resip/dum/MergedRequestRemovalCommand.hxx" #include "resip/dum/MergedRequestRemovalCommand.hxx"
#include "resip/dum/InMemorySyncPubDb.hxx"
#include "rutil/ResipAssert.h"
#include "rutil/Inserter.hxx" #include "rutil/Inserter.hxx"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
#include "rutil/Random.hxx" #include "rutil/Random.hxx"
#include "rutil/Lockable.hxx" #include "rutil/Lockable.hxx"
#include "rutil/WinLeakCheck.hxx"
#include "rutil/Timer.hxx" #include "rutil/Timer.hxx"
#include "rutil/WinLeakCheck.hxx"
#ifdef USE_SSL #ifdef USE_SSL
#include "resip/stack/ssl/Security.hxx" #include "resip/stack/ssl/Security.hxx"
@ -83,7 +85,7 @@ using namespace std;
{ \ { \
if(mThreadDebugKey) \ if(mThreadDebugKey) \
{ \ { \
assert(ThreadIf::tlsGetValue(mThreadDebugKey)); \ resip_assert(ThreadIf::tlsGetValue(mThreadDebugKey)); \
} \ } \
} while (false) } while (false)
#else #else
@ -103,6 +105,7 @@ DialogUsageManager::DialogUsageManager(SipStack& stack, bool createDefaultFeatur
mDialogSetHandler(0), mDialogSetHandler(0),
mRequestValidationHandler(0), mRequestValidationHandler(0),
mRegistrationPersistenceManager(0), mRegistrationPersistenceManager(0),
mPublicationPersistenceManager(0),
mIsDefaultServerReferHandler(true), mIsDefaultServerReferHandler(true),
mClientPagerMessageHandler(0), mClientPagerMessageHandler(0),
mServerPagerMessageHandler(0), mServerPagerMessageHandler(0),
@ -142,9 +145,7 @@ DialogUsageManager::DialogUsageManager(SipStack& stack, bool createDefaultFeatur
#if defined (USE_SSL) #if defined (USE_SSL)
addOutgoingFeature(encryptionOutgoing); addOutgoingFeature(encryptionOutgoing);
#endif #endif
} }
} }
DialogUsageManager::~DialogUsageManager() DialogUsageManager::~DialogUsageManager()
@ -152,14 +153,6 @@ DialogUsageManager::~DialogUsageManager()
mShutdownState = Destroying; mShutdownState = Destroying;
//InfoLog ( << "~DialogUsageManager" ); //InfoLog ( << "~DialogUsageManager" );
#if(0)
// !kh!
DialogSetMap::iterator dialogSet = mDialogSetMap.begin();
for (; dialogSet != mDialogSetMap.end(); ++dialogSet)
{
delete dialogSet->second;
}
#endif
if(!mDialogSetMap.empty()) if(!mDialogSetMap.empty())
{ {
DebugLog(<< "DialogUsageManager::mDialogSetMap has " << mDialogSetMap.size() << " DialogSets"); DebugLog(<< "DialogUsageManager::mDialogSetMap has " << mDialogSetMap.size() << " DialogSets");
@ -179,7 +172,7 @@ DialogUsageManager::~DialogUsageManager()
while(!mDialogSetMap.empty()) while(!mDialogSetMap.empty())
{ {
DialogSet* ds = mDialogSetMap.begin()->second; DialogSet* ds = mDialogSetMap.begin()->second;
delete ds; delete ds; // Deleting a dialog set removes itself from the map
} }
if(mIsDefaultServerReferHandler) if(mIsDefaultServerReferHandler)
@ -190,6 +183,18 @@ DialogUsageManager::~DialogUsageManager()
delete mIncomingTarget; delete mIncomingTarget;
delete mOutgoingTarget; delete mOutgoingTarget;
// Delete Server Publications
while (!mServerPublications.empty())
{
delete mServerPublications.begin()->second; // Deleting a ServerPublication removes itself from the map
}
// Remove any lingering incoming feature chain memory
for(FeatureChainMap::iterator it = mIncomingFeatureChainMap.begin(); it != mIncomingFeatureChainMap.end(); it++)
{
delete it->second;
}
//InfoLog ( << "~DialogUsageManager done" ); //InfoLog ( << "~DialogUsageManager done" );
} }
@ -292,41 +297,41 @@ DialogUsageManager::forceShutdown(DumShutdownHandler* h)
DialogUsageManager::onAllHandlesDestroyed(); DialogUsageManager::onAllHandlesDestroyed();
} }
void DialogUsageManager::setAppDialogSetFactory(std::unique_ptr<AppDialogSetFactory> factory) void DialogUsageManager::setAppDialogSetFactory(std::auto_ptr<AppDialogSetFactory> factory)
{ {
mAppDialogSetFactory = std::move(factory); mAppDialogSetFactory = factory;
} }
SharedPtr<MasterProfile>& SharedPtr<MasterProfile>&
DialogUsageManager::getMasterProfile() DialogUsageManager::getMasterProfile()
{ {
assert(mMasterProfile.get()); resip_assert(mMasterProfile.get());
return mMasterProfile; return mMasterProfile;
} }
SharedPtr<UserProfile>& SharedPtr<UserProfile>&
DialogUsageManager::getMasterUserProfile() DialogUsageManager::getMasterUserProfile()
{ {
assert(mMasterUserProfile.get()); resip_assert(mMasterUserProfile.get());
return mMasterUserProfile; return mMasterUserProfile;
} }
void DialogUsageManager::setMasterProfile(const SharedPtr<MasterProfile>& masterProfile) void DialogUsageManager::setMasterProfile(const SharedPtr<MasterProfile>& masterProfile)
{ {
assert(!mMasterProfile.get()); resip_assert(!mMasterProfile.get());
mMasterProfile = masterProfile; mMasterProfile = masterProfile;
mMasterUserProfile = masterProfile; // required so that we can return a reference to SharedPtr<UserProfile> in getMasterUserProfile mMasterUserProfile = masterProfile; // required so that we can return a reference to SharedPtr<UserProfile> in getMasterUserProfile
} }
void DialogUsageManager::setKeepAliveManager(std::unique_ptr<KeepAliveManager> manager) void DialogUsageManager::setKeepAliveManager(std::auto_ptr<KeepAliveManager> manager)
{ {
mKeepAliveManager = std::move(manager); mKeepAliveManager = manager;
mKeepAliveManager->setDialogUsageManager(this); mKeepAliveManager->setDialogUsageManager(this);
} }
void DialogUsageManager::setRedirectManager(std::unique_ptr<RedirectManager> manager) void DialogUsageManager::setRedirectManager(std::auto_ptr<RedirectManager> manager)
{ {
mRedirectManager = std::move(manager); mRedirectManager = manager;
} }
void DialogUsageManager::setRedirectHandler(RedirectHandler* handler) void DialogUsageManager::setRedirectHandler(RedirectHandler* handler)
@ -340,9 +345,9 @@ RedirectHandler* DialogUsageManager::getRedirectHandler()
} }
void void
DialogUsageManager::setClientAuthManager(std::unique_ptr<ClientAuthManager> manager) DialogUsageManager::setClientAuthManager(std::auto_ptr<ClientAuthManager> manager)
{ {
mClientAuthManager = std::move(manager); mClientAuthManager = manager;
} }
void void
@ -354,14 +359,14 @@ DialogUsageManager::setServerAuthManager(SharedPtr<ServerAuthManager> manager)
void void
DialogUsageManager::setClientRegistrationHandler(ClientRegistrationHandler* handler) DialogUsageManager::setClientRegistrationHandler(ClientRegistrationHandler* handler)
{ {
assert(!mClientRegistrationHandler); resip_assert(!mClientRegistrationHandler);
mClientRegistrationHandler = handler; mClientRegistrationHandler = handler;
} }
void void
DialogUsageManager::setServerRegistrationHandler(ServerRegistrationHandler* handler) DialogUsageManager::setServerRegistrationHandler(ServerRegistrationHandler* handler)
{ {
assert(!mServerRegistrationHandler); resip_assert(!mServerRegistrationHandler);
mServerRegistrationHandler = handler; mServerRegistrationHandler = handler;
} }
@ -374,27 +379,29 @@ DialogUsageManager::setDialogSetHandler(DialogSetHandler* handler)
void void
DialogUsageManager::setInviteSessionHandler(InviteSessionHandler* handler) DialogUsageManager::setInviteSessionHandler(InviteSessionHandler* handler)
{ {
assert(!mInviteSessionHandler); resip_assert(!mInviteSessionHandler);
mInviteSessionHandler = handler; mInviteSessionHandler = handler;
} }
void void
DialogUsageManager::setRequestValidationHandler(RequestValidationHandler* handler) DialogUsageManager::setRequestValidationHandler(RequestValidationHandler* handler)
{ {
assert(!mRequestValidationHandler); resip_assert(!mRequestValidationHandler);
mRequestValidationHandler = handler; mRequestValidationHandler = handler;
} }
void void
DialogUsageManager::setRegistrationPersistenceManager(RegistrationPersistenceManager* manager) DialogUsageManager::setRegistrationPersistenceManager(RegistrationPersistenceManager* manager)
{ {
assert(!mRegistrationPersistenceManager); resip_assert(!mRegistrationPersistenceManager);
mRegistrationPersistenceManager = manager; mRegistrationPersistenceManager = manager;
} }
void void
DialogUsageManager::setRemoteCertStore(unique_ptr<RemoteCertStore> store) DialogUsageManager::setPublicationPersistenceManager(PublicationPersistenceManager* manager)
{ {
resip_assert(!mPublicationPersistenceManager);
mPublicationPersistenceManager = manager;
} }
void void
@ -417,15 +424,15 @@ DialogUsageManager::addTimerMs(DumTimeout::Type type, unsigned long duration,
void void
DialogUsageManager::addClientSubscriptionHandler(const Data& eventType, ClientSubscriptionHandler* handler) DialogUsageManager::addClientSubscriptionHandler(const Data& eventType, ClientSubscriptionHandler* handler)
{ {
assert(handler); resip_assert(handler);
assert(mClientSubscriptionHandlers.count(eventType) == 0); resip_assert(mClientSubscriptionHandlers.count(eventType) == 0);
mClientSubscriptionHandlers[eventType] = handler; mClientSubscriptionHandlers[eventType] = handler;
} }
void void
DialogUsageManager::addServerSubscriptionHandler(const Data& eventType, ServerSubscriptionHandler* handler) DialogUsageManager::addServerSubscriptionHandler(const Data& eventType, ServerSubscriptionHandler* handler)
{ {
assert(handler); resip_assert(handler);
//default do-nothing server side refer handler can be replaced //default do-nothing server side refer handler can be replaced
if (eventType == "refer" && mServerSubscriptionHandlers.count(eventType)) if (eventType == "refer" && mServerSubscriptionHandlers.count(eventType))
{ {
@ -440,24 +447,24 @@ DialogUsageManager::addServerSubscriptionHandler(const Data& eventType, ServerSu
void void
DialogUsageManager::addClientPublicationHandler(const Data& eventType, ClientPublicationHandler* handler) DialogUsageManager::addClientPublicationHandler(const Data& eventType, ClientPublicationHandler* handler)
{ {
assert(handler); resip_assert(handler);
assert(mClientPublicationHandlers.count(eventType) == 0); resip_assert(mClientPublicationHandlers.count(eventType) == 0);
mClientPublicationHandlers[eventType] = handler; mClientPublicationHandlers[eventType] = handler;
} }
void void
DialogUsageManager::addServerPublicationHandler(const Data& eventType, ServerPublicationHandler* handler) DialogUsageManager::addServerPublicationHandler(const Data& eventType, ServerPublicationHandler* handler)
{ {
assert(handler); resip_assert(handler);
assert(mServerPublicationHandlers.count(eventType) == 0); resip_assert(mServerPublicationHandlers.count(eventType) == 0);
mServerPublicationHandlers[eventType] = handler; mServerPublicationHandlers[eventType] = handler;
} }
void void
DialogUsageManager::addOutOfDialogHandler(MethodTypes type, OutOfDialogHandler* handler) DialogUsageManager::addOutOfDialogHandler(MethodTypes type, OutOfDialogHandler* handler)
{ {
assert(handler); resip_assert(handler);
assert(mOutOfDialogHandlers.count(type) == 0); resip_assert(mOutOfDialogHandlers.count(type) == 0);
mOutOfDialogHandlers[type] = handler; mOutOfDialogHandlers[type] = handler;
} }
@ -539,14 +546,14 @@ DialogUsageManager::makeResponse(SipMessage& response,
int responseCode, int responseCode,
const Data& reason) const const Data& reason) const
{ {
assert(request.isRequest()); resip_assert(request.isRequest());
Helper::makeResponse(response, request, responseCode, reason); Helper::makeResponse(response, request, responseCode, reason);
} }
void void
DialogUsageManager::sendResponse(const SipMessage& response) DialogUsageManager::sendResponse(const SipMessage& response)
{ {
assert(response.isResponse()); resip_assert(response.isResponse());
mStack.send(response, this); mStack.send(response, this);
} }
@ -585,6 +592,24 @@ DialogUsageManager::makeInviteSession(const NameAddr& target,
return makeInviteSession(target, getMasterUserProfile(), initialOffer, level, alternative, appDs); return makeInviteSession(target, getMasterUserProfile(), initialOffer, level, alternative, appDs);
} }
SharedPtr<SipMessage>
DialogUsageManager::makeInviteSession(const NameAddr& target,
const DialogSetId& dialogSetId,
const SharedPtr<UserProfile>& userProfile,
const Contents* initialOffer,
EncryptionLevel level,
const Contents* alternative,
AppDialogSet* appDs)
{
assert(mDialogSetMap.find(dialogSetId) == mDialogSetMap.end());
BaseCreator* baseCreator(new InviteSessionCreator(*this, target, userProfile, initialOffer, level, alternative));
baseCreator->getLastRequest()->header(h_CallID).value() = dialogSetId.getCallId();
baseCreator->getLastRequest()->header(h_From).param(p_tag) = dialogSetId.getLocalTag();
SharedPtr<SipMessage> inv = makeNewSession(baseCreator, appDs);
DumHelper::setOutgoingEncryptionLevel(*inv, level);
return inv;
}
SharedPtr<SipMessage> SharedPtr<SipMessage>
DialogUsageManager::makeInviteSession(const NameAddr& target, DialogUsageManager::makeInviteSession(const NameAddr& target,
InviteSessionHandle sessionToReplace, InviteSessionHandle sessionToReplace,
@ -594,11 +619,11 @@ DialogUsageManager::makeInviteSession(const NameAddr& target,
{ {
SharedPtr<SipMessage> inv = makeInviteSession(target, userProfile, initialOffer, ads); SharedPtr<SipMessage> inv = makeInviteSession(target, userProfile, initialOffer, ads);
// add replaces header // add replaces header
assert(sessionToReplace.isValid()); resip_assert(sessionToReplace.isValid());
if(sessionToReplace.isValid()) if(sessionToReplace.isValid())
{ {
CallId replaces; CallId replaces;
DialogId id = sessionToReplace->getDialogId(); const DialogId& id = sessionToReplace->getDialogId();
replaces.value() = id.getCallId(); replaces.value() = id.getCallId();
replaces.param(p_toTag) = id.getRemoteTag(); replaces.param(p_toTag) = id.getRemoteTag();
replaces.param(p_fromTag) = id.getLocalTag(); replaces.param(p_fromTag) = id.getLocalTag();
@ -618,11 +643,11 @@ DialogUsageManager::makeInviteSession(const NameAddr& target,
{ {
SharedPtr<SipMessage> inv = makeInviteSession(target, userProfile, initialOffer, level, alternative, ads); SharedPtr<SipMessage> inv = makeInviteSession(target, userProfile, initialOffer, level, alternative, ads);
// add replaces header // add replaces header
assert(sessionToReplace.isValid()); resip_assert(sessionToReplace.isValid());
if(sessionToReplace.isValid()) if(sessionToReplace.isValid())
{ {
CallId replaces; CallId replaces;
DialogId id = sessionToReplace->getDialogId(); const DialogId& id = sessionToReplace->getDialogId();
replaces.value() = id.getCallId(); replaces.value() = id.getCallId();
replaces.param(p_toTag) = id.getRemoteTag(); replaces.param(p_toTag) = id.getRemoteTag();
replaces.param(p_fromTag) = id.getLocalTag(); replaces.param(p_fromTag) = id.getLocalTag();
@ -641,11 +666,11 @@ DialogUsageManager::makeInviteSession(const NameAddr& target,
{ {
SharedPtr<SipMessage> inv = makeInviteSession(target, initialOffer, level, alternative, ads); SharedPtr<SipMessage> inv = makeInviteSession(target, initialOffer, level, alternative, ads);
// add replaces header // add replaces header
assert(sessionToReplace.isValid()); resip_assert(sessionToReplace.isValid());
if(sessionToReplace.isValid()) if(sessionToReplace.isValid())
{ {
CallId replaces; CallId replaces;
DialogId id = sessionToReplace->getDialogId(); const DialogId& id = sessionToReplace->getDialogId();
replaces.value() = id.getCallId(); replaces.value() = id.getCallId();
replaces.param(p_toTag) = id.getRemoteTag(); replaces.param(p_toTag) = id.getRemoteTag();
replaces.param(p_fromTag) = id.getLocalTag(); replaces.param(p_fromTag) = id.getLocalTag();
@ -751,7 +776,7 @@ DialogUsageManager::makeRefer(const NameAddr& target, const H_ReferTo::Type& ref
SharedPtr<SipMessage> SharedPtr<SipMessage>
DialogUsageManager::makeSubscription(const NameAddr& target, const SharedPtr<UserProfile>& userProfile, const Data& eventType, AppDialogSet* appDs) DialogUsageManager::makeSubscription(const NameAddr& target, const SharedPtr<UserProfile>& userProfile, const Data& eventType, AppDialogSet* appDs)
{ {
assert(userProfile.get()); resip_assert(userProfile.get());
return makeNewSession(new SubscriptionCreator(*this, target, userProfile, eventType, userProfile->getDefaultSubscriptionTime()), appDs); return makeNewSession(new SubscriptionCreator(*this, target, userProfile, eventType, userProfile->getDefaultSubscriptionTime()), appDs);
} }
@ -792,7 +817,7 @@ DialogUsageManager::makeSubscription(const NameAddr& target, const Data& eventTy
SharedPtr<SipMessage> SharedPtr<SipMessage>
DialogUsageManager::makeRegistration(const NameAddr& target, const SharedPtr<UserProfile>& userProfile, AppDialogSet* appDs) DialogUsageManager::makeRegistration(const NameAddr& target, const SharedPtr<UserProfile>& userProfile, AppDialogSet* appDs)
{ {
assert(userProfile.get()); resip_assert(userProfile.get());
return makeNewSession(new RegistrationCreator(*this, target, userProfile, userProfile->getDefaultRegistrationTime()), appDs); return makeNewSession(new RegistrationCreator(*this, target, userProfile, userProfile->getDefaultRegistrationTime()), appDs);
} }
@ -881,7 +906,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
userProfile = ds->getUserProfile().get(); userProfile = ds->getUserProfile().get();
} }
assert(userProfile); resip_assert(userProfile);
if (!userProfile->isAnonymous() && userProfile->hasUserAgent()) if (!userProfile->isAnonymous() && userProfile->hasUserAgent())
{ {
msg->header(h_UserAgent).value() = userProfile->getUserAgent(); msg->header(h_UserAgent).value() = userProfile->getUserAgent();
@ -899,7 +924,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
msg->remove(h_Warnings); msg->remove(h_Warnings);
} }
assert(userProfile); resip_assert(userProfile);
if (msg->isRequest() if (msg->isRequest()
&& userProfile->hasProxyRequires() && userProfile->hasProxyRequires()
&& msg->header(h_RequestLine).method() != ACK && msg->header(h_RequestLine).method() != ACK
@ -924,11 +949,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
SharedPtr<MessageDecorator> outboundDecorator = userProfile->getOutboundDecorator(); SharedPtr<MessageDecorator> outboundDecorator = userProfile->getOutboundDecorator();
if (outboundDecorator.get()) if (outboundDecorator.get())
{ {
msg->addOutboundDecorator(std::unique_ptr<MessageDecorator>(outboundDecorator->clone())); msg->addOutboundDecorator(std::auto_ptr<MessageDecorator>(outboundDecorator->clone()));
}
else
{
DebugLog(<< "No outbound decorator for message");
} }
if (msg->isRequest()) if (msg->isRequest())
@ -943,7 +964,11 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
if (msg->exists(h_Vias)) if (msg->exists(h_Vias))
{ {
if(!userProfile->getRportEnabled()) if(userProfile->getRportEnabled())
{
msg->header(h_Vias).front().param(p_rport);
}
else
{ {
msg->header(h_Vias).front().remove(p_rport); msg->header(h_Vias).front().remove(p_rport);
} }
@ -971,12 +996,9 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
if (mDialogEventStateManager) if (mDialogEventStateManager)
{ {
Dialog* d = ds->findDialog(*msg); Dialog* d = ds->findDialog(*msg);
if (d != 0) if (d == 0)
{
mDialogEventStateManager->onConfirmed(*d, d->getInviteSession());
}
else
{ {
// If we don't have a dialog yet and we are sending an INVITE, this is a new outbound (UAC) INVITE
mDialogEventStateManager->onTryingUac(*ds, *msg); mDialogEventStateManager->onTryingUac(*ds, *msg);
} }
} }
@ -987,7 +1009,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
DebugLog (<< "SEND: " << std::endl << std::endl << *msg); DebugLog (<< "SEND: " << std::endl << std::endl << *msg);
OutgoingEvent* event = new OutgoingEvent(msg); OutgoingEvent* event = new OutgoingEvent(msg);
outgoingProcess(unique_ptr<Message>(event)); outgoingProcess(auto_ptr<Message>(event));
} }
void void
@ -998,7 +1020,7 @@ DialogUsageManager::sendCommand(SharedPtr<SipMessage> request)
} }
void DialogUsageManager::outgoingProcess(unique_ptr<Message> message) void DialogUsageManager::outgoingProcess(auto_ptr<Message> message)
{ {
Data tid = Data::Empty; Data tid = Data::Empty;
{ {
@ -1071,12 +1093,12 @@ void DialogUsageManager::outgoingProcess(unique_ptr<Message> message)
userProfile = ds->getUserProfile().get(); userProfile = ds->getUserProfile().get();
} }
assert(userProfile); resip_assert(userProfile);
//!dcm! -- unique SharedPtr to unique_ptr conversion prob. a worthwhile //!dcm! -- unique SharedPtr to auto_ptr conversion prob. a worthwhile
//optimzation here. SharedPtr would have to be changed; would //optimzation here. SharedPtr would have to be changed; would
//throw/assert if not unique. //throw/assert if not unique.
std::unique_ptr<SipMessage> toSend(static_cast<SipMessage*>(event->message()->clone())); std::auto_ptr<SipMessage> toSend(static_cast<SipMessage*>(event->message()->clone()));
// .bwc. Protect ourselves from garbage with an isWellFormed() check. // .bwc. Protect ourselves from garbage with an isWellFormed() check.
// (Code in Dialog doesn't check for well-formedness in the // (Code in Dialog doesn't check for well-formedness in the
@ -1087,11 +1109,11 @@ void DialogUsageManager::outgoingProcess(unique_ptr<Message> message)
!event->message()->header(h_Routes).front().uri().exists(p_lr)) !event->message()->header(h_Routes).front().uri().exists(p_lr))
{ {
Helper::processStrictRoute(*toSend); Helper::processStrictRoute(*toSend);
sendUsingOutboundIfAppropriate(*userProfile, std::move(toSend)); sendUsingOutboundIfAppropriate(*userProfile, toSend);
} }
else else
{ {
sendUsingOutboundIfAppropriate(*userProfile, std::move(toSend)); sendUsingOutboundIfAppropriate(*userProfile, toSend);
} }
} }
else else
@ -1102,7 +1124,7 @@ void DialogUsageManager::outgoingProcess(unique_ptr<Message> message)
} }
void void
DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, unique_ptr<SipMessage> msg) DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, auto_ptr<SipMessage> msg)
{ {
//a little inefficient, branch parameter might be better //a little inefficient, branch parameter might be better
DialogId id(*msg); DialogId id(*msg);
@ -1121,12 +1143,12 @@ DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, uni
{ {
DebugLog ( << "Sending with client outbound flow tuple to express outbound" ); DebugLog ( << "Sending with client outbound flow tuple to express outbound" );
DebugLog ( << "Flow Tuple: " << userProfile.mClientOutboundFlowTuple << " and key: " << userProfile.mClientOutboundFlowTuple.mFlowKey); DebugLog ( << "Flow Tuple: " << userProfile.mClientOutboundFlowTuple << " and key: " << userProfile.mClientOutboundFlowTuple.mFlowKey);
mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this); mStack.sendTo(msg, userProfile.mClientOutboundFlowTuple, this);
} }
else else
{ {
DebugLog ( << "Sending to express outbound w/o flow tuple"); DebugLog ( << "Sending to express outbound w/o flow tuple");
mStack.send(std::move(msg), this); mStack.send(msg, this);
} }
} }
else else
@ -1134,12 +1156,12 @@ DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, uni
if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0) if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0)
{ {
DebugLog ( << "Sending to outbound (no express) with flow tuple"); DebugLog ( << "Sending to outbound (no express) with flow tuple");
mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this); mStack.sendTo(msg, userProfile.mClientOutboundFlowTuple, this);
} }
else else
{ {
DebugLog ( << "Sending to outbound uri"); DebugLog ( << "Sending to outbound uri");
mStack.sendTo(std::move(msg), userProfile.getOutboundProxy().uri(), this); mStack.sendTo(msg, userProfile.getOutboundProxy().uri(), this);
} }
} }
} }
@ -1148,11 +1170,11 @@ DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, uni
DebugLog (<< "Send: " << msg->brief()); DebugLog (<< "Send: " << msg->brief());
if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0) if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0)
{ {
mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this); mStack.sendTo(msg, userProfile.mClientOutboundFlowTuple, this);
} }
else else
{ {
mStack.send(std::move(msg), this); mStack.send(msg, this);
} }
} }
} }
@ -1162,7 +1184,7 @@ void
DialogUsageManager::end(DialogSetId setid) DialogUsageManager::end(DialogSetId setid)
{ {
DialogSet* ds = findDialogSet(setid); DialogSet* ds = findDialogSet(setid);
if (ds == nullptr) if (ds == 0)
{ {
throw Exception("Request no longer exists", __FILE__, __LINE__); throw Exception("Request no longer exists", __FILE__, __LINE__);
} }
@ -1308,14 +1330,14 @@ AppDialogSetHandle DialogUsageManager::findAppDialogSet(const DialogSetId& id)
} }
void void
DialogUsageManager::internalProcess(std::unique_ptr<Message> msg) DialogUsageManager::internalProcess(std::auto_ptr<Message> msg)
{ {
#ifdef RESIP_DUM_THREAD_DEBUG #ifdef RESIP_DUM_THREAD_DEBUG
if(!mThreadDebugKey) if(!mThreadDebugKey)
{ {
// .bwc. Probably means multiple threads are trying to give DUM cycles // .bwc. Probably means multiple threads are trying to give DUM cycles
// simultaneously. // simultaneously.
assert(!mHiddenThreadDebugKey); resip_assert(!mHiddenThreadDebugKey);
// No d'tor needed, since we're just going to use a pointer to this. // No d'tor needed, since we're just going to use a pointer to this.
if(!ThreadIf::tlsKeyCreate(mThreadDebugKey, 0)) if(!ThreadIf::tlsKeyCreate(mThreadDebugKey, 0))
{ {
@ -1344,8 +1366,8 @@ DialogUsageManager::internalProcess(std::unique_ptr<Message> msg)
if (tuMsg) if (tuMsg)
{ {
InfoLog (<< "TU unregistered "); InfoLog (<< "TU unregistered ");
assert(mShutdownState == RemovingTransactionUser); resip_assert(mShutdownState == RemovingTransactionUser);
assert(tuMsg->type() == TransactionUserMessage::TransactionUserRemoved); resip_assert(tuMsg->type() == TransactionUserMessage::TransactionUserRemoved);
mShutdownState = Shutdown; mShutdownState = Shutdown;
if (mDumShutdownHandler) if (mDumShutdownHandler)
{ {
@ -1480,7 +1502,7 @@ DialogUsageManager::internalProcess(std::unique_ptr<Message> msg)
} }
} }
incomingProcess(std::move(msg)); incomingProcess(msg);
} }
void void
@ -1499,7 +1521,7 @@ DialogUsageManager::processExternalMessage(ExternalMessageBase* externalMessage)
} }
void void
DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg) DialogUsageManager::incomingProcess(std::auto_ptr<Message> msg)
{ {
//call or create feature chain if appropriate //call or create feature chain if appropriate
Data tid = Data::Empty; Data tid = Data::Empty;
@ -1568,8 +1590,16 @@ DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
} }
else else
{ {
assert(dynamic_cast<SipMessage*>(msg.get())); if(dynamic_cast<SipMessage*>(msg.get()))
it = mIncomingFeatureChainMap.insert(lb, FeatureChainMap::value_type(tid, new DumFeatureChain(*this, mIncomingFeatureList, *mIncomingTarget))); {
it = mIncomingFeatureChainMap.insert(lb, FeatureChainMap::value_type(tid, new DumFeatureChain(*this, mIncomingFeatureList, *mIncomingTarget)));
}
else
{
// Certain messages from the wire (ie: CANCEL) can end a feature, however there may still be some
// pending Async requests (non-SipMessages) that are coming in - just drop them if so
return;
}
} }
} }
@ -1592,7 +1622,7 @@ DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
try try
{ {
InfoLog (<< "Got: " << msg->brief()); DebugLog (<< "Got: " << msg->brief());
DumDecrypted* decryptedMsg = dynamic_cast<DumDecrypted*>(msg.get()); DumDecrypted* decryptedMsg = dynamic_cast<DumDecrypted*>(msg.get());
SipMessage* sipMsg = 0; SipMessage* sipMsg = 0;
if (decryptedMsg) if (decryptedMsg)
@ -1625,7 +1655,7 @@ DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
DebugLog (<< "Failed required options validation " << *sipMsg); DebugLog (<< "Failed required options validation " << *sipMsg);
return; return;
} }
if( !validate100RelSuport(*sipMsg) ) if( !validate100RelSupport(*sipMsg) )
{ {
DebugLog (<< "Remote party does not support 100rel " << *sipMsg); DebugLog (<< "Remote party does not support 100rel " << *sipMsg);
return; return;
@ -1660,7 +1690,7 @@ DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
catch(BaseException& e) catch(BaseException& e)
{ {
//unparseable, bad 403 w/ 2543 trans it from FWD, etc //unparseable, bad 403 w/ 2543 trans it from FWD, etc
ErrLog(<<"Illegal message rejected: " << e.getMessage()); ErrLog(<<"Illegal message rejected: " << e.getMessage());
} }
} }
@ -1680,7 +1710,7 @@ DialogUsageManager::process(resip::Lockable* mutex)
#ifdef RESIP_DUM_THREAD_DEBUG #ifdef RESIP_DUM_THREAD_DEBUG
mThreadDebugKey=mHiddenThreadDebugKey; mThreadDebugKey=mHiddenThreadDebugKey;
#endif #endif
internalProcess(std::unique_ptr<Message>(mFifo.getNext())); internalProcess(std::auto_ptr<Message>(mFifo.getNext()));
#ifdef RESIP_DUM_THREAD_DEBUG #ifdef RESIP_DUM_THREAD_DEBUG
// .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app // .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
// is using this mutex-locked process() call, we only enable thread- // is using this mutex-locked process() call, we only enable thread-
@ -1698,7 +1728,7 @@ DialogUsageManager::process(resip::Lockable* mutex)
bool bool
DialogUsageManager::process(int timeoutMs, resip::Lockable* mutex) DialogUsageManager::process(int timeoutMs, resip::Lockable* mutex)
{ {
std::unique_ptr<Message> message; std::auto_ptr<Message> message;
if(timeoutMs == -1) if(timeoutMs == -1)
{ {
@ -1714,7 +1744,7 @@ DialogUsageManager::process(int timeoutMs, resip::Lockable* mutex)
#ifdef RESIP_DUM_THREAD_DEBUG #ifdef RESIP_DUM_THREAD_DEBUG
mThreadDebugKey=mHiddenThreadDebugKey; mThreadDebugKey=mHiddenThreadDebugKey;
#endif #endif
internalProcess(std::move(message)); internalProcess(message);
#ifdef RESIP_DUM_THREAD_DEBUG #ifdef RESIP_DUM_THREAD_DEBUG
// .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app // .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
// is using this mutex-locked process() call, we only enable thread- // is using this mutex-locked process() call, we only enable thread-
@ -1771,8 +1801,8 @@ DialogUsageManager::validateRequiredOptions(const SipMessage& request)
{ {
// RFC 2162 - 8.2.2 // RFC 2162 - 8.2.2
if(request.exists(h_Requires) && // Don't check requires if method is ACK or CANCEL if(request.exists(h_Requires) && // Don't check requires if method is ACK or CANCEL
(request.header(h_RequestLine).getMethod() != ACK || request.header(h_RequestLine).getMethod() != ACK &&
request.header(h_RequestLine).getMethod() != CANCEL)) request.header(h_RequestLine).getMethod() != CANCEL)
{ {
Tokens unsupported = getMasterProfile()->getUnsupportedOptionsTags(request.header(h_Requires)); Tokens unsupported = getMasterProfile()->getUnsupportedOptionsTags(request.header(h_Requires));
if (!unsupported.empty()) if (!unsupported.empty())
@ -1796,7 +1826,7 @@ DialogUsageManager::validateRequiredOptions(const SipMessage& request)
bool bool
DialogUsageManager::validate100RelSuport(const SipMessage& request) DialogUsageManager::validate100RelSupport(const SipMessage& request)
{ {
if(request.header(h_RequestLine).getMethod() == INVITE) if(request.header(h_RequestLine).getMethod() == INVITE)
{ {
@ -1811,7 +1841,9 @@ DialogUsageManager::validate100RelSuport(const SipMessage& request)
sendResponse(failure); sendResponse(failure);
if(mRequestValidationHandler) if(mRequestValidationHandler)
{
mRequestValidationHandler->on100RelNotSupportedByRemote(request); mRequestValidationHandler->on100RelNotSupportedByRemote(request);
}
return false; return false;
} }
@ -1927,8 +1959,8 @@ DialogUsageManager::validateAccept(const SipMessage& request)
bool bool
DialogUsageManager::mergeRequest(const SipMessage& request) DialogUsageManager::mergeRequest(const SipMessage& request)
{ {
assert(request.isRequest()); resip_assert(request.isRequest());
assert(request.isExternal()); resip_assert(request.isExternal());
if (!request.header(h_To).exists(p_tag)) if (!request.header(h_To).exists(p_tag))
{ {
@ -1972,7 +2004,7 @@ DialogUsageManager::processRequest(const SipMessage& request)
toTag = false; toTag = false;
} }
assert(mAppDialogSetFactory.get()); resip_assert(mAppDialogSetFactory.get());
// !jf! note, the logic was reversed during ye great merge of March of Ought 5 // !jf! note, the logic was reversed during ye great merge of March of Ought 5
if (toTag || if (toTag ||
findDialogSet(DialogSetId(request))) findDialogSet(DialogSetId(request)))
@ -2043,7 +2075,7 @@ DialogUsageManager::processRequest(const SipMessage& request)
} }
else else
{ {
InfoLog (<< "Received a CANCEL on a non-existent transaction "); InfoLog (<< "Received a CANCEL on a non-existent transaction: tid=" << request.getTransactionId());
SipMessage failure; SipMessage failure;
makeResponse(failure, request, 481); makeResponse(failure, request, 481);
sendResponse(failure); sendResponse(failure);
@ -2051,8 +2083,8 @@ DialogUsageManager::processRequest(const SipMessage& request)
break; break;
} }
case PUBLISH: case PUBLISH:
assert(false); resip_assert(false);
return; return;
case SUBSCRIBE: case SUBSCRIBE:
if (!checkEventPackage(request)) if (!checkEventPackage(request))
{ {
@ -2060,7 +2092,7 @@ DialogUsageManager::processRequest(const SipMessage& request)
<< request.brief()); << request.brief());
return; return;
} }
/*FALLTHRU*/ /*FALLTHRU*/
case NOTIFY : // handle unsolicited (illegal) NOTIFYs case NOTIFY : // handle unsolicited (illegal) NOTIFYs
case INVITE: // new INVITE case INVITE: // new INVITE
case REFER: // out-of-dialog REFER case REFER: // out-of-dialog REFER
@ -2121,11 +2153,11 @@ DialogUsageManager::processRequest(const SipMessage& request)
} }
case RESPONSE: case RESPONSE:
case SERVICE: case SERVICE:
assert(false); resip_assert(false);
break; break;
case UNKNOWN: case UNKNOWN:
case MAX_METHODS: case MAX_METHODS:
assert(false); resip_assert(false);
break; break;
} }
} }
@ -2145,7 +2177,7 @@ DialogUsageManager::processResponse(const SipMessage& response)
} }
else else
{ {
InfoLog (<< "Throwing away stray response: " << std::endl << std::endl << response.brief()); InfoLog (<< "Throwing away stray response: " << std::endl << std::endl << response.brief());
} }
} }
} }
@ -2168,9 +2200,22 @@ DialogUsageManager::processPublish(const SipMessage& request)
} }
else else
{ {
SharedPtr<SipMessage> response(new SipMessage); // Check if publication exists in PublicationDb - may have been sync'd over,
makeResponse(*response, request, 412); // or exists from a restart. In this case, fabricate a new ServerSubcription
send(response); // to handle this request.
if (mPublicationPersistenceManager &&
mPublicationPersistenceManager->documentExists(request.header(h_Event).value(), request.header(h_RequestLine).uri().getAor(), request.header(h_SIPIfMatch).value()))
{
ServerPublication* sp = new ServerPublication(*this, request.header(h_SIPIfMatch).value(), request);
mServerPublications[request.header(h_SIPIfMatch).value()] = sp;
sp->dispatch(request);
}
else
{
SharedPtr<SipMessage> response(new SipMessage);
makeResponse(*response, request, 412);
send(response);
}
} }
} }
else else
@ -2239,7 +2284,7 @@ DialogUsageManager::checkEventPackage(const SipMessage& request)
} }
break; break;
default: default:
assert(0); resip_assert(0);
} }
} }
@ -2247,6 +2292,10 @@ DialogUsageManager::checkEventPackage(const SipMessage& request)
{ {
SharedPtr<SipMessage> response(new SipMessage); SharedPtr<SipMessage> response(new SipMessage);
makeResponse(*response, request, failureCode); makeResponse(*response, request, failureCode);
if(failureCode == 489)
{
response->header(h_AllowEvents) = getMasterProfile()->getAllowedEvents();
}
send(response); send(response);
return false; return false;
} }
@ -2263,16 +2312,19 @@ DialogUsageManager::findDialogSet(const DialogSetId& id)
if (it == mDialogSetMap.end()) if (it == mDialogSetMap.end())
{ {
StackLog ( << "Not found" );
return 0; return 0;
} }
else else
{ {
if(it->second->isDestroying()) if(it->second->isDestroying())
{ {
StackLog ( << "isDestroying() == true" );
return 0; return 0;
} }
else else
{ {
StackLog ( << "found" );
return it->second; return it->second;
} }
} }
@ -2397,7 +2449,7 @@ DialogUsageManager::setOutgoingMessageInterceptor(SharedPtr<DumFeature> feat)
void void
DialogUsageManager::applyToAllServerSubscriptions(ServerSubscriptionFunctor* functor) DialogUsageManager::applyToAllServerSubscriptions(ServerSubscriptionFunctor* functor)
{ {
assert(functor); resip_assert(functor);
for (DialogSetMap::iterator it = mDialogSetMap.begin(); it != mDialogSetMap.end(); ++it) for (DialogSetMap::iterator it = mDialogSetMap.begin(); it != mDialogSetMap.end(); ++it)
{ {
for (DialogSet::DialogMap::iterator i = it->second->mDialogs.begin(); i != it->second->mDialogs.end(); ++i) for (DialogSet::DialogMap::iterator i = it->second->mDialogs.begin(); i != it->second->mDialogs.end(); ++i)
@ -2414,7 +2466,7 @@ DialogUsageManager::applyToAllServerSubscriptions(ServerSubscriptionFunctor* fun
void void
DialogUsageManager::applyToAllClientSubscriptions(ClientSubscriptionFunctor* functor) DialogUsageManager::applyToAllClientSubscriptions(ClientSubscriptionFunctor* functor)
{ {
assert(functor); resip_assert(functor);
for (DialogSetMap::iterator it = mDialogSetMap.begin(); it != mDialogSetMap.end(); ++it) for (DialogSetMap::iterator it = mDialogSetMap.begin(); it != mDialogSetMap.end(); ++it)
{ {
for (DialogSet::DialogMap::iterator i = it->second->mDialogs.begin(); i != it->second->mDialogs.end(); ++i) for (DialogSet::DialogMap::iterator i = it->second->mDialogs.begin(); i != it->second->mDialogs.end(); ++i)
@ -2428,6 +2480,32 @@ DialogUsageManager::applyToAllClientSubscriptions(ClientSubscriptionFunctor* fun
} }
} }
void
DialogUsageManager::endAllServerSubscriptions(TerminateReason reason)
{
// Make a copy of the map - since calling end can cause an immediate delete this on the subscription and thus cause
// the object to remove itself from the mServerSubscriptions map, messing up our iterator
ServerSubscriptions tempSubscriptions = mServerSubscriptions;
ServerSubscriptions::iterator it = tempSubscriptions.begin();
for (; it != tempSubscriptions.end(); it++)
{
it->second->end(reason);
}
}
void
DialogUsageManager::endAllServerPublications()
{
// Make a copy of the map - since calling end can cause an immediate delete this on the publication and thus cause
// the object to remove itself from the mServerPublications map, messing up our iterator
ServerPublications tempPublications = mServerPublications;
ServerPublications::iterator it = tempPublications.begin();
for (; it != tempPublications.end(); it++)
{
it->second->end();
}
}
void void
DialogUsageManager::registerForConnectionTermination(Postable* listener) DialogUsageManager::registerForConnectionTermination(Postable* listener)
{ {
@ -2443,9 +2521,13 @@ DialogUsageManager::unRegisterForConnectionTermination(Postable* listener)
void void
DialogUsageManager::requestMergedRequestRemoval(const MergedRequestKey& key) DialogUsageManager::requestMergedRequestRemoval(const MergedRequestKey& key)
{ {
DebugLog(<< "Got merged request removal request"); // Only post delayed merge request removal if running, if we are shutting down, then there is no need
MergedRequestRemovalCommand command(*this, key); if (mShutdownState == Running)
mStack.postMS(command, Timer::TF, this); {
DebugLog(<< "Got merged request removal request");
MergedRequestRemovalCommand command(*this, key);
mStack.postMS(command, Timer::TF, this);
}
} }
void void
@ -2483,6 +2565,30 @@ DialogUsageManager::createDialogEventStateManager(DialogEventHandler* handler)
return mDialogEventStateManager; return mDialogEventStateManager;
} }
void
DialogUsageManager::setAdvertisedCapabilities(SipMessage& msg, SharedPtr<UserProfile> userProfile)
{
if(userProfile->isAdvertisedCapability(Headers::Allow))
{
msg.header(h_Allows) = getMasterProfile()->getAllowedMethods();
}
if(userProfile->isAdvertisedCapability(Headers::AcceptEncoding))
{
msg.header(h_AcceptEncodings) = getMasterProfile()->getSupportedEncodings();
}
if(userProfile->isAdvertisedCapability(Headers::AcceptLanguage))
{
msg.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
}
if(userProfile->isAdvertisedCapability(Headers::AllowEvents))
{
msg.header(h_AllowEvents) = getMasterProfile()->getAllowedEvents();
}
if(userProfile->isAdvertisedCapability(Headers::Supported))
{
msg.header(h_Supporteds) = getMasterProfile()->getSupportedOptionTags();
}
}
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0

View File

@ -14,6 +14,7 @@
#include "resip/dum/Handles.hxx" #include "resip/dum/Handles.hxx"
#include "resip/dum/MergedRequestKey.hxx" #include "resip/dum/MergedRequestKey.hxx"
#include "resip/dum/RegistrationPersistenceManager.hxx" #include "resip/dum/RegistrationPersistenceManager.hxx"
#include "resip/dum/PublicationPersistenceManager.hxx"
#include "resip/dum/ServerSubscription.hxx" #include "resip/dum/ServerSubscription.hxx"
#include "rutil/BaseException.hxx" #include "rutil/BaseException.hxx"
#include "rutil/SharedPtr.hxx" #include "rutil/SharedPtr.hxx"
@ -111,7 +112,8 @@ class DialogUsageManager : public HandleManager, public TransactionUser
void forceShutdown(DumShutdownHandler*); void forceShutdown(DumShutdownHandler*);
void addTransport( TransportType protocol, // Use SipStack::addTransport instead
RESIP_DEPRECATED(void addTransport( TransportType protocol,
int port=0, int port=0,
IpVersion version=V4, IpVersion version=V4,
const Data& ipInterface = Data::Empty, const Data& ipInterface = Data::Empty,
@ -119,8 +121,8 @@ class DialogUsageManager : public HandleManager, public TransactionUser
// for TLS // for TLS
// based stuff // based stuff
const Data& privateKeyPassPhrase = Data::Empty, const Data& privateKeyPassPhrase = Data::Empty,
SecurityTypes::SSLType sslType = SecurityTypes::TLSv1, SecurityTypes::SSLType sslType = SecurityTypes::SSLv23,
unsigned transportFlags = 0); unsigned transportFlags = 0));
SipStack& getSipStack(); SipStack& getSipStack();
const SipStack& getSipStack() const; const SipStack& getSipStack() const;
@ -128,7 +130,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
Data getHostAddress(); Data getHostAddress();
void setAppDialogSetFactory(std::unique_ptr<AppDialogSetFactory>); void setAppDialogSetFactory(std::auto_ptr<AppDialogSetFactory>);
void setMasterProfile(const SharedPtr<MasterProfile>& masterProfile); void setMasterProfile(const SharedPtr<MasterProfile>& masterProfile);
SharedPtr<MasterProfile>& getMasterProfile(); SharedPtr<MasterProfile>& getMasterProfile();
@ -137,18 +139,18 @@ class DialogUsageManager : public HandleManager, public TransactionUser
//optional handler to track the progress of DialogSets //optional handler to track the progress of DialogSets
void setDialogSetHandler(DialogSetHandler* handler); void setDialogSetHandler(DialogSetHandler* handler);
void setKeepAliveManager(std::unique_ptr<KeepAliveManager> keepAlive); void setKeepAliveManager(std::auto_ptr<KeepAliveManager> keepAlive);
//There is a default RedirectManager. Setting one may cause the old one //There is a default RedirectManager. Setting one may cause the old one
//to be deleted. //to be deleted.
void setRedirectManager(std::unique_ptr<RedirectManager> redirect); void setRedirectManager(std::auto_ptr<RedirectManager> redirect);
//informational, so a RedirectHandler is not required //informational, so a RedirectHandler is not required
void setRedirectHandler(RedirectHandler* handler); void setRedirectHandler(RedirectHandler* handler);
RedirectHandler* getRedirectHandler(); RedirectHandler* getRedirectHandler();
/// If there is no ClientAuthManager, when the client receives a 401/407, /// If there is no ClientAuthManager, when the client receives a 401/407,
/// pass it up through the normal BaseUsageHandler /// pass it up through the normal BaseUsageHandler
void setClientAuthManager(std::unique_ptr<ClientAuthManager> client); void setClientAuthManager(std::auto_ptr<ClientAuthManager> client);
/// If there is no ServerAuthManager, the server does not authenticate requests /// If there is no ServerAuthManager, the server does not authenticate requests
void setServerAuthManager(resip::SharedPtr<ServerAuthManager> server); void setServerAuthManager(resip::SharedPtr<ServerAuthManager> server);
@ -185,10 +187,11 @@ class DialogUsageManager : public HandleManager, public TransactionUser
void removeExternalMessageHandler(ExternalMessageHandler* handler); void removeExternalMessageHandler(ExternalMessageHandler* handler);
void clearExternalMessageHandler(); void clearExternalMessageHandler();
/// Sets a manager to handle storage of registration state /// Sets a manager to handle storage of registration or publication state
void setRegistrationPersistenceManager(RegistrationPersistenceManager*); void setRegistrationPersistenceManager(RegistrationPersistenceManager*);
RegistrationPersistenceManager* getRegistrationPersistenceManager() { return mRegistrationPersistenceManager; }
void setRemoteCertStore(std::unique_ptr<RemoteCertStore> store); void setPublicationPersistenceManager(PublicationPersistenceManager*);
PublicationPersistenceManager* getPublicationPersistenceManager() { return mPublicationPersistenceManager; }
// The message is owned by the underlying datastructure and may go away in // The message is owned by the underlying datastructure and may go away in
// the future. If the caller wants to keep it, it should make a copy. The // the future. If the caller wants to keep it, it should make a copy. The
@ -198,6 +201,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, const Contents* initialOffer, AppDialogSet* ads = 0); SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, const Contents* initialOffer, AppDialogSet* ads = 0);
SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, EncryptionLevel level, const Contents* alternative = 0, AppDialogSet* ads = 0); SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, EncryptionLevel level, const Contents* alternative = 0, AppDialogSet* ads = 0);
SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, const Contents* initialOffer, EncryptionLevel level, const Contents* alternative = 0, AppDialogSet* ads = 0); SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, const Contents* initialOffer, EncryptionLevel level, const Contents* alternative = 0, AppDialogSet* ads = 0);
SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, const DialogSetId& dialogSetId, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, EncryptionLevel level, const Contents* alternative = 0, AppDialogSet* ads = 0);
// Versions that add a replaces header // Versions that add a replaces header
SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, InviteSessionHandle sessionToReplace, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, AppDialogSet* ads = 0); SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, InviteSessionHandle sessionToReplace, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, AppDialogSet* ads = 0);
SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, InviteSessionHandle sessionToReplace, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, EncryptionLevel level = None, const Contents* alternative = 0, AppDialogSet* ads = 0); SharedPtr<SipMessage> makeInviteSession(const NameAddr& target, InviteSessionHandle sessionToReplace, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, EncryptionLevel level = None, const Contents* alternative = 0, AppDialogSet* ads = 0);
@ -338,12 +342,15 @@ class DialogUsageManager : public HandleManager, public TransactionUser
//exposed so DumThread variants can be written //exposed so DumThread variants can be written
Message* getNext(int ms) { return mFifo.getNext(ms); } Message* getNext(int ms) { return mFifo.getNext(ms); }
void internalProcess(std::unique_ptr<Message> msg); void internalProcess(std::auto_ptr<Message> msg);
bool messageAvailable(void) { return mFifo.messageAvailable(); } bool messageAvailable(void) { return mFifo.messageAvailable(); }
void applyToAllClientSubscriptions(ClientSubscriptionFunctor*); void applyToAllClientSubscriptions(ClientSubscriptionFunctor*);
void applyToAllServerSubscriptions(ServerSubscriptionFunctor*); void applyToAllServerSubscriptions(ServerSubscriptionFunctor*);
void endAllServerSubscriptions(TerminateReason reason = Deactivated);
void endAllServerPublications();
/// Note: Implementations of Postable must delete the message passed via post /// Note: Implementations of Postable must delete the message passed via post
void registerForConnectionTermination(Postable*); void registerForConnectionTermination(Postable*);
void unRegisterForConnectionTermination(Postable*); void unRegisterForConnectionTermination(Postable*);
@ -354,6 +361,8 @@ class DialogUsageManager : public HandleManager, public TransactionUser
// at the same time it deletes other handlers when DUM is destroyed. // at the same time it deletes other handlers when DUM is destroyed.
DialogEventStateManager* createDialogEventStateManager(DialogEventHandler* handler); DialogEventStateManager* createDialogEventStateManager(DialogEventHandler* handler);
void setAdvertisedCapabilities(SipMessage& msg, SharedPtr<UserProfile> userProfile);
protected: protected:
virtual void onAllHandlesDestroyed(); virtual void onAllHandlesDestroyed();
//TransactionUser virtuals //TransactionUser virtuals
@ -400,9 +409,9 @@ class DialogUsageManager : public HandleManager, public TransactionUser
{ {
} }
virtual void post(std::unique_ptr<Message> msg) virtual void post(std::auto_ptr<Message> msg)
{ {
mDum.incomingProcess(std::move(msg)); mDum.incomingProcess(msg);
} }
}; };
@ -413,9 +422,9 @@ class DialogUsageManager : public HandleManager, public TransactionUser
{ {
} }
virtual void post(std::unique_ptr<Message> msg) virtual void post(std::auto_ptr<Message> msg)
{ {
mDum.outgoingProcess(std::move(msg)); mDum.outgoingProcess(msg);
} }
}; };
@ -430,7 +439,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
// May call a callback to let the app adorn // May call a callback to let the app adorn
void sendResponse(const SipMessage& response); void sendResponse(const SipMessage& response);
void sendUsingOutboundIfAppropriate(UserProfile& userProfile, std::unique_ptr<SipMessage> msg); void sendUsingOutboundIfAppropriate(UserProfile& userProfile, std::auto_ptr<SipMessage> msg);
void addTimer(DumTimeout::Type type, void addTimer(DumTimeout::Type type,
unsigned long durationSeconds, unsigned long durationSeconds,
@ -459,7 +468,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
bool validateContent(const SipMessage& request); bool validateContent(const SipMessage& request);
bool validateAccept(const SipMessage& request); bool validateAccept(const SipMessage& request);
bool validateTo(const SipMessage& request); bool validateTo(const SipMessage& request);
bool validate100RelSuport(const SipMessage& request); bool validate100RelSupport(const SipMessage& request);
bool mergeRequest(const SipMessage& request); bool mergeRequest(const SipMessage& request);
@ -472,8 +481,8 @@ class DialogUsageManager : public HandleManager, public TransactionUser
bool queueForIdentityCheck(SipMessage* msg); bool queueForIdentityCheck(SipMessage* msg);
void processIdentityCheckResponse(const HttpGetMessage& msg); void processIdentityCheckResponse(const HttpGetMessage& msg);
void incomingProcess(std::unique_ptr<Message> msg); void incomingProcess(std::auto_ptr<Message> msg);
void outgoingProcess(std::unique_ptr<Message> msg); void outgoingProcess(std::auto_ptr<Message> msg);
void processExternalMessage(ExternalMessageBase* externalMessage); void processExternalMessage(ExternalMessageBase* externalMessage);
// For delayed delete of a Usage // For delayed delete of a Usage
@ -495,9 +504,9 @@ class DialogUsageManager : public HandleManager, public TransactionUser
SharedPtr<MasterProfile> mMasterProfile; SharedPtr<MasterProfile> mMasterProfile;
SharedPtr<UserProfile> mMasterUserProfile; SharedPtr<UserProfile> mMasterUserProfile;
std::unique_ptr<RedirectManager> mRedirectManager; std::auto_ptr<RedirectManager> mRedirectManager;
std::unique_ptr<ClientAuthManager> mClientAuthManager; std::auto_ptr<ClientAuthManager> mClientAuthManager;
//std::unique_ptr<ServerAuthManager> mServerAuthManager; //std::auto_ptr<ServerAuthManager> mServerAuthManager;
InviteSessionHandler* mInviteSessionHandler; InviteSessionHandler* mInviteSessionHandler;
ClientRegistrationHandler* mClientRegistrationHandler; ClientRegistrationHandler* mClientRegistrationHandler;
@ -507,6 +516,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
RequestValidationHandler* mRequestValidationHandler; RequestValidationHandler* mRequestValidationHandler;
RegistrationPersistenceManager *mRegistrationPersistenceManager; RegistrationPersistenceManager *mRegistrationPersistenceManager;
PublicationPersistenceManager *mPublicationPersistenceManager;
OutOfDialogHandler* getOutOfDialogHandler(const MethodTypes type); OutOfDialogHandler* getOutOfDialogHandler(const MethodTypes type);
@ -515,7 +525,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
std::map<Data, ClientPublicationHandler*> mClientPublicationHandlers; std::map<Data, ClientPublicationHandler*> mClientPublicationHandlers;
std::map<Data, ServerPublicationHandler*> mServerPublicationHandlers; std::map<Data, ServerPublicationHandler*> mServerPublicationHandlers;
std::map<MethodTypes, OutOfDialogHandler*> mOutOfDialogHandlers; std::map<MethodTypes, OutOfDialogHandler*> mOutOfDialogHandlers;
std::unique_ptr<KeepAliveManager> mKeepAliveManager; std::auto_ptr<KeepAliveManager> mKeepAliveManager;
bool mIsDefaultServerReferHandler; bool mIsDefaultServerReferHandler;
ClientPagerMessageHandler* mClientPagerMessageHandler; ClientPagerMessageHandler* mClientPagerMessageHandler;
@ -526,7 +536,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
// server subscription handler for the 'dialog' event... // server subscription handler for the 'dialog' event...
DialogEventStateManager* mDialogEventStateManager; DialogEventStateManager* mDialogEventStateManager;
std::unique_ptr<AppDialogSetFactory> mAppDialogSetFactory; std::auto_ptr<AppDialogSetFactory> mAppDialogSetFactory;
SipStack& mStack; SipStack& mStack;
DumShutdownHandler* mDumShutdownHandler; DumShutdownHandler* mDumShutdownHandler;

View File

@ -20,7 +20,7 @@ public:
virtual Message* clone() const virtual Message* clone() const
{ {
assert(false); resip_assert(false);
return NULL; return NULL;
} }

View File

@ -1,5 +1,5 @@
#if !defined(RESIP_DUMEXCEPTION_HXX) #if !defined(RESIP_DUMEXCEPTION_HXX)
#define RESIP__DUMEXCEPTION_HXX #define RESIP_DUMEXCEPTION_HXX
#include "rutil/BaseException.hxx" #include "rutil/BaseException.hxx"

View File

@ -16,7 +16,7 @@ DumFeature::~DumFeature()
{ {
} }
void DumFeature::postCommand(std::unique_ptr<Message> message) void DumFeature::postCommand(std::auto_ptr<Message> message)
{ {
mDum.post(new TargetCommand(mTarget, std::move(message))); mDum.post(new TargetCommand(mTarget, message));
} }

View File

@ -40,7 +40,7 @@ class DumFeature
// taken ownership of msg until we get a return. If we throw, the // taken ownership of msg until we get a return. If we throw, the
// ownership of msg is unknown. This is unacceptable. // ownership of msg is unknown. This is unacceptable.
virtual ProcessingResult process(Message* msg) = 0; virtual ProcessingResult process(Message* msg) = 0;
virtual void postCommand(std::unique_ptr<Message> message); virtual void postCommand(std::auto_ptr<Message> message);
protected: protected:
DialogUsageManager& mDum; DialogUsageManager& mDum;

View File

@ -1,4 +1,4 @@
#include <cassert> #include "rutil/ResipAssert.h"
#include "DumFeatureMessage.hxx" #include "DumFeatureMessage.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"
#include "resip/dum/BaseUsage.hxx" #include "resip/dum/BaseUsage.hxx"

View File

@ -7,23 +7,26 @@ using namespace std;
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
void DumHelper::setOutgoingEncryptionLevel(SipMessage& message, void
DialogUsageManager::EncryptionLevel level) DumHelper::setOutgoingEncryptionLevel(SipMessage& message,
DialogUsageManager::EncryptionLevel level)
{ {
SecurityAttributes* attr = new SecurityAttributes(); SecurityAttributes* attr = new SecurityAttributes();
attr->setOutgoingEncryptionLevel(convert(level)); attr->setOutgoingEncryptionLevel(convert(level));
message.setSecurityAttributes(unique_ptr<SecurityAttributes>(attr)); message.setSecurityAttributes(auto_ptr<SecurityAttributes>(attr));
} }
void DumHelper::setEncryptionPerformed(SipMessage& message) void
DumHelper::setEncryptionPerformed(SipMessage& message)
{ {
SecurityAttributes* attr = new SecurityAttributes(); SecurityAttributes* attr = new SecurityAttributes();
attr->setOutgoingEncryptionLevel(message.getSecurityAttributes()->getOutgoingEncryptionLevel()); attr->setOutgoingEncryptionLevel(message.getSecurityAttributes()->getOutgoingEncryptionLevel());
attr->setEncryptionPerformed(true); attr->setEncryptionPerformed(true);
message.setSecurityAttributes(unique_ptr<SecurityAttributes>(attr)); message.setSecurityAttributes(auto_ptr<SecurityAttributes>(attr));
} }
SecurityAttributes::OutgoingEncryptionLevel DumHelper::convert(DialogUsageManager::EncryptionLevel level) SecurityAttributes::OutgoingEncryptionLevel
DumHelper::convert(DialogUsageManager::EncryptionLevel level)
{ {
SecurityAttributes::OutgoingEncryptionLevel ret = SecurityAttributes::None; SecurityAttributes::OutgoingEncryptionLevel ret = SecurityAttributes::None;

View File

@ -55,7 +55,7 @@ DumProcessHandler::handleProcessNotification()
{ {
mExternalTimer->deleteTimer(mTimerID); mExternalTimer->deleteTimer(mTimerID);
} }
assert(timeTillProcess < 60*4*60*1000); //4hr sanity check resip_assert(timeTillProcess < 60*4*60*1000); //4hr sanity check
mTimerID = mExternalTimer->generateAsyncID(); mTimerID = mExternalTimer->generateAsyncID();
DebugLog ( << "Setting dum process timer: " << timeTillProcess); DebugLog ( << "Setting dum process timer: " << timeTillProcess);
mExternalTimer->createTimer(mTimerID, timeTillProcess); mExternalTimer->createTimer(mTimerID, timeTillProcess);
@ -69,7 +69,7 @@ DumProcessHandler::handleProcessNotification()
void void
DumProcessHandler::handleTimeout(AsyncID timerID) DumProcessHandler::handleTimeout(AsyncID timerID)
{ {
assert(timerID == mTimerID); resip_assert(timerID == mTimerID);
mHaveActiveTimer = false; mHaveActiveTimer = false;
handleProcessNotification(); handleProcessNotification();
} }

View File

@ -18,10 +18,10 @@ DumThread::thread()
{ {
try try
{ {
std::unique_ptr<Message> msg(mDum.mFifo.getNext(1000)); // Only need to wake up to see if we are shutdown std::auto_ptr<Message> msg(mDum.mFifo.getNext(1000)); // Only need to wake up to see if we are shutdown
if (msg.get()) if (msg.get())
{ {
mDum.internalProcess(std::move(msg)); mDum.internalProcess(msg);
} }
} }
catch (BaseException& e) catch (BaseException& e)

View File

@ -1,4 +1,4 @@
#include <cassert> #include "rutil/ResipAssert.h"
#include "DumTimeout.hxx" #include "DumTimeout.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"
#include "resip/dum/BaseUsage.hxx" #include "resip/dum/BaseUsage.hxx"
@ -63,7 +63,7 @@ const Data & DumTimeout::transactionId() const
bool bool
DumTimeout::isClientTransaction() const DumTimeout::isClientTransaction() const
{ {
assert(0); resip_assert(0);
return false; return false;
} }
@ -100,6 +100,12 @@ DumTimeout::encode(EncodeStream& strm) const
case Retransmit1xx: case Retransmit1xx:
strm <<"Retransmit1xx"; strm <<"Retransmit1xx";
break; break;
case Retransmit1xxRel:
strm <<"Retransmit1xxRel";
break;
case Resubmit1xxRel:
strm <<"Resubmit1xxRel";
break;
case WaitForAck: case WaitForAck:
strm <<"WaitForAck"; strm <<"WaitForAck";
break; break;

View File

@ -20,6 +20,8 @@ class DumTimeout : public ApplicationMessage
Publication, Publication,
Retransmit200, Retransmit200,
Retransmit1xx, Retransmit1xx,
Retransmit1xxRel,
Resubmit1xxRel,
WaitForAck, // UAS gets no ACK WaitForAck, // UAS gets no ACK
CanDiscardAck, CanDiscardAck,
StaleCall, // UAC gets no final response StaleCall, // UAC gets no final response

View File

@ -2,7 +2,7 @@
#define RESIP_HANDLE_HXX #define RESIP_HANDLE_HXX
#include <iosfwd> #include <iosfwd>
#include <cassert> #include "rutil/ResipAssert.h"
#include "resip/dum/Handled.hxx" #include "resip/dum/Handled.hxx"
#include "resip/dum/HandleManager.hxx" #include "resip/dum/HandleManager.hxx"
#include "resip/dum/HandleException.hxx" #include "resip/dum/HandleException.hxx"
@ -95,8 +95,8 @@ class Handle
// !nash! to be able to use Handle in Set or Map container // !nash! to be able to use Handle in Set or Map container
bool operator<(const Handle<T>& other) const bool operator<(const Handle<T>& other) const
{ {
assert(mHam); resip_assert(mHam);
assert(other.mHam); resip_assert(other.mHam);
return mId < other.mId; return mId < other.mId;
} }

View File

@ -1,4 +1,4 @@
#include <cassert> #include "rutil/ResipAssert.h"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
#include "rutil/Inserter.hxx" #include "rutil/Inserter.hxx"
#include "resip/dum/HandleManager.hxx" #include "resip/dum/HandleManager.hxx"
@ -72,7 +72,7 @@ void
HandleManager::remove(Handled::Id id) HandleManager::remove(Handled::Id id)
{ {
HandleMap::iterator i = mHandleMap.find(id); HandleMap::iterator i = mHandleMap.find(id);
assert (i != mHandleMap.end()); resip_assert (i != mHandleMap.end());
mHandleMap.erase(i); mHandleMap.erase(i);
if (mShuttingDown) if (mShuttingDown)
{ {
@ -110,112 +110,64 @@ HandleManager::getHandled(Handled::Id id) const
if (i == mHandleMap.end()) if (i == mHandleMap.end())
{ {
InfoLog (<< "Reference to stale handle: " << id); InfoLog (<< "Reference to stale handle: " << id);
assert(0); resip_assert(0);
throw HandleException("Stale handle", __FILE__, __LINE__); throw HandleException("Stale handle", __FILE__, __LINE__);
} }
else else
{ {
assert(i->second); resip_assert(i->second);
return i->second; return i->second;
} }
} }
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0
* *
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
* *
* 1. Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in * notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the * the documentation and/or other materials provided with the
* distribution. * distribution.
* *
* 3. The names "VOCAL", "Vovida Open Communication Application Library", * 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must * and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this * not be used to endorse or promote products derived from this
* software without prior written permission. For written * software without prior written permission. For written
* permission, please contact vocal@vovida.org. * permission, please contact vocal@vovida.org.
* *
* 4. Products derived from this software may not be called "VOCAL", nor * 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written * may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc. * permission of Vovida Networks, Inc.
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE. * DAMAGE.
* *
* ==================================================================== * ====================================================================
* *
* This software consists of voluntary contributions made by Vovida * This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks, * Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see * Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>. * <http://www.vovida.org/>.
* *
*/ */

View File

@ -4,13 +4,13 @@
using namespace resip; using namespace resip;
HttpProvider* HttpProvider::mInstance = 0; HttpProvider* HttpProvider::mInstance = 0;
std::unique_ptr<HttpProviderFactory> HttpProvider::mFactory; std::auto_ptr<HttpProviderFactory> HttpProvider::mFactory;
Mutex HttpProvider::mMutex; Mutex HttpProvider::mMutex;
void void
HttpProvider::setFactory(std::unique_ptr<HttpProviderFactory> fact) HttpProvider::setFactory(std::auto_ptr<HttpProviderFactory> fact)
{ {
mFactory = std::move(fact); mFactory = fact;
} }
HttpProvider* HttpProvider*

View File

@ -21,7 +21,7 @@ class HttpProvider
{ {
public: public:
//HttpProvider assumes memory //HttpProvider assumes memory
static void setFactory(std::unique_ptr<HttpProviderFactory> fact); static void setFactory(std::auto_ptr<HttpProviderFactory> fact);
//ptr so users can check for existence //ptr so users can check for existence
static HttpProvider* instance(); static HttpProvider* instance();
@ -30,7 +30,7 @@ class HttpProvider
virtual ~HttpProvider(){} //impl. singleton destructor pattern later virtual ~HttpProvider(){} //impl. singleton destructor pattern later
private: private:
static HttpProvider* mInstance; static HttpProvider* mInstance;
static std::unique_ptr<HttpProviderFactory> mFactory; static std::auto_ptr<HttpProviderFactory> mFactory;
static Mutex mMutex; static Mutex mMutex;
}; };

View File

@ -98,10 +98,10 @@ IdentityHandler::queueForIdentityCheck(SipMessage* sipMsg)
} }
#endif #endif
std::unique_ptr<SecurityAttributes> sec(new SecurityAttributes); std::auto_ptr<SecurityAttributes> sec(new SecurityAttributes);
sec->setIdentity(sipMsg->header(h_From).uri().getAor()); sec->setIdentity(sipMsg->header(h_From).uri().getAor());
sec->setIdentityStrength(SecurityAttributes::From); sec->setIdentityStrength(SecurityAttributes::From);
sipMsg->setSecurityAttributes(std::move(sec)); sipMsg->setSecurityAttributes(sec);
return false; return false;
} }
@ -114,7 +114,7 @@ IdentityHandler::processIdentityCheckResponse(const HttpGetMessage& msg)
if (it != mRequiresCerts.end()) if (it != mRequiresCerts.end())
{ {
mDum.getSecurity()->checkAndSetIdentity( *it->second, msg.getBodyData() ); mDum.getSecurity()->checkAndSetIdentity( *it->second, msg.getBodyData() );
postCommand(unique_ptr<Message>(it->second)); postCommand(auto_ptr<Message>(it->second));
mRequiresCerts.erase(it); mRequiresCerts.erase(it);
} }
#endif #endif

View File

@ -106,7 +106,7 @@ InMemoryRegistrationDatabase::unlockRecord(const Uri& aor)
database_map_t::iterator i = mDatabase.find(aor); database_map_t::iterator i = mDatabase.find(aor);
// The record must have been inserted when we locked it in the first place // The record must have been inserted when we locked it in the first place
assert (i != mDatabase.end()); resip_assert (i != mDatabase.end());
if (i->second == 0) if (i->second == 0)
{ {
@ -141,7 +141,7 @@ InMemoryRegistrationDatabase::updateContact(const resip::Uri& aor,
} }
assert(contactList); resip_assert(contactList);
ContactList::iterator j; ContactList::iterator j;

View File

@ -47,7 +47,7 @@ class InMemoryRegistrationDatabase : public RegistrationPersistenceManager
/// return all the AOR in the DB /// return all the AOR in the DB
virtual void getAors(UriList& container); virtual void getAors(UriList& container);
private: protected:
typedef std::map<Uri,ContactList *> database_map_t; typedef std::map<Uri,ContactList *> database_map_t;
database_map_t mDatabase; database_map_t mDatabase;
Mutex mDatabaseMutex; Mutex mDatabaseMutex;
@ -58,14 +58,12 @@ class InMemoryRegistrationDatabase : public RegistrationPersistenceManager
bool mCheckExpiry; bool mCheckExpiry;
protected:
/** /**
* Find aor in mDatabase * Find aor in mDatabase
* Before returning the iterator pointing to aor, * Before returning the iterator pointing to aor,
* delete all expired contacts * delete all expired contacts
*/ */
database_map_t::iterator findNotExpired(const Uri& aor); database_map_t::iterator findNotExpired(const Uri& aor);
}; };
} }

View File

@ -0,0 +1,437 @@
#include "resip/dum/InMemorySyncPubDb.hxx"
#include "rutil/compat.hxx"
#include "rutil/Timer.hxx"
#include "rutil/Logger.hxx"
#include "rutil/WinLeakCheck.hxx"
using namespace resip;
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
InMemorySyncPubDb::InMemorySyncPubDb(bool syncEnabled) : mSyncEnabled(syncEnabled)
{
}
InMemorySyncPubDb::~InMemorySyncPubDb()
{
}
void
InMemorySyncPubDb::addHandler(InMemorySyncPubDbHandler* handler)
{
Lock lock(mHandlerMutex);
mHandlers.push_back(handler);
}
void
InMemorySyncPubDb::removeHandler(InMemorySyncPubDbHandler* handler)
{
Lock lock(mHandlerMutex);
for(HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
{
if(*it == handler)
{
mHandlers.erase(it);
break;
}
}
}
bool
InMemorySyncPubDb::shouldEraseDocument(PubDocument& document, UInt64 now)
{
if (mSyncEnabled)
{
// Check if already lingering
if (document.mExpirationTime == 0)
{
// Check if linger time is done
if (document.mLingerTime <= now)
{
return true;
}
}
else if (document.mExpirationTime <= now)
{
// Tag document to linger
document.mLastUpdated = document.mExpirationTime;
document.mExpirationTime = 0;
}
}
else
{
if (document.mExpirationTime <= now)
{
return true;
}
}
return false;
}
void
InMemorySyncPubDb::initialSync(unsigned int connectionId)
{
Lock g(mDatabaseMutex);
UInt64 now = Timer::getTimeSecs();
// Iterate through keys
KeyToETagMap::iterator keyIt = mPublicationDb.begin();
for (; keyIt != mPublicationDb.end(); )
{
// Iterator through documents in sub-map
ETagToDocumentMap::iterator eTagIt = keyIt->second.begin();
for (; eTagIt != keyIt->second.end();)
{
if (shouldEraseDocument(eTagIt->second, now))
{
keyIt->second.erase(eTagIt++);
}
else
{
invokeOnInitialSyncDocument(connectionId, eTagIt->second.mEventType, eTagIt->second.mDocumentKey, eTagIt->second.mETag, eTagIt->second.mExpirationTime, eTagIt->second.mLastUpdated, eTagIt->second.mContents.get(), eTagIt->second.mSecurityAttributes.get());
eTagIt++;
}
}
// If there are no more eTags then remove entity
if (keyIt->second.size() == 0)
{
mPublicationDb.erase(keyIt++);
}
else
{
keyIt++;
}
}
}
void
InMemorySyncPubDb::addUpdateDocument(const PubDocument& document)
{
Lock g(mDatabaseMutex);
Data mapKey = document.mEventType + document.mDocumentKey;
bool found = false;
KeyToETagMap::iterator keyIt = mPublicationDb.find(mapKey);
if (keyIt != mPublicationDb.end())
{
// Next find eTag in sub-map
ETagToDocumentMap::iterator eTagIt = keyIt->second.find(document.mETag);
if (eTagIt != keyIt->second.end())
{
// Doc was found! Do some checks
found = true;
// If doc is from sync then ensure it is newer
if (!document.mSyncPublication || (document.mLastUpdated > eTagIt->second.mLastUpdated))
{
UInt64 now = Timer::getTimeSecs();
SharedPtr<Contents> contentsForOnDocumentModified = document.mContents;
SharedPtr<SecurityAttributes> securityAttributesForOnDocumentModified = document.mSecurityAttributes;
// We should only need to linger a document past the latest expiration time we have ever seen, since both sides will
// treat the publication as gone after this time anyway. However this is timing sensitive with the sync process.
// So we will linger a document for twice this duration.
UInt64 lingerDuration = (resipMax(document.mExpirationTime, eTagIt->second.mExpirationTime) - now) * 2;
if (document.mContents.get() == 0) // If this is a pub refresh then ensure we don't get rid of existing doc body
{
// If previous document was expired then ensure we push out a notify on the refresh to tell everyone it's back
// This can happen if someone deletes a publication on the web page, then it is refreshed. The delete causes a
// notify of closed state, the refresh should bring the state back.
if (eTagIt->second.mExpirationTime == 0 ||
eTagIt->second.mExpirationTime < now)
{
contentsForOnDocumentModified = eTagIt->second.mContents;
securityAttributesForOnDocumentModified = eTagIt->second.mSecurityAttributes;
}
SharedPtr<Contents> contents = eTagIt->second.mContents;
SharedPtr<SecurityAttributes> securityAttributes = eTagIt->second.mSecurityAttributes;
eTagIt->second = document;
eTagIt->second.mContents = contents;
eTagIt->second.mSecurityAttributes = securityAttributes;
}
else
{
eTagIt->second = document;
}
eTagIt->second.mLingerTime = now + lingerDuration;
// Only pass sync as true if this update just came from an inbound sync operation
invokeOnDocumentModified(document.mSyncPublication /* sync publication? */, document.mEventType, document.mDocumentKey, document.mETag, document.mExpirationTime, document.mLastUpdated, contentsForOnDocumentModified.get(), securityAttributesForOnDocumentModified.get());
}
}
}
// If we didn't find an existing document and we have a contents, then add this doc.
// Note: Pub refreshes don't contain a contents - so we happen to receive a refresh as our
// first message for an etag we don't want to add it to the store - until we have
// at least a doc body.
if (!found && document.mContents.get() != 0)
{
// Add new
mPublicationDb[mapKey][document.mETag] = document;
// Only pass sync as true if this update just came from an inbound sync operation
invokeOnDocumentModified(document.mSyncPublication /* sync publication? */, document.mEventType, document.mDocumentKey, document.mETag, document.mExpirationTime, document.mLastUpdated, document.mContents.get(), document.mSecurityAttributes.get());
}
}
bool
InMemorySyncPubDb::removeDocument(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated, bool syncPublication)
{
bool result = false;
Lock g(mDatabaseMutex);
// First find entity in map
KeyToETagMap::iterator keyIt = mPublicationDb.find(eventType + documentKey);
if (keyIt != mPublicationDb.end())
{
// Next find eTag in sub-map
ETagToDocumentMap::iterator eTagIt = keyIt->second.find(eTag);
if (eTagIt != keyIt->second.end())
{
result = true;
// If remove is from sync then ensure it is newer
if (!syncPublication || (lastUpdated > eTagIt->second.mLastUpdated))
{
// If sync is enabled - then linger the record in memory until it expires
if (mSyncEnabled)
{
// Tag document as expired, but in a linger state
eTagIt->second.mExpirationTime = 0;
eTagIt->second.mLastUpdated = Timer::getTimeSecs();
}
else
{
// ETag was found - remove it
keyIt->second.erase(eTagIt);
}
// Only pass sync as true if this update just come from an inbound sync operation
invokeOnDocumentRemoved(syncPublication /* sync? */, eventType, documentKey, eTag, lastUpdated);
}
}
// If there are no more eTags then remove entity
if (keyIt->second.size() == 0)
{
mPublicationDb.erase(keyIt);
}
}
return result;
}
bool
InMemorySyncPubDb::getMergedETags(const Data& eventType, const Data& documentKey, ETagMerger& merger, Contents* destination)
{
Lock g(mDatabaseMutex);
// Find entity
KeyToETagMap::iterator keyIt = mPublicationDb.find(eventType + documentKey);
if (keyIt != mPublicationDb.end())
{
bool isFirst = true;
UInt64 now = Timer::getTimeSecs();
// Iterate through all Etags
ETagToDocumentMap::iterator eTagIt = keyIt->second.begin();
for (; eTagIt != keyIt->second.end(); )
{
if (!shouldEraseDocument(eTagIt->second, now))
{
// Just because we don't need to erase it doesn't mean it didn't expire - check for expiration
if (eTagIt->second.mExpirationTime > now && eTagIt->second.mContents.get() != 0)
{
merger.mergeETag(destination, eTagIt->second.mContents.get(), isFirst);
isFirst = false;
}
eTagIt++;
}
else
{
// ETag has expired - remove it
keyIt->second.erase(eTagIt++);
// If no more Etags for key, then remove key entry and bail out
if (keyIt->second.size() == 0)
{
mPublicationDb.erase(keyIt);
break;
}
}
}
// If we have at least on ETag then return true
if (!isFirst)
{
return true;
}
}
return false;
}
bool
InMemorySyncPubDb::documentExists(const Data& eventType, const Data& documentKey, const Data& eTag)
{
Lock g(mDatabaseMutex);
// First find entity in map
KeyToETagMap::iterator keyIt = mPublicationDb.find(eventType + documentKey);
if (keyIt != mPublicationDb.end())
{
// Next find eTag in sub-map
ETagToDocumentMap::iterator eTagIt = keyIt->second.find(eTag);
if (eTagIt != keyIt->second.end())
{
// Decided not to check if expired or not. Not checking allows us to handle
// a scenario where the publication refresh went to another repro node and
// syncing was broken for some reason. Then a new publish comes here and
// the record is still lingering.
//if (eTagIt->second.mExpirationTime <= Timer::getTimeSecs())
{
return true;
}
}
}
return false;
}
// If lastUpdated != 0 then we make sure that passed in lastUpdated matches the document before returning true
// This method is used in timer expirey and the lastUpdated checks helps us to make sure the timer that just
// expired hasn't been made obsolete due to a new update.
bool InMemorySyncPubDb::checkExpired(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated)
{
Lock g(mDatabaseMutex);
// First find entity in map
KeyToETagMap::iterator keyIt = mPublicationDb.find(eventType + documentKey);
if (keyIt != mPublicationDb.end())
{
// Next find eTag in sub-map
ETagToDocumentMap::iterator eTagIt = keyIt->second.find(eTag);
if (eTagIt != keyIt->second.end())
{
UInt64 now = Timer::getTimeSecs();
if (eTagIt->second.mExpirationTime >= now &&
(lastUpdated == 0 || lastUpdated == eTagIt->second.mLastUpdated))
{
DebugLog(<< "InMemorySyncPubDb::checkExpired: found expired publication, docKey=" << documentKey << ", tag=" << eTag);
bool syncPublication = eTagIt->second.mSyncPublication;
// If sync is enabled - then linger the record in memory until it expires
if (mSyncEnabled)
{
// Tag document as expired, but in a linger state
eTagIt->second.mExpirationTime = 0;
eTagIt->second.mLastUpdated = now;
}
else
{
// ETag was found - remove it
keyIt->second.erase(eTagIt);
// If no more Etags for key, then remove key entry
if (keyIt->second.size() == 0)
{
mPublicationDb.erase(keyIt);
}
}
invokeOnDocumentRemoved(syncPublication /* sync? */, eventType, documentKey, eTag, now);
return true;
}
}
}
return false;
}
void
InMemorySyncPubDb::lockDocuments()
{
mDatabaseMutex.lock();
}
PublicationPersistenceManager::KeyToETagMap&
InMemorySyncPubDb::getDocuments()
{
return mPublicationDb;
}
void
InMemorySyncPubDb::unlockDocuments()
{
mDatabaseMutex.unlock();
}
void
InMemorySyncPubDb::invokeOnDocumentModified(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, UInt64 lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes)
{
Lock lock(mHandlerMutex);
for (HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
{
// If handler mode is all, then send notification, otherwise handler mode is sync and we ensure passed
// in syncPublication flag is false - so we don't sync back to originator
if (!sync || (*it)->getMode() == InMemorySyncPubDbHandler::AllChanges)
{
(*it)->onDocumentModified(sync, eventType, documentKey, eTag, expirationTime, lastUpdated, contents, securityAttributes);
}
}
}
void
InMemorySyncPubDb::invokeOnDocumentRemoved(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated)
{
Lock lock(mHandlerMutex);
for (HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
{
// If handler mode is all, then send notification, otherwise handler mode is sync and we ensure passed
// in syncPublication flag is false - so we don't sync back to originator
if (!sync || (*it)->getMode() == InMemorySyncPubDbHandler::AllChanges)
{
(*it)->onDocumentRemoved(sync, eventType, documentKey, eTag, lastUpdated);
}
}
}
void
InMemorySyncPubDb::invokeOnInitialSyncDocument(unsigned int connectionId, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, UInt64 lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes)
{
Lock lock(mHandlerMutex);
for (HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
{
// If handler mode is all, then send notification, otherwise handler mode is sync and we check the passed
// in sync flag
if ((*it)->getMode() == InMemorySyncPubDbHandler::SyncServer)
{
(*it)->onInitialSyncDocument(connectionId, eventType, documentKey, eTag, expirationTime, lastUpdated, contents, securityAttributes);
}
}
}
/* ====================================================================
*
* Copyright (c) 2015 SIP Spectrum, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
*
*/
/*
* vi: set shiftwidth=3 expandtab:
*/

View File

@ -0,0 +1,119 @@
#if !defined(RESIP_INMEMORYSYNCPUBDB_HXX)
#define RESIP_INMEMORYSYNCPUBDB_HXX
#include <list>
#include "resip/dum/PublicationPersistenceManager.hxx"
#include "rutil/Mutex.hxx"
#include "rutil/Lock.hxx"
namespace resip
{
class SecurityAttributes;
class InMemorySyncPubDbHandler
{
public:
typedef enum
{
SyncServer,
AllChanges
} HandlerMode;
InMemorySyncPubDbHandler(HandlerMode mode = SyncServer) : mMode(mode) {}
virtual ~InMemorySyncPubDbHandler(){}
HandlerMode getMode() { return mMode; }
virtual void onDocumentModified(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, UInt64 lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes) = 0;
virtual void onDocumentRemoved(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated) = 0;
virtual void onInitialSyncDocument(unsigned int connectionId, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, UInt64 lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes) {}
protected:
HandlerMode mMode;
};
/**
Implementation of a persistence manager. This class keeps
all publications in memory, and is used for remote replication.
The InMemorySyncPubDbHandler can be used by an external mechanism to
transport publication documents to a remote peer for replication.
See the RegSyncClient and RegSyncServer implementations in the repro
project.
*/
class InMemorySyncPubDb : public PublicationPersistenceManager
{
public:
InMemorySyncPubDb(bool syncEnabled = false);
virtual ~InMemorySyncPubDb();
virtual void addHandler(InMemorySyncPubDbHandler* handler);
virtual void removeHandler(InMemorySyncPubDbHandler* handler);
virtual void initialSync(unsigned int connectionId);
// PublicationPersistenceManager Methods
virtual void addUpdateDocument(const PubDocument& document);
virtual bool removeDocument(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated, bool syncPublication = false);
virtual bool getMergedETags(const Data& eventType, const Data& documentKey, ETagMerger& merger, Contents* destination);
virtual bool documentExists(const Data& eventType, const Data& documentKey, const Data& eTag);
virtual bool checkExpired(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated);
virtual void lockDocuments();
virtual KeyToETagMap& getDocuments(); // Ensure you lock before calling this and unlock when done
virtual void unlockDocuments();
protected:
void invokeOnDocumentModified(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, UInt64 lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes);
void invokeOnDocumentRemoved(bool sync, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated);
void invokeOnInitialSyncDocument(unsigned int connectionId, const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, UInt64 lastUpdated, const Contents* contents, const SecurityAttributes* securityAttributes);
bool shouldEraseDocument(PubDocument& document, UInt64 now);
bool mSyncEnabled;
typedef std::list<InMemorySyncPubDbHandler*> HandlerList;
HandlerList mHandlers; // use list over set to preserve add order
Mutex mHandlerMutex;
KeyToETagMap mPublicationDb;
Mutex mDatabaseMutex;
};
}
#endif
/* ====================================================================
*
* Copyright (c) 2015 SIP Spectrum, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
*
*/
/*
* vi: set shiftwidth=3 expandtab:
*/

View File

@ -54,8 +54,7 @@ contactsRemoveIfRequired(ContactList& contacts, UInt64& now,
} }
InMemorySyncRegDb::InMemorySyncRegDb(unsigned int removeLingerSecs) : InMemorySyncRegDb::InMemorySyncRegDb(unsigned int removeLingerSecs) :
mRemoveLingerSecs(removeLingerSecs), mRemoveLingerSecs(removeLingerSecs)
mHandler(0)
{ {
} }
@ -69,6 +68,55 @@ InMemorySyncRegDb::~InMemorySyncRegDb()
mDatabase.clear(); mDatabase.clear();
} }
void
InMemorySyncRegDb::addHandler(InMemorySyncRegDbHandler* handler)
{
Lock lock(mHandlerMutex);
mHandlers.push_back(handler);
}
void
InMemorySyncRegDb::removeHandler(InMemorySyncRegDbHandler* handler)
{
Lock lock(mHandlerMutex);
for(HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
{
if(*it == handler)
{
mHandlers.erase(it);
break;
}
}
}
void
InMemorySyncRegDb::invokeOnAorModified(bool sync, const resip::Uri& aor, const ContactList& contacts)
{
Lock lock(mHandlerMutex);
for(HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
{
// If handler mode is all, then send notification, otherwise handler mode is sync and we check the passed
// in sync flag
if (sync || (*it)->getMode() == InMemorySyncRegDbHandler::AllChanges)
{
(*it)->onAorModified(aor, contacts);
}
}
}
void
InMemorySyncRegDb::invokeOnInitialSyncAor(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts)
{
Lock lock(mHandlerMutex);
for (HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
{
if ((*it)->getMode() == InMemorySyncRegDbHandler::SyncServer)
{
(*it)->onInitialSyncAor(connectionId, aor, contacts);
}
}
}
void void
InMemorySyncRegDb::initialSync(unsigned int connectionId) InMemorySyncRegDb::initialSync(unsigned int connectionId)
{ {
@ -83,7 +131,7 @@ InMemorySyncRegDb::initialSync(unsigned int connectionId)
{ {
contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs); contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs);
} }
if(mHandler) mHandler->onInitialSyncAor(connectionId, it->first, contacts); invokeOnInitialSyncAor(connectionId, it->first, contacts);
} }
} }
} }
@ -109,7 +157,7 @@ InMemorySyncRegDb::addAor(const Uri& aor,
{ {
mDatabase[aor] = new ContactList(contacts); mDatabase[aor] = new ContactList(contacts);
} }
if(mHandler) mHandler->onAorModified(aor, contacts); invokeOnAorModified(true /* sync? */, aor, contacts);
} }
void void
@ -134,7 +182,7 @@ InMemorySyncRegDb::removeAor(const Uri& aor)
it->mRegExpires = 0; it->mRegExpires = 0;
it->mLastUpdated = now; it->mLastUpdated = now;
} }
if(mHandler) mHandler->onAorModified(aor, contacts); invokeOnAorModified(true /* sync? */, aor, contacts);
} }
else else
{ {
@ -142,7 +190,7 @@ InMemorySyncRegDb::removeAor(const Uri& aor)
// Setting this to 0 causes it to be removed when we unlock the AOR. // Setting this to 0 causes it to be removed when we unlock the AOR.
i->second = 0; i->second = 0;
ContactList emptyList; ContactList emptyList;
if(mHandler) mHandler->onAorModified(aor, emptyList); invokeOnAorModified(true /* sync? */, aor, emptyList);
} }
} }
} }
@ -160,14 +208,21 @@ InMemorySyncRegDb::getAors(InMemorySyncRegDb::UriList& container)
} }
} }
bool bool
InMemorySyncRegDb::aorIsRegistered(const Uri& aor) InMemorySyncRegDb::aorIsRegistered(const Uri& aor)
{
return aorIsRegistered(aor, 0);
}
bool
InMemorySyncRegDb::aorIsRegistered(const Uri& aor, UInt64* maxExpires)
{ {
Lock g(mDatabaseMutex); Lock g(mDatabaseMutex);
bool registered = false;
database_map_t::iterator i = mDatabase.find(aor); database_map_t::iterator i = mDatabase.find(aor);
if (i != mDatabase.end() && i->second == 0) if (i != mDatabase.end() && i->second != 0)
{ {
if(mRemoveLingerSecs > 0) if (mRemoveLingerSecs > 0 || maxExpires)
{ {
ContactList& contacts = *(i->second); ContactList& contacts = *(i->second);
UInt64 now = Timer::getTimeSecs(); UInt64 now = Timer::getTimeSecs();
@ -175,16 +230,24 @@ InMemorySyncRegDb::aorIsRegistered(const Uri& aor)
{ {
if(it->mRegExpires > now) if(it->mRegExpires > now)
{ {
return true; registered = true;
if (maxExpires)
{
*maxExpires = resipMax(*maxExpires, it->mRegExpires);
}
else
{
break; // Not looking for maxExpires - so we can quit iterating now
}
} }
} }
} }
else else
{ {
return true; registered = true;
} }
} }
return false; return registered;
} }
void void
@ -221,7 +284,7 @@ InMemorySyncRegDb::unlockRecord(const Uri& aor)
database_map_t::iterator i = mDatabase.find(aor); database_map_t::iterator i = mDatabase.find(aor);
// The record must have been inserted when we locked it in the first place // The record must have been inserted when we locked it in the first place
assert (i != mDatabase.end()); resip_assert (i != mDatabase.end());
if (i->second == 0) if (i->second == 0)
{ {
@ -255,7 +318,7 @@ InMemorySyncRegDb::updateContact(const resip::Uri& aor,
} }
} }
assert(contactList); resip_assert(contactList);
ContactList::iterator j; ContactList::iterator j;
@ -274,14 +337,16 @@ InMemorySyncRegDb::updateContact(const resip::Uri& aor,
status = CONTACT_CREATED; status = CONTACT_CREATED;
} }
*j=rec; *j=rec;
if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList); // Only pass sync as true if this update didn't just come from an inbound sync operation
invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
return status; return status;
} }
} }
// This is a new contact, so we add it to the list. // This is a new contact, so we add it to the list.
contactList->push_back(rec); contactList->push_back(rec);
if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList); // Only pass sync as true if this update didn't just come from an inbound sync operation
invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
return CONTACT_CREATED; return CONTACT_CREATED;
} }
@ -314,7 +379,8 @@ InMemorySyncRegDb::removeContact(const Uri& aor,
{ {
j->mRegExpires = 0; j->mRegExpires = 0;
j->mLastUpdated = Timer::getTimeSecs(); j->mLastUpdated = Timer::getTimeSecs();
if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList); // Only pass sync as true if this update didn't just come from an inbound sync operation
invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
} }
else else
{ {
@ -325,7 +391,8 @@ InMemorySyncRegDb::removeContact(const Uri& aor,
} }
else else
{ {
if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList); // Only pass sync as true if this update didn't just come from an inbound sync operation
invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
} }
} }
return; return;

View File

@ -3,6 +3,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <list>
#include "resip/dum/RegistrationPersistenceManager.hxx" #include "resip/dum/RegistrationPersistenceManager.hxx"
#include "rutil/Mutex.hxx" #include "rutil/Mutex.hxx"
@ -15,11 +16,21 @@ namespace resip
class InMemorySyncRegDbHandler class InMemorySyncRegDbHandler
{ {
public: public:
virtual ~InMemorySyncRegDbHandler(){} typedef enum
virtual void onAorModified(const resip::Uri& aor, const ContactList& contacts) = 0; {
virtual void onInitialSyncAor(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts) = 0; SyncServer,
AllChanges
} HandlerMode;
InMemorySyncRegDbHandler(HandlerMode mode = SyncServer) : mMode(mode) {}
virtual ~InMemorySyncRegDbHandler(){}
HandlerMode getMode() { return mMode; }
virtual void onAorModified(const resip::Uri& aor, const ContactList& contacts) = 0;
virtual void onInitialSyncAor(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts) {}
protected:
HandlerMode mMode;
}; };
/** /**
Implementation of a persistence manager. This class keeps Implementation of a persistence manager. This class keeps
all registrations in memory, and is used for remote replication. all registrations in memory, and is used for remote replication.
@ -45,12 +56,15 @@ class InMemorySyncRegDb : public RegistrationPersistenceManager
InMemorySyncRegDb(unsigned int removeLingerSecs = 0); InMemorySyncRegDb(unsigned int removeLingerSecs = 0);
virtual ~InMemorySyncRegDb(); virtual ~InMemorySyncRegDb();
virtual void setHandler(InMemorySyncRegDbHandler* handler) { mHandler = handler; } virtual void addHandler(InMemorySyncRegDbHandler* handler);
virtual void removeHandler(InMemorySyncRegDbHandler* handler);
virtual void initialSync(unsigned int connectionId); virtual void initialSync(unsigned int connectionId);
virtual void addAor(const Uri& aor, const ContactList& contacts); virtual void addAor(const Uri& aor, const ContactList& contacts);
virtual void removeAor(const Uri& aor); virtual void removeAor(const Uri& aor);
virtual bool aorIsRegistered(const Uri& aor); virtual bool aorIsRegistered(const Uri& aor);
virtual bool aorIsRegistered(const Uri& aor, UInt64* maxExpires);
virtual void lockRecord(const Uri& aor); virtual void lockRecord(const Uri& aor);
virtual void unlockRecord(const Uri& aor); virtual void unlockRecord(const Uri& aor);
@ -66,7 +80,7 @@ class InMemorySyncRegDb : public RegistrationPersistenceManager
/// return all the AOR in the DB /// return all the AOR in the DB
virtual void getAors(UriList& container); virtual void getAors(UriList& container);
private: protected:
typedef std::map<Uri,ContactList *> database_map_t; typedef std::map<Uri,ContactList *> database_map_t;
database_map_t mDatabase; database_map_t mDatabase;
Mutex mDatabaseMutex; Mutex mDatabaseMutex;
@ -75,8 +89,12 @@ class InMemorySyncRegDb : public RegistrationPersistenceManager
Mutex mLockedRecordsMutex; Mutex mLockedRecordsMutex;
Condition mRecordUnlocked; Condition mRecordUnlocked;
void invokeOnAorModified(bool sync, const resip::Uri& aor, const ContactList& contacts);
void invokeOnInitialSyncAor(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts);
unsigned int mRemoveLingerSecs; unsigned int mRemoveLingerSecs;
InMemorySyncRegDbHandler* mHandler; typedef std::list<InMemorySyncRegDbHandler*> HandlerList;
HandlerList mHandlers; // use list over set to preserve add order
Mutex mHandlerMutex;
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -22,8 +22,6 @@ class SdpContents;
class InviteSession : public DialogUsage class InviteSession : public DialogUsage
{ {
public: public:
bool canProvideOffer();
/** Called to set the offer that will be used in the next message that /** Called to set the offer that will be used in the next message that
sends an offer. If possible, this will synchronously send the sends an offer. If possible, this will synchronously send the
appropriate request or response. In some cases, the UAS might have to appropriate request or response. In some cases, the UAS might have to
@ -72,19 +70,22 @@ class InviteSession : public DialogUsage
virtual void reject(int statusCode, WarningCategory *warning = 0); virtual void reject(int statusCode, WarningCategory *warning = 0);
/** will send a reINVITE (current offerAnswer) or UPDATE with new Contact header */ /** will send a reINVITE (current offerAnswer) or UPDATE with new Contact header */
/** currently only supported when in the Connected state, UAC_Early states are allowed by RFC but not yet supported */
virtual void targetRefresh(const NameAddr& localUri); virtual void targetRefresh(const NameAddr& localUri);
// Following methods are for sending requests within a dialog // Following methods are for sending requests within a dialog
/** sends a refer request */ /** sends a refer request */
virtual void refer(const NameAddr& referTo, bool referSub = true); virtual void refer(const NameAddr& referTo, bool referSub = true);
virtual void refer(const NameAddr& referTo, std::unique_ptr<resip::Contents> contents, bool referSub = true); virtual void refer(const NameAddr& referTo, const NameAddr& referredBy, bool referSub = true);
virtual void refer(const NameAddr& referTo, std::auto_ptr<resip::Contents> contents, bool referSub = true);
virtual void refer(const NameAddr& referTo, const NameAddr& referredBy, std::auto_ptr<resip::Contents> contents, bool referSub = true);
/** sends a refer request with a replaces header */ /** sends a refer request with a replaces header */
virtual void refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub = true); virtual void refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub = true);
virtual void refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, std::unique_ptr<resip::Contents> contents, bool referSub = true); virtual void refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, std::auto_ptr<resip::Contents> contents, bool referSub = true);
virtual void refer(const NameAddr& referTo, const CallId& replaces, bool referSub = true); virtual void refer(const NameAddr& referTo, const CallId& replaces, bool referSub = true);
virtual void refer(const NameAddr& referTo, const CallId& replaces, std::unique_ptr<resip::Contents> contents, bool referSub = true); virtual void refer(const NameAddr& referTo, const CallId& replaces, std::auto_ptr<resip::Contents> contents, bool referSub = true);
/** sends an info request */ /** sends an info request */
virtual void info(const Contents& contents); virtual void info(const Contents& contents);
@ -221,17 +222,23 @@ class InviteSession : public DialogUsage
UAS_WaitingToRequestOffer, UAS_WaitingToRequestOffer,
UAS_AcceptedWaitingAnswer, UAS_AcceptedWaitingAnswer,
UAS_ReceivedOfferReliable, UAS_OfferReliable,
UAS_OfferReliableProvidedAnswer,
UAS_NoOfferReliable, UAS_NoOfferReliable,
UAS_ProvidedOfferReliable,
UAS_FirstSentOfferReliable, UAS_FirstSentOfferReliable,
UAS_FirstSentAnswerReliable, UAS_FirstSentAnswerReliable,
UAS_NoAnswerReliableWaitingPrack,
UAS_NegotiatedReliable, UAS_NegotiatedReliable,
UAS_NoAnswerReliable,
UAS_SentUpdate, UAS_SentUpdate,
UAS_SentUpdateAccepted, UAS_SentUpdateAccepted,
UAS_SentUpdateGlare,
UAS_ReceivedUpdate, UAS_ReceivedUpdate,
UAS_ReceivedUpdateWaitingAnswer, UAS_ReceivedUpdateWaitingAnswer,
UAS_WaitingToTerminate,
UAS_WaitingToHangup UAS_WaitingToHangup
// !!!!WARNING!!!! when adding new UAS state - make sure you check if they
// need to be added to the isAccepted method
} State; } State;
typedef enum typedef enum
@ -279,7 +286,6 @@ class InviteSession : public DialogUsage
InviteSession(DialogUsageManager& dum, Dialog& dialog); InviteSession(DialogUsageManager& dum, Dialog& dialog);
virtual ~InviteSession(); virtual ~InviteSession();
virtual void dialogDestroyed(const SipMessage& msg);
virtual void onReadyToSend(SipMessage& msg); virtual void onReadyToSend(SipMessage& msg);
virtual void flowTerminated(); virtual void flowTerminated();
@ -320,10 +326,10 @@ class InviteSession : public DialogUsage
static Data toData(State state); static Data toData(State state);
void transition(State target); void transition(State target);
std::unique_ptr<Contents> getOfferAnswer(const SipMessage& msg); std::auto_ptr<Contents> getOfferAnswer(const SipMessage& msg);
bool isReliable(const SipMessage& msg); bool isReliable(const SipMessage& msg) const;
static std::unique_ptr<Contents> makeOfferAnswer(const Contents& offerAnswer); static std::auto_ptr<Contents> makeOfferAnswer(const Contents& offerAnswer);
static std::unique_ptr<Contents> makeOfferAnswer(const Contents& offerAnswer, const Contents* alternative); static std::auto_ptr<Contents> makeOfferAnswer(const Contents& offerAnswer, const Contents* alternative);
static void setOfferAnswer(SipMessage& msg, const Contents& offerAnswer, const Contents* alternative = 0); static void setOfferAnswer(SipMessage& msg, const Contents& offerAnswer, const Contents* alternative = 0);
static void setOfferAnswer(SipMessage& msg, const Contents* offerAnswer); static void setOfferAnswer(SipMessage& msg, const Contents* offerAnswer);
void provideProposedOffer(); void provideProposedOffer();
@ -355,17 +361,16 @@ class InviteSession : public DialogUsage
NitState mNitState; NitState mNitState;
NitState mServerNitState; NitState mServerNitState;
std::unique_ptr<Contents> mCurrentLocalOfferAnswer; std::auto_ptr<Contents> mCurrentLocalOfferAnswer; // This gets set with mProposedLocalOfferAnswer after we receive an SDP answer from the remote end or when we send and SDP answer to the remote end
std::unique_ptr<Contents> mProposedLocalOfferAnswer; std::auto_ptr<Contents> mProposedLocalOfferAnswer; // This get set when we send an offer to the remote end
std::unique_ptr<Contents> mCurrentRemoteOfferAnswer; std::auto_ptr<Contents> mCurrentRemoteOfferAnswer; // This gets set with mProposedRemoteOfferAnswer after we send an SDP answer, or when we receive an SDP answer from the remote end
std::unique_ptr<Contents> mProposedRemoteOfferAnswer; std::auto_ptr<Contents> mProposedRemoteOfferAnswer; // This gets set when we receive an offer from the remote end
SharedPtr<SipMessage> mLastLocalSessionModification; // last UPDATE or reINVITE sent SharedPtr<SipMessage> mLastLocalSessionModification; // last UPDATE or reINVITE sent
SharedPtr<SipMessage> mLastRemoteSessionModification; // last UPDATE or reINVITE received SharedPtr<SipMessage> mLastRemoteSessionModification; // last UPDATE or reINVITE received
SharedPtr<SipMessage> mInvite200; // 200 OK for reINVITE for retransmissions SharedPtr<SipMessage> mInvite200; // 200 OK for reINVITE for retransmissions
SharedPtr<SipMessage> mLastNitResponse; // SharedPtr<SipMessage> mLastNitResponse;
//?dcm? -- ptr, delete when not needed?
SipMessage mLastReferNoSubRequest; SipMessage mLastReferNoSubRequest;
@ -396,7 +401,7 @@ class InviteSession : public DialogUsage
SharedPtr<SipMessage> mLastSentNITRequest; SharedPtr<SipMessage> mLastSentNITRequest;
DialogUsageManager::EncryptionLevel mCurrentEncryptionLevel; DialogUsageManager::EncryptionLevel mCurrentEncryptionLevel;
DialogUsageManager::EncryptionLevel mProposedEncryptionLevel; // UPDATE or RE-INVITE DialogUsageManager::EncryptionLevel mProposedEncryptionLevel; // UPDATE or RE-INVITE or PRACK
EndReason mEndReason; EndReason mEndReason;
@ -406,7 +411,7 @@ class InviteSession : public DialogUsage
// Used to respond to 2xx retransmissions. // Used to respond to 2xx retransmissions.
typedef HashMap<Data, SharedPtr<SipMessage> > AckMap; typedef HashMap<Data, SharedPtr<SipMessage> > AckMap;
AckMap mAcks; AckMap mAcks;
private: private:
friend class Dialog; friend class Dialog;
friend class DialogUsageManager; friend class DialogUsageManager;

View File

@ -29,7 +29,7 @@ InviteSessionCreator::InviteSessionCreator(DialogUsageManager& dum,
DumHelper::setOutgoingEncryptionLevel(*mLastRequest, level); DumHelper::setOutgoingEncryptionLevel(*mLastRequest, level);
if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer))) if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
{ {
assert(userProfile.get()); resip_assert(userProfile.get());
if(userProfile->getDefaultSessionTime() >= 90) if(userProfile->getDefaultSessionTime() >= 90)
{ {
getLastRequest()->header(h_SessionExpires).value() = userProfile->getDefaultSessionTime(); getLastRequest()->header(h_SessionExpires).value() = userProfile->getDefaultSessionTime();
@ -37,7 +37,7 @@ InviteSessionCreator::InviteSessionCreator(DialogUsageManager& dum,
} }
} }
std::unique_ptr<Contents> initialOffer; std::auto_ptr<Contents> initialOffer;
if (initial) if (initial)
{ {
if (alternative) if (alternative)
@ -51,7 +51,7 @@ InviteSessionCreator::InviteSessionCreator(DialogUsageManager& dum,
{ {
initialOffer.reset(initial->clone()); initialOffer.reset(initial->clone());
} }
getLastRequest()->setContents(std::move(initialOffer)); getLastRequest()->setContents(initialOffer);
} }
//100rel //100rel
switch(mDum.getMasterProfile()->getUacReliableProvisionalMode()) switch(mDum.getMasterProfile()->getUacReliableProvisionalMode())
@ -60,13 +60,14 @@ InviteSessionCreator::InviteSessionCreator(DialogUsageManager& dum,
//no support, do nothing //no support, do nothing
break; break;
case MasterProfile::Supported: case MasterProfile::Supported:
case MasterProfile::SupportedEssential:
getLastRequest()->header(h_Supporteds).push_back(Token(Symbols::C100rel)); getLastRequest()->header(h_Supporteds).push_back(Token(Symbols::C100rel));
break; break;
case MasterProfile::Required: case MasterProfile::Required:
getLastRequest()->header(h_Requires).push_back(Token(Symbols::C100rel)); getLastRequest()->header(h_Requires).push_back(Token(Symbols::C100rel));
break; break;
default: default:
assert(0); resip_assert(0);
} }
} }
@ -77,7 +78,7 @@ InviteSessionCreator::~InviteSessionCreator()
void void
InviteSessionCreator::end() InviteSessionCreator::end()
{ {
assert(0); resip_assert(0);
} }
void void

View File

@ -14,7 +14,7 @@ InviteSessionHandler::onEarlyMedia(ClientInviteSessionHandle h, const SipMessage
if(!mGenericOfferAnswer) if(!mGenericOfferAnswer)
{ {
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body); const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
assert(sdp); resip_assert(sdp);
onEarlyMedia(h, msg, *sdp); onEarlyMedia(h, msg, *sdp);
} }
} }
@ -69,7 +69,7 @@ InviteSessionHandler::onAnswer(InviteSessionHandle h, const SipMessage& msg, con
if(!mGenericOfferAnswer) if(!mGenericOfferAnswer)
{ {
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body); const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
assert(sdp); resip_assert(sdp);
onAnswer(h, msg, *sdp); onAnswer(h, msg, *sdp);
} }
} }
@ -80,7 +80,7 @@ InviteSessionHandler::onOffer(InviteSessionHandle h, const SipMessage& msg, cons
if(!mGenericOfferAnswer) if(!mGenericOfferAnswer)
{ {
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body); const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
assert(sdp); resip_assert(sdp);
onOffer(h, msg, *sdp); onOffer(h, msg, *sdp);
} }
} }
@ -96,7 +96,7 @@ InviteSessionHandler::onRemoteAnswerChanged(InviteSessionHandle h, const SipMess
if(!mGenericOfferAnswer) if(!mGenericOfferAnswer)
{ {
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body); const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
assert(sdp); resip_assert(sdp);
onRemoteSdpChanged(h, msg, *sdp); onRemoteSdpChanged(h, msg, *sdp);
} }
} }
@ -117,6 +117,11 @@ InviteSessionHandler::onConnectedConfirmed(InviteSessionHandle handle, const Sip
{ {
} }
void
InviteSessionHandler::onPrack(ServerInviteSessionHandle, const SipMessage &msg)
{
}
void void
InviteSessionHandler::onFlowTerminated(InviteSessionHandle) InviteSessionHandler::onFlowTerminated(InviteSessionHandle)
{ {

View File

@ -67,6 +67,9 @@ class InviteSessionHandler
/// called when ACK (with out an answer) is received for initial invite (UAS) /// called when ACK (with out an answer) is received for initial invite (UAS)
virtual void onConnectedConfirmed(InviteSessionHandle, const SipMessage &msg); virtual void onConnectedConfirmed(InviteSessionHandle, const SipMessage &msg);
/// called when PRACK is received for a reliable provisional answer (UAS)
virtual void onPrack(ServerInviteSessionHandle, const SipMessage &msg);
/** UAC gets no final response within the stale call timeout (default is 3 /** UAC gets no final response within the stale call timeout (default is 3
* minutes). This is just a notification. After the notification is * minutes). This is just a notification. After the notification is
* called, the InviteSession will then call * called, the InviteSession will then call
@ -91,7 +94,7 @@ class InviteSessionHandler
LocalCancel, LocalCancel,
RemoteCancel, RemoteCancel,
Rejected, //Only as UAS, UAC has distinct onFailure callback Rejected, //Only as UAS, UAC has distinct onFailure callback
Referred Referred //!slg! - This is really Redirected - not sure why it is called Referred. Only gets used when we send a redirect (ie: 302).
}; };
virtual void onTerminated(InviteSessionHandle, InviteSessionHandler::TerminatedReason reason, const SipMessage* related=0)=0; virtual void onTerminated(InviteSessionHandle, InviteSessionHandler::TerminatedReason reason, const SipMessage* related=0)=0;
@ -141,6 +144,8 @@ class InviteSessionHandler
virtual void onOfferRejected(InviteSessionHandle, const SipMessage* msg)=0; virtual void onOfferRejected(InviteSessionHandle, const SipMessage* msg)=0;
/// called when INFO message is received /// called when INFO message is received
/// the application must call acceptNIT() or rejectNIT()
/// once it is ready for another message.
virtual void onInfo(InviteSessionHandle, const SipMessage& msg)=0; virtual void onInfo(InviteSessionHandle, const SipMessage& msg)=0;
/// called when response to INFO message is received /// called when response to INFO message is received

View File

@ -5,6 +5,7 @@
#include "resip/dum/DialogUsageManager.hxx" #include "resip/dum/DialogUsageManager.hxx"
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
#include "rutil/TransportType.hxx"
#include "resip/stack/SipStack.hxx" #include "resip/stack/SipStack.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
@ -17,7 +18,7 @@ int KeepAliveManager::mKeepAlivePongTimeoutMs = 10000; // Defaults to 10000ms (
void void
KeepAliveManager::add(const Tuple& target, int keepAliveInterval, bool targetSupportsOutbound) KeepAliveManager::add(const Tuple& target, int keepAliveInterval, bool targetSupportsOutbound)
{ {
assert(mDum); resip_assert(mDum);
NetworkAssociationMap::iterator it = mNetworkAssociations.find(target); NetworkAssociationMap::iterator it = mNetworkAssociations.find(target);
if (it == mNetworkAssociations.end()) if (it == mNetworkAssociations.end())
{ {
@ -87,7 +88,7 @@ KeepAliveManager::remove(const Tuple& target)
void void
KeepAliveManager::process(KeepAliveTimeout& timeout) KeepAliveManager::process(KeepAliveTimeout& timeout)
{ {
assert(mDum); resip_assert(mDum);
static KeepAliveMessage msg; static KeepAliveMessage msg;
NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target()); NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target());
if (it != mNetworkAssociations.end() && timeout.id() == it->second.id) if (it != mNetworkAssociations.end() && timeout.id() == it->second.id)
@ -102,10 +103,10 @@ KeepAliveManager::process(KeepAliveTimeout& timeout)
{ {
// Assert if keep alive interval is too short in order to properly detect // Assert if keep alive interval is too short in order to properly detect
// missing pong responses - ie. interval must be greater than 10s // missing pong responses - ie. interval must be greater than 10s
assert((it->second.keepAliveInterval*1000) > mKeepAlivePongTimeoutMs); resip_assert((it->second.keepAliveInterval*1000) > mKeepAlivePongTimeoutMs);
// Start pong timeout if transport is TCP based (note: pong processing of Stun messaging is currently not implemented) // Start pong timeout if transport is TCP based (note: pong processing of Stun messaging is currently not implemented)
if(it->first.getType() == TCP || it->first.getType() == TLS) if(isReliable(it->first.getType()))
{ {
DebugLog( << "Starting pong timeout for keepalive id " << it->second.id); DebugLog( << "Starting pong timeout for keepalive id " << it->second.id);
KeepAlivePongTimeout t(it->first, it->second.id); KeepAlivePongTimeout t(it->first, it->second.id);
@ -131,7 +132,7 @@ KeepAliveManager::process(KeepAliveTimeout& timeout)
void void
KeepAliveManager::process(KeepAlivePongTimeout& timeout) KeepAliveManager::process(KeepAlivePongTimeout& timeout)
{ {
assert(mDum); resip_assert(mDum);
NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target()); NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target());
if (it != mNetworkAssociations.end() && timeout.id() == it->second.id) if (it != mNetworkAssociations.end() && timeout.id() == it->second.id)
{ {

View File

@ -0,0 +1,266 @@
# $Id$
EXTRA_DIST = Doxyfile
EXTRA_DIST += *.vcxproj
EXTRA_DIST += doc
SUBDIRS = . test
#AM_CXXFLAGS = -DUSE_ARES
AM_CXXFLAGS = -I $(top_srcdir)
lib_LTLIBRARIES = libdum.la
libdum_la_LIBADD = ../stack/libresip.la
libdum_la_LIBADD += ../../rutil/librutil.la
libdum_la_LIBADD += @LIBSSL_LIBADD@ @LIBRADIUS_LIBADD@
libdum_la_LIBADD += @LIBSTL_LIBADD@
libdum_la_LDFLAGS = @LIBTOOL_VERSION_RELEASE@ -export-dynamic
libdum_la_SOURCES = \
AppDialog.cxx \
AppDialogSet.cxx \
AppDialogSetFactory.cxx \
BaseCreator.cxx \
BaseUsage.cxx \
UserAuthInfo.cxx \
BaseSubscription.cxx \
ChallengeInfo.cxx \
ClientAuthManager.cxx \
ClientAuthExtension.cxx \
ClientInviteSession.cxx \
ClientOutOfDialogReq.cxx \
ClientPagerMessage.cxx \
ClientPublication.cxx \
ClientRegistration.cxx \
ClientSubscription.cxx \
ContactInstanceRecord.cxx \
DefaultServerReferHandler.cxx \
DestroyUsage.cxx \
Dialog.cxx \
DialogEventInfo.cxx \
DialogEventStateManager.cxx \
DialogId.cxx \
DialogSet.cxx \
DialogSetId.cxx \
DialogUsage.cxx \
DialogUsageManager.cxx \
DumProcessHandler.cxx \
DumThread.cxx \
DumTimeout.cxx \
EncryptionRequest.cxx \
HandleException.cxx \
HandleManager.cxx \
Handle.cxx \
Handled.cxx \
InMemoryRegistrationDatabase.cxx \
InMemorySyncPubDb.cxx \
InMemorySyncRegDb.cxx \
InviteSession.cxx \
InviteSessionCreator.cxx \
InviteSessionHandler.cxx \
MergedRequestKey.cxx \
NonDialogUsage.cxx \
OutOfDialogReqCreator.cxx \
PagerMessageCreator.cxx \
MasterProfile.cxx \
UserProfile.cxx \
Profile.cxx \
PublicationCreator.cxx \
RADIUSServerAuthManager.cxx \
RedirectManager.cxx \
RegistrationCreator.cxx \
RegistrationHandler.cxx \
ServerAuthManager.cxx \
ServerInviteSession.cxx \
ServerOutOfDialogReq.cxx \
ServerPagerMessage.cxx \
ServerPublication.cxx \
ServerRegistration.cxx \
ServerSubscription.cxx \
SubscriptionHandler.cxx \
SubscriptionCreator.cxx \
SubscriptionState.cxx \
TlsPeerAuthManager.cxx \
TlsPeerIdentityInfoMessage.cxx \
WsCookieAuthManager.cxx \
KeepAliveManager.cxx \
KeepAliveTimeout.cxx \
NetworkAssociation.cxx \
DumDecrypted.cxx \
CertMessage.cxx \
DumFeatureChain.cxx \
DumFeatureMessage.cxx \
IdentityHandler.cxx \
TargetCommand.cxx \
DumFeature.cxx \
OutgoingEvent.cxx \
HttpProvider.cxx \
HttpGetMessage.cxx \
DumHelper.cxx \
MergedRequestRemovalCommand.cxx
if USE_SSL
libdum_la_SOURCES += \
ssl/EncryptionManager.cxx
endif
dumincludedir = $(includedir)/resip/dum
nobase_duminclude_HEADERS = AppDialog.hxx \
AppDialogSetFactory.hxx \
AppDialogSet.hxx \
BaseCreator.hxx \
BaseSubscription.hxx \
BaseUsage.hxx \
CertMessage.hxx \
ChallengeInfo.hxx \
ClientAuthExtension.hxx \
ClientAuthManager.hxx \
ClientInviteSession.hxx \
ClientOutOfDialogReq.hxx \
ClientPagerMessage.hxx \
ClientPublication.hxx \
ClientRegistration.hxx \
ClientSubscriptionFunctor.hxx \
ClientSubscription.hxx \
ContactInstanceRecord.hxx \
DefaultServerReferHandler.hxx \
DestroyUsage.hxx \
DialogEventHandler.hxx \
DialogEventInfo.hxx \
DialogEventStateManager.hxx \
Dialog.hxx \
DialogId.hxx \
DialogSetHandler.hxx \
DialogSet.hxx \
DialogSetId.hxx \
DialogUsage.hxx \
DialogUsageManager.hxx \
DumCommand.hxx \
DumDecrypted.hxx \
DumException.hxx \
DumFeatureChain.hxx \
DumFeature.hxx \
DumFeatureMessage.hxx \
DumHelper.hxx \
DumProcessHandler.hxx \
DumShutdownHandler.hxx \
DumThread.hxx \
DumTimeout.hxx \
EncryptionRequest.hxx \
EventDispatcher.hxx \
ExternalMessageBase.hxx \
ExternalMessageHandler.hxx \
ExternalTimer.hxx \
Handled.hxx \
HandleException.hxx \
Handle.hxx \
HandleManager.hxx \
Handles.hxx \
HttpGetMessage.hxx \
HttpProvider.hxx \
IdentityHandler.hxx \
InMemoryRegistrationDatabase.hxx \
InMemorySyncPubDb.hxx \
InMemorySyncRegDb.hxx \
InviteDialogs.hxx \
InviteSessionCreator.hxx \
InviteSessionHandler.hxx \
InviteSession.hxx \
KeepAliveManager.hxx \
KeepAliveTimeout.hxx \
MasterProfile.hxx \
MergedRequestKey.hxx \
MergedRequestRemovalCommand.hxx \
NetworkAssociation.hxx \
NonDialogUsage.hxx \
OutgoingEvent.hxx \
OutOfDialogHandler.hxx \
OutOfDialogReqCreator.hxx \
PagerMessageCreator.hxx \
PagerMessageHandler.hxx \
Postable.hxx \
Profile.hxx \
PublicationCreator.hxx \
PublicationHandler.hxx \
PublicationPersistenceManager.hxx \
RADIUSServerAuthManager.hxx \
RedirectHandler.hxx \
RedirectManager.hxx \
RefCountedDestroyer.hxx \
RegistrationCreator.hxx \
RegistrationHandler.hxx \
RegistrationPersistenceManager.hxx \
RemoteCertStore.hxx \
RequestValidationHandler.hxx \
ServerAuthManager.hxx \
ServerInviteSession.hxx \
ServerOutOfDialogReq.hxx \
ServerPagerMessage.hxx \
ServerPublication.hxx \
ServerRegistration.hxx \
ServerSubscriptionFunctor.hxx \
ServerSubscription.hxx \
ssl/EncryptionManager.hxx \
SubscriptionCreator.hxx \
SubscriptionHandler.hxx \
SubscriptionPersistenceManager.hxx \
SubscriptionState.hxx \
TargetCommand.hxx \
TlsPeerAuthManager.hxx \
TlsPeerIdentityInfoMessage.hxx \
WsCookieAuthManager.hxx \
UsageUseException.hxx \
UserAuthInfo.hxx \
UserProfile.hxx
##############################################################################
#
# The Vovida Software License, Version 1.0
# Copyright (c) 2000-2007 Vovida Networks, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. The names "VOCAL", "Vovida Open Communication Application Library",
# and "Vovida Open Communication Application Library (VOCAL)" must
# not be used to endorse or promote products derived from this
# software without prior written permission. For written
# permission, please contact vocal@vovida.org.
#
# 4. Products derived from this software may not be called "VOCAL", nor
# may "VOCAL" appear in their name, without prior written
# permission of Vovida Networks, Inc.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
# NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
# IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
# ====================================================================
#
# This software consists of voluntary contributions made by Vovida
# Networks, Inc. and many individuals on behalf of Vovida Networks,
# Inc. For more information on Vovida Networks, Inc., please see
# <http://www.vovida.org/>.
#
##############################################################################

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
#include "resip/dum/Profile.hxx" #include "resip/dum/Profile.hxx"
#include "resip/dum/MasterProfile.hxx" #include "resip/dum/MasterProfile.hxx"
#include "resip/stack/HeaderTypes.hxx" #include "resip/stack/HeaderTypes.hxx"
#include "rutil/Logger.hxx"
using namespace resip; using namespace resip;
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
@ -22,7 +23,8 @@ MasterProfile::MasterProfile() :
mUasReliableProvisionalMode(Never), mUasReliableProvisionalMode(Never),
mServerRegistrationMinExpires(0), mServerRegistrationMinExpires(0),
mServerRegistrationMaxExpires(UINT_MAX), mServerRegistrationMaxExpires(UINT_MAX),
mServerRegistrationDefaultExpires(3600) mServerRegistrationDefaultExpires(3600),
mAdditionalTransactionTerminatingResponsesEnabled(false)
{ {
// Default settings // Default settings
addSupportedMimeType(INVITE, Mime("application", "sdp")); addSupportedMimeType(INVITE, Mime("application", "sdp"));
@ -64,6 +66,24 @@ MasterProfile::addSupportedMethod(const MethodTypes& method)
mSupportedMethods.push_back(Token(getMethodName(method))); mSupportedMethods.push_back(Token(getMethodName(method)));
} }
void
MasterProfile::removeSupportedMethod(const MethodTypes& method)
{
mSupportedMethodTypes.erase(method);
for (Tokens::iterator i = mSupportedMethods.begin();
i != mSupportedMethods.end(); ++i)
{
if (getMethodType(i->value()) == method)
{
mSupportedMethods.erase(i);
break;
}
}
// Should we clear the mimetypes as well?
// clearSupportedMimeTypes(method);
}
bool bool
MasterProfile::isMethodSupported(MethodTypes method) const MasterProfile::isMethodSupported(MethodTypes method) const
{ {
@ -106,8 +126,8 @@ MasterProfile::addSupportedOptionTag(const Token& tag)
{ {
if (tag == Token(Symbols::C100rel)) if (tag == Token(Symbols::C100rel))
{ {
//use enablePrackUas and enablePrackUac //use setUasReliableProvisionalMode and setUacReliableProvisionalMode
assert(0); resip_assert(0);
} }
mSupportedOptionTags.push_back(tag); mSupportedOptionTags.push_back(tag);
} }
@ -122,9 +142,12 @@ MasterProfile::getUnsupportedOptionsTags(const Tokens& requiresOptionTags)
{ {
tokens.push_back(Token("malformedTag")); tokens.push_back(Token("malformedTag"));
} }
else if (*i == Token(Symbols::C100rel) && mUasReliableProvisionalMode == Never) else if (*i == Token(Symbols::C100rel) )
{ {
tokens.push_back(*i); if (mUasReliableProvisionalMode == Never)
{
tokens.push_back(*i);
}
} }
// if this option is not supported // if this option is not supported
else if (!mSupportedOptionTags.find(*i)) else if (!mSupportedOptionTags.find(*i))
@ -157,8 +180,6 @@ MasterProfile::setUacReliableProvisionalMode(ReliableProvisionalMode mode)
void void
MasterProfile::setUasReliableProvisionalMode(ReliableProvisionalMode mode) MasterProfile::setUasReliableProvisionalMode(ReliableProvisionalMode mode)
{ {
//.dcm. not supported yet
assert(0);
mUasReliableProvisionalMode = mode; mUasReliableProvisionalMode = mode;
} }
@ -431,6 +452,40 @@ MasterProfile::clone() const
return new MasterProfile(*this); return new MasterProfile(*this);
} }
bool& MasterProfile::additionalTransactionTerminatingResponsesEnabled()
{
return mAdditionalTransactionTerminatingResponsesEnabled;
}
bool MasterProfile::additionalTransactionTerminatingResponsesEnabled() const
{
return mAdditionalTransactionTerminatingResponsesEnabled;
}
void MasterProfile::addAdditionalTransactionTerminatingResponses(int code)
{
DebugLog(<< "MasterProfile::addAdditionalTransactionTerminatingResponses" << "added code: " << code);
mAdditionalTransactionTerminatingResponsess.insert(code);
}
bool MasterProfile::isAdditionalTransactionTerminatingResponse(int code) const
{
bool isAllowed = (mAdditionalTransactionTerminatingResponsess.end() != mAdditionalTransactionTerminatingResponsess.find(code));
DebugLog(<< "MasterProfile::isAdditionalTransactionTerminatingResponse" << "is code " << code << " allowed: " << isAllowed);
return isAllowed;
}
const std::set<int>& MasterProfile::getAdditionalTransactionTerminatingResponses() const
{
return mAdditionalTransactionTerminatingResponsess;
}
void MasterProfile::clearAdditionalTransactionTerminatingResponses(void)
{
mAdditionalTransactionTerminatingResponsess.clear();
}
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0
* *

View File

@ -28,6 +28,7 @@ class MasterProfile : public UserProfile
/// Defaults are: INVITE, ACK, CANCEL, OPTIONS, BYE, UPDATE /// Defaults are: INVITE, ACK, CANCEL, OPTIONS, BYE, UPDATE
virtual void addSupportedMethod(const MethodTypes& method); virtual void addSupportedMethod(const MethodTypes& method);
virtual void removeSupportedMethod(const MethodTypes& method);
virtual bool isMethodSupported(MethodTypes method) const; virtual bool isMethodSupported(MethodTypes method) const;
virtual Tokens getAllowedMethods() const; virtual Tokens getAllowedMethods() const;
virtual Data getAllowedMethodsData() const; virtual Data getAllowedMethodsData() const;
@ -42,36 +43,48 @@ class MasterProfile : public UserProfile
typedef enum typedef enum
{ {
Never, Never,
Supported, SupportedEssential, // If UAS - Only use reliable provisionals if sending a body and far end supports
Required Supported, // If UAS - Always use reliable provisionals if far end supports
Required // If UAS - Always use reliable provisionals
} ReliableProvisionalMode; } ReliableProvisionalMode;
// UAC PRACK support. UPDATE must be enabled(currently defaults to on, do // UAC PRACK support. UPDATE must be enabled(currently defaults to on, do
// not disable w/out disabling UAC PRACK support). // not disable w/out disabling UAC PRACK support).
// //
// Flows where an an answer is received in a 180rel and subsequent O/A // Flows where an an answer is received in a 180rel and subsequent O/A
// exchanges using UPDATE occur in the early dialog // exchanges using UPDATE occur in the early dialog
// have been tested. // have been tested.
// //
// A subsequent O/A exchange using 180rel/PRACK is also supported. This is // A subsequent O/A exchange using 180rel/PRACK is also supported. This is
// a really bad idea, as an answer must be generated; the offer cannot be // a really bad idea, as an answer must be generated; the offer cannot be
// rejected. UPDATE should always be used for O/A exchanges once the // rejected. UPDATE should always be used for O/A exchanges once the
// dialog is established. // dialog is established.
// Invite/18x(offer)/PRACK(ans) should work but has not been tested. //
// Invite/18x(offer)/PRACK(ans) also works
//
// Invite(offer)/18x(ans)/PRACK(offer)/200P(ans) issupported, but not recommended.
// The UAC MUST call provideOffer from the onAnswer callback in order to generate
// the offer in the PRACK.
// //
// Explicit limitations are: // Explicit limitations are:
// Overlapping reliable provisional responses that contain a body are not // - Overlapping reliable provisional responses that contain a body are not
// handled. // handled.
// Offers in a 200(PRACK) are not supported, and anyone who generates them //
// should be summarily executed. // Note: Using SupportedEssential is exactly the same as using Supported,
// SupportedEssential only effects UAS Prack implementation
virtual void setUacReliableProvisionalMode(ReliableProvisionalMode mode); virtual void setUacReliableProvisionalMode(ReliableProvisionalMode mode);
virtual ReliableProvisionalMode getUacReliableProvisionalMode() const; virtual ReliableProvisionalMode getUacReliableProvisionalMode() const;
//Not supported as UAS. Calling setUacReliableProvisionalMode will result // UAS PRACK support. UPDATE must be enabled(currently defaults to on, do
//in an assert. // not disable w/out disabling UAS PRACK support).
//
// All flows and limitations mentioned in UAC Prack comments apply
//
// Modes work as follows:
// SupportedEssential - Only send reliable provisionals if sending a body and far end supports
// Supported - Always send reliable provisionals if far end supports
// Required - Always send reliable provisionals
virtual void setUasReliableProvisionalMode(ReliableProvisionalMode mode); virtual void setUasReliableProvisionalMode(ReliableProvisionalMode mode);
virtual ReliableProvisionalMode getUasReliableProvisionalMode() const; virtual ReliableProvisionalMode getUasReliableProvisionalMode() const;
@ -151,6 +164,29 @@ class MasterProfile : public UserProfile
virtual bool& checkReqUriInMergeDetectionEnabled(); virtual bool& checkReqUriInMergeDetectionEnabled();
virtual bool checkReqUriInMergeDetectionEnabled() const; 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 additionalTransactionTerminatingResponsesEnabled() = true on master profile
/// 2. Call method addAdditionalTransactionTerminatingResponses(code) to provide SIP responses for which the application
/// need the transaction to be terminated
virtual bool& additionalTransactionTerminatingResponsesEnabled();
virtual bool additionalTransactionTerminatingResponsesEnabled() const;
virtual void addAdditionalTransactionTerminatingResponses(int code);
virtual bool isAdditionalTransactionTerminatingResponse(int code) const;
virtual const std::set<int>& getAdditionalTransactionTerminatingResponses() const;
virtual void clearAdditionalTransactionTerminatingResponses(void);
private: private:
virtual UserProfile* clone() const; virtual UserProfile* clone() const;
std::set<Data> mSupportedSchemes; std::set<Data> mSupportedSchemes;
@ -173,6 +209,9 @@ class MasterProfile : public UserProfile
UInt32 mServerRegistrationMinExpires; UInt32 mServerRegistrationMinExpires;
UInt32 mServerRegistrationMaxExpires; UInt32 mServerRegistrationMaxExpires;
UInt32 mServerRegistrationDefaultExpires; UInt32 mServerRegistrationDefaultExpires;
bool mAdditionalTransactionTerminatingResponsesEnabled;
std::set<int> mAdditionalTransactionTerminatingResponsess;
}; };
} }

View File

@ -12,7 +12,7 @@ namespace resip
class OutgoingEvent : public Message class OutgoingEvent : public Message
{ {
public: public:
//OutgoingEvent(std::unique_ptr<SipMessage> msg); //OutgoingEvent(std::auto_ptr<SipMessage> msg);
OutgoingEvent(SharedPtr<SipMessage> msg); OutgoingEvent(SharedPtr<SipMessage> msg);
OutgoingEvent(const OutgoingEvent&); OutgoingEvent(const OutgoingEvent&);
~OutgoingEvent(); ~OutgoingEvent();
@ -27,7 +27,7 @@ class OutgoingEvent : public Message
virtual EncodeStream& encodeBrief(EncodeStream& strm) const; virtual EncodeStream& encodeBrief(EncodeStream& strm) const;
private: private:
//mutable std::unique_ptr<SipMessage> mMessage; //mutable std::auto_ptr<SipMessage> mMessage;
SharedPtr<SipMessage> mMessage; SharedPtr<SipMessage> mMessage;
}; };

View File

@ -22,7 +22,7 @@ class ClientPagerMessageHandler
virtual void onSuccess(ClientPagerMessageHandle, const SipMessage& status)=0; virtual void onSuccess(ClientPagerMessageHandle, const SipMessage& status)=0;
//!kh! //!kh!
// Application could re-page the failed contents or just ingore it. // Application could re-page the failed contents or just ingore it.
virtual void onFailure(ClientPagerMessageHandle, const SipMessage& status, std::unique_ptr<Contents> contents)=0; virtual void onFailure(ClientPagerMessageHandle, const SipMessage& status, std::auto_ptr<Contents> contents)=0;
}; };
class ServerPagerMessageHandler class ServerPagerMessageHandler

View File

@ -16,7 +16,7 @@ Profile::Profile(SharedPtr<Profile> baseProfile) :
mHasOutboundDecorator(false), mHasOutboundDecorator(false),
mBaseProfile(baseProfile) mBaseProfile(baseProfile)
{ {
assert(baseProfile.get()); resip_assert(baseProfile.get());
reset(); // default all settings to fallthrough to mBaseProfile reset(); // default all settings to fallthrough to mBaseProfile
} }
@ -38,6 +38,7 @@ Profile::reset()
unsetDefaultSessionTime(); unsetDefaultSessionTime();
unsetDefaultSessionTimerMode(); unsetDefaultSessionTimerMode();
unset1xxRetransmissionTime(); unset1xxRetransmissionTime();
unset1xxRelResubmitTime();
unsetOverrideHostAndPort(); unsetOverrideHostAndPort();
unsetAdvertisedCapabilities(); unsetAdvertisedCapabilities();
unsetOutboundProxy(); unsetOutboundProxy();
@ -377,6 +378,38 @@ Profile::unset1xxRetransmissionTime()
} }
} }
void
Profile::set1xxRelResubmitTime(int secs)
{
m1xxRelResubmitTime = secs;
mHas1xxRelResubmitTime = true;
}
int
Profile::get1xxRelResubmitTime() const
{
// Fall through seting (if required)
if(!mHas1xxRelResubmitTime && mBaseProfile.get())
{
return mBaseProfile->get1xxRelResubmitTime();
}
return m1xxRelResubmitTime;
}
void
Profile::unset1xxRelResubmitTime()
{
if(mBaseProfile.get())
{
mHas1xxRelResubmitTime = false;
}
else // No Base profile - so return to default setting
{
mHas1xxRelResubmitTime = true;
m1xxRelResubmitTime = 150; // RFC3262 section says the UAS SHOULD send provisional reliable responses once every two and half minutes
}
}
void void
Profile::setOverrideHostAndPort(const Uri& hostPort) Profile::setOverrideHostAndPort(const Uri& hostPort)
{ {
@ -415,10 +448,11 @@ Profile::unsetOverrideHostAndPort()
void void
Profile::addAdvertisedCapability(const Headers::Type header) Profile::addAdvertisedCapability(const Headers::Type header)
{ {
assert(header == Headers::Allow || resip_assert(header == Headers::Allow ||
header == Headers::AcceptEncoding || header == Headers::AcceptEncoding ||
header == Headers::AcceptLanguage || header == Headers::AcceptLanguage ||
header == Headers::Supported); header == Headers::AllowEvents ||
header == Headers::Supported);
mAdvertisedCapabilities.insert(header); mAdvertisedCapabilities.insert(header);
mHasAdvertisedCapabilities = true; mHasAdvertisedCapabilities = true;
@ -474,7 +508,7 @@ Profile::getOutboundProxy() const
{ {
return mBaseProfile->getOutboundProxy(); return mBaseProfile->getOutboundProxy();
} }
assert(mHasOutboundProxy); resip_assert(mHasOutboundProxy);
return mOutboundProxy; return mOutboundProxy;
} }
@ -606,7 +640,7 @@ Profile::getUserAgent() const
{ {
return mBaseProfile->getUserAgent(); return mBaseProfile->getUserAgent();
} }
assert(mHasUserAgent); resip_assert(mHasUserAgent);
return mUserAgent; return mUserAgent;
} }
@ -642,7 +676,7 @@ Profile::getProxyRequires() const
{ {
return mBaseProfile->getProxyRequires(); return mBaseProfile->getProxyRequires();
} }
assert(mHasProxyRequires); resip_assert(mHasProxyRequires);
return mProxyRequires; return mProxyRequires;
} }
@ -905,7 +939,7 @@ Profile::getUserAgentCapabilities() const
{ {
return mBaseProfile->getUserAgentCapabilities(); return mBaseProfile->getUserAgentCapabilities();
} }
assert(mHasUserAgentCapabilities); resip_assert(mHasUserAgentCapabilities);
return mUserAgentCapabilities; return mUserAgentCapabilities;
} }

View File

@ -104,7 +104,12 @@ class Profile
/// The amount of time that can pass before dum will resubmit an unreliable provisional response /// The amount of time that can pass before dum will resubmit an unreliable provisional response
virtual void set1xxRetransmissionTime(int secs); virtual void set1xxRetransmissionTime(int secs);
virtual int get1xxRetransmissionTime() const; virtual int get1xxRetransmissionTime() const;
virtual void unset1xxRetransmissionTime(); virtual void unset1xxRetransmissionTime();
/// The amount of time that can pass before dum will resubmit a reliable provisional response
virtual void set1xxRelResubmitTime(int secs);
virtual int get1xxRelResubmitTime() const;
virtual void unset1xxRelResubmitTime();
///overrides the value used to populate the contact ///overrides the value used to populate the contact
///?dcm? -- also change via entries? Also, dum currently uses(as a uas) ///?dcm? -- also change via entries? Also, dum currently uses(as a uas)
@ -119,7 +124,7 @@ class Profile
///enable/disable sending of Allow/Supported/Accept-Language/Accept-Encoding headers ///enable/disable sending of Allow/Supported/Accept-Language/Accept-Encoding headers
///on initial outbound requests (ie. Initial INVITE, REGISTER, etc.) and Invite 200 responses ///on initial outbound requests (ie. Initial INVITE, REGISTER, etc.) and Invite 200 responses
///Note: Default is to advertise Headers::Allow and Headers::Supported, use clearAdvertisedCapabilities to remove these ///Note: Default is to advertise Headers::Allow and Headers::Supported, use clearAdvertisedCapabilities to remove these
/// Currently implemented header values are: Headers::Allow, /// Currently implemented header values are: Headers::Allow, Headers::AllowEvents
/// Headers::AcceptEncoding, Headers::AcceptLanguage, Headers::Supported /// Headers::AcceptEncoding, Headers::AcceptLanguage, Headers::Supported
virtual void addAdvertisedCapability(const Headers::Type header); virtual void addAdvertisedCapability(const Headers::Type header);
virtual bool isAdvertisedCapability(const Headers::Type header) const; virtual bool isAdvertisedCapability(const Headers::Type header) const;
@ -262,6 +267,9 @@ class Profile
bool mHas1xxRetransmissionTime; bool mHas1xxRetransmissionTime;
int m1xxRetransmissionTime; int m1xxRetransmissionTime;
bool mHas1xxRelResubmitTime;
int m1xxRelResubmitTime;
bool mHasOutboundProxy; bool mHasOutboundProxy;
NameAddr mOutboundProxy; NameAddr mOutboundProxy;

View File

@ -3,6 +3,7 @@
#include "resip/dum/Handles.hxx" #include "resip/dum/Handles.hxx"
#include "resip/stack/Mime.hxx" #include "resip/stack/Mime.hxx"
#include "resip/stack/Contents.hxx"
namespace resip namespace resip
{ {

View File

@ -0,0 +1,408 @@
#if !defined(RESIP_PUBLICATIONPERSISTENCEMANAGER_HXX)
#define RESIP_PUBLICATIONPERSISTENCEMANAGER_HXX
#include <map>
#include "rutil/XMLCursor.hxx"
#include "resip/stack/Contents.hxx"
#include "resip/stack/SecurityAttributes.hxx"
#include "rutil/Data.hxx"
#include "rutil/Timer.hxx"
#include "rutil/SharedPtr.hxx"
namespace resip
{
/** Abstract interface of a datastore of all publication documents processed by DUM. Derived classes implement the
actual storage of publication documents. resip::InMemorySyncPubDb is an example of a local datastore.
*/
class PublicationPersistenceManager
{
public:
struct PubDocument
{
PubDocument() : mExpirationTime(0), mLastUpdated(0), mLingerTime(0), mSyncPublication(false) {}
PubDocument(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, const Contents* contents, const SecurityAttributes* securityAttributes, bool syncPublication = false) :
mEventType(eventType), mDocumentKey(documentKey), mETag(eTag), mExpirationTime(expirationTime), mLastUpdated(Timer::getTimeSecs()), mLingerTime(expirationTime), mSyncPublication(syncPublication)
{
if (contents)
{
mContents.reset(contents->clone());
}
if (securityAttributes)
{
mSecurityAttributes.reset(new SecurityAttributes);
*mSecurityAttributes = *securityAttributes;
}
}
void stream(std::iostream& s) const
{
UInt64 now = Timer::getTimeSecs();
// Note: for compatibility with RegSyncServer/Client, using pubinfo for tag name instead of pubdocument
s << "<pubinfo>" << Symbols::CRLF;
s << " <eventtype>" << mEventType.xmlCharDataEncode() << "</eventtype>" << Symbols::CRLF;
s << " <documentkey>" << mDocumentKey.xmlCharDataEncode() << "</documentkey>" << Symbols::CRLF;
s << " <etag>" << mETag.xmlCharDataEncode() << "</etag>" << Symbols::CRLF;
s << " <expires>" << (((mExpirationTime == 0) || (mExpirationTime <= now)) ? 0 : (mExpirationTime - now)) << "</expires>" << Symbols::CRLF;
s << " <lastupdate>" << now - mLastUpdated << "</lastupdate>" << Symbols::CRLF;
if (mExpirationTime != 0 && mContents.get()) // lingering records will have expirationTime as 0 - don't need to send contents - refreshes also have no body
{
Mime mimeType = mContents->getType();
// There is an assumption that the contenttype and contentsubtype tags will always occur
// before the content tag in the deserialization
s << " <contentstype>" << mimeType.type().xmlCharDataEncode() << "</contentstype>" << Symbols::CRLF;
s << " <contentssubtype>" << mimeType.subType().xmlCharDataEncode() << "</contentssubtype>" << Symbols::CRLF;
s << " <contents>" << mContents->getBodyData().xmlCharDataEncode() << "</contents>" << Symbols::CRLF;
if(mSecurityAttributes.get())
{
resip_assert(mSecurityAttributes);
s << " <isencrypted>" << (mSecurityAttributes->isEncrypted() ? "true" : "false") << "</isencrypted>" << Symbols::CRLF;
if (mSecurityAttributes->isEncrypted())
{
s << " <sigstatus>";
switch (mSecurityAttributes->getSignatureStatus())
{
case SignatureNone:
s << "none";
break;
case SignatureIsBad:
s << "bad";
break;
case SignatureTrusted:
s << "trusted";
break;
case SignatureCATrusted:
s << "catrusted";
break;
case SignatureNotTrusted:
s << "nottrusted";
break;
case SignatureSelfSigned:
s << "selfsigned";
break;
default:
resip_assert(false);
s << "unknown";
break;
}
s << "</sigstatus>" << Symbols::CRLF;
if (!mSecurityAttributes->getSigner().empty())
{
s << " <signer>" << mSecurityAttributes->getSigner().xmlCharDataEncode() << "</signer>" << Symbols::CRLF;
}
if (!mSecurityAttributes->getIdentity().empty())
{
s << " <identity>" << mSecurityAttributes->getIdentity().xmlCharDataEncode() << "</identity>" << Symbols::CRLF;
s << " <identitystrength>";
switch (mSecurityAttributes->getIdentityStrength())
{
case SecurityAttributes::From:
s << "from";
break;
case SecurityAttributes::FailedIdentity:
s << "failedidentity";
break;
case SecurityAttributes::Identity:
s << "identity";
break;
default:
resip_assert(false);
s << "unknown";
break;
}
s << "</identitystrength>" << Symbols::CRLF;
}
// Note: intentionally not syncing mLevel and mEncryptionPerformed from SecurityAttributes since they are for outbound messages only
}
}
}
s << "</pubinfo>" << Symbols::CRLF;
}
bool deserialize(resip::XMLCursor& xml, UInt64 now = 0)
{
bool success = false;
*this = PubDocument();
if(now <= 0)
{
now = Timer::getTimeSecs();
}
Data mimeTypeString;
Data mimeSubtypeString;
if(isEqualNoCase(xml.getTag(), "pubinfo"))
{
if(xml.firstChild())
{
do
{
if(isEqualNoCase(xml.getTag(), "eventtype"))
{
if(xml.firstChild())
{
mEventType = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "documentkey"))
{
if(xml.firstChild())
{
mDocumentKey = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "etag"))
{
if(xml.firstChild())
{
mETag = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "expires"))
{
if(xml.firstChild())
{
UInt64 expires = xml.getValue().convertUInt64();
mExpirationTime = (expires == 0 ? 0 : now + expires);
mLingerTime = mExpirationTime;
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "lastupdated"))
{
if(xml.firstChild())
{
mLastUpdated = now - xml.getValue().convertUInt64();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "contentstype"))
{
if(xml.firstChild())
{
mimeTypeString = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "contentssubtype"))
{
if(xml.firstChild())
{
mimeSubtypeString = xml.getValue().xmlCharDataDecode();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "contents"))
{
if(xml.firstChild())
{
// There is an assumption that the contenttype and contentsubtype tags will always occur
// before the content tag
Mime mimeType(mimeTypeString, mimeSubtypeString);
// Need explilcit Data decodedBody as serializedContents refers to it in parser
Data decodedBody(xml.getValue().xmlCharDataDecode());
Contents* serializedContents = Contents::createContents(mimeType, decodedBody);
// Need to clone, as serializedContents is still referring to decodedBody, via the LazyParser,
// which will go out of scope.
mContents.reset(serializedContents->clone());
delete serializedContents;
serializedContents = 0;
xml.parent();
success = true;
}
}
else if (isEqualNoCase(xml.getTag(), "isencrypted"))
{
if (xml.firstChild())
{
if (mSecurityAttributes.get() == 0)
{
mSecurityAttributes.reset(new SecurityAttributes);
}
if (isEqualNoCase(xml.getValue(), "true"))
{
mSecurityAttributes->setEncrypted();
}
xml.parent();
}
}
else if (isEqualNoCase(xml.getTag(), "sigstatus"))
{
if (xml.firstChild())
{
if (mSecurityAttributes.get() == 0)
{
mSecurityAttributes.reset(new SecurityAttributes);
}
if (isEqualNoCase(xml.getValue(), "none"))
{
mSecurityAttributes->setSignatureStatus(SignatureNone);
}
else if (isEqualNoCase(xml.getValue(), "bad"))
{
mSecurityAttributes->setSignatureStatus(SignatureIsBad);
}
else if (isEqualNoCase(xml.getValue(), "trusted"))
{
mSecurityAttributes->setSignatureStatus(SignatureTrusted);
}
else if (isEqualNoCase(xml.getValue(), "catrusted"))
{
mSecurityAttributes->setSignatureStatus(SignatureCATrusted);
}
else if (isEqualNoCase(xml.getValue(), "nottrusted"))
{
mSecurityAttributes->setSignatureStatus(SignatureNotTrusted);
}
else if (isEqualNoCase(xml.getValue(), "selfsigned"))
{
mSecurityAttributes->setSignatureStatus(SignatureSelfSigned);
}
xml.parent();
}
}
else if (isEqualNoCase(xml.getTag(), "signer"))
{
if (xml.firstChild())
{
if (mSecurityAttributes.get() == 0)
{
mSecurityAttributes.reset(new SecurityAttributes);
}
mSecurityAttributes->setSigner(xml.getValue().xmlCharDataDecode());
xml.parent();
}
}
else if (isEqualNoCase(xml.getTag(), "identity"))
{
if (xml.firstChild())
{
if (mSecurityAttributes.get() == 0)
{
mSecurityAttributes.reset(new SecurityAttributes);
}
mSecurityAttributes->setIdentity(xml.getValue().xmlCharDataDecode());
xml.parent();
}
}
else if (isEqualNoCase(xml.getTag(), "identitystrength"))
{
if (xml.firstChild())
{
if (mSecurityAttributes.get() == 0)
{
mSecurityAttributes.reset(new SecurityAttributes);
}
if (isEqualNoCase(xml.getValue(), "from"))
{
mSecurityAttributes->setIdentityStrength(SecurityAttributes::From);
}
else if (isEqualNoCase(xml.getValue(), "failedidentity"))
{
mSecurityAttributes->setIdentityStrength(SecurityAttributes::FailedIdentity);
}
else if (isEqualNoCase(xml.getValue(), "identity"))
{
mSecurityAttributes->setIdentityStrength(SecurityAttributes::Identity);
}
xml.parent();
}
}
} while(xml.nextSibling());
xml.parent();
}
}
return(success);
}
Data mEventType;
Data mDocumentKey;
Data mETag;
UInt64 mExpirationTime;
UInt64 mLastUpdated;
UInt64 mLingerTime; // No need to sync this - this is essentially the latest expiration time we have seen for this ETag
SharedPtr<Contents> mContents;
SharedPtr<SecurityAttributes> mSecurityAttributes;
bool mSyncPublication; // No need to sync this
};
typedef std::map<resip::Data, PubDocument> ETagToDocumentMap;
typedef std::map<resip::Data, ETagToDocumentMap> KeyToETagMap;
class ETagMerger
{
public:
virtual ~ETagMerger() {}
virtual bool mergeETag(Contents* eTagDest, Contents* eTagSrc, bool isFirst) = 0;
};
PublicationPersistenceManager() {}
virtual ~PublicationPersistenceManager() {}
virtual void addUpdateDocument(const PubDocument& document) = 0;
virtual void addUpdateDocument(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 expirationTime, const Contents* contents, const SecurityAttributes* securityAttributes, bool syncPublication = false)
{
addUpdateDocument(PubDocument(eventType, documentKey, eTag, expirationTime, contents, securityAttributes, syncPublication));
}
virtual bool removeDocument(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated, bool syncPublication = false) = 0;
virtual bool getMergedETags(const Data& eventType, const Data& documentKey, ETagMerger& merger, Contents* destination) = 0;
virtual bool documentExists(const Data& eventType, const Data& documentKey, const Data& eTag) = 0;
virtual bool getDocument(const resip::Data& eventType, const resip::Data& documentKey, const resip::Data& eTag, PubDocument& document) { return false; }
virtual bool checkExpired(const Data& eventType, const Data& documentKey, const Data& eTag, UInt64 lastUpdated) = 0;
virtual void lockDocuments() = 0;
virtual KeyToETagMap& getDocuments() = 0; // Ensure you lock before calling this and unlock when done
virtual void unlockDocuments() = 0;
};
}
#endif
/* ====================================================================
*
* Copyright (c) 2015 SIP Spectrum, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
*
*/
/*
* vi: set shiftwidth=3 expandtab:
*/

View File

@ -22,131 +22,208 @@ using namespace std;
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
RADIUSServerAuthManager::RADIUSServerAuthManager(resip::DialogUsageManager& dum) : ServerAuthManager(dum, dum.dumIncomingTarget()), dum(dum) { RADIUSServerAuthManager::RADIUSServerAuthManager(
resip::DialogUsageManager& dum,
RADIUSDigestAuthenticator::init(NULL); TargetCommand::Target& target,
const Data& configurationFile,
bool challengeThirdParties,
const Data& staticRealm) :
ServerAuthManager(dum, target, challengeThirdParties, staticRealm),
dum(dum)
{
RADIUSDigestAuthenticator::init(
configurationFile.empty() ? 0 : configurationFile.c_str());
} }
RADIUSServerAuthManager::~RADIUSServerAuthManager() { RADIUSServerAuthManager::~RADIUSServerAuthManager()
} {
ServerAuthManager::AsyncBool RADIUSServerAuthManager::requiresChallenge(const SipMessage& msg) {
ostringstream s;
s << msg.header(h_RequestLine).uri();
DebugLog(<<"RADIUSServerAuthManager::requiresChallenge, uri = " << s.str().c_str());
// default behaviour is to challenge
ChallengeInfo *cmsg = new ChallengeInfo(false, true, msg.getTransactionId());
dum.post(cmsg);
return Async;
}
void RADIUSServerAuthManager::requestCredential(const resip::Data& user, const resip::Data& realm, const resip::SipMessage& msg, const resip::Auth& auth, const resip::Data& transactionId) {
ostringstream s;
s << msg.header(h_RequestLine).uri();
DebugLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << s << " authUser = " << user);
MyRADIUSDigestAuthListener *radiusListener = NULL;
try {
radiusListener = new MyRADIUSDigestAuthListener(user, realm, dum, transactionId);
Data radiusUser(user + "@" + realm);
DebugLog(<< "radiusUser = " << radiusUser.c_str() << ", " << "user = " << user.c_str());
Data reqUri("");
Data reqMethod("");
if(msg.isRequest()) {
//reqUri = Data(msg.header(h_RequestLine).uri());
// ostringstream s;
// s << msg.header(h_RequestLine).uri();
//reqUri = Data(s.str());
reqUri = auth.param(p_uri);
reqMethod = Data(resip::getMethodName(msg.header(h_RequestLine).getMethod()));
}
RADIUSDigestAuthenticator *radius = NULL;
if(auth.exists(p_qop)) {
if(auth.param(p_qop) == Symbols::auth) {
Data myQop("auth");
radius = new RADIUSDigestAuthenticator(radiusUser, user, realm, auth.param(p_nonce), reqUri, reqMethod, myQop, auth.param(p_nc), auth.param(p_cnonce), auth.param(p_response), radiusListener);
} else if(auth.param(p_qop) == Symbols::authInt) {
Data myQop("auth-int");
radius = new RADIUSDigestAuthenticator(radiusUser, user, realm, auth.param(p_nonce), reqUri, reqMethod, myQop, auth.param(p_nc), auth.param(p_cnonce), auth.param(p_opaque), auth.param(p_response), radiusListener);
}
}
if(radius == NULL) {
radius = new RADIUSDigestAuthenticator(radiusUser, user, realm, auth.param(p_nonce), reqUri, reqMethod, auth.param(p_response), radiusListener);
}
int result = radius->doRADIUSCheck();
if(result < 0) {
ErrLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << s <<" failed to start thread, error = " << result);
}
} catch(...) {
WarningLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << s <<" exception");
delete radiusListener;
}
}
bool RADIUSServerAuthManager::useAuthInt() const {
return true;
}
bool RADIUSServerAuthManager::authorizedForThisIdentity(const resip::Data &user, const resip::Data &realm, resip::Uri &fromUri) {
// Always returns true: in other words, any user can send any from URI
// or forge any CLI
return true;
} }
void void
RADIUSServerAuthManager::onAuthSuccess(const resip::SipMessage& msg) { RADIUSServerAuthManager::requestCredential(
const resip::Data& user,
const resip::Data& realm,
const resip::SipMessage& msg,
const resip::Auth& auth,
const resip::Data& transactionId)
{
DebugLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << msg.header(h_RequestLine).uri() << " authUser = " << user);
MyRADIUSDigestAuthListener *radiusListener = NULL;
try
{
radiusListener = new MyRADIUSDigestAuthListener(user, realm, dum, transactionId);
Data radiusUser = user;
DebugLog(<< "radiusUser = " << radiusUser.c_str() << ", " << "user = " << user.c_str());
resip_assert(msg.isRequest());
Data reqUri = auth.param(p_uri);
Data reqMethod = Data(resip::getMethodName(msg.header(h_RequestLine).getMethod()));
RADIUSDigestAuthenticator *radius = NULL;
if(auth.exists(p_qop))
{
if(auth.param(p_qop) == Symbols::auth)
{
Data myQop("auth");
radius = new RADIUSDigestAuthenticator(
radiusUser, user, realm, auth.param(p_nonce),
reqUri, reqMethod, myQop, auth.param(p_nc), auth.param(p_cnonce),
auth.param(p_response),
radiusListener);
}
else if(auth.param(p_qop) == Symbols::authInt)
{
Data myQop("auth-int");
radius = new RADIUSDigestAuthenticator(
radiusUser, user, realm, auth.param(p_nonce),
reqUri, reqMethod, myQop, auth.param(p_nc), auth.param(p_cnonce),
auth.param(p_opaque),
auth.param(p_response),
radiusListener);
}
}
if(radius == NULL)
{
radius = new RADIUSDigestAuthenticator(
radiusUser, user, realm, auth.param(p_nonce),
reqUri, reqMethod,
auth.param(p_response),
radiusListener);
}
int result = radius->doRADIUSCheck();
if(result < 0)
{
ErrLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << msg.header(h_RequestLine).uri() <<" failed to start thread, error = " << result);
}
}
catch(...)
{
WarningLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << msg.header(h_RequestLine).uri() <<" exception");
delete radiusListener;
}
}
bool
RADIUSServerAuthManager::useAuthInt() const
{
return true;
}
void
RADIUSServerAuthManager::onAuthSuccess(const resip::SipMessage& msg)
{
} }
void void
RADIUSServerAuthManager::onAuthFailure(resip::ServerAuthManager::AuthFailureReason reason, const resip::SipMessage& msg) { RADIUSServerAuthManager::onAuthFailure(resip::ServerAuthManager::AuthFailureReason reason, const resip::SipMessage& msg)
Data failureMsg("unknown failure"); {
switch(reason) { Data failureMsg("unknown failure");
case InvalidRequest: switch(reason) {
failureMsg = Data("InvalidRequest"); case InvalidRequest:
break; failureMsg = Data("InvalidRequest");
case BadCredentials: break;
failureMsg = Data("BadCredentials"); case BadCredentials:
break; failureMsg = Data("BadCredentials");
case Error: break;
failureMsg = Data("Error"); case Error:
break; failureMsg = Data("Error");
} break;
Tuple sourceTuple = msg.getSource(); }
Data sourceIp = Data(inet_ntoa(sourceTuple.toGenericIPAddress().v4Address.sin_addr)); Tuple sourceTuple = msg.getSource();
WarningLog(<<"auth failure: " << failureMsg << ": src IP=" << sourceIp << ", uri=" << msg.header(h_RequestLine).uri().user() << ", from=" <<msg.header(h_From).uri().user() << ", to=" << msg.header(h_To).uri().user()); Data sourceIp = Data(inet_ntoa(sourceTuple.toGenericIPAddress().v4Address.sin_addr));
WarningLog(<<"auth failure: " << failureMsg
<< ": src IP=" << sourceIp
<< ", uri=" << msg.header(h_RequestLine).uri().user()
<< ", from=" <<msg.header(h_From).uri().user()
<< ", to=" << msg.header(h_To).uri().user());
} }
MyRADIUSDigestAuthListener::MyRADIUSDigestAuthListener(const resip::Data& user, const resip::Data& realm, resip::TransactionUser& tu, const resip::Data& transactionId) : user(user), realm(realm), tu(tu), transactionId(transactionId) { MyRADIUSDigestAuthListener::MyRADIUSDigestAuthListener(
const resip::Data& user,
const resip::Data& realm,
resip::TransactionUser& tu,
const resip::Data& transactionId) :
user(user),
realm(realm),
tu(tu),
transactionId(transactionId)
{
} }
MyRADIUSDigestAuthListener::~MyRADIUSDigestAuthListener() { MyRADIUSDigestAuthListener::~MyRADIUSDigestAuthListener()
{
} }
void MyRADIUSDigestAuthListener::onSuccess(const resip::Data& rpid) { void
DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess"); MyRADIUSDigestAuthListener::onSuccess(const resip::Data& rpid)
if(!rpid.empty()) {
DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess rpid = " << rpid.c_str()); DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess");
else if(!rpid.empty())
DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess, no rpid"); {
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::DigestAccepted, transactionId); DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess rpid = " << rpid.c_str());
tu.post(uai); }
else
{
DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess, no rpid");
}
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::DigestAccepted, transactionId);
tu.post(uai);
} }
void MyRADIUSDigestAuthListener::onAccessDenied() { void
DebugLog(<<"MyRADIUSDigestAuthListener::onAccessDenied"); MyRADIUSDigestAuthListener::onAccessDenied()
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::DigestNotAccepted, transactionId); {
tu.post(uai); DebugLog(<<"MyRADIUSDigestAuthListener::onAccessDenied");
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::DigestNotAccepted, transactionId);
tu.post(uai);
} }
void MyRADIUSDigestAuthListener::onError() { void
WarningLog(<<"MyRADIUSDigestAuthListener::onError"); MyRADIUSDigestAuthListener::onError()
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::Error, transactionId); {
tu.post(uai); WarningLog(<<"MyRADIUSDigestAuthListener::onError");
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::Error, transactionId);
tu.post(uai);
} }
#endif #endif
/* ====================================================================
*
* Copyright 2008-2013 Daniel Pocock http://danielpocock.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
*
*
*/

View File

@ -14,39 +14,43 @@
namespace resip namespace resip
{ {
class RADIUSServerAuthManager : public resip::ServerAuthManager { class RADIUSServerAuthManager : public resip::ServerAuthManager
{
private:
resip::DialogUsageManager& dum;
private: public:
resip::DialogUsageManager& dum; RADIUSServerAuthManager(resip::DialogUsageManager& dum,
TargetCommand::Target& target,
const Data& configurationFile,
bool challengeThirdParties = true,
const Data& staticRealm = "");
virtual ~RADIUSServerAuthManager();
public: protected:
RADIUSServerAuthManager(resip::DialogUsageManager& dum); void requestCredential(const resip::Data& user, const resip::Data& realm,
virtual ~RADIUSServerAuthManager(); const resip::SipMessage& msg, const resip::Auth& auth,
const resip::Data& transactionId);
protected: bool useAuthInt() const;
resip::ServerAuthManager::AsyncBool requiresChallenge(const resip::SipMessage& msg);
void requestCredential(const resip::Data& user, const resip::Data& realm, const resip::SipMessage& msg, const resip::Auth& auth, const resip::Data& transactionId);
bool useAuthInt() const;
bool authorizedForThisIdentity(const resip::Data &user, const resip::Data &realm, resip::Uri &fromUri);
void onAuthSuccess(const resip::SipMessage& msg);
void onAuthFailure(resip::ServerAuthManager::AuthFailureReason reason, const resip::SipMessage& msg);
void onAuthSuccess(const resip::SipMessage& msg);
void onAuthFailure(resip::ServerAuthManager::AuthFailureReason reason, const resip::SipMessage& msg);
}; };
class MyRADIUSDigestAuthListener : public RADIUSDigestAuthListener { class MyRADIUSDigestAuthListener : public RADIUSDigestAuthListener
private: {
resip::Data user; private:
resip::Data realm; resip::Data user;
resip::TransactionUser& tu; resip::Data realm;
resip::Data transactionId; resip::TransactionUser& tu;
public: resip::Data transactionId;
MyRADIUSDigestAuthListener(const resip::Data& user, const resip::Data& realm, resip::TransactionUser& tu, const resip::Data& transactionId); public:
virtual ~MyRADIUSDigestAuthListener(); MyRADIUSDigestAuthListener(const resip::Data& user, const resip::Data& realm,
void onSuccess(const resip::Data& rpid); resip::TransactionUser& tu, const resip::Data& transactionId);
void onAccessDenied(); virtual ~MyRADIUSDigestAuthListener();
void onError(); void onSuccess(const resip::Data& rpid);
void onAccessDenied();
void onError();
}; };
} }
@ -55,3 +59,41 @@ public:
#endif #endif
/* ====================================================================
*
* Copyright 2008-2013 Daniel Pocock http://danielpocock.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
*
*
*/

View File

@ -14,8 +14,8 @@ using namespace resip;
bool bool
RedirectManager::handle(DialogSet& dSet, SipMessage& origRequest, const SipMessage& response) RedirectManager::handle(DialogSet& dSet, SipMessage& origRequest, const SipMessage& response)
{ {
assert( response.isResponse() ); resip_assert( response.isResponse() );
assert( origRequest.isRequest() ); resip_assert( origRequest.isRequest() );
//380, 305 fall through to the application //380, 305 fall through to the application
int code = response.header(h_StatusLine).statusCode(); int code = response.header(h_StatusLine).statusCode();

View File

@ -1,153 +1,160 @@
#include "resip/dum/MasterProfile.hxx" #include "resip/dum/MasterProfile.hxx"
#include "resip/stack/SipMessage.hxx" #include "resip/stack/SipMessage.hxx"
#include "resip/dum/RegistrationHandler.hxx" #include "resip/dum/RegistrationHandler.hxx"
#include "resip/dum/ClientRegistration.hxx" #include "resip/dum/ClientRegistration.hxx"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
using namespace resip;
void
ClientRegistrationHandler::onFlowTerminated(ClientRegistrationHandle h)
{
InfoLog (<< "ClientRegistrationHandler::onFlowTerminated, refreshing registration to open new flow");
h->requestRefresh();
}
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM bool
ClientRegistrationHandler::onRefreshRequired(ClientRegistrationHandle h, const SipMessage& lastRequest)
using namespace resip;
void
ClientRegistrationHandler::onFlowTerminated(ClientRegistrationHandle h)
{ {
InfoLog (<< "ClientRegistrationHandler::onFlowTerminated, refreshing registration to open new flow"); InfoLog(<<"ClientRegistrationHandler::onRefreshRequired, returning true");
h->requestRefresh(); return true;
} }
void void
ServerRegistrationHandler::getGlobalExpires(const SipMessage& msg, SharedPtr<MasterProfile> masterProfile, ServerRegistrationHandler::getGlobalExpires(const SipMessage& msg, SharedPtr<MasterProfile> masterProfile,
UInt32 &expires, UInt32 &returnCode) UInt32 &expires, UInt32 &returnCode)
{ {
if (!masterProfile) if (!masterProfile)
{ {
returnCode = 500; returnCode = 500;
assert(0); resip_assert(0);
return; return;
} }
expires=3600; expires=3600;
returnCode=0; returnCode=0;
if (!msg.empty(h_Expires) && msg.header(h_Expires).isWellFormed()) if (!msg.empty(h_Expires) && msg.header(h_Expires).isWellFormed())
{ {
//only client specified Expires value is subject to the min/max constraints, default is used if none specified. //only client specified Expires value is subject to the min/max constraints, default is used if none specified.
expires = msg.header(h_Expires).value(); expires = msg.header(h_Expires).value();
if (expires != 0) if (expires != 0)
{ {
//check min expires first since max expires will not return an error and will just change the expires value. //check min expires first since max expires will not return an error and will just change the expires value.
UInt32 minExpires = masterProfile->serverRegistrationMinExpiresTime(); UInt32 minExpires = masterProfile->serverRegistrationMinExpiresTime();
if (expires < minExpires) if (expires < minExpires)
{ {
returnCode = 423; returnCode = 423;
expires = minExpires; expires = minExpires;
} }
else else
{ {
UInt32 maxExpires = masterProfile->serverRegistrationMaxExpiresTime(); UInt32 maxExpires = masterProfile->serverRegistrationMaxExpiresTime();
if (expires > maxExpires) if (expires > maxExpires)
{ {
expires = maxExpires; expires = maxExpires;
} }
} }
} }
} }
else else
{ {
expires = masterProfile->serverRegistrationDefaultExpiresTime(); expires = masterProfile->serverRegistrationDefaultExpiresTime();
} }
} }
void void
ServerRegistrationHandler::getContactExpires(const NameAddr &contact, SharedPtr<MasterProfile> masterProfile, ServerRegistrationHandler::getContactExpires(const NameAddr &contact, SharedPtr<MasterProfile> masterProfile,
UInt32 &expires, UInt32 &returnCode) UInt32 &expires, UInt32 &returnCode)
{ {
if (!masterProfile) if (!masterProfile)
{ {
returnCode = 500; returnCode = 500;
assert(0); resip_assert(0);
return; return;
} }
returnCode=0; returnCode=0;
if (contact.exists(p_expires)) if (contact.exists(p_expires))
{ {
expires = contact.param(p_expires); expires = contact.param(p_expires);
if (expires != 0) if (expires != 0)
{ {
//check min expires first since max expires will not return an error and will just change the expires value. //check min expires first since max expires will not return an error and will just change the expires value.
UInt32 minExpires = masterProfile->serverRegistrationMinExpiresTime(); UInt32 minExpires = masterProfile->serverRegistrationMinExpiresTime();
if (expires < minExpires) if (expires < minExpires)
{ {
returnCode = 423; returnCode = 423;
expires = minExpires; expires = minExpires;
} }
else else
{ {
UInt32 maxExpires = masterProfile->serverRegistrationMaxExpiresTime(); UInt32 maxExpires = masterProfile->serverRegistrationMaxExpiresTime();
if (expires > maxExpires) if (expires > maxExpires)
{ {
expires = maxExpires; expires = maxExpires;
} }
} }
} }
} }
} }
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0
* *
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
* *
* 1. Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in * notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the * the documentation and/or other materials provided with the
* distribution. * distribution.
* *
* 3. The names "VOCAL", "Vovida Open Communication Application Library", * 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must * and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this * not be used to endorse or promote products derived from this
* software without prior written permission. For written * software without prior written permission. For written
* permission, please contact vocal@vovida.org. * permission, please contact vocal@vovida.org.
* *
* 4. Products derived from this software may not be called "VOCAL", nor * 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written * may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc. * permission of Vovida Networks, Inc.
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE. * DAMAGE.
* *
* ==================================================================== * ====================================================================
* *
* This software consists of voluntary contributions made by Vovida * This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks, * Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see * Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>. * <http://www.vovida.org/>.
* *
*/ */

View File

@ -37,6 +37,11 @@ class ClientRegistrationHandler
/// supports RFC5626 (outbound). /// supports RFC5626 (outbound).
/// Default implementation is to immediately re-Register in an attempt to form a new flow. /// Default implementation is to immediately re-Register in an attempt to form a new flow.
virtual void onFlowTerminated(ClientRegistrationHandle); virtual void onFlowTerminated(ClientRegistrationHandle);
/// Called before attempting to refresh a registration
/// Return true if the refresh should go ahead or false otherwise
/// Default implementation always returns true
virtual bool onRefreshRequired(ClientRegistrationHandle, const SipMessage& lastRequest);
}; };
class ServerRegistrationHandler class ServerRegistrationHandler
@ -102,8 +107,8 @@ class ServerRegistrationHandler
*/ */
virtual void asyncUpdateContacts(ServerRegistrationHandle, virtual void asyncUpdateContacts(ServerRegistrationHandle,
const Uri& aor, const Uri& aor,
std::unique_ptr<ContactPtrList> modifiedContactList, std::auto_ptr<ContactPtrList> modifiedContactList,
std::unique_ptr<ContactRecordTransactionLog> transactionLog) std::auto_ptr<ContactRecordTransactionLog> transactionLog)
{ {
} }
@ -112,7 +117,7 @@ class ServerRegistrationHandler
*/ */
virtual void asyncRemoveExpired(ServerRegistrationHandle, virtual void asyncRemoveExpired(ServerRegistrationHandle,
const resip::Uri& aor, const resip::Uri& aor,
std::unique_ptr<resip::ContactPtrList> contacts) std::auto_ptr<resip::ContactPtrList> contacts)
{ {
} }
}; };

View File

@ -1,4 +1,4 @@
#include <cassert> #include "rutil/ResipAssert.h"
#include "resip/dum/ChallengeInfo.hxx" #include "resip/dum/ChallengeInfo.hxx"
#include "resip/dum/DumFeature.hxx" #include "resip/dum/DumFeature.hxx"
@ -16,9 +16,10 @@
using namespace resip; using namespace resip;
using namespace std; using namespace std;
ServerAuthManager::ServerAuthManager(DialogUsageManager& dum, TargetCommand::Target& target, bool challengeThirdParties) : ServerAuthManager::ServerAuthManager(DialogUsageManager& dum, TargetCommand::Target& target, bool challengeThirdParties, const Data& staticRealm) :
DumFeature(dum, target), DumFeature(dum, target),
mChallengeThirdParties(challengeThirdParties) mChallengeThirdParties(challengeThirdParties),
mStaticRealm(staticRealm)
{ {
} }
@ -64,8 +65,8 @@ ServerAuthManager::process(Message* msg)
{ {
InfoLog(<< "ServerAuth got ChallengeInfo " << challengeInfo->brief()); InfoLog(<< "ServerAuth got ChallengeInfo " << challengeInfo->brief());
MessageMap::iterator it = mMessages.find(challengeInfo->getTransactionId()); MessageMap::iterator it = mMessages.find(challengeInfo->getTransactionId());
assert(it != mMessages.end()); resip_assert(it != mMessages.end());
std::unique_ptr<SipMessage> sipMsg(it->second); std::auto_ptr<SipMessage> sipMsg(it->second);
mMessages.erase(it); mMessages.erase(it);
if(challengeInfo->isFailed()) if(challengeInfo->isFailed())
@ -88,7 +89,7 @@ ServerAuthManager::process(Message* msg)
else else
{ {
// challenge is not required, re-instate original message // challenge is not required, re-instate original message
postCommand(std::move(sipMsg)); postCommand(auto_ptr<Message>(sipMsg));
return FeatureDoneAndEventDone; return FeatureDoneAndEventDone;
} }
} }
@ -103,7 +104,7 @@ ServerAuthManager::process(Message* msg)
Message* result = handleUserAuthInfo(userAuth); Message* result = handleUserAuthInfo(userAuth);
if (result) if (result)
{ {
postCommand(unique_ptr<Message>(result)); postCommand(auto_ptr<Message>(result));
return FeatureDoneAndEventDone; return FeatureDoneAndEventDone;
} }
else else
@ -119,10 +120,10 @@ ServerAuthManager::process(Message* msg)
SipMessage* SipMessage*
ServerAuthManager::handleUserAuthInfo(UserAuthInfo* userAuth) ServerAuthManager::handleUserAuthInfo(UserAuthInfo* userAuth)
{ {
assert(userAuth); resip_assert(userAuth);
MessageMap::iterator it = mMessages.find(userAuth->getTransactionId()); MessageMap::iterator it = mMessages.find(userAuth->getTransactionId());
assert(it != mMessages.end()); resip_assert(it != mMessages.end());
SipMessage* requestWithAuth = it->second; SipMessage* requestWithAuth = it->second;
mMessages.erase(it); mMessages.erase(it);
@ -269,7 +270,7 @@ ServerAuthManager::rejectBadNonces() const
} }
ServerAuthManager::AsyncBool AsyncBool
ServerAuthManager::requiresChallenge(const SipMessage& msg) ServerAuthManager::requiresChallenge(const SipMessage& msg)
{ {
if(!mChallengeThirdParties) if(!mChallengeThirdParties)
@ -300,7 +301,7 @@ ServerAuthManager::authorizedForThisIdentity(const resip::Data &user,
// header is the full fromUri, e.g. // header is the full fromUri, e.g.
// Proxy-Authorization: Digest username="user@domain" ... // Proxy-Authorization: Digest username="user@domain" ...
// //
if ((fromUri.getAorNoPort() == user) && (fromUri.host() == realm)) if (fromUri.getAorNoPort() == user)
return true; return true;
// catch-all: access denied // catch-all: access denied
@ -311,6 +312,19 @@ ServerAuthManager::authorizedForThisIdentity(const resip::Data &user,
const Data& const Data&
ServerAuthManager::getChallengeRealm(const SipMessage& msg) ServerAuthManager::getChallengeRealm(const SipMessage& msg)
{ {
// (1) Check if static realm is defined
if (!mStaticRealm.empty())
{
return mStaticRealm;
}
// (2) Check From domain
if (mDum.isMyDomain(msg.header(h_From).uri().host()))
{
return msg.header(h_From).uri().host();
}
// (3) Punt: Use Request URI
return msg.header(h_RequestLine).uri().host(); return msg.header(h_RequestLine).uri().host();
} }
@ -318,6 +332,10 @@ ServerAuthManager::getChallengeRealm(const SipMessage& msg)
bool bool
ServerAuthManager::isMyRealm(const Data& realm) ServerAuthManager::isMyRealm(const Data& realm)
{ {
if(!mStaticRealm.empty())
{
return mStaticRealm == realm;
}
return mDum.isMyDomain(realm); return mDum.isMyDomain(realm);
} }
@ -327,58 +345,93 @@ ServerAuthManager::Result
ServerAuthManager::handle(SipMessage* sipMsg) ServerAuthManager::handle(SipMessage* sipMsg)
{ {
//InfoLog( << "trying to do auth" ); //InfoLog( << "trying to do auth" );
if (sipMsg->isRequest() && if (sipMsg->isRequest())
sipMsg->header(h_RequestLine).method() != ACK &&
sipMsg->header(h_RequestLine).method() != CANCEL) // Do not challenge ACKs or CANCELs
{ {
ParserContainer<Auth>* auths; if(sipMsg->method() == CANCEL)
if (proxyAuthenticationMode())
{ {
if(!sipMsg->exists(h_ProxyAuthorizations)) // If we receive a cancel - check to see if we have the matching INVITE in our message map.
// If we do, then we haven't created a DUM dialog for it yet, since we are still waiting
// for the credential information to arrive. We need to properly respond to the CANCEL here
// since it won't be handled externally.
MessageMap::iterator it = mMessages.find(sipMsg->getTransactionId());
if(it != mMessages.end())
{ {
return issueChallengeIfRequired(sipMsg); // Ensure message is an INVITE - if not then something fishy is going on. Either
} // someone has cancelled a non-INVITE transaction or we have a tid collision.
auths = &sipMsg->header(h_ProxyAuthorizations); if(it->second->isRequest() && it->second->method() == INVITE)
}
else
{
if(!sipMsg->exists(h_Authorizations))
{
return issueChallengeIfRequired(sipMsg);
}
auths = &sipMsg->header(h_Authorizations);
}
try
{
for(Auths::iterator it = auths->begin(); it != auths->end(); it++)
{
if (isMyRealm(it->param(p_realm)))
{ {
InfoLog (<< "Requesting credential for " std::auto_ptr<SipMessage> inviteMsg(it->second);
<< it->param(p_username) << " @ " << it->param(p_realm)); mMessages.erase(it); // Remove the INVITE from the message map and respond to it
requestCredential(it->param(p_username), InfoLog (<< "Received a CANCEL for an INVITE request that we are still waiting on auth "
it->param(p_realm), << "info for, responding appropriately, tid="
*sipMsg, << sipMsg->getTransactionId());
*it,
sipMsg->getTransactionId()); // Send 487/Inv
mMessages[sipMsg->getTransactionId()] = sipMsg; SharedPtr<SipMessage> inviteResponse(new SipMessage);
return RequestedCredentials; Helper::makeResponse(*inviteResponse, *inviteMsg, 487); // Request Cancelled
mDum.send(inviteResponse);
// Send 200/Cancel
SharedPtr<SipMessage> cancelResponse(new SipMessage);
Helper::makeResponse(*cancelResponse, *sipMsg, 200);
mDum.send(cancelResponse);
return Rejected; // Use rejected since handling is what we want - stop DUM from processing the cancel any further
} }
} }
InfoLog (<< "Didn't find matching realm ");
return issueChallengeIfRequired(sipMsg);
} }
catch(BaseException& e) else if(sipMsg->method() != ACK) // Do not challenge ACKs or CANCELs (picked off above)
{ {
InfoLog (<< "Invalid auth header provided " << e); ParserContainer<Auth>* auths;
SharedPtr<SipMessage> response(new SipMessage); if (proxyAuthenticationMode())
Helper::makeResponse(*response, *sipMsg, 400, "Invalid auth header"); {
mDum.send(response); if(!sipMsg->exists(h_ProxyAuthorizations))
onAuthFailure(InvalidRequest, *sipMsg); {
return Rejected; return issueChallengeIfRequired(sipMsg);
}
auths = &sipMsg->header(h_ProxyAuthorizations);
}
else
{
if(!sipMsg->exists(h_Authorizations))
{
return issueChallengeIfRequired(sipMsg);
}
auths = &sipMsg->header(h_Authorizations);
}
try
{
for(Auths::iterator it = auths->begin(); it != auths->end(); it++)
{
if (isMyRealm(it->param(p_realm)))
{
InfoLog (<< "Requesting credential for "
<< it->param(p_username) << " @ " << it->param(p_realm));
requestCredential(it->param(p_username),
it->param(p_realm),
*sipMsg,
*it,
sipMsg->getTransactionId());
mMessages[sipMsg->getTransactionId()] = sipMsg;
return RequestedCredentials;
}
}
InfoLog (<< "Didn't find matching realm ");
return issueChallengeIfRequired(sipMsg);
}
catch(BaseException& e)
{
InfoLog (<< "Invalid auth header provided " << e);
SharedPtr<SipMessage> response(new SipMessage);
Helper::makeResponse(*response, *sipMsg, 400, "Invalid auth header");
mDum.send(response);
onAuthFailure(InvalidRequest, *sipMsg);
return Rejected;
}
} }
} }
return Skipped; return Skipped;

View File

@ -3,6 +3,7 @@
#include <map> #include <map>
#include "rutil/AsyncBool.hxx"
#include "resip/stack/Auth.hxx" #include "resip/stack/Auth.hxx"
#include "resip/stack/SipMessage.hxx" #include "resip/stack/SipMessage.hxx"
#include "DumFeature.hxx" #include "DumFeature.hxx"
@ -26,7 +27,7 @@ class ServerAuthManager : public DumFeature
Rejected Rejected
}; };
ServerAuthManager(DialogUsageManager& dum, TargetCommand::Target& target, bool challengeThirdParties = true); ServerAuthManager(DialogUsageManager& dum, TargetCommand::Target& target, bool challengeThirdParties = true, const resip::Data& staticRealm = "");
virtual ~ServerAuthManager(); virtual ~ServerAuthManager();
virtual ProcessingResult process(Message* msg); virtual ProcessingResult process(Message* msg);
@ -43,13 +44,6 @@ class ServerAuthManager : public DumFeature
protected: protected:
enum AsyncBool
{
True, // response is true
False, // response is false
Async // response will be sent asynchronously
};
enum AuthFailureReason enum AuthFailureReason
{ {
InvalidRequest, // some aspect of the request (e.g. nonce) InvalidRequest, // some aspect of the request (e.g. nonce)
@ -100,8 +94,8 @@ class ServerAuthManager : public DumFeature
virtual void onAuthSuccess(const SipMessage& msg); virtual void onAuthSuccess(const SipMessage& msg);
virtual void onAuthFailure(AuthFailureReason reason, const SipMessage& msg); virtual void onAuthFailure(AuthFailureReason reason, const SipMessage& msg);
private:
bool mChallengeThirdParties; bool mChallengeThirdParties;
resip::Data mStaticRealm;
}; };

File diff suppressed because it is too large Load Diff

View File

@ -26,9 +26,14 @@ class ServerInviteSession: public InviteSession
/** Called to set the offer that will be used in the next message that /** Called to set the offer that will be used in the next message that
sends an offer. If possible, this will synchronously send the sends an offer. If possible, this will synchronously send the
appropriate request or response. In some cases, the UAS might have to appropriate request or response. In some cases, the UAS might have to
call accept in order to cause the message to be sent. */ call accept in order to cause the message to be sent.
If sendOfferAtAccept is true, no UPDATE will be sent if media is negotiated reliable,
it will be sent at accept */
virtual void provideOffer(const Contents& offer); virtual void provideOffer(const Contents& offer);
virtual void provideOffer(const Contents& offer, DialogUsageManager::EncryptionLevel level, const Contents* alternative); virtual void provideOffer(const Contents& offer, DialogUsageManager::EncryptionLevel level, const Contents* alternative);
virtual void provideOffer(const Contents& offer, bool sendOfferAtAccept);
virtual void provideOffer(const Contents& offer, DialogUsageManager::EncryptionLevel level,
const Contents* alternative, bool sendOfferAtAccept);
/** Called to request that the far end provide an offer. This will cause a /** Called to request that the far end provide an offer. This will cause a
reinvite with no body to be sent. */ reinvite with no body to be sent. */
@ -55,7 +60,7 @@ class ServerInviteSession: public InviteSession
* Provide asynchronous method access by using command * Provide asynchronous method access by using command
*/ */
void redirectCommand(const NameAddrs& contacts, int code=302); void redirectCommand(const NameAddrs& contacts, int code=302);
void provisionalCommand(int code=180); void provisionalCommand(int code=180, bool earlyFlag=true);
void acceptCommand(int statusCode=200); void acceptCommand(int statusCode=200);
private: private:
@ -70,17 +75,17 @@ class ServerInviteSession: public InviteSession
void dispatchWaitingToOffer(const SipMessage& msg); void dispatchWaitingToOffer(const SipMessage& msg);
void dispatchWaitingToRequestOffer(const SipMessage& msg); void dispatchWaitingToRequestOffer(const SipMessage& msg);
void dispatchAcceptedWaitingAnswer(const SipMessage& msg); void dispatchAcceptedWaitingAnswer(const SipMessage& msg);
void dispatchOfferReliable(const SipMessage& msg);
void dispatchNoOfferReliable(const SipMessage& msg);
void dispatchFirstSentOfferReliable(const SipMessage& msg); void dispatchFirstSentOfferReliable(const SipMessage& msg);
void dispatchFirstEarlyReliable(const SipMessage& msg); void dispatchOfferReliableProvidedAnswer(const SipMessage& msg);
void dispatchEarlyReliable(const SipMessage& msg); void dispatchFirstSentAnswerReliable(const SipMessage& msg);
void dispatchNoAnswerReliableWaitingPrack(const SipMessage& msg);
void dispatchSentUpdate(const SipMessage& msg); void dispatchSentUpdate(const SipMessage& msg);
void dispatchSentUpdateGlare(const SipMessage& msg);
void dispatchSentUpdateAccepted(const SipMessage& msg); void dispatchSentUpdateAccepted(const SipMessage& msg);
void dispatchReceivedUpdate(const SipMessage& msg); void dispatchReceivedUpdate(const SipMessage& msg);
void dispatchReceivedUpdateWaitingAnswer(const SipMessage& msg); void dispatchReceivedUpdateWaitingAnswer(const SipMessage& msg);
void dispatchWaitingToTerminate(const SipMessage& msg);
void dispatchWaitingToHangup(const SipMessage& msg); void dispatchWaitingToHangup(const SipMessage& msg);
void dispatchNegotiatedReliable(const SipMessage& msg);
void dispatchCancel(const SipMessage& msg); void dispatchCancel(const SipMessage& msg);
void dispatchBye(const SipMessage& msg); void dispatchBye(const SipMessage& msg);
@ -88,9 +93,15 @@ class ServerInviteSession: public InviteSession
// utilities // utilities
void startRetransmit1xxTimer(); void startRetransmit1xxTimer();
void startResubmit1xxRelTimer();
void startRetransmit1xxRelTimer();
void sendAccept(int code, Contents* offerAnswer); // sends 2xxI void sendAccept(int code, Contents* offerAnswer); // sends 2xxI
void sendProvisional(int code, bool earlyFlag); bool sendProvisional(int code, bool earlyFlag); // returns true if sent reliably
void queueResponse(int code, bool earlyFlag);
void sendUpdate(const Contents& offerAnswer); void sendUpdate(const Contents& offerAnswer);
bool handlePrack(const SipMessage& msg); // verify that prack matches our last send reliable 1xx
void prackCheckQueue(); // send a queued message after prack
void updateCheckQueue(); // send a queued message after update
ServerInviteSession(DialogUsageManager& dum, Dialog& dialog, const SipMessage& msg); ServerInviteSession(DialogUsageManager& dum, Dialog& dialog, const SipMessage& msg);
@ -101,10 +112,14 @@ class ServerInviteSession: public InviteSession
// stores the original request // stores the original request
const SipMessage mFirstRequest; const SipMessage mFirstRequest;
SharedPtr<SipMessage> m1xx; // for 1xx retransmissions SharedPtr<SipMessage> m1xx; // for 1xx retransmissions
unsigned long mCurrentRetransmit1xx; unsigned long mCurrentRetransmit1xxSeq;
//std::deque<SipMessage> mUnacknowledgedProvisionals; // all of them // UAS Prack members
//SipMessage m200; // for retransmission unsigned int mLocalRSeq;
SharedPtr<SipMessage> mUnacknowledgedReliableProvisional; // We won't send a new reliable provisional until the previous one is acknowledge - used for re-transmissions
std::deque< std::pair<int, bool> > mQueuedResponses;
bool mAnswerSentReliably;
SharedPtr<SipMessage> mPrackWithOffer; // for 1xx retransmissions
}; };
} }

View File

@ -42,35 +42,35 @@ ServerOutOfDialogReq::end()
void void
ServerOutOfDialogReq::dispatch(const SipMessage& msg) ServerOutOfDialogReq::dispatch(const SipMessage& msg)
{ {
assert(msg.isRequest()); resip_assert(msg.isRequest());
OutOfDialogHandler *pHandler = mDum.getOutOfDialogHandler(msg.header(h_CSeq).method()); OutOfDialogHandler *pHandler = mDum.getOutOfDialogHandler(msg.header(h_CSeq).method());
if(pHandler != NULL) if(pHandler != NULL)
{ {
// Let handler deal with message // Let handler deal with message
mRequest = msg; mRequest = msg;
DebugLog ( << "ServerOutOfDialogReq::dispatch - handler found for " << getMethodName(msg.header(h_CSeq).method()) << " method."); DebugLog ( << "ServerOutOfDialogReq::dispatch - handler found for " << getMethodName(msg.header(h_CSeq).method()) << " method.");
pHandler->onReceivedRequest(getHandle(), msg); // Wait for application to send response pHandler->onReceivedRequest(getHandle(), msg); // Wait for application to send response
} }
else else
{ {
if(msg.header(h_CSeq).method() == OPTIONS) if(msg.header(h_CSeq).method() == OPTIONS)
{ {
DebugLog ( << "ServerOutOfDialogReq::dispatch - handler not found for OPTIONS - sending autoresponse."); DebugLog ( << "ServerOutOfDialogReq::dispatch - handler not found for OPTIONS - sending autoresponse.");
// If no handler exists for OPTIONS then handle internally // If no handler exists for OPTIONS then handle internally
mRequest = msg; mRequest = msg;
mDum.send(answerOptions()); mDum.send(answerOptions());
delete this; delete this;
} }
else else
{ {
DebugLog ( << "ServerOutOfDialogReq::dispatch - handler not found for " << getMethodName(msg.header(h_CSeq).method()) << " method - sending 405."); DebugLog ( << "ServerOutOfDialogReq::dispatch - handler not found for " << getMethodName(msg.header(h_CSeq).method()) << " method - sending 405.");
// No handler found for out of dialog request - return a 405 // No handler found for out of dialog request - return a 405
mDum.makeResponse(*mResponse, msg, 405); mDum.makeResponse(*mResponse, msg, 405);
mDum.send(mResponse); mDum.send(mResponse);
delete this; delete this;
} }
} }
} }
void void
@ -81,23 +81,23 @@ ServerOutOfDialogReq::dispatch(const DumTimeout& msg)
SharedPtr<SipMessage> SharedPtr<SipMessage>
ServerOutOfDialogReq::answerOptions() ServerOutOfDialogReq::answerOptions()
{ {
mDum.makeResponse(*mResponse, mRequest, 200); mDum.makeResponse(*mResponse, mRequest, 200);
// Add in Allow, Accept, Accept-Encoding, Accept-Language, and Supported Headers from Profile // Add in Allow, Accept, Accept-Encoding, Accept-Language, and Supported Headers from Profile
mResponse->header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods(); mResponse->header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
mResponse->header(h_Accepts) = mDum.getMasterProfile()->getSupportedMimeTypes(INVITE); mResponse->header(h_Accepts) = mDum.getMasterProfile()->getSupportedMimeTypes(INVITE);
mResponse->header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings(); mResponse->header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
mResponse->header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages(); mResponse->header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
mResponse->header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents(); mResponse->header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
mResponse->header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags(); mResponse->header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
return mResponse; return mResponse;
} }
void void
ServerOutOfDialogReq::send(SharedPtr<SipMessage> response) ServerOutOfDialogReq::send(SharedPtr<SipMessage> response)
{ {
assert(response->isResponse()); resip_assert(response->isResponse());
mDum.send(response); mDum.send(response);
delete this; delete this;
} }

View File

@ -42,15 +42,18 @@ ServerPagerMessage::end()
class ServerPagerMessageEndCommand : public DumCommandAdapter class ServerPagerMessageEndCommand : public DumCommandAdapter
{ {
public: public:
ServerPagerMessageEndCommand(ServerPagerMessage& serverPagerMessage) ServerPagerMessageEndCommand(const ServerPagerMessageHandle& serverPagerMessageHandle)
: mServerPagerMessage(serverPagerMessage) : mServerPagerMessageHandle(serverPagerMessageHandle)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mServerPagerMessage.end(); if(mServerPagerMessageHandle.isValid())
{
mServerPagerMessageHandle->end();
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -58,18 +61,18 @@ public:
return strm << "ServerPagerMessageEndCommand"; return strm << "ServerPagerMessageEndCommand";
} }
private: private:
ServerPagerMessage& mServerPagerMessage; ServerPagerMessageHandle mServerPagerMessageHandle;
}; };
void ServerPagerMessage::endCommand() void ServerPagerMessage::endCommand()
{ {
mDum.post(new ServerPagerMessageEndCommand(*this)); mDum.post(new ServerPagerMessageEndCommand(getHandle()));
} }
void void
ServerPagerMessage::dispatch(const SipMessage& msg) ServerPagerMessage::dispatch(const SipMessage& msg)
{ {
assert(msg.isRequest()); resip_assert(msg.isRequest());
ServerPagerMessageHandler* handler = mDum.mServerPagerMessageHandler; ServerPagerMessageHandler* handler = mDum.mServerPagerMessageHandler;
//?dcm? check in DialogUsageManager //?dcm? check in DialogUsageManager
@ -91,7 +94,7 @@ ServerPagerMessage::dispatch(const DumTimeout& msg)
void void
ServerPagerMessage::send(SharedPtr<SipMessage> response) ServerPagerMessage::send(SharedPtr<SipMessage> response)
{ {
assert(response->isResponse()); resip_assert(response->isResponse());
mDum.send(response); mDum.send(response);
delete this; delete this;
} }
@ -108,15 +111,18 @@ ServerPagerMessage::accept(int statusCode)
class ServerPagerMessageAcceptCommand : public DumCommandAdapter class ServerPagerMessageAcceptCommand : public DumCommandAdapter
{ {
public: public:
ServerPagerMessageAcceptCommand(ServerPagerMessage& serverPagerMessage, int statusCode) ServerPagerMessageAcceptCommand(const ServerPagerMessageHandle& serverPagerMessageHandle, int statusCode)
: mServerPagerMessage(serverPagerMessage), : mServerPagerMessageHandle(serverPagerMessageHandle),
mStatusCode(statusCode) mStatusCode(statusCode)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mServerPagerMessage.accept(mStatusCode); if(mServerPagerMessageHandle.isValid())
{
mServerPagerMessageHandle->send(mServerPagerMessageHandle->accept(mStatusCode));
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -124,14 +130,14 @@ public:
return strm << "ServerPagerMessageAcceptCommand"; return strm << "ServerPagerMessageAcceptCommand";
} }
private: private:
ServerPagerMessage& mServerPagerMessage; ServerPagerMessageHandle mServerPagerMessageHandle;
int mStatusCode; int mStatusCode;
}; };
void void
ServerPagerMessage::acceptCommand(int statusCode) ServerPagerMessage::acceptCommand(int statusCode)
{ {
mDum.post(new ServerPagerMessageAcceptCommand(*this, statusCode)); mDum.post(new ServerPagerMessageAcceptCommand(getHandle(), statusCode));
} }
SharedPtr<SipMessage> SharedPtr<SipMessage>
@ -145,15 +151,18 @@ ServerPagerMessage::reject(int statusCode)
class ServerPagerMessageRejectCommand : public DumCommandAdapter class ServerPagerMessageRejectCommand : public DumCommandAdapter
{ {
public: public:
ServerPagerMessageRejectCommand(ServerPagerMessage& serverPagerMessage, int statusCode) ServerPagerMessageRejectCommand(const ServerPagerMessageHandle& serverPagerMessageHandle, int statusCode)
: mServerPagerMessage(serverPagerMessage), : mServerPagerMessageHandle(serverPagerMessageHandle),
mStatusCode(statusCode) mStatusCode(statusCode)
{ {
} }
virtual void executeCommand() virtual void executeCommand()
{ {
mServerPagerMessage.reject(mStatusCode); if(mServerPagerMessageHandle.isValid())
{
mServerPagerMessageHandle->send(mServerPagerMessageHandle->reject(mStatusCode));
}
} }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const virtual EncodeStream& encodeBrief(EncodeStream& strm) const
@ -161,14 +170,14 @@ public:
return strm << "ServerPagerMessageRejectCommand"; return strm << "ServerPagerMessageRejectCommand";
} }
private: private:
ServerPagerMessage& mServerPagerMessage; ServerPagerMessageHandle mServerPagerMessageHandle;
int mStatusCode; int mStatusCode;
}; };
void void
ServerPagerMessage::rejectCommand(int statusCode) ServerPagerMessage::rejectCommand(int statusCode)
{ {
mDum.post(new ServerPagerMessageRejectCommand(*this, statusCode)); mDum.post(new ServerPagerMessageRejectCommand(getHandle(), statusCode));
} }
EncodeStream& EncodeStream&
@ -180,7 +189,6 @@ ServerPagerMessage::dump(EncodeStream& strm) const
} }
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0
* *

View File

@ -3,6 +3,7 @@
#include "resip/dum/PublicationHandler.hxx" #include "resip/dum/PublicationHandler.hxx"
#include "resip/dum/ServerSubscription.hxx" #include "resip/dum/ServerSubscription.hxx"
#include "resip/dum/SubscriptionHandler.hxx" #include "resip/dum/SubscriptionHandler.hxx"
#include "resip/dum/PublicationPersistenceManager.hxx"
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "resip/stack/SecurityAttributes.hxx" #include "resip/stack/SecurityAttributes.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"
@ -16,6 +17,7 @@ ServerPublication::ServerPublication(DialogUsageManager& dum,
mLastResponse(new SipMessage), mLastResponse(new SipMessage),
mEtag(etag), mEtag(etag),
mEventType(msg.header(h_Event).value()), mEventType(msg.header(h_Event).value()),
mDocumentKey(msg.header(h_RequestLine).uri().getAor()),
mTimerSeq(0) mTimerSeq(0)
{ {
} }
@ -52,7 +54,7 @@ ServerPublication::getPublisher() const
void void
ServerPublication::updateMatchingSubscriptions() ServerPublication::updateMatchingSubscriptions()
{ {
Data key = mEventType + mLastRequest.header(h_RequestLine).uri().getAor(); Data key = mEventType + mDocumentKey;
std::pair<DialogUsageManager::ServerSubscriptions::iterator,DialogUsageManager::ServerSubscriptions::iterator> subs; std::pair<DialogUsageManager::ServerSubscriptions::iterator,DialogUsageManager::ServerSubscriptions::iterator> subs;
subs = mDum.mServerSubscriptions.equal_range(key); subs = mDum.mServerSubscriptions.equal_range(key);
@ -75,8 +77,6 @@ ServerPublication::accept(int statusCode)
Helper::makeResponse(*mLastResponse, mLastRequest, statusCode); Helper::makeResponse(*mLastResponse, mLastRequest, statusCode);
mLastResponse->header(h_Expires).value() = mExpires; mLastResponse->header(h_Expires).value() = mExpires;
updateMatchingSubscriptions();
return mLastResponse; return mLastResponse;
} }
@ -97,7 +97,7 @@ ServerPublication::end()
void void
ServerPublication::dispatch(const SipMessage& msg) ServerPublication::dispatch(const SipMessage& msg)
{ {
assert(msg.isRequest()); resip_assert(msg.isRequest());
ServerPublicationHandler* handler = mDum.getServerPublicationHandler(mEventType); ServerPublicationHandler* handler = mDum.getServerPublicationHandler(mEventType);
mLastRequest = msg; mLastRequest = msg;
mExpires = 3600; //bad mExpires = 3600; //bad
@ -113,6 +113,15 @@ ServerPublication::dispatch(const SipMessage& msg)
Helper::makeResponse(*mLastResponse, mLastRequest, 200); Helper::makeResponse(*mLastResponse, mLastRequest, 200);
mLastResponse->header(h_Expires).value() = mExpires; mLastResponse->header(h_Expires).value() = mExpires;
mDum.send(mLastResponse); mDum.send(mLastResponse);
if (mDum.mPublicationPersistenceManager)
{
// Remove document from persistence manager
mDum.mPublicationPersistenceManager->removeDocument(mEventType, mDocumentKey, mEtag, Timer::getTimeSecs());
}
// Notify all matching subscriptions removal - by sending a null body
updateMatchingSubscriptions();
delete this; delete this;
return; return;
} }
@ -134,6 +143,18 @@ ServerPublication::dispatch(const SipMessage& msg)
} }
else else
{ {
if (mExpires == 0)
{
// This can happen if we receive an unpublish after startup with an e-tag.
// We will then 412 the request. The sender will likely resend with no e-tag
// and we will end up here. There is nothing really to do. The sender is
// essentially unpublishing a publication we don't have, so we can just ignore it.
Helper::makeResponse(*mLastResponse, mLastRequest, 200);
mLastResponse->header(h_Expires).value() = mExpires;
mDum.send(mLastResponse);
delete this;
return;
}
mLastBody = Helper::extractFromPkcs7(msg, *mDum.getSecurity()); mLastBody = Helper::extractFromPkcs7(msg, *mDum.getSecurity());
handler->onInitial(getHandle(), mEtag, msg, handler->onInitial(getHandle(), mEtag, msg,
mLastBody.mContents.get(), mLastBody.mContents.get(),
@ -145,10 +166,19 @@ ServerPublication::dispatch(const SipMessage& msg)
void void
ServerPublication::dispatch(const DumTimeout& msg) ServerPublication::dispatch(const DumTimeout& msg)
{ {
// If this timer expires with a matching seq - it indicates the publisher didn't
// rePUBLISH within the expiry time and the publication has expired.
if (msg.seq() == mTimerSeq) if (msg.seq() == mTimerSeq)
{ {
ServerPublicationHandler* handler = mDum.getServerPublicationHandler(mEventType); ServerPublicationHandler* handler = mDum.getServerPublicationHandler(mEventType);
handler->onExpired(getHandle(), mEtag); handler->onExpired(getHandle(), mEtag);
if (mDum.mPublicationPersistenceManager)
{
// Remove document from persistence manager
mDum.mPublicationPersistenceManager->removeDocument(mEventType, mDocumentKey, mEtag, Timer::getTimeSecs());
}
delete this; delete this;
} }
} }
@ -156,7 +186,7 @@ ServerPublication::dispatch(const DumTimeout& msg)
void void
ServerPublication::send(SharedPtr<SipMessage> response) ServerPublication::send(SharedPtr<SipMessage> response)
{ {
assert(response->isResponse()); resip_assert(response->isResponse());
response->header(h_SIPETag).value() = mEtag; response->header(h_SIPETag).value() = mEtag;
mDum.send(response); mDum.send(response);
if (response->header(h_StatusLine).statusCode() >= 300) if (response->header(h_StatusLine).statusCode() >= 300)
@ -165,7 +195,23 @@ ServerPublication::send(SharedPtr<SipMessage> response)
} }
else else
{ {
mDum.addTimer(DumTimeout::Publication, response->header(h_Expires).value(), getBaseHandle(), ++mTimerSeq); UInt32 expires = response->header(h_Expires).value(); // ServerPublicationHandler may have changed expiration time
mDum.addTimer(DumTimeout::Publication, expires, getBaseHandle(), ++mTimerSeq);
if (mDum.mPublicationPersistenceManager)
{
// Add document to persistence manager
UInt64 now = Timer::getTimeSecs();
mDum.mPublicationPersistenceManager->addUpdateDocument(mEventType, mDocumentKey, mEtag, now + expires, mLastBody.mContents.get(), mLastBody.mAttributes.get());
}
// If we don't have a contents then it was a refresh (note: Unpublishes don't go through here)
if (mLastBody.mContents.get())
{
// Notify all matching subscriptions of new document
// Note: we do this after all uses of mLastBody, since calling this will release the contents stored in mLastBody
updateMatchingSubscriptions();
}
} }
} }

View File

@ -17,6 +17,7 @@ class ServerPublication : public BaseUsage
const Data& getEtag() const; const Data& getEtag() const;
const Data& getDocumentKey() const; const Data& getDocumentKey() const;
const Data& getEventType() const {return(mEventType);}
SharedPtr<SipMessage> accept(int statusCode = 200); SharedPtr<SipMessage> accept(int statusCode = 200);
SharedPtr<SipMessage> reject(int responseCode); SharedPtr<SipMessage> reject(int responseCode);
@ -38,7 +39,6 @@ class ServerPublication : public BaseUsage
private: private:
friend class DialogUsageManager; friend class DialogUsageManager;
ServerPublication(DialogUsageManager& dum, const Data& etag, const SipMessage& request); ServerPublication(DialogUsageManager& dum, const Data& etag, const SipMessage& request);
SipMessage mLastRequest; SipMessage mLastRequest;
SharedPtr<SipMessage> mLastResponse; SharedPtr<SipMessage> mLastResponse;
const Data mEtag; const Data mEtag;

View File

@ -11,6 +11,7 @@
#include "rutil/DnsUtil.hxx" #include "rutil/DnsUtil.hxx"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
#include "rutil/Timer.hxx" #include "rutil/Timer.hxx"
#include "rutil/TransportType.hxx"
#include "rutil/WinLeakCheck.hxx" #include "rutil/WinLeakCheck.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
@ -81,12 +82,12 @@ ServerRegistration::accept(SipMessage& ok)
{ {
if (!mAsyncLocalStore.get()) if (!mAsyncLocalStore.get())
{ {
assert(0); resip_assert(0);
} }
else else
{ {
std::unique_ptr<ContactRecordTransactionLog> log; std::auto_ptr<ContactRecordTransactionLog> log;
std::unique_ptr<ContactPtrList> contacts; std::auto_ptr<ContactPtrList> contacts;
mAsyncLocalStore->releaseLog(log,contacts); mAsyncLocalStore->releaseLog(log,contacts);
@ -104,20 +105,20 @@ ServerRegistration::accept(SipMessage& ok)
{ {
if (!mAsyncLocalStore.get()) if (!mAsyncLocalStore.get())
{ {
assert(0); resip_assert(0);
return; return;
} }
//This register was accepted, but still need to apply the changes made by this register and then //This register was accepted, but still need to apply the changes made by this register and then
//receive a final contact list before sending the 200. //receive a final contact list before sending the 200.
mAsyncState = asyncStateAcceptedWaitingForFinalContactList; mAsyncState = asyncStateAcceptedWaitingForFinalContactList;
std::unique_ptr<ContactRecordTransactionLog> log; std::auto_ptr<ContactRecordTransactionLog> log;
std::unique_ptr<ContactPtrList> modifiedContacts; std::auto_ptr<ContactPtrList> modifiedContacts;
mAsyncLocalStore->releaseLog(log,modifiedContacts); mAsyncLocalStore->releaseLog(log,modifiedContacts);
mAsyncOkMsg = SharedPtr<SipMessage>(static_cast<SipMessage*>(ok.clone())); mAsyncOkMsg = SharedPtr<SipMessage>(static_cast<SipMessage*>(ok.clone()));
mDum.mServerRegistrationHandler->asyncUpdateContacts(getHandle(), mAor, std::move(modifiedContacts), std::move(log)); mDum.mServerRegistrationHandler->asyncUpdateContacts(getHandle(),mAor,modifiedContacts,log);
//!WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction. //!WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.
return; return;
} }
@ -175,7 +176,7 @@ ServerRegistration::dispatch(const SipMessage& msg)
{ {
DebugLog( << "got a registration" ); DebugLog( << "got a registration" );
assert(msg.isRequest()); resip_assert(msg.isRequest());
ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler; ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager; RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
@ -330,7 +331,10 @@ ServerRegistration::processRegistration(const SipMessage& msg)
{ {
rec.mInstance=i->param(p_Instance); rec.mInstance=i->param(p_Instance);
} }
if (msg.exists(h_UserAgent))
{
rec.mUserAgent = msg.header(h_UserAgent).value();
}
if(!msg.empty(h_Paths)) if(!msg.empty(h_Paths))
{ {
rec.mSipPath=msg.header(h_Paths); rec.mSipPath=msg.header(h_Paths);
@ -431,7 +435,7 @@ ServerRegistration::processRegistration(const SipMessage& msg)
return; return;
default: default:
assert(0); resip_assert(0);
} }
} }
@ -499,6 +503,13 @@ ServerRegistration::tryFlow(ContactInstanceRecord& rec,
return true; return true;
} }
} }
if(msg.header(h_Vias).size() > 1 && InteropHelper::getAssumeFirstHopSupportsFlowTokensEnabled())
{
rec.mUseFlowRouting = true;
rec.mReceivedFrom.onlyUseExistingConnection=false;
return true;
}
} }
catch(resip::ParseBuffer::Exception&) catch(resip::ParseBuffer::Exception&)
{} {}
@ -512,7 +523,10 @@ ServerRegistration::testFlowRequirements(ContactInstanceRecord &rec,
{ {
const resip::NameAddr& contact(rec.mContact); const resip::NameAddr& contact(rec.mContact);
if(contact.exists(p_Instance) && contact.exists(p_regid)) if(!msg.empty(h_Supporteds) &&
msg.header(h_Supporteds).find(Token(Symbols::Outbound)) &&
contact.exists(p_Instance) &&
contact.exists(p_regid))
{ {
// Client has explicitly requested Outbound processing, which requires us // Client has explicitly requested Outbound processing, which requires us
// to have a flow. // to have a flow.
@ -560,7 +574,7 @@ ServerRegistration::flowTokenNeededForTls(const ContactInstanceRecord &rec) cons
if(contact.uri().exists(p_transport)) if(contact.uri().exists(p_transport))
{ {
TransportType type = Tuple::toTransport(contact.uri().param(p_transport)); TransportType type = Tuple::toTransport(contact.uri().param(p_transport));
if(type==TLS || type == DTLS) if(isSecure(type))
{ {
// secure transport and IP-address. Almost certainly won't work, but // secure transport and IP-address. Almost certainly won't work, but
// we'll try anyway. // we'll try anyway.
@ -612,7 +626,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
ContactPtrList::iterator it(contacts.begin()); ContactPtrList::iterator it(contacts.begin());
ContactPtrList::iterator itEnd(contacts.end()); ContactPtrList::iterator itEnd(contacts.end());
std::unique_ptr<ContactPtrList> expired; std::auto_ptr<ContactPtrList> expired;
UInt64 now=Timer::getTimeSecs(); UInt64 now=Timer::getTimeSecs();
@ -622,7 +636,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
if (!rec) if (!rec)
{ {
assert(0); resip_assert(0);
continue; continue;
} }
@ -630,7 +644,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
{ {
if (!expired.get()) if (!expired.get())
{ {
expired = std::unique_ptr<ContactPtrList>(new ContactPtrList()); expired = std::auto_ptr<ContactPtrList>(new ContactPtrList());
} }
expired->push_back(rec); expired->push_back(rec);
continue; continue;
@ -642,7 +656,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
if (expired.get() && expired->size() > 0) if (expired.get() && expired->size() > 0)
{ {
mDum.mServerRegistrationHandler->asyncRemoveExpired(getHandle(), mAor, std::move(expired)); mDum.mServerRegistrationHandler->asyncRemoveExpired(getHandle(),mAor,expired);
//!WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction. //!WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.
return; return;
} }
@ -677,32 +691,32 @@ ServerRegistration::processFinalOkMsg(SipMessage &msg, ContactList &contacts)
} }
bool bool
ServerRegistration::asyncProvideContacts(std::unique_ptr<resip::ContactPtrList> contacts) ServerRegistration::asyncProvideContacts(std::auto_ptr<resip::ContactPtrList> contacts)
{ {
switch (mAsyncState) switch (mAsyncState)
{ {
case asyncStateWaitingForInitialContactList: case asyncStateWaitingForInitialContactList:
{ {
assert(mAsyncLocalStore.get() == 0); resip_assert(mAsyncLocalStore.get() == 0);
mAsyncLocalStore = resip::SharedPtr<AsyncLocalStore>(new AsyncLocalStore(std::move(contacts))); mAsyncLocalStore = resip::SharedPtr<AsyncLocalStore>(new AsyncLocalStore(contacts));
mAsyncState = asyncStateProcessingRegistration; mAsyncState = asyncStateProcessingRegistration;
processRegistration(mRequest); processRegistration(mRequest);
break; break;
} }
case asyncStateWaitingForAcceptReject: case asyncStateWaitingForAcceptReject:
{ {
assert(0); //need to call accept() or reject(), wait for asyncUpdateContacts(), then call this function. resip_assert(0); //need to call accept() or reject(), wait for asyncUpdateContacts(), then call this function.
return false; return false;
} }
case asyncStateAcceptedWaitingForFinalContactList: case asyncStateAcceptedWaitingForFinalContactList:
{ {
mAsyncState = asyncStateProvidedFinalContacts; mAsyncState = asyncStateProvidedFinalContacts;
asyncProcessFinalContacts(std::move(contacts)); asyncProcessFinalContacts(contacts);
break; break;
} }
default: default:
{ {
assert(0); resip_assert(0);
return false; return false;
} }
} }
@ -711,13 +725,13 @@ ServerRegistration::asyncProvideContacts(std::unique_ptr<resip::ContactPtrList>
} }
void void
ServerRegistration::asyncProcessFinalContacts(std::unique_ptr<resip::ContactPtrList> contacts) ServerRegistration::asyncProcessFinalContacts(std::auto_ptr<resip::ContactPtrList> contacts)
{ {
if (contacts.get()) if (contacts.get())
{ {
if (!mAsyncOkMsg.get()) if (!mAsyncOkMsg.get())
{ {
assert(0); resip_assert(0);
} }
else else
{ {
@ -732,10 +746,10 @@ ServerRegistration::asyncProcessFinalContacts(std::unique_ptr<resip::ContactPtrL
} }
void void
ServerRegistration::AsyncLocalStore::create(std::unique_ptr<ContactPtrList> originalContacts) ServerRegistration::AsyncLocalStore::create(std::auto_ptr<ContactPtrList> originalContacts)
{ {
mModifiedContacts = std::move(originalContacts); mModifiedContacts = originalContacts;
mLog = std::unique_ptr<ContactRecordTransactionLog>(new ContactRecordTransactionLog()); mLog = std::auto_ptr<ContactRecordTransactionLog>(new ContactRecordTransactionLog());
} }
void void
@ -750,7 +764,7 @@ ServerRegistration::AsyncLocalStore::updateContact(const ContactInstanceRecord &
{ {
if (!mModifiedContacts.get() || !mLog.get()) if (!mModifiedContacts.get() || !mLog.get())
{ {
assert(0); resip_assert(0);
return RegistrationPersistenceManager::CONTACT_UPDATED; return RegistrationPersistenceManager::CONTACT_UPDATED;
} }
@ -789,7 +803,7 @@ ServerRegistration::AsyncLocalStore::removeContact(const ContactInstanceRecord &
{ {
if (!mModifiedContacts.get() || !mLog.get()) if (!mModifiedContacts.get() || !mLog.get())
{ {
assert(0); resip_assert(0);
return; return;
} }

View File

@ -47,7 +47,7 @@ class ServerRegistration: public NonDialogUsage
!CAUTION! This function must be called from the DUM thread. !CAUTION! This function must be called from the DUM thread.
*/ */
bool asyncProvideContacts(std::unique_ptr<resip::ContactPtrList> contacts); bool asyncProvideContacts(std::auto_ptr<resip::ContactPtrList> contacts);
resip::SharedPtr<ContactList> getOriginalContacts() { return mOriginalContacts; } // WARNING - use this only if async mode is not used resip::SharedPtr<ContactList> getOriginalContacts() { return mOriginalContacts; } // WARNING - use this only if async mode is not used
const ContactList& getRequestContacts() { return mRequestContacts; } const ContactList& getRequestContacts() { return mRequestContacts; }
@ -132,7 +132,7 @@ class ServerRegistration: public NonDialogUsage
* contact list. Once the final list is received via asyncProvideContacts(), this function finishes the REGISTER * contact list. Once the final list is received via asyncProvideContacts(), this function finishes the REGISTER
* processing. * processing.
*/ */
void asyncProcessFinalContacts(std::unique_ptr<resip::ContactPtrList> contacts); void asyncProcessFinalContacts(std::auto_ptr<resip::ContactPtrList> contacts);
/** Local datastore used to aggregate all changes to the current contact list when using the asynchronous logic. /** Local datastore used to aggregate all changes to the current contact list when using the asynchronous logic.
*/ */
@ -140,9 +140,9 @@ class ServerRegistration: public NonDialogUsage
{ {
public: public:
AsyncLocalStore(std::unique_ptr<ContactPtrList> originalContacts) AsyncLocalStore(std::auto_ptr<ContactPtrList> originalContacts)
{ {
create(std::move(originalContacts)); create(originalContacts);
} }
~AsyncLocalStore(void) ~AsyncLocalStore(void)
@ -153,7 +153,7 @@ class ServerRegistration: public NonDialogUsage
/** Setup this object in preparation for updating the records. Updates occur when processing a REGISTER /** Setup this object in preparation for updating the records. Updates occur when processing a REGISTER
message. message.
*/ */
void create(std::unique_ptr<ContactPtrList> originalContacts); void create(std::auto_ptr<ContactPtrList> originalContacts);
void destroy(void); void destroy(void);
@ -170,16 +170,16 @@ class ServerRegistration: public NonDialogUsage
/** Remove the transacation log and updated contact list. This object should be considered destroyed and /** Remove the transacation log and updated contact list. This object should be considered destroyed and
not used after releasing. not used after releasing.
*/ */
void releaseLog(std::unique_ptr<ContactRecordTransactionLog> &log, std::unique_ptr<ContactPtrList> &modifiedContacts) void releaseLog(std::auto_ptr<ContactRecordTransactionLog> &log, std::auto_ptr<ContactPtrList> &modifiedContacts)
{ {
log = std::move(mLog); log = mLog;
modifiedContacts = std::move(mModifiedContacts); modifiedContacts = mModifiedContacts;
} }
unsigned int numContacts() { if(mModifiedContacts.get()) return (unsigned int)mModifiedContacts->size(); return 0; } unsigned int numContacts() { if(mModifiedContacts.get()) return (unsigned int)mModifiedContacts->size(); return 0; }
private: private:
std::unique_ptr<ContactRecordTransactionLog> mLog; std::auto_ptr<ContactRecordTransactionLog> mLog;
std::unique_ptr<ContactPtrList> mModifiedContacts; std::auto_ptr<ContactPtrList> mModifiedContacts;
}; };
resip::SharedPtr<AsyncLocalStore> mAsyncLocalStore; resip::SharedPtr<AsyncLocalStore> mAsyncLocalStore;

View File

@ -4,6 +4,7 @@
#include "resip/dum/ServerSubscription.hxx" #include "resip/dum/ServerSubscription.hxx"
#include "resip/dum/SubscriptionHandler.hxx" #include "resip/dum/SubscriptionHandler.hxx"
#include "resip/dum/UsageUseException.hxx" #include "resip/dum/UsageUseException.hxx"
#include "resip/dum/MasterProfile.hxx"
#include "resip/stack/Helper.hxx" #include "resip/stack/Helper.hxx"
#include "rutil/Logger.hxx" #include "rutil/Logger.hxx"
@ -73,7 +74,9 @@ ServerSubscription::getTimeLeft()
SharedPtr<SipMessage> SharedPtr<SipMessage>
ServerSubscription::accept(int statusCode) ServerSubscription::accept(int statusCode)
{ {
mDialog.makeResponse(*mLastResponse, mLastSubscribe, statusCode); // Response is built in dispatch when request arrives, just need to adjust the status code here
mLastResponse->header(h_StatusLine).responseCode() = statusCode;
Helper::getResponseCodeReason(statusCode, mLastResponse->header(h_StatusLine).reason());
mLastResponse->header(h_Expires).value() = mExpires; mLastResponse->header(h_Expires).value() = mExpires;
return mLastResponse; return mLastResponse;
} }
@ -85,18 +88,27 @@ ServerSubscription::reject(int statusCode)
{ {
throw UsageUseException("Must reject with a code greater than or equal to 300", __FILE__, __LINE__); throw UsageUseException("Must reject with a code greater than or equal to 300", __FILE__, __LINE__);
} }
mDialog.makeResponse(*mLastResponse, mLastSubscribe, statusCode); // Response is built in dispatch when request arrives, just need to adjust the status code here
mLastResponse->header(h_StatusLine).responseCode() = statusCode;
Helper::getResponseCodeReason(statusCode, mLastResponse->header(h_StatusLine).reason());
mLastResponse->remove(h_Contacts); // Remove any contact header for non-success response
return mLastResponse; return mLastResponse;
} }
void ServerSubscription::terminateSubscription(ServerSubscriptionHandler* handler)
{
handler->onTerminated(getHandle());
delete this;
}
void void
ServerSubscription::send(SharedPtr<SipMessage> msg) ServerSubscription::send(SharedPtr<SipMessage> msg)
{ {
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType); ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
if (msg->isResponse()) if (msg->isResponse())
{ {
mLastResponse.reset(); // Release ref count on memory - so message goes away when send is done
int code = msg->header(h_StatusLine).statusCode(); int code = msg->header(h_StatusLine).statusCode();
if (code < 200) if (code < 200)
{ {
@ -119,8 +131,7 @@ ServerSubscription::send(SharedPtr<SipMessage> msg)
else if (code < 400) else if (code < 400)
{ {
DialogUsage::send(msg); DialogUsage::send(msg);
handler->onTerminated(getHandle()); terminateSubscription(handler);
delete this;
return; return;
} }
else else
@ -128,8 +139,7 @@ ServerSubscription::send(SharedPtr<SipMessage> msg)
if (shouldDestroyAfterSendingFailure(*msg)) if (shouldDestroyAfterSendingFailure(*msg))
{ {
DialogUsage::send(msg); DialogUsage::send(msg);
handler->onTerminated(getHandle()); terminateSubscription(handler);
delete this;
return; return;
} }
else else
@ -143,8 +153,7 @@ ServerSubscription::send(SharedPtr<SipMessage> msg)
DialogUsage::send(msg); DialogUsage::send(msg);
if (mSubscriptionState == Terminated) if (mSubscriptionState == Terminated)
{ {
handler->onTerminated(getHandle()); terminateSubscription(handler);
delete this;
} }
} }
} }
@ -158,7 +167,7 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
case SubDlgInitial: case SubDlgInitial:
return true; return true;
case SubDlgTerminating: //terminated state not using in ServerSubscription case SubDlgTerminating: //terminated state not using in ServerSubscription
assert(0); resip_assert(0);
return true; return true;
case SubDlgEstablished: case SubDlgEstablished:
{ {
@ -166,7 +175,7 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
{ {
return true; return true;
} }
switch (Helper::determineFailureMessageEffect(*mLastResponse)) switch (Helper::determineFailureMessageEffect(msg))
{ {
case Helper::TransactionTermination: case Helper::TransactionTermination:
case Helper::RetryAfter: case Helper::RetryAfter:
@ -187,9 +196,8 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
break; break;
} }
default: // !jf! default: // !jf!
assert(0); resip_assert(0);
break; break;
} }
return false; return false;
} }
@ -197,23 +205,31 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
void void
ServerSubscription::setSubscriptionState(SubscriptionState state) ServerSubscription::setSubscriptionState(SubscriptionState state)
{ {
mSubscriptionState = state; // Don't allow a transition out of Terminated state
if (mSubscriptionState != Terminated)
{
mSubscriptionState = state;
}
} }
void void
ServerSubscription::dispatch(const SipMessage& msg) ServerSubscription::dispatch(const SipMessage& msg)
{ {
DebugLog( << "ServerSubscriptionHandler::dispatch: " << msg.brief()); DebugLog( << "ServerSubscription::dispatch: " << msg.brief());
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType); ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
if (msg.isRequest()) if (msg.isRequest())
{ {
//!dcm! -- need to have a mechanism to retrieve default & acceptable //!dcm! -- need to have a mechanism to retrieve default & acceptable
//expiration times for an event package--part of handler API? //expiration times for an event package--part of handler API?
//added to handler for now. //added to handler for now.
mLastSubscribe = msg; if (mLastResponse.get() == 0)
{
mLastResponse.reset(new SipMessage);
}
mDialog.makeResponse(*mLastResponse, msg, 200); // Generate response now and wait for user to accept or reject, then adjust status code
int errorResponseCode = 0; int errorResponseCode = 0;
handler->getExpires(msg,mExpires,errorResponseCode); handler->getExpires(msg,mExpires,errorResponseCode);
@ -244,7 +260,11 @@ ServerSubscription::dispatch(const SipMessage& msg)
*/ */
if (mSubscriptionState == Invalid) if (mSubscriptionState == Invalid)
{ {
// Move to terminated state - application is not allowed to switch out of this state. This
// allows applications to treat polling requests just like normal subscriptions. Any attempt
// to call setSubscriptionState will NoOp.
mSubscriptionState = Terminated; mSubscriptionState = Terminated;
if (mEventType != "refer" ) if (mEventType != "refer" )
{ {
handler->onNewSubscription(getHandle(), msg); handler->onNewSubscription(getHandle(), msg);
@ -253,16 +273,21 @@ ServerSubscription::dispatch(const SipMessage& msg)
{ {
handler->onNewSubscriptionFromRefer(getHandle(), msg); handler->onNewSubscriptionFromRefer(getHandle(), msg);
} }
// note: it might be nice to call onExpiredByClient here, but it's dangerous, since inline calls
// to reject or the inline sending of a Notify in the onNewSubscription handler will cause
// 'this' to be deleted
return;
} }
makeNotifyExpires(); makeNotifyExpires(); // builds a NOTIFY message into mLastRequest
handler->onExpiredByClient(getHandle(), msg, *mLastRequest); handler->onExpiredByClient(getHandle(), msg, *mLastRequest);
mDialog.makeResponse(*mLastResponse, mLastSubscribe, 200); // Send 200 response to sender
mLastResponse->header(h_Expires).value() = mExpires; mLastResponse->header(h_Expires).value() = mExpires;
send(mLastResponse); send(mLastResponse);
send(mLastRequest); // Send Notify Expires // Send Notify Expires
send(mLastRequest);
return; return;
} }
if (mSubscriptionState == Invalid) if (mSubscriptionState == Invalid)
@ -289,25 +314,33 @@ ServerSubscription::dispatch(const SipMessage& msg)
else else
{ {
//.dcm. - will need to change if retry-afters are reaching here //.dcm. - will need to change if retry-afters are reaching here
mLastRequest->releaseContents(); //mLastRequest->releaseContents();
mLastRequest.reset(); // Release ref count on memory - so message goes away when send is done
int code = msg.header(h_StatusLine).statusCode(); int code = msg.header(h_StatusLine).statusCode();
if (code < 300)
{ if(code < 200)
{
return;
}
else if (code < 300)
{
handler->onNotifyAccepted(getHandle(), msg);
return; return;
} }
else if (code < 400) else if (code < 400)
{ {
//in dialog NOTIFY got redirected? Bizarre... //in dialog NOTIFY got redirected? Bizarre...
handler->onError(getHandle(), msg); handler->onError(getHandle(), msg);
handler->onTerminated(getHandle()); terminateSubscription(handler);
delete this;
} }
else else
{ {
switch(Helper::determineFailureMessageEffect(msg)) switch(Helper::determineFailureMessageEffect(msg,
(mDum.getMasterProfile()->additionalTransactionTerminatingResponsesEnabled()) ?
&mDum.getMasterProfile()->getAdditionalTransactionTerminatingResponses() : NULL))
{ {
case Helper::TransactionTermination: case Helper::TransactionTermination:
DebugLog( << "ServerSubscriptionHandler::TransactionTermination: " << msg.brief()); DebugLog( << "ServerSubscription::TransactionTermination: " << msg.brief());
handler->onNotifyRejected(getHandle(), msg); handler->onNotifyRejected(getHandle(), msg);
break; break;
case Helper::UsageTermination: case Helper::UsageTermination:
@ -315,10 +348,9 @@ ServerSubscription::dispatch(const SipMessage& msg)
case Helper::OptionalRetryAfter: case Helper::OptionalRetryAfter:
case Helper::ApplicationDependant: case Helper::ApplicationDependant:
case Helper::DialogTermination: case Helper::DialogTermination:
DebugLog( << "ServerSubscriptionHandler::UsageTermination: " << msg.brief()); DebugLog( << "ServerSubscription::UsageTermination: " << msg.brief());
handler->onError(getHandle(), msg); handler->onError(getHandle(), msg);
handler->onTerminated(getHandle()); terminateSubscription(handler);
delete this;
break; break;
} }
} }
@ -336,6 +368,10 @@ ServerSubscription::makeNotifyExpires()
void void
ServerSubscription::makeNotify() ServerSubscription::makeNotify()
{ {
if (mLastRequest.get() == 0)
{
mLastRequest.reset(new SipMessage);
}
mDialog.makeRequest(*mLastRequest, NOTIFY); mDialog.makeRequest(*mLastRequest, NOTIFY);
mLastRequest->header(h_SubscriptionState).value() = getSubscriptionStateString(mSubscriptionState); mLastRequest->header(h_SubscriptionState).value() = getSubscriptionStateString(mSubscriptionState);
if (mSubscriptionState == Terminated) if (mSubscriptionState == Terminated)
@ -356,16 +392,23 @@ ServerSubscription::makeNotify()
void void
ServerSubscription::end(TerminateReason reason, const Contents* document) ServerSubscription::end(TerminateReason reason, const Contents* document, int retryAfter)
{ {
mSubscriptionState = Terminated; if (mSubscriptionState != Terminated) // NoOp if called twice or already ending
makeNotify();
mLastRequest->header(h_SubscriptionState).param(p_reason) = getTerminateReasonString(reason);
if (document)
{ {
mLastRequest->setContents(document); mSubscriptionState = Terminated;
makeNotify();
mLastRequest->header(h_SubscriptionState).param(p_reason) = getTerminateReasonString(reason);
if (document)
{
mLastRequest->setContents(document);
}
if (retryAfter != 0)
{
mLastRequest->header(h_SubscriptionState).param(p_retryAfter) = retryAfter;
}
send(mLastRequest);
} }
send(mLastRequest);
} }
void void
@ -377,11 +420,11 @@ ServerSubscription::end()
void void
ServerSubscription::dispatch(const DumTimeout& timeout) ServerSubscription::dispatch(const DumTimeout& timeout)
{ {
assert(timeout.type() == DumTimeout::Subscription); resip_assert(timeout.type() == DumTimeout::Subscription);
if (timeout.seq() == mTimerSeq) if (timeout.seq() == mTimerSeq)
{ {
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType); ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
makeNotifyExpires(); makeNotifyExpires();
handler->onExpired(getHandle(), *mLastRequest); handler->onExpired(getHandle(), *mLastRequest);
send(mLastRequest); send(mLastRequest);
@ -404,21 +447,11 @@ ServerSubscription::neutralNotify()
return mLastRequest; return mLastRequest;
} }
void
ServerSubscription::dialogDestroyed(const SipMessage& msg)
{
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
assert(handler);
handler->onError(getHandle(), msg);
handler->onTerminated(getHandle());
delete this;
}
void void
ServerSubscription::onReadyToSend(SipMessage& msg) ServerSubscription::onReadyToSend(SipMessage& msg)
{ {
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType); ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
handler->onReadyToSend(getHandle(), msg); handler->onReadyToSend(getHandle(), msg);
} }
@ -427,7 +460,7 @@ ServerSubscription::flowTerminated()
{ {
// notify handler // notify handler
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType); ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
assert(handler); resip_assert(handler);
handler->onFlowTerminated(getHandle()); handler->onFlowTerminated(getHandle());
} }
@ -438,7 +471,6 @@ ServerSubscription::dump(EncodeStream& strm) const
return strm; return strm;
} }
/* ==================================================================== /* ====================================================================
* The Vovida Software License, Version 1.0 * The Vovida Software License, Version 1.0
* *

View File

@ -1,12 +1,14 @@
#if !defined(RESIP_SERVERSUBSCRIPTION_HXX) #if !defined(RESIP_SERVERSUBSCRIPTION_HXX)
#define RESIP_SERVERSUBSCRIPTION_HXX #define RESIP_SERVERSUBSCRIPTION_HXX
#include "resip/stack/Helper.hxx"
#include "resip/dum/BaseSubscription.hxx" #include "resip/dum/BaseSubscription.hxx"
namespace resip namespace resip
{ {
class DialogUsageManager; class DialogUsageManager;
class ServerSubscriptionHandler;
//!dcm! -- no Subscription State expires parameter generation yet. //!dcm! -- no Subscription State expires parameter generation yet.
class ServerSubscription : public BaseSubscription class ServerSubscription : public BaseSubscription
@ -30,7 +32,7 @@ class ServerSubscription : public BaseSubscription
void setSubscriptionState(SubscriptionState state); void setSubscriptionState(SubscriptionState state);
SharedPtr<SipMessage> update(const Contents* document); SharedPtr<SipMessage> update(const Contents* document);
void end(TerminateReason reason, const Contents* document = 0); void end(TerminateReason reason, const Contents* document = 0, int retryAfter = 0);
virtual void end(); virtual void end();
virtual void send(SharedPtr<SipMessage> msg); virtual void send(SharedPtr<SipMessage> msg);
@ -49,7 +51,6 @@ class ServerSubscription : public BaseSubscription
protected: protected:
virtual ~ServerSubscription(); virtual ~ServerSubscription();
virtual void dialogDestroyed(const SipMessage& msg);
void onReadyToSend(SipMessage& msg); void onReadyToSend(SipMessage& msg);
virtual void flowTerminated(); virtual void flowTerminated();
@ -63,11 +64,9 @@ class ServerSubscription : public BaseSubscription
bool shouldDestroyAfterSendingFailure(const SipMessage& msg); bool shouldDestroyAfterSendingFailure(const SipMessage& msg);
void terminateSubscription(ServerSubscriptionHandler* handler);
Data mSubscriber; Data mSubscriber;
// const Contents* mCurrentEventDocument;
SipMessage mLastSubscribe;
UInt32 mExpires; UInt32 mExpires;
// disabled // disabled

View File

@ -133,6 +133,10 @@ ServerSubscriptionHandler::onPublished(ServerSubscriptionHandle associated,
// do nothing by default // do nothing by default
} }
void
ServerSubscriptionHandler::onNotifyAccepted(ServerSubscriptionHandle h, const SipMessage& msg)
{
}
void void
ServerSubscriptionHandler::onNotifyRejected(ServerSubscriptionHandle h, const SipMessage& msg) ServerSubscriptionHandler::onNotifyRejected(ServerSubscriptionHandle h, const SipMessage& msg)

View File

@ -25,7 +25,7 @@ class ClientSubscriptionHandler
//subscription can be ended through a notify or a failure response. //subscription can be ended through a notify or a failure response.
virtual void onTerminated(ClientSubscriptionHandle, const SipMessage* msg)=0; virtual void onTerminated(ClientSubscriptionHandle, const SipMessage* msg)=0;
//not sure if this has any value. //not sure if this has any value - can be called for either a 200/SUBSCRIBE or a NOTIFY - whichever arrives first
virtual void onNewSubscription(ClientSubscriptionHandle, const SipMessage& notify)=0; virtual void onNewSubscription(ClientSubscriptionHandle, const SipMessage& notify)=0;
/// called to allow app to adorn a message. /// called to allow app to adorn a message.
@ -48,11 +48,15 @@ class ServerSubscriptionHandler
virtual void onNewSubscription(ServerSubscriptionHandle, const SipMessage& sub)=0; virtual void onNewSubscription(ServerSubscriptionHandle, const SipMessage& sub)=0;
virtual void onNewSubscriptionFromRefer(ServerSubscriptionHandle, const SipMessage& sub); virtual void onNewSubscriptionFromRefer(ServerSubscriptionHandle, const SipMessage& sub);
virtual void onRefresh(ServerSubscriptionHandle, const SipMessage& sub); virtual void onRefresh(ServerSubscriptionHandle, const SipMessage& sub);
//called when a new document is Published that matches this subscription. Also
//called when the publication is removed or expires, in which case contents
//and attrs are passed as null pointers.
virtual void onPublished(ServerSubscriptionHandle associated, virtual void onPublished(ServerSubscriptionHandle associated,
ServerPublicationHandle publication, ServerPublicationHandle publication,
const Contents* contents, const Contents* contents,
const SecurityAttributes* attrs); const SecurityAttributes* attrs);
virtual void onNotifyAccepted(ServerSubscriptionHandle, const SipMessage& msg);
virtual void onNotifyRejected(ServerSubscriptionHandle, const SipMessage& msg); virtual void onNotifyRejected(ServerSubscriptionHandle, const SipMessage& msg);
//called when this usage is destroyed for any reason. One of the following //called when this usage is destroyed for any reason. One of the following

View File

@ -7,21 +7,21 @@ using namespace std;
TargetCommand::TargetCommand(Target& target, TargetCommand::TargetCommand(Target& target,
unique_ptr<Message> message) auto_ptr<Message> message)
: mTarget(target), : mTarget(target),
mMessage(std::move(message)) mMessage(message)
{ {
} }
TargetCommand::TargetCommand(const TargetCommand& from) TargetCommand::TargetCommand(const TargetCommand& from)
: mTarget(from.mTarget), : mTarget(from.mTarget),
mMessage(std::move(from.mMessage)) mMessage(from.mMessage)
{ {
} }
void TargetCommand::executeCommand() void TargetCommand::executeCommand()
{ {
mTarget.post(std::move(mMessage)); mTarget.post(mMessage);
} }
Message* TargetCommand::clone() const Message* TargetCommand::clone() const

View File

@ -19,13 +19,13 @@ class TargetCommand : public DumCommand
{ {
} }
virtual ~Target()=0; virtual ~Target()=0;
virtual void post(std::unique_ptr<Message>)=0; virtual void post(std::auto_ptr<Message>)=0;
protected: protected:
DialogUsageManager& mDum; DialogUsageManager& mDum;
}; };
TargetCommand(Target& target, std::unique_ptr<Message> message); TargetCommand(Target& target, std::auto_ptr<Message> message);
TargetCommand(const TargetCommand&); TargetCommand(const TargetCommand&);
void executeCommand(); void executeCommand();
@ -36,7 +36,7 @@ class TargetCommand : public DumCommand
private: private:
Target& mTarget; Target& mTarget;
mutable std::unique_ptr<Message> mMessage; mutable std::auto_ptr<Message> mMessage;
}; };
} }

Some files were not shown because too many files have changed in this diff Show More