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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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