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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8400 - (hide annotations) (download)
Wed Jan 21 18:24:57 2009 UTC (10 years, 10 months ago) by sgodin
File MIME type: text/plain
File size: 87306 byte(s)
-fixed a bug where the Content-Type header could be set in a UPDATE Session Refresh 
 to application/sdp, but the content length would be 0 - the content-type header 
 should not be present
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->onDialogModified(getSessionHandle(), None, msg);
1259     handler->onOfferRequired(getSessionHandle(), msg);
1260     break;
1261 sgodin 3392
1262 jason 4010 case OnInviteOffer:
1263     case OnInviteReliableOffer:
1264 daniel 5757 *mLastRemoteSessionModification = msg;
1265 jason 4010 transition(ReceivedReinvite);
1266 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1267 jason 7102 mProposedRemoteSdp = sdp;
1268 sgodin 5555
1269 jason 4010 //handler->onDialogModified(getSessionHandle(), Offer, msg);
1270 nash 7084 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteSdp);
1271 jason 4010 break;
1272    
1273     case On2xx:
1274     case On2xxOffer:
1275     case On2xxAnswer:
1276     // retransmission of 200I
1277     // !jf! Need to include the answer here.
1278 sgodin 5747 sendAck();
1279 jason 4010 break;
1280    
1281 sgodin 4369 case OnUpdateOffer:
1282 jason 4010 transition(ReceivedUpdate);
1283    
1284     // !kh!
1285     // Find out if it's an UPDATE requiring state change.
1286     // See rfc3311 5.2, 4th paragraph.
1287 daniel 5757 *mLastRemoteSessionModification = msg;
1288 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1289 jason 7102 mProposedRemoteSdp = sdp;
1290 nash 7084 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteSdp);
1291 jason 4010 break;
1292    
1293 sgodin 4369 case OnUpdate:
1294     {
1295 sgodin 6755 // ?slg? no sdp in update - just respond immediately (likely session timer) - do we need a callback?
1296 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1297     *mLastRemoteSessionModification = msg;
1298     mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
1299     handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1300 sgodin 5747 send(response);
1301 sgodin 4369 break;
1302     }
1303    
1304 jason 4010 case OnUpdateRejected:
1305     case On200Update:
1306 sgodin 6121 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
1307     assert(0);
1308 jason 4010 break;
1309    
1310     case OnAck:
1311 bcampen 7267 case OnAckAnswer: // .bwc. Don't drop ACK with SDP!
1312 jason 4010 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1313 nash 7042 handler->onAckReceived(getSessionHandle(), msg);
1314 jason 4010 break;
1315    
1316     default:
1317     dispatchOthers(msg);
1318     break;
1319     }
1320     }
1321    
1322     void
1323     InviteSession::dispatchSentUpdate(const SipMessage& msg)
1324     {
1325     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1326     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1327    
1328     switch (toEvent(msg, sdp.get()))
1329     {
1330     case OnInvite:
1331     case OnInviteReliable:
1332     case OnInviteOffer:
1333     case OnInviteReliableOffer:
1334     case OnUpdate:
1335 sgodin 4369 case OnUpdateOffer:
1336 sgodin 3392 {
1337 jason 4010 // glare
1338 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1339     mDialog.makeResponse(*response, msg, 491);
1340 sgodin 5747 send(response);
1341 jason 4010 break;
1342     }
1343    
1344     case On200Update:
1345     transition(Connected);
1346     handleSessionTimerResponse(msg);
1347 sgodin 5746 if (sdp.get() && mProposedLocalSdp.get())
1348 sgodin 3392 {
1349 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1350     setCurrentLocalSdp(msg);
1351 jason 7102
1352     mCurrentRemoteSdp = sdp;
1353 vann 7159 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteSdp);
1354 sgodin 3392 }
1355 sgodin 4369 else if(mProposedLocalSdp.get())
1356 sgodin 3392 {
1357 sgodin 4369 // If we sent an offer in the Update Request and no answer is received
1358 jason 4010 handler->onIllegalNegotiation(getSessionHandle(), msg);
1359 sgodin 5567 mProposedLocalSdp.reset();
1360 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1361 jason 4010 }
1362     break;
1363    
1364     case On491Update:
1365 sgodin 4369 transition(SentUpdateGlare);
1366 jason 4010 start491Timer();
1367     break;
1368    
1369 daniel 5068 case On422Update: // session timer
1370 sgodin 4394 if(msg.exists(h_MinSE))
1371     {
1372     // Change interval to min from 422 response
1373     mSessionInterval = msg.header(h_MinSE).value();
1374 sgodin 4691 mMinSE = mSessionInterval;
1375 sgodin 4394 sessionRefresh();
1376     }
1377     else
1378     {
1379 sgodin 5747 // Response must contain Min_SE - if not - just ignore
1380 sgodin 5001 // ?slg? callback?
1381 sgodin 4394 transition(Connected);
1382 sgodin 5567 mProposedLocalSdp.reset();
1383 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1384 sgodin 4394 }
1385     break;
1386    
1387 jason 4010 case OnUpdateRejected:
1388 derek 7144 transition(Connected);
1389 sgodin 5567 mProposedLocalSdp.reset();
1390 derek 7144 handler->onOfferRejected(getSessionHandle(), &msg);
1391 jason 4010 break;
1392    
1393     case OnGeneralFailure:
1394     sendBye();
1395     transition(Terminated);
1396 bcampen 8200 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1397 jason 4010 break;
1398    
1399     default:
1400     dispatchOthers(msg);
1401     break;
1402     }
1403     }
1404    
1405     void
1406     InviteSession::dispatchSentReinvite(const SipMessage& msg)
1407     {
1408     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1409     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1410    
1411     switch (toEvent(msg, sdp.get()))
1412     {
1413     case OnInvite:
1414     case OnInviteReliable:
1415     case OnInviteOffer:
1416     case OnInviteReliableOffer:
1417     case OnUpdate:
1418 sgodin 4369 case OnUpdateOffer:
1419 jason 4010 {
1420 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1421     mDialog.makeResponse(*response, msg, 491);
1422 sgodin 5747 send(response);
1423 jason 4010 break;
1424 sgodin 3392 }
1425 jason 4010
1426     case On1xx:
1427     case On1xxEarly:
1428 sgodin 5001 // Some UA's send a 100 response to a ReInvite - just ignore it
1429 jason 4010 break;
1430    
1431     case On2xxAnswer:
1432 sgodin 7200 case On2xxOffer: // .slg. doesn't really make sense
1433 sgodin 3392 {
1434 sgodin 7292 mStaleReInviteTimerSeq++;
1435 jason 4010 transition(Connected);
1436     handleSessionTimerResponse(msg);
1437 daniel 5068 setCurrentLocalSdp(msg);
1438 jason 5544
1439 jason 4010 // !jf! I need to potentially include an answer in the ACK here
1440 sgodin 5747 sendAck();
1441 jason 5544 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1442    
1443     if (mSessionRefreshReInvite)
1444     {
1445     mSessionRefreshReInvite = false;
1446    
1447     MD5Stream currentRemote;
1448     currentRemote<< *mCurrentRemoteSdp;
1449     MD5Stream newRemote;
1450     newRemote << *sdp;
1451     bool changed = currentRemote.getHex() != newRemote.getHex();
1452 jason 4010
1453 jason 5544 if (changed)
1454     {
1455 jason 7102 mCurrentRemoteSdp = sdp;
1456 nash 7084 handler->onRemoteSdpChanged(getSessionHandle(), msg, *mCurrentRemoteSdp);
1457 jason 5544 }
1458     }
1459     else
1460     {
1461 sgodin 8093 mCurrentRemoteSdp = sdp;
1462 sgodin 8112 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteSdp);
1463 jason 5544 }
1464    
1465 jason 4010 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1466     // the ACK when a 200I is received? If yes, then I need to store all
1467     // ACK messages for 64*T1
1468     break;
1469     }
1470     case On2xx:
1471 sgodin 7292 mStaleReInviteTimerSeq++;
1472 sgodin 5747 sendAck();
1473 jason 4010 transition(Connected);
1474     handleSessionTimerResponse(msg);
1475     handler->onIllegalNegotiation(getSessionHandle(), msg);
1476 sgodin 5567 mProposedLocalSdp.reset();
1477 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1478 jason 4010 break;
1479    
1480 sgodin 4394 case On422Invite:
1481 sgodin 7292 mStaleReInviteTimerSeq++;
1482 sgodin 4394 if(msg.exists(h_MinSE))
1483     {
1484     // Change interval to min from 422 response
1485     mSessionInterval = msg.header(h_MinSE).value();
1486 sgodin 4691 mMinSE = mSessionInterval;
1487 sgodin 4394 sessionRefresh();
1488     }
1489     else
1490     {
1491     // Response must contact Min_SE - if not - just ignore
1492 sgodin 5001 // ?slg? callback?
1493 sgodin 4394 transition(Connected);
1494 sgodin 5567 mProposedLocalSdp.reset();
1495 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1496 sgodin 4394 }
1497     break;
1498    
1499 jason 4010 case On491Invite:
1500 sgodin 7292 mStaleReInviteTimerSeq++;
1501 sgodin 4369 transition(SentReinviteGlare);
1502 jason 4010 start491Timer();
1503     break;
1504    
1505     case OnGeneralFailure:
1506 sgodin 7292 mStaleReInviteTimerSeq++;
1507 jason 4010 sendBye();
1508     transition(Terminated);
1509 bcampen 8200 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1510 jason 4010 break;
1511    
1512     case OnInviteFailure:
1513 sgodin 5130 case On487Invite:
1514 sgodin 7292 mStaleReInviteTimerSeq++;
1515 jason 4010 transition(Connected);
1516 sgodin 5567 mProposedLocalSdp.reset();
1517 derek 5355 handler->onOfferRejected(getSessionHandle(), &msg);
1518 jason 4010 break;
1519    
1520     default:
1521     dispatchOthers(msg);
1522     break;
1523     }
1524     }
1525    
1526 sgodin 5555 void
1527     InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1528     {
1529     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1530     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1531    
1532     switch (toEvent(msg, sdp.get()))
1533     {
1534     case OnInvite:
1535     case OnInviteReliable:
1536     case OnInviteOffer:
1537     case OnInviteReliableOffer:
1538     case OnUpdate:
1539     case OnUpdateOffer:
1540     {
1541 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1542     mDialog.makeResponse(*response, msg, 491);
1543 sgodin 5747 send(response);
1544 sgodin 5555 break;
1545     }
1546    
1547     case On1xx:
1548     case On1xxEarly:
1549     // Some UA's send a 100 response to a ReInvite - just ignore it
1550     break;
1551    
1552 sgodin 7200 case On2xxAnswer: // .slg. doesn't really make sense
1553 sgodin 5555 case On2xxOffer:
1554     {
1555 sgodin 7292 mStaleReInviteTimerSeq++;
1556 sgodin 5555 transition(SentReinviteAnswered);
1557     handleSessionTimerResponse(msg);
1558 sgodin 5586 // mLastSessionModification = msg; // ?slg? why are we storing 200's?
1559 sgodin 5555 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1560 jason 7102 mProposedRemoteSdp = sdp;
1561 nash 7084 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteSdp);
1562 sgodin 5555 break;
1563     }
1564    
1565     case On2xx:
1566 sgodin 7292 mStaleReInviteTimerSeq++;
1567 sgodin 5747 sendAck();
1568 sgodin 5555 transition(Connected);
1569     handleSessionTimerResponse(msg);
1570     handler->onIllegalNegotiation(getSessionHandle(), msg);
1571 sgodin 5567 mProposedLocalSdp.reset();
1572 sgodin 5555 mProposedEncryptionLevel = DialogUsageManager::None;
1573     break;
1574    
1575     case On422Invite:
1576 sgodin 7292 mStaleReInviteTimerSeq++;
1577 sgodin 5555 if(msg.exists(h_MinSE))
1578     {
1579     // Change interval to min from 422 response
1580     mSessionInterval = msg.header(h_MinSE).value();
1581     mMinSE = mSessionInterval;
1582 sgodin 6186 sessionRefresh();
1583 sgodin 5555 }
1584     else
1585     {
1586     // Response must contact Min_SE - if not - just ignore
1587     // ?slg? callback?
1588     transition(Connected);
1589 sgodin 5567 mProposedLocalSdp.reset();
1590 sgodin 5555 mProposedEncryptionLevel = DialogUsageManager::None;
1591     }
1592     break;
1593    
1594     case On491Invite:
1595 sgodin 7292 mStaleReInviteTimerSeq++;
1596 sgodin 5555 transition(SentReinviteNoOfferGlare);
1597     start491Timer();
1598     break;
1599    
1600     case OnGeneralFailure:
1601 sgodin 7292 mStaleReInviteTimerSeq++;
1602 sgodin 5555 sendBye();
1603     transition(Terminated);
1604 bcampen 8200 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1605 sgodin 5555 break;
1606    
1607     case OnInviteFailure:
1608     case On487Invite:
1609 sgodin 7292 mStaleReInviteTimerSeq++;
1610 sgodin 5555 transition(Connected);
1611 sgodin 5567 mProposedLocalSdp.reset();
1612 sgodin 5555 handler->onOfferRejected(getSessionHandle(), &msg);
1613     break;
1614    
1615     default:
1616     dispatchOthers(msg);
1617     break;
1618     }
1619     }
1620    
1621 jason 5544 void
1622     InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1623 derek 5355 {
1624     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1625     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1626    
1627     switch (toEvent(msg, sdp.get()))
1628     {
1629     case OnInvite:
1630     case OnInviteReliable:
1631     case OnInviteOffer:
1632     case OnInviteReliableOffer:
1633     case OnUpdate:
1634     case OnUpdateOffer:
1635     {
1636 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1637     mDialog.makeResponse(*response, msg, 491);
1638 sgodin 5747 send(response);
1639 derek 5355 break;
1640     }
1641     case OnAckAnswer:
1642     transition(Connected);
1643     setCurrentLocalSdp(msg);
1644 jason 7102 mCurrentRemoteSdp = sdp;
1645 derek 5355 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1646     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1647 derek 7144
1648 vann 7159 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteSdp);
1649 derek 5355 break;
1650     case OnAck:
1651 daniel 6267 if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
1652 daniel 6266 {
1653     InfoLog(<< "dropped stale ACK");
1654     }
1655     else
1656     {
1657     InfoLog(<< "Got Ack with no answer");
1658     transition(Connected);
1659     mProposedLocalSdp.reset();
1660     mProposedEncryptionLevel = DialogUsageManager::None;
1661     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1662     //!dcm! -- should this be onIllegalNegotiation?
1663     handler->onOfferRejected(getSessionHandle(), &msg);
1664     }
1665 derek 5355 break;
1666     default:
1667     dispatchOthers(msg);
1668     break;
1669     }
1670     }
1671    
1672 jason 4010 void
1673     InviteSession::dispatchGlare(const SipMessage& msg)
1674     {
1675     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1676     MethodTypes method = msg.header(h_CSeq).method();
1677 sgodin 5555 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1678 jason 4010 {
1679 daniel 5591 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1680 sgodin 5555 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1681 derek 5355 handler->onOfferRejected(getSessionHandle(), &msg);
1682 sgodin 7404 if(!isTerminated()) // make sure application didn't call end()
1683     {
1684     dispatchConnected(msg); // act as if we received message in Connected state
1685     }
1686     else
1687     {
1688     dispatchTerminated(msg);
1689     }
1690 jason 4010 }
1691 sgodin 5555 else
1692 jason 4010 {
1693 sgodin 5555 dispatchOthers(msg);
1694 jason 4010 }
1695 sgodin 5555 }
1696    
1697     void
1698     InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1699     {
1700     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1701     MethodTypes method = msg.header(h_CSeq).method();
1702     if (msg.isRequest() && (method == INVITE || method == UPDATE))
1703     {
1704     // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1705     handler->onOfferRequestRejected(getSessionHandle(), msg);
1706 sgodin 7404 if(!isTerminated()) // make sure application didn't call end()
1707     {
1708     dispatchConnected(msg); // act as if we received message in Connected state
1709     }
1710     else
1711     {
1712     dispatchTerminated(msg);
1713     }
1714 sgodin 5555 }
1715 jason 4010 else
1716     {
1717     dispatchOthers(msg);
1718     }
1719     }
1720    
1721     void
1722     InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1723     {
1724     MethodTypes method = msg.header(h_CSeq).method();
1725     if (method == INVITE || method == UPDATE)
1726     {
1727     // Means that the UAC has sent us a second reINVITE or UPDATE before we
1728     // responded to the first one. Bastard!
1729 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1730     mDialog.makeResponse(*response, msg, 500);
1731     response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1732 daniel 5505 send(response);
1733 jason 4010 }
1734     else
1735     {
1736     dispatchOthers(msg);
1737     }
1738     }
1739    
1740    
1741     void
1742     InviteSession::dispatchAnswered(const SipMessage& msg)
1743     {
1744     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1745     {
1746     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1747     transition(Connected);
1748     }
1749     else
1750     {
1751     dispatchOthers(msg);
1752     }
1753     }
1754    
1755     void
1756 sgodin 5555 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1757     {
1758 sgodin 6076 if (msg.isResponse() &&
1759     msg.header(h_CSeq).method() == INVITE &&
1760     msg.header(h_StatusLine).statusCode() / 200 == 1)
1761     {
1762     // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
1763     // called by the app - so just drop the retransmission
1764     return;
1765     }
1766 sgodin 5555 dispatchOthers(msg);
1767     }
1768    
1769     void
1770 jason 4010 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1771     {
1772     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1773     {
1774 daniel 5068 assert(mProposedLocalSdp.get());
1775 jason 4010 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1776 sgodin 5555 provideProposedOffer();
1777 jason 4010 }
1778     else
1779     {
1780     dispatchOthers(msg);
1781     }
1782     }
1783    
1784     void
1785 sgodin 5555 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1786     {
1787     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1788     {
1789     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1790     requestOffer();
1791     }
1792     else
1793     {
1794     dispatchOthers(msg);
1795     }
1796     }
1797    
1798     void
1799 jason 4010 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1800     {
1801     if (msg.isResponse() &&
1802     msg.header(h_CSeq).method() == INVITE)
1803     {
1804     if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1805     {
1806     // !jf! Need to include the answer here.
1807 sgodin 5747 sendAck();
1808 jason 4010 }
1809     sendBye();
1810     transition(Terminated);
1811 bcampen 8200 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1812 jason 4010 }
1813 sgodin 7292 else if(msg.isRequest())
1814     {
1815     if(msg.method() == BYE)
1816     {
1817     dispatchBye(msg);
1818     }
1819     else
1820     {
1821     SharedPtr<SipMessage> response(new SipMessage);
1822     mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
1823     send(response);
1824     }
1825     }
1826 jason 4010 }
1827    
1828     void
1829 sgodin 5377 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1830     {
1831     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1832    
1833     switch (toEvent(msg, sdp.get()))
1834     {
1835     case OnAck:
1836     case OnAckAnswer:
1837     {
1838     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1839    
1840     sendBye();
1841     transition(Terminated);
1842 bcampen 8200 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1843 sgodin 5377 break;
1844     }
1845    
1846     default:
1847     break;
1848     }
1849     }
1850    
1851     void
1852 jason 4010 InviteSession::dispatchTerminated(const SipMessage& msg)
1853     {
1854     InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1855    
1856     if (msg.isRequest())
1857     {
1858 daniel 6912 if (BYE == msg.header(h_CSeq).method())
1859     {
1860     SharedPtr<SipMessage> response(new SipMessage);
1861     mDialog.makeResponse(*response, msg, 200);
1862     send(response);
1863     }
1864     else
1865     {
1866     SharedPtr<SipMessage> response(new SipMessage);
1867     mDialog.makeResponse(*response, msg, 481);
1868     send(response);
1869     }
1870 jason 4010
1871     // !jf! means the peer sent BYE while we are waiting for response to BYE
1872     //mDum.destroy(this);
1873     }
1874     else
1875     {
1876     mDum.destroy(this);
1877     }
1878     }
1879    
1880     void
1881     InviteSession::dispatchOthers(const SipMessage& msg)
1882     {
1883     // handle OnGeneralFailure
1884     // handle OnRedirect
1885    
1886     switch (msg.header(h_CSeq).method())
1887     {
1888     case PRACK:
1889     dispatchPrack(msg);
1890     break;
1891     case CANCEL:
1892     dispatchCancel(msg);
1893     break;
1894     case BYE:
1895     dispatchBye(msg);
1896     break;
1897     case INFO:
1898     dispatchInfo(msg);
1899     break;
1900 sgodin 5265 case MESSAGE:
1901     dispatchMessage(msg);
1902     break;
1903 jason 4010 case ACK:
1904     // Ignore duplicate ACKs from 2xx reTransmissions
1905     break;
1906     default:
1907     // handled in Dialog
1908     WarningLog (<< "DUM delivered a "
1909     << msg.header(h_CSeq).unknownMethodName()
1910 derek 7144 << " to the InviteSession in state: " << toData(mState)
1911 jason 4010 << endl
1912     << msg);
1913     assert(0);
1914     break;
1915     }
1916     }
1917    
1918     void
1919     InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
1920     {
1921     assert(msg.isRequest());
1922     assert(msg.header(h_CSeq).method() == INVITE);
1923    
1924     // If we get an INVITE request from the wire and we are not in
1925     // Connected state, reject the request and send a BYE
1926 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1927     mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
1928     InfoLog (<< "Sending " << response->brief());
1929 daniel 5505 send(response);
1930 jason 4010
1931     sendBye();
1932     transition(Terminated);
1933 bcampen 8200 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1934 jason 4010 }
1935    
1936     void
1937     InviteSession::dispatchPrack(const SipMessage& msg)
1938     {
1939     assert(msg.header(h_CSeq).method() == PRACK);
1940     if(msg.isRequest())
1941     {
1942 daniel 5757 SharedPtr<SipMessage> rsp(new SipMessage);
1943     mDialog.makeResponse(*rsp, msg, 481);
1944 daniel 5505 send(rsp);
1945 jason 4010
1946     sendBye();
1947     // !jf! should we make some other callback here
1948     transition(Terminated);
1949 bcampen 8200 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1950 jason 4010 }
1951     else
1952     {
1953     // ignore. could be PRACK/200
1954     }
1955     }
1956    
1957     void
1958     InviteSession::dispatchCancel(const SipMessage& msg)
1959     {
1960     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1961     assert(msg.header(h_CSeq).method() == CANCEL);
1962     if(msg.isRequest())
1963     {
1964 daniel 5757 SharedPtr<SipMessage> rsp(new SipMessage);
1965     mDialog.makeResponse(*rsp, msg, 200);
1966 daniel 5505 send(rsp);
1967 jason 4010
1968     sendBye();
1969     // !jf! should we make some other callback here
1970     transition(Terminated);
1971 bcampen 8200
1972     handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteCancel, &msg);
1973 jason 4010 }
1974     else
1975     {
1976     WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1977     assert(0);
1978     }
1979     }
1980    
1981     void
1982     InviteSession::dispatchBye(const SipMessage& msg)
1983     {
1984     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1985    
1986     if (msg.isRequest())
1987     {
1988    
1989 daniel 5757 SharedPtr<SipMessage> rsp(new SipMessage);
1990 jason 4010 InfoLog (<< "Received " << msg.brief());
1991 daniel 5757 mDialog.makeResponse(*rsp, msg, 200);
1992 daniel 5505 send(rsp);
1993 jason 4010
1994     // !jf! should we make some other callback here
1995     transition(Terminated);
1996 bcampen 8200
1997     if (mDum.mDialogEventStateManager)
1998     {
1999     mDum.mDialogEventStateManager->onTerminated(mDialog, msg,
2000     InviteSessionHandler::RemoteBye);
2001     }
2002    
2003     handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
2004 jason 4010 mDum.destroy(this);
2005     }
2006     else
2007     {
2008     WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
2009     assert(0);
2010     }
2011     }
2012    
2013     void
2014     InviteSession::dispatchInfo(const SipMessage& msg)
2015     {
2016     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2017     if (msg.isRequest())
2018     {
2019     InfoLog (<< "Received " << msg.brief());
2020 daniel 5757 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2021 jason 4010 handler->onInfo(getSessionHandle(), msg);
2022     }
2023     else
2024     {
2025     assert(mNitState == NitProceeding);
2026     //!dcm! -- toss away 1xx to an info?
2027     if (msg.header(h_StatusLine).statusCode() >= 300)
2028     {
2029     handler->onInfoFailure(getSessionHandle(), msg);
2030     }
2031     else if (msg.header(h_StatusLine).statusCode() >= 200)
2032     {
2033     handler->onInfoSuccess(getSessionHandle(), msg);
2034     }
2035 sgodin 7565 nitComplete();
2036 jason 4010 }
2037     }
2038    
2039     void
2040 sgodin 5592 InviteSession::acceptNIT(int statusCode, const Contents * contents)
2041 jason 4010 {
2042     if (statusCode / 100 != 2)
2043     {
2044     throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2045     }
2046    
2047 daniel 5757 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2048     mLastNitResponse->setContents(contents);
2049     Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2050 sgodin 5747 send(mLastNitResponse);
2051 jason 4010 }
2052    
2053 nash 7042 class InviteSessionAcceptNITCommand : public DumCommandAdapter
2054     {
2055     public:
2056     InviteSessionAcceptNITCommand(InviteSession& inviteSession, int statusCode, const Contents* contents)
2057     : mInviteSession(inviteSession),
2058     mStatusCode(statusCode),
2059     mContents(contents?contents->clone():0)
2060     {
2061    
2062     }
2063    
2064     virtual void executeCommand()
2065     {
2066     mInviteSession.acceptNITCommand(mStatusCode, mContents.get());
2067     }
2068    
2069 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2070 nash 7042 {
2071     return strm << "InviteSessionAcceptNITCommand";
2072     }
2073     private:
2074     InviteSession& mInviteSession;
2075     int mStatusCode;
2076     std::auto_ptr<Contents> mContents;
2077     };
2078    
2079 jason 4010 void
2080 nash 7042 InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
2081     {
2082 bcampen 7081 mDum.post(new InviteSessionAcceptNITCommand(*this, statusCode, contents));
2083 nash 7042 }
2084    
2085     void
2086 sgodin 5265 InviteSession::rejectNIT(int statusCode)
2087 jason 4010 {
2088     if (statusCode < 400)
2089     {
2090     throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2091     }
2092 daniel 5757 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2093 sgodin 8400 mLastNitResponse->setContents(0);
2094 daniel 5757 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2095 sgodin 5747 send(mLastNitResponse);
2096 jason 4010 }
2097    
2098 nash 7042 class InviteSessionRejectNITCommand : public DumCommandAdapter
2099     {
2100     public:
2101     InviteSessionRejectNITCommand(InviteSession& inviteSession, int statusCode)
2102     : mInviteSession(inviteSession),
2103     mStatusCode(statusCode)
2104     {
2105     }
2106    
2107     virtual void executeCommand()
2108     {
2109     mInviteSession.rejectNITCommand(mStatusCode);
2110     }
2111    
2112 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2113 nash 7042 {
2114     return strm << "InviteSessionRejectNITCommand";
2115     }
2116     private:
2117     InviteSession& mInviteSession;
2118     int mStatusCode;
2119     };
2120    
2121 jason 4010 void
2122 nash 7042 InviteSession::rejectNITCommand(int statusCode)
2123     {
2124 bcampen 7081 mDum.post(new InviteSessionRejectNITCommand(*this, statusCode));
2125 nash 7042 }
2126    
2127     void
2128 sgodin 5265 InviteSession::dispatchMessage(const SipMessage& msg)
2129     {
2130     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2131     if (msg.isRequest())
2132     {
2133     InfoLog (<< "Received " << msg.brief());
2134 daniel 5757 mDialog.makeResponse(*mLastNitResponse, msg, 200);
2135     mLastNitResponse->header(h_Contacts).clear();
2136 sgodin 5265 handler->onMessage(getSessionHandle(), msg);
2137     }
2138     else
2139     {
2140     assert(mNitState == NitProceeding);
2141     //!dcm! -- toss away 1xx to an message?
2142     if (msg.header(h_StatusLine).statusCode() >= 300)
2143     {
2144     handler->onMessageFailure(getSessionHandle(), msg);
2145     }
2146     else if (msg.header(h_StatusLine).statusCode() >= 200)
2147     {
2148     handler->onMessageSuccess(getSessionHandle(), msg);
2149     }
2150 sgodin 7565 nitComplete();
2151 sgodin 5265 }
2152     }
2153    
2154     void
2155 jason 4010 InviteSession::startRetransmit200Timer()
2156     {
2157     mCurrentRetransmit200 = Timer::T1;
2158 sgodin 6416 unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
2159 jason 4010 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
2160     mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
2161     }
2162    
2163 daniel 5591 // RFC3261 section 14.1
2164     // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
2165     // a value T chosen as follows:
2166     // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
2167     // chosen value between 2.1 and 4 seconds in units of 10 ms.
2168     // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
2169     // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
2170 jason 4010 void
2171     InviteSession::start491Timer()
2172     {
2173 sgodin 6416 unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
2174 daniel 5591
2175     if (dynamic_cast<ClientInviteSession*>(this))
2176     {
2177     int timer = Random::getRandom() % (4000 - 2100);
2178     timer += 2100;
2179     timer -= timer % 10;
2180    
2181     DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2182     mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2183     }
2184     else
2185     {
2186     int timer = Random::getRandom() % 2000;
2187     timer -= timer % 10;
2188     DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2189     mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2190     }
2191 jason 4010 }
2192    
2193 sgodin 4369 void
2194 sgodin 7292 InviteSession::startStaleReInviteTimer()
2195     {
2196     InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
2197     unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
2198    
2199     mDum.addTimer(DumTimeout::StaleReInvite,
2200     when,
2201     getBaseHandle(),
2202     ++mStaleReInviteTimerSeq);
2203     }
2204    
2205     void
2206 sgodin 4369 InviteSession::setSessionTimerHeaders(SipMessage &msg)
2207     {
2208     if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
2209     {
2210     msg.header(h_SessionExpires).value() = mSessionInterval;
2211 sgodin 4691 if(msg.isRequest())
2212     {
2213     msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
2214     }
2215     else
2216     {
2217     msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
2218     }
2219     msg.header(h_MinSE).value() = mMinSE;
2220 sgodin 4369 }
2221     else
2222     {
2223     msg.remove(h_SessionExpires);
2224     msg.remove(h_MinSE);
2225     }
2226     }
2227    
2228 jason 4010 void
2229 sgodin 4369 InviteSession::sessionRefresh()
2230     {
2231     if (updateMethodSupported())
2232     {
2233     transition(SentUpdate);
2234 daniel 5757 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
2235 sgodin 8400 mLastLocalSessionModification->setContents(0); // Don't send SDP
2236 sgodin 4369 }
2237     else
2238     {
2239     transition(SentReinvite);
2240 daniel 5757 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
2241 sgodin 7292 startStaleReInviteTimer();
2242 daniel 5757 InviteSession::setSdp(*mLastLocalSessionModification, mCurrentLocalSdp.get());
2243 daniel 5068 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
2244 jason 5544 mSessionRefreshReInvite = true;
2245 sgodin 4369 }
2246 daniel 5757 setSessionTimerHeaders(*mLastLocalSessionModification);
2247 sgodin 4369
2248 daniel 5757 InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
2249     DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
2250 sgodin 5747 send(mLastLocalSessionModification);
2251 sgodin 4369 }
2252    
2253     void
2254 sgodin 4691 InviteSession::setSessionTimerPreferences()
2255     {
2256     mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
2257     if(mSessionInterval != 0)
2258     {
2259     // If session timers are no disabled then ensure interval is greater than or equal to MinSE
2260     mSessionInterval = resipMax(mMinSE, mSessionInterval);
2261     }
2262     switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
2263     {
2264     case Profile::PreferLocalRefreshes:
2265     mSessionRefresher = true; // Default refresher is Local
2266     break;
2267     case Profile::PreferRemoteRefreshes:
2268     mSessionRefresher = false; // Default refresher is Remote
2269     break;
2270     case Profile::PreferUASRefreshes:
2271     mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
2272     break;
2273     case Profile::PreferUACRefreshes:
2274     mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
2275     break;
2276     }
2277     }
2278    
2279     void
2280     InviteSession::startSessionTimer()
2281     {
2282     if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
2283     {
2284     // Check if we are the refresher
2285     if(mSessionRefresher)
2286     {
2287     // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
2288     mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
2289     }
2290     else
2291     {
2292     // 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)
2293 sgodin 6507 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
2294 sgodin 4691 }
2295     }
2296     else // Session Interval less than 90 - consider timers disabled
2297     {
2298     ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
2299     }
2300     }
2301    
2302     void
2303 jason 4010 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
2304     {
2305     assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
2306    
2307 sgodin 6755 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2308     if (msg.exists(h_PAssertedIdentities))
2309     {
2310     mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
2311     }
2312    
2313 jason 4010 // If session timers are locally supported then handle response
2314     if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2315     {
2316 sgodin 4691 setSessionTimerPreferences();
2317 jason 4010
2318     if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
2319     && !msg.exists(h_SessionExpires))
2320     {
2321     // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
2322     mSessionInterval = 0;
2323     }
2324     // Process Session Timer headers
2325     else if(msg.exists(h_SessionExpires))
2326     {
2327 sgodin 3392 mSessionInterval = msg.header(h_SessionExpires).value();
2328     if(msg.header(h_SessionExpires).exists(p_refresher))
2329     {
2330 jason 4010 // Remote end specified refresher preference
2331 sgodin 4691 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
2332 sgodin 3392 }
2333     }
2334 jason 4010 else
2335     {
2336     // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
2337     // - we are free to use our SessionInterval settings (set above as a default)
2338     // If far end doesn't support then refresher must be local
2339 sgodin 4691 mSessionRefresher = true;
2340 jason 4010 }
2341 sgodin 3392
2342 sgodin 4691 // Update MinSE if specified and longer than current value
2343     if(msg.exists(h_MinSE))
2344 sgodin 3392 {
2345 sgodin 4691 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
2346 sgodin 3392 }
2347 sgodin 4691
2348     startSessionTimer();
2349 sgodin 3392 }
2350     }
2351    
2352 jason 4010 void
2353     InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
2354 sgodin 3392 {
2355 jason 4010 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
2356    
2357 sgodin 6755 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2358     if (request.exists(h_PAssertedIdentities))
2359     {
2360     mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
2361     }
2362    
2363 sgodin 3392 // If session timers are locally supported then add necessary headers to response
2364 jason 4010 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2365 sgodin 3392 {
2366 sgodin 4691 setSessionTimerPreferences();
2367 sgodin 3392
2368     // Check if far-end supports
2369     bool farEndSupportsTimer = false;
2370     if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
2371     {
2372     farEndSupportsTimer = true;
2373     if(request.exists(h_SessionExpires))
2374     {
2375 jason 4010 // Use Session Interval requested by remote - if none then use local settings
2376 sgodin 3392 mSessionInterval = request.header(h_SessionExpires).value();
2377     if(request.header(h_SessionExpires).exists(p_refresher))
2378     {
2379 sgodin 4691 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
2380 sgodin 3392 }
2381     }
2382 sgodin 4691
2383     // Update MinSE if specified and longer than current value
2384     if(request.exists(h_MinSE))
2385     {
2386     mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
2387     }
2388 sgodin 3392 }
2389 jason 4010 else
2390     {
2391     // If far end doesn't support then refresher must be local
2392 sgodin 4691 mSessionRefresher = true;
2393 jason 4010 }
2394 sgodin 3392
2395 jason 4010 // Add Session-Expires to response if required
2396 sgodin 3392 if(mSessionInterval >= 90)
2397     {
2398 jason 4010 if(farEndSupportsTimer)
2399 sgodin 3392 {
2400 jason 4010 // If far end supports session-timer then require it, if not already present
2401     if(!response.header(h_Requires).find(Token(Symbols::Timer)))
2402     {
2403     response.header(h_Requires).push_back(Token(Symbols::Timer));
2404     }
2405 sgodin 3392 }
2406 sgodin 4691 setSessionTimerHeaders(response);
2407     }
2408 sgodin 3392
2409 sgodin 4691 startSessionTimer();
2410 sgodin 3392 }
2411     }
2412    
2413 jason 4010 Data
2414     InviteSession::toData(State state)
2415 jason 2856 {
2416 jason 4010 switch (state)
2417 derek 3255 {
2418 jason 4010 case Undefined:
2419     return "InviteSession::Undefined";
2420     case Connected:
2421     return "InviteSession::Connected";
2422     case SentUpdate:
2423     return "InviteSession::SentUpdate";
2424     case SentUpdateGlare:
2425     return "InviteSession::SentUpdateGlare";
2426     case SentReinvite:
2427     return "InviteSession::SentReinvite";
2428     case SentReinviteGlare:
2429     return "InviteSession::SentReinviteGlare";
2430 sgodin 5555 case SentReinviteNoOffer:
2431     return "InviteSession::SentReinviteNoOffer";
2432     case SentReinviteAnswered:
2433     return "InviteSession::SentReinviteAnswered";
2434     case SentReinviteNoOfferGlare:
2435     return "InviteSession::SentReinviteNoOfferGlare";
2436 jason 4010 case ReceivedUpdate:
2437     return "InviteSession::ReceivedUpdate";
2438     case ReceivedReinvite:
2439     return "InviteSession::ReceivedReinvite";
2440     case ReceivedReinviteNoOffer:
2441     return "InviteSession::ReceivedReinviteNoOffer";
2442 derek 5355 case ReceivedReinviteSentOffer:
2443     return "InviteSession::ReceivedReinviteSentOffer";
2444 jason 4010 case Answered:
2445     return "InviteSession::Answered";
2446     case WaitingToOffer:
2447     return "InviteSession::WaitingToOffer";
2448 sgodin 5555 case WaitingToRequestOffer:
2449     return "InviteSession::WaitingToRequestOffer";
2450 jason 4010 case WaitingToTerminate:
2451     return "InviteSession::WaitingToTerminate";
2452 sgodin 5377 case WaitingToHangup:
2453     return "InviteSession::WaitingToHangup";
2454 derek 2961 case Terminated:
2455 jason 4010 return "InviteSession::Terminated";
2456 jason 2856
2457 jason 4010 case UAC_Start:
2458     return "UAC_Start";
2459     case UAS_Offer:
2460     return "UAS_Offer";
2461     case UAS_OfferProvidedAnswer:
2462     return "UAS_OfferProvidedAnswer";
2463     case UAS_EarlyOffer:
2464     return "UAS_EarlyOffer";
2465     case UAS_EarlyProvidedAnswer:
2466     return "UAS_EarlyProvidedAnswer";
2467     case UAS_NoOffer:
2468     return "UAS_NoOffer";
2469     case UAS_ProvidedOffer:
2470     return "UAS_ProvidedOffer";
2471     case UAS_EarlyNoOffer:
2472     return "UAS_EarlyNoOffer";
2473     case UAS_EarlyProvidedOffer:
2474     return "UAS_EarlyProvidedOffer";
2475     case UAS_Accepted:
2476     return "UAS_Accepted";
2477     case UAS_WaitingToOffer:
2478     return "UAS_WaitingToOffer";
2479     case UAS_AcceptedWaitingAnswer:
2480     return "UAS_AcceptedWaitingAnswer";
2481     case UAC_Early:
2482     return "UAC_Early";
2483     case UAC_EarlyWithOffer:
2484     return "UAC_EarlyWithOffer";
2485     case UAC_EarlyWithAnswer:
2486     return "UAC_EarlyWithAnswer";
2487     case UAC_Answered:
2488     return "UAC_Answered";
2489     case UAC_SentUpdateEarly:
2490     return "UAC_SentUpdateEarly";
2491 derek 7144 case UAC_SentUpdateEarlyGlare:
2492     return "UAC_SentUpdateEarlyGlare";
2493 jason 4010 case UAC_ReceivedUpdateEarly:
2494     return "UAC_ReceivedUpdateEarly";
2495     case UAC_SentAnswer:
2496     return "UAC_SentAnswer";
2497     case UAC_QueuedUpdate:
2498     return "UAC_QueuedUpdate";
2499     case UAC_Cancelled:
2500     return "UAC_Cancelled";
2501 derek 7144
2502 jason 4010 case UAS_Start:
2503     return "UAS_Start";
2504 derek 7144 case UAS_ReceivedOfferReliable:
2505     return "UAS_ReceivedOfferReliable";
2506 jason 4010 case UAS_NoOfferReliable:
2507     return "UAS_NoOfferReliable";
2508     case UAS_FirstSentOfferReliable:
2509     return "UAS_FirstSentOfferReliable";
2510 derek 7144 case UAS_FirstSentAnswerReliable:
2511     return "UAS_FirstSentAnswerReliable";
2512     case UAS_NegotiatedReliable:
2513     return "UAS_NegotiatedReliable";
2514 jason 4010 case UAS_SentUpdate:
2515     return "UAS_SentUpdate";
2516     case UAS_SentUpdateAccepted:
2517     return "UAS_SentUpdateAccepted";
2518     case UAS_ReceivedUpdate:
2519     return "UAS_ReceivedUpdate";
2520     case UAS_ReceivedUpdateWaitingAnswer:
2521     return "UAS_ReceivedUpdateWaitingAnswer";
2522     case UAS_WaitingToTerminate:
2523     return "UAS_WaitingToTerminate";
2524     case UAS_WaitingToHangup:
2525     return "UAS_WaitingToHangup";
2526 sgodin 6139 case UAS_WaitingToRequestOffer:
2527     return "UAS_WaitingToRequestOffer";
2528 jason 4010 }
2529     assert(0);
2530     return "Undefined";
2531     }
2532 sgodin 3392
2533    
2534 jason 4010 void
2535     InviteSession::transition(State target)
2536     {
2537     InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
2538     mState = target;
2539     }
2540 sgodin 3392
2541 jason 4010 bool
2542     InviteSession::isReliable(const SipMessage& msg)
2543     {
2544 derek 7144 if(msg.method() != INVITE)
2545     {
2546     return false;
2547     }
2548     if(msg.isRequest())
2549     {
2550     return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never
2551     && (msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel))
2552     || msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel)));
2553     }
2554     else
2555     {
2556 vann 7227 return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never
2557     && (msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel))
2558     || (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
2559 derek 7144 }
2560 jason 2856 }
2561    
2562 jason 4010 std::auto_ptr<SdpContents>
2563     InviteSession::getSdp(const SipMessage& msg)
2564 derek 3255 {
2565 daniel 5591 return Helper::getSdp(msg.getContents());
2566 derek 3255 }
2567    
2568 jason 4010 std::auto_ptr<SdpContents>
2569     InviteSession::makeSdp(const SdpContents& sdp)
2570 derek 2955 {
2571 jason 4010 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
2572 derek 2955 }
2573 jason 2856
2574 daniel 5068 auto_ptr<Contents>
2575     InviteSession::makeSdp(const SdpContents& sdp,
2576     const SdpContents* alternative)
2577     {
2578     if (alternative)
2579     {
2580     MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2581     mac->parts().push_back(alternative->clone());
2582     mac->parts().push_back(sdp.clone());
2583     return auto_ptr<Contents>(mac);
2584     }
2585     else
2586     {
2587     return auto_ptr<Contents>(sdp.clone());
2588     }
2589     }
2590    
2591 jason 4010 void
2592 daniel 5068 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
2593 derek 3112 {
2594 jason 4010 // !jf! should deal with multipart here
2595 derek 3112
2596 jason 4010 // This will clone the sdp since the InviteSession also wants to keep its own
2597     // copy of the sdp around for the application to access
2598 daniel 5068 if (alternative)
2599     {
2600     MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2601     mac->parts().push_back(alternative->clone());
2602     mac->parts().push_back(sdp.clone());
2603     msg.setContents(auto_ptr<Contents>(mac));
2604     }
2605     else
2606     {
2607     msg.setContents(&sdp);
2608     }
2609 derek 3112 }
2610    
2611 daniel 5068 void
2612     InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
2613     {
2614     assert(sdp);
2615     msg.setContents(sdp);
2616     }
2617    
2618 sgodin 5555 void
2619     InviteSession::provideProposedOffer()
2620     {
2621     if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2622     {
2623     provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
2624     mProposedEncryptionLevel,
2625     dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
2626     }
2627     else
2628     {
2629     provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
2630     }
2631     }
2632    
2633 jason 4010 InviteSession::Event
2634     InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
2635 jason 2621 {
2636 jason 4010 MethodTypes method = msg.header(h_CSeq).method();
2637     int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2638 derek 7144
2639     //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
2640     //responses, reiable provisionals should only be received if the invite was
2641     //sent reliably. Spurious reliable provisional respnoses are dropped outside
2642     //the state machine.
2643 jason 4010 bool reliable = isReliable(msg);
2644     bool sentOffer = mProposedLocalSdp.get();
2645    
2646     if (code == 481 || code == 408)
2647 derek 2961 {
2648 jason 4010 return OnGeneralFailure;
2649     }
2650     else if (code >= 300 && code <= 399)
2651     {
2652     return OnRedirect;
2653     }
2654     else if (method == INVITE && code == 0)
2655     {
2656     if (sdp)
2657     {
2658     if (reliable)
2659 sgodin 3363 {
2660 jason 4010 return OnInviteReliableOffer;
2661     }
2662     else
2663     {
2664     return OnInviteOffer;
2665     }
2666     }
2667     else
2668     {
2669     if (reliable)
2670     {
2671     return OnInviteReliable;
2672     }
2673     else
2674     {
2675     return OnInvite;
2676     }
2677     }
2678     }
2679 derek 7144 else if (method == INVITE && code > 100 && code < 200)
2680 jason 4010 {
2681     if (reliable)
2682     {
2683     if (sdp)
2684     {
2685     if (sentOffer)
2686 sgodin 3363 {
2687 jason 4010 return On1xxAnswer;
2688 sgodin 3363 }
2689     else
2690     {
2691 jason 4010 return On1xxOffer;
2692 sgodin 3363 }
2693     }
2694     else
2695     {
2696 jason 4010 return On1xx;
2697 sgodin 3363 }
2698 jason 4010 }
2699     else
2700     {
2701     if (sdp)
2702 sgodin 3363 {
2703 jason 4010 return On1xxEarly;
2704 sgodin 3363 }
2705     else
2706     {
2707 jason 4010 return On1xx;
2708 sgodin 3363 }
2709 jason 4010 }
2710 derek 2961 }
2711 jason 4010 else if (method == INVITE && code >= 200 && code < 300)
2712 jason 2809 {
2713 jason 4010 if (sdp)
2714     {
2715     if (sentOffer)
2716 jason 2809 {
2717 jason 4010 return On2xxAnswer;
2718 jason 2809 }
2719     else
2720     {
2721 jason 4010 return On2xxOffer;
2722 jason 2809 }
2723 jason 4010 }
2724     else
2725     {
2726     return On2xx;
2727     }
2728 jason 2809 }
2729 sgodin 4394 else if (method == INVITE && code == 422)
2730     {
2731     return On422Invite;
2732     }
2733 jason 4010 else if (method == INVITE && code == 487)
2734 derek 3293 {
2735 jason 4010 return On487Invite;
2736 derek 3293 }
2737 jason 4010 else if (method == INVITE && code == 491)
2738 derek 2965 {
2739 jason 4010 return On491Invite;
2740 derek 2965 }
2741 jason 4010 else if (method == INVITE && code >= 400)
2742 derek 2965 {
2743 jason 4010 return OnInviteFailure;
2744     }
2745     else if (method == ACK)
2746     {
2747     if (sdp)
2748 derek 2965 {
2749 jason 4010 return OnAckAnswer;
2750 derek 2965 }
2751 derek 2978 else
2752     {
2753 jason 4010 return OnAck;
2754 derek 2978 }
2755 jason 4010 }
2756     else if (method == CANCEL && code == 0)
2757 jason 2809 {
2758 jason 4010 return OnCancel;
2759 jason 2809 }
2760 jason 4010 else if (method == CANCEL && code / 200 == 1)
2761 sgodin 3338 {
2762 jason 4010 return On200Cancel;
2763 sgodin 3338 }
2764 jason 4010 else if (method == CANCEL && code >= 400)
2765 sgodin 3338 {
2766 jason 4010 return OnCancelFailure;
2767 sgodin 3338 }
2768 jason 4010 else if (method == BYE && code == 0)
2769 jason 2846 {
2770 jason 4010 return OnBye;
2771 jason 2846 }
2772 jason 4010 else if (method == BYE && code / 200 == 1)
2773 derek 3101 {
2774 jason 4010 return On200Bye;
2775 derek 3101 }
2776 jason 4010 else if (method == PRACK && code == 0)
2777     {
2778     return OnPrack;
2779     }
2780     else if (method == PRACK && code / 200 == 1)
2781     {
2782     return On200Prack;
2783     }
2784     else if (method == UPDATE && code == 0)
2785     {
2786 sgodin 4369 if (sdp)
2787     {
2788     return OnUpdateOffer;
2789     }
2790     else
2791     {
2792     return OnUpdate;
2793     }
2794 jason 4010 }
2795     else if (method == UPDATE && code / 200 == 1)
2796     {
2797     return On200Update;
2798     }
2799 sgodin 4394 else if (method == UPDATE && code == 422)
2800     {
2801     return On422Update;
2802     }
2803 jason 4010 else if (method == UPDATE && code == 491)
2804     {
2805     return On491Update;
2806     }
2807     else if (method == UPDATE && code >= 400)
2808     {
2809     return OnUpdateRejected;
2810     }
2811     else
2812     {
2813 sgodin 5012 //assert(0); // dispatchOthers will throw if the message type is really unknown
2814 jason 4010 return Unknown;
2815     }
2816 derek 2965 }
2817    
2818 sgodin 5747 void InviteSession::sendAck(const SdpContents *sdp)
2819 derek 2955 {
2820 daniel 5757 SharedPtr<SipMessage> ack(new SipMessage);
2821 sgodin 5586
2822 jmatthewsr 7238 assert(mAcks.count(mLastLocalSessionModification->getTransactionId()) == 0);
2823 derek 7144 SharedPtr<SipMessage> source;
2824    
2825     if (mLastLocalSessionModification->method() == UPDATE)
2826     {
2827     //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
2828     source = mDialog.mDialogSet.getCreator()->getLastRequest();
2829     }
2830     else
2831     {
2832     source = mLastLocalSessionModification;
2833     }
2834 sgodin 5586
2835 daniel 5757 mDialog.makeRequest(*ack, ACK);
2836 sgodin 5586
2837     // Copy Authorization, Proxy Authorization headers and CSeq from original Invite
2838 derek 7144 if(source->exists(h_Authorizations))
2839 sgodin 5586 {
2840 derek 7144 ack->header(h_Authorizations) = source->header(h_Authorizations);
2841 sgodin 5586 }
2842 derek 7144 if(source->exists(h_ProxyAuthorizations))
2843 sgodin 5586 {
2844 derek 7144 ack->header(h_ProxyAuthorizations) = source->header(h_ProxyAuthorizations);
2845 sgodin 5586 }
2846 derek 7144 ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
2847 sgodin 5586
2848 jason 4010 if(sdp != 0)
2849 derek 3255 {
2850 daniel 5757 setSdp(*ack, *sdp);
2851 derek 3255 }
2852 sgodin 7424 mAcks[source->getTransactionId()] = ack;
2853     mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(), 0, source->getTransactionId());
2854 sgodin 5586
2855 daniel 5757 InfoLog (<< "Sending " << ack->brief());
2856 daniel 5505 send(ack);
2857 derek 2981 }
2858    
2859 jason 4010 void InviteSession::sendBye()
2860 derek 2849 {
2861 daniel 5757 SharedPtr<SipMessage> bye(new SipMessage());
2862     mDialog.makeRequest(*bye, BYE);
2863 daniel 6047 Data txt;
2864 derek 5531 if (mEndReason != NotSpecified)
2865     {
2866 daniel 6047 Token reason("SIP");
2867     txt = getEndReasonString(mEndReason);
2868     reason.param(p_description) = txt;
2869     bye->header(h_Reasons).push_back(reason);
2870 derek 5531 }
2871 bcampen 8200
2872     if (mDum.mDialogEventStateManager)
2873     {
2874     mDum.mDialogEventStateManager->onTerminated(mDialog, *bye, InviteSessionHandler::LocalBye);
2875     }
2876 derek 5531
2877 daniel 6047 InfoLog (<< myAddr() << " Sending BYE " << txt);
2878 daniel 5505 send(bye);
2879 jason 4010 }
2880 derek 2992
2881 daniel 5068 DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg)
2882     {
2883     DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
2884     const SecurityAttributes* secAttr = msg.getSecurityAttributes();
2885     if (secAttr)
2886     {
2887     SignatureStatus sig = secAttr->getSignatureStatus();
2888     bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
2889     bool encrypted = secAttr->isEncrypted();
2890     if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
2891     else if (encrypted) level = DialogUsageManager::Encrypt;
2892     else if (sign) level = DialogUsageManager::Sign;
2893     }
2894     return level;
2895     }
2896 derek 2992
2897 daniel 5068 void InviteSession::setCurrentLocalSdp(const SipMessage& msg)
2898     {
2899     assert(mProposedLocalSdp.get());
2900     if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2901     {
2902     if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
2903     {
2904     mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone()));
2905     }
2906     else
2907     {
2908     mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone()));
2909     }
2910     }
2911     else
2912     {
2913     mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
2914     }
2915 sgodin 5567 mProposedLocalSdp.reset();
2916 daniel 5068 }
2917    
2918 daniel 5505 void InviteSession::onReadyToSend(SipMessage& msg)
2919     {
2920     mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
2921     }
2922 daniel 5068
2923 daniel 5830 void InviteSession::referNoSub(const SipMessage& msg)
2924     {
2925     assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
2926     mLastReferNoSubRequest = msg;
2927     mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
2928     }
2929    
2930     void
2931     InviteSession::acceptReferNoSub(int statusCode)
2932     {
2933     if (statusCode / 100 != 2)
2934     {
2935     throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2936     }
2937    
2938     SharedPtr<SipMessage> response(new SipMessage);
2939     mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
2940     response->header(h_ReferSub).value() = "false";
2941 sgodin 6617 //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
2942 daniel 5830
2943     send(response);
2944     }
2945    
2946     void
2947     InviteSession::rejectReferNoSub(int responseCode)
2948     {
2949     if (responseCode < 400)
2950     {
2951     throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2952     }
2953    
2954     SharedPtr<SipMessage> response(new SipMessage);
2955     mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
2956     send(response);
2957     }
2958    
2959 davidb 2575 /* ====================================================================
2960 jason 4010 * The Vovida Software License, Version 1.0
2961     *
2962 davidb 2575 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2963 jason 4010 *
2964 davidb 2575 * Redistribution and use in source and binary forms, with or without
2965     * modification, are permitted provided that the following conditions
2966     * are met:
2967 jason 4010 *
2968 davidb 2575 * 1. Redistributions of source code must retain the above copyright
2969     * notice, this list of conditions and the following disclaimer.
2970 jason 4010 *
2971 davidb 2575 * 2. Redistributions in binary form must reproduce the above copyright
2972     * notice, this list of conditions and the following disclaimer in
2973     * the documentation and/or other materials provided with the
2974    
2975     * distribution.
2976 jason 4010 *
2977 davidb 2575 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2978     * and "Vovida Open Communication Application Library (VOCAL)" must
2979     * not be used to endorse or promote products derived from this
2980     * software without prior written permission. For written
2981     * permission, please contact vocal@vovida.org.
2982     *
2983     * 4. Products derived from this software may not be called "VOCAL", nor
2984     * may "VOCAL" appear in their name, without prior written
2985     * permission of Vovida Networks, Inc.
2986 jason 4010 *
2987 davidb 2575 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2988     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2989     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2990     * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2991     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2992     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2993     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2994     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2995     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2996     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2997     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2998     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2999     * DAMAGE.
3000 jason 4010 *
3001 davidb 2575 * ====================================================================
3002 jason 4010 *
3003 davidb 2575 * This software consists of voluntary contributions made by Vovida
3004     * Networks, Inc. and many individuals on behalf of Vovida Networks,
3005     * Inc. For more information on Vovida Networks, Inc., please see
3006     * <http://www.vovida.org/>.
3007     *
3008     */
3009 jason 5459
3010 sgodin 7544
3011 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