22#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
36 std::shared_ptr<SipMessage> request)
38 mLastRequest(request),
40 mState(mLastRequest->exists(h_Contacts) ? Adding : Querying),
44 mRegistrationTime(mDialogSet.mUserProfile->getDefaultRegistrationTime()),
51 if (mLastRequest->exists(h_Contacts))
55 if(!(mLastRequest->header(h_Contacts).front() == all))
58 mMyContacts = mLastRequest->header(h_Contacts);
62 if(mLastRequest->exists(h_Expires) &&
63 mLastRequest->header(h_Expires).isWellFormed())
65 mRegistrationTime = mLastRequest->header(h_Expires).value();
68 mNetworkAssociation.
setDum(&dum);
73 DebugLog ( <<
"ClientRegistration::~ClientRegistration" );
86std::shared_ptr<SipMessage>
87ClientRegistration::tryModification(ClientRegistration::State state)
89 if (mState != Registered)
91 if(mState != RetryAdding && mState != RetryRefreshing)
93 if (mQueuedState != None)
95 WarningLog (<<
"Trying to modify bindings when another request is already queued");
96 throw UsageUseException(
"Queuing multiple requests for Registration Bindings", __FILE__,__LINE__);
99 *mQueuedRequest = *mLastRequest;
100 mQueuedState = state;
102 return mQueuedRequest;
119 auto next = tryModification(Adding);
123 next->header(h_Contacts) = mMyContacts;
124 mRegistrationTime = registrationTime;
125 next->header(h_Expires).value() = mRegistrationTime;
126 next->header(h_CSeq).sequence()++;
129 if (mQueuedState == None)
138 if (mState == Removing)
141 throw UsageUseException(
"Can't remove binding when already removing registration bindings", __FILE__,__LINE__);
144 auto next = tryModification(Removing);
145 for (NameAddrs::iterator i=mMyContacts.
begin(); i != mMyContacts.
end(); i++)
147 if (i->uri() == contact.
uri())
149 next->header(h_Contacts).clear();
150 next->header(h_Contacts).push_back(*i);
151 next->header(h_Expires).value() = 0;
152 next->header(h_CSeq).sequence()++;
154 if (mQueuedState == None)
159 mMyContacts.
erase(i);
165 throw Exception(
"No such binding", __FILE__, __LINE__);
171 if (mState == Removing)
174 throw UsageUseException(
"Can't remove binding when already removing registration bindings", __FILE__,__LINE__);
177 auto next = tryModification(Removing);
179 mAllContacts.
clear();
184 next->header(h_Contacts).clear();
185 next->header(h_Contacts).push_back(all);
186 next->header(h_Expires).value() = 0;
187 next->header(h_CSeq).sequence()++;
188 mEndWhenDone = stopRegisteringWhenDone;
190 if (mQueuedState == None)
199 InfoLog (<<
"Removing binding");
201 if (mState == Removing)
204 throw UsageUseException(
"Can't remove binding when already removing registration bindings", __FILE__,__LINE__);
207 if (mMyContacts.
empty())
213 auto next = tryModification(Removing);
215 next->header(h_Contacts) = mMyContacts;
222 myContact.param(p_expires) = 0;
225 next->remove(h_Expires);
226 next->header(h_CSeq).sequence()++;
229 mEndWhenDone = stopRegisteringWhenDone;
231 if (mQueuedState == None)
248 : mClientRegistrationHandle(clientRegistrationHandle),
249 mStopRegisteringWhenDone(stopRegisteringWhenDone)
255 if(mClientRegistrationHandle.isValid())
257 mClientRegistrationHandle->removeMyBindings(mStopRegisteringWhenDone);
263 return strm <<
"ClientRegistrationRemoveMyBindings";
267 bool mStopRegisteringWhenDone;
288 internalRequestRefresh(expires);
292ClientRegistration::internalRequestRefresh(
uint32_t expires)
294 if(mState == RetryAdding || mState == RetryRefreshing)
299 else if (mState != Registered)
301 InfoLog (<<
"a request is already in progress, no need to refresh " << *
this);
308 InfoLog (<<
"application doesn't want to refresh " << *
this);
313 InfoLog (<<
"requesting refresh of " << *
this);
316 mLastRequest->header(h_CSeq).sequence()++;
317 mLastRequest->header(h_Contacts)=mMyContacts;
320 mRegistrationTime = expires;
322 mLastRequest->header(h_Expires).value()=mRegistrationTime;
345 return static_cast<uint32_t>(mExpires - now);
367 : mClientRegistrationHandle(clientRegistrationHandle)
373 if(mClientRegistrationHandle.isValid())
375 mClientRegistrationHandle->end();
381 return strm <<
"ClientRegistrationEndCommand";
396 strm <<
"ClientRegistration " << mLastRequest->header(h_From).uri();
408 bool nextHopSupportsOutbound =
false;
409 int keepAliveTime = 0;
412 if(
mDialogSet.mUserProfile->clientOutboundEnabled() && msg.
isExternal() && code >= 200 && code < 300)
424 mDialogSet.mUserProfile->mClientOutboundFlowTuple.onlyUseExistingConnection =
true;
425 nextHopSupportsOutbound =
true;
426 if(!msg.
empty(h_FlowTimer))
428 keepAliveTime = msg.
header(h_FlowTimer).value();
434 ErrLog(<<
"Error parsing Path or Requires:" << e);
444 if (keepAliveTime == 0 ||
mDialogSet.mUserProfile->getKeepAliveTimeForStream() < keepAliveTime)
446 keepAliveTime =
mDialogSet.mUserProfile->getKeepAliveTimeForStream();
452 if (keepAliveTime == 0 ||
mDialogSet.mUserProfile->getKeepAliveTimeForDatagram() < keepAliveTime)
454 keepAliveTime =
mDialogSet.mUserProfile->getKeepAliveTimeForDatagram();
458 if(keepAliveTime > 0)
460 mNetworkAssociation.
update(msg, keepAliveTime, nextHopSupportsOutbound);
473 if (msg.
exists(h_ServiceRoutes))
486 ErrLog(<<
"Error Parsing Service Route:" << e);
494 for (NameAddrs::const_iterator it = msg.
header(h_Contacts).begin();
495 it != msg.
header(h_Contacts).end(); it++)
497 if (it->exists(p_Instance) && it->param(p_Instance) ==
mDialogSet.mUserProfile->getInstanceId())
499 if(it->exists(p_pubGruu))
501 mDialogSet.mUserProfile->setPublicGruu(
Uri(it->param(p_pubGruu)));
503 if(it->exists(p_tempGruu))
505 mDialogSet.mUserProfile->setTempGruu(
Uri(it->param(p_tempGruu)));
514 ErrLog(<<
"Error parsing GRUU:" << e);
522 uint32_t expiry = calculateExpiry(msg);
523 mExpires = nowSecs + expiry;
524 if(msg.
exists(h_Contacts))
526 mAllContacts = msg.
header(h_Contacts);
530 mAllContacts.
clear();
533 if (expiry != 0 && expiry != UINT_MAX)
538 mRefreshTime = exp + nowSecs;
546 WarningLog(<<
"Server is using an unreasonably low expiry: "
548 <<
" We're just going to end this registration.");
566 checkProfileRetry(msg);
573 InfoLog (<<
"Finished removing registration " << *
this <<
" mEndWhenDone=" << mEndWhenDone);
592 mUserRefresh =
false;
599 checkProfileRetry(msg);
607 if (mQueuedState != None)
609 if(mQueuedState == Removing && mEnding &&
whenExpires() == 0)
616 InfoLog (<<
"Sending queued request: " << *mQueuedRequest);
617 mState = mQueuedState;
619 *mLastRequest = *mQueuedRequest;
625 if((mState == Adding || mState == Refreshing) && !mEndWhenDone)
629 uint32_t maxRegistrationTime =
mDialogSet.mUserProfile->getDefaultMaxRegistrationTime();
630 if (msg.
exists(h_MinExpires) &&
631 (maxRegistrationTime == 0 || msg.
header(h_MinExpires).value() < maxRegistrationTime))
633 mRegistrationTime = msg.
header(h_MinExpires).value();
634 mLastRequest->header(h_Expires).value() = mRegistrationTime;
635 mLastRequest->header(h_CSeq).sequence()++;
640 else if (code == 408 || (code == 503 && !msg.
isFromWire()))
646 DebugLog(<<
"Application requested failure on Retry-After");
650 DebugLog(<<
"Application requested immediate retry on 408 or internal 503");
652 mLastRequest->header(h_CSeq).sequence()++;
659 DebugLog(<<
"Application requested delayed retry on 408 or internal 503: " << retry);
664 mState = RetryAdding;
667 mState = RetryRefreshing;
673 if(
mDum.mClientAuthManager.get())
mDum.mClientAuthManager.get()->clearAuthenticationState(
DialogSetId(*mLastRequest));
688 unsigned int retryInterval = checkProfileRetry(msg);
689 if(retryInterval > 0)
691 InfoLog( <<
"Registration error " << code <<
" for " << msg.
header(h_To) <<
", retrying in " << retryInterval <<
" seconds.");
726 if(userProfile->hasInstanceId())
728 contact.
param(p_Instance) = userProfile->getInstanceId();
729 if(userProfile->getRegId() != 0)
731 contact.
param(p_regid) = userProfile->getRegId();
734 else if(userProfile->getRinstanceEnabled())
738 InfoLog(<<
"You really should consider setting an instance id in"
739 " the UserProfile (see UserProfile::setInstanceId())."
740 " This is really easy, and makes this class much less "
741 "likely to clash with another endpoint registering at "
747 WarningLog(<<
"Ok, not only have you not specified an instance id, "
748 "you have disabled the rinstance hack (ie; resip's \"poor"
749 " man's +sip.instance\"). We will try to match Contacts"
750 " based on what you've put in the user-part of your "
751 "Contact, but this can be dicey, especially if you've put"
752 " something there that another endpoint is likely to "
757 ErrLog(<<
"Ok, not only have you not specified an instance id, "
758 "you have disabled the rinstance hack (ie; resip's \"poor"
759 " man's +sip.instance\"), _and_ you haven't put anything"
760 " in the user-part of your Contact. This is asking for "
761 "confusion later. We'll do our best to try to match things"
762 " up later when the response comes in...");
769 if(userProfile->getRinstanceEnabled())
777 WarningLog(<<
"You're trying to do a third-party registration, but "
778 "you have disabled the rinstance hack (ie; resip's \"poor"
779 " man's +sip.instance\"). We will try to match Contacts"
780 " based on what you've put in the user-part of your "
781 "Contact, but this can be dicey, especially if you've put"
782 " something there that another endpoint is likely to "
787 ErrLog(<<
"You're trying to do a third-party registration, and "
788 "not only have you disabled the rinstance hack (ie; "
789 "resip's \"poor man's +sip.instance\"), you haven't"
790 " put anything in the user-part of your Contact. This is "
791 "asking for confusion later. We'll do our best to try to "
792 "match things up later when the response comes in...");
796 if (userProfile->getMethodsParamEnabled())
805ClientRegistration::calculateExpiry(
const SipMessage& reg200)
const
807 unsigned long expiry=mRegistrationTime;
808 if(reg200.
exists(h_Expires) &&
810 reg200.
header(h_Expires).value() < expiry)
812 expiry=reg200.
header(h_Expires).value();
815 if(!reg200.
exists(h_Contacts))
841 unsigned long reasonableExpiry = 0xFFFFFFFF;
843 for(NameAddrs::const_iterator c=contacts.begin();c!=contacts.end();++c)
849 if(c->isWellFormed() && c->exists(p_expires))
851 const unsigned long contactExpires = c->param(p_expires);
852 if((contactExpires < expiry ||
853 contactExpires < reasonableExpiry) &&
856 expiry = contactExpires;
859 reasonableExpiry = contactExpires;
869 expiry = reasonableExpiry;
875ClientRegistration::contactIsMine(
const NameAddr& contact)
const
878 if(
mDialogSet.mUserProfile->hasInstanceId() &&
879 contact.
exists(p_Instance))
881 return contact.
param(p_Instance)==
mDialogSet.mUserProfile->getInstanceId();
883 else if(
mDialogSet.mUserProfile->getRinstanceEnabled() &&
886 return rinstanceIsMine(contact.
uri().
param(p_rinstance));
890 return searchByUri(contact.
uri());
895ClientRegistration::rinstanceIsMine(
const Data& rinstance)
const
898 for(NameAddrs::const_iterator m=mMyContacts.
begin(); m!=mMyContacts.
end(); ++m)
900 if(m->uri().exists(p_rinstance) && m->uri().param(p_rinstance)==rinstance)
909ClientRegistration::searchByUri(
const Uri& cUri)
const
911 for(NameAddrs::const_iterator m=mMyContacts.
begin(); m!=mMyContacts.
end(); ++m)
917 else if(m->uri().host().empty() &&
918 m->uri().user()==cUri.
user() &&
919 m->uri().scheme()==cUri.
scheme() &&
931ClientRegistration::checkProfileRetry(
const SipMessage& msg)
933 unsigned int retryInterval =
mDialogSet.mUserProfile->getDefaultRegistrationRetryTime();
934 if (retryInterval > 0 &&
935 (mState == Adding || mState == Refreshing) &&
938 if (msg.
exists(h_RetryAfter) && msg.
header(h_RetryAfter).value() > 0)
941 retryInterval = msg.
header(h_RetryAfter).value();
947 mState = RetryAdding;
950 mState = RetryRefreshing;
957 if(
mDum.mClientAuthManager)
mDum.mClientAuthManager->clearAuthenticationState(
DialogSetId(*mLastRequest));
962 return retryInterval;
975 if (timer.
seq() == mTimerSeq && mState == Registered)
977 if (!mMyContacts.
empty())
979 internalRequestRefresh();
985 if (timer.
seq() == mTimerSeq)
992 case RetryRefreshing:
1001 mLastRequest->header(h_CSeq).sequence()++;
1002 mLastRequest->remove(h_ProxyAuthorizations);
1003 mLastRequest->remove(h_Authorizations);
1013ClientRegistration::flowTerminated()
1016 mNetworkAssociation.
clear();
static const uint32_t UnreasonablyLowExpirationThreshold
#define WarningLog(args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ClientRegistrationEndCommand(const ClientRegistrationHandle &clientRegistrationHandle)
void executeCommand() override
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
void executeCommand() override
ClientRegistrationRemoveMyBindings(const ClientRegistrationHandle &clientRegistrationHandle, bool stopRegisteringWhenDone)
The abstract base-class for all exceptions thrown by resip code.
const Data & getMessage() const noexcept
BaseUsageHandle getBaseHandle() const
DialogUsageManager & mDum
virtual void onFailure(ClientRegistrationHandle, const SipMessage &response)=0
Called if registration fails, usage will be destroyed (unless a Registration retry interval is enable...
virtual void onFlowTerminated(ClientRegistrationHandle)
Called when a TCP or TLS flow to the server has terminated.
virtual int onRequestRetry(ClientRegistrationHandle, int retrySeconds, const SipMessage &response)=0
call on Retry-After failure.
virtual bool onRefreshRequired(ClientRegistrationHandle, const SipMessage &lastRequest)
Called before attempting to refresh a registration Return true if the refresh should go ahead or fals...
virtual void onSuccess(ClientRegistrationHandle, const SipMessage &response)=0
Called when registration succeeds or each time it is successfully refreshed (manual refreshes only).
virtual void onRemoved(ClientRegistrationHandle, const SipMessage &response)=0
void removeAll(bool stopRegisteringWhenDone=false)
Removes all bindings associated with the AOR - even those that may have been by a another UA.
EncodeStream & dump(EncodeStream &strm) const override
void addBinding(const NameAddr &contact)
Adds a registration binding, using the registration from the UserProfile.
void removeBinding(const NameAddr &contact)
Removes one particular binding.
virtual ~ClientRegistration()
const NameAddrs & myContacts() const noexcept
returns a list of contacts added by addBinding
void stopRegistering()
kills the usgage, does not unregister, call removeMyBindings to unregister
ClientRegistrationHandle getHandle()
void removeMyBindingsCommand(bool stopRegisteringWhenDone=false)
Provide asynchronous method access by using command.
void requestRefresh(uint32_t expires=0)
Request a manual refresh of the registration.
static void tagContact(NameAddr &contact, DialogUsageManager &dum, const std::shared_ptr< UserProfile > &userProfile)
ClientRegistration(DialogUsageManager &dum, DialogSet &dialog, std::shared_ptr< SipMessage > req)
virtual void endCommand()
void removeMyBindings(bool stopRegisteringWhenDone=false)
Removes all bindings added by addBinding.
void end() override
Calls removeMyBindings and ends usage when complete.
void dispatch(const SipMessage &msg) override
const NameAddrs & allContacts() const noexcept
returns a list of all contacts for this AOR - may include those added by other UA's
uint32_t whenExpires() const
returns the number of seconds until the registration expires - relative, returns 0 if already expired
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
bool empty() const noexcept
Checks whether the Data is empty.
std::shared_ptr< MasterProfile > & getMasterProfile()
static T aBitSmallerThan(T secs)
Used by Registration, Publication and Subscription refreshes, to calculate the time at which a refres...
bool isWellFormed() const
Returns true iff this element was parsed successfully, according to the implementation of parse().
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
bool exists(const Param< NameAddr > ¶mType) const
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
void setDum(DialogUsageManager *dum)
bool update(const SipMessage &msg, int keepAliveInterval, bool targetSupportsOutbound)
virtual void send(std::shared_ptr< SipMessage > msg)
std::shared_ptr< UserProfile > getUserProfile() const noexcept
bool empty() const
return true or false indicating whether the mParsers vector is empty or not
void clear()
clear the mParsers vector
iterator end()
Returns an iterator pointing to the last header field value.
T & back()
Returns the last header field value in this container.
iterator erase(iterator i)
Erases the header field value pointed to by i.
iterator begin()
Returns an iterator pointing to the first header field value.
void push_back(const T &t)
Inserts a header field value at the back of this container.
static Data getCryptoRandomHex(unsigned int numBytes)
Represents a SIP message.
bool empty(const HeaderBase &headerType) const
Returns true if the header field is present and non-empty, false otherwise.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
bool isResponse() const
Returns true if message is a response, false otherwise.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
const Tuple & getSource() const
Returns the source tuple that the message was received from only makes sense for messages received fr...
bool isFromWire() const
Check if SipMessage came off the wire.
bool isExternal() const
Check if SipMessage is to be treated as it came off the wire.
bool isMyDomain(const Data &domain, int port) const
Returns true if domain is handled by this stack.
static const char * Outbound
static uint64_t getTimeSecs()
Returns the current clock time in seconds.
Represents the "token" element in the RFC 3261 grammar.
void post(Message *msg)
Posts a Message to this TransactionUser's fifo.
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
bool exists(const Param< Uri > ¶mType) const
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
InserterClass< T > Inserter(const T &t)
Templatized function to construct an instance of InserterClass for a container to be inserted.
Handle< ClientRegistration > ClientRegistrationHandle
TransportType toTransportType(const resip::Data &transportName)
unsigned long long uint64_t
ParserContainer< NameAddr > NameAddrs
TransportType
An enumeration of transport protocols.
bool isReliable(TransportType type)
Returns true if passed in transport type is a reliable transport protocol.