|
reSIProcate/DialogUsageManager
9680
|
00001 #include <queue> 00002 00003 #include "resip/stack/Helper.hxx" 00004 #include "rutil/Logger.hxx" 00005 #include "resip/stack/SipFrag.hxx" 00006 #include "resip/stack/SipMessage.hxx" 00007 #include "resip/dum/ClientSubscription.hxx" 00008 #include "resip/dum/Dialog.hxx" 00009 #include "resip/dum/DialogUsageManager.hxx" 00010 #include "resip/dum/SubscriptionHandler.hxx" 00011 #include "resip/dum/SubscriptionCreator.hxx" 00012 #include "resip/dum/UsageUseException.hxx" 00013 00014 #include "resip/dum/AppDialogSet.hxx" 00015 00016 using namespace resip; 00017 00018 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM 00019 00020 00021 ClientSubscription::ClientSubscription(DialogUsageManager& dum, Dialog& dialog, 00022 const SipMessage& request, UInt32 defaultSubExpiration) 00023 : BaseSubscription(dum, dialog, request), 00024 mOnNewSubscriptionCalled(mEventType == "refer"), // don't call onNewSubscription for Refer subscriptions 00025 mEnded(false), 00026 mNextRefreshSecs(0), 00027 mLastSubSecs(Timer::getTimeSecs()), // Not exactly, but more forgiving 00028 mDefaultExpires(defaultSubExpiration), 00029 mRefreshing(false), 00030 mHaveQueuedRefresh(false), 00031 mQueuedRefreshInterval(-1), 00032 mLargestNotifyCSeq(0) 00033 { 00034 DebugLog (<< "ClientSubscription::ClientSubscription from " << request.brief()); 00035 if(request.method() == SUBSCRIBE) 00036 { 00037 *mLastRequest = request; 00038 if (defaultSubExpiration > 0) 00039 { 00040 mLastRequest->header(h_Expires).value() = defaultSubExpiration; 00041 } 00042 } 00043 else 00044 { 00045 // If a NOTIFY request is use to make this ClientSubscription, then create the implied SUBSCRIBE 00046 // request as the mLastRequest 00047 mDialog.makeRequest(*mLastRequest, SUBSCRIBE); 00048 } 00049 } 00050 00051 ClientSubscription::~ClientSubscription() 00052 { 00053 mDialog.mClientSubscriptions.remove(this); 00054 00055 while (!mQueuedNotifies.empty()) 00056 { 00057 delete mQueuedNotifies.front(); 00058 mQueuedNotifies.pop_front(); 00059 } 00060 00061 clearDustbin(); 00062 } 00063 00064 ClientSubscriptionHandle 00065 ClientSubscription::getHandle() 00066 { 00067 return ClientSubscriptionHandle(mDum, getBaseHandle().getId()); 00068 } 00069 00070 void 00071 ClientSubscription::dispatch(const SipMessage& msg) 00072 { 00073 DebugLog (<< "ClientSubscription::dispatch " << msg.brief()); 00074 00075 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00076 assert(handler); 00077 00078 clearDustbin(); 00079 00080 // asserts are checks the correctness of Dialog::dispatch 00081 if (msg.isRequest() ) 00082 { 00083 assert( msg.header(h_RequestLine).getMethod() == NOTIFY ); 00084 mRefreshing = false; 00085 00086 // !dlb! 481 NOTIFY iff state is dead? 00087 00089 //mLastNotify = msg; 00090 00091 if (!mOnNewSubscriptionCalled && !getAppDialogSet()->isReUsed()) 00092 { 00093 InfoLog (<< "[ClientSubscription] " << mLastRequest->header(h_To)); 00094 if (msg.exists(h_Contacts)) 00095 { 00096 mDialog.mRemoteTarget = msg.header(h_Contacts).front(); 00097 } 00098 00099 handler->onNewSubscription(getHandle(), msg); 00100 mOnNewSubscriptionCalled = true; 00101 } 00102 00103 bool outOfOrder = mLargestNotifyCSeq > msg.header(h_CSeq).sequence(); 00104 if (!outOfOrder) 00105 { 00106 mLargestNotifyCSeq = msg.header(h_CSeq).sequence(); 00107 } 00108 else 00109 { 00110 DebugLog(<< "received out of order notify"); 00111 } 00112 00113 mQueuedNotifies.push_back(new QueuedNotify(msg, outOfOrder)); 00114 if (mQueuedNotifies.size() == 1) 00115 { 00116 DebugLog(<< "no queued notify"); 00117 processNextNotify(); 00118 return; 00119 } 00120 else 00121 { 00122 DebugLog(<< "Notify gets queued"); 00123 } 00124 } 00125 else 00126 { 00127 DebugLog(<< "processing client subscription response"); 00128 processResponse(msg); 00129 } 00130 } 00131 00132 void 00133 ClientSubscription::processResponse(const SipMessage& msg) 00134 { 00135 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00136 assert(handler); 00137 00138 mRefreshing = false; 00139 int statusCode = msg.header(h_StatusLine).statusCode(); 00140 00141 if (statusCode >= 200 && statusCode <300) 00142 { 00143 if (msg.exists(h_Expires)) 00144 { 00145 // grab the expires from the 2xx in case there is not one on the NOTIFY .mjf. 00146 UInt32 expires = msg.header(h_Expires).value(); 00147 UInt32 lastExpires = mLastRequest->header(h_Expires).value(); 00148 if (expires < lastExpires) 00149 { 00150 mLastRequest->header(h_Expires).value() = expires; 00151 } 00152 } 00153 00154 if(!mOnNewSubscriptionCalled) 00155 { 00156 // Timer for initial NOTIFY; since we don't know when the initial 00157 // SUBSRIBE is sent, we have to set the timer when the 200 comes in, if 00158 // it beat the NOTIFY. 00159 mDum.addTimer(DumTimeout::WaitForNotify, 00160 64*Timer::T1, 00161 getBaseHandle(), 00162 ++mTimerSeq); 00163 } 00164 00165 sendQueuedRefreshRequest(); 00166 } 00167 else if (!mEnded && 00168 statusCode == 481 && 00169 msg.exists(h_Expires) && msg.header(h_Expires).value() > 0) 00170 { 00171 InfoLog (<< "Received 481 to SUBSCRIBE, reSUBSCRIBEing (presence server probably restarted) " 00172 << mLastRequest->header(h_To)); 00173 00174 reSubscribe(); // will delete "this" 00175 return; 00176 } 00177 else if (!mEnded && 00178 (statusCode == 408 || 00179 (statusCode == 503 && msg.getReceivedTransport() == 0) || 00180 ((statusCode == 413 || 00181 statusCode == 480 || 00182 statusCode == 486 || 00183 statusCode == 500 || 00184 statusCode == 503 || 00185 statusCode == 600 || 00186 statusCode == 603) && 00187 msg.exists(h_RetryAfter)))) 00188 { 00189 int retry; 00190 int retryAfter = 0; 00191 if(msg.exists(h_RetryAfter)) 00192 { 00193 retryAfter = msg.header(h_RetryAfter).value(); 00194 } 00195 00196 InfoLog (<< "Received " << statusCode << " to SUBSCRIBE " 00197 << mLastRequest->header(h_To)); 00198 retry = handler->onRequestRetry(getHandle(), retryAfter, msg); 00199 00200 if (retry < 0) 00201 { 00202 DebugLog(<< "Application requested failure on Retry-After"); 00203 mEnded = true; 00204 handler->onTerminated(getHandle(), &msg); 00205 delete this; 00206 return; 00207 } 00208 else if (retry == 0) 00209 { 00210 DebugLog(<< "Application requested immediate retry on Retry-After"); 00211 00212 if (mOnNewSubscriptionCalled) 00213 { 00214 // If we already have a dialog, then just refresh again 00215 requestRefresh(); 00216 } 00217 else 00218 { 00219 reSubscribe(); // will delete "this" 00220 return; 00221 } 00222 } 00223 else 00224 { 00225 // leave the usage around until the timeout 00226 // !dlb! would be nice to set the state to something dead, but not used 00227 mDum.addTimer(DumTimeout::SubscriptionRetry, 00228 retry, 00229 getBaseHandle(), 00230 ++mTimerSeq); 00231 // leave the usage around until the timeout 00232 return; 00233 } 00234 } 00235 else if (msg.header(h_StatusLine).statusCode() >= 300) 00236 { 00237 if (msg.header(h_StatusLine).statusCode() == 423 00238 && msg.exists(h_MinExpires)) 00239 { 00240 requestRefresh(msg.header(h_MinExpires).value()); 00241 } 00242 else 00243 { 00244 mEnded = true; 00245 handler->onTerminated(getHandle(), &msg); 00246 delete this; 00247 return; 00248 } 00249 } 00250 } 00251 00252 void 00253 ClientSubscription::processNextNotify() 00254 { 00258 //assert(!mQueuedNotifies.empty()); 00259 if (mQueuedNotifies.empty()) 00260 { 00261 return; 00262 } 00263 00264 QueuedNotify* qn = mQueuedNotifies.front(); 00265 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00266 assert(handler); 00267 00268 unsigned long refreshInterval = 0; 00269 bool setRefreshTimer=false; 00270 if (!qn->outOfOrder()) 00271 { 00272 UInt32 expires = 0; 00273 //default to 3600 seconds so non-compliant endpoints don't result in leaked usages 00274 if (qn->notify().exists(h_SubscriptionState) && qn->notify().header(h_SubscriptionState).exists(p_expires)) 00275 { 00276 expires = qn->notify().header(h_SubscriptionState).param(p_expires); 00277 } 00278 else if (mLastRequest->exists(h_Expires)) 00279 { 00280 expires = mLastRequest->header(h_Expires).value(); 00281 } 00282 else if (mDefaultExpires) 00283 { 00284 /* if we haven't gotten an expires value from: 00285 1. the subscription state from this notify 00286 2. the last request 00287 then use the default expires (meaning it came from the 2xx in response 00288 to the initial SUBSCRIBE). .mjf. 00289 */ 00290 expires = mDefaultExpires; 00291 } 00292 else 00293 { 00294 expires = 3600; 00295 } 00296 00297 if (!mLastRequest->exists(h_Expires)) 00298 { 00299 DebugLog(<< "No expires header in last request, set to " << expires); 00300 mLastRequest->header(h_Expires).value() = expires; 00301 } 00302 00303 if(!qn->notify().exists(h_SubscriptionState) || 00304 !isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated)) 00305 { 00306 // Don't do this stuff for a NOTIFY terminated. 00307 UInt64 now = Timer::getTimeSecs(); 00308 refreshInterval = Helper::aBitSmallerThan((signed long)expires); 00309 00310 if (mNextRefreshSecs == 0 || now + refreshInterval < mNextRefreshSecs) 00311 { 00312 mNextRefreshSecs = now + refreshInterval; 00313 setRefreshTimer = true; 00314 } 00315 } 00316 } 00317 //if no subscription state header, treat as an extension. Only allow for 00318 //refer to handle non-compliant implementations 00319 if (!qn->notify().exists(h_SubscriptionState)) 00320 { 00321 if (qn->notify().exists(h_Event) && qn->notify().header(h_Event).value() == "refer") 00322 { 00323 SipFrag* frag = dynamic_cast<SipFrag*>(qn->notify().getContents()); 00324 if (frag) 00325 { 00326 if (frag->message().isResponse()) 00327 { 00328 int code = frag->message().header(h_StatusLine).statusCode(); 00329 if (code < 200) 00330 { 00331 handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder()); 00332 } 00333 else 00334 { 00335 acceptUpdate(); 00336 mEnded = true; 00337 handler->onTerminated(getHandle(), &qn->notify()); 00338 delete this; 00339 } 00340 } 00341 else 00342 { 00343 acceptUpdate(); 00344 mEnded = true; 00345 handler->onTerminated(getHandle(), &qn->notify()); 00346 delete this; 00347 } 00348 } 00349 else 00350 { 00351 acceptUpdate(); 00352 mEnded = true; 00353 handler->onTerminated(getHandle(), &qn->notify()); 00354 delete this; 00355 } 00356 } 00357 else 00358 { 00359 mDialog.makeResponse(*mLastResponse, qn->notify(), 400); 00360 mLastResponse->header(h_StatusLine).reason() = "Missing Subscription-State header"; 00361 send(mLastResponse); 00362 mEnded = true; 00363 handler->onTerminated(getHandle(), &qn->notify()); 00364 delete this; 00365 } 00366 return; 00367 } 00368 00369 if (!mEnded && isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Active)) 00370 { 00371 if (setRefreshTimer) 00372 { 00373 scheduleRefresh(refreshInterval); 00374 } 00375 00376 handler->onUpdateActive(getHandle(), qn->notify(), qn->outOfOrder()); 00377 } 00378 else if (!mEnded && isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Pending)) 00379 { 00380 if (setRefreshTimer) 00381 { 00382 scheduleRefresh(refreshInterval); 00383 } 00384 00385 handler->onUpdatePending(getHandle(), qn->notify(), qn->outOfOrder()); 00386 } 00387 else if (isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated)) 00388 { 00389 if(mLastRequest->header(h_Expires).value()!=0 && 00390 isEqualNoCase(qn->notify().header(h_SubscriptionState).param(p_reason), "timeout")) 00391 { 00392 // Unexpected timeout of some sort. Look closer. 00393 if(mNextRefreshSecs==0) 00394 { 00395 // No refresh scheduled; maybe we are trying to avoid a tight SUB/ 00396 // NOT loop here? 00397 if(Helper::aBitSmallerThan((signed long)(Timer::getTimeSecs() - mLastSubSecs)) < 2) 00398 { 00399 acceptUpdate(200, "I just sent a refresh, what more do you want " 00400 "from me?"); 00401 } 00402 else 00403 { 00404 acceptUpdate(200, "Why didn't I refresh here?"); 00405 } 00406 } 00407 else 00408 { 00409 acceptUpdate(200, "You terminated my subscription early! What " 00410 "gives?"); 00411 } 00412 } 00413 else 00414 { 00415 acceptUpdate(); 00416 } 00417 mEnded = true; 00418 handler->onTerminated(getHandle(), &qn->notify()); 00419 DebugLog (<< "[ClientSubscription] " << mLastRequest->header(h_To) << "[ClientSubscription] Terminated"); 00420 delete this; 00421 return; 00422 } 00423 else if (!mEnded) 00424 { 00425 handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder()); 00426 } 00427 else if (mEnded) 00428 { 00429 // We received a NOTIFY message when we thought the subscription was 00430 // ended. This can happen, for example, when a previously sent NOTIFY gets 00431 // resent while we (ClientSubscription) are trying to terminate the 00432 // subscription. If we don't accept/reject this NOTIFY, it will stay into 00433 // the mQueuedNotifies queue and we'll never terminate the subscription 00434 // even if the server sends a NOTIFY/terminated. All received NOTIFY would 00435 // get piled up on mQueuedNotifies and they will never get processed. 00436 // 00437 // Note that if that NOTIFY is in fact the terminated one, it will get 00438 // caught by another if statement above and acted upon appropriately. 00439 // 00441 InfoLog(<< "[ClientSubscription] received NOTIFY when subscription was ended, rejecting it..."); 00442 rejectUpdate(481); 00443 } 00444 } 00445 00446 void 00447 ClientSubscription::dispatch(const DumTimeout& timer) 00448 { 00449 if (timer.seq() == mTimerSeq) 00450 { 00451 if(timer.type() == DumTimeout::WaitForNotify) 00452 { 00453 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00454 if(mOnNewSubscriptionCalled && mEnded) 00455 { 00456 // NOTIFY terminated didn't come in 00457 handler->onTerminated(getHandle(),0); 00458 delete this; 00459 return; 00460 } 00461 00462 // Initial NOTIFY never came in; let app decide what to do 00463 handler->onNotifyNotReceived(getHandle()); 00464 } 00465 else if (timer.type() == DumTimeout::SubscriptionRetry) 00466 { 00467 // this indicates that the ClientSubscription was created by a 408 00468 if (mOnNewSubscriptionCalled) 00469 { 00470 InfoLog(<< "ClientSubscription: application retry refresh"); 00471 requestRefresh(); 00472 } 00473 else 00474 { 00475 InfoLog(<< "ClientSubscription: application retry new request"); 00476 reSubscribe(); // will delete "this" 00477 return; 00478 } 00479 } 00480 else if(timer.type() == DumTimeout::Subscription) 00481 { 00482 requestRefresh(); 00483 } 00484 } 00485 else if(timer.seq() == 0 && timer.type() == DumTimeout::SendNextNotify) 00486 { 00487 DebugLog(<< "got DumTimeout::SendNextNotify"); 00488 processNextNotify(); 00489 } 00490 } 00491 00492 void 00493 ClientSubscription::requestRefresh(UInt32 expires) 00494 { 00495 if (!mEnded) 00496 { 00497 if (mRefreshing) 00498 { 00499 DebugLog(<< "queue up refresh request"); 00500 mHaveQueuedRefresh = true; 00501 mQueuedRefreshInterval = expires; 00502 return; 00503 } 00504 00505 mDialog.makeRequest(*mLastRequest, SUBSCRIBE); 00507 //the map that stores the handlers, or part of the handler API 00508 if(expires > 0) 00509 { 00510 mLastRequest->header(h_Expires).value() = expires; 00511 } 00512 mNextRefreshSecs = 0; 00513 InfoLog (<< "Refresh subscription: " << mLastRequest->header(h_Contacts).front()); 00514 mRefreshing = true; 00515 mLastSubSecs = Timer::getTimeSecs(); 00516 send(mLastRequest); 00517 // Timer for reSUB NOTIFY. 00518 mDum.addTimer(DumTimeout::WaitForNotify, 00519 64*Timer::T1, 00520 getBaseHandle(), 00521 ++mTimerSeq); 00522 } 00523 } 00524 00525 class ClientSubscriptionRefreshCommand : public DumCommandAdapter 00526 { 00527 public: 00528 ClientSubscriptionRefreshCommand(ClientSubscription& clientSubscription, UInt32 expires) 00529 : mClientSubscription(clientSubscription), 00530 mExpires(expires) 00531 { 00532 00533 } 00534 virtual void executeCommand() 00535 { 00536 mClientSubscription.requestRefresh(mExpires); 00537 } 00538 00539 virtual EncodeStream& encodeBrief(EncodeStream& strm) const 00540 { 00541 return strm << "ClientSubscriptionRefreshCommand"; 00542 } 00543 private: 00544 ClientSubscription& mClientSubscription; 00545 UInt32 mExpires; 00546 }; 00547 00548 void 00549 ClientSubscription::requestRefreshCommand(UInt32 expires) 00550 { 00551 mDum.post(new ClientSubscriptionRefreshCommand(*this, expires)); 00552 } 00553 00554 void 00555 ClientSubscription::end() 00556 { 00557 end(false /* immediate? */); 00558 } 00559 00560 void 00561 ClientSubscription::end(bool immediate) 00562 { 00563 InfoLog (<< "End subscription: " << mLastRequest->header(h_RequestLine).uri()); 00564 00565 if (!mEnded) 00566 { 00567 if(!immediate) 00568 { 00569 mDialog.makeRequest(*mLastRequest, SUBSCRIBE); 00570 mLastRequest->header(h_Expires).value() = 0; 00571 mEnded = true; 00572 send(mLastRequest); 00573 // Timer for NOTIFY terminated 00574 mDum.addTimer(DumTimeout::WaitForNotify, 00575 64*Timer::T1, 00576 getBaseHandle(), 00577 ++mTimerSeq); 00578 } 00579 else 00580 { 00581 delete this; 00582 } 00583 } 00584 } 00585 00586 class ClientSubscriptionEndCommand : public DumCommandAdapter 00587 { 00588 public: 00589 ClientSubscriptionEndCommand(ClientSubscription& clientSubscription, bool immediate) 00590 :mClientSubscription(clientSubscription), mImmediate(immediate) 00591 { 00592 00593 } 00594 00595 virtual void executeCommand() 00596 { 00597 mClientSubscription.end(mImmediate); 00598 } 00599 00600 virtual EncodeStream& encodeBrief(EncodeStream& strm) const 00601 { 00602 return strm << "ClientSubscriptionEndCommand"; 00603 } 00604 private: 00605 ClientSubscription& mClientSubscription; 00606 bool mImmediate; 00607 }; 00608 00609 void 00610 ClientSubscription::endCommand(bool immediate) 00611 { 00612 mDum.post(new ClientSubscriptionEndCommand(*this, immediate)); 00613 } 00614 00615 void 00616 ClientSubscription::acceptUpdate(int statusCode, const char* reason) 00617 { 00618 assert(!mQueuedNotifies.empty()); 00619 if (mQueuedNotifies.empty()) 00620 { 00621 InfoLog(<< "No queued notify to accept"); 00622 return; 00623 } 00624 00625 QueuedNotify* qn = mQueuedNotifies.front(); 00626 mQueuedNotifies.pop_front(); 00627 mDustbin.push_back(qn); 00628 mDialog.makeResponse(*mLastResponse, qn->notify(), statusCode); 00629 if(reason) 00630 { 00631 mLastResponse->header(h_StatusLine).reason()=reason; 00632 } 00633 send(mLastResponse); 00634 } 00635 00636 class ClientSubscriptionAcceptUpdateCommand : public DumCommandAdapter 00637 { 00638 public: 00639 ClientSubscriptionAcceptUpdateCommand(ClientSubscription& clientSubscription, int statusCode, const char* reason) 00640 : mClientSubscription(clientSubscription), 00641 mStatusCode(statusCode), 00642 mReason(reason ? Data(reason) : Data::Empty) 00643 { 00644 00645 } 00646 00647 virtual void executeCommand() 00648 { 00649 mClientSubscription.acceptUpdate(mStatusCode, mReason.c_str()); 00650 } 00651 00652 virtual EncodeStream& encodeBrief(EncodeStream& strm) const 00653 { 00654 return strm << "ClientSubscriptionAcceptUpdateCommand"; 00655 } 00656 private: 00657 ClientSubscription& mClientSubscription; 00658 int mStatusCode; 00659 Data mReason; 00660 }; 00661 00662 void 00663 ClientSubscription::acceptUpdateCommand(int statusCode, const char* reason) 00664 { 00665 mDum.post(new ClientSubscriptionAcceptUpdateCommand(*this, statusCode, reason)); 00666 } 00667 00668 void 00669 ClientSubscription::reSubscribe() 00670 { 00671 NameAddr target(mLastRequest->header(h_To)); 00672 target.remove(p_tag); // ensure To tag is removed 00673 SharedPtr<SipMessage> sub = mDum.makeSubscription(target, getUserProfile(), getEventType(), getAppDialogSet()->reuse()); 00674 mDum.send(sub); 00675 00676 delete this; 00677 } 00678 00679 void 00680 ClientSubscription::send(SharedPtr<SipMessage> msg) 00681 { 00682 DialogUsage::send(msg); 00683 00684 if (!mEnded) 00685 { 00686 if (!mQueuedNotifies.empty() && msg->isResponse()) 00687 { 00688 mDum.addTimer(DumTimeout::SendNextNotify, 00689 0, 00690 getBaseHandle(), 00691 0); 00692 } 00693 } 00694 00695 } 00696 00697 void 00698 ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase) 00699 { 00700 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00701 assert(handler); 00702 assert(!mQueuedNotifies.empty()); 00703 if (mQueuedNotifies.empty()) 00704 { 00705 InfoLog(<< "No queued notify to reject"); 00706 return; 00707 } 00708 00709 QueuedNotify* qn = mQueuedNotifies.front(); 00710 mQueuedNotifies.pop_front(); 00711 mDustbin.push_back(qn); 00712 00713 mDialog.makeResponse(*mLastResponse, qn->notify(), statusCode); 00714 if (!reasonPhrase.empty()) 00715 { 00716 mLastResponse->header(h_StatusLine).reason() = reasonPhrase; 00717 } 00718 00719 send(mLastResponse); 00720 switch (Helper::determineFailureMessageEffect(*mLastResponse)) 00721 { 00722 case Helper::TransactionTermination: 00723 case Helper::RetryAfter: 00724 break; 00725 case Helper::OptionalRetryAfter: 00726 case Helper::ApplicationDependant: 00727 throw UsageUseException("Not a reasonable code to reject a NOTIFY with inside an established dialog.", 00728 __FILE__, __LINE__); 00729 break; 00730 case Helper::DialogTermination: //?dcm? -- throw or destroy this? 00731 case Helper::UsageTermination: 00732 mEnded = true; 00733 handler->onTerminated(getHandle(), mLastResponse.get()); 00734 delete this; 00735 break; 00736 } 00737 } 00738 00739 class ClientSubscriptionRejectUpdateCommand : public DumCommandAdapter 00740 { 00741 public: 00742 ClientSubscriptionRejectUpdateCommand(ClientSubscription& clientSubscription, int statusCode, const Data& reasonPhrase) 00743 : mClientSubscription(clientSubscription), 00744 mStatusCode(statusCode), 00745 mReasonPhrase(reasonPhrase) 00746 { 00747 } 00748 00749 virtual void executeCommand() 00750 { 00751 mClientSubscription.rejectUpdate(mStatusCode, mReasonPhrase); 00752 } 00753 00754 virtual EncodeStream& encodeBrief(EncodeStream& strm) const 00755 { 00756 return strm << "ClientSubscriptionRejectUpdateCommand"; 00757 } 00758 private: 00759 ClientSubscription& mClientSubscription; 00760 int mStatusCode; 00761 Data mReasonPhrase; 00762 }; 00763 00764 void 00765 ClientSubscription::rejectUpdateCommand(int statusCode, const Data& reasonPhrase) 00766 { 00767 mDum.post(new ClientSubscriptionRejectUpdateCommand(*this, statusCode, reasonPhrase)); 00768 } 00769 00770 void ClientSubscription::dialogDestroyed(const SipMessage& msg) 00771 { 00772 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00773 assert(handler); 00774 mEnded = true; 00775 handler->onTerminated(getHandle(), &msg); 00776 delete this; 00777 } 00778 00779 EncodeStream& 00780 ClientSubscription::dump(EncodeStream& strm) const 00781 { 00782 strm << "ClientSubscription " << mLastRequest->header(h_From).uri(); 00783 return strm; 00784 } 00785 00786 void 00787 ClientSubscription::onReadyToSend(SipMessage& msg) 00788 { 00789 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00790 assert(handler); 00791 handler->onReadyToSend(getHandle(), msg); 00792 } 00793 00794 void 00795 ClientSubscription::flowTerminated() 00796 { 00797 // notify handler 00798 ClientSubscriptionHandler* handler = mDum.getClientSubscriptionHandler(mEventType); 00799 assert(handler); 00800 handler->onFlowTerminated(getHandle()); 00801 } 00802 00803 void 00804 ClientSubscription::sendQueuedRefreshRequest() 00805 { 00806 assert(!mRefreshing); 00807 00808 if (mHaveQueuedRefresh) 00809 { 00810 DebugLog(<< "send queued refresh request"); 00811 mHaveQueuedRefresh = false; 00812 requestRefresh(mQueuedRefreshInterval); 00813 } 00814 } 00815 00816 void 00817 ClientSubscription::clearDustbin() 00818 { 00819 for (Dustbin::iterator it = mDustbin.begin(); it != mDustbin.end(); ++it) 00820 { 00821 delete *it; 00822 } 00823 00824 mDustbin.clear(); 00825 00826 } 00827 00828 void 00829 ClientSubscription::scheduleRefresh(unsigned long refreshInterval) 00830 { 00831 if(mNextRefreshSecs-mLastSubSecs < 2) 00832 { 00833 // Server is using an unreasonably short expiry; we sent a SUB 00834 // very recently, and the server has told us to refresh almost 00835 // immediately. By the time our refresh timer pops, less than two 00836 // seconds will have elapsed since our last SUBSCRIBE. This is 00837 // unacceptable. Just let the subscription end. 00838 // It is also possible that our refresh SUB has crossed an update NOTIFY 00839 // on the wire; in this case, the right thing to do is to wait until a 00840 // NOTIFY for our refresh SUB comes in, which is exactly what this code 00841 // ends up doing in this case. 00842 // ?bwc? Make this minimum inter-SUBSCRIBE time configurable? 00843 WarningLog(<< "Server is using an unacceptably short expiry. " 00844 "Letting the subscription end so we don't get in a" 00845 " tight SUB/NOT loop."); 00846 mNextRefreshSecs=0; 00847 } 00848 else 00849 { 00850 mDum.addTimer(DumTimeout::Subscription, refreshInterval, getBaseHandle(), ++mTimerSeq); 00851 InfoLog (<< "[ClientSubscription] reSUBSCRIBE in " << refreshInterval); 00852 } 00853 } 00854 00855 00856 00857 /* ==================================================================== 00858 * The Vovida Software License, Version 1.0 00859 * 00860 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00861 * 00862 * Redistribution and use in source and binary forms, with or without 00863 * modification, are permitted provided that the following conditions 00864 * are met: 00865 * 00866 * 1. Redistributions of source code must retain the above copyright 00867 * notice, this list of conditions and the following disclaimer. 00868 * 00869 * 2. Redistributions in binary form must reproduce the above copyright 00870 * notice, this list of conditions and the following disclaimer in 00871 * the documentation and/or other materials provided with the 00872 * distribution. 00873 * 00874 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00875 * and "Vovida Open Communication Application Library (VOCAL)" must 00876 * not be used to endorse or promote products derived from this 00877 * software without prior written permission. For written 00878 * permission, please contact vocal@vovida.org. 00879 * 00880 * 4. Products derived from this software may not be called "VOCAL", nor 00881 * may "VOCAL" appear in their name, without prior written 00882 * permission of Vovida Networks, Inc. 00883 * 00884 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00885 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00886 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00887 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00888 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00889 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00890 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00891 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00892 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00893 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00894 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00895 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00896 * DAMAGE. 00897 * 00898 * ==================================================================== 00899 * 00900 * This software consists of voluntary contributions made by Vovida 00901 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00902 * Inc. For more information on Vovida Networks, Inc., please see 00903 * <http://www.vovida.org/>. 00904 * 00905 */
1.7.5.1