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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9823 - (show annotations) (download)
Fri Aug 3 20:16:52 2012 UTC (7 years, 5 months ago) by fjoanis
File MIME type: text/plain
File size: 93963 byte(s)
resip/dum: InviteSession: fixed recursive calls to refer (w/ sessionToReplace) when using referCommand and InviteSessionReferExCommand.
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 // Sent a reINVITE no offer and received a 200-offer.
761 // Simply send an ACK without an answer and stay in Connected.
762 case SentReinviteAnswered:
763 {
764 InfoLog (<< "Not sending " << statusCode << " error since transaction"
765 "already completed, sending answer-less ACK");
766 transition(Connected);
767 sendAck();
768 break;
769 }
770 default:
771 assert(0);
772 break;
773 }
774 }
775
776 class InviteSessionRejectCommand : public DumCommandAdapter
777 {
778 public:
779 InviteSessionRejectCommand(InviteSession& inviteSession, int code, WarningCategory* warning)
780 : mInviteSession(inviteSession),
781 mCode(code),
782 mWarning(warning?new WarningCategory(*warning):0)
783 {
784 }
785
786 virtual void executeCommand()
787 {
788 mInviteSession.reject(mCode, mWarning.get());
789 }
790
791 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
792 {
793 return strm << "InviteSessionRejectCommand";
794 }
795 private:
796 InviteSession& mInviteSession;
797 int mCode;
798 std::auto_ptr<WarningCategory> mWarning;
799 };
800
801 void
802 InviteSession::rejectCommand(int code, WarningCategory *warning)
803 {
804 mDum.post(new InviteSessionRejectCommand(*this, code, warning));
805 }
806
807 void
808 InviteSession::targetRefresh(const NameAddr& localUri)
809 {
810 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
811 {
812 mDialog.mLocalContact = localUri;
813 sessionRefresh();
814 }
815 else
816 {
817 WarningLog (<< "Can't targetRefresh before Connected");
818 throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
819 }
820 }
821
822 void
823 InviteSession::refer(const NameAddr& referTo, bool referSub)
824 {
825 refer(referTo,std::auto_ptr<resip::Contents>(0),referSub);
826 }
827 void
828 InviteSession::refer(const NameAddr& referTo, std::auto_ptr<resip::Contents> contents,bool referSub)
829 {
830 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
831 {
832 SharedPtr<SipMessage> refer(new SipMessage());
833 mDialog.makeRequest(*refer, REFER);
834 refer->header(h_ReferTo) = referTo;
835 refer->header(h_ReferredBy) = myAddr();
836 refer->header(h_ReferredBy).remove(p_tag); // tag-param not permitted in rfc3892; not the same as generic-param
837 refer->setContents(contents);
838 if (!referSub)
839 {
840 refer->header(h_ReferSub).value() = "false";
841 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
842 }
843
844 if(mNitState == NitComplete)
845 {
846 mNitState = NitProceeding;
847 mReferSub = referSub;
848 mLastSentNITRequest = refer;
849 send(refer);
850 return;
851 }
852 mNITQueue.push(new QueuedNIT(refer,referSub));
853 InfoLog(<< "refer - queuing NIT:" << refer->brief());
854 return;
855 }
856 else
857 {
858 WarningLog (<< "Can't refer before Connected");
859 assert(0);
860 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
861 }
862 }
863
864 const SharedPtr<SipMessage>
865 InviteSession::getLastSentNITRequest() const
866 {
867 return mLastSentNITRequest;
868 }
869
870 void
871 InviteSession::nitComplete()
872 {
873 mNitState = NitComplete;
874 if (mNITQueue.size())
875 {
876 QueuedNIT *qn=mNITQueue.front();
877 mNITQueue.pop();
878 mNitState = NitProceeding;
879 mReferSub = qn->referSubscription();
880 mLastSentNITRequest = qn->getNIT();
881 InfoLog(<< "checkNITQueue - sending queued NIT:" << mLastSentNITRequest->brief());
882 send(mLastSentNITRequest);
883 delete qn;
884 }
885 }
886
887 class InviteSessionReferCommand : public DumCommandAdapter
888 {
889 public:
890 InviteSessionReferCommand(InviteSession& inviteSession, const NameAddr& referTo, bool referSub)
891 : mInviteSession(inviteSession),
892 mReferTo(referTo),
893 mReferSub(referSub)
894 {
895
896 }
897
898 virtual void executeCommand()
899 {
900 mInviteSession.refer(mReferTo, mReferSub);
901 }
902
903 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
904 {
905 return strm << "InviteSessionReferCommand";
906 }
907
908 private:
909 InviteSession& mInviteSession;
910 NameAddr mReferTo;
911 bool mReferSub;
912 };
913
914 void
915 InviteSession::referCommand(const NameAddr& referTo, bool referSub)
916 {
917 mDum.post(new InviteSessionReferCommand(*this, referTo, referSub));
918 }
919
920 void
921 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
922 {
923 refer(referTo,sessionToReplace,std::auto_ptr<resip::Contents>(0),referSub);
924 }
925
926 void
927 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, std::auto_ptr<resip::Contents> contents, bool referSub)
928 {
929 if (!sessionToReplace.isValid())
930 {
931 throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
932 }
933
934 CallId replaces;
935 DialogId id = sessionToReplace->mDialog.getId();
936 replaces.value() = id.getCallId();
937 replaces.param(p_toTag) = id.getRemoteTag();
938 replaces.param(p_fromTag) = id.getLocalTag();
939
940 refer(referTo, replaces, contents, referSub);
941 }
942
943 void
944 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, bool referSub)
945 {
946 refer(referTo,replaces,std::auto_ptr<resip::Contents>(0),referSub);
947 }
948
949 void
950 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, std::auto_ptr<resip::Contents> contents, bool referSub)
951 {
952 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
953 {
954 SharedPtr<SipMessage> refer(new SipMessage());
955 mDialog.makeRequest(*refer, REFER);
956 refer->setContents(contents);
957 refer->header(h_ReferTo) = referTo;
958 refer->header(h_ReferredBy) = myAddr();
959 refer->header(h_ReferredBy).remove(p_tag);
960
961 refer->header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
962
963 if (!referSub)
964 {
965 refer->header(h_ReferSub).value() = "false";
966 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
967 }
968
969 if(mNitState == NitComplete)
970 {
971 mNitState = NitProceeding;
972 mReferSub = referSub;
973 mLastSentNITRequest = refer;
974 send(refer);
975 return;
976 }
977 mNITQueue.push(new QueuedNIT(refer,referSub));
978 InfoLog(<< "refer/replace - queuing NIT:" << refer->brief());
979 return;
980 }
981 else
982 {
983 WarningLog (<< "Can't refer before Connected");
984 assert(0);
985 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
986 }
987 }
988
989 class InviteSessionReferExCommand : public DumCommandAdapter
990 {
991 public:
992 InviteSessionReferExCommand(InviteSession& inviteSession, const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
993 : mInviteSession(inviteSession),
994 mSessionToReplace(sessionToReplace),
995 mReferTo(referTo),
996 mReferSub(referSub)
997 {
998 }
999
1000 virtual void executeCommand()
1001 {
1002 mInviteSession.refer(mReferTo, mSessionToReplace, mReferSub);
1003 }
1004
1005 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1006 {
1007 return strm << "InviteSessionReferExCommand";
1008 }
1009
1010 private:
1011 InviteSession& mInviteSession;
1012 InviteSessionHandle mSessionToReplace;
1013 NameAddr mReferTo;
1014 bool mReferSub;
1015 };
1016
1017 void
1018 InviteSession::referCommand(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
1019 {
1020 mDum.post(new InviteSessionReferExCommand(*this, referTo, sessionToReplace, referSub));
1021 }
1022
1023 void
1024 InviteSession::info(const Contents& contents)
1025 {
1026 SharedPtr<SipMessage> info(new SipMessage());
1027 mDialog.makeRequest(*info, INFO);
1028 // !jf! handle multipart here
1029 info->setContents(&contents);
1030 DumHelper::setOutgoingEncryptionLevel(*info, mCurrentEncryptionLevel);
1031 if (mNitState == NitComplete)
1032 {
1033 mNitState = NitProceeding;
1034 mLastSentNITRequest = info;
1035 send(info);
1036 return;
1037 }
1038 mNITQueue.push(new QueuedNIT(info));
1039 InfoLog(<< "info - queuing NIT:" << info->brief());
1040 return;
1041 }
1042
1043 class InviteSessionInfoCommand : public DumCommandAdapter
1044 {
1045 public:
1046 InviteSessionInfoCommand(InviteSession& inviteSession, const Contents& contents)
1047 : mInviteSession(inviteSession),
1048 mContents(contents.clone())
1049 {
1050 }
1051
1052 virtual void executeCommand()
1053 {
1054 mInviteSession.info(*mContents);
1055 }
1056
1057 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1058 {
1059 return strm << "InviteSessionInfoCommand";
1060 }
1061 private:
1062 InviteSession& mInviteSession;
1063 std::auto_ptr<Contents> mContents;
1064 };
1065
1066 void
1067 InviteSession::infoCommand(const Contents& contents)
1068 {
1069 mDum.post(new InviteSessionInfoCommand(*this, contents));
1070 }
1071
1072 void
1073 InviteSession::message(const Contents& contents)
1074 {
1075 SharedPtr<SipMessage> message(new SipMessage());
1076 mDialog.makeRequest(*message, MESSAGE);
1077 // !jf! handle multipart here
1078 message->setContents(&contents);
1079 DumHelper::setOutgoingEncryptionLevel(*message, mCurrentEncryptionLevel);
1080 InfoLog (<< "Trying to send MESSAGE: " << message);
1081 if (mNitState == NitComplete)
1082 {
1083 mNitState = NitProceeding;
1084 mLastSentNITRequest = message;
1085 send(message);
1086 return;
1087 }
1088 mNITQueue.push(new QueuedNIT(message));
1089 InfoLog(<< "message - queuing NIT:" << message->brief());
1090 return;
1091 }
1092
1093 class InviteSessionMessageCommand : public DumCommandAdapter
1094 {
1095 public:
1096 InviteSessionMessageCommand(InviteSession& inviteSession, const Contents& contents)
1097 : mInviteSession(inviteSession),
1098 mContents(contents.clone())
1099 {
1100 }
1101
1102 virtual void executeCommand()
1103 {
1104 mInviteSession.message(*mContents);
1105 }
1106
1107 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1108 {
1109 return strm << "InviteSessionMessageCommand";
1110 }
1111 private:
1112 InviteSession& mInviteSession;
1113 std::auto_ptr<Contents> mContents;
1114 };
1115
1116
1117 void
1118 InviteSession::messageCommand(const Contents& contents)
1119 {
1120 mDum.post(new InviteSessionMessageCommand(*this, contents));
1121 }
1122
1123 void
1124 InviteSession::dispatch(const SipMessage& msg)
1125 {
1126 // Look for 2xx retransmissions - resend ACK and filter out of state machine
1127 if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 100 == 2)
1128 {
1129 AckMap::iterator i = mAcks.find(msg.getTransactionId());
1130 if (i != mAcks.end())
1131 {
1132 send(i->second); // resend ACK
1133 return;
1134 }
1135 }
1136
1137 // !jf! do we need to handle 3xx here or is it handled elsewhere?
1138 switch (mState)
1139 {
1140 case Connected:
1141 dispatchConnected(msg);
1142 break;
1143 case SentUpdate:
1144 dispatchSentUpdate(msg);
1145 break;
1146 case SentReinvite:
1147 dispatchSentReinvite(msg);
1148 break;
1149 case SentReinviteNoOffer:
1150 dispatchSentReinviteNoOffer(msg);
1151 break;
1152 case SentReinviteAnswered:
1153 dispatchSentReinviteAnswered(msg);
1154 break;
1155 case SentUpdateGlare:
1156 case SentReinviteGlare:
1157 // The behavior is the same except for timer which is handled in dispatch(Timer)
1158 dispatchGlare(msg);
1159 break;
1160 case SentReinviteNoOfferGlare:
1161 dispatchReinviteNoOfferGlare(msg);
1162 break;
1163 case ReceivedUpdate:
1164 case ReceivedReinvite:
1165 case ReceivedReinviteNoOffer:
1166 dispatchReceivedUpdateOrReinvite(msg);
1167 break;
1168 case ReceivedReinviteSentOffer:
1169 dispatchReceivedReinviteSentOffer(msg);
1170 break;
1171 case Answered:
1172 dispatchAnswered(msg);
1173 break;
1174 case WaitingToOffer:
1175 dispatchWaitingToOffer(msg);
1176 break;
1177 case WaitingToRequestOffer:
1178 dispatchWaitingToRequestOffer(msg);
1179 break;
1180 case WaitingToTerminate:
1181 dispatchWaitingToTerminate(msg);
1182 break;
1183 case WaitingToHangup:
1184 dispatchWaitingToHangup(msg);
1185 break;
1186 case Terminated:
1187 dispatchTerminated(msg);
1188 break;
1189 case Undefined:
1190 default:
1191 assert(0);
1192 break;
1193 }
1194 }
1195
1196 void
1197 InviteSession::dispatch(const DumTimeout& timeout)
1198 {
1199 if (timeout.type() == DumTimeout::Retransmit200)
1200 {
1201 if (mCurrentRetransmit200)
1202 {
1203 InfoLog (<< "Retransmitting: " << endl << mInvite200->brief());
1204 //DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
1205 send(mInvite200);
1206 mCurrentRetransmit200 *= 2;
1207 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
1208 }
1209 }
1210 else if (timeout.type() == DumTimeout::WaitForAck)
1211 {
1212 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
1213 {
1214 if (timeout.seq() == mLastRemoteSessionModification->header(h_CSeq).sequence())
1215 {
1216 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1217
1218 // If we are waiting for an Ack and it times out, then end with a BYE
1219 if(mState == UAS_WaitingToHangup ||
1220 mState == WaitingToHangup)
1221 {
1222 SharedPtr<SipMessage> msg = sendBye();
1223 transition(Terminated);
1224 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1225 }
1226 else if(mState == ReceivedReinviteSentOffer)
1227 {
1228 transition(Connected);
1229 mProposedLocalOfferAnswer.reset();
1230 mProposedEncryptionLevel = DialogUsageManager::None;
1231 //!dcm! -- should this be onIllegalNegotiation?
1232 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
1233 }
1234 else if(mState == WaitingToOffer ||
1235 mState == UAS_WaitingToOffer)
1236 {
1237 assert(mProposedLocalOfferAnswer.get());
1238 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1239 if(!isTerminated())
1240 {
1241 provideProposedOffer();
1242 }
1243 }
1244 else if(mState == WaitingToRequestOffer ||
1245 mState == UAS_WaitingToRequestOffer)
1246 {
1247 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1248 if(!isTerminated())
1249 {
1250 requestOffer();
1251 }
1252 }
1253 else
1254 {
1255 // this is so the app can decided to ignore this. default implementation
1256 // will call end next
1257 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1258 }
1259 }
1260 }
1261 }
1262 else if (timeout.type() == DumTimeout::CanDiscardAck)
1263 {
1264 AckMap::iterator i = mAcks.find(timeout.transactionId());
1265 if (i != mAcks.end())
1266 {
1267 mAcks.erase(i);
1268 }
1269 }
1270 else if (timeout.type() == DumTimeout::Glare)
1271 {
1272 if (mState == SentUpdateGlare)
1273 {
1274 transition(SentUpdate);
1275
1276 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
1277 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE); // increments CSeq
1278 send(mLastLocalSessionModification);
1279 }
1280 else if (mState == SentReinviteGlare)
1281 {
1282 transition(SentReinvite);
1283
1284 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
1285 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1286 startStaleReInviteTimer();
1287 send(mLastLocalSessionModification);
1288 }
1289 else if (mState == SentReinviteNoOfferGlare)
1290 {
1291 transition(SentReinviteNoOffer);
1292
1293 InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
1294 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1295 startStaleReInviteTimer();
1296 send(mLastLocalSessionModification);
1297 }
1298 }
1299 else if (timeout.type() == DumTimeout::StaleReInvite)
1300 {
1301 if(timeout.seq() == mStaleReInviteTimerSeq)
1302 {
1303 if(mState == WaitingToTerminate)
1304 {
1305 SharedPtr<SipMessage> msg = sendBye();
1306 transition(Terminated);
1307 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1308 }
1309 else if(mState == SentReinvite ||
1310 mState == SentReinviteNoOffer)
1311 {
1312 transition(Connected);
1313 mProposedLocalOfferAnswer.reset();
1314 mProposedEncryptionLevel = DialogUsageManager::None;
1315
1316 // this is so the app can decide to ignore this. default implementation
1317 // will call end next - which will send a BYE
1318 mDum.mInviteSessionHandler->onStaleReInviteTimeout(getSessionHandle());
1319 }
1320 }
1321 }
1322 else if (timeout.type() == DumTimeout::SessionExpiration)
1323 {
1324 if(timeout.seq() == mSessionTimerSeq)
1325 {
1326 // this is so the app can decide to ignore this. default implementation
1327 // will call end next - which will send a BYE
1328 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
1329 }
1330 }
1331 else if (timeout.type() == DumTimeout::SessionRefresh)
1332 {
1333 if(timeout.seq() == mSessionTimerSeq)
1334 {
1335 // Note: If not connected then we must be issueing a reinvite/update or
1336 // receiving one - in either case the session timer stuff will get
1337 // reset/renegotiated - thus just ignore this referesh
1338 if(mState == Connected)
1339 {
1340 sessionRefresh();
1341 }
1342 }
1343 }
1344 }
1345
1346 void
1347 InviteSession::dispatchConnected(const SipMessage& msg)
1348 {
1349 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1350 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1351
1352 switch (toEvent(msg, offerAnswer.get()))
1353 {
1354 case OnInvite:
1355 case OnInviteReliable:
1356 *mLastRemoteSessionModification = msg;
1357 transition(ReceivedReinviteNoOffer);
1358 handler->onOfferRequired(getSessionHandle(), msg);
1359 break;
1360
1361 case OnInviteOffer:
1362 case OnInviteReliableOffer:
1363 *mLastRemoteSessionModification = msg;
1364 transition(ReceivedReinvite);
1365 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1366 mProposedRemoteOfferAnswer = offerAnswer;
1367
1368 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1369 break;
1370
1371 case On2xx:
1372 case On2xxOffer:
1373 case On2xxAnswer:
1374 // retransmission of 200I
1375 // !jf! Need to include the answer here.
1376 sendAck();
1377 break;
1378
1379 case OnUpdateOffer:
1380 transition(ReceivedUpdate);
1381
1382 // !kh!
1383 // Find out if it's an UPDATE requiring state change.
1384 // See rfc3311 5.2, 4th paragraph.
1385 *mLastRemoteSessionModification = msg;
1386 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1387 mProposedRemoteOfferAnswer = offerAnswer;
1388 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1389 break;
1390
1391 case OnUpdate:
1392 {
1393 // ?slg? no offerAnswer in update - just respond immediately (likely session timer) - do we need a callback?
1394 SharedPtr<SipMessage> response(new SipMessage);
1395 *mLastRemoteSessionModification = msg;
1396 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
1397 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1398 send(response);
1399 break;
1400 }
1401
1402 case OnUpdateRejected:
1403 case On200Update:
1404 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
1405 assert(0);
1406 break;
1407
1408 case OnAck:
1409 case OnAckAnswer: // .bwc. Don't drop ACK with SDP!
1410 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1411 handler->onAckReceived(getSessionHandle(), msg);
1412 break;
1413
1414 default:
1415 dispatchOthers(msg);
1416 break;
1417 }
1418 }
1419
1420 void
1421 InviteSession::dispatchSentUpdate(const SipMessage& msg)
1422 {
1423 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1424 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1425
1426 switch (toEvent(msg, offerAnswer.get()))
1427 {
1428 case OnInvite:
1429 case OnInviteReliable:
1430 case OnInviteOffer:
1431 case OnInviteReliableOffer:
1432 case OnUpdate:
1433 case OnUpdateOffer:
1434 {
1435 // glare
1436 SharedPtr<SipMessage> response(new SipMessage);
1437 mDialog.makeResponse(*response, msg, 491);
1438 send(response);
1439 break;
1440 }
1441
1442 case On200Update:
1443 transition(Connected);
1444 handleSessionTimerResponse(msg);
1445 if (offerAnswer.get() && mProposedLocalOfferAnswer.get())
1446 {
1447 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1448 setCurrentLocalOfferAnswer(msg);
1449
1450 mCurrentRemoteOfferAnswer = offerAnswer;
1451 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1452 }
1453 else if(mProposedLocalOfferAnswer.get())
1454 {
1455 // If we sent an offer in the Update Request and no answer is received
1456 handler->onIllegalNegotiation(getSessionHandle(), msg);
1457 mProposedLocalOfferAnswer.reset();
1458 mProposedEncryptionLevel = DialogUsageManager::None;
1459 }
1460 break;
1461
1462 case On491Update:
1463 transition(SentUpdateGlare);
1464 start491Timer();
1465 break;
1466
1467 case On422Update: // session timer
1468 if(msg.exists(h_MinSE))
1469 {
1470 // Change interval to min from 422 response
1471 mSessionInterval = msg.header(h_MinSE).value();
1472 mMinSE = mSessionInterval;
1473 sessionRefresh();
1474 }
1475 else
1476 {
1477 // Response must contain Min_SE - if not - just ignore
1478 // ?slg? callback?
1479 transition(Connected);
1480 mProposedLocalOfferAnswer.reset();
1481 mProposedEncryptionLevel = DialogUsageManager::None;
1482 }
1483 break;
1484
1485 case OnUpdateRejected:
1486 transition(Connected);
1487 mProposedLocalOfferAnswer.reset();
1488 handler->onOfferRejected(getSessionHandle(), &msg);
1489 break;
1490
1491 case OnGeneralFailure:
1492 sendBye();
1493 transition(Terminated);
1494 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1495 break;
1496
1497 default:
1498 dispatchOthers(msg);
1499 break;
1500 }
1501 }
1502
1503 void
1504 InviteSession::dispatchSentReinvite(const SipMessage& msg)
1505 {
1506 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1507 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1508
1509 switch (toEvent(msg, offerAnswer.get()))
1510 {
1511 case OnInvite:
1512 case OnInviteReliable:
1513 case OnInviteOffer:
1514 case OnInviteReliableOffer:
1515 case OnUpdate:
1516 case OnUpdateOffer:
1517 {
1518 SharedPtr<SipMessage> response(new SipMessage);
1519 mDialog.makeResponse(*response, msg, 491);
1520 send(response);
1521 break;
1522 }
1523
1524 case On1xx:
1525 case On1xxEarly:
1526 // Some UA's send a 100 response to a ReInvite - just ignore it
1527 break;
1528
1529 case On2xxAnswer:
1530 case On2xxOffer: // .slg. doesn't really make sense
1531 {
1532 mStaleReInviteTimerSeq++;
1533 transition(Connected);
1534 handleSessionTimerResponse(msg);
1535 setCurrentLocalOfferAnswer(msg);
1536
1537 // !jf! I need to potentially include an answer in the ACK here
1538 sendAck();
1539 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1540
1541 if (mSessionRefreshReInvite)
1542 {
1543 mSessionRefreshReInvite = false;
1544
1545 MD5Stream currentRemote;
1546 currentRemote<< *mCurrentRemoteOfferAnswer;
1547 MD5Stream newRemote;
1548 newRemote << *offerAnswer;
1549 bool changed = currentRemote.getHex() != newRemote.getHex();
1550
1551 if (changed)
1552 {
1553 mCurrentRemoteOfferAnswer = offerAnswer;
1554 handler->onRemoteAnswerChanged(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1555 }
1556 }
1557 else
1558 {
1559 mCurrentRemoteOfferAnswer = offerAnswer;
1560 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1561 }
1562
1563 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1564 // the ACK when a 200I is received? If yes, then I need to store all
1565 // ACK messages for 64*T1
1566 break;
1567 }
1568 case On2xx:
1569 mStaleReInviteTimerSeq++;
1570 sendAck();
1571 transition(Connected);
1572 handleSessionTimerResponse(msg);
1573 handler->onIllegalNegotiation(getSessionHandle(), msg);
1574 mProposedLocalOfferAnswer.reset();
1575 mProposedEncryptionLevel = DialogUsageManager::None;
1576 break;
1577
1578 case On422Invite:
1579 mStaleReInviteTimerSeq++;
1580 if(msg.exists(h_MinSE))
1581 {
1582 // Change interval to min from 422 response
1583 mSessionInterval = msg.header(h_MinSE).value();
1584 mMinSE = mSessionInterval;
1585 sessionRefresh();
1586 }
1587 else
1588 {
1589 // Response must contact Min_SE - if not - just ignore
1590 // ?slg? callback?
1591 transition(Connected);
1592 mProposedLocalOfferAnswer.reset();
1593 mProposedEncryptionLevel = DialogUsageManager::None;
1594 }
1595 break;
1596
1597 case On491Invite:
1598 mStaleReInviteTimerSeq++;
1599 transition(SentReinviteGlare);
1600 start491Timer();
1601 break;
1602
1603 case OnGeneralFailure:
1604 mStaleReInviteTimerSeq++;
1605 sendBye();
1606 transition(Terminated);
1607 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1608 break;
1609
1610 case OnInviteFailure:
1611 case On487Invite:
1612 mStaleReInviteTimerSeq++;
1613 transition(Connected);
1614 mProposedLocalOfferAnswer.reset();
1615 handler->onOfferRejected(getSessionHandle(), &msg);
1616 break;
1617
1618 default:
1619 dispatchOthers(msg);
1620 break;
1621 }
1622 }
1623
1624 void
1625 InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1626 {
1627 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1628 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1629
1630 switch (toEvent(msg, offerAnswer.get()))
1631 {
1632 case OnInvite:
1633 case OnInviteReliable:
1634 case OnInviteOffer:
1635 case OnInviteReliableOffer:
1636 case OnUpdate:
1637 case OnUpdateOffer:
1638 {
1639 SharedPtr<SipMessage> response(new SipMessage);
1640 mDialog.makeResponse(*response, msg, 491);
1641 send(response);
1642 break;
1643 }
1644
1645 case On1xx:
1646 case On1xxEarly:
1647 // Some UA's send a 100 response to a ReInvite - just ignore it
1648 break;
1649
1650 case On2xxAnswer: // .slg. doesn't really make sense
1651 case On2xxOffer:
1652 {
1653 mStaleReInviteTimerSeq++;
1654 transition(SentReinviteAnswered);
1655 handleSessionTimerResponse(msg);
1656 // mLastSessionModification = msg; // ?slg? why are we storing 200's?
1657 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1658 mProposedRemoteOfferAnswer = offerAnswer;
1659 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1660 break;
1661 }
1662
1663 case On2xx:
1664 mStaleReInviteTimerSeq++;
1665 sendAck();
1666 transition(Connected);
1667 handleSessionTimerResponse(msg);
1668 handler->onIllegalNegotiation(getSessionHandle(), msg);
1669 mProposedLocalOfferAnswer.reset();
1670 mProposedEncryptionLevel = DialogUsageManager::None;
1671 break;
1672
1673 case On422Invite:
1674 mStaleReInviteTimerSeq++;
1675 if(msg.exists(h_MinSE))
1676 {
1677 // Change interval to min from 422 response
1678 mSessionInterval = msg.header(h_MinSE).value();
1679 mMinSE = mSessionInterval;
1680 sessionRefresh();
1681 }
1682 else
1683 {
1684 // Response must contact Min_SE - if not - just ignore
1685 // ?slg? callback?
1686 transition(Connected);
1687 mProposedLocalOfferAnswer.reset();
1688 mProposedEncryptionLevel = DialogUsageManager::None;
1689 }
1690 break;
1691
1692 case On491Invite:
1693 mStaleReInviteTimerSeq++;
1694 transition(SentReinviteNoOfferGlare);
1695 start491Timer();
1696 break;
1697
1698 case OnGeneralFailure:
1699 mStaleReInviteTimerSeq++;
1700 sendBye();
1701 transition(Terminated);
1702 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1703 break;
1704
1705 case OnInviteFailure:
1706 case On487Invite:
1707 mStaleReInviteTimerSeq++;
1708 transition(Connected);
1709 mProposedLocalOfferAnswer.reset();
1710 handler->onOfferRejected(getSessionHandle(), &msg);
1711 break;
1712
1713 default:
1714 dispatchOthers(msg);
1715 break;
1716 }
1717 }
1718
1719 void
1720 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1721 {
1722 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1723 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1724
1725 switch (toEvent(msg, offerAnswer.get()))
1726 {
1727 case OnInvite:
1728 case OnInviteReliable:
1729 case OnInviteOffer:
1730 case OnInviteReliableOffer:
1731 case OnUpdate:
1732 case OnUpdateOffer:
1733 {
1734 SharedPtr<SipMessage> response(new SipMessage);
1735 mDialog.makeResponse(*response, msg, 491);
1736 send(response);
1737 break;
1738 }
1739 case OnAckAnswer:
1740 transition(Connected);
1741 setCurrentLocalOfferAnswer(msg);
1742 mCurrentRemoteOfferAnswer = offerAnswer;
1743 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1744 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1745
1746 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1747 break;
1748 case OnAck:
1749 if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
1750 {
1751 InfoLog(<< "dropped stale ACK");
1752 }
1753 else
1754 {
1755 InfoLog(<< "Got Ack with no answer");
1756 transition(Connected);
1757 mProposedLocalOfferAnswer.reset();
1758 mProposedEncryptionLevel = DialogUsageManager::None;
1759 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1760 //!dcm! -- should this be onIllegalNegotiation?
1761 handler->onOfferRejected(getSessionHandle(), &msg);
1762 }
1763 break;
1764 default:
1765 dispatchOthers(msg);
1766 break;
1767 }
1768 }
1769
1770 void
1771 InviteSession::dispatchGlare(const SipMessage& msg)
1772 {
1773 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1774 MethodTypes method = msg.header(h_CSeq).method();
1775 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1776 {
1777 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1778 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1779 handler->onOfferRejected(getSessionHandle(), &msg);
1780 if(!isTerminated()) // make sure application didn't call end()
1781 {
1782 dispatchConnected(msg); // act as if we received message in Connected state
1783 }
1784 else
1785 {
1786 dispatchTerminated(msg);
1787 }
1788 }
1789 else
1790 {
1791 dispatchOthers(msg);
1792 }
1793 }
1794
1795 void
1796 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1797 {
1798 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1799 MethodTypes method = msg.header(h_CSeq).method();
1800 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1801 {
1802 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1803 handler->onOfferRequestRejected(getSessionHandle(), msg);
1804 if(!isTerminated()) // make sure application didn't call end()
1805 {
1806 dispatchConnected(msg); // act as if we received message in Connected state
1807 }
1808 else
1809 {
1810 dispatchTerminated(msg);
1811 }
1812 }
1813 else
1814 {
1815 dispatchOthers(msg);
1816 }
1817 }
1818
1819 void
1820 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1821 {
1822 // InviteSessionHandler* handler = mDum.mInviteSessionHandler; // unused
1823 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1824
1825 switch (toEvent(msg, offerAnswer.get()))
1826 {
1827 case OnInvite:
1828 case OnInviteReliable:
1829 case OnInviteOffer:
1830 case OnInviteReliableOffer:
1831 case OnUpdate:
1832 case OnUpdateOffer:
1833 {
1834 // Means that the UAC has sent us a second reINVITE or UPDATE before we
1835 // responded to the first one. Bastard!
1836 SharedPtr<SipMessage> response(new SipMessage);
1837 mDialog.makeResponse(*response, msg, 500);
1838 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1839 send(response);
1840 break;
1841 }
1842 case OnBye:
1843 {
1844 // BYE received after a reINVITE, terminate the reINVITE transaction.
1845 SharedPtr<SipMessage> response(new SipMessage);
1846 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 487); // Request Terminated
1847 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1848 send(response);
1849
1850 dispatchBye(msg);
1851 break;
1852 }
1853 default:
1854 dispatchOthers(msg);
1855 break;
1856 }
1857 }
1858
1859
1860 void
1861 InviteSession::dispatchAnswered(const SipMessage& msg)
1862 {
1863 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1864 {
1865 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1866 transition(Connected);
1867 }
1868 else
1869 {
1870 dispatchOthers(msg);
1871 }
1872 }
1873
1874 void
1875 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1876 {
1877 if (msg.isResponse() &&
1878 msg.header(h_CSeq).method() == INVITE &&
1879 msg.header(h_StatusLine).statusCode() / 200 == 1)
1880 {
1881 // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
1882 // called by the app - so just drop the retransmission
1883 return;
1884 }
1885 dispatchOthers(msg);
1886 }
1887
1888 void
1889 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1890 {
1891 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1892 {
1893 assert(mProposedLocalOfferAnswer.get());
1894 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1895 provideProposedOffer();
1896 }
1897 else
1898 {
1899 dispatchOthers(msg);
1900 }
1901 }
1902
1903 void
1904 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1905 {
1906 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1907 {
1908 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1909 requestOffer();
1910 }
1911 else
1912 {
1913 dispatchOthers(msg);
1914 }
1915 }
1916
1917 void
1918 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1919 {
1920 if (msg.isResponse() &&
1921 msg.header(h_CSeq).method() == INVITE)
1922 {
1923 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1924 {
1925 // !jf! Need to include the answer here.
1926 sendAck();
1927 }
1928 SharedPtr<SipMessage> msg = sendBye();
1929 transition(Terminated);
1930 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1931 }
1932 else if(msg.isRequest())
1933 {
1934 if(msg.method() == BYE)
1935 {
1936 dispatchBye(msg);
1937 }
1938 else
1939 {
1940 SharedPtr<SipMessage> response(new SipMessage);
1941 mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
1942 send(response);
1943 }
1944 }
1945 }
1946
1947 void
1948 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1949 {
1950 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1951
1952 switch (toEvent(msg, offerAnswer.get()))
1953 {
1954 case OnAck:
1955 case OnAckAnswer:
1956 {
1957 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1958
1959 SharedPtr<SipMessage> msg = sendBye();
1960 transition(Terminated);
1961 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1962 break;
1963 }
1964
1965 default:
1966 break;
1967 }
1968 }
1969
1970 void
1971 InviteSession::dispatchTerminated(const SipMessage& msg)
1972 {
1973 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1974
1975 if (msg.isRequest())
1976 {
1977 if (BYE == msg.header(h_CSeq).method())
1978 {
1979 SharedPtr<SipMessage> response(new SipMessage);
1980 mDialog.makeResponse(*response, msg, 200);
1981 send(response);
1982 }
1983 else
1984 {
1985 SharedPtr<SipMessage> response(new SipMessage);
1986 mDialog.makeResponse(*response, msg, 481);
1987 send(response);
1988 }
1989
1990 // !jf! means the peer sent BYE while we are waiting for response to BYE
1991 //mDum.destroy(this);
1992 }
1993 else
1994 {
1995 mDum.destroy(this);
1996 }
1997 }
1998
1999 void
2000 InviteSession::dispatchOthers(const SipMessage& msg)
2001 {
2002 // handle OnGeneralFailure
2003 // handle OnRedirect
2004
2005 switch (msg.header(h_CSeq).method())
2006 {
2007 case PRACK:
2008 dispatchPrack(msg);
2009 break;
2010 case CANCEL:
2011 dispatchCancel(msg);
2012 break;
2013 case BYE:
2014 dispatchBye(msg);
2015 break;
2016 case INFO:
2017 dispatchInfo(msg);
2018 break;
2019 case MESSAGE:
2020 dispatchMessage(msg);
2021 break;
2022 case ACK:
2023 // Ignore duplicate ACKs from 2xx reTransmissions
2024 break;
2025 default:
2026 // handled in Dialog
2027 WarningLog (<< "DUM delivered a "
2028 << msg.header(h_CSeq).unknownMethodName()
2029 << " to the InviteSession in state: " << toData(mState)
2030 << endl
2031 << msg);
2032 assert(0);
2033 break;
2034 }
2035 }
2036
2037 void
2038 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
2039 {
2040 assert(msg.isRequest());
2041 assert(msg.header(h_CSeq).method() == INVITE);
2042
2043 // If we get an INVITE request from the wire and we are not in
2044 // Connected state, reject the request and send a BYE
2045 SharedPtr<SipMessage> response(new SipMessage);
2046 mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
2047 InfoLog (<< "Sending " << response->brief());
2048 send(response);
2049
2050 sendBye();
2051 transition(Terminated);
2052 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2053 }
2054
2055 void
2056 InviteSession::dispatchPrack(const SipMessage& msg)
2057 {
2058 assert(msg.header(h_CSeq).method() == PRACK);
2059 if(msg.isRequest())
2060 {
2061 SharedPtr<SipMessage> rsp(new SipMessage);
2062 mDialog.makeResponse(*rsp, msg, 481);
2063 send(rsp);
2064
2065 sendBye();
2066 // !jf! should we make some other callback here
2067 transition(Terminated);
2068 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2069 }
2070 else
2071 {
2072 // ignore. could be PRACK/200
2073 }
2074 }
2075
2076 void
2077 InviteSession::dispatchCancel(const SipMessage& msg)
2078 {
2079 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2080 assert(msg.header(h_CSeq).method() == CANCEL);
2081 if(msg.isRequest())
2082 {
2083 SharedPtr<SipMessage> rsp(new SipMessage);
2084 mDialog.makeResponse(*rsp, msg, 200);
2085 send(rsp);
2086
2087 sendBye();
2088 // !jf! should we make some other callback here
2089 transition(Terminated);
2090
2091 handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteCancel, &msg);
2092 }
2093 else
2094 {
2095 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
2096 assert(0);
2097 }
2098 }
2099
2100 void
2101 InviteSession::dispatchBye(const SipMessage& msg)
2102 {
2103 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2104
2105 if (msg.isRequest())
2106 {
2107 // Check for any non-invite server transactions (e.g. INFO)
2108 // that have not been responded yet and terminate them.
2109 if (mServerNitState == NitProceeding)
2110 {
2111 mLastNitResponse->header(h_StatusLine).statusCode() = 487;
2112 mLastNitResponse->setContents(0);
2113 Helper::getResponseCodeReason(487, mLastNitResponse->header(h_StatusLine).reason());
2114 send(mLastNitResponse);
2115 mServerNitState = NitComplete;
2116 }
2117
2118 SharedPtr<SipMessage> rsp(new SipMessage);
2119 InfoLog (<< "Received " << msg.brief());
2120 mDialog.makeResponse(*rsp, msg, 200);
2121 send(rsp);
2122
2123 // !jf! should we make some other callback here
2124 transition(Terminated);
2125
2126 if (mDum.mDialogEventStateManager)
2127 {
2128 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::RemoteBye);
2129 }
2130
2131 handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
2132 mDum.destroy(this);
2133 }
2134 else
2135 {
2136 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
2137 assert(0);
2138 }
2139 }
2140
2141 void
2142 InviteSession::dispatchInfo(const SipMessage& msg)
2143 {
2144 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2145 if (msg.isRequest())
2146 {
2147 if (mServerNitState == NitProceeding)
2148 {
2149 // Means that the UAC has sent us a second INFO before we
2150 // responded to the first one.
2151 SharedPtr<SipMessage> response(new SipMessage);
2152 mDialog.makeResponse(*response, msg, 500);
2153 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2154 send(response);
2155 }
2156 else
2157 {
2158 InfoLog (<< "Received " << msg.brief());
2159 mServerNitState = NitProceeding;
2160 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2161 handler->onInfo(getSessionHandle(), msg);
2162 }
2163 }
2164 else
2165 {
2166 assert(mNitState == NitProceeding);
2167 //!dcm! -- toss away 1xx to an info?
2168 if (msg.header(h_StatusLine).statusCode() >= 300)
2169 {
2170 handler->onInfoFailure(getSessionHandle(), msg);
2171 }
2172 else if (msg.header(h_StatusLine).statusCode() >= 200)
2173 {
2174 handler->onInfoSuccess(getSessionHandle(), msg);
2175 }
2176 nitComplete();
2177 }
2178 }
2179
2180 void
2181 InviteSession::acceptNIT(int statusCode, const Contents * contents)
2182 {
2183 if (statusCode / 100 != 2)
2184 {
2185 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2186 }
2187
2188 if (mServerNitState != NitProceeding )
2189 {
2190 throw UsageUseException("No transaction to accept", __FILE__, __LINE__);
2191 }
2192
2193 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2194 mLastNitResponse->setContents(contents);
2195 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2196 send(mLastNitResponse);
2197 mServerNitState = NitComplete;
2198 }
2199
2200 class InviteSessionAcceptNITCommand : public DumCommandAdapter
2201 {
2202 public:
2203 InviteSessionAcceptNITCommand(InviteSession& inviteSession, int statusCode, const Contents* contents)
2204 : mInviteSession(inviteSession),
2205 mStatusCode(statusCode),
2206 mContents(contents?contents->clone():0)
2207 {
2208
2209 }
2210
2211 virtual void executeCommand()
2212 {
2213 mInviteSession.acceptNITCommand(mStatusCode, mContents.get());
2214 }
2215
2216 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2217 {
2218 return strm << "InviteSessionAcceptNITCommand";
2219 }
2220 private:
2221 InviteSession& mInviteSession;
2222 int mStatusCode;
2223 std::auto_ptr<Contents> mContents;
2224 };
2225
2226 void
2227 InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
2228 {
2229 mDum.post(new InviteSessionAcceptNITCommand(*this, statusCode, contents));
2230 }
2231
2232 void
2233 InviteSession::rejectNIT(int statusCode)
2234 {
2235 if (statusCode < 400)
2236 {
2237 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2238 }
2239
2240 if (mServerNitState != NitProceeding )
2241 {
2242 throw UsageUseException("No transaction to reject", __FILE__, __LINE__);
2243 }
2244
2245 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2246 mLastNitResponse->setContents(0);
2247 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2248 send(mLastNitResponse);
2249 mServerNitState = NitComplete;
2250 }
2251
2252 class InviteSessionRejectNITCommand : public DumCommandAdapter
2253 {
2254 public:
2255 InviteSessionRejectNITCommand(InviteSession& inviteSession, int statusCode)
2256 : mInviteSession(inviteSession),
2257 mStatusCode(statusCode)
2258 {
2259 }
2260
2261 virtual void executeCommand()
2262 {
2263 mInviteSession.rejectNITCommand(mStatusCode);
2264 }
2265
2266 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2267 {
2268 return strm << "InviteSessionRejectNITCommand";
2269 }
2270 private:
2271 InviteSession& mInviteSession;
2272 int mStatusCode;
2273 };
2274
2275 void
2276 InviteSession::rejectNITCommand(int statusCode)
2277 {
2278 mDum.post(new InviteSessionRejectNITCommand(*this, statusCode));
2279 }
2280
2281 void
2282 InviteSession::dispatchMessage(const SipMessage& msg)
2283 {
2284 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2285 if (msg.isRequest())
2286 {
2287 if (mServerNitState == NitProceeding)
2288 {
2289 // Means that the UAC has sent us a second NIT message before we
2290 // responded to the first one.
2291 SharedPtr<SipMessage> response(new SipMessage);
2292 mDialog.makeResponse(*response, msg, 500);
2293 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2294 send(response);
2295 }
2296 else
2297 {
2298 InfoLog (<< "Received " << msg.brief());
2299 mServerNitState = NitProceeding;
2300 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2301 mLastNitResponse->header(h_Contacts).clear();
2302 handler->onMessage(getSessionHandle(), msg);
2303 }
2304 }
2305 else
2306 {
2307 assert(mNitState == NitProceeding);
2308 //!dcm! -- toss away 1xx to an message?
2309 if (msg.header(h_StatusLine).statusCode() >= 300)
2310 {
2311 handler->onMessageFailure(getSessionHandle(), msg);
2312 }
2313 else if (msg.header(h_StatusLine).statusCode() >= 200)
2314 {
2315 handler->onMessageSuccess(getSessionHandle(), msg);
2316 }
2317 nitComplete();
2318 }
2319 }
2320
2321 void
2322 InviteSession::startRetransmit200Timer()
2323 {
2324 mCurrentRetransmit200 = Timer::T1;
2325 unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
2326 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
2327 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
2328 }
2329
2330 // RFC3261 section 14.1
2331 // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
2332 // a value T chosen as follows:
2333 // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
2334 // chosen value between 2.1 and 4 seconds in units of 10 ms.
2335 // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
2336 // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
2337 void
2338 InviteSession::start491Timer()
2339 {
2340 unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
2341
2342 if (dynamic_cast<ClientInviteSession*>(this))
2343 {
2344 int timer = Random::getRandom() % (4000 - 2100);
2345 timer += 2100;
2346 timer -= timer % 10;
2347
2348 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2349 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2350 }
2351 else
2352 {
2353 int timer = Random::getRandom() % 2000;
2354 timer -= timer % 10;
2355 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2356 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2357 }
2358 }
2359
2360 void
2361 InviteSession::startStaleReInviteTimer()
2362 {
2363 InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
2364 unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
2365
2366 mDum.addTimer(DumTimeout::StaleReInvite,
2367 when,
2368 getBaseHandle(),
2369 ++mStaleReInviteTimerSeq);
2370 }
2371
2372 void
2373 InviteSession::setSessionTimerHeaders(SipMessage &msg)
2374 {
2375 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
2376 {
2377 msg.header(h_SessionExpires).value() = mSessionInterval;
2378 if(msg.isRequest())
2379 {
2380 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
2381 }
2382 else
2383 {
2384 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
2385 }
2386 msg.header(h_MinSE).value() = mMinSE;
2387 }
2388 else
2389 {
2390 msg.remove(h_SessionExpires);
2391 msg.remove(h_MinSE);
2392 }
2393 }
2394
2395 void
2396 InviteSession::sessionRefresh()
2397 {
2398 if (updateMethodSupported())
2399 {
2400 transition(SentUpdate);
2401 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
2402 mLastLocalSessionModification->setContents(0); // Don't send SDP
2403 }
2404 else
2405 {
2406 transition(SentReinvite);
2407 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
2408 startStaleReInviteTimer();
2409 InviteSession::setOfferAnswer(*mLastLocalSessionModification, mCurrentLocalOfferAnswer.get());
2410 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(*mCurrentLocalOfferAnswer.get(), 0);
2411 mSessionRefreshReInvite = true;
2412 }
2413 setSessionTimerHeaders(*mLastLocalSessionModification);
2414
2415 InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
2416 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
2417 send(mLastLocalSessionModification);
2418 }
2419
2420 void
2421 InviteSession::setSessionTimerPreferences()
2422 {
2423 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
2424 if(mSessionInterval != 0)
2425 {
2426 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
2427 mSessionInterval = resipMax(mMinSE, mSessionInterval);
2428 }
2429 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
2430 {
2431 case Profile::PreferLocalRefreshes:
2432 mSessionRefresher = true; // Default refresher is Local
2433 break;
2434 case Profile::PreferRemoteRefreshes:
2435 mSessionRefresher = false; // Default refresher is Remote
2436 break;
2437 case Profile::PreferCalleeRefreshes:
2438 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is callee
2439 break;
2440 case Profile::PreferCallerRefreshes:
2441 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is caller
2442 break;
2443 }
2444 }
2445
2446 void
2447 InviteSession::startSessionTimer()
2448 {
2449 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
2450 {
2451 // Check if we are the refresher
2452 if(mSessionRefresher)
2453 {
2454 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
2455 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
2456 }
2457 else
2458 {
2459 // 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)
2460 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
2461 }
2462 }
2463 else // Session Interval less than 90 - consider timers disabled
2464 {
2465 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
2466 }
2467 }
2468
2469 void
2470 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
2471 {
2472 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
2473
2474 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2475 if (msg.exists(h_PAssertedIdentities))
2476 {
2477 mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
2478 }
2479
2480 // If session timers are locally supported then handle response
2481 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2482 {
2483 setSessionTimerPreferences();
2484
2485 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
2486 && !msg.exists(h_SessionExpires))
2487 {
2488 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
2489 mSessionInterval = 0;
2490 }
2491 // Process Session Timer headers
2492 else if(msg.exists(h_SessionExpires))
2493 {
2494 mSessionInterval = msg.header(h_SessionExpires).value();
2495 if(msg.header(h_SessionExpires).exists(p_refresher))
2496 {
2497 // Remote end specified refresher preference
2498 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
2499 }
2500 }
2501 else
2502 {
2503 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
2504 // - we are free to use our SessionInterval settings (set above as a default)
2505 // If far end doesn't support then refresher must be local
2506 mSessionRefresher = true;
2507 }
2508
2509 // Update MinSE if specified and longer than current value
2510 if(msg.exists(h_MinSE))
2511 {
2512 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
2513 }
2514
2515 startSessionTimer();
2516 }
2517 }
2518
2519 void
2520 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
2521 {
2522 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
2523
2524 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2525 if (request.exists(h_PAssertedIdentities))
2526 {
2527 mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
2528 }
2529
2530 // If session timers are locally supported then add necessary headers to response
2531 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2532 {
2533 setSessionTimerPreferences();
2534
2535 // Check if far-end supports
2536 bool farEndSupportsTimer = false;
2537 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
2538 {
2539 farEndSupportsTimer = true;
2540 if(request.exists(h_SessionExpires))
2541 {
2542 // Use Session Interval requested by remote - if none then use local settings
2543 mSessionInterval = request.header(h_SessionExpires).value();
2544 if(request.header(h_SessionExpires).exists(p_refresher))
2545 {
2546 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
2547 }
2548 }
2549
2550 // Update MinSE if specified and longer than current value
2551 if(request.exists(h_MinSE))
2552 {
2553 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
2554 }
2555 }
2556 else
2557 {
2558 // If far end doesn't support then refresher must be local
2559 mSessionRefresher = true;
2560 }
2561
2562 // Add Session-Expires to response if required
2563 if(mSessionInterval >= 90)
2564 {
2565 if(farEndSupportsTimer)
2566 {
2567 // If far end supports session-timer then require it, if not already present
2568 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
2569 {
2570 response.header(h_Requires).push_back(Token(Symbols::Timer));
2571 }
2572 }
2573 setSessionTimerHeaders(response);
2574 }
2575
2576 startSessionTimer();
2577 }
2578 }
2579
2580 Data
2581 InviteSession::toData(State state)
2582 {
2583 switch (state)
2584 {
2585 case Undefined:
2586 return "InviteSession::Undefined";
2587 case Connected:
2588 return "InviteSession::Connected";
2589 case SentUpdate:
2590 return "InviteSession::SentUpdate";
2591 case SentUpdateGlare:
2592 return "InviteSession::SentUpdateGlare";
2593 case SentReinvite:
2594 return "InviteSession::SentReinvite";
2595 case SentReinviteGlare:
2596 return "InviteSession::SentReinviteGlare";
2597 case SentReinviteNoOffer:
2598 return "InviteSession::SentReinviteNoOffer";
2599 case SentReinviteAnswered:
2600 return "InviteSession::SentReinviteAnswered";
2601 case SentReinviteNoOfferGlare:
2602 return "InviteSession::SentReinviteNoOfferGlare";
2603 case ReceivedUpdate:
2604 return "InviteSession::ReceivedUpdate";
2605 case ReceivedReinvite:
2606 return "InviteSession::ReceivedReinvite";
2607 case ReceivedReinviteNoOffer:
2608 return "InviteSession::ReceivedReinviteNoOffer";
2609 case ReceivedReinviteSentOffer:
2610 return "InviteSession::ReceivedReinviteSentOffer";
2611 case Answered:
2612 return "InviteSession::Answered";
2613 case WaitingToOffer:
2614 return "InviteSession::WaitingToOffer";
2615 case WaitingToRequestOffer:
2616 return "InviteSession::WaitingToRequestOffer";
2617 case WaitingToTerminate:
2618 return "InviteSession::WaitingToTerminate";
2619 case WaitingToHangup:
2620 return "InviteSession::WaitingToHangup";
2621 case Terminated:
2622 return "InviteSession::Terminated";
2623
2624 case UAC_Start:
2625 return "UAC_Start";
2626 case UAS_Offer:
2627 return "UAS_Offer";
2628 case UAS_OfferProvidedAnswer:
2629 return "UAS_OfferProvidedAnswer";
2630 case UAS_EarlyOffer:
2631 return "UAS_EarlyOffer";
2632 case UAS_EarlyProvidedAnswer:
2633 return "UAS_EarlyProvidedAnswer";
2634 case UAS_NoOffer:
2635 return "UAS_NoOffer";
2636 case UAS_ProvidedOffer:
2637 return "UAS_ProvidedOffer";
2638 case UAS_EarlyNoOffer:
2639 return "UAS_EarlyNoOffer";
2640 case UAS_EarlyProvidedOffer:
2641 return "UAS_EarlyProvidedOffer";
2642 case UAS_Accepted:
2643 return "UAS_Accepted";
2644 case UAS_WaitingToOffer:
2645 return "UAS_WaitingToOffer";
2646 case UAS_AcceptedWaitingAnswer:
2647 return "UAS_AcceptedWaitingAnswer";
2648 case UAC_Early:
2649 return "UAC_Early";
2650 case UAC_EarlyWithOffer:
2651 return "UAC_EarlyWithOffer";
2652 case UAC_EarlyWithAnswer:
2653 return "UAC_EarlyWithAnswer";
2654 case UAC_Answered:
2655 return "UAC_Answered";
2656 case UAC_SentUpdateEarly:
2657 return "UAC_SentUpdateEarly";
2658 case UAC_SentUpdateEarlyGlare:
2659 return "UAC_SentUpdateEarlyGlare";
2660 case UAC_ReceivedUpdateEarly:
2661 return "UAC_ReceivedUpdateEarly";
2662 case UAC_SentAnswer:
2663 return "UAC_SentAnswer";
2664 case UAC_QueuedUpdate:
2665 return "UAC_QueuedUpdate";
2666 case UAC_Cancelled:
2667 return "UAC_Cancelled";
2668
2669 case UAS_Start:
2670 return "UAS_Start";
2671 case UAS_ReceivedOfferReliable:
2672 return "UAS_ReceivedOfferReliable";
2673 case UAS_NoOfferReliable:
2674 return "UAS_NoOfferReliable";
2675 case UAS_FirstSentOfferReliable:
2676 return "UAS_FirstSentOfferReliable";
2677 case UAS_FirstSentAnswerReliable:
2678 return "UAS_FirstSentAnswerReliable";
2679 case UAS_NegotiatedReliable:
2680 return "UAS_NegotiatedReliable";
2681 case UAS_SentUpdate:
2682 return "UAS_SentUpdate";
2683 case UAS_SentUpdateAccepted:
2684 return "UAS_SentUpdateAccepted";
2685 case UAS_ReceivedUpdate:
2686 return "UAS_ReceivedUpdate";
2687 case UAS_ReceivedUpdateWaitingAnswer:
2688 return "UAS_ReceivedUpdateWaitingAnswer";
2689 case UAS_WaitingToTerminate:
2690 return "UAS_WaitingToTerminate";
2691 case UAS_WaitingToHangup:
2692 return "UAS_WaitingToHangup";
2693 case UAS_WaitingToRequestOffer:
2694 return "UAS_WaitingToRequestOffer";
2695 }
2696 assert(0);
2697 return "Undefined";
2698 }
2699
2700
2701 void
2702 InviteSession::transition(State target)
2703 {
2704 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
2705 mState = target;
2706 }
2707
2708 bool
2709 InviteSession::isReliable(const SipMessage& msg)
2710 {
2711 if(msg.method() != INVITE)
2712 {
2713 return false;
2714 }
2715 if(msg.isRequest())
2716 {
2717 return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never
2718 && ((msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)))
2719 || (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
2720 }
2721 else
2722 {
2723 return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never
2724 && msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel));
2725 }
2726 }
2727
2728 //static std::auto_ptr<SdpContents> emptySdp;
2729 std::auto_ptr<Contents>
2730 InviteSession::getOfferAnswer(const SipMessage& msg)
2731 {
2732 if(mDum.mInviteSessionHandler->isGenericOfferAnswer())
2733 {
2734 if(msg.getContents())
2735 {
2736 return std::auto_ptr<Contents>(msg.getContents()->clone());
2737 }
2738 else
2739 {
2740 return std::auto_ptr<Contents>();
2741 }
2742 }
2743 else
2744 {
2745 return std::auto_ptr<Contents>(Helper::getSdp(msg.getContents()));
2746 }
2747 }
2748
2749 std::auto_ptr<Contents>
2750 InviteSession::makeOfferAnswer(const Contents& offerAnswer)
2751 {
2752 return std::auto_ptr<Contents>(static_cast<Contents*>(offerAnswer.clone()));
2753 }
2754
2755 auto_ptr<Contents>
2756 InviteSession::makeOfferAnswer(const Contents& offerAnswer,
2757 const Contents* alternative)
2758 {
2759 if (alternative)
2760 {
2761 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2762 mac->parts().push_back(alternative->clone());
2763 mac->parts().push_back(offerAnswer.clone());
2764 return auto_ptr<Contents>(mac);
2765 }
2766 else
2767 {
2768 return auto_ptr<Contents>(offerAnswer.clone());
2769 }
2770 }
2771
2772 void
2773 InviteSession::setOfferAnswer(SipMessage& msg, const Contents& offerAnswer, const Contents* alternative)
2774 {
2775 // !jf! should deal with multipart here
2776
2777 // This will clone the offerAnswer since the InviteSession also wants to keep its own
2778 // copy of the offerAnswer around for the application to access
2779 if (alternative)
2780 {
2781 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2782 mac->parts().push_back(alternative->clone());
2783 mac->parts().push_back(offerAnswer.clone());
2784 msg.setContents(auto_ptr<Contents>(mac));
2785 }
2786 else
2787 {
2788 msg.setContents(&offerAnswer);
2789 }
2790 }
2791
2792 void
2793 InviteSession::setOfferAnswer(SipMessage& msg, const Contents* offerAnswer)
2794 {
2795 assert(offerAnswer);
2796 msg.setContents(offerAnswer);
2797 }
2798
2799 void
2800 InviteSession::provideProposedOffer()
2801 {
2802 MultipartAlternativeContents* mp_ans =
2803 dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get());
2804 if (mp_ans)
2805 {
2806 // .kw. can cast below ever be NULL? Need assert/throw?
2807 provideOffer( *(dynamic_cast<Contents*>((mp_ans)->parts().back())),
2808 mProposedEncryptionLevel,
2809 dynamic_cast<Contents*>((mp_ans)->parts().front()));
2810 }
2811 else
2812 {
2813 // .kw. can cast below ever be NULL? Need assert/throw?
2814 provideOffer(*(dynamic_cast<Contents*>(mProposedLocalOfferAnswer.get())), mProposedEncryptionLevel, 0);
2815 }
2816 }
2817
2818 InviteSession::Event
2819 InviteSession::toEvent(const SipMessage& msg, const Contents* offerAnswer)
2820 {
2821 MethodTypes method = msg.header(h_CSeq).method();
2822 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2823
2824 //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
2825 //responses, reiable provisionals should only be received if the invite was
2826 //sent reliably. Spurious reliable provisional respnoses are dropped outside
2827 //the state machine.
2828 bool reliable = isReliable(msg);
2829 bool sentOffer = mProposedLocalOfferAnswer.get();
2830
2831 if (code == 481 || code == 408)
2832 {
2833 return OnGeneralFailure;
2834 }
2835 else if (code >= 300 && code <= 399)
2836 {
2837 return OnRedirect;
2838 }
2839 else if (method == INVITE && code == 0)
2840 {
2841 if (offerAnswer)
2842 {
2843 if (reliable)
2844 {
2845 return OnInviteReliableOffer;
2846 }
2847 else
2848 {
2849 return OnInviteOffer;
2850 }
2851 }
2852 else
2853 {
2854 if (reliable)
2855 {
2856 return OnInviteReliable;
2857 }
2858 else
2859 {
2860 return OnInvite;
2861 }
2862 }
2863 }
2864 else if (method == INVITE && code > 100 && code < 200)
2865 {
2866 if (reliable)
2867 {
2868 if (offerAnswer)
2869 {
2870 if (sentOffer)
2871 {
2872 return On1xxAnswer;
2873 }
2874 else
2875 {
2876 return On1xxOffer;
2877 }
2878 }
2879 else
2880 {
2881 return On1xx;
2882 }
2883 }
2884 else
2885 {
2886 if (offerAnswer)
2887 {
2888 return On1xxEarly;
2889 }
2890 else
2891 {
2892 return On1xx;
2893 }
2894 }
2895 }
2896 else if (method == INVITE && code >= 200 && code < 300)
2897 {
2898 if (offerAnswer)
2899 {
2900 if (sentOffer)
2901 {
2902 return On2xxAnswer;
2903 }
2904 else
2905 {
2906 return On2xxOffer;
2907 }
2908 }
2909 else
2910 {
2911 return On2xx;
2912 }
2913 }
2914 else if (method == INVITE && code == 422)
2915 {
2916 return On422Invite;
2917 }
2918 else if (method == INVITE && code == 487)
2919 {
2920 return On487Invite;
2921 }
2922 else if (method == INVITE && code == 491)
2923 {
2924 return On491Invite;
2925 }
2926 else if (method == INVITE && code >= 400)
2927 {
2928 return OnInviteFailure;
2929 }
2930 else if (method == ACK)
2931 {
2932 if (offerAnswer)
2933 {
2934 return OnAckAnswer;
2935 }
2936 else
2937 {
2938 return OnAck;
2939 }
2940 }
2941 else if (method == CANCEL && code == 0)
2942 {
2943 return OnCancel;
2944 }
2945 else if (method == CANCEL && code / 200 == 1)
2946 {
2947 return On200Cancel;
2948 }
2949 else if (method == CANCEL && code >= 400)
2950 {
2951 return OnCancelFailure;
2952 }
2953 else if (method == BYE && code == 0)
2954 {
2955 return OnBye;
2956 }
2957 else if (method == BYE && code / 200 == 1)
2958 {
2959 return On200Bye;
2960 }
2961 else if (method == PRACK && code == 0)
2962 {
2963 return OnPrack;
2964 }
2965 else if (method == PRACK && code / 200 == 1)
2966 {
2967 return On200Prack;
2968 }
2969 else if (method == UPDATE && code == 0)
2970 {
2971 if (offerAnswer)
2972 {
2973 return OnUpdateOffer;
2974 }
2975 else
2976 {
2977 return OnUpdate;
2978 }
2979 }
2980 else if (method == UPDATE && code / 200 == 1)
2981 {
2982 return On200Update;
2983 }
2984 else if (method == UPDATE && code == 422)
2985 {
2986 return On422Update;
2987 }
2988 else if (method == UPDATE && code == 491)
2989 {
2990 return On491Update;
2991 }
2992 else if (method == UPDATE && code >= 400)
2993 {
2994 return OnUpdateRejected;
2995 }
2996 else
2997 {
2998 //assert(0); // dispatchOthers will throw if the message type is really unknown
2999 return Unknown;
3000 }
3001 }
3002
3003 void
3004 InviteSession::sendAck(const Contents *answer)
3005 {
3006 SharedPtr<SipMessage> ack(new SipMessage);
3007
3008 SharedPtr<SipMessage> source;
3009
3010 if (mLastLocalSessionModification->method() == UPDATE)
3011 {
3012 //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
3013 source = mDialog.mDialogSet.getCreator()->getLastRequest();
3014 }
3015 else
3016 {
3017 source = mLastLocalSessionModification;
3018 }
3019
3020 assert(mAcks.count(source->getTransactionId()) == 0);
3021
3022 mDialog.makeRequest(*ack, ACK);
3023
3024 // Copy Authorization and Proxy Authorization headers from
3025 // mLastLocalSessionModification; regardless of whether this was the original
3026 // INVITE or not, this is the correct place to go for auth headers.
3027 if(mLastLocalSessionModification->exists(h_Authorizations))
3028 {
3029 ack->header(h_Authorizations) = mLastLocalSessionModification->header(h_Authorizations);
3030 }
3031 if(mLastLocalSessionModification->exists(h_ProxyAuthorizations))
3032 {
3033 ack->header(h_ProxyAuthorizations) = mLastLocalSessionModification->header(h_ProxyAuthorizations);
3034 }
3035
3036 // Copy CSeq from original INVITE
3037 ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
3038
3039 if(answer != 0)
3040 {
3041 setOfferAnswer(*ack, *answer);
3042 }
3043 mAcks[source->getTransactionId()] = ack;
3044 mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(), 0, source->getTransactionId());
3045
3046 InfoLog (<< "Sending " << ack->brief());
3047 send(ack);
3048 }
3049
3050 SharedPtr<SipMessage>
3051 InviteSession::sendBye()
3052 {
3053 SharedPtr<SipMessage> bye(new SipMessage());
3054 mDialog.makeRequest(*bye, BYE);
3055 Data txt;
3056 if (mEndReason != NotSpecified)
3057 {
3058 Token reason("SIP");
3059 txt = getEndReasonString(mEndReason);
3060 reason.param(p_text) = txt;
3061 bye->header(h_Reasons).push_back(reason);
3062 }
3063
3064 if (mDum.mDialogEventStateManager)
3065 {
3066 mDum.mDialogEventStateManager->onTerminated(mDialog, *bye, InviteSessionHandler::LocalBye);
3067 }
3068
3069 InfoLog (<< myAddr() << " Sending BYE " << txt);
3070 send(bye);
3071 return bye;
3072 }
3073
3074 DialogUsageManager::EncryptionLevel
3075 InviteSession::getEncryptionLevel(const SipMessage& msg)
3076 {
3077 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
3078 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
3079 if (secAttr)
3080 {
3081 SignatureStatus sig = secAttr->getSignatureStatus();
3082 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
3083 bool encrypted = secAttr->isEncrypted();
3084 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
3085 else if (encrypted) level = DialogUsageManager::Encrypt;
3086 else if (sign) level = DialogUsageManager::Sign;
3087 }
3088 return level;
3089 }
3090
3091 void
3092 InviteSession::setCurrentLocalOfferAnswer(const SipMessage& msg)
3093 {
3094 assert(mProposedLocalOfferAnswer.get());
3095 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))
3096 {
3097 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
3098 {
3099 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().back()->clone()));
3100 }
3101 else
3102 {
3103 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().front()->clone()));
3104 }
3105 }
3106 else
3107 {
3108 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>(mProposedLocalOfferAnswer.get()->clone()));
3109 }
3110 mProposedLocalOfferAnswer.reset();
3111 }
3112
3113 void
3114 InviteSession::onReadyToSend(SipMessage& msg)
3115 {
3116 mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
3117 }
3118
3119 void
3120 InviteSession::flowTerminated()
3121 {
3122 // notify handler
3123 mDum.mInviteSessionHandler->onFlowTerminated(getSessionHandle());
3124 }
3125
3126 void
3127 InviteSession::referNoSub(const SipMessage& msg)
3128 {
3129 assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
3130 mLastReferNoSubRequest = msg;
3131 mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
3132 }
3133
3134 void
3135 InviteSession::acceptReferNoSub(int statusCode)
3136 {
3137 if (statusCode / 100 != 2)
3138 {
3139 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
3140 }
3141
3142 SharedPtr<SipMessage> response(new SipMessage);
3143 mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
3144 response->header(h_ReferSub).value() = "false";
3145 //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
3146
3147 send(response);
3148 }
3149
3150 void
3151 InviteSession::rejectReferNoSub(int responseCode)
3152 {
3153 if (responseCode < 400)
3154 {
3155 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
3156 }
3157
3158 SharedPtr<SipMessage> response(new SipMessage);
3159 mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
3160 send(response);
3161 }
3162
3163 /* ====================================================================
3164 * The Vovida Software License, Version 1.0
3165 *
3166 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
3167 *
3168 * Redistribution and use in source and binary forms, with or without
3169 * modification, are permitted provided that the following conditions
3170 * are met:
3171 *
3172 * 1. Redistributions of source code must retain the above copyright
3173 * notice, this list of conditions and the following disclaimer.
3174 *
3175 * 2. Redistributions in binary form must reproduce the above copyright
3176 * notice, this list of conditions and the following disclaimer in
3177 * the documentation and/or other materials provided with the
3178
3179 * distribution.
3180 *
3181 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
3182 * and "Vovida Open Communication Application Library (VOCAL)" must
3183 * not be used to endorse or promote products derived from this
3184 * software without prior written permission. For written
3185 * permission, please contact vocal@vovida.org.
3186 *
3187 * 4. Products derived from this software may not be called "VOCAL", nor
3188 * may "VOCAL" appear in their name, without prior written
3189 * permission of Vovida Networks, Inc.
3190 *
3191 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
3192 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3193 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
3194 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
3195 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
3196 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
3197 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3198 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3199 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
3200 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3201 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3202 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3203 * DAMAGE.
3204 *
3205 * ====================================================================
3206 *
3207 * This software consists of voluntary contributions made by Vovida
3208 * Networks, Inc. and many individuals on behalf of Vovida Networks,
3209 * Inc. For more information on Vovida Networks, Inc., please see
3210 * <http://www.vovida.org/>.
3211 *
3212 */
3213
3214
3215

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