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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7077 - (hide annotations) (download)
Mon Apr 16 10:07:24 2007 UTC (12 years, 7 months ago) by nash
File MIME type: text/plain
File size: 84047 byte(s)
inside resip/stack/Transaction::process method contains complex 
logics and message ptr can be easily leaked if it's not maintained by 
original coder, therefore I changed to SharedPtr usage and made a bunch 
of code changed to make it compile.

Also another place worth mention as TimeLimitFifo::add method could 
result memory leak usage, and it's fixed on the way for above changes.

The tests under rutil/stack/dum has passed as well.

resip/stack/Security add to allow disable server authentication check



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

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