reSIProcate/DialogUsageManager  9694
InviteSession.cxx
Go to the documentation of this file.
00001 #include "resip/stack/MultipartMixedContents.hxx"
00002 #include "resip/stack/MultipartAlternativeContents.hxx"
00003 #include "resip/stack/SdpContents.hxx"
00004 #include "resip/stack/SipMessage.hxx"
00005 #include "resip/stack/Helper.hxx"
00006 #include "resip/dum/BaseCreator.hxx"
00007 #include "resip/dum/Dialog.hxx"
00008 #include "resip/dum/DialogEventStateManager.hxx"
00009 #include "resip/dum/DialogUsageManager.hxx"
00010 #include "resip/dum/InviteSession.hxx"
00011 #include "resip/dum/ServerInviteSession.hxx"
00012 #include "resip/dum/ClientSubscription.hxx"
00013 #include "resip/dum/ServerSubscription.hxx"
00014 #include "resip/dum/ClientInviteSession.hxx"
00015 #include "resip/dum/InviteSessionHandler.hxx"
00016 #include "resip/dum/MasterProfile.hxx"
00017 #include "resip/dum/UsageUseException.hxx"
00018 #include "resip/dum/DumHelper.hxx"
00019 #include "rutil/Inserter.hxx"
00020 #include "rutil/Logger.hxx"
00021 #include "rutil/MD5Stream.hxx"
00022 #include "rutil/Timer.hxx"
00023 #include "rutil/Random.hxx"
00024 #include "rutil/compat.hxx"
00025 #include "rutil/WinLeakCheck.hxx"
00026 
00027 // Remove warning about 'this' use in initiator list - pointer is only stored
00028 #if defined(WIN32) && !defined(__GNUC__)
00029 #pragma warning( disable : 4355 ) // using this in base member initializer list
00030 #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
00031 #endif
00032 
00033 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
00034 #define THROW(msg)  throw DialogUsage::Exception(msg, __FILE__,__LINE__);
00035 
00036 using namespace resip;
00037 using namespace std;
00038 
00039 Data EndReasons[] =
00040 {
00041    "Not Specified",
00042    "User Hung Up",
00043    "Application Rejected Sdp(usually no common codec)",
00044    "Illegal Sdp Negotiation",
00045    "ACK not received",
00046    "Session Timer Expired",
00047    "Stale re-Invite"
00048 };
00049 
00050 const Data& InviteSession::getEndReasonString(InviteSession::EndReason reason)
00051 {
00052    if(reason != InviteSession::UserSpecified)
00053    {
00054       assert(reason >= InviteSession::NotSpecified && reason < InviteSession::ENDREASON_MAX); 
00055       return EndReasons[reason];
00056    }
00057    else
00058    {
00059       return mUserEndReason;
00060    }
00061 }
00062 
00063 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
00064    : DialogUsage(dum, dialog),
00065      mState(Undefined),
00066      mNitState(NitComplete),
00067      mServerNitState(NitComplete),
00068      mLastLocalSessionModification(new SipMessage),
00069      mLastRemoteSessionModification(new SipMessage),
00070      mInvite200(new SipMessage),
00071      mLastNitResponse(new SipMessage),
00072      mCurrentRetransmit200(0),
00073      mStaleReInviteTimerSeq(1),
00074      mSessionInterval(0),
00075      mMinSE(90), 
00076      mSessionRefresher(false),
00077      mSessionTimerSeq(0),
00078      mSessionRefreshReInvite(false),
00079      mReferSub(true),
00080      mCurrentEncryptionLevel(DialogUsageManager::None),
00081      mProposedEncryptionLevel(DialogUsageManager::None),
00082      mEndReason(NotSpecified)
00083 {
00084    DebugLog ( << "^^^ InviteSession::InviteSession " << this);
00085    assert(mDum.mInviteSessionHandler);
00086 }
00087 
00088 InviteSession::~InviteSession()
00089 {
00090    DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
00091    mDialog.mInviteSession = 0;
00092    while(!mNITQueue.empty())
00093    {
00094       delete mNITQueue.front();
00095       mNITQueue.pop();
00096    }
00097 }
00098 
00099 void 
00100 InviteSession::dialogDestroyed(const SipMessage& msg)
00101 {
00102    assert(0);
00103    
00104    // !jf! Is this correct? Merged from main...
00105    // !jf! what reason - guessed for now?
00106    //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);   
00107    //delete this;   
00108 }
00109 
00110 bool
00111 InviteSession::hasLocalOfferAnswer() const
00112 {
00113    return (mCurrentLocalOfferAnswer.get());
00114 }
00115 
00116 const Contents&
00117 InviteSession::getLocalOfferAnswer() const
00118 {
00119    if(mCurrentLocalOfferAnswer.get())
00120    {
00121       return *mCurrentLocalOfferAnswer;
00122    }
00123    else
00124    {
00125       return SdpContents::Empty;
00126    }
00127 }
00128 
00129 bool
00130 InviteSession::hasRemoteOfferAnswer() const
00131 {
00132    return (mCurrentRemoteOfferAnswer.get());
00133 }
00134 
00135 const Contents&
00136 InviteSession::getRemoteOfferAnswer() const
00137 {
00138    if(mCurrentRemoteOfferAnswer.get())
00139    {
00140       return *mCurrentRemoteOfferAnswer;
00141    }
00142    else
00143    {
00144       return SdpContents::Empty;
00145    }
00146 }
00147 
00148 bool
00149 InviteSession::hasProposedRemoteOfferAnswer() const
00150 {
00151    return (mProposedRemoteOfferAnswer.get());
00152 }
00153 
00154 const Contents&
00155 InviteSession::getProposedRemoteOfferAnswer() const
00156 {
00157    if(mProposedRemoteOfferAnswer.get())
00158    {
00159       return *mProposedRemoteOfferAnswer;
00160    }
00161    else
00162    {
00163       return SdpContents::Empty;
00164    }
00165 }
00166 
00167 bool
00168 InviteSession::hasLocalSdp() const
00169 {
00170    assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
00171    return (mCurrentLocalOfferAnswer.get());
00172 }
00173 
00174 const SdpContents&
00175 InviteSession::getLocalSdp() const
00176 {
00177    assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
00178    if(mCurrentLocalOfferAnswer.get())
00179    {
00180       const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentLocalOfferAnswer.get());
00181       assert(sdp);
00182       return *sdp;
00183    }
00184    else
00185    {
00186       return SdpContents::Empty;
00187    }
00188 }
00189 
00190 bool
00191 InviteSession::hasRemoteSdp() const
00192 {
00193    assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
00194    return (mCurrentRemoteOfferAnswer.get());
00195 }
00196 
00197 const SdpContents&
00198 InviteSession::getRemoteSdp() const
00199 {
00200    assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
00201    if(mCurrentRemoteOfferAnswer.get())
00202    {
00203       const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentRemoteOfferAnswer.get());
00204       assert(sdp);
00205       return *sdp;
00206    }
00207    else
00208    {
00209       return SdpContents::Empty;
00210    }
00211 }
00212 
00213 bool
00214 InviteSession::hasProposedRemoteSdp() const
00215 {
00216    assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
00217    return (mProposedRemoteOfferAnswer.get());
00218 }
00219 
00220 const SdpContents&
00221 InviteSession::getProposedRemoteSdp() const
00222 {
00223    assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
00224    if(mProposedRemoteOfferAnswer.get())
00225    {
00226       const SdpContents* sdp = dynamic_cast<const SdpContents*>(mProposedRemoteOfferAnswer.get());
00227       assert(sdp);
00228       return *sdp;
00229    }
00230    else
00231    {
00232       return SdpContents::Empty;
00233    }
00234 }
00235 
00236 InviteSessionHandle
00237 InviteSession::getSessionHandle()
00238 {
00239    return InviteSessionHandle(mDum, getBaseHandle().getId());
00240 }
00241 
00242 void InviteSession::storePeerCapabilities(const SipMessage& msg)
00243 {
00244    if (msg.exists(h_Allows))
00245    {
00246       mPeerSupportedMethods = msg.header(h_Allows);
00247    }
00248    if (msg.exists(h_Supporteds))
00249    {
00250       mPeerSupportedOptionTags = msg.header(h_Supporteds);
00251    }
00252    if (msg.exists(h_AcceptEncodings))
00253    {
00254       mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
00255    }
00256    if (msg.exists(h_AcceptLanguages))
00257    {
00258       mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
00259    }
00260    if (msg.exists(h_AllowEvents))
00261    {
00262       mPeerAllowedEvents = msg.header(h_AllowEvents);
00263    }
00264    if (msg.exists(h_Accepts))
00265    {
00266       mPeerSupportedMimeTypes = msg.header(h_Accepts);
00267    }
00268    if (msg.exists(h_UserAgent))
00269    {
00270       mPeerUserAgent = msg.header(h_UserAgent).value();
00271    }
00272 }
00273 
00274 bool
00275 InviteSession::updateMethodSupported() const
00276 {
00277    // Check if Update is supported locally
00278    if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
00279    {
00280        // Check if peer supports UPDATE
00281        return mPeerSupportedMethods.find(Token("UPDATE"));
00282    }
00283    return false;
00284 }
00285 
00286 bool
00287 InviteSession::isConnected() const
00288 {
00289    switch (mState)
00290    {
00291       case Connected:
00292       case SentUpdate:
00293       case SentUpdateGlare:
00294       case SentReinvite:
00295       case SentReinviteGlare:
00296       case SentReinviteNoOffer:
00297       case SentReinviteAnswered:
00298       case SentReinviteNoOfferGlare:
00299       case ReceivedUpdate:
00300       case ReceivedReinvite:
00301       case ReceivedReinviteNoOffer:
00302       case ReceivedReinviteSentOffer:
00303       case Answered:
00304       case WaitingToOffer:
00305       case WaitingToRequestOffer:
00306          return true;
00307 
00308       default:
00309          return false;
00310    }
00311 }
00312 
00313 bool
00314 InviteSession::isEarly() const
00315 {
00316    switch (mState)
00317    {
00318       case UAC_Early:
00319       case UAC_EarlyWithOffer:
00320       case UAC_EarlyWithAnswer:
00321       case UAC_SentUpdateEarly:
00322       case UAC_ReceivedUpdateEarly:
00323       case UAC_SentAnswer:
00324       case UAC_QueuedUpdate:
00325          return true;
00326       default:
00327          return false;
00328    }
00329 }
00330 
00331 bool 
00332 InviteSession::isAccepted() const
00333 {
00334    switch (mState)
00335    {
00336       case UAS_Start:
00337       case UAS_Offer:
00338       case UAS_NoOffer:
00339       case UAS_NoOfferReliable:
00340       case UAS_ProvidedOffer:
00341       case UAS_OfferProvidedAnswer:
00342       case UAS_EarlyOffer:
00343       case UAS_EarlyProvidedOffer:
00344       case UAS_EarlyProvidedAnswer:
00345       case UAS_EarlyNoOffer:
00346       case UAS_FirstSentAnswerReliable:
00347       case UAS_FirstSentOfferReliable:
00348       case UAS_NegotiatedReliable:
00349          return false;
00350       default:
00351          return true;
00352    }
00353 }
00354 
00355 bool
00356 InviteSession::isTerminated() const
00357 {
00358    switch (mState)
00359    {
00360       case Terminated:
00361       case WaitingToTerminate:
00362       case WaitingToHangup:
00363       case UAC_Cancelled:
00364       case UAS_WaitingToTerminate:
00365       case UAS_WaitingToHangup:
00366          return true;
00367       default:
00368          return false;
00369    }
00370 }
00371 
00372 EncodeStream&
00373 InviteSession::dump(EncodeStream& strm) const
00374 {
00375    strm << "INVITE: " << mId
00376         << " " << toData(mState)
00377         << " ADDR=" << myAddr()
00378         << " PEER=" << peerAddr();
00379    return strm;
00380 }
00381 
00382 void
00383 InviteSession::requestOffer()
00384 {
00385    switch (mState)
00386    {
00387       case Connected:
00388       case WaitingToRequestOffer:
00389       case UAS_WaitingToRequestOffer:
00390          transition(SentReinviteNoOffer);
00391          mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
00392          startStaleReInviteTimer();
00393          mLastLocalSessionModification->setContents(0);         // Clear the contents from the INVITE
00394          setSessionTimerHeaders(*mLastLocalSessionModification);
00395 
00396          InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
00397 
00398          // call send to give app an chance to adorn the message.
00399          send(mLastLocalSessionModification);
00400          break;
00401 
00402       case Answered:
00403          // queue the offer to be sent after the ACK is received
00404          transition(WaitingToRequestOffer);
00405          break;        
00406          
00407       // ?slg? Can we handle all of the states listed in isConnected() ???
00408       default:
00409          WarningLog (<< "Can't requestOffer when not in Connected state");
00410          throw DialogUsage::Exception("Can't request an offer", __FILE__,__LINE__);
00411    }
00412 }
00413 
00414 void
00415 InviteSession::provideOffer(const Contents& offer,
00416                             DialogUsageManager::EncryptionLevel level,
00417                             const Contents* alternative)
00418 {
00419    switch (mState)
00420    {
00421       case Connected:
00422       case WaitingToOffer:
00423       case UAS_WaitingToOffer:
00424          transition(SentReinvite);
00425          mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
00426          startStaleReInviteTimer();
00427 
00428                  setSessionTimerHeaders(*mLastLocalSessionModification);
00429 
00430          InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
00431          InviteSession::setOfferAnswer(*mLastLocalSessionModification, offer, alternative);
00432          mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
00433          mProposedEncryptionLevel = level;
00434          DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
00435 
00436          // call send to give app an chance to adorn the message.
00437          send(mLastLocalSessionModification);
00438          break;
00439 
00440       case Answered:
00441          // queue the offer to be sent after the ACK is received
00442          transition(WaitingToOffer);
00443          mProposedEncryptionLevel = level;
00444          mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
00445          break;
00446 
00447       case ReceivedReinviteNoOffer:
00448          assert(!mProposedRemoteOfferAnswer.get());
00449          transition(ReceivedReinviteSentOffer);
00450          mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
00451          handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
00452          InviteSession::setOfferAnswer(*mInvite200, offer, 0);
00453          mProposedLocalOfferAnswer  = InviteSession::makeOfferAnswer(offer);
00454 
00455          InfoLog (<< "Sending " << mInvite200->brief());
00456          DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
00457          send(mInvite200);
00458          startRetransmit200Timer();
00459          break;
00460                   
00461       default:
00462          WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
00463          throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
00464    }
00465 }
00466 
00467 class InviteSessionProvideOfferExCommand : public DumCommandAdapter
00468 {
00469 public:
00470    InviteSessionProvideOfferExCommand(InviteSession& inviteSession, 
00471       const Contents& offer, 
00472       DialogUsageManager::EncryptionLevel level, 
00473       const Contents* alternative)
00474       : mInviteSession(inviteSession),
00475         mOffer(offer.clone()),
00476         mLevel(level),
00477                 mAlternative(alternative ? alternative->clone() : 0)
00478    {
00479    }
00480 
00481    virtual void executeCommand()
00482    {
00483       mInviteSession.provideOffer(*mOffer, mLevel, mAlternative.get());
00484    }
00485 
00486    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00487    {
00488       return strm << "InviteSessionProvideOfferExCommand";
00489    }
00490 private:
00491    InviteSession& mInviteSession;
00492    std::auto_ptr<const Contents> mOffer;
00493    DialogUsageManager::EncryptionLevel mLevel;
00494    std::auto_ptr<const Contents> mAlternative;
00495 };
00496 
00497 void
00498 InviteSession::provideOfferCommand(const Contents& offer, DialogUsageManager::EncryptionLevel level, const Contents* alternative)
00499 {
00500    mDum.post(new InviteSessionProvideOfferExCommand(*this, offer, level, alternative));
00501 }
00502 
00503 void
00504 InviteSession::provideOffer(const Contents& offer)
00505 {
00506    return provideOffer(offer, mCurrentEncryptionLevel, 0);
00507 }
00508 
00509 class InviteSessionProvideOfferCommand : public DumCommandAdapter
00510 {
00511 public:
00512    InviteSessionProvideOfferCommand(InviteSession& inviteSession, const Contents& offer)
00513       : mInviteSession(inviteSession),
00514       mOffer(offer.clone())
00515    {
00516    }
00517 
00518    virtual void executeCommand()
00519    {
00520       mInviteSession.provideOffer(*mOffer);
00521    }
00522 
00523    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00524    {
00525       return strm << "InviteSessionProvideOfferCommand";
00526    }
00527 private:
00528    InviteSession& mInviteSession;
00529    std::auto_ptr<const Contents> mOffer;
00530 };
00531 
00532 void
00533 InviteSession::provideOfferCommand(const Contents& offer)
00534 {
00535    mDum.post(new InviteSessionProvideOfferCommand(*this, offer));
00536 }
00537 
00538 void
00539 InviteSession::provideAnswer(const Contents& answer)
00540 {
00541    switch (mState)
00542    {
00543       case ReceivedReinvite:
00544          transition(Connected);
00545          mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
00546          handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
00547          InviteSession::setOfferAnswer(*mInvite200, answer, 0);
00548          mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
00549          mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
00550          InfoLog (<< "Sending " << mInvite200->brief());
00551          DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
00552          send(mInvite200);
00553          startRetransmit200Timer();
00554          break;
00555 
00556       case ReceivedUpdate: // same as ReceivedReinvite case.
00557       {
00558          transition(Connected);
00559 
00560          SharedPtr<SipMessage> response(new SipMessage);
00561          mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
00562          handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
00563          InviteSession::setOfferAnswer(*response, answer, 0);
00564          mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
00565          mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
00566          InfoLog (<< "Sending " << response->brief());
00567          DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
00568          send(response);
00569          break;
00570       }
00571 
00572       case SentReinviteAnswered:
00573          transition(Connected);
00574          sendAck(&answer);
00575 
00576          mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
00577          mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
00578          break;
00579 
00580       default:
00581          WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
00582          throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
00583    }
00584 }
00585 
00586 class InviteSessionProvideAnswerCommand : public DumCommandAdapter
00587 {
00588 public:
00589    InviteSessionProvideAnswerCommand(InviteSession& inviteSession, const Contents& answer)
00590       : mInviteSession(inviteSession),
00591         mAnswer(answer.clone())
00592    {
00593    }
00594 
00595    virtual void executeCommand()
00596    {
00597       mInviteSession.provideAnswer(*mAnswer);
00598    }
00599 
00600    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00601    {
00602       return strm << "InviteSessionProvideAnswerCommand";
00603    }
00604 private:
00605    InviteSession& mInviteSession;
00606    std::auto_ptr<const Contents> mAnswer;
00607 };
00608 
00609 void
00610 InviteSession::provideAnswerCommand(const Contents& answer)
00611 {
00612    mDum.post(new InviteSessionProvideAnswerCommand(*this, answer));
00613 }
00614 
00615 void
00616 InviteSession::end()
00617 {
00618    end(NotSpecified);
00619 }
00620 
00621 void
00622 InviteSession::end(const Data& userReason)
00623 {
00624    mUserEndReason = userReason;
00625    end(UserSpecified);
00626 }
00627 
00628 void
00629 InviteSession::end(EndReason reason)
00630 {
00631    if (mEndReason == NotSpecified)
00632    {
00633       mEndReason = reason;   
00634    }
00635    
00636    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
00637 
00638    switch (mState)
00639    {
00640       case Connected:
00641       case SentUpdate:
00642       case SentUpdateGlare:
00643       case SentReinviteGlare:
00644       case SentReinviteNoOfferGlare:
00645       case SentReinviteAnswered:
00646       {
00647          // !jf! do we need to store the BYE somewhere?
00648          // .dw. BYE message handled
00649          SharedPtr<SipMessage> msg = sendBye();
00650          transition(Terminated);
00651          handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get()); 
00652          break;
00653       }
00654 
00655       case SentReinvite:
00656       case SentReinviteNoOffer:
00657          transition(WaitingToTerminate);
00658          break;
00659 
00660       case Answered:
00661       case WaitingToOffer:
00662       case WaitingToRequestOffer:
00663       case ReceivedReinviteSentOffer:
00664          if(mCurrentRetransmit200)  // If retransmit200 timer is active then ACK is not received yet - wait for it
00665          {
00666             transition(WaitingToHangup);
00667          }
00668          else
00669          {
00670              // ACK has likely timedout - hangup immediately
00671              SharedPtr<SipMessage> msg = sendBye();
00672              transition(Terminated);
00673              mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
00674          }
00675          break;
00676 
00677       case ReceivedUpdate:
00678       case ReceivedReinvite:
00679       case ReceivedReinviteNoOffer:
00680       {
00681          SharedPtr<SipMessage> response(new SipMessage);
00682          mDialog.makeResponse(*response, *mLastRemoteSessionModification, 488);
00683          InfoLog (<< "Sending " << response->brief());
00684          send(response);
00685 
00686          SharedPtr<SipMessage> msg = sendBye();
00687          transition(Terminated);
00688          handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get()); 
00689          break;
00690       }
00691 
00692       case WaitingToTerminate:  // ?slg?  Why is this here?
00693       {
00694          SharedPtr<SipMessage> msg = sendBye();
00695          transition(Terminated);
00696          handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get()); 
00697          break;
00698       }
00699 
00700       case Terminated:
00701          // no-op.
00702          break;
00703 
00704       default:
00705          assert(0);
00706          break;
00707    }
00708 }
00709 
00710 class InviteSessionEndCommand : public DumCommandAdapter
00711 {
00712 public:
00713    InviteSessionEndCommand(InviteSession& inviteSession, InviteSession::EndReason reason)
00714       : mInviteSession(inviteSession),
00715         mReason(reason)
00716    {
00717    }
00718 
00719    virtual void executeCommand()
00720    {
00721       mInviteSession.end(mReason);
00722    }
00723 
00724    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00725    {
00726       return strm << "InviteSessionEndCommand";
00727    }
00728 private:
00729    InviteSession& mInviteSession;
00730    InviteSession::EndReason mReason;
00731 };
00732 
00733 void
00734 InviteSession::endCommand(EndReason reason)
00735 {
00736    mDum.post(new InviteSessionEndCommand(*this, reason));
00737 }
00738 
00739 void
00740 InviteSession::reject(int statusCode, WarningCategory *warning)
00741 {
00742    switch (mState)
00743    {
00744       case ReceivedUpdate:
00745       case ReceivedReinvite:
00746       case ReceivedReinviteNoOffer:
00747       {
00748          transition(Connected);
00749 
00750          SharedPtr<SipMessage> response(new SipMessage);
00751          mDialog.makeResponse(*response, *mLastRemoteSessionModification, statusCode);
00752          if(warning)
00753          {
00754             response->header(h_Warnings).push_back(*warning);
00755          }
00756          InfoLog (<< "Sending " << response->brief());
00757          send(response);
00758          break;
00759       }
00760       // Sent a reINVITE no offer and received a 200-offer.
00761       // Simply send an ACK without an answer and stay in Connected.
00762       case SentReinviteAnswered:
00763       {
00764          InfoLog (<< "Not sending " << statusCode << " error since transaction"
00765                      "already completed, sending answer-less ACK");
00766          transition(Connected);
00767          sendAck();
00768          break;
00769       }
00770       default:
00771          assert(0);
00772          break;
00773    }
00774 }
00775 
00776 class InviteSessionRejectCommand : public DumCommandAdapter
00777 {
00778 public:
00779    InviteSessionRejectCommand(InviteSession& inviteSession, int code, WarningCategory* warning)
00780       : mInviteSession(inviteSession),
00781         mCode(code),
00782         mWarning(warning?new WarningCategory(*warning):0)
00783    {
00784    }
00785 
00786    virtual void executeCommand()
00787    {
00788       mInviteSession.reject(mCode, mWarning.get());
00789    }
00790 
00791    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00792    {
00793       return strm << "InviteSessionRejectCommand";
00794    }
00795 private:
00796    InviteSession& mInviteSession;
00797    int mCode;
00798    std::auto_ptr<WarningCategory> mWarning;
00799 };
00800 
00801 void
00802 InviteSession::rejectCommand(int code, WarningCategory *warning)
00803 {
00804    mDum.post(new InviteSessionRejectCommand(*this, code, warning));
00805 }
00806 
00807 void
00808 InviteSession::targetRefresh(const NameAddr& localUri)
00809 {
00810    if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
00811    {
00812       mDialog.mLocalContact = localUri;
00813       sessionRefresh();
00814    }
00815    else
00816    {
00817       WarningLog (<< "Can't targetRefresh before Connected");
00818       throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
00819    }
00820 }
00821 
00822 void
00823 InviteSession::refer(const NameAddr& referTo, bool referSub)
00824 {
00825    refer(referTo,std::auto_ptr<resip::Contents>(0),referSub);
00826 }
00827 void
00828 InviteSession::refer(const NameAddr& referTo, std::auto_ptr<resip::Contents> contents,bool referSub)
00829 {
00830    if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
00831    {
00832       SharedPtr<SipMessage> refer(new SipMessage());
00833       mDialog.makeRequest(*refer, REFER);
00834       refer->header(h_ReferTo) = referTo;
00835       refer->header(h_ReferredBy) = myAddr(); 
00836       refer->header(h_ReferredBy).remove(p_tag);   // tag-param not permitted in rfc3892; not the same as generic-param
00837       refer->setContents(contents);
00838       if (!referSub)
00839       {
00840          refer->header(h_ReferSub).value() = "false";
00841          refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
00842       }
00843 
00844       if(mNitState == NitComplete)
00845       {
00846          mNitState = NitProceeding;
00847          mReferSub = referSub;
00848          mLastSentNITRequest = refer;
00849          send(refer);
00850          return;
00851       }
00852       mNITQueue.push(new QueuedNIT(refer,referSub));
00853       InfoLog(<< "refer - queuing NIT:" << refer->brief());
00854       return;
00855    }
00856    else
00857    {
00858       WarningLog (<< "Can't refer before Connected");
00859       assert(0);
00860       throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
00861    }
00862 }
00863 
00864 const SharedPtr<SipMessage>
00865 InviteSession::getLastSentNITRequest() const
00866 {
00867    return mLastSentNITRequest;
00868 }
00869 
00870 void
00871 InviteSession::nitComplete()
00872 {
00873    mNitState = NitComplete;
00874    if (mNITQueue.size())
00875    {
00876       QueuedNIT *qn=mNITQueue.front();
00877       mNITQueue.pop();
00878       mNitState = NitProceeding;
00879       mReferSub = qn->referSubscription();
00880       mLastSentNITRequest = qn->getNIT();
00881       InfoLog(<< "checkNITQueue - sending queued NIT:" << mLastSentNITRequest->brief());
00882       send(mLastSentNITRequest);
00883       delete qn;
00884    }
00885 }
00886 
00887 class InviteSessionReferCommand : public DumCommandAdapter
00888 {
00889 public:
00890    InviteSessionReferCommand(InviteSession& inviteSession, const NameAddr& referTo, bool referSub)
00891       : mInviteSession(inviteSession),
00892       mReferTo(referTo),
00893       mReferSub(referSub)
00894    {
00895 
00896    }
00897 
00898    virtual void executeCommand()
00899    {
00900       mInviteSession.refer(mReferTo, mReferSub);
00901    }
00902 
00903    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00904    {
00905       return strm << "InviteSessionReferCommand";
00906    }
00907 
00908 private:
00909    InviteSession& mInviteSession;
00910    NameAddr mReferTo;
00911    bool mReferSub;
00912 };
00913 
00914 void
00915 InviteSession::referCommand(const NameAddr& referTo, bool referSub)
00916 {
00917    mDum.post(new InviteSessionReferCommand(*this, referTo, referSub));
00918 }
00919 
00920 void
00921 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
00922 {
00923    refer(referTo,sessionToReplace,std::auto_ptr<resip::Contents>(0),referSub);
00924 }
00925 
00926 void
00927 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, std::auto_ptr<resip::Contents> contents, bool referSub)
00928 {
00929    if (!sessionToReplace.isValid())
00930    {
00931       throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
00932    }
00933 
00934    CallId replaces;
00935    DialogId id = sessionToReplace->mDialog.getId();
00936    replaces.value() = id.getCallId();
00937    replaces.param(p_toTag) = id.getRemoteTag();
00938    replaces.param(p_fromTag) = id.getLocalTag();
00939 
00940    refer(referTo, replaces, contents, referSub);
00941 }
00942 
00943 void 
00944 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, bool referSub)
00945 {
00946    refer(referTo,replaces,std::auto_ptr<resip::Contents>(0),referSub);
00947 }
00948 
00949 void 
00950 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, std::auto_ptr<resip::Contents> contents, bool referSub)
00951 {
00952    if (isConnected())  // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
00953    {
00954       SharedPtr<SipMessage> refer(new SipMessage());      
00955       mDialog.makeRequest(*refer, REFER);
00956       refer->setContents(contents);
00957       refer->header(h_ReferTo) = referTo;
00958       refer->header(h_ReferredBy) = myAddr();
00959       refer->header(h_ReferredBy).remove(p_tag);
00960 
00961       refer->header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
00962       
00963       if (!referSub)
00964       {
00965          refer->header(h_ReferSub).value() = "false";
00966          refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
00967       }
00968 
00969       if(mNitState == NitComplete)
00970       {
00971          mNitState = NitProceeding;
00972          mReferSub = referSub;
00973          mLastSentNITRequest = refer;
00974          send(refer);
00975          return;
00976       }
00977       mNITQueue.push(new QueuedNIT(refer,referSub));
00978       InfoLog(<< "refer/replace - queuing NIT:" << refer->brief());
00979       return;
00980    }
00981    else
00982    {
00983       WarningLog (<< "Can't refer before Connected");
00984       assert(0);
00985       throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
00986    }
00987 }
00988 
00989 class InviteSessionReferExCommand : public DumCommandAdapter
00990 {
00991 public:
00992    InviteSessionReferExCommand(InviteSession& inviteSession, const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
00993       : mInviteSession(inviteSession),
00994       mSessionToReplace(sessionToReplace),
00995       mReferTo(referTo),
00996       mReferSub(referSub)
00997    {
00998    }
00999 
01000    virtual void executeCommand()
01001    {
01002       mInviteSession.referCommand(mReferTo, mSessionToReplace, mReferSub);
01003    }
01004 
01005    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
01006    {
01007       return strm << "InviteSessionReferExCommand";
01008    }
01009 
01010 private:
01011    InviteSession& mInviteSession;
01012    InviteSessionHandle mSessionToReplace;
01013    NameAddr mReferTo;
01014    bool mReferSub;
01015 };
01016 
01017 void
01018 InviteSession::referCommand(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
01019 {
01020    mDum.post(new InviteSessionReferExCommand(*this, referTo, sessionToReplace, referSub));
01021 }
01022 
01023 void
01024 InviteSession::info(const Contents& contents)
01025 {
01026    SharedPtr<SipMessage> info(new SipMessage());
01027    mDialog.makeRequest(*info, INFO);
01028    // !jf! handle multipart here
01029    info->setContents(&contents);
01030    DumHelper::setOutgoingEncryptionLevel(*info, mCurrentEncryptionLevel);
01031    if (mNitState == NitComplete)
01032    {
01033       mNitState = NitProceeding;
01034       mLastSentNITRequest = info;
01035       send(info);
01036       return;
01037    }
01038    mNITQueue.push(new QueuedNIT(info));
01039    InfoLog(<< "info - queuing NIT:" << info->brief());
01040    return;
01041 }
01042 
01043 class InviteSessionInfoCommand : public DumCommandAdapter
01044 {
01045 public:
01046    InviteSessionInfoCommand(InviteSession& inviteSession, const Contents& contents)
01047       : mInviteSession(inviteSession),
01048         mContents(contents.clone())
01049    {
01050    }
01051 
01052    virtual void executeCommand()
01053    {
01054       mInviteSession.info(*mContents);
01055    }
01056 
01057    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
01058    {
01059       return strm << "InviteSessionInfoCommand";
01060    }
01061 private:
01062    InviteSession& mInviteSession;
01063    std::auto_ptr<Contents> mContents;
01064 };
01065 
01066 void
01067 InviteSession::infoCommand(const Contents& contents)
01068 {
01069    mDum.post(new InviteSessionInfoCommand(*this, contents));
01070 }
01071 
01072 void
01073 InviteSession::message(const Contents& contents)
01074 {
01075    SharedPtr<SipMessage> message(new SipMessage());
01076    mDialog.makeRequest(*message, MESSAGE);
01077    // !jf! handle multipart here
01078    message->setContents(&contents);
01079    DumHelper::setOutgoingEncryptionLevel(*message, mCurrentEncryptionLevel);
01080    InfoLog (<< "Trying to send MESSAGE: " << message);
01081    if (mNitState == NitComplete)
01082    {
01083       mNitState = NitProceeding;
01084       mLastSentNITRequest = message;
01085       send(message);
01086       return;
01087    }
01088    mNITQueue.push(new QueuedNIT(message));
01089    InfoLog(<< "message - queuing NIT:" << message->brief());
01090    return;
01091 }
01092 
01093 class InviteSessionMessageCommand : public DumCommandAdapter
01094 {
01095 public:
01096    InviteSessionMessageCommand(InviteSession& inviteSession, const Contents& contents)
01097       : mInviteSession(inviteSession),
01098         mContents(contents.clone())
01099    {
01100    }
01101 
01102    virtual void executeCommand()
01103    {
01104       mInviteSession.message(*mContents);
01105    }
01106 
01107    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
01108    {
01109       return strm << "InviteSessionMessageCommand";
01110    }
01111 private:
01112    InviteSession& mInviteSession;
01113    std::auto_ptr<Contents> mContents;
01114 };
01115 
01116 
01117 void
01118 InviteSession::messageCommand(const Contents& contents)
01119 {
01120    mDum.post(new InviteSessionMessageCommand(*this, contents));
01121 }
01122 
01123 void
01124 InviteSession::dispatch(const SipMessage& msg)
01125 {
01126    // Look for 2xx retransmissions - resend ACK and filter out of state machine
01127    if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 100 == 2)
01128    {
01129       AckMap::iterator i = mAcks.find(msg.getTransactionId());
01130       if (i != mAcks.end())
01131       {
01132          send(i->second);  // resend ACK
01133          return;
01134       }
01135    }
01136 
01137    // !jf! do we need to handle 3xx here or is it handled elsewhere?
01138    switch (mState)
01139    {
01140       case Connected:
01141          dispatchConnected(msg);
01142          break;
01143       case SentUpdate:
01144          dispatchSentUpdate(msg);
01145          break; 
01146       case SentReinvite:
01147          dispatchSentReinvite(msg);
01148          break;
01149       case SentReinviteNoOffer:
01150          dispatchSentReinviteNoOffer(msg);
01151          break;
01152       case SentReinviteAnswered:
01153          dispatchSentReinviteAnswered(msg);
01154          break;
01155       case SentUpdateGlare:
01156       case SentReinviteGlare:
01157          // The behavior is the same except for timer which is handled in dispatch(Timer)
01158          dispatchGlare(msg);
01159          break;
01160       case SentReinviteNoOfferGlare:
01161          dispatchReinviteNoOfferGlare(msg);
01162          break;
01163       case ReceivedUpdate:
01164       case ReceivedReinvite:
01165       case ReceivedReinviteNoOffer:
01166          dispatchReceivedUpdateOrReinvite(msg);
01167          break;
01168       case ReceivedReinviteSentOffer:
01169          dispatchReceivedReinviteSentOffer(msg);
01170          break;
01171       case Answered:
01172          dispatchAnswered(msg);
01173          break;
01174       case WaitingToOffer:
01175          dispatchWaitingToOffer(msg);
01176          break;
01177       case WaitingToRequestOffer:
01178          dispatchWaitingToRequestOffer(msg);
01179          break;
01180       case WaitingToTerminate:
01181          dispatchWaitingToTerminate(msg);
01182          break;
01183       case WaitingToHangup:
01184          dispatchWaitingToHangup(msg);
01185          break;
01186       case Terminated:
01187          dispatchTerminated(msg);
01188          break;
01189       case Undefined:
01190       default:
01191          assert(0);
01192          break;
01193    }
01194 }
01195 
01196 void
01197 InviteSession::dispatch(const DumTimeout& timeout)
01198 {
01199    if (timeout.type() == DumTimeout::Retransmit200)
01200    {
01201       if (mCurrentRetransmit200)
01202       {
01203          InfoLog (<< "Retransmitting: " << endl << mInvite200->brief());
01204          //DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
01205          send(mInvite200);
01206          mCurrentRetransmit200 *= 2;
01207          mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(),  timeout.seq());
01208       }
01209    }
01210    else if (timeout.type() == DumTimeout::WaitForAck)
01211    {
01212       if(mCurrentRetransmit200)  // If retransmit200 timer is active then ACK is not received yet
01213       {
01214          if (timeout.seq() == mLastRemoteSessionModification->header(h_CSeq).sequence())
01215          {
01216             mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01217 
01218             // If we are waiting for an Ack and it times out, then end with a BYE
01219             if(mState == UAS_WaitingToHangup || 
01220                mState == WaitingToHangup)
01221             {
01222                SharedPtr<SipMessage> msg = sendBye();
01223                transition(Terminated);
01224                mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get()); 
01225             }
01226             else if(mState == ReceivedReinviteSentOffer)
01227             {
01228                transition(Connected);
01229                mProposedLocalOfferAnswer.reset();
01230                mProposedEncryptionLevel = DialogUsageManager::None;
01232                mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
01233             }
01234             else if(mState == WaitingToOffer || 
01235                     mState == UAS_WaitingToOffer)
01236             {
01237                assert(mProposedLocalOfferAnswer.get());
01238                mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
01239                if(!isTerminated())  
01240                {
01241                   provideProposedOffer(); 
01242                }
01243             }
01244             else if(mState == WaitingToRequestOffer ||
01245                     mState == UAS_WaitingToRequestOffer)
01246             {
01247                mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
01248                if(!isTerminated())  
01249                {
01250                   requestOffer(); 
01251                }
01252             }
01253             else
01254             {
01255                // this is so the app can decided to ignore this. default implementation
01256                // will call end next
01257                mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
01258             }
01259          }
01260       }
01261    }
01262    else if (timeout.type() == DumTimeout::CanDiscardAck)
01263    {
01264       AckMap::iterator i = mAcks.find(timeout.transactionId());
01265       if (i != mAcks.end())
01266       {
01267          mAcks.erase(i);
01268       }
01269    }
01270    else if (timeout.type() == DumTimeout::Glare)
01271    {
01272       if (mState == SentUpdateGlare)
01273       {
01274          transition(SentUpdate);
01275 
01276          InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
01277          mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);  // increments CSeq
01278          send(mLastLocalSessionModification);
01279       }
01280       else if (mState == SentReinviteGlare)
01281       {
01282          transition(SentReinvite);
01283 
01284          InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
01285          mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
01286          startStaleReInviteTimer();
01287          send(mLastLocalSessionModification);
01288       }
01289       else if (mState == SentReinviteNoOfferGlare)
01290       {
01291          transition(SentReinviteNoOffer);
01292 
01293          InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
01294          mDialog.makeRequest(*mLastLocalSessionModification, INVITE);  // increments CSeq
01295          startStaleReInviteTimer();
01296          send(mLastLocalSessionModification);
01297       }
01298    }
01299    else if (timeout.type() == DumTimeout::StaleReInvite)
01300    {
01301       if(timeout.seq() == mStaleReInviteTimerSeq)
01302       {
01303          if(mState == WaitingToTerminate)
01304          {
01305             SharedPtr<SipMessage> msg = sendBye();
01306             transition(Terminated);
01307             mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get()); 
01308          }
01309          else if(mState == SentReinvite ||
01310                  mState == SentReinviteNoOffer)
01311          {
01312             transition(Connected);
01313             mProposedLocalOfferAnswer.reset();
01314             mProposedEncryptionLevel = DialogUsageManager::None;
01315 
01316             // this is so the app can decide to ignore this. default implementation
01317             // will call end next - which will send a BYE
01318             mDum.mInviteSessionHandler->onStaleReInviteTimeout(getSessionHandle());
01319          }
01320       }
01321    }
01322    else if (timeout.type() == DumTimeout::SessionExpiration)
01323    {
01324       if(timeout.seq() == mSessionTimerSeq)
01325       {
01326          // this is so the app can decide to ignore this. default implementation
01327          // will call end next - which will send a BYE
01328          mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
01329       }
01330    }
01331    else if (timeout.type() == DumTimeout::SessionRefresh)
01332    {
01333      if(timeout.seq() == mSessionTimerSeq)
01334      {
01335         // Note: If not connected then we must be issueing a reinvite/update or
01336         // receiving one - in either case the session timer stuff will get
01337         // reset/renegotiated - thus just ignore this referesh
01338         if(mState == Connected)  
01339         {
01340            sessionRefresh();
01341         }
01342      }
01343    }
01344 }
01345 
01346 void
01347 InviteSession::dispatchConnected(const SipMessage& msg)
01348 {
01349    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
01350    std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
01351 
01352    switch (toEvent(msg, offerAnswer.get()))
01353    {
01354       case OnInvite:
01355       case OnInviteReliable:
01356          *mLastRemoteSessionModification = msg;
01357          transition(ReceivedReinviteNoOffer);
01358          handler->onOfferRequired(getSessionHandle(), msg);
01359          break;
01360 
01361       case OnInviteOffer:
01362       case OnInviteReliableOffer:
01363          *mLastRemoteSessionModification = msg;
01364          transition(ReceivedReinvite);
01365          mCurrentEncryptionLevel = getEncryptionLevel(msg);
01366          mProposedRemoteOfferAnswer = offerAnswer; 
01367 
01368          handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
01369          break;
01370 
01371       case On2xx:
01372       case On2xxOffer:
01373       case On2xxAnswer:
01374          // retransmission of 200I
01375          // !jf! Need to include the answer here.
01376          sendAck(); 
01377          break;
01378 
01379       case OnUpdateOffer:
01380          transition(ReceivedUpdate);
01381 
01382          //  !kh!
01383          //  Find out if it's an UPDATE requiring state change.
01384          //  See rfc3311 5.2, 4th paragraph.
01385          *mLastRemoteSessionModification = msg;
01386          mCurrentEncryptionLevel = getEncryptionLevel(msg);
01387          mProposedRemoteOfferAnswer = offerAnswer; 
01388          handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
01389          break;
01390 
01391       case OnUpdate:
01392       {
01393          // ?slg? no offerAnswer in update - just respond immediately (likely session timer) - do we need a callback?
01394          SharedPtr<SipMessage> response(new SipMessage);
01395          *mLastRemoteSessionModification = msg;
01396          mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
01397          handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
01398          send(response);
01399          break;
01400       }
01401 
01402       case OnUpdateRejected:
01403       case On200Update:
01404          WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
01405          assert(0);
01406          break;
01407 
01408       case OnAck:
01409       case OnAckAnswer: // .bwc. Don't drop ACK with SDP!
01410          mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01411          handler->onAckReceived(getSessionHandle(), msg);
01412          break;
01413 
01414       default:
01415          dispatchOthers(msg);
01416          break;
01417    }
01418 }
01419 
01420 void
01421 InviteSession::dispatchSentUpdate(const SipMessage& msg)
01422 {
01423    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
01424    std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
01425 
01426    switch (toEvent(msg, offerAnswer.get()))
01427    {
01428       case OnInvite:
01429       case OnInviteReliable:
01430       case OnInviteOffer:
01431       case OnInviteReliableOffer:
01432       case OnUpdate:
01433       case OnUpdateOffer:
01434       {
01435          // glare
01436          SharedPtr<SipMessage> response(new SipMessage);
01437          mDialog.makeResponse(*response, msg, 491);
01438          send(response);
01439          break;
01440       }
01441 
01442       case On200Update:
01443          transition(Connected);
01444          handleSessionTimerResponse(msg);
01445          if (offerAnswer.get() && mProposedLocalOfferAnswer.get())
01446          {
01447             mCurrentEncryptionLevel = getEncryptionLevel(msg);
01448             setCurrentLocalOfferAnswer(msg);
01449 
01450             mCurrentRemoteOfferAnswer = offerAnswer; 
01451             handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
01452          }
01453          else if(mProposedLocalOfferAnswer.get()) 
01454          {
01455             // If we sent an offer in the Update Request and no answer is received
01456             handler->onIllegalNegotiation(getSessionHandle(), msg);
01457             mProposedLocalOfferAnswer.reset();
01458             mProposedEncryptionLevel = DialogUsageManager::None;
01459          }
01460          break;
01461 
01462       case On491Update:
01463          transition(SentUpdateGlare);
01464          start491Timer();
01465          break;
01466 
01467       case On422Update: // session timer
01468          if(msg.exists(h_MinSE))
01469          {
01470             // Change interval to min from 422 response
01471             mSessionInterval = msg.header(h_MinSE).value();
01472             mMinSE = mSessionInterval;
01473             sessionRefresh();
01474          }
01475          else
01476          {
01477             // Response must contain Min_SE - if not - just ignore
01478             // ?slg? callback?
01479             transition(Connected);
01480             mProposedLocalOfferAnswer.reset();
01481             mProposedEncryptionLevel = DialogUsageManager::None;
01482          }
01483          break;
01484 
01485       case OnUpdateRejected:
01486          transition(Connected);
01487          mProposedLocalOfferAnswer.reset();
01488          handler->onOfferRejected(getSessionHandle(), &msg);
01489          break;
01490 
01491       case OnGeneralFailure:
01492          sendBye();
01493          transition(Terminated);
01494          handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
01495          break;
01496 
01497       default:
01498          dispatchOthers(msg);
01499          break;
01500    }
01501 }
01502 
01503 void
01504 InviteSession::dispatchSentReinvite(const SipMessage& msg)
01505 {
01506    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
01507    std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
01508 
01509    switch (toEvent(msg, offerAnswer.get()))
01510    {
01511       case OnInvite:
01512       case OnInviteReliable:
01513       case OnInviteOffer:
01514       case OnInviteReliableOffer:
01515       case OnUpdate:
01516       case OnUpdateOffer:
01517       {
01518          SharedPtr<SipMessage> response(new SipMessage);
01519          mDialog.makeResponse(*response, msg, 491);
01520          send(response);
01521          break;
01522       }
01523 
01524       case On1xx:
01525       case On1xxEarly:
01526          // Some UA's send a 100 response to a ReInvite - just ignore it
01527          break;
01528 
01529       case On2xxAnswer:
01530       case On2xxOffer:  // .slg. doesn't really make sense
01531       {
01532          mStaleReInviteTimerSeq++;
01533          transition(Connected);
01534          handleSessionTimerResponse(msg);
01535          setCurrentLocalOfferAnswer(msg);
01536 
01537          // !jf! I need to potentially include an answer in the ACK here
01538          sendAck();
01539          mCurrentEncryptionLevel = getEncryptionLevel(msg);
01540          
01541          if (mSessionRefreshReInvite)
01542          {
01543             mSessionRefreshReInvite = false;
01544          
01545             MD5Stream currentRemote;
01546             currentRemote<< *mCurrentRemoteOfferAnswer;
01547             MD5Stream newRemote;
01548             newRemote << *offerAnswer;
01549             bool changed = currentRemote.getHex() != newRemote.getHex();
01550 
01551             if (changed)
01552             {
01553                mCurrentRemoteOfferAnswer = offerAnswer; 
01554                handler->onRemoteAnswerChanged(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
01555             }
01556          }
01557          else
01558          {
01559             mCurrentRemoteOfferAnswer = offerAnswer; 
01560             handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
01561          }
01562          
01563          // !jf! do I need to allow a reINVITE overlapping the retransmission of
01564          // the ACK when a 200I is received? If yes, then I need to store all
01565          // ACK messages for 64*T1
01566          break;
01567       }
01568       case On2xx:
01569          mStaleReInviteTimerSeq++;
01570          sendAck();
01571          transition(Connected);
01572          handleSessionTimerResponse(msg);
01573          handler->onIllegalNegotiation(getSessionHandle(), msg);
01574          mProposedLocalOfferAnswer.reset();
01575          mProposedEncryptionLevel = DialogUsageManager::None;
01576          break;
01577 
01578       case On422Invite:
01579          mStaleReInviteTimerSeq++;
01580          if(msg.exists(h_MinSE))
01581          {
01582             // Change interval to min from 422 response
01583             mSessionInterval = msg.header(h_MinSE).value();
01584             mMinSE = mSessionInterval;
01585             sessionRefresh();
01586          }
01587          else
01588          {
01589             // Response must contact Min_SE - if not - just ignore
01590             // ?slg? callback?
01591             transition(Connected);
01592             mProposedLocalOfferAnswer.reset();
01593             mProposedEncryptionLevel = DialogUsageManager::None;
01594          }
01595          break;
01596 
01597       case On491Invite:
01598          mStaleReInviteTimerSeq++;
01599          transition(SentReinviteGlare);
01600          start491Timer();
01601          break;
01602 
01603       case OnGeneralFailure:
01604          mStaleReInviteTimerSeq++;
01605          sendBye();
01606          transition(Terminated);
01607          handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
01608          break;
01609 
01610       case OnInviteFailure:
01611       case On487Invite:
01612          mStaleReInviteTimerSeq++;
01613          transition(Connected);
01614          mProposedLocalOfferAnswer.reset();
01615          handler->onOfferRejected(getSessionHandle(), &msg);
01616          break;
01617 
01618       default:
01619          dispatchOthers(msg);
01620          break;
01621    }
01622 }
01623 
01624 void
01625 InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
01626 {
01627    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
01628    std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
01629 
01630    switch (toEvent(msg, offerAnswer.get()))
01631    {
01632       case OnInvite:
01633       case OnInviteReliable:
01634       case OnInviteOffer:
01635       case OnInviteReliableOffer:
01636       case OnUpdate:
01637       case OnUpdateOffer:
01638       {
01639          SharedPtr<SipMessage> response(new SipMessage);
01640          mDialog.makeResponse(*response, msg, 491);
01641          send(response);
01642          break;
01643       }
01644 
01645       case On1xx:
01646       case On1xxEarly:
01647          // Some UA's send a 100 response to a ReInvite - just ignore it
01648          break;
01649 
01650       case On2xxAnswer:  // .slg. doesn't really make sense
01651       case On2xxOffer:
01652       {
01653          mStaleReInviteTimerSeq++;
01654          transition(SentReinviteAnswered);
01655          handleSessionTimerResponse(msg);
01656          // mLastSessionModification = msg;   // ?slg? why are we storing 200's?
01657          mCurrentEncryptionLevel = getEncryptionLevel(msg);
01658          mProposedRemoteOfferAnswer = offerAnswer; 
01659          handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
01660          break;
01661       }
01662 
01663       case On2xx:
01664          mStaleReInviteTimerSeq++;
01665          sendAck();
01666          transition(Connected);
01667          handleSessionTimerResponse(msg);
01668          handler->onIllegalNegotiation(getSessionHandle(), msg);
01669          mProposedLocalOfferAnswer.reset();
01670          mProposedEncryptionLevel = DialogUsageManager::None;
01671          break;
01672 
01673       case On422Invite:
01674          mStaleReInviteTimerSeq++;
01675          if(msg.exists(h_MinSE))
01676          {
01677             // Change interval to min from 422 response
01678             mSessionInterval = msg.header(h_MinSE).value();
01679             mMinSE = mSessionInterval;
01680             sessionRefresh();
01681          }
01682          else
01683          {
01684             // Response must contact Min_SE - if not - just ignore
01685             // ?slg? callback?
01686             transition(Connected);
01687             mProposedLocalOfferAnswer.reset();
01688             mProposedEncryptionLevel = DialogUsageManager::None;
01689          }
01690          break;
01691 
01692       case On491Invite:
01693          mStaleReInviteTimerSeq++;
01694          transition(SentReinviteNoOfferGlare);
01695          start491Timer();
01696          break;
01697 
01698       case OnGeneralFailure:
01699          mStaleReInviteTimerSeq++;
01700          sendBye();
01701          transition(Terminated);
01702          handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
01703          break;
01704 
01705       case OnInviteFailure:
01706       case On487Invite:
01707          mStaleReInviteTimerSeq++;
01708          transition(Connected);
01709          mProposedLocalOfferAnswer.reset();
01710          handler->onOfferRejected(getSessionHandle(), &msg);
01711          break;
01712 
01713       default:
01714          dispatchOthers(msg);
01715          break;
01716    }
01717 }
01718 
01719 void 
01720 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
01721 {
01722    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
01723    std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
01724 
01725    switch (toEvent(msg, offerAnswer.get()))
01726    {
01727       case OnInvite:
01728       case OnInviteReliable:
01729       case OnInviteOffer:
01730       case OnInviteReliableOffer:
01731       case OnUpdate:
01732       case OnUpdateOffer:
01733       {
01734          SharedPtr<SipMessage> response(new SipMessage);
01735          mDialog.makeResponse(*response, msg, 491);
01736          send(response);
01737          break;
01738       }
01739       case OnAckAnswer:
01740          transition(Connected);
01741          setCurrentLocalOfferAnswer(msg);
01742          mCurrentRemoteOfferAnswer = offerAnswer; 
01743          mCurrentEncryptionLevel = getEncryptionLevel(msg);
01744          mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01745 
01746          handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
01747          break;         
01748       case OnAck:
01749          if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
01750          {
01751             InfoLog(<< "dropped stale ACK");
01752          }
01753          else
01754          {
01755             InfoLog(<< "Got Ack with no answer");
01756             transition(Connected);
01757             mProposedLocalOfferAnswer.reset();
01758             mProposedEncryptionLevel = DialogUsageManager::None;
01759             mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01761             handler->onOfferRejected(getSessionHandle(), &msg);
01762          }
01763          break;
01764       default:
01765          dispatchOthers(msg);
01766          break;
01767    }
01768 }
01769 
01770 void
01771 InviteSession::dispatchGlare(const SipMessage& msg)
01772 {
01773    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
01774    MethodTypes method = msg.header(h_CSeq).method();
01775    if (msg.isRequest() && (method == INVITE || method == UPDATE))
01776    {
01777       DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
01778       // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
01779       handler->onOfferRejected(getSessionHandle(), &msg);
01780       if(!isTerminated())   // make sure application didn't call end()
01781       {
01782          dispatchConnected(msg);  // act as if we received message in Connected state
01783       }
01784       else
01785       {
01786          dispatchTerminated(msg);
01787       }
01788    }
01789    else
01790    {
01791       dispatchOthers(msg);
01792    }
01793 }
01794 
01795 void
01796 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
01797 {
01798    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
01799    MethodTypes method = msg.header(h_CSeq).method();
01800    if (msg.isRequest() && (method == INVITE || method == UPDATE))
01801    {
01802       // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
01803       handler->onOfferRequestRejected(getSessionHandle(), msg);
01804       if(!isTerminated())   // make sure application didn't call end()
01805       {
01806          dispatchConnected(msg);  // act as if we received message in Connected state
01807       }
01808       else
01809       {
01810          dispatchTerminated(msg);
01811       }
01812    }
01813    else
01814    {
01815       dispatchOthers(msg);
01816    }
01817 }
01818 
01819 void
01820 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
01821 {
01822    // InviteSessionHandler* handler = mDum.mInviteSessionHandler; // unused
01823    std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
01824 
01825    switch (toEvent(msg, offerAnswer.get()))
01826    {
01827       case OnInvite:
01828       case OnInviteReliable:
01829       case OnInviteOffer:
01830       case OnInviteReliableOffer:
01831       case OnUpdate:
01832       case OnUpdateOffer:
01833       {
01834          // Means that the UAC has sent us a second reINVITE or UPDATE before we
01835          // responded to the first one. Bastard!
01836          SharedPtr<SipMessage> response(new SipMessage);
01837          mDialog.makeResponse(*response, msg, 500);
01838          response->header(h_RetryAfter).value() = Random::getRandom() % 10;
01839          send(response);
01840          break;
01841       }
01842       case OnBye:
01843       {
01844          // BYE received after a reINVITE, terminate the reINVITE transaction.
01845          SharedPtr<SipMessage> response(new SipMessage);
01846          mDialog.makeResponse(*response, *mLastRemoteSessionModification, 487); // Request Terminated
01847          handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
01848          send(response);
01849 
01850          dispatchBye(msg);
01851          break;
01852       }
01853       default:
01854          dispatchOthers(msg);
01855          break;
01856    }
01857 }
01858 
01859 
01860 void
01861 InviteSession::dispatchAnswered(const SipMessage& msg)
01862 {
01863    if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
01864    {
01865       mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01866       transition(Connected);
01867    }
01868    else
01869    {
01870       dispatchOthers(msg);
01871    }
01872 }
01873 
01874 void
01875 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
01876 {
01877    if (msg.isResponse() &&
01878        msg.header(h_CSeq).method() == INVITE &&
01879        msg.header(h_StatusLine).statusCode() / 200 == 1)
01880    {
01881       // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
01882       // called by the app - so just drop the retransmission
01883       return;
01884    }
01885    dispatchOthers(msg);
01886 }
01887 
01888 void
01889 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
01890 {
01891    if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
01892    {
01893       assert(mProposedLocalOfferAnswer.get());
01894       mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01895       provideProposedOffer(); 
01896    }
01897    else
01898    {
01899       dispatchOthers(msg);
01900    }
01901 }
01902 
01903 void
01904 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
01905 {
01906    if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
01907    {
01908       mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01909       requestOffer(); 
01910    }
01911    else
01912    {
01913       dispatchOthers(msg);
01914    }
01915 }
01916 
01917 void
01918 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
01919 {
01920    if (msg.isResponse() &&
01921        msg.header(h_CSeq).method() == INVITE)
01922    {
01923       if(msg.header(h_StatusLine).statusCode() / 200 == 1)  // Note: stack ACK's non-2xx final responses only
01924       {
01925          // !jf! Need to include the answer here.
01926          sendAck();
01927       }
01928       SharedPtr<SipMessage> msg = sendBye();
01929       transition(Terminated);
01930       mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get()); 
01931    }
01932    else if(msg.isRequest())
01933    {
01934       if(msg.method() == BYE)
01935       {
01936          dispatchBye(msg);
01937       }
01938       else
01939       {
01940          SharedPtr<SipMessage> response(new SipMessage);
01941          mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
01942          send(response);
01943       }
01944    }
01945 }
01946 
01947 void
01948 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
01949 {
01950    std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
01951 
01952    switch (toEvent(msg, offerAnswer.get()))
01953    {
01954       case OnAck:
01955       case OnAckAnswer:
01956       {
01957          mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
01958 
01959          SharedPtr<SipMessage> msg = sendBye();
01960          transition(Terminated);
01961          mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
01962          break;
01963       }
01964       
01965       default:
01966          break;
01967    }
01968 }
01969 
01970 void
01971 InviteSession::dispatchTerminated(const SipMessage& msg)
01972 {
01973    InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
01974 
01975    if (msg.isRequest())
01976    {
01977       if (BYE == msg.header(h_CSeq).method())
01978       {
01979          SharedPtr<SipMessage> response(new SipMessage);
01980          mDialog.makeResponse(*response, msg, 200);
01981          send(response);
01982       }
01983       else
01984       {
01985          SharedPtr<SipMessage> response(new SipMessage);
01986          mDialog.makeResponse(*response, msg, 481);
01987          send(response);
01988       }
01989 
01990       // !jf! means the peer sent BYE while we are waiting for response to BYE
01991       //mDum.destroy(this);
01992    }
01993    else
01994    {
01995       mDum.destroy(this);
01996    }
01997 }
01998 
01999 void
02000 InviteSession::dispatchOthers(const SipMessage& msg)
02001 {
02002    // handle OnGeneralFailure
02003    // handle OnRedirect
02004 
02005    switch (msg.header(h_CSeq).method())
02006    {
02007       case PRACK:
02008          dispatchPrack(msg);
02009          break;
02010       case CANCEL:
02011          dispatchCancel(msg);
02012          break;
02013       case BYE:
02014          dispatchBye(msg);
02015          break;
02016       case INFO:
02017          dispatchInfo(msg);
02018          break;
02019       case MESSAGE:
02020          dispatchMessage(msg);
02021          break;
02022           case ACK:
02023                   // Ignore duplicate ACKs from 2xx reTransmissions
02024                   break;
02025       default:
02026          // handled in Dialog
02027          WarningLog (<< "DUM delivered a "
02028                      << msg.header(h_CSeq).unknownMethodName()
02029                      << " to the InviteSession in state: " << toData(mState)
02030                      << endl
02031                      << msg);
02032          assert(0);
02033          break;
02034    }
02035 }
02036 
02037 void
02038 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
02039 {
02040    assert(msg.isRequest());
02041    assert(msg.header(h_CSeq).method() == INVITE);
02042 
02043    // If we get an INVITE request from the wire and we are not in
02044    // Connected state, reject the request and send a BYE
02045    SharedPtr<SipMessage> response(new SipMessage);
02046    mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
02047    InfoLog (<< "Sending " << response->brief());
02048    send(response);
02049 
02050    sendBye();
02051    transition(Terminated);
02052    mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg); 
02053 }
02054 
02055 void
02056 InviteSession::dispatchPrack(const SipMessage& msg)
02057 {
02058    assert(msg.header(h_CSeq).method() == PRACK);
02059    if(msg.isRequest())
02060    {
02061       SharedPtr<SipMessage> rsp(new SipMessage);
02062       mDialog.makeResponse(*rsp, msg, 481);
02063       send(rsp);
02064 
02065       sendBye();
02066       // !jf! should we make some other callback here
02067       transition(Terminated);
02068       mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
02069    }
02070    else
02071    {
02072       // ignore. could be PRACK/200
02073    }
02074 }
02075 
02076 void
02077 InviteSession::dispatchCancel(const SipMessage& msg)
02078 {
02079    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
02080    assert(msg.header(h_CSeq).method() == CANCEL);
02081    if(msg.isRequest())
02082    {
02083       SharedPtr<SipMessage> rsp(new SipMessage);
02084       mDialog.makeResponse(*rsp, msg, 200);
02085       send(rsp);
02086 
02087       sendBye();
02088       // !jf! should we make some other callback here
02089       transition(Terminated);
02090 
02091       handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteCancel, &msg);
02092    }
02093    else
02094    {
02095       WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
02096       assert(0);
02097    }
02098 }
02099 
02100 void
02101 InviteSession::dispatchBye(const SipMessage& msg)
02102 {
02103    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
02104 
02105    if (msg.isRequest())
02106    {
02107       // Check for any non-invite server transactions (e.g. INFO)
02108       // that have not been responded yet and terminate them.
02109       if (mServerNitState == NitProceeding)
02110       {
02111          mLastNitResponse->header(h_StatusLine).statusCode() = 487;  
02112          mLastNitResponse->setContents(0);
02113          Helper::getResponseCodeReason(487, mLastNitResponse->header(h_StatusLine).reason());
02114          send(mLastNitResponse);
02115          mServerNitState = NitComplete;
02116       }
02117 
02118       SharedPtr<SipMessage> rsp(new SipMessage);
02119       InfoLog (<< "Received " << msg.brief());
02120       mDialog.makeResponse(*rsp, msg, 200);
02121       send(rsp);
02122 
02123       // !jf! should we make some other callback here
02124       transition(Terminated);
02125 
02126       if (mDum.mDialogEventStateManager)
02127       {
02128          mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::RemoteBye);
02129       }
02130 
02131       handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
02132       mDum.destroy(this);
02133    }
02134    else
02135    {
02136       WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
02137       assert(0);
02138    }
02139 }
02140 
02141 void
02142 InviteSession::dispatchInfo(const SipMessage& msg)
02143 {
02144    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
02145    if (msg.isRequest())
02146    {
02147       if (mServerNitState == NitProceeding)
02148       {
02149          // Means that the UAC has sent us a second INFO before we
02150          // responded to the first one.
02151          SharedPtr<SipMessage> response(new SipMessage);
02152          mDialog.makeResponse(*response, msg, 500);
02153          response->header(h_RetryAfter).value() = Random::getRandom() % 10;
02154          send(response);
02155       }
02156       else
02157       {
02158          InfoLog (<< "Received " << msg.brief());
02159          mServerNitState = NitProceeding;
02160          mDialog.makeResponse(*mLastNitResponse, msg, 200);
02161          handler->onInfo(getSessionHandle(), msg);
02162       }
02163    }
02164    else
02165    {
02166       assert(mNitState == NitProceeding);
02168       if (msg.header(h_StatusLine).statusCode() >= 300)
02169       {
02170          handler->onInfoFailure(getSessionHandle(), msg);
02171       }
02172       else if (msg.header(h_StatusLine).statusCode() >= 200)
02173       {
02174          handler->onInfoSuccess(getSessionHandle(), msg);
02175       }
02176       nitComplete();
02177    }
02178 }
02179 
02180 void
02181 InviteSession::acceptNIT(int statusCode, const Contents * contents)
02182 {
02183    if (statusCode / 100  != 2)
02184    {
02185       throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
02186    }
02187 
02188    if (mServerNitState != NitProceeding )
02189    {
02190       throw UsageUseException("No transaction to accept", __FILE__, __LINE__);
02191    }
02192 
02193    mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;   
02194    mLastNitResponse->setContents(contents);
02195    Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
02196    send(mLastNitResponse);   
02197    mServerNitState = NitComplete;
02198 } 
02199 
02200 class InviteSessionAcceptNITCommand : public DumCommandAdapter
02201 {
02202 public:
02203    InviteSessionAcceptNITCommand(InviteSession& inviteSession, int statusCode, const Contents* contents)
02204       : mInviteSession(inviteSession),
02205         mStatusCode(statusCode),
02206         mContents(contents?contents->clone():0)
02207    {
02208 
02209    }
02210 
02211    virtual void executeCommand()
02212    {
02213       mInviteSession.acceptNITCommand(mStatusCode, mContents.get());
02214    }
02215 
02216    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
02217    {
02218       return strm << "InviteSessionAcceptNITCommand";
02219    }
02220 private:
02221    InviteSession& mInviteSession;
02222    int mStatusCode;
02223    std::auto_ptr<Contents> mContents;
02224 };
02225 
02226 void
02227 InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
02228 {
02229    mDum.post(new InviteSessionAcceptNITCommand(*this, statusCode, contents));
02230 } 
02231 
02232 void
02233 InviteSession::rejectNIT(int statusCode)
02234 {
02235    if (statusCode < 400)
02236    {
02237       throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
02238    }
02239 
02240    if (mServerNitState != NitProceeding )
02241    {
02242       throw UsageUseException("No transaction to reject", __FILE__, __LINE__);
02243    }
02244 
02245    mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;  
02246    mLastNitResponse->setContents(0);
02247    Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
02248    send(mLastNitResponse);
02249    mServerNitState = NitComplete;
02250 }
02251 
02252 class InviteSessionRejectNITCommand : public DumCommandAdapter
02253 {
02254 public:
02255    InviteSessionRejectNITCommand(InviteSession& inviteSession, int statusCode)
02256       : mInviteSession(inviteSession),
02257       mStatusCode(statusCode)
02258    {
02259    }
02260 
02261    virtual void executeCommand()
02262    {
02263       mInviteSession.rejectNITCommand(mStatusCode);
02264    }
02265 
02266    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
02267    {
02268       return strm << "InviteSessionRejectNITCommand";
02269    }
02270 private:
02271    InviteSession& mInviteSession;
02272    int mStatusCode;
02273 };
02274 
02275 void
02276 InviteSession::rejectNITCommand(int statusCode)
02277 {
02278    mDum.post(new InviteSessionRejectNITCommand(*this, statusCode));
02279 }
02280 
02281 void
02282 InviteSession::dispatchMessage(const SipMessage& msg)
02283 {
02284    InviteSessionHandler* handler = mDum.mInviteSessionHandler;
02285    if (msg.isRequest())
02286    {
02287       if (mServerNitState == NitProceeding)
02288       {
02289          // Means that the UAC has sent us a second NIT message before we
02290          // responded to the first one.
02291          SharedPtr<SipMessage> response(new SipMessage);
02292          mDialog.makeResponse(*response, msg, 500);
02293          response->header(h_RetryAfter).value() = Random::getRandom() % 10;
02294          send(response);
02295       }
02296       else
02297       {
02298          InfoLog (<< "Received " << msg.brief());
02299          mServerNitState = NitProceeding;
02300          mDialog.makeResponse(*mLastNitResponse, msg, 200);
02301          mLastNitResponse->header(h_Contacts).clear();
02302          handler->onMessage(getSessionHandle(), msg);
02303       }
02304    }
02305    else
02306    {
02307       assert(mNitState == NitProceeding);
02309       if (msg.header(h_StatusLine).statusCode() >= 300)
02310       {
02311          handler->onMessageFailure(getSessionHandle(), msg);
02312       }
02313       else if (msg.header(h_StatusLine).statusCode() >= 200)
02314       {
02315          handler->onMessageSuccess(getSessionHandle(), msg);
02316       }
02317       nitComplete();
02318    }
02319 }
02320 
02321 void
02322 InviteSession::startRetransmit200Timer()
02323 {
02324    mCurrentRetransmit200 = Timer::T1;
02325    unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
02326    mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
02327    mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
02328 }
02329 
02330 // RFC3261 section 14.1
02331 // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
02332 // a value T chosen as follows:
02333 //  1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
02334 //  chosen value between 2.1 and 4 seconds in units of 10 ms.
02335 //  2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
02336 //  randomly chosen value of between 0 and 2 seconds in units of 10 ms.
02337 void
02338 InviteSession::start491Timer()
02339 {
02340    unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
02341 
02342    if (dynamic_cast<ClientInviteSession*>(this))
02343    {
02344       int timer = Random::getRandom() % (4000 - 2100);
02345       timer += 2100;
02346       timer -= timer % 10;
02347       
02348       DebugLog(<< "491 timer value: " << timer << "ms" << endl);
02349       mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
02350    }
02351    else
02352    {
02353       int timer = Random::getRandom() % 2000;
02354       timer -= timer % 10;
02355       DebugLog(<< "491 timer value: " << timer << "ms" << endl);
02356       mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
02357    }
02358 }
02359 
02360 void 
02361 InviteSession::startStaleReInviteTimer()
02362 {
02363    InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
02364    unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
02365    
02366    mDum.addTimer(DumTimeout::StaleReInvite, 
02367                  when, 
02368                  getBaseHandle(), 
02369                  ++mStaleReInviteTimerSeq);
02370 }
02371 
02372 void 
02373 InviteSession::setSessionTimerHeaders(SipMessage &msg)
02374 {
02375    if(mSessionInterval >= 90)  // If mSessionInterval is 0 then SessionTimers are considered disabled
02376    {
02377       msg.header(h_SessionExpires).value() = mSessionInterval;
02378       if(msg.isRequest())
02379       {
02380          msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
02381       }
02382       else
02383       {
02384          msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
02385       }
02386       msg.header(h_MinSE).value() = mMinSE;
02387    }
02388    else
02389    {
02390       msg.remove(h_SessionExpires);
02391       msg.remove(h_MinSE);
02392    }
02393 }
02394 
02395 void
02396 InviteSession::sessionRefresh()
02397 {
02398    if (updateMethodSupported())
02399    {
02400       transition(SentUpdate);
02401       mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
02402       mLastLocalSessionModification->setContents(0);  // Don't send SDP
02403    }
02404    else
02405    {
02406       transition(SentReinvite);
02407       mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
02408       startStaleReInviteTimer();
02409       InviteSession::setOfferAnswer(*mLastLocalSessionModification, mCurrentLocalOfferAnswer.get());
02410       mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(*mCurrentLocalOfferAnswer.get(), 0);
02411       mSessionRefreshReInvite = true;      
02412    }
02413    setSessionTimerHeaders(*mLastLocalSessionModification);
02414 
02415    InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
02416    DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
02417    send(mLastLocalSessionModification);
02418 }
02419 
02420 void
02421 InviteSession::setSessionTimerPreferences()
02422 {
02423    mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime();  // Used only if remote doesn't request a time
02424    if(mSessionInterval != 0)
02425    {
02426        // If session timers are no disabled then ensure interval is greater than or equal to MinSE
02427        mSessionInterval = resipMax(mMinSE, mSessionInterval);
02428    }
02429    switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
02430    {
02431    case Profile::PreferLocalRefreshes:
02432       mSessionRefresher = true;   // Default refresher is Local
02433       break;
02434    case Profile::PreferRemoteRefreshes:
02435       mSessionRefresher = false;  // Default refresher is Remote
02436       break;
02437    case Profile::PreferCalleeRefreshes:  
02438       mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is callee
02439       break;
02440    case Profile::PreferCallerRefreshes:
02441       mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is caller
02442       break;
02443    }
02444 }
02445 
02446 void
02447 InviteSession::startSessionTimer()
02448 {
02449    if(mSessionInterval >= 90)  // 90 is the absolute minimum - RFC4028
02450    {
02451       // Check if we are the refresher
02452       if(mSessionRefresher)
02453       {
02454          // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
02455          mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
02456       }
02457       else
02458       {
02459          // Start Session-Expiration Timer to mSessionInterval - BYE should be sent a minimum of 32 and one third of the SessionInterval, seconds before the session expires (recommended by RFC4028)
02460          mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
02461       }
02462    }
02463    else  // Session Interval less than 90 - consider timers disabled
02464    {
02465        ++mSessionTimerSeq;  // increment seq, incase old timers are running and now session timers are disabled
02466    }
02467 }
02468 
02469 void
02470 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
02471 {
02472    assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
02473 
02474    // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
02475    if (msg.exists(h_PAssertedIdentities))
02476    {
02477        mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
02478    }
02479 
02480    // If session timers are locally supported then handle response
02481    if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
02482    {
02483       setSessionTimerPreferences();
02484 
02485       if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
02486          && !msg.exists(h_SessionExpires))
02487       {
02488          // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
02489          mSessionInterval = 0;
02490       }
02491       // Process Session Timer headers
02492       else if(msg.exists(h_SessionExpires))
02493       {
02494          mSessionInterval = msg.header(h_SessionExpires).value();
02495          if(msg.header(h_SessionExpires).exists(p_refresher))
02496          {
02497              // Remote end specified refresher preference
02498              mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
02499          }
02500       }
02501       else
02502       {
02503          // Note:  If no Requires or Session-Expires, then UAS does not support Session Timers
02504          // - we are free to use our SessionInterval settings (set above as a default)
02505          // If far end doesn't support then refresher must be local
02506          mSessionRefresher = true;
02507       }
02508 
02509       // Update MinSE if specified and longer than current value
02510       if(msg.exists(h_MinSE))
02511       {
02512           mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
02513       }
02514 
02515       startSessionTimer();
02516    }
02517 }
02518 
02519 void
02520 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
02521 {
02522    assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
02523 
02524    // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
02525    if (request.exists(h_PAssertedIdentities))
02526    {
02527        mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
02528    }
02529 
02530    // If session timers are locally supported then add necessary headers to response
02531    if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
02532    {
02533       setSessionTimerPreferences();
02534 
02535       // Check if far-end supports
02536       bool farEndSupportsTimer = false;
02537       if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
02538       {
02539          farEndSupportsTimer = true;
02540          if(request.exists(h_SessionExpires))
02541          {
02542             // Use Session Interval requested by remote - if none then use local settings
02543             mSessionInterval = request.header(h_SessionExpires).value();
02544             if(request.header(h_SessionExpires).exists(p_refresher))
02545             {
02546                 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
02547             }
02548          }
02549 
02550          // Update MinSE if specified and longer than current value
02551          if(request.exists(h_MinSE))
02552          {
02553              mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
02554          }
02555       }
02556       else
02557       {
02558          // If far end doesn't support then refresher must be local
02559          mSessionRefresher = true;
02560       }
02561 
02562       // Add Session-Expires to response if required
02563       if(mSessionInterval >= 90)
02564       {
02565          if(farEndSupportsTimer)
02566          {
02567             // If far end supports session-timer then require it, if not already present
02568             if(!response.header(h_Requires).find(Token(Symbols::Timer)))
02569             {
02570                 response.header(h_Requires).push_back(Token(Symbols::Timer));
02571             }
02572          }
02573          setSessionTimerHeaders(response);
02574       }
02575 
02576       startSessionTimer();
02577    }
02578 }
02579 
02580 Data
02581 InviteSession::toData(State state)
02582 {
02583    switch (state)
02584    {
02585       case Undefined:
02586          return "InviteSession::Undefined";
02587       case Connected:
02588          return "InviteSession::Connected";
02589       case SentUpdate:
02590          return "InviteSession::SentUpdate";
02591       case SentUpdateGlare:
02592          return "InviteSession::SentUpdateGlare";
02593       case SentReinvite:
02594          return "InviteSession::SentReinvite";
02595       case SentReinviteGlare:
02596          return "InviteSession::SentReinviteGlare";
02597       case SentReinviteNoOffer:
02598          return "InviteSession::SentReinviteNoOffer";
02599       case SentReinviteAnswered:
02600          return "InviteSession::SentReinviteAnswered";
02601       case SentReinviteNoOfferGlare:
02602          return "InviteSession::SentReinviteNoOfferGlare";
02603       case ReceivedUpdate:
02604          return "InviteSession::ReceivedUpdate";
02605       case ReceivedReinvite:
02606          return "InviteSession::ReceivedReinvite";
02607       case ReceivedReinviteNoOffer:
02608          return "InviteSession::ReceivedReinviteNoOffer";
02609           case ReceivedReinviteSentOffer:
02610                   return "InviteSession::ReceivedReinviteSentOffer";
02611       case Answered:
02612          return "InviteSession::Answered";
02613       case WaitingToOffer:
02614          return "InviteSession::WaitingToOffer";
02615       case WaitingToRequestOffer:
02616          return "InviteSession::WaitingToRequestOffer";
02617       case WaitingToTerminate:
02618          return "InviteSession::WaitingToTerminate";
02619       case WaitingToHangup:
02620          return "InviteSession::WaitingToHangup";
02621       case Terminated:
02622          return "InviteSession::Terminated";
02623 
02624       case UAC_Start:
02625          return "UAC_Start";
02626       case UAS_Offer:
02627          return "UAS_Offer";
02628       case UAS_OfferProvidedAnswer:
02629          return "UAS_OfferProvidedAnswer";
02630       case UAS_EarlyOffer:
02631          return "UAS_EarlyOffer";
02632       case UAS_EarlyProvidedAnswer:
02633          return "UAS_EarlyProvidedAnswer";
02634       case UAS_NoOffer:
02635          return "UAS_NoOffer";
02636       case UAS_ProvidedOffer:
02637          return "UAS_ProvidedOffer";
02638       case UAS_EarlyNoOffer:
02639          return "UAS_EarlyNoOffer";
02640       case UAS_EarlyProvidedOffer:
02641          return "UAS_EarlyProvidedOffer";
02642       case UAS_Accepted:
02643          return "UAS_Accepted";
02644       case UAS_WaitingToOffer:
02645          return "UAS_WaitingToOffer";
02646       case UAS_AcceptedWaitingAnswer:
02647          return "UAS_AcceptedWaitingAnswer";
02648       case UAC_Early:
02649          return "UAC_Early";
02650       case UAC_EarlyWithOffer:
02651          return "UAC_EarlyWithOffer";
02652       case UAC_EarlyWithAnswer:
02653          return "UAC_EarlyWithAnswer";
02654       case UAC_Answered:
02655          return "UAC_Answered";
02656       case UAC_SentUpdateEarly:
02657          return "UAC_SentUpdateEarly";
02658       case UAC_SentUpdateEarlyGlare:
02659          return "UAC_SentUpdateEarlyGlare";
02660       case UAC_ReceivedUpdateEarly:
02661          return "UAC_ReceivedUpdateEarly";
02662       case UAC_SentAnswer:
02663          return "UAC_SentAnswer";
02664       case UAC_QueuedUpdate:
02665          return "UAC_QueuedUpdate";
02666       case UAC_Cancelled:
02667          return "UAC_Cancelled";
02668          
02669       case UAS_Start:
02670          return "UAS_Start";
02671       case UAS_ReceivedOfferReliable:
02672          return "UAS_ReceivedOfferReliable";
02673       case UAS_NoOfferReliable:
02674          return "UAS_NoOfferReliable";
02675       case UAS_FirstSentOfferReliable:
02676          return "UAS_FirstSentOfferReliable";
02677       case UAS_FirstSentAnswerReliable:
02678          return "UAS_FirstSentAnswerReliable";
02679       case UAS_NegotiatedReliable:
02680          return "UAS_NegotiatedReliable";
02681       case UAS_SentUpdate:
02682          return "UAS_SentUpdate";
02683       case UAS_SentUpdateAccepted:
02684          return "UAS_SentUpdateAccepted";
02685       case UAS_ReceivedUpdate:
02686          return "UAS_ReceivedUpdate";
02687       case UAS_ReceivedUpdateWaitingAnswer:
02688          return "UAS_ReceivedUpdateWaitingAnswer";
02689       case UAS_WaitingToTerminate:
02690          return "UAS_WaitingToTerminate";
02691       case UAS_WaitingToHangup:
02692          return "UAS_WaitingToHangup";
02693       case UAS_WaitingToRequestOffer:
02694          return "UAS_WaitingToRequestOffer";
02695    }
02696    assert(0);
02697    return "Undefined";
02698 }
02699 
02700 
02701 void
02702 InviteSession::transition(State target)
02703 {
02704    InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
02705    mState = target;
02706 }
02707 
02708 bool
02709 InviteSession::isReliable(const SipMessage& msg)
02710 {
02711    if(msg.method() != INVITE)
02712    {
02713       return false;
02714    }
02715    if(msg.isRequest())
02716    {
02717       return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never
02718          && ((msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)))
02719              || (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
02720    }
02721    else
02722    {
02723       return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never
02724          && msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel));
02725    }
02726 }
02727 
02728 //static std::auto_ptr<SdpContents> emptySdp;
02729 std::auto_ptr<Contents>
02730 InviteSession::getOfferAnswer(const SipMessage& msg)
02731 {
02732         if(mDum.mInviteSessionHandler->isGenericOfferAnswer())   
02733    {
02734       if(msg.getContents())
02735       {
02736          return std::auto_ptr<Contents>(msg.getContents()->clone());
02737       }
02738       else
02739       {
02740          return std::auto_ptr<Contents>();
02741       }
02742    }
02743    else
02744    {
02745       return std::auto_ptr<Contents>(Helper::getSdp(msg.getContents()));
02746    }
02747 }
02748 
02749 std::auto_ptr<Contents>
02750 InviteSession::makeOfferAnswer(const Contents& offerAnswer)
02751 {
02752    return std::auto_ptr<Contents>(static_cast<Contents*>(offerAnswer.clone()));
02753 }
02754 
02755 auto_ptr<Contents>
02756 InviteSession::makeOfferAnswer(const Contents& offerAnswer,
02757                                const Contents* alternative)
02758 {
02759    if (alternative)
02760    {
02761       MultipartAlternativeContents* mac = new MultipartAlternativeContents;
02762       mac->parts().push_back(alternative->clone());
02763       mac->parts().push_back(offerAnswer.clone());
02764       return auto_ptr<Contents>(mac);
02765    }
02766    else
02767    {
02768       return auto_ptr<Contents>(offerAnswer.clone());
02769    }
02770 }
02771 
02772 void
02773 InviteSession::setOfferAnswer(SipMessage& msg, const Contents& offerAnswer, const Contents* alternative)
02774 {
02775    // !jf! should deal with multipart here
02776 
02777    // This will clone the offerAnswer since the InviteSession also wants to keep its own
02778    // copy of the offerAnswer around for the application to access
02779    if (alternative)
02780    {
02781       MultipartAlternativeContents* mac = new MultipartAlternativeContents;
02782       mac->parts().push_back(alternative->clone());
02783       mac->parts().push_back(offerAnswer.clone());
02784       msg.setContents(auto_ptr<Contents>(mac));
02785    }
02786    else
02787    {
02788       msg.setContents(&offerAnswer);
02789    }
02790 }
02791 
02792 void
02793 InviteSession::setOfferAnswer(SipMessage& msg, const Contents* offerAnswer)
02794 {
02795    assert(offerAnswer);
02796    msg.setContents(offerAnswer);
02797 }
02798 
02799 void 
02800 InviteSession::provideProposedOffer()
02801 {
02802    MultipartAlternativeContents* mp_ans =
02803      dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get());
02804    if (mp_ans)
02805    {
02806       // .kw. can cast below ever be NULL? Need assert/throw?
02807       provideOffer( *(dynamic_cast<Contents*>((mp_ans)->parts().back())),
02808                     mProposedEncryptionLevel,
02809                     dynamic_cast<Contents*>((mp_ans)->parts().front()));
02810    }
02811    else
02812    {
02813       // .kw. can cast below ever be NULL? Need assert/throw?
02814       provideOffer(*(dynamic_cast<Contents*>(mProposedLocalOfferAnswer.get())), mProposedEncryptionLevel, 0);
02815    }
02816 }
02817 
02818 InviteSession::Event
02819 InviteSession::toEvent(const SipMessage& msg, const Contents* offerAnswer)
02820 {
02821    MethodTypes method = msg.header(h_CSeq).method();
02822    int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
02823    
02824    //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
02825    //responses, reiable provisionals should only be received if the invite was
02826    //sent reliably.  Spurious reliable provisional respnoses are dropped outside
02827    //the state machine.
02828    bool reliable = isReliable(msg);
02829    bool sentOffer = mProposedLocalOfferAnswer.get();
02830 
02831    if (code == 481 || code == 408)
02832    {
02833       return OnGeneralFailure;
02834    }
02835    else if (code >= 300 && code <= 399)
02836    {
02837       return OnRedirect;
02838    }
02839    else if (method == INVITE && code == 0)
02840    {
02841       if (offerAnswer)
02842       {
02843          if (reliable)
02844          {
02845             return OnInviteReliableOffer;
02846          }
02847          else
02848          {
02849             return OnInviteOffer;
02850          }
02851       }
02852       else
02853       {
02854          if (reliable)
02855          {
02856             return OnInviteReliable;
02857          }
02858          else
02859          {
02860             return OnInvite;
02861          }
02862       }
02863    }
02864    else if (method == INVITE && code > 100 && code < 200)
02865    {
02866       if (reliable)
02867       {
02868          if (offerAnswer)
02869          {
02870             if (sentOffer)
02871             {
02872                return On1xxAnswer;
02873             }
02874             else
02875             {
02876                return On1xxOffer;
02877             }
02878          }
02879          else
02880          {
02881             return On1xx;
02882          }
02883       }
02884       else
02885       {
02886          if (offerAnswer)
02887          {
02888             return On1xxEarly;
02889          }
02890          else
02891          {
02892             return On1xx;
02893          }
02894       }
02895    }
02896    else if (method == INVITE && code >= 200 && code < 300)
02897    {
02898       if (offerAnswer)
02899       {
02900          if (sentOffer)
02901          {
02902             return On2xxAnswer;
02903          }
02904          else
02905          {
02906             return On2xxOffer;
02907          }
02908       }
02909       else
02910       {
02911          return On2xx;
02912       }
02913    }
02914    else if (method == INVITE && code == 422)
02915    {
02916       return On422Invite;
02917    }
02918    else if (method == INVITE && code == 487)
02919    {
02920       return On487Invite;
02921    }
02922    else if (method == INVITE && code == 491)
02923    {
02924       return On491Invite;
02925    }
02926    else if (method == INVITE && code >= 400)
02927    {
02928       return OnInviteFailure;
02929    }
02930    else if (method == ACK)
02931    {
02932       if (offerAnswer)
02933       {
02934          return OnAckAnswer;
02935       }
02936       else
02937       {
02938          return OnAck;
02939       }
02940    }
02941    else if (method == CANCEL && code == 0)
02942    {
02943       return OnCancel;
02944    }
02945    else if (method == CANCEL && code / 200 == 1)
02946    {
02947       return On200Cancel;
02948    }
02949    else if (method == CANCEL && code >= 400)
02950    {
02951       return OnCancelFailure;
02952    }
02953    else if (method == BYE && code == 0)
02954    {
02955       return OnBye;
02956    }
02957    else if (method == BYE && code / 200 == 1)
02958    {
02959       return On200Bye;
02960    }
02961    else if (method == PRACK && code == 0)
02962    {
02963       return OnPrack;
02964    }
02965    else if (method == PRACK && code / 200 == 1)
02966    {
02967       return On200Prack;
02968    }
02969    else if (method == UPDATE && code == 0)
02970    {
02971       if (offerAnswer)
02972       {
02973           return OnUpdateOffer;
02974       }
02975       else
02976       {
02977           return OnUpdate;
02978       }
02979    }
02980    else if (method == UPDATE && code / 200 == 1)
02981    {
02982       return On200Update;
02983    }
02984    else if (method == UPDATE && code == 422)
02985    {
02986       return On422Update;
02987    }
02988    else if (method == UPDATE && code == 491)
02989    {
02990       return On491Update;
02991    }
02992    else if (method == UPDATE && code >= 400)
02993    {
02994       return OnUpdateRejected;
02995    }
02996    else
02997    {
02998       //assert(0);   // dispatchOthers will throw if the message type is really unknown
02999       return Unknown;
03000    }
03001 }
03002 
03003 void 
03004 InviteSession::sendAck(const Contents *answer)
03005 {
03006    SharedPtr<SipMessage> ack(new SipMessage);
03007 
03008    SharedPtr<SipMessage> source;
03009    
03010    if (mLastLocalSessionModification->method() == UPDATE)
03011    {
03012       //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
03013       source = mDialog.mDialogSet.getCreator()->getLastRequest();
03014    }
03015    else
03016    {
03017       source = mLastLocalSessionModification;
03018    }
03019 
03020    assert(mAcks.count(source->getTransactionId()) == 0);
03021 
03022    mDialog.makeRequest(*ack, ACK);
03023 
03024    // Copy Authorization and Proxy Authorization headers from 
03025    // mLastLocalSessionModification; regardless of whether this was the original 
03026    // INVITE or not, this is the correct place to go for auth headers.
03027    if(mLastLocalSessionModification->exists(h_Authorizations))
03028    {
03029       ack->header(h_Authorizations) = mLastLocalSessionModification->header(h_Authorizations);
03030    }
03031    if(mLastLocalSessionModification->exists(h_ProxyAuthorizations))
03032    {
03033       ack->header(h_ProxyAuthorizations) = mLastLocalSessionModification->header(h_ProxyAuthorizations);
03034    }
03035 
03036    // Copy CSeq from original INVITE
03037    ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
03038 
03039    if(answer != 0)
03040    {
03041       setOfferAnswer(*ack, *answer);
03042    }
03043    mAcks[source->getTransactionId()] = ack;
03044    mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(), 0, source->getTransactionId());
03045 
03046    InfoLog (<< "Sending " << ack->brief());
03047    send(ack);
03048 }
03049 
03050 SharedPtr<SipMessage>
03051 InviteSession::sendBye()
03052 {
03053    SharedPtr<SipMessage> bye(new SipMessage());
03054    mDialog.makeRequest(*bye, BYE);
03055    Data txt;
03056    if (mEndReason != NotSpecified)
03057    {
03058       Token reason("SIP");
03059       txt = getEndReasonString(mEndReason);
03060       reason.param(p_text) = txt;
03061       bye->header(h_Reasons).push_back(reason);      
03062    }
03063 
03064    if (mDum.mDialogEventStateManager)
03065    {
03066       mDum.mDialogEventStateManager->onTerminated(mDialog, *bye, InviteSessionHandler::LocalBye);
03067    }
03068    
03069    InfoLog (<< myAddr() << " Sending BYE " << txt);
03070    send(bye);
03071    return bye;
03072 }
03073 
03074 DialogUsageManager::EncryptionLevel 
03075 InviteSession::getEncryptionLevel(const SipMessage& msg)
03076 {
03077    DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
03078    const SecurityAttributes* secAttr = msg.getSecurityAttributes();
03079    if (secAttr)
03080    {
03081       SignatureStatus sig = secAttr->getSignatureStatus();
03082       bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
03083       bool encrypted = secAttr->isEncrypted();
03084       if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
03085       else if (encrypted) level = DialogUsageManager::Encrypt;
03086       else if (sign) level = DialogUsageManager::Sign;
03087    }
03088    return level;
03089 }
03090 
03091 void 
03092 InviteSession::setCurrentLocalOfferAnswer(const SipMessage& msg)
03093 {
03094    assert(mProposedLocalOfferAnswer.get());
03095    if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))
03096    {
03097       if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
03098       {
03099          mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().back()->clone()));
03100       }
03101       else
03102       {
03103          mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().front()->clone()));
03104       }
03105    }
03106    else
03107    {
03108       mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>(mProposedLocalOfferAnswer.get()->clone()));
03109    }
03110    mProposedLocalOfferAnswer.reset();   
03111 }
03112 
03113 void 
03114 InviteSession::onReadyToSend(SipMessage& msg)
03115 {
03116    mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
03117 }
03118 
03119 void
03120 InviteSession::flowTerminated()
03121 {
03122    // notify handler
03123    mDum.mInviteSessionHandler->onFlowTerminated(getSessionHandle());
03124 }
03125 
03126 void 
03127 InviteSession::referNoSub(const SipMessage& msg)
03128 {
03129    assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
03130    mLastReferNoSubRequest = msg;
03131    mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
03132 }
03133 
03134 void
03135 InviteSession::acceptReferNoSub(int statusCode)
03136 {
03137    if (statusCode / 100  != 2)
03138    {
03139       throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
03140    }
03141 
03142    SharedPtr<SipMessage> response(new SipMessage);
03143    mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
03144    response->header(h_ReferSub).value() = "false";
03145    //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
03146    
03147    send(response);
03148 } 
03149 
03150 void
03151 InviteSession::rejectReferNoSub(int responseCode)
03152 {
03153    if (responseCode < 400)
03154    {
03155       throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
03156    }
03157 
03158    SharedPtr<SipMessage> response(new SipMessage);
03159    mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
03160    send(response);
03161 }
03162 
03163 /* ====================================================================
03164  * The Vovida Software License, Version 1.0
03165  *
03166  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
03167  *
03168  * Redistribution and use in source and binary forms, with or without
03169  * modification, are permitted provided that the following conditions
03170  * are met:
03171  *
03172  * 1. Redistributions of source code must retain the above copyright
03173  *    notice, this list of conditions and the following disclaimer.
03174  *
03175  * 2. Redistributions in binary form must reproduce the above copyright
03176  *    notice, this list of conditions and the following disclaimer in
03177  *    the documentation and/or other materials provided with the
03178 
03179  *    distribution.
03180  *
03181  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
03182  *    and "Vovida Open Communication Application Library (VOCAL)" must
03183  *    not be used to endorse or promote products derived from this
03184  *    software without prior written permission. For written
03185  *    permission, please contact vocal@vovida.org.
03186  *
03187  * 4. Products derived from this software may not be called "VOCAL", nor
03188  *    may "VOCAL" appear in their name, without prior written
03189  *    permission of Vovida Networks, Inc.
03190  *
03191  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
03192  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
03193  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
03194  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
03195  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
03196  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
03197  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
03198  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
03199  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
03200  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
03201  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
03202  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
03203  * DAMAGE.
03204  *
03205  * ====================================================================
03206  *
03207  * This software consists of voluntary contributions made by Vovida
03208  * Networks, Inc. and many individuals on behalf of Vovida Networks,
03209  * Inc.  For more information on Vovida Networks, Inc., please see
03210  * <http://www.vovida.org/>.
03211  *
03212  */
03213 
03214 
03215