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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5697 - (show annotations) (download)
Thu Nov 24 17:19:12 2005 UTC (14 years ago) by sgodin
File size: 70538 byte(s)
- added checks to InviteSession to verify CSeq on 2xx responses match our last request (or are a retransmission) - if not just drop them
- added onConnectedConfirmed callback for ACK (without answer) on initial invite
- removed enumSuffix vector copying (note:  there are still some mulit-threaded concerns)
- added missing InvalidContents files from .vcproj


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 // If not in Map, make sure CSeq matches last request
672 if(mLastSessionModification.isRequest() && msg.header(h_CSeq).sequence() != mLastSessionModification.header(h_CSeq).sequence())
673 {
674 InfoLog (<< "Throwing out 200 with mismatched CSeq=" << msg.header(h_CSeq).sequence() << " expected=" << mLastSessionModification.header(h_CSeq).sequence() << ".");
675 return; // just throw away 200 with bad CSeq
676 }
677 }
678
679 // !jf! do we need to handle 3xx here or is it handled elsewhere?
680 switch (mState)
681 {
682 case Connected:
683 dispatchConnected(msg);
684 break;
685 case SentUpdate:
686 dispatchSentUpdate(msg);
687 break;
688 case SentReinvite:
689 dispatchSentReinvite(msg);
690 break;
691 case SentReinviteNoOffer:
692 dispatchSentReinviteNoOffer(msg);
693 break;
694 case SentReinviteAnswered:
695 dispatchSentReinviteAnswered(msg);
696 break;
697 case SentUpdateGlare:
698 case SentReinviteGlare:
699 // The behavior is the same except for timer which is handled in dispatch(Timer)
700 dispatchGlare(msg);
701 break;
702 case SentReinviteNoOfferGlare:
703 dispatchReinviteNoOfferGlare(msg);
704 break;
705 case ReceivedUpdate:
706 case ReceivedReinvite:
707 case ReceivedReinviteNoOffer:
708 dispatchReceivedUpdateOrReinvite(msg);
709 break;
710 case ReceivedReinviteSentOffer:
711 dispatchReceivedReinviteSentOffer(msg);
712 break;
713 case Answered:
714 dispatchAnswered(msg);
715 break;
716 case WaitingToOffer:
717 dispatchWaitingToOffer(msg);
718 break;
719 case WaitingToRequestOffer:
720 dispatchWaitingToRequestOffer(msg);
721 break;
722 case WaitingToTerminate:
723 dispatchWaitingToTerminate(msg);
724 break;
725 case WaitingToHangup:
726 dispatchWaitingToHangup(msg);
727 break;
728 case Terminated:
729 dispatchTerminated(msg);
730 break;
731 case Undefined:
732 default:
733 assert(0);
734 break;
735 }
736 }
737
738 void
739 InviteSession::dispatch(const DumTimeout& timeout)
740 {
741 if (timeout.type() == DumTimeout::Retransmit200)
742 {
743 if (mCurrentRetransmit200)
744 {
745 InfoLog (<< "Retransmitting: " << endl << mInvite200);
746 DumHelper::setOutgoingEncryptionLevel(mInvite200, mCurrentEncryptionLevel);
747 send(mInvite200);
748 mCurrentRetransmit200 *= 2;
749 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
750 }
751 }
752 else if (timeout.type() == DumTimeout::WaitForAck)
753 {
754 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
755 {
756 if (timeout.seq() == mLastSessionModification.header(h_CSeq).sequence())
757 {
758 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
759
760 // If we are waiting for an Ack and it times out, then end with a BYE
761 if(mState == UAS_WaitingToHangup ||
762 mState == WaitingToHangup)
763 {
764 sendBye();
765 transition(Terminated);
766 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
767 }
768 else if(mState == ReceivedReinviteSentOffer)
769 {
770 transition(Connected);
771 mProposedLocalSdp.reset();
772 mProposedEncryptionLevel = DialogUsageManager::None;
773 //!dcm! -- should this be onIllegalNegotiation?
774 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
775 }
776 else if(mState == WaitingToOffer)
777 {
778 assert(mProposedLocalSdp.get());
779 //!dcm! -- should this be onIllegalNegotiation?
780 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
781 provideProposedOffer();
782 }
783 else
784 {
785 // this is so the app can decided to ignore this. default implementation
786 // will call end next
787 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
788 }
789 }
790 }
791 }
792 else if (timeout.type() == DumTimeout::CanDiscardAck)
793 {
794 AckMap::iterator i = mAcks.find(timeout.seq());
795 if (i != mAcks.end())
796 {
797 mAcks.erase(i);
798 }
799 }
800 else if (timeout.type() == DumTimeout::Glare)
801 {
802 if (mState == SentUpdateGlare)
803 {
804 transition(SentUpdate);
805
806 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
807 send(mLastSessionModification);
808 }
809 else if (mState == SentReinviteGlare)
810 {
811 transition(SentReinvite);
812
813 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
814 send(mLastSessionModification);
815 }
816 else if (mState == SentReinviteNoOfferGlare)
817 {
818 transition(SentReinviteNoOffer);
819
820 InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
821 send(mLastSessionModification);
822 }
823 }
824 else if (timeout.type() == DumTimeout::SessionExpiration)
825 {
826 if(timeout.seq() == mSessionTimerSeq)
827 {
828 // this is so the app can decided to ignore this. default implementation
829 // will call end next - which will send a BYE
830 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
831 }
832 }
833 else if (timeout.type() == DumTimeout::SessionRefresh)
834 {
835 if(timeout.seq() == mSessionTimerSeq)
836 {
837 // Note: If not connected then we must be issueing a reinvite/update or
838 // receiving one - in either case the session timer stuff will get
839 // reset/renegotiated - thus just ignore this referesh
840 if(mState == Connected)
841 {
842 sessionRefresh();
843 }
844 }
845 }
846 }
847
848 void
849 InviteSession::dispatchConnected(const SipMessage& msg)
850 {
851 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
852 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
853
854 switch (toEvent(msg, sdp.get()))
855 {
856 case OnInvite:
857 case OnInviteReliable:
858 mLastSessionModification = msg;
859 transition(ReceivedReinviteNoOffer);
860 //handler->onDialogModified(getSessionHandle(), None, msg);
861 handler->onOfferRequired(getSessionHandle(), msg);
862 break;
863
864 case OnInviteOffer:
865 case OnInviteReliableOffer:
866 mLastSessionModification = msg;
867 transition(ReceivedReinvite);
868 mCurrentEncryptionLevel = getEncryptionLevel(msg);
869 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
870
871 //handler->onDialogModified(getSessionHandle(), Offer, msg);
872 handler->onOffer(getSessionHandle(), msg, *sdp);
873 break;
874
875 case On2xx:
876 case On2xxOffer:
877 case On2xxAnswer:
878 // retransmission of 200I
879 // !jf! Need to include the answer here.
880 sendAck(mLastSessionModification);
881 break;
882
883 case OnUpdateOffer:
884 transition(ReceivedUpdate);
885
886 // !kh!
887 // Find out if it's an UPDATE requiring state change.
888 // See rfc3311 5.2, 4th paragraph.
889 mLastSessionModification = msg;
890 mCurrentEncryptionLevel = getEncryptionLevel(msg);
891 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
892 handler->onOffer(getSessionHandle(), msg, *sdp);
893 break;
894
895 case OnUpdate:
896 {
897 // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
898 SipMessage response;
899 mLastSessionModification = msg;
900 mDialog.makeResponse(response, mLastSessionModification, 200);
901 handleSessionTimerRequest(response, mLastSessionModification);
902 BaseUsage::send(response);
903 break;
904 }
905
906 case OnUpdateRejected:
907 case On200Update:
908 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
909 assert(0);
910 break;
911
912 case OnAck:
913 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
914 break;
915
916 default:
917 dispatchOthers(msg);
918 break;
919 }
920 }
921
922 void
923 InviteSession::dispatchSentUpdate(const SipMessage& msg)
924 {
925 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
926 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
927
928 switch (toEvent(msg, sdp.get()))
929 {
930 case OnInvite:
931 case OnInviteReliable:
932 case OnInviteOffer:
933 case OnInviteReliableOffer:
934 case OnUpdate:
935 case OnUpdateOffer:
936 {
937 // glare
938 SipMessage response;
939 mDialog.makeResponse(response, msg, 491);
940 BaseUsage::send(response);
941 break;
942 }
943
944 case On200Update:
945 transition(Connected);
946 handleSessionTimerResponse(msg);
947 if (sdp.get())
948 {
949 mCurrentEncryptionLevel = getEncryptionLevel(msg);
950 setCurrentLocalSdp(msg);
951 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
952 handler->onAnswer(getSessionHandle(), msg, *sdp);
953 }
954 else if(mProposedLocalSdp.get())
955 {
956 // If we sent an offer in the Update Request and no answer is received
957 handler->onIllegalNegotiation(getSessionHandle(), msg);
958 mProposedLocalSdp.reset();
959 mProposedEncryptionLevel = DialogUsageManager::None;
960 }
961 break;
962
963 case On491Update:
964 transition(SentUpdateGlare);
965 start491Timer();
966 break;
967
968 case On422Update: // session timer
969 if(msg.exists(h_MinSE))
970 {
971 // Change interval to min from 422 response
972 mSessionInterval = msg.header(h_MinSE).value();
973 mMinSE = mSessionInterval;
974 sessionRefresh();
975 }
976 else
977 {
978 // Response must contact Min_SE - if not - just ignore
979 // ?slg? callback?
980 transition(Connected);
981 mProposedLocalSdp.reset();
982 mProposedEncryptionLevel = DialogUsageManager::None;
983 }
984 break;
985
986 case OnUpdateRejected:
987 // !jf! - callback?
988 mProposedLocalSdp.reset();
989 mProposedEncryptionLevel = DialogUsageManager::None;
990 transition(Connected);
991 break;
992
993 case OnGeneralFailure:
994 sendBye();
995 transition(Terminated);
996 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
997 break;
998
999 default:
1000 dispatchOthers(msg);
1001 break;
1002 }
1003 }
1004
1005 void
1006 InviteSession::dispatchSentReinvite(const SipMessage& msg)
1007 {
1008 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1009 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1010
1011 switch (toEvent(msg, sdp.get()))
1012 {
1013 case OnInvite:
1014 case OnInviteReliable:
1015 case OnInviteOffer:
1016 case OnInviteReliableOffer:
1017 case OnUpdate:
1018 case OnUpdateOffer:
1019 {
1020 SipMessage response;
1021 mDialog.makeResponse(response, msg, 491);
1022 BaseUsage::send(response);
1023 break;
1024 }
1025
1026 case On1xx:
1027 case On1xxEarly:
1028 // Some UA's send a 100 response to a ReInvite - just ignore it
1029 break;
1030
1031 case On2xxAnswer:
1032 case On2xxOffer: // !slg! doesn't really make sense
1033 {
1034 transition(Connected);
1035 handleSessionTimerResponse(msg);
1036 setCurrentLocalSdp(msg);
1037
1038 // !jf! I need to potentially include an answer in the ACK here
1039 sendAck(mLastSessionModification);
1040 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1041
1042 if (mSessionRefreshReInvite)
1043 {
1044 mSessionRefreshReInvite = false;
1045
1046 MD5Stream currentRemote;
1047 currentRemote<< *mCurrentRemoteSdp;
1048 MD5Stream newRemote;
1049 newRemote << *sdp;
1050 bool changed = currentRemote.getHex() != newRemote.getHex();
1051
1052 if (changed)
1053 {
1054 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
1055 handler->onRemoteSdpChanged(getSessionHandle(), msg, *sdp);
1056 }
1057 }
1058 else
1059 {
1060 handler->onAnswer(getSessionHandle(), msg, *sdp);
1061 }
1062
1063 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1064 // the ACK when a 200I is received? If yes, then I need to store all
1065 // ACK messages for 64*T1
1066 break;
1067 }
1068 case On2xx:
1069 sendAck(mLastSessionModification);
1070 transition(Connected);
1071 handleSessionTimerResponse(msg);
1072 handler->onIllegalNegotiation(getSessionHandle(), msg);
1073 mProposedLocalSdp.reset();
1074 mProposedEncryptionLevel = DialogUsageManager::None;
1075 break;
1076
1077 case On422Invite:
1078 if(msg.exists(h_MinSE))
1079 {
1080 // Change interval to min from 422 response
1081 mSessionInterval = msg.header(h_MinSE).value();
1082 mMinSE = mSessionInterval;
1083 sessionRefresh();
1084 }
1085 else
1086 {
1087 // Response must contact Min_SE - if not - just ignore
1088 // ?slg? callback?
1089 transition(Connected);
1090 mProposedLocalSdp.reset();
1091 mProposedEncryptionLevel = DialogUsageManager::None;
1092 }
1093 break;
1094
1095 case On491Invite:
1096 transition(SentReinviteGlare);
1097 start491Timer();
1098 break;
1099
1100 case OnGeneralFailure:
1101 sendBye();
1102 transition(Terminated);
1103 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1104 break;
1105
1106 case OnInviteFailure:
1107 case On487Invite:
1108 case On489Invite:
1109 transition(Connected);
1110 mProposedLocalSdp.reset();
1111 handler->onOfferRejected(getSessionHandle(), &msg);
1112 break;
1113
1114 default:
1115 dispatchOthers(msg);
1116 break;
1117 }
1118 }
1119
1120 void
1121 InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1122 {
1123 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1124 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1125
1126 switch (toEvent(msg, sdp.get()))
1127 {
1128 case OnInvite:
1129 case OnInviteReliable:
1130 case OnInviteOffer:
1131 case OnInviteReliableOffer:
1132 case OnUpdate:
1133 case OnUpdateOffer:
1134 {
1135 SipMessage response;
1136 mDialog.makeResponse(response, msg, 491);
1137 BaseUsage::send(response);
1138 break;
1139 }
1140
1141 case On1xx:
1142 case On1xxEarly:
1143 // Some UA's send a 100 response to a ReInvite - just ignore it
1144 break;
1145
1146 case On2xxAnswer: // !slg! doesn't really make sense
1147 case On2xxOffer:
1148 {
1149 transition(SentReinviteAnswered);
1150 handleSessionTimerResponse(msg);
1151 // mLastSessionModification = msg; // ?slg? why are we storing 200's?
1152 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1153 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
1154 handler->onOffer(getSessionHandle(), msg, *sdp);
1155
1156 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1157 // the ACK when a 200I is received? If yes, then I need to store all
1158 // ACK messages for 64*T1
1159 break;
1160 }
1161
1162 case On2xx:
1163 sendAck(mLastSessionModification);
1164 transition(Connected);
1165 handleSessionTimerResponse(msg);
1166 handler->onIllegalNegotiation(getSessionHandle(), msg);
1167 mProposedLocalSdp.reset();
1168 mProposedEncryptionLevel = DialogUsageManager::None;
1169 break;
1170
1171 case On422Invite:
1172 if(msg.exists(h_MinSE))
1173 {
1174 // Change interval to min from 422 response
1175 mSessionInterval = msg.header(h_MinSE).value();
1176 mMinSE = mSessionInterval;
1177 setSessionTimerHeaders(mLastSessionModification);
1178 send(mLastSessionModification);
1179 }
1180 else
1181 {
1182 // Response must contact Min_SE - if not - just ignore
1183 // ?slg? callback?
1184 transition(Connected);
1185 mProposedLocalSdp.reset();
1186 mProposedEncryptionLevel = DialogUsageManager::None;
1187 }
1188 break;
1189
1190 case On491Invite:
1191 transition(SentReinviteNoOfferGlare);
1192 start491Timer();
1193 break;
1194
1195 case OnGeneralFailure:
1196 sendBye();
1197 transition(Terminated);
1198 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1199 break;
1200
1201 case OnInviteFailure:
1202 case On487Invite:
1203 case On489Invite:
1204 transition(Connected);
1205 mProposedLocalSdp.reset();
1206 handler->onOfferRejected(getSessionHandle(), &msg);
1207 break;
1208
1209 default:
1210 dispatchOthers(msg);
1211 break;
1212 }
1213 }
1214
1215 void
1216 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1217 {
1218 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1219 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1220
1221 switch (toEvent(msg, sdp.get()))
1222 {
1223 case OnInvite:
1224 case OnInviteReliable:
1225 case OnInviteOffer:
1226 case OnInviteReliableOffer:
1227 case OnUpdate:
1228 case OnUpdateOffer:
1229 {
1230 SipMessage response;
1231 mDialog.makeResponse(response, msg, 491);
1232 BaseUsage::send(response);
1233 break;
1234 }
1235 case OnAckAnswer:
1236 transition(Connected);
1237 setCurrentLocalSdp(msg);
1238 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
1239 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1240 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1241 handler->onAnswer(getSessionHandle(), msg, *sdp);
1242 break;
1243 case OnAck:
1244 transition(Connected);
1245 mProposedLocalSdp.reset();
1246 mProposedEncryptionLevel = DialogUsageManager::None;
1247 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1248 //!dcm! -- should this be onIllegalNegotiation?
1249 handler->onOfferRejected(getSessionHandle(), &msg);
1250 break;
1251 default:
1252 dispatchOthers(msg);
1253 break;
1254 }
1255 }
1256
1257 void
1258 InviteSession::dispatchGlare(const SipMessage& msg)
1259 {
1260 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1261 MethodTypes method = msg.header(h_CSeq).method();
1262 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1263 {
1264 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1265 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1266 handler->onOfferRejected(getSessionHandle(), &msg);
1267 dispatchConnected(msg); // act as if we received message in Connected state
1268 }
1269 else
1270 {
1271 dispatchOthers(msg);
1272 }
1273 }
1274
1275 void
1276 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1277 {
1278 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1279 MethodTypes method = msg.header(h_CSeq).method();
1280 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1281 {
1282 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1283 handler->onOfferRequestRejected(getSessionHandle(), msg);
1284 dispatchConnected(msg); // act as if we received message in Connected state
1285 }
1286 else
1287 {
1288 dispatchOthers(msg);
1289 }
1290 }
1291
1292 void
1293 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1294 {
1295 MethodTypes method = msg.header(h_CSeq).method();
1296 if (method == INVITE || method == UPDATE)
1297 {
1298 // Means that the UAC has sent us a second reINVITE or UPDATE before we
1299 // responded to the first one. Bastard!
1300 SipMessage response;
1301 mDialog.makeResponse(response, msg, 500);
1302 response.header(h_RetryAfter).value() = Random::getRandom() % 10;
1303 send(response);
1304 }
1305 else
1306 {
1307 dispatchOthers(msg);
1308 }
1309 }
1310
1311
1312 void
1313 InviteSession::dispatchAnswered(const SipMessage& msg)
1314 {
1315 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1316 {
1317 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1318 transition(Connected);
1319 }
1320 else
1321 {
1322 dispatchOthers(msg);
1323 }
1324 }
1325
1326 void
1327 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1328 {
1329 dispatchOthers(msg);
1330 }
1331
1332 void
1333 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1334 {
1335 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1336 {
1337 assert(mProposedLocalSdp.get());
1338 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1339 provideProposedOffer();
1340 }
1341 else
1342 {
1343 dispatchOthers(msg);
1344 }
1345 }
1346
1347 void
1348 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1349 {
1350 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1351 {
1352 assert(mProposedLocalSdp.get());
1353 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1354 requestOffer();
1355 }
1356 else
1357 {
1358 dispatchOthers(msg);
1359 }
1360 }
1361
1362 void
1363 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1364 {
1365 if (msg.isResponse() &&
1366 msg.header(h_CSeq).method() == INVITE)
1367 {
1368 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1369 {
1370 // !jf! Need to include the answer here.
1371 sendAck(mLastSessionModification);
1372 }
1373 sendBye();
1374 transition(Terminated);
1375 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1376 }
1377 }
1378
1379 void
1380 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1381 {
1382 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1383
1384 switch (toEvent(msg, sdp.get()))
1385 {
1386 case OnAck:
1387 case OnAckAnswer:
1388 {
1389 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1390
1391 sendBye();
1392 transition(Terminated);
1393 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1394 break;
1395 }
1396
1397 default:
1398 break;
1399 }
1400 }
1401
1402 void
1403 InviteSession::dispatchTerminated(const SipMessage& msg)
1404 {
1405 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1406
1407 if (msg.isRequest())
1408 {
1409 SipMessage response;
1410 mDialog.makeResponse(response, msg, 481);
1411 send(response);
1412
1413 // !jf! means the peer sent BYE while we are waiting for response to BYE
1414 //mDum.destroy(this);
1415 }
1416 else
1417 {
1418 mDum.destroy(this);
1419 }
1420 }
1421
1422 void
1423 InviteSession::dispatchOthers(const SipMessage& msg)
1424 {
1425 // handle OnGeneralFailure
1426 // handle OnRedirect
1427
1428 switch (msg.header(h_CSeq).method())
1429 {
1430 case PRACK:
1431 dispatchPrack(msg);
1432 break;
1433 case CANCEL:
1434 dispatchCancel(msg);
1435 break;
1436 case BYE:
1437 dispatchBye(msg);
1438 break;
1439 case INFO:
1440 dispatchInfo(msg);
1441 break;
1442 case MESSAGE:
1443 dispatchMessage(msg);
1444 break;
1445 case ACK:
1446 // Ignore duplicate ACKs from 2xx reTransmissions
1447 break;
1448 default:
1449 // handled in Dialog
1450 WarningLog (<< "DUM delivered a "
1451 << msg.header(h_CSeq).unknownMethodName()
1452 << " to the InviteSession "
1453 << endl
1454 << msg);
1455 assert(0);
1456 break;
1457 }
1458 }
1459
1460 void
1461 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
1462 {
1463 assert(msg.isRequest());
1464 assert(msg.header(h_CSeq).method() == INVITE);
1465
1466 // If we get an INVITE request from the wire and we are not in
1467 // Connected state, reject the request and send a BYE
1468 SipMessage response;
1469 mDialog.makeResponse(response, msg, 400); // !jf! what code to use?
1470 InfoLog (<< "Sending " << response.brief());
1471 send(response);
1472
1473 sendBye();
1474 transition(Terminated);
1475 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1476 }
1477
1478 void
1479 InviteSession::dispatchPrack(const SipMessage& msg)
1480 {
1481 assert(msg.header(h_CSeq).method() == PRACK);
1482 if(msg.isRequest())
1483 {
1484 SipMessage rsp;
1485 mDialog.makeResponse(rsp, msg, 481);
1486 send(rsp);
1487
1488 sendBye();
1489 // !jf! should we make some other callback here
1490 transition(Terminated);
1491 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1492 }
1493 else
1494 {
1495 // ignore. could be PRACK/200
1496 }
1497 }
1498
1499 void
1500 InviteSession::dispatchCancel(const SipMessage& msg)
1501 {
1502 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1503 assert(msg.header(h_CSeq).method() == CANCEL);
1504 if(msg.isRequest())
1505 {
1506 SipMessage rsp;
1507 mDialog.makeResponse(rsp, msg, 200);
1508 send(rsp);
1509
1510 sendBye();
1511 // !jf! should we make some other callback here
1512 transition(Terminated);
1513 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1514 }
1515 else
1516 {
1517 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1518 assert(0);
1519 }
1520 }
1521
1522 void
1523 InviteSession::dispatchBye(const SipMessage& msg)
1524 {
1525 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1526
1527 if (msg.isRequest())
1528 {
1529
1530 SipMessage rsp;
1531 InfoLog (<< "Received " << msg.brief());
1532 mDialog.makeResponse(rsp, msg, 200);
1533 send(rsp);
1534
1535 // !jf! should we make some other callback here
1536 transition(Terminated);
1537 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1538 mDum.destroy(this);
1539 }
1540 else
1541 {
1542 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1543 assert(0);
1544 }
1545 }
1546
1547 void
1548 InviteSession::dispatchInfo(const SipMessage& msg)
1549 {
1550 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1551 if (msg.isRequest())
1552 {
1553 InfoLog (<< "Received " << msg.brief());
1554 mDialog.makeResponse(mLastNitResponse, msg, 200);
1555 handler->onInfo(getSessionHandle(), msg);
1556 }
1557 else
1558 {
1559 assert(mNitState == NitProceeding);
1560 mNitState = NitComplete;
1561 //!dcm! -- toss away 1xx to an info?
1562 if (msg.header(h_StatusLine).statusCode() >= 300)
1563 {
1564 handler->onInfoFailure(getSessionHandle(), msg);
1565 }
1566 else if (msg.header(h_StatusLine).statusCode() >= 200)
1567 {
1568 handler->onInfoSuccess(getSessionHandle(), msg);
1569 }
1570 }
1571 }
1572
1573 void
1574 InviteSession::acceptNIT(int statusCode, const Contents * contents)
1575 {
1576 if (statusCode / 100 != 2)
1577 {
1578 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
1579 }
1580
1581 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1582 mLastNitResponse.setContents(contents);
1583 Helper::getResponseCodeReason(statusCode, mLastNitResponse.header(h_StatusLine).reason());
1584 BaseUsage::send(mLastNitResponse);
1585 }
1586
1587 void
1588 InviteSession::rejectNIT(int statusCode)
1589 {
1590 if (statusCode < 400)
1591 {
1592 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
1593 }
1594 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1595 mLastNitResponse.releaseContents();
1596 Helper::getResponseCodeReason(statusCode, mLastNitResponse.header(h_StatusLine).reason());
1597 BaseUsage::send(mLastNitResponse);
1598 }
1599
1600 void
1601 InviteSession::dispatchMessage(const SipMessage& msg)
1602 {
1603 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1604 if (msg.isRequest())
1605 {
1606 InfoLog (<< "Received " << msg.brief());
1607 mDialog.makeResponse(mLastNitResponse, msg, 200);
1608 mLastNitResponse.header(h_Contacts).clear();
1609 handler->onMessage(getSessionHandle(), msg);
1610 }
1611 else
1612 {
1613 assert(mNitState == NitProceeding);
1614 mNitState = NitComplete;
1615 //!dcm! -- toss away 1xx to an message?
1616 if (msg.header(h_StatusLine).statusCode() >= 300)
1617 {
1618 handler->onMessageFailure(getSessionHandle(), msg);
1619 }
1620 else if (msg.header(h_StatusLine).statusCode() >= 200)
1621 {
1622 handler->onMessageSuccess(getSessionHandle(), msg);
1623 }
1624 }
1625 }
1626
1627 void
1628 InviteSession::startRetransmit200Timer()
1629 {
1630 mCurrentRetransmit200 = Timer::T1;
1631 int seq = mLastSessionModification.header(h_CSeq).sequence();
1632 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
1633 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
1634 }
1635
1636 // RFC3261 section 14.1
1637 // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
1638 // a value T chosen as follows:
1639 // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
1640 // chosen value between 2.1 and 4 seconds in units of 10 ms.
1641 // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
1642 // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
1643 void
1644 InviteSession::start491Timer()
1645 {
1646 int seq = mLastSessionModification.header(h_CSeq).sequence();
1647
1648 if (dynamic_cast<ClientInviteSession*>(this))
1649 {
1650 int timer = Random::getRandom() % (4000 - 2100);
1651 timer += 2100;
1652 timer -= timer % 10;
1653
1654 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
1655 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1656 }
1657 else
1658 {
1659 int timer = Random::getRandom() % 2000;
1660 timer -= timer % 10;
1661 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
1662 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1663 }
1664 }
1665
1666 void
1667 InviteSession::setSessionTimerHeaders(SipMessage &msg)
1668 {
1669 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
1670 {
1671 msg.header(h_SessionExpires).value() = mSessionInterval;
1672 if(msg.isRequest())
1673 {
1674 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
1675 }
1676 else
1677 {
1678 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
1679 }
1680 msg.header(h_MinSE).value() = mMinSE;
1681 }
1682 else
1683 {
1684 msg.remove(h_SessionExpires);
1685 msg.remove(h_MinSE);
1686 }
1687 }
1688
1689 void
1690 InviteSession::sessionRefresh()
1691 {
1692 if (updateMethodSupported())
1693 {
1694 transition(SentUpdate);
1695 mDialog.makeRequest(mLastSessionModification, UPDATE);
1696 mLastSessionModification.releaseContents(); // Don't send SDP
1697 }
1698 else
1699 {
1700 transition(SentReinvite);
1701 mDialog.makeRequest(mLastSessionModification, INVITE);
1702 InviteSession::setSdp(mLastSessionModification, mCurrentLocalSdp.get());
1703 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
1704 mSessionRefreshReInvite = true;
1705 }
1706 mLastSessionModification.remove(h_ProxyAuthorizations); // remove remote credentials.
1707 setSessionTimerHeaders(mLastSessionModification);
1708
1709 InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief());
1710 DumHelper::setOutgoingEncryptionLevel(mLastSessionModification, mCurrentEncryptionLevel);
1711 send(mLastSessionModification);
1712 }
1713
1714 void
1715 InviteSession::setSessionTimerPreferences()
1716 {
1717 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
1718 if(mSessionInterval != 0)
1719 {
1720 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
1721 mSessionInterval = resipMax(mMinSE, mSessionInterval);
1722 }
1723 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1724 {
1725 case Profile::PreferLocalRefreshes:
1726 mSessionRefresher = true; // Default refresher is Local
1727 break;
1728 case Profile::PreferRemoteRefreshes:
1729 mSessionRefresher = false; // Default refresher is Remote
1730 break;
1731 case Profile::PreferUASRefreshes:
1732 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
1733 break;
1734 case Profile::PreferUACRefreshes:
1735 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
1736 break;
1737 }
1738 }
1739
1740 void
1741 InviteSession::startSessionTimer()
1742 {
1743 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
1744 {
1745 // Check if we are the refresher
1746 if(mSessionRefresher)
1747 {
1748 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
1749 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1750 }
1751 else
1752 {
1753 // 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)
1754 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1755 }
1756 }
1757 else // Session Interval less than 90 - consider timers disabled
1758 {
1759 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1760 }
1761 }
1762
1763 void
1764 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
1765 {
1766 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
1767
1768 // If session timers are locally supported then handle response
1769 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1770 {
1771 setSessionTimerPreferences();
1772
1773 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
1774 && !msg.exists(h_SessionExpires))
1775 {
1776 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
1777 mSessionInterval = 0;
1778 }
1779 // Process Session Timer headers
1780 else if(msg.exists(h_SessionExpires))
1781 {
1782 mSessionInterval = msg.header(h_SessionExpires).value();
1783 if(msg.header(h_SessionExpires).exists(p_refresher))
1784 {
1785 // Remote end specified refresher preference
1786 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
1787 }
1788 }
1789 else
1790 {
1791 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
1792 // - we are free to use our SessionInterval settings (set above as a default)
1793 // If far end doesn't support then refresher must be local
1794 mSessionRefresher = true;
1795 }
1796
1797 // Update MinSE if specified and longer than current value
1798 if(msg.exists(h_MinSE))
1799 {
1800 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
1801 }
1802
1803 startSessionTimer();
1804 }
1805 }
1806
1807 void
1808 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1809 {
1810 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1811
1812 // If session timers are locally supported then add necessary headers to response
1813 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1814 {
1815 setSessionTimerPreferences();
1816
1817 // Check if far-end supports
1818 bool farEndSupportsTimer = false;
1819 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
1820 {
1821 farEndSupportsTimer = true;
1822 if(request.exists(h_SessionExpires))
1823 {
1824 // Use Session Interval requested by remote - if none then use local settings
1825 mSessionInterval = request.header(h_SessionExpires).value();
1826 if(request.header(h_SessionExpires).exists(p_refresher))
1827 {
1828 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1829 }
1830 }
1831
1832 // Update MinSE if specified and longer than current value
1833 if(request.exists(h_MinSE))
1834 {
1835 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
1836 }
1837 }
1838 else
1839 {
1840 // If far end doesn't support then refresher must be local
1841 mSessionRefresher = true;
1842 }
1843
1844 // Add Session-Expires to response if required
1845 if(mSessionInterval >= 90)
1846 {
1847 if(farEndSupportsTimer)
1848 {
1849 // If far end supports session-timer then require it, if not already present
1850 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
1851 {
1852 response.header(h_Requires).push_back(Token(Symbols::Timer));
1853 }
1854 }
1855 setSessionTimerHeaders(response);
1856 }
1857
1858 startSessionTimer();
1859 }
1860 }
1861
1862 Data
1863 InviteSession::toData(State state)
1864 {
1865 switch (state)
1866 {
1867 case Undefined:
1868 return "InviteSession::Undefined";
1869 case Connected:
1870 return "InviteSession::Connected";
1871 case SentUpdate:
1872 return "InviteSession::SentUpdate";
1873 case SentUpdateGlare:
1874 return "InviteSession::SentUpdateGlare";
1875 case SentReinvite:
1876 return "InviteSession::SentReinvite";
1877 case SentReinviteGlare:
1878 return "InviteSession::SentReinviteGlare";
1879 case SentReinviteNoOffer:
1880 return "InviteSession::SentReinviteNoOffer";
1881 case SentReinviteAnswered:
1882 return "InviteSession::SentReinviteAnswered";
1883 case SentReinviteNoOfferGlare:
1884 return "InviteSession::SentReinviteNoOfferGlare";
1885 case ReceivedUpdate:
1886 return "InviteSession::ReceivedUpdate";
1887 case ReceivedReinvite:
1888 return "InviteSession::ReceivedReinvite";
1889 case ReceivedReinviteNoOffer:
1890 return "InviteSession::ReceivedReinviteNoOffer";
1891 case ReceivedReinviteSentOffer:
1892 return "InviteSession::ReceivedReinviteSentOffer";
1893 case Answered:
1894 return "InviteSession::Answered";
1895 case WaitingToOffer:
1896 return "InviteSession::WaitingToOffer";
1897 case WaitingToRequestOffer:
1898 return "InviteSession::WaitingToRequestOffer";
1899 case WaitingToTerminate:
1900 return "InviteSession::WaitingToTerminate";
1901 case WaitingToHangup:
1902 return "InviteSession::WaitingToHangup";
1903 case Terminated:
1904 return "InviteSession::Terminated";
1905
1906 case UAC_Start:
1907 return "UAC_Start";
1908 case UAS_Offer:
1909 return "UAS_Offer";
1910 case UAS_OfferProvidedAnswer:
1911 return "UAS_OfferProvidedAnswer";
1912 case UAS_EarlyOffer:
1913 return "UAS_EarlyOffer";
1914 case UAS_EarlyProvidedAnswer:
1915 return "UAS_EarlyProvidedAnswer";
1916 case UAS_NoOffer:
1917 return "UAS_NoOffer";
1918 case UAS_ProvidedOffer:
1919 return "UAS_ProvidedOffer";
1920 case UAS_EarlyNoOffer:
1921 return "UAS_EarlyNoOffer";
1922 case UAS_EarlyProvidedOffer:
1923 return "UAS_EarlyProvidedOffer";
1924 case UAS_Accepted:
1925 return "UAS_Accepted";
1926 case UAS_WaitingToOffer:
1927 return "UAS_WaitingToOffer";
1928 case UAS_AcceptedWaitingAnswer:
1929 return "UAS_AcceptedWaitingAnswer";
1930 case UAC_Early:
1931 return "UAC_Early";
1932 case UAC_EarlyWithOffer:
1933 return "UAC_EarlyWithOffer";
1934 case UAC_EarlyWithAnswer:
1935 return "UAC_EarlyWithAnswer";
1936 case UAC_Answered:
1937 return "UAC_Answered";
1938 case UAC_SentUpdateEarly:
1939 return "UAC_SentUpdateEarly";
1940 case UAC_SentUpdateConnected:
1941 return "UAC_SentUpdateConnected";
1942 case UAC_ReceivedUpdateEarly:
1943 return "UAC_ReceivedUpdateEarly";
1944 case UAC_SentAnswer:
1945 return "UAC_SentAnswer";
1946 case UAC_QueuedUpdate:
1947 return "UAC_QueuedUpdate";
1948 case UAC_Cancelled:
1949 return "UAC_Cancelled";
1950
1951 case UAS_Start:
1952 return "UAS_Start";
1953 case UAS_OfferReliable:
1954 return "UAS_OfferReliable";
1955 case UAS_NoOfferReliable:
1956 return "UAS_NoOfferReliable";
1957 case UAS_FirstSentOfferReliable:
1958 return "UAS_FirstSentOfferReliable";
1959 case UAS_FirstEarlyReliable:
1960 return "UAS_FirstEarlyReliable";
1961 case UAS_EarlyReliable:
1962 return "UAS_EarlyReliable";
1963 case UAS_SentUpdate:
1964 return "UAS_SentUpdate";
1965 case UAS_SentUpdateAccepted:
1966 return "UAS_SentUpdateAccepted";
1967 case UAS_ReceivedUpdate:
1968 return "UAS_ReceivedUpdate";
1969 case UAS_ReceivedUpdateWaitingAnswer:
1970 return "UAS_ReceivedUpdateWaitingAnswer";
1971 case UAS_WaitingToTerminate:
1972 return "UAS_WaitingToTerminate";
1973 case UAS_WaitingToHangup:
1974 return "UAS_WaitingToHangup";
1975 }
1976 assert(0);
1977 return "Undefined";
1978 }
1979
1980
1981 void
1982 InviteSession::transition(State target)
1983 {
1984 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1985 mState = target;
1986 }
1987
1988 bool
1989 InviteSession::isReliable(const SipMessage& msg)
1990 {
1991 // Ensure supported both locally and remotely
1992 return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&
1993 mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));
1994 }
1995
1996 std::auto_ptr<SdpContents>
1997 InviteSession::getSdp(const SipMessage& msg)
1998 {
1999 return Helper::getSdp(msg.getContents());
2000 }
2001
2002 std::auto_ptr<SdpContents>
2003 InviteSession::makeSdp(const SdpContents& sdp)
2004 {
2005 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
2006 }
2007
2008 auto_ptr<Contents>
2009 InviteSession::makeSdp(const SdpContents& sdp,
2010 const SdpContents* alternative)
2011 {
2012 if (alternative)
2013 {
2014 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2015 mac->parts().push_back(alternative->clone());
2016 mac->parts().push_back(sdp.clone());
2017 return auto_ptr<Contents>(mac);
2018 }
2019 else
2020 {
2021 return auto_ptr<Contents>(sdp.clone());
2022 }
2023 }
2024
2025 void
2026 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
2027 {
2028 // !jf! should deal with multipart here
2029
2030 // This will clone the sdp since the InviteSession also wants to keep its own
2031 // copy of the sdp around for the application to access
2032 if (alternative)
2033 {
2034 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2035 mac->parts().push_back(alternative->clone());
2036 mac->parts().push_back(sdp.clone());
2037 msg.setContents(auto_ptr<Contents>(mac));
2038 }
2039 else
2040 {
2041 msg.setContents(&sdp);
2042 }
2043 }
2044
2045 void
2046 InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
2047 {
2048 assert(sdp);
2049 msg.setContents(sdp);
2050 }
2051
2052 void
2053 InviteSession::provideProposedOffer()
2054 {
2055 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2056 {
2057 provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
2058 mProposedEncryptionLevel,
2059 dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
2060 }
2061 else
2062 {
2063 provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
2064 }
2065 }
2066
2067 InviteSession::Event
2068 InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
2069 {
2070 MethodTypes method = msg.header(h_CSeq).method();
2071 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2072 bool reliable = isReliable(msg);
2073 bool sentOffer = mProposedLocalSdp.get();
2074
2075 if (code == 481 || code == 408)
2076 {
2077 return OnGeneralFailure;
2078 }
2079 else if (code >= 300 && code <= 399)
2080 {
2081 return OnRedirect;
2082 }
2083 else if (method == INVITE && code == 0)
2084 {
2085 if (sdp)
2086 {
2087 if (reliable)
2088 {
2089 return OnInviteReliableOffer;
2090 }
2091 else
2092 {
2093 return OnInviteOffer;
2094 }
2095 }
2096 else
2097 {
2098 if (reliable)
2099 {
2100 return OnInviteReliable;
2101 }
2102 else
2103 {
2104 return OnInvite;
2105 }
2106 }
2107 }
2108 else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer.
2109 {
2110 if (reliable)
2111 {
2112 if (sdp)
2113 {
2114 if (sentOffer)
2115 {
2116 return On1xxAnswer;
2117 }
2118 else
2119 {
2120 return On1xxOffer;
2121 }
2122 }
2123 else
2124 {
2125 return On1xx;
2126 }
2127 }
2128 else
2129 {
2130 if (sdp)
2131 {
2132 return On1xxEarly;
2133 }
2134 else
2135 {
2136 return On1xx;
2137 }
2138 }
2139 }
2140 else if (method == INVITE && code >= 200 && code < 300)
2141 {
2142 if (sdp)
2143 {
2144 if (sentOffer)
2145 {
2146 return On2xxAnswer;
2147 }
2148 else
2149 {
2150 return On2xxOffer;
2151 }
2152 }
2153 else
2154 {
2155 return On2xx;
2156 }
2157 }
2158 else if (method == INVITE && code == 422)
2159 {
2160 return On422Invite;
2161 }
2162 else if (method == INVITE && code == 487)
2163 {
2164 return On487Invite;
2165 }
2166 else if (method == INVITE && code == 489)
2167 {
2168 return On489Invite;
2169 }
2170 else if (method == INVITE && code == 491)
2171 {
2172 return On491Invite;
2173 }
2174 else if (method == INVITE && code >= 400)
2175 {
2176 return OnInviteFailure;
2177 }
2178 else if (method == ACK)
2179 {
2180 if (sdp)
2181 {
2182 return OnAckAnswer;
2183 }
2184 else
2185 {
2186 return OnAck;
2187 }
2188 }
2189 else if (method == CANCEL && code == 0)
2190 {
2191 return OnCancel;
2192 }
2193 else if (method == CANCEL && code / 200 == 1)
2194 {
2195 return On200Cancel;
2196 }
2197 else if (method == CANCEL && code >= 400)
2198 {
2199 return OnCancelFailure;
2200 }
2201 else if (method == BYE && code == 0)
2202 {
2203 return OnBye;
2204 }
2205 else if (method == BYE && code / 200 == 1)
2206 {
2207 return On200Bye;
2208 }
2209 else if (method == PRACK && code == 0)
2210 {
2211 return OnPrack;
2212 }
2213 else if (method == PRACK && code / 200 == 1)
2214 {
2215 return On200Prack;
2216 }
2217 else if (method == UPDATE && code == 0)
2218 {
2219 if (sdp)
2220 {
2221 return OnUpdateOffer;
2222 }
2223 else
2224 {
2225 return OnUpdate;
2226 }
2227 }
2228 else if (method == UPDATE && code / 200 == 1)
2229 {
2230 return On200Update;
2231 }
2232 else if (method == UPDATE && code == 422)
2233 {
2234 return On422Update;
2235 }
2236 else if (method == UPDATE && code == 489)
2237 {
2238 return On489Update;
2239 }
2240 else if (method == UPDATE && code == 491)
2241 {
2242 return On491Update;
2243 }
2244 else if (method == UPDATE && code >= 400)
2245 {
2246 return OnUpdateRejected;
2247 }
2248 else
2249 {
2250 //assert(0); // dispatchOthers will throw if the message type is really unknown
2251 return Unknown;
2252 }
2253 }
2254
2255 void InviteSession::sendAck(SipMessage& originalInvite, const SdpContents *sdp)
2256 {
2257 SipMessage ack;
2258
2259 assert(mAcks.count(originalInvite.header(h_CSeq).sequence()) == 0);
2260
2261 mDialog.makeRequest(ack, ACK);
2262
2263 // Copy Authorization, Proxy Authorization headers and CSeq from original Invite
2264 if(originalInvite.exists(h_Authorizations))
2265 {
2266 ack.header(h_Authorizations) = originalInvite.header(h_Authorizations);
2267 }
2268 if(originalInvite.exists(h_ProxyAuthorizations))
2269 {
2270 ack.header(h_ProxyAuthorizations) = originalInvite.header(h_ProxyAuthorizations);
2271 }
2272 ack.header(h_CSeq).sequence() = originalInvite.header(h_CSeq).sequence();
2273
2274 if(sdp != 0)
2275 {
2276 setSdp(ack, *sdp);
2277 }
2278 mAcks[ack.header(h_CSeq).sequence()] = ack;
2279 mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack.header(h_CSeq).sequence());
2280
2281 InfoLog (<< "Sending " << ack.brief());
2282 send(ack);
2283 }
2284
2285 void InviteSession::sendBye()
2286 {
2287 SipMessage bye;
2288 mDialog.makeRequest(bye, BYE);
2289 Data reason;
2290 if (mEndReason != NotSpecified)
2291 {
2292 reason = getEndReasonString(mEndReason);
2293 bye.header(h_Reasons).push_back(Token(reason));
2294 }
2295
2296 InfoLog (<< myAddr() << " Sending BYE " << reason);
2297 send(bye);
2298 }
2299
2300 DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg)
2301 {
2302 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
2303 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
2304 if (secAttr)
2305 {
2306 SignatureStatus sig = secAttr->getSignatureStatus();
2307 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
2308 bool encrypted = secAttr->isEncrypted();
2309 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
2310 else if (encrypted) level = DialogUsageManager::Encrypt;
2311 else if (sign) level = DialogUsageManager::Sign;
2312 }
2313 return level;
2314 }
2315
2316 void InviteSession::setCurrentLocalSdp(const SipMessage& msg)
2317 {
2318 assert(mProposedLocalSdp.get());
2319 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2320 {
2321 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
2322 {
2323 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone()));
2324 }
2325 else
2326 {
2327 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone()));
2328 }
2329 }
2330 else
2331 {
2332 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
2333 }
2334 mProposedLocalSdp.reset();
2335 }
2336
2337 void InviteSession::onReadyToSend(SipMessage& msg)
2338 {
2339 mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
2340 }
2341
2342 /* ====================================================================
2343 * The Vovida Software License, Version 1.0
2344 *
2345 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2346 *
2347 * Redistribution and use in source and binary forms, with or without
2348 * modification, are permitted provided that the following conditions
2349 * are met:
2350 *
2351 * 1. Redistributions of source code must retain the above copyright
2352 * notice, this list of conditions and the following disclaimer.
2353 *
2354 * 2. Redistributions in binary form must reproduce the above copyright
2355 * notice, this list of conditions and the following disclaimer in
2356 * the documentation and/or other materials provided with the
2357
2358 * distribution.
2359 *
2360 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2361 * and "Vovida Open Communication Application Library (VOCAL)" must
2362 * not be used to endorse or promote products derived from this
2363 * software without prior written permission. For written
2364 * permission, please contact vocal@vovida.org.
2365 *
2366 * 4. Products derived from this software may not be called "VOCAL", nor
2367 * may "VOCAL" appear in their name, without prior written
2368 * permission of Vovida Networks, Inc.
2369 *
2370 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2371 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2372 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2373 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2374 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2375 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2376 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2377 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2378 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2379 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2380 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2381 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2382 * DAMAGE.
2383 *
2384 * ====================================================================
2385 *
2386 * This software consists of voluntary contributions made by Vovida
2387 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2388 * Inc. For more information on Vovida Networks, Inc., please see
2389 * <http://www.vovida.org/>.
2390 *
2391 */
2392

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27