|
reSIProcate/DialogUsageManager
9694
|
dcm! -- update contact in dialog if required More...
#include <ClientSubscription.hxx>


Classes | |
| class | QueuedNotify |
Public Types | |
| typedef Handle < ClientSubscription > | ClientSubscriptionHandle |
Public Member Functions | |
| ClientSubscription (DialogUsageManager &dum, Dialog &dialog, const SipMessage &request, UInt32 defaultSubExpiration) | |
| ClientSubscriptionHandle | getHandle () |
| void | acceptUpdate (int statusCode=200, const char *reason=0) |
| void | rejectUpdate (int statusCode=400, const Data &reasonPhrase=Data::Empty) |
| void | requestRefresh (UInt32 expires=0) |
| virtual void | end () |
| void | end (bool immediate) |
| virtual void | reSubscribe () |
| void | acceptUpdateCommand (int statusCode=200, const char *reason=0) |
| Provide asynchronous method access by using command. | |
| void | rejectUpdateCommand (int statusCode=400, const Data &reasonPhrase=Data::Empty) |
| void | requestRefreshCommand (UInt32 expires=0) |
| virtual void | endCommand (bool immediate=false) |
| virtual EncodeStream & | dump (EncodeStream &strm) const |
Protected Member Functions | |
| virtual | ~ClientSubscription () |
| virtual void | dialogDestroyed (const SipMessage &msg) |
| virtual void | onReadyToSend (SipMessage &msg) |
| virtual void | send (SharedPtr< SipMessage > msg) |
| virtual void | flowTerminated () |
Private Types | |
| typedef std::deque < QueuedNotify * > | NotifyQueue |
| typedef std::vector < QueuedNotify * > | Dustbin |
Private Member Functions | |
| virtual void | dispatch (const SipMessage &msg) |
| virtual void | dispatch (const DumTimeout &timer) |
| void | sendQueuedRefreshRequest () |
| void | processNextNotify () |
| void | processResponse (const SipMessage &response) |
| void | clearDustbin () |
| void | scheduleRefresh (unsigned long refreshInterval) |
| ClientSubscription (const ClientSubscription &) | |
| ClientSubscription & | operator= (const ClientSubscription &) |
Private Attributes | |
| NotifyQueue | mQueuedNotifies |
| Dustbin | mDustbin |
| bool | mOnNewSubscriptionCalled |
| bool | mEnded |
| UInt64 | mNextRefreshSecs |
| UInt64 | mLastSubSecs |
| UInt32 | mDefaultExpires |
| bool | mRefreshing |
| bool | mHaveQueuedRefresh |
| int | mQueuedRefreshInterval |
| unsigned int | mLargestNotifyCSeq |
Friends | |
| class | Dialog |
| class | InviteSession |
dcm! -- update contact in dialog if required
Definition at line 14 of file ClientSubscription.hxx.
Definition at line 20 of file ClientSubscription.hxx.
typedef std::vector<QueuedNotify*> resip::ClientSubscription::Dustbin [private] |
Definition at line 68 of file ClientSubscription.hxx.
typedef std::deque<QueuedNotify*> resip::ClientSubscription::NotifyQueue [private] |
Definition at line 65 of file ClientSubscription.hxx.
| ClientSubscription::ClientSubscription | ( | DialogUsageManager & | dum, |
| Dialog & | dialog, | ||
| const SipMessage & | request, | ||
| UInt32 | defaultSubExpiration | ||
| ) |
Definition at line 21 of file ClientSubscription.cxx.
References resip::Message::brief(), DebugLog, resip::Dialog::makeRequest(), resip::DialogUsage::mDialog, resip::SipMessage::method(), and resip::BaseSubscription::mLastRequest.
: 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), mRefreshing(false), mHaveQueuedRefresh(false), mQueuedRefreshInterval(-1), mLargestNotifyCSeq(0) { DebugLog (<< "ClientSubscription::ClientSubscription from " << request.brief()); if(request.method() == SUBSCRIBE) { *mLastRequest = request; if (defaultSubExpiration > 0) { mLastRequest->header(h_Expires).value() = defaultSubExpiration; } } else { // If a NOTIFY request is use to make this ClientSubscription, then create the implied SUBSCRIBE // request as the mLastRequest mDialog.makeRequest(*mLastRequest, SUBSCRIBE); } }

| ClientSubscription::~ClientSubscription | ( | ) | [protected, virtual] |
Definition at line 51 of file ClientSubscription.cxx.
References clearDustbin(), resip::Dialog::mClientSubscriptions, resip::DialogUsage::mDialog, and mQueuedNotifies.
{
mDialog.mClientSubscriptions.remove(this);
while (!mQueuedNotifies.empty())
{
delete mQueuedNotifies.front();
mQueuedNotifies.pop_front();
}
clearDustbin();
}

| resip::ClientSubscription::ClientSubscription | ( | const ClientSubscription & | ) | [private] |
| void ClientSubscription::acceptUpdate | ( | int | statusCode = 200, |
| const char * | reason = 0 |
||
| ) |
Definition at line 616 of file ClientSubscription.cxx.
References h_StatusLine, InfoLog, resip::Dialog::makeResponse(), resip::DialogUsage::mDialog, mDustbin, resip::BaseSubscription::mLastResponse, mQueuedNotifies, resip::ClientSubscription::QueuedNotify::notify(), and send().
Referenced by processNextNotify().
{
assert(!mQueuedNotifies.empty());
if (mQueuedNotifies.empty())
{
InfoLog(<< "No queued notify to accept");
return;
}
QueuedNotify* qn = mQueuedNotifies.front();
mQueuedNotifies.pop_front();
mDustbin.push_back(qn);
mDialog.makeResponse(*mLastResponse, qn->notify(), statusCode);
if(reason)
{
mLastResponse->header(h_StatusLine).reason()=reason;
}
send(mLastResponse);
}

| void ClientSubscription::acceptUpdateCommand | ( | int | statusCode = 200, |
| const char * | reason = 0 |
||
| ) |
Provide asynchronous method access by using command.
Definition at line 663 of file ClientSubscription.cxx.
References resip::BaseUsage::mDum, and resip::TransactionUser::post().
{
mDum.post(new ClientSubscriptionAcceptUpdateCommand(*this, statusCode, reason));
}

| void ClientSubscription::clearDustbin | ( | ) | [private] |
Definition at line 817 of file ClientSubscription.cxx.
References mDustbin.
Referenced by dispatch(), and ~ClientSubscription().
| void ClientSubscription::dialogDestroyed | ( | const SipMessage & | msg | ) | [protected, virtual] |
Implements resip::DialogUsage.
Definition at line 770 of file ClientSubscription.cxx.
References resip::DialogUsageManager::getClientSubscriptionHandler(), getHandle(), resip::BaseUsage::mDum, mEnded, resip::BaseSubscription::mEventType, and resip::ClientSubscriptionHandler::onTerminated().
Referenced by resip::Dialog::dispatch().
{
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
mEnded = true;
handler->onTerminated(getHandle(), &msg);
delete this;
}

| void ClientSubscription::dispatch | ( | const SipMessage & | msg | ) | [private, virtual] |
dcm! -- heavy, should just store enough information to make response
Implements resip::BaseUsage.
Definition at line 71 of file ClientSubscription.cxx.
References resip::Message::brief(), clearDustbin(), DebugLog, resip::SipMessage::exists(), resip::DialogUsage::getAppDialogSet(), resip::DialogUsageManager::getClientSubscriptionHandler(), getHandle(), resip::RequestLine::getMethod(), h_RequestLine, resip::SipMessage::header(), InfoLog, resip::SipMessage::isRequest(), resip::DialogUsage::mDialog, resip::BaseUsage::mDum, resip::BaseSubscription::mEventType, mLargestNotifyCSeq, resip::BaseSubscription::mLastRequest, mOnNewSubscriptionCalled, mQueuedNotifies, mRefreshing, resip::Dialog::mRemoteTarget, processNextNotify(), and processResponse().
Referenced by resip::Dialog::dispatch().
{
DebugLog (<< "ClientSubscription::dispatch " << msg.brief());
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
clearDustbin();
// asserts are checks the correctness of Dialog::dispatch
if (msg.isRequest() )
{
assert( msg.header(h_RequestLine).getMethod() == NOTIFY );
mRefreshing = false;
// !dlb! 481 NOTIFY iff state is dead?
//mLastNotify = msg;
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;
}
bool outOfOrder = mLargestNotifyCSeq > msg.header(h_CSeq).sequence();
if (!outOfOrder)
{
mLargestNotifyCSeq = msg.header(h_CSeq).sequence();
}
else
{
DebugLog(<< "received out of order notify");
}
mQueuedNotifies.push_back(new QueuedNotify(msg, outOfOrder));
if (mQueuedNotifies.size() == 1)
{
DebugLog(<< "no queued notify");
processNextNotify();
return;
}
else
{
DebugLog(<< "Notify gets queued");
}
}
else
{
DebugLog(<< "processing client subscription response");
processResponse(msg);
}
}

| void ClientSubscription::dispatch | ( | const DumTimeout & | timer | ) | [private, virtual] |
Implements resip::BaseUsage.
Definition at line 447 of file ClientSubscription.cxx.
References DebugLog, resip::DialogUsageManager::getClientSubscriptionHandler(), getHandle(), InfoLog, resip::BaseUsage::mDum, mEnded, resip::BaseSubscription::mEventType, mOnNewSubscriptionCalled, resip::BaseSubscription::mTimerSeq, resip::ClientSubscriptionHandler::onNotifyNotReceived(), resip::ClientSubscriptionHandler::onTerminated(), processNextNotify(), requestRefresh(), reSubscribe(), resip::DumTimeout::SendNextNotify, resip::DumTimeout::seq(), resip::DumTimeout::Subscription, resip::DumTimeout::SubscriptionRetry, resip::DumTimeout::type(), and resip::DumTimeout::WaitForNotify.
{
if (timer.seq() == mTimerSeq)
{
if(timer.type() == DumTimeout::WaitForNotify)
{
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
if(mOnNewSubscriptionCalled && mEnded)
{
// NOTIFY terminated didn't come in
handler->onTerminated(getHandle(),0);
delete this;
return;
}
// Initial NOTIFY never came in; let app decide what to do
handler->onNotifyNotReceived(getHandle());
}
else if (timer.type() == DumTimeout::SubscriptionRetry)
{
// this indicates that the ClientSubscription was created by a 408
if (mOnNewSubscriptionCalled)
{
InfoLog(<< "ClientSubscription: application retry refresh");
requestRefresh();
}
else
{
InfoLog(<< "ClientSubscription: application retry new request");
reSubscribe(); // will delete "this"
return;
}
}
else if(timer.type() == DumTimeout::Subscription)
{
requestRefresh();
}
}
else if(timer.seq() == 0 && timer.type() == DumTimeout::SendNextNotify)
{
DebugLog(<< "got DumTimeout::SendNextNotify");
processNextNotify();
}
}

| EncodeStream & ClientSubscription::dump | ( | EncodeStream & | strm | ) | const [virtual] |
Implements resip::BaseUsage.
Definition at line 780 of file ClientSubscription.cxx.
References resip::BaseSubscription::mLastRequest.
{
strm << "ClientSubscription " << mLastRequest->header(h_From).uri();
return strm;
}
| void ClientSubscription::end | ( | ) | [virtual] |
Implements resip::BaseUsage.
Definition at line 555 of file ClientSubscription.cxx.
Referenced by resip::Dialog::end().
{
end(false /* immediate? */);
}
| void ClientSubscription::end | ( | bool | immediate | ) |
Definition at line 561 of file ClientSubscription.cxx.
References resip::DialogUsageManager::addTimer(), resip::BaseUsage::getBaseHandle(), h_RequestLine, InfoLog, resip::Dialog::makeRequest(), resip::DialogUsage::mDialog, resip::BaseUsage::mDum, mEnded, resip::BaseSubscription::mLastRequest, resip::BaseSubscription::mTimerSeq, send(), resip::Timer::T1, and resip::DumTimeout::WaitForNotify.
{
InfoLog (<< "End subscription: " << mLastRequest->header(h_RequestLine).uri());
if (!mEnded)
{
if(!immediate)
{
mDialog.makeRequest(*mLastRequest, SUBSCRIBE);
mLastRequest->header(h_Expires).value() = 0;
mEnded = true;
send(mLastRequest);
// Timer for NOTIFY terminated
mDum.addTimer(DumTimeout::WaitForNotify,
64*Timer::T1,
getBaseHandle(),
++mTimerSeq);
}
else
{
delete this;
}
}
}

| void ClientSubscription::endCommand | ( | bool | immediate = false | ) | [virtual] |
Definition at line 610 of file ClientSubscription.cxx.
References resip::BaseUsage::mDum, and resip::TransactionUser::post().
{
mDum.post(new ClientSubscriptionEndCommand(*this, immediate));
}

| void ClientSubscription::flowTerminated | ( | ) | [protected, virtual] |
Definition at line 795 of file ClientSubscription.cxx.
References resip::DialogUsageManager::getClientSubscriptionHandler(), getHandle(), resip::BaseUsage::mDum, resip::BaseSubscription::mEventType, and resip::ClientSubscriptionHandler::onFlowTerminated().
{
// notify handler
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
handler->onFlowTerminated(getHandle());
}

| ClientSubscriptionHandle ClientSubscription::getHandle | ( | ) |
Definition at line 65 of file ClientSubscription.cxx.
References resip::BaseUsage::getBaseHandle(), resip::BaseSubscription::getId(), and resip::BaseUsage::mDum.
Referenced by dialogDestroyed(), resip::Dialog::dispatch(), dispatch(), flowTerminated(), onReadyToSend(), processNextNotify(), processResponse(), and rejectUpdate().
{
return ClientSubscriptionHandle(mDum, getBaseHandle().getId());
}

| void ClientSubscription::onReadyToSend | ( | SipMessage & | msg | ) | [protected, virtual] |
Reimplemented from resip::DialogUsage.
Definition at line 787 of file ClientSubscription.cxx.
References resip::DialogUsageManager::getClientSubscriptionHandler(), getHandle(), resip::BaseUsage::mDum, resip::BaseSubscription::mEventType, and resip::ClientSubscriptionHandler::onReadyToSend().
{
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
handler->onReadyToSend(getHandle(), msg);
}

| ClientSubscription& resip::ClientSubscription::operator= | ( | const ClientSubscription & | ) | [private] |
| void ClientSubscription::processNextNotify | ( | ) | [private] |
dcm! There is a timing issue in this code which can cause this to be called when there are no queued NOTIFY messages. Probably a subscription teardown/timer crossover.
fjoanis! Is 481 a proper error code in this case?
Definition at line 253 of file ClientSubscription.cxx.
References resip::Helper::aBitSmallerThan(), acceptUpdate(), resip::Symbols::Active, DebugLog, resip::SipMessage::exists(), resip::DialogUsageManager::getClientSubscriptionHandler(), resip::SipMessage::getContents(), getHandle(), resip::Timer::getTimeSecs(), h_StatusLine, resip::SipMessage::header(), InfoLog, resip::isEqualNoCase(), resip::SipMessage::isResponse(), resip::Dialog::makeResponse(), mDefaultExpires, resip::DialogUsage::mDialog, resip::BaseUsage::mDum, mEnded, resip::SipFrag::message(), resip::BaseSubscription::mEventType, resip::BaseSubscription::mLastRequest, resip::BaseSubscription::mLastResponse, mLastSubSecs, mNextRefreshSecs, mQueuedNotifies, resip::ClientSubscription::QueuedNotify::notify(), resip::ClientSubscriptionHandler::onTerminated(), resip::ClientSubscriptionHandler::onUpdateActive(), resip::ClientSubscriptionHandler::onUpdateExtension(), resip::ClientSubscriptionHandler::onUpdatePending(), resip::ClientSubscription::QueuedNotify::outOfOrder(), resip::Symbols::Pending, rejectUpdate(), scheduleRefresh(), send(), and resip::Symbols::Terminated.
Referenced by dispatch().
{
//assert(!mQueuedNotifies.empty());
if (mQueuedNotifies.empty())
{
return;
}
QueuedNotify* qn = mQueuedNotifies.front();
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
unsigned long refreshInterval = 0;
bool setRefreshTimer=false;
if (!qn->outOfOrder())
{
UInt32 expires = 0;
//default to 3600 seconds so non-compliant endpoints don't result in leaked usages
if (qn->notify().exists(h_SubscriptionState) && qn->notify().header(h_SubscriptionState).exists(p_expires))
{
expires = qn->notify().header(h_SubscriptionState).param(p_expires);
}
else if (mLastRequest->exists(h_Expires))
{
expires = mLastRequest->header(h_Expires).value();
}
else if (mDefaultExpires)
{
/* 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.
*/
expires = mDefaultExpires;
}
else
{
expires = 3600;
}
if (!mLastRequest->exists(h_Expires))
{
DebugLog(<< "No expires header in last request, set to " << expires);
mLastRequest->header(h_Expires).value() = expires;
}
if(!qn->notify().exists(h_SubscriptionState) ||
!isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated))
{
// Don't do this stuff for a NOTIFY terminated.
UInt64 now = Timer::getTimeSecs();
refreshInterval = Helper::aBitSmallerThan((signed long)expires);
if (mNextRefreshSecs == 0 || now + refreshInterval < mNextRefreshSecs)
{
mNextRefreshSecs = now + refreshInterval;
setRefreshTimer = true;
}
}
}
//if no subscription state header, treat as an extension. Only allow for
//refer to handle non-compliant implementations
if (!qn->notify().exists(h_SubscriptionState))
{
if (qn->notify().exists(h_Event) && qn->notify().header(h_Event).value() == "refer")
{
SipFrag* frag = dynamic_cast<SipFrag*>(qn->notify().getContents());
if (frag)
{
if (frag->message().isResponse())
{
int code = frag->message().header(h_StatusLine).statusCode();
if (code < 200)
{
handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder());
}
else
{
acceptUpdate();
mEnded = true;
handler->onTerminated(getHandle(), &qn->notify());
delete this;
}
}
else
{
acceptUpdate();
mEnded = true;
handler->onTerminated(getHandle(), &qn->notify());
delete this;
}
}
else
{
acceptUpdate();
mEnded = true;
handler->onTerminated(getHandle(), &qn->notify());
delete this;
}
}
else
{
mDialog.makeResponse(*mLastResponse, qn->notify(), 400);
mLastResponse->header(h_StatusLine).reason() = "Missing Subscription-State header";
send(mLastResponse);
mEnded = true;
handler->onTerminated(getHandle(), &qn->notify());
delete this;
}
return;
}
if (!mEnded && isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Active))
{
if (setRefreshTimer)
{
scheduleRefresh(refreshInterval);
}
handler->onUpdateActive(getHandle(), qn->notify(), qn->outOfOrder());
}
else if (!mEnded && isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Pending))
{
if (setRefreshTimer)
{
scheduleRefresh(refreshInterval);
}
handler->onUpdatePending(getHandle(), qn->notify(), qn->outOfOrder());
}
else if (isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated))
{
if(mLastRequest->header(h_Expires).value()!=0 &&
isEqualNoCase(qn->notify().header(h_SubscriptionState).param(p_reason), "timeout"))
{
// Unexpected timeout of some sort. Look closer.
if(mNextRefreshSecs==0)
{
// No refresh scheduled; maybe we are trying to avoid a tight SUB/
// 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?");
}
else
{
acceptUpdate(200, "Why didn't I refresh here?");
}
}
else
{
acceptUpdate(200, "You terminated my subscription early! What "
"gives?");
}
}
else
{
acceptUpdate();
}
mEnded = true;
handler->onTerminated(getHandle(), &qn->notify());
DebugLog (<< "[ClientSubscription] " << mLastRequest->header(h_To) << "[ClientSubscription] Terminated");
delete this;
return;
}
else if (!mEnded)
{
handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder());
}
else if (mEnded)
{
// We received a NOTIFY message when we thought the subscription was
// ended. This can happen, for example, when a previously sent NOTIFY gets
// resent while we (ClientSubscription) are trying to terminate the
// subscription. If we don't accept/reject this NOTIFY, it will stay into
// the mQueuedNotifies queue and we'll never terminate the subscription
// even if the server sends a NOTIFY/terminated. All received NOTIFY would
// get piled up on mQueuedNotifies and they will never get processed.
//
// Note that if that NOTIFY is in fact the terminated one, it will get
// caught by another if statement above and acted upon appropriately.
//
InfoLog(<< "[ClientSubscription] received NOTIFY when subscription was ended, rejecting it...");
rejectUpdate(481);
}
}

| void ClientSubscription::processResponse | ( | const SipMessage & | response | ) | [private] |
Definition at line 133 of file ClientSubscription.cxx.
References resip::DialogUsageManager::addTimer(), DebugLog, resip::SipMessage::exists(), resip::BaseUsage::getBaseHandle(), resip::DialogUsageManager::getClientSubscriptionHandler(), getHandle(), resip::SipMessage::getReceivedTransport(), h_StatusLine, resip::SipMessage::header(), InfoLog, resip::BaseUsage::mDum, mEnded, resip::BaseSubscription::mEventType, resip::BaseSubscription::mLastRequest, mOnNewSubscriptionCalled, mRefreshing, resip::BaseSubscription::mTimerSeq, resip::ClientSubscriptionHandler::onRequestRetry(), resip::ClientSubscriptionHandler::onTerminated(), requestRefresh(), reSubscribe(), sendQueuedRefreshRequest(), resip::DumTimeout::SubscriptionRetry, resip::Timer::T1, and resip::DumTimeout::WaitForNotify.
Referenced by dispatch().
{
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
mRefreshing = false;
int statusCode = msg.header(h_StatusLine).statusCode();
if (statusCode >= 200 && statusCode <300)
{
if (msg.exists(h_Expires))
{
// grab the expires from the 2xx in case there is not one on the NOTIFY .mjf.
UInt32 expires = msg.header(h_Expires).value();
UInt32 lastExpires = mLastRequest->header(h_Expires).value();
if (expires < lastExpires)
{
mLastRequest->header(h_Expires).value() = expires;
}
}
if(!mOnNewSubscriptionCalled)
{
// Timer for initial NOTIFY; since we don't know when the initial
// SUBSRIBE is sent, we have to set the timer when the 200 comes in, if
// it beat the NOTIFY.
mDum.addTimer(DumTimeout::WaitForNotify,
64*Timer::T1,
getBaseHandle(),
++mTimerSeq);
}
sendQueuedRefreshRequest();
}
else if (!mEnded &&
statusCode == 481 &&
msg.exists(h_Expires) && msg.header(h_Expires).value() > 0)
{
InfoLog (<< "Received 481 to SUBSCRIBE, reSUBSCRIBEing (presence server probably restarted) "
<< mLastRequest->header(h_To));
reSubscribe(); // will delete "this"
return;
}
else if (!mEnded &&
(statusCode == 408 ||
(statusCode == 503 && msg.getReceivedTransport() == 0) ||
((statusCode == 413 ||
statusCode == 480 ||
statusCode == 486 ||
statusCode == 500 ||
statusCode == 503 ||
statusCode == 600 ||
statusCode == 603) &&
msg.exists(h_RetryAfter))))
{
int retry;
int retryAfter = 0;
if(msg.exists(h_RetryAfter))
{
retryAfter = msg.header(h_RetryAfter).value();
}
InfoLog (<< "Received " << statusCode << " to SUBSCRIBE "
<< mLastRequest->header(h_To));
retry = handler->onRequestRetry(getHandle(), retryAfter, msg);
if (retry < 0)
{
DebugLog(<< "Application requested failure on Retry-After");
mEnded = true;
handler->onTerminated(getHandle(), &msg);
delete this;
return;
}
else if (retry == 0)
{
DebugLog(<< "Application requested immediate retry on Retry-After");
if (mOnNewSubscriptionCalled)
{
// If we already have a dialog, then just refresh again
requestRefresh();
}
else
{
reSubscribe(); // will delete "this"
return;
}
}
else
{
// leave the usage around until the timeout
// !dlb! would be nice to set the state to something dead, but not used
mDum.addTimer(DumTimeout::SubscriptionRetry,
retry,
getBaseHandle(),
++mTimerSeq);
// leave the usage around until the timeout
return;
}
}
else if (msg.header(h_StatusLine).statusCode() >= 300)
{
if (msg.header(h_StatusLine).statusCode() == 423
&& msg.exists(h_MinExpires))
{
requestRefresh(msg.header(h_MinExpires).value());
}
else
{
mEnded = true;
handler->onTerminated(getHandle(), &msg);
delete this;
return;
}
}
}

| void ClientSubscription::rejectUpdate | ( | int | statusCode = 400, |
| const Data & | reasonPhrase = Data::Empty |
||
| ) |
Definition at line 698 of file ClientSubscription.cxx.
References resip::Helper::ApplicationDependant, resip::Helper::determineFailureMessageEffect(), resip::Helper::DialogTermination, resip::Data::empty(), resip::SharedPtr< T >::get(), resip::DialogUsageManager::getClientSubscriptionHandler(), getHandle(), h_StatusLine, InfoLog, resip::Dialog::makeResponse(), resip::DialogUsage::mDialog, resip::BaseUsage::mDum, mDustbin, mEnded, resip::BaseSubscription::mEventType, resip::BaseSubscription::mLastResponse, mQueuedNotifies, resip::ClientSubscription::QueuedNotify::notify(), resip::ClientSubscriptionHandler::onTerminated(), resip::Helper::OptionalRetryAfter, resip::Helper::RetryAfter, send(), resip::Helper::TransactionTermination, and resip::Helper::UsageTermination.
Referenced by processNextNotify().
{
ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType);
assert(handler);
assert(!mQueuedNotifies.empty());
if (mQueuedNotifies.empty())
{
InfoLog(<< "No queued notify to reject");
return;
}
QueuedNotify* qn = mQueuedNotifies.front();
mQueuedNotifies.pop_front();
mDustbin.push_back(qn);
mDialog.makeResponse(*mLastResponse, qn->notify(), statusCode);
if (!reasonPhrase.empty())
{
mLastResponse->header(h_StatusLine).reason() = reasonPhrase;
}
send(mLastResponse);
switch (Helper::determineFailureMessageEffect(*mLastResponse))
{
case Helper::TransactionTermination:
case Helper::RetryAfter:
break;
case Helper::OptionalRetryAfter:
case Helper::ApplicationDependant:
throw UsageUseException("Not a reasonable code to reject a NOTIFY with inside an established dialog.",
__FILE__, __LINE__);
break;
case Helper::DialogTermination: //?dcm? -- throw or destroy this?
case Helper::UsageTermination:
mEnded = true;
handler->onTerminated(getHandle(), mLastResponse.get());
delete this;
break;
}
}

| void ClientSubscription::rejectUpdateCommand | ( | int | statusCode = 400, |
| const Data & | reasonPhrase = Data::Empty |
||
| ) |
Definition at line 765 of file ClientSubscription.cxx.
References resip::BaseUsage::mDum, and resip::TransactionUser::post().
{
mDum.post(new ClientSubscriptionRejectUpdateCommand(*this, statusCode, reasonPhrase));
}

| void ClientSubscription::requestRefresh | ( | UInt32 | expires = 0 | ) |
dcm! -- need a mechanism to retrieve this for the event package...part of
Definition at line 493 of file ClientSubscription.cxx.
References resip::DialogUsageManager::addTimer(), DebugLog, resip::BaseUsage::getBaseHandle(), resip::Timer::getTimeSecs(), InfoLog, resip::Dialog::makeRequest(), resip::DialogUsage::mDialog, resip::BaseUsage::mDum, mEnded, mHaveQueuedRefresh, resip::BaseSubscription::mLastRequest, mLastSubSecs, mNextRefreshSecs, mQueuedRefreshInterval, mRefreshing, resip::BaseSubscription::mTimerSeq, send(), resip::Timer::T1, and resip::DumTimeout::WaitForNotify.
Referenced by dispatch(), processResponse(), and sendQueuedRefreshRequest().
{
if (!mEnded)
{
if (mRefreshing)
{
DebugLog(<< "queue up refresh request");
mHaveQueuedRefresh = true;
mQueuedRefreshInterval = expires;
return;
}
mDialog.makeRequest(*mLastRequest, SUBSCRIBE);
//the map that stores the handlers, or part of the handler API
if(expires > 0)
{
mLastRequest->header(h_Expires).value() = expires;
}
mNextRefreshSecs = 0;
InfoLog (<< "Refresh subscription: " << mLastRequest->header(h_Contacts).front());
mRefreshing = true;
mLastSubSecs = Timer::getTimeSecs();
send(mLastRequest);
// Timer for reSUB NOTIFY.
mDum.addTimer(DumTimeout::WaitForNotify,
64*Timer::T1,
getBaseHandle(),
++mTimerSeq);
}
}

| void ClientSubscription::requestRefreshCommand | ( | UInt32 | expires = 0 | ) |
Definition at line 549 of file ClientSubscription.cxx.
References resip::BaseUsage::mDum, and resip::TransactionUser::post().
{
mDum.post(new ClientSubscriptionRefreshCommand(*this, expires));
}

| void ClientSubscription::reSubscribe | ( | ) | [virtual] |
Definition at line 669 of file ClientSubscription.cxx.
References resip::DialogUsage::getAppDialogSet(), resip::BaseSubscription::getEventType(), resip::DialogUsage::getUserProfile(), resip::DialogUsageManager::makeSubscription(), resip::BaseUsage::mDum, resip::BaseSubscription::mLastRequest, resip::NameAddr::remove(), and resip::DialogUsageManager::send().
Referenced by dispatch(), and processResponse().
{
NameAddr target(mLastRequest->header(h_To));
target.remove(p_tag); // ensure To tag is removed
SharedPtr<SipMessage> sub = mDum.makeSubscription(target, getUserProfile(), getEventType(), getAppDialogSet()->reuse());
mDum.send(sub);
delete this;
}

| void ClientSubscription::scheduleRefresh | ( | unsigned long | refreshInterval | ) | [private] |
Definition at line 829 of file ClientSubscription.cxx.
References resip::DialogUsageManager::addTimer(), resip::BaseUsage::getBaseHandle(), InfoLog, resip::BaseUsage::mDum, mLastSubSecs, mNextRefreshSecs, resip::BaseSubscription::mTimerSeq, resip::DumTimeout::Subscription, and WarningLog.
Referenced by processNextNotify().
{
if(mNextRefreshSecs-mLastSubSecs < 2)
{
// Server is using an unreasonably short expiry; we sent a SUB
// very recently, and the server has told us to refresh almost
// immediately. By the time our refresh timer pops, less than two
// seconds will have elapsed since our last SUBSCRIBE. This is
// unacceptable. Just let the subscription end.
// It is also possible that our refresh SUB has crossed an update NOTIFY
// on the wire; in this case, the right thing to do is to wait until a
// NOTIFY for our refresh SUB comes in, which is exactly what this code
// ends up doing in this case.
// ?bwc? Make this minimum inter-SUBSCRIBE time configurable?
WarningLog(<< "Server is using an unacceptably short expiry. "
"Letting the subscription end so we don't get in a"
" tight SUB/NOT loop.");
mNextRefreshSecs=0;
}
else
{
mDum.addTimer(DumTimeout::Subscription, refreshInterval, getBaseHandle(), ++mTimerSeq);
InfoLog (<< "[ClientSubscription] reSUBSCRIBE in " << refreshInterval);
}
}

| void ClientSubscription::send | ( | SharedPtr< SipMessage > | msg | ) | [protected, virtual] |
Reimplemented from resip::DialogUsage.
Definition at line 680 of file ClientSubscription.cxx.
References resip::DialogUsageManager::addTimer(), resip::BaseUsage::getBaseHandle(), resip::BaseUsage::mDum, mEnded, mQueuedNotifies, and resip::DumTimeout::SendNextNotify.
Referenced by acceptUpdate(), end(), processNextNotify(), rejectUpdate(), and requestRefresh().
{
DialogUsage::send(msg);
if (!mEnded)
{
if (!mQueuedNotifies.empty() && msg->isResponse())
{
mDum.addTimer(DumTimeout::SendNextNotify,
0,
getBaseHandle(),
0);
}
}
}

| void ClientSubscription::sendQueuedRefreshRequest | ( | ) | [private] |
Definition at line 804 of file ClientSubscription.cxx.
References DebugLog, mHaveQueuedRefresh, mQueuedRefreshInterval, mRefreshing, and requestRefresh().
Referenced by processResponse().
{
assert(!mRefreshing);
if (mHaveQueuedRefresh)
{
DebugLog(<< "send queued refresh request");
mHaveQueuedRefresh = false;
requestRefresh(mQueuedRefreshInterval);
}
}

friend class Dialog [friend] |
Reimplemented from resip::BaseSubscription.
Definition at line 48 of file ClientSubscription.hxx.
friend class InviteSession [friend] |
Definition at line 49 of file ClientSubscription.hxx.
Definition at line 79 of file ClientSubscription.hxx.
Referenced by processNextNotify().
Dustbin resip::ClientSubscription::mDustbin [private] |
Definition at line 69 of file ClientSubscription.hxx.
Referenced by acceptUpdate(), clearDustbin(), and rejectUpdate().
bool resip::ClientSubscription::mEnded [private] |
Definition at line 73 of file ClientSubscription.hxx.
Referenced by dialogDestroyed(), dispatch(), end(), processNextNotify(), processResponse(), rejectUpdate(), requestRefresh(), and send().
bool resip::ClientSubscription::mHaveQueuedRefresh [private] |
Definition at line 82 of file ClientSubscription.hxx.
Referenced by requestRefresh(), and sendQueuedRefreshRequest().
unsigned int resip::ClientSubscription::mLargestNotifyCSeq [private] |
Definition at line 85 of file ClientSubscription.hxx.
Referenced by dispatch().
Definition at line 76 of file ClientSubscription.hxx.
Referenced by processNextNotify(), requestRefresh(), and scheduleRefresh().
Definition at line 75 of file ClientSubscription.hxx.
Referenced by processNextNotify(), requestRefresh(), and scheduleRefresh().
bool resip::ClientSubscription::mOnNewSubscriptionCalled [private] |
Definition at line 71 of file ClientSubscription.hxx.
Referenced by dispatch(), and processResponse().
Definition at line 66 of file ClientSubscription.hxx.
Referenced by acceptUpdate(), dispatch(), processNextNotify(), rejectUpdate(), send(), and ~ClientSubscription().
int resip::ClientSubscription::mQueuedRefreshInterval [private] |
Definition at line 83 of file ClientSubscription.hxx.
Referenced by requestRefresh(), and sendQueuedRefreshRequest().
bool resip::ClientSubscription::mRefreshing [private] |
Definition at line 81 of file ClientSubscription.hxx.
Referenced by dispatch(), processResponse(), requestRefresh(), and sendQueuedRefreshRequest().
1.7.5.1