reSIProcate/DialogUsageManager  9694
Classes | Public Member Functions | Protected Member Functions | Private Types | Private Member Functions | Private Attributes | Friends
resip::ServerRegistration Class Reference

#include <ServerRegistration.hxx>

Inheritance diagram for resip::ServerRegistration:
Inheritance graph
[legend]
Collaboration diagram for resip::ServerRegistration:
Collaboration graph
[legend]

List of all members.

Classes

class  AsyncLocalStore
 Local datastore used to aggregate all changes to the current contact list when using the asynchronous logic. More...

Public Member Functions

ServerRegistrationHandle getHandle ()
void accept (SipMessage &ok)
 Accept a SIP registration with a specific response.
void accept (int statusCode=200)
 Accept a SIP registration.
void reject (int statusCode)
 Reject a SIP registration.
virtual void end ()
virtual void dispatch (const SipMessage &msg)
virtual void dispatch (const DumTimeout &timer)
virtual EncodeStreamdump (EncodeStream &strm) const
bool asyncProvideContacts (std::auto_ptr< resip::ContactPtrList > contacts)
 Used when useAsyncProcessing() is true.
resip::SharedPtr< ContactList > getOriginalContacts ()
const ContactList & getRequestContacts ()

Protected Member Functions

virtual ~ServerRegistration ()

Private Types

enum  AsyncState {
  asyncStateNone, asyncStateWaitingForInitialContactList, asyncStateProcessingRegistration, asyncStateWaitingForAcceptReject,
  asyncStateAcceptedWaitingForFinalContactList, asyncStateProvidedFinalContacts, asyncStateQueryOnly
}
 States are used to keep track of asynchronous requests made to the database. More...
typedef enum
resip::ServerRegistration::AsyncState 
AsyncState
 States are used to keep track of asynchronous requests made to the database.

Private Member Functions

 ServerRegistration (DialogUsageManager &dum, DialogSet &dialogSet, const SipMessage &request)
bool tryFlow (ContactInstanceRecord &rec, const resip::SipMessage &msg)
bool flowTokenNeededForTls (const ContactInstanceRecord &rec) const
bool flowTokenNeededForSigcomp (const ContactInstanceRecord &rec) const
bool testFlowRequirements (ContactInstanceRecord &rec, const resip::SipMessage &msg, bool hasFlow) const
 ServerRegistration (const ServerRegistration &)
ServerRegistrationoperator= (const ServerRegistration &)
void processRegistration (const SipMessage &msg)
 Look at the contacts provided by the incoming REGISTER.
void asyncProcessFinalOkMsg (SipMessage &msg, ContactPtrList &contacts)
void processFinalOkMsg (SipMessage &msg, ContactList &contacts)
 Add contacs to msg, adding expires param.
void asyncProcessFinalContacts (std::auto_ptr< resip::ContactPtrList > contacts)
 After the user calls accept(), ServerRegistration will apply the local contact list and wait for a final contact list.

Private Attributes

SipMessage mRequest
Uri mAor
resip::SharedPtr< ContactList > mOriginalContacts
ContactList mRequestContacts
bool mDidOutbound
AsyncState mAsyncState
resip::SharedPtr< AsyncLocalStoremAsyncLocalStore
resip::SharedPtr< SipMessagemAsyncOkMsg
 Message stored during accept() call when waiting for final contact list from database.

Friends

class DialogSet

Detailed Description

Definition at line 11 of file ServerRegistration.hxx.


Member Typedef Documentation

States are used to keep track of asynchronous requests made to the database.

Typical activity & state progression for a successful registration (onQuery & reject() are slightly different):

DUM ServerRegistration RegistrationHandler _____________________________________________________________________________________________________

1) dispatch()/asyncStateNone---> 2) asyncGetContacts()/asyncStateWaitingForInitialContactList---> ====================================================================================================== 3) <---asyncProvideContacts()/asyncStateProcessingRegistration 4) processRegistration() 5) (onRefresh()|onRemove()|onAdd()|onRemoveAll()|onQuery)/asyncStateWaitingForAcceptReject---> ====================================================================================================== 6) <---accept() 7) asyncUpdateContacts/asyncStateAcceptedWaitingForFinalContactList---> ====================================================================================================== 8) <---asyncProvideContacts()/asyncStateProvidedFinalContacts 9) asyncProcessFinalContacts()/asyncStateNone 10) <---send(200Ok) ______________________________________________________________________________________________________

onQuery processing is similar, except it immediately sends the 200Ok after handling the accept().

ServerRegistration::reject() does not require roll-back and the error is immediately sent back to DUM.

It is possible to call ServerRegistration::reject() after calling accept() (DB failure, app failure, etc)


Member Enumeration Documentation

States are used to keep track of asynchronous requests made to the database.

Typical activity & state progression for a successful registration (onQuery & reject() are slightly different):

DUM ServerRegistration RegistrationHandler _____________________________________________________________________________________________________

1) dispatch()/asyncStateNone---> 2) asyncGetContacts()/asyncStateWaitingForInitialContactList---> ====================================================================================================== 3) <---asyncProvideContacts()/asyncStateProcessingRegistration 4) processRegistration() 5) (onRefresh()|onRemove()|onAdd()|onRemoveAll()|onQuery)/asyncStateWaitingForAcceptReject---> ====================================================================================================== 6) <---accept() 7) asyncUpdateContacts/asyncStateAcceptedWaitingForFinalContactList---> ====================================================================================================== 8) <---asyncProvideContacts()/asyncStateProvidedFinalContacts 9) asyncProcessFinalContacts()/asyncStateNone 10) <---send(200Ok) ______________________________________________________________________________________________________

onQuery processing is similar, except it immediately sends the 200Ok after handling the accept().

ServerRegistration::reject() does not require roll-back and the error is immediately sent back to DUM.

It is possible to call ServerRegistration::reject() after calling accept() (DB failure, app failure, etc)

Enumerator:
asyncStateNone 
asyncStateWaitingForInitialContactList 

Sent an asynchronous request to get the current contact list from the DB.

asyncStateProcessingRegistration 

received the initial contact list, processing the current REGISTER request and updating the contact list.

asyncStateWaitingForAcceptReject 

RegistrationHandler called, waiting for accept() or reject() from user.

asyncStateAcceptedWaitingForFinalContactList 

asyncUpdateContacts() has been called, waiting for final list.

asyncStateProvidedFinalContacts 

After receiving the final contact list; process the accepted register and send response.

asyncStateQueryOnly 

The REGISTER is a query, so just send back the current list in accept().

Definition at line 107 of file ServerRegistration.hxx.


Constructor & Destructor Documentation

ServerRegistration::~ServerRegistration ( ) [protected, virtual]
ServerRegistration::ServerRegistration ( DialogUsageManager dum,
DialogSet dialogSet,
const SipMessage request 
) [private]

Definition at line 26 of file ServerRegistration.cxx.

   : NonDialogUsage(dum, dialogSet),
     mRequest(request),
      mDidOutbound(false),
      mAsyncState(asyncStateNone)
{}
resip::ServerRegistration::ServerRegistration ( const ServerRegistration ) [private]

Member Function Documentation

void ServerRegistration::accept ( SipMessage ok)

Accept a SIP registration with a specific response.

Any contacts in this message will be deleted and replaced with the list created during REGISTER processing.

!Warning! After calling this function from a ServerRegistrationHandle, do not access the handle as this function may delete this object. Use ServerRegistrationHandle::isValidHandle() to test if it's deleted.

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

Definition at line 45 of file ServerRegistration.cxx.

References asyncProcessFinalOkMsg(), resip::ServerRegistrationHandler::asyncProcessing(), asyncStateAcceptedWaitingForFinalContactList, asyncStateQueryOnly, resip::ServerRegistrationHandler::asyncUpdateContacts(), resip::SipMessage::clone(), resip::SipStack::enableFlowTimer(), resip::SharedPtr< T >::get(), resip::RegistrationPersistenceManager::getContacts(), resip::InteropHelper::getFlowTimerSeconds(), getHandle(), resip::DialogUsageManager::getSipStack(), resip::SipMessage::getSource(), resip::SipMessage::header(), InfoLog, mAor, mAsyncLocalStore, mAsyncOkMsg, mAsyncState, mDidOutbound, resip::BaseUsage::mDum, resip::DialogUsageManager::mRegistrationPersistenceManager, mRequest, resip::DialogUsageManager::mServerRegistrationHandler, outbound, processFinalOkMsg(), resip::SipMessage::remove(), resip::DialogUsageManager::send(), and resip::RegistrationPersistenceManager::unlockRecord().

Referenced by accept().

{
   ok.remove(h_Contacts);

   InfoLog( << "accepted a registration " << mAor );

   if (mDidOutbound)
   {
      ok.header(h_Requires).push_back(outbound);
      if(InteropHelper::getFlowTimerSeconds() > 0)
      {
         ok.header(h_FlowTimer).value() = InteropHelper::getFlowTimerSeconds();         
         mDum.getSipStack().enableFlowTimer(mRequest.getSource());
      }
   }

   if (!mDum.mServerRegistrationHandler->asyncProcessing())
   {
      // Add all registered contacts to the message.
      RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;

      ContactList contacts;
      database->getContacts(mAor, contacts);

      //removes expired entries from the ok msg as well as calls the database to remove expired contacts.
      processFinalOkMsg(ok,contacts);

      database->unlockRecord(mAor);

      SharedPtr<SipMessage> msg(static_cast<SipMessage*>(ok.clone()));
      mDum.send(msg);
      delete(this);
   }
   else
   {
      if (mAsyncState == asyncStateQueryOnly)
      {
         if (!mAsyncLocalStore.get())
         {
            assert(0);
         }
         else
         {
            std::auto_ptr<ContactRecordTransactionLog> log;
            std::auto_ptr<ContactPtrList> contacts;

            mAsyncLocalStore->releaseLog(log,contacts);

            if (contacts.get())
            {
               asyncProcessFinalOkMsg(ok,*contacts);
            }
         }

         SharedPtr<SipMessage> msg(static_cast<SipMessage*>(ok.clone()));
         mDum.send(msg);
         delete(this);        
      }
      else
      {
         if (!mAsyncLocalStore.get())
         {
            assert(0);
            return;
         }
         //This register was accepted, but still need to apply the changes made by this register and then
         //receive a final contact list before sending the 200.
         mAsyncState = asyncStateAcceptedWaitingForFinalContactList;

         std::auto_ptr<ContactRecordTransactionLog> log;
         std::auto_ptr<ContactPtrList> modifiedContacts;

         mAsyncLocalStore->releaseLog(log,modifiedContacts);

         mAsyncOkMsg = SharedPtr<SipMessage>(static_cast<SipMessage*>(ok.clone()));
         mDum.mServerRegistrationHandler->asyncUpdateContacts(getHandle(),mAor,modifiedContacts,log);
         return;
      }
   }
}

Here is the call graph for this function:

void ServerRegistration::accept ( int  statusCode = 200)

Accept a SIP registration.

!Warning! After calling this function from a ServerRegistrationHandle, do not access the handle as this function may delete this object. Use ServerRegistrationHandle::isValidHandle() to test if it's deleted.

Definition at line 128 of file ServerRegistration.cxx.

References accept(), resip::SipMessage::empty(), resip::SipMessage::header(), resip::DialogUsageManager::makeResponse(), resip::BaseUsage::mDum, mRequest, and resip::Symbols::Path.

{
   SipMessage success;
   mDum.makeResponse(success, mRequest, statusCode);
   // .bwc. Copy Path headers if present, indicate Path support
   // ?bwc? If path headers are present, but client indicates no path support, 
   // RFC 3327 says it is a matter of policy of whether to accept the 
   // registration or not. What should we do here? Is it worth it to make this 
   // configurable?
   if(!mRequest.empty(h_Paths))
   {
      success.header(h_Paths)=mRequest.header(h_Paths);
      success.header(h_Supporteds).push_back(Token(Symbols::Path));
   }
   accept(success);
}

Here is the call graph for this function:

void ServerRegistration::asyncProcessFinalContacts ( std::auto_ptr< resip::ContactPtrList >  contacts) [private]

After the user calls accept(), ServerRegistration will apply the local contact list and wait for a final contact list.

Once the final list is received via asyncProvideContacts(), this function finishes the REGISTER processing.

Definition at line 714 of file ServerRegistration.cxx.

References asyncProcessFinalOkMsg(), asyncStateNone, resip::SharedPtr< T >::get(), mAsyncOkMsg, mAsyncState, resip::BaseUsage::mDum, resip::SharedPtr< T >::reset(), and resip::DialogUsageManager::send().

Referenced by asyncProvideContacts().

{
   if (contacts.get())
   {
      if (!mAsyncOkMsg.get())
      {
         assert(0);
      }
      else
      {
         asyncProcessFinalOkMsg(*mAsyncOkMsg,*contacts);
      }
   }

   mAsyncState = asyncStateNone;
   mDum.send(mAsyncOkMsg);
   mAsyncOkMsg.reset();
   delete(this);
}

Here is the call graph for this function:

void ServerRegistration::asyncProcessFinalOkMsg ( SipMessage msg,
ContactPtrList &  contacts 
) [private]

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

Definition at line 608 of file ServerRegistration.cxx.

References resip::ServerRegistrationHandler::asyncRemoveExpired(), expired(), getHandle(), resip::Timer::getTimeSecs(), resip::SipMessage::header(), mAor, resip::BaseUsage::mDum, and resip::DialogUsageManager::mServerRegistrationHandler.

Referenced by accept(), and asyncProcessFinalContacts().

{
   if (contacts.size() > 0)
   {
      ContactPtrList::iterator it(contacts.begin());
      ContactPtrList::iterator itEnd(contacts.end());

      std::auto_ptr<ContactPtrList> expired;

      UInt64 now=Timer::getTimeSecs();

      for (;it != itEnd;++it)
      {
         resip::SharedPtr<ContactInstanceRecord> rec(*it);

         if (!rec)
         {
            assert(0);
            continue;
         }

         if (rec->mRegExpires <= now)
         {
            if (!expired.get())
            {
               expired = std::auto_ptr<ContactPtrList>(new ContactPtrList());
            }
            expired->push_back(rec);
            continue;
         }

         rec->mContact.param(p_expires) = UInt32(rec->mRegExpires - now);
         msg.header(h_Contacts).push_back(rec->mContact);
      }

      if (expired.get() && expired->size() > 0)
      {
         mDum.mServerRegistrationHandler->asyncRemoveExpired(getHandle(),mAor,expired);
         return;
      }
   }
}

Here is the call graph for this function:

bool ServerRegistration::asyncProvideContacts ( std::auto_ptr< resip::ContactPtrList >  contacts)

Used when useAsyncProcessing() is true.

Provide the current set of contacts for this registration for processing. This is required during initial registration processing to provide a local copy of the registered contacts, which are then updated by the registration processing. At the end of the registration processing this function must provide a final list of contacts after any user-defined manipulation.

!CAUTION! This function must be called from the DUM thread.

Definition at line 680 of file ServerRegistration.cxx.

References asyncProcessFinalContacts(), asyncStateAcceptedWaitingForFinalContactList, asyncStateProcessingRegistration, asyncStateProvidedFinalContacts, asyncStateWaitingForAcceptReject, asyncStateWaitingForInitialContactList, resip::SharedPtr< T >::get(), mAsyncLocalStore, mAsyncState, mRequest, and processRegistration().

{
   switch (mAsyncState)
   {
      case asyncStateWaitingForInitialContactList:
      {
         assert(mAsyncLocalStore.get() == 0);
         mAsyncLocalStore = resip::SharedPtr<AsyncLocalStore>(new AsyncLocalStore(contacts));
         mAsyncState = asyncStateProcessingRegistration;
         processRegistration(mRequest);
         break;
      }
      case asyncStateWaitingForAcceptReject:
      {
         assert(0); //need to call accept() or reject(), wait for asyncUpdateContacts(), then call this function.
         return false;
      }
      case asyncStateAcceptedWaitingForFinalContactList:
      {
         mAsyncState = asyncStateProvidedFinalContacts;
         asyncProcessFinalContacts(contacts);
         break;
      }
      default:
      {
         assert(0);
         return false;
      }
   }

   return true;
}

Here is the call graph for this function:

void ServerRegistration::dispatch ( const SipMessage msg) [virtual]

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

Implements resip::BaseUsage.

Definition at line 174 of file ServerRegistration.cxx.

References asyncStateWaitingForInitialContactList, DebugLog, resip::Uri::getAorAsUri(), getHandle(), resip::DialogUsageManager::getMasterProfile(), resip::SipMessage::getSource(), resip::Tuple::getType(), h_StatusLine, resip::SipMessage::header(), resip::SipMessage::isRequest(), resip::DialogUsageManager::makeResponse(), mAor, mAsyncState, resip::BaseUsage::mDum, resip::DialogUsageManager::mRegistrationPersistenceManager, resip::DialogUsageManager::mServerRegistrationHandler, processRegistration(), resip::Uri::scheme(), resip::DialogUsageManager::send(), and resip::RequestLine::uri().

Referenced by resip::DialogSet::dispatch().

{
   DebugLog( << "got a registration" );
   
   assert(msg.isRequest());
   ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
   RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;

   if (!handler || (!handler->asyncProcessing() && !database))
   {
      // ?bwc? This is a server error; why are we sending a 4xx?
      // ?jmatthewsr? Possibly because of the note in section 21.5.2 about recognizing the method, but not supporting it?
       DebugLog( << "No handler or DB - sending 405" );
       
       SharedPtr<SipMessage> failure(new SipMessage);
       mDum.makeResponse(*failure, msg, 405);
       mDum.send(failure);
       delete(this);
       return;
    }

    mAor = msg.header(h_To).uri().getAorAsUri(msg.getSource().getType());

   // Checks to see whether this scheme is valid, and supported.
   if (!((mAor.scheme()=="sip" || mAor.scheme()=="sips")
         && mDum.getMasterProfile()->isSchemeSupported(mAor.scheme())))
   {
       DebugLog( << "Bad scheme in Aor" );
       
       SharedPtr<SipMessage> failure(new SipMessage);
       mDum.makeResponse(*failure, msg, 400);
       failure->header(h_StatusLine).reason() = "Bad/unsupported scheme in To: " + mAor.scheme();
       mDum.send(failure);
       delete(this);
       return;
   }
   
   if (handler->asyncProcessing())
   {
      mAsyncState = asyncStateWaitingForInitialContactList;
      handler->asyncGetContacts(getHandle(),mAor);
      return;
   }

   processRegistration(msg);
}

Here is the call graph for this function:

void ServerRegistration::dispatch ( const DumTimeout timer) [virtual]

Implements resip::BaseUsage.

Definition at line 439 of file ServerRegistration.cxx.

{
}
EncodeStream & ServerRegistration::dump ( EncodeStream strm) const [virtual]

Implements resip::BaseUsage.

Definition at line 444 of file ServerRegistration.cxx.

References mAor.

{
   strm << "ServerRegistration " << mAor;
   return strm;
}
void ServerRegistration::end ( ) [virtual]

Implements resip::BaseUsage.

Definition at line 39 of file ServerRegistration.cxx.

{
}
bool ServerRegistration::flowTokenNeededForSigcomp ( const ContactInstanceRecord rec) const [private]

Definition at line 575 of file ServerRegistration.cxx.

References DebugLog, resip::Uri::exists(), resip::ContactInstanceRecord::mContact, resip::ParserCategory::param(), resip::TCP, resip::TLS, resip::Tuple::toTransport(), type, and resip::NameAddr::uri().

Referenced by testFlowRequirements(), and tryFlow().

{
   const resip::NameAddr& contact(rec.mContact);

   if(contact.uri().exists(p_sigcompId))
   {
      if(contact.uri().exists(p_transport))
      {
         TransportType type = Tuple::toTransport(contact.uri().param(p_transport));
         if(type == TLS || type == TCP)
         {
            // Client is using sigcomp on the first hop using a connection-
            // oriented transport. For this to work, that connection has to be
            // reused for all traffic.
            return true;
         }
      }
      else
      {
         // ?bwc? Client is using sigcomp, but we're not sure whether this is
         // over a connection-oriented transport or not.
         DebugLog(<< "Client is using sigcomp, but we're not sure whether this "
                     "is over a connection-oriented transport or not, because "
                     "the contact doesn't have a transport param in it. It is "
                     "possible this will work though, so we'll let it proceed."
                     );
      }
   }
   return false;
}

Here is the call graph for this function:

bool ServerRegistration::flowTokenNeededForTls ( const ContactInstanceRecord rec) const [private]

Definition at line 548 of file ServerRegistration.cxx.

References resip::DTLS, resip::Uri::exists(), resip::Uri::host(), resip::DnsUtil::isIpAddress(), resip::ContactInstanceRecord::mContact, resip::ParserCategory::param(), resip::Uri::scheme(), resip::TLS, resip::Tuple::toTransport(), type, and resip::NameAddr::uri().

Referenced by testFlowRequirements(), and tryFlow().

{
   const resip::NameAddr& contact(rec.mContact);
   if(DnsUtil::isIpAddress(contact.uri().host()))
   {
      // IP address in host-part.
      if(contact.uri().scheme()=="sips")
      {
         // sips: and IP-address in contact. This will probably not work anyway.
         return true;
      }

      if(contact.uri().exists(p_transport))
      {
         TransportType type = Tuple::toTransport(contact.uri().param(p_transport));
         if(type==TLS || type == DTLS)
         {
            // secure transport and IP-address. Almost certainly won't work, but
            // we'll try anyway.
            return true;
         }
      }
   }
   return false;
}

Here is the call graph for this function:

ServerRegistrationHandle ServerRegistration::getHandle ( )
resip::SharedPtr<ContactList> resip::ServerRegistration::getOriginalContacts ( ) [inline]

Definition at line 52 of file ServerRegistration.hxx.

References mOriginalContacts.

{ return mOriginalContacts; }  // WARNING - use this only if async mode is not used
const ContactList& resip::ServerRegistration::getRequestContacts ( ) [inline]

Definition at line 53 of file ServerRegistration.hxx.

References mRequestContacts.

{ return mRequestContacts; }
ServerRegistration& resip::ServerRegistration::operator= ( const ServerRegistration ) [private]
void ServerRegistration::processFinalOkMsg ( SipMessage msg,
ContactList &  contacts 
) [private]

Add contacs to msg, adding expires param.

Also removes expired entries from contacts and calls the appropriate DB functions to remove them.

Definition at line 653 of file ServerRegistration.cxx.

References resip::Timer::getTimeSecs(), resip::SipMessage::header(), mAor, resip::BaseUsage::mDum, and resip::DialogUsageManager::mRegistrationPersistenceManager.

Referenced by accept().

{
   //build the 200Ok and remove any expired entries.
   //the non-asynchronous behavior is to call the database directly, the async behavior is to build a
   //list of all expired entries and send it to the handler.
   if (contacts.size() > 0)
   {
      ContactList::iterator it(contacts.begin());
      ContactList::iterator itEnd(contacts.end());

      RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
      UInt64 now=Timer::getTimeSecs();

      for (;it != itEnd;++it)
      {
         if (it->mRegExpires <= now)
         {
            database->removeContact(mAor,*it);
            continue;
         }
         it->mContact.param(p_expires) = UInt32(it->mRegExpires - now);
         msg.header(h_Contacts).push_back(it->mContact);
      }
   }
}

Here is the call graph for this function:

void ServerRegistration::processRegistration ( const SipMessage msg) [private]

Look at the contacts provided by the incoming REGISTER.

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

WARN! Must not access this object beyond this point. The client my call reject() or accept(), deleting this object. Also, watch out for local objects that are still in scope and access this object on destruction.

Definition at line 223 of file ServerRegistration.cxx.

References resip::ServerRegistrationHandler::asyncProcessing(), asyncStateQueryOnly, asyncStateWaitingForAcceptReject, resip::RegistrationPersistenceManager::CONTACT_CREATED, DebugLog, resip::SipMessage::empty(), resip::SipMessage::exists(), resip::Helper::getClientPublicAddress(), resip::ServerRegistrationHandler::getContactExpires(), resip::RegistrationPersistenceManager::getContacts(), resip::ServerRegistrationHandler::getGlobalExpires(), getHandle(), resip::DialogUsageManager::getMasterProfile(), resip::SipMessage::getSource(), resip::Timer::getTimeSecs(), h_StatusLine, resip::SipMessage::header(), InfoLog, resip::RegistrationPersistenceManager::lockRecord(), resip::DialogUsageManager::makeResponse(), mAor, mAsyncLocalStore, mAsyncState, resip::ContactInstanceRecord::mContact, resip::BaseUsage::mDum, resip::ContactInstanceRecord::mInstance, resip::ContactInstanceRecord::mLastUpdated, mOriginalContacts, resip::ContactInstanceRecord::mPublicAddress, resip::ContactInstanceRecord::mReceivedFrom, resip::ContactInstanceRecord::mRegExpires, resip::DialogUsageManager::mRegistrationPersistenceManager, mRequestContacts, resip::DialogUsageManager::mServerRegistrationHandler, resip::ContactInstanceRecord::mSipPath, resip::ServerRegistrationHandler::onAdd(), resip::ServerRegistrationHandler::onQuery(), resip::ServerRegistrationHandler::onRefresh(), resip::ServerRegistrationHandler::onRemove(), resip::ServerRegistrationHandler::onRemoveAll(), resip::RegistrationPersistenceManager::removeAor(), resip::RegistrationPersistenceManager::removeContact(), resip::DialogUsageManager::send(), testFlowRequirements(), tryFlow(), resip::RegistrationPersistenceManager::unlockRecord(), and resip::RegistrationPersistenceManager::updateContact().

Referenced by asyncProvideContacts(), and dispatch().

{
   ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
   RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;

   enum {ADD, REMOVE, REFRESH} operation = REFRESH;

   UInt32 globalExpires=3600;
   UInt32 returnCode=0;
   handler->getGlobalExpires(msg,mDum.getMasterProfile(),globalExpires,returnCode);

   bool async = handler->asyncProcessing();

   if (returnCode >= 400)
   {
      SharedPtr<SipMessage> failure(new SipMessage);
      mDum.makeResponse(*failure, msg, returnCode);
      if (423 == returnCode)
      {
         failure->header(h_StatusLine).reason() = "Interval Too Brief";
         failure->header(h_MinExpires).value() = globalExpires;
      }
      mDum.send(failure);
      delete(this);
      return;
   }

   if (!async)
   {
      database->lockRecord(mAor);

      mOriginalContacts = resip::SharedPtr<ContactList>(new ContactList);
      database->getContacts(mAor, *mOriginalContacts);
   }

   // If no contacts are present in the request, this is simply a query.
   if (!msg.exists(h_Contacts))
   {
      if (async)
      {
         mAsyncState = asyncStateQueryOnly;
      }
      handler->onQuery(getHandle(), msg);
      return;
   }

   ParserContainer<NameAddr> contactList(msg.header(h_Contacts));
   ParserContainer<NameAddr>::iterator i(contactList.begin());
   ParserContainer<NameAddr>::iterator iEnd(contactList.end());
   UInt64 now=Timer::getTimeSecs();
   UInt32 expires=0;

   for (; i != iEnd; ++i)
   {
      if (!i->isWellFormed())
      {
         SharedPtr<SipMessage> failure(new SipMessage);
         mDum.makeResponse(*failure, msg, 400, "Malformed Contact");
         mDum.send(failure);
         if (!async)
         {
            database->unlockRecord(mAor);
         }
         delete(this);
         return;
      }

      expires = globalExpires;
      handler->getContactExpires(*i, mDum.getMasterProfile(), expires, returnCode);

      // Check for "Contact: *" style deregistration
      if (i->isAllContacts())
      {
         if (contactList.size() > 1 || expires != 0)
         {
            SharedPtr<SipMessage> failure(new SipMessage);
            mDum.makeResponse(*failure, msg, 400, "Invalid use of 'Contact: *'");
            mDum.send(failure);
            if (!async)
            {
               database->unlockRecord(mAor);
            }
            delete(this);
            return;
         }

         if (!async)
         {
            database->removeAor(mAor);
         }
         else
         {
            mAsyncLocalStore->removeAllContacts();
            mAsyncState = asyncStateWaitingForAcceptReject;
         }

         handler->onRemoveAll(getHandle(), msg);
         return;
      }

      ContactInstanceRecord rec;
      rec.mContact=*i;
      rec.mRegExpires=(UInt64)expires+now;

      if(i->exists(p_Instance))
      {
         rec.mInstance=i->param(p_Instance);
      }

      if(!msg.empty(h_Paths))
      {
         rec.mSipPath=msg.header(h_Paths);
      }

      rec.mLastUpdated=now;
      rec.mReceivedFrom=msg.getSource();
      rec.mPublicAddress=Helper::getClientPublicAddress(msg);

      bool hasFlow = tryFlow(rec,msg);
      
      if(!testFlowRequirements(rec, msg, hasFlow))
      {
         // We have rejected the request. Bail.
         if (!async)
         {
            database->unlockRecord(mAor);
         }
         delete(this);
         return;
      }

      // Add ContactInstanceRecord to List
      mRequestContacts.push_back(rec);

      // Check to see if this is a removal.
      if (expires == 0)
      {
         if (operation == REFRESH)
         {
            operation = REMOVE;
         }

         if (!async)
         {
            database->removeContact(mAor, rec);
         }
         else
         {
            mAsyncLocalStore->removeContact(rec);
         }
      }
      else // Otherwise, it's an addition or refresh.
      {
         RegistrationPersistenceManager::update_status_t status;
         InfoLog(<< "Adding " << mAor << " -> " << *i);
         DebugLog(<< "Contact has tuple " << rec.mReceivedFrom << " and detected public address " << rec.mPublicAddress);

         if (!async)
         {
            status = database->updateContact(mAor, rec);
         }
         else
         {
            status =  mAsyncLocalStore->updateContact(rec);
         }

         if (status == RegistrationPersistenceManager::CONTACT_CREATED)
         {
            operation = ADD;
         }
      }
   }

   // The way this works is:
   //
   //  - If no additions or removals are performed, this is a refresh
   //
   //  - If at least one contact is removed and none are added, this
   //    is a removal.
   //
   //  - If at least one contact is added, this is an addition, *even*
   //    *if* a contact was also removed.

   //for async processing, need to wait for accept()/reject().  If accepted, the modifications made here will be
   //sent to the user via asyncUpdateContacts().  The user then returns a final contact list, which is then processed
   //and sent back in the 200.
   if (async)
   {
      mAsyncState = asyncStateWaitingForAcceptReject;
   }

   switch (operation)
   {
      case REFRESH:
         handler->onRefresh(getHandle(), msg);
         return;

      case REMOVE:
         handler->onRemove(getHandle(), msg);
         return;

      case ADD:
         handler->onAdd(getHandle(), msg);
         return;

      default:
         assert(0);
   }
}

Here is the call graph for this function:

void ServerRegistration::reject ( int  statusCode)

Reject a SIP registration.

!Warning! After calling this function from a ServerRegistrationHandle, do not access the handle as this function may delete this object. Use ServerRegistrationHandle::isValidHandle() to test if it's deleted.

Definition at line 146 of file ServerRegistration.cxx.

References resip::RegistrationPersistenceManager::addAor(), resip::ServerRegistrationHandler::asyncProcessing(), resip::SharedPtr< T >::get(), InfoLog, resip::DialogUsageManager::makeResponse(), mAor, resip::BaseUsage::mDum, mOriginalContacts, resip::DialogUsageManager::mRegistrationPersistenceManager, mRequest, resip::DialogUsageManager::mServerRegistrationHandler, resip::RegistrationPersistenceManager::removeAor(), resip::DialogUsageManager::send(), and resip::RegistrationPersistenceManager::unlockRecord().

{
   InfoLog( << "rejected a registration " << mAor << " with statusCode=" << statusCode );

   // First, we roll back the contact database to
   // the state it was before the registration request.

   // Async processing hasn't actually updated the database yet, so no need to roll back.
   if (mDum.mServerRegistrationHandler && !mDum.mServerRegistrationHandler->asyncProcessing())
   {
      // Rollback changes, since rejected
      RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
      database->removeAor(mAor);
      if (mOriginalContacts.get())
      {
         database->addAor(mAor, *mOriginalContacts);
      }
      database->unlockRecord(mAor);
   }

   SharedPtr<SipMessage> failure(new SipMessage);
   mDum.makeResponse(*failure, mRequest, statusCode);
   failure->remove(h_Contacts);
   mDum.send(failure);
   delete(this);
}

Here is the call graph for this function:

bool ServerRegistration::testFlowRequirements ( ContactInstanceRecord rec,
const resip::SipMessage msg,
bool  hasFlow 
) const [private]

Definition at line 509 of file ServerRegistration.cxx.

References resip::NameAddr::exists(), flowTokenNeededForSigcomp(), flowTokenNeededForTls(), resip::DialogUsageManager::makeResponse(), resip::ContactInstanceRecord::mContact, resip::BaseUsage::mDum, and resip::DialogUsageManager::send().

Referenced by processRegistration().

{
   const resip::NameAddr& contact(rec.mContact);

   if(contact.exists(p_Instance) && contact.exists(p_regid))
   {
      // Client has explicitly requested Outbound processing, which requires us 
      // to have a flow.
      if(!hasFlow)
      {
         SharedPtr<SipMessage> failure(new SipMessage);
         mDum.makeResponse(*failure, msg, 439);
         mDum.send(failure);
         return false;
      }
   }

   if(!hasFlow && flowTokenNeededForTls(rec))
   {
      SharedPtr<SipMessage> failure(new SipMessage);
      mDum.makeResponse(*failure, msg, 400, "Trying to use TLS with an IP-address in your Contact header won't work if you don't have a flow. Consider implementing outbound, or putting an FQDN in your contact header.");
      mDum.send(failure);
      return false;
   }

   if(!hasFlow && flowTokenNeededForSigcomp(rec))
   {
      SharedPtr<SipMessage> failure(new SipMessage);
      mDum.makeResponse(*failure, msg, 400, "Trying to use sigcomp on a connection-oriented protocol won't work if you don't have a flow. Consider implementing outbound, or using UDP/DTLS for this case.");
      mDum.send(failure);
      return false;
   }

   return true;
}

Here is the call graph for this function:

bool ServerRegistration::tryFlow ( ContactInstanceRecord rec,
const resip::SipMessage msg 
) [private]

Definition at line 451 of file ServerRegistration.cxx.

References resip::InteropHelper::ClientNATDetectionDisabled, resip::InteropHelper::ClientNATDetectionPrivateToPublicOnly, resip::SipMessage::empty(), resip::NameAddr::exists(), resip::Uri::exists(), flowTokenNeededForSigcomp(), flowTokenNeededForTls(), resip::InteropHelper::getAssumeFirstHopSupportsOutboundEnabled(), resip::InteropHelper::getClientNATDetectionMode(), resip::InteropHelper::getOutboundSupported(), resip::InteropHelper::getRRTokenHackEnabled(), resip::SipMessage::header(), resip::Helper::isClientBehindNAT(), resip::ContactInstanceRecord::mContact, mDidOutbound, resip::ContactInstanceRecord::mReceivedFrom, resip::ContactInstanceRecord::mRegId, resip::ContactInstanceRecord::mUseFlowRouting, resip::Tuple::onlyUseExistingConnection, resip::ParserCategory::param(), and resip::RequestLine::uri().

Referenced by processRegistration().

{
   // .bwc. ie. Can we assure that the connection the client is using on the
   // first hop can be re-used later?
   try
   {
      // Outbound logic
      if(InteropHelper::getOutboundSupported())
      {
         resip::NameAddr& contact(rec.mContact);
         if(contact.exists(p_Instance) && contact.exists(p_regid))
         {
            if(!msg.empty(h_Paths) && (msg.header(h_Paths).back().uri().exists(p_ob) ||
                                       InteropHelper::getAssumeFirstHopSupportsOutboundEnabled()))
            {
               rec.mRegId=contact.param(p_regid);
               // Edge-proxy is directly connected to the client, and ready to 
               // send traffic down the "connection" (TCP connection, or NAT 
               // pinhole, or what-have-you).
               mDidOutbound=true;
               return true;
            }
            else if(msg.header(h_Vias).size() == 1)
            {
               rec.mRegId=contact.param(p_regid);
               // We are directly connected to the client.
               // .bwc. In the outbound case, we should fail if the connection 
               // is gone. No recovery should be attempted by the server.
               rec.mUseFlowRouting = true;
               rec.mReceivedFrom.onlyUseExistingConnection=true;
               mDidOutbound=true;
               return true;
            }
         }
      }

      // Record-Route flow token hack, or client NAT detect hack; use with caution
      if(msg.header(h_Vias).size() == 1)  // client is directly connected to this server
      {
         if(InteropHelper::getRRTokenHackEnabled() || 
            flowTokenNeededForTls(rec) || 
            flowTokenNeededForSigcomp(rec) ||
            (InteropHelper::getClientNATDetectionMode() != InteropHelper::ClientNATDetectionDisabled &&
             Helper::isClientBehindNAT(msg, InteropHelper::getClientNATDetectionMode() == InteropHelper::ClientNATDetectionPrivateToPublicOnly)))
         {
               rec.mUseFlowRouting = true;
               rec.mReceivedFrom.onlyUseExistingConnection=false;
               return true;
         }
      }
   }
   catch(resip::ParseBuffer::Exception&)
   {}
   return false;
}

Here is the call graph for this function:


Friends And Related Function Documentation

friend class DialogSet [friend]

Definition at line 58 of file ServerRegistration.hxx.


Member Data Documentation

Definition at line 185 of file ServerRegistration.hxx.

Referenced by accept(), asyncProvideContacts(), and processRegistration().

Message stored during accept() call when waiting for final contact list from database.

Is eventually used as the 200Ok sent back to DUM when all is finished.

Definition at line 190 of file ServerRegistration.hxx.

Referenced by accept(), and asyncProcessFinalContacts().

Definition at line 73 of file ServerRegistration.hxx.

Referenced by accept(), and tryFlow().

Definition at line 71 of file ServerRegistration.hxx.

Referenced by getOriginalContacts(), processRegistration(), and reject().

Definition at line 69 of file ServerRegistration.hxx.

Referenced by accept(), asyncProvideContacts(), and reject().

Definition at line 72 of file ServerRegistration.hxx.

Referenced by getRequestContacts(), and processRegistration().


The documentation for this class was generated from the following files: