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

#include <DialogSet.hxx>

Collaboration diagram for resip::DialogSet:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 DialogSet (BaseCreator *creator, DialogUsageManager &dum)
 DialogSet (const SipMessage &request, DialogUsageManager &dum)
virtual ~DialogSet ()
DialogSetId getId () const
void addDialog (Dialog *)
bool empty () const
BaseCreatorgetCreator ()
SharedPtr< UserProfilegetUserProfile () const
void setUserProfile (SharedPtr< UserProfile > userProfile)
void end ()
void dispatch (const SipMessage &msg)
ClientRegistrationHandle getClientRegistration ()
ServerRegistrationHandle getServerRegistration ()
ClientPublicationHandle getClientPublication ()
ClientOutOfDialogReqHandle getClientOutOfDialog ()
ServerOutOfDialogReqHandle getServerOutOfDialog ()
bool isDestroying ()

Private Types

enum  State {
  Initial, WaitingToEnd, ReceivedProvisional, Established,
  Terminating, Cancelling, Destroying
}
typedef std::map< DialogId,
Dialog * > 
DialogMap

Private Member Functions

void possiblyDie ()
void onForkAccepted ()
bool handledByAuthOrRedirect (const SipMessage &msg)
void appDissociate ()
 Abandon this dialog set, but keep the AppDialogSet around.
DialogfindDialog (const SipMessage &msg)
DialogfindDialog (const DialogId id)
ClientOutOfDialogReqfindMatchingClientOutOfDialogReq (const SipMessage &msg)
ClientRegistrationmakeClientRegistration (const SipMessage &msg)
ClientPublicationmakeClientPublication (const SipMessage &msg)
ClientOutOfDialogReqmakeClientOutOfDialogReq (const SipMessage &msg)
ServerRegistrationmakeServerRegistration (const SipMessage &msg)
ServerOutOfDialogReqmakeServerOutOfDialog (const SipMessage &msg)
ServerPagerMessagemakeServerPagerMessage (const SipMessage &request)
void dispatchToAllDialogs (const SipMessage &msg)
void flowTerminated (const Tuple &flow)

Private Attributes

MergedRequestKey mMergeKey
Data mCancelKey
DialogMap mDialogs
BaseCreatormCreator
DialogSetId mId
DialogUsageManagermDum
AppDialogSetmAppDialogSet
State mState
ClientRegistrationmClientRegistration
ServerRegistrationmServerRegistration
ClientPublicationmClientPublication
std::list< ClientOutOfDialogReq * > mClientOutOfDialogRequests
ServerOutOfDialogReqmServerOutOfDialogRequest
ClientPagerMessagemClientPagerMessage
ServerPagerMessagemServerPagerMessage
SharedPtr< UserProfilemUserProfile

Friends

class Dialog
class DialogUsage
class ClientInviteSession
class NonDialogUsage
class DialogUsageManager
class ClientRegistration
class ServerRegistration
class ClientOutOfDialogReq
class ServerOutOfDialogReq
class ClientPublication
class RedirectManager
class ClientPagerMessage
class ServerPagerMessage
class AppDialogSet
EncodeStreamoperator<< (EncodeStream &strm, const DialogSet &ds)

Detailed Description

Definition at line 24 of file DialogSet.hxx.


Member Typedef Documentation

typedef std::map<DialogId,Dialog*> resip::DialogSet::DialogMap [private]

Definition at line 109 of file DialogSet.hxx.


Member Enumeration Documentation

enum resip::DialogSet::State [private]
Enumerator:
Initial 
WaitingToEnd 
ReceivedProvisional 
Established 
Terminating 
Cancelling 
Destroying 

Definition at line 65 of file DialogSet.hxx.

      {
         Initial,  // No session setup yet
         WaitingToEnd,
         ReceivedProvisional,
         Established,
         Terminating,
         Cancelling,  // only used when cancelling and no dialogs exist
         Destroying
      } State;

Constructor & Destructor Documentation

DialogSet::DialogSet ( BaseCreator creator,
DialogUsageManager dum 
)

Definition at line 34 of file DialogSet.cxx.

References DebugLog, resip::BaseCreator::getLastRequest(), resip::BaseCreator::getUserProfile(), mId, and setUserProfile().

                                                                  :
   mMergeKey(),
   mDialogs(),
   mCreator(creator),
   mId(*creator->getLastRequest()),
   mDum(dum),
   mAppDialogSet(0),
   mState(Initial),
   mClientRegistration(0),
   mServerRegistration(0),
   mClientPublication(0),
   mClientOutOfDialogRequests(),
   mServerOutOfDialogRequest(0),
   mClientPagerMessage(0),
   mServerPagerMessage(0)
{
   setUserProfile(creator->getUserProfile());
   assert(!creator->getLastRequest()->isExternal());
   DebugLog ( << " ************* Created DialogSet(UAC)  -- " << mId << "*************" );
}

Here is the call graph for this function:

DialogSet::DialogSet ( const SipMessage request,
DialogUsageManager dum 
)

Definition at line 56 of file DialogSet.cxx.

References DebugLog, resip::SipMessage::getTransactionId(), h_RequestLine, resip::SipMessage::header(), resip::SipMessage::isExternal(), resip::SipMessage::isRequest(), mCancelKey, resip::DialogUsageManager::mCancelMap, mDum, resip::RequestLine::method(), mId, resip::DialogUsageManager::mMergedRequests, mMergeKey, and WarningLog.

                                                                       :
   mMergeKey(request, dum.getMasterProfile()->checkReqUriInMergeDetectionEnabled()),
   mDialogs(),
   mCreator(0),
   mId(request),
   mDum(dum),
   mAppDialogSet(0),
   mState(Established),
   mClientRegistration(0),
   mServerRegistration(0),
   mClientPublication(0),
   mClientOutOfDialogRequests(),
   mServerOutOfDialogRequest(0),
   mClientPagerMessage(0),
   mServerPagerMessage(0)
{
   assert(request.isRequest());
   assert(request.isExternal());
   mDum.mMergedRequests.insert(mMergeKey);
   if (request.header(h_RequestLine).method() == INVITE)
   {
      if(mDum.mCancelMap.count(request.getTransactionId()) != 0)
      {
         WarningLog ( << "An endpoint is using the same tid in multiple INVITE requests, ability to match CANCEL requests correctly may be comprimised, tid=" << request.getTransactionId() );
      }
      mCancelKey = request.getTransactionId();
      mDum.mCancelMap[mCancelKey] = this;
   }
   DebugLog ( << " ************* Created DialogSet(UAS) *************: " << mId);
}

Here is the call graph for this function:

DialogSet::~DialogSet ( ) [virtual]

Member Function Documentation

void DialogSet::addDialog ( Dialog dialog)

Definition at line 163 of file DialogSet.cxx.

References resip::Dialog::getId(), and mDialogs.

Referenced by resip::Dialog::Dialog().

{
   mDialogs[dialog->getId()] = dialog;
}

Here is the call graph for this function:

void resip::DialogSet::appDissociate ( ) [inline, private]

Abandon this dialog set, but keep the AppDialogSet around.

Definition at line 82 of file DialogSet.hxx.

References mAppDialogSet.

Referenced by resip::AppDialogSet::reuse().

      {
         assert(mAppDialogSet);
         mAppDialogSet = 0;
      }
void DialogSet::dispatch ( const SipMessage msg)

Definition at line 316 of file DialogSet.cxx.

References Cancelling, resip::AppDialogSet::createAppDialog(), DebugLog, resip::DialogUsageManager::destroy(), Destroying, Dialog, resip::ServerOutOfDialogReq::dispatch(), resip::ClientOutOfDialogReq::dispatch(), resip::ServerPagerMessage::dispatch(), resip::ClientPublication::dispatch(), resip::ServerRegistration::dispatch(), resip::ClientPagerMessage::dispatch(), resip::ClientRegistration::dispatch(), resip::Dialog::dispatch(), dispatchToAllDialogs(), end(), ErrLog, resip::InviteSessionHandler::Error, Established, resip::SipMessage::exists(), findDialog(), findMatchingClientOutOfDialogReq(), resip::SharedPtr< T >::get(), getCreator(), resip::AppDialogSet::getHandle(), resip::BaseCreator::getLastRequest(), resip::BaseException::getMessage(), h_RequestLine, h_StatusLine, handledByAuthOrRedirect(), resip::SipMessage::header(), InfoLog, Initial, resip::Dialog::isDestroying(), resip::SipMessage::isRequest(), resip::SipMessage::isResponse(), resip::LazyParser::isWellFormed(), resip::InviteSessionHandler::LocalBye, makeClientOutOfDialogReq(), makeClientPublication(), makeClientRegistration(), resip::Dialog::makeRequest(), resip::Helper::makeResponse(), resip::DialogUsageManager::makeResponse(), makeServerOutOfDialog(), makeServerPagerMessage(), makeServerRegistration(), resip::Dialog::mAppDialog, mAppDialogSet, mClientOutOfDialogRequests, mClientPagerMessage, mClientPublication, mClientRegistration, mCreator, resip::AppDialog::mDialog, resip::DialogUsageManager::mDialogEventStateManager, mDialogs, resip::DialogUsageManager::mDialogSetHandler, mDum, resip::SipMessage::method(), resip::RequestLine::method(), mServerOutOfDialogRequest, mServerPagerMessage, mServerRegistration, mState, resip::DialogSetHandler::onNonDialogCreatingProvisional(), resip::DialogEventStateManager::onProceedingUac(), resip::DialogEventStateManager::onTerminated(), resip::DialogSetHandler::onTrying(), ReceivedProvisional, resip::InviteSessionHandler::Rejected, resip::Dialog::send(), resip::DialogUsageManager::send(), resip::DialogUsageManager::sendResponse(), StackLog, and WaitingToEnd.

Referenced by resip::DialogUsageManager::processRequest(), and resip::DialogUsageManager::processResponse().

{
   if(!mAppDialogSet)
   {
      // !bwc! There are conditions where reuse of the AppDialogSet will cause
      // us to hit this code. This is because the teardown of DialogSets is not
      // atomic, causing the DialogSet to hang around for a short time after it
      // has given up its AppDialogSet. Also, if we have multiple Usages in
      // this DialogSet, one of the Usages may decide to re-establish itself in 
      // a new Dialog, and take the AppDialogSet with it, leaving all the others
      // high and dry. This is a design issue that will take some real effort to
      // fix properly. This is a band-aid for now.
      // TODO fix this properly
      if(msg.isRequest())
      {
         if(msg.method() != ACK)
         {
            SipMessage err;
            Helper::makeResponse(err, msg, 500, "DialogSet: My AppDialogSet is "
                                       "missing!");
            mDum.sendResponse(err);
         }
      }
      else
      {
         ErrLog(<<"Response came in, but no AppDialogSet! Dropping this is very"
                  "likely to cause leaks, but continuing to process it is "
                  "likely to cause a core. Taking the lesser of two evils...");
      }
      return;
   }

   assert(msg.isRequest() || msg.isResponse());

   if (mState == WaitingToEnd)
   {
      assert(mDialogs.empty());
      if (msg.isResponse())         
      {
         int code = msg.header(h_StatusLine).statusCode();
         switch(mCreator->getLastRequest()->header(h_CSeq).method())
         {
            case INVITE:
               if (code / 100 == 1)
               {
                  mState = ReceivedProvisional;
                  end();
               }
               else if (code / 100 == 2)
               {
                  Dialog dialog(mDum, msg, *this);

                  SharedPtr<SipMessage> ack(new SipMessage);
                  dialog.makeRequest(*ack, ACK);
                  ack->header(h_CSeq).sequence() = msg.header(h_CSeq).sequence();
                  dialog.send(ack);
                  
                  SharedPtr<SipMessage> bye(new SipMessage);
                  dialog.makeRequest(*bye, BYE);
                  dialog.send(bye);
                  
                  if (mDum.mDialogEventStateManager)
                  {
                     mDum.mDialogEventStateManager->onTerminated(dialog, *bye, InviteSessionHandler::LocalBye);
                  }
                  // Note:  Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy
               }
               else
               {
                  if (mDum.mDialogEventStateManager)
                  {
                     mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Rejected);
                  }           
                  mState = Destroying;
                  mDum.destroy(this);
               }
               break;
            case SUBSCRIBE:
               if (code / 100 == 1)
               {
                  // do nothing - wait for final response
               }
               else if (code / 100 == 2)
               {
                  Dialog dialog(mDum, msg, *this);

                  SharedPtr<SipMessage> unsubscribe(new SipMessage(*mCreator->getLastRequest().get()));  // create message from initial request so we get proper headers
                  dialog.makeRequest(*unsubscribe, SUBSCRIBE);
                  unsubscribe->header(h_Expires).value() = 0;
                  dialog.send(unsubscribe);
                  
                  // Note:  Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy
               }
               else
               {
                  mState = Destroying;
                  mDum.destroy(this);
               }
               break;
            case PUBLISH:
               if (code / 100 == 1)
               {
                  // do nothing - wait for final response
               }
               else if (code / 100 == 2)
               {
                  Dialog dialog(mDum, msg, *this);

                  SharedPtr<SipMessage> unpublish(new SipMessage(*mCreator->getLastRequest().get()));  // create message from initial request so we get proper headers
                  dialog.makeRequest(*unpublish, PUBLISH);
                  unpublish->header(h_Expires).value() = 0;
                  dialog.send(unpublish);
                  
                  // Note:  Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy
               }
               else
               {
                  mState = Destroying;
                  mDum.destroy(this);
               }
               break;
               // ?slg? shouldn't we handle register, ood and refer here too?
            default:
               mState = Destroying;
               mDum.destroy(this);
               break;
         }
      }
      else
      {
         SharedPtr<SipMessage> response(new SipMessage);         
         mDum.makeResponse(*response, msg, 481);
         mDum.send(response);
      }
      return;
   }
   else if(mState == Cancelling)
   {
      assert(mDialogs.empty());
      if (msg.isResponse())         
      {
         int code = msg.header(h_StatusLine).statusCode();
         if(mCreator->getLastRequest()->header(h_CSeq).method() == INVITE)
         {
            if (code / 100 == 1)
            {
               // do nothing - wait for final response
            }
            // 200/Inv crossing CANCEL case
            else if (code / 100 == 2)
            {
               Dialog dialog(mDum, msg, *this);

               SharedPtr<SipMessage> ack(new SipMessage);
               dialog.makeRequest(*ack, ACK);
               ack->header(h_CSeq).sequence() = msg.header(h_CSeq).sequence();
               dialog.send(ack);
                  
               SharedPtr<SipMessage> bye(new SipMessage);
               dialog.makeRequest(*bye, BYE);
               dialog.send(bye);                  

               // Note:  Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy
            }
            else
            {
               mState = Destroying;
               mDum.destroy(this);
            }
         }
      }
      else // is a request
      {
         SharedPtr<SipMessage> response(new SipMessage);         
         mDum.makeResponse(*response, msg, 481);
         mDum.send(response);
      }
      return;
   }

   if (handledByAuthOrRedirect(msg))
   {
      return;
   }

   Dialog* dialog = 0;
   if (!(msg.isResponse() && msg.header(h_StatusLine).statusCode() == 100))  // Don't look for dialog if msg is a 100 response
   {
      DialogMap::iterator i = mDialogs.find(DialogId(msg));
      if (i != mDialogs.end())
      {
         dialog = i->second;
      }
   }
   if (dialog)
   {
      if(dialog->isDestroying())
      {
         if( msg.isRequest() )
         {
            StackLog (<< "Matching dialog is destroying, sending 481 " << endl << msg);
            SharedPtr<SipMessage> response(new SipMessage);
            mDum.makeResponse(*response, msg, 481);
            mDum.send(response);
         }
         else
         {
          StackLog (<< "Matching dialog is destroying, dropping response message " << endl << msg);
         }
         return;
      }
      else
      {
         DebugLog (<< "Found matching dialog " << *dialog << " for " << endl << endl << msg);
      }
   }
   else
   {
      StackLog (<< "No matching dialog for " << endl << endl << msg);
   }
   
   if (msg.isRequest())
   {
      const SipMessage& request = msg;
      switch (request.header(h_CSeq).method())
      {
         case INVITE:
         case CANCEL:  //cancel needs work
         case SUBSCRIBE:
            break; //dialog creating/handled by dialog

         case BYE:
         case INFO:
         case ACK:
         case UPDATE:
            if(!dialog)
            {
               SharedPtr<SipMessage> response(new SipMessage);         
               mDum.makeResponse(*response, msg, 481);
               mDum.send(response);
               return;
            }
            break;
            
         case REFER:
            if (request.header(h_To).exists(p_tag) || findDialog(request))
            {
               DebugLog(<< "in dialog refer request");
               break; // in dialog
            }
            else if((request.exists(h_ReferSub) && 
                     request.header(h_ReferSub).isWellFormed() &&
                     request.header(h_ReferSub).value()=="false") ||
                     (request.exists(h_Requires) &&
                     request.header(h_Requires).find(Token("norefersub"))))// out of dialog & noReferSub=true
            {
               DebugLog(<< "out of dialog refer request with norefersub");
               assert(mServerOutOfDialogRequest == 0);
               mServerOutOfDialogRequest = makeServerOutOfDialog(request);
               mServerOutOfDialogRequest->dispatch(request);
               return;
            }
            else
            {
               DebugLog(<< "out of dialog refer request with refer sub");
               break; // dialog creating
            }
            break;            
         case NOTIFY:

            // !jf! there shouldn't be a dialogset for ServerOutOfDialogReq
            if (request.header(h_To).exists(p_tag) || findDialog(request))
            {
               break; //dialog creating/handled by dialog
            }
            else // no to tag - unsolicited notify
            {
               // unsolicited - not allowed but commonly implemented
               // by large companies with a bridge as their logo
               assert(mServerOutOfDialogRequest == 0);
               mServerOutOfDialogRequest = makeServerOutOfDialog(request);
               mServerOutOfDialogRequest->dispatch(request);
               return;
            }
            break;

         case PUBLISH:
            assert(false); // handled in DialogUsageManager
            return;
            
         case REGISTER:
            // !jf! move this to DialogUsageManager
            if (mServerRegistration == 0)
            {
               mServerRegistration = makeServerRegistration(request);
            }
            mServerRegistration->dispatch(request);
            return;

         case MESSAGE:
            // !jf! move this to DialogUsageManager
            if(!dialog)
            {
               mServerPagerMessage = makeServerPagerMessage(request);
               mServerPagerMessage->dispatch(request);
               return;
            }
            break;

         default:
            // !jf! move this to DialogUsageManager
            DebugLog ( << "In DialogSet::dispatch, default(ServerOutOfDialogRequest), msg: " << msg );
            // only can be one ServerOutOfDialogReq at a time
            assert(mServerOutOfDialogRequest == 0);
            mServerOutOfDialogRequest = makeServerOutOfDialog(request);
            mServerOutOfDialogRequest->dispatch(request);
            return;
      }
   }
   else // the message is a response
   {
      const SipMessage& response = msg;

      int code = msg.header(h_StatusLine).statusCode();
      if (code == 423
          && msg.header(h_CSeq).method() == SUBSCRIBE
          && msg.exists(h_MinExpires)
          && getCreator()
          && msg.header(h_CSeq) == getCreator()->getLastRequest()->header(h_CSeq))
      {
         getCreator()->getLastRequest()->header(h_CSeq).sequence()++;
         getCreator()->getLastRequest()->header(h_Expires).value() = msg.header(h_MinExpires).value();
         DebugLog( << "Re sending inital(dialog forming) SUBSCRIBE due to 423, MinExpires is: " << msg.header(h_MinExpires).value());
         mDum.send(getCreator()->getLastRequest());
         return;
      }
      
      // We should only do DialogState processing if this is a response to our initial request
      if(getCreator() &&
         msg.header(h_CSeq) == getCreator()->getLastRequest()->header(h_CSeq))
      {
         switch(mState)
         {
            case Initial:
               if (code < 200)
               {
                  mState = ReceivedProvisional;
               }
               else if(code < 300)
               {
                  mState = Established;
               }
               else
               {
                  mState = Established;
                  if (!mDialogs.empty())
                  {
                     dispatchToAllDialogs(msg);
                     return;
                  }
               }
               break;
            case ReceivedProvisional:
               if (code < 200)
               {
                  // fall through
               }
               else if (code < 300)
               {
                  mState = Established;
                  for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
                  {
                     if (it->second != dialog) // this is dialog that accepted
                     {
                        it->second->onForkAccepted();
                     }
                  }
               }
               else // failure response
               {
                  mState = Established;
                  if (!mDialogs.empty())
                  {
                     dispatchToAllDialogs(msg);
                     return;
                  }
               }
               break;
            default:
               // !jf!
               break;            
         }
      }

      if (response.header(h_StatusLine).statusCode() == 100)
      {
         if (mDum.mDialogSetHandler)
         {
            mDum.mDialogSetHandler->onTrying(mAppDialogSet->getHandle(), msg);
         }
         return;
      }
      
      switch (response.header(h_CSeq).method())
      {
         case INVITE:
         case SUBSCRIBE:
         case BYE:
         case ACK:
         case CANCEL:
            break; 

         case PUBLISH:
            if (mClientPublication == 0)
            {
               mClientPublication = makeClientPublication(response);
            }
            mClientPublication->dispatch(response);
            return;

         case REGISTER:
            if (mClientRegistration == 0)
            {
               mClientRegistration = makeClientRegistration(response);
            }
            mClientRegistration->dispatch(response);
            return;

         case MESSAGE:
             if (dialog)
            {
                break;
            }
            else if (mClientPagerMessage)
            {
               mClientPagerMessage->dispatch(response);
            }
            return;            

         case INFO:   
         case UPDATE:
            if (dialog)
            {
               break;
            }
            else // not allowed
            {
               return;
            }
         case REFER:
            if (dynamic_cast<SubscriptionCreator*>(getCreator()))
            {
               break;
            }
         case NOTIFY:
            if (dialog)
            {
               break;
            }
            
         default:
         {
            ClientOutOfDialogReq* req = findMatchingClientOutOfDialogReq(response);
            if (req == 0)
            {
               req = makeClientOutOfDialogReq(response);
               mClientOutOfDialogRequests.push_back(req);
            }
            req->dispatch(response);
            return;
         }
      }
   }

   if (dialog == 0)
   {
      if (msg.isRequest() && msg.header(h_RequestLine).method() == CANCEL)
      {
         dispatchToAllDialogs(msg);
         return;
      }

      if (msg.isResponse())
      {
         if( mCreator )
         {
            SharedPtr<SipMessage> lastRequest(mCreator->getLastRequest());
            if( 0 != lastRequest.get() && !(lastRequest->header(h_CSeq) == msg.header(h_CSeq)))
            {
               InfoLog(<< "Cannot create a dialog, cseq does not match initial dialog request (illegal mid-dialog fork? see 3261 14.1).");
               return;
            }
         }
         else
         {
            ErrLog(<< "Can’t create a dialog, on a UAS response.");
            return;
         }

         int code = msg.header(h_StatusLine).statusCode();

         if (code > 100 && code < 200 && 
             (!msg.exists(h_Contacts) ||
              !msg.exists(h_To) || !msg.header(h_To).exists(p_tag)))
         {
            InfoLog ( << "Cannot create a dialog, no Contact or To tag in 1xx." );
            if (mDum.mDialogSetHandler)
            {
               if (mDum.mDialogEventStateManager)
               {
                  mDum.mDialogEventStateManager->onProceedingUac(*this, msg);
               }
               mDum.mDialogSetHandler->onNonDialogCreatingProvisional(mAppDialogSet->getHandle(), msg);
            }
            return;         
         }
         // If failure response and no dialogs, create a dialog, otherwise
         else if (code >= 300 && !mDialogs.empty())
         {
            dispatchToAllDialogs(msg);
            return;
         }
      }

      DebugLog ( << "mState == " << mState << " Creating a new Dialog from msg: " << std::endl << std::endl <<msg);
      try
      {
         // !jf! This could throw due to bad header in msg, should we catch and rethrow
         dialog = new Dialog(mDum, msg, *this);
      }
      catch(BaseException& e)
      {
         InfoLog( << "Unable to create dialog: " << e.getMessage());
         if (msg.isResponse())
         {
            //don't delete on provisional responses, as FWD will eventually send a
            //valid 200
            if(mDialogs.empty() && 
               msg.header(h_StatusLine).statusCode() >= 200)
            {
               // really we should wait around 32s before deleting this
               if (mDum.mDialogEventStateManager)
               {
                  mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Error);
               }
               
               mState = Destroying;
               mDum.destroy(this);
            }
         }
         else
         {
            // !jf! derek thinks we should destroy only on invalid CANCEL or
            // BYE, hmmphh. see draft-sparks-sipping-dialogusage-01.txt
            SharedPtr<SipMessage> response(new SipMessage);
            mDum.makeResponse(*response, msg, 400);
            mDum.send(response);
            if(mDialogs.empty())
            {
               if (mDum.mDialogEventStateManager)
               {
                  mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Error);
               }
               mState = Destroying;
               mDum.destroy(this);
            }
         }
         return;
      }

      assert(mState != WaitingToEnd);
      DebugLog ( << "### Calling CreateAppDialog ###: " << std::endl << std::endl <<msg);
      AppDialog* appDialog = mAppDialogSet->createAppDialog(msg);
      dialog->mAppDialog = appDialog;
      appDialog->mDialog = dialog;
      dialog->dispatch(msg);
   }
   else
   {     
      dialog->dispatch(msg);
   }
}

Here is the call graph for this function:

void DialogSet::dispatchToAllDialogs ( const SipMessage msg) [private]

Definition at line 1101 of file DialogSet.cxx.

References mDialogs.

Referenced by dispatch().

{
   if (!mDialogs.empty())
   {
      for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
      {
         it->second->dispatch(msg);         
      }
   }
}
bool DialogSet::empty ( ) const

Definition at line 233 of file DialogSet.cxx.

References mDialogs.

{
   return mDialogs.empty();
}
void DialogSet::end ( )

Definition at line 938 of file DialogSet.cxx.

References Cancelling, DebugLog, Destroying, Established, getCreator(), resip::BaseCreator::getLastRequest(), InfoLog, Initial, resip::InviteSessionHandler::LocalCancel, resip::Helper::makeCancel(), mCreator, resip::DialogUsageManager::mDialogEventStateManager, mDialogs, mDum, mState, resip::DialogEventStateManager::onTerminated(), ReceivedProvisional, resip::DialogUsageManager::send(), Terminating, and WaitingToEnd.

Referenced by dispatch(), resip::AppDialogSet::end(), and resip::DialogUsageManager::end().

{
   switch(mState)
   {
      case Initial:
         mState = WaitingToEnd;
         break;
      case WaitingToEnd:
         break;         
      case ReceivedProvisional:
      {
         assert (mCreator->getLastRequest()->header(h_CSeq).method() == INVITE);
         mState = Terminating;
         // !jf! this should be made exception safe
         SharedPtr<SipMessage> cancel(Helper::makeCancel(*getCreator()->getLastRequest()));
         mDum.send(cancel);

         if (mDum.mDialogEventStateManager)
         {
            mDum.mDialogEventStateManager->onTerminated(*this, *cancel, InviteSessionHandler::LocalCancel);
         }

         if (mDialogs.empty())
         {
            mState = Cancelling;
         }
         else
         {
            //need to lag and do last element ouside of look as this DialogSet will be
            //deleted if all dialogs are destroyed
            for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
            {
               try
               {
                  it->second->cancel();
               }
               catch(UsageUseException& e)
               {
                  InfoLog (<< "Caught: " << e);
               }
            }
         }
      }            
      break;         
      case Established:
      {
         for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); ++it)
         {
            try
            {
               it->second->end();
            }
            catch(UsageUseException& e)
            {
               InfoLog (<< "Caught: " << e);
            }
         }            
         mState = Terminating;
         break;
      }
      case Terminating:
      case Cancelling:
      case Destroying:
         DebugLog (<< "DialogSet::end() called on a DialogSet that is already Terminating");
         //assert(0);
   }
}

Here is the call graph for this function:

Dialog * DialogSet::findDialog ( const SipMessage msg) [private]

Definition at line 175 of file DialogSet.cxx.

References resip::SipMessage::exists(), resip::DialogId::getCallId(), resip::Dialog::getId(), resip::DialogId::getLocalTag(), h_StatusLine, resip::SipMessage::header(), resip::SipMessage::isResponse(), mDialogs, mDum, resip::Dialog::mId, resip::Dialog::mRemoteNameAddr, resip::ParserCategory::param(), and resip::RequestLine::uri().

Referenced by dispatch(), resip::DialogUsageManager::findDialog(), and resip::DialogUsageManager::send().

{
   if (msg.isResponse() && msg.header(h_StatusLine).statusCode() == 100)
   {
      return 0;
   }
   return findDialog(DialogId(msg));
#if 0   
   DialogId id(msg);
   Dialog* dlog = findDialog(id);
   //vonage/2543 matching here
   if (dlog)
   {
      return dlog;
   }
   //match off transaction ID
   else if (msg.isResponse() && !msg.header(h_To).exists(p_tag))
   {
      for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
      {
         if (it->second->matches(msg))
         {
            return it->second;            
         }
      }
   }
   else if (msg.exists(h_Contacts) && !msg.header(h_Contacts).empty()
            && msg.isResponse() 
            && mDum.getProfile()->looseToTagMatching()
            && msg.header(h_To).exists(p_tag))     
   {
      const Uri& contact = msg.header(h_Contacts).front().uri();
      
      //match by contact
      for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
      {
         if (it->second->mRemoteTarget.uri() == msg.header(h_Contacts).front().uri())
         {
            // !dcm! in the vonage case, the to tag should be updated to match the fake
            //vonage tag introduced in the 200 which is also used for the BYE.
            //find out how deep this rabbit hole goes, may just have a pugabble
            //filter api that can be added for dialog matching if things get any
            //more specific--this is the VonageKludgeFilter
            Dialog* dialog = it->second;
            DialogId old = dialog->getId();
            dialog->mId = DialogId(old.getCallId(), old.getLocalTag(), msg.header(h_To).param(p_tag));
            dialog->mRemoteNameAddr.param(p_tag) = msg.header(h_To).param(p_tag);
            mDialogs.erase(it);
            mDialogs[dialog->getId()] = dialog;
            return dialog;
         }
      }
   }
   return 0;
#endif
}

Here is the call graph for this function:

Dialog * DialogSet::findDialog ( const DialogId  id) [private]

Definition at line 915 of file DialogSet.cxx.

References resip::InserterP(), mDialogs, and StackLog.

{
   StackLog (<< "findDialog: " << id << " in " << InserterP(mDialogs));

   DialogMap::iterator i = mDialogs.find(id);
   if (i == mDialogs.end())
   {
      return 0;
   }
   else
   {
      if(i->second->isDestroying())
      {
         return 0;
      }
      else
      {
         return i->second;
      }
   }
}

Here is the call graph for this function:

ClientOutOfDialogReq * DialogSet::findMatchingClientOutOfDialogReq ( const SipMessage msg) [private]

Definition at line 901 of file DialogSet.cxx.

References mClientOutOfDialogRequests.

Referenced by dispatch().

{
   for (std::list<ClientOutOfDialogReq*>::iterator i=mClientOutOfDialogRequests.begin();
        i != mClientOutOfDialogRequests.end(); ++i)
   {
      if ((*i)->matches(msg))
      {
         return *i;
      }
   }
   return 0;
}
void DialogSet::flowTerminated ( const Tuple flow) [private]

Definition at line 1134 of file DialogSet.cxx.

References resip::ClientRegistration::flowTerminated(), mClientRegistration, mDialogs, and mUserProfile.

{
   // The flow has failed - clear the flow key/tuple in the UserProfile
   mUserProfile->clearClientOutboundFlowTuple();

   // If this profile is configured for client outbound and the connectionTerminated
   // matches the connection stored in the profile, then notify the client registration
   // and all dialogs in this dialogset that the flow has terminated
   // Check other usage types that we send requests on
   if(mClientRegistration)
   {
      mClientRegistration->flowTerminated();
   }

   for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
   {
      it->second->flowTerminated();
   }
}

Here is the call graph for this function:

ClientOutOfDialogReqHandle resip::DialogSet::getClientOutOfDialog ( )
ClientPublicationHandle DialogSet::getClientPublication ( )

Definition at line 1034 of file DialogSet.cxx.

References resip::ClientPublication::getHandle(), mClientPublication, and resip::Handle< T >::NotValid().

Here is the call graph for this function:

ClientRegistrationHandle DialogSet::getClientRegistration ( )

Definition at line 1008 of file DialogSet.cxx.

References resip::ClientRegistration::getHandle(), mClientRegistration, and resip::Handle< ClientRegistration >::NotValid().

Here is the call graph for this function:

BaseCreator * DialogSet::getCreator ( )
DialogSetId DialogSet::getId ( ) const
ServerOutOfDialogReqHandle DialogSet::getServerOutOfDialog ( )

Definition at line 1089 of file DialogSet.cxx.

References resip::ServerOutOfDialogReq::getHandle(), mServerOutOfDialogRequest, and resip::Handle< T >::NotValid().

Here is the call graph for this function:

ServerRegistrationHandle DialogSet::getServerRegistration ( )

Definition at line 1021 of file DialogSet.cxx.

References resip::ServerRegistration::getHandle(), mServerRegistration, and resip::Handle< T >::NotValid().

Here is the call graph for this function:

SharedPtr< UserProfile > DialogSet::getUserProfile ( ) const
bool DialogSet::handledByAuthOrRedirect ( const SipMessage msg) [private]

Definition at line 239 of file DialogSet.cxx.

References Cancelling, DebugLog, Destroying, Established, resip::SipMessage::exists(), getCreator(), resip::BaseCreator::getLastRequest(), getUserProfile(), h_StatusLine, resip::SipMessage::header(), InfoLog, Initial, resip::SipMessage::isResponse(), resip::DialogUsageManager::mClientAuthManager, resip::DialogUsageManager::mDialogEventStateManager, mDialogs, mDum, resip::DialogUsageManager::mRedirectManager, mState, resip::DialogEventStateManager::onTerminated(), resip::InviteSessionHandler::Rejected, resip::DialogUsageManager::send(), StackLog, Terminating, and WaitingToEnd.

Referenced by dispatch().

{
   if (msg.isResponse() && !(mState == Terminating || 
                             mState == WaitingToEnd || 
                             mState == Destroying || 
                             mState == Cancelling))
   {
      // !dcm! -- multiple usage grief...only one of each method type allowed
      if (getCreator() &&
          msg.header(h_CSeq) == getCreator()->getLastRequest()->header(h_CSeq))
      {
         if (mDum.mClientAuthManager.get())
         {
            if (mDum.mClientAuthManager->handle(*getUserProfile().get(), *getCreator()->getLastRequest(), msg))
            {
               // Note:  ClientAuthManager->handle will end up incrementing the CSeq sequence of getLastRequest
               DebugLog( << "about to re-send request with digest credentials" );
               StackLog( << getCreator()->getLastRequest() );
               
               mDum.send(getCreator()->getLastRequest());
               return true;                     
            }
         }
         // !dcm! -- need to protect against 3xx highjacking a dialogset which
         //has a fully established dialog. also could case strange behaviour
         //by sending 401/407 at the wrong time.
         if (mDum.mRedirectManager.get() && mState != Established)  // !slg! for now don't handle redirect in established dialogs - alternatively we could treat as a target referesh (using 1st Contact) and reissue request
         {
            if (mDum.mRedirectManager->handle(*this, *getCreator()->getLastRequest(), msg))
            {
               //terminating existing dialogs(branches) as this is a final
               //response--?dcm?--merge w/ forking logic somehow?                              
               // !dcm! -- really, really horrible.  Should make a don't die
               //scoped guard
               mState = Initial;               
               for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end();)
               {
                  (it++)->second->redirected(msg);
               }

               if (mDialogs.size() == 0)
               {
                  if (mDum.mDialogEventStateManager)
                  {
                     mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Rejected);
                  }
               }

               InfoLog( << "about to re-send request to redirect destination" );
               DebugLog( << getCreator()->getLastRequest() );
               
               mDum.send(getCreator()->getLastRequest());
               return true;                     
            }

            // Check if a 422 response to initial Invite (RFC4028)
            if(msg.header(h_StatusLine).statusCode() == 422 && msg.exists(h_MinSE))
            {
               // Change interval to min from 422 response
               getCreator()->getLastRequest()->header(h_SessionExpires).value() = msg.header(h_MinSE).value();
               getCreator()->getLastRequest()->header(h_MinSE).value() = msg.header(h_MinSE).value();
               getCreator()->getLastRequest()->header(h_CSeq).sequence()++;

               InfoLog( << "about to re-send request with new session expiration time" );
               DebugLog( << getCreator()->getLastRequest() );
               
               mDum.send(getCreator()->getLastRequest());
               return true;                     
            }
         }
      }
   }
   return false;
}

Here is the call graph for this function:

bool resip::DialogSet::isDestroying ( ) [inline]

Definition at line 48 of file DialogSet.hxx.

References Destroying, and mState.

{ return mState == Destroying; };
ClientOutOfDialogReq * DialogSet::makeClientOutOfDialogReq ( const SipMessage msg) [private]

Definition at line 1063 of file DialogSet.cxx.

References ClientOutOfDialogReq, getCreator(), resip::BaseCreator::getLastRequest(), and mDum.

Referenced by dispatch().

{
   BaseCreator* creator = getCreator();
   assert(creator);
   return new ClientOutOfDialogReq(mDum, *this, *creator->getLastRequest());
}

Here is the call graph for this function:

ClientPublication * DialogSet::makeClientPublication ( const SipMessage msg) [private]

Definition at line 1055 of file DialogSet.cxx.

References ClientPublication, getCreator(), resip::BaseCreator::getLastRequest(), and mDum.

Referenced by dispatch().

{
   BaseCreator* creator = getCreator();
   assert(creator);
   return new ClientPublication(mDum, *this, creator->getLastRequest());
}

Here is the call graph for this function:

ClientRegistration * DialogSet::makeClientRegistration ( const SipMessage msg) [private]

Definition at line 1047 of file DialogSet.cxx.

References ClientRegistration, getCreator(), resip::BaseCreator::getLastRequest(), and mDum.

Referenced by dispatch().

{
   BaseCreator* creator = getCreator();
   assert(creator);
   return new ClientRegistration(mDum, *this, creator->getLastRequest());
}

Here is the call graph for this function:

ServerOutOfDialogReq * DialogSet::makeServerOutOfDialog ( const SipMessage msg) [private]

Definition at line 1077 of file DialogSet.cxx.

References mDum, and ServerOutOfDialogReq.

Referenced by dispatch().

{
   return new ServerOutOfDialogReq(mDum, *this, request);
}
ServerPagerMessage * DialogSet::makeServerPagerMessage ( const SipMessage request) [private]

Definition at line 1083 of file DialogSet.cxx.

References mDum, and ServerPagerMessage.

Referenced by dispatch().

{
   return new ServerPagerMessage(mDum, *this, request);
}
ServerRegistration * DialogSet::makeServerRegistration ( const SipMessage msg) [private]

Definition at line 1071 of file DialogSet.cxx.

References mDum, and ServerRegistration.

Referenced by dispatch().

{
   return new ServerRegistration(mDum, *this, request);
}
void resip::DialogSet::onForkAccepted ( ) [private]
void DialogSet::possiblyDie ( ) [private]

Definition at line 132 of file DialogSet.cxx.

References resip::DialogUsageManager::destroy(), Destroying, Initial, mClientOutOfDialogRequests, mClientPagerMessage, mClientPublication, mClientRegistration, mCreator, mDialogs, mDum, mServerOutOfDialogRequest, mServerPagerMessage, mServerRegistration, mState, and ReceivedProvisional.

Referenced by resip::Dialog::~Dialog(), and resip::NonDialogUsage::~NonDialogUsage().

{
   if(mState != Destroying &&
      mDialogs.empty() &&
      // The following check ensures we are not a UAC DialogSet in the Initial or 
      // ReceivedProvisional states.
      // .slg. this check fixes a case where we might receive a short term usuage 
      //       request (such as OPTIONS) in the same dialogset as a UAC dialogset
      //       for which we have not created any Dialogs yet - in this case
      //       we don't want the dialogset to die, since the UAC usage is not complete.     
      (mCreator == 0 || (mState != Initial && mState != ReceivedProvisional)) &&  
      mClientOutOfDialogRequests.empty() &&
      !(mClientPublication ||
        mServerOutOfDialogRequest ||
        mClientPagerMessage ||
        mServerPagerMessage ||
        mClientRegistration ||
        mServerRegistration))
   {
      mState = Destroying;
      mDum.destroy(this);
   }
}

Here is the call graph for this function:

void DialogSet::setUserProfile ( SharedPtr< UserProfile userProfile)

Definition at line 1127 of file DialogSet.cxx.

References resip::SharedPtr< T >::get(), and mUserProfile.

Referenced by DialogSet(), and resip::DialogUsageManager::processRequest().

{
   assert(userProfile.get());
   mUserProfile = userProfile;
}

Here is the call graph for this function:


Friends And Related Function Documentation

friend class AppDialogSet [friend]

Definition at line 87 of file DialogSet.hxx.

friend class ClientInviteSession [friend]

Definition at line 53 of file DialogSet.hxx.

friend class ClientOutOfDialogReq [friend]

Definition at line 58 of file DialogSet.hxx.

Referenced by makeClientOutOfDialogReq().

friend class ClientPagerMessage [friend]

Definition at line 62 of file DialogSet.hxx.

friend class ClientPublication [friend]

Definition at line 60 of file DialogSet.hxx.

Referenced by makeClientPublication().

friend class ClientRegistration [friend]

Definition at line 56 of file DialogSet.hxx.

Referenced by makeClientRegistration().

friend class Dialog [friend]

Definition at line 48 of file DialogSet.hxx.

Referenced by dispatch().

friend class DialogUsage [friend]

Definition at line 52 of file DialogSet.hxx.

friend class DialogUsageManager [friend]

Definition at line 55 of file DialogSet.hxx.

friend class NonDialogUsage [friend]

Definition at line 54 of file DialogSet.hxx.

EncodeStream& operator<< ( EncodeStream strm,
const DialogSet ds 
) [friend]
friend class RedirectManager [friend]

Definition at line 61 of file DialogSet.hxx.

friend class ServerOutOfDialogReq [friend]

Definition at line 59 of file DialogSet.hxx.

Referenced by makeServerOutOfDialog().

friend class ServerPagerMessage [friend]

Definition at line 63 of file DialogSet.hxx.

Referenced by makeServerPagerMessage().

friend class ServerRegistration [friend]

Definition at line 57 of file DialogSet.hxx.

Referenced by makeServerRegistration().


Member Data Documentation

Definition at line 108 of file DialogSet.hxx.

Referenced by DialogSet(), and ~DialogSet().

Definition at line 111 of file DialogSet.hxx.

Referenced by dispatch(), end(), getCreator(), possiblyDie(), and ~DialogSet().

Definition at line 112 of file DialogSet.hxx.

Referenced by DialogSet(), getId(), and ~DialogSet().

Definition at line 107 of file DialogSet.hxx.

Referenced by DialogSet(), and ~DialogSet().

Definition at line 115 of file DialogSet.hxx.

Referenced by dispatch(), end(), handledByAuthOrRedirect(), isDestroying(), and possiblyDie().


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