/[resiprocate]/main/resip/dum/InviteSession.cxx
ViewVC logotype

Contents of /main/resip/dum/InviteSession.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9176 - (show annotations) (download)
Tue May 17 21:59:50 2011 UTC (8 years, 6 months ago) by bcampen
File MIME type: text/plain
File size: 93577 byte(s)
Merge work from b-bwc-parameter_scoping

1 #include "resip/stack/MultipartMixedContents.hxx"
2 #include "resip/stack/MultipartAlternativeContents.hxx"
3 #include "resip/stack/SdpContents.hxx"
4 #include "resip/stack/SipMessage.hxx"
5 #include "resip/stack/Helper.hxx"
6 #include "resip/dum/BaseCreator.hxx"
7 #include "resip/dum/Dialog.hxx"
8 #include "resip/dum/DialogEventStateManager.hxx"
9 #include "resip/dum/DialogUsageManager.hxx"
10 #include "resip/dum/InviteSession.hxx"
11 #include "resip/dum/ServerInviteSession.hxx"
12 #include "resip/dum/ClientSubscription.hxx"
13 #include "resip/dum/ServerSubscription.hxx"
14 #include "resip/dum/ClientInviteSession.hxx"
15 #include "resip/dum/InviteSessionHandler.hxx"
16 #include "resip/dum/MasterProfile.hxx"
17 #include "resip/dum/UsageUseException.hxx"
18 #include "resip/dum/DumHelper.hxx"
19 #include "rutil/Inserter.hxx"
20 #include "rutil/Logger.hxx"
21 #include "rutil/MD5Stream.hxx"
22 #include "rutil/Timer.hxx"
23 #include "rutil/Random.hxx"
24 #include "rutil/compat.hxx"
25 #include "rutil/WinLeakCheck.hxx"
26
27 // Remove warning about 'this' use in initiator list - pointer is only stored
28 #if defined(WIN32) && !defined(__GNUC__)
29 #pragma warning( disable : 4355 ) // using this in base member initializer list
30 #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
31 #endif
32
33 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
34 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
35
36 using namespace resip;
37 using namespace std;
38
39 Data EndReasons[] =
40 {
41 "Not Specified",
42 "User Hung Up",
43 "Application Rejected Sdp(usually no common codec)",
44 "Illegal Sdp Negotiation",
45 "ACK not received",
46 "Session Timer Expired",
47 "Stale re-Invite"
48 };
49
50 const Data& InviteSession::getEndReasonString(InviteSession::EndReason reason)
51 {
52 if(reason != InviteSession::UserSpecified)
53 {
54 assert(reason >= InviteSession::NotSpecified && reason < InviteSession::ENDREASON_MAX); //!dcm! -- necessary?
55 return EndReasons[reason];
56 }
57 else
58 {
59 return mUserEndReason;
60 }
61 }
62
63 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
64 : DialogUsage(dum, dialog),
65 mState(Undefined),
66 mNitState(NitComplete),
67 mServerNitState(NitComplete),
68 mLastLocalSessionModification(new SipMessage),
69 mLastRemoteSessionModification(new SipMessage),
70 mInvite200(new SipMessage),
71 mLastNitResponse(new SipMessage),
72 mCurrentRetransmit200(0),
73 mStaleReInviteTimerSeq(1),
74 mSessionInterval(0),
75 mMinSE(90),
76 mSessionRefresher(false),
77 mSessionTimerSeq(0),
78 mSessionRefreshReInvite(false),
79 mReferSub(true),
80 mCurrentEncryptionLevel(DialogUsageManager::None),
81 mProposedEncryptionLevel(DialogUsageManager::None),
82 mEndReason(NotSpecified)
83 {
84 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
85 assert(mDum.mInviteSessionHandler);
86 }
87
88 InviteSession::~InviteSession()
89 {
90 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
91 mDialog.mInviteSession = 0;
92 while(!mNITQueue.empty())
93 {
94 delete mNITQueue.front();
95 mNITQueue.pop();
96 }
97 }
98
99 void
100 InviteSession::dialogDestroyed(const SipMessage& msg)
101 {
102 assert(0);
103
104 // !jf! Is this correct? Merged from main...
105 // !jf! what reason - guessed for now?
106 //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);
107 //delete this;
108 }
109
110 bool
111 InviteSession::hasLocalOfferAnswer() const
112 {
113 return (mCurrentLocalOfferAnswer.get());
114 }
115
116 const Contents&
117 InviteSession::getLocalOfferAnswer() const
118 {
119 if(mCurrentLocalOfferAnswer.get())
120 {
121 return *mCurrentLocalOfferAnswer;
122 }
123 else
124 {
125 return SdpContents::Empty;
126 }
127 }
128
129 bool
130 InviteSession::hasRemoteOfferAnswer() const
131 {
132 return (mCurrentRemoteOfferAnswer.get());
133 }
134
135 const Contents&
136 InviteSession::getRemoteOfferAnswer() const
137 {
138 if(mCurrentRemoteOfferAnswer.get())
139 {
140 return *mCurrentRemoteOfferAnswer;
141 }
142 else
143 {
144 return SdpContents::Empty;
145 }
146 }
147
148 bool
149 InviteSession::hasProposedRemoteOfferAnswer() const
150 {
151 return (mProposedRemoteOfferAnswer.get());
152 }
153
154 const Contents&
155 InviteSession::getProposedRemoteOfferAnswer() const
156 {
157 if(mProposedRemoteOfferAnswer.get())
158 {
159 return *mProposedRemoteOfferAnswer;
160 }
161 else
162 {
163 return SdpContents::Empty;
164 }
165 }
166
167 bool
168 InviteSession::hasLocalSdp() const
169 {
170 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
171 return (mCurrentLocalOfferAnswer.get());
172 }
173
174 const SdpContents&
175 InviteSession::getLocalSdp() const
176 {
177 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
178 if(mCurrentLocalOfferAnswer.get())
179 {
180 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentLocalOfferAnswer.get());
181 assert(sdp);
182 return *sdp;
183 }
184 else
185 {
186 return SdpContents::Empty;
187 }
188 }
189
190 bool
191 InviteSession::hasRemoteSdp() const
192 {
193 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
194 return (mCurrentRemoteOfferAnswer.get());
195 }
196
197 const SdpContents&
198 InviteSession::getRemoteSdp() const
199 {
200 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
201 if(mCurrentRemoteOfferAnswer.get())
202 {
203 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentRemoteOfferAnswer.get());
204 assert(sdp);
205 return *sdp;
206 }
207 else
208 {
209 return SdpContents::Empty;
210 }
211 }
212
213 bool
214 InviteSession::hasProposedRemoteSdp() const
215 {
216 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
217 return (mProposedRemoteOfferAnswer.get());
218 }
219
220 const SdpContents&
221 InviteSession::getProposedRemoteSdp() const
222 {
223 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
224 if(mProposedRemoteOfferAnswer.get())
225 {
226 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mProposedRemoteOfferAnswer.get());
227 assert(sdp);
228 return *sdp;
229 }
230 else
231 {
232 return SdpContents::Empty;
233 }
234 }
235
236 InviteSessionHandle
237 InviteSession::getSessionHandle()
238 {
239 return InviteSessionHandle(mDum, getBaseHandle().getId());
240 }
241
242 void InviteSession::storePeerCapabilities(const SipMessage& msg)
243 {
244 if (msg.exists(h_Allows))
245 {
246 mPeerSupportedMethods = msg.header(h_Allows);
247 }
248 if (msg.exists(h_Supporteds))
249 {
250 mPeerSupportedOptionTags = msg.header(h_Supporteds);
251 }
252 if (msg.exists(h_AcceptEncodings))
253 {
254 mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
255 }
256 if (msg.exists(h_AcceptLanguages))
257 {
258 mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
259 }
260 if (msg.exists(h_AllowEvents))
261 {
262 mPeerAllowedEvents = msg.header(h_AllowEvents);
263 }
264 if (msg.exists(h_Accepts))
265 {
266 mPeerSupportedMimeTypes = msg.header(h_Accepts);
267 }
268 if (msg.exists(h_UserAgent))
269 {
270 mPeerUserAgent = msg.header(h_UserAgent).value();
271 }
272 }
273
274 bool
275 InviteSession::updateMethodSupported() const
276 {
277 // Check if Update is supported locally
278 if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
279 {
280 // Check if peer supports UPDATE
281 return mPeerSupportedMethods.find(Token("UPDATE"));
282 }
283 return false;
284 }
285
286 bool
287 InviteSession::isConnected() const
288 {
289 switch (mState)
290 {
291 case Connected:
292 case SentUpdate:
293 case SentUpdateGlare:
294 case SentReinvite:
295 case SentReinviteGlare:
296 case SentReinviteNoOffer:
297 case SentReinviteAnswered:
298 case SentReinviteNoOfferGlare:
299 case ReceivedUpdate:
300 case ReceivedReinvite:
301 case ReceivedReinviteNoOffer:
302 case ReceivedReinviteSentOffer:
303 case Answered:
304 case WaitingToOffer:
305 case WaitingToRequestOffer:
306 return true;
307
308 default:
309 return false;
310 }
311 }
312
313 bool
314 InviteSession::isEarly() const
315 {
316 switch (mState)
317 {
318 case UAC_Early:
319 case UAC_EarlyWithOffer:
320 case UAC_EarlyWithAnswer:
321 case UAC_SentUpdateEarly:
322 case UAC_ReceivedUpdateEarly:
323 case UAC_SentAnswer:
324 case UAC_QueuedUpdate:
325 return true;
326 default:
327 return false;
328 }
329 }
330
331 bool
332 InviteSession::isAccepted() const
333 {
334 switch (mState)
335 {
336 case UAS_Start:
337 case UAS_Offer:
338 case UAS_NoOffer:
339 case UAS_NoOfferReliable:
340 case UAS_ProvidedOffer:
341 case UAS_OfferProvidedAnswer:
342 case UAS_EarlyOffer:
343 case UAS_EarlyProvidedOffer:
344 case UAS_EarlyProvidedAnswer:
345 case UAS_EarlyNoOffer:
346 case UAS_FirstSentAnswerReliable:
347 case UAS_FirstSentOfferReliable:
348 case UAS_NegotiatedReliable:
349 return false;
350 default:
351 return true;
352 }
353 }
354
355 bool
356 InviteSession::isTerminated() const
357 {
358 switch (mState)
359 {
360 case Terminated:
361 case WaitingToTerminate:
362 case WaitingToHangup:
363 case UAC_Cancelled:
364 case UAS_WaitingToTerminate:
365 case UAS_WaitingToHangup:
366 return true;
367 default:
368 return false;
369 }
370 }
371
372 EncodeStream&
373 InviteSession::dump(EncodeStream& strm) const
374 {
375 strm << "INVITE: " << mId
376 << " " << toData(mState)
377 << " ADDR=" << myAddr()
378 << " PEER=" << peerAddr();
379 return strm;
380 }
381
382 void
383 InviteSession::requestOffer()
384 {
385 switch (mState)
386 {
387 case Connected:
388 case WaitingToRequestOffer:
389 case UAS_WaitingToRequestOffer:
390 transition(SentReinviteNoOffer);
391 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
392 startStaleReInviteTimer();
393 mLastLocalSessionModification->setContents(0); // Clear the contents from the INVITE
394 setSessionTimerHeaders(*mLastLocalSessionModification);
395
396 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
397
398 // call send to give app an chance to adorn the message.
399 send(mLastLocalSessionModification);
400 break;
401
402 case Answered:
403 // queue the offer to be sent after the ACK is received
404 transition(WaitingToRequestOffer);
405 break;
406
407 // ?slg? Can we handle all of the states listed in isConnected() ???
408 default:
409 WarningLog (<< "Can't requestOffer when not in Connected state");
410 throw DialogUsage::Exception("Can't request an offer", __FILE__,__LINE__);
411 }
412 }
413
414 void
415 InviteSession::provideOffer(const Contents& offer,
416 DialogUsageManager::EncryptionLevel level,
417 const Contents* alternative)
418 {
419 switch (mState)
420 {
421 case Connected:
422 case WaitingToOffer:
423 case UAS_WaitingToOffer:
424 transition(SentReinvite);
425 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
426 startStaleReInviteTimer();
427
428 setSessionTimerHeaders(*mLastLocalSessionModification);
429
430 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
431 InviteSession::setOfferAnswer(*mLastLocalSessionModification, offer, alternative);
432 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
433 mProposedEncryptionLevel = level;
434 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
435
436 // call send to give app an chance to adorn the message.
437 send(mLastLocalSessionModification);
438 break;
439
440 case Answered:
441 // queue the offer to be sent after the ACK is received
442 transition(WaitingToOffer);
443 mProposedEncryptionLevel = level;
444 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
445 break;
446
447 case ReceivedReinviteNoOffer:
448 assert(!mProposedRemoteOfferAnswer.get());
449 transition(ReceivedReinviteSentOffer);
450 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
451 handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
452 InviteSession::setOfferAnswer(*mInvite200, offer, 0);
453 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer);
454
455 InfoLog (<< "Sending " << mInvite200->brief());
456 DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
457 send(mInvite200);
458 startRetransmit200Timer();
459 break;
460
461 default:
462 WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
463 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
464 }
465 }
466
467 class InviteSessionProvideOfferExCommand : public DumCommandAdapter
468 {
469 public:
470 InviteSessionProvideOfferExCommand(InviteSession& inviteSession,
471 const Contents& offer,
472 DialogUsageManager::EncryptionLevel level,
473 const Contents* alternative)
474 : mInviteSession(inviteSession),
475 mOffer(offer.clone()),
476 mLevel(level),
477 mAlternative(alternative ? alternative->clone() : 0)
478 {
479 }
480
481 virtual void executeCommand()
482 {
483 mInviteSession.provideOffer(*mOffer, mLevel, mAlternative.get());
484 }
485
486 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
487 {
488 return strm << "InviteSessionProvideOfferExCommand";
489 }
490 private:
491 InviteSession& mInviteSession;
492 std::auto_ptr<const Contents> mOffer;
493 DialogUsageManager::EncryptionLevel mLevel;
494 std::auto_ptr<const Contents> mAlternative;
495 };
496
497 void
498 InviteSession::provideOfferCommand(const Contents& offer, DialogUsageManager::EncryptionLevel level, const Contents* alternative)
499 {
500 mDum.post(new InviteSessionProvideOfferExCommand(*this, offer, level, alternative));
501 }
502
503 void
504 InviteSession::provideOffer(const Contents& offer)
505 {
506 return provideOffer(offer, mCurrentEncryptionLevel, 0);
507 }
508
509 class InviteSessionProvideOfferCommand : public DumCommandAdapter
510 {
511 public:
512 InviteSessionProvideOfferCommand(InviteSession& inviteSession, const Contents& offer)
513 : mInviteSession(inviteSession),
514 mOffer(offer.clone())
515 {
516 }
517
518 virtual void executeCommand()
519 {
520 mInviteSession.provideOffer(*mOffer);
521 }
522
523 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
524 {
525 return strm << "InviteSessionProvideOfferCommand";
526 }
527 private:
528 InviteSession& mInviteSession;
529 std::auto_ptr<const Contents> mOffer;
530 };
531
532 void
533 InviteSession::provideOfferCommand(const Contents& offer)
534 {
535 mDum.post(new InviteSessionProvideOfferCommand(*this, offer));
536 }
537
538 void
539 InviteSession::provideAnswer(const Contents& answer)
540 {
541 switch (mState)
542 {
543 case ReceivedReinvite:
544 transition(Connected);
545 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
546 handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
547 InviteSession::setOfferAnswer(*mInvite200, answer, 0);
548 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
549 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
550 InfoLog (<< "Sending " << mInvite200->brief());
551 DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
552 send(mInvite200);
553 startRetransmit200Timer();
554 break;
555
556 case ReceivedUpdate: // same as ReceivedReinvite case.
557 {
558 transition(Connected);
559
560 SharedPtr<SipMessage> response(new SipMessage);
561 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
562 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
563 InviteSession::setOfferAnswer(*response, answer, 0);
564 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
565 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
566 InfoLog (<< "Sending " << response->brief());
567 DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
568 send(response);
569 break;
570 }
571
572 case SentReinviteAnswered:
573 transition(Connected);
574 sendAck(&answer);
575
576 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
577 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
578 break;
579
580 default:
581 WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
582 throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
583 }
584 }
585
586 class InviteSessionProvideAnswerCommand : public DumCommandAdapter
587 {
588 public:
589 InviteSessionProvideAnswerCommand(InviteSession& inviteSession, const Contents& answer)
590 : mInviteSession(inviteSession),
591 mAnswer(answer.clone())
592 {
593 }
594
595 virtual void executeCommand()
596 {
597 mInviteSession.provideAnswer(*mAnswer);
598 }
599
600 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
601 {
602 return strm << "InviteSessionProvideAnswerCommand";
603 }
604 private:
605 InviteSession& mInviteSession;
606 std::auto_ptr<const Contents> mAnswer;
607 };
608
609 void
610 InviteSession::provideAnswerCommand(const Contents& answer)
611 {
612 mDum.post(new InviteSessionProvideAnswerCommand(*this, answer));
613 }
614
615 void
616 InviteSession::end()
617 {
618 end(NotSpecified);
619 }
620
621 void
622 InviteSession::end(const Data& userReason)
623 {
624 mUserEndReason = userReason;
625 end(UserSpecified);
626 }
627
628 void
629 InviteSession::end(EndReason reason)
630 {
631 if (mEndReason == NotSpecified)
632 {
633 mEndReason = reason;
634 }
635
636 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
637
638 switch (mState)
639 {
640 case Connected:
641 case SentUpdate:
642 case SentUpdateGlare:
643 case SentReinviteGlare:
644 case SentReinviteNoOfferGlare:
645 case SentReinviteAnswered:
646 {
647 // !jf! do we need to store the BYE somewhere?
648 // .dw. BYE message handled
649 SharedPtr<SipMessage> msg = sendBye();
650 transition(Terminated);
651 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
652 break;
653 }
654
655 case SentReinvite:
656 case SentReinviteNoOffer:
657 transition(WaitingToTerminate);
658 break;
659
660 case Answered:
661 case WaitingToOffer:
662 case WaitingToRequestOffer:
663 case ReceivedReinviteSentOffer:
664 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet - wait for it
665 {
666 transition(WaitingToHangup);
667 }
668 else
669 {
670 // ACK has likely timedout - hangup immediately
671 SharedPtr<SipMessage> msg = sendBye();
672 transition(Terminated);
673 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
674 }
675 break;
676
677 case ReceivedUpdate:
678 case ReceivedReinvite:
679 case ReceivedReinviteNoOffer:
680 {
681 SharedPtr<SipMessage> response(new SipMessage);
682 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 488);
683 InfoLog (<< "Sending " << response->brief());
684 send(response);
685
686 SharedPtr<SipMessage> msg = sendBye();
687 transition(Terminated);
688 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
689 break;
690 }
691
692 case WaitingToTerminate: // ?slg? Why is this here?
693 {
694 SharedPtr<SipMessage> msg = sendBye();
695 transition(Terminated);
696 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
697 break;
698 }
699
700 case Terminated:
701 // no-op.
702 break;
703
704 default:
705 assert(0);
706 break;
707 }
708 }
709
710 class InviteSessionEndCommand : public DumCommandAdapter
711 {
712 public:
713 InviteSessionEndCommand(InviteSession& inviteSession, InviteSession::EndReason reason)
714 : mInviteSession(inviteSession),
715 mReason(reason)
716 {
717 }
718
719 virtual void executeCommand()
720 {
721 mInviteSession.end(mReason);
722 }
723
724 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
725 {
726 return strm << "InviteSessionEndCommand";
727 }
728 private:
729 InviteSession& mInviteSession;
730 InviteSession::EndReason mReason;
731 };
732
733 void
734 InviteSession::endCommand(EndReason reason)
735 {
736 mDum.post(new InviteSessionEndCommand(*this, reason));
737 }
738
739 void
740 InviteSession::reject(int statusCode, WarningCategory *warning)
741 {
742 switch (mState)
743 {
744 case ReceivedUpdate:
745 case ReceivedReinvite:
746 case ReceivedReinviteNoOffer:
747 {
748 transition(Connected);
749
750 SharedPtr<SipMessage> response(new SipMessage);
751 mDialog.makeResponse(*response, *mLastRemoteSessionModification, statusCode);
752 if(warning)
753 {
754 response->header(h_Warnings).push_back(*warning);
755 }
756 InfoLog (<< "Sending " << response->brief());
757 send(response);
758 break;
759 }
760
761 default:
762 assert(0);
763 break;
764 }
765 }
766
767 class InviteSessionRejectCommand : public DumCommandAdapter
768 {
769 public:
770 InviteSessionRejectCommand(InviteSession& inviteSession, int code, WarningCategory* warning)
771 : mInviteSession(inviteSession),
772 mCode(code),
773 mWarning(warning?new WarningCategory(*warning):0)
774 {
775 }
776
777 virtual void executeCommand()
778 {
779 mInviteSession.reject(mCode, mWarning.get());
780 }
781
782 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
783 {
784 return strm << "InviteSessionRejectCommand";
785 }
786 private:
787 InviteSession& mInviteSession;
788 int mCode;
789 std::auto_ptr<WarningCategory> mWarning;
790 };
791
792 void
793 InviteSession::rejectCommand(int code, WarningCategory *warning)
794 {
795 mDum.post(new InviteSessionRejectCommand(*this, code, warning));
796 }
797
798 void
799 InviteSession::targetRefresh(const NameAddr& localUri)
800 {
801 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
802 {
803 mDialog.mLocalContact = localUri;
804 sessionRefresh();
805 }
806 else
807 {
808 WarningLog (<< "Can't targetRefresh before Connected");
809 throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
810 }
811 }
812
813 void
814 InviteSession::refer(const NameAddr& referTo, bool referSub)
815 {
816 refer(referTo,std::auto_ptr<resip::Contents>(0),referSub);
817 }
818 void
819 InviteSession::refer(const NameAddr& referTo, std::auto_ptr<resip::Contents> contents,bool referSub)
820 {
821 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
822 {
823 SharedPtr<SipMessage> refer(new SipMessage());
824 mDialog.makeRequest(*refer, REFER);
825 refer->header(h_ReferTo) = referTo;
826 refer->header(h_ReferredBy) = myAddr();
827 refer->header(h_ReferredBy).remove(p_tag); // tag-param not permitted in rfc3892; not the same as generic-param
828 refer->setContents(contents);
829 if (!referSub)
830 {
831 refer->header(h_ReferSub).value() = "false";
832 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
833 }
834
835 if(mNitState == NitComplete)
836 {
837 mNitState = NitProceeding;
838 mReferSub = referSub;
839 mLastSentNITRequest = refer;
840 send(refer);
841 return;
842 }
843 mNITQueue.push(new QueuedNIT(refer,referSub));
844 InfoLog(<< "refer - queuing NIT:" << refer->brief());
845 return;
846 }
847 else
848 {
849 WarningLog (<< "Can't refer before Connected");
850 assert(0);
851 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
852 }
853 }
854
855 const SharedPtr<SipMessage>
856 InviteSession::getLastSentNITRequest() const
857 {
858 return mLastSentNITRequest;
859 }
860
861 void
862 InviteSession::nitComplete()
863 {
864 mNitState = NitComplete;
865 if (mNITQueue.size())
866 {
867 QueuedNIT *qn=mNITQueue.front();
868 mNITQueue.pop();
869 mNitState = NitProceeding;
870 mReferSub = qn->referSubscription();
871 mLastSentNITRequest = qn->getNIT();
872 InfoLog(<< "checkNITQueue - sending queued NIT:" << mLastSentNITRequest->brief());
873 send(mLastSentNITRequest);
874 delete qn;
875 }
876 }
877
878 class InviteSessionReferCommand : public DumCommandAdapter
879 {
880 public:
881 InviteSessionReferCommand(InviteSession& inviteSession, const NameAddr& referTo, bool referSub)
882 : mInviteSession(inviteSession),
883 mReferTo(referTo),
884 mReferSub(referSub)
885 {
886
887 }
888
889 virtual void executeCommand()
890 {
891 mInviteSession.refer(mReferTo, mReferSub);
892 }
893
894 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
895 {
896 return strm << "InviteSessionReferCommand";
897 }
898
899 private:
900 InviteSession& mInviteSession;
901 NameAddr mReferTo;
902 bool mReferSub;
903 };
904
905 void
906 InviteSession::referCommand(const NameAddr& referTo, bool referSub)
907 {
908 mDum.post(new InviteSessionReferCommand(*this, referTo, referSub));
909 }
910
911 void
912 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
913 {
914 refer(referTo,sessionToReplace,std::auto_ptr<resip::Contents>(0),referSub);
915 }
916
917 void
918 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, std::auto_ptr<resip::Contents> contents, bool referSub)
919 {
920 if (!sessionToReplace.isValid())
921 {
922 throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
923 }
924
925 CallId replaces;
926 DialogId id = sessionToReplace->mDialog.getId();
927 replaces.value() = id.getCallId();
928 replaces.param(p_toTag) = id.getRemoteTag();
929 replaces.param(p_fromTag) = id.getLocalTag();
930
931 refer(referTo, replaces, contents, referSub);
932 }
933
934 void
935 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, bool referSub)
936 {
937 refer(referTo,replaces,std::auto_ptr<resip::Contents>(0),referSub);
938 }
939
940 void
941 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, std::auto_ptr<resip::Contents> contents, bool referSub)
942 {
943 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
944 {
945 SharedPtr<SipMessage> refer(new SipMessage());
946 mDialog.makeRequest(*refer, REFER);
947 refer->setContents(contents);
948 refer->header(h_ReferTo) = referTo;
949 refer->header(h_ReferredBy) = myAddr();
950 refer->header(h_ReferredBy).remove(p_tag);
951
952 refer->header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
953
954 if (!referSub)
955 {
956 refer->header(h_ReferSub).value() = "false";
957 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
958 }
959
960 if(mNitState == NitComplete)
961 {
962 mNitState = NitProceeding;
963 mReferSub = referSub;
964 mLastSentNITRequest = refer;
965 send(refer);
966 return;
967 }
968 mNITQueue.push(new QueuedNIT(refer,referSub));
969 InfoLog(<< "refer/replace - queuing NIT:" << refer->brief());
970 return;
971 }
972 else
973 {
974 WarningLog (<< "Can't refer before Connected");
975 assert(0);
976 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
977 }
978 }
979
980 class InviteSessionReferExCommand : public DumCommandAdapter
981 {
982 public:
983 InviteSessionReferExCommand(InviteSession& inviteSession, const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
984 : mInviteSession(inviteSession),
985 mSessionToReplace(sessionToReplace),
986 mReferTo(referTo),
987 mReferSub(referSub)
988 {
989 }
990
991 virtual void executeCommand()
992 {
993 mInviteSession.referCommand(mReferTo, mSessionToReplace, mReferSub);
994 }
995
996 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
997 {
998 return strm << "InviteSessionReferExCommand";
999 }
1000
1001 private:
1002 InviteSession& mInviteSession;
1003 InviteSessionHandle mSessionToReplace;
1004 NameAddr mReferTo;
1005 bool mReferSub;
1006 };
1007
1008 void
1009 InviteSession::referCommand(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
1010 {
1011 mDum.post(new InviteSessionReferExCommand(*this, referTo, sessionToReplace, referSub));
1012 }
1013
1014 void
1015 InviteSession::info(const Contents& contents)
1016 {
1017 SharedPtr<SipMessage> info(new SipMessage());
1018 mDialog.makeRequest(*info, INFO);
1019 // !jf! handle multipart here
1020 info->setContents(&contents);
1021 DumHelper::setOutgoingEncryptionLevel(*info, mCurrentEncryptionLevel);
1022 if (mNitState == NitComplete)
1023 {
1024 mNitState = NitProceeding;
1025 mLastSentNITRequest = info;
1026 send(info);
1027 return;
1028 }
1029 mNITQueue.push(new QueuedNIT(info));
1030 InfoLog(<< "info - queuing NIT:" << info->brief());
1031 return;
1032 }
1033
1034 class InviteSessionInfoCommand : public DumCommandAdapter
1035 {
1036 public:
1037 InviteSessionInfoCommand(InviteSession& inviteSession, const Contents& contents)
1038 : mInviteSession(inviteSession),
1039 mContents(contents.clone())
1040 {
1041 }
1042
1043 virtual void executeCommand()
1044 {
1045 mInviteSession.info(*mContents);
1046 }
1047
1048 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1049 {
1050 return strm << "InviteSessionInfoCommand";
1051 }
1052 private:
1053 InviteSession& mInviteSession;
1054 std::auto_ptr<Contents> mContents;
1055 };
1056
1057 void
1058 InviteSession::infoCommand(const Contents& contents)
1059 {
1060 mDum.post(new InviteSessionInfoCommand(*this, contents));
1061 }
1062
1063 void
1064 InviteSession::message(const Contents& contents)
1065 {
1066 SharedPtr<SipMessage> message(new SipMessage());
1067 mDialog.makeRequest(*message, MESSAGE);
1068 // !jf! handle multipart here
1069 message->setContents(&contents);
1070 DumHelper::setOutgoingEncryptionLevel(*message, mCurrentEncryptionLevel);
1071 InfoLog (<< "Trying to send MESSAGE: " << message);
1072 if (mNitState == NitComplete)
1073 {
1074 mNitState = NitProceeding;
1075 mLastSentNITRequest = message;
1076 send(message);
1077 return;
1078 }
1079 mNITQueue.push(new QueuedNIT(message));
1080 InfoLog(<< "message - queuing NIT:" << message->brief());
1081 return;
1082 }
1083
1084 class InviteSessionMessageCommand : public DumCommandAdapter
1085 {
1086 public:
1087 InviteSessionMessageCommand(InviteSession& inviteSession, const Contents& contents)
1088 : mInviteSession(inviteSession),
1089 mContents(contents.clone())
1090 {
1091 }
1092
1093 virtual void executeCommand()
1094 {
1095 mInviteSession.message(*mContents);
1096 }
1097
1098 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1099 {
1100 return strm << "InviteSessionMessageCommand";
1101 }
1102 private:
1103 InviteSession& mInviteSession;
1104 std::auto_ptr<Contents> mContents;
1105 };
1106
1107
1108 void
1109 InviteSession::messageCommand(const Contents& contents)
1110 {
1111 mDum.post(new InviteSessionMessageCommand(*this, contents));
1112 }
1113
1114 void
1115 InviteSession::dispatch(const SipMessage& msg)
1116 {
1117 // Look for 2xx retransmissions - resend ACK and filter out of state machine
1118 if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 100 == 2)
1119 {
1120 AckMap::iterator i = mAcks.find(msg.getTransactionId());
1121 if (i != mAcks.end())
1122 {
1123 send(i->second); // resend ACK
1124 return;
1125 }
1126 }
1127
1128 // !jf! do we need to handle 3xx here or is it handled elsewhere?
1129 switch (mState)
1130 {
1131 case Connected:
1132 dispatchConnected(msg);
1133 break;
1134 case SentUpdate:
1135 dispatchSentUpdate(msg);
1136 break;
1137 case SentReinvite:
1138 dispatchSentReinvite(msg);
1139 break;
1140 case SentReinviteNoOffer:
1141 dispatchSentReinviteNoOffer(msg);
1142 break;
1143 case SentReinviteAnswered:
1144 dispatchSentReinviteAnswered(msg);
1145 break;
1146 case SentUpdateGlare:
1147 case SentReinviteGlare:
1148 // The behavior is the same except for timer which is handled in dispatch(Timer)
1149 dispatchGlare(msg);
1150 break;
1151 case SentReinviteNoOfferGlare:
1152 dispatchReinviteNoOfferGlare(msg);
1153 break;
1154 case ReceivedUpdate:
1155 case ReceivedReinvite:
1156 case ReceivedReinviteNoOffer:
1157 dispatchReceivedUpdateOrReinvite(msg);
1158 break;
1159 case ReceivedReinviteSentOffer:
1160 dispatchReceivedReinviteSentOffer(msg);
1161 break;
1162 case Answered:
1163 dispatchAnswered(msg);
1164 break;
1165 case WaitingToOffer:
1166 dispatchWaitingToOffer(msg);
1167 break;
1168 case WaitingToRequestOffer:
1169 dispatchWaitingToRequestOffer(msg);
1170 break;
1171 case WaitingToTerminate:
1172 dispatchWaitingToTerminate(msg);
1173 break;
1174 case WaitingToHangup:
1175 dispatchWaitingToHangup(msg);
1176 break;
1177 case Terminated:
1178 dispatchTerminated(msg);
1179 break;
1180 case Undefined:
1181 default:
1182 assert(0);
1183 break;
1184 }
1185 }
1186
1187 void
1188 InviteSession::dispatch(const DumTimeout& timeout)
1189 {
1190 if (timeout.type() == DumTimeout::Retransmit200)
1191 {
1192 if (mCurrentRetransmit200)
1193 {
1194 InfoLog (<< "Retransmitting: " << endl << mInvite200->brief());
1195 //DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
1196 send(mInvite200);
1197 mCurrentRetransmit200 *= 2;
1198 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
1199 }
1200 }
1201 else if (timeout.type() == DumTimeout::WaitForAck)
1202 {
1203 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
1204 {
1205 if (timeout.seq() == mLastRemoteSessionModification->header(h_CSeq).sequence())
1206 {
1207 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1208
1209 // If we are waiting for an Ack and it times out, then end with a BYE
1210 if(mState == UAS_WaitingToHangup ||
1211 mState == WaitingToHangup)
1212 {
1213 SharedPtr<SipMessage> msg = sendBye();
1214 transition(Terminated);
1215 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1216 }
1217 else if(mState == ReceivedReinviteSentOffer)
1218 {
1219 transition(Connected);
1220 mProposedLocalOfferAnswer.reset();
1221 mProposedEncryptionLevel = DialogUsageManager::None;
1222 //!dcm! -- should this be onIllegalNegotiation?
1223 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
1224 }
1225 else if(mState == WaitingToOffer ||
1226 mState == UAS_WaitingToOffer)
1227 {
1228 assert(mProposedLocalOfferAnswer.get());
1229 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1230 if(!isTerminated())
1231 {
1232 provideProposedOffer();
1233 }
1234 }
1235 else if(mState == WaitingToRequestOffer ||
1236 mState == UAS_WaitingToRequestOffer)
1237 {
1238 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1239 if(!isTerminated())
1240 {
1241 requestOffer();
1242 }
1243 }
1244 else
1245 {
1246 // this is so the app can decided to ignore this. default implementation
1247 // will call end next
1248 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1249 }
1250 }
1251 }
1252 }
1253 else if (timeout.type() == DumTimeout::CanDiscardAck)
1254 {
1255 AckMap::iterator i = mAcks.find(timeout.transactionId());
1256 if (i != mAcks.end())
1257 {
1258 mAcks.erase(i);
1259 }
1260 }
1261 else if (timeout.type() == DumTimeout::Glare)
1262 {
1263 if (mState == SentUpdateGlare)
1264 {
1265 transition(SentUpdate);
1266
1267 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
1268 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE); // increments CSeq
1269 send(mLastLocalSessionModification);
1270 }
1271 else if (mState == SentReinviteGlare)
1272 {
1273 transition(SentReinvite);
1274
1275 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
1276 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1277 startStaleReInviteTimer();
1278 send(mLastLocalSessionModification);
1279 }
1280 else if (mState == SentReinviteNoOfferGlare)
1281 {
1282 transition(SentReinviteNoOffer);
1283
1284 InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
1285 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1286 startStaleReInviteTimer();
1287 send(mLastLocalSessionModification);
1288 }
1289 }
1290 else if (timeout.type() == DumTimeout::StaleReInvite)
1291 {
1292 if(timeout.seq() == mStaleReInviteTimerSeq)
1293 {
1294 if(mState == WaitingToTerminate)
1295 {
1296 SharedPtr<SipMessage> msg = sendBye();
1297 transition(Terminated);
1298 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1299 }
1300 else if(mState == SentReinvite ||
1301 mState == SentReinviteNoOffer)
1302 {
1303 transition(Connected);
1304 mProposedLocalOfferAnswer.reset();
1305 mProposedEncryptionLevel = DialogUsageManager::None;
1306
1307 // this is so the app can decide to ignore this. default implementation
1308 // will call end next - which will send a BYE
1309 mDum.mInviteSessionHandler->onStaleReInviteTimeout(getSessionHandle());
1310 }
1311 }
1312 }
1313 else if (timeout.type() == DumTimeout::SessionExpiration)
1314 {
1315 if(timeout.seq() == mSessionTimerSeq)
1316 {
1317 // this is so the app can decide to ignore this. default implementation
1318 // will call end next - which will send a BYE
1319 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
1320 }
1321 }
1322 else if (timeout.type() == DumTimeout::SessionRefresh)
1323 {
1324 if(timeout.seq() == mSessionTimerSeq)
1325 {
1326 // Note: If not connected then we must be issueing a reinvite/update or
1327 // receiving one - in either case the session timer stuff will get
1328 // reset/renegotiated - thus just ignore this referesh
1329 if(mState == Connected)
1330 {
1331 sessionRefresh();
1332 }
1333 }
1334 }
1335 }
1336
1337 void
1338 InviteSession::dispatchConnected(const SipMessage& msg)
1339 {
1340 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1341 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1342
1343 switch (toEvent(msg, offerAnswer.get()))
1344 {
1345 case OnInvite:
1346 case OnInviteReliable:
1347 *mLastRemoteSessionModification = msg;
1348 transition(ReceivedReinviteNoOffer);
1349 handler->onOfferRequired(getSessionHandle(), msg);
1350 break;
1351
1352 case OnInviteOffer:
1353 case OnInviteReliableOffer:
1354 *mLastRemoteSessionModification = msg;
1355 transition(ReceivedReinvite);
1356 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1357 mProposedRemoteOfferAnswer = offerAnswer;
1358
1359 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1360 break;
1361
1362 case On2xx:
1363 case On2xxOffer:
1364 case On2xxAnswer:
1365 // retransmission of 200I
1366 // !jf! Need to include the answer here.
1367 sendAck();
1368 break;
1369
1370 case OnUpdateOffer:
1371 transition(ReceivedUpdate);
1372
1373 // !kh!
1374 // Find out if it's an UPDATE requiring state change.
1375 // See rfc3311 5.2, 4th paragraph.
1376 *mLastRemoteSessionModification = msg;
1377 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1378 mProposedRemoteOfferAnswer = offerAnswer;
1379 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1380 break;
1381
1382 case OnUpdate:
1383 {
1384 // ?slg? no offerAnswer in update - just respond immediately (likely session timer) - do we need a callback?
1385 SharedPtr<SipMessage> response(new SipMessage);
1386 *mLastRemoteSessionModification = msg;
1387 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
1388 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1389 send(response);
1390 break;
1391 }
1392
1393 case OnUpdateRejected:
1394 case On200Update:
1395 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
1396 assert(0);
1397 break;
1398
1399 case OnAck:
1400 case OnAckAnswer: // .bwc. Don't drop ACK with SDP!
1401 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1402 handler->onAckReceived(getSessionHandle(), msg);
1403 break;
1404
1405 default:
1406 dispatchOthers(msg);
1407 break;
1408 }
1409 }
1410
1411 void
1412 InviteSession::dispatchSentUpdate(const SipMessage& msg)
1413 {
1414 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1415 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1416
1417 switch (toEvent(msg, offerAnswer.get()))
1418 {
1419 case OnInvite:
1420 case OnInviteReliable:
1421 case OnInviteOffer:
1422 case OnInviteReliableOffer:
1423 case OnUpdate:
1424 case OnUpdateOffer:
1425 {
1426 // glare
1427 SharedPtr<SipMessage> response(new SipMessage);
1428 mDialog.makeResponse(*response, msg, 491);
1429 send(response);
1430 break;
1431 }
1432
1433 case On200Update:
1434 transition(Connected);
1435 handleSessionTimerResponse(msg);
1436 if (offerAnswer.get() && mProposedLocalOfferAnswer.get())
1437 {
1438 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1439 setCurrentLocalOfferAnswer(msg);
1440
1441 mCurrentRemoteOfferAnswer = offerAnswer;
1442 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1443 }
1444 else if(mProposedLocalOfferAnswer.get())
1445 {
1446 // If we sent an offer in the Update Request and no answer is received
1447 handler->onIllegalNegotiation(getSessionHandle(), msg);
1448 mProposedLocalOfferAnswer.reset();
1449 mProposedEncryptionLevel = DialogUsageManager::None;
1450 }
1451 break;
1452
1453 case On491Update:
1454 transition(SentUpdateGlare);
1455 start491Timer();
1456 break;
1457
1458 case On422Update: // session timer
1459 if(msg.exists(h_MinSE))
1460 {
1461 // Change interval to min from 422 response
1462 mSessionInterval = msg.header(h_MinSE).value();
1463 mMinSE = mSessionInterval;
1464 sessionRefresh();
1465 }
1466 else
1467 {
1468 // Response must contain Min_SE - if not - just ignore
1469 // ?slg? callback?
1470 transition(Connected);
1471 mProposedLocalOfferAnswer.reset();
1472 mProposedEncryptionLevel = DialogUsageManager::None;
1473 }
1474 break;
1475
1476 case OnUpdateRejected:
1477 transition(Connected);
1478 mProposedLocalOfferAnswer.reset();
1479 handler->onOfferRejected(getSessionHandle(), &msg);
1480 break;
1481
1482 case OnGeneralFailure:
1483 sendBye();
1484 transition(Terminated);
1485 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1486 break;
1487
1488 default:
1489 dispatchOthers(msg);
1490 break;
1491 }
1492 }
1493
1494 void
1495 InviteSession::dispatchSentReinvite(const SipMessage& msg)
1496 {
1497 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1498 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1499
1500 switch (toEvent(msg, offerAnswer.get()))
1501 {
1502 case OnInvite:
1503 case OnInviteReliable:
1504 case OnInviteOffer:
1505 case OnInviteReliableOffer:
1506 case OnUpdate:
1507 case OnUpdateOffer:
1508 {
1509 SharedPtr<SipMessage> response(new SipMessage);
1510 mDialog.makeResponse(*response, msg, 491);
1511 send(response);
1512 break;
1513 }
1514
1515 case On1xx:
1516 case On1xxEarly:
1517 // Some UA's send a 100 response to a ReInvite - just ignore it
1518 break;
1519
1520 case On2xxAnswer:
1521 case On2xxOffer: // .slg. doesn't really make sense
1522 {
1523 mStaleReInviteTimerSeq++;
1524 transition(Connected);
1525 handleSessionTimerResponse(msg);
1526 setCurrentLocalOfferAnswer(msg);
1527
1528 // !jf! I need to potentially include an answer in the ACK here
1529 sendAck();
1530 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1531
1532 if (mSessionRefreshReInvite)
1533 {
1534 mSessionRefreshReInvite = false;
1535
1536 MD5Stream currentRemote;
1537 currentRemote<< *mCurrentRemoteOfferAnswer;
1538 MD5Stream newRemote;
1539 newRemote << *offerAnswer;
1540 bool changed = currentRemote.getHex() != newRemote.getHex();
1541
1542 if (changed)
1543 {
1544 mCurrentRemoteOfferAnswer = offerAnswer;
1545 handler->onRemoteAnswerChanged(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1546 }
1547 }
1548 else
1549 {
1550 mCurrentRemoteOfferAnswer = offerAnswer;
1551 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1552 }
1553
1554 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1555 // the ACK when a 200I is received? If yes, then I need to store all
1556 // ACK messages for 64*T1
1557 break;
1558 }
1559 case On2xx:
1560 mStaleReInviteTimerSeq++;
1561 sendAck();
1562 transition(Connected);
1563 handleSessionTimerResponse(msg);
1564 handler->onIllegalNegotiation(getSessionHandle(), msg);
1565 mProposedLocalOfferAnswer.reset();
1566 mProposedEncryptionLevel = DialogUsageManager::None;
1567 break;
1568
1569 case On422Invite:
1570 mStaleReInviteTimerSeq++;
1571 if(msg.exists(h_MinSE))
1572 {
1573 // Change interval to min from 422 response
1574 mSessionInterval = msg.header(h_MinSE).value();
1575 mMinSE = mSessionInterval;
1576 sessionRefresh();
1577 }
1578 else
1579 {
1580 // Response must contact Min_SE - if not - just ignore
1581 // ?slg? callback?
1582 transition(Connected);
1583 mProposedLocalOfferAnswer.reset();
1584 mProposedEncryptionLevel = DialogUsageManager::None;
1585 }
1586 break;
1587
1588 case On491Invite:
1589 mStaleReInviteTimerSeq++;
1590 transition(SentReinviteGlare);
1591 start491Timer();
1592 break;
1593
1594 case OnGeneralFailure:
1595 mStaleReInviteTimerSeq++;
1596 sendBye();
1597 transition(Terminated);
1598 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1599 break;
1600
1601 case OnInviteFailure:
1602 case On487Invite:
1603 mStaleReInviteTimerSeq++;
1604 transition(Connected);
1605 mProposedLocalOfferAnswer.reset();
1606 handler->onOfferRejected(getSessionHandle(), &msg);
1607 break;
1608
1609 default:
1610 dispatchOthers(msg);
1611 break;
1612 }
1613 }
1614
1615 void
1616 InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1617 {
1618 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1619 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1620
1621 switch (toEvent(msg, offerAnswer.get()))
1622 {
1623 case OnInvite:
1624 case OnInviteReliable:
1625 case OnInviteOffer:
1626 case OnInviteReliableOffer:
1627 case OnUpdate:
1628 case OnUpdateOffer:
1629 {
1630 SharedPtr<SipMessage> response(new SipMessage);
1631 mDialog.makeResponse(*response, msg, 491);
1632 send(response);
1633 break;
1634 }
1635
1636 case On1xx:
1637 case On1xxEarly:
1638 // Some UA's send a 100 response to a ReInvite - just ignore it
1639 break;
1640
1641 case On2xxAnswer: // .slg. doesn't really make sense
1642 case On2xxOffer:
1643 {
1644 mStaleReInviteTimerSeq++;
1645 transition(SentReinviteAnswered);
1646 handleSessionTimerResponse(msg);
1647 // mLastSessionModification = msg; // ?slg? why are we storing 200's?
1648 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1649 mProposedRemoteOfferAnswer = offerAnswer;
1650 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1651 break;
1652 }
1653
1654 case On2xx:
1655 mStaleReInviteTimerSeq++;
1656 sendAck();
1657 transition(Connected);
1658 handleSessionTimerResponse(msg);
1659 handler->onIllegalNegotiation(getSessionHandle(), msg);
1660 mProposedLocalOfferAnswer.reset();
1661 mProposedEncryptionLevel = DialogUsageManager::None;
1662 break;
1663
1664 case On422Invite:
1665 mStaleReInviteTimerSeq++;
1666 if(msg.exists(h_MinSE))
1667 {
1668 // Change interval to min from 422 response
1669 mSessionInterval = msg.header(h_MinSE).value();
1670 mMinSE = mSessionInterval;
1671 sessionRefresh();
1672 }
1673 else
1674 {
1675 // Response must contact Min_SE - if not - just ignore
1676 // ?slg? callback?
1677 transition(Connected);
1678 mProposedLocalOfferAnswer.reset();
1679 mProposedEncryptionLevel = DialogUsageManager::None;
1680 }
1681 break;
1682
1683 case On491Invite:
1684 mStaleReInviteTimerSeq++;
1685 transition(SentReinviteNoOfferGlare);
1686 start491Timer();
1687 break;
1688
1689 case OnGeneralFailure:
1690 mStaleReInviteTimerSeq++;
1691 sendBye();
1692 transition(Terminated);
1693 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1694 break;
1695
1696 case OnInviteFailure:
1697 case On487Invite:
1698 mStaleReInviteTimerSeq++;
1699 transition(Connected);
1700 mProposedLocalOfferAnswer.reset();
1701 handler->onOfferRejected(getSessionHandle(), &msg);
1702 break;
1703
1704 default:
1705 dispatchOthers(msg);
1706 break;
1707 }
1708 }
1709
1710 void
1711 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1712 {
1713 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1714 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1715
1716 switch (toEvent(msg, offerAnswer.get()))
1717 {
1718 case OnInvite:
1719 case OnInviteReliable:
1720 case OnInviteOffer:
1721 case OnInviteReliableOffer:
1722 case OnUpdate:
1723 case OnUpdateOffer:
1724 {
1725 SharedPtr<SipMessage> response(new SipMessage);
1726 mDialog.makeResponse(*response, msg, 491);
1727 send(response);
1728 break;
1729 }
1730 case OnAckAnswer:
1731 transition(Connected);
1732 setCurrentLocalOfferAnswer(msg);
1733 mCurrentRemoteOfferAnswer = offerAnswer;
1734 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1735 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1736
1737 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1738 break;
1739 case OnAck:
1740 if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
1741 {
1742 InfoLog(<< "dropped stale ACK");
1743 }
1744 else
1745 {
1746 InfoLog(<< "Got Ack with no answer");
1747 transition(Connected);
1748 mProposedLocalOfferAnswer.reset();
1749 mProposedEncryptionLevel = DialogUsageManager::None;
1750 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1751 //!dcm! -- should this be onIllegalNegotiation?
1752 handler->onOfferRejected(getSessionHandle(), &msg);
1753 }
1754 break;
1755 default:
1756 dispatchOthers(msg);
1757 break;
1758 }
1759 }
1760
1761 void
1762 InviteSession::dispatchGlare(const SipMessage& msg)
1763 {
1764 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1765 MethodTypes method = msg.header(h_CSeq).method();
1766 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1767 {
1768 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1769 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1770 handler->onOfferRejected(getSessionHandle(), &msg);
1771 if(!isTerminated()) // make sure application didn't call end()
1772 {
1773 dispatchConnected(msg); // act as if we received message in Connected state
1774 }
1775 else
1776 {
1777 dispatchTerminated(msg);
1778 }
1779 }
1780 else
1781 {
1782 dispatchOthers(msg);
1783 }
1784 }
1785
1786 void
1787 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1788 {
1789 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1790 MethodTypes method = msg.header(h_CSeq).method();
1791 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1792 {
1793 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1794 handler->onOfferRequestRejected(getSessionHandle(), msg);
1795 if(!isTerminated()) // make sure application didn't call end()
1796 {
1797 dispatchConnected(msg); // act as if we received message in Connected state
1798 }
1799 else
1800 {
1801 dispatchTerminated(msg);
1802 }
1803 }
1804 else
1805 {
1806 dispatchOthers(msg);
1807 }
1808 }
1809
1810 void
1811 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1812 {
1813 // InviteSessionHandler* handler = mDum.mInviteSessionHandler; // unused
1814 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1815
1816 switch (toEvent(msg, offerAnswer.get()))
1817 {
1818 case OnInvite:
1819 case OnInviteReliable:
1820 case OnInviteOffer:
1821 case OnInviteReliableOffer:
1822 case OnUpdate:
1823 case OnUpdateOffer:
1824 {
1825 // Means that the UAC has sent us a second reINVITE or UPDATE before we
1826 // responded to the first one. Bastard!
1827 SharedPtr<SipMessage> response(new SipMessage);
1828 mDialog.makeResponse(*response, msg, 500);
1829 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1830 send(response);
1831 break;
1832 }
1833 case OnBye:
1834 {
1835 // BYE received after a reINVITE, terminate the reINVITE transaction.
1836 SharedPtr<SipMessage> response(new SipMessage);
1837 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 487); // Request Terminated
1838 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1839 send(response);
1840
1841 dispatchBye(msg);
1842 break;
1843 }
1844 default:
1845 dispatchOthers(msg);
1846 break;
1847 }
1848 }
1849
1850
1851 void
1852 InviteSession::dispatchAnswered(const SipMessage& msg)
1853 {
1854 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1855 {
1856 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1857 transition(Connected);
1858 }
1859 else
1860 {
1861 dispatchOthers(msg);
1862 }
1863 }
1864
1865 void
1866 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1867 {
1868 if (msg.isResponse() &&
1869 msg.header(h_CSeq).method() == INVITE &&
1870 msg.header(h_StatusLine).statusCode() / 200 == 1)
1871 {
1872 // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
1873 // called by the app - so just drop the retransmission
1874 return;
1875 }
1876 dispatchOthers(msg);
1877 }
1878
1879 void
1880 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1881 {
1882 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1883 {
1884 assert(mProposedLocalOfferAnswer.get());
1885 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1886 provideProposedOffer();
1887 }
1888 else
1889 {
1890 dispatchOthers(msg);
1891 }
1892 }
1893
1894 void
1895 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1896 {
1897 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1898 {
1899 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1900 requestOffer();
1901 }
1902 else
1903 {
1904 dispatchOthers(msg);
1905 }
1906 }
1907
1908 void
1909 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1910 {
1911 if (msg.isResponse() &&
1912 msg.header(h_CSeq).method() == INVITE)
1913 {
1914 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1915 {
1916 // !jf! Need to include the answer here.
1917 sendAck();
1918 }
1919 SharedPtr<SipMessage> msg = sendBye();
1920 transition(Terminated);
1921 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1922 }
1923 else if(msg.isRequest())
1924 {
1925 if(msg.method() == BYE)
1926 {
1927 dispatchBye(msg);
1928 }
1929 else
1930 {
1931 SharedPtr<SipMessage> response(new SipMessage);
1932 mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
1933 send(response);
1934 }
1935 }
1936 }
1937
1938 void
1939 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1940 {
1941 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1942
1943 switch (toEvent(msg, offerAnswer.get()))
1944 {
1945 case OnAck:
1946 case OnAckAnswer:
1947 {
1948 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1949
1950 SharedPtr<SipMessage> msg = sendBye();
1951 transition(Terminated);
1952 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1953 break;
1954 }
1955
1956 default:
1957 break;
1958 }
1959 }
1960
1961 void
1962 InviteSession::dispatchTerminated(const SipMessage& msg)
1963 {
1964 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1965
1966 if (msg.isRequest())
1967 {
1968 if (BYE == msg.header(h_CSeq).method())
1969 {
1970 SharedPtr<SipMessage> response(new SipMessage);
1971 mDialog.makeResponse(*response, msg, 200);
1972 send(response);
1973 }
1974 else
1975 {
1976 SharedPtr<SipMessage> response(new SipMessage);
1977 mDialog.makeResponse(*response, msg, 481);
1978 send(response);
1979 }
1980
1981 // !jf! means the peer sent BYE while we are waiting for response to BYE
1982 //mDum.destroy(this);
1983 }
1984 else
1985 {
1986 mDum.destroy(this);
1987 }
1988 }
1989
1990 void
1991 InviteSession::dispatchOthers(const SipMessage& msg)
1992 {
1993 // handle OnGeneralFailure
1994 // handle OnRedirect
1995
1996 switch (msg.header(h_CSeq).method())
1997 {
1998 case PRACK:
1999 dispatchPrack(msg);
2000 break;
2001 case CANCEL:
2002 dispatchCancel(msg);
2003 break;
2004 case BYE:
2005 dispatchBye(msg);
2006 break;
2007 case INFO:
2008 dispatchInfo(msg);
2009 break;
2010 case MESSAGE:
2011 dispatchMessage(msg);
2012 break;
2013 case ACK:
2014 // Ignore duplicate ACKs from 2xx reTransmissions
2015 break;
2016 default:
2017 // handled in Dialog
2018 WarningLog (<< "DUM delivered a "
2019 << msg.header(h_CSeq).unknownMethodName()
2020 << " to the InviteSession in state: " << toData(mState)
2021 << endl
2022 << msg);
2023 assert(0);
2024 break;
2025 }
2026 }
2027
2028 void
2029 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
2030 {
2031 assert(msg.isRequest());
2032 assert(msg.header(h_CSeq).method() == INVITE);
2033
2034 // If we get an INVITE request from the wire and we are not in
2035 // Connected state, reject the request and send a BYE
2036 SharedPtr<SipMessage> response(new SipMessage);
2037 mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
2038 InfoLog (<< "Sending " << response->brief());
2039 send(response);
2040
2041 sendBye();
2042 transition(Terminated);
2043 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2044 }
2045
2046 void
2047 InviteSession::dispatchPrack(const SipMessage& msg)
2048 {
2049 assert(msg.header(h_CSeq).method() == PRACK);
2050 if(msg.isRequest())
2051 {
2052 SharedPtr<SipMessage> rsp(new SipMessage);
2053 mDialog.makeResponse(*rsp, msg, 481);
2054 send(rsp);
2055
2056 sendBye();
2057 // !jf! should we make some other callback here
2058 transition(Terminated);
2059 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2060 }
2061 else
2062 {
2063 // ignore. could be PRACK/200
2064 }
2065 }
2066
2067 void
2068 InviteSession::dispatchCancel(const SipMessage& msg)
2069 {
2070 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2071 assert(msg.header(h_CSeq).method() == CANCEL);
2072 if(msg.isRequest())
2073 {
2074 SharedPtr<SipMessage> rsp(new SipMessage);
2075 mDialog.makeResponse(*rsp, msg, 200);
2076 send(rsp);
2077
2078 sendBye();
2079 // !jf! should we make some other callback here
2080 transition(Terminated);
2081
2082 handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteCancel, &msg);
2083 }
2084 else
2085 {
2086 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
2087 assert(0);
2088 }
2089 }
2090
2091 void
2092 InviteSession::dispatchBye(const SipMessage& msg)
2093 {
2094 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2095
2096 if (msg.isRequest())
2097 {
2098 // Check for any non-invite server transactions (e.g. INFO)
2099 // that have not been responded yet and terminate them.
2100 if (mServerNitState == NitProceeding)
2101 {
2102 mLastNitResponse->header(h_StatusLine).statusCode() = 487;
2103 mLastNitResponse->setContents(0);
2104 Helper::getResponseCodeReason(487, mLastNitResponse->header(h_StatusLine).reason());
2105 send(mLastNitResponse);
2106 mServerNitState = NitComplete;
2107 }
2108
2109 SharedPtr<SipMessage> rsp(new SipMessage);
2110 InfoLog (<< "Received " << msg.brief());
2111 mDialog.makeResponse(*rsp, msg, 200);
2112 send(rsp);
2113
2114 // !jf! should we make some other callback here
2115 transition(Terminated);
2116
2117 if (mDum.mDialogEventStateManager)
2118 {
2119 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::RemoteBye);
2120 }
2121
2122 handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
2123 mDum.destroy(this);
2124 }
2125 else
2126 {
2127 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
2128 assert(0);
2129 }
2130 }
2131
2132 void
2133 InviteSession::dispatchInfo(const SipMessage& msg)
2134 {
2135 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2136 if (msg.isRequest())
2137 {
2138 if (mServerNitState == NitProceeding)
2139 {
2140 // Means that the UAC has sent us a second INFO before we
2141 // responded to the first one.
2142 SharedPtr<SipMessage> response(new SipMessage);
2143 mDialog.makeResponse(*response, msg, 500);
2144 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2145 send(response);
2146 }
2147 else
2148 {
2149 InfoLog (<< "Received " << msg.brief());
2150 mServerNitState = NitProceeding;
2151 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2152 handler->onInfo(getSessionHandle(), msg);
2153 }
2154 }
2155 else
2156 {
2157 assert(mNitState == NitProceeding);
2158 //!dcm! -- toss away 1xx to an info?
2159 if (msg.header(h_StatusLine).statusCode() >= 300)
2160 {
2161 handler->onInfoFailure(getSessionHandle(), msg);
2162 }
2163 else if (msg.header(h_StatusLine).statusCode() >= 200)
2164 {
2165 handler->onInfoSuccess(getSessionHandle(), msg);
2166 }
2167 nitComplete();
2168 }
2169 }
2170
2171 void
2172 InviteSession::acceptNIT(int statusCode, const Contents * contents)
2173 {
2174 if (statusCode / 100 != 2)
2175 {
2176 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2177 }
2178
2179 if (mServerNitState != NitProceeding )
2180 {
2181 throw UsageUseException("No transaction to accept", __FILE__, __LINE__);
2182 }
2183
2184 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2185 mLastNitResponse->setContents(contents);
2186 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2187 send(mLastNitResponse);
2188 mServerNitState = NitComplete;
2189 }
2190
2191 class InviteSessionAcceptNITCommand : public DumCommandAdapter
2192 {
2193 public:
2194 InviteSessionAcceptNITCommand(InviteSession& inviteSession, int statusCode, const Contents* contents)
2195 : mInviteSession(inviteSession),
2196 mStatusCode(statusCode),
2197 mContents(contents?contents->clone():0)
2198 {
2199
2200 }
2201
2202 virtual void executeCommand()
2203 {
2204 mInviteSession.acceptNITCommand(mStatusCode, mContents.get());
2205 }
2206
2207 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2208 {
2209 return strm << "InviteSessionAcceptNITCommand";
2210 }
2211 private:
2212 InviteSession& mInviteSession;
2213 int mStatusCode;
2214 std::auto_ptr<Contents> mContents;
2215 };
2216
2217 void
2218 InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
2219 {
2220 mDum.post(new InviteSessionAcceptNITCommand(*this, statusCode, contents));
2221 }
2222
2223 void
2224 InviteSession::rejectNIT(int statusCode)
2225 {
2226 if (statusCode < 400)
2227 {
2228 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2229 }
2230
2231 if (mServerNitState != NitProceeding )
2232 {
2233 throw UsageUseException("No transaction to reject", __FILE__, __LINE__);
2234 }
2235
2236 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2237 mLastNitResponse->setContents(0);
2238 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2239 send(mLastNitResponse);
2240 mServerNitState = NitComplete;
2241 }
2242
2243 class InviteSessionRejectNITCommand : public DumCommandAdapter
2244 {
2245 public:
2246 InviteSessionRejectNITCommand(InviteSession& inviteSession, int statusCode)
2247 : mInviteSession(inviteSession),
2248 mStatusCode(statusCode)
2249 {
2250 }
2251
2252 virtual void executeCommand()
2253 {
2254 mInviteSession.rejectNITCommand(mStatusCode);
2255 }
2256
2257 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2258 {
2259 return strm << "InviteSessionRejectNITCommand";
2260 }
2261 private:
2262 InviteSession& mInviteSession;
2263 int mStatusCode;
2264 };
2265
2266 void
2267 InviteSession::rejectNITCommand(int statusCode)
2268 {
2269 mDum.post(new InviteSessionRejectNITCommand(*this, statusCode));
2270 }
2271
2272 void
2273 InviteSession::dispatchMessage(const SipMessage& msg)
2274 {
2275 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2276 if (msg.isRequest())
2277 {
2278 if (mServerNitState == NitProceeding)
2279 {
2280 // Means that the UAC has sent us a second NIT message before we
2281 // responded to the first one.
2282 SharedPtr<SipMessage> response(new SipMessage);
2283 mDialog.makeResponse(*response, msg, 500);
2284 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2285 send(response);
2286 }
2287 else
2288 {
2289 InfoLog (<< "Received " << msg.brief());
2290 mServerNitState = NitProceeding;
2291 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2292 mLastNitResponse->header(h_Contacts).clear();
2293 handler->onMessage(getSessionHandle(), msg);
2294 }
2295 }
2296 else
2297 {
2298 assert(mNitState == NitProceeding);
2299 //!dcm! -- toss away 1xx to an message?
2300 if (msg.header(h_StatusLine).statusCode() >= 300)
2301 {
2302 handler->onMessageFailure(getSessionHandle(), msg);
2303 }
2304 else if (msg.header(h_StatusLine).statusCode() >= 200)
2305 {
2306 handler->onMessageSuccess(getSessionHandle(), msg);
2307 }
2308 nitComplete();
2309 }
2310 }
2311
2312 void
2313 InviteSession::startRetransmit200Timer()
2314 {
2315 mCurrentRetransmit200 = Timer::T1;
2316 unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
2317 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
2318 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
2319 }
2320
2321 // RFC3261 section 14.1
2322 // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
2323 // a value T chosen as follows:
2324 // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
2325 // chosen value between 2.1 and 4 seconds in units of 10 ms.
2326 // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
2327 // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
2328 void
2329 InviteSession::start491Timer()
2330 {
2331 unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
2332
2333 if (dynamic_cast<ClientInviteSession*>(this))
2334 {
2335 int timer = Random::getRandom() % (4000 - 2100);
2336 timer += 2100;
2337 timer -= timer % 10;
2338
2339 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2340 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2341 }
2342 else
2343 {
2344 int timer = Random::getRandom() % 2000;
2345 timer -= timer % 10;
2346 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2347 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2348 }
2349 }
2350
2351 void
2352 InviteSession::startStaleReInviteTimer()
2353 {
2354 InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
2355 unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
2356
2357 mDum.addTimer(DumTimeout::StaleReInvite,
2358 when,
2359 getBaseHandle(),
2360 ++mStaleReInviteTimerSeq);
2361 }
2362
2363 void
2364 InviteSession::setSessionTimerHeaders(SipMessage &msg)
2365 {
2366 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
2367 {
2368 msg.header(h_SessionExpires).value() = mSessionInterval;
2369 if(msg.isRequest())
2370 {
2371 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
2372 }
2373 else
2374 {
2375 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
2376 }
2377 msg.header(h_MinSE).value() = mMinSE;
2378 }
2379 else
2380 {
2381 msg.remove(h_SessionExpires);
2382 msg.remove(h_MinSE);
2383 }
2384 }
2385
2386 void
2387 InviteSession::sessionRefresh()
2388 {
2389 if (updateMethodSupported())
2390 {
2391 transition(SentUpdate);
2392 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
2393 mLastLocalSessionModification->setContents(0); // Don't send SDP
2394 }
2395 else
2396 {
2397 transition(SentReinvite);
2398 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
2399 startStaleReInviteTimer();
2400 InviteSession::setOfferAnswer(*mLastLocalSessionModification, mCurrentLocalOfferAnswer.get());
2401 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(*mCurrentLocalOfferAnswer.get(), 0);
2402 mSessionRefreshReInvite = true;
2403 }
2404 setSessionTimerHeaders(*mLastLocalSessionModification);
2405
2406 InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
2407 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
2408 send(mLastLocalSessionModification);
2409 }
2410
2411 void
2412 InviteSession::setSessionTimerPreferences()
2413 {
2414 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
2415 if(mSessionInterval != 0)
2416 {
2417 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
2418 mSessionInterval = resipMax(mMinSE, mSessionInterval);
2419 }
2420 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
2421 {
2422 case Profile::PreferLocalRefreshes:
2423 mSessionRefresher = true; // Default refresher is Local
2424 break;
2425 case Profile::PreferRemoteRefreshes:
2426 mSessionRefresher = false; // Default refresher is Remote
2427 break;
2428 case Profile::PreferCalleeRefreshes:
2429 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is callee
2430 break;
2431 case Profile::PreferCallerRefreshes:
2432 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is caller
2433 break;
2434 }
2435 }
2436
2437 void
2438 InviteSession::startSessionTimer()
2439 {
2440 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
2441 {
2442 // Check if we are the refresher
2443 if(mSessionRefresher)
2444 {
2445 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
2446 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
2447 }
2448 else
2449 {
2450 // 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)
2451 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
2452 }
2453 }
2454 else // Session Interval less than 90 - consider timers disabled
2455 {
2456 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
2457 }
2458 }
2459
2460 void
2461 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
2462 {
2463 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
2464
2465 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2466 if (msg.exists(h_PAssertedIdentities))
2467 {
2468 mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
2469 }
2470
2471 // If session timers are locally supported then handle response
2472 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2473 {
2474 setSessionTimerPreferences();
2475
2476 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
2477 && !msg.exists(h_SessionExpires))
2478 {
2479 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
2480 mSessionInterval = 0;
2481 }
2482 // Process Session Timer headers
2483 else if(msg.exists(h_SessionExpires))
2484 {
2485 mSessionInterval = msg.header(h_SessionExpires).value();
2486 if(msg.header(h_SessionExpires).exists(p_refresher))
2487 {
2488 // Remote end specified refresher preference
2489 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
2490 }
2491 }
2492 else
2493 {
2494 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
2495 // - we are free to use our SessionInterval settings (set above as a default)
2496 // If far end doesn't support then refresher must be local
2497 mSessionRefresher = true;
2498 }
2499
2500 // Update MinSE if specified and longer than current value
2501 if(msg.exists(h_MinSE))
2502 {
2503 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
2504 }
2505
2506 startSessionTimer();
2507 }
2508 }
2509
2510 void
2511 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
2512 {
2513 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
2514
2515 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2516 if (request.exists(h_PAssertedIdentities))
2517 {
2518 mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
2519 }
2520
2521 // If session timers are locally supported then add necessary headers to response
2522 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2523 {
2524 setSessionTimerPreferences();
2525
2526 // Check if far-end supports
2527 bool farEndSupportsTimer = false;
2528 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
2529 {
2530 farEndSupportsTimer = true;
2531 if(request.exists(h_SessionExpires))
2532 {
2533 // Use Session Interval requested by remote - if none then use local settings
2534 mSessionInterval = request.header(h_SessionExpires).value();
2535 if(request.header(h_SessionExpires).exists(p_refresher))
2536 {
2537 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
2538 }
2539 }
2540
2541 // Update MinSE if specified and longer than current value
2542 if(request.exists(h_MinSE))
2543 {
2544 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
2545 }
2546 }
2547 else
2548 {
2549 // If far end doesn't support then refresher must be local
2550 mSessionRefresher = true;
2551 }
2552
2553 // Add Session-Expires to response if required
2554 if(mSessionInterval >= 90)
2555 {
2556 if(farEndSupportsTimer)
2557 {
2558 // If far end supports session-timer then require it, if not already present
2559 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
2560 {
2561 response.header(h_Requires).push_back(Token(Symbols::Timer));
2562 }
2563 }
2564 setSessionTimerHeaders(response);
2565 }
2566
2567 startSessionTimer();
2568 }
2569 }
2570
2571 Data
2572 InviteSession::toData(State state)
2573 {
2574 switch (state)
2575 {
2576 case Undefined:
2577 return "InviteSession::Undefined";
2578 case Connected:
2579 return "InviteSession::Connected";
2580 case SentUpdate:
2581 return "InviteSession::SentUpdate";
2582 case SentUpdateGlare:
2583 return "InviteSession::SentUpdateGlare";
2584 case SentReinvite:
2585 return "InviteSession::SentReinvite";
2586 case SentReinviteGlare:
2587 return "InviteSession::SentReinviteGlare";
2588 case SentReinviteNoOffer:
2589 return "InviteSession::SentReinviteNoOffer";
2590 case SentReinviteAnswered:
2591 return "InviteSession::SentReinviteAnswered";
2592 case SentReinviteNoOfferGlare:
2593 return "InviteSession::SentReinviteNoOfferGlare";
2594 case ReceivedUpdate:
2595 return "InviteSession::ReceivedUpdate";
2596 case ReceivedReinvite:
2597 return "InviteSession::ReceivedReinvite";
2598 case ReceivedReinviteNoOffer:
2599 return "InviteSession::ReceivedReinviteNoOffer";
2600 case ReceivedReinviteSentOffer:
2601 return "InviteSession::ReceivedReinviteSentOffer";
2602 case Answered:
2603 return "InviteSession::Answered";
2604 case WaitingToOffer:
2605 return "InviteSession::WaitingToOffer";
2606 case WaitingToRequestOffer:
2607 return "InviteSession::WaitingToRequestOffer";
2608 case WaitingToTerminate:
2609 return "InviteSession::WaitingToTerminate";
2610 case WaitingToHangup:
2611 return "InviteSession::WaitingToHangup";
2612 case Terminated:
2613 return "InviteSession::Terminated";
2614
2615 case UAC_Start:
2616 return "UAC_Start";
2617 case UAS_Offer:
2618 return "UAS_Offer";
2619 case UAS_OfferProvidedAnswer:
2620 return "UAS_OfferProvidedAnswer";
2621 case UAS_EarlyOffer:
2622 return "UAS_EarlyOffer";
2623 case UAS_EarlyProvidedAnswer:
2624 return "UAS_EarlyProvidedAnswer";
2625 case UAS_NoOffer:
2626 return "UAS_NoOffer";
2627 case UAS_ProvidedOffer:
2628 return "UAS_ProvidedOffer";
2629 case UAS_EarlyNoOffer:
2630 return "UAS_EarlyNoOffer";
2631 case UAS_EarlyProvidedOffer:
2632 return "UAS_EarlyProvidedOffer";
2633 case UAS_Accepted:
2634 return "UAS_Accepted";
2635 case UAS_WaitingToOffer:
2636 return "UAS_WaitingToOffer";
2637 case UAS_AcceptedWaitingAnswer:
2638 return "UAS_AcceptedWaitingAnswer";
2639 case UAC_Early:
2640 return "UAC_Early";
2641 case UAC_EarlyWithOffer:
2642 return "UAC_EarlyWithOffer";
2643 case UAC_EarlyWithAnswer:
2644 return "UAC_EarlyWithAnswer";
2645 case UAC_Answered:
2646 return "UAC_Answered";
2647 case UAC_SentUpdateEarly:
2648 return "UAC_SentUpdateEarly";
2649 case UAC_SentUpdateEarlyGlare:
2650 return "UAC_SentUpdateEarlyGlare";
2651 case UAC_ReceivedUpdateEarly:
2652 return "UAC_ReceivedUpdateEarly";
2653 case UAC_SentAnswer:
2654 return "UAC_SentAnswer";
2655 case UAC_QueuedUpdate:
2656 return "UAC_QueuedUpdate";
2657 case UAC_Cancelled:
2658 return "UAC_Cancelled";
2659
2660 case UAS_Start:
2661 return "UAS_Start";
2662 case UAS_ReceivedOfferReliable:
2663 return "UAS_ReceivedOfferReliable";
2664 case UAS_NoOfferReliable:
2665 return "UAS_NoOfferReliable";
2666 case UAS_FirstSentOfferReliable:
2667 return "UAS_FirstSentOfferReliable";
2668 case UAS_FirstSentAnswerReliable:
2669 return "UAS_FirstSentAnswerReliable";
2670 case UAS_NegotiatedReliable:
2671 return "UAS_NegotiatedReliable";
2672 case UAS_SentUpdate:
2673 return "UAS_SentUpdate";
2674 case UAS_SentUpdateAccepted:
2675 return "UAS_SentUpdateAccepted";
2676 case UAS_ReceivedUpdate:
2677 return "UAS_ReceivedUpdate";
2678 case UAS_ReceivedUpdateWaitingAnswer:
2679 return "UAS_ReceivedUpdateWaitingAnswer";
2680 case UAS_WaitingToTerminate:
2681 return "UAS_WaitingToTerminate";
2682 case UAS_WaitingToHangup:
2683 return "UAS_WaitingToHangup";
2684 case UAS_WaitingToRequestOffer:
2685 return "UAS_WaitingToRequestOffer";
2686 }
2687 assert(0);
2688 return "Undefined";
2689 }
2690
2691
2692 void
2693 InviteSession::transition(State target)
2694 {
2695 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
2696 mState = target;
2697 }
2698
2699 bool
2700 InviteSession::isReliable(const SipMessage& msg)
2701 {
2702 if(msg.method() != INVITE)
2703 {
2704 return false;
2705 }
2706 if(msg.isRequest())
2707 {
2708 return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never
2709 && ((msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)))
2710 || (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
2711 }
2712 else
2713 {
2714 return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never
2715 && msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel));
2716 }
2717 }
2718
2719 //static std::auto_ptr<SdpContents> emptySdp;
2720 std::auto_ptr<Contents>
2721 InviteSession::getOfferAnswer(const SipMessage& msg)
2722 {
2723 if(mDum.mInviteSessionHandler->isGenericOfferAnswer())
2724 {
2725 if(msg.getContents())
2726 {
2727 return std::auto_ptr<Contents>(msg.getContents()->clone());
2728 }
2729 else
2730 {
2731 return std::auto_ptr<Contents>();
2732 }
2733 }
2734 else
2735 {
2736 return std::auto_ptr<Contents>(Helper::getSdp(msg.getContents()));
2737 }
2738 }
2739
2740 std::auto_ptr<Contents>
2741 InviteSession::makeOfferAnswer(const Contents& offerAnswer)
2742 {
2743 return std::auto_ptr<Contents>(static_cast<Contents*>(offerAnswer.clone()));
2744 }
2745
2746 auto_ptr<Contents>
2747 InviteSession::makeOfferAnswer(const Contents& offerAnswer,
2748 const Contents* alternative)
2749 {
2750 if (alternative)
2751 {
2752 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2753 mac->parts().push_back(alternative->clone());
2754 mac->parts().push_back(offerAnswer.clone());
2755 return auto_ptr<Contents>(mac);
2756 }
2757 else
2758 {
2759 return auto_ptr<Contents>(offerAnswer.clone());
2760 }
2761 }
2762
2763 void
2764 InviteSession::setOfferAnswer(SipMessage& msg, const Contents& offerAnswer, const Contents* alternative)
2765 {
2766 // !jf! should deal with multipart here
2767
2768 // This will clone the offerAnswer since the InviteSession also wants to keep its own
2769 // copy of the offerAnswer around for the application to access
2770 if (alternative)
2771 {
2772 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2773 mac->parts().push_back(alternative->clone());
2774 mac->parts().push_back(offerAnswer.clone());
2775 msg.setContents(auto_ptr<Contents>(mac));
2776 }
2777 else
2778 {
2779 msg.setContents(&offerAnswer);
2780 }
2781 }
2782
2783 void
2784 InviteSession::setOfferAnswer(SipMessage& msg, const Contents* offerAnswer)
2785 {
2786 assert(offerAnswer);
2787 msg.setContents(offerAnswer);
2788 }
2789
2790 void
2791 InviteSession::provideProposedOffer()
2792 {
2793 MultipartAlternativeContents* mp_ans =
2794 dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get());
2795 if (mp_ans)
2796 {
2797 // .kw. can cast below ever be NULL? Need assert/throw?
2798 provideOffer( *(dynamic_cast<Contents*>((mp_ans)->parts().back())),
2799 mProposedEncryptionLevel,
2800 dynamic_cast<Contents*>((mp_ans)->parts().front()));
2801 }
2802 else
2803 {
2804 // .kw. can cast below ever be NULL? Need assert/throw?
2805 provideOffer(*(dynamic_cast<Contents*>(mProposedLocalOfferAnswer.get())), mProposedEncryptionLevel, 0);
2806 }
2807 }
2808
2809 InviteSession::Event
2810 InviteSession::toEvent(const SipMessage& msg, const Contents* offerAnswer)
2811 {
2812 MethodTypes method = msg.header(h_CSeq).method();
2813 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2814
2815 //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
2816 //responses, reiable provisionals should only be received if the invite was
2817 //sent reliably. Spurious reliable provisional respnoses are dropped outside
2818 //the state machine.
2819 bool reliable = isReliable(msg);
2820 bool sentOffer = mProposedLocalOfferAnswer.get();
2821
2822 if (code == 481 || code == 408)
2823 {
2824 return OnGeneralFailure;
2825 }
2826 else if (code >= 300 && code <= 399)
2827 {
2828 return OnRedirect;
2829 }
2830 else if (method == INVITE && code == 0)
2831 {
2832 if (offerAnswer)
2833 {
2834 if (reliable)
2835 {
2836 return OnInviteReliableOffer;
2837 }
2838 else
2839 {
2840 return OnInviteOffer;
2841 }
2842 }
2843 else
2844 {
2845 if (reliable)
2846 {
2847 return OnInviteReliable;
2848 }
2849 else
2850 {
2851 return OnInvite;
2852 }
2853 }
2854 }
2855 else if (method == INVITE && code > 100 && code < 200)
2856 {
2857 if (reliable)
2858 {
2859 if (offerAnswer)
2860 {
2861 if (sentOffer)
2862 {
2863 return On1xxAnswer;
2864 }
2865 else
2866 {
2867 return On1xxOffer;
2868 }
2869 }
2870 else
2871 {
2872 return On1xx;
2873 }
2874 }
2875 else
2876 {
2877 if (offerAnswer)
2878 {
2879 return On1xxEarly;
2880 }
2881 else
2882 {
2883 return On1xx;
2884 }
2885 }
2886 }
2887 else if (method == INVITE && code >= 200 && code < 300)
2888 {
2889 if (offerAnswer)
2890 {
2891 if (sentOffer)
2892 {
2893 return On2xxAnswer;
2894 }
2895 else
2896 {
2897 return On2xxOffer;
2898 }
2899 }
2900 else
2901 {
2902 return On2xx;
2903 }
2904 }
2905 else if (method == INVITE && code == 422)
2906 {
2907 return On422Invite;
2908 }
2909 else if (method == INVITE && code == 487)
2910 {
2911 return On487Invite;
2912 }
2913 else if (method == INVITE && code == 491)
2914 {
2915 return On491Invite;
2916 }
2917 else if (method == INVITE && code >= 400)
2918 {
2919 return OnInviteFailure;
2920 }
2921 else if (method == ACK)
2922 {
2923 if (offerAnswer)
2924 {
2925 return OnAckAnswer;
2926 }
2927 else
2928 {
2929 return OnAck;
2930 }
2931 }
2932 else if (method == CANCEL && code == 0)
2933 {
2934 return OnCancel;
2935 }
2936 else if (method == CANCEL && code / 200 == 1)
2937 {
2938 return On200Cancel;
2939 }
2940 else if (method == CANCEL && code >= 400)
2941 {
2942 return OnCancelFailure;
2943 }
2944 else if (method == BYE && code == 0)
2945 {
2946 return OnBye;
2947 }
2948 else if (method == BYE && code / 200 == 1)
2949 {
2950 return On200Bye;
2951 }
2952 else if (method == PRACK && code == 0)
2953 {
2954 return OnPrack;
2955 }
2956 else if (method == PRACK && code / 200 == 1)
2957 {
2958 return On200Prack;
2959 }
2960 else if (method == UPDATE && code == 0)
2961 {
2962 if (offerAnswer)
2963 {
2964 return OnUpdateOffer;
2965 }
2966 else
2967 {
2968 return OnUpdate;
2969 }
2970 }
2971 else if (method == UPDATE && code / 200 == 1)
2972 {
2973 return On200Update;
2974 }
2975 else if (method == UPDATE && code == 422)
2976 {
2977 return On422Update;
2978 }
2979 else if (method == UPDATE && code == 491)
2980 {
2981 return On491Update;
2982 }
2983 else if (method == UPDATE && code >= 400)
2984 {
2985 return OnUpdateRejected;
2986 }
2987 else
2988 {
2989 //assert(0); // dispatchOthers will throw if the message type is really unknown
2990 return Unknown;
2991 }
2992 }
2993
2994 void
2995 InviteSession::sendAck(const Contents *answer)
2996 {
2997 SharedPtr<SipMessage> ack(new SipMessage);
2998
2999 SharedPtr<SipMessage> source;
3000
3001 if (mLastLocalSessionModification->method() == UPDATE)
3002 {
3003 //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
3004 source = mDialog.mDialogSet.getCreator()->getLastRequest();
3005 }
3006 else
3007 {
3008 source = mLastLocalSessionModification;
3009 }
3010
3011 assert(mAcks.count(source->getTransactionId()) == 0);
3012
3013 mDialog.makeRequest(*ack, ACK);
3014
3015 // Copy Authorization and Proxy Authorization headers from
3016 // mLastLocalSessionModification; regardless of whether this was the original
3017 // INVITE or not, this is the correct place to go for auth headers.
3018 if(mLastLocalSessionModification->exists(h_Authorizations))
3019 {
3020 ack->header(h_Authorizations) = mLastLocalSessionModification->header(h_Authorizations);
3021 }
3022 if(mLastLocalSessionModification->exists(h_ProxyAuthorizations))
3023 {
3024 ack->header(h_ProxyAuthorizations) = mLastLocalSessionModification->header(h_ProxyAuthorizations);
3025 }
3026
3027 // Copy CSeq from original INVITE
3028 ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
3029
3030 if(answer != 0)
3031 {
3032 setOfferAnswer(*ack, *answer);
3033 }
3034 mAcks[source->getTransactionId()] = ack;
3035 mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(), 0, source->getTransactionId());
3036
3037 InfoLog (<< "Sending " << ack->brief());
3038 send(ack);
3039 }
3040
3041 SharedPtr<SipMessage>
3042 InviteSession::sendBye()
3043 {
3044 SharedPtr<SipMessage> bye(new SipMessage());
3045 mDialog.makeRequest(*bye, BYE);
3046 Data txt;
3047 if (mEndReason != NotSpecified)
3048 {
3049 Token reason("SIP");
3050 txt = getEndReasonString(mEndReason);
3051 reason.param(p_text) = txt;
3052 bye->header(h_Reasons).push_back(reason);
3053 }
3054
3055 if (mDum.mDialogEventStateManager)
3056 {
3057 mDum.mDialogEventStateManager->onTerminated(mDialog, *bye, InviteSessionHandler::LocalBye);
3058 }
3059
3060 InfoLog (<< myAddr() << " Sending BYE " << txt);
3061 send(bye);
3062 return bye;
3063 }
3064
3065 DialogUsageManager::EncryptionLevel
3066 InviteSession::getEncryptionLevel(const SipMessage& msg)
3067 {
3068 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
3069 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
3070 if (secAttr)
3071 {
3072 SignatureStatus sig = secAttr->getSignatureStatus();
3073 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
3074 bool encrypted = secAttr->isEncrypted();
3075 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
3076 else if (encrypted) level = DialogUsageManager::Encrypt;
3077 else if (sign) level = DialogUsageManager::Sign;
3078 }
3079 return level;
3080 }
3081
3082 void
3083 InviteSession::setCurrentLocalOfferAnswer(const SipMessage& msg)
3084 {
3085 assert(mProposedLocalOfferAnswer.get());
3086 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))
3087 {
3088 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
3089 {
3090 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().back()->clone()));
3091 }
3092 else
3093 {
3094 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().front()->clone()));
3095 }
3096 }
3097 else
3098 {
3099 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>(mProposedLocalOfferAnswer.get()->clone()));
3100 }
3101 mProposedLocalOfferAnswer.reset();
3102 }
3103
3104 void
3105 InviteSession::onReadyToSend(SipMessage& msg)
3106 {
3107 mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
3108 }
3109
3110 void
3111 InviteSession::flowTerminated()
3112 {
3113 // notify handler
3114 mDum.mInviteSessionHandler->onFlowTerminated(getSessionHandle());
3115 }
3116
3117 void
3118 InviteSession::referNoSub(const SipMessage& msg)
3119 {
3120 assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
3121 mLastReferNoSubRequest = msg;
3122 mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
3123 }
3124
3125 void
3126 InviteSession::acceptReferNoSub(int statusCode)
3127 {
3128 if (statusCode / 100 != 2)
3129 {
3130 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
3131 }
3132
3133 SharedPtr<SipMessage> response(new SipMessage);
3134 mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
3135 response->header(h_ReferSub).value() = "false";
3136 //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
3137
3138 send(response);
3139 }
3140
3141 void
3142 InviteSession::rejectReferNoSub(int responseCode)
3143 {
3144 if (responseCode < 400)
3145 {
3146 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
3147 }
3148
3149 SharedPtr<SipMessage> response(new SipMessage);
3150 mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
3151 send(response);
3152 }
3153
3154 /* ====================================================================
3155 * The Vovida Software License, Version 1.0
3156 *
3157 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
3158 *
3159 * Redistribution and use in source and binary forms, with or without
3160 * modification, are permitted provided that the following conditions
3161 * are met:
3162 *
3163 * 1. Redistributions of source code must retain the above copyright
3164 * notice, this list of conditions and the following disclaimer.
3165 *
3166 * 2. Redistributions in binary form must reproduce the above copyright
3167 * notice, this list of conditions and the following disclaimer in
3168 * the documentation and/or other materials provided with the
3169
3170 * distribution.
3171 *
3172 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
3173 * and "Vovida Open Communication Application Library (VOCAL)" must
3174 * not be used to endorse or promote products derived from this
3175 * software without prior written permission. For written
3176 * permission, please contact vocal@vovida.org.
3177 *
3178 * 4. Products derived from this software may not be called "VOCAL", nor
3179 * may "VOCAL" appear in their name, without prior written
3180 * permission of Vovida Networks, Inc.
3181 *
3182 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
3183 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3184 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
3185 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
3186 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
3187 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
3188 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3189 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3190 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
3191 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3192 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3193 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3194 * DAMAGE.
3195 *
3196 * ====================================================================
3197 *
3198 * This software consists of voluntary contributions made by Vovida
3199 * Networks, Inc. and many individuals on behalf of Vovida Networks,
3200 * Inc. For more information on Vovida Networks, Inc., please see
3201 * <http://www.vovida.org/>.
3202 *
3203 */
3204
3205
3206

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27