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

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

Parent Directory Parent Directory | Revision Log Revision Log


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