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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8690 - (show annotations) (download)
Wed Nov 11 16:36:26 2009 UTC (10 years, 2 months ago) by sgodin
File MIME type: text/plain
File size: 89345 byte(s)
- According to RFC3311 is it recommended to not use UPDATE for comfirmed dialogs - all three states here are 
  confirmed dialogs, so we can just remove the sending of UPDATE from here entirely

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

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