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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7406 - (show annotations) (download)
Thu Nov 15 17:20:31 2007 UTC (12 years ago) by sgodin
File MIME type: text/plain
File size: 86190 byte(s)
- removed an out dated comment and fixed the graph name in dum-invite-connected-state.dot
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 break;
1533 }
1534
1535 case On2xx:
1536 mStaleReInviteTimerSeq++;
1537 sendAck();
1538 transition(Connected);
1539 handleSessionTimerResponse(msg);
1540 handler->onIllegalNegotiation(getSessionHandle(), msg);
1541 mProposedLocalSdp.reset();
1542 mProposedEncryptionLevel = DialogUsageManager::None;
1543 break;
1544
1545 case On422Invite:
1546 mStaleReInviteTimerSeq++;
1547 if(msg.exists(h_MinSE))
1548 {
1549 // Change interval to min from 422 response
1550 mSessionInterval = msg.header(h_MinSE).value();
1551 mMinSE = mSessionInterval;
1552 sessionRefresh();
1553 }
1554 else
1555 {
1556 // Response must contact Min_SE - if not - just ignore
1557 // ?slg? callback?
1558 transition(Connected);
1559 mProposedLocalSdp.reset();
1560 mProposedEncryptionLevel = DialogUsageManager::None;
1561 }
1562 break;
1563
1564 case On491Invite:
1565 mStaleReInviteTimerSeq++;
1566 transition(SentReinviteNoOfferGlare);
1567 start491Timer();
1568 break;
1569
1570 case OnGeneralFailure:
1571 mStaleReInviteTimerSeq++;
1572 sendBye();
1573 transition(Terminated);
1574 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1575 break;
1576
1577 case OnInviteFailure:
1578 case On487Invite:
1579 mStaleReInviteTimerSeq++;
1580 transition(Connected);
1581 mProposedLocalSdp.reset();
1582 handler->onOfferRejected(getSessionHandle(), &msg);
1583 break;
1584
1585 default:
1586 dispatchOthers(msg);
1587 break;
1588 }
1589 }
1590
1591 void
1592 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1593 {
1594 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1595 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1596
1597 switch (toEvent(msg, sdp.get()))
1598 {
1599 case OnInvite:
1600 case OnInviteReliable:
1601 case OnInviteOffer:
1602 case OnInviteReliableOffer:
1603 case OnUpdate:
1604 case OnUpdateOffer:
1605 {
1606 SharedPtr<SipMessage> response(new SipMessage);
1607 mDialog.makeResponse(*response, msg, 491);
1608 send(response);
1609 break;
1610 }
1611 case OnAckAnswer:
1612 transition(Connected);
1613 setCurrentLocalSdp(msg);
1614 mCurrentRemoteSdp = sdp;
1615 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1616 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1617
1618 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteSdp);
1619 break;
1620 case OnAck:
1621 if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
1622 {
1623 InfoLog(<< "dropped stale ACK");
1624 }
1625 else
1626 {
1627 InfoLog(<< "Got Ack with no answer");
1628 transition(Connected);
1629 mProposedLocalSdp.reset();
1630 mProposedEncryptionLevel = DialogUsageManager::None;
1631 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1632 //!dcm! -- should this be onIllegalNegotiation?
1633 handler->onOfferRejected(getSessionHandle(), &msg);
1634 }
1635 break;
1636 default:
1637 dispatchOthers(msg);
1638 break;
1639 }
1640 }
1641
1642 void
1643 InviteSession::dispatchGlare(const SipMessage& msg)
1644 {
1645 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1646 MethodTypes method = msg.header(h_CSeq).method();
1647 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1648 {
1649 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1650 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1651 handler->onOfferRejected(getSessionHandle(), &msg);
1652 if(!isTerminated()) // make sure application didn't call end()
1653 {
1654 dispatchConnected(msg); // act as if we received message in Connected state
1655 }
1656 else
1657 {
1658 dispatchTerminated(msg);
1659 }
1660 }
1661 else
1662 {
1663 dispatchOthers(msg);
1664 }
1665 }
1666
1667 void
1668 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1669 {
1670 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1671 MethodTypes method = msg.header(h_CSeq).method();
1672 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1673 {
1674 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1675 handler->onOfferRequestRejected(getSessionHandle(), msg);
1676 if(!isTerminated()) // make sure application didn't call end()
1677 {
1678 dispatchConnected(msg); // act as if we received message in Connected state
1679 }
1680 else
1681 {
1682 dispatchTerminated(msg);
1683 }
1684 }
1685 else
1686 {
1687 dispatchOthers(msg);
1688 }
1689 }
1690
1691 void
1692 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1693 {
1694 MethodTypes method = msg.header(h_CSeq).method();
1695 if (method == INVITE || method == UPDATE)
1696 {
1697 // Means that the UAC has sent us a second reINVITE or UPDATE before we
1698 // responded to the first one. Bastard!
1699 SharedPtr<SipMessage> response(new SipMessage);
1700 mDialog.makeResponse(*response, msg, 500);
1701 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1702 send(response);
1703 }
1704 else
1705 {
1706 dispatchOthers(msg);
1707 }
1708 }
1709
1710
1711 void
1712 InviteSession::dispatchAnswered(const SipMessage& msg)
1713 {
1714 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1715 {
1716 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1717 transition(Connected);
1718 }
1719 else
1720 {
1721 dispatchOthers(msg);
1722 }
1723 }
1724
1725 void
1726 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1727 {
1728 if (msg.isResponse() &&
1729 msg.header(h_CSeq).method() == INVITE &&
1730 msg.header(h_StatusLine).statusCode() / 200 == 1)
1731 {
1732 // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
1733 // called by the app - so just drop the retransmission
1734 return;
1735 }
1736 dispatchOthers(msg);
1737 }
1738
1739 void
1740 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1741 {
1742 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1743 {
1744 assert(mProposedLocalSdp.get());
1745 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1746 provideProposedOffer();
1747 }
1748 else
1749 {
1750 dispatchOthers(msg);
1751 }
1752 }
1753
1754 void
1755 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1756 {
1757 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1758 {
1759 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1760 requestOffer();
1761 }
1762 else
1763 {
1764 dispatchOthers(msg);
1765 }
1766 }
1767
1768 void
1769 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1770 {
1771 if (msg.isResponse() &&
1772 msg.header(h_CSeq).method() == INVITE)
1773 {
1774 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1775 {
1776 // !jf! Need to include the answer here.
1777 sendAck();
1778 }
1779 sendBye();
1780 transition(Terminated);
1781 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1782 }
1783 else if(msg.isRequest())
1784 {
1785 if(msg.method() == BYE)
1786 {
1787 dispatchBye(msg);
1788 }
1789 else
1790 {
1791 SharedPtr<SipMessage> response(new SipMessage);
1792 mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
1793 send(response);
1794 }
1795 }
1796 }
1797
1798 void
1799 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1800 {
1801 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1802
1803 switch (toEvent(msg, sdp.get()))
1804 {
1805 case OnAck:
1806 case OnAckAnswer:
1807 {
1808 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1809
1810 sendBye();
1811 transition(Terminated);
1812 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1813 break;
1814 }
1815
1816 default:
1817 break;
1818 }
1819 }
1820
1821 void
1822 InviteSession::dispatchTerminated(const SipMessage& msg)
1823 {
1824 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1825
1826 if (msg.isRequest())
1827 {
1828 if (BYE == msg.header(h_CSeq).method())
1829 {
1830 SharedPtr<SipMessage> response(new SipMessage);
1831 mDialog.makeResponse(*response, msg, 200);
1832 send(response);
1833 }
1834 else
1835 {
1836 SharedPtr<SipMessage> response(new SipMessage);
1837 mDialog.makeResponse(*response, msg, 481);
1838 send(response);
1839 }
1840
1841 // !jf! means the peer sent BYE while we are waiting for response to BYE
1842 //mDum.destroy(this);
1843 }
1844 else
1845 {
1846 mDum.destroy(this);
1847 }
1848 }
1849
1850 void
1851 InviteSession::dispatchOthers(const SipMessage& msg)
1852 {
1853 // handle OnGeneralFailure
1854 // handle OnRedirect
1855
1856 switch (msg.header(h_CSeq).method())
1857 {
1858 case PRACK:
1859 dispatchPrack(msg);
1860 break;
1861 case CANCEL:
1862 dispatchCancel(msg);
1863 break;
1864 case BYE:
1865 dispatchBye(msg);
1866 break;
1867 case INFO:
1868 dispatchInfo(msg);
1869 break;
1870 case MESSAGE:
1871 dispatchMessage(msg);
1872 break;
1873 case ACK:
1874 // Ignore duplicate ACKs from 2xx reTransmissions
1875 break;
1876 default:
1877 // handled in Dialog
1878 WarningLog (<< "DUM delivered a "
1879 << msg.header(h_CSeq).unknownMethodName()
1880 << " to the InviteSession in state: " << toData(mState)
1881 << endl
1882 << msg);
1883 assert(0);
1884 break;
1885 }
1886 }
1887
1888 void
1889 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
1890 {
1891 assert(msg.isRequest());
1892 assert(msg.header(h_CSeq).method() == INVITE);
1893
1894 // If we get an INVITE request from the wire and we are not in
1895 // Connected state, reject the request and send a BYE
1896 SharedPtr<SipMessage> response(new SipMessage);
1897 mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
1898 InfoLog (<< "Sending " << response->brief());
1899 send(response);
1900
1901 sendBye();
1902 transition(Terminated);
1903 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1904 }
1905
1906 void
1907 InviteSession::dispatchPrack(const SipMessage& msg)
1908 {
1909 assert(msg.header(h_CSeq).method() == PRACK);
1910 if(msg.isRequest())
1911 {
1912 SharedPtr<SipMessage> rsp(new SipMessage);
1913 mDialog.makeResponse(*rsp, msg, 481);
1914 send(rsp);
1915
1916 sendBye();
1917 // !jf! should we make some other callback here
1918 transition(Terminated);
1919 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1920 }
1921 else
1922 {
1923 // ignore. could be PRACK/200
1924 }
1925 }
1926
1927 void
1928 InviteSession::dispatchCancel(const SipMessage& msg)
1929 {
1930 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1931 assert(msg.header(h_CSeq).method() == CANCEL);
1932 if(msg.isRequest())
1933 {
1934 SharedPtr<SipMessage> rsp(new SipMessage);
1935 mDialog.makeResponse(*rsp, msg, 200);
1936 send(rsp);
1937
1938 sendBye();
1939 // !jf! should we make some other callback here
1940 transition(Terminated);
1941 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1942 }
1943 else
1944 {
1945 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1946 assert(0);
1947 }
1948 }
1949
1950 void
1951 InviteSession::dispatchBye(const SipMessage& msg)
1952 {
1953 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1954
1955 if (msg.isRequest())
1956 {
1957
1958 SharedPtr<SipMessage> rsp(new SipMessage);
1959 InfoLog (<< "Received " << msg.brief());
1960 mDialog.makeResponse(*rsp, msg, 200);
1961 send(rsp);
1962
1963 // !jf! should we make some other callback here
1964 transition(Terminated);
1965 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1966 mDum.destroy(this);
1967 }
1968 else
1969 {
1970 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1971 assert(0);
1972 }
1973 }
1974
1975 void
1976 InviteSession::dispatchInfo(const SipMessage& msg)
1977 {
1978 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1979 if (msg.isRequest())
1980 {
1981 InfoLog (<< "Received " << msg.brief());
1982 mDialog.makeResponse(*mLastNitResponse, msg, 200);
1983 handler->onInfo(getSessionHandle(), msg);
1984 }
1985 else
1986 {
1987 assert(mNitState == NitProceeding);
1988 mNitState = NitComplete;
1989 //!dcm! -- toss away 1xx to an info?
1990 if (msg.header(h_StatusLine).statusCode() >= 300)
1991 {
1992 handler->onInfoFailure(getSessionHandle(), msg);
1993 }
1994 else if (msg.header(h_StatusLine).statusCode() >= 200)
1995 {
1996 handler->onInfoSuccess(getSessionHandle(), msg);
1997 }
1998 }
1999 }
2000
2001 void
2002 InviteSession::acceptNIT(int statusCode, const Contents * contents)
2003 {
2004 if (statusCode / 100 != 2)
2005 {
2006 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2007 }
2008
2009 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2010 mLastNitResponse->setContents(contents);
2011 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2012 send(mLastNitResponse);
2013 }
2014
2015 class InviteSessionAcceptNITCommand : public DumCommandAdapter
2016 {
2017 public:
2018 InviteSessionAcceptNITCommand(InviteSession& inviteSession, int statusCode, const Contents* contents)
2019 : mInviteSession(inviteSession),
2020 mStatusCode(statusCode),
2021 mContents(contents?contents->clone():0)
2022 {
2023
2024 }
2025
2026 virtual void executeCommand()
2027 {
2028 mInviteSession.acceptNITCommand(mStatusCode, mContents.get());
2029 }
2030
2031 virtual std::ostream& encodeBrief(std::ostream& strm) const
2032 {
2033 return strm << "InviteSessionAcceptNITCommand";
2034 }
2035 private:
2036 InviteSession& mInviteSession;
2037 int mStatusCode;
2038 std::auto_ptr<Contents> mContents;
2039 };
2040
2041 void
2042 InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
2043 {
2044 mDum.post(new InviteSessionAcceptNITCommand(*this, statusCode, contents));
2045 }
2046
2047 void
2048 InviteSession::rejectNIT(int statusCode)
2049 {
2050 if (statusCode < 400)
2051 {
2052 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2053 }
2054 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2055 mLastNitResponse->releaseContents();
2056 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2057 send(mLastNitResponse);
2058 }
2059
2060 class InviteSessionRejectNITCommand : public DumCommandAdapter
2061 {
2062 public:
2063 InviteSessionRejectNITCommand(InviteSession& inviteSession, int statusCode)
2064 : mInviteSession(inviteSession),
2065 mStatusCode(statusCode)
2066 {
2067 }
2068
2069 virtual void executeCommand()
2070 {
2071 mInviteSession.rejectNITCommand(mStatusCode);
2072 }
2073
2074 virtual std::ostream& encodeBrief(std::ostream& strm) const
2075 {
2076 return strm << "InviteSessionRejectNITCommand";
2077 }
2078 private:
2079 InviteSession& mInviteSession;
2080 int mStatusCode;
2081 };
2082
2083 void
2084 InviteSession::rejectNITCommand(int statusCode)
2085 {
2086 mDum.post(new InviteSessionRejectNITCommand(*this, statusCode));
2087 }
2088
2089 void
2090 InviteSession::dispatchMessage(const SipMessage& msg)
2091 {
2092 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2093 if (msg.isRequest())
2094 {
2095 InfoLog (<< "Received " << msg.brief());
2096 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2097 mLastNitResponse->header(h_Contacts).clear();
2098 handler->onMessage(getSessionHandle(), msg);
2099 }
2100 else
2101 {
2102 assert(mNitState == NitProceeding);
2103 mNitState = NitComplete;
2104 //!dcm! -- toss away 1xx to an message?
2105 if (msg.header(h_StatusLine).statusCode() >= 300)
2106 {
2107 handler->onMessageFailure(getSessionHandle(), msg);
2108 }
2109 else if (msg.header(h_StatusLine).statusCode() >= 200)
2110 {
2111 handler->onMessageSuccess(getSessionHandle(), msg);
2112 }
2113 }
2114 }
2115
2116 void
2117 InviteSession::startRetransmit200Timer()
2118 {
2119 mCurrentRetransmit200 = Timer::T1;
2120 unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
2121 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
2122 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
2123 }
2124
2125 // RFC3261 section 14.1
2126 // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
2127 // a value T chosen as follows:
2128 // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
2129 // chosen value between 2.1 and 4 seconds in units of 10 ms.
2130 // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
2131 // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
2132 void
2133 InviteSession::start491Timer()
2134 {
2135 unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
2136
2137 if (dynamic_cast<ClientInviteSession*>(this))
2138 {
2139 int timer = Random::getRandom() % (4000 - 2100);
2140 timer += 2100;
2141 timer -= timer % 10;
2142
2143 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2144 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2145 }
2146 else
2147 {
2148 int timer = Random::getRandom() % 2000;
2149 timer -= timer % 10;
2150 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2151 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2152 }
2153 }
2154
2155 void
2156 InviteSession::startStaleReInviteTimer()
2157 {
2158 InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
2159 unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
2160
2161 mDum.addTimer(DumTimeout::StaleReInvite,
2162 when,
2163 getBaseHandle(),
2164 ++mStaleReInviteTimerSeq);
2165 }
2166
2167 void
2168 InviteSession::setSessionTimerHeaders(SipMessage &msg)
2169 {
2170 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
2171 {
2172 msg.header(h_SessionExpires).value() = mSessionInterval;
2173 if(msg.isRequest())
2174 {
2175 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
2176 }
2177 else
2178 {
2179 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
2180 }
2181 msg.header(h_MinSE).value() = mMinSE;
2182 }
2183 else
2184 {
2185 msg.remove(h_SessionExpires);
2186 msg.remove(h_MinSE);
2187 }
2188 }
2189
2190 void
2191 InviteSession::sessionRefresh()
2192 {
2193 if (updateMethodSupported())
2194 {
2195 transition(SentUpdate);
2196 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
2197 mLastLocalSessionModification->releaseContents(); // Don't send SDP
2198 }
2199 else
2200 {
2201 transition(SentReinvite);
2202 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
2203 startStaleReInviteTimer();
2204 InviteSession::setSdp(*mLastLocalSessionModification, mCurrentLocalSdp.get());
2205 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
2206 mSessionRefreshReInvite = true;
2207 }
2208 setSessionTimerHeaders(*mLastLocalSessionModification);
2209
2210 InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
2211 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
2212 send(mLastLocalSessionModification);
2213 }
2214
2215 void
2216 InviteSession::setSessionTimerPreferences()
2217 {
2218 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
2219 if(mSessionInterval != 0)
2220 {
2221 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
2222 mSessionInterval = resipMax(mMinSE, mSessionInterval);
2223 }
2224 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
2225 {
2226 case Profile::PreferLocalRefreshes:
2227 mSessionRefresher = true; // Default refresher is Local
2228 break;
2229 case Profile::PreferRemoteRefreshes:
2230 mSessionRefresher = false; // Default refresher is Remote
2231 break;
2232 case Profile::PreferUASRefreshes:
2233 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
2234 break;
2235 case Profile::PreferUACRefreshes:
2236 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
2237 break;
2238 }
2239 }
2240
2241 void
2242 InviteSession::startSessionTimer()
2243 {
2244 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
2245 {
2246 // Check if we are the refresher
2247 if(mSessionRefresher)
2248 {
2249 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
2250 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
2251 }
2252 else
2253 {
2254 // 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)
2255 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
2256 }
2257 }
2258 else // Session Interval less than 90 - consider timers disabled
2259 {
2260 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
2261 }
2262 }
2263
2264 void
2265 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
2266 {
2267 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
2268
2269 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2270 if (msg.exists(h_PAssertedIdentities))
2271 {
2272 mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
2273 }
2274
2275 // If session timers are locally supported then handle response
2276 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2277 {
2278 setSessionTimerPreferences();
2279
2280 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
2281 && !msg.exists(h_SessionExpires))
2282 {
2283 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
2284 mSessionInterval = 0;
2285 }
2286 // Process Session Timer headers
2287 else if(msg.exists(h_SessionExpires))
2288 {
2289 mSessionInterval = msg.header(h_SessionExpires).value();
2290 if(msg.header(h_SessionExpires).exists(p_refresher))
2291 {
2292 // Remote end specified refresher preference
2293 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
2294 }
2295 }
2296 else
2297 {
2298 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
2299 // - we are free to use our SessionInterval settings (set above as a default)
2300 // If far end doesn't support then refresher must be local
2301 mSessionRefresher = true;
2302 }
2303
2304 // Update MinSE if specified and longer than current value
2305 if(msg.exists(h_MinSE))
2306 {
2307 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
2308 }
2309
2310 startSessionTimer();
2311 }
2312 }
2313
2314 void
2315 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
2316 {
2317 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
2318
2319 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2320 if (request.exists(h_PAssertedIdentities))
2321 {
2322 mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
2323 }
2324
2325 // If session timers are locally supported then add necessary headers to response
2326 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2327 {
2328 setSessionTimerPreferences();
2329
2330 // Check if far-end supports
2331 bool farEndSupportsTimer = false;
2332 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
2333 {
2334 farEndSupportsTimer = true;
2335 if(request.exists(h_SessionExpires))
2336 {
2337 // Use Session Interval requested by remote - if none then use local settings
2338 mSessionInterval = request.header(h_SessionExpires).value();
2339 if(request.header(h_SessionExpires).exists(p_refresher))
2340 {
2341 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
2342 }
2343 }
2344
2345 // Update MinSE if specified and longer than current value
2346 if(request.exists(h_MinSE))
2347 {
2348 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
2349 }
2350 }
2351 else
2352 {
2353 // If far end doesn't support then refresher must be local
2354 mSessionRefresher = true;
2355 }
2356
2357 // Add Session-Expires to response if required
2358 if(mSessionInterval >= 90)
2359 {
2360 if(farEndSupportsTimer)
2361 {
2362 // If far end supports session-timer then require it, if not already present
2363 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
2364 {
2365 response.header(h_Requires).push_back(Token(Symbols::Timer));
2366 }
2367 }
2368 setSessionTimerHeaders(response);
2369 }
2370
2371 startSessionTimer();
2372 }
2373 }
2374
2375 Data
2376 InviteSession::toData(State state)
2377 {
2378 switch (state)
2379 {
2380 case Undefined:
2381 return "InviteSession::Undefined";
2382 case Connected:
2383 return "InviteSession::Connected";
2384 case SentUpdate:
2385 return "InviteSession::SentUpdate";
2386 case SentUpdateGlare:
2387 return "InviteSession::SentUpdateGlare";
2388 case SentReinvite:
2389 return "InviteSession::SentReinvite";
2390 case SentReinviteGlare:
2391 return "InviteSession::SentReinviteGlare";
2392 case SentReinviteNoOffer:
2393 return "InviteSession::SentReinviteNoOffer";
2394 case SentReinviteAnswered:
2395 return "InviteSession::SentReinviteAnswered";
2396 case SentReinviteNoOfferGlare:
2397 return "InviteSession::SentReinviteNoOfferGlare";
2398 case ReceivedUpdate:
2399 return "InviteSession::ReceivedUpdate";
2400 case ReceivedReinvite:
2401 return "InviteSession::ReceivedReinvite";
2402 case ReceivedReinviteNoOffer:
2403 return "InviteSession::ReceivedReinviteNoOffer";
2404 case ReceivedReinviteSentOffer:
2405 return "InviteSession::ReceivedReinviteSentOffer";
2406 case Answered:
2407 return "InviteSession::Answered";
2408 case WaitingToOffer:
2409 return "InviteSession::WaitingToOffer";
2410 case WaitingToRequestOffer:
2411 return "InviteSession::WaitingToRequestOffer";
2412 case WaitingToTerminate:
2413 return "InviteSession::WaitingToTerminate";
2414 case WaitingToHangup:
2415 return "InviteSession::WaitingToHangup";
2416 case Terminated:
2417 return "InviteSession::Terminated";
2418
2419 case UAC_Start:
2420 return "UAC_Start";
2421 case UAS_Offer:
2422 return "UAS_Offer";
2423 case UAS_OfferProvidedAnswer:
2424 return "UAS_OfferProvidedAnswer";
2425 case UAS_EarlyOffer:
2426 return "UAS_EarlyOffer";
2427 case UAS_EarlyProvidedAnswer:
2428 return "UAS_EarlyProvidedAnswer";
2429 case UAS_NoOffer:
2430 return "UAS_NoOffer";
2431 case UAS_ProvidedOffer:
2432 return "UAS_ProvidedOffer";
2433 case UAS_EarlyNoOffer:
2434 return "UAS_EarlyNoOffer";
2435 case UAS_EarlyProvidedOffer:
2436 return "UAS_EarlyProvidedOffer";
2437 case UAS_Accepted:
2438 return "UAS_Accepted";
2439 case UAS_WaitingToOffer:
2440 return "UAS_WaitingToOffer";
2441 case UAS_AcceptedWaitingAnswer:
2442 return "UAS_AcceptedWaitingAnswer";
2443 case UAC_Early:
2444 return "UAC_Early";
2445 case UAC_EarlyWithOffer:
2446 return "UAC_EarlyWithOffer";
2447 case UAC_EarlyWithAnswer:
2448 return "UAC_EarlyWithAnswer";
2449 case UAC_Answered:
2450 return "UAC_Answered";
2451 case UAC_SentUpdateEarly:
2452 return "UAC_SentUpdateEarly";
2453 case UAC_SentUpdateEarlyGlare:
2454 return "UAC_SentUpdateEarlyGlare";
2455 case UAC_ReceivedUpdateEarly:
2456 return "UAC_ReceivedUpdateEarly";
2457 case UAC_SentAnswer:
2458 return "UAC_SentAnswer";
2459 case UAC_QueuedUpdate:
2460 return "UAC_QueuedUpdate";
2461 case UAC_Cancelled:
2462 return "UAC_Cancelled";
2463
2464 case UAS_Start:
2465 return "UAS_Start";
2466 case UAS_ReceivedOfferReliable:
2467 return "UAS_ReceivedOfferReliable";
2468 case UAS_NoOfferReliable:
2469 return "UAS_NoOfferReliable";
2470 case UAS_FirstSentOfferReliable:
2471 return "UAS_FirstSentOfferReliable";
2472 case UAS_FirstSentAnswerReliable:
2473 return "UAS_FirstSentAnswerReliable";
2474 case UAS_NegotiatedReliable:
2475 return "UAS_NegotiatedReliable";
2476 case UAS_SentUpdate:
2477 return "UAS_SentUpdate";
2478 case UAS_SentUpdateAccepted:
2479 return "UAS_SentUpdateAccepted";
2480 case UAS_ReceivedUpdate:
2481 return "UAS_ReceivedUpdate";
2482 case UAS_ReceivedUpdateWaitingAnswer:
2483 return "UAS_ReceivedUpdateWaitingAnswer";
2484 case UAS_WaitingToTerminate:
2485 return "UAS_WaitingToTerminate";
2486 case UAS_WaitingToHangup:
2487 return "UAS_WaitingToHangup";
2488 case UAS_WaitingToRequestOffer:
2489 return "UAS_WaitingToRequestOffer";
2490 }
2491 assert(0);
2492 return "Undefined";
2493 }
2494
2495
2496 void
2497 InviteSession::transition(State target)
2498 {
2499 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
2500 mState = target;
2501 }
2502
2503 bool
2504 InviteSession::isReliable(const SipMessage& msg)
2505 {
2506 if(msg.method() != INVITE)
2507 {
2508 return false;
2509 }
2510 if(msg.isRequest())
2511 {
2512 return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never
2513 && (msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel))
2514 || msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel)));
2515 }
2516 else
2517 {
2518 return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never
2519 && (msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel))
2520 || (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
2521 }
2522 }
2523
2524 std::auto_ptr<SdpContents>
2525 InviteSession::getSdp(const SipMessage& msg)
2526 {
2527 return Helper::getSdp(msg.getContents());
2528 }
2529
2530 std::auto_ptr<SdpContents>
2531 InviteSession::makeSdp(const SdpContents& sdp)
2532 {
2533 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
2534 }
2535
2536 auto_ptr<Contents>
2537 InviteSession::makeSdp(const SdpContents& sdp,
2538 const SdpContents* alternative)
2539 {
2540 if (alternative)
2541 {
2542 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2543 mac->parts().push_back(alternative->clone());
2544 mac->parts().push_back(sdp.clone());
2545 return auto_ptr<Contents>(mac);
2546 }
2547 else
2548 {
2549 return auto_ptr<Contents>(sdp.clone());
2550 }
2551 }
2552
2553 void
2554 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
2555 {
2556 // !jf! should deal with multipart here
2557
2558 // This will clone the sdp since the InviteSession also wants to keep its own
2559 // copy of the sdp around for the application to access
2560 if (alternative)
2561 {
2562 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2563 mac->parts().push_back(alternative->clone());
2564 mac->parts().push_back(sdp.clone());
2565 msg.setContents(auto_ptr<Contents>(mac));
2566 }
2567 else
2568 {
2569 msg.setContents(&sdp);
2570 }
2571 }
2572
2573 void
2574 InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
2575 {
2576 assert(sdp);
2577 msg.setContents(sdp);
2578 }
2579
2580 void
2581 InviteSession::provideProposedOffer()
2582 {
2583 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2584 {
2585 provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
2586 mProposedEncryptionLevel,
2587 dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
2588 }
2589 else
2590 {
2591 provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
2592 }
2593 }
2594
2595 InviteSession::Event
2596 InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
2597 {
2598 MethodTypes method = msg.header(h_CSeq).method();
2599 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2600
2601 //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
2602 //responses, reiable provisionals should only be received if the invite was
2603 //sent reliably. Spurious reliable provisional respnoses are dropped outside
2604 //the state machine.
2605 bool reliable = isReliable(msg);
2606 bool sentOffer = mProposedLocalSdp.get();
2607
2608 if (code == 481 || code == 408)
2609 {
2610 return OnGeneralFailure;
2611 }
2612 else if (code >= 300 && code <= 399)
2613 {
2614 return OnRedirect;
2615 }
2616 else if (method == INVITE && code == 0)
2617 {
2618 if (sdp)
2619 {
2620 if (reliable)
2621 {
2622 return OnInviteReliableOffer;
2623 }
2624 else
2625 {
2626 return OnInviteOffer;
2627 }
2628 }
2629 else
2630 {
2631 if (reliable)
2632 {
2633 return OnInviteReliable;
2634 }
2635 else
2636 {
2637 return OnInvite;
2638 }
2639 }
2640 }
2641 else if (method == INVITE && code > 100 && code < 200)
2642 {
2643 if (reliable)
2644 {
2645 if (sdp)
2646 {
2647 if (sentOffer)
2648 {
2649 return On1xxAnswer;
2650 }
2651 else
2652 {
2653 return On1xxOffer;
2654 }
2655 }
2656 else
2657 {
2658 return On1xx;
2659 }
2660 }
2661 else
2662 {
2663 if (sdp)
2664 {
2665 return On1xxEarly;
2666 }
2667 else
2668 {
2669 return On1xx;
2670 }
2671 }
2672 }
2673 else if (method == INVITE && code >= 200 && code < 300)
2674 {
2675 if (sdp)
2676 {
2677 if (sentOffer)
2678 {
2679 return On2xxAnswer;
2680 }
2681 else
2682 {
2683 return On2xxOffer;
2684 }
2685 }
2686 else
2687 {
2688 return On2xx;
2689 }
2690 }
2691 else if (method == INVITE && code == 422)
2692 {
2693 return On422Invite;
2694 }
2695 else if (method == INVITE && code == 487)
2696 {
2697 return On487Invite;
2698 }
2699 else if (method == INVITE && code == 491)
2700 {
2701 return On491Invite;
2702 }
2703 else if (method == INVITE && code >= 400)
2704 {
2705 return OnInviteFailure;
2706 }
2707 else if (method == ACK)
2708 {
2709 if (sdp)
2710 {
2711 return OnAckAnswer;
2712 }
2713 else
2714 {
2715 return OnAck;
2716 }
2717 }
2718 else if (method == CANCEL && code == 0)
2719 {
2720 return OnCancel;
2721 }
2722 else if (method == CANCEL && code / 200 == 1)
2723 {
2724 return On200Cancel;
2725 }
2726 else if (method == CANCEL && code >= 400)
2727 {
2728 return OnCancelFailure;
2729 }
2730 else if (method == BYE && code == 0)
2731 {
2732 return OnBye;
2733 }
2734 else if (method == BYE && code / 200 == 1)
2735 {
2736 return On200Bye;
2737 }
2738 else if (method == PRACK && code == 0)
2739 {
2740 return OnPrack;
2741 }
2742 else if (method == PRACK && code / 200 == 1)
2743 {
2744 return On200Prack;
2745 }
2746 else if (method == UPDATE && code == 0)
2747 {
2748 if (sdp)
2749 {
2750 return OnUpdateOffer;
2751 }
2752 else
2753 {
2754 return OnUpdate;
2755 }
2756 }
2757 else if (method == UPDATE && code / 200 == 1)
2758 {
2759 return On200Update;
2760 }
2761 else if (method == UPDATE && code == 422)
2762 {
2763 return On422Update;
2764 }
2765 else if (method == UPDATE && code == 491)
2766 {
2767 return On491Update;
2768 }
2769 else if (method == UPDATE && code >= 400)
2770 {
2771 return OnUpdateRejected;
2772 }
2773 else
2774 {
2775 //assert(0); // dispatchOthers will throw if the message type is really unknown
2776 return Unknown;
2777 }
2778 }
2779
2780 void InviteSession::sendAck(const SdpContents *sdp)
2781 {
2782 SharedPtr<SipMessage> ack(new SipMessage);
2783
2784 assert(mAcks.count(mLastLocalSessionModification->getTransactionId()) == 0);
2785 SharedPtr<SipMessage> source;
2786
2787 if (mLastLocalSessionModification->method() == UPDATE)
2788 {
2789 //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
2790 source = mDialog.mDialogSet.getCreator()->getLastRequest();
2791 }
2792 else
2793 {
2794 source = mLastLocalSessionModification;
2795 }
2796
2797 mDialog.makeRequest(*ack, ACK);
2798
2799 // Copy Authorization, Proxy Authorization headers and CSeq from original Invite
2800 if(source->exists(h_Authorizations))
2801 {
2802 ack->header(h_Authorizations) = source->header(h_Authorizations);
2803 }
2804 if(source->exists(h_ProxyAuthorizations))
2805 {
2806 ack->header(h_ProxyAuthorizations) = source->header(h_ProxyAuthorizations);
2807 }
2808 ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
2809
2810 if(sdp != 0)
2811 {
2812 setSdp(*ack, *sdp);
2813 }
2814 mAcks[ack->getTransactionId()] = ack;
2815 mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(),0,ack->getTransactionId());
2816
2817 InfoLog (<< "Sending " << ack->brief());
2818 send(ack);
2819 }
2820
2821 void InviteSession::sendBye()
2822 {
2823 SharedPtr<SipMessage> bye(new SipMessage());
2824 mDialog.makeRequest(*bye, BYE);
2825 Data txt;
2826 if (mEndReason != NotSpecified)
2827 {
2828 Token reason("SIP");
2829 txt = getEndReasonString(mEndReason);
2830 reason.param(p_description) = txt;
2831 bye->header(h_Reasons).push_back(reason);
2832 }
2833
2834 InfoLog (<< myAddr() << " Sending BYE " << txt);
2835 send(bye);
2836 }
2837
2838 DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg)
2839 {
2840 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
2841 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
2842 if (secAttr)
2843 {
2844 SignatureStatus sig = secAttr->getSignatureStatus();
2845 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
2846 bool encrypted = secAttr->isEncrypted();
2847 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
2848 else if (encrypted) level = DialogUsageManager::Encrypt;
2849 else if (sign) level = DialogUsageManager::Sign;
2850 }
2851 return level;
2852 }
2853
2854 void InviteSession::setCurrentLocalSdp(const SipMessage& msg)
2855 {
2856 assert(mProposedLocalSdp.get());
2857 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2858 {
2859 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
2860 {
2861 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone()));
2862 }
2863 else
2864 {
2865 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone()));
2866 }
2867 }
2868 else
2869 {
2870 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
2871 }
2872 mProposedLocalSdp.reset();
2873 }
2874
2875 void InviteSession::onReadyToSend(SipMessage& msg)
2876 {
2877 mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
2878 }
2879
2880 void InviteSession::referNoSub(const SipMessage& msg)
2881 {
2882 assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
2883 mLastReferNoSubRequest = msg;
2884 mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
2885 }
2886
2887 void
2888 InviteSession::acceptReferNoSub(int statusCode)
2889 {
2890 if (statusCode / 100 != 2)
2891 {
2892 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2893 }
2894
2895 SharedPtr<SipMessage> response(new SipMessage);
2896 mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
2897 response->header(h_ReferSub).value() = "false";
2898 //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
2899
2900 send(response);
2901 }
2902
2903 void
2904 InviteSession::rejectReferNoSub(int responseCode)
2905 {
2906 if (responseCode < 400)
2907 {
2908 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2909 }
2910
2911 SharedPtr<SipMessage> response(new SipMessage);
2912 mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
2913 send(response);
2914 }
2915
2916 /* ====================================================================
2917 * The Vovida Software License, Version 1.0
2918 *
2919 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2920 *
2921 * Redistribution and use in source and binary forms, with or without
2922 * modification, are permitted provided that the following conditions
2923 * are met:
2924 *
2925 * 1. Redistributions of source code must retain the above copyright
2926 * notice, this list of conditions and the following disclaimer.
2927 *
2928 * 2. Redistributions in binary form must reproduce the above copyright
2929 * notice, this list of conditions and the following disclaimer in
2930 * the documentation and/or other materials provided with the
2931
2932 * distribution.
2933 *
2934 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2935 * and "Vovida Open Communication Application Library (VOCAL)" must
2936 * not be used to endorse or promote products derived from this
2937 * software without prior written permission. For written
2938 * permission, please contact vocal@vovida.org.
2939 *
2940 * 4. Products derived from this software may not be called "VOCAL", nor
2941 * may "VOCAL" appear in their name, without prior written
2942 * permission of Vovida Networks, Inc.
2943 *
2944 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2945 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2946 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2947 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2948 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2949 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2950 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2951 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2952 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2953 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2954 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2955 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2956 * DAMAGE.
2957 *
2958 * ====================================================================
2959 *
2960 * This software consists of voluntary contributions made by Vovida
2961 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2962 * Inc. For more information on Vovida Networks, Inc., please see
2963 * <http://www.vovida.org/>.
2964 *
2965 */
2966

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