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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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