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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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