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

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

Parent Directory Parent Directory | Revision Log Revision Log


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