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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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