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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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