|
reSIProcate/DialogUsageManager
9680
|
00001 #include <algorithm> 00002 #include <iterator> 00003 00004 #include "resip/stack/Helper.hxx" 00005 #include "resip/dum/BaseCreator.hxx" 00006 #include "resip/dum/ClientAuthManager.hxx" 00007 #include "resip/dum/ClientRegistration.hxx" 00008 #include "resip/dum/RegistrationHandler.hxx" 00009 #include "resip/dum/DialogUsageManager.hxx" 00010 #include "resip/dum/Dialog.hxx" 00011 #include "resip/dum/MasterProfile.hxx" 00012 #include "resip/dum/UsageUseException.hxx" 00013 #include "rutil/Logger.hxx" 00014 #include "rutil/Inserter.hxx" 00015 #include "rutil/Random.hxx" 00016 #include "rutil/ParseBuffer.hxx" 00017 #include "rutil/WinLeakCheck.hxx" 00018 00019 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM 00020 00021 using namespace resip; 00022 00023 ClientRegistrationHandle 00024 ClientRegistration::getHandle() 00025 { 00026 return ClientRegistrationHandle(mDum, getBaseHandle().getId()); 00027 } 00028 00029 ClientRegistration::ClientRegistration(DialogUsageManager& dum, 00030 DialogSet& dialogSet, 00031 SharedPtr<SipMessage> request) 00032 : NonDialogUsage(dum, dialogSet), 00033 mLastRequest(request), 00034 mTimerSeq(0), 00035 mState(mLastRequest->exists(h_Contacts) ? Adding : Querying), 00036 mEndWhenDone(false), 00037 mUserRefresh(false), 00038 mRegistrationTime(mDialogSet.mUserProfile->getDefaultRegistrationTime()), 00039 mExpires(0), 00040 mQueuedState(None), 00041 mQueuedRequest(new SipMessage) 00042 { 00043 // If no Contacts header, this is a query 00044 if (mLastRequest->exists(h_Contacts)) 00045 { 00046 mMyContacts = mLastRequest->header(h_Contacts); 00047 } 00048 00049 if(mLastRequest->exists(h_Expires) && 00050 mLastRequest->header(h_Expires).isWellFormed()) 00051 { 00052 mRegistrationTime = mLastRequest->header(h_Expires).value(); 00053 } 00054 00055 mNetworkAssociation.setDum(&dum); 00056 } 00057 00058 ClientRegistration::~ClientRegistration() 00059 { 00060 DebugLog ( << "ClientRegistration::~ClientRegistration" ); 00061 mDialogSet.mClientRegistration = 0; 00062 00063 // !dcm! Will not interact well with multiple registrations from the same AOR 00064 mDialogSet.mUserProfile->setServiceRoute(NameAddrs()); 00065 } 00066 00067 void 00068 ClientRegistration::addBinding(const NameAddr& contact) 00069 { 00070 addBinding(contact, mDialogSet.mUserProfile->getDefaultRegistrationTime()); 00071 } 00072 00073 SharedPtr<SipMessage> 00074 ClientRegistration::tryModification(ClientRegistration::State state) 00075 { 00076 if (mState != Registered) 00077 { 00078 if(mState != RetryAdding && mState != RetryRefreshing) 00079 { 00080 if (mQueuedState != None) 00081 { 00082 WarningLog (<< "Trying to modify bindings when another request is already queued"); 00083 throw UsageUseException("Queuing multiple requests for Registration Bindings", __FILE__,__LINE__); 00084 } 00085 00086 *mQueuedRequest = *mLastRequest; 00087 mQueuedState = state; 00088 00089 return mQueuedRequest; 00090 } 00091 else 00092 { 00093 ++mTimerSeq; // disable retry timer 00094 } 00095 } 00096 00097 assert(mQueuedState == None); 00098 mState = state; 00099 00100 return mLastRequest; 00101 } 00102 00103 void 00104 ClientRegistration::addBinding(const NameAddr& contact, UInt32 registrationTime) 00105 { 00106 SharedPtr<SipMessage> next = tryModification(Adding); 00107 mMyContacts.push_back(contact); 00108 tagContact(mMyContacts.back()); 00109 00110 next->header(h_Contacts) = mMyContacts; 00111 mRegistrationTime = registrationTime; 00112 next->header(h_Expires).value() = mRegistrationTime; 00113 next->header(h_CSeq).sequence()++; 00114 // caller prefs 00115 00116 if (mQueuedState == None) 00117 { 00118 send(next); 00119 } 00120 } 00121 00122 void 00123 ClientRegistration::removeBinding(const NameAddr& contact) 00124 { 00125 if (mState == Removing) 00126 { 00127 WarningLog (<< "Already removing a binding"); 00128 throw UsageUseException("Can't remove binding when already removing registration bindings", __FILE__,__LINE__); 00129 } 00130 00131 SharedPtr<SipMessage> next = tryModification(Removing); 00132 for (NameAddrs::iterator i=mMyContacts.begin(); i != mMyContacts.end(); i++) 00133 { 00134 if (i->uri() == contact.uri()) 00135 { 00136 next->header(h_Contacts).clear(); 00137 next->header(h_Contacts).push_back(*i); 00138 next->header(h_Expires).value() = 0; 00139 next->header(h_CSeq).sequence()++; 00140 00141 if (mQueuedState == None) 00142 { 00143 send(next); 00144 } 00145 00146 mMyContacts.erase(i); 00147 return; 00148 } 00149 } 00150 00151 // !jf! What state are we left in now? 00152 throw Exception("No such binding", __FILE__, __LINE__); 00153 } 00154 00155 void 00156 ClientRegistration::removeAll(bool stopRegisteringWhenDone) 00157 { 00158 if (mState == Removing) 00159 { 00160 WarningLog (<< "Already removing a binding"); 00161 throw UsageUseException("Can't remove binding when already removing registration bindings", __FILE__,__LINE__); 00162 } 00163 00164 SharedPtr<SipMessage> next = tryModification(Removing); 00165 00166 mAllContacts.clear(); 00167 mMyContacts.clear(); 00168 00169 NameAddr all; 00170 all.setAllContacts(); 00171 next->header(h_Contacts).clear(); 00172 next->header(h_Contacts).push_back(all); 00173 next->header(h_Expires).value() = 0; 00174 next->header(h_CSeq).sequence()++; 00175 mEndWhenDone = stopRegisteringWhenDone; 00176 00177 if (mQueuedState == None) 00178 { 00179 send(next); 00180 } 00181 } 00182 00183 void 00184 ClientRegistration::removeMyBindings(bool stopRegisteringWhenDone) 00185 { 00186 InfoLog (<< "Removing binding"); 00187 00188 if (mState == Removing) 00189 { 00190 WarningLog (<< "Already removing a binding"); 00191 throw UsageUseException("Can't remove binding when already removing registration bindings", __FILE__,__LINE__); 00192 } 00193 00194 if (mMyContacts.empty()) 00195 { 00196 WarningLog (<< "No bindings to remove"); 00197 throw UsageUseException("No bindings to remove", __FILE__,__LINE__); 00198 } 00199 00200 SharedPtr<SipMessage> next = tryModification(Removing); 00201 00202 next->header(h_Contacts) = mMyContacts; 00203 mMyContacts.clear(); 00204 00205 NameAddrs& myContacts = next->header(h_Contacts); 00206 00207 for (NameAddrs::iterator i=myContacts.begin(); i != myContacts.end(); i++) 00208 { 00209 i->param(p_expires) = 0; 00210 } 00211 00212 next->remove(h_Expires); 00213 next->header(h_CSeq).sequence()++; 00214 00215 // !jf! is this ok if queued 00216 mEndWhenDone = stopRegisteringWhenDone; 00217 00218 if (mQueuedState == None) 00219 { 00220 send(next); 00221 } 00222 } 00223 00224 class ClientRegistrationRemoveMyBindings : public DumCommandAdapter 00225 { 00226 public: 00227 ClientRegistrationRemoveMyBindings(ClientRegistration& clientRegistration, bool stopRegisteringWhenDone) 00228 : mClientRegistration(clientRegistration), 00229 mStopRegisteringWhenDone(stopRegisteringWhenDone) 00230 { 00231 } 00232 00233 virtual void executeCommand() 00234 { 00235 mClientRegistration.removeMyBindings(mStopRegisteringWhenDone); 00236 } 00237 00238 virtual EncodeStream& encodeBrief(EncodeStream& strm) const 00239 { 00240 return strm << "ClientRegistrationRemoveMyBindings"; 00241 } 00242 private: 00243 ClientRegistration& mClientRegistration; 00244 bool mStopRegisteringWhenDone; 00245 }; 00246 00247 void 00248 ClientRegistration::removeMyBindingsCommand(bool stopRegisteringWhenDone) 00249 { 00250 mDum.post(new ClientRegistrationRemoveMyBindings(*this, stopRegisteringWhenDone)); 00251 } 00252 00253 void 00254 ClientRegistration::stopRegistering() 00255 { 00256 //timers aren't a concern, as DUM checks for Handle validity before firing. 00257 delete this; 00258 } 00259 00260 void 00261 ClientRegistration::requestRefresh(UInt32 expires) 00262 { 00263 // Set flag so that handlers get called for success/failure 00264 mUserRefresh = true; 00265 internalRequestRefresh(expires); 00266 } 00267 00268 void 00269 ClientRegistration::internalRequestRefresh(UInt32 expires) 00270 { 00271 if(mState == RetryAdding && mState == RetryRefreshing) 00272 { 00273 // disable retry time and try refresh immediately 00274 ++mTimerSeq; 00275 } 00276 else if (mState != Registered) 00277 { 00278 InfoLog (<< "a request is already in progress, no need to refresh " << *this); 00279 return; 00280 } 00281 00282 InfoLog (<< "requesting refresh of " << *this); 00283 00284 mState = Refreshing; 00285 mLastRequest->header(h_CSeq).sequence()++; 00286 mLastRequest->header(h_Contacts)=mMyContacts; 00287 if(expires > 0) 00288 { 00289 mRegistrationTime = expires; 00290 } 00291 mLastRequest->header(h_Expires).value()=mRegistrationTime; 00292 00293 send(mLastRequest); 00294 } 00295 00296 const NameAddrs& 00297 ClientRegistration::myContacts() 00298 { 00299 return mMyContacts; 00300 } 00301 00302 const NameAddrs& 00303 ClientRegistration::allContacts() 00304 { 00305 return mAllContacts; 00306 } 00307 00308 UInt32 00309 ClientRegistration::whenExpires() const 00310 { 00311 // !cj! - TODO - I'm supisious these time are getting confused on what units they are in 00312 UInt64 now = Timer::getTimeSecs(); 00313 UInt64 ret = mExpires - now; 00314 return (UInt32)ret; 00315 } 00316 00317 void 00318 ClientRegistration::end() 00319 { 00320 removeMyBindings(true); 00321 } 00322 00323 class ClientRegistrationEndCommand : public DumCommandAdapter 00324 { 00325 public: 00326 ClientRegistrationEndCommand(ClientRegistration& clientRegistration) 00327 : mClientRegistration(clientRegistration) 00328 { 00329 00330 } 00331 00332 virtual void executeCommand() 00333 { 00334 mClientRegistration.end(); 00335 } 00336 00337 virtual EncodeStream& encodeBrief(EncodeStream& strm) const 00338 { 00339 return strm << "ClientRegistrationEndCommand"; 00340 } 00341 private: 00342 ClientRegistration& mClientRegistration; 00343 }; 00344 00345 void 00346 ClientRegistration::endCommand() 00347 { 00348 mDum.post(new ClientRegistrationEndCommand(*this)); 00349 } 00350 00351 EncodeStream& 00352 ClientRegistration::dump(EncodeStream& strm) const 00353 { 00354 strm << "ClientRegistration " << mLastRequest->header(h_From).uri(); 00355 return strm; 00356 } 00357 00358 void 00359 ClientRegistration::dispatch(const SipMessage& msg) 00360 { 00361 try 00362 { 00363 // !jf! there may be repairable errors that we can handle here 00364 assert(msg.isResponse()); 00365 const int& code = msg.header(h_StatusLine).statusCode(); 00366 bool nextHopSupportsOutbound = false; 00367 int keepAliveTime = 0; 00368 00369 // If registration was successful - look for next hop indicating support for outbound 00370 if(mDialogSet.mUserProfile->clientOutboundEnabled() && msg.isExternal() && code >= 200 && code < 300) 00371 { 00372 // If ClientOutbound support is enabled and the registration response contains 00373 // Requires: outbound or a Path with outbound then outbound is supported by the 00374 // server, so store the flow key in the UserProfile 00375 // and use it for sending all messages (DialogUsageManager::sendUsingOutboundIfAppropriate) 00376 try 00377 { 00378 if((!msg.empty(h_Paths) && msg.header(h_Paths).back().uri().exists(p_ob)) || 00379 (!msg.empty(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Outbound)))) 00380 { 00381 mDialogSet.mUserProfile->mClientOutboundFlowTuple = msg.getSource(); 00382 mDialogSet.mUserProfile->mClientOutboundFlowTuple.onlyUseExistingConnection = true; 00383 nextHopSupportsOutbound = true; 00384 if(!msg.empty(h_FlowTimer)) 00385 { 00386 keepAliveTime = msg.header(h_FlowTimer).value(); 00387 } 00388 } 00389 } 00390 catch(BaseException&e) 00391 { 00392 ErrLog(<<"Error parsing Path or Requires:" << e); 00393 } 00394 } 00395 00396 if(msg.isExternal()) 00397 { 00398 const Data& receivedTransport = msg.header(h_Vias).front().transport(); 00399 if(keepAliveTime == 0) 00400 { 00401 if(receivedTransport == Symbols::TCP || 00402 receivedTransport == Symbols::TLS || 00403 receivedTransport == Symbols::SCTP) 00404 { 00405 keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream(); 00406 } 00407 else 00408 { 00409 keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForDatagram(); 00410 } 00411 } 00412 00413 if(keepAliveTime > 0) 00414 { 00415 mNetworkAssociation.update(msg, keepAliveTime, nextHopSupportsOutbound); 00416 } 00417 } 00418 00419 if (code < 200) 00420 { 00421 // throw it away 00422 return; 00423 } 00424 else if (code < 300) // success 00425 { 00426 try 00427 { 00428 if (msg.exists(h_ServiceRoutes)) 00429 { 00430 InfoLog(<< "Updating service route: " << Inserter(msg.header(h_ServiceRoutes))); 00431 mDialogSet.mUserProfile->setServiceRoute(msg.header(h_ServiceRoutes)); 00432 } 00433 else 00434 { 00435 DebugLog(<< "Clearing service route (" << Inserter(getUserProfile()->getServiceRoute()) << ")"); 00436 mDialogSet.mUserProfile->setServiceRoute(NameAddrs()); 00437 } 00438 } 00439 catch(BaseException &e) 00440 { 00441 ErrLog(<< "Error Parsing Service Route:" << e); 00442 } 00443 00444 //gruu update, should be optimized 00445 try 00446 { 00447 if(mDialogSet.mUserProfile->gruuEnabled() && msg.exists(h_Contacts)) 00448 { 00449 for (NameAddrs::const_iterator it = msg.header(h_Contacts).begin(); 00450 it != msg.header(h_Contacts).end(); it++) 00451 { 00452 if (it->exists(p_Instance) && it->param(p_Instance) == mDialogSet.mUserProfile->getInstanceId()) 00453 { 00454 if(it->exists(p_pubGruu)) 00455 { 00456 mDialogSet.mUserProfile->setPublicGruu(Uri(it->param(p_pubGruu))); 00457 } 00458 if(it->exists(p_tempGruu)) 00459 { 00460 mDialogSet.mUserProfile->setTempGruu(Uri(it->param(p_tempGruu))); 00461 } 00462 break; 00463 } 00464 } 00465 } 00466 } 00467 catch(BaseException&e) 00468 { 00469 ErrLog(<<"Error parsing GRUU:" << e); 00470 } 00471 00472 // !jf! consider what to do if no contacts 00473 // !ah! take list of ctcs and push into mMy or mOther as required. 00474 00475 // make timers to re-register 00476 UInt32 expiry = calculateExpiry(msg); 00477 if(msg.exists(h_Contacts)) 00478 { 00479 mAllContacts = msg.header(h_Contacts); 00480 } 00481 else 00482 { 00483 mAllContacts.clear(); 00484 } 00485 00486 if (expiry != 0 && expiry != UINT_MAX) 00487 { 00488 if(expiry>=7) 00489 { 00490 int exp = Helper::aBitSmallerThan(expiry); 00491 mExpires = exp + Timer::getTimeSecs(); 00492 mDum.addTimer(DumTimeout::Registration, 00493 exp, 00494 getBaseHandle(), 00495 ++mTimerSeq); 00496 } 00497 else 00498 { 00499 WarningLog(<< "Server is using an unreasonably low expiry: " 00500 << expiry 00501 << " We're just going to end this registration."); 00502 end(); 00503 return; 00504 } 00505 } 00506 00507 switch (mState) 00508 { 00509 case Querying: 00510 case Adding: 00511 if(expiry != 0) 00512 { 00513 mState = Registered; 00514 mDum.mClientRegistrationHandler->onSuccess(getHandle(), msg); 00515 } 00516 else 00517 { 00518 mDum.mClientRegistrationHandler->onRemoved(getHandle(), msg); 00519 checkProfileRetry(msg); 00520 } 00521 break; 00522 00523 case Removing: 00524 //mDum.mClientRegistrationHandler->onSuccess(getHandle(), msg); 00525 mDum.mClientRegistrationHandler->onRemoved(getHandle(), msg); 00526 InfoLog (<< "Finished removing registration " << *this << " mEndWhenDone=" << mEndWhenDone); 00527 if (mEndWhenDone) 00528 { 00529 // !kh! 00530 // stopRegistering() deletes 'this' 00531 // furthur processing makes no sense 00532 //assert(mQueuedState == None); 00533 stopRegistering(); 00534 return; 00535 } 00536 break; 00537 00538 case Registered: 00539 case Refreshing: 00540 mState = Registered; 00541 if(expiry != 0) 00542 { 00543 if(mUserRefresh) 00544 { 00545 mUserRefresh = false; 00546 mDum.mClientRegistrationHandler->onSuccess(getHandle(), msg); 00547 } 00548 } 00549 else 00550 { 00551 mDum.mClientRegistrationHandler->onRemoved(getHandle(), msg); 00552 checkProfileRetry(msg); 00553 } 00554 break; 00555 00556 default: 00557 break; 00558 } 00559 00560 if (mQueuedState != None) 00561 { 00562 InfoLog (<< "Sending queued request: " << *mQueuedRequest); 00563 mState = mQueuedState; 00564 mQueuedState = None; 00565 *mLastRequest = *mQueuedRequest; 00566 send(mLastRequest); 00567 } 00568 } 00569 else 00570 { 00571 if((mState == Adding || mState == Refreshing) && !mEndWhenDone) 00572 { 00573 if (code == 423) // interval too short 00574 { 00575 UInt32 maxRegistrationTime = mDialogSet.mUserProfile->getDefaultMaxRegistrationTime(); 00576 if (msg.exists(h_MinExpires) && 00577 (maxRegistrationTime == 0 || msg.header(h_MinExpires).value() < maxRegistrationTime)) // If maxRegistrationTime is enabled, then check it 00578 { 00579 mRegistrationTime = msg.header(h_MinExpires).value(); 00580 mLastRequest->header(h_Expires).value() = mRegistrationTime; 00581 mLastRequest->header(h_CSeq).sequence()++; 00582 send(mLastRequest); 00583 return; 00584 } 00585 } 00586 else if (code == 408 || (code == 503 && msg.getReceivedTransport() == 0)) 00587 { 00588 int retry = mDum.mClientRegistrationHandler->onRequestRetry(getHandle(), 0, msg); 00589 00590 if (retry < 0) 00591 { 00592 DebugLog(<< "Application requested failure on Retry-After"); 00593 } 00594 else if (retry == 0) 00595 { 00596 DebugLog(<< "Application requested immediate retry on 408 or internal 503"); 00597 00598 mLastRequest->header(h_CSeq).sequence()++; 00599 send(mLastRequest); 00600 mUserRefresh = true; // Reset this flag, so that the onSuccess callback will be called if we are successful when re-trying 00601 return; 00602 } 00603 else 00604 { 00605 DebugLog(<< "Application requested delayed retry on 408 or internal 503: " << retry); 00606 mExpires = 0; 00607 switch(mState) 00608 { 00609 case Adding: 00610 mState = RetryAdding; 00611 break; 00612 case Refreshing: 00613 mState = RetryRefreshing; 00614 break; 00615 default: 00616 assert(false); 00617 break; 00618 } 00619 if(mDum.mClientAuthManager.get()) mDum.mClientAuthManager.get()->clearAuthenticationState(DialogSetId(*mLastRequest)); 00620 mDum.addTimer(DumTimeout::RegistrationRetry, 00621 retry, 00622 getBaseHandle(), 00623 ++mTimerSeq); 00624 mUserRefresh = true; // Reset this flag, so that the onSuccess callback will be called if we are successful when re-trying 00625 return; 00626 } 00627 } 00628 } 00629 00630 mDum.mClientRegistrationHandler->onFailure(getHandle(), msg); 00631 mUserRefresh = true; // Reset this flag, so that the onSuccess callback will be called if we are successful when re-trying 00632 00633 // Retry if Profile setting is set 00634 unsigned int retryInterval = checkProfileRetry(msg); 00635 if(retryInterval > 0) 00636 { 00637 InfoLog( << "Registration error " << code << " for " << msg.header(h_To) << ", retrying in " << retryInterval << " seconds."); 00638 return; 00639 } 00640 00641 // assume that if a failure occurred, the bindings are gone 00642 if (mEndWhenDone) 00643 { 00644 mDum.mClientRegistrationHandler->onRemoved(getHandle(), msg); 00645 } 00646 delete this; 00647 } 00648 } 00649 catch(BaseException& e) 00650 { 00651 InfoLog( << "Exception in ClientRegistration::dispatch: " << e.getMessage()); 00652 mDum.mClientRegistrationHandler->onFailure(getHandle(), msg); 00653 delete this; 00654 } 00655 } 00656 00657 void 00658 ClientRegistration::tagContact(NameAddr& contact) const 00659 { 00660 tagContact(contact, mDum, mDialogSet.mUserProfile); 00661 } 00662 00663 void 00664 ClientRegistration::tagContact(NameAddr& contact, DialogUsageManager& dum, SharedPtr<UserProfile>& userProfile) 00665 { 00666 if(contact.uri().host().empty() || 00667 dum.getSipStack().isMyDomain(contact.uri().host(), contact.uri().port())) 00668 { 00669 // Contact points at us; it is appropriate to add a +sip.instance to 00670 // this Contact. We don't need to have full gruu support enabled to add 00671 // a +sip.instance either... 00672 if(userProfile->hasInstanceId()) 00673 { 00674 contact.param(p_Instance) = userProfile->getInstanceId(); 00675 if(userProfile->getRegId() != 0) 00676 { 00677 contact.param(p_regid) = userProfile->getRegId(); 00678 } 00679 } 00680 else if(userProfile->getRinstanceEnabled()) 00681 { 00682 // !slg! poor mans instance id so that we can tell which contacts 00683 // are ours - to be replaced by gruu someday. 00684 InfoLog(<< "You really should consider setting an instance id in" 00685 " the UserProfile (see UserProfile::setInstanceId())." 00686 " This is really easy, and makes this class much less " 00687 "likely to clash with another endpoint registering at " 00688 "the same AOR."); 00689 contact.uri().param(p_rinstance) = Random::getCryptoRandomHex(8); 00690 } 00691 else if(!contact.uri().user().empty()) 00692 { 00693 WarningLog(<< "Ok, not only have you not specified an instance id, " 00694 "you have disabled the rinstance hack (ie; resip's \"poor" 00695 " man's +sip.instance\"). We will try to match Contacts" 00696 " based on what you've put in the user-part of your " 00697 "Contact, but this can be dicey, especially if you've put" 00698 " something there that another endpoint is likely to " 00699 "use."); 00700 } 00701 else 00702 { 00703 ErrLog(<< "Ok, not only have you not specified an instance id, " 00704 "you have disabled the rinstance hack (ie; resip's \"poor" 00705 " man's +sip.instance\"), _and_ you haven't put anything" 00706 " in the user-part of your Contact. This is asking for " 00707 "confusion later. We'll do our best to try to match things" 00708 " up later when the response comes in..."); 00709 } 00710 } 00711 else 00712 { 00713 // Looks like a third-party registration. +sip.instance is out of the 00714 // question, but we can still use rinstance. 00715 if(userProfile->getRinstanceEnabled()) 00716 { 00717 // !slg! poor mans instance id so that we can tell which contacts 00718 // are ours - to be replaced by gruu someday. 00719 contact.uri().param(p_rinstance) = Random::getCryptoRandomHex(8); 00720 } 00721 else if(!contact.uri().user().empty()) 00722 { 00723 WarningLog(<< "You're trying to do a third-party registration, but " 00724 "you have disabled the rinstance hack (ie; resip's \"poor" 00725 " man's +sip.instance\"). We will try to match Contacts" 00726 " based on what you've put in the user-part of your " 00727 "Contact, but this can be dicey, especially if you've put" 00728 " something there that another endpoint is likely to " 00729 "use."); 00730 } 00731 else 00732 { 00733 ErrLog(<< "You're trying to do a third-party registration, and " 00734 "not only have you disabled the rinstance hack (ie; " 00735 "resip's \"poor man's +sip.instance\"), you haven't" 00736 " put anything in the user-part of your Contact. This is " 00737 "asking for confusion later. We'll do our best to try to " 00738 "match things up later when the response comes in..."); 00739 } 00740 } 00741 00742 if (userProfile->getMethodsParamEnabled()) 00743 { 00744 contact.param(p_methods) = dum.getMasterProfile()->getAllowedMethodsData(); 00745 } 00746 00747 // ?bwc? Host and port override? 00748 } 00749 00750 unsigned long 00751 ClientRegistration::calculateExpiry(const SipMessage& reg200) const 00752 { 00753 unsigned long expiry=mRegistrationTime; 00754 if(reg200.exists(h_Expires) && 00755 reg200.header(h_Expires).isWellFormed() && 00756 reg200.header(h_Expires).value() < expiry) 00757 { 00758 expiry=reg200.header(h_Expires).value(); 00759 } 00760 00761 if(!reg200.exists(h_Contacts)) 00762 { 00763 return expiry; 00764 } 00765 00766 const NameAddrs& contacts(reg200.header(h_Contacts)); 00767 00768 for(NameAddrs::const_iterator c=contacts.begin();c!=contacts.end();++c) 00769 { 00770 // Our expiry is never going to increase if we find one of our contacts, 00771 // so if the expiry is not lower, we just ignore it. For registrars that 00772 // leave our requested expiry alone, this code ends up being pretty quick, 00773 // especially if there aren't contacts from other endpoints laying around. 00774 if(c->isWellFormed() && 00775 c->exists(p_expires) && 00776 c->param(p_expires) < expiry && 00777 contactIsMine(*c)) 00778 { 00779 expiry=c->param(p_expires); 00780 } 00781 } 00782 return expiry; 00783 } 00784 00785 bool 00786 ClientRegistration::contactIsMine(const NameAddr& contact) const 00787 { 00788 // Try to find this contact in mMyContacts 00789 if(mDialogSet.mUserProfile->hasInstanceId() && 00790 contact.exists(p_Instance)) 00791 { 00792 return contact.param(p_Instance)==mDialogSet.mUserProfile->getInstanceId(); 00793 } 00794 else if(mDialogSet.mUserProfile->getRinstanceEnabled() && 00795 contact.uri().exists(p_rinstance)) 00796 { 00797 return rinstanceIsMine(contact.uri().param(p_rinstance)); 00798 } 00799 else 00800 { 00801 return searchByUri(contact.uri()); 00802 } 00803 } 00804 00805 bool 00806 ClientRegistration::rinstanceIsMine(const Data& rinstance) const 00807 { 00808 // !bwc! This could be made faster if we used a single rinstance... 00809 for(NameAddrs::const_iterator m=mMyContacts.begin(); m!=mMyContacts.end(); ++m) 00810 { 00811 if(m->uri().exists(p_rinstance) && m->uri().param(p_rinstance)==rinstance) 00812 { 00813 return true; 00814 } 00815 } 00816 return false; 00817 } 00818 00819 bool 00820 ClientRegistration::searchByUri(const Uri& cUri) const 00821 { 00822 for(NameAddrs::const_iterator m=mMyContacts.begin(); m!=mMyContacts.end(); ++m) 00823 { 00824 if(m->uri()==cUri) 00825 { 00826 return true; 00827 } 00828 else if(m->uri().host().empty() && 00829 m->uri().user()==cUri.user() && 00830 m->uri().scheme()==cUri.scheme() && 00831 mDum.getSipStack().isMyDomain(cUri.host(), cUri.port())) 00832 { 00833 // Empty host-part in our contact; this means we're relying on the 00834 // stack to fill out this Contact header. Also, the user-part matches. 00835 return true; 00836 } 00837 } 00838 return false; 00839 } 00840 00841 unsigned int 00842 ClientRegistration::checkProfileRetry(const SipMessage& msg) 00843 { 00844 unsigned int retryInterval = mDialogSet.mUserProfile->getDefaultRegistrationRetryTime(); 00845 if (retryInterval > 0 && 00846 (mState == Adding || mState == Refreshing) && 00847 !mEndWhenDone) 00848 { 00849 if (msg.exists(h_RetryAfter) && msg.header(h_RetryAfter).value() > 0) 00850 { 00851 // Use retry interval from error response 00852 retryInterval = msg.header(h_RetryAfter).value(); 00853 } 00854 mExpires = 0; 00855 switch(mState) 00856 { 00857 case Adding: 00858 mState = RetryAdding; 00859 break; 00860 case Refreshing: 00861 mState = RetryRefreshing; 00862 break; 00863 default: 00864 assert(false); 00865 break; 00866 } 00867 00868 if(mDum.mClientAuthManager.get()) mDum.mClientAuthManager.get()->clearAuthenticationState(DialogSetId(*mLastRequest)); 00869 mDum.addTimer(DumTimeout::RegistrationRetry, 00870 retryInterval, 00871 getBaseHandle(), 00872 ++mTimerSeq); 00873 return retryInterval; 00874 } 00875 return 0; 00876 } 00877 00878 void 00879 ClientRegistration::dispatch(const DumTimeout& timer) 00880 { 00881 switch(timer.type()) 00882 { 00883 case DumTimeout::Registration: 00884 // If you happen to be Adding/Updating when the timer goes off, you should just ignore 00885 // it since a new timer will get added when the 2xx is received. 00886 if (timer.seq() == mTimerSeq && mState == Registered) 00887 { 00888 if (!mMyContacts.empty()) 00889 { 00890 internalRequestRefresh(); 00891 } 00892 } 00893 break; 00894 00895 case DumTimeout::RegistrationRetry: 00896 if (timer.seq() == mTimerSeq) 00897 { 00898 switch(mState) 00899 { 00900 case RetryAdding: 00901 mState = Adding; 00902 break; 00903 case RetryRefreshing: 00904 mState = Refreshing; 00905 break; 00906 default: 00907 assert(false); 00908 break; 00909 } 00910 00911 // Resend last request 00912 mLastRequest->header(h_CSeq).sequence()++; 00913 mLastRequest->remove(h_ProxyAuthorizations); 00914 mLastRequest->remove(h_Authorizations); 00915 send(mLastRequest); 00916 } 00917 break; 00918 default: 00919 break; 00920 } 00921 } 00922 00923 void 00924 ClientRegistration::flowTerminated() 00925 { 00926 // Clear the network association 00927 mNetworkAssociation.clear(); 00928 00929 // Notify application - not default handler implementation is to immediately attempt 00930 // a re-registration in order to form a new flow 00931 mDum.mClientRegistrationHandler->onFlowTerminated(getHandle()); 00932 } 00933 00934 00935 /* ==================================================================== 00936 * The Vovida Software License, Version 1.0 00937 * 00938 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00939 * 00940 * Redistribution and use in source and binary forms, with or without 00941 * modification, are permitted provided that the following conditions 00942 * are met: 00943 * 00944 * 1. Redistributions of source code must retain the above copyright 00945 * notice, this list of conditions and the following disclaimer. 00946 * 00947 * 2. Redistributions in binary form must reproduce the above copyright 00948 * notice, this list of conditions and the following disclaimer in 00949 * the documentation and/or other materials provided with the 00950 00951 * distribution. 00952 * 00953 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00954 * and "Vovida Open Communication Application Library (VOCAL)" must 00955 * not be used to endorse or promote products derived from this 00956 * software without prior written permission. For written 00957 * permission, please contact vocal@vovida.org. 00958 * 00959 * 4. Products derived from this software may not be called "VOCAL", nor 00960 * may "VOCAL" appear in their name, without prior written 00961 * permission of Vovida Networks, Inc. 00962 * 00963 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00964 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00965 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00966 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00967 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00968 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00969 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00970 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00971 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00972 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00973 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00974 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00975 * DAMAGE. 00976 * 00977 * ==================================================================== 00978 * 00979 * This software consists of voluntary contributions made by Vovida 00980 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00981 * Inc. For more information on Vovida Networks, Inc., please see 00982 * <http://www.vovida.org/>. 00983 * 00984 */
1.7.5.1