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

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

Parent Directory Parent Directory | Revision Log Revision Log


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