- start upgrade to resiprocate 1.12

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

View File

@ -58,7 +58,6 @@ set (STACK_SOURCES
resip/stack/DeprecatedDialog.cxx
resip/stack/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
)

View File

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

View File

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

View File

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

View File

@ -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"

View File

@ -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);
}

View File

@ -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()
{
}

View File

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

View File

@ -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;

View File

@ -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&

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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)
{
@ -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;
};
}
@ -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
*

View File

@ -42,7 +42,6 @@ class ClientAuthManager
// bool operator()(const Auth& lhs, const Auth& rhs) const;
// };
class RealmState
{
public:
@ -74,9 +73,6 @@ 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;
@ -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;

View File

@ -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());
@ -680,7 +687,7 @@ ClientInviteSession::dispatchStart (const SipMessage& msg)
}
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()))
{
@ -1362,19 +1410,26 @@ ClientInviteSession::dispatchSentUpdateEarlyGlare (const SipMessage& msg)
void
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)

View File

@ -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&);

View File

@ -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)
{

View File

@ -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,63 +123,88 @@ 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());
{
assert(mMsgQueue.empty() == false);
if (code < 200)
{
DebugLog ( << "ClientPagerMessageReq::dispatch - encountered provisional response" << msg.brief() );
}
else if (code < 300)
{
// 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)
{
@ -190,12 +214,21 @@ ClientPagerMessage::dispatch(const SipMessage& msg)
{
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)
@ -203,11 +236,17 @@ ClientPagerMessage::dispatch(const SipMessage& msg)
Contents* p = contents->contents;
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()));
}
}
}
}
}
@ -262,7 +301,7 @@ ClientPagerMessage::msgQueued () const
void
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);

View File

@ -23,19 +23,29 @@ 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);

View File

@ -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

View File

@ -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;

View File

@ -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/>.
*
*/

View File

@ -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

View File

@ -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,
// 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;
}
@ -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)
{

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

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

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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)
{
@ -345,11 +345,11 @@ DialogSet::dispatch(const SipMessage& msg)
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()));
@ -978,6 +993,30 @@ DialogSet::end()
}
}
}
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;
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
*/

View File

@ -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;
};
}

View File

@ -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)
{
@ -2442,11 +2520,15 @@ 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
DialogUsageManager::removeMergedRequest(const MergedRequestKey& key)
@ -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

View File

@ -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;

View File

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

View File

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

View File

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

View File

@ -40,7 +40,7 @@ class DumFeature
// taken ownership of msg until we get a return. If we throw, the
// 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;

View File

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

View File

@ -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;

View File

@ -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();
}

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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/>.
*
*/

View File

@ -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*

View File

@ -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;
};

View File

@ -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

View File

@ -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;

View File

@ -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);
};
}

View File

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

View File

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

View File

@ -54,8 +54,7 @@ contactsRemoveIfRequired(ContactList& contacts, UInt64& now,
}
InMemorySyncRegDb::InMemorySyncRegDb(unsigned int removeLingerSecs) :
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);
}
}
}
@ -163,11 +211,18 @@ InMemorySyncRegDb::getAors(InMemorySyncRegDb::UriList& container)
bool
InMemorySyncRegDb::aorIsRegistered(const Uri& aor)
{
Lock g(mDatabaseMutex);
database_map_t::iterator i = mDatabase.find(aor);
if (i != mDatabase.end() && i->second == 0)
return aorIsRegistered(aor, 0);
}
bool
InMemorySyncRegDb::aorIsRegistered(const Uri& aor, UInt64* maxExpires)
{
if(mRemoveLingerSecs > 0)
Lock g(mDatabaseMutex);
bool registered = false;
database_map_t::iterator i = mDatabase.find(aor);
if (i != mDatabase.end() && i->second != 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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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)
{

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
#include "resip/dum/Profile.hxx"
#include "resip/dum/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
*

View File

@ -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;
};
}

View File

@ -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;
};

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

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

View File

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

View File

@ -22,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.
*
* ====================================================================
*
*
*/

View File

@ -14,35 +14,39 @@
namespace resip
{
class RADIUSServerAuthManager : public resip::ServerAuthManager {
class RADIUSServerAuthManager : public resip::ServerAuthManager
{
private:
resip::DialogUsageManager& dum;
public:
RADIUSServerAuthManager(resip::DialogUsageManager& dum);
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);
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 {
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);
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.
*
* ====================================================================
*
*
*/

View File

@ -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();

View File

@ -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;
}

View File

@ -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)
{
}
};

View File

@ -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;
}

View File

@ -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

View File

@ -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
};
}

View File

@ -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;
}

View File

@ -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
*

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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,33 +196,40 @@ ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
break;
}
default: // !jf!
assert(0);
resip_assert(0);
break;
}
return false;
}
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,7 +392,9 @@ 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();
@ -365,8 +403,13 @@ ServerSubscription::end(TerminateReason reason, const Contents* document)
{
mLastRequest->setContents(document);
}
if (retryAfter != 0)
{
mLastRequest->header(h_SubscriptionState).param(p_retryAfter) = retryAfter;
}
send(mLastRequest);
}
}
void
ServerSubscription::end()
@ -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
*

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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