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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8762 - (hide annotations) (download)
Wed Mar 3 17:43:33 2010 UTC (9 years, 9 months ago) by bcampen
File MIME type: text/plain
File size: 92370 byte(s)
Tweak to RSeq check; check RSeq if a reliable provisional comes in when we
didn't use Require: 100rel, but used Supported: 100rel instead. Also, don't
treat Supported: 100rel in a provisional response as indicating reliability.
(3262 says reliable provisionals MUST have a Require: 100rel and an RSeq)

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