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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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