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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5929 - (show annotations) (download)
Thu Feb 16 22:36:43 2006 UTC (13 years, 9 months ago) by dworley
File size: 72268 byte(s)
Start cleaning up svn:eol-style and EOLs in files.
Note that text and program files that can be used on both Un*x and Windows
should have svn:eol-style=native so they check out correctly on both
platforms.

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/Dialog.hxx"
7 #include "resip/dum/DialogUsageManager.hxx"
8 #include "resip/dum/InviteSession.hxx"
9 #include "resip/dum/ServerInviteSession.hxx"
10 #include "resip/dum/ClientSubscription.hxx"
11 #include "resip/dum/ServerSubscription.hxx"
12 #include "resip/dum/ClientInviteSession.hxx"
13 #include "resip/dum/InviteSessionHandler.hxx"
14 #include "resip/dum/MasterProfile.hxx"
15 #include "resip/dum/UsageUseException.hxx"
16 #include "resip/dum/DumHelper.hxx"
17 #include "rutil/Inserter.hxx"
18 #include "rutil/Logger.hxx"
19 #include "rutil/MD5Stream.hxx"
20 #include "rutil/Timer.hxx"
21 #include "rutil/Random.hxx"
22 #include "rutil/compat.hxx"
23 #include "rutil/WinLeakCheck.hxx"
24
25 // Remove warning about 'this' use in initiator list - pointer is only stored
26 #if defined(WIN32)
27 #pragma warning( disable : 4355 ) // using this in base member initializer list
28 #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
29 #endif
30
31 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
32 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
33
34 using namespace resip;
35 using namespace std;
36
37 Data EndReasons[] =
38 {
39 "Not Specified",
40 "User Hung Up",
41 "Application Rejected Sdp(usually no common codec)",
42 "Illegal Sdp Negotiation",
43 "ACK not received",
44 "Session Timer Expired"
45 };
46
47 const Data& getEndReasonString(InviteSession::EndReason reason)
48 {
49 assert(reason >= InviteSession::NotSpecified && reason < InviteSession::ENDREASON_MAX); //!dcm! -- necessary?
50 return EndReasons[reason];
51 }
52
53 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
54 : DialogUsage(dum, dialog),
55 mState(Undefined),
56 mNitState(NitComplete),
57 mLastLocalSessionModification(new SipMessage),
58 mLastRemoteSessionModification(new SipMessage),
59 mInvite200(new SipMessage),
60 mLastNitResponse(new SipMessage),
61 mCurrentRetransmit200(0),
62 mSessionInterval(0),
63 mMinSE(90),
64 mSessionRefresher(false),
65 mSessionTimerSeq(0),
66 mSessionRefreshReInvite(false),
67 mSentRefer(false),
68 mReferSub(true),
69 mCurrentEncryptionLevel(DialogUsageManager::None),
70 mProposedEncryptionLevel(DialogUsageManager::None),
71 mEndReason(NotSpecified)
72 {
73 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
74 assert(mDum.mInviteSessionHandler);
75 }
76
77 InviteSession::~InviteSession()
78 {
79 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
80 mDialog.mInviteSession = 0;
81 }
82
83 void
84 InviteSession::dialogDestroyed(const SipMessage& msg)
85 {
86 assert(0);
87
88 // !jf! Is this correct? Merged from main...
89 // !jf! what reason - guessed for now?
90 //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);
91 //delete this;
92 }
93
94 const SdpContents&
95 InviteSession::getLocalSdp() const
96 {
97 if(mCurrentLocalSdp.get())
98 {
99 return *mCurrentLocalSdp;
100 }
101 else
102 {
103 return SdpContents::Empty;
104 }
105 }
106
107 const SdpContents&
108 InviteSession::getRemoteSdp() const
109 {
110 if(mCurrentRemoteSdp.get())
111 {
112 return *mCurrentRemoteSdp;
113 }
114 else
115 {
116 return SdpContents::Empty;
117 }
118 }
119
120 const Data&
121 InviteSession::getDialogId() const
122 {
123 return mDialog.getId().getCallId();
124 }
125
126 InviteSessionHandle
127 InviteSession::getSessionHandle()
128 {
129 return InviteSessionHandle(mDum, getBaseHandle().getId());
130 }
131
132 void InviteSession::storePeerCapabilities(const SipMessage& msg)
133 {
134 // !slg! ToDo - add methods to get this data, App may be interested
135 if (msg.exists(h_Allows))
136 {
137 mPeerSupportedMethods = msg.header(h_Allows);
138 }
139 if (msg.exists(h_Supporteds))
140 {
141 mPeerSupportedOptionTags = msg.header(h_Supporteds);
142 }
143 if (msg.exists(h_AcceptEncodings))
144 {
145 mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
146 }
147 if (msg.exists(h_AcceptLanguages))
148 {
149 mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
150 }
151 if (msg.exists(h_AllowEvents))
152 {
153 mPeerAllowedEvents = msg.header(h_AllowEvents);
154 }
155 if (msg.exists(h_Accepts))
156 {
157 mPeerSupportedMimeTypes = msg.header(h_Accepts);
158 }
159 }
160
161 bool
162 InviteSession::updateMethodSupported() const
163 {
164 // Check if Update is supported locally
165 if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
166 {
167 // Check if peer supports UPDATE
168 return mPeerSupportedMethods.find(Token("UPDATE"));
169 }
170 return false;
171 }
172
173 const NameAddr&
174 InviteSession::myAddr() const
175 {
176 return mDialog.mLocalNameAddr;
177 }
178
179 const NameAddr&
180 InviteSession::peerAddr() const
181 {
182 return mDialog.mRemoteNameAddr;
183 }
184
185 bool
186 InviteSession::isConnected() const
187 {
188 switch (mState)
189 {
190 case Connected:
191 case SentUpdate:
192 case SentUpdateGlare:
193 case SentReinvite:
194 case SentReinviteGlare:
195 case SentReinviteNoOffer:
196 case SentReinviteAnswered:
197 case SentReinviteNoOfferGlare:
198 case ReceivedUpdate:
199 case ReceivedReinvite:
200 case ReceivedReinviteNoOffer:
201 case Answered:
202 case WaitingToOffer:
203 return true;
204
205 default:
206 return false;
207 }
208 }
209
210 bool
211 InviteSession::isEarly() const
212 {
213 switch (mState)
214 {
215 case UAC_Early:
216 case UAC_EarlyWithOffer:
217 case UAC_EarlyWithAnswer:
218 case UAC_SentUpdateEarly:
219 case UAC_ReceivedUpdateEarly:
220 case UAC_SentAnswer:
221 case UAC_QueuedUpdate:
222 return true;
223 default:
224 return false;
225 }
226 }
227
228 bool
229 InviteSession::isAccepted() const
230 {
231 switch (mState)
232 {
233 case UAS_Start:
234 case UAS_Offer:
235 case UAS_OfferProvidedAnswer:
236 case UAS_EarlyOffer:
237 case UAS_EarlyProvidedOffer:
238 case UAS_EarlyProvidedAnswer:
239 case UAS_EarlyNoOffer:
240 case UAS_FirstEarlyReliable:
241 case UAS_FirstSentOfferReliable:
242 case UAS_EarlyReliable:
243 return false;
244 default:
245 return true;
246 }
247 }
248
249 bool
250 InviteSession::isTerminated() const
251 {
252 switch (mState)
253 {
254 case Terminated:
255 case WaitingToTerminate:
256 case WaitingToHangup:
257 case UAC_Cancelled:
258 case UAS_WaitingToTerminate:
259 case UAS_WaitingToHangup:
260 return true;
261 default:
262 return false;
263 }
264 }
265
266 std::ostream&
267 InviteSession::dump(std::ostream& strm) const
268 {
269 strm << "INVITE: " << mId
270 << " " << toData(mState)
271 << " ADDR=" << myAddr()
272 << " PEER=" << peerAddr();
273 return strm;
274 }
275
276 void
277 InviteSession::requestOffer()
278 {
279 switch (mState)
280 {
281 case Connected:
282 case WaitingToRequestOffer:
283 transition(SentReinviteNoOffer);
284 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
285 mLastLocalSessionModification->setContents(0); // Clear the SDP contents from the INVITE
286 setSessionTimerHeaders(*mLastLocalSessionModification);
287
288 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
289
290 // call send to give app an chance to adorn the message.
291 send(mLastLocalSessionModification);
292 break;
293
294 case Answered:
295 // queue the offer to be sent after the ACK is received
296 transition(WaitingToRequestOffer);
297 break;
298
299 // ?slg? Can we handle all of the states listed in isConnected() ???
300 default:
301 WarningLog (<< "Can't requestOffer when not in Connected state");
302 throw DialogUsage::Exception("Can't request an offer", __FILE__,__LINE__);
303 }
304 }
305
306 void
307 InviteSession::provideOffer(const SdpContents& offer,
308 DialogUsageManager::EncryptionLevel level,
309 const SdpContents* alternative)
310 {
311 switch (mState)
312 {
313 case Connected:
314 case WaitingToOffer:
315 case UAS_WaitingToOffer:
316 if (updateMethodSupported())
317 {
318 transition(SentUpdate);
319 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
320 }
321 else
322 {
323 transition(SentReinvite);
324 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
325 }
326 setSessionTimerHeaders(*mLastLocalSessionModification);
327
328 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
329 InviteSession::setSdp(*mLastLocalSessionModification, offer, alternative);
330 mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);
331 mProposedEncryptionLevel = level;
332 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
333
334 // call send to give app an chance to adorn the message.
335 send(mLastLocalSessionModification);
336 break;
337
338 case Answered:
339 // queue the offer to be sent after the ACK is received
340 transition(WaitingToOffer);
341 mProposedEncryptionLevel = level;
342 mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);
343 break;
344
345 case ReceivedReinviteNoOffer:
346 assert(!mProposedRemoteSdp.get());
347 transition(ReceivedReinviteSentOffer);
348 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
349 handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
350 InviteSession::setSdp(*mInvite200, offer, 0);
351 mProposedLocalSdp = InviteSession::makeSdp(offer);
352
353 InfoLog (<< "Sending " << mInvite200->brief());
354 DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
355 send(mInvite200);
356 startRetransmit200Timer();
357 break;
358
359
360 // ?slg? Can we handle all of the states listed in isConnected() ???
361 default:
362 WarningLog (<< "Can't provideOffer when not in Connected state");
363 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
364 }
365 }
366
367 void
368 InviteSession::provideOffer(const SdpContents& offer)
369 {
370 return provideOffer(offer, mCurrentEncryptionLevel, 0);
371 }
372
373 void
374 InviteSession::provideAnswer(const SdpContents& answer)
375 {
376 switch (mState)
377 {
378 case ReceivedReinvite:
379 transition(Connected);
380 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
381 handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
382 InviteSession::setSdp(*mInvite200, answer, 0);
383 mCurrentLocalSdp = InviteSession::makeSdp(answer);
384 mCurrentRemoteSdp = mProposedRemoteSdp;
385 InfoLog (<< "Sending " << mInvite200->brief());
386 DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
387 send(mInvite200);
388 startRetransmit200Timer();
389 break;
390
391 case ReceivedUpdate: // same as ReceivedReinvite case.
392 {
393 transition(Connected);
394
395 SharedPtr<SipMessage> response(new SipMessage);
396 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
397 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
398 InviteSession::setSdp(*response, answer, 0);
399 mCurrentLocalSdp = InviteSession::makeSdp(answer);
400 mCurrentRemoteSdp = mProposedRemoteSdp;
401 InfoLog (<< "Sending " << response->brief());
402 DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
403 send(response);
404 break;
405 }
406
407 case SentReinviteAnswered:
408 transition(Connected);
409 sendAck(&answer);
410
411 mCurrentRemoteSdp = mProposedRemoteSdp;
412 mCurrentLocalSdp = InviteSession::makeSdp(answer);
413 break;
414
415 default:
416 WarningLog (<< "Can't provideAnswer when not in Connected state");
417 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
418 }
419 }
420
421 void
422 InviteSession::end()
423 {
424 end(NotSpecified);
425 }
426
427 void
428 InviteSession::end(EndReason reason)
429 {
430 if (mEndReason == NotSpecified)
431 {
432 mEndReason = reason;
433 }
434
435 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
436
437 switch (mState)
438 {
439 case Connected:
440 case SentUpdate:
441 case SentUpdateGlare:
442 case SentReinviteGlare:
443 case SentReinviteNoOfferGlare:
444 case SentReinviteAnswered:
445 {
446 // !jf! do we need to store the BYE somewhere?
447 sendBye();
448 transition(Terminated);
449 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
450 break;
451 }
452
453 case SentReinvite:
454 case SentReinviteNoOffer:
455 transition(WaitingToTerminate);
456 break;
457
458 case Answered:
459 case WaitingToOffer:
460 case ReceivedReinviteSentOffer:
461 transition(WaitingToHangup);
462 break;
463
464 case ReceivedUpdate:
465 case ReceivedReinvite:
466 case ReceivedReinviteNoOffer:
467 {
468 SharedPtr<SipMessage> response(new SipMessage);
469 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 488);
470 InfoLog (<< "Sending " << response->brief());
471 send(response);
472
473 sendBye();
474 transition(Terminated);
475 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
476 break;
477 }
478
479 case WaitingToTerminate: // ?slg? Why is this here?
480 {
481 sendBye();
482 transition(Terminated);
483 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
484 break;
485 }
486
487 case Terminated:
488 // no-op.
489 break;
490
491 default:
492 assert(0);
493 break;
494 }
495 }
496
497 void
498 InviteSession::reject(int statusCode, WarningCategory *warning)
499 {
500 switch (mState)
501 {
502 case ReceivedUpdate:
503 case ReceivedReinvite:
504 case ReceivedReinviteNoOffer:
505 {
506 transition(Connected);
507
508 SharedPtr<SipMessage> response(new SipMessage);
509 mDialog.makeResponse(*response, *mLastRemoteSessionModification, statusCode);
510 if(warning)
511 {
512 response->header(h_Warnings).push_back(*warning);
513 }
514 InfoLog (<< "Sending " << response->brief());
515 send(response);
516 break;
517 }
518
519 default:
520 assert(0);
521 break;
522 }
523 }
524
525 void
526 InviteSession::targetRefresh(const NameAddr& localUri)
527 {
528 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
529 {
530 // !jf! add interface to Dialog
531 //mDialog.setLocalContact(localUri);
532 provideOffer(*mCurrentLocalSdp);
533 }
534 else
535 {
536 WarningLog (<< "Can't targetRefresh before Connected");
537 assert(0);
538 throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
539 }
540 }
541
542 void
543 InviteSession::refer(const NameAddr& referTo, bool referSub)
544 {
545 if (mSentRefer)
546 {
547 throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
548 }
549
550 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
551 {
552 mSentRefer = true;
553 mReferSub = referSub;
554 SharedPtr<SipMessage> refer(new SipMessage());
555 mDialog.makeRequest(*refer, REFER);
556 refer->header(h_ReferTo) = referTo;
557 refer->header(h_ReferredBy) = mDialog.mLocalContact; //
558 // !slg! is it ok to do this - should it be an option?
559 if (!referSub)
560 {
561 refer->header(h_ReferSub).value() = "false";
562 refer->header(h_Supporteds).push_back(Token("norefersub"));
563 }
564
565 send(refer);
566 }
567 else
568 {
569 WarningLog (<< "Can't refer before Connected");
570 assert(0);
571 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
572 }
573 }
574
575 void
576 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
577 {
578 if (!sessionToReplace.isValid())
579 {
580 throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
581 }
582
583 if (mSentRefer)
584 {
585 throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
586 }
587
588 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
589 {
590 mSentRefer = true;
591 mReferSub = referSub;
592 SharedPtr<SipMessage> refer(new SipMessage());
593 mDialog.makeRequest(*refer, REFER);
594
595 refer->header(h_ReferTo) = referTo;
596 refer->header(h_ReferredBy) = mDialog.mLocalContact; // ?slg? is it ok to do this - should it be an option?
597 CallId replaces;
598 DialogId id = sessionToReplace->mDialog.getId();
599 replaces.value() = id.getCallId();
600 replaces.param(p_toTag) = id.getRemoteTag();
601 replaces.param(p_fromTag) = id.getLocalTag();
602
603 refer->header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
604
605 if (!referSub)
606 {
607 refer->header(h_ReferSub).value() = "false";
608 refer->header(h_Supporteds).push_back(Token("norefersub"));
609 }
610
611 send(refer);
612 }
613 else
614 {
615 WarningLog (<< "Can't refer before Connected");
616 assert(0);
617 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
618 }
619 }
620
621 void
622 InviteSession::info(const Contents& contents)
623 {
624 if (mNitState == NitComplete)
625 {
626 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
627 {
628 mNitState = NitProceeding;
629 SharedPtr<SipMessage> info(new SipMessage());
630 mDialog.makeRequest(*info, INFO);
631 // !jf! handle multipart here
632 info->setContents(&contents);
633 DumHelper::setOutgoingEncryptionLevel(*info, mCurrentEncryptionLevel);
634 send(info);
635 }
636 else
637 {
638 WarningLog (<< "Can't send INFO before Connected");
639 assert(0);
640 throw UsageUseException("Can't send INFO before Connected", __FILE__, __LINE__);
641 }
642 }
643 else
644 {
645 throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
646 __FILE__, __LINE__);
647 }
648 }
649
650 void
651 InviteSession::message(const Contents& contents)
652 {
653 if (mNitState == NitComplete)
654 {
655 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
656 {
657 mNitState = NitProceeding;
658 SharedPtr<SipMessage> message(new SipMessage());
659 mDialog.makeRequest(*message, MESSAGE);
660 // !jf! handle multipart here
661 message->setContents(&contents);
662 DumHelper::setOutgoingEncryptionLevel(*message, mCurrentEncryptionLevel);
663 send(message);
664 InfoLog (<< "Trying to send MESSAGE: " << message);
665 }
666 else
667 {
668 WarningLog (<< "Can't send MESSAGE before Connected");
669 assert(0);
670 throw UsageUseException("Can't send MESSAGE before Connected", __FILE__, __LINE__);
671 }
672 }
673 else
674 {
675 throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
676 __FILE__, __LINE__);
677 }
678 }
679
680 void
681 InviteSession::dispatch(const SipMessage& msg)
682 {
683 // Look for 2xx retransmissions - resend ACK and filter out of state machine
684 if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 200 == 1)
685 {
686 AckMap::iterator i = mAcks.find(msg.header(h_CSeq).sequence());
687 if (i != mAcks.end())
688 {
689 send(i->second); // resend ACK
690 return;
691 }
692 }
693
694 // !jf! do we need to handle 3xx here or is it handled elsewhere?
695 switch (mState)
696 {
697 case Connected:
698 dispatchConnected(msg);
699 break;
700 case SentUpdate:
701 dispatchSentUpdate(msg);
702 break;
703 case SentReinvite:
704 dispatchSentReinvite(msg);
705 break;
706 case SentReinviteNoOffer:
707 dispatchSentReinviteNoOffer(msg);
708 break;
709 case SentReinviteAnswered:
710 dispatchSentReinviteAnswered(msg);
711 break;
712 case SentUpdateGlare:
713 case SentReinviteGlare:
714 // The behavior is the same except for timer which is handled in dispatch(Timer)
715 dispatchGlare(msg);
716 break;
717 case SentReinviteNoOfferGlare:
718 dispatchReinviteNoOfferGlare(msg);
719 break;
720 case ReceivedUpdate:
721 case ReceivedReinvite:
722 case ReceivedReinviteNoOffer:
723 dispatchReceivedUpdateOrReinvite(msg);
724 break;
725 case ReceivedReinviteSentOffer:
726 dispatchReceivedReinviteSentOffer(msg);
727 break;
728 case Answered:
729 dispatchAnswered(msg);
730 break;
731 case WaitingToOffer:
732 dispatchWaitingToOffer(msg);
733 break;
734 case WaitingToRequestOffer:
735 dispatchWaitingToRequestOffer(msg);
736 break;
737 case WaitingToTerminate:
738 dispatchWaitingToTerminate(msg);
739 break;
740 case WaitingToHangup:
741 dispatchWaitingToHangup(msg);
742 break;
743 case Terminated:
744 dispatchTerminated(msg);
745 break;
746 case Undefined:
747 default:
748 assert(0);
749 break;
750 }
751 }
752
753 void
754 InviteSession::dispatch(const DumTimeout& timeout)
755 {
756 if (timeout.type() == DumTimeout::Retransmit200)
757 {
758 if (mCurrentRetransmit200)
759 {
760 InfoLog (<< "Retransmitting: " << endl << *mInvite200);
761 //DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
762 send(mInvite200);
763 mCurrentRetransmit200 *= 2;
764 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
765 }
766 }
767 else if (timeout.type() == DumTimeout::WaitForAck)
768 {
769 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
770 {
771 if (timeout.seq() == mLastRemoteSessionModification->header(h_CSeq).sequence())
772 {
773 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
774
775 // If we are waiting for an Ack and it times out, then end with a BYE
776 if(mState == UAS_WaitingToHangup ||
777 mState == WaitingToHangup)
778 {
779 sendBye();
780 transition(Terminated);
781 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
782 }
783 else if(mState == ReceivedReinviteSentOffer)
784 {
785 transition(Connected);
786 mProposedLocalSdp.reset();
787 mProposedEncryptionLevel = DialogUsageManager::None;
788 //!dcm! -- should this be onIllegalNegotiation?
789 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
790 }
791 else if(mState == WaitingToOffer)
792 {
793 assert(mProposedLocalSdp.get());
794 //!dcm! -- should this be onIllegalNegotiation?
795 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
796 provideProposedOffer();
797 }
798 else
799 {
800 // this is so the app can decided to ignore this. default implementation
801 // will call end next
802 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
803 }
804 }
805 }
806 }
807 else if (timeout.type() == DumTimeout::CanDiscardAck)
808 {
809 AckMap::iterator i = mAcks.find(timeout.seq());
810 if (i != mAcks.end())
811 {
812 mAcks.erase(i);
813 }
814 }
815 else if (timeout.type() == DumTimeout::Glare)
816 {
817 if (mState == SentUpdateGlare)
818 {
819 transition(SentUpdate);
820
821 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
822 send(mLastLocalSessionModification);
823 }
824 else if (mState == SentReinviteGlare)
825 {
826 transition(SentReinvite);
827
828 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
829 send(mLastLocalSessionModification);
830 }
831 else if (mState == SentReinviteNoOfferGlare)
832 {
833 transition(SentReinviteNoOffer);
834
835 InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
836 send(mLastLocalSessionModification);
837 }
838 }
839 else if (timeout.type() == DumTimeout::SessionExpiration)
840 {
841 if(timeout.seq() == mSessionTimerSeq)
842 {
843 // this is so the app can decided to ignore this. default implementation
844 // will call end next - which will send a BYE
845 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
846 }
847 }
848 else if (timeout.type() == DumTimeout::SessionRefresh)
849 {
850 if(timeout.seq() == mSessionTimerSeq)
851 {
852 // Note: If not connected then we must be issueing a reinvite/update or
853 // receiving one - in either case the session timer stuff will get
854 // reset/renegotiated - thus just ignore this referesh
855 if(mState == Connected)
856 {
857 sessionRefresh();
858 }
859 }
860 }
861 }
862
863 void
864 InviteSession::dispatchConnected(const SipMessage& msg)
865 {
866 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
867 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
868
869 switch (toEvent(msg, sdp.get()))
870 {
871 case OnInvite:
872 case OnInviteReliable:
873 *mLastRemoteSessionModification = msg;
874 transition(ReceivedReinviteNoOffer);
875 //handler->onDialogModified(getSessionHandle(), None, msg);
876 handler->onOfferRequired(getSessionHandle(), msg);
877 break;
878
879 case OnInviteOffer:
880 case OnInviteReliableOffer:
881 *mLastRemoteSessionModification = msg;
882 transition(ReceivedReinvite);
883 mCurrentEncryptionLevel = getEncryptionLevel(msg);
884 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
885
886 //handler->onDialogModified(getSessionHandle(), Offer, msg);
887 handler->onOffer(getSessionHandle(), msg, *sdp);
888 break;
889
890 case On2xx:
891 case On2xxOffer:
892 case On2xxAnswer:
893 // retransmission of 200I
894 // !jf! Need to include the answer here.
895 sendAck();
896 break;
897
898 case OnUpdateOffer:
899 transition(ReceivedUpdate);
900
901 // !kh!
902 // Find out if it's an UPDATE requiring state change.
903 // See rfc3311 5.2, 4th paragraph.
904 *mLastRemoteSessionModification = msg;
905 mCurrentEncryptionLevel = getEncryptionLevel(msg);
906 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
907 handler->onOffer(getSessionHandle(), msg, *sdp);
908 break;
909
910 case OnUpdate:
911 {
912 // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
913 SharedPtr<SipMessage> response(new SipMessage);
914 *mLastRemoteSessionModification = msg;
915 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
916 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
917 send(response);
918 break;
919 }
920
921 case OnUpdateRejected:
922 case On200Update:
923 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
924 assert(0);
925 break;
926
927 case OnAck:
928 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
929 break;
930
931 default:
932 dispatchOthers(msg);
933 break;
934 }
935 }
936
937 void
938 InviteSession::dispatchSentUpdate(const SipMessage& msg)
939 {
940 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
941 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
942
943 switch (toEvent(msg, sdp.get()))
944 {
945 case OnInvite:
946 case OnInviteReliable:
947 case OnInviteOffer:
948 case OnInviteReliableOffer:
949 case OnUpdate:
950 case OnUpdateOffer:
951 {
952 // glare
953 SharedPtr<SipMessage> response(new SipMessage);
954 mDialog.makeResponse(*response, msg, 491);
955 send(response);
956 break;
957 }
958
959 case On200Update:
960 transition(Connected);
961 handleSessionTimerResponse(msg);
962 if (sdp.get() && mProposedLocalSdp.get())
963 {
964 mCurrentEncryptionLevel = getEncryptionLevel(msg);
965 setCurrentLocalSdp(msg);
966 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
967 handler->onAnswer(getSessionHandle(), msg, *sdp);
968 }
969 else if(mProposedLocalSdp.get())
970 {
971 // If we sent an offer in the Update Request and no answer is received
972 handler->onIllegalNegotiation(getSessionHandle(), msg);
973 mProposedLocalSdp.reset();
974 mProposedEncryptionLevel = DialogUsageManager::None;
975 }
976 break;
977
978 case On491Update:
979 transition(SentUpdateGlare);
980 start491Timer();
981 break;
982
983 case On422Update: // session timer
984 if(msg.exists(h_MinSE))
985 {
986 // Change interval to min from 422 response
987 mSessionInterval = msg.header(h_MinSE).value();
988 mMinSE = mSessionInterval;
989 sessionRefresh();
990 }
991 else
992 {
993 // Response must contain Min_SE - if not - just ignore
994 // ?slg? callback?
995 transition(Connected);
996 mProposedLocalSdp.reset();
997 mProposedEncryptionLevel = DialogUsageManager::None;
998 }
999 break;
1000
1001 case OnUpdateRejected:
1002 // !jf! - callback?
1003 mProposedLocalSdp.reset();
1004 mProposedEncryptionLevel = DialogUsageManager::None;
1005 transition(Connected);
1006 break;
1007
1008 case OnGeneralFailure:
1009 sendBye();
1010 transition(Terminated);
1011 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1012 break;
1013
1014 default:
1015 dispatchOthers(msg);
1016 break;
1017 }
1018 }
1019
1020 void
1021 InviteSession::dispatchSentReinvite(const SipMessage& msg)
1022 {
1023 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1024 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1025
1026 switch (toEvent(msg, sdp.get()))
1027 {
1028 case OnInvite:
1029 case OnInviteReliable:
1030 case OnInviteOffer:
1031 case OnInviteReliableOffer:
1032 case OnUpdate:
1033 case OnUpdateOffer:
1034 {
1035 SharedPtr<SipMessage> response(new SipMessage);
1036 mDialog.makeResponse(*response, msg, 491);
1037 send(response);
1038 break;
1039 }
1040
1041 case On1xx:
1042 case On1xxEarly:
1043 // Some UA's send a 100 response to a ReInvite - just ignore it
1044 break;
1045
1046 case On2xxAnswer:
1047 case On2xxOffer: // !slg! doesn't really make sense
1048 {
1049 transition(Connected);
1050 handleSessionTimerResponse(msg);
1051 setCurrentLocalSdp(msg);
1052
1053 // !jf! I need to potentially include an answer in the ACK here
1054 sendAck();
1055 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1056
1057 if (mSessionRefreshReInvite)
1058 {
1059 mSessionRefreshReInvite = false;
1060
1061 MD5Stream currentRemote;
1062 currentRemote<< *mCurrentRemoteSdp;
1063 MD5Stream newRemote;
1064 newRemote << *sdp;
1065 bool changed = currentRemote.getHex() != newRemote.getHex();
1066
1067 if (changed)
1068 {
1069 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
1070 handler->onRemoteSdpChanged(getSessionHandle(), msg, *sdp);
1071 }
1072 }
1073 else
1074 {
1075 handler->onAnswer(getSessionHandle(), msg, *sdp);
1076 }
1077
1078 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1079 // the ACK when a 200I is received? If yes, then I need to store all
1080 // ACK messages for 64*T1
1081 break;
1082 }
1083 case On2xx:
1084 sendAck();
1085 transition(Connected);
1086 handleSessionTimerResponse(msg);
1087 handler->onIllegalNegotiation(getSessionHandle(), msg);
1088 mProposedLocalSdp.reset();
1089 mProposedEncryptionLevel = DialogUsageManager::None;
1090 break;
1091
1092 case On422Invite:
1093 if(msg.exists(h_MinSE))
1094 {
1095 // Change interval to min from 422 response
1096 mSessionInterval = msg.header(h_MinSE).value();
1097 mMinSE = mSessionInterval;
1098 sessionRefresh();
1099 }
1100 else
1101 {
1102 // Response must contact Min_SE - if not - just ignore
1103 // ?slg? callback?
1104 transition(Connected);
1105 mProposedLocalSdp.reset();
1106 mProposedEncryptionLevel = DialogUsageManager::None;
1107 }
1108 break;
1109
1110 case On491Invite:
1111 transition(SentReinviteGlare);
1112 start491Timer();
1113 break;
1114
1115 case OnGeneralFailure:
1116 sendBye();
1117 transition(Terminated);
1118 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1119 break;
1120
1121 case OnInviteFailure:
1122 case On487Invite:
1123 case On489Invite:
1124 transition(Connected);
1125 mProposedLocalSdp.reset();
1126 handler->onOfferRejected(getSessionHandle(), &msg);
1127 break;
1128
1129 default:
1130 dispatchOthers(msg);
1131 break;
1132 }
1133 }
1134
1135 void
1136 InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1137 {
1138 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1139 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1140
1141 switch (toEvent(msg, sdp.get()))
1142 {
1143 case OnInvite:
1144 case OnInviteReliable:
1145 case OnInviteOffer:
1146 case OnInviteReliableOffer:
1147 case OnUpdate:
1148 case OnUpdateOffer:
1149 {
1150 SharedPtr<SipMessage> response(new SipMessage);
1151 mDialog.makeResponse(*response, msg, 491);
1152 send(response);
1153 break;
1154 }
1155
1156 case On1xx:
1157 case On1xxEarly:
1158 // Some UA's send a 100 response to a ReInvite - just ignore it
1159 break;
1160
1161 case On2xxAnswer: // !slg! doesn't really make sense
1162 case On2xxOffer:
1163 {
1164 transition(SentReinviteAnswered);
1165 handleSessionTimerResponse(msg);
1166 // mLastSessionModification = msg; // ?slg? why are we storing 200's?
1167 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1168 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
1169 handler->onOffer(getSessionHandle(), msg, *sdp);
1170
1171 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1172 // the ACK when a 200I is received? If yes, then I need to store all
1173 // ACK messages for 64*T1
1174 break;
1175 }
1176
1177 case On2xx:
1178 sendAck();
1179 transition(Connected);
1180 handleSessionTimerResponse(msg);
1181 handler->onIllegalNegotiation(getSessionHandle(), msg);
1182 mProposedLocalSdp.reset();
1183 mProposedEncryptionLevel = DialogUsageManager::None;
1184 break;
1185
1186 case On422Invite:
1187 if(msg.exists(h_MinSE))
1188 {
1189 // Change interval to min from 422 response
1190 mSessionInterval = msg.header(h_MinSE).value();
1191 mMinSE = mSessionInterval;
1192 setSessionTimerHeaders(*mLastLocalSessionModification);
1193 send(mLastLocalSessionModification);
1194 }
1195 else
1196 {
1197 // Response must contact Min_SE - if not - just ignore
1198 // ?slg? callback?
1199 transition(Connected);
1200 mProposedLocalSdp.reset();
1201 mProposedEncryptionLevel = DialogUsageManager::None;
1202 }
1203 break;
1204
1205 case On491Invite:
1206 transition(SentReinviteNoOfferGlare);
1207 start491Timer();
1208 break;
1209
1210 case OnGeneralFailure:
1211 sendBye();
1212 transition(Terminated);
1213 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1214 break;
1215
1216 case OnInviteFailure:
1217 case On487Invite:
1218 case On489Invite:
1219 transition(Connected);
1220 mProposedLocalSdp.reset();
1221 handler->onOfferRejected(getSessionHandle(), &msg);
1222 break;
1223
1224 default:
1225 dispatchOthers(msg);
1226 break;
1227 }
1228 }
1229
1230 void
1231 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1232 {
1233 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1234 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1235
1236 switch (toEvent(msg, sdp.get()))
1237 {
1238 case OnInvite:
1239 case OnInviteReliable:
1240 case OnInviteOffer:
1241 case OnInviteReliableOffer:
1242 case OnUpdate:
1243 case OnUpdateOffer:
1244 {
1245 SharedPtr<SipMessage> response(new SipMessage);
1246 mDialog.makeResponse(*response, msg, 491);
1247 send(response);
1248 break;
1249 }
1250 case OnAckAnswer:
1251 transition(Connected);
1252 setCurrentLocalSdp(msg);
1253 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
1254 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1255 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1256 handler->onAnswer(getSessionHandle(), msg, *sdp);
1257 break;
1258 case OnAck:
1259 transition(Connected);
1260 mProposedLocalSdp.reset();
1261 mProposedEncryptionLevel = DialogUsageManager::None;
1262 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1263 //!dcm! -- should this be onIllegalNegotiation?
1264 handler->onOfferRejected(getSessionHandle(), &msg);
1265 break;
1266 default:
1267 dispatchOthers(msg);
1268 break;
1269 }
1270 }
1271
1272 void
1273 InviteSession::dispatchGlare(const SipMessage& msg)
1274 {
1275 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1276 MethodTypes method = msg.header(h_CSeq).method();
1277 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1278 {
1279 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1280 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1281 handler->onOfferRejected(getSessionHandle(), &msg);
1282 dispatchConnected(msg); // act as if we received message in Connected state
1283 }
1284 else
1285 {
1286 dispatchOthers(msg);
1287 }
1288 }
1289
1290 void
1291 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1292 {
1293 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1294 MethodTypes method = msg.header(h_CSeq).method();
1295 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1296 {
1297 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1298 handler->onOfferRequestRejected(getSessionHandle(), msg);
1299 dispatchConnected(msg); // act as if we received message in Connected state
1300 }
1301 else
1302 {
1303 dispatchOthers(msg);
1304 }
1305 }
1306
1307 void
1308 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1309 {
1310 MethodTypes method = msg.header(h_CSeq).method();
1311 if (method == INVITE || method == UPDATE)
1312 {
1313 // Means that the UAC has sent us a second reINVITE or UPDATE before we
1314 // responded to the first one. Bastard!
1315 SharedPtr<SipMessage> response(new SipMessage);
1316 mDialog.makeResponse(*response, msg, 500);
1317 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1318 send(response);
1319 }
1320 else
1321 {
1322 dispatchOthers(msg);
1323 }
1324 }
1325
1326
1327 void
1328 InviteSession::dispatchAnswered(const SipMessage& msg)
1329 {
1330 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1331 {
1332 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1333 transition(Connected);
1334 }
1335 else
1336 {
1337 dispatchOthers(msg);
1338 }
1339 }
1340
1341 void
1342 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1343 {
1344 dispatchOthers(msg);
1345 }
1346
1347 void
1348 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1349 {
1350 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1351 {
1352 assert(mProposedLocalSdp.get());
1353 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1354 provideProposedOffer();
1355 }
1356 else
1357 {
1358 dispatchOthers(msg);
1359 }
1360 }
1361
1362 void
1363 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1364 {
1365 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1366 {
1367 assert(mProposedLocalSdp.get());
1368 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1369 requestOffer();
1370 }
1371 else
1372 {
1373 dispatchOthers(msg);
1374 }
1375 }
1376
1377 void
1378 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1379 {
1380 if (msg.isResponse() &&
1381 msg.header(h_CSeq).method() == INVITE)
1382 {
1383 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1384 {
1385 // !jf! Need to include the answer here.
1386 sendAck();
1387 }
1388 sendBye();
1389 transition(Terminated);
1390 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1391 }
1392 }
1393
1394 void
1395 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1396 {
1397 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1398
1399 switch (toEvent(msg, sdp.get()))
1400 {
1401 case OnAck:
1402 case OnAckAnswer:
1403 {
1404 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1405
1406 sendBye();
1407 transition(Terminated);
1408 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1409 break;
1410 }
1411
1412 default:
1413 break;
1414 }
1415 }
1416
1417 void
1418 InviteSession::dispatchTerminated(const SipMessage& msg)
1419 {
1420 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1421
1422 if (msg.isRequest())
1423 {
1424 SharedPtr<SipMessage> response(new SipMessage);
1425 mDialog.makeResponse(*response, msg, 481);
1426 send(response);
1427
1428 // !jf! means the peer sent BYE while we are waiting for response to BYE
1429 //mDum.destroy(this);
1430 }
1431 else
1432 {
1433 mDum.destroy(this);
1434 }
1435 }
1436
1437 void
1438 InviteSession::dispatchOthers(const SipMessage& msg)
1439 {
1440 // handle OnGeneralFailure
1441 // handle OnRedirect
1442
1443 switch (msg.header(h_CSeq).method())
1444 {
1445 case PRACK:
1446 dispatchPrack(msg);
1447 break;
1448 case CANCEL:
1449 dispatchCancel(msg);
1450 break;
1451 case BYE:
1452 dispatchBye(msg);
1453 break;
1454 case INFO:
1455 dispatchInfo(msg);
1456 break;
1457 case MESSAGE:
1458 dispatchMessage(msg);
1459 break;
1460 case ACK:
1461 // Ignore duplicate ACKs from 2xx reTransmissions
1462 break;
1463 default:
1464 // handled in Dialog
1465 WarningLog (<< "DUM delivered a "
1466 << msg.header(h_CSeq).unknownMethodName()
1467 << " to the InviteSession "
1468 << endl
1469 << msg);
1470 assert(0);
1471 break;
1472 }
1473 }
1474
1475 void
1476 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
1477 {
1478 assert(msg.isRequest());
1479 assert(msg.header(h_CSeq).method() == INVITE);
1480
1481 // If we get an INVITE request from the wire and we are not in
1482 // Connected state, reject the request and send a BYE
1483 SharedPtr<SipMessage> response(new SipMessage);
1484 mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
1485 InfoLog (<< "Sending " << response->brief());
1486 send(response);
1487
1488 sendBye();
1489 transition(Terminated);
1490 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1491 }
1492
1493 void
1494 InviteSession::dispatchPrack(const SipMessage& msg)
1495 {
1496 assert(msg.header(h_CSeq).method() == PRACK);
1497 if(msg.isRequest())
1498 {
1499 SharedPtr<SipMessage> rsp(new SipMessage);
1500 mDialog.makeResponse(*rsp, msg, 481);
1501 send(rsp);
1502
1503 sendBye();
1504 // !jf! should we make some other callback here
1505 transition(Terminated);
1506 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1507 }
1508 else
1509 {
1510 // ignore. could be PRACK/200
1511 }
1512 }
1513
1514 void
1515 InviteSession::dispatchCancel(const SipMessage& msg)
1516 {
1517 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1518 assert(msg.header(h_CSeq).method() == CANCEL);
1519 if(msg.isRequest())
1520 {
1521 SharedPtr<SipMessage> rsp(new SipMessage);
1522 mDialog.makeResponse(*rsp, msg, 200);
1523 send(rsp);
1524
1525 sendBye();
1526 // !jf! should we make some other callback here
1527 transition(Terminated);
1528 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1529 }
1530 else
1531 {
1532 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1533 assert(0);
1534 }
1535 }
1536
1537 void
1538 InviteSession::dispatchBye(const SipMessage& msg)
1539 {
1540 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1541
1542 if (msg.isRequest())
1543 {
1544
1545 SharedPtr<SipMessage> rsp(new SipMessage);
1546 InfoLog (<< "Received " << msg.brief());
1547 mDialog.makeResponse(*rsp, msg, 200);
1548 send(rsp);
1549
1550 // !jf! should we make some other callback here
1551 transition(Terminated);
1552 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1553 mDum.destroy(this);
1554 }
1555 else
1556 {
1557 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1558 assert(0);
1559 }
1560 }
1561
1562 void
1563 InviteSession::dispatchInfo(const SipMessage& msg)
1564 {
1565 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1566 if (msg.isRequest())
1567 {
1568 InfoLog (<< "Received " << msg.brief());
1569 mDialog.makeResponse(*mLastNitResponse, msg, 200);
1570 handler->onInfo(getSessionHandle(), msg);
1571 }
1572 else
1573 {
1574 assert(mNitState == NitProceeding);
1575 mNitState = NitComplete;
1576 //!dcm! -- toss away 1xx to an info?
1577 if (msg.header(h_StatusLine).statusCode() >= 300)
1578 {
1579 handler->onInfoFailure(getSessionHandle(), msg);
1580 }
1581 else if (msg.header(h_StatusLine).statusCode() >= 200)
1582 {
1583 handler->onInfoSuccess(getSessionHandle(), msg);
1584 }
1585 }
1586 }
1587
1588 void
1589 InviteSession::acceptNIT(int statusCode, const Contents * contents)
1590 {
1591 if (statusCode / 100 != 2)
1592 {
1593 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
1594 }
1595
1596 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
1597 mLastNitResponse->setContents(contents);
1598 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
1599 send(mLastNitResponse);
1600 }
1601
1602 void
1603 InviteSession::rejectNIT(int statusCode)
1604 {
1605 if (statusCode < 400)
1606 {
1607 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
1608 }
1609 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
1610 mLastNitResponse->releaseContents();
1611 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
1612 send(mLastNitResponse);
1613 }
1614
1615 void
1616 InviteSession::dispatchMessage(const SipMessage& msg)
1617 {
1618 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1619 if (msg.isRequest())
1620 {
1621 InfoLog (<< "Received " << msg.brief());
1622 mDialog.makeResponse(*mLastNitResponse, msg, 200);
1623 mLastNitResponse->header(h_Contacts).clear();
1624 handler->onMessage(getSessionHandle(), msg);
1625 }
1626 else
1627 {
1628 assert(mNitState == NitProceeding);
1629 mNitState = NitComplete;
1630 //!dcm! -- toss away 1xx to an message?
1631 if (msg.header(h_StatusLine).statusCode() >= 300)
1632 {
1633 handler->onMessageFailure(getSessionHandle(), msg);
1634 }
1635 else if (msg.header(h_StatusLine).statusCode() >= 200)
1636 {
1637 handler->onMessageSuccess(getSessionHandle(), msg);
1638 }
1639 }
1640 }
1641
1642 void
1643 InviteSession::startRetransmit200Timer()
1644 {
1645 mCurrentRetransmit200 = Timer::T1;
1646 int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
1647 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
1648 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
1649 }
1650
1651 // RFC3261 section 14.1
1652 // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
1653 // a value T chosen as follows:
1654 // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
1655 // chosen value between 2.1 and 4 seconds in units of 10 ms.
1656 // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
1657 // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
1658 void
1659 InviteSession::start491Timer()
1660 {
1661 int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
1662
1663 if (dynamic_cast<ClientInviteSession*>(this))
1664 {
1665 int timer = Random::getRandom() % (4000 - 2100);
1666 timer += 2100;
1667 timer -= timer % 10;
1668
1669 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
1670 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1671 }
1672 else
1673 {
1674 int timer = Random::getRandom() % 2000;
1675 timer -= timer % 10;
1676 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
1677 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1678 }
1679 }
1680
1681 void
1682 InviteSession::setSessionTimerHeaders(SipMessage &msg)
1683 {
1684 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
1685 {
1686 msg.header(h_SessionExpires).value() = mSessionInterval;
1687 if(msg.isRequest())
1688 {
1689 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
1690 }
1691 else
1692 {
1693 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
1694 }
1695 msg.header(h_MinSE).value() = mMinSE;
1696 }
1697 else
1698 {
1699 msg.remove(h_SessionExpires);
1700 msg.remove(h_MinSE);
1701 }
1702 }
1703
1704 void
1705 InviteSession::sessionRefresh()
1706 {
1707 if (updateMethodSupported())
1708 {
1709 transition(SentUpdate);
1710 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
1711 mLastLocalSessionModification->releaseContents(); // Don't send SDP
1712 }
1713 else
1714 {
1715 transition(SentReinvite);
1716 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
1717 InviteSession::setSdp(*mLastLocalSessionModification, mCurrentLocalSdp.get());
1718 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
1719 mSessionRefreshReInvite = true;
1720 }
1721 setSessionTimerHeaders(*mLastLocalSessionModification);
1722
1723 InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
1724 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
1725 send(mLastLocalSessionModification);
1726 }
1727
1728 void
1729 InviteSession::setSessionTimerPreferences()
1730 {
1731 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
1732 if(mSessionInterval != 0)
1733 {
1734 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
1735 mSessionInterval = resipMax(mMinSE, mSessionInterval);
1736 }
1737 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1738 {
1739 case Profile::PreferLocalRefreshes:
1740 mSessionRefresher = true; // Default refresher is Local
1741 break;
1742 case Profile::PreferRemoteRefreshes:
1743 mSessionRefresher = false; // Default refresher is Remote
1744 break;
1745 case Profile::PreferUASRefreshes:
1746 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
1747 break;
1748 case Profile::PreferUACRefreshes:
1749 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
1750 break;
1751 }
1752 }
1753
1754 void
1755 InviteSession::startSessionTimer()
1756 {
1757 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
1758 {
1759 // Check if we are the refresher
1760 if(mSessionRefresher)
1761 {
1762 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
1763 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1764 }
1765 else
1766 {
1767 // 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)
1768 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1769 }
1770 }
1771 else // Session Interval less than 90 - consider timers disabled
1772 {
1773 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1774 }
1775 }
1776
1777 void
1778 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
1779 {
1780 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
1781
1782 // If session timers are locally supported then handle response
1783 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1784 {
1785 setSessionTimerPreferences();
1786
1787 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
1788 && !msg.exists(h_SessionExpires))
1789 {
1790 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
1791 mSessionInterval = 0;
1792 }
1793 // Process Session Timer headers
1794 else if(msg.exists(h_SessionExpires))
1795 {
1796 mSessionInterval = msg.header(h_SessionExpires).value();
1797 if(msg.header(h_SessionExpires).exists(p_refresher))
1798 {
1799 // Remote end specified refresher preference
1800 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
1801 }
1802 }
1803 else
1804 {
1805 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
1806 // - we are free to use our SessionInterval settings (set above as a default)
1807 // If far end doesn't support then refresher must be local
1808 mSessionRefresher = true;
1809 }
1810
1811 // Update MinSE if specified and longer than current value
1812 if(msg.exists(h_MinSE))
1813 {
1814 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
1815 }
1816
1817 startSessionTimer();
1818 }
1819 }
1820
1821 void
1822 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1823 {
1824 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1825
1826 // If session timers are locally supported then add necessary headers to response
1827 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1828 {
1829 setSessionTimerPreferences();
1830
1831 // Check if far-end supports
1832 bool farEndSupportsTimer = false;
1833 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
1834 {
1835 farEndSupportsTimer = true;
1836 if(request.exists(h_SessionExpires))
1837 {
1838 // Use Session Interval requested by remote - if none then use local settings
1839 mSessionInterval = request.header(h_SessionExpires).value();
1840 if(request.header(h_SessionExpires).exists(p_refresher))
1841 {
1842 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1843 }
1844 }
1845
1846 // Update MinSE if specified and longer than current value
1847 if(request.exists(h_MinSE))
1848 {
1849 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
1850 }
1851 }
1852 else
1853 {
1854 // If far end doesn't support then refresher must be local
1855 mSessionRefresher = true;
1856 }
1857
1858 // Add Session-Expires to response if required
1859 if(mSessionInterval >= 90)
1860 {
1861 if(farEndSupportsTimer)
1862 {
1863 // If far end supports session-timer then require it, if not already present
1864 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
1865 {
1866 response.header(h_Requires).push_back(Token(Symbols::Timer));
1867 }
1868 }
1869 setSessionTimerHeaders(response);
1870 }
1871
1872 startSessionTimer();
1873 }
1874 }
1875
1876 Data
1877 InviteSession::toData(State state)
1878 {
1879 switch (state)
1880 {
1881 case Undefined:
1882 return "InviteSession::Undefined";
1883 case Connected:
1884 return "InviteSession::Connected";
1885 case SentUpdate:
1886 return "InviteSession::SentUpdate";
1887 case SentUpdateGlare:
1888 return "InviteSession::SentUpdateGlare";
1889 case SentReinvite:
1890 return "InviteSession::SentReinvite";
1891 case SentReinviteGlare:
1892 return "InviteSession::SentReinviteGlare";
1893 case SentReinviteNoOffer:
1894 return "InviteSession::SentReinviteNoOffer";
1895 case SentReinviteAnswered:
1896 return "InviteSession::SentReinviteAnswered";
1897 case SentReinviteNoOfferGlare:
1898 return "InviteSession::SentReinviteNoOfferGlare";
1899 case ReceivedUpdate:
1900 return "InviteSession::ReceivedUpdate";
1901 case ReceivedReinvite:
1902 return "InviteSession::ReceivedReinvite";
1903 case ReceivedReinviteNoOffer:
1904 return "InviteSession::ReceivedReinviteNoOffer";
1905 case ReceivedReinviteSentOffer:
1906 return "InviteSession::ReceivedReinviteSentOffer";
1907 case Answered:
1908 return "InviteSession::Answered";
1909 case WaitingToOffer:
1910 return "InviteSession::WaitingToOffer";
1911 case WaitingToRequestOffer:
1912 return "InviteSession::WaitingToRequestOffer";
1913 case WaitingToTerminate:
1914 return "InviteSession::WaitingToTerminate";
1915 case WaitingToHangup:
1916 return "InviteSession::WaitingToHangup";
1917 case Terminated:
1918 return "InviteSession::Terminated";
1919
1920 case UAC_Start:
1921 return "UAC_Start";
1922 case UAS_Offer:
1923 return "UAS_Offer";
1924 case UAS_OfferProvidedAnswer:
1925 return "UAS_OfferProvidedAnswer";
1926 case UAS_EarlyOffer:
1927 return "UAS_EarlyOffer";
1928 case UAS_EarlyProvidedAnswer:
1929 return "UAS_EarlyProvidedAnswer";
1930 case UAS_NoOffer:
1931 return "UAS_NoOffer";
1932 case UAS_ProvidedOffer:
1933 return "UAS_ProvidedOffer";
1934 case UAS_EarlyNoOffer:
1935 return "UAS_EarlyNoOffer";
1936 case UAS_EarlyProvidedOffer:
1937 return "UAS_EarlyProvidedOffer";
1938 case UAS_Accepted:
1939 return "UAS_Accepted";
1940 case UAS_WaitingToOffer:
1941 return "UAS_WaitingToOffer";
1942 case UAS_AcceptedWaitingAnswer:
1943 return "UAS_AcceptedWaitingAnswer";
1944 case UAC_Early:
1945 return "UAC_Early";
1946 case UAC_EarlyWithOffer:
1947 return "UAC_EarlyWithOffer";
1948 case UAC_EarlyWithAnswer:
1949 return "UAC_EarlyWithAnswer";
1950 case UAC_Answered:
1951 return "UAC_Answered";
1952 case UAC_SentUpdateEarly:
1953 return "UAC_SentUpdateEarly";
1954 case UAC_SentUpdateConnected:
1955 return "UAC_SentUpdateConnected";
1956 case UAC_ReceivedUpdateEarly:
1957 return "UAC_ReceivedUpdateEarly";
1958 case UAC_SentAnswer:
1959 return "UAC_SentAnswer";
1960 case UAC_QueuedUpdate:
1961 return "UAC_QueuedUpdate";
1962 case UAC_Cancelled:
1963 return "UAC_Cancelled";
1964
1965 case UAS_Start:
1966 return "UAS_Start";
1967 case UAS_OfferReliable:
1968 return "UAS_OfferReliable";
1969 case UAS_NoOfferReliable:
1970 return "UAS_NoOfferReliable";
1971 case UAS_FirstSentOfferReliable:
1972 return "UAS_FirstSentOfferReliable";
1973 case UAS_FirstEarlyReliable:
1974 return "UAS_FirstEarlyReliable";
1975 case UAS_EarlyReliable:
1976 return "UAS_EarlyReliable";
1977 case UAS_SentUpdate:
1978 return "UAS_SentUpdate";
1979 case UAS_SentUpdateAccepted:
1980 return "UAS_SentUpdateAccepted";
1981 case UAS_ReceivedUpdate:
1982 return "UAS_ReceivedUpdate";
1983 case UAS_ReceivedUpdateWaitingAnswer:
1984 return "UAS_ReceivedUpdateWaitingAnswer";
1985 case UAS_WaitingToTerminate:
1986 return "UAS_WaitingToTerminate";
1987 case UAS_WaitingToHangup:
1988 return "UAS_WaitingToHangup";
1989 }
1990 assert(0);
1991 return "Undefined";
1992 }
1993
1994
1995 void
1996 InviteSession::transition(State target)
1997 {
1998 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1999 mState = target;
2000 }
2001
2002 bool
2003 InviteSession::isReliable(const SipMessage& msg)
2004 {
2005 // Ensure supported both locally and remotely
2006 return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&
2007 mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));
2008 }
2009
2010 std::auto_ptr<SdpContents>
2011 InviteSession::getSdp(const SipMessage& msg)
2012 {
2013 return Helper::getSdp(msg.getContents());
2014 }
2015
2016 std::auto_ptr<SdpContents>
2017 InviteSession::makeSdp(const SdpContents& sdp)
2018 {
2019 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
2020 }
2021
2022 auto_ptr<Contents>
2023 InviteSession::makeSdp(const SdpContents& sdp,
2024 const SdpContents* alternative)
2025 {
2026 if (alternative)
2027 {
2028 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2029 mac->parts().push_back(alternative->clone());
2030 mac->parts().push_back(sdp.clone());
2031 return auto_ptr<Contents>(mac);
2032 }
2033 else
2034 {
2035 return auto_ptr<Contents>(sdp.clone());
2036 }
2037 }
2038
2039 void
2040 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
2041 {
2042 // !jf! should deal with multipart here
2043
2044 // This will clone the sdp since the InviteSession also wants to keep its own
2045 // copy of the sdp around for the application to access
2046 if (alternative)
2047 {
2048 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2049 mac->parts().push_back(alternative->clone());
2050 mac->parts().push_back(sdp.clone());
2051 msg.setContents(auto_ptr<Contents>(mac));
2052 }
2053 else
2054 {
2055 msg.setContents(&sdp);
2056 }
2057 }
2058
2059 void
2060 InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
2061 {
2062 assert(sdp);
2063 msg.setContents(sdp);
2064 }
2065
2066 void
2067 InviteSession::provideProposedOffer()
2068 {
2069 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2070 {
2071 provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
2072 mProposedEncryptionLevel,
2073 dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
2074 }
2075 else
2076 {
2077 provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
2078 }
2079 }
2080
2081 InviteSession::Event
2082 InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
2083 {
2084 MethodTypes method = msg.header(h_CSeq).method();
2085 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2086 bool reliable = isReliable(msg);
2087 bool sentOffer = mProposedLocalSdp.get();
2088
2089 if (code == 481 || code == 408)
2090 {
2091 return OnGeneralFailure;
2092 }
2093 else if (code >= 300 && code <= 399)
2094 {
2095 return OnRedirect;
2096 }
2097 else if (method == INVITE && code == 0)
2098 {
2099 if (sdp)
2100 {
2101 if (reliable)
2102 {
2103 return OnInviteReliableOffer;
2104 }
2105 else
2106 {
2107 return OnInviteOffer;
2108 }
2109 }
2110 else
2111 {
2112 if (reliable)
2113 {
2114 return OnInviteReliable;
2115 }
2116 else
2117 {
2118 return OnInvite;
2119 }
2120 }
2121 }
2122 else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer.
2123 {
2124 if (reliable)
2125 {
2126 if (sdp)
2127 {
2128 if (sentOffer)
2129 {
2130 return On1xxAnswer;
2131 }
2132 else
2133 {
2134 return On1xxOffer;
2135 }
2136 }
2137 else
2138 {
2139 return On1xx;
2140 }
2141 }
2142 else
2143 {
2144 if (sdp)
2145 {
2146 return On1xxEarly;
2147 }
2148 else
2149 {
2150 return On1xx;
2151 }
2152 }
2153 }
2154 else if (method == INVITE && code >= 200 && code < 300)
2155 {
2156 if (sdp)
2157 {
2158 if (sentOffer)
2159 {
2160 return On2xxAnswer;
2161 }
2162 else
2163 {
2164 return On2xxOffer;
2165 }
2166 }
2167 else
2168 {
2169 return On2xx;
2170 }
2171 }
2172 else if (method == INVITE && code == 422)
2173 {
2174 return On422Invite;
2175 }
2176 else if (method == INVITE && code == 487)
2177 {
2178 return On487Invite;
2179 }
2180 else if (method == INVITE && code == 489)
2181 {
2182 return On489Invite;
2183 }
2184 else if (method == INVITE && code == 491)
2185 {
2186 return On491Invite;
2187 }
2188 else if (method == INVITE && code >= 400)
2189 {
2190 return OnInviteFailure;
2191 }
2192 else if (method == ACK)
2193 {
2194 if (sdp)
2195 {
2196 return OnAckAnswer;
2197 }
2198 else
2199 {
2200 return OnAck;
2201 }
2202 }
2203 else if (method == CANCEL && code == 0)
2204 {
2205 return OnCancel;
2206 }
2207 else if (method == CANCEL && code / 200 == 1)
2208 {
2209 return On200Cancel;
2210 }
2211 else if (method == CANCEL && code >= 400)
2212 {
2213 return OnCancelFailure;
2214 }
2215 else if (method == BYE && code == 0)
2216 {
2217 return OnBye;
2218 }
2219 else if (method == BYE && code / 200 == 1)
2220 {
2221 return On200Bye;
2222 }
2223 else if (method == PRACK && code == 0)
2224 {
2225 return OnPrack;
2226 }
2227 else if (method == PRACK && code / 200 == 1)
2228 {
2229 return On200Prack;
2230 }
2231 else if (method == UPDATE && code == 0)
2232 {
2233 if (sdp)
2234 {
2235 return OnUpdateOffer;
2236 }
2237 else
2238 {
2239 return OnUpdate;
2240 }
2241 }
2242 else if (method == UPDATE && code / 200 == 1)
2243 {
2244 return On200Update;
2245 }
2246 else if (method == UPDATE && code == 422)
2247 {
2248 return On422Update;
2249 }
2250 else if (method == UPDATE && code == 489)
2251 {
2252 return On489Update;
2253 }
2254 else if (method == UPDATE && code == 491)
2255 {
2256 return On491Update;
2257 }
2258 else if (method == UPDATE && code >= 400)
2259 {
2260 return OnUpdateRejected;
2261 }
2262 else
2263 {
2264 //assert(0); // dispatchOthers will throw if the message type is really unknown
2265 return Unknown;
2266 }
2267 }
2268
2269 void InviteSession::sendAck(const SdpContents *sdp)
2270 {
2271 SharedPtr<SipMessage> ack(new SipMessage);
2272
2273 assert(mAcks.count(mLastLocalSessionModification->header(h_CSeq).sequence()) == 0);
2274
2275 mDialog.makeRequest(*ack, ACK);
2276
2277 // Copy Authorization, Proxy Authorization headers and CSeq from original Invite
2278 if(mLastLocalSessionModification->exists(h_Authorizations))
2279 {
2280 ack->header(h_Authorizations) = mLastLocalSessionModification->header(h_Authorizations);
2281 }
2282 if(mLastLocalSessionModification->exists(h_ProxyAuthorizations))
2283 {
2284 ack->header(h_ProxyAuthorizations) = mLastLocalSessionModification->header(h_ProxyAuthorizations);
2285 }
2286 ack->header(h_CSeq).sequence() = mLastLocalSessionModification->header(h_CSeq).sequence();
2287
2288 if(sdp != 0)
2289 {
2290 setSdp(*ack, *sdp);
2291 }
2292 mAcks[ack->header(h_CSeq).sequence()] = ack;
2293 mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence());
2294
2295 InfoLog (<< "Sending " << ack->brief());
2296 send(ack);
2297 }
2298
2299 void InviteSession::sendBye()
2300 {
2301 SharedPtr<SipMessage> bye(new SipMessage());
2302 mDialog.makeRequest(*bye, BYE);
2303 Data reason;
2304 if (mEndReason != NotSpecified)
2305 {
2306 reason = getEndReasonString(mEndReason);
2307 bye->header(h_Reasons).push_back(Token(reason));
2308 }
2309
2310 InfoLog (<< myAddr() << " Sending BYE " << reason);
2311 send(bye);
2312 }
2313
2314 DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg)
2315 {
2316 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
2317 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
2318 if (secAttr)
2319 {
2320 SignatureStatus sig = secAttr->getSignatureStatus();
2321 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
2322 bool encrypted = secAttr->isEncrypted();
2323 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
2324 else if (encrypted) level = DialogUsageManager::Encrypt;
2325 else if (sign) level = DialogUsageManager::Sign;
2326 }
2327 return level;
2328 }
2329
2330 void InviteSession::setCurrentLocalSdp(const SipMessage& msg)
2331 {
2332 assert(mProposedLocalSdp.get());
2333 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2334 {
2335 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
2336 {
2337 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone()));
2338 }
2339 else
2340 {
2341 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone()));
2342 }
2343 }
2344 else
2345 {
2346 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
2347 }
2348 mProposedLocalSdp.reset();
2349 }
2350
2351 void InviteSession::onReadyToSend(SipMessage& msg)
2352 {
2353 mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
2354 }
2355
2356 void InviteSession::referNoSub(const SipMessage& msg)
2357 {
2358 assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
2359 mLastReferNoSubRequest = msg;
2360 mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
2361 }
2362
2363 void
2364 InviteSession::acceptReferNoSub(int statusCode)
2365 {
2366 if (statusCode / 100 != 2)
2367 {
2368 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2369 }
2370
2371 SharedPtr<SipMessage> response(new SipMessage);
2372 mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
2373 response->header(h_ReferSub).value() = "false";
2374 //response->header(h_Supporteds).push_back(Token("norefersub"));
2375
2376 send(response);
2377 }
2378
2379 void
2380 InviteSession::rejectReferNoSub(int responseCode)
2381 {
2382 if (responseCode < 400)
2383 {
2384 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2385 }
2386
2387 SharedPtr<SipMessage> response(new SipMessage);
2388 mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
2389 send(response);
2390 }
2391
2392 /* ====================================================================
2393 * The Vovida Software License, Version 1.0
2394 *
2395 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2396 *
2397 * Redistribution and use in source and binary forms, with or without
2398 * modification, are permitted provided that the following conditions
2399 * are met:
2400 *
2401 * 1. Redistributions of source code must retain the above copyright
2402 * notice, this list of conditions and the following disclaimer.
2403 *
2404 * 2. Redistributions in binary form must reproduce the above copyright
2405 * notice, this list of conditions and the following disclaimer in
2406 * the documentation and/or other materials provided with the
2407
2408 * distribution.
2409 *
2410 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2411 * and "Vovida Open Communication Application Library (VOCAL)" must
2412 * not be used to endorse or promote products derived from this
2413 * software without prior written permission. For written
2414 * permission, please contact vocal@vovida.org.
2415 *
2416 * 4. Products derived from this software may not be called "VOCAL", nor
2417 * may "VOCAL" appear in their name, without prior written
2418 * permission of Vovida Networks, Inc.
2419 *
2420 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2421 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2422 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2423 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2424 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2425 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2426 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2427 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2428 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2429 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2430 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2431 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2432 * DAMAGE.
2433 *
2434 * ====================================================================
2435 *
2436 * This software consists of voluntary contributions made by Vovida
2437 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2438 * Inc. For more information on Vovida Networks, Inc., please see
2439 * <http://www.vovida.org/>.
2440 *
2441 */
2442

Properties

Name Value
svn:eol-style native

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27