- start upgrade to resiprocate 1.12
This commit is contained in:
parent
aeedeb0626
commit
0c4bf77a67
|
|
@ -58,7 +58,6 @@ set (STACK_SOURCES
|
|||
resip/stack/DeprecatedDialog.cxx
|
||||
resip/stack/GenericUri.cxx
|
||||
resip/stack/GenericContents.cxx
|
||||
resip/stack/FloatParameter.cxx
|
||||
resip/stack/ExternalBodyContents.cxx
|
||||
resip/stack/ExtensionParameter.cxx
|
||||
resip/stack/ExtensionHeader.cxx
|
||||
|
|
@ -68,13 +67,13 @@ set (STACK_SOURCES
|
|||
resip/stack/EventStackThread.cxx
|
||||
resip/stack/Embedded.cxx
|
||||
resip/stack/DtlsMessage.cxx
|
||||
resip/stack/HeaderHash.cxx
|
||||
# resip/stack/HeaderHash.cxx
|
||||
resip/stack/HeaderFieldValueList.cxx
|
||||
resip/stack/HeaderFieldValue.cxx
|
||||
resip/stack/MsgHeaderScanner.cxx
|
||||
resip/stack/Mime.cxx
|
||||
resip/stack/MethodTypes.cxx
|
||||
resip/stack/MethodHash.cxx
|
||||
# resip/stack/MethodHash.cxx
|
||||
resip/stack/MessageWaitingContents.cxx
|
||||
resip/stack/MessageFilterRule.cxx
|
||||
resip/stack/Message.cxx
|
||||
|
|
@ -89,7 +88,7 @@ set (STACK_SOURCES
|
|||
resip/stack/Helper.cxx
|
||||
resip/stack/HeaderTypes.cxx
|
||||
resip/stack/Headers.cxx
|
||||
resip/stack/ParameterHash.cxx
|
||||
# resip/stack/ParameterHash.cxx
|
||||
resip/stack/Parameter.cxx
|
||||
resip/stack/OctetContents.cxx
|
||||
resip/stack/NonceHelper.cxx
|
||||
|
|
@ -305,7 +304,6 @@ SET (RUTIL_SOURCES
|
|||
rutil/KeyValueStore.cxx
|
||||
rutil/HeapInstanceCounter.cxx
|
||||
rutil/GeneralCongestionManager.cxx
|
||||
rutil/AtomicCounter.cxx
|
||||
rutil/WinCompat.cxx
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include "resip/dum/Dialog.hxx"
|
||||
#include "resip/dum/AppDialog.hxx"
|
||||
#include "resip/dum/Dialog.hxx"
|
||||
|
||||
using namespace resip;
|
||||
using namespace std;
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ AppDialogSet::getDialogSetId()
|
|||
AppDialogSet*
|
||||
AppDialogSet::reuse()
|
||||
{
|
||||
assert(mDialogSet);
|
||||
resip_assert(mDialogSet);
|
||||
mDialogSet->appDissociate();
|
||||
mDialogSet = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "resip/dum/DialogUsageManager.hxx"
|
||||
#include "resip/dum/AppDialogSetFactory.hxx"
|
||||
#include "resip/dum/DialogUsageManager.hxx"
|
||||
#include "resip/stack/SipMessage.hxx"
|
||||
#include "resip/dum/AppDialogSet.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "rutil/Logger.hxx"
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "rutil/Logger.hxx"
|
||||
#include "resip/dum/DialogUsageManager.hxx"
|
||||
#include "resip/dum/MasterProfile.hxx"
|
||||
#include "resip/dum/BaseCreator.hxx"
|
||||
|
|
@ -43,7 +43,7 @@ BaseCreator::getUserProfile()
|
|||
void
|
||||
BaseCreator::makeInitialRequest(const NameAddr& target, MethodTypes method)
|
||||
{
|
||||
assert(mUserProfile.get());
|
||||
resip_assert(mUserProfile.get());
|
||||
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_CallId).value() = Helper::computeCallId();
|
||||
|
||||
assert(mUserProfile.get());
|
||||
resip_assert(mUserProfile.get());
|
||||
if (!mUserProfile->getImsAuthUserName().empty())
|
||||
{
|
||||
Auth auth;
|
||||
|
|
@ -137,33 +137,15 @@ BaseCreator::makeInitialRequest(const NameAddr& target, const NameAddr& from, Me
|
|||
Via via;
|
||||
mLastRequest->header(h_Vias).push_front(via);
|
||||
|
||||
if(mUserProfile->isAdvertisedCapability(Headers::Allow))
|
||||
{
|
||||
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();
|
||||
}
|
||||
// Add Advertised Capabilities to initial request
|
||||
mDum.setAdvertisedCapabilities(*mLastRequest.get(), mUserProfile);
|
||||
|
||||
// Merge Embedded parameters
|
||||
mLastRequest->mergeUri(target.uri());
|
||||
|
||||
//DumHelper::setOutgoingEncryptionLevel(mLastRequest, mEncryptionLevel);
|
||||
|
||||
DebugLog ( << "BaseCreator::makeInitialRequest: " << std::endl << std::endl << mLastRequest);
|
||||
DebugLog ( << "BaseCreator::makeInitialRequest: " << std::endl << std::endl << *mLastRequest);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ BaseSubscription::BaseSubscription(DialogUsageManager& dum, Dialog& dialog, cons
|
|||
mSubscriptionId(Data::Empty),
|
||||
mTimerSeq(0),
|
||||
mSubscriptionState(Invalid)
|
||||
|
||||
{
|
||||
if (request.exists(h_Event))
|
||||
{
|
||||
|
|
@ -37,7 +36,7 @@ BaseSubscription::BaseSubscription(DialogUsageManager& dum, Dialog& dialog, cons
|
|||
bool
|
||||
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;
|
||||
}
|
||||
|
|
@ -48,7 +47,6 @@ BaseSubscription::matches(const SipMessage& msg)
|
|||
return msg.header(h_Event).value() == mEventType
|
||||
&& ( !msg.header(h_Event).exists(p_id) ||
|
||||
msg.header(h_Event).param(p_id) == mSubscriptionId);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -58,7 +56,6 @@ BaseSubscription::matches(const SipMessage& msg)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
BaseSubscription::~BaseSubscription()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ BaseUsage::getBaseHandle()
|
|||
return mHandle;
|
||||
}
|
||||
|
||||
void BaseUsage::postDum(Message* messageForDum)
|
||||
{
|
||||
mDum.post(messageForDum);
|
||||
}
|
||||
|
||||
#if 0
|
||||
EncodeStream&
|
||||
BaseUsage::dump(EncodeStream& strm) const
|
||||
|
|
|
|||
|
|
@ -8,11 +8,12 @@
|
|||
namespace resip
|
||||
{
|
||||
|
||||
class DialogUsageManager;
|
||||
class Dialog;
|
||||
class DialogUsageManager;
|
||||
class DumTimeout;
|
||||
class SipMessage;
|
||||
class Message;
|
||||
class NameAddr;
|
||||
class SipMessage;
|
||||
|
||||
class BaseUsage : public Handled
|
||||
{
|
||||
|
|
@ -24,6 +25,9 @@ class BaseUsage : public Handled
|
|||
virtual const char* name() const;
|
||||
};
|
||||
|
||||
/// @brief posts a message on dum
|
||||
virtual void postDum(Message* messageForDum);
|
||||
|
||||
virtual void end()=0;
|
||||
virtual EncodeStream& dump(EncodeStream& strm) const=0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
|
||||
#include "resip/dum/ChallengeInfo.hxx"
|
||||
#include "rutil/Data.hxx"
|
||||
|
|
@ -49,7 +49,7 @@ ChallengeInfo::brief() const
|
|||
resip::Message*
|
||||
ChallengeInfo::clone() const
|
||||
{
|
||||
assert(false); return NULL;
|
||||
resip_assert(false); return NULL;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
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
|
||||
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,
|
||||
Auth& auth)
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -34,7 +34,7 @@ ClientAuthExtension::makeChallengeResponseAuthWithA1(const SipMessage& request,
|
|||
const Data& nonceCountString,
|
||||
Auth& auth)
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class ClientAuthExtension
|
|||
|
||||
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()
|
||||
{
|
||||
return *mInstance;
|
||||
|
|
@ -54,7 +54,7 @@ class ClientAuthExtension
|
|||
ClientAuthExtension() {}
|
||||
|
||||
|
||||
static std::unique_ptr<ClientAuthExtension> mInstance;
|
||||
static std::auto_ptr<ClientAuthExtension> mInstance;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "resip/stack/SipMessage.hxx"
|
||||
|
|
@ -100,18 +100,18 @@ private:
|
|||
Data mNonceCountString;
|
||||
};
|
||||
|
||||
|
||||
ClientAuthManager::ClientAuthManager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, const SipMessage& response)
|
||||
{
|
||||
try
|
||||
{
|
||||
assert( response.isResponse() );
|
||||
assert( origRequest.isRequest() );
|
||||
resip_assert( response.isResponse() );
|
||||
resip_assert( origRequest.isRequest() );
|
||||
|
||||
DialogSetId id(origRequest);
|
||||
|
||||
|
|
@ -133,6 +133,7 @@ ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, con
|
|||
return false;
|
||||
}
|
||||
|
||||
// 401 or 407...
|
||||
if (!(response.exists(h_WWWAuthenticates) || response.exists(h_ProxyAuthenticates)))
|
||||
{
|
||||
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
|
||||
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()++;
|
||||
DebugLog (<< "Produced response to digest challenge for " << userProfile );
|
||||
return true;
|
||||
|
|
@ -157,7 +158,7 @@ ClientAuthManager::handle(UserProfile& userProfile, SipMessage& origRequest, con
|
|||
}
|
||||
catch(BaseException& e)
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
ErrLog(<< "Unexpected exception in ClientAuthManager::handle " << e);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -176,15 +177,26 @@ ClientAuthManager::addAuthentication(SipMessage& request)
|
|||
void
|
||||
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() :
|
||||
mFailed(false)
|
||||
mFailed(false),
|
||||
mCacheUseLimit(0),
|
||||
mCacheUseCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const SipMessage& challenge)
|
||||
{
|
||||
|
|
@ -214,7 +226,7 @@ ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const Si
|
|||
}
|
||||
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)
|
||||
{
|
||||
if (i->exists(p_realm))
|
||||
|
|
@ -230,10 +242,14 @@ ClientAuthManager::AuthState::handleChallenge(UserProfile& userProfile, const Si
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!handled)
|
||||
{
|
||||
InfoLog( << "ClientAuthManager::AuthState::handleChallenge failed for: " << challenge);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCacheUseLimit = userProfile.getDigestCacheUseLimit();
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
|
@ -245,6 +261,13 @@ ClientAuthManager::AuthState::authSucceeded()
|
|||
{
|
||||
i->second.authSucceeded();
|
||||
}
|
||||
mCacheUseCount++;
|
||||
if(mCacheUseLimit != 0 && mCacheUseCount >= mCacheUseLimit)
|
||||
{
|
||||
// Cache use limit reached - clear auth state
|
||||
mRealms.clear();
|
||||
mCacheUseCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -265,8 +288,7 @@ ClientAuthManager::AuthState::addAuthentication(SipMessage& request)
|
|||
ClientAuthManager::RealmState::RealmState() :
|
||||
mIsProxyCredential(false),
|
||||
mState(Invalid),
|
||||
mNonceCount(0),
|
||||
mAuthPtr(NULL)
|
||||
mNonceCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +320,7 @@ ClientAuthManager::RealmState::authSucceeded()
|
|||
switch(mState)
|
||||
{
|
||||
case Invalid:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
break;
|
||||
case Current:
|
||||
case Cached:
|
||||
|
|
@ -306,7 +328,7 @@ ClientAuthManager::RealmState::authSucceeded()
|
|||
transition(Cached);
|
||||
break;
|
||||
case Failed:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
|
@ -388,11 +410,11 @@ ClientAuthManager::RealmState::findCredential(UserProfile& userProfile, const Au
|
|||
const Data& realm = auth.param(p_realm);
|
||||
//!dcm! -- icky, expose static empty soon...ptr instead of reference?
|
||||
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 (<< auth);
|
||||
// DebugLog (<< response);
|
||||
// DebugLog (<< auth);
|
||||
// DebugLog (<< response);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -401,7 +423,7 @@ ClientAuthManager::RealmState::findCredential(UserProfile& userProfile, const Au
|
|||
void
|
||||
ClientAuthManager::RealmState::addAuthentication(SipMessage& request)
|
||||
{
|
||||
assert(mState != Failed);
|
||||
resip_assert(mState != Failed);
|
||||
if (mState == Failed) return;
|
||||
|
||||
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
|
||||
// may be modifying the message body
|
||||
std::unique_ptr<MessageDecorator> clientAuthDecorator(new ClientAuthDecorator(mIsProxyCredential, mAuth, mCredential, authQop, nonceCountString));
|
||||
request.addOutboundDecorator(std::move(clientAuthDecorator));
|
||||
}
|
||||
|
||||
void ClientAuthManager::dialogSetDestroyed(const DialogSetId& id)
|
||||
{
|
||||
if ( mAttemptedAuths.find(id) != mAttemptedAuths.end())
|
||||
{
|
||||
mAttemptedAuths.erase(id);
|
||||
}
|
||||
std::auto_ptr<MessageDecorator> clientAuthDecorator(new ClientAuthDecorator(mIsProxyCredential, mAuth, mCredential, authQop, nonceCountString));
|
||||
request.addOutboundDecorator(clientAuthDecorator);
|
||||
}
|
||||
|
||||
// bool
|
||||
|
|
@ -443,7 +457,6 @@ void ClientAuthManager::dialogSetDestroyed(const DialogSetId& id)
|
|||
// }
|
||||
|
||||
|
||||
|
||||
/* ====================================================================
|
||||
* The Vovida Software License, Version 1.0
|
||||
*
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ class ClientAuthManager
|
|||
// bool operator()(const Auth& lhs, const Auth& rhs) const;
|
||||
// };
|
||||
|
||||
|
||||
class RealmState
|
||||
{
|
||||
public:
|
||||
|
|
@ -74,13 +73,10 @@ class ClientAuthManager
|
|||
unsigned int mNonceCount;
|
||||
Auth mAuth;
|
||||
|
||||
// FH add the realm state so it can change
|
||||
Auth *mAuthPtr;
|
||||
|
||||
// .dcm. only one credential per realm per challenge supported
|
||||
// typedef std::map<Auth, UserProfile::DigestCredential, CompareAuth > CredentialMap;
|
||||
// CredentialMap proxyCredentials;
|
||||
// CredentialMap wwwCredentials;
|
||||
// .dcm. only one credential per realm per challenge supported
|
||||
// typedef std::map<Auth, UserProfile::DigestCredential, CompareAuth > CredentialMap;
|
||||
// CredentialMap proxyCredentials;
|
||||
// CredentialMap wwwCredentials;
|
||||
};
|
||||
|
||||
class AuthState
|
||||
|
|
@ -95,6 +91,8 @@ class ClientAuthManager
|
|||
typedef std::map<Data, RealmState> RealmStates;
|
||||
RealmStates mRealms;
|
||||
bool mFailed;
|
||||
unsigned long mCacheUseLimit;
|
||||
unsigned long mCacheUseCount;
|
||||
};
|
||||
|
||||
typedef std::map<DialogSetId, AuthState> AttemptedAuthMap;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include "resip/stack/Contents.hxx"
|
||||
#include "resip/dum/BaseCreator.hxx"
|
||||
#include "resip/dum/ClientInviteSession.hxx"
|
||||
#include "resip/dum/Dialog.hxx"
|
||||
#include "resip/dum/DialogEventStateManager.hxx"
|
||||
|
|
@ -31,12 +32,13 @@ ClientInviteSession::ClientInviteSession(DialogUsageManager& dum,
|
|||
InviteSession(dum, dialog),
|
||||
mStaleCallTimerSeq(1),
|
||||
mCancelledTimerSeq(1),
|
||||
mServerSub(serverSub)
|
||||
mServerSub(serverSub),
|
||||
mAllowOfferInPrack(false)
|
||||
{
|
||||
assert(request->isRequest());
|
||||
resip_assert(request->isRequest());
|
||||
if(initialOffer)
|
||||
{
|
||||
mProposedLocalOfferAnswer = unique_ptr<Contents>(initialOffer->clone());
|
||||
mProposedLocalOfferAnswer = auto_ptr<Contents>(initialOffer->clone());
|
||||
mProposedEncryptionLevel = level;
|
||||
}
|
||||
*mLastLocalSessionModification = *request; // Copy message, so that modifications to mLastLocalSessionModification don't effect creator->getLastRequest
|
||||
|
|
@ -64,6 +66,16 @@ ClientInviteSession::provideOffer(const Contents& offer, DialogUsageManager::Enc
|
|||
switch(mState)
|
||||
{
|
||||
case UAC_EarlyWithAnswer:
|
||||
if(mAllowOfferInPrack)
|
||||
{
|
||||
// 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);
|
||||
|
||||
|
|
@ -78,8 +90,8 @@ ClientInviteSession::provideOffer(const Contents& offer, DialogUsageManager::Enc
|
|||
// Send the req and do state transition.
|
||||
DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
|
||||
send(mLastLocalSessionModification);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case UAC_SentAnswer:
|
||||
// just queue it for later
|
||||
|
|
@ -97,7 +109,8 @@ ClientInviteSession::provideOffer(const Contents& offer, DialogUsageManager::Enc
|
|||
case UAC_Cancelled:
|
||||
case UAC_QueuedUpdate:
|
||||
case Terminated:
|
||||
assert(0);
|
||||
WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
|
||||
throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -124,11 +137,11 @@ ClientInviteSession::provideAnswer (const Contents& answer)
|
|||
transition(UAC_SentAnswer);
|
||||
|
||||
// Remember proposed local offerAnswer.
|
||||
mCurrentRemoteOfferAnswer = std::move(mProposedRemoteOfferAnswer);
|
||||
mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
|
||||
mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
|
||||
|
||||
// Creates an PRACK request with application supplied offer.
|
||||
sendPrack(answer);
|
||||
// Creates a PRACK request with application supplied answer
|
||||
sendPrack(answer, mCurrentEncryptionLevel);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -137,9 +150,8 @@ ClientInviteSession::provideAnswer (const Contents& answer)
|
|||
transition(Connected);
|
||||
sendAck(&answer);
|
||||
|
||||
mCurrentRemoteOfferAnswer = std::move(mProposedRemoteOfferAnswer);
|
||||
mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
|
||||
mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
|
||||
// mLastSessionModification = ack; // ?slg? is this needed?
|
||||
break;
|
||||
}
|
||||
case UAC_ReceivedUpdateEarly:
|
||||
|
|
@ -154,7 +166,7 @@ ClientInviteSession::provideAnswer (const Contents& answer)
|
|||
mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
|
||||
InviteSession::setOfferAnswer(*response, answer, 0);
|
||||
mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
|
||||
mCurrentRemoteOfferAnswer = std::move(mProposedRemoteOfferAnswer);
|
||||
mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
|
||||
InfoLog (<< "Sending " << response->brief());
|
||||
DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
|
||||
send(response);
|
||||
|
|
@ -169,7 +181,8 @@ ClientInviteSession::provideAnswer (const Contents& answer)
|
|||
case UAC_Cancelled:
|
||||
case UAC_QueuedUpdate:
|
||||
case Terminated:
|
||||
assert(0);
|
||||
WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
|
||||
throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -220,7 +233,7 @@ ClientInviteSession::end(EndReason reason)
|
|||
|
||||
case UAC_Start:
|
||||
WarningLog (<< "Try to end when in state=" << toData(mState));
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
break;
|
||||
|
||||
case Terminated:
|
||||
|
|
@ -255,7 +268,8 @@ ClientInviteSession::reject (int statusCode, WarningCategory *warning)
|
|||
break;
|
||||
}
|
||||
|
||||
case UAC_Answered:{
|
||||
case UAC_Answered:
|
||||
{
|
||||
// We received an offer in a 2xx response, and we want to reject it
|
||||
// ACK with no body, then send bye
|
||||
sendAck();
|
||||
|
|
@ -273,7 +287,7 @@ ClientInviteSession::reject (int statusCode, WarningCategory *warning)
|
|||
case UAC_SentAnswer:
|
||||
case UAC_Cancelled:
|
||||
WarningLog (<< "Try to reject when in state=" << toData(mState));
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -304,7 +318,7 @@ ClientInviteSession::cancel()
|
|||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -344,7 +358,6 @@ ClientInviteSession::startStaleCallTimer()
|
|||
{
|
||||
InfoLog (<< toData(mState) << ": startStaleCallTimer");
|
||||
unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleCallTime();
|
||||
when += Random::getRandom() % 120;
|
||||
|
||||
mDum.addTimer(DumTimeout::StaleCall,
|
||||
when,
|
||||
|
|
@ -405,7 +418,7 @@ ClientInviteSession::dispatch(const SipMessage& msg)
|
|||
}
|
||||
}
|
||||
|
||||
if (checkRseq(msg))
|
||||
if (isBadRseq(msg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -529,15 +542,16 @@ ClientInviteSession::handleRedirect (const SipMessage& msg)
|
|||
void
|
||||
ClientInviteSession::handleProvisional(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isResponse());
|
||||
assert(msg.header(h_StatusLine).statusCode() < 200);
|
||||
assert(msg.header(h_StatusLine).statusCode() > 100);
|
||||
resip_assert(msg.isResponse());
|
||||
resip_assert(msg.header(h_StatusLine).statusCode() < 200);
|
||||
resip_assert(msg.header(h_StatusLine).statusCode() > 100);
|
||||
|
||||
//.dcm. Kept the following checks here rather than discardMessage as the
|
||||
// state machine can be affected(termination).
|
||||
|
||||
// !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());
|
||||
onFailureAspect(getHandle(), msg);
|
||||
|
|
@ -562,9 +576,9 @@ ClientInviteSession::handleProvisional(const SipMessage& msg)
|
|||
void
|
||||
ClientInviteSession::handleFinalResponse(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isResponse());
|
||||
assert(msg.header(h_StatusLine).statusCode() >= 200);
|
||||
assert(msg.header(h_StatusLine).statusCode() < 300);
|
||||
resip_assert(msg.isResponse());
|
||||
resip_assert(msg.header(h_StatusLine).statusCode() >= 200);
|
||||
resip_assert(msg.header(h_StatusLine).statusCode() < 300);
|
||||
|
||||
handleSessionTimerResponse(msg);
|
||||
storePeerCapabilities(msg);
|
||||
|
|
@ -572,7 +586,7 @@ ClientInviteSession::handleFinalResponse(const SipMessage& msg)
|
|||
}
|
||||
|
||||
void
|
||||
ClientInviteSession::handleOffer (const SipMessage& msg, const Contents& offer)
|
||||
ClientInviteSession::handle1xxOffer(const SipMessage& msg, const Contents& offer)
|
||||
{
|
||||
InviteSessionHandler* handler = mDum.mInviteSessionHandler;
|
||||
|
||||
|
|
@ -583,27 +597,44 @@ ClientInviteSession::handleOffer (const SipMessage& msg, const Contents& offer)
|
|||
}
|
||||
|
||||
void
|
||||
ClientInviteSession::handleAnswer(const SipMessage& msg, const Contents& answer)
|
||||
ClientInviteSession::handle1xxAnswer(const SipMessage& msg, const Contents& answer)
|
||||
{
|
||||
//mCurrentLocalOfferAnswer = mProposedLocalOfferAnswer;
|
||||
setCurrentLocalOfferAnswer(msg);
|
||||
mCurrentEncryptionLevel = getEncryptionLevel(msg);
|
||||
mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(answer);
|
||||
|
||||
InviteSessionHandler* handler = mDum.mInviteSessionHandler;
|
||||
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);
|
||||
|
||||
// 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)
|
||||
void
|
||||
ClientInviteSession::sendPrackIfNeeded(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isResponse());
|
||||
assert(msg.header(h_StatusLine).statusCode() < 200);
|
||||
assert(msg.header(h_StatusLine).statusCode() > 100);
|
||||
resip_assert(msg.isResponse());
|
||||
resip_assert(msg.header(h_StatusLine).statusCode() < 200);
|
||||
resip_assert(msg.header(h_StatusLine).statusCode() > 100);
|
||||
|
||||
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
|
||||
// from EarlyWithOffer state. Assumes that it is the first PRACK. Subsequent
|
||||
// PRACK will not have SDP
|
||||
// This version is used to send an answer to the UAS in PRACK from EarlyWithOffer
|
||||
// state. Assumes that it is the first PRACK. Subsequent PRACK will not have SDP
|
||||
// Also used to send an offer in the first PRACK if the 18x included an
|
||||
// answer.
|
||||
void
|
||||
ClientInviteSession::sendPrack(const Contents& offerAnswer)
|
||||
ClientInviteSession::sendPrack(const Contents& offerAnswer, DialogUsageManager::EncryptionLevel encryptionLevel)
|
||||
{
|
||||
SharedPtr<SipMessage> prack(new SipMessage);
|
||||
mDialog.makeRequest(*prack, PRACK);
|
||||
|
|
@ -626,44 +658,19 @@ ClientInviteSession::sendPrack(const Contents& offerAnswer)
|
|||
|
||||
InviteSession::setOfferAnswer(*prack, offerAnswer);
|
||||
|
||||
// Remember last session modification.
|
||||
// mLastSessionModification = prack; // ?slg? is this needed?
|
||||
|
||||
DumHelper::setOutgoingEncryptionLevel(*prack, mCurrentEncryptionLevel);
|
||||
DumHelper::setOutgoingEncryptionLevel(*prack, encryptionLevel);
|
||||
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
|
||||
ClientInviteSession::dispatchStart (const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isResponse());
|
||||
assert(msg.header(h_StatusLine).statusCode() > 100);
|
||||
assert(msg.header(h_CSeq).method() == INVITE);
|
||||
resip_assert(msg.isResponse());
|
||||
resip_assert(msg.header(h_StatusLine).statusCode() > 100);
|
||||
resip_assert(msg.header(h_CSeq).method() == INVITE);
|
||||
|
||||
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());
|
||||
|
||||
|
|
@ -675,12 +682,12 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
|
|||
if(!isTerminated())
|
||||
{
|
||||
handleProvisional(msg);
|
||||
sendPrackIfNeeded(msg); //may wish to move emprty PRACK handling
|
||||
//outside the state machine
|
||||
sendPrackIfNeeded(msg); // may wish to move emprty PRACK handling
|
||||
// outside the state machine
|
||||
}
|
||||
break;
|
||||
|
||||
case On1xxEarly:
|
||||
case On1xxEarly: // only unreliable
|
||||
//!dcm! according to draft-ietf-sipping-offeranswer there can be a non
|
||||
// reliable 1xx followed by a reliable 1xx. Also, the intial 1xx
|
||||
// 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);
|
||||
if(!isTerminated())
|
||||
{
|
||||
handleOffer(msg, *offerAnswer);
|
||||
handle1xxOffer(msg, *offerAnswer);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -713,7 +720,7 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
|
|||
handler->onNewSession(getHandle(), InviteSession::Answer, msg);
|
||||
if(!isTerminated())
|
||||
{
|
||||
handleAnswer(msg, *offerAnswer);
|
||||
handle1xxAnswer(msg, *offerAnswer);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -722,7 +729,7 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
|
|||
handleFinalResponse(msg);
|
||||
mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
|
||||
handler->onNewSession(getHandle(), InviteSession::Offer, msg);
|
||||
assert(mProposedLocalOfferAnswer.get() == 0);
|
||||
resip_assert(mProposedLocalOfferAnswer.get() == 0);
|
||||
mCurrentEncryptionLevel = getEncryptionLevel(msg);
|
||||
if(!isTerminated())
|
||||
{
|
||||
|
|
@ -738,7 +745,6 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
|
|||
transition(Connected);
|
||||
sendAck();
|
||||
handleFinalResponse(msg);
|
||||
//mCurrentLocalOfferAnswer = mProposedLocalOfferAnswer;
|
||||
setCurrentLocalOfferAnswer(msg);
|
||||
mCurrentEncryptionLevel = getEncryptionLevel(msg);
|
||||
mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
|
||||
|
|
@ -793,13 +799,14 @@ void
|
|||
ClientInviteSession::dispatchEarly (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
case On1xx:
|
||||
transition(UAC_Early);
|
||||
handleProvisional(msg);
|
||||
sendPrackIfNeeded(msg);
|
||||
break;
|
||||
|
||||
case On1xxEarly: // only unreliable
|
||||
|
|
@ -814,19 +821,19 @@ ClientInviteSession::dispatchEarly (const SipMessage& msg)
|
|||
|
||||
case On1xxOffer:
|
||||
transition(UAC_EarlyWithOffer);
|
||||
handleOffer(msg, *offerAnswer);
|
||||
handle1xxOffer(msg, *offerAnswer);
|
||||
break;
|
||||
|
||||
case On1xxAnswer:
|
||||
transition(UAC_EarlyWithAnswer);
|
||||
handleAnswer(msg, *offerAnswer);
|
||||
handle1xxAnswer(msg, *offerAnswer);
|
||||
break;
|
||||
|
||||
case On2xxOffer:
|
||||
transition(UAC_Answered);
|
||||
handleFinalResponse(msg);
|
||||
|
||||
assert(mProposedLocalOfferAnswer.get() == 0);
|
||||
resip_assert(mProposedLocalOfferAnswer.get() == 0);
|
||||
mCurrentEncryptionLevel = getEncryptionLevel(msg);
|
||||
mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
|
||||
|
||||
|
|
@ -841,7 +848,6 @@ ClientInviteSession::dispatchEarly (const SipMessage& msg)
|
|||
transition(Connected);
|
||||
sendAck();
|
||||
handleFinalResponse(msg);
|
||||
//mCurrentLocalOfferAnswer = mProposedLocalOfferAnswer;
|
||||
setCurrentLocalOfferAnswer(msg);
|
||||
mCurrentEncryptionLevel = getEncryptionLevel(msg);
|
||||
mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
|
||||
|
|
@ -902,12 +908,14 @@ ClientInviteSession::dispatchEarly (const SipMessage& msg)
|
|||
{
|
||||
// ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
|
||||
SharedPtr<SipMessage> response(new SipMessage);
|
||||
*mLastRemoteSessionModification = msg;
|
||||
mDialog.makeResponse(*response, msg, 200);
|
||||
send(response);
|
||||
break;
|
||||
}
|
||||
|
||||
case On200Prack:
|
||||
break;
|
||||
|
||||
default:
|
||||
// !kh!
|
||||
// should not assert here for peer sent us garbage.
|
||||
|
|
@ -920,7 +928,7 @@ void
|
|||
ClientInviteSession::dispatchAnswered (const SipMessage& msg)
|
||||
{
|
||||
//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()))
|
||||
{
|
||||
|
|
@ -972,7 +980,7 @@ void
|
|||
ClientInviteSession::dispatchEarlyWithOffer (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
|
|
@ -1022,7 +1030,6 @@ ClientInviteSession::dispatchEarlyWithOffer (const SipMessage& msg)
|
|||
{
|
||||
// ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
|
||||
SharedPtr<SipMessage> response(new SipMessage);
|
||||
*mLastRemoteSessionModification = msg;
|
||||
mDialog.makeResponse(*response, msg, 200);
|
||||
send(response);
|
||||
break;
|
||||
|
|
@ -1040,7 +1047,7 @@ void
|
|||
ClientInviteSession::dispatchSentAnswer (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
|
|
@ -1055,18 +1062,29 @@ ClientInviteSession::dispatchSentAnswer (const SipMessage& msg)
|
|||
onConnectedAspect(getHandle(), msg);
|
||||
break;
|
||||
|
||||
case On2xxAnswer:
|
||||
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 On1xxOffer:
|
||||
sendAck();
|
||||
sendBye();
|
||||
InfoLog (<< "Failure: illegal offer/answer: " << msg.brief());
|
||||
WarningLog(<< "Failure: illegal offer/answer: " << msg.brief());
|
||||
transition(Terminated);
|
||||
onFailureAspect(getHandle(), msg);
|
||||
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
|
||||
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:
|
||||
handleProvisional(msg);
|
||||
sendPrackIfNeeded(msg);
|
||||
|
|
@ -1101,7 +1119,7 @@ void
|
|||
ClientInviteSession::dispatchQueuedUpdate (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
|
|
@ -1131,18 +1149,29 @@ ClientInviteSession::dispatchQueuedUpdate (const SipMessage& msg)
|
|||
onConnectedAspect(getHandle(), msg);
|
||||
break;
|
||||
|
||||
case On2xxAnswer:
|
||||
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 On1xxOffer:
|
||||
sendAck();
|
||||
sendBye();
|
||||
InfoLog (<< "Failure: illegal offer/answer: " << msg.brief());
|
||||
WarningLog(<< "Failure: illegal offer/answer: " << msg.brief());
|
||||
transition(Terminated);
|
||||
onFailureAspect(getHandle(), msg);
|
||||
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
|
||||
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:
|
||||
handleProvisional(msg);
|
||||
sendPrackIfNeeded(msg);
|
||||
|
|
@ -1179,21 +1208,19 @@ void
|
|||
ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
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:
|
||||
handleProvisional(msg);
|
||||
sendPrackIfNeeded(msg);
|
||||
break;
|
||||
case On1xxOffer:
|
||||
if(!isTerminated())
|
||||
{
|
||||
transition(UAC_EarlyWithOffer);
|
||||
handleOffer(msg, *offerAnswer);
|
||||
}
|
||||
break;
|
||||
|
||||
case On2xx:
|
||||
transition(Connected);
|
||||
sendAck();
|
||||
|
|
@ -1201,11 +1228,19 @@ ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
|
|||
onConnectedAspect(getHandle(), msg);
|
||||
break;
|
||||
|
||||
case On2xxAnswer:
|
||||
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();
|
||||
sendBye();
|
||||
InfoLog (<< "Failure: illegal offer/answer: " << msg.brief());
|
||||
WarningLog(<< "Failure: illegal offer/answer: " << msg.brief());
|
||||
transition(Terminated);
|
||||
onFailureAspect(getHandle(), 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?
|
||||
SharedPtr<SipMessage> response(new SipMessage);
|
||||
*mLastRemoteSessionModification = msg;
|
||||
mDialog.makeResponse(*response, msg, 200);
|
||||
send(response);
|
||||
break;
|
||||
|
|
@ -1246,6 +1280,18 @@ ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
|
|||
dispatchBye(msg);
|
||||
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:
|
||||
// !kh!
|
||||
// should not assert here for peer sent us garbage.
|
||||
|
|
@ -1258,7 +1304,7 @@ void
|
|||
ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
|
|
@ -1282,7 +1328,6 @@ ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg)
|
|||
{
|
||||
// ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
|
||||
SharedPtr<SipMessage> response(new SipMessage);
|
||||
*mLastRemoteSessionModification = msg;
|
||||
mDialog.makeResponse(*response, msg, 200);
|
||||
send(response);
|
||||
break;
|
||||
|
|
@ -1312,6 +1357,9 @@ ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg)
|
|||
mDum.destroy(this);
|
||||
break;
|
||||
|
||||
case On200Prack:
|
||||
break;
|
||||
|
||||
default:
|
||||
WarningLog (<< "Don't know what this is : " << msg);
|
||||
break;
|
||||
|
|
@ -1322,7 +1370,7 @@ void
|
|||
ClientInviteSession::dispatchSentUpdateEarlyGlare (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
|
|
@ -1360,21 +1408,28 @@ ClientInviteSession::dispatchSentUpdateEarlyGlare (const SipMessage& msg)
|
|||
}
|
||||
|
||||
void
|
||||
ClientInviteSession::dispatchReceivedUpdateEarly (const SipMessage& msg)
|
||||
ClientInviteSession::dispatchReceivedUpdateEarly(const SipMessage& msg)
|
||||
{
|
||||
/*
|
||||
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()))
|
||||
{
|
||||
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:
|
||||
// !kh!
|
||||
// should not assert here for peer sent us garbage.
|
||||
WarningLog (<< "Don't know what this is : " << msg);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
WarningLog (<< "Ignoring message received in ReceivedUpdateEarly: " << msg);
|
||||
}
|
||||
|
||||
|
|
@ -1382,7 +1437,7 @@ void
|
|||
ClientInviteSession::dispatchCancelled (const SipMessage& msg)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
|
|
@ -1422,7 +1477,7 @@ ClientInviteSession::dispatchCancelled (const SipMessage& msg)
|
|||
|
||||
//true if 180rel should be ignored. Saves rseq as a side effect.
|
||||
bool
|
||||
ClientInviteSession::checkRseq(const SipMessage& msg)
|
||||
ClientInviteSession::isBadRseq(const SipMessage& msg)
|
||||
{
|
||||
int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
|
||||
if (msg.method() == INVITE && code > 100 && code < 200)
|
||||
|
|
|
|||
|
|
@ -64,10 +64,10 @@ class ClientInviteSession : public InviteSession
|
|||
void handleRedirect (const SipMessage& msg);
|
||||
void handleProvisional (const SipMessage& msg);
|
||||
void handleFinalResponse (const SipMessage& msg);
|
||||
void handleOffer (const SipMessage& msg, const Contents& offer);
|
||||
void handleAnswer (const SipMessage& msg, const Contents& answer);
|
||||
void handle1xxOffer (const SipMessage& msg, const Contents& offer);
|
||||
void handle1xxAnswer (const SipMessage& msg, const Contents& answer);
|
||||
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
|
||||
void cancel();
|
||||
|
|
@ -75,7 +75,7 @@ class ClientInviteSession : public InviteSession
|
|||
// Called by the DialogSet when it receives a 2xx response
|
||||
void onForkAccepted();
|
||||
|
||||
bool checkRseq(const SipMessage& msg);
|
||||
bool isBadRseq(const SipMessage& msg);
|
||||
private:
|
||||
void startCancelTimer();
|
||||
void startStaleCallTimer();
|
||||
|
|
@ -85,12 +85,13 @@ class ClientInviteSession : public InviteSession
|
|||
void onProvisionalAspect(ClientInviteSessionHandle c, const SipMessage& msg);
|
||||
void onFailureAspect(ClientInviteSessionHandle c, const SipMessage& msg);
|
||||
|
||||
std::unique_ptr<Contents> mEarlyMedia;
|
||||
std::auto_ptr<Contents> mEarlyMedia;
|
||||
|
||||
RAckCategory mRelRespInfo;
|
||||
unsigned int mStaleCallTimerSeq;
|
||||
unsigned int mCancelledTimerSeq;
|
||||
ServerSubscriptionHandle mServerSub;
|
||||
bool mAllowOfferInPrack;
|
||||
|
||||
// disabled
|
||||
ClientInviteSession(const ClientInviteSession&);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ ClientOutOfDialogReq::end()
|
|||
void
|
||||
ClientOutOfDialogReq::dispatch(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isResponse());
|
||||
resip_assert(msg.isResponse());
|
||||
|
||||
if (msg.header(h_StatusLine).statusCode() >= 200)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -113,10 +113,9 @@ ClientPagerMessage::getMessageRequest()
|
|||
}
|
||||
|
||||
void
|
||||
ClientPagerMessage::page(std::unique_ptr<Contents> contents,
|
||||
DialogUsageManager::EncryptionLevel level)
|
||||
ClientPagerMessage::page(std::auto_ptr<Contents> contents, DialogUsageManager::EncryptionLevel level)
|
||||
{
|
||||
assert(contents.get() != 0);
|
||||
resip_assert(contents.get() != 0);
|
||||
bool do_page = mMsgQueue.empty();
|
||||
Item item;
|
||||
item.contents = contents.release();
|
||||
|
|
@ -124,90 +123,130 @@ ClientPagerMessage::page(std::unique_ptr<Contents> contents,
|
|||
mMsgQueue.push_back(item);
|
||||
if(do_page)
|
||||
{
|
||||
this->pageFirstMsgQueued();
|
||||
pageFirstMsgQueued();
|
||||
}
|
||||
}
|
||||
|
||||
class ClientPagerMessagePageCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientPagerMessagePageCommand(ClientPagerMessage& clientPagerMessage,
|
||||
std::unique_ptr<Contents> contents,
|
||||
ClientPagerMessagePageCommand(const ClientPagerMessageHandle& clientPagerMessageHandle,
|
||||
std::auto_ptr<Contents> contents,
|
||||
DialogUsageManager::EncryptionLevel level)
|
||||
: mClientPagerMessage(clientPagerMessage),
|
||||
mContents(std::move(contents)),
|
||||
: mClientPagerMessageHandle(clientPagerMessageHandle),
|
||||
mContents(contents),
|
||||
mLevel(level)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientPagerMessage.page(std::move(mContents), mLevel);
|
||||
if(mClientPagerMessageHandle.isValid())
|
||||
{
|
||||
mClientPagerMessageHandle->page(mContents, mLevel);
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
{
|
||||
return strm << "ClientPagerMessagePageCommand";
|
||||
}
|
||||
|
||||
private:
|
||||
ClientPagerMessage& mClientPagerMessage;
|
||||
std::unique_ptr<Contents> mContents;
|
||||
ClientPagerMessageHandle mClientPagerMessageHandle;
|
||||
std::auto_ptr<Contents> mContents;
|
||||
DialogUsageManager::EncryptionLevel mLevel;
|
||||
};
|
||||
|
||||
void
|
||||
ClientPagerMessage::pageCommand(std::unique_ptr<Contents> contents,
|
||||
ClientPagerMessage::pageCommand(std::auto_ptr<Contents> contents,
|
||||
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
|
||||
ClientPagerMessage::dispatch(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isResponse());
|
||||
resip_assert(msg.isResponse());
|
||||
|
||||
ClientPagerMessageHandler* handler = mDum.mClientPagerMessageHandler;
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
|
||||
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)
|
||||
{
|
||||
DebugLog ( << "ClientPagerMessageReq::dispatch - encountered provisional response" << msg.brief() );
|
||||
}
|
||||
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
|
||||
// item to a new target
|
||||
if (msg.header(h_CSeq).sequence() == mRequest->header(h_CSeq).sequence())
|
||||
{
|
||||
if (mMsgQueue.empty() == false)
|
||||
{
|
||||
delete mMsgQueue.front().contents;
|
||||
mMsgQueue.pop_front();
|
||||
if(mMsgQueue.empty() == false)
|
||||
if (mMsgQueue.empty() == false)
|
||||
{
|
||||
this->pageFirstMsgQueued();
|
||||
}
|
||||
|
||||
}
|
||||
handler->onSuccess(getHandle(), msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if cseq doesn't match last message paged then someone must have called newTargetInfoSet
|
||||
// we want to supress the onFailure callback and logic, since we re-sent this first queued
|
||||
// item to a new target
|
||||
if (msg.header(h_CSeq).sequence() == mRequest->header(h_CSeq).sequence())
|
||||
{
|
||||
if (!mMsgQueue.empty())
|
||||
{
|
||||
// if cseq doesn't match first queued element - someone must have called newTargetInfoSet
|
||||
// we want to supress the onFailure callback and logic, since we re-sent this first queued item to a new target
|
||||
SipMessage errResponse;
|
||||
MsgQueue::iterator contents;
|
||||
for(contents = mMsgQueue.begin(); contents != mMsgQueue.end(); ++contents)
|
||||
for (contents = mMsgQueue.begin(); contents != mMsgQueue.end(); ++contents)
|
||||
{
|
||||
Contents* p = contents->contents;
|
||||
WarningLog ( << "Paging failed " << *p );
|
||||
WarningLog(<< "Paging failed " << *p);
|
||||
Helper::makeResponse(errResponse, *mRequest, code);
|
||||
handler->onFailure(getHandle(), errResponse, std::unique_ptr<Contents>(p));
|
||||
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
|
||||
ClientPagerMessage::msgQueued () const
|
||||
ClientPagerMessage::msgQueued() const
|
||||
{
|
||||
return mMsgQueue.size();
|
||||
}
|
||||
|
||||
void
|
||||
ClientPagerMessage::pageFirstMsgQueued ()
|
||||
ClientPagerMessage::pageFirstMsgQueued()
|
||||
{
|
||||
assert(mMsgQueue.empty() == false);
|
||||
resip_assert(mMsgQueue.empty() == false);
|
||||
mRequest->header(h_CSeq).sequence()++;
|
||||
mRequest->setContents(mMsgQueue.front().contents);
|
||||
DumHelper::setOutgoingEncryptionLevel(*mRequest, mMsgQueue.front().encryptionLevel);
|
||||
|
|
@ -271,7 +310,7 @@ ClientPagerMessage::pageFirstMsgQueued ()
|
|||
}
|
||||
|
||||
void
|
||||
ClientPagerMessage::clearMsgQueued ()
|
||||
ClientPagerMessage::clearMsgQueued()
|
||||
{
|
||||
MsgQueue::iterator contents;
|
||||
for(contents = mMsgQueue.begin(); contents != mMsgQueue.end(); ++contents)
|
||||
|
|
|
|||
|
|
@ -23,24 +23,34 @@ class ClientPagerMessage : public NonDialogUsage
|
|||
//I don't know how this would interact with the queuing mechanism.
|
||||
//Will come back to re-visit this in the future.
|
||||
SipMessage& getMessageRequest();
|
||||
SharedPtr<SipMessage> getMessageRequestSharedPtr() { return mRequest; }
|
||||
|
||||
//!kh!
|
||||
//queues the message if there is one sent but not yet received a response
|
||||
//for it.
|
||||
//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();
|
||||
|
||||
// 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
|
||||
*/
|
||||
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 DumTimeout& timer);
|
||||
|
||||
size_t msgQueued () const;
|
||||
size_t msgQueued() const;
|
||||
|
||||
virtual EncodeStream& dump(EncodeStream& strm) const;
|
||||
|
||||
|
|
@ -68,8 +78,8 @@ class ClientPagerMessage : public NonDialogUsage
|
|||
ClientPagerMessage(const ClientPagerMessage&);
|
||||
ClientPagerMessage& operator=(const ClientPagerMessage&);
|
||||
|
||||
void pageFirstMsgQueued ();
|
||||
void clearMsgQueued ();
|
||||
void pageFirstMsgQueued();
|
||||
void clearMsgQueued();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "resip/stack/SipMessage.hxx"
|
||||
|
|
@ -24,8 +24,10 @@ ClientPublication::ClientPublication(DialogUsageManager& dum,
|
|||
DialogSet& dialogSet,
|
||||
SharedPtr<SipMessage> req)
|
||||
: NonDialogUsage(dum, dialogSet),
|
||||
mPublished(false),
|
||||
mWaitingForResponse(false),
|
||||
mPendingPublish(false),
|
||||
mPendingEnd(false),
|
||||
mPublish(req),
|
||||
mEventType(req->header(h_Event).value()),
|
||||
mTimerSeq(0),
|
||||
|
|
@ -50,14 +52,28 @@ ClientPublication::end()
|
|||
void
|
||||
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->releaseContents();
|
||||
send(mPublish);
|
||||
}
|
||||
else
|
||||
{
|
||||
InfoLog(<< "End client publication immediately (not published) to " << mPublish->header(h_RequestLine).uri());
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
|
@ -65,15 +81,17 @@ ClientPublication::end(bool immediate)
|
|||
class ClientPublicationEndCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientPublicationEndCommand(ClientPublication& clientPublication, bool immediate)
|
||||
: mClientPublication(clientPublication), mImmediate(immediate)
|
||||
ClientPublicationEndCommand(const ClientPublicationHandle& clientPublicationHandle, bool immediate)
|
||||
: mClientPublicationHandle(clientPublicationHandle), mImmediate(immediate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientPublication.end(mImmediate);
|
||||
if(mClientPublicationHandle.isValid())
|
||||
{
|
||||
mClientPublicationHandle->end(mImmediate);
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -81,21 +99,21 @@ public:
|
|||
return strm << "ClientPublicationEndCommand";
|
||||
}
|
||||
private:
|
||||
ClientPublication& mClientPublication;
|
||||
ClientPublicationHandle mClientPublicationHandle;
|
||||
bool mImmediate;
|
||||
};
|
||||
|
||||
void
|
||||
ClientPublication::endCommand(bool immediate)
|
||||
{
|
||||
mDum.post(new ClientPublicationEndCommand(*this, immediate));
|
||||
mDum.post(new ClientPublicationEndCommand(getHandle(), immediate));
|
||||
}
|
||||
|
||||
void
|
||||
ClientPublication::dispatch(const SipMessage& msg)
|
||||
{
|
||||
ClientPublicationHandler* handler = mDum.getClientPublicationHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
|
||||
if (msg.isRequest())
|
||||
{
|
||||
|
|
@ -109,11 +127,12 @@ ClientPublication::dispatch(const SipMessage& msg)
|
|||
return;
|
||||
}
|
||||
|
||||
assert(code >= 200);
|
||||
resip_assert(code >= 200);
|
||||
mWaitingForResponse = false;
|
||||
|
||||
if (code < 300)
|
||||
{
|
||||
mPublished = true;
|
||||
if (mPublish->exists(h_Expires) && mPublish->header(h_Expires).value() == 0)
|
||||
{
|
||||
handler->onRemove(getHandle(), msg);
|
||||
|
|
@ -167,7 +186,7 @@ ClientPublication::dispatch(const SipMessage& msg)
|
|||
}
|
||||
}
|
||||
else if (code == 408 ||
|
||||
(code == 503 && msg.getReceivedTransport() == 0) ||
|
||||
(code == 503 && !msg.isFromWire()) ||
|
||||
((code == 404 ||
|
||||
code == 413 ||
|
||||
code == 480 ||
|
||||
|
|
@ -208,7 +227,6 @@ ClientPublication::dispatch(const SipMessage& msg)
|
|||
getBaseHandle(),
|
||||
++mTimerSeq);
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -217,10 +235,26 @@ ClientPublication::dispatch(const SipMessage& msg)
|
|||
delete this;
|
||||
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());
|
||||
send(mPublish);
|
||||
|
|
@ -240,9 +274,9 @@ ClientPublication::dispatch(const DumTimeout& timer)
|
|||
void
|
||||
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);
|
||||
}
|
||||
|
|
@ -250,16 +284,18 @@ ClientPublication::refresh(unsigned int expiration)
|
|||
class ClientPublicationRefreshCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientPublicationRefreshCommand(ClientPublication& clientPublication, unsigned int expiration)
|
||||
: mClientPublication(clientPublication),
|
||||
ClientPublicationRefreshCommand(const ClientPublicationHandle& clientPublicationHandle, unsigned int expiration)
|
||||
: mClientPublicationHandle(clientPublicationHandle),
|
||||
mExpiration(expiration)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientPublication.refresh(mExpiration);
|
||||
if(mClientPublicationHandle.isValid())
|
||||
{
|
||||
mClientPublicationHandle->refresh(mExpiration);
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -268,14 +304,14 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
ClientPublication& mClientPublication;
|
||||
ClientPublicationHandle mClientPublicationHandle;
|
||||
unsigned int mExpiration;
|
||||
};
|
||||
|
||||
void
|
||||
ClientPublication::refreshCommand(unsigned int expiration)
|
||||
{
|
||||
mDum.post(new ClientPublicationRefreshCommand(*this, expiration));
|
||||
mDum.post(new ClientPublicationRefreshCommand(getHandle(), expiration));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -303,16 +339,18 @@ ClientPublication::update(const Contents* body)
|
|||
class ClientPublicationUpdateCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientPublicationUpdateCommand(ClientPublication& clientPublication, const Contents* body)
|
||||
: mClientPublication(clientPublication),
|
||||
ClientPublicationUpdateCommand(const ClientPublicationHandle& clientPublicationHandle, const Contents* body)
|
||||
: mClientPublicationHandle(clientPublicationHandle),
|
||||
mBody(body?body->clone():0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientPublication.update(mBody.get());
|
||||
if(mClientPublicationHandle.isValid())
|
||||
{
|
||||
mClientPublicationHandle->update(mBody.get());
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -321,14 +359,14 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
ClientPublication& mClientPublication;
|
||||
std::unique_ptr<Contents> mBody;
|
||||
ClientPublicationHandle mClientPublicationHandle;
|
||||
std::auto_ptr<Contents> mBody;
|
||||
};
|
||||
|
||||
void
|
||||
ClientPublication::updateCommand(const Contents* body)
|
||||
{
|
||||
mDum.post(new ClientPublicationUpdateCommand(*this, body));
|
||||
mDum.post(new ClientPublicationUpdateCommand(getHandle(), body));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -41,8 +41,10 @@ class ClientPublication : public NonDialogUsage
|
|||
private:
|
||||
friend class DialogSet;
|
||||
|
||||
bool mPublished;
|
||||
bool mWaitingForResponse;
|
||||
bool mPendingPublish;
|
||||
bool mPendingEnd;
|
||||
|
||||
SharedPtr<SipMessage> mPublish;
|
||||
Data mEventType;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include <iterator>
|
||||
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "resip/stack/ExtensionHeader.hxx"
|
||||
#include "resip/dum/BaseCreator.hxx"
|
||||
#include "resip/dum/ClientAuthManager.hxx"
|
||||
#include "resip/dum/ClientRegistration.hxx"
|
||||
|
|
@ -15,20 +14,21 @@
|
|||
#include "rutil/Inserter.hxx"
|
||||
#include "rutil/Random.hxx"
|
||||
#include "rutil/ParseBuffer.hxx"
|
||||
#include "rutil/TransportType.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
#include "rutil/AtomicCounter.hxx"
|
||||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
||||
using namespace resip;
|
||||
|
||||
static const UInt32 UnreasonablyLowExpirationThreshold = 7; // The threshold before which we consider a contacts expiry to be unreasonably low
|
||||
|
||||
ClientRegistrationHandle
|
||||
ClientRegistration::getHandle()
|
||||
{
|
||||
return ClientRegistrationHandle(mDum, getBaseHandle().getId());
|
||||
}
|
||||
|
||||
AtomicCounter ClientRegistration::InstanceCounter;
|
||||
|
||||
ClientRegistration::ClientRegistration(DialogUsageManager& dum,
|
||||
DialogSet& dialogSet,
|
||||
SharedPtr<SipMessage> request)
|
||||
|
|
@ -36,20 +36,26 @@ ClientRegistration::ClientRegistration(DialogUsageManager& dum,
|
|||
mLastRequest(request),
|
||||
mTimerSeq(0),
|
||||
mState(mLastRequest->exists(h_Contacts) ? Adding : Querying),
|
||||
mEnding(false),
|
||||
mEndWhenDone(false),
|
||||
mUserRefresh(false),
|
||||
mRegistrationTime(mDialogSet.mUserProfile->getDefaultRegistrationTime()),
|
||||
mExpires(0),
|
||||
mRefreshTime(0),
|
||||
mQueuedState(None),
|
||||
mQueuedRequest(new SipMessage),
|
||||
mCustomHeader(false)
|
||||
mQueuedRequest(new SipMessage)
|
||||
{
|
||||
InstanceCounter.increment();
|
||||
// If no Contacts header, this is a query
|
||||
if (mLastRequest->exists(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) &&
|
||||
mLastRequest->header(h_Expires).isWellFormed())
|
||||
|
|
@ -67,7 +73,6 @@ ClientRegistration::~ClientRegistration()
|
|||
|
||||
// !dcm! Will not interact well with multiple registrations from the same AOR
|
||||
mDialogSet.mUserProfile->setServiceRoute(NameAddrs());
|
||||
InstanceCounter.decrement();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -100,7 +105,7 @@ ClientRegistration::tryModification(ClientRegistration::State state)
|
|||
}
|
||||
}
|
||||
|
||||
assert(mQueuedState == None);
|
||||
resip_assert(mQueuedState == None);
|
||||
mState = state;
|
||||
|
||||
return mLastRequest;
|
||||
|
|
@ -117,8 +122,6 @@ ClientRegistration::addBinding(const NameAddr& contact, UInt32 registrationTime)
|
|||
mRegistrationTime = registrationTime;
|
||||
next->header(h_Expires).value() = mRegistrationTime;
|
||||
next->header(h_CSeq).sequence()++;
|
||||
updateWithCustomHeader(next);
|
||||
|
||||
// caller prefs
|
||||
|
||||
if (mQueuedState == None)
|
||||
|
|
@ -145,7 +148,6 @@ ClientRegistration::removeBinding(const NameAddr& contact)
|
|||
next->header(h_Contacts).push_back(*i);
|
||||
next->header(h_Expires).value() = 0;
|
||||
next->header(h_CSeq).sequence()++;
|
||||
updateWithCustomHeader(next);
|
||||
|
||||
if (mQueuedState == None)
|
||||
{
|
||||
|
|
@ -182,7 +184,7 @@ ClientRegistration::removeAll(bool stopRegisteringWhenDone)
|
|||
next->header(h_Expires).value() = 0;
|
||||
next->header(h_CSeq).sequence()++;
|
||||
mEndWhenDone = stopRegisteringWhenDone;
|
||||
updateWithCustomHeader(next);
|
||||
|
||||
if (mQueuedState == None)
|
||||
{
|
||||
send(next);
|
||||
|
|
@ -226,6 +228,13 @@ ClientRegistration::removeMyBindings(bool stopRegisteringWhenDone)
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -233,15 +242,18 @@ ClientRegistration::removeMyBindings(bool stopRegisteringWhenDone)
|
|||
class ClientRegistrationRemoveMyBindings : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientRegistrationRemoveMyBindings(ClientRegistration& clientRegistration, bool stopRegisteringWhenDone)
|
||||
: mClientRegistration(clientRegistration),
|
||||
ClientRegistrationRemoveMyBindings(const ClientRegistrationHandle& clientRegistrationHandle, bool stopRegisteringWhenDone)
|
||||
: mClientRegistrationHandle(clientRegistrationHandle),
|
||||
mStopRegisteringWhenDone(stopRegisteringWhenDone)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientRegistration.removeMyBindings(mStopRegisteringWhenDone);
|
||||
if(mClientRegistrationHandle.isValid())
|
||||
{
|
||||
mClientRegistrationHandle->removeMyBindings(mStopRegisteringWhenDone);
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -249,14 +261,14 @@ public:
|
|||
return strm << "ClientRegistrationRemoveMyBindings";
|
||||
}
|
||||
private:
|
||||
ClientRegistration& mClientRegistration;
|
||||
ClientRegistrationHandle mClientRegistrationHandle;
|
||||
bool mStopRegisteringWhenDone;
|
||||
};
|
||||
|
||||
void
|
||||
ClientRegistration::removeMyBindingsCommand(bool stopRegisteringWhenDone)
|
||||
{
|
||||
mDum.post(new ClientRegistrationRemoveMyBindings(*this, stopRegisteringWhenDone));
|
||||
mDum.post(new ClientRegistrationRemoveMyBindings(getHandle(), stopRegisteringWhenDone));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -277,7 +289,7 @@ ClientRegistration::requestRefresh(UInt32 expires)
|
|||
void
|
||||
ClientRegistration::internalRequestRefresh(UInt32 expires)
|
||||
{
|
||||
if(mState == RetryAdding && mState == RetryRefreshing)
|
||||
if(mState == RetryAdding || mState == RetryRefreshing)
|
||||
{
|
||||
// disable retry time and try refresh immediately
|
||||
++mTimerSeq;
|
||||
|
|
@ -288,14 +300,19 @@ ClientRegistration::internalRequestRefresh(UInt32 expires)
|
|||
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);
|
||||
|
||||
mState = Refreshing;
|
||||
mLastRequest->header(h_CSeq).sequence()++;
|
||||
mLastRequest->header(h_Contacts)=mMyContacts;
|
||||
|
||||
updateWithCustomHeader(mLastRequest);
|
||||
|
||||
if(expires > 0)
|
||||
{
|
||||
mRegistrationTime = expires;
|
||||
|
|
@ -320,30 +337,41 @@ ClientRegistration::allContacts()
|
|||
UInt32
|
||||
ClientRegistration::whenExpires() const
|
||||
{
|
||||
// !cj! - TODO - I'm suspisious these time are getting confused on what units they are in
|
||||
UInt64 now = Timer::getTimeSecs();
|
||||
UInt64 ret = mExpires - now;
|
||||
return (UInt32)ret;
|
||||
if(mExpires > now)
|
||||
{
|
||||
return (UInt32)(mExpires - now);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientRegistration::end()
|
||||
{
|
||||
if(!mEnding)
|
||||
{
|
||||
mEnding = true;
|
||||
removeMyBindings(true);
|
||||
}
|
||||
}
|
||||
|
||||
class ClientRegistrationEndCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientRegistrationEndCommand(ClientRegistration& clientRegistration)
|
||||
: mClientRegistration(clientRegistration)
|
||||
ClientRegistrationEndCommand(const ClientRegistrationHandle& clientRegistrationHandle)
|
||||
: mClientRegistrationHandle(clientRegistrationHandle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientRegistration.end();
|
||||
if(mClientRegistrationHandle.isValid())
|
||||
{
|
||||
mClientRegistrationHandle->end();
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -351,13 +379,13 @@ public:
|
|||
return strm << "ClientRegistrationEndCommand";
|
||||
}
|
||||
private:
|
||||
ClientRegistration& mClientRegistration;
|
||||
ClientRegistrationHandle mClientRegistrationHandle;
|
||||
};
|
||||
|
||||
void
|
||||
ClientRegistration::endCommand()
|
||||
{
|
||||
mDum.post(new ClientRegistrationEndCommand(*this));
|
||||
mDum.post(new ClientRegistrationEndCommand(getHandle()));
|
||||
}
|
||||
|
||||
EncodeStream&
|
||||
|
|
@ -373,7 +401,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
|
|||
try
|
||||
{
|
||||
// !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();
|
||||
bool nextHopSupportsOutbound = false;
|
||||
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(receivedTransport == Symbols::TCP ||
|
||||
receivedTransport == Symbols::TLS ||
|
||||
receivedTransport == Symbols::SCTP)
|
||||
if(isReliable(receivedTransport))
|
||||
{
|
||||
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.
|
||||
|
||||
// make timers to re-register
|
||||
UInt64 nowSecs = Timer::getTimeSecs();
|
||||
UInt32 expiry = calculateExpiry(msg);
|
||||
mExpires = nowSecs + expiry;
|
||||
if(msg.exists(h_Contacts))
|
||||
{
|
||||
mAllContacts = msg.header(h_Contacts);
|
||||
|
|
@ -497,10 +526,10 @@ ClientRegistration::dispatch(const SipMessage& msg)
|
|||
|
||||
if (expiry != 0 && expiry != UINT_MAX)
|
||||
{
|
||||
if(expiry>=7)
|
||||
if(expiry >= UnreasonablyLowExpirationThreshold)
|
||||
{
|
||||
int exp = Helper::aBitSmallerThan(expiry);
|
||||
mExpires = exp + Timer::getTimeSecs();
|
||||
mRefreshTime = exp + nowSecs;
|
||||
mDum.addTimer(DumTimeout::Registration,
|
||||
exp,
|
||||
getBaseHandle(),
|
||||
|
|
@ -571,6 +600,13 @@ ClientRegistration::dispatch(const SipMessage& msg)
|
|||
|
||||
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);
|
||||
mState = mQueuedState;
|
||||
mQueuedState = None;
|
||||
|
|
@ -595,7 +631,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
|
|||
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);
|
||||
|
||||
|
|
@ -615,7 +651,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
|
|||
else
|
||||
{
|
||||
DebugLog(<< "Application requested delayed retry on 408 or internal 503: " << retry);
|
||||
mExpires = 0;
|
||||
mRefreshTime = 0;
|
||||
switch(mState)
|
||||
{
|
||||
case Adding:
|
||||
|
|
@ -625,7 +661,7 @@ ClientRegistration::dispatch(const SipMessage& msg)
|
|||
mState = RetryRefreshing;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
resip_assert(false);
|
||||
break;
|
||||
}
|
||||
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));
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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
|
||||
// leave our requested expiry alone, this code ends up being pretty quick,
|
||||
// especially if there aren't contacts from other endpoints laying around.
|
||||
if(c->isWellFormed() &&
|
||||
c->exists(p_expires) &&
|
||||
c->param(p_expires) < expiry &&
|
||||
if(c->isWellFormed() && c->exists(p_expires))
|
||||
{
|
||||
unsigned long contactExpires = c->param(p_expires);
|
||||
if((contactExpires < expiry ||
|
||||
contactExpires < reasonableExpiry) &&
|
||||
contactIsMine(*c))
|
||||
{
|
||||
expiry=c->param(p_expires);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -863,7 +934,7 @@ ClientRegistration::checkProfileRetry(const SipMessage& msg)
|
|||
// Use retry interval from error response
|
||||
retryInterval = msg.header(h_RetryAfter).value();
|
||||
}
|
||||
mExpires = 0;
|
||||
mRefreshTime = 0;
|
||||
switch(mState)
|
||||
{
|
||||
case Adding:
|
||||
|
|
@ -873,7 +944,7 @@ ClientRegistration::checkProfileRetry(const SipMessage& msg)
|
|||
mState = RetryRefreshing;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
resip_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -916,7 +987,7 @@ ClientRegistration::dispatch(const DumTimeout& timer)
|
|||
mState = Refreshing;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
resip_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -943,31 +1014,6 @@ ClientRegistration::flowTerminated()
|
|||
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
|
||||
|
|
@ -1019,4 +1065,3 @@ ClientRegistration::updateWithCustomHeader(SharedPtr<SipMessage> msg)
|
|||
* <http://www.vovida.org/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,11 @@ namespace resip
|
|||
|
||||
class SipMessage;
|
||||
class BaseCreator;
|
||||
class AtomicCounter;
|
||||
|
||||
//!dcm! -- shutdown/deletion API -- end?
|
||||
class ClientRegistration: public NonDialogUsage
|
||||
{
|
||||
public:
|
||||
static AtomicCounter InstanceCounter;
|
||||
|
||||
//ClientRegistration(DialogUsageManager& dum, DialogSet& dialog,
|
||||
//SipMessage& req);
|
||||
ClientRegistration(DialogUsageManager& dum, DialogSet& dialog, SharedPtr<SipMessage> req);
|
||||
|
|
@ -42,7 +39,6 @@ class ClientRegistration: public NonDialogUsage
|
|||
when complete */
|
||||
void removeMyBindings(bool stopRegisteringWhenDone=false);
|
||||
|
||||
|
||||
/** Request a manual refresh of the registration. If 0 then default to using original
|
||||
expires value (to remove use removeXXX() instead) */
|
||||
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 */
|
||||
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;
|
||||
|
||||
/** Calls removeMyBindings and ends usage when complete */
|
||||
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
|
||||
*/
|
||||
|
|
@ -73,8 +72,6 @@ class ClientRegistration: public NonDialogUsage
|
|||
virtual void dispatch(const DumTimeout& timer);
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -102,7 +99,6 @@ class ClientRegistration: public NonDialogUsage
|
|||
bool contactIsMine(const NameAddr& contact) const;
|
||||
bool rinstanceIsMine(const Data& rinstance) const;
|
||||
bool searchByUri(const Uri& cUri) const;
|
||||
void updateWithCustomHeader(SharedPtr<SipMessage> msg);
|
||||
|
||||
friend class DialogSet;
|
||||
void flowTerminated();
|
||||
|
|
@ -114,14 +110,15 @@ class ClientRegistration: public NonDialogUsage
|
|||
unsigned int mTimerSeq; // expected timer seq (all < are stale)
|
||||
|
||||
State mState;
|
||||
bool mEnding;
|
||||
bool mEndWhenDone;
|
||||
bool mUserRefresh;
|
||||
UInt32 mRegistrationTime;
|
||||
UInt64 mExpires;
|
||||
UInt64 mRefreshTime;
|
||||
State mQueuedState;
|
||||
SharedPtr<SipMessage> mQueuedRequest;
|
||||
resip::Data mCustomHeaderName, mCustomHeaderValue;
|
||||
bool mCustomHeader;
|
||||
|
||||
NetworkAssociation mNetworkAssociation;
|
||||
|
||||
// disabled
|
||||
|
|
|
|||
|
|
@ -18,27 +18,22 @@ using namespace resip;
|
|||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
||||
|
||||
ClientSubscription::ClientSubscription(DialogUsageManager& dum, Dialog& dialog,
|
||||
const SipMessage& request, UInt32 defaultSubExpiration)
|
||||
ClientSubscription::ClientSubscription(DialogUsageManager& dum, Dialog& dialog, const SipMessage& request)
|
||||
: BaseSubscription(dum, dialog, request),
|
||||
mOnNewSubscriptionCalled(mEventType == "refer"), // don't call onNewSubscription for Refer subscriptions
|
||||
mEnded(false),
|
||||
mNextRefreshSecs(0),
|
||||
mLastSubSecs(Timer::getTimeSecs()), // Not exactly, but more forgiving
|
||||
mDefaultExpires(defaultSubExpiration),
|
||||
mSubscribed(false),
|
||||
mRefreshing(false),
|
||||
mHaveQueuedRefresh(false),
|
||||
mQueuedRefreshInterval(-1),
|
||||
mLargestNotifyCSeq(0)
|
||||
{
|
||||
DebugLog (<< "ClientSubscription::ClientSubscription from " << request.brief());
|
||||
DebugLog (<< "ClientSubscription::ClientSubscription from " << request.brief() << ": " << this);
|
||||
if(request.method() == SUBSCRIBE)
|
||||
{
|
||||
*mLastRequest = request;
|
||||
if (defaultSubExpiration > 0)
|
||||
{
|
||||
mLastRequest->header(h_Expires).value() = defaultSubExpiration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -59,6 +54,7 @@ ClientSubscription::~ClientSubscription()
|
|||
}
|
||||
|
||||
clearDustbin();
|
||||
DebugLog(<< "ClientSubscription::~ClientSubscription: " << this);
|
||||
}
|
||||
|
||||
ClientSubscriptionHandle
|
||||
|
|
@ -73,37 +69,46 @@ ClientSubscription::dispatch(const SipMessage& msg)
|
|||
DebugLog (<< "ClientSubscription::dispatch " << msg.brief());
|
||||
|
||||
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
|
||||
clearDustbin();
|
||||
|
||||
// asserts are checks the correctness of Dialog::dispatch
|
||||
if (msg.isRequest() )
|
||||
{
|
||||
assert( msg.header(h_RequestLine).getMethod() == NOTIFY );
|
||||
resip_assert( msg.header(h_RequestLine).getMethod() == NOTIFY );
|
||||
mRefreshing = false;
|
||||
mSubscribed = true; // If we got a NOTIFY then we are subscribed
|
||||
|
||||
// !dlb! 481 NOTIFY iff state is dead?
|
||||
|
||||
//!dcm! -- heavy, should just store enough information to make response
|
||||
//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())
|
||||
{
|
||||
InfoLog (<< "[ClientSubscription] " << mLastRequest->header(h_To));
|
||||
if (msg.exists(h_Contacts))
|
||||
{
|
||||
mDialog.mRemoteTarget = msg.header(h_Contacts).front();
|
||||
}
|
||||
|
||||
handler->onNewSubscription(getHandle(), msg);
|
||||
mOnNewSubscriptionCalled = true;
|
||||
InfoLog(<< "[ClientSubscription] " << mLastRequest->header(h_To));
|
||||
handler->onNewSubscription(getHandle(), msg);
|
||||
if (mEnded) return;
|
||||
}
|
||||
|
||||
bool outOfOrder = mLargestNotifyCSeq > msg.header(h_CSeq).sequence();
|
||||
if (!outOfOrder)
|
||||
{
|
||||
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
|
||||
{
|
||||
|
|
@ -133,13 +138,14 @@ void
|
|||
ClientSubscription::processResponse(const SipMessage& msg)
|
||||
{
|
||||
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
|
||||
mRefreshing = false;
|
||||
int statusCode = msg.header(h_StatusLine).statusCode();
|
||||
|
||||
if (statusCode >= 200 && statusCode <300)
|
||||
{
|
||||
mSubscribed = true; // If we got a 200 response then we are subscribed
|
||||
if (msg.exists(h_Expires))
|
||||
{
|
||||
// grab the expires from the 2xx in case there is not one on the NOTIFY .mjf.
|
||||
|
|
@ -152,23 +158,31 @@ ClientSubscription::processResponse(const SipMessage& msg)
|
|||
}
|
||||
|
||||
if(!mOnNewSubscriptionCalled)
|
||||
{
|
||||
mOnNewSubscriptionCalled = true;
|
||||
handler->onNewSubscription(getHandle(), msg);
|
||||
if (!mEnded)
|
||||
{
|
||||
// Timer for initial NOTIFY; since we don't know when the initial
|
||||
// SUBSRIBE is sent, we have to set the timer when the 200 comes in, if
|
||||
// it beat the NOTIFY.
|
||||
mDum.addTimer(DumTimeout::WaitForNotify,
|
||||
64*Timer::T1,
|
||||
// SUBSCRIBE is sent, we have to set the timer when the 200 comes in, if
|
||||
// it beats the NOTIFY.
|
||||
mDum.addTimerMs(DumTimeout::WaitForNotify,
|
||||
64 * Timer::T1,
|
||||
getBaseHandle(),
|
||||
++mTimerSeq);
|
||||
}
|
||||
|
||||
}
|
||||
else if (!mEnded)
|
||||
{
|
||||
sendQueuedRefreshRequest();
|
||||
}
|
||||
}
|
||||
else if (!mEnded &&
|
||||
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)
|
||||
{
|
||||
InfoLog (<< "Received 481 to SUBSCRIBE, reSUBSCRIBEing (presence server probably restarted) "
|
||||
InfoLog (<< "Received 481 to SUBSCRIBE, reSUBSCRIBEing (subscription server probably restarted) "
|
||||
<< mLastRequest->header(h_To));
|
||||
|
||||
reSubscribe(); // will delete "this"
|
||||
|
|
@ -176,7 +190,7 @@ ClientSubscription::processResponse(const SipMessage& msg)
|
|||
}
|
||||
else if (!mEnded &&
|
||||
(statusCode == 408 ||
|
||||
(statusCode == 503 && msg.getReceivedTransport() == 0) ||
|
||||
(statusCode == 503 && !msg.isFromWire()) ||
|
||||
((statusCode == 413 ||
|
||||
statusCode == 480 ||
|
||||
statusCode == 486 ||
|
||||
|
|
@ -263,7 +277,7 @@ ClientSubscription::processNextNotify()
|
|||
|
||||
QueuedNotify* qn = mQueuedNotifies.front();
|
||||
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
|
||||
unsigned long refreshInterval = 0;
|
||||
bool setRefreshTimer=false;
|
||||
|
|
@ -279,18 +293,13 @@ ClientSubscription::processNextNotify()
|
|||
{
|
||||
expires = mLastRequest->header(h_Expires).value();
|
||||
}
|
||||
else if (mDefaultExpires)
|
||||
else
|
||||
{
|
||||
/* if we haven't gotten an expires value from:
|
||||
1. the subscription state from this notify
|
||||
2. the last request
|
||||
then use the default expires (meaning it came from the 2xx in response
|
||||
to the initial SUBSCRIBE). .mjf.
|
||||
2. the last request (may have came from the 2xx in response)
|
||||
then use some reasonable value.
|
||||
*/
|
||||
expires = mDefaultExpires;
|
||||
}
|
||||
else
|
||||
{
|
||||
expires = 3600;
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +395,7 @@ ClientSubscription::processNextNotify()
|
|||
}
|
||||
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"))
|
||||
{
|
||||
// Unexpected timeout of some sort. Look closer.
|
||||
|
|
@ -396,8 +405,7 @@ ClientSubscription::processNextNotify()
|
|||
// NOT loop here?
|
||||
if(Helper::aBitSmallerThan((signed long)(Timer::getTimeSecs() - mLastSubSecs)) < 2)
|
||||
{
|
||||
acceptUpdate(200, "I just sent a refresh, what more do you want "
|
||||
"from me?");
|
||||
acceptUpdate(200, "I just sent a refresh, what more do you want from me?");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -406,8 +414,7 @@ ClientSubscription::processNextNotify()
|
|||
}
|
||||
else
|
||||
{
|
||||
acceptUpdate(200, "You terminated my subscription early! What "
|
||||
"gives?");
|
||||
acceptUpdate(200, "You terminated my subscription early! What gives?");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -422,6 +429,11 @@ ClientSubscription::processNextNotify()
|
|||
}
|
||||
else if (!mEnded)
|
||||
{
|
||||
if (setRefreshTimer)
|
||||
{
|
||||
scheduleRefresh(refreshInterval);
|
||||
}
|
||||
|
||||
handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder());
|
||||
}
|
||||
else if (mEnded)
|
||||
|
|
@ -451,8 +463,9 @@ ClientSubscription::dispatch(const DumTimeout& timer)
|
|||
if(timer.type() == DumTimeout::WaitForNotify)
|
||||
{
|
||||
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
|
||||
handler->onTerminated(getHandle(),0);
|
||||
delete this;
|
||||
|
|
@ -463,6 +476,9 @@ ClientSubscription::dispatch(const DumTimeout& timer)
|
|||
handler->onNotifyNotReceived(getHandle());
|
||||
}
|
||||
else if (timer.type() == DumTimeout::SubscriptionRetry)
|
||||
{
|
||||
// Ensure someone hasn't called end() while we were waiting
|
||||
if (!mEnded)
|
||||
{
|
||||
// this indicates that the ClientSubscription was created by a 408
|
||||
if (mOnNewSubscriptionCalled)
|
||||
|
|
@ -477,6 +493,7 @@ ClientSubscription::dispatch(const DumTimeout& timer)
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(timer.type() == DumTimeout::Subscription)
|
||||
{
|
||||
requestRefresh();
|
||||
|
|
@ -515,7 +532,7 @@ ClientSubscription::requestRefresh(UInt32 expires)
|
|||
mLastSubSecs = Timer::getTimeSecs();
|
||||
send(mLastRequest);
|
||||
// Timer for reSUB NOTIFY.
|
||||
mDum.addTimer(DumTimeout::WaitForNotify,
|
||||
mDum.addTimerMs(DumTimeout::WaitForNotify,
|
||||
64*Timer::T1,
|
||||
getBaseHandle(),
|
||||
++mTimerSeq);
|
||||
|
|
@ -525,15 +542,18 @@ ClientSubscription::requestRefresh(UInt32 expires)
|
|||
class ClientSubscriptionRefreshCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientSubscriptionRefreshCommand(ClientSubscription& clientSubscription, UInt32 expires)
|
||||
: mClientSubscription(clientSubscription),
|
||||
ClientSubscriptionRefreshCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, UInt32 expires)
|
||||
: mClientSubscriptionHandle(clientSubscriptionHandle),
|
||||
mExpires(expires)
|
||||
{
|
||||
|
||||
}
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientSubscription.requestRefresh(mExpires);
|
||||
if(mClientSubscriptionHandle.isValid())
|
||||
{
|
||||
mClientSubscriptionHandle->requestRefresh(mExpires);
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -541,14 +561,14 @@ public:
|
|||
return strm << "ClientSubscriptionRefreshCommand";
|
||||
}
|
||||
private:
|
||||
ClientSubscription& mClientSubscription;
|
||||
ClientSubscriptionHandle mClientSubscriptionHandle;
|
||||
UInt32 mExpires;
|
||||
};
|
||||
|
||||
void
|
||||
ClientSubscription::requestRefreshCommand(UInt32 expires)
|
||||
{
|
||||
mDum.post(new ClientSubscriptionRefreshCommand(*this, expires));
|
||||
mDum.post(new ClientSubscriptionRefreshCommand(getHandle(), expires));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -560,41 +580,49 @@ ClientSubscription::end()
|
|||
void
|
||||
ClientSubscription::end(bool immediate)
|
||||
{
|
||||
InfoLog (<< "End subscription: " << mLastRequest->header(h_RequestLine).uri());
|
||||
|
||||
if (!mEnded)
|
||||
{
|
||||
if(!immediate)
|
||||
if(!immediate && mSubscribed)
|
||||
{
|
||||
InfoLog(<< "End subscription: " << mLastRequest->header(h_RequestLine).uri());
|
||||
mDialog.makeRequest(*mLastRequest, SUBSCRIBE);
|
||||
mLastRequest->header(h_Expires).value() = 0;
|
||||
mEnded = true;
|
||||
send(mLastRequest);
|
||||
// Timer for NOTIFY terminated
|
||||
mDum.addTimer(DumTimeout::WaitForNotify,
|
||||
mDum.addTimerMs(DumTimeout::WaitForNotify,
|
||||
64*Timer::T1,
|
||||
getBaseHandle(),
|
||||
++mTimerSeq);
|
||||
}
|
||||
else
|
||||
{
|
||||
InfoLog(<< "End subscription immediately: " << mLastRequest->header(h_RequestLine).uri());
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InfoLog(<< "End subscription called but already ended: " << mLastRequest->header(h_RequestLine).uri());
|
||||
}
|
||||
}
|
||||
|
||||
class ClientSubscriptionEndCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientSubscriptionEndCommand(ClientSubscription& clientSubscription, bool immediate)
|
||||
:mClientSubscription(clientSubscription), mImmediate(immediate)
|
||||
ClientSubscriptionEndCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, bool immediate)
|
||||
:mClientSubscriptionHandle(clientSubscriptionHandle), mImmediate(immediate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientSubscription.end(mImmediate);
|
||||
if(mClientSubscriptionHandle.isValid())
|
||||
{
|
||||
mClientSubscriptionHandle->end(mImmediate);
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -602,20 +630,20 @@ public:
|
|||
return strm << "ClientSubscriptionEndCommand";
|
||||
}
|
||||
private:
|
||||
ClientSubscription& mClientSubscription;
|
||||
ClientSubscriptionHandle mClientSubscriptionHandle;
|
||||
bool mImmediate;
|
||||
};
|
||||
|
||||
void
|
||||
ClientSubscription::endCommand(bool immediate)
|
||||
{
|
||||
mDum.post(new ClientSubscriptionEndCommand(*this, immediate));
|
||||
mDum.post(new ClientSubscriptionEndCommand(getHandle(), immediate));
|
||||
}
|
||||
|
||||
void
|
||||
ClientSubscription::acceptUpdate(int statusCode, const char* reason)
|
||||
{
|
||||
assert(!mQueuedNotifies.empty());
|
||||
resip_assert(!mQueuedNotifies.empty());
|
||||
if (mQueuedNotifies.empty())
|
||||
{
|
||||
InfoLog(<< "No queued notify to accept");
|
||||
|
|
@ -636,8 +664,8 @@ ClientSubscription::acceptUpdate(int statusCode, const char* reason)
|
|||
class ClientSubscriptionAcceptUpdateCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientSubscriptionAcceptUpdateCommand(ClientSubscription& clientSubscription, int statusCode, const char* reason)
|
||||
: mClientSubscription(clientSubscription),
|
||||
ClientSubscriptionAcceptUpdateCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, int statusCode, const char* reason)
|
||||
: mClientSubscriptionHandle(clientSubscriptionHandle),
|
||||
mStatusCode(statusCode),
|
||||
mReason(reason ? Data(reason) : Data::Empty)
|
||||
{
|
||||
|
|
@ -646,7 +674,10 @@ public:
|
|||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientSubscription.acceptUpdate(mStatusCode, mReason.c_str());
|
||||
if(mClientSubscriptionHandle.isValid())
|
||||
{
|
||||
mClientSubscriptionHandle->acceptUpdate(mStatusCode, mReason.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -654,7 +685,7 @@ public:
|
|||
return strm << "ClientSubscriptionAcceptUpdateCommand";
|
||||
}
|
||||
private:
|
||||
ClientSubscription& mClientSubscription;
|
||||
ClientSubscriptionHandle mClientSubscriptionHandle;
|
||||
int mStatusCode;
|
||||
Data mReason;
|
||||
};
|
||||
|
|
@ -662,7 +693,7 @@ private:
|
|||
void
|
||||
ClientSubscription::acceptUpdateCommand(int statusCode, const char* reason)
|
||||
{
|
||||
mDum.post(new ClientSubscriptionAcceptUpdateCommand(*this, statusCode, reason));
|
||||
mDum.post(new ClientSubscriptionAcceptUpdateCommand(getHandle(), statusCode, reason));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -698,8 +729,8 @@ void
|
|||
ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase)
|
||||
{
|
||||
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
assert(!mQueuedNotifies.empty());
|
||||
resip_assert(handler);
|
||||
resip_assert(!mQueuedNotifies.empty());
|
||||
if (mQueuedNotifies.empty())
|
||||
{
|
||||
InfoLog(<< "No queued notify to reject");
|
||||
|
|
@ -729,9 +760,15 @@ ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase)
|
|||
break;
|
||||
case Helper::DialogTermination: //?dcm? -- throw or destroy this?
|
||||
case Helper::UsageTermination:
|
||||
// If we are already "ended" then we are likely here because we are rejecting an inbound
|
||||
// NOTIFY with a 481 that crossed with our un-subscribe request (due to end()). In this case we don't
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -739,8 +776,8 @@ ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase)
|
|||
class ClientSubscriptionRejectUpdateCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ClientSubscriptionRejectUpdateCommand(ClientSubscription& clientSubscription, int statusCode, const Data& reasonPhrase)
|
||||
: mClientSubscription(clientSubscription),
|
||||
ClientSubscriptionRejectUpdateCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, int statusCode, const Data& reasonPhrase)
|
||||
: mClientSubscriptionHandle(clientSubscriptionHandle),
|
||||
mStatusCode(statusCode),
|
||||
mReasonPhrase(reasonPhrase)
|
||||
{
|
||||
|
|
@ -748,7 +785,10 @@ public:
|
|||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mClientSubscription.rejectUpdate(mStatusCode, mReasonPhrase);
|
||||
if(mClientSubscriptionHandle.isValid())
|
||||
{
|
||||
mClientSubscriptionHandle->rejectUpdate(mStatusCode, mReasonPhrase);
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -756,7 +796,7 @@ public:
|
|||
return strm << "ClientSubscriptionRejectUpdateCommand";
|
||||
}
|
||||
private:
|
||||
ClientSubscription& mClientSubscription;
|
||||
ClientSubscriptionHandle mClientSubscriptionHandle;
|
||||
int mStatusCode;
|
||||
Data mReasonPhrase;
|
||||
};
|
||||
|
|
@ -764,16 +804,7 @@ private:
|
|||
void
|
||||
ClientSubscription::rejectUpdateCommand(int statusCode, const Data& reasonPhrase)
|
||||
{
|
||||
mDum.post(new ClientSubscriptionRejectUpdateCommand(*this, statusCode, reasonPhrase));
|
||||
}
|
||||
|
||||
void ClientSubscription::dialogDestroyed(const SipMessage& msg)
|
||||
{
|
||||
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
mEnded = true;
|
||||
handler->onTerminated(getHandle(), &msg);
|
||||
delete this;
|
||||
mDum.post(new ClientSubscriptionRejectUpdateCommand(getHandle(), statusCode, reasonPhrase));
|
||||
}
|
||||
|
||||
EncodeStream&
|
||||
|
|
@ -787,7 +818,7 @@ void
|
|||
ClientSubscription::onReadyToSend(SipMessage& msg)
|
||||
{
|
||||
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
handler->onReadyToSend(getHandle(), msg);
|
||||
}
|
||||
|
||||
|
|
@ -796,14 +827,14 @@ ClientSubscription::flowTerminated()
|
|||
{
|
||||
// notify handler
|
||||
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
handler->onFlowTerminated(getHandle());
|
||||
}
|
||||
|
||||
void
|
||||
ClientSubscription::sendQueuedRefreshRequest()
|
||||
{
|
||||
assert(!mRefreshing);
|
||||
resip_assert(!mRefreshing);
|
||||
|
||||
if (mHaveQueuedRefresh)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ class DialogUsageManager;
|
|||
class ClientSubscription: public BaseSubscription
|
||||
{
|
||||
public:
|
||||
ClientSubscription(DialogUsageManager& dum, Dialog& dialog,
|
||||
const SipMessage& request, UInt32 defaultSubExpiration);
|
||||
ClientSubscription(DialogUsageManager& dum, Dialog& dialog, const SipMessage& request);
|
||||
|
||||
typedef Handle<ClientSubscription> ClientSubscriptionHandle;
|
||||
ClientSubscriptionHandle getHandle();
|
||||
|
|
@ -39,7 +38,6 @@ class ClientSubscription: public BaseSubscription
|
|||
|
||||
protected:
|
||||
virtual ~ClientSubscription();
|
||||
virtual void dialogDestroyed(const SipMessage& msg);
|
||||
virtual void onReadyToSend(SipMessage& msg);
|
||||
virtual void send(SharedPtr<SipMessage> msg);
|
||||
virtual void flowTerminated();
|
||||
|
|
@ -69,15 +67,12 @@ class ClientSubscription: public BaseSubscription
|
|||
Dustbin mDustbin;
|
||||
|
||||
bool mOnNewSubscriptionCalled;
|
||||
//SipMessage mLastNotify;
|
||||
bool mEnded;
|
||||
// .bwc. This is when our next reSUB is scheduled to happen.
|
||||
UInt64 mNextRefreshSecs;
|
||||
UInt64 mLastSubSecs;
|
||||
|
||||
// this is the expires value from the 2xx coming from the SUB message
|
||||
UInt32 mDefaultExpires;
|
||||
|
||||
bool mSubscribed;
|
||||
bool mRefreshing;
|
||||
bool mHaveQueuedRefresh;
|
||||
int mQueuedRefreshInterval;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
#include <sstream>
|
||||
|
||||
#include "resip/dum/ContactInstanceRecord.hxx"
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "rutil/Timer.hxx"
|
||||
#include "resip/stack/SipMessage.hxx"
|
||||
#include "rutil/XMLCursor.hxx"
|
||||
#include "rutil/Timer.hxx"
|
||||
|
||||
using namespace resip;
|
||||
|
||||
|
|
@ -11,10 +14,58 @@ ContactInstanceRecord::ContactInstanceRecord() :
|
|||
mRegId(0),
|
||||
mSyncContact(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
|
||||
ContactInstanceRecord::operator==(const ContactInstanceRecord& rhs) const
|
||||
{
|
||||
|
|
@ -26,6 +77,13 @@ ContactInstanceRecord::operator==(const ContactInstanceRecord& rhs) const
|
|||
return mInstance == rhs.mInstance &&
|
||||
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
|
||||
{
|
||||
// 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::makeRemoveDelta(const NameAddr& contact)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
namespace resip
|
||||
{
|
||||
|
||||
class XMLCursor;
|
||||
|
||||
static const UInt64 NeverExpire = 0xFFFFFFFFFFFFFFFFULL;
|
||||
|
||||
/** A single contact record, bound to an Aor during registration.
|
||||
|
|
@ -20,11 +23,23 @@ class ContactInstanceRecord
|
|||
{
|
||||
public:
|
||||
ContactInstanceRecord();
|
||||
ContactInstanceRecord(const ContactInstanceRecord& rhs);
|
||||
ContactInstanceRecord& operator=(const ContactInstanceRecord& rhs);
|
||||
virtual ~ContactInstanceRecord();
|
||||
|
||||
static ContactInstanceRecord makeRemoveDelta(const NameAddr& contact);
|
||||
static ContactInstanceRecord makeUpdateDelta(const NameAddr& contact,
|
||||
UInt64 expires, // absolute time in secs
|
||||
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
|
||||
UInt64 mRegExpires; // in seconds
|
||||
UInt64 mLastUpdated; // in seconds
|
||||
|
|
@ -33,6 +48,7 @@ class ContactInstanceRecord
|
|||
NameAddrs mSipPath; // Value of SIP Path header from the request
|
||||
Data mInstance; // From the instance parameter; usually a UUID URI
|
||||
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 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
|
||||
|
|
@ -40,8 +56,10 @@ class ContactInstanceRecord
|
|||
// Data mServerSessionId;// if there is no SIP Path header, the connection/session identifier
|
||||
// Uri gruu; (GRUU is currently derived)
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
typedef std::list<ContactInstanceRecord> ContactList;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#if !defined(RESIP_DEFAULTSERVERREFERHANDLER_HXX)
|
||||
#define RESIP__DEFAULTSERVERREFERHANDLER_HXX
|
||||
#define RESIP_DEFAULTSERVERREFERHANDLER_HXX
|
||||
|
||||
#include "resip/dum/SubscriptionHandler.hxx"
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "resip/dum/DialogSet.hxx"
|
||||
#include "resip/dum/Dialog.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@
|
|||
#include "resip/dum/ServerSubscription.hxx"
|
||||
#include "resip/dum/SubscriptionHandler.hxx"
|
||||
#include "resip/dum/UsageUseException.hxx"
|
||||
#include "rutil/ResipAssert.h"
|
||||
#include "rutil/Logger.hxx"
|
||||
#include "rutil/Inserter.hxx"
|
||||
#include "rutil/TransportType.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
|
@ -40,16 +42,15 @@ Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
|
|||
mLocalNameAddr(),
|
||||
mRemoteNameAddr(),
|
||||
mCallId(msg.header(h_CallID)),
|
||||
mDefaultSubExpiration(0),
|
||||
mAppDialog(0),
|
||||
mDestroying(false),
|
||||
mReUseDialogSet(false)
|
||||
{
|
||||
assert(msg.isExternal());
|
||||
resip_assert(msg.isExternal());
|
||||
|
||||
assert(msg.header(h_CSeq).method() != MESSAGE);
|
||||
assert(msg.header(h_CSeq).method() != REGISTER);
|
||||
assert(msg.header(h_CSeq).method() != PUBLISH);
|
||||
resip_assert(msg.header(h_CSeq).method() != MESSAGE);
|
||||
resip_assert(msg.header(h_CSeq).method() != REGISTER);
|
||||
resip_assert(msg.header(h_CSeq).method() != PUBLISH);
|
||||
|
||||
mNetworkAssociation.setDum(&dum);
|
||||
|
||||
|
|
@ -239,7 +240,7 @@ Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
|
|||
InfoLog(<< response);
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
|
@ -337,9 +338,9 @@ Dialog::getRouteSet() const
|
|||
void
|
||||
Dialog::cancel()
|
||||
{
|
||||
assert(mType == Invitation);
|
||||
resip_assert(mType == Invitation);
|
||||
ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
|
||||
assert (uac);
|
||||
resip_assert (uac);
|
||||
uac->cancel();
|
||||
}
|
||||
|
||||
|
|
@ -378,6 +379,8 @@ Dialog::handleTargetRefresh(const SipMessage& msg)
|
|||
{
|
||||
case INVITE:
|
||||
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))
|
||||
{
|
||||
//?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());
|
||||
|
||||
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;
|
||||
if(receivedTransport == Symbols::TCP ||
|
||||
receivedTransport == Symbols::TLS ||
|
||||
receivedTransport == Symbols::SCTP)
|
||||
if(isReliable(receivedTransport))
|
||||
{
|
||||
keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream();
|
||||
}
|
||||
|
|
@ -483,6 +485,17 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
mInviteSession->dispatch(request);
|
||||
}
|
||||
break;
|
||||
case PRACK:
|
||||
if (mInviteSession == 0)
|
||||
{
|
||||
InfoLog ( << "Spurious PRACK" );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mInviteSession->dispatch(request);
|
||||
}
|
||||
break;
|
||||
case ACK:
|
||||
case CANCEL:
|
||||
if (mInviteSession == 0)
|
||||
|
|
@ -552,7 +565,7 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
(request.exists(h_Requires) &&
|
||||
request.header(h_Requires).find(Token("norefersub"))))
|
||||
{
|
||||
assert(mInviteSession);
|
||||
resip_assert(mInviteSession);
|
||||
mInviteSession->referNoSub(msg);
|
||||
}
|
||||
else
|
||||
|
|
@ -622,7 +635,7 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -642,7 +655,7 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
{
|
||||
InfoLog( << "about to re-send request with digest credentials" << r->second->brief());
|
||||
|
||||
assert (r->second->isRequest());
|
||||
resip_assert (r->second->isRequest());
|
||||
|
||||
mLocalCSeq++;
|
||||
send(r->second);
|
||||
|
|
@ -664,11 +677,24 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
mRouteSet = response.header(h_RecordRoutes).reverse();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: This is code to facilitate Dialog recovery, and works in conjunction with the
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// !jf! should this only be for 2xx responses? !jf! Propose no as an
|
||||
// answer !dcm! what is he on?
|
||||
|
|
@ -700,6 +726,7 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
case INFO:
|
||||
case MESSAGE:
|
||||
case UPDATE:
|
||||
case PRACK:
|
||||
if (mInviteSession)
|
||||
{
|
||||
mInviteSession->dispatch(response);
|
||||
|
|
@ -733,39 +760,11 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
|
||||
case SUBSCRIBE:
|
||||
{
|
||||
int code = response.header(h_StatusLine).statusCode();
|
||||
ClientSubscription* client = findMatchingClientSub(response);
|
||||
if (client)
|
||||
{
|
||||
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
|
||||
{
|
||||
//!dcm! -- can't subscribe in an existing Dialog, this is all
|
||||
|
|
@ -792,9 +791,8 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
break;
|
||||
case NOTIFY:
|
||||
{
|
||||
//2xx responses are treated as retransmission quenchers(handled by
|
||||
//the stack). Failures are dispatched to all ServerSubsscriptions,
|
||||
//which may not be correct.
|
||||
//Failures are dispatched to all ServerSubsscriptions,
|
||||
//which may not be correct as per RFC 5057.
|
||||
|
||||
int code = msg.header(h_StatusLine).statusCode();
|
||||
if (code >= 300)
|
||||
|
|
@ -811,49 +809,20 @@ Dialog::dispatch(const SipMessage& msg)
|
|||
mDestroying = false;
|
||||
possiblyDie();
|
||||
}
|
||||
// ServerSubscription* server = findMatchingServerSub(response);
|
||||
// if (server)
|
||||
// {
|
||||
// server->dispatch(response);
|
||||
// }
|
||||
else if (code >= 200)
|
||||
{
|
||||
ServerSubscription* server = findMatchingServerSub(response);
|
||||
if (server)
|
||||
{
|
||||
server->dispatch(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
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
|
||||
Dialog::makeRequest(SipMessage& request, MethodTypes method)
|
||||
Dialog::makeRequest(SipMessage& request, MethodTypes method, bool incrementCSeq)
|
||||
{
|
||||
RequestLine rLine(method);
|
||||
|
||||
|
|
@ -1012,13 +981,16 @@ Dialog::makeRequest(SipMessage& request, MethodTypes method)
|
|||
}
|
||||
else
|
||||
{
|
||||
assert(request.exists(h_Vias));
|
||||
resip_assert(request.exists(h_Vias));
|
||||
}
|
||||
|
||||
//don't increment CSeq for ACK or CANCEL
|
||||
if (method != ACK && method != CANCEL)
|
||||
{
|
||||
request.header(h_CSeq).sequence() = ++mLocalCSeq;
|
||||
if(incrementCSeq)
|
||||
{
|
||||
setRequestNextCSeq(request);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1036,31 +1008,28 @@ Dialog::makeRequest(SipMessage& request, MethodTypes method)
|
|||
// If method is INVITE then advertise required headers
|
||||
if(method == INVITE || method == UPDATE)
|
||||
{
|
||||
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
|
||||
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
|
||||
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();
|
||||
// Add Advertised Capabilities
|
||||
mDum.setAdvertisedCapabilities(request, mDialogSet.mUserProfile);
|
||||
}
|
||||
|
||||
if (mDialogSet.mUserProfile->isAnonymous())
|
||||
{
|
||||
request.remove(h_Privacys);
|
||||
request.header(h_Privacys).push_back(PrivacyCategory(Symbols::id));
|
||||
}
|
||||
|
||||
DebugLog ( << "Dialog::makeRequest: " << std::endl << std::endl << request );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
|
||||
{
|
||||
assert( code >= 100 );
|
||||
resip_assert( code >= 100 );
|
||||
response.remove(h_Contacts);
|
||||
if (code < 300 && code > 100)
|
||||
{
|
||||
assert(request.isRequest());
|
||||
assert(request.header(h_RequestLine).getMethod() == INVITE ||
|
||||
resip_assert(request.isRequest());
|
||||
resip_assert(request.header(h_RequestLine).getMethod() == INVITE ||
|
||||
request.header(h_RequestLine).getMethod() == SUBSCRIBE ||
|
||||
request.header(h_RequestLine).getMethod() == BYE ||
|
||||
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() == INFO ||
|
||||
request.header(h_RequestLine).getMethod() == OPTIONS ||
|
||||
request.header(h_RequestLine).getMethod() == PRACK ||
|
||||
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();
|
||||
|
||||
if((request.header(h_RequestLine).getMethod() == INVITE ||
|
||||
request.header(h_RequestLine).getMethod() == PRACK ||
|
||||
request.header(h_RequestLine).getMethod() == UPDATE)
|
||||
&& code >= 200 && code < 300)
|
||||
{
|
||||
// Check if we should add our capabilites to the invite success response
|
||||
if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Allow))
|
||||
{
|
||||
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();
|
||||
}
|
||||
// Add Advertised Capabilities
|
||||
mDum.setAdvertisedCapabilities(response, mDialogSet.mUserProfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1114,6 +1066,12 @@ Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
|
|||
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*
|
||||
Dialog::makeClientInviteSession(const SipMessage& response)
|
||||
|
|
@ -1121,7 +1079,7 @@ Dialog::makeClientInviteSession(const SipMessage& response)
|
|||
InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
|
||||
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 mDum.createAppClientInviteSession(*this, *creator);
|
||||
|
|
@ -1129,15 +1087,12 @@ Dialog::makeClientInviteSession(const SipMessage& response)
|
|||
creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription());
|
||||
}
|
||||
|
||||
|
||||
|
||||
ClientSubscription*
|
||||
Dialog::makeClientSubscription(const SipMessage& request)
|
||||
{
|
||||
return new ClientSubscription(mDum, *this, request, mDefaultSubExpiration);
|
||||
return new ClientSubscription(mDum, *this, request);
|
||||
}
|
||||
|
||||
|
||||
ServerInviteSession*
|
||||
Dialog::makeServerInviteSession(const SipMessage& request)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,8 +51,9 @@ class Dialog
|
|||
void send(SharedPtr<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 setRequestNextCSeq(SipMessage& request);
|
||||
|
||||
//void setLocalContact(const NameAddr& localContact);
|
||||
//void setRemoteTarget(const NameAddr& remoteTarget);
|
||||
|
|
@ -146,9 +147,6 @@ class Dialog
|
|||
NameAddr mRemoteNameAddr;
|
||||
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)
|
||||
// !jf! this shouldn't be necessary
|
||||
// !dcm! -- no longer used for subscriptions, INVITE will take more thought/work
|
||||
|
|
|
|||
|
|
@ -31,17 +31,17 @@ DialogEventInfo::DialogEventInfo(const DialogEventInfo& rhs)
|
|||
{
|
||||
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->getRemoteTag()));
|
||||
}
|
||||
if (rhs.mLocalOfferAnswer.get())
|
||||
{
|
||||
mLocalOfferAnswer = std::unique_ptr<Contents>(rhs.mLocalOfferAnswer->clone());
|
||||
mLocalOfferAnswer = std::auto_ptr<Contents>(rhs.mLocalOfferAnswer->clone());
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
assert(mLocalOfferAnswer.get() != NULL);
|
||||
resip_assert(mLocalOfferAnswer.get() != NULL);
|
||||
return *mLocalOfferAnswer;
|
||||
}
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ DialogEventInfo::getRemoteOfferAnswer() const
|
|||
return mInviteSession->getRemoteOfferAnswer();
|
||||
}
|
||||
}
|
||||
assert(mRemoteOfferAnswer.get() != NULL);
|
||||
resip_assert(mRemoteOfferAnswer.get() != NULL);
|
||||
return *mRemoteOfferAnswer;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,22 +83,22 @@ class DialogEventInfo
|
|||
DialogId mDialogId;
|
||||
Direction mDirection;
|
||||
//ID of the dialog this dialog replaced.
|
||||
std::unique_ptr<DialogId> mReplacesId;
|
||||
std::auto_ptr<DialogId> mReplacesId;
|
||||
InviteSessionHandle mInviteSession;
|
||||
|
||||
std::unique_ptr<NameAddr> mReferredBy;
|
||||
std::auto_ptr<NameAddr> mReferredBy;
|
||||
|
||||
//could back-point to dialog for this information to save space
|
||||
NameAddrs mRouteSet;
|
||||
NameAddr mLocalIdentity;
|
||||
NameAddr mRemoteIdentity;
|
||||
Uri mLocalTarget;
|
||||
std::unique_ptr<Uri> mRemoteTarget;
|
||||
std::auto_ptr<Uri> mRemoteTarget;
|
||||
|
||||
UInt64 mCreationTimeSeconds;
|
||||
|
||||
std::unique_ptr<Contents> mLocalOfferAnswer;
|
||||
std::unique_ptr<Contents> mRemoteOfferAnswer;
|
||||
std::auto_ptr<Contents> mLocalOfferAnswer;
|
||||
std::auto_ptr<Contents> mRemoteOfferAnswer;
|
||||
|
||||
private:
|
||||
bool mReplaced;
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ DialogEventStateManager::onTryingUas(Dialog& dialog, const SipMessage& invite)
|
|||
eventInfo->mDirection = DialogEventInfo::Recipient;
|
||||
eventInfo->mCreationTimeSeconds = Timer::getTimeSecs();
|
||||
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->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->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->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 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,
|
||||
replacesFromTag));
|
||||
|
||||
std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(*(eventInfo->mReplacesId));
|
||||
if (it != mDialogIdToEventInfo.end())
|
||||
{
|
||||
// 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) &&
|
||||
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;
|
||||
|
|
@ -94,17 +99,17 @@ DialogEventStateManager::onTryingUac(DialogSet& dialogSet, const SipMessage& inv
|
|||
// ?bwc? Has something already checked for well-formedness here?
|
||||
// Maybe DialogSet? We need to be absolutely certain that this exists and is
|
||||
// well-formed. Assert for now.
|
||||
assert(!invite.empty(h_Contacts));
|
||||
assert(invite.header(h_Contacts).front().isWellFormed());
|
||||
resip_assert(!invite.empty(h_Contacts));
|
||||
resip_assert(invite.header(h_Contacts).front().isWellFormed());
|
||||
eventInfo->mLocalTarget = invite.header(h_Contacts).front().uri();
|
||||
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;
|
||||
|
||||
if (invite.exists(h_ReferredBy) &&
|
||||
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;
|
||||
|
|
@ -131,8 +136,8 @@ DialogEventStateManager::onProceedingUac(const DialogSet& dialogSet, const SipMe
|
|||
{
|
||||
// ?bwc? Has something already checked for well-formedness here?
|
||||
// Maybe DialogSet? Assert for now.
|
||||
assert(response.header(h_Contacts).front().isWellFormed());
|
||||
eventInfo->mRemoteTarget = std::unique_ptr<Uri>(new Uri(response.header(h_Contacts).front().uri()));
|
||||
resip_assert(response.header(h_Contacts).front().isWellFormed());
|
||||
eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(response.header(h_Contacts).front().uri()));
|
||||
}
|
||||
ProceedingDialogEvent evt(*eventInfo);
|
||||
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
|
||||
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);
|
||||
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
|
||||
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
|
||||
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;
|
||||
// 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);
|
||||
delete it->second;
|
||||
mDialogIdToEventInfo.erase(it++);
|
||||
|
|
@ -283,7 +292,7 @@ DialogEventStateManager::onDialogSetTerminatedImpl(const DialogSetId& dialogSetI
|
|||
it->first.getDialogSetId() == dialogSetId)
|
||||
{
|
||||
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);
|
||||
delete it->second;
|
||||
mDialogIdToEventInfo.erase(it++);
|
||||
|
|
@ -311,7 +320,7 @@ DialogEventStateManager::onDialogTerminatedImpl(DialogEventInfo* eventInfo,
|
|||
|
||||
if (remoteTarget)
|
||||
{
|
||||
eventInfo->mRemoteTarget = std::unique_ptr<Uri>(remoteTarget);
|
||||
eventInfo->mRemoteTarget = std::auto_ptr<Uri>(remoteTarget);
|
||||
}
|
||||
|
||||
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?
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
|
@ -359,6 +368,34 @@ DialogEventStateManager::getDialogEventInfo() const
|
|||
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*
|
||||
DialogEventStateManager::findOrCreateDialogInfo(const Dialog& dialog)
|
||||
{
|
||||
|
|
@ -403,7 +440,7 @@ DialogEventStateManager::findOrCreateDialogInfo(const Dialog& dialog)
|
|||
newForkInfo->mCreationTimeSeconds = Timer::getTimeSecs();
|
||||
newForkInfo->mDialogId = dialog.getId();
|
||||
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();
|
||||
eventInfo = newForkInfo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class DialogEventStateManager
|
|||
public:
|
||||
typedef std::vector<DialogEventInfo> DialogEventInfos;
|
||||
DialogEventInfos getDialogEventInfo() const;
|
||||
DialogEventInfos getDialogEventInfo(const Uri& entityUri, bool bMatchRemoteIdentityOnly = false) const;
|
||||
|
||||
virtual ~DialogEventStateManager();
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ DialogSet::DialogSet(BaseCreator* creator, DialogUsageManager& dum) :
|
|||
mServerPagerMessage(0)
|
||||
{
|
||||
setUserProfile(creator->getUserProfile());
|
||||
assert(!creator->getLastRequest()->isExternal());
|
||||
resip_assert(!creator->getLastRequest()->isExternal());
|
||||
DebugLog ( << " ************* Created DialogSet(UAC) -- " << mId << "*************" );
|
||||
}
|
||||
|
||||
|
|
@ -69,8 +69,8 @@ DialogSet::DialogSet(const SipMessage& request, DialogUsageManager& dum) :
|
|||
mClientPagerMessage(0),
|
||||
mServerPagerMessage(0)
|
||||
{
|
||||
assert(request.isRequest());
|
||||
assert(request.isExternal());
|
||||
resip_assert(request.isRequest());
|
||||
resip_assert(request.isExternal());
|
||||
mDum.mMergedRequests.insert(mMergeKey);
|
||||
if (request.header(h_RequestLine).method() == INVITE)
|
||||
{
|
||||
|
|
@ -338,18 +338,18 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
}
|
||||
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 a core. Taking the lesser of two evils...");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(msg.isRequest() || msg.isResponse());
|
||||
resip_assert(msg.isRequest() || msg.isResponse());
|
||||
|
||||
if (mState == WaitingToEnd)
|
||||
{
|
||||
assert(mDialogs.empty());
|
||||
resip_assert(mDialogs.empty());
|
||||
if (msg.isResponse())
|
||||
{
|
||||
int code = msg.header(h_StatusLine).statusCode();
|
||||
|
|
@ -451,7 +451,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
}
|
||||
else if(mState == Cancelling)
|
||||
{
|
||||
assert(mDialogs.empty());
|
||||
resip_assert(mDialogs.empty());
|
||||
if (msg.isResponse())
|
||||
{
|
||||
int code = msg.header(h_StatusLine).statusCode();
|
||||
|
|
@ -547,6 +547,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
case BYE:
|
||||
case INFO:
|
||||
case ACK:
|
||||
case PRACK:
|
||||
case UPDATE:
|
||||
if(!dialog)
|
||||
{
|
||||
|
|
@ -570,7 +571,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
request.header(h_Requires).find(Token("norefersub"))))// out of dialog & noReferSub=true
|
||||
{
|
||||
DebugLog(<< "out of dialog refer request with norefersub");
|
||||
assert(mServerOutOfDialogRequest == 0);
|
||||
resip_assert(mServerOutOfDialogRequest == 0);
|
||||
mServerOutOfDialogRequest = makeServerOutOfDialog(request);
|
||||
mServerOutOfDialogRequest->dispatch(request);
|
||||
return;
|
||||
|
|
@ -592,7 +593,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
{
|
||||
// unsolicited - not allowed but commonly implemented
|
||||
// by large companies with a bridge as their logo
|
||||
assert(mServerOutOfDialogRequest == 0);
|
||||
resip_assert(mServerOutOfDialogRequest == 0);
|
||||
mServerOutOfDialogRequest = makeServerOutOfDialog(request);
|
||||
mServerOutOfDialogRequest->dispatch(request);
|
||||
return;
|
||||
|
|
@ -600,7 +601,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
break;
|
||||
|
||||
case PUBLISH:
|
||||
assert(false); // handled in DialogUsageManager
|
||||
resip_assert(false); // handled in DialogUsageManager
|
||||
return;
|
||||
|
||||
case REGISTER:
|
||||
|
|
@ -626,7 +627,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
// !jf! move this to DialogUsageManager
|
||||
DebugLog ( << "In DialogSet::dispatch, default(ServerOutOfDialogRequest), msg: " << msg );
|
||||
// only can be one ServerOutOfDialogReq at a time
|
||||
assert(mServerOutOfDialogRequest == 0);
|
||||
resip_assert(mServerOutOfDialogRequest == 0);
|
||||
mServerOutOfDialogRequest = makeServerOutOfDialog(request);
|
||||
mServerOutOfDialogRequest->dispatch(request);
|
||||
return;
|
||||
|
|
@ -754,6 +755,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
|
||||
case INFO:
|
||||
case UPDATE:
|
||||
case PRACK:
|
||||
if (dialog)
|
||||
{
|
||||
break;
|
||||
|
|
@ -790,8 +792,20 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
if (dialog == 0)
|
||||
{
|
||||
if (msg.isRequest() && msg.header(h_RequestLine).method() == CANCEL)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -883,7 +897,7 @@ DialogSet::dispatch(const SipMessage& msg)
|
|||
return;
|
||||
}
|
||||
|
||||
assert(mState != WaitingToEnd);
|
||||
resip_assert(mState != WaitingToEnd);
|
||||
DebugLog ( << "### Calling CreateAppDialog ###: " << std::endl << std::endl <<msg);
|
||||
AppDialog* appDialog = mAppDialogSet->createAppDialog(msg);
|
||||
dialog->mAppDialog = appDialog;
|
||||
|
|
@ -946,7 +960,8 @@ DialogSet::end()
|
|||
break;
|
||||
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
|
||||
SharedPtr<SipMessage> cancel(Helper::makeCancel(*getCreator()->getLastRequest()));
|
||||
|
|
@ -971,13 +986,37 @@ DialogSet::end()
|
|||
{
|
||||
it->second->cancel();
|
||||
}
|
||||
catch(UsageUseException& e)
|
||||
catch (UsageUseException& e)
|
||||
{
|
||||
InfoLog (<< "Caught: " << 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;
|
||||
case Established:
|
||||
{
|
||||
|
|
@ -1047,7 +1086,7 @@ ClientRegistration*
|
|||
DialogSet::makeClientRegistration(const SipMessage& response)
|
||||
{
|
||||
BaseCreator* creator = getCreator();
|
||||
assert(creator);
|
||||
resip_assert(creator);
|
||||
return new ClientRegistration(mDum, *this, creator->getLastRequest());
|
||||
}
|
||||
|
||||
|
|
@ -1055,7 +1094,7 @@ ClientPublication*
|
|||
DialogSet::makeClientPublication(const SipMessage& response)
|
||||
{
|
||||
BaseCreator* creator = getCreator();
|
||||
assert(creator);
|
||||
resip_assert(creator);
|
||||
return new ClientPublication(mDum, *this, creator->getLastRequest());
|
||||
}
|
||||
|
||||
|
|
@ -1063,7 +1102,7 @@ ClientOutOfDialogReq*
|
|||
DialogSet::makeClientOutOfDialogReq(const SipMessage& response)
|
||||
{
|
||||
BaseCreator* creator = getCreator();
|
||||
assert(creator);
|
||||
resip_assert(creator);
|
||||
return new ClientOutOfDialogReq(mDum, *this, *creator->getLastRequest());
|
||||
}
|
||||
|
||||
|
|
@ -1126,7 +1165,7 @@ DialogSet::getUserProfile() const
|
|||
void
|
||||
DialogSet::setUserProfile(SharedPtr<UserProfile> userProfile)
|
||||
{
|
||||
assert(userProfile.get());
|
||||
resip_assert(userProfile.get());
|
||||
mUserProfile = userProfile;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class DialogSet
|
|||
/// Abandon this dialog set, but keep the AppDialogSet around
|
||||
void appDissociate()
|
||||
{
|
||||
assert(mAppDialogSet);
|
||||
resip_assert(mAppDialogSet);
|
||||
mAppDialogSet = 0;
|
||||
}
|
||||
friend class AppDialogSet;
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ DialogSetId::DialogSetId(const SipMessage& msg) :
|
|||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,26 +4,13 @@
|
|||
#include "resip/dum/Dialog.hxx"
|
||||
#include "resip/dum/DialogSet.hxx"
|
||||
#include "resip/dum/DialogUsageManager.hxx"
|
||||
#include "resip/stack/ExtensionHeader.hxx"
|
||||
#include "resip/stack/ExtensionParameter.hxx"
|
||||
#include "rutil/ResipAssert.h"
|
||||
#include "rutil/Logger.hxx"
|
||||
|
||||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
||||
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)
|
||||
: BaseException(msg, file, line)
|
||||
{
|
||||
|
|
@ -49,6 +36,11 @@ DialogUsage::~DialogUsage()
|
|||
AppDialogSetHandle
|
||||
DialogUsage::getAppDialogSet()
|
||||
{
|
||||
if (mDialog.mDialogSet.mAppDialogSet == 0)
|
||||
{
|
||||
ErrLog(<< "mDialog.mDialogSet.mAppDialogSet is NULL!!!");
|
||||
return AppDialogSetHandle();
|
||||
}
|
||||
return mDialog.mDialogSet.mAppDialogSet->getHandle();
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +68,12 @@ DialogUsage::remoteTarget() const
|
|||
return mDialog.mRemoteTarget;
|
||||
}
|
||||
|
||||
const NameAddrs&
|
||||
DialogUsage::getRouteSet() const
|
||||
{
|
||||
return mDialog.mRouteSet;
|
||||
}
|
||||
|
||||
const DialogId&
|
||||
DialogUsage::getDialogId() const
|
||||
{
|
||||
|
|
@ -99,9 +97,6 @@ DialogUsage::send(SharedPtr<SipMessage> msg)
|
|||
{
|
||||
// give app an chance to adorn the message.
|
||||
onReadyToSend(*msg);
|
||||
|
||||
putUserHeaders(mUserHeaders, *msg);
|
||||
|
||||
mDialog.send(msg);
|
||||
}
|
||||
|
||||
|
|
@ -111,17 +106,12 @@ DialogUsage::sendCommand(SharedPtr<SipMessage> message)
|
|||
mDum.post(new DialogUsageSendCommand(*this, message));
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsage::setUserHeaders(const std::map<std::string, std::string> &headers)
|
||||
{
|
||||
mUserHeaders = headers;
|
||||
}
|
||||
|
||||
/*
|
||||
void
|
||||
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);
|
||||
}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
#include "resip/dum/UserProfile.hxx"
|
||||
#include "resip/dum/BaseUsage.hxx"
|
||||
#include "resip/dum/Handles.hxx"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace resip
|
||||
{
|
||||
|
|
@ -37,10 +35,10 @@ class DialogUsage : public BaseUsage
|
|||
const NameAddr& myAddr() const;
|
||||
const NameAddr& peerAddr() const;
|
||||
const NameAddr& remoteTarget() const;
|
||||
const NameAddrs& getRouteSet() const;
|
||||
const DialogId& getDialogId() const;
|
||||
const Data& getCallId() const;
|
||||
SharedPtr<UserProfile> getUserProfile();
|
||||
void setUserHeaders(const std::map<std::string, std::string>& headers);
|
||||
|
||||
protected:
|
||||
friend class DialogSet;
|
||||
|
|
@ -82,14 +80,7 @@ class DialogUsage : public BaseUsage
|
|||
DialogUsage(DialogUsageManager& dum, Dialog& dialog);
|
||||
virtual ~DialogUsage();
|
||||
|
||||
//virtual void sendToDialog(SharedPtr<SipMessage> msg);
|
||||
|
||||
virtual void dialogDestroyed(const SipMessage& msg) = 0;
|
||||
|
||||
Dialog& mDialog;
|
||||
|
||||
// Custom headers
|
||||
std::map<std::string, std::string> mUserHeaders;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,12 +60,14 @@
|
|||
#include "resip/dum/OutgoingEvent.hxx"
|
||||
#include "resip/dum/DumHelper.hxx"
|
||||
#include "resip/dum/MergedRequestRemovalCommand.hxx"
|
||||
#include "resip/dum/InMemorySyncPubDb.hxx"
|
||||
#include "rutil/ResipAssert.h"
|
||||
#include "rutil/Inserter.hxx"
|
||||
#include "rutil/Logger.hxx"
|
||||
#include "rutil/Random.hxx"
|
||||
#include "rutil/Lockable.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
#include "rutil/Timer.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
|
||||
#ifdef USE_SSL
|
||||
#include "resip/stack/ssl/Security.hxx"
|
||||
|
|
@ -83,7 +85,7 @@ using namespace std;
|
|||
{ \
|
||||
if(mThreadDebugKey) \
|
||||
{ \
|
||||
assert(ThreadIf::tlsGetValue(mThreadDebugKey)); \
|
||||
resip_assert(ThreadIf::tlsGetValue(mThreadDebugKey)); \
|
||||
} \
|
||||
} while (false)
|
||||
#else
|
||||
|
|
@ -103,6 +105,7 @@ DialogUsageManager::DialogUsageManager(SipStack& stack, bool createDefaultFeatur
|
|||
mDialogSetHandler(0),
|
||||
mRequestValidationHandler(0),
|
||||
mRegistrationPersistenceManager(0),
|
||||
mPublicationPersistenceManager(0),
|
||||
mIsDefaultServerReferHandler(true),
|
||||
mClientPagerMessageHandler(0),
|
||||
mServerPagerMessageHandler(0),
|
||||
|
|
@ -142,9 +145,7 @@ DialogUsageManager::DialogUsageManager(SipStack& stack, bool createDefaultFeatur
|
|||
#if defined (USE_SSL)
|
||||
addOutgoingFeature(encryptionOutgoing);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DialogUsageManager::~DialogUsageManager()
|
||||
|
|
@ -152,14 +153,6 @@ DialogUsageManager::~DialogUsageManager()
|
|||
mShutdownState = Destroying;
|
||||
//InfoLog ( << "~DialogUsageManager" );
|
||||
|
||||
#if(0)
|
||||
// !kh!
|
||||
DialogSetMap::iterator dialogSet = mDialogSetMap.begin();
|
||||
for (; dialogSet != mDialogSetMap.end(); ++dialogSet)
|
||||
{
|
||||
delete dialogSet->second;
|
||||
}
|
||||
#endif
|
||||
if(!mDialogSetMap.empty())
|
||||
{
|
||||
DebugLog(<< "DialogUsageManager::mDialogSetMap has " << mDialogSetMap.size() << " DialogSets");
|
||||
|
|
@ -179,7 +172,7 @@ DialogUsageManager::~DialogUsageManager()
|
|||
while(!mDialogSetMap.empty())
|
||||
{
|
||||
DialogSet* ds = mDialogSetMap.begin()->second;
|
||||
delete ds;
|
||||
delete ds; // Deleting a dialog set removes itself from the map
|
||||
}
|
||||
|
||||
if(mIsDefaultServerReferHandler)
|
||||
|
|
@ -190,6 +183,18 @@ DialogUsageManager::~DialogUsageManager()
|
|||
delete mIncomingTarget;
|
||||
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" );
|
||||
}
|
||||
|
||||
|
|
@ -292,41 +297,41 @@ DialogUsageManager::forceShutdown(DumShutdownHandler* h)
|
|||
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>&
|
||||
DialogUsageManager::getMasterProfile()
|
||||
{
|
||||
assert(mMasterProfile.get());
|
||||
resip_assert(mMasterProfile.get());
|
||||
return mMasterProfile;
|
||||
}
|
||||
|
||||
SharedPtr<UserProfile>&
|
||||
DialogUsageManager::getMasterUserProfile()
|
||||
{
|
||||
assert(mMasterUserProfile.get());
|
||||
resip_assert(mMasterUserProfile.get());
|
||||
return mMasterUserProfile;
|
||||
}
|
||||
|
||||
void DialogUsageManager::setMasterProfile(const SharedPtr<MasterProfile>& masterProfile)
|
||||
{
|
||||
assert(!mMasterProfile.get());
|
||||
resip_assert(!mMasterProfile.get());
|
||||
mMasterProfile = masterProfile;
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -340,9 +345,9 @@ RedirectHandler* DialogUsageManager::getRedirectHandler()
|
|||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::setClientAuthManager(std::unique_ptr<ClientAuthManager> manager)
|
||||
DialogUsageManager::setClientAuthManager(std::auto_ptr<ClientAuthManager> manager)
|
||||
{
|
||||
mClientAuthManager = std::move(manager);
|
||||
mClientAuthManager = manager;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -354,14 +359,14 @@ DialogUsageManager::setServerAuthManager(SharedPtr<ServerAuthManager> manager)
|
|||
void
|
||||
DialogUsageManager::setClientRegistrationHandler(ClientRegistrationHandler* handler)
|
||||
{
|
||||
assert(!mClientRegistrationHandler);
|
||||
resip_assert(!mClientRegistrationHandler);
|
||||
mClientRegistrationHandler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::setServerRegistrationHandler(ServerRegistrationHandler* handler)
|
||||
{
|
||||
assert(!mServerRegistrationHandler);
|
||||
resip_assert(!mServerRegistrationHandler);
|
||||
mServerRegistrationHandler = handler;
|
||||
}
|
||||
|
||||
|
|
@ -374,27 +379,29 @@ DialogUsageManager::setDialogSetHandler(DialogSetHandler* handler)
|
|||
void
|
||||
DialogUsageManager::setInviteSessionHandler(InviteSessionHandler* handler)
|
||||
{
|
||||
assert(!mInviteSessionHandler);
|
||||
resip_assert(!mInviteSessionHandler);
|
||||
mInviteSessionHandler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::setRequestValidationHandler(RequestValidationHandler* handler)
|
||||
{
|
||||
assert(!mRequestValidationHandler);
|
||||
resip_assert(!mRequestValidationHandler);
|
||||
mRequestValidationHandler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::setRegistrationPersistenceManager(RegistrationPersistenceManager* manager)
|
||||
{
|
||||
assert(!mRegistrationPersistenceManager);
|
||||
resip_assert(!mRegistrationPersistenceManager);
|
||||
mRegistrationPersistenceManager = manager;
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::setRemoteCertStore(unique_ptr<RemoteCertStore> store)
|
||||
DialogUsageManager::setPublicationPersistenceManager(PublicationPersistenceManager* manager)
|
||||
{
|
||||
resip_assert(!mPublicationPersistenceManager);
|
||||
mPublicationPersistenceManager = manager;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -417,15 +424,15 @@ DialogUsageManager::addTimerMs(DumTimeout::Type type, unsigned long duration,
|
|||
void
|
||||
DialogUsageManager::addClientSubscriptionHandler(const Data& eventType, ClientSubscriptionHandler* handler)
|
||||
{
|
||||
assert(handler);
|
||||
assert(mClientSubscriptionHandlers.count(eventType) == 0);
|
||||
resip_assert(handler);
|
||||
resip_assert(mClientSubscriptionHandlers.count(eventType) == 0);
|
||||
mClientSubscriptionHandlers[eventType] = handler;
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::addServerSubscriptionHandler(const Data& eventType, ServerSubscriptionHandler* handler)
|
||||
{
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
//default do-nothing server side refer handler can be replaced
|
||||
if (eventType == "refer" && mServerSubscriptionHandlers.count(eventType))
|
||||
{
|
||||
|
|
@ -440,24 +447,24 @@ DialogUsageManager::addServerSubscriptionHandler(const Data& eventType, ServerSu
|
|||
void
|
||||
DialogUsageManager::addClientPublicationHandler(const Data& eventType, ClientPublicationHandler* handler)
|
||||
{
|
||||
assert(handler);
|
||||
assert(mClientPublicationHandlers.count(eventType) == 0);
|
||||
resip_assert(handler);
|
||||
resip_assert(mClientPublicationHandlers.count(eventType) == 0);
|
||||
mClientPublicationHandlers[eventType] = handler;
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::addServerPublicationHandler(const Data& eventType, ServerPublicationHandler* handler)
|
||||
{
|
||||
assert(handler);
|
||||
assert(mServerPublicationHandlers.count(eventType) == 0);
|
||||
resip_assert(handler);
|
||||
resip_assert(mServerPublicationHandlers.count(eventType) == 0);
|
||||
mServerPublicationHandlers[eventType] = handler;
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::addOutOfDialogHandler(MethodTypes type, OutOfDialogHandler* handler)
|
||||
{
|
||||
assert(handler);
|
||||
assert(mOutOfDialogHandlers.count(type) == 0);
|
||||
resip_assert(handler);
|
||||
resip_assert(mOutOfDialogHandlers.count(type) == 0);
|
||||
mOutOfDialogHandlers[type] = handler;
|
||||
}
|
||||
|
||||
|
|
@ -539,14 +546,14 @@ DialogUsageManager::makeResponse(SipMessage& response,
|
|||
int responseCode,
|
||||
const Data& reason) const
|
||||
{
|
||||
assert(request.isRequest());
|
||||
resip_assert(request.isRequest());
|
||||
Helper::makeResponse(response, request, responseCode, reason);
|
||||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::sendResponse(const SipMessage& response)
|
||||
{
|
||||
assert(response.isResponse());
|
||||
resip_assert(response.isResponse());
|
||||
mStack.send(response, this);
|
||||
}
|
||||
|
||||
|
|
@ -585,6 +592,24 @@ DialogUsageManager::makeInviteSession(const NameAddr& target,
|
|||
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>
|
||||
DialogUsageManager::makeInviteSession(const NameAddr& target,
|
||||
InviteSessionHandle sessionToReplace,
|
||||
|
|
@ -594,11 +619,11 @@ DialogUsageManager::makeInviteSession(const NameAddr& target,
|
|||
{
|
||||
SharedPtr<SipMessage> inv = makeInviteSession(target, userProfile, initialOffer, ads);
|
||||
// add replaces header
|
||||
assert(sessionToReplace.isValid());
|
||||
resip_assert(sessionToReplace.isValid());
|
||||
if(sessionToReplace.isValid())
|
||||
{
|
||||
CallId replaces;
|
||||
DialogId id = sessionToReplace->getDialogId();
|
||||
const DialogId& id = sessionToReplace->getDialogId();
|
||||
replaces.value() = id.getCallId();
|
||||
replaces.param(p_toTag) = id.getRemoteTag();
|
||||
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);
|
||||
// add replaces header
|
||||
assert(sessionToReplace.isValid());
|
||||
resip_assert(sessionToReplace.isValid());
|
||||
if(sessionToReplace.isValid())
|
||||
{
|
||||
CallId replaces;
|
||||
DialogId id = sessionToReplace->getDialogId();
|
||||
const DialogId& id = sessionToReplace->getDialogId();
|
||||
replaces.value() = id.getCallId();
|
||||
replaces.param(p_toTag) = id.getRemoteTag();
|
||||
replaces.param(p_fromTag) = id.getLocalTag();
|
||||
|
|
@ -641,11 +666,11 @@ DialogUsageManager::makeInviteSession(const NameAddr& target,
|
|||
{
|
||||
SharedPtr<SipMessage> inv = makeInviteSession(target, initialOffer, level, alternative, ads);
|
||||
// add replaces header
|
||||
assert(sessionToReplace.isValid());
|
||||
resip_assert(sessionToReplace.isValid());
|
||||
if(sessionToReplace.isValid())
|
||||
{
|
||||
CallId replaces;
|
||||
DialogId id = sessionToReplace->getDialogId();
|
||||
const DialogId& id = sessionToReplace->getDialogId();
|
||||
replaces.value() = id.getCallId();
|
||||
replaces.param(p_toTag) = id.getRemoteTag();
|
||||
replaces.param(p_fromTag) = id.getLocalTag();
|
||||
|
|
@ -751,7 +776,7 @@ DialogUsageManager::makeRefer(const NameAddr& target, const H_ReferTo::Type& ref
|
|||
SharedPtr<SipMessage>
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -792,7 +817,7 @@ DialogUsageManager::makeSubscription(const NameAddr& target, const Data& eventTy
|
|||
SharedPtr<SipMessage>
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -881,7 +906,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
|
|||
userProfile = ds->getUserProfile().get();
|
||||
}
|
||||
|
||||
assert(userProfile);
|
||||
resip_assert(userProfile);
|
||||
if (!userProfile->isAnonymous() && userProfile->hasUserAgent())
|
||||
{
|
||||
msg->header(h_UserAgent).value() = userProfile->getUserAgent();
|
||||
|
|
@ -899,7 +924,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
|
|||
msg->remove(h_Warnings);
|
||||
}
|
||||
|
||||
assert(userProfile);
|
||||
resip_assert(userProfile);
|
||||
if (msg->isRequest()
|
||||
&& userProfile->hasProxyRequires()
|
||||
&& msg->header(h_RequestLine).method() != ACK
|
||||
|
|
@ -924,11 +949,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
|
|||
SharedPtr<MessageDecorator> outboundDecorator = userProfile->getOutboundDecorator();
|
||||
if (outboundDecorator.get())
|
||||
{
|
||||
msg->addOutboundDecorator(std::unique_ptr<MessageDecorator>(outboundDecorator->clone()));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog(<< "No outbound decorator for message");
|
||||
msg->addOutboundDecorator(std::auto_ptr<MessageDecorator>(outboundDecorator->clone()));
|
||||
}
|
||||
|
||||
if (msg->isRequest())
|
||||
|
|
@ -943,7 +964,11 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
@ -971,12 +996,9 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
|
|||
if (mDialogEventStateManager)
|
||||
{
|
||||
Dialog* d = ds->findDialog(*msg);
|
||||
if (d != 0)
|
||||
{
|
||||
mDialogEventStateManager->onConfirmed(*d, d->getInviteSession());
|
||||
}
|
||||
else
|
||||
if (d == 0)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -987,7 +1009,7 @@ DialogUsageManager::send(SharedPtr<SipMessage> msg)
|
|||
DebugLog (<< "SEND: " << std::endl << std::endl << *msg);
|
||||
|
||||
OutgoingEvent* event = new OutgoingEvent(msg);
|
||||
outgoingProcess(unique_ptr<Message>(event));
|
||||
outgoingProcess(auto_ptr<Message>(event));
|
||||
}
|
||||
|
||||
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;
|
||||
{
|
||||
|
|
@ -1071,12 +1093,12 @@ void DialogUsageManager::outgoingProcess(unique_ptr<Message> message)
|
|||
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
|
||||
//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.
|
||||
// (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))
|
||||
{
|
||||
Helper::processStrictRoute(*toSend);
|
||||
sendUsingOutboundIfAppropriate(*userProfile, std::move(toSend));
|
||||
sendUsingOutboundIfAppropriate(*userProfile, toSend);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendUsingOutboundIfAppropriate(*userProfile, std::move(toSend));
|
||||
sendUsingOutboundIfAppropriate(*userProfile, toSend);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1102,7 +1124,7 @@ void DialogUsageManager::outgoingProcess(unique_ptr<Message> message)
|
|||
}
|
||||
|
||||
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
|
||||
DialogId id(*msg);
|
||||
|
|
@ -1121,12 +1143,12 @@ DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, uni
|
|||
{
|
||||
DebugLog ( << "Sending with client outbound flow tuple to express outbound" );
|
||||
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
|
||||
{
|
||||
DebugLog ( << "Sending to express outbound w/o flow tuple");
|
||||
mStack.send(std::move(msg), this);
|
||||
mStack.send(msg, this);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1134,12 +1156,12 @@ DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, uni
|
|||
if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0)
|
||||
{
|
||||
DebugLog ( << "Sending to outbound (no express) with flow tuple");
|
||||
mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this);
|
||||
mStack.sendTo(msg, userProfile.mClientOutboundFlowTuple, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
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());
|
||||
if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0)
|
||||
{
|
||||
mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this);
|
||||
mStack.sendTo(msg, userProfile.mClientOutboundFlowTuple, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
mStack.send(std::move(msg), this);
|
||||
mStack.send(msg, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1162,7 +1184,7 @@ void
|
|||
DialogUsageManager::end(DialogSetId setid)
|
||||
{
|
||||
DialogSet* ds = findDialogSet(setid);
|
||||
if (ds == nullptr)
|
||||
if (ds == 0)
|
||||
{
|
||||
throw Exception("Request no longer exists", __FILE__, __LINE__);
|
||||
}
|
||||
|
|
@ -1308,14 +1330,14 @@ AppDialogSetHandle DialogUsageManager::findAppDialogSet(const DialogSetId& id)
|
|||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::internalProcess(std::unique_ptr<Message> msg)
|
||||
DialogUsageManager::internalProcess(std::auto_ptr<Message> msg)
|
||||
{
|
||||
#ifdef RESIP_DUM_THREAD_DEBUG
|
||||
if(!mThreadDebugKey)
|
||||
{
|
||||
// .bwc. Probably means multiple threads are trying to give DUM cycles
|
||||
// simultaneously.
|
||||
assert(!mHiddenThreadDebugKey);
|
||||
resip_assert(!mHiddenThreadDebugKey);
|
||||
// No d'tor needed, since we're just going to use a pointer to this.
|
||||
if(!ThreadIf::tlsKeyCreate(mThreadDebugKey, 0))
|
||||
{
|
||||
|
|
@ -1344,8 +1366,8 @@ DialogUsageManager::internalProcess(std::unique_ptr<Message> msg)
|
|||
if (tuMsg)
|
||||
{
|
||||
InfoLog (<< "TU unregistered ");
|
||||
assert(mShutdownState == RemovingTransactionUser);
|
||||
assert(tuMsg->type() == TransactionUserMessage::TransactionUserRemoved);
|
||||
resip_assert(mShutdownState == RemovingTransactionUser);
|
||||
resip_assert(tuMsg->type() == TransactionUserMessage::TransactionUserRemoved);
|
||||
mShutdownState = Shutdown;
|
||||
if (mDumShutdownHandler)
|
||||
{
|
||||
|
|
@ -1480,7 +1502,7 @@ DialogUsageManager::internalProcess(std::unique_ptr<Message> msg)
|
|||
}
|
||||
}
|
||||
|
||||
incomingProcess(std::move(msg));
|
||||
incomingProcess(msg);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1499,7 +1521,7 @@ DialogUsageManager::processExternalMessage(ExternalMessageBase* externalMessage)
|
|||
}
|
||||
|
||||
void
|
||||
DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
|
||||
DialogUsageManager::incomingProcess(std::auto_ptr<Message> msg)
|
||||
{
|
||||
//call or create feature chain if appropriate
|
||||
Data tid = Data::Empty;
|
||||
|
|
@ -1568,9 +1590,17 @@ DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
|
|||
}
|
||||
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)));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DumFeatureChain::ProcessingResult res = it->second->process(msg.get());
|
||||
|
|
@ -1592,7 +1622,7 @@ DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
|
|||
|
||||
try
|
||||
{
|
||||
InfoLog (<< "Got: " << msg->brief());
|
||||
DebugLog (<< "Got: " << msg->brief());
|
||||
DumDecrypted* decryptedMsg = dynamic_cast<DumDecrypted*>(msg.get());
|
||||
SipMessage* sipMsg = 0;
|
||||
if (decryptedMsg)
|
||||
|
|
@ -1625,7 +1655,7 @@ DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
|
|||
DebugLog (<< "Failed required options validation " << *sipMsg);
|
||||
return;
|
||||
}
|
||||
if( !validate100RelSuport(*sipMsg) )
|
||||
if( !validate100RelSupport(*sipMsg) )
|
||||
{
|
||||
DebugLog (<< "Remote party does not support 100rel " << *sipMsg);
|
||||
return;
|
||||
|
|
@ -1680,7 +1710,7 @@ DialogUsageManager::process(resip::Lockable* mutex)
|
|||
#ifdef RESIP_DUM_THREAD_DEBUG
|
||||
mThreadDebugKey=mHiddenThreadDebugKey;
|
||||
#endif
|
||||
internalProcess(std::unique_ptr<Message>(mFifo.getNext()));
|
||||
internalProcess(std::auto_ptr<Message>(mFifo.getNext()));
|
||||
#ifdef RESIP_DUM_THREAD_DEBUG
|
||||
// .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
|
||||
// is using this mutex-locked process() call, we only enable thread-
|
||||
|
|
@ -1698,7 +1728,7 @@ DialogUsageManager::process(resip::Lockable* mutex)
|
|||
bool
|
||||
DialogUsageManager::process(int timeoutMs, resip::Lockable* mutex)
|
||||
{
|
||||
std::unique_ptr<Message> message;
|
||||
std::auto_ptr<Message> message;
|
||||
|
||||
if(timeoutMs == -1)
|
||||
{
|
||||
|
|
@ -1714,7 +1744,7 @@ DialogUsageManager::process(int timeoutMs, resip::Lockable* mutex)
|
|||
#ifdef RESIP_DUM_THREAD_DEBUG
|
||||
mThreadDebugKey=mHiddenThreadDebugKey;
|
||||
#endif
|
||||
internalProcess(std::move(message));
|
||||
internalProcess(message);
|
||||
#ifdef RESIP_DUM_THREAD_DEBUG
|
||||
// .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
|
||||
// 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
|
||||
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() != CANCEL))
|
||||
request.header(h_RequestLine).getMethod() != ACK &&
|
||||
request.header(h_RequestLine).getMethod() != CANCEL)
|
||||
{
|
||||
Tokens unsupported = getMasterProfile()->getUnsupportedOptionsTags(request.header(h_Requires));
|
||||
if (!unsupported.empty())
|
||||
|
|
@ -1796,7 +1826,7 @@ DialogUsageManager::validateRequiredOptions(const SipMessage& request)
|
|||
|
||||
|
||||
bool
|
||||
DialogUsageManager::validate100RelSuport(const SipMessage& request)
|
||||
DialogUsageManager::validate100RelSupport(const SipMessage& request)
|
||||
{
|
||||
if(request.header(h_RequestLine).getMethod() == INVITE)
|
||||
{
|
||||
|
|
@ -1811,7 +1841,9 @@ DialogUsageManager::validate100RelSuport(const SipMessage& request)
|
|||
sendResponse(failure);
|
||||
|
||||
if(mRequestValidationHandler)
|
||||
{
|
||||
mRequestValidationHandler->on100RelNotSupportedByRemote(request);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1927,8 +1959,8 @@ DialogUsageManager::validateAccept(const SipMessage& request)
|
|||
bool
|
||||
DialogUsageManager::mergeRequest(const SipMessage& request)
|
||||
{
|
||||
assert(request.isRequest());
|
||||
assert(request.isExternal());
|
||||
resip_assert(request.isRequest());
|
||||
resip_assert(request.isExternal());
|
||||
|
||||
if (!request.header(h_To).exists(p_tag))
|
||||
{
|
||||
|
|
@ -1972,7 +2004,7 @@ DialogUsageManager::processRequest(const SipMessage& request)
|
|||
toTag = false;
|
||||
}
|
||||
|
||||
assert(mAppDialogSetFactory.get());
|
||||
resip_assert(mAppDialogSetFactory.get());
|
||||
// !jf! note, the logic was reversed during ye great merge of March of Ought 5
|
||||
if (toTag ||
|
||||
findDialogSet(DialogSetId(request)))
|
||||
|
|
@ -2043,7 +2075,7 @@ DialogUsageManager::processRequest(const SipMessage& request)
|
|||
}
|
||||
else
|
||||
{
|
||||
InfoLog (<< "Received a CANCEL on a non-existent transaction ");
|
||||
InfoLog (<< "Received a CANCEL on a non-existent transaction: tid=" << request.getTransactionId());
|
||||
SipMessage failure;
|
||||
makeResponse(failure, request, 481);
|
||||
sendResponse(failure);
|
||||
|
|
@ -2051,7 +2083,7 @@ DialogUsageManager::processRequest(const SipMessage& request)
|
|||
break;
|
||||
}
|
||||
case PUBLISH:
|
||||
assert(false);
|
||||
resip_assert(false);
|
||||
return;
|
||||
case SUBSCRIBE:
|
||||
if (!checkEventPackage(request))
|
||||
|
|
@ -2121,11 +2153,11 @@ DialogUsageManager::processRequest(const SipMessage& request)
|
|||
}
|
||||
case RESPONSE:
|
||||
case SERVICE:
|
||||
assert(false);
|
||||
resip_assert(false);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
case MAX_METHODS:
|
||||
assert(false);
|
||||
resip_assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2167,12 +2199,25 @@ DialogUsageManager::processPublish(const SipMessage& request)
|
|||
i->second->dispatch(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if publication exists in PublicationDb - may have been sync'd over,
|
||||
// or exists from a restart. In this case, fabricate a new ServerSubcription
|
||||
// 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
|
||||
{
|
||||
Data etag = Random::getCryptoRandomHex(8);
|
||||
|
|
@ -2239,7 +2284,7 @@ DialogUsageManager::checkEventPackage(const SipMessage& request)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2247,6 +2292,10 @@ DialogUsageManager::checkEventPackage(const SipMessage& request)
|
|||
{
|
||||
SharedPtr<SipMessage> response(new SipMessage);
|
||||
makeResponse(*response, request, failureCode);
|
||||
if(failureCode == 489)
|
||||
{
|
||||
response->header(h_AllowEvents) = getMasterProfile()->getAllowedEvents();
|
||||
}
|
||||
send(response);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2263,16 +2312,19 @@ DialogUsageManager::findDialogSet(const DialogSetId& id)
|
|||
|
||||
if (it == mDialogSetMap.end())
|
||||
{
|
||||
StackLog ( << "Not found" );
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(it->second->isDestroying())
|
||||
{
|
||||
StackLog ( << "isDestroying() == true" );
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
StackLog ( << "found" );
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
|
@ -2397,7 +2449,7 @@ DialogUsageManager::setOutgoingMessageInterceptor(SharedPtr<DumFeature> feat)
|
|||
void
|
||||
DialogUsageManager::applyToAllServerSubscriptions(ServerSubscriptionFunctor* functor)
|
||||
{
|
||||
assert(functor);
|
||||
resip_assert(functor);
|
||||
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)
|
||||
|
|
@ -2414,7 +2466,7 @@ DialogUsageManager::applyToAllServerSubscriptions(ServerSubscriptionFunctor* fun
|
|||
void
|
||||
DialogUsageManager::applyToAllClientSubscriptions(ClientSubscriptionFunctor* functor)
|
||||
{
|
||||
assert(functor);
|
||||
resip_assert(functor);
|
||||
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)
|
||||
|
|
@ -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
|
||||
DialogUsageManager::registerForConnectionTermination(Postable* listener)
|
||||
{
|
||||
|
|
@ -2443,9 +2521,13 @@ DialogUsageManager::unRegisterForConnectionTermination(Postable* listener)
|
|||
void
|
||||
DialogUsageManager::requestMergedRequestRemoval(const MergedRequestKey& key)
|
||||
{
|
||||
// Only post delayed merge request removal if running, if we are shutting down, then there is no need
|
||||
if (mShutdownState == Running)
|
||||
{
|
||||
DebugLog(<< "Got merged request removal request");
|
||||
MergedRequestRemovalCommand command(*this, key);
|
||||
mStack.postMS(command, Timer::TF, this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2483,6 +2565,30 @@ DialogUsageManager::createDialogEventStateManager(DialogEventHandler* handler)
|
|||
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
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "resip/dum/Handles.hxx"
|
||||
#include "resip/dum/MergedRequestKey.hxx"
|
||||
#include "resip/dum/RegistrationPersistenceManager.hxx"
|
||||
#include "resip/dum/PublicationPersistenceManager.hxx"
|
||||
#include "resip/dum/ServerSubscription.hxx"
|
||||
#include "rutil/BaseException.hxx"
|
||||
#include "rutil/SharedPtr.hxx"
|
||||
|
|
@ -111,7 +112,8 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
|
||||
void forceShutdown(DumShutdownHandler*);
|
||||
|
||||
void addTransport( TransportType protocol,
|
||||
// Use SipStack::addTransport instead
|
||||
RESIP_DEPRECATED(void addTransport( TransportType protocol,
|
||||
int port=0,
|
||||
IpVersion version=V4,
|
||||
const Data& ipInterface = Data::Empty,
|
||||
|
|
@ -119,8 +121,8 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
// for TLS
|
||||
// based stuff
|
||||
const Data& privateKeyPassPhrase = Data::Empty,
|
||||
SecurityTypes::SSLType sslType = SecurityTypes::TLSv1,
|
||||
unsigned transportFlags = 0);
|
||||
SecurityTypes::SSLType sslType = SecurityTypes::SSLv23,
|
||||
unsigned transportFlags = 0));
|
||||
|
||||
SipStack& getSipStack();
|
||||
const SipStack& getSipStack() const;
|
||||
|
|
@ -128,7 +130,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
|
||||
Data getHostAddress();
|
||||
|
||||
void setAppDialogSetFactory(std::unique_ptr<AppDialogSetFactory>);
|
||||
void setAppDialogSetFactory(std::auto_ptr<AppDialogSetFactory>);
|
||||
|
||||
void setMasterProfile(const SharedPtr<MasterProfile>& masterProfile);
|
||||
SharedPtr<MasterProfile>& getMasterProfile();
|
||||
|
|
@ -137,18 +139,18 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
//optional handler to track the progress of DialogSets
|
||||
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
|
||||
//to be deleted.
|
||||
void setRedirectManager(std::unique_ptr<RedirectManager> redirect);
|
||||
void setRedirectManager(std::auto_ptr<RedirectManager> redirect);
|
||||
//informational, so a RedirectHandler is not required
|
||||
void setRedirectHandler(RedirectHandler* handler);
|
||||
RedirectHandler* getRedirectHandler();
|
||||
|
||||
/// If there is no ClientAuthManager, when the client receives a 401/407,
|
||||
/// 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
|
||||
void setServerAuthManager(resip::SharedPtr<ServerAuthManager> server);
|
||||
|
|
@ -185,10 +187,11 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
void removeExternalMessageHandler(ExternalMessageHandler* handler);
|
||||
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 setRemoteCertStore(std::unique_ptr<RemoteCertStore> store);
|
||||
RegistrationPersistenceManager* getRegistrationPersistenceManager() { return mRegistrationPersistenceManager; }
|
||||
void setPublicationPersistenceManager(PublicationPersistenceManager*);
|
||||
PublicationPersistenceManager* getPublicationPersistenceManager() { return mPublicationPersistenceManager; }
|
||||
|
||||
// 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
|
||||
|
|
@ -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 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 DialogSetId& dialogSetId, const SharedPtr<UserProfile>& userProfile, const Contents* initialOffer, EncryptionLevel level, const Contents* alternative = 0, AppDialogSet* ads = 0);
|
||||
// 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, 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
|
||||
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(); }
|
||||
|
||||
void applyToAllClientSubscriptions(ClientSubscriptionFunctor*);
|
||||
void applyToAllServerSubscriptions(ServerSubscriptionFunctor*);
|
||||
|
||||
void endAllServerSubscriptions(TerminateReason reason = Deactivated);
|
||||
void endAllServerPublications();
|
||||
|
||||
/// Note: Implementations of Postable must delete the message passed via post
|
||||
void registerForConnectionTermination(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.
|
||||
DialogEventStateManager* createDialogEventStateManager(DialogEventHandler* handler);
|
||||
|
||||
void setAdvertisedCapabilities(SipMessage& msg, SharedPtr<UserProfile> userProfile);
|
||||
|
||||
protected:
|
||||
virtual void onAllHandlesDestroyed();
|
||||
//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
|
||||
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,
|
||||
unsigned long durationSeconds,
|
||||
|
|
@ -459,7 +468,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
bool validateContent(const SipMessage& request);
|
||||
bool validateAccept(const SipMessage& request);
|
||||
bool validateTo(const SipMessage& request);
|
||||
bool validate100RelSuport(const SipMessage& request);
|
||||
bool validate100RelSupport(const SipMessage& request);
|
||||
|
||||
bool mergeRequest(const SipMessage& request);
|
||||
|
||||
|
|
@ -472,8 +481,8 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
bool queueForIdentityCheck(SipMessage* msg);
|
||||
void processIdentityCheckResponse(const HttpGetMessage& msg);
|
||||
|
||||
void incomingProcess(std::unique_ptr<Message> msg);
|
||||
void outgoingProcess(std::unique_ptr<Message> msg);
|
||||
void incomingProcess(std::auto_ptr<Message> msg);
|
||||
void outgoingProcess(std::auto_ptr<Message> msg);
|
||||
void processExternalMessage(ExternalMessageBase* externalMessage);
|
||||
|
||||
// For delayed delete of a Usage
|
||||
|
|
@ -495,9 +504,9 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
|
||||
SharedPtr<MasterProfile> mMasterProfile;
|
||||
SharedPtr<UserProfile> mMasterUserProfile;
|
||||
std::unique_ptr<RedirectManager> mRedirectManager;
|
||||
std::unique_ptr<ClientAuthManager> mClientAuthManager;
|
||||
//std::unique_ptr<ServerAuthManager> mServerAuthManager;
|
||||
std::auto_ptr<RedirectManager> mRedirectManager;
|
||||
std::auto_ptr<ClientAuthManager> mClientAuthManager;
|
||||
//std::auto_ptr<ServerAuthManager> mServerAuthManager;
|
||||
|
||||
InviteSessionHandler* mInviteSessionHandler;
|
||||
ClientRegistrationHandler* mClientRegistrationHandler;
|
||||
|
|
@ -507,6 +516,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
RequestValidationHandler* mRequestValidationHandler;
|
||||
|
||||
RegistrationPersistenceManager *mRegistrationPersistenceManager;
|
||||
PublicationPersistenceManager *mPublicationPersistenceManager;
|
||||
|
||||
OutOfDialogHandler* getOutOfDialogHandler(const MethodTypes type);
|
||||
|
||||
|
|
@ -515,7 +525,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
std::map<Data, ClientPublicationHandler*> mClientPublicationHandlers;
|
||||
std::map<Data, ServerPublicationHandler*> mServerPublicationHandlers;
|
||||
std::map<MethodTypes, OutOfDialogHandler*> mOutOfDialogHandlers;
|
||||
std::unique_ptr<KeepAliveManager> mKeepAliveManager;
|
||||
std::auto_ptr<KeepAliveManager> mKeepAliveManager;
|
||||
bool mIsDefaultServerReferHandler;
|
||||
|
||||
ClientPagerMessageHandler* mClientPagerMessageHandler;
|
||||
|
|
@ -526,7 +536,7 @@ class DialogUsageManager : public HandleManager, public TransactionUser
|
|||
// server subscription handler for the 'dialog' event...
|
||||
DialogEventStateManager* mDialogEventStateManager;
|
||||
|
||||
std::unique_ptr<AppDialogSetFactory> mAppDialogSetFactory;
|
||||
std::auto_ptr<AppDialogSetFactory> mAppDialogSetFactory;
|
||||
|
||||
SipStack& mStack;
|
||||
DumShutdownHandler* mDumShutdownHandler;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public:
|
|||
|
||||
virtual Message* clone() const
|
||||
{
|
||||
assert(false);
|
||||
resip_assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#if !defined(RESIP_DUMEXCEPTION_HXX)
|
||||
#define RESIP__DUMEXCEPTION_HXX
|
||||
#define RESIP_DUMEXCEPTION_HXX
|
||||
|
||||
#include "rutil/BaseException.hxx"
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class DumFeature
|
|||
// taken ownership of msg until we get a return. If we throw, the
|
||||
// ownership of msg is unknown. This is unacceptable.
|
||||
virtual ProcessingResult process(Message* msg) = 0;
|
||||
virtual void postCommand(std::unique_ptr<Message> message);
|
||||
virtual void postCommand(std::auto_ptr<Message> message);
|
||||
|
||||
protected:
|
||||
DialogUsageManager& mDum;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
#include "DumFeatureMessage.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
#include "resip/dum/BaseUsage.hxx"
|
||||
|
|
|
|||
|
|
@ -7,23 +7,26 @@ using namespace std;
|
|||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
||||
void DumHelper::setOutgoingEncryptionLevel(SipMessage& message,
|
||||
void
|
||||
DumHelper::setOutgoingEncryptionLevel(SipMessage& message,
|
||||
DialogUsageManager::EncryptionLevel level)
|
||||
{
|
||||
SecurityAttributes* attr = new SecurityAttributes();
|
||||
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();
|
||||
attr->setOutgoingEncryptionLevel(message.getSecurityAttributes()->getOutgoingEncryptionLevel());
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ DumProcessHandler::handleProcessNotification()
|
|||
{
|
||||
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();
|
||||
DebugLog ( << "Setting dum process timer: " << timeTillProcess);
|
||||
mExternalTimer->createTimer(mTimerID, timeTillProcess);
|
||||
|
|
@ -69,7 +69,7 @@ DumProcessHandler::handleProcessNotification()
|
|||
void
|
||||
DumProcessHandler::handleTimeout(AsyncID timerID)
|
||||
{
|
||||
assert(timerID == mTimerID);
|
||||
resip_assert(timerID == mTimerID);
|
||||
mHaveActiveTimer = false;
|
||||
handleProcessNotification();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ DumThread::thread()
|
|||
{
|
||||
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())
|
||||
{
|
||||
mDum.internalProcess(std::move(msg));
|
||||
mDum.internalProcess(msg);
|
||||
}
|
||||
}
|
||||
catch (BaseException& e)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
#include "DumTimeout.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
#include "resip/dum/BaseUsage.hxx"
|
||||
|
|
@ -63,7 +63,7 @@ const Data & DumTimeout::transactionId() const
|
|||
bool
|
||||
DumTimeout::isClientTransaction() const
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -100,6 +100,12 @@ DumTimeout::encode(EncodeStream& strm) const
|
|||
case Retransmit1xx:
|
||||
strm <<"Retransmit1xx";
|
||||
break;
|
||||
case Retransmit1xxRel:
|
||||
strm <<"Retransmit1xxRel";
|
||||
break;
|
||||
case Resubmit1xxRel:
|
||||
strm <<"Resubmit1xxRel";
|
||||
break;
|
||||
case WaitForAck:
|
||||
strm <<"WaitForAck";
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class DumTimeout : public ApplicationMessage
|
|||
Publication,
|
||||
Retransmit200,
|
||||
Retransmit1xx,
|
||||
Retransmit1xxRel,
|
||||
Resubmit1xxRel,
|
||||
WaitForAck, // UAS gets no ACK
|
||||
CanDiscardAck,
|
||||
StaleCall, // UAC gets no final response
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define RESIP_HANDLE_HXX
|
||||
|
||||
#include <iosfwd>
|
||||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
#include "resip/dum/Handled.hxx"
|
||||
#include "resip/dum/HandleManager.hxx"
|
||||
#include "resip/dum/HandleException.hxx"
|
||||
|
|
@ -95,8 +95,8 @@ class Handle
|
|||
// !nash! to be able to use Handle in Set or Map container
|
||||
bool operator<(const Handle<T>& other) const
|
||||
{
|
||||
assert(mHam);
|
||||
assert(other.mHam);
|
||||
resip_assert(mHam);
|
||||
resip_assert(other.mHam);
|
||||
return mId < other.mId;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
#include "rutil/Logger.hxx"
|
||||
#include "rutil/Inserter.hxx"
|
||||
#include "resip/dum/HandleManager.hxx"
|
||||
|
|
@ -72,7 +72,7 @@ void
|
|||
HandleManager::remove(Handled::Id id)
|
||||
{
|
||||
HandleMap::iterator i = mHandleMap.find(id);
|
||||
assert (i != mHandleMap.end());
|
||||
resip_assert (i != mHandleMap.end());
|
||||
mHandleMap.erase(i);
|
||||
if (mShuttingDown)
|
||||
{
|
||||
|
|
@ -110,112 +110,64 @@ HandleManager::getHandled(Handled::Id id) const
|
|||
if (i == mHandleMap.end())
|
||||
{
|
||||
InfoLog (<< "Reference to stale handle: " << id);
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
throw HandleException("Stale handle", __FILE__, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(i->second);
|
||||
resip_assert(i->second);
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================
|
||||
|
||||
* The Vovida Software License, Version 1.0
|
||||
|
||||
*
|
||||
|
||||
* Copyright (c) 2000 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/>.
|
||||
|
||||
*
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
using namespace resip;
|
||||
|
||||
HttpProvider* HttpProvider::mInstance = 0;
|
||||
std::unique_ptr<HttpProviderFactory> HttpProvider::mFactory;
|
||||
std::auto_ptr<HttpProviderFactory> HttpProvider::mFactory;
|
||||
Mutex HttpProvider::mMutex;
|
||||
|
||||
void
|
||||
HttpProvider::setFactory(std::unique_ptr<HttpProviderFactory> fact)
|
||||
HttpProvider::setFactory(std::auto_ptr<HttpProviderFactory> fact)
|
||||
{
|
||||
mFactory = std::move(fact);
|
||||
mFactory = fact;
|
||||
}
|
||||
|
||||
HttpProvider*
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class HttpProvider
|
|||
{
|
||||
public:
|
||||
//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
|
||||
static HttpProvider* instance();
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ class HttpProvider
|
|||
virtual ~HttpProvider(){} //impl. singleton destructor pattern later
|
||||
private:
|
||||
static HttpProvider* mInstance;
|
||||
static std::unique_ptr<HttpProviderFactory> mFactory;
|
||||
static std::auto_ptr<HttpProviderFactory> mFactory;
|
||||
static Mutex mMutex;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -98,10 +98,10 @@ IdentityHandler::queueForIdentityCheck(SipMessage* sipMsg)
|
|||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<SecurityAttributes> sec(new SecurityAttributes);
|
||||
std::auto_ptr<SecurityAttributes> sec(new SecurityAttributes);
|
||||
sec->setIdentity(sipMsg->header(h_From).uri().getAor());
|
||||
sec->setIdentityStrength(SecurityAttributes::From);
|
||||
sipMsg->setSecurityAttributes(std::move(sec));
|
||||
sipMsg->setSecurityAttributes(sec);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ IdentityHandler::processIdentityCheckResponse(const HttpGetMessage& msg)
|
|||
if (it != mRequiresCerts.end())
|
||||
{
|
||||
mDum.getSecurity()->checkAndSetIdentity( *it->second, msg.getBodyData() );
|
||||
postCommand(unique_ptr<Message>(it->second));
|
||||
postCommand(auto_ptr<Message>(it->second));
|
||||
mRequiresCerts.erase(it);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ InMemoryRegistrationDatabase::unlockRecord(const Uri& aor)
|
|||
database_map_t::iterator i = mDatabase.find(aor);
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
@ -141,7 +141,7 @@ InMemoryRegistrationDatabase::updateContact(const resip::Uri& aor,
|
|||
|
||||
}
|
||||
|
||||
assert(contactList);
|
||||
resip_assert(contactList);
|
||||
|
||||
ContactList::iterator j;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class InMemoryRegistrationDatabase : public RegistrationPersistenceManager
|
|||
/// return all the AOR in the DB
|
||||
virtual void getAors(UriList& container);
|
||||
|
||||
private:
|
||||
protected:
|
||||
typedef std::map<Uri,ContactList *> database_map_t;
|
||||
database_map_t mDatabase;
|
||||
Mutex mDatabaseMutex;
|
||||
|
|
@ -58,14 +58,12 @@ class InMemoryRegistrationDatabase : public RegistrationPersistenceManager
|
|||
|
||||
bool mCheckExpiry;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Find aor in mDatabase
|
||||
* Before returning the iterator pointing to aor,
|
||||
* delete all expired contacts
|
||||
*/
|
||||
database_map_t::iterator findNotExpired(const Uri& aor);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -54,8 +54,7 @@ contactsRemoveIfRequired(ContactList& contacts, UInt64& now,
|
|||
}
|
||||
|
||||
InMemorySyncRegDb::InMemorySyncRegDb(unsigned int removeLingerSecs) :
|
||||
mRemoveLingerSecs(removeLingerSecs),
|
||||
mHandler(0)
|
||||
mRemoveLingerSecs(removeLingerSecs)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +68,55 @@ InMemorySyncRegDb::~InMemorySyncRegDb()
|
|||
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
|
||||
InMemorySyncRegDb::initialSync(unsigned int connectionId)
|
||||
{
|
||||
|
|
@ -83,7 +131,7 @@ InMemorySyncRegDb::initialSync(unsigned int connectionId)
|
|||
{
|
||||
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);
|
||||
}
|
||||
if(mHandler) mHandler->onAorModified(aor, contacts);
|
||||
invokeOnAorModified(true /* sync? */, aor, contacts);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -134,7 +182,7 @@ InMemorySyncRegDb::removeAor(const Uri& aor)
|
|||
it->mRegExpires = 0;
|
||||
it->mLastUpdated = now;
|
||||
}
|
||||
if(mHandler) mHandler->onAorModified(aor, contacts);
|
||||
invokeOnAorModified(true /* sync? */, aor, contacts);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -142,7 +190,7 @@ InMemorySyncRegDb::removeAor(const Uri& aor)
|
|||
// Setting this to 0 causes it to be removed when we unlock the AOR.
|
||||
i->second = 0;
|
||||
ContactList emptyList;
|
||||
if(mHandler) mHandler->onAorModified(aor, emptyList);
|
||||
invokeOnAorModified(true /* sync? */, aor, emptyList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -162,12 +210,19 @@ InMemorySyncRegDb::getAors(InMemorySyncRegDb::UriList& container)
|
|||
|
||||
bool
|
||||
InMemorySyncRegDb::aorIsRegistered(const Uri& aor)
|
||||
{
|
||||
return aorIsRegistered(aor, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
InMemorySyncRegDb::aorIsRegistered(const Uri& aor, UInt64* maxExpires)
|
||||
{
|
||||
Lock g(mDatabaseMutex);
|
||||
bool registered = false;
|
||||
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);
|
||||
UInt64 now = Timer::getTimeSecs();
|
||||
|
|
@ -175,16 +230,24 @@ InMemorySyncRegDb::aorIsRegistered(const Uri& aor)
|
|||
{
|
||||
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
|
||||
{
|
||||
return true;
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return registered;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -221,7 +284,7 @@ InMemorySyncRegDb::unlockRecord(const Uri& aor)
|
|||
database_map_t::iterator i = mDatabase.find(aor);
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
@ -255,7 +318,7 @@ InMemorySyncRegDb::updateContact(const resip::Uri& aor,
|
|||
}
|
||||
}
|
||||
|
||||
assert(contactList);
|
||||
resip_assert(contactList);
|
||||
|
||||
ContactList::iterator j;
|
||||
|
||||
|
|
@ -274,14 +337,16 @@ InMemorySyncRegDb::updateContact(const resip::Uri& aor,
|
|||
status = CONTACT_CREATED;
|
||||
}
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a new contact, so we add it to the list.
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +379,8 @@ InMemorySyncRegDb::removeContact(const Uri& aor,
|
|||
{
|
||||
j->mRegExpires = 0;
|
||||
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
|
||||
{
|
||||
|
|
@ -325,7 +391,8 @@ InMemorySyncRegDb::removeContact(const Uri& aor,
|
|||
}
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
|
||||
#include "resip/dum/RegistrationPersistenceManager.hxx"
|
||||
#include "rutil/Mutex.hxx"
|
||||
|
|
@ -15,11 +16,21 @@ namespace resip
|
|||
class InMemorySyncRegDbHandler
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
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) = 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
|
||||
all registrations in memory, and is used for remote replication.
|
||||
|
|
@ -45,12 +56,15 @@ class InMemorySyncRegDb : public RegistrationPersistenceManager
|
|||
InMemorySyncRegDb(unsigned int removeLingerSecs = 0);
|
||||
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 addAor(const Uri& aor, const ContactList& contacts);
|
||||
virtual void removeAor(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 unlockRecord(const Uri& aor);
|
||||
|
|
@ -66,7 +80,7 @@ class InMemorySyncRegDb : public RegistrationPersistenceManager
|
|||
/// return all the AOR in the DB
|
||||
virtual void getAors(UriList& container);
|
||||
|
||||
private:
|
||||
protected:
|
||||
typedef std::map<Uri,ContactList *> database_map_t;
|
||||
database_map_t mDatabase;
|
||||
Mutex mDatabaseMutex;
|
||||
|
|
@ -75,8 +89,12 @@ class InMemorySyncRegDb : public RegistrationPersistenceManager
|
|||
Mutex mLockedRecordsMutex;
|
||||
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;
|
||||
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
|
|
@ -22,8 +22,6 @@ class SdpContents;
|
|||
class InviteSession : public DialogUsage
|
||||
{
|
||||
public:
|
||||
bool canProvideOffer();
|
||||
|
||||
/** Called to set the offer that will be used in the next message that
|
||||
sends an offer. If possible, this will synchronously send the
|
||||
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);
|
||||
|
||||
/** 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);
|
||||
|
||||
// Following methods are for sending requests within a dialog
|
||||
|
||||
/** sends a refer request */
|
||||
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 */
|
||||
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, 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 */
|
||||
virtual void info(const Contents& contents);
|
||||
|
|
@ -221,17 +222,23 @@ class InviteSession : public DialogUsage
|
|||
UAS_WaitingToRequestOffer,
|
||||
|
||||
UAS_AcceptedWaitingAnswer,
|
||||
UAS_ReceivedOfferReliable,
|
||||
UAS_OfferReliable,
|
||||
UAS_OfferReliableProvidedAnswer,
|
||||
UAS_NoOfferReliable,
|
||||
UAS_ProvidedOfferReliable,
|
||||
UAS_FirstSentOfferReliable,
|
||||
UAS_FirstSentAnswerReliable,
|
||||
UAS_NoAnswerReliableWaitingPrack,
|
||||
UAS_NegotiatedReliable,
|
||||
UAS_NoAnswerReliable,
|
||||
UAS_SentUpdate,
|
||||
UAS_SentUpdateAccepted,
|
||||
UAS_SentUpdateGlare,
|
||||
UAS_ReceivedUpdate,
|
||||
UAS_ReceivedUpdateWaitingAnswer,
|
||||
UAS_WaitingToTerminate,
|
||||
UAS_WaitingToHangup
|
||||
// !!!!WARNING!!!! when adding new UAS state - make sure you check if they
|
||||
// need to be added to the isAccepted method
|
||||
} State;
|
||||
|
||||
typedef enum
|
||||
|
|
@ -279,7 +286,6 @@ class InviteSession : public DialogUsage
|
|||
|
||||
InviteSession(DialogUsageManager& dum, Dialog& dialog);
|
||||
virtual ~InviteSession();
|
||||
virtual void dialogDestroyed(const SipMessage& msg);
|
||||
virtual void onReadyToSend(SipMessage& msg);
|
||||
virtual void flowTerminated();
|
||||
|
||||
|
|
@ -320,10 +326,10 @@ class InviteSession : public DialogUsage
|
|||
static Data toData(State state);
|
||||
void transition(State target);
|
||||
|
||||
std::unique_ptr<Contents> getOfferAnswer(const SipMessage& msg);
|
||||
bool isReliable(const SipMessage& msg);
|
||||
static std::unique_ptr<Contents> makeOfferAnswer(const Contents& offerAnswer);
|
||||
static std::unique_ptr<Contents> makeOfferAnswer(const Contents& offerAnswer, const Contents* alternative);
|
||||
std::auto_ptr<Contents> getOfferAnswer(const SipMessage& msg);
|
||||
bool isReliable(const SipMessage& msg) const;
|
||||
static std::auto_ptr<Contents> makeOfferAnswer(const Contents& offerAnswer);
|
||||
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);
|
||||
void provideProposedOffer();
|
||||
|
|
@ -355,17 +361,16 @@ class InviteSession : public DialogUsage
|
|||
NitState mNitState;
|
||||
NitState mServerNitState;
|
||||
|
||||
std::unique_ptr<Contents> mCurrentLocalOfferAnswer;
|
||||
std::unique_ptr<Contents> mProposedLocalOfferAnswer;
|
||||
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::auto_ptr<Contents> mProposedLocalOfferAnswer; // This get set when we send an offer to the remote end
|
||||
|
||||
std::unique_ptr<Contents> mCurrentRemoteOfferAnswer;
|
||||
std::unique_ptr<Contents> mProposedRemoteOfferAnswer;
|
||||
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::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> mLastRemoteSessionModification; // last UPDATE or reINVITE received
|
||||
SharedPtr<SipMessage> mInvite200; // 200 OK for reINVITE for retransmissions
|
||||
SharedPtr<SipMessage> mLastNitResponse; //
|
||||
//?dcm? -- ptr, delete when not needed?
|
||||
SharedPtr<SipMessage> mLastNitResponse;
|
||||
|
||||
SipMessage mLastReferNoSubRequest;
|
||||
|
||||
|
|
@ -396,7 +401,7 @@ class InviteSession : public DialogUsage
|
|||
SharedPtr<SipMessage> mLastSentNITRequest;
|
||||
|
||||
DialogUsageManager::EncryptionLevel mCurrentEncryptionLevel;
|
||||
DialogUsageManager::EncryptionLevel mProposedEncryptionLevel; // UPDATE or RE-INVITE
|
||||
DialogUsageManager::EncryptionLevel mProposedEncryptionLevel; // UPDATE or RE-INVITE or PRACK
|
||||
|
||||
EndReason mEndReason;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ InviteSessionCreator::InviteSessionCreator(DialogUsageManager& dum,
|
|||
DumHelper::setOutgoingEncryptionLevel(*mLastRequest, level);
|
||||
if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
|
||||
{
|
||||
assert(userProfile.get());
|
||||
resip_assert(userProfile.get());
|
||||
if(userProfile->getDefaultSessionTime() >= 90)
|
||||
{
|
||||
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 (alternative)
|
||||
|
|
@ -51,7 +51,7 @@ InviteSessionCreator::InviteSessionCreator(DialogUsageManager& dum,
|
|||
{
|
||||
initialOffer.reset(initial->clone());
|
||||
}
|
||||
getLastRequest()->setContents(std::move(initialOffer));
|
||||
getLastRequest()->setContents(initialOffer);
|
||||
}
|
||||
//100rel
|
||||
switch(mDum.getMasterProfile()->getUacReliableProvisionalMode())
|
||||
|
|
@ -60,13 +60,14 @@ InviteSessionCreator::InviteSessionCreator(DialogUsageManager& dum,
|
|||
//no support, do nothing
|
||||
break;
|
||||
case MasterProfile::Supported:
|
||||
case MasterProfile::SupportedEssential:
|
||||
getLastRequest()->header(h_Supporteds).push_back(Token(Symbols::C100rel));
|
||||
break;
|
||||
case MasterProfile::Required:
|
||||
getLastRequest()->header(h_Requires).push_back(Token(Symbols::C100rel));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +78,7 @@ InviteSessionCreator::~InviteSessionCreator()
|
|||
void
|
||||
InviteSessionCreator::end()
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ InviteSessionHandler::onEarlyMedia(ClientInviteSessionHandle h, const SipMessage
|
|||
if(!mGenericOfferAnswer)
|
||||
{
|
||||
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
|
||||
assert(sdp);
|
||||
resip_assert(sdp);
|
||||
onEarlyMedia(h, msg, *sdp);
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ InviteSessionHandler::onAnswer(InviteSessionHandle h, const SipMessage& msg, con
|
|||
if(!mGenericOfferAnswer)
|
||||
{
|
||||
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
|
||||
assert(sdp);
|
||||
resip_assert(sdp);
|
||||
onAnswer(h, msg, *sdp);
|
||||
}
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ InviteSessionHandler::onOffer(InviteSessionHandle h, const SipMessage& msg, cons
|
|||
if(!mGenericOfferAnswer)
|
||||
{
|
||||
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
|
||||
assert(sdp);
|
||||
resip_assert(sdp);
|
||||
onOffer(h, msg, *sdp);
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ InviteSessionHandler::onRemoteAnswerChanged(InviteSessionHandle h, const SipMess
|
|||
if(!mGenericOfferAnswer)
|
||||
{
|
||||
const SdpContents* sdp = dynamic_cast<const SdpContents*>(&body);
|
||||
assert(sdp);
|
||||
resip_assert(sdp);
|
||||
onRemoteSdpChanged(h, msg, *sdp);
|
||||
}
|
||||
}
|
||||
|
|
@ -117,6 +117,11 @@ InviteSessionHandler::onConnectedConfirmed(InviteSessionHandle handle, const Sip
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
InviteSessionHandler::onPrack(ServerInviteSessionHandle, const SipMessage &msg)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
InviteSessionHandler::onFlowTerminated(InviteSessionHandle)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ class InviteSessionHandler
|
|||
/// called when ACK (with out an answer) is received for initial invite (UAS)
|
||||
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
|
||||
* minutes). This is just a notification. After the notification is
|
||||
* called, the InviteSession will then call
|
||||
|
|
@ -91,7 +94,7 @@ class InviteSessionHandler
|
|||
LocalCancel,
|
||||
RemoteCancel,
|
||||
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;
|
||||
|
|
@ -141,6 +144,8 @@ class InviteSessionHandler
|
|||
virtual void onOfferRejected(InviteSessionHandle, const SipMessage* msg)=0;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// called when response to INFO message is received
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "resip/dum/DialogUsageManager.hxx"
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "rutil/Logger.hxx"
|
||||
#include "rutil/TransportType.hxx"
|
||||
#include "resip/stack/SipStack.hxx"
|
||||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
|
@ -17,7 +18,7 @@ int KeepAliveManager::mKeepAlivePongTimeoutMs = 10000; // Defaults to 10000ms (
|
|||
void
|
||||
KeepAliveManager::add(const Tuple& target, int keepAliveInterval, bool targetSupportsOutbound)
|
||||
{
|
||||
assert(mDum);
|
||||
resip_assert(mDum);
|
||||
NetworkAssociationMap::iterator it = mNetworkAssociations.find(target);
|
||||
if (it == mNetworkAssociations.end())
|
||||
{
|
||||
|
|
@ -87,7 +88,7 @@ KeepAliveManager::remove(const Tuple& target)
|
|||
void
|
||||
KeepAliveManager::process(KeepAliveTimeout& timeout)
|
||||
{
|
||||
assert(mDum);
|
||||
resip_assert(mDum);
|
||||
static KeepAliveMessage msg;
|
||||
NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target());
|
||||
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
|
||||
// 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)
|
||||
if(it->first.getType() == TCP || it->first.getType() == TLS)
|
||||
if(isReliable(it->first.getType()))
|
||||
{
|
||||
DebugLog( << "Starting pong timeout for keepalive id " << it->second.id);
|
||||
KeepAlivePongTimeout t(it->first, it->second.id);
|
||||
|
|
@ -131,7 +132,7 @@ KeepAliveManager::process(KeepAliveTimeout& timeout)
|
|||
void
|
||||
KeepAliveManager::process(KeepAlivePongTimeout& timeout)
|
||||
{
|
||||
assert(mDum);
|
||||
resip_assert(mDum);
|
||||
NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target());
|
||||
if (it != mNetworkAssociations.end() && timeout.id() == it->second.id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -2,6 +2,7 @@
|
|||
#include "resip/dum/Profile.hxx"
|
||||
#include "resip/dum/MasterProfile.hxx"
|
||||
#include "resip/stack/HeaderTypes.hxx"
|
||||
#include "rutil/Logger.hxx"
|
||||
|
||||
using namespace resip;
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
|
@ -22,7 +23,8 @@ MasterProfile::MasterProfile() :
|
|||
mUasReliableProvisionalMode(Never),
|
||||
mServerRegistrationMinExpires(0),
|
||||
mServerRegistrationMaxExpires(UINT_MAX),
|
||||
mServerRegistrationDefaultExpires(3600)
|
||||
mServerRegistrationDefaultExpires(3600),
|
||||
mAdditionalTransactionTerminatingResponsesEnabled(false)
|
||||
{
|
||||
// Default settings
|
||||
addSupportedMimeType(INVITE, Mime("application", "sdp"));
|
||||
|
|
@ -64,6 +66,24 @@ MasterProfile::addSupportedMethod(const MethodTypes& 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
|
||||
MasterProfile::isMethodSupported(MethodTypes method) const
|
||||
{
|
||||
|
|
@ -106,8 +126,8 @@ MasterProfile::addSupportedOptionTag(const Token& tag)
|
|||
{
|
||||
if (tag == Token(Symbols::C100rel))
|
||||
{
|
||||
//use enablePrackUas and enablePrackUac
|
||||
assert(0);
|
||||
//use setUasReliableProvisionalMode and setUacReliableProvisionalMode
|
||||
resip_assert(0);
|
||||
}
|
||||
mSupportedOptionTags.push_back(tag);
|
||||
}
|
||||
|
|
@ -122,10 +142,13 @@ MasterProfile::getUnsupportedOptionsTags(const Tokens& requiresOptionTags)
|
|||
{
|
||||
tokens.push_back(Token("malformedTag"));
|
||||
}
|
||||
else if (*i == Token(Symbols::C100rel) && mUasReliableProvisionalMode == Never)
|
||||
else if (*i == Token(Symbols::C100rel) )
|
||||
{
|
||||
if (mUasReliableProvisionalMode == Never)
|
||||
{
|
||||
tokens.push_back(*i);
|
||||
}
|
||||
}
|
||||
// if this option is not supported
|
||||
else if (!mSupportedOptionTags.find(*i))
|
||||
{
|
||||
|
|
@ -157,8 +180,6 @@ MasterProfile::setUacReliableProvisionalMode(ReliableProvisionalMode mode)
|
|||
void
|
||||
MasterProfile::setUasReliableProvisionalMode(ReliableProvisionalMode mode)
|
||||
{
|
||||
//.dcm. not supported yet
|
||||
assert(0);
|
||||
mUasReliableProvisionalMode = mode;
|
||||
}
|
||||
|
||||
|
|
@ -431,6 +452,40 @@ MasterProfile::clone() const
|
|||
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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class MasterProfile : public UserProfile
|
|||
|
||||
/// Defaults are: INVITE, ACK, CANCEL, OPTIONS, BYE, UPDATE
|
||||
virtual void addSupportedMethod(const MethodTypes& method);
|
||||
virtual void removeSupportedMethod(const MethodTypes& method);
|
||||
virtual bool isMethodSupported(MethodTypes method) const;
|
||||
virtual Tokens getAllowedMethods() const;
|
||||
virtual Data getAllowedMethodsData() const;
|
||||
|
|
@ -43,11 +44,11 @@ class MasterProfile : public UserProfile
|
|||
typedef enum
|
||||
{
|
||||
Never,
|
||||
Supported,
|
||||
Required
|
||||
SupportedEssential, // If UAS - Only use reliable provisionals if sending a body and far end supports
|
||||
Supported, // If UAS - Always use reliable provisionals if far end supports
|
||||
Required // If UAS - Always use reliable provisionals
|
||||
} ReliableProvisionalMode;
|
||||
|
||||
|
||||
// UAC PRACK support. UPDATE must be enabled(currently defaults to on, do
|
||||
// not disable w/out disabling UAC PRACK support).
|
||||
//
|
||||
|
|
@ -59,19 +60,31 @@ class MasterProfile : public UserProfile
|
|||
// 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
|
||||
// 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:
|
||||
// Overlapping reliable provisional responses that contain a body are not
|
||||
// - Overlapping reliable provisional responses that contain a body are not
|
||||
// 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 ReliableProvisionalMode getUacReliableProvisionalMode() const;
|
||||
|
||||
//Not supported as UAS. Calling setUacReliableProvisionalMode will result
|
||||
//in an assert.
|
||||
// UAS PRACK support. UPDATE must be enabled(currently defaults to on, do
|
||||
// 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 ReliableProvisionalMode getUasReliableProvisionalMode() const;
|
||||
|
||||
|
|
@ -151,6 +164,29 @@ class MasterProfile : public UserProfile
|
|||
virtual bool& checkReqUriInMergeDetectionEnabled();
|
||||
virtual bool checkReqUriInMergeDetectionEnabled() const;
|
||||
|
||||
/// Enabling this setting will allow the application layer to provide additional SIP responses, from class 4xx, 5xx, 6xx,
|
||||
/// that will lead to transaction termination instead of other failure effects like dialog termination, as defined by
|
||||
/// method Helper::determineFailureMessageEffect. (See header Helper.hxx for all transaction failure effects).
|
||||
/// A scenarui when this is useful is when, for a server subscription, a NOTIFY is responded with an error response due to a timeout
|
||||
/// condition, but the application needs the subscription to be continued. Even though RFC 3265 prescribes the
|
||||
/// notifier should remove the subscription in such cases, timeouts may occur for transient conditions like a
|
||||
/// overloaded proxy, a slow network connection, eventually nobody would benefit if the subscription is terminated by the server.
|
||||
/// With this setting enabled the subscription will be continued, but only until the subscription expires.
|
||||
/// Currently, it is only used by ServerSubscriptions.
|
||||
/// Default is to not allow additional transaction terminating responses
|
||||
/// To enable it:
|
||||
/// 1. Set 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:
|
||||
virtual UserProfile* clone() const;
|
||||
std::set<Data> mSupportedSchemes;
|
||||
|
|
@ -173,6 +209,9 @@ class MasterProfile : public UserProfile
|
|||
UInt32 mServerRegistrationMinExpires;
|
||||
UInt32 mServerRegistrationMaxExpires;
|
||||
UInt32 mServerRegistrationDefaultExpires;
|
||||
|
||||
bool mAdditionalTransactionTerminatingResponsesEnabled;
|
||||
std::set<int> mAdditionalTransactionTerminatingResponsess;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace resip
|
|||
class OutgoingEvent : public Message
|
||||
{
|
||||
public:
|
||||
//OutgoingEvent(std::unique_ptr<SipMessage> msg);
|
||||
//OutgoingEvent(std::auto_ptr<SipMessage> msg);
|
||||
OutgoingEvent(SharedPtr<SipMessage> msg);
|
||||
OutgoingEvent(const OutgoingEvent&);
|
||||
~OutgoingEvent();
|
||||
|
|
@ -27,7 +27,7 @@ class OutgoingEvent : public Message
|
|||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const;
|
||||
|
||||
private:
|
||||
//mutable std::unique_ptr<SipMessage> mMessage;
|
||||
//mutable std::auto_ptr<SipMessage> mMessage;
|
||||
SharedPtr<SipMessage> mMessage;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class ClientPagerMessageHandler
|
|||
virtual void onSuccess(ClientPagerMessageHandle, const SipMessage& status)=0;
|
||||
//!kh!
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Profile::Profile(SharedPtr<Profile> baseProfile) :
|
|||
mHasOutboundDecorator(false),
|
||||
mBaseProfile(baseProfile)
|
||||
{
|
||||
assert(baseProfile.get());
|
||||
resip_assert(baseProfile.get());
|
||||
|
||||
reset(); // default all settings to fallthrough to mBaseProfile
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ Profile::reset()
|
|||
unsetDefaultSessionTime();
|
||||
unsetDefaultSessionTimerMode();
|
||||
unset1xxRetransmissionTime();
|
||||
unset1xxRelResubmitTime();
|
||||
unsetOverrideHostAndPort();
|
||||
unsetAdvertisedCapabilities();
|
||||
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
|
||||
Profile::setOverrideHostAndPort(const Uri& hostPort)
|
||||
{
|
||||
|
|
@ -415,9 +448,10 @@ Profile::unsetOverrideHostAndPort()
|
|||
void
|
||||
Profile::addAdvertisedCapability(const Headers::Type header)
|
||||
{
|
||||
assert(header == Headers::Allow ||
|
||||
resip_assert(header == Headers::Allow ||
|
||||
header == Headers::AcceptEncoding ||
|
||||
header == Headers::AcceptLanguage ||
|
||||
header == Headers::AllowEvents ||
|
||||
header == Headers::Supported);
|
||||
|
||||
mAdvertisedCapabilities.insert(header);
|
||||
|
|
@ -474,7 +508,7 @@ Profile::getOutboundProxy() const
|
|||
{
|
||||
return mBaseProfile->getOutboundProxy();
|
||||
}
|
||||
assert(mHasOutboundProxy);
|
||||
resip_assert(mHasOutboundProxy);
|
||||
return mOutboundProxy;
|
||||
}
|
||||
|
||||
|
|
@ -606,7 +640,7 @@ Profile::getUserAgent() const
|
|||
{
|
||||
return mBaseProfile->getUserAgent();
|
||||
}
|
||||
assert(mHasUserAgent);
|
||||
resip_assert(mHasUserAgent);
|
||||
return mUserAgent;
|
||||
}
|
||||
|
||||
|
|
@ -642,7 +676,7 @@ Profile::getProxyRequires() const
|
|||
{
|
||||
return mBaseProfile->getProxyRequires();
|
||||
}
|
||||
assert(mHasProxyRequires);
|
||||
resip_assert(mHasProxyRequires);
|
||||
return mProxyRequires;
|
||||
}
|
||||
|
||||
|
|
@ -905,7 +939,7 @@ Profile::getUserAgentCapabilities() const
|
|||
{
|
||||
return mBaseProfile->getUserAgentCapabilities();
|
||||
}
|
||||
assert(mHasUserAgentCapabilities);
|
||||
resip_assert(mHasUserAgentCapabilities);
|
||||
return mUserAgentCapabilities;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,11 @@ class Profile
|
|||
virtual int get1xxRetransmissionTime() const;
|
||||
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
|
||||
///?dcm? -- also change via entries? Also, dum currently uses(as a uas)
|
||||
///the request uri of the dialog constructing request for the local contact
|
||||
|
|
@ -119,7 +124,7 @@ class Profile
|
|||
///enable/disable sending of Allow/Supported/Accept-Language/Accept-Encoding headers
|
||||
///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
|
||||
/// Currently implemented header values are: Headers::Allow,
|
||||
/// Currently implemented header values are: Headers::Allow, Headers::AllowEvents
|
||||
/// Headers::AcceptEncoding, Headers::AcceptLanguage, Headers::Supported
|
||||
virtual void addAdvertisedCapability(const Headers::Type header);
|
||||
virtual bool isAdvertisedCapability(const Headers::Type header) const;
|
||||
|
|
@ -262,6 +267,9 @@ class Profile
|
|||
bool mHas1xxRetransmissionTime;
|
||||
int m1xxRetransmissionTime;
|
||||
|
||||
bool mHas1xxRelResubmitTime;
|
||||
int m1xxRelResubmitTime;
|
||||
|
||||
bool mHasOutboundProxy;
|
||||
NameAddr mOutboundProxy;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "resip/dum/Handles.hxx"
|
||||
#include "resip/stack/Mime.hxx"
|
||||
#include "resip/stack/Contents.hxx"
|
||||
|
||||
namespace resip
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -22,87 +22,102 @@ using namespace std;
|
|||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
||||
RADIUSServerAuthManager::RADIUSServerAuthManager(resip::DialogUsageManager& dum) : ServerAuthManager(dum, dum.dumIncomingTarget()), dum(dum) {
|
||||
|
||||
RADIUSDigestAuthenticator::init(NULL);
|
||||
RADIUSServerAuthManager::RADIUSServerAuthManager(
|
||||
resip::DialogUsageManager& dum,
|
||||
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);
|
||||
void
|
||||
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 {
|
||||
|
||||
try
|
||||
{
|
||||
radiusListener = new MyRADIUSDigestAuthListener(user, realm, dum, transactionId);
|
||||
Data radiusUser(user + "@" + realm);
|
||||
Data radiusUser = user;
|
||||
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()));
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
if(result < 0)
|
||||
{
|
||||
ErrLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << msg.header(h_RequestLine).uri() <<" failed to start thread, error = " << result);
|
||||
}
|
||||
} catch(...) {
|
||||
WarningLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << s <<" exception");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
WarningLog(<<"RADIUSServerAuthManager::requestCredential, uri = " << msg.header(h_RequestLine).uri() <<" 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
|
||||
bool
|
||||
RADIUSServerAuthManager::useAuthInt() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
RADIUSServerAuthManager::onAuthSuccess(const resip::SipMessage& msg) {
|
||||
RADIUSServerAuthManager::onAuthSuccess(const resip::SipMessage& msg)
|
||||
{
|
||||
}
|
||||
|
||||
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) {
|
||||
case InvalidRequest:
|
||||
|
|
@ -117,32 +132,56 @@ RADIUSServerAuthManager::onAuthFailure(resip::ServerAuthManager::AuthFailureReas
|
|||
}
|
||||
Tuple sourceTuple = msg.getSource();
|
||||
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());
|
||||
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
|
||||
MyRADIUSDigestAuthListener::onSuccess(const resip::Data& rpid)
|
||||
{
|
||||
DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess");
|
||||
if(!rpid.empty())
|
||||
{
|
||||
DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess rpid = " << rpid.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog(<<"MyRADIUSDigestAuthListener::onSuccess, no rpid");
|
||||
}
|
||||
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::DigestAccepted, transactionId);
|
||||
tu.post(uai);
|
||||
}
|
||||
|
||||
void MyRADIUSDigestAuthListener::onAccessDenied() {
|
||||
void
|
||||
MyRADIUSDigestAuthListener::onAccessDenied()
|
||||
{
|
||||
DebugLog(<<"MyRADIUSDigestAuthListener::onAccessDenied");
|
||||
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::DigestNotAccepted, transactionId);
|
||||
tu.post(uai);
|
||||
}
|
||||
|
||||
void MyRADIUSDigestAuthListener::onError() {
|
||||
void
|
||||
MyRADIUSDigestAuthListener::onError()
|
||||
{
|
||||
WarningLog(<<"MyRADIUSDigestAuthListener::onError");
|
||||
UserAuthInfo *uai = new UserAuthInfo(user, realm, UserAuthInfo::Error, transactionId);
|
||||
tu.post(uai);
|
||||
|
|
@ -150,3 +189,41 @@ void MyRADIUSDigestAuthListener::onError() {
|
|||
|
||||
#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.
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -14,35 +14,39 @@
|
|||
namespace resip
|
||||
{
|
||||
|
||||
class RADIUSServerAuthManager : public resip::ServerAuthManager {
|
||||
|
||||
private:
|
||||
class RADIUSServerAuthManager : public resip::ServerAuthManager
|
||||
{
|
||||
private:
|
||||
resip::DialogUsageManager& dum;
|
||||
|
||||
public:
|
||||
RADIUSServerAuthManager(resip::DialogUsageManager& dum);
|
||||
public:
|
||||
RADIUSServerAuthManager(resip::DialogUsageManager& dum,
|
||||
TargetCommand::Target& target,
|
||||
const Data& configurationFile,
|
||||
bool challengeThirdParties = true,
|
||||
const Data& staticRealm = "");
|
||||
virtual ~RADIUSServerAuthManager();
|
||||
|
||||
protected:
|
||||
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);
|
||||
protected:
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
class MyRADIUSDigestAuthListener : public RADIUSDigestAuthListener {
|
||||
private:
|
||||
class MyRADIUSDigestAuthListener : public RADIUSDigestAuthListener
|
||||
{
|
||||
private:
|
||||
resip::Data user;
|
||||
resip::Data realm;
|
||||
resip::TransactionUser& tu;
|
||||
resip::Data transactionId;
|
||||
public:
|
||||
MyRADIUSDigestAuthListener(const resip::Data& user, const resip::Data& realm, resip::TransactionUser& tu, const resip::Data& transactionId);
|
||||
public:
|
||||
MyRADIUSDigestAuthListener(const resip::Data& user, const resip::Data& realm,
|
||||
resip::TransactionUser& tu, const resip::Data& transactionId);
|
||||
virtual ~MyRADIUSDigestAuthListener();
|
||||
void onSuccess(const resip::Data& rpid);
|
||||
void onAccessDenied();
|
||||
|
|
@ -55,3 +59,41 @@ public:
|
|||
|
||||
#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.
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ using namespace resip;
|
|||
bool
|
||||
RedirectManager::handle(DialogSet& dSet, SipMessage& origRequest, const SipMessage& response)
|
||||
{
|
||||
assert( response.isResponse() );
|
||||
assert( origRequest.isRequest() );
|
||||
resip_assert( response.isResponse() );
|
||||
resip_assert( origRequest.isRequest() );
|
||||
|
||||
//380, 305 fall through to the application
|
||||
int code = response.header(h_StatusLine).statusCode();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,13 @@ ClientRegistrationHandler::onFlowTerminated(ClientRegistrationHandle h)
|
|||
h->requestRefresh();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientRegistrationHandler::onRefreshRequired(ClientRegistrationHandle h, const SipMessage& lastRequest)
|
||||
{
|
||||
InfoLog(<<"ClientRegistrationHandler::onRefreshRequired, returning true");
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ServerRegistrationHandler::getGlobalExpires(const SipMessage& msg, SharedPtr<MasterProfile> masterProfile,
|
||||
UInt32 &expires, UInt32 &returnCode)
|
||||
|
|
@ -22,7 +29,7 @@ ServerRegistrationHandler::getGlobalExpires(const SipMessage& msg, SharedPtr<Mas
|
|||
if (!masterProfile)
|
||||
{
|
||||
returnCode = 500;
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +75,7 @@ ServerRegistrationHandler::getContactExpires(const NameAddr &contact, SharedPtr<
|
|||
if (!masterProfile)
|
||||
{
|
||||
returnCode = 500;
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ class ClientRegistrationHandler
|
|||
/// supports RFC5626 (outbound).
|
||||
/// Default implementation is to immediately re-Register in an attempt to form a new flow.
|
||||
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
|
||||
|
|
@ -102,8 +107,8 @@ class ServerRegistrationHandler
|
|||
*/
|
||||
virtual void asyncUpdateContacts(ServerRegistrationHandle,
|
||||
const Uri& aor,
|
||||
std::unique_ptr<ContactPtrList> modifiedContactList,
|
||||
std::unique_ptr<ContactRecordTransactionLog> transactionLog)
|
||||
std::auto_ptr<ContactPtrList> modifiedContactList,
|
||||
std::auto_ptr<ContactRecordTransactionLog> transactionLog)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +117,7 @@ class ServerRegistrationHandler
|
|||
*/
|
||||
virtual void asyncRemoveExpired(ServerRegistrationHandle,
|
||||
const resip::Uri& aor,
|
||||
std::unique_ptr<resip::ContactPtrList> contacts)
|
||||
std::auto_ptr<resip::ContactPtrList> contacts)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <cassert>
|
||||
#include "rutil/ResipAssert.h"
|
||||
|
||||
#include "resip/dum/ChallengeInfo.hxx"
|
||||
#include "resip/dum/DumFeature.hxx"
|
||||
|
|
@ -16,9 +16,10 @@
|
|||
using namespace resip;
|
||||
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),
|
||||
mChallengeThirdParties(challengeThirdParties)
|
||||
mChallengeThirdParties(challengeThirdParties),
|
||||
mStaticRealm(staticRealm)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -64,8 +65,8 @@ ServerAuthManager::process(Message* msg)
|
|||
{
|
||||
InfoLog(<< "ServerAuth got ChallengeInfo " << challengeInfo->brief());
|
||||
MessageMap::iterator it = mMessages.find(challengeInfo->getTransactionId());
|
||||
assert(it != mMessages.end());
|
||||
std::unique_ptr<SipMessage> sipMsg(it->second);
|
||||
resip_assert(it != mMessages.end());
|
||||
std::auto_ptr<SipMessage> sipMsg(it->second);
|
||||
mMessages.erase(it);
|
||||
|
||||
if(challengeInfo->isFailed())
|
||||
|
|
@ -88,7 +89,7 @@ ServerAuthManager::process(Message* msg)
|
|||
else
|
||||
{
|
||||
// challenge is not required, re-instate original message
|
||||
postCommand(std::move(sipMsg));
|
||||
postCommand(auto_ptr<Message>(sipMsg));
|
||||
return FeatureDoneAndEventDone;
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +104,7 @@ ServerAuthManager::process(Message* msg)
|
|||
Message* result = handleUserAuthInfo(userAuth);
|
||||
if (result)
|
||||
{
|
||||
postCommand(unique_ptr<Message>(result));
|
||||
postCommand(auto_ptr<Message>(result));
|
||||
return FeatureDoneAndEventDone;
|
||||
}
|
||||
else
|
||||
|
|
@ -119,10 +120,10 @@ ServerAuthManager::process(Message* msg)
|
|||
SipMessage*
|
||||
ServerAuthManager::handleUserAuthInfo(UserAuthInfo* userAuth)
|
||||
{
|
||||
assert(userAuth);
|
||||
resip_assert(userAuth);
|
||||
|
||||
MessageMap::iterator it = mMessages.find(userAuth->getTransactionId());
|
||||
assert(it != mMessages.end());
|
||||
resip_assert(it != mMessages.end());
|
||||
SipMessage* requestWithAuth = it->second;
|
||||
mMessages.erase(it);
|
||||
|
||||
|
|
@ -269,7 +270,7 @@ ServerAuthManager::rejectBadNonces() const
|
|||
}
|
||||
|
||||
|
||||
ServerAuthManager::AsyncBool
|
||||
AsyncBool
|
||||
ServerAuthManager::requiresChallenge(const SipMessage& msg)
|
||||
{
|
||||
if(!mChallengeThirdParties)
|
||||
|
|
@ -300,7 +301,7 @@ ServerAuthManager::authorizedForThisIdentity(const resip::Data &user,
|
|||
// header is the full fromUri, e.g.
|
||||
// Proxy-Authorization: Digest username="user@domain" ...
|
||||
//
|
||||
if ((fromUri.getAorNoPort() == user) && (fromUri.host() == realm))
|
||||
if (fromUri.getAorNoPort() == user)
|
||||
return true;
|
||||
|
||||
// catch-all: access denied
|
||||
|
|
@ -311,6 +312,19 @@ ServerAuthManager::authorizedForThisIdentity(const resip::Data &user,
|
|||
const Data&
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -318,6 +332,10 @@ ServerAuthManager::getChallengeRealm(const SipMessage& msg)
|
|||
bool
|
||||
ServerAuthManager::isMyRealm(const Data& realm)
|
||||
{
|
||||
if(!mStaticRealm.empty())
|
||||
{
|
||||
return mStaticRealm == realm;
|
||||
}
|
||||
return mDum.isMyDomain(realm);
|
||||
}
|
||||
|
||||
|
|
@ -327,9 +345,43 @@ ServerAuthManager::Result
|
|||
ServerAuthManager::handle(SipMessage* sipMsg)
|
||||
{
|
||||
//InfoLog( << "trying to do auth" );
|
||||
if (sipMsg->isRequest() &&
|
||||
sipMsg->header(h_RequestLine).method() != ACK &&
|
||||
sipMsg->header(h_RequestLine).method() != CANCEL) // Do not challenge ACKs or CANCELs
|
||||
if (sipMsg->isRequest())
|
||||
{
|
||||
if(sipMsg->method() == CANCEL)
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
// 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.
|
||||
if(it->second->isRequest() && it->second->method() == INVITE)
|
||||
{
|
||||
std::auto_ptr<SipMessage> inviteMsg(it->second);
|
||||
mMessages.erase(it); // Remove the INVITE from the message map and respond to it
|
||||
|
||||
InfoLog (<< "Received a CANCEL for an INVITE request that we are still waiting on auth "
|
||||
<< "info for, responding appropriately, tid="
|
||||
<< sipMsg->getTransactionId());
|
||||
|
||||
// Send 487/Inv
|
||||
SharedPtr<SipMessage> inviteResponse(new SipMessage);
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(sipMsg->method() != ACK) // Do not challenge ACKs or CANCELs (picked off above)
|
||||
{
|
||||
ParserContainer<Auth>* auths;
|
||||
if (proxyAuthenticationMode())
|
||||
|
|
@ -381,6 +433,7 @@ ServerAuthManager::handle(SipMessage* sipMsg)
|
|||
return Rejected;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Skipped;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
#include "rutil/AsyncBool.hxx"
|
||||
#include "resip/stack/Auth.hxx"
|
||||
#include "resip/stack/SipMessage.hxx"
|
||||
#include "DumFeature.hxx"
|
||||
|
|
@ -26,7 +27,7 @@ class ServerAuthManager : public DumFeature
|
|||
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 ProcessingResult process(Message* msg);
|
||||
|
|
@ -43,13 +44,6 @@ class ServerAuthManager : public DumFeature
|
|||
|
||||
protected:
|
||||
|
||||
enum AsyncBool
|
||||
{
|
||||
True, // response is true
|
||||
False, // response is false
|
||||
Async // response will be sent asynchronously
|
||||
};
|
||||
|
||||
enum AuthFailureReason
|
||||
{
|
||||
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 onAuthFailure(AuthFailureReason reason, const SipMessage& msg);
|
||||
|
||||
private:
|
||||
bool mChallengeThirdParties;
|
||||
resip::Data mStaticRealm;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -26,9 +26,14 @@ class ServerInviteSession: public InviteSession
|
|||
/** Called to set the offer that will be used in the next message that
|
||||
sends an offer. If possible, this will synchronously send the
|
||||
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, 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
|
||||
reinvite with no body to be sent. */
|
||||
|
|
@ -55,7 +60,7 @@ class ServerInviteSession: public InviteSession
|
|||
* Provide asynchronous method access by using command
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
|
|
@ -70,17 +75,17 @@ class ServerInviteSession: public InviteSession
|
|||
void dispatchWaitingToOffer(const SipMessage& msg);
|
||||
void dispatchWaitingToRequestOffer(const SipMessage& msg);
|
||||
void dispatchAcceptedWaitingAnswer(const SipMessage& msg);
|
||||
void dispatchOfferReliable(const SipMessage& msg);
|
||||
void dispatchNoOfferReliable(const SipMessage& msg);
|
||||
void dispatchFirstSentOfferReliable(const SipMessage& msg);
|
||||
void dispatchFirstEarlyReliable(const SipMessage& msg);
|
||||
void dispatchEarlyReliable(const SipMessage& msg);
|
||||
void dispatchOfferReliableProvidedAnswer(const SipMessage& msg);
|
||||
void dispatchFirstSentAnswerReliable(const SipMessage& msg);
|
||||
void dispatchNoAnswerReliableWaitingPrack(const SipMessage& msg);
|
||||
void dispatchSentUpdate(const SipMessage& msg);
|
||||
void dispatchSentUpdateGlare(const SipMessage& msg);
|
||||
void dispatchSentUpdateAccepted(const SipMessage& msg);
|
||||
void dispatchReceivedUpdate(const SipMessage& msg);
|
||||
void dispatchReceivedUpdateWaitingAnswer(const SipMessage& msg);
|
||||
void dispatchWaitingToTerminate(const SipMessage& msg);
|
||||
void dispatchWaitingToHangup(const SipMessage& msg);
|
||||
void dispatchNegotiatedReliable(const SipMessage& msg);
|
||||
|
||||
void dispatchCancel(const SipMessage& msg);
|
||||
void dispatchBye(const SipMessage& msg);
|
||||
|
|
@ -88,9 +93,15 @@ class ServerInviteSession: public InviteSession
|
|||
|
||||
// utilities
|
||||
void startRetransmit1xxTimer();
|
||||
void startResubmit1xxRelTimer();
|
||||
void startRetransmit1xxRelTimer();
|
||||
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);
|
||||
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);
|
||||
|
||||
|
|
@ -101,10 +112,14 @@ class ServerInviteSession: public InviteSession
|
|||
// stores the original request
|
||||
const SipMessage mFirstRequest;
|
||||
SharedPtr<SipMessage> m1xx; // for 1xx retransmissions
|
||||
unsigned long mCurrentRetransmit1xx;
|
||||
unsigned long mCurrentRetransmit1xxSeq;
|
||||
|
||||
//std::deque<SipMessage> mUnacknowledgedProvisionals; // all of them
|
||||
//SipMessage m200; // for retransmission
|
||||
// UAS Prack members
|
||||
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
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ ServerOutOfDialogReq::end()
|
|||
void
|
||||
ServerOutOfDialogReq::dispatch(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isRequest());
|
||||
resip_assert(msg.isRequest());
|
||||
|
||||
OutOfDialogHandler *pHandler = mDum.getOutOfDialogHandler(msg.header(h_CSeq).method());
|
||||
if(pHandler != NULL)
|
||||
|
|
@ -97,7 +97,7 @@ ServerOutOfDialogReq::answerOptions()
|
|||
void
|
||||
ServerOutOfDialogReq::send(SharedPtr<SipMessage> response)
|
||||
{
|
||||
assert(response->isResponse());
|
||||
resip_assert(response->isResponse());
|
||||
mDum.send(response);
|
||||
delete this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,15 +42,18 @@ ServerPagerMessage::end()
|
|||
class ServerPagerMessageEndCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ServerPagerMessageEndCommand(ServerPagerMessage& serverPagerMessage)
|
||||
: mServerPagerMessage(serverPagerMessage)
|
||||
ServerPagerMessageEndCommand(const ServerPagerMessageHandle& serverPagerMessageHandle)
|
||||
: mServerPagerMessageHandle(serverPagerMessageHandle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mServerPagerMessage.end();
|
||||
if(mServerPagerMessageHandle.isValid())
|
||||
{
|
||||
mServerPagerMessageHandle->end();
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -58,18 +61,18 @@ public:
|
|||
return strm << "ServerPagerMessageEndCommand";
|
||||
}
|
||||
private:
|
||||
ServerPagerMessage& mServerPagerMessage;
|
||||
ServerPagerMessageHandle mServerPagerMessageHandle;
|
||||
};
|
||||
|
||||
void ServerPagerMessage::endCommand()
|
||||
{
|
||||
mDum.post(new ServerPagerMessageEndCommand(*this));
|
||||
mDum.post(new ServerPagerMessageEndCommand(getHandle()));
|
||||
}
|
||||
|
||||
void
|
||||
ServerPagerMessage::dispatch(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isRequest());
|
||||
resip_assert(msg.isRequest());
|
||||
ServerPagerMessageHandler* handler = mDum.mServerPagerMessageHandler;
|
||||
|
||||
//?dcm? check in DialogUsageManager
|
||||
|
|
@ -91,7 +94,7 @@ ServerPagerMessage::dispatch(const DumTimeout& msg)
|
|||
void
|
||||
ServerPagerMessage::send(SharedPtr<SipMessage> response)
|
||||
{
|
||||
assert(response->isResponse());
|
||||
resip_assert(response->isResponse());
|
||||
mDum.send(response);
|
||||
delete this;
|
||||
}
|
||||
|
|
@ -108,15 +111,18 @@ ServerPagerMessage::accept(int statusCode)
|
|||
class ServerPagerMessageAcceptCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ServerPagerMessageAcceptCommand(ServerPagerMessage& serverPagerMessage, int statusCode)
|
||||
: mServerPagerMessage(serverPagerMessage),
|
||||
ServerPagerMessageAcceptCommand(const ServerPagerMessageHandle& serverPagerMessageHandle, int statusCode)
|
||||
: mServerPagerMessageHandle(serverPagerMessageHandle),
|
||||
mStatusCode(statusCode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mServerPagerMessage.accept(mStatusCode);
|
||||
if(mServerPagerMessageHandle.isValid())
|
||||
{
|
||||
mServerPagerMessageHandle->send(mServerPagerMessageHandle->accept(mStatusCode));
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -124,14 +130,14 @@ public:
|
|||
return strm << "ServerPagerMessageAcceptCommand";
|
||||
}
|
||||
private:
|
||||
ServerPagerMessage& mServerPagerMessage;
|
||||
ServerPagerMessageHandle mServerPagerMessageHandle;
|
||||
int mStatusCode;
|
||||
};
|
||||
|
||||
void
|
||||
ServerPagerMessage::acceptCommand(int statusCode)
|
||||
{
|
||||
mDum.post(new ServerPagerMessageAcceptCommand(*this, statusCode));
|
||||
mDum.post(new ServerPagerMessageAcceptCommand(getHandle(), statusCode));
|
||||
}
|
||||
|
||||
SharedPtr<SipMessage>
|
||||
|
|
@ -145,15 +151,18 @@ ServerPagerMessage::reject(int statusCode)
|
|||
class ServerPagerMessageRejectCommand : public DumCommandAdapter
|
||||
{
|
||||
public:
|
||||
ServerPagerMessageRejectCommand(ServerPagerMessage& serverPagerMessage, int statusCode)
|
||||
: mServerPagerMessage(serverPagerMessage),
|
||||
ServerPagerMessageRejectCommand(const ServerPagerMessageHandle& serverPagerMessageHandle, int statusCode)
|
||||
: mServerPagerMessageHandle(serverPagerMessageHandle),
|
||||
mStatusCode(statusCode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void executeCommand()
|
||||
{
|
||||
mServerPagerMessage.reject(mStatusCode);
|
||||
if(mServerPagerMessageHandle.isValid())
|
||||
{
|
||||
mServerPagerMessageHandle->send(mServerPagerMessageHandle->reject(mStatusCode));
|
||||
}
|
||||
}
|
||||
|
||||
virtual EncodeStream& encodeBrief(EncodeStream& strm) const
|
||||
|
|
@ -161,14 +170,14 @@ public:
|
|||
return strm << "ServerPagerMessageRejectCommand";
|
||||
}
|
||||
private:
|
||||
ServerPagerMessage& mServerPagerMessage;
|
||||
ServerPagerMessageHandle mServerPagerMessageHandle;
|
||||
int mStatusCode;
|
||||
};
|
||||
|
||||
void
|
||||
ServerPagerMessage::rejectCommand(int statusCode)
|
||||
{
|
||||
mDum.post(new ServerPagerMessageRejectCommand(*this, statusCode));
|
||||
mDum.post(new ServerPagerMessageRejectCommand(getHandle(), statusCode));
|
||||
}
|
||||
|
||||
EncodeStream&
|
||||
|
|
@ -180,7 +189,6 @@ ServerPagerMessage::dump(EncodeStream& strm) const
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* ====================================================================
|
||||
* The Vovida Software License, Version 1.0
|
||||
*
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "resip/dum/PublicationHandler.hxx"
|
||||
#include "resip/dum/ServerSubscription.hxx"
|
||||
#include "resip/dum/SubscriptionHandler.hxx"
|
||||
#include "resip/dum/PublicationPersistenceManager.hxx"
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "resip/stack/SecurityAttributes.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
|
|
@ -16,6 +17,7 @@ ServerPublication::ServerPublication(DialogUsageManager& dum,
|
|||
mLastResponse(new SipMessage),
|
||||
mEtag(etag),
|
||||
mEventType(msg.header(h_Event).value()),
|
||||
mDocumentKey(msg.header(h_RequestLine).uri().getAor()),
|
||||
mTimerSeq(0)
|
||||
{
|
||||
}
|
||||
|
|
@ -52,7 +54,7 @@ ServerPublication::getPublisher() const
|
|||
void
|
||||
ServerPublication::updateMatchingSubscriptions()
|
||||
{
|
||||
Data key = mEventType + mLastRequest.header(h_RequestLine).uri().getAor();
|
||||
Data key = mEventType + mDocumentKey;
|
||||
std::pair<DialogUsageManager::ServerSubscriptions::iterator,DialogUsageManager::ServerSubscriptions::iterator> subs;
|
||||
subs = mDum.mServerSubscriptions.equal_range(key);
|
||||
|
||||
|
|
@ -75,8 +77,6 @@ ServerPublication::accept(int statusCode)
|
|||
Helper::makeResponse(*mLastResponse, mLastRequest, statusCode);
|
||||
mLastResponse->header(h_Expires).value() = mExpires;
|
||||
|
||||
updateMatchingSubscriptions();
|
||||
|
||||
return mLastResponse;
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ ServerPublication::end()
|
|||
void
|
||||
ServerPublication::dispatch(const SipMessage& msg)
|
||||
{
|
||||
assert(msg.isRequest());
|
||||
resip_assert(msg.isRequest());
|
||||
ServerPublicationHandler* handler = mDum.getServerPublicationHandler(mEventType);
|
||||
mLastRequest = msg;
|
||||
mExpires = 3600; //bad
|
||||
|
|
@ -113,6 +113,15 @@ ServerPublication::dispatch(const SipMessage& msg)
|
|||
Helper::makeResponse(*mLastResponse, mLastRequest, 200);
|
||||
mLastResponse->header(h_Expires).value() = mExpires;
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
|
@ -134,6 +143,18 @@ ServerPublication::dispatch(const SipMessage& msg)
|
|||
}
|
||||
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());
|
||||
handler->onInitial(getHandle(), mEtag, msg,
|
||||
mLastBody.mContents.get(),
|
||||
|
|
@ -145,10 +166,19 @@ ServerPublication::dispatch(const SipMessage& msg)
|
|||
void
|
||||
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)
|
||||
{
|
||||
ServerPublicationHandler* handler = mDum.getServerPublicationHandler(mEventType);
|
||||
handler->onExpired(getHandle(), mEtag);
|
||||
|
||||
if (mDum.mPublicationPersistenceManager)
|
||||
{
|
||||
// Remove document from persistence manager
|
||||
mDum.mPublicationPersistenceManager->removeDocument(mEventType, mDocumentKey, mEtag, Timer::getTimeSecs());
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
|
@ -156,7 +186,7 @@ ServerPublication::dispatch(const DumTimeout& msg)
|
|||
void
|
||||
ServerPublication::send(SharedPtr<SipMessage> response)
|
||||
{
|
||||
assert(response->isResponse());
|
||||
resip_assert(response->isResponse());
|
||||
response->header(h_SIPETag).value() = mEtag;
|
||||
mDum.send(response);
|
||||
if (response->header(h_StatusLine).statusCode() >= 300)
|
||||
|
|
@ -165,7 +195,23 @@ ServerPublication::send(SharedPtr<SipMessage> response)
|
|||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class ServerPublication : public BaseUsage
|
|||
|
||||
const Data& getEtag() const;
|
||||
const Data& getDocumentKey() const;
|
||||
const Data& getEventType() const {return(mEventType);}
|
||||
|
||||
SharedPtr<SipMessage> accept(int statusCode = 200);
|
||||
SharedPtr<SipMessage> reject(int responseCode);
|
||||
|
|
@ -38,7 +39,6 @@ class ServerPublication : public BaseUsage
|
|||
private:
|
||||
friend class DialogUsageManager;
|
||||
ServerPublication(DialogUsageManager& dum, const Data& etag, const SipMessage& request);
|
||||
|
||||
SipMessage mLastRequest;
|
||||
SharedPtr<SipMessage> mLastResponse;
|
||||
const Data mEtag;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "rutil/DnsUtil.hxx"
|
||||
#include "rutil/Logger.hxx"
|
||||
#include "rutil/Timer.hxx"
|
||||
#include "rutil/TransportType.hxx"
|
||||
#include "rutil/WinLeakCheck.hxx"
|
||||
|
||||
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
|
||||
|
|
@ -81,12 +82,12 @@ ServerRegistration::accept(SipMessage& ok)
|
|||
{
|
||||
if (!mAsyncLocalStore.get())
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<ContactRecordTransactionLog> log;
|
||||
std::unique_ptr<ContactPtrList> contacts;
|
||||
std::auto_ptr<ContactRecordTransactionLog> log;
|
||||
std::auto_ptr<ContactPtrList> contacts;
|
||||
|
||||
mAsyncLocalStore->releaseLog(log,contacts);
|
||||
|
||||
|
|
@ -104,20 +105,20 @@ ServerRegistration::accept(SipMessage& ok)
|
|||
{
|
||||
if (!mAsyncLocalStore.get())
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return;
|
||||
}
|
||||
//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.
|
||||
mAsyncState = asyncStateAcceptedWaitingForFinalContactList;
|
||||
|
||||
std::unique_ptr<ContactRecordTransactionLog> log;
|
||||
std::unique_ptr<ContactPtrList> modifiedContacts;
|
||||
std::auto_ptr<ContactRecordTransactionLog> log;
|
||||
std::auto_ptr<ContactPtrList> modifiedContacts;
|
||||
|
||||
mAsyncLocalStore->releaseLog(log,modifiedContacts);
|
||||
|
||||
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.
|
||||
return;
|
||||
}
|
||||
|
|
@ -175,7 +176,7 @@ ServerRegistration::dispatch(const SipMessage& msg)
|
|||
{
|
||||
DebugLog( << "got a registration" );
|
||||
|
||||
assert(msg.isRequest());
|
||||
resip_assert(msg.isRequest());
|
||||
ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
|
||||
RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
|
||||
|
||||
|
|
@ -330,7 +331,10 @@ ServerRegistration::processRegistration(const SipMessage& msg)
|
|||
{
|
||||
rec.mInstance=i->param(p_Instance);
|
||||
}
|
||||
|
||||
if (msg.exists(h_UserAgent))
|
||||
{
|
||||
rec.mUserAgent = msg.header(h_UserAgent).value();
|
||||
}
|
||||
if(!msg.empty(h_Paths))
|
||||
{
|
||||
rec.mSipPath=msg.header(h_Paths);
|
||||
|
|
@ -431,7 +435,7 @@ ServerRegistration::processRegistration(const SipMessage& msg)
|
|||
return;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -499,6 +503,13 @@ ServerRegistration::tryFlow(ContactInstanceRecord& rec,
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(msg.header(h_Vias).size() > 1 && InteropHelper::getAssumeFirstHopSupportsFlowTokensEnabled())
|
||||
{
|
||||
rec.mUseFlowRouting = true;
|
||||
rec.mReceivedFrom.onlyUseExistingConnection=false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(resip::ParseBuffer::Exception&)
|
||||
{}
|
||||
|
|
@ -512,7 +523,10 @@ ServerRegistration::testFlowRequirements(ContactInstanceRecord &rec,
|
|||
{
|
||||
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
|
||||
// to have a flow.
|
||||
|
|
@ -560,7 +574,7 @@ ServerRegistration::flowTokenNeededForTls(const ContactInstanceRecord &rec) cons
|
|||
if(contact.uri().exists(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
|
||||
// we'll try anyway.
|
||||
|
|
@ -612,7 +626,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
|
|||
ContactPtrList::iterator it(contacts.begin());
|
||||
ContactPtrList::iterator itEnd(contacts.end());
|
||||
|
||||
std::unique_ptr<ContactPtrList> expired;
|
||||
std::auto_ptr<ContactPtrList> expired;
|
||||
|
||||
UInt64 now=Timer::getTimeSecs();
|
||||
|
||||
|
|
@ -622,7 +636,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
|
|||
|
||||
if (!rec)
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -630,7 +644,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
|
|||
{
|
||||
if (!expired.get())
|
||||
{
|
||||
expired = std::unique_ptr<ContactPtrList>(new ContactPtrList());
|
||||
expired = std::auto_ptr<ContactPtrList>(new ContactPtrList());
|
||||
}
|
||||
expired->push_back(rec);
|
||||
continue;
|
||||
|
|
@ -642,7 +656,7 @@ ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &cont
|
|||
|
||||
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.
|
||||
return;
|
||||
}
|
||||
|
|
@ -677,32 +691,32 @@ ServerRegistration::processFinalOkMsg(SipMessage &msg, ContactList &contacts)
|
|||
}
|
||||
|
||||
bool
|
||||
ServerRegistration::asyncProvideContacts(std::unique_ptr<resip::ContactPtrList> contacts)
|
||||
ServerRegistration::asyncProvideContacts(std::auto_ptr<resip::ContactPtrList> contacts)
|
||||
{
|
||||
switch (mAsyncState)
|
||||
{
|
||||
case asyncStateWaitingForInitialContactList:
|
||||
{
|
||||
assert(mAsyncLocalStore.get() == 0);
|
||||
mAsyncLocalStore = resip::SharedPtr<AsyncLocalStore>(new AsyncLocalStore(std::move(contacts)));
|
||||
resip_assert(mAsyncLocalStore.get() == 0);
|
||||
mAsyncLocalStore = resip::SharedPtr<AsyncLocalStore>(new AsyncLocalStore(contacts));
|
||||
mAsyncState = asyncStateProcessingRegistration;
|
||||
processRegistration(mRequest);
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
case asyncStateAcceptedWaitingForFinalContactList:
|
||||
{
|
||||
mAsyncState = asyncStateProvidedFinalContacts;
|
||||
asyncProcessFinalContacts(std::move(contacts));
|
||||
asyncProcessFinalContacts(contacts);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -711,13 +725,13 @@ ServerRegistration::asyncProvideContacts(std::unique_ptr<resip::ContactPtrList>
|
|||
}
|
||||
|
||||
void
|
||||
ServerRegistration::asyncProcessFinalContacts(std::unique_ptr<resip::ContactPtrList> contacts)
|
||||
ServerRegistration::asyncProcessFinalContacts(std::auto_ptr<resip::ContactPtrList> contacts)
|
||||
{
|
||||
if (contacts.get())
|
||||
{
|
||||
if (!mAsyncOkMsg.get())
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -732,10 +746,10 @@ ServerRegistration::asyncProcessFinalContacts(std::unique_ptr<resip::ContactPtrL
|
|||
}
|
||||
|
||||
void
|
||||
ServerRegistration::AsyncLocalStore::create(std::unique_ptr<ContactPtrList> originalContacts)
|
||||
ServerRegistration::AsyncLocalStore::create(std::auto_ptr<ContactPtrList> originalContacts)
|
||||
{
|
||||
mModifiedContacts = std::move(originalContacts);
|
||||
mLog = std::unique_ptr<ContactRecordTransactionLog>(new ContactRecordTransactionLog());
|
||||
mModifiedContacts = originalContacts;
|
||||
mLog = std::auto_ptr<ContactRecordTransactionLog>(new ContactRecordTransactionLog());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -750,7 +764,7 @@ ServerRegistration::AsyncLocalStore::updateContact(const ContactInstanceRecord &
|
|||
{
|
||||
if (!mModifiedContacts.get() || !mLog.get())
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return RegistrationPersistenceManager::CONTACT_UPDATED;
|
||||
}
|
||||
|
||||
|
|
@ -789,7 +803,7 @@ ServerRegistration::AsyncLocalStore::removeContact(const ContactInstanceRecord &
|
|||
{
|
||||
if (!mModifiedContacts.get() || !mLog.get())
|
||||
{
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class ServerRegistration: public NonDialogUsage
|
|||
|
||||
!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
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -140,9 +140,9 @@ class ServerRegistration: public NonDialogUsage
|
|||
{
|
||||
public:
|
||||
|
||||
AsyncLocalStore(std::unique_ptr<ContactPtrList> originalContacts)
|
||||
AsyncLocalStore(std::auto_ptr<ContactPtrList> originalContacts)
|
||||
{
|
||||
create(std::move(originalContacts));
|
||||
create(originalContacts);
|
||||
}
|
||||
|
||||
~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
|
||||
message.
|
||||
*/
|
||||
void create(std::unique_ptr<ContactPtrList> originalContacts);
|
||||
void create(std::auto_ptr<ContactPtrList> originalContacts);
|
||||
|
||||
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
|
||||
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);
|
||||
modifiedContacts = std::move(mModifiedContacts);
|
||||
log = mLog;
|
||||
modifiedContacts = mModifiedContacts;
|
||||
}
|
||||
|
||||
unsigned int numContacts() { if(mModifiedContacts.get()) return (unsigned int)mModifiedContacts->size(); return 0; }
|
||||
private:
|
||||
std::unique_ptr<ContactRecordTransactionLog> mLog;
|
||||
std::unique_ptr<ContactPtrList> mModifiedContacts;
|
||||
std::auto_ptr<ContactRecordTransactionLog> mLog;
|
||||
std::auto_ptr<ContactPtrList> mModifiedContacts;
|
||||
};
|
||||
|
||||
resip::SharedPtr<AsyncLocalStore> mAsyncLocalStore;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "resip/dum/ServerSubscription.hxx"
|
||||
#include "resip/dum/SubscriptionHandler.hxx"
|
||||
#include "resip/dum/UsageUseException.hxx"
|
||||
#include "resip/dum/MasterProfile.hxx"
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "rutil/Logger.hxx"
|
||||
|
||||
|
|
@ -73,7 +74,9 @@ ServerSubscription::getTimeLeft()
|
|||
SharedPtr<SipMessage>
|
||||
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;
|
||||
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__);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void ServerSubscription::terminateSubscription(ServerSubscriptionHandler* handler)
|
||||
{
|
||||
handler->onTerminated(getHandle());
|
||||
delete this;
|
||||
}
|
||||
|
||||
void
|
||||
ServerSubscription::send(SharedPtr<SipMessage> msg)
|
||||
{
|
||||
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
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();
|
||||
if (code < 200)
|
||||
{
|
||||
|
|
@ -119,8 +131,7 @@ ServerSubscription::send(SharedPtr<SipMessage> msg)
|
|||
else if (code < 400)
|
||||
{
|
||||
DialogUsage::send(msg);
|
||||
handler->onTerminated(getHandle());
|
||||
delete this;
|
||||
terminateSubscription(handler);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
|
@ -128,8 +139,7 @@ ServerSubscription::send(SharedPtr<SipMessage> msg)
|
|||
if (shouldDestroyAfterSendingFailure(*msg))
|
||||
{
|
||||
DialogUsage::send(msg);
|
||||
handler->onTerminated(getHandle());
|
||||
delete this;
|
||||
terminateSubscription(handler);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
|
@ -143,8 +153,7 @@ ServerSubscription::send(SharedPtr<SipMessage> msg)
|
|||
DialogUsage::send(msg);
|
||||
if (mSubscriptionState == Terminated)
|
||||
{
|
||||
handler->onTerminated(getHandle());
|
||||
delete this;
|
||||
terminateSubscription(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +167,7 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
|
|||
case SubDlgInitial:
|
||||
return true;
|
||||
case SubDlgTerminating: //terminated state not using in ServerSubscription
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
return true;
|
||||
case SubDlgEstablished:
|
||||
{
|
||||
|
|
@ -166,7 +175,7 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
|
|||
{
|
||||
return true;
|
||||
}
|
||||
switch (Helper::determineFailureMessageEffect(*mLastResponse))
|
||||
switch (Helper::determineFailureMessageEffect(msg))
|
||||
{
|
||||
case Helper::TransactionTermination:
|
||||
case Helper::RetryAfter:
|
||||
|
|
@ -187,9 +196,8 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
|
|||
break;
|
||||
}
|
||||
default: // !jf!
|
||||
assert(0);
|
||||
resip_assert(0);
|
||||
break;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -197,23 +205,31 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
|
|||
void
|
||||
ServerSubscription::setSubscriptionState(SubscriptionState state)
|
||||
{
|
||||
// Don't allow a transition out of Terminated state
|
||||
if (mSubscriptionState != Terminated)
|
||||
{
|
||||
mSubscriptionState = state;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServerSubscription::dispatch(const SipMessage& msg)
|
||||
{
|
||||
DebugLog( << "ServerSubscriptionHandler::dispatch: " << msg.brief());
|
||||
DebugLog( << "ServerSubscription::dispatch: " << msg.brief());
|
||||
|
||||
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
|
||||
if (msg.isRequest())
|
||||
{
|
||||
//!dcm! -- need to have a mechanism to retrieve default & acceptable
|
||||
//expiration times for an event package--part of handler API?
|
||||
//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;
|
||||
handler->getExpires(msg,mExpires,errorResponseCode);
|
||||
|
|
@ -244,7 +260,11 @@ ServerSubscription::dispatch(const SipMessage& msg)
|
|||
*/
|
||||
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;
|
||||
|
||||
if (mEventType != "refer" )
|
||||
{
|
||||
handler->onNewSubscription(getHandle(), msg);
|
||||
|
|
@ -253,16 +273,21 @@ ServerSubscription::dispatch(const SipMessage& 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);
|
||||
|
||||
mDialog.makeResponse(*mLastResponse, mLastSubscribe, 200);
|
||||
// Send 200 response to sender
|
||||
mLastResponse->header(h_Expires).value() = mExpires;
|
||||
send(mLastResponse);
|
||||
|
||||
send(mLastRequest); // Send Notify Expires
|
||||
// Send Notify Expires
|
||||
send(mLastRequest);
|
||||
return;
|
||||
}
|
||||
if (mSubscriptionState == Invalid)
|
||||
|
|
@ -289,25 +314,33 @@ ServerSubscription::dispatch(const SipMessage& msg)
|
|||
else
|
||||
{
|
||||
//.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();
|
||||
if (code < 300)
|
||||
|
||||
if(code < 200)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (code < 300)
|
||||
{
|
||||
handler->onNotifyAccepted(getHandle(), msg);
|
||||
return;
|
||||
}
|
||||
else if (code < 400)
|
||||
{
|
||||
//in dialog NOTIFY got redirected? Bizarre...
|
||||
handler->onError(getHandle(), msg);
|
||||
handler->onTerminated(getHandle());
|
||||
delete this;
|
||||
terminateSubscription(handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(Helper::determineFailureMessageEffect(msg))
|
||||
switch(Helper::determineFailureMessageEffect(msg,
|
||||
(mDum.getMasterProfile()->additionalTransactionTerminatingResponsesEnabled()) ?
|
||||
&mDum.getMasterProfile()->getAdditionalTransactionTerminatingResponses() : NULL))
|
||||
{
|
||||
case Helper::TransactionTermination:
|
||||
DebugLog( << "ServerSubscriptionHandler::TransactionTermination: " << msg.brief());
|
||||
DebugLog( << "ServerSubscription::TransactionTermination: " << msg.brief());
|
||||
handler->onNotifyRejected(getHandle(), msg);
|
||||
break;
|
||||
case Helper::UsageTermination:
|
||||
|
|
@ -315,10 +348,9 @@ ServerSubscription::dispatch(const SipMessage& msg)
|
|||
case Helper::OptionalRetryAfter:
|
||||
case Helper::ApplicationDependant:
|
||||
case Helper::DialogTermination:
|
||||
DebugLog( << "ServerSubscriptionHandler::UsageTermination: " << msg.brief());
|
||||
DebugLog( << "ServerSubscription::UsageTermination: " << msg.brief());
|
||||
handler->onError(getHandle(), msg);
|
||||
handler->onTerminated(getHandle());
|
||||
delete this;
|
||||
terminateSubscription(handler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -336,6 +368,10 @@ ServerSubscription::makeNotifyExpires()
|
|||
void
|
||||
ServerSubscription::makeNotify()
|
||||
{
|
||||
if (mLastRequest.get() == 0)
|
||||
{
|
||||
mLastRequest.reset(new SipMessage);
|
||||
}
|
||||
mDialog.makeRequest(*mLastRequest, NOTIFY);
|
||||
mLastRequest->header(h_SubscriptionState).value() = getSubscriptionStateString(mSubscriptionState);
|
||||
if (mSubscriptionState == Terminated)
|
||||
|
|
@ -356,8 +392,10 @@ ServerSubscription::makeNotify()
|
|||
|
||||
|
||||
void
|
||||
ServerSubscription::end(TerminateReason reason, const Contents* document)
|
||||
ServerSubscription::end(TerminateReason reason, const Contents* document, int retryAfter)
|
||||
{
|
||||
if (mSubscriptionState != Terminated) // NoOp if called twice or already ending
|
||||
{
|
||||
mSubscriptionState = Terminated;
|
||||
makeNotify();
|
||||
mLastRequest->header(h_SubscriptionState).param(p_reason) = getTerminateReasonString(reason);
|
||||
|
|
@ -365,7 +403,12 @@ ServerSubscription::end(TerminateReason reason, const Contents* document)
|
|||
{
|
||||
mLastRequest->setContents(document);
|
||||
}
|
||||
if (retryAfter != 0)
|
||||
{
|
||||
mLastRequest->header(h_SubscriptionState).param(p_retryAfter) = retryAfter;
|
||||
}
|
||||
send(mLastRequest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -377,11 +420,11 @@ ServerSubscription::end()
|
|||
void
|
||||
ServerSubscription::dispatch(const DumTimeout& timeout)
|
||||
{
|
||||
assert(timeout.type() == DumTimeout::Subscription);
|
||||
resip_assert(timeout.type() == DumTimeout::Subscription);
|
||||
if (timeout.seq() == mTimerSeq)
|
||||
{
|
||||
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
makeNotifyExpires();
|
||||
handler->onExpired(getHandle(), *mLastRequest);
|
||||
send(mLastRequest);
|
||||
|
|
@ -404,21 +447,11 @@ ServerSubscription::neutralNotify()
|
|||
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
|
||||
ServerSubscription::onReadyToSend(SipMessage& msg)
|
||||
{
|
||||
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
handler->onReadyToSend(getHandle(), msg);
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +460,7 @@ ServerSubscription::flowTerminated()
|
|||
{
|
||||
// notify handler
|
||||
ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
|
||||
assert(handler);
|
||||
resip_assert(handler);
|
||||
handler->onFlowTerminated(getHandle());
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +471,6 @@ ServerSubscription::dump(EncodeStream& strm) const
|
|||
return strm;
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================
|
||||
* The Vovida Software License, Version 1.0
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
#if !defined(RESIP_SERVERSUBSCRIPTION_HXX)
|
||||
#define RESIP_SERVERSUBSCRIPTION_HXX
|
||||
|
||||
#include "resip/stack/Helper.hxx"
|
||||
#include "resip/dum/BaseSubscription.hxx"
|
||||
|
||||
namespace resip
|
||||
{
|
||||
|
||||
class DialogUsageManager;
|
||||
class ServerSubscriptionHandler;
|
||||
|
||||
//!dcm! -- no Subscription State expires parameter generation yet.
|
||||
class ServerSubscription : public BaseSubscription
|
||||
|
|
@ -30,7 +32,7 @@ class ServerSubscription : public BaseSubscription
|
|||
void setSubscriptionState(SubscriptionState state);
|
||||
|
||||
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 send(SharedPtr<SipMessage> msg);
|
||||
|
|
@ -49,7 +51,6 @@ class ServerSubscription : public BaseSubscription
|
|||
|
||||
protected:
|
||||
virtual ~ServerSubscription();
|
||||
virtual void dialogDestroyed(const SipMessage& msg);
|
||||
void onReadyToSend(SipMessage& msg);
|
||||
virtual void flowTerminated();
|
||||
|
||||
|
|
@ -63,11 +64,9 @@ class ServerSubscription : public BaseSubscription
|
|||
|
||||
bool shouldDestroyAfterSendingFailure(const SipMessage& msg);
|
||||
|
||||
void terminateSubscription(ServerSubscriptionHandler* handler);
|
||||
|
||||
Data mSubscriber;
|
||||
|
||||
// const Contents* mCurrentEventDocument;
|
||||
SipMessage mLastSubscribe;
|
||||
|
||||
UInt32 mExpires;
|
||||
|
||||
// disabled
|
||||
|
|
|
|||
|
|
@ -133,6 +133,10 @@ ServerSubscriptionHandler::onPublished(ServerSubscriptionHandle associated,
|
|||
// do nothing by default
|
||||
}
|
||||
|
||||
void
|
||||
ServerSubscriptionHandler::onNotifyAccepted(ServerSubscriptionHandle h, const SipMessage& msg)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ServerSubscriptionHandler::onNotifyRejected(ServerSubscriptionHandle h, const SipMessage& msg)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class ClientSubscriptionHandler
|
|||
|
||||
//subscription can be ended through a notify or a failure response.
|
||||
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;
|
||||
|
||||
/// called to allow app to adorn a message.
|
||||
|
|
@ -48,11 +48,15 @@ class ServerSubscriptionHandler
|
|||
virtual void onNewSubscription(ServerSubscriptionHandle, const SipMessage& sub)=0;
|
||||
virtual void onNewSubscriptionFromRefer(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,
|
||||
ServerPublicationHandle publication,
|
||||
const Contents* contents,
|
||||
const SecurityAttributes* attrs);
|
||||
|
||||
virtual void onNotifyAccepted(ServerSubscriptionHandle, const SipMessage& msg);
|
||||
virtual void onNotifyRejected(ServerSubscriptionHandle, const SipMessage& msg);
|
||||
|
||||
//called when this usage is destroyed for any reason. One of the following
|
||||
|
|
|
|||
|
|
@ -7,21 +7,21 @@ using namespace std;
|
|||
|
||||
|
||||
TargetCommand::TargetCommand(Target& target,
|
||||
unique_ptr<Message> message)
|
||||
auto_ptr<Message> message)
|
||||
: mTarget(target),
|
||||
mMessage(std::move(message))
|
||||
mMessage(message)
|
||||
{
|
||||
}
|
||||
|
||||
TargetCommand::TargetCommand(const TargetCommand& from)
|
||||
: mTarget(from.mTarget),
|
||||
mMessage(std::move(from.mMessage))
|
||||
mMessage(from.mMessage)
|
||||
{
|
||||
}
|
||||
|
||||
void TargetCommand::executeCommand()
|
||||
{
|
||||
mTarget.post(std::move(mMessage));
|
||||
mTarget.post(mMessage);
|
||||
}
|
||||
|
||||
Message* TargetCommand::clone() const
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ class TargetCommand : public DumCommand
|
|||
{
|
||||
}
|
||||
virtual ~Target()=0;
|
||||
virtual void post(std::unique_ptr<Message>)=0;
|
||||
virtual void post(std::auto_ptr<Message>)=0;
|
||||
|
||||
protected:
|
||||
DialogUsageManager& mDum;
|
||||
};
|
||||
|
||||
TargetCommand(Target& target, std::unique_ptr<Message> message);
|
||||
TargetCommand(Target& target, std::auto_ptr<Message> message);
|
||||
TargetCommand(const TargetCommand&);
|
||||
void executeCommand();
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ class TargetCommand : public DumCommand
|
|||
|
||||
private:
|
||||
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
Loading…
Reference in New Issue