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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7084 - (hide annotations) (download)
Thu Apr 19 08:50:33 2007 UTC (12 years, 7 months ago) by nash
File MIME type: text/plain
File size: 84187 byte(s)
Security.cxx/hxx:
 allow to disable server authentication

InviteSession.cxx:
 public getProposedRemoteSdp() method
 when assigning mProposedRemoteSdp, don't make clone it simply take over ownership as sdp is not used later part of the codes
 

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