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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5645 - (show annotations) (download)
Tue Nov 15 05:20:40 2005 UTC (14 years, 1 month ago) by derek
File size: 70136 byte(s)
fixup endreason

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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27