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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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