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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.2809  
changed lines
  Added in v.7042

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27