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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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