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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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