|
reSIProcate/DialogUsageManager
9694
|
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
1.7.5.1