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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9033 - (show annotations) (download)
Sun Feb 27 17:17:15 2011 UTC (8 years, 9 months ago) by sgodin
File MIME type: text/plain
File size: 92972 byte(s)
-merge work from b-client-outbound-20110213 - client outbound support (RFC 5626)
   - New UserProfile settings
      - clientOutboundEnabled
      - setRegId
   - UserProfile now tracks flow used at registration time if server indicates outbound support, and 
     all usages that are assigned the same UserProfile will use this flow
   - ;ob parameter is added to contact headers of non-REGISTER requests if clientOutboundEnabled
   - ;reg-id parameter is added to contact headers of REGISTER requests if configured
   - ;+sip.instance is added to all contact headers if configured
   - ClientRegistration tagContact is now static and is used in RegistrationCreator for consistency
   - Keep alive pong responses are now routed from Stack to DUM Keepalive Manager
   - DUM Keep alive manager will terminate flows if a pong response is not received from 
     an outbound enabled connection after a default of 10 seconds
   -removed a bunch of non-implemented methods from DialogUsageManager.hxx
   -optimized some accesses to user profile from usages
   -added new makeInviteSession calls that accept an InviteSessionHandle and add an appropriate replaces header
   -treat internal 503 errors the same as 408 errors when dispatching onRequestRetry callback for
    ClientRegistration, ClientSubscription and ClientPublication
      - allows retry logic that is consistent when using both UDP or TCP/TLS transports
      - note:  TCP/TLS transports get a 503 error when they cannot connect, UDP transports typically
               get a 408 error when the far end is not present
   -ClientRegistration changes to ensure calling requestRefresh will not assert in any state
      - allow calling requestRefresh while a retry timer is running to request an immediate retry 
   -created onFlowTerminated callbacks on:
      - ClientRegistrationHandler - default implementation is to retry registration immediately
      - InviteSessionHandler - current default implementation is to do nothing
      - ServerSubscriptionHandler - default implementation is to end the Subscription
      - ClientSubscriptionHandler - default implementation is to reSubscribe (new Dialog)
   -fix for ContactInstanceRecord equality checks - registration server was not treating contacts with the same
    instance id as equal if the contact URI was different
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/BaseCreator.hxx"
7 #include "resip/dum/Dialog.hxx"
8 #include "resip/dum/DialogEventStateManager.hxx"
9 #include "resip/dum/DialogUsageManager.hxx"
10 #include "resip/dum/InviteSession.hxx"
11 #include "resip/dum/ServerInviteSession.hxx"
12 #include "resip/dum/ClientSubscription.hxx"
13 #include "resip/dum/ServerSubscription.hxx"
14 #include "resip/dum/ClientInviteSession.hxx"
15 #include "resip/dum/InviteSessionHandler.hxx"
16 #include "resip/dum/MasterProfile.hxx"
17 #include "resip/dum/UsageUseException.hxx"
18 #include "resip/dum/DumHelper.hxx"
19 #include "rutil/Inserter.hxx"
20 #include "rutil/Logger.hxx"
21 #include "rutil/MD5Stream.hxx"
22 #include "rutil/Timer.hxx"
23 #include "rutil/Random.hxx"
24 #include "rutil/compat.hxx"
25 #include "rutil/WinLeakCheck.hxx"
26
27 // Remove warning about 'this' use in initiator list - pointer is only stored
28 #if defined(WIN32) && !defined(__GNUC__)
29 #pragma warning( disable : 4355 ) // using this in base member initializer list
30 #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
31 #endif
32
33 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
34 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
35
36 using namespace resip;
37 using namespace std;
38
39 Data EndReasons[] =
40 {
41 "Not Specified",
42 "User Hung Up",
43 "Application Rejected Sdp(usually no common codec)",
44 "Illegal Sdp Negotiation",
45 "ACK not received",
46 "Session Timer Expired",
47 "Stale re-Invite"
48 };
49
50 const Data& getEndReasonString(InviteSession::EndReason reason)
51 {
52 assert(reason >= InviteSession::NotSpecified && reason < InviteSession::ENDREASON_MAX); //!dcm! -- necessary?
53 return EndReasons[reason];
54 }
55
56 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
57 : DialogUsage(dum, dialog),
58 mState(Undefined),
59 mNitState(NitComplete),
60 mServerNitState(NitComplete),
61 mLastLocalSessionModification(new SipMessage),
62 mLastRemoteSessionModification(new SipMessage),
63 mInvite200(new SipMessage),
64 mLastNitResponse(new SipMessage),
65 mCurrentRetransmit200(0),
66 mStaleReInviteTimerSeq(1),
67 mSessionInterval(0),
68 mMinSE(90),
69 mSessionRefresher(false),
70 mSessionTimerSeq(0),
71 mSessionRefreshReInvite(false),
72 mReferSub(true),
73 mCurrentEncryptionLevel(DialogUsageManager::None),
74 mProposedEncryptionLevel(DialogUsageManager::None),
75 mEndReason(NotSpecified)
76 {
77 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
78 assert(mDum.mInviteSessionHandler);
79 }
80
81 InviteSession::~InviteSession()
82 {
83 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
84 mDialog.mInviteSession = 0;
85 while(!mNITQueue.empty())
86 {
87 delete mNITQueue.front();
88 mNITQueue.pop();
89 }
90 }
91
92 void
93 InviteSession::dialogDestroyed(const SipMessage& msg)
94 {
95 assert(0);
96
97 // !jf! Is this correct? Merged from main...
98 // !jf! what reason - guessed for now?
99 //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);
100 //delete this;
101 }
102
103 bool
104 InviteSession::hasLocalOfferAnswer() const
105 {
106 return (mCurrentLocalOfferAnswer.get());
107 }
108
109 const Contents&
110 InviteSession::getLocalOfferAnswer() const
111 {
112 if(mCurrentLocalOfferAnswer.get())
113 {
114 return *mCurrentLocalOfferAnswer;
115 }
116 else
117 {
118 return SdpContents::Empty;
119 }
120 }
121
122 bool
123 InviteSession::hasRemoteOfferAnswer() const
124 {
125 return (mCurrentRemoteOfferAnswer.get());
126 }
127
128 const Contents&
129 InviteSession::getRemoteOfferAnswer() const
130 {
131 if(mCurrentRemoteOfferAnswer.get())
132 {
133 return *mCurrentRemoteOfferAnswer;
134 }
135 else
136 {
137 return SdpContents::Empty;
138 }
139 }
140
141 bool
142 InviteSession::hasProposedRemoteOfferAnswer() const
143 {
144 return (mProposedRemoteOfferAnswer.get());
145 }
146
147 const Contents&
148 InviteSession::getProposedRemoteOfferAnswer() const
149 {
150 if(mProposedRemoteOfferAnswer.get())
151 {
152 return *mProposedRemoteOfferAnswer;
153 }
154 else
155 {
156 return SdpContents::Empty;
157 }
158 }
159
160 bool
161 InviteSession::hasLocalSdp() const
162 {
163 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
164 return (mCurrentLocalOfferAnswer.get());
165 }
166
167 const SdpContents&
168 InviteSession::getLocalSdp() const
169 {
170 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
171 if(mCurrentLocalOfferAnswer.get())
172 {
173 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentLocalOfferAnswer.get());
174 assert(sdp);
175 return *sdp;
176 }
177 else
178 {
179 return SdpContents::Empty;
180 }
181 }
182
183 bool
184 InviteSession::hasRemoteSdp() const
185 {
186 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
187 return (mCurrentRemoteOfferAnswer.get());
188 }
189
190 const SdpContents&
191 InviteSession::getRemoteSdp() const
192 {
193 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
194 if(mCurrentRemoteOfferAnswer.get())
195 {
196 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentRemoteOfferAnswer.get());
197 assert(sdp);
198 return *sdp;
199 }
200 else
201 {
202 return SdpContents::Empty;
203 }
204 }
205
206 bool
207 InviteSession::hasProposedRemoteSdp() const
208 {
209 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
210 return (mProposedRemoteOfferAnswer.get());
211 }
212
213 const SdpContents&
214 InviteSession::getProposedRemoteSdp() const
215 {
216 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
217 if(mProposedRemoteOfferAnswer.get())
218 {
219 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mProposedRemoteOfferAnswer.get());
220 assert(sdp);
221 return *sdp;
222 }
223 else
224 {
225 return SdpContents::Empty;
226 }
227 }
228
229 InviteSessionHandle
230 InviteSession::getSessionHandle()
231 {
232 return InviteSessionHandle(mDum, getBaseHandle().getId());
233 }
234
235 void InviteSession::storePeerCapabilities(const SipMessage& msg)
236 {
237 if (msg.exists(h_Allows))
238 {
239 mPeerSupportedMethods = msg.header(h_Allows);
240 }
241 if (msg.exists(h_Supporteds))
242 {
243 mPeerSupportedOptionTags = msg.header(h_Supporteds);
244 }
245 if (msg.exists(h_AcceptEncodings))
246 {
247 mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
248 }
249 if (msg.exists(h_AcceptLanguages))
250 {
251 mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
252 }
253 if (msg.exists(h_AllowEvents))
254 {
255 mPeerAllowedEvents = msg.header(h_AllowEvents);
256 }
257 if (msg.exists(h_Accepts))
258 {
259 mPeerSupportedMimeTypes = msg.header(h_Accepts);
260 }
261 if (msg.exists(h_UserAgent))
262 {
263 mPeerUserAgent = msg.header(h_UserAgent).value();
264 }
265 }
266
267 bool
268 InviteSession::updateMethodSupported() const
269 {
270 // Check if Update is supported locally
271 if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
272 {
273 // Check if peer supports UPDATE
274 return mPeerSupportedMethods.find(Token("UPDATE"));
275 }
276 return false;
277 }
278
279 bool
280 InviteSession::isConnected() const
281 {
282 switch (mState)
283 {
284 case Connected:
285 case SentUpdate:
286 case SentUpdateGlare:
287 case SentReinvite:
288 case SentReinviteGlare:
289 case SentReinviteNoOffer:
290 case SentReinviteAnswered:
291 case SentReinviteNoOfferGlare:
292 case ReceivedUpdate:
293 case ReceivedReinvite:
294 case ReceivedReinviteNoOffer:
295 case ReceivedReinviteSentOffer:
296 case Answered:
297 case WaitingToOffer:
298 case WaitingToRequestOffer:
299 return true;
300
301 default:
302 return false;
303 }
304 }
305
306 bool
307 InviteSession::isEarly() const
308 {
309 switch (mState)
310 {
311 case UAC_Early:
312 case UAC_EarlyWithOffer:
313 case UAC_EarlyWithAnswer:
314 case UAC_SentUpdateEarly:
315 case UAC_ReceivedUpdateEarly:
316 case UAC_SentAnswer:
317 case UAC_QueuedUpdate:
318 return true;
319 default:
320 return false;
321 }
322 }
323
324 bool
325 InviteSession::isAccepted() const
326 {
327 switch (mState)
328 {
329 case UAS_Start:
330 case UAS_Offer:
331 case UAS_NoOffer:
332 case UAS_NoOfferReliable:
333 case UAS_ProvidedOffer:
334 case UAS_OfferProvidedAnswer:
335 case UAS_EarlyOffer:
336 case UAS_EarlyProvidedOffer:
337 case UAS_EarlyProvidedAnswer:
338 case UAS_EarlyNoOffer:
339 case UAS_FirstSentAnswerReliable:
340 case UAS_FirstSentOfferReliable:
341 case UAS_NegotiatedReliable:
342 return false;
343 default:
344 return true;
345 }
346 }
347
348 bool
349 InviteSession::isTerminated() const
350 {
351 switch (mState)
352 {
353 case Terminated:
354 case WaitingToTerminate:
355 case WaitingToHangup:
356 case UAC_Cancelled:
357 case UAS_WaitingToTerminate:
358 case UAS_WaitingToHangup:
359 return true;
360 default:
361 return false;
362 }
363 }
364
365 EncodeStream&
366 InviteSession::dump(EncodeStream& strm) const
367 {
368 strm << "INVITE: " << mId
369 << " " << toData(mState)
370 << " ADDR=" << myAddr()
371 << " PEER=" << peerAddr();
372 return strm;
373 }
374
375 void
376 InviteSession::requestOffer()
377 {
378 switch (mState)
379 {
380 case Connected:
381 case WaitingToRequestOffer:
382 case UAS_WaitingToRequestOffer:
383 transition(SentReinviteNoOffer);
384 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
385 startStaleReInviteTimer();
386 mLastLocalSessionModification->setContents(0); // Clear the contents from the INVITE
387 setSessionTimerHeaders(*mLastLocalSessionModification);
388
389 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
390
391 // call send to give app an chance to adorn the message.
392 send(mLastLocalSessionModification);
393 break;
394
395 case Answered:
396 // queue the offer to be sent after the ACK is received
397 transition(WaitingToRequestOffer);
398 break;
399
400 // ?slg? Can we handle all of the states listed in isConnected() ???
401 default:
402 WarningLog (<< "Can't requestOffer when not in Connected state");
403 throw DialogUsage::Exception("Can't request an offer", __FILE__,__LINE__);
404 }
405 }
406
407 void
408 InviteSession::provideOffer(const Contents& offer,
409 DialogUsageManager::EncryptionLevel level,
410 const Contents* alternative)
411 {
412 switch (mState)
413 {
414 case Connected:
415 case WaitingToOffer:
416 case UAS_WaitingToOffer:
417 transition(SentReinvite);
418 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
419 startStaleReInviteTimer();
420
421 setSessionTimerHeaders(*mLastLocalSessionModification);
422
423 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
424 InviteSession::setOfferAnswer(*mLastLocalSessionModification, offer, alternative);
425 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
426 mProposedEncryptionLevel = level;
427 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
428
429 // call send to give app an chance to adorn the message.
430 send(mLastLocalSessionModification);
431 break;
432
433 case Answered:
434 // queue the offer to be sent after the ACK is received
435 transition(WaitingToOffer);
436 mProposedEncryptionLevel = level;
437 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
438 break;
439
440 case ReceivedReinviteNoOffer:
441 assert(!mProposedRemoteOfferAnswer.get());
442 transition(ReceivedReinviteSentOffer);
443 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
444 handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
445 InviteSession::setOfferAnswer(*mInvite200, offer, 0);
446 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer);
447
448 InfoLog (<< "Sending " << mInvite200->brief());
449 DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
450 send(mInvite200);
451 startRetransmit200Timer();
452 break;
453
454 default:
455 WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
456 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
457 }
458 }
459
460 class InviteSessionProvideOfferExCommand : public DumCommandAdapter
461 {
462 public:
463 InviteSessionProvideOfferExCommand(InviteSession& inviteSession,
464 const Contents& offer,
465 DialogUsageManager::EncryptionLevel level,
466 const Contents* alternative)
467 : mInviteSession(inviteSession),
468 mOffer(offer.clone()),
469 mLevel(level),
470 mAlternative(alternative ? alternative->clone() : 0)
471 {
472 }
473
474 virtual void executeCommand()
475 {
476 mInviteSession.provideOffer(*mOffer, mLevel, mAlternative.get());
477 }
478
479 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
480 {
481 return strm << "InviteSessionProvideOfferExCommand";
482 }
483 private:
484 InviteSession& mInviteSession;
485 std::auto_ptr<const Contents> mOffer;
486 DialogUsageManager::EncryptionLevel mLevel;
487 std::auto_ptr<const Contents> mAlternative;
488 };
489
490 void
491 InviteSession::provideOfferCommand(const Contents& offer, DialogUsageManager::EncryptionLevel level, const Contents* alternative)
492 {
493 mDum.post(new InviteSessionProvideOfferExCommand(*this, offer, level, alternative));
494 }
495
496 void
497 InviteSession::provideOffer(const Contents& offer)
498 {
499 return provideOffer(offer, mCurrentEncryptionLevel, 0);
500 }
501
502 class InviteSessionProvideOfferCommand : public DumCommandAdapter
503 {
504 public:
505 InviteSessionProvideOfferCommand(InviteSession& inviteSession, const Contents& offer)
506 : mInviteSession(inviteSession),
507 mOffer(offer.clone())
508 {
509 }
510
511 virtual void executeCommand()
512 {
513 mInviteSession.provideOffer(*mOffer);
514 }
515
516 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
517 {
518 return strm << "InviteSessionProvideOfferCommand";
519 }
520 private:
521 InviteSession& mInviteSession;
522 std::auto_ptr<const Contents> mOffer;
523 };
524
525 void
526 InviteSession::provideOfferCommand(const Contents& offer)
527 {
528 mDum.post(new InviteSessionProvideOfferCommand(*this, offer));
529 }
530
531 void
532 InviteSession::provideAnswer(const Contents& answer)
533 {
534 switch (mState)
535 {
536 case ReceivedReinvite:
537 transition(Connected);
538 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
539 handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
540 InviteSession::setOfferAnswer(*mInvite200, answer, 0);
541 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
542 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
543 InfoLog (<< "Sending " << mInvite200->brief());
544 DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
545 send(mInvite200);
546 startRetransmit200Timer();
547 break;
548
549 case ReceivedUpdate: // same as ReceivedReinvite case.
550 {
551 transition(Connected);
552
553 SharedPtr<SipMessage> response(new SipMessage);
554 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
555 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
556 InviteSession::setOfferAnswer(*response, answer, 0);
557 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
558 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
559 InfoLog (<< "Sending " << response->brief());
560 DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
561 send(response);
562 break;
563 }
564
565 case SentReinviteAnswered:
566 transition(Connected);
567 sendAck(&answer);
568
569 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
570 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
571 break;
572
573 default:
574 WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
575 throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
576 }
577 }
578
579 class InviteSessionProvideAnswerCommand : public DumCommandAdapter
580 {
581 public:
582 InviteSessionProvideAnswerCommand(InviteSession& inviteSession, const Contents& answer)
583 : mInviteSession(inviteSession),
584 mAnswer(answer.clone())
585 {
586 }
587
588 virtual void executeCommand()
589 {
590 mInviteSession.provideAnswer(*mAnswer);
591 }
592
593 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
594 {
595 return strm << "InviteSessionProvideAnswerCommand";
596 }
597 private:
598 InviteSession& mInviteSession;
599 std::auto_ptr<const Contents> mAnswer;
600 };
601
602 void
603 InviteSession::provideAnswerCommand(const Contents& answer)
604 {
605 mDum.post(new InviteSessionProvideAnswerCommand(*this, answer));
606 }
607
608 void
609 InviteSession::end()
610 {
611 end(NotSpecified);
612 }
613
614 void
615 InviteSession::end(EndReason reason)
616 {
617 if (mEndReason == NotSpecified)
618 {
619 mEndReason = reason;
620 }
621
622 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
623
624 switch (mState)
625 {
626 case Connected:
627 case SentUpdate:
628 case SentUpdateGlare:
629 case SentReinviteGlare:
630 case SentReinviteNoOfferGlare:
631 case SentReinviteAnswered:
632 {
633 // !jf! do we need to store the BYE somewhere?
634 sendBye();
635 transition(Terminated);
636 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
637 break;
638 }
639
640 case SentReinvite:
641 case SentReinviteNoOffer:
642 transition(WaitingToTerminate);
643 break;
644
645 case Answered:
646 case WaitingToOffer:
647 case WaitingToRequestOffer:
648 case ReceivedReinviteSentOffer:
649 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet - wait for it
650 {
651 transition(WaitingToHangup);
652 }
653 else
654 {
655 // ACK has likely timedout - hangup immediately
656 sendBye();
657 transition(Terminated);
658 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
659 }
660 break;
661
662 case ReceivedUpdate:
663 case ReceivedReinvite:
664 case ReceivedReinviteNoOffer:
665 {
666 SharedPtr<SipMessage> response(new SipMessage);
667 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 488);
668 InfoLog (<< "Sending " << response->brief());
669 send(response);
670
671 sendBye();
672 transition(Terminated);
673 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
674 break;
675 }
676
677 case WaitingToTerminate: // ?slg? Why is this here?
678 {
679 sendBye();
680 transition(Terminated);
681 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
682 break;
683 }
684
685 case Terminated:
686 // no-op.
687 break;
688
689 default:
690 assert(0);
691 break;
692 }
693 }
694
695 class InviteSessionEndCommand : public DumCommandAdapter
696 {
697 public:
698 InviteSessionEndCommand(InviteSession& inviteSession, InviteSession::EndReason reason)
699 : mInviteSession(inviteSession),
700 mReason(reason)
701 {
702 }
703
704 virtual void executeCommand()
705 {
706 mInviteSession.end(mReason);
707 }
708
709 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
710 {
711 return strm << "InviteSessionEndCommand";
712 }
713 private:
714 InviteSession& mInviteSession;
715 InviteSession::EndReason mReason;
716 };
717
718 void
719 InviteSession::endCommand(EndReason reason)
720 {
721 mDum.post(new InviteSessionEndCommand(*this, reason));
722 }
723
724 void
725 InviteSession::reject(int statusCode, WarningCategory *warning)
726 {
727 switch (mState)
728 {
729 case ReceivedUpdate:
730 case ReceivedReinvite:
731 case ReceivedReinviteNoOffer:
732 {
733 transition(Connected);
734
735 SharedPtr<SipMessage> response(new SipMessage);
736 mDialog.makeResponse(*response, *mLastRemoteSessionModification, statusCode);
737 if(warning)
738 {
739 response->header(h_Warnings).push_back(*warning);
740 }
741 InfoLog (<< "Sending " << response->brief());
742 send(response);
743 break;
744 }
745
746 default:
747 assert(0);
748 break;
749 }
750 }
751
752 class InviteSessionRejectCommand : public DumCommandAdapter
753 {
754 public:
755 InviteSessionRejectCommand(InviteSession& inviteSession, int code, WarningCategory* warning)
756 : mInviteSession(inviteSession),
757 mCode(code),
758 mWarning(warning?new WarningCategory(*warning):0)
759 {
760 }
761
762 virtual void executeCommand()
763 {
764 mInviteSession.reject(mCode, mWarning.get());
765 }
766
767 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
768 {
769 return strm << "InviteSessionRejectCommand";
770 }
771 private:
772 InviteSession& mInviteSession;
773 int mCode;
774 std::auto_ptr<WarningCategory> mWarning;
775 };
776
777 void
778 InviteSession::rejectCommand(int code, WarningCategory *warning)
779 {
780 mDum.post(new InviteSessionRejectCommand(*this, code, warning));
781 }
782
783 void
784 InviteSession::targetRefresh(const NameAddr& localUri)
785 {
786 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
787 {
788 mDialog.mLocalContact = localUri;
789 sessionRefresh();
790 }
791 else
792 {
793 WarningLog (<< "Can't targetRefresh before Connected");
794 throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
795 }
796 }
797
798 void
799 InviteSession::refer(const NameAddr& referTo, bool referSub)
800 {
801 refer(referTo,std::auto_ptr<resip::Contents>(0),referSub);
802 }
803 void
804 InviteSession::refer(const NameAddr& referTo, std::auto_ptr<resip::Contents> contents,bool referSub)
805 {
806 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
807 {
808 SharedPtr<SipMessage> refer(new SipMessage());
809 mDialog.makeRequest(*refer, REFER);
810 refer->header(h_ReferTo) = referTo;
811 refer->header(h_ReferredBy) = myAddr();
812 refer->header(h_ReferredBy).remove(p_tag); // tag-param not permitted in rfc3892; not the same as generic-param
813 refer->setContents(contents);
814 if (!referSub)
815 {
816 refer->header(h_ReferSub).value() = "false";
817 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
818 }
819
820 if(mNitState == NitComplete)
821 {
822 mNitState = NitProceeding;
823 mReferSub = referSub;
824 mLastSentNITRequest = refer;
825 send(refer);
826 return;
827 }
828 mNITQueue.push(new QueuedNIT(refer,referSub));
829 InfoLog(<< "refer - queuing NIT:" << refer->brief());
830 return;
831 }
832 else
833 {
834 WarningLog (<< "Can't refer before Connected");
835 assert(0);
836 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
837 }
838 }
839
840 const SharedPtr<SipMessage>
841 InviteSession::getLastSentNITRequest() const
842 {
843 return mLastSentNITRequest;
844 }
845
846 void
847 InviteSession::nitComplete()
848 {
849 mNitState = NitComplete;
850 if (mNITQueue.size())
851 {
852 QueuedNIT *qn=mNITQueue.front();
853 mNITQueue.pop();
854 mNitState = NitProceeding;
855 mReferSub = qn->referSubscription();
856 mLastSentNITRequest = qn->getNIT();
857 InfoLog(<< "checkNITQueue - sending queued NIT:" << mLastSentNITRequest->brief());
858 send(mLastSentNITRequest);
859 delete qn;
860 }
861 }
862
863 class InviteSessionReferCommand : public DumCommandAdapter
864 {
865 public:
866 InviteSessionReferCommand(InviteSession& inviteSession, const NameAddr& referTo, bool referSub)
867 : mInviteSession(inviteSession),
868 mReferTo(referTo),
869 mReferSub(referSub)
870 {
871
872 }
873
874 virtual void executeCommand()
875 {
876 mInviteSession.refer(mReferTo, mReferSub);
877 }
878
879 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
880 {
881 return strm << "InviteSessionReferCommand";
882 }
883
884 private:
885 InviteSession& mInviteSession;
886 NameAddr mReferTo;
887 bool mReferSub;
888 };
889
890 void
891 InviteSession::referCommand(const NameAddr& referTo, bool referSub)
892 {
893 mDum.post(new InviteSessionReferCommand(*this, referTo, referSub));
894 }
895
896 void
897 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
898 {
899 refer(referTo,sessionToReplace,std::auto_ptr<resip::Contents>(0),referSub);
900 }
901
902 void
903 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, std::auto_ptr<resip::Contents> contents, bool referSub)
904 {
905 if (!sessionToReplace.isValid())
906 {
907 throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
908 }
909
910 CallId replaces;
911 DialogId id = sessionToReplace->mDialog.getId();
912 replaces.value() = id.getCallId();
913 replaces.param(p_toTag) = id.getRemoteTag();
914 replaces.param(p_fromTag) = id.getLocalTag();
915
916 refer(referTo, replaces, contents, referSub);
917 }
918
919 void
920 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, bool referSub)
921 {
922 refer(referTo,replaces,std::auto_ptr<resip::Contents>(0),referSub);
923 }
924
925 void
926 InviteSession::refer(const NameAddr& referTo, const CallId& replaces, std::auto_ptr<resip::Contents> contents, bool referSub)
927 {
928 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
929 {
930 SharedPtr<SipMessage> refer(new SipMessage());
931 mDialog.makeRequest(*refer, REFER);
932 refer->setContents(contents);
933 refer->header(h_ReferTo) = referTo;
934 refer->header(h_ReferredBy) = myAddr();
935 refer->header(h_ReferredBy).remove(p_tag);
936
937 refer->header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
938
939 if (!referSub)
940 {
941 refer->header(h_ReferSub).value() = "false";
942 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
943 }
944
945 if(mNitState == NitComplete)
946 {
947 mNitState = NitProceeding;
948 mReferSub = referSub;
949 mLastSentNITRequest = refer;
950 send(refer);
951 return;
952 }
953 mNITQueue.push(new QueuedNIT(refer,referSub));
954 InfoLog(<< "refer/replace - queuing NIT:" << refer->brief());
955 return;
956 }
957 else
958 {
959 WarningLog (<< "Can't refer before Connected");
960 assert(0);
961 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
962 }
963 }
964
965 class InviteSessionReferExCommand : public DumCommandAdapter
966 {
967 public:
968 InviteSessionReferExCommand(InviteSession& inviteSession, const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
969 : mInviteSession(inviteSession),
970 mSessionToReplace(sessionToReplace),
971 mReferTo(referTo),
972 mReferSub(referSub)
973 {
974 }
975
976 virtual void executeCommand()
977 {
978 mInviteSession.referCommand(mReferTo, mSessionToReplace, mReferSub);
979 }
980
981 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
982 {
983 return strm << "InviteSessionReferExCommand";
984 }
985
986 private:
987 InviteSession& mInviteSession;
988 InviteSessionHandle mSessionToReplace;
989 NameAddr mReferTo;
990 bool mReferSub;
991 };
992
993 void
994 InviteSession::referCommand(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
995 {
996 mDum.post(new InviteSessionReferExCommand(*this, referTo, sessionToReplace, referSub));
997 }
998
999 void
1000 InviteSession::info(const Contents& contents)
1001 {
1002 SharedPtr<SipMessage> info(new SipMessage());
1003 mDialog.makeRequest(*info, INFO);
1004 // !jf! handle multipart here
1005 info->setContents(&contents);
1006 DumHelper::setOutgoingEncryptionLevel(*info, mCurrentEncryptionLevel);
1007 if (mNitState == NitComplete)
1008 {
1009 mNitState = NitProceeding;
1010 mLastSentNITRequest = info;
1011 send(info);
1012 return;
1013 }
1014 mNITQueue.push(new QueuedNIT(info));
1015 InfoLog(<< "info - queuing NIT:" << info->brief());
1016 return;
1017 }
1018
1019 class InviteSessionInfoCommand : public DumCommandAdapter
1020 {
1021 public:
1022 InviteSessionInfoCommand(InviteSession& inviteSession, const Contents& contents)
1023 : mInviteSession(inviteSession),
1024 mContents(contents.clone())
1025 {
1026 }
1027
1028 virtual void executeCommand()
1029 {
1030 mInviteSession.info(*mContents);
1031 }
1032
1033 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1034 {
1035 return strm << "InviteSessionInfoCommand";
1036 }
1037 private:
1038 InviteSession& mInviteSession;
1039 std::auto_ptr<Contents> mContents;
1040 };
1041
1042 void
1043 InviteSession::infoCommand(const Contents& contents)
1044 {
1045 mDum.post(new InviteSessionInfoCommand(*this, contents));
1046 }
1047
1048 void
1049 InviteSession::message(const Contents& contents)
1050 {
1051 SharedPtr<SipMessage> message(new SipMessage());
1052 mDialog.makeRequest(*message, MESSAGE);
1053 // !jf! handle multipart here
1054 message->setContents(&contents);
1055 DumHelper::setOutgoingEncryptionLevel(*message, mCurrentEncryptionLevel);
1056 InfoLog (<< "Trying to send MESSAGE: " << message);
1057 if (mNitState == NitComplete)
1058 {
1059 mNitState = NitProceeding;
1060 mLastSentNITRequest = message;
1061 send(message);
1062 return;
1063 }
1064 mNITQueue.push(new QueuedNIT(message));
1065 InfoLog(<< "message - queuing NIT:" << message->brief());
1066 return;
1067 }
1068
1069 class InviteSessionMessageCommand : public DumCommandAdapter
1070 {
1071 public:
1072 InviteSessionMessageCommand(InviteSession& inviteSession, const Contents& contents)
1073 : mInviteSession(inviteSession),
1074 mContents(contents.clone())
1075 {
1076 }
1077
1078 virtual void executeCommand()
1079 {
1080 mInviteSession.message(*mContents);
1081 }
1082
1083 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1084 {
1085 return strm << "InviteSessionMessageCommand";
1086 }
1087 private:
1088 InviteSession& mInviteSession;
1089 std::auto_ptr<Contents> mContents;
1090 };
1091
1092
1093 void
1094 InviteSession::messageCommand(const Contents& contents)
1095 {
1096 mDum.post(new InviteSessionMessageCommand(*this, contents));
1097 }
1098
1099 void
1100 InviteSession::dispatch(const SipMessage& msg)
1101 {
1102 // Look for 2xx retransmissions - resend ACK and filter out of state machine
1103 if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 100 == 2)
1104 {
1105 AckMap::iterator i = mAcks.find(msg.getTransactionId());
1106 if (i != mAcks.end())
1107 {
1108 send(i->second); // resend ACK
1109 return;
1110 }
1111 }
1112
1113 // !jf! do we need to handle 3xx here or is it handled elsewhere?
1114 switch (mState)
1115 {
1116 case Connected:
1117 dispatchConnected(msg);
1118 break;
1119 case SentUpdate:
1120 dispatchSentUpdate(msg);
1121 break;
1122 case SentReinvite:
1123 dispatchSentReinvite(msg);
1124 break;
1125 case SentReinviteNoOffer:
1126 dispatchSentReinviteNoOffer(msg);
1127 break;
1128 case SentReinviteAnswered:
1129 dispatchSentReinviteAnswered(msg);
1130 break;
1131 case SentUpdateGlare:
1132 case SentReinviteGlare:
1133 // The behavior is the same except for timer which is handled in dispatch(Timer)
1134 dispatchGlare(msg);
1135 break;
1136 case SentReinviteNoOfferGlare:
1137 dispatchReinviteNoOfferGlare(msg);
1138 break;
1139 case ReceivedUpdate:
1140 case ReceivedReinvite:
1141 case ReceivedReinviteNoOffer:
1142 dispatchReceivedUpdateOrReinvite(msg);
1143 break;
1144 case ReceivedReinviteSentOffer:
1145 dispatchReceivedReinviteSentOffer(msg);
1146 break;
1147 case Answered:
1148 dispatchAnswered(msg);
1149 break;
1150 case WaitingToOffer:
1151 dispatchWaitingToOffer(msg);
1152 break;
1153 case WaitingToRequestOffer:
1154 dispatchWaitingToRequestOffer(msg);
1155 break;
1156 case WaitingToTerminate:
1157 dispatchWaitingToTerminate(msg);
1158 break;
1159 case WaitingToHangup:
1160 dispatchWaitingToHangup(msg);
1161 break;
1162 case Terminated:
1163 dispatchTerminated(msg);
1164 break;
1165 case Undefined:
1166 default:
1167 assert(0);
1168 break;
1169 }
1170 }
1171
1172 void
1173 InviteSession::dispatch(const DumTimeout& timeout)
1174 {
1175 if (timeout.type() == DumTimeout::Retransmit200)
1176 {
1177 if (mCurrentRetransmit200)
1178 {
1179 InfoLog (<< "Retransmitting: " << endl << mInvite200->brief());
1180 //DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
1181 send(mInvite200);
1182 mCurrentRetransmit200 *= 2;
1183 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
1184 }
1185 }
1186 else if (timeout.type() == DumTimeout::WaitForAck)
1187 {
1188 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
1189 {
1190 if (timeout.seq() == mLastRemoteSessionModification->header(h_CSeq).sequence())
1191 {
1192 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1193
1194 // If we are waiting for an Ack and it times out, then end with a BYE
1195 if(mState == UAS_WaitingToHangup ||
1196 mState == WaitingToHangup)
1197 {
1198 sendBye();
1199 transition(Terminated);
1200 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1201 }
1202 else if(mState == ReceivedReinviteSentOffer)
1203 {
1204 transition(Connected);
1205 mProposedLocalOfferAnswer.reset();
1206 mProposedEncryptionLevel = DialogUsageManager::None;
1207 //!dcm! -- should this be onIllegalNegotiation?
1208 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
1209 }
1210 else if(mState == WaitingToOffer ||
1211 mState == UAS_WaitingToOffer)
1212 {
1213 assert(mProposedLocalOfferAnswer.get());
1214 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1215 if(!isTerminated())
1216 {
1217 provideProposedOffer();
1218 }
1219 }
1220 else if(mState == WaitingToRequestOffer ||
1221 mState == UAS_WaitingToRequestOffer)
1222 {
1223 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1224 if(!isTerminated())
1225 {
1226 requestOffer();
1227 }
1228 }
1229 else
1230 {
1231 // this is so the app can decided to ignore this. default implementation
1232 // will call end next
1233 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1234 }
1235 }
1236 }
1237 }
1238 else if (timeout.type() == DumTimeout::CanDiscardAck)
1239 {
1240 AckMap::iterator i = mAcks.find(timeout.transactionId());
1241 if (i != mAcks.end())
1242 {
1243 mAcks.erase(i);
1244 }
1245 }
1246 else if (timeout.type() == DumTimeout::Glare)
1247 {
1248 if (mState == SentUpdateGlare)
1249 {
1250 transition(SentUpdate);
1251
1252 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
1253 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE); // increments CSeq
1254 send(mLastLocalSessionModification);
1255 }
1256 else if (mState == SentReinviteGlare)
1257 {
1258 transition(SentReinvite);
1259
1260 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
1261 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1262 startStaleReInviteTimer();
1263 send(mLastLocalSessionModification);
1264 }
1265 else if (mState == SentReinviteNoOfferGlare)
1266 {
1267 transition(SentReinviteNoOffer);
1268
1269 InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
1270 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1271 startStaleReInviteTimer();
1272 send(mLastLocalSessionModification);
1273 }
1274 }
1275 else if (timeout.type() == DumTimeout::StaleReInvite)
1276 {
1277 if(timeout.seq() == mStaleReInviteTimerSeq)
1278 {
1279 if(mState == WaitingToTerminate)
1280 {
1281 sendBye();
1282 transition(Terminated);
1283 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1284 }
1285 else if(mState == SentReinvite ||
1286 mState == SentReinviteNoOffer)
1287 {
1288 transition(Connected);
1289 mProposedLocalOfferAnswer.reset();
1290 mProposedEncryptionLevel = DialogUsageManager::None;
1291
1292 // this is so the app can decide to ignore this. default implementation
1293 // will call end next - which will send a BYE
1294 mDum.mInviteSessionHandler->onStaleReInviteTimeout(getSessionHandle());
1295 }
1296 }
1297 }
1298 else if (timeout.type() == DumTimeout::SessionExpiration)
1299 {
1300 if(timeout.seq() == mSessionTimerSeq)
1301 {
1302 // this is so the app can decide to ignore this. default implementation
1303 // will call end next - which will send a BYE
1304 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
1305 }
1306 }
1307 else if (timeout.type() == DumTimeout::SessionRefresh)
1308 {
1309 if(timeout.seq() == mSessionTimerSeq)
1310 {
1311 // Note: If not connected then we must be issueing a reinvite/update or
1312 // receiving one - in either case the session timer stuff will get
1313 // reset/renegotiated - thus just ignore this referesh
1314 if(mState == Connected)
1315 {
1316 sessionRefresh();
1317 }
1318 }
1319 }
1320 }
1321
1322 void
1323 InviteSession::dispatchConnected(const SipMessage& msg)
1324 {
1325 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1326 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1327
1328 switch (toEvent(msg, offerAnswer.get()))
1329 {
1330 case OnInvite:
1331 case OnInviteReliable:
1332 *mLastRemoteSessionModification = msg;
1333 transition(ReceivedReinviteNoOffer);
1334 handler->onOfferRequired(getSessionHandle(), msg);
1335 break;
1336
1337 case OnInviteOffer:
1338 case OnInviteReliableOffer:
1339 *mLastRemoteSessionModification = msg;
1340 transition(ReceivedReinvite);
1341 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1342 mProposedRemoteOfferAnswer = offerAnswer;
1343
1344 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1345 break;
1346
1347 case On2xx:
1348 case On2xxOffer:
1349 case On2xxAnswer:
1350 // retransmission of 200I
1351 // !jf! Need to include the answer here.
1352 sendAck();
1353 break;
1354
1355 case OnUpdateOffer:
1356 transition(ReceivedUpdate);
1357
1358 // !kh!
1359 // Find out if it's an UPDATE requiring state change.
1360 // See rfc3311 5.2, 4th paragraph.
1361 *mLastRemoteSessionModification = msg;
1362 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1363 mProposedRemoteOfferAnswer = offerAnswer;
1364 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1365 break;
1366
1367 case OnUpdate:
1368 {
1369 // ?slg? no offerAnswer in update - just respond immediately (likely session timer) - do we need a callback?
1370 SharedPtr<SipMessage> response(new SipMessage);
1371 *mLastRemoteSessionModification = msg;
1372 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
1373 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1374 send(response);
1375 break;
1376 }
1377
1378 case OnUpdateRejected:
1379 case On200Update:
1380 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
1381 assert(0);
1382 break;
1383
1384 case OnAck:
1385 case OnAckAnswer: // .bwc. Don't drop ACK with SDP!
1386 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1387 handler->onAckReceived(getSessionHandle(), msg);
1388 break;
1389
1390 default:
1391 dispatchOthers(msg);
1392 break;
1393 }
1394 }
1395
1396 void
1397 InviteSession::dispatchSentUpdate(const SipMessage& msg)
1398 {
1399 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1400 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1401
1402 switch (toEvent(msg, offerAnswer.get()))
1403 {
1404 case OnInvite:
1405 case OnInviteReliable:
1406 case OnInviteOffer:
1407 case OnInviteReliableOffer:
1408 case OnUpdate:
1409 case OnUpdateOffer:
1410 {
1411 // glare
1412 SharedPtr<SipMessage> response(new SipMessage);
1413 mDialog.makeResponse(*response, msg, 491);
1414 send(response);
1415 break;
1416 }
1417
1418 case On200Update:
1419 transition(Connected);
1420 handleSessionTimerResponse(msg);
1421 if (offerAnswer.get() && mProposedLocalOfferAnswer.get())
1422 {
1423 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1424 setCurrentLocalOfferAnswer(msg);
1425
1426 mCurrentRemoteOfferAnswer = offerAnswer;
1427 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1428 }
1429 else if(mProposedLocalOfferAnswer.get())
1430 {
1431 // If we sent an offer in the Update Request and no answer is received
1432 handler->onIllegalNegotiation(getSessionHandle(), msg);
1433 mProposedLocalOfferAnswer.reset();
1434 mProposedEncryptionLevel = DialogUsageManager::None;
1435 }
1436 break;
1437
1438 case On491Update:
1439 transition(SentUpdateGlare);
1440 start491Timer();
1441 break;
1442
1443 case On422Update: // session timer
1444 if(msg.exists(h_MinSE))
1445 {
1446 // Change interval to min from 422 response
1447 mSessionInterval = msg.header(h_MinSE).value();
1448 mMinSE = mSessionInterval;
1449 sessionRefresh();
1450 }
1451 else
1452 {
1453 // Response must contain Min_SE - if not - just ignore
1454 // ?slg? callback?
1455 transition(Connected);
1456 mProposedLocalOfferAnswer.reset();
1457 mProposedEncryptionLevel = DialogUsageManager::None;
1458 }
1459 break;
1460
1461 case OnUpdateRejected:
1462 transition(Connected);
1463 mProposedLocalOfferAnswer.reset();
1464 handler->onOfferRejected(getSessionHandle(), &msg);
1465 break;
1466
1467 case OnGeneralFailure:
1468 sendBye();
1469 transition(Terminated);
1470 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1471 break;
1472
1473 default:
1474 dispatchOthers(msg);
1475 break;
1476 }
1477 }
1478
1479 void
1480 InviteSession::dispatchSentReinvite(const SipMessage& msg)
1481 {
1482 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1483 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1484
1485 switch (toEvent(msg, offerAnswer.get()))
1486 {
1487 case OnInvite:
1488 case OnInviteReliable:
1489 case OnInviteOffer:
1490 case OnInviteReliableOffer:
1491 case OnUpdate:
1492 case OnUpdateOffer:
1493 {
1494 SharedPtr<SipMessage> response(new SipMessage);
1495 mDialog.makeResponse(*response, msg, 491);
1496 send(response);
1497 break;
1498 }
1499
1500 case On1xx:
1501 case On1xxEarly:
1502 // Some UA's send a 100 response to a ReInvite - just ignore it
1503 break;
1504
1505 case On2xxAnswer:
1506 case On2xxOffer: // .slg. doesn't really make sense
1507 {
1508 mStaleReInviteTimerSeq++;
1509 transition(Connected);
1510 handleSessionTimerResponse(msg);
1511 setCurrentLocalOfferAnswer(msg);
1512
1513 // !jf! I need to potentially include an answer in the ACK here
1514 sendAck();
1515 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1516
1517 if (mSessionRefreshReInvite)
1518 {
1519 mSessionRefreshReInvite = false;
1520
1521 MD5Stream currentRemote;
1522 currentRemote<< *mCurrentRemoteOfferAnswer;
1523 MD5Stream newRemote;
1524 newRemote << *offerAnswer;
1525 bool changed = currentRemote.getHex() != newRemote.getHex();
1526
1527 if (changed)
1528 {
1529 mCurrentRemoteOfferAnswer = offerAnswer;
1530 handler->onRemoteAnswerChanged(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1531 }
1532 }
1533 else
1534 {
1535 mCurrentRemoteOfferAnswer = offerAnswer;
1536 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1537 }
1538
1539 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1540 // the ACK when a 200I is received? If yes, then I need to store all
1541 // ACK messages for 64*T1
1542 break;
1543 }
1544 case On2xx:
1545 mStaleReInviteTimerSeq++;
1546 sendAck();
1547 transition(Connected);
1548 handleSessionTimerResponse(msg);
1549 handler->onIllegalNegotiation(getSessionHandle(), msg);
1550 mProposedLocalOfferAnswer.reset();
1551 mProposedEncryptionLevel = DialogUsageManager::None;
1552 break;
1553
1554 case On422Invite:
1555 mStaleReInviteTimerSeq++;
1556 if(msg.exists(h_MinSE))
1557 {
1558 // Change interval to min from 422 response
1559 mSessionInterval = msg.header(h_MinSE).value();
1560 mMinSE = mSessionInterval;
1561 sessionRefresh();
1562 }
1563 else
1564 {
1565 // Response must contact Min_SE - if not - just ignore
1566 // ?slg? callback?
1567 transition(Connected);
1568 mProposedLocalOfferAnswer.reset();
1569 mProposedEncryptionLevel = DialogUsageManager::None;
1570 }
1571 break;
1572
1573 case On491Invite:
1574 mStaleReInviteTimerSeq++;
1575 transition(SentReinviteGlare);
1576 start491Timer();
1577 break;
1578
1579 case OnGeneralFailure:
1580 mStaleReInviteTimerSeq++;
1581 sendBye();
1582 transition(Terminated);
1583 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1584 break;
1585
1586 case OnInviteFailure:
1587 case On487Invite:
1588 mStaleReInviteTimerSeq++;
1589 transition(Connected);
1590 mProposedLocalOfferAnswer.reset();
1591 handler->onOfferRejected(getSessionHandle(), &msg);
1592 break;
1593
1594 default:
1595 dispatchOthers(msg);
1596 break;
1597 }
1598 }
1599
1600 void
1601 InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1602 {
1603 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1604 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1605
1606 switch (toEvent(msg, offerAnswer.get()))
1607 {
1608 case OnInvite:
1609 case OnInviteReliable:
1610 case OnInviteOffer:
1611 case OnInviteReliableOffer:
1612 case OnUpdate:
1613 case OnUpdateOffer:
1614 {
1615 SharedPtr<SipMessage> response(new SipMessage);
1616 mDialog.makeResponse(*response, msg, 491);
1617 send(response);
1618 break;
1619 }
1620
1621 case On1xx:
1622 case On1xxEarly:
1623 // Some UA's send a 100 response to a ReInvite - just ignore it
1624 break;
1625
1626 case On2xxAnswer: // .slg. doesn't really make sense
1627 case On2xxOffer:
1628 {
1629 mStaleReInviteTimerSeq++;
1630 transition(SentReinviteAnswered);
1631 handleSessionTimerResponse(msg);
1632 // mLastSessionModification = msg; // ?slg? why are we storing 200's?
1633 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1634 mProposedRemoteOfferAnswer = offerAnswer;
1635 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1636 break;
1637 }
1638
1639 case On2xx:
1640 mStaleReInviteTimerSeq++;
1641 sendAck();
1642 transition(Connected);
1643 handleSessionTimerResponse(msg);
1644 handler->onIllegalNegotiation(getSessionHandle(), msg);
1645 mProposedLocalOfferAnswer.reset();
1646 mProposedEncryptionLevel = DialogUsageManager::None;
1647 break;
1648
1649 case On422Invite:
1650 mStaleReInviteTimerSeq++;
1651 if(msg.exists(h_MinSE))
1652 {
1653 // Change interval to min from 422 response
1654 mSessionInterval = msg.header(h_MinSE).value();
1655 mMinSE = mSessionInterval;
1656 sessionRefresh();
1657 }
1658 else
1659 {
1660 // Response must contact Min_SE - if not - just ignore
1661 // ?slg? callback?
1662 transition(Connected);
1663 mProposedLocalOfferAnswer.reset();
1664 mProposedEncryptionLevel = DialogUsageManager::None;
1665 }
1666 break;
1667
1668 case On491Invite:
1669 mStaleReInviteTimerSeq++;
1670 transition(SentReinviteNoOfferGlare);
1671 start491Timer();
1672 break;
1673
1674 case OnGeneralFailure:
1675 mStaleReInviteTimerSeq++;
1676 sendBye();
1677 transition(Terminated);
1678 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1679 break;
1680
1681 case OnInviteFailure:
1682 case On487Invite:
1683 mStaleReInviteTimerSeq++;
1684 transition(Connected);
1685 mProposedLocalOfferAnswer.reset();
1686 handler->onOfferRejected(getSessionHandle(), &msg);
1687 break;
1688
1689 default:
1690 dispatchOthers(msg);
1691 break;
1692 }
1693 }
1694
1695 void
1696 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1697 {
1698 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1699 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1700
1701 switch (toEvent(msg, offerAnswer.get()))
1702 {
1703 case OnInvite:
1704 case OnInviteReliable:
1705 case OnInviteOffer:
1706 case OnInviteReliableOffer:
1707 case OnUpdate:
1708 case OnUpdateOffer:
1709 {
1710 SharedPtr<SipMessage> response(new SipMessage);
1711 mDialog.makeResponse(*response, msg, 491);
1712 send(response);
1713 break;
1714 }
1715 case OnAckAnswer:
1716 transition(Connected);
1717 setCurrentLocalOfferAnswer(msg);
1718 mCurrentRemoteOfferAnswer = offerAnswer;
1719 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1720 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1721
1722 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1723 break;
1724 case OnAck:
1725 if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
1726 {
1727 InfoLog(<< "dropped stale ACK");
1728 }
1729 else
1730 {
1731 InfoLog(<< "Got Ack with no answer");
1732 transition(Connected);
1733 mProposedLocalOfferAnswer.reset();
1734 mProposedEncryptionLevel = DialogUsageManager::None;
1735 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1736 //!dcm! -- should this be onIllegalNegotiation?
1737 handler->onOfferRejected(getSessionHandle(), &msg);
1738 }
1739 break;
1740 default:
1741 dispatchOthers(msg);
1742 break;
1743 }
1744 }
1745
1746 void
1747 InviteSession::dispatchGlare(const SipMessage& msg)
1748 {
1749 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1750 MethodTypes method = msg.header(h_CSeq).method();
1751 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1752 {
1753 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1754 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1755 handler->onOfferRejected(getSessionHandle(), &msg);
1756 if(!isTerminated()) // make sure application didn't call end()
1757 {
1758 dispatchConnected(msg); // act as if we received message in Connected state
1759 }
1760 else
1761 {
1762 dispatchTerminated(msg);
1763 }
1764 }
1765 else
1766 {
1767 dispatchOthers(msg);
1768 }
1769 }
1770
1771 void
1772 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1773 {
1774 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1775 MethodTypes method = msg.header(h_CSeq).method();
1776 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1777 {
1778 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1779 handler->onOfferRequestRejected(getSessionHandle(), msg);
1780 if(!isTerminated()) // make sure application didn't call end()
1781 {
1782 dispatchConnected(msg); // act as if we received message in Connected state
1783 }
1784 else
1785 {
1786 dispatchTerminated(msg);
1787 }
1788 }
1789 else
1790 {
1791 dispatchOthers(msg);
1792 }
1793 }
1794
1795 void
1796 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1797 {
1798 // InviteSessionHandler* handler = mDum.mInviteSessionHandler; // unused
1799 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1800
1801 switch (toEvent(msg, offerAnswer.get()))
1802 {
1803 case OnInvite:
1804 case OnInviteReliable:
1805 case OnInviteOffer:
1806 case OnInviteReliableOffer:
1807 case OnUpdate:
1808 case OnUpdateOffer:
1809 {
1810 // Means that the UAC has sent us a second reINVITE or UPDATE before we
1811 // responded to the first one. Bastard!
1812 SharedPtr<SipMessage> response(new SipMessage);
1813 mDialog.makeResponse(*response, msg, 500);
1814 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1815 send(response);
1816 break;
1817 }
1818 case OnBye:
1819 {
1820 // BYE received after a reINVITE, terminate the reINVITE transaction.
1821 SharedPtr<SipMessage> response(new SipMessage);
1822 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 487); // Request Terminated
1823 handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1824 send(response);
1825
1826 dispatchBye(msg);
1827 break;
1828 }
1829 default:
1830 dispatchOthers(msg);
1831 break;
1832 }
1833 }
1834
1835
1836 void
1837 InviteSession::dispatchAnswered(const SipMessage& msg)
1838 {
1839 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1840 {
1841 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1842 transition(Connected);
1843 }
1844 else
1845 {
1846 dispatchOthers(msg);
1847 }
1848 }
1849
1850 void
1851 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1852 {
1853 if (msg.isResponse() &&
1854 msg.header(h_CSeq).method() == INVITE &&
1855 msg.header(h_StatusLine).statusCode() / 200 == 1)
1856 {
1857 // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
1858 // called by the app - so just drop the retransmission
1859 return;
1860 }
1861 dispatchOthers(msg);
1862 }
1863
1864 void
1865 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1866 {
1867 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1868 {
1869 assert(mProposedLocalOfferAnswer.get());
1870 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1871 provideProposedOffer();
1872 }
1873 else
1874 {
1875 dispatchOthers(msg);
1876 }
1877 }
1878
1879 void
1880 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1881 {
1882 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1883 {
1884 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1885 requestOffer();
1886 }
1887 else
1888 {
1889 dispatchOthers(msg);
1890 }
1891 }
1892
1893 void
1894 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1895 {
1896 if (msg.isResponse() &&
1897 msg.header(h_CSeq).method() == INVITE)
1898 {
1899 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1900 {
1901 // !jf! Need to include the answer here.
1902 sendAck();
1903 }
1904 sendBye();
1905 transition(Terminated);
1906 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1907 }
1908 else if(msg.isRequest())
1909 {
1910 if(msg.method() == BYE)
1911 {
1912 dispatchBye(msg);
1913 }
1914 else
1915 {
1916 SharedPtr<SipMessage> response(new SipMessage);
1917 mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
1918 send(response);
1919 }
1920 }
1921 }
1922
1923 void
1924 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1925 {
1926 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1927
1928 switch (toEvent(msg, offerAnswer.get()))
1929 {
1930 case OnAck:
1931 case OnAckAnswer:
1932 {
1933 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1934
1935 sendBye();
1936 transition(Terminated);
1937 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1938 break;
1939 }
1940
1941 default:
1942 break;
1943 }
1944 }
1945
1946 void
1947 InviteSession::dispatchTerminated(const SipMessage& msg)
1948 {
1949 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1950
1951 if (msg.isRequest())
1952 {
1953 if (BYE == msg.header(h_CSeq).method())
1954 {
1955 SharedPtr<SipMessage> response(new SipMessage);
1956 mDialog.makeResponse(*response, msg, 200);
1957 send(response);
1958 }
1959 else
1960 {
1961 SharedPtr<SipMessage> response(new SipMessage);
1962 mDialog.makeResponse(*response, msg, 481);
1963 send(response);
1964 }
1965
1966 // !jf! means the peer sent BYE while we are waiting for response to BYE
1967 //mDum.destroy(this);
1968 }
1969 else
1970 {
1971 mDum.destroy(this);
1972 }
1973 }
1974
1975 void
1976 InviteSession::dispatchOthers(const SipMessage& msg)
1977 {
1978 // handle OnGeneralFailure
1979 // handle OnRedirect
1980
1981 switch (msg.header(h_CSeq).method())
1982 {
1983 case PRACK:
1984 dispatchPrack(msg);
1985 break;
1986 case CANCEL:
1987 dispatchCancel(msg);
1988 break;
1989 case BYE:
1990 dispatchBye(msg);
1991 break;
1992 case INFO:
1993 dispatchInfo(msg);
1994 break;
1995 case MESSAGE:
1996 dispatchMessage(msg);
1997 break;
1998 case ACK:
1999 // Ignore duplicate ACKs from 2xx reTransmissions
2000 break;
2001 default:
2002 // handled in Dialog
2003 WarningLog (<< "DUM delivered a "
2004 << msg.header(h_CSeq).unknownMethodName()
2005 << " to the InviteSession in state: " << toData(mState)
2006 << endl
2007 << msg);
2008 assert(0);
2009 break;
2010 }
2011 }
2012
2013 void
2014 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
2015 {
2016 assert(msg.isRequest());
2017 assert(msg.header(h_CSeq).method() == INVITE);
2018
2019 // If we get an INVITE request from the wire and we are not in
2020 // Connected state, reject the request and send a BYE
2021 SharedPtr<SipMessage> response(new SipMessage);
2022 mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
2023 InfoLog (<< "Sending " << response->brief());
2024 send(response);
2025
2026 sendBye();
2027 transition(Terminated);
2028 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2029 }
2030
2031 void
2032 InviteSession::dispatchPrack(const SipMessage& msg)
2033 {
2034 assert(msg.header(h_CSeq).method() == PRACK);
2035 if(msg.isRequest())
2036 {
2037 SharedPtr<SipMessage> rsp(new SipMessage);
2038 mDialog.makeResponse(*rsp, msg, 481);
2039 send(rsp);
2040
2041 sendBye();
2042 // !jf! should we make some other callback here
2043 transition(Terminated);
2044 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2045 }
2046 else
2047 {
2048 // ignore. could be PRACK/200
2049 }
2050 }
2051
2052 void
2053 InviteSession::dispatchCancel(const SipMessage& msg)
2054 {
2055 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2056 assert(msg.header(h_CSeq).method() == CANCEL);
2057 if(msg.isRequest())
2058 {
2059 SharedPtr<SipMessage> rsp(new SipMessage);
2060 mDialog.makeResponse(*rsp, msg, 200);
2061 send(rsp);
2062
2063 sendBye();
2064 // !jf! should we make some other callback here
2065 transition(Terminated);
2066
2067 handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteCancel, &msg);
2068 }
2069 else
2070 {
2071 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
2072 assert(0);
2073 }
2074 }
2075
2076 void
2077 InviteSession::dispatchBye(const SipMessage& msg)
2078 {
2079 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2080
2081 if (msg.isRequest())
2082 {
2083 // Check for any non-invite server transactions (e.g. INFO)
2084 // that have not been responded yet and terminate them.
2085 if (mServerNitState == NitProceeding)
2086 {
2087 mLastNitResponse->header(h_StatusLine).statusCode() = 487;
2088 mLastNitResponse->setContents(0);
2089 Helper::getResponseCodeReason(487, mLastNitResponse->header(h_StatusLine).reason());
2090 send(mLastNitResponse);
2091 mServerNitState = NitComplete;
2092 }
2093
2094 SharedPtr<SipMessage> rsp(new SipMessage);
2095 InfoLog (<< "Received " << msg.brief());
2096 mDialog.makeResponse(*rsp, msg, 200);
2097 send(rsp);
2098
2099 // !jf! should we make some other callback here
2100 transition(Terminated);
2101
2102 if (mDum.mDialogEventStateManager)
2103 {
2104 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::RemoteBye);
2105 }
2106
2107 handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
2108 mDum.destroy(this);
2109 }
2110 else
2111 {
2112 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
2113 assert(0);
2114 }
2115 }
2116
2117 void
2118 InviteSession::dispatchInfo(const SipMessage& msg)
2119 {
2120 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2121 if (msg.isRequest())
2122 {
2123 if (mServerNitState == NitProceeding)
2124 {
2125 // Means that the UAC has sent us a second INFO before we
2126 // responded to the first one.
2127 SharedPtr<SipMessage> response(new SipMessage);
2128 mDialog.makeResponse(*response, msg, 500);
2129 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2130 send(response);
2131 }
2132 else
2133 {
2134 InfoLog (<< "Received " << msg.brief());
2135 mServerNitState = NitProceeding;
2136 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2137 handler->onInfo(getSessionHandle(), msg);
2138 }
2139 }
2140 else
2141 {
2142 assert(mNitState == NitProceeding);
2143 //!dcm! -- toss away 1xx to an info?
2144 if (msg.header(h_StatusLine).statusCode() >= 300)
2145 {
2146 handler->onInfoFailure(getSessionHandle(), msg);
2147 }
2148 else if (msg.header(h_StatusLine).statusCode() >= 200)
2149 {
2150 handler->onInfoSuccess(getSessionHandle(), msg);
2151 }
2152 nitComplete();
2153 }
2154 }
2155
2156 void
2157 InviteSession::acceptNIT(int statusCode, const Contents * contents)
2158 {
2159 if (statusCode / 100 != 2)
2160 {
2161 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2162 }
2163
2164 if (mServerNitState != NitProceeding )
2165 {
2166 throw UsageUseException("No transaction to accept", __FILE__, __LINE__);
2167 }
2168
2169 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2170 mLastNitResponse->setContents(contents);
2171 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2172 send(mLastNitResponse);
2173 mServerNitState = NitComplete;
2174 }
2175
2176 class InviteSessionAcceptNITCommand : public DumCommandAdapter
2177 {
2178 public:
2179 InviteSessionAcceptNITCommand(InviteSession& inviteSession, int statusCode, const Contents* contents)
2180 : mInviteSession(inviteSession),
2181 mStatusCode(statusCode),
2182 mContents(contents?contents->clone():0)
2183 {
2184
2185 }
2186
2187 virtual void executeCommand()
2188 {
2189 mInviteSession.acceptNITCommand(mStatusCode, mContents.get());
2190 }
2191
2192 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2193 {
2194 return strm << "InviteSessionAcceptNITCommand";
2195 }
2196 private:
2197 InviteSession& mInviteSession;
2198 int mStatusCode;
2199 std::auto_ptr<Contents> mContents;
2200 };
2201
2202 void
2203 InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
2204 {
2205 mDum.post(new InviteSessionAcceptNITCommand(*this, statusCode, contents));
2206 }
2207
2208 void
2209 InviteSession::rejectNIT(int statusCode)
2210 {
2211 if (statusCode < 400)
2212 {
2213 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2214 }
2215
2216 if (mServerNitState != NitProceeding )
2217 {
2218 throw UsageUseException("No transaction to reject", __FILE__, __LINE__);
2219 }
2220
2221 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2222 mLastNitResponse->setContents(0);
2223 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2224 send(mLastNitResponse);
2225 mServerNitState = NitComplete;
2226 }
2227
2228 class InviteSessionRejectNITCommand : public DumCommandAdapter
2229 {
2230 public:
2231 InviteSessionRejectNITCommand(InviteSession& inviteSession, int statusCode)
2232 : mInviteSession(inviteSession),
2233 mStatusCode(statusCode)
2234 {
2235 }
2236
2237 virtual void executeCommand()
2238 {
2239 mInviteSession.rejectNITCommand(mStatusCode);
2240 }
2241
2242 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2243 {
2244 return strm << "InviteSessionRejectNITCommand";
2245 }
2246 private:
2247 InviteSession& mInviteSession;
2248 int mStatusCode;
2249 };
2250
2251 void
2252 InviteSession::rejectNITCommand(int statusCode)
2253 {
2254 mDum.post(new InviteSessionRejectNITCommand(*this, statusCode));
2255 }
2256
2257 void
2258 InviteSession::dispatchMessage(const SipMessage& msg)
2259 {
2260 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2261 if (msg.isRequest())
2262 {
2263 if (mServerNitState == NitProceeding)
2264 {
2265 // Means that the UAC has sent us a second NIT message before we
2266 // responded to the first one.
2267 SharedPtr<SipMessage> response(new SipMessage);
2268 mDialog.makeResponse(*response, msg, 500);
2269 response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2270 send(response);
2271 }
2272 else
2273 {
2274 InfoLog (<< "Received " << msg.brief());
2275 mServerNitState = NitProceeding;
2276 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2277 mLastNitResponse->header(h_Contacts).clear();
2278 handler->onMessage(getSessionHandle(), msg);
2279 }
2280 }
2281 else
2282 {
2283 assert(mNitState == NitProceeding);
2284 //!dcm! -- toss away 1xx to an message?
2285 if (msg.header(h_StatusLine).statusCode() >= 300)
2286 {
2287 handler->onMessageFailure(getSessionHandle(), msg);
2288 }
2289 else if (msg.header(h_StatusLine).statusCode() >= 200)
2290 {
2291 handler->onMessageSuccess(getSessionHandle(), msg);
2292 }
2293 nitComplete();
2294 }
2295 }
2296
2297 void
2298 InviteSession::startRetransmit200Timer()
2299 {
2300 mCurrentRetransmit200 = Timer::T1;
2301 unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
2302 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
2303 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
2304 }
2305
2306 // RFC3261 section 14.1
2307 // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
2308 // a value T chosen as follows:
2309 // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
2310 // chosen value between 2.1 and 4 seconds in units of 10 ms.
2311 // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
2312 // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
2313 void
2314 InviteSession::start491Timer()
2315 {
2316 unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
2317
2318 if (dynamic_cast<ClientInviteSession*>(this))
2319 {
2320 int timer = Random::getRandom() % (4000 - 2100);
2321 timer += 2100;
2322 timer -= timer % 10;
2323
2324 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2325 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2326 }
2327 else
2328 {
2329 int timer = Random::getRandom() % 2000;
2330 timer -= timer % 10;
2331 DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2332 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2333 }
2334 }
2335
2336 void
2337 InviteSession::startStaleReInviteTimer()
2338 {
2339 InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
2340 unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
2341
2342 mDum.addTimer(DumTimeout::StaleReInvite,
2343 when,
2344 getBaseHandle(),
2345 ++mStaleReInviteTimerSeq);
2346 }
2347
2348 void
2349 InviteSession::setSessionTimerHeaders(SipMessage &msg)
2350 {
2351 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
2352 {
2353 msg.header(h_SessionExpires).value() = mSessionInterval;
2354 if(msg.isRequest())
2355 {
2356 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
2357 }
2358 else
2359 {
2360 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
2361 }
2362 msg.header(h_MinSE).value() = mMinSE;
2363 }
2364 else
2365 {
2366 msg.remove(h_SessionExpires);
2367 msg.remove(h_MinSE);
2368 }
2369 }
2370
2371 void
2372 InviteSession::sessionRefresh()
2373 {
2374 if (updateMethodSupported())
2375 {
2376 transition(SentUpdate);
2377 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
2378 mLastLocalSessionModification->setContents(0); // Don't send SDP
2379 }
2380 else
2381 {
2382 transition(SentReinvite);
2383 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
2384 startStaleReInviteTimer();
2385 InviteSession::setOfferAnswer(*mLastLocalSessionModification, mCurrentLocalOfferAnswer.get());
2386 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(*mCurrentLocalOfferAnswer.get(), 0);
2387 mSessionRefreshReInvite = true;
2388 }
2389 setSessionTimerHeaders(*mLastLocalSessionModification);
2390
2391 InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
2392 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
2393 send(mLastLocalSessionModification);
2394 }
2395
2396 void
2397 InviteSession::setSessionTimerPreferences()
2398 {
2399 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
2400 if(mSessionInterval != 0)
2401 {
2402 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
2403 mSessionInterval = resipMax(mMinSE, mSessionInterval);
2404 }
2405 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
2406 {
2407 case Profile::PreferLocalRefreshes:
2408 mSessionRefresher = true; // Default refresher is Local
2409 break;
2410 case Profile::PreferRemoteRefreshes:
2411 mSessionRefresher = false; // Default refresher is Remote
2412 break;
2413 case Profile::PreferCalleeRefreshes:
2414 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is callee
2415 break;
2416 case Profile::PreferCallerRefreshes:
2417 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is caller
2418 break;
2419 }
2420 }
2421
2422 void
2423 InviteSession::startSessionTimer()
2424 {
2425 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
2426 {
2427 // Check if we are the refresher
2428 if(mSessionRefresher)
2429 {
2430 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
2431 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
2432 }
2433 else
2434 {
2435 // 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)
2436 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
2437 }
2438 }
2439 else // Session Interval less than 90 - consider timers disabled
2440 {
2441 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
2442 }
2443 }
2444
2445 void
2446 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
2447 {
2448 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
2449
2450 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2451 if (msg.exists(h_PAssertedIdentities))
2452 {
2453 mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
2454 }
2455
2456 // If session timers are locally supported then handle response
2457 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2458 {
2459 setSessionTimerPreferences();
2460
2461 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
2462 && !msg.exists(h_SessionExpires))
2463 {
2464 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
2465 mSessionInterval = 0;
2466 }
2467 // Process Session Timer headers
2468 else if(msg.exists(h_SessionExpires))
2469 {
2470 mSessionInterval = msg.header(h_SessionExpires).value();
2471 if(msg.header(h_SessionExpires).exists(p_refresher))
2472 {
2473 // Remote end specified refresher preference
2474 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
2475 }
2476 }
2477 else
2478 {
2479 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
2480 // - we are free to use our SessionInterval settings (set above as a default)
2481 // If far end doesn't support then refresher must be local
2482 mSessionRefresher = true;
2483 }
2484
2485 // Update MinSE if specified and longer than current value
2486 if(msg.exists(h_MinSE))
2487 {
2488 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
2489 }
2490
2491 startSessionTimer();
2492 }
2493 }
2494
2495 void
2496 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
2497 {
2498 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
2499
2500 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2501 if (request.exists(h_PAssertedIdentities))
2502 {
2503 mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
2504 }
2505
2506 // If session timers are locally supported then add necessary headers to response
2507 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2508 {
2509 setSessionTimerPreferences();
2510
2511 // Check if far-end supports
2512 bool farEndSupportsTimer = false;
2513 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
2514 {
2515 farEndSupportsTimer = true;
2516 if(request.exists(h_SessionExpires))
2517 {
2518 // Use Session Interval requested by remote - if none then use local settings
2519 mSessionInterval = request.header(h_SessionExpires).value();
2520 if(request.header(h_SessionExpires).exists(p_refresher))
2521 {
2522 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
2523 }
2524 }
2525
2526 // Update MinSE if specified and longer than current value
2527 if(request.exists(h_MinSE))
2528 {
2529 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
2530 }
2531 }
2532 else
2533 {
2534 // If far end doesn't support then refresher must be local
2535 mSessionRefresher = true;
2536 }
2537
2538 // Add Session-Expires to response if required
2539 if(mSessionInterval >= 90)
2540 {
2541 if(farEndSupportsTimer)
2542 {
2543 // If far end supports session-timer then require it, if not already present
2544 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
2545 {
2546 response.header(h_Requires).push_back(Token(Symbols::Timer));
2547 }
2548 }
2549 setSessionTimerHeaders(response);
2550 }
2551
2552 startSessionTimer();
2553 }
2554 }
2555
2556 Data
2557 InviteSession::toData(State state)
2558 {
2559 switch (state)
2560 {
2561 case Undefined:
2562 return "InviteSession::Undefined";
2563 case Connected:
2564 return "InviteSession::Connected";
2565 case SentUpdate:
2566 return "InviteSession::SentUpdate";
2567 case SentUpdateGlare:
2568 return "InviteSession::SentUpdateGlare";
2569 case SentReinvite:
2570 return "InviteSession::SentReinvite";
2571 case SentReinviteGlare:
2572 return "InviteSession::SentReinviteGlare";
2573 case SentReinviteNoOffer:
2574 return "InviteSession::SentReinviteNoOffer";
2575 case SentReinviteAnswered:
2576 return "InviteSession::SentReinviteAnswered";
2577 case SentReinviteNoOfferGlare:
2578 return "InviteSession::SentReinviteNoOfferGlare";
2579 case ReceivedUpdate:
2580 return "InviteSession::ReceivedUpdate";
2581 case ReceivedReinvite:
2582 return "InviteSession::ReceivedReinvite";
2583 case ReceivedReinviteNoOffer:
2584 return "InviteSession::ReceivedReinviteNoOffer";
2585 case ReceivedReinviteSentOffer:
2586 return "InviteSession::ReceivedReinviteSentOffer";
2587 case Answered:
2588 return "InviteSession::Answered";
2589 case WaitingToOffer:
2590 return "InviteSession::WaitingToOffer";
2591 case WaitingToRequestOffer:
2592 return "InviteSession::WaitingToRequestOffer";
2593 case WaitingToTerminate:
2594 return "InviteSession::WaitingToTerminate";
2595 case WaitingToHangup:
2596 return "InviteSession::WaitingToHangup";
2597 case Terminated:
2598 return "InviteSession::Terminated";
2599
2600 case UAC_Start:
2601 return "UAC_Start";
2602 case UAS_Offer:
2603 return "UAS_Offer";
2604 case UAS_OfferProvidedAnswer:
2605 return "UAS_OfferProvidedAnswer";
2606 case UAS_EarlyOffer:
2607 return "UAS_EarlyOffer";
2608 case UAS_EarlyProvidedAnswer:
2609 return "UAS_EarlyProvidedAnswer";
2610 case UAS_NoOffer:
2611 return "UAS_NoOffer";
2612 case UAS_ProvidedOffer:
2613 return "UAS_ProvidedOffer";
2614 case UAS_EarlyNoOffer:
2615 return "UAS_EarlyNoOffer";
2616 case UAS_EarlyProvidedOffer:
2617 return "UAS_EarlyProvidedOffer";
2618 case UAS_Accepted:
2619 return "UAS_Accepted";
2620 case UAS_WaitingToOffer:
2621 return "UAS_WaitingToOffer";
2622 case UAS_AcceptedWaitingAnswer:
2623 return "UAS_AcceptedWaitingAnswer";
2624 case UAC_Early:
2625 return "UAC_Early";
2626 case UAC_EarlyWithOffer:
2627 return "UAC_EarlyWithOffer";
2628 case UAC_EarlyWithAnswer:
2629 return "UAC_EarlyWithAnswer";
2630 case UAC_Answered:
2631 return "UAC_Answered";
2632 case UAC_SentUpdateEarly:
2633 return "UAC_SentUpdateEarly";
2634 case UAC_SentUpdateEarlyGlare:
2635 return "UAC_SentUpdateEarlyGlare";
2636 case UAC_ReceivedUpdateEarly:
2637 return "UAC_ReceivedUpdateEarly";
2638 case UAC_SentAnswer:
2639 return "UAC_SentAnswer";
2640 case UAC_QueuedUpdate:
2641 return "UAC_QueuedUpdate";
2642 case UAC_Cancelled:
2643 return "UAC_Cancelled";
2644
2645 case UAS_Start:
2646 return "UAS_Start";
2647 case UAS_ReceivedOfferReliable:
2648 return "UAS_ReceivedOfferReliable";
2649 case UAS_NoOfferReliable:
2650 return "UAS_NoOfferReliable";
2651 case UAS_FirstSentOfferReliable:
2652 return "UAS_FirstSentOfferReliable";
2653 case UAS_FirstSentAnswerReliable:
2654 return "UAS_FirstSentAnswerReliable";
2655 case UAS_NegotiatedReliable:
2656 return "UAS_NegotiatedReliable";
2657 case UAS_SentUpdate:
2658 return "UAS_SentUpdate";
2659 case UAS_SentUpdateAccepted:
2660 return "UAS_SentUpdateAccepted";
2661 case UAS_ReceivedUpdate:
2662 return "UAS_ReceivedUpdate";
2663 case UAS_ReceivedUpdateWaitingAnswer:
2664 return "UAS_ReceivedUpdateWaitingAnswer";
2665 case UAS_WaitingToTerminate:
2666 return "UAS_WaitingToTerminate";
2667 case UAS_WaitingToHangup:
2668 return "UAS_WaitingToHangup";
2669 case UAS_WaitingToRequestOffer:
2670 return "UAS_WaitingToRequestOffer";
2671 }
2672 assert(0);
2673 return "Undefined";
2674 }
2675
2676
2677 void
2678 InviteSession::transition(State target)
2679 {
2680 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
2681 mState = target;
2682 }
2683
2684 bool
2685 InviteSession::isReliable(const SipMessage& msg)
2686 {
2687 if(msg.method() != INVITE)
2688 {
2689 return false;
2690 }
2691 if(msg.isRequest())
2692 {
2693 return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never
2694 && ((msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)))
2695 || (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
2696 }
2697 else
2698 {
2699 return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never
2700 && msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel));
2701 }
2702 }
2703
2704 //static std::auto_ptr<SdpContents> emptySdp;
2705 std::auto_ptr<Contents>
2706 InviteSession::getOfferAnswer(const SipMessage& msg)
2707 {
2708 if(mDum.mInviteSessionHandler->isGenericOfferAnswer())
2709 {
2710 if(msg.getContents())
2711 {
2712 return std::auto_ptr<Contents>(msg.getContents()->clone());
2713 }
2714 else
2715 {
2716 return std::auto_ptr<Contents>();
2717 }
2718 }
2719 else
2720 {
2721 return std::auto_ptr<Contents>(Helper::getSdp(msg.getContents()));
2722 }
2723 }
2724
2725 std::auto_ptr<Contents>
2726 InviteSession::makeOfferAnswer(const Contents& offerAnswer)
2727 {
2728 return std::auto_ptr<Contents>(static_cast<Contents*>(offerAnswer.clone()));
2729 }
2730
2731 auto_ptr<Contents>
2732 InviteSession::makeOfferAnswer(const Contents& offerAnswer,
2733 const Contents* alternative)
2734 {
2735 if (alternative)
2736 {
2737 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2738 mac->parts().push_back(alternative->clone());
2739 mac->parts().push_back(offerAnswer.clone());
2740 return auto_ptr<Contents>(mac);
2741 }
2742 else
2743 {
2744 return auto_ptr<Contents>(offerAnswer.clone());
2745 }
2746 }
2747
2748 void
2749 InviteSession::setOfferAnswer(SipMessage& msg, const Contents& offerAnswer, const Contents* alternative)
2750 {
2751 // !jf! should deal with multipart here
2752
2753 // This will clone the offerAnswer since the InviteSession also wants to keep its own
2754 // copy of the offerAnswer around for the application to access
2755 if (alternative)
2756 {
2757 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2758 mac->parts().push_back(alternative->clone());
2759 mac->parts().push_back(offerAnswer.clone());
2760 msg.setContents(auto_ptr<Contents>(mac));
2761 }
2762 else
2763 {
2764 msg.setContents(&offerAnswer);
2765 }
2766 }
2767
2768 void
2769 InviteSession::setOfferAnswer(SipMessage& msg, const Contents* offerAnswer)
2770 {
2771 assert(offerAnswer);
2772 msg.setContents(offerAnswer);
2773 }
2774
2775 void
2776 InviteSession::provideProposedOffer()
2777 {
2778 MultipartAlternativeContents* mp_ans =
2779 dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get());
2780 if (mp_ans)
2781 {
2782 // .kw. can cast below ever be NULL? Need assert/throw?
2783 provideOffer( *(dynamic_cast<Contents*>((mp_ans)->parts().back())),
2784 mProposedEncryptionLevel,
2785 dynamic_cast<Contents*>((mp_ans)->parts().front()));
2786 }
2787 else
2788 {
2789 // .kw. can cast below ever be NULL? Need assert/throw?
2790 provideOffer(*(dynamic_cast<Contents*>(mProposedLocalOfferAnswer.get())), mProposedEncryptionLevel, 0);
2791 }
2792 }
2793
2794 InviteSession::Event
2795 InviteSession::toEvent(const SipMessage& msg, const Contents* offerAnswer)
2796 {
2797 MethodTypes method = msg.header(h_CSeq).method();
2798 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2799
2800 //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
2801 //responses, reiable provisionals should only be received if the invite was
2802 //sent reliably. Spurious reliable provisional respnoses are dropped outside
2803 //the state machine.
2804 bool reliable = isReliable(msg);
2805 bool sentOffer = mProposedLocalOfferAnswer.get();
2806
2807 if (code == 481 || code == 408)
2808 {
2809 return OnGeneralFailure;
2810 }
2811 else if (code >= 300 && code <= 399)
2812 {
2813 return OnRedirect;
2814 }
2815 else if (method == INVITE && code == 0)
2816 {
2817 if (offerAnswer)
2818 {
2819 if (reliable)
2820 {
2821 return OnInviteReliableOffer;
2822 }
2823 else
2824 {
2825 return OnInviteOffer;
2826 }
2827 }
2828 else
2829 {
2830 if (reliable)
2831 {
2832 return OnInviteReliable;
2833 }
2834 else
2835 {
2836 return OnInvite;
2837 }
2838 }
2839 }
2840 else if (method == INVITE && code > 100 && code < 200)
2841 {
2842 if (reliable)
2843 {
2844 if (offerAnswer)
2845 {
2846 if (sentOffer)
2847 {
2848 return On1xxAnswer;
2849 }
2850 else
2851 {
2852 return On1xxOffer;
2853 }
2854 }
2855 else
2856 {
2857 return On1xx;
2858 }
2859 }
2860 else
2861 {
2862 if (offerAnswer)
2863 {
2864 return On1xxEarly;
2865 }
2866 else
2867 {
2868 return On1xx;
2869 }
2870 }
2871 }
2872 else if (method == INVITE && code >= 200 && code < 300)
2873 {
2874 if (offerAnswer)
2875 {
2876 if (sentOffer)
2877 {
2878 return On2xxAnswer;
2879 }
2880 else
2881 {
2882 return On2xxOffer;
2883 }
2884 }
2885 else
2886 {
2887 return On2xx;
2888 }
2889 }
2890 else if (method == INVITE && code == 422)
2891 {
2892 return On422Invite;
2893 }
2894 else if (method == INVITE && code == 487)
2895 {
2896 return On487Invite;
2897 }
2898 else if (method == INVITE && code == 491)
2899 {
2900 return On491Invite;
2901 }
2902 else if (method == INVITE && code >= 400)
2903 {
2904 return OnInviteFailure;
2905 }
2906 else if (method == ACK)
2907 {
2908 if (offerAnswer)
2909 {
2910 return OnAckAnswer;
2911 }
2912 else
2913 {
2914 return OnAck;
2915 }
2916 }
2917 else if (method == CANCEL && code == 0)
2918 {
2919 return OnCancel;
2920 }
2921 else if (method == CANCEL && code / 200 == 1)
2922 {
2923 return On200Cancel;
2924 }
2925 else if (method == CANCEL && code >= 400)
2926 {
2927 return OnCancelFailure;
2928 }
2929 else if (method == BYE && code == 0)
2930 {
2931 return OnBye;
2932 }
2933 else if (method == BYE && code / 200 == 1)
2934 {
2935 return On200Bye;
2936 }
2937 else if (method == PRACK && code == 0)
2938 {
2939 return OnPrack;
2940 }
2941 else if (method == PRACK && code / 200 == 1)
2942 {
2943 return On200Prack;
2944 }
2945 else if (method == UPDATE && code == 0)
2946 {
2947 if (offerAnswer)
2948 {
2949 return OnUpdateOffer;
2950 }
2951 else
2952 {
2953 return OnUpdate;
2954 }
2955 }
2956 else if (method == UPDATE && code / 200 == 1)
2957 {
2958 return On200Update;
2959 }
2960 else if (method == UPDATE && code == 422)
2961 {
2962 return On422Update;
2963 }
2964 else if (method == UPDATE && code == 491)
2965 {
2966 return On491Update;
2967 }
2968 else if (method == UPDATE && code >= 400)
2969 {
2970 return OnUpdateRejected;
2971 }
2972 else
2973 {
2974 //assert(0); // dispatchOthers will throw if the message type is really unknown
2975 return Unknown;
2976 }
2977 }
2978
2979 void
2980 InviteSession::sendAck(const Contents *answer)
2981 {
2982 SharedPtr<SipMessage> ack(new SipMessage);
2983
2984 SharedPtr<SipMessage> source;
2985
2986 if (mLastLocalSessionModification->method() == UPDATE)
2987 {
2988 //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
2989 source = mDialog.mDialogSet.getCreator()->getLastRequest();
2990 }
2991 else
2992 {
2993 source = mLastLocalSessionModification;
2994 }
2995
2996 assert(mAcks.count(source->getTransactionId()) == 0);
2997
2998 mDialog.makeRequest(*ack, ACK);
2999
3000 // Copy Authorization and Proxy Authorization headers from
3001 // mLastLocalSessionModification; regardless of whether this was the original
3002 // INVITE or not, this is the correct place to go for auth headers.
3003 if(mLastLocalSessionModification->exists(h_Authorizations))
3004 {
3005 ack->header(h_Authorizations) = mLastLocalSessionModification->header(h_Authorizations);
3006 }
3007 if(mLastLocalSessionModification->exists(h_ProxyAuthorizations))
3008 {
3009 ack->header(h_ProxyAuthorizations) = mLastLocalSessionModification->header(h_ProxyAuthorizations);
3010 }
3011
3012 // Copy CSeq from original INVITE
3013 ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
3014
3015 if(answer != 0)
3016 {
3017 setOfferAnswer(*ack, *answer);
3018 }
3019 mAcks[source->getTransactionId()] = ack;
3020 mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(), 0, source->getTransactionId());
3021
3022 InfoLog (<< "Sending " << ack->brief());
3023 send(ack);
3024 }
3025
3026 void
3027 InviteSession::sendBye()
3028 {
3029 SharedPtr<SipMessage> bye(new SipMessage());
3030 mDialog.makeRequest(*bye, BYE);
3031 Data txt;
3032 if (mEndReason != NotSpecified)
3033 {
3034 Token reason("SIP");
3035 txt = getEndReasonString(mEndReason);
3036 reason.param(p_description) = txt;
3037 bye->header(h_Reasons).push_back(reason);
3038 }
3039
3040 if (mDum.mDialogEventStateManager)
3041 {
3042 mDum.mDialogEventStateManager->onTerminated(mDialog, *bye, InviteSessionHandler::LocalBye);
3043 }
3044
3045 InfoLog (<< myAddr() << " Sending BYE " << txt);
3046 send(bye);
3047 }
3048
3049 DialogUsageManager::EncryptionLevel
3050 InviteSession::getEncryptionLevel(const SipMessage& msg)
3051 {
3052 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
3053 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
3054 if (secAttr)
3055 {
3056 SignatureStatus sig = secAttr->getSignatureStatus();
3057 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
3058 bool encrypted = secAttr->isEncrypted();
3059 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
3060 else if (encrypted) level = DialogUsageManager::Encrypt;
3061 else if (sign) level = DialogUsageManager::Sign;
3062 }
3063 return level;
3064 }
3065
3066 void
3067 InviteSession::setCurrentLocalOfferAnswer(const SipMessage& msg)
3068 {
3069 assert(mProposedLocalOfferAnswer.get());
3070 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))
3071 {
3072 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
3073 {
3074 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().back()->clone()));
3075 }
3076 else
3077 {
3078 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().front()->clone()));
3079 }
3080 }
3081 else
3082 {
3083 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>(mProposedLocalOfferAnswer.get()->clone()));
3084 }
3085 mProposedLocalOfferAnswer.reset();
3086 }
3087
3088 void
3089 InviteSession::onReadyToSend(SipMessage& msg)
3090 {
3091 mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
3092 }
3093
3094 void
3095 InviteSession::flowTerminated()
3096 {
3097 // notify handler
3098 mDum.mInviteSessionHandler->onFlowTerminated(getSessionHandle());
3099 }
3100
3101 void
3102 InviteSession::referNoSub(const SipMessage& msg)
3103 {
3104 assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
3105 mLastReferNoSubRequest = msg;
3106 mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
3107 }
3108
3109 void
3110 InviteSession::acceptReferNoSub(int statusCode)
3111 {
3112 if (statusCode / 100 != 2)
3113 {
3114 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
3115 }
3116
3117 SharedPtr<SipMessage> response(new SipMessage);
3118 mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
3119 response->header(h_ReferSub).value() = "false";
3120 //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
3121
3122 send(response);
3123 }
3124
3125 void
3126 InviteSession::rejectReferNoSub(int responseCode)
3127 {
3128 if (responseCode < 400)
3129 {
3130 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
3131 }
3132
3133 SharedPtr<SipMessage> response(new SipMessage);
3134 mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
3135 send(response);
3136 }
3137
3138 /* ====================================================================
3139 * The Vovida Software License, Version 1.0
3140 *
3141 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
3142 *
3143 * Redistribution and use in source and binary forms, with or without
3144 * modification, are permitted provided that the following conditions
3145 * are met:
3146 *
3147 * 1. Redistributions of source code must retain the above copyright
3148 * notice, this list of conditions and the following disclaimer.
3149 *
3150 * 2. Redistributions in binary form must reproduce the above copyright
3151 * notice, this list of conditions and the following disclaimer in
3152 * the documentation and/or other materials provided with the
3153
3154 * distribution.
3155 *
3156 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
3157 * and "Vovida Open Communication Application Library (VOCAL)" must
3158 * not be used to endorse or promote products derived from this
3159 * software without prior written permission. For written
3160 * permission, please contact vocal@vovida.org.
3161 *
3162 * 4. Products derived from this software may not be called "VOCAL", nor
3163 * may "VOCAL" appear in their name, without prior written
3164 * permission of Vovida Networks, Inc.
3165 *
3166 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
3167 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3168 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
3169 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
3170 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
3171 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
3172 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3173 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3174 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
3175 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3176 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3177 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3178 * DAMAGE.
3179 *
3180 * ====================================================================
3181 *
3182 * This software consists of voluntary contributions made by Vovida
3183 * Networks, Inc. and many individuals on behalf of Vovida Networks,
3184 * Inc. For more information on Vovida Networks, Inc., please see
3185 * <http://www.vovida.org/>.
3186 *
3187 */
3188
3189
3190

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27