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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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