/[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

revision 5544 by jason, Tue Oct 18 01:11:48 2005 UTC revision 8690 by sgodin, Wed Nov 11 16:36:26 2009 UTC
# Line 3  Line 3 
3  #include "resip/stack/SdpContents.hxx"  #include "resip/stack/SdpContents.hxx"
4  #include "resip/stack/SipMessage.hxx"  #include "resip/stack/SipMessage.hxx"
5  #include "resip/stack/Helper.hxx"  #include "resip/stack/Helper.hxx"
6    #include "resip/dum/BaseCreator.hxx"
7  #include "resip/dum/Dialog.hxx"  #include "resip/dum/Dialog.hxx"
8    #include "resip/dum/DialogEventStateManager.hxx"
9  #include "resip/dum/DialogUsageManager.hxx"  #include "resip/dum/DialogUsageManager.hxx"
10  #include "resip/dum/InviteSession.hxx"  #include "resip/dum/InviteSession.hxx"
11  #include "resip/dum/ServerInviteSession.hxx"  #include "resip/dum/ServerInviteSession.hxx"
# Line 23  Line 25 
25  #include "rutil/WinLeakCheck.hxx"  #include "rutil/WinLeakCheck.hxx"
26    
27  // Remove warning about 'this' use in initiator list - pointer is only stored  // Remove warning about 'this' use in initiator list - pointer is only stored
28  #if defined(WIN32)  #if defined(WIN32) && !defined(__GNUC__)
29  #pragma warning( disable : 4355 ) // using this in base member initializer list  #pragma warning( disable : 4355 ) // using this in base member initializer list
30  #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)  #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
31  #endif  #endif
# Line 41  Line 43 
43     "Application Rejected Sdp(usually no common codec)",     "Application Rejected Sdp(usually no common codec)",
44     "Illegal Sdp Negotiation",     "Illegal Sdp Negotiation",
45     "ACK not received",     "ACK not received",
46     "Session Timer Expired"     "Session Timer Expired",
47       "Stale re-Invite"
48  };  };
49    
50  const Data& getEndReasonString(InviteSession::EndReason reason)  const Data& getEndReasonString(InviteSession::EndReason reason)
# Line 54  Line 57 
57     : DialogUsage(dum, dialog),     : DialogUsage(dum, dialog),
58       mState(Undefined),       mState(Undefined),
59       mNitState(NitComplete),       mNitState(NitComplete),
60         mServerNitState(NitComplete),
61         mLastLocalSessionModification(new SipMessage),
62         mLastRemoteSessionModification(new SipMessage),
63         mInvite200(new SipMessage),
64         mLastNitResponse(new SipMessage),
65       mCurrentRetransmit200(0),       mCurrentRetransmit200(0),
66         mStaleReInviteTimerSeq(1),
67       mSessionInterval(0),       mSessionInterval(0),
68       mMinSE(90),       mMinSE(90),
69       mSessionRefresher(false),       mSessionRefresher(false),
70       mSessionTimerSeq(0),       mSessionTimerSeq(0),
71       mSessionRefreshReInvite(false),       mSessionRefreshReInvite(false),
72       mSentRefer(false),       mReferSub(true),
73       mCurrentEncryptionLevel(DialogUsageManager::None),       mCurrentEncryptionLevel(DialogUsageManager::None),
74       mProposedEncryptionLevel(DialogUsageManager::None),       mProposedEncryptionLevel(DialogUsageManager::None),
75       mEndReason(NotSpecified)       mEndReason(NotSpecified)
# Line 73  Line 82 
82  {  {
83     DebugLog ( << "^^^ InviteSession::~InviteSession " << this);     DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
84     mDialog.mInviteSession = 0;     mDialog.mInviteSession = 0;
85       while(!mNITQueue.empty())
86       {
87          delete mNITQueue.front();
88          mNITQueue.pop();
89       }
90  }  }
91    
92  void  void
# Line 86  Line 100 
100     //delete this;       //delete this;  
101  }  }
102    
103    bool
104    InviteSession::hasLocalSdp() const
105    {
106       return (mCurrentLocalSdp.get());
107    }
108    
109  const SdpContents&  const SdpContents&
110  InviteSession::getLocalSdp() const  InviteSession::getLocalSdp() const
111  {  {
112       if(mCurrentLocalSdp.get())
113       {
114     return *mCurrentLocalSdp;     return *mCurrentLocalSdp;
115  }  }
116       else
117       {
118          return SdpContents::Empty;
119       }
120    }
121    
122    bool
123    InviteSession::hasRemoteSdp() const
124    {
125       return (mCurrentRemoteSdp.get());
126    }
127    
128  const SdpContents&  const SdpContents&
129  InviteSession::getRemoteSdp() const  InviteSession::getRemoteSdp() const
130  {  {
131       if(mCurrentRemoteSdp.get())
132       {
133     return *mCurrentRemoteSdp;     return *mCurrentRemoteSdp;
134  }  }
135       else
136       {
137          return SdpContents::Empty;
138       }
139    }
140    
141  const Data&  bool
142  InviteSession::getDialogId() const  InviteSession::hasProposedRemoteSdp() const
143    {
144       return (mProposedRemoteSdp.get());
145    }
146    
147    const SdpContents&
148    InviteSession::getProposedRemoteSdp() const
149    {
150       if(mProposedRemoteSdp.get())
151  {  {
152     return mDialog.getId().getCallId();        return *mProposedRemoteSdp;
153       }
154       else
155       {
156          return SdpContents::Empty;
157       }
158  }  }
159    
160  InviteSessionHandle  InviteSessionHandle
# Line 112  Line 165 
165    
166  void InviteSession::storePeerCapabilities(const SipMessage& msg)  void InviteSession::storePeerCapabilities(const SipMessage& msg)
167  {  {
    // !slg! ToDo - add methods to get this data, App may be interested  
168     if (msg.exists(h_Allows))     if (msg.exists(h_Allows))
169     {     {
170        mPeerSupportedMethods = msg.header(h_Allows);        mPeerSupportedMethods = msg.header(h_Allows);
# Line 137  Line 189 
189     {     {
190        mPeerSupportedMimeTypes = msg.header(h_Accepts);        mPeerSupportedMimeTypes = msg.header(h_Accepts);
191     }     }
192       if (msg.exists(h_UserAgent))
193       {
194          mPeerUserAgent = msg.header(h_UserAgent).value();
195       }
196  }  }
197    
198  bool  bool
# Line 151  Line 207 
207     return false;     return false;
208  }  }
209    
 const NameAddr&  
 InviteSession::myAddr() const  
 {  
    return mDialog.mLocalNameAddr;  
 }  
   
 const NameAddr&  
 InviteSession::peerAddr() const  
 {  
    return mDialog.mRemoteNameAddr;  
 }  
   
210  bool  bool
211  InviteSession::isConnected() const  InviteSession::isConnected() const
212  {  {
# Line 173  Line 217 
217        case SentUpdateGlare:        case SentUpdateGlare:
218        case SentReinvite:        case SentReinvite:
219        case SentReinviteGlare:        case SentReinviteGlare:
220          case SentReinviteNoOffer:
221          case SentReinviteAnswered:
222          case SentReinviteNoOfferGlare:
223        case ReceivedUpdate:        case ReceivedUpdate:
224        case ReceivedReinvite:        case ReceivedReinvite:
225        case ReceivedReinviteNoOffer:        case ReceivedReinviteNoOffer:
226          case ReceivedReinviteSentOffer:
227        case Answered:        case Answered:
228        case WaitingToOffer:        case WaitingToOffer:
229          case WaitingToRequestOffer:
230           return true;           return true;
231    
232        default:        default:
# Line 190  Line 239 
239  {  {
240     switch (mState)     switch (mState)
241     {     {
       case UAC_Start:  
242        case UAC_Early:        case UAC_Early:
243        case UAC_EarlyWithOffer:        case UAC_EarlyWithOffer:
244        case UAC_EarlyWithAnswer:        case UAC_EarlyWithAnswer:
           
          //case UAC_Answered:  
          //case UAC_Terminated:  
245        case UAC_SentUpdateEarly:        case UAC_SentUpdateEarly:
       case UAC_SentUpdateConnected:  
246        case UAC_ReceivedUpdateEarly:        case UAC_ReceivedUpdateEarly:
247           //case UAC_SentAnswer:        case UAC_SentAnswer:
248        case UAC_QueuedUpdate:        case UAC_QueuedUpdate:
249             return true;
250          default:
251             return false;
252       }
253    }
254    
255    bool
256    InviteSession::isAccepted() const
257    {
258       switch (mState)
259       {
260        case UAS_Start:        case UAS_Start:
261        case UAS_Offer:        case UAS_Offer:
262          case UAS_NoOffer:
263          case UAS_NoOfferReliable:
264          case UAS_ProvidedOffer:
265        case UAS_OfferProvidedAnswer:        case UAS_OfferProvidedAnswer:
266        case UAS_EarlyOffer:        case UAS_EarlyOffer:
267          case UAS_EarlyProvidedOffer:
268        case UAS_EarlyProvidedAnswer:        case UAS_EarlyProvidedAnswer:
269        case UAS_EarlyNoOffer:        case UAS_EarlyNoOffer:
270        case UAS_FirstEarlyReliable:        case UAS_FirstSentAnswerReliable:
271        case UAS_EarlyReliable:        case UAS_FirstSentOfferReliable:
272           return true;        case UAS_NegotiatedReliable:
   
       default:  
273           return false;           return false;
274          default:
275             return true;
276     }     }
277  }  }
278    
   
279  bool  bool
280  InviteSession::isTerminated() const  InviteSession::isTerminated() const
281  {  {
# Line 236  Line 293 
293     }     }
294  }  }
295    
296  std::ostream&  EncodeStream&
297  InviteSession::dump(std::ostream& strm) const  InviteSession::dump(EncodeStream& strm) const
298  {  {
299     strm << "INVITE: " << mId     strm << "INVITE: " << mId
300          << " " << toData(mState)          << " " << toData(mState)
# Line 247  Line 304 
304  }  }
305    
306  void  void
307    InviteSession::requestOffer()
308    {
309       switch (mState)
310       {
311          case Connected:
312          case WaitingToRequestOffer:
313          case UAS_WaitingToRequestOffer:
314             transition(SentReinviteNoOffer);
315             mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
316             startStaleReInviteTimer();
317             mLastLocalSessionModification->setContents(0);         // Clear the SDP contents from the INVITE
318             setSessionTimerHeaders(*mLastLocalSessionModification);
319    
320             InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
321    
322             // call send to give app an chance to adorn the message.
323             send(mLastLocalSessionModification);
324             break;
325    
326          case Answered:
327             // queue the offer to be sent after the ACK is received
328             transition(WaitingToRequestOffer);
329             break;        
330            
331          // ?slg? Can we handle all of the states listed in isConnected() ???
332          default:
333             WarningLog (<< "Can't requestOffer when not in Connected state");
334             throw DialogUsage::Exception("Can't request an offer", __FILE__,__LINE__);
335       }
336    }
337    
338    void
339  InviteSession::provideOffer(const SdpContents& offer,  InviteSession::provideOffer(const SdpContents& offer,
340                              DialogUsageManager::EncryptionLevel level,                              DialogUsageManager::EncryptionLevel level,
341                              const SdpContents* alternative)                              const SdpContents* alternative)
# Line 256  Line 345 
345        case Connected:        case Connected:
346        case WaitingToOffer:        case WaitingToOffer:
347        case UAS_WaitingToOffer:        case UAS_WaitingToOffer:
          if (updateMethodSupported())  
          {  
             transition(SentUpdate);  
             mDialog.makeRequest(mLastSessionModification, UPDATE);  
          }  
          else  
          {  
348              transition(SentReinvite);              transition(SentReinvite);
349              mDialog.makeRequest(mLastSessionModification, INVITE);           mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
350           }           startStaleReInviteTimer();
          mLastSessionModification.remove(h_ProxyAuthorizations); // remove remote credentials.  
          setSessionTimerHeaders(mLastSessionModification);  
351    
352           InfoLog (<< "Sending " << mLastSessionModification.brief());           setSessionTimerHeaders(*mLastLocalSessionModification);
353           InviteSession::setSdp(mLastSessionModification, offer, alternative);  
354             InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
355             InviteSession::setSdp(*mLastLocalSessionModification, offer, alternative);
356           mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);           mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);
357           mProposedEncryptionLevel = level;           mProposedEncryptionLevel = level;
358           DumHelper::setOutgoingEncrptionLevel(mLastSessionModification, mProposedEncryptionLevel);           DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
359    
360           // call send to give app an chance to adorn the message.           // call send to give app an chance to adorn the message.
361           send(mLastSessionModification);           send(mLastLocalSessionModification);
362           break;           break;
363    
364        case Answered:        case Answered:
# Line 288  Line 371 
371        case ReceivedReinviteNoOffer:        case ReceivedReinviteNoOffer:
372           assert(!mProposedRemoteSdp.get());           assert(!mProposedRemoteSdp.get());
373           transition(ReceivedReinviteSentOffer);           transition(ReceivedReinviteSentOffer);
374           mDialog.makeResponse(mInvite200, mLastSessionModification, 200);           mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
375           handleSessionTimerRequest(mInvite200, mLastSessionModification);           handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
376           InviteSession::setSdp(mInvite200, offer, 0);           InviteSession::setSdp(*mInvite200, offer, 0);
377           mProposedLocalSdp  = InviteSession::makeSdp(offer);           mProposedLocalSdp  = InviteSession::makeSdp(offer);
378    
379           InfoLog (<< "Sending " << mInvite200.brief());           InfoLog (<< "Sending " << mInvite200->brief());
380           DumHelper::setOutgoingEncrptionLevel(mInvite200, mCurrentEncryptionLevel);           DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
381           send(mInvite200);           send(mInvite200);
382           startRetransmit200Timer();           startRetransmit200Timer();
383           break;           break;
384                    
           
       // ?slg? Can we handle all of the states listed in isConnected() ???  
385        default:        default:
386           WarningLog (<< "Can't provideOffer when not in Connected state");           WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
387           throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);           throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
388     }     }
389  }  }
390    
391    class InviteSessionProvideOfferExCommand : public DumCommandAdapter
392    {
393    public:
394       InviteSessionProvideOfferExCommand(InviteSession& inviteSession,
395          const SdpContents& offer,
396          DialogUsageManager::EncryptionLevel level,
397          const SdpContents* alternative)
398          : mInviteSession(inviteSession),
399          mOffer(offer)
400       {
401       }
402    
403       virtual void executeCommand()
404       {
405          mInviteSession.provideOffer(mOffer, mLevel, mAlternative.get());
406       }
407    
408       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
409       {
410          return strm << "InviteSessionProvideOfferExCommand";
411       }
412    private:
413       InviteSession& mInviteSession;
414       SdpContents mOffer;
415       DialogUsageManager::EncryptionLevel mLevel;
416       std::auto_ptr<const SdpContents> mAlternative;
417    };
418    
419    void
420    InviteSession::provideOfferCommand(const SdpContents& offer, DialogUsageManager::EncryptionLevel level, const SdpContents* alternative)
421    {
422       mDum.post(new InviteSessionProvideOfferExCommand(*this, offer, level, alternative));
423    }
424    
425  void  void
426  InviteSession::provideOffer(const SdpContents& offer)  InviteSession::provideOffer(const SdpContents& offer)
427  {  {
428     return provideOffer(offer, mCurrentEncryptionLevel, 0);     return provideOffer(offer, mCurrentEncryptionLevel, 0);
429  }  }
430    
431    class InviteSessionProvideOfferCommand : public DumCommandAdapter
432    {
433    public:
434       InviteSessionProvideOfferCommand(InviteSession& inviteSession, const SdpContents& offer)
435          : mInviteSession(inviteSession),
436          mOffer(offer)
437       {
438       }
439    
440       virtual void executeCommand()
441       {
442          mInviteSession.provideOffer(mOffer);
443       }
444    
445       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
446       {
447          return strm << "InviteSessionProvideOfferCommand";
448       }
449    private:
450       InviteSession& mInviteSession;
451       SdpContents mOffer;
452    };
453    
454    void
455    InviteSession::provideOfferCommand(const SdpContents& offer)
456    {
457       mDum.post(new InviteSessionProvideOfferCommand(*this, offer));
458    }
459    
460  void  void
461  InviteSession::provideAnswer(const SdpContents& answer)  InviteSession::provideAnswer(const SdpContents& answer)
462  {  {
# Line 320  Line 464 
464     {     {
465        case ReceivedReinvite:        case ReceivedReinvite:
466           transition(Connected);           transition(Connected);
467           mDialog.makeResponse(mInvite200, mLastSessionModification, 200);           mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
468           handleSessionTimerRequest(mInvite200, mLastSessionModification);           handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
469           InviteSession::setSdp(mInvite200, answer, 0);           InviteSession::setSdp(*mInvite200, answer, 0);
470           mCurrentLocalSdp = InviteSession::makeSdp(answer);           mCurrentLocalSdp = InviteSession::makeSdp(answer);
471           mCurrentRemoteSdp = mProposedRemoteSdp;           mCurrentRemoteSdp = mProposedRemoteSdp;
472           InfoLog (<< "Sending " << mInvite200.brief());           InfoLog (<< "Sending " << mInvite200->brief());
473           DumHelper::setOutgoingEncrptionLevel(mInvite200, mCurrentEncryptionLevel);           DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
474           send(mInvite200);           send(mInvite200);
475           startRetransmit200Timer();           startRetransmit200Timer();
476           break;           break;
# Line 335  Line 479 
479        {        {
480           transition(Connected);           transition(Connected);
481    
482           SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
483           mDialog.makeResponse(response, mLastSessionModification, 200);           mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
484           handleSessionTimerRequest(response, mLastSessionModification);           handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
485           InviteSession::setSdp(response, answer, 0);           InviteSession::setSdp(*response, answer, 0);
486           mCurrentLocalSdp = InviteSession::makeSdp(answer);           mCurrentLocalSdp = InviteSession::makeSdp(answer);
487           mCurrentRemoteSdp = mProposedRemoteSdp;           mCurrentRemoteSdp = mProposedRemoteSdp;
488           InfoLog (<< "Sending " << response.brief());           InfoLog (<< "Sending " << response->brief());
489           DumHelper::setOutgoingEncrptionLevel(response, mCurrentEncryptionLevel);           DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
490           send(response);           send(response);
491           break;           break;
492        }        }
493    
494          case SentReinviteAnswered:
495             transition(Connected);
496             sendAck(&answer);
497    
498             mCurrentRemoteSdp = mProposedRemoteSdp;
499             mCurrentLocalSdp = InviteSession::makeSdp(answer);
500             break;
501    
502        default:        default:
503           WarningLog (<< "Can't provideAnswer when not in Connected state");           WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
504           throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);           throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
505       }
506     }     }
507    
508    class InviteSessionProvideAnswerCommand : public DumCommandAdapter
509    {
510    public:
511       InviteSessionProvideAnswerCommand(InviteSession& inviteSession, const SdpContents& answer)
512          : mInviteSession(inviteSession),
513            mAnswer(answer)
514       {
515       }
516    
517       virtual void executeCommand()
518       {
519          mInviteSession.provideAnswer(mAnswer);
520       }
521    
522       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
523       {
524          return strm << "InviteSessionProvideAnswerCommand";
525       }
526    private:
527       InviteSession& mInviteSession;
528       SdpContents mAnswer;
529    };
530    
531    void
532    InviteSession::provideAnswerCommand(const SdpContents& answer)
533    {
534       mDum.post(new InviteSessionProvideAnswerCommand(*this, answer));
535  }  }
536    
537  void  void
# Line 362  Line 543 
543  void  void
544  InviteSession::end(EndReason reason)  InviteSession::end(EndReason reason)
545  {  {
546     if (mEndReason != NotSpecified && reason != NotSpecified)     if (mEndReason == NotSpecified)
547     {     {
548        mEndReason = reason;          mEndReason = reason;  
549     }     }
# Line 375  Line 556 
556        case SentUpdate:        case SentUpdate:
557        case SentUpdateGlare:        case SentUpdateGlare:
558        case SentReinviteGlare:        case SentReinviteGlare:
559          case SentReinviteNoOfferGlare:
560          case SentReinviteAnswered:
561        {        {
562           // !jf! do we need to store the BYE somewhere?           // !jf! do we need to store the BYE somewhere?
563           sendBye();           sendBye();
564           transition(Terminated);           transition(Terminated);
565           handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);           handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
566           break;           break;
567        }        }
568    
569        case SentReinvite:        case SentReinvite:
570          case SentReinviteNoOffer:
571           transition(WaitingToTerminate);           transition(WaitingToTerminate);
572           break;           break;
573    
574        case Answered:        case Answered:
575        case WaitingToOffer:        case WaitingToOffer:
576          case WaitingToRequestOffer:
577        case ReceivedReinviteSentOffer:        case ReceivedReinviteSentOffer:
578             if(mCurrentRetransmit200)  // If retransmit200 timer is active then ACK is not received yet - wait for it
579             {
580           transition(WaitingToHangup);           transition(WaitingToHangup);
581             }
582             else
583             {
584                 // ACK has likely timedout - hangup immediately
585                 sendBye();
586                 transition(Terminated);
587                 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
588             }
589           break;           break;
590    
591        case ReceivedUpdate:        case ReceivedUpdate:
592        case ReceivedReinvite:        case ReceivedReinvite:
593        case ReceivedReinviteNoOffer:        case ReceivedReinviteNoOffer:
594        {        {
595           SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
596           mDialog.makeResponse(response, mLastSessionModification, 488);           mDialog.makeResponse(*response, *mLastRemoteSessionModification, 488);
597           InfoLog (<< "Sending " << response.brief());           InfoLog (<< "Sending " << response->brief());
598           send(response);           send(response);
599    
600           sendBye();           sendBye();
601           transition(Terminated);           transition(Terminated);
602           handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);           handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
603           break;           break;
604        }        }
605    
# Line 412  Line 607 
607        {        {
608           sendBye();           sendBye();
609           transition(Terminated);           transition(Terminated);
610           handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);           handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
611           break;           break;
612        }        }
613    
# Line 426  Line 621 
621     }     }
622  }  }
623    
624    class InviteSessionEndCommand : public DumCommandAdapter
625    {
626    public:
627       InviteSessionEndCommand(InviteSession& inviteSession, InviteSession::EndReason reason)
628          : mInviteSession(inviteSession),
629            mReason(reason)
630       {
631       }
632    
633       virtual void executeCommand()
634       {
635          mInviteSession.end(mReason);
636       }
637    
638       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
639       {
640          return strm << "InviteSessionEndCommand";
641       }
642    private:
643       InviteSession& mInviteSession;
644       InviteSession::EndReason mReason;
645    };
646    
647    void
648    InviteSession::endCommand(EndReason reason)
649    {
650       mDum.post(new InviteSessionEndCommand(*this, reason));
651    }
652    
653  void  void
654  InviteSession::reject(int statusCode, WarningCategory *warning)  InviteSession::reject(int statusCode, WarningCategory *warning)
655  {  {
# Line 437  Line 661 
661        {        {
662           transition(Connected);           transition(Connected);
663    
664           SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
665           mDialog.makeResponse(response, mLastSessionModification, statusCode);           mDialog.makeResponse(*response, *mLastRemoteSessionModification, statusCode);
666           if(warning)           if(warning)
667           {           {
668              response.header(h_Warnings).push_back(*warning);              response->header(h_Warnings).push_back(*warning);
669           }           }
670           InfoLog (<< "Sending " << response.brief());           InfoLog (<< "Sending " << response->brief());
671           send(response);           send(response);
672           break;           break;
673        }        }
# Line 454  Line 678 
678     }     }
679  }  }
680    
681    class InviteSessionRejectCommand : public DumCommandAdapter
682    {
683    public:
684       InviteSessionRejectCommand(InviteSession& inviteSession, int code, WarningCategory* warning)
685          : mInviteSession(inviteSession),
686            mCode(code),
687            mWarning(warning?new WarningCategory(*warning):0)
688       {
689       }
690    
691       virtual void executeCommand()
692       {
693          mInviteSession.reject(mCode, mWarning.get());
694       }
695    
696       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
697       {
698          return strm << "InviteSessionRejectCommand";
699       }
700    private:
701       InviteSession& mInviteSession;
702       int mCode;
703       std::auto_ptr<WarningCategory> mWarning;
704    };
705    
706    void
707    InviteSession::rejectCommand(int code, WarningCategory *warning)
708    {
709       mDum.post(new InviteSessionRejectCommand(*this, code, warning));
710    }
711    
712  void  void
713  InviteSession::targetRefresh(const NameAddr& localUri)  InviteSession::targetRefresh(const NameAddr& localUri)
714  {  {
715     if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?     if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
716     {     {
717        // !jf! add interface to Dialog        mDialog.mLocalContact = localUri;
718        //mDialog.setLocalContact(localUri);        sessionRefresh();
       provideOffer(*mCurrentLocalSdp);  
719     }     }
720     else     else
721     {     {
722        WarningLog (<< "Can't targetRefresh before Connected");        WarningLog (<< "Can't targetRefresh before Connected");
       assert(0);  
723        throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);        throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
724     }     }
725  }  }
726    
727  void  void
728  InviteSession::refer(const NameAddr& referTo)  InviteSession::refer(const NameAddr& referTo, bool referSub)
729  {  {
730     if (mSentRefer)     refer(referTo,std::auto_ptr<resip::Contents>(0),referSub);
731    }
732    void
733    InviteSession::refer(const NameAddr& referTo, std::auto_ptr<resip::Contents> contents,bool referSub)
734    {
735       if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
736     {     {
737        throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);        SharedPtr<SipMessage> refer(new SipMessage());
738          mDialog.makeRequest(*refer, REFER);
739          refer->header(h_ReferTo) = referTo;
740          refer->header(h_ReferredBy) = myAddr();
741          refer->header(h_ReferredBy).remove(p_tag);   // tag-param not permitted in rfc3892; not the same as generic-param
742          refer->setContents(contents);
743          if (!referSub)
744          {
745             refer->header(h_ReferSub).value() = "false";
746             refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
747     }     }
748    
749     if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?        if(mNitState == NitComplete)
750     {     {
751        mSentRefer = true;           mNitState = NitProceeding;
752        SipMessage refer;           mReferSub = referSub;
       mDialog.makeRequest(refer, REFER);  
       refer.header(h_ReferTo) = referTo;  
       refer.header(h_ReferredBy) = mDialog.mLocalContact; // !slg! is it ok to do this - should it be an option?  
753        send(refer);        send(refer);
754             return;
755          }
756          mNITQueue.push(new QueuedNIT(refer,referSub));
757          InfoLog(<< "refer - queuing NIT:" << refer->brief());
758          return;
759     }     }
760     else     else
761     {     {
# Line 497  Line 766 
766  }  }
767    
768  void  void
769  InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace)  InviteSession::nitComplete()
770  {  {
771     if (!sessionToReplace.isValid())     mNitState = NitComplete;
772       if (mNITQueue.size())
773     {     {
774        throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);        QueuedNIT *qn=mNITQueue.front();
775          mNITQueue.pop();
776          mNitState = NitProceeding;
777          mReferSub = qn->referSubscription();
778          InfoLog(<< "checkNITQueue - sending queued NIT:" << qn->getNIT()->brief());
779          send(qn->getNIT());
780          delete qn;
781       }
782     }     }
783    
784     if (mSentRefer)  class InviteSessionReferCommand : public DumCommandAdapter
785     {     {
786        throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);  public:
787       InviteSessionReferCommand(InviteSession& inviteSession, const NameAddr& referTo, bool referSub)
788          : mInviteSession(inviteSession),
789          mReferTo(referTo),
790          mReferSub(referSub)
791       {
792    
793       }
794    
795       virtual void executeCommand()
796       {
797          mInviteSession.refer(mReferTo, mReferSub);
798       }
799    
800       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
801       {
802          return strm << "InviteSessionReferCommand";
803       }
804    
805    private:
806       InviteSession& mInviteSession;
807       NameAddr mReferTo;
808       bool mReferSub;
809    };
810    
811    void
812    InviteSession::referCommand(const NameAddr& referTo, bool referSub)
813    {
814       mDum.post(new InviteSessionReferCommand(*this, referTo, referSub));
815    }
816    
817    void
818    InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
819    {
820       if (!sessionToReplace.isValid())
821       {
822          throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
823     }     }
824    
825     if (isConnected())  // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?     if (isConnected())  // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
826     {     {
827        mSentRefer = true;        SharedPtr<SipMessage> refer(new SipMessage());      
828        SipMessage refer;        mDialog.makeRequest(*refer, REFER);
829        mDialog.makeRequest(refer, REFER);  
830          refer->header(h_ReferTo) = referTo;
831          refer->header(h_ReferredBy) = myAddr();
832          refer->header(h_ReferredBy).remove(p_tag);
833    
       refer.header(h_ReferTo) = referTo;  
       refer.header(h_ReferredBy) = mDialog.mLocalContact; // ?slg? is it ok to do this - should it be an option?  
834        CallId replaces;        CallId replaces;
835        DialogId id = sessionToReplace->mDialog.getId();        DialogId id = sessionToReplace->mDialog.getId();
836        replaces.value() = id.getCallId();        replaces.value() = id.getCallId();
837        replaces.param(p_toTag) = id.getRemoteTag();        replaces.param(p_toTag) = id.getRemoteTag();
838        replaces.param(p_fromTag) = id.getLocalTag();        replaces.param(p_fromTag) = id.getLocalTag();
839    
840        refer.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;        refer->header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
841          
842          if (!referSub)
843          {
844             refer->header(h_ReferSub).value() = "false";
845             refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
846          }
847    
848          if(mNitState == NitComplete)
849          {
850             mNitState = NitProceeding;
851             mReferSub = referSub;
852        send(refer);        send(refer);
853             return;
854          }
855          mNITQueue.push(new QueuedNIT(refer,referSub));
856          InfoLog(<< "refer/replace - queuing NIT:" << refer->brief());
857          return;
858     }     }
859     else     else
860     {     {
# Line 534  Line 864 
864     }     }
865  }  }
866    
867    class InviteSessionReferExCommand : public DumCommandAdapter
868    {
869    public:
870       InviteSessionReferExCommand(InviteSession& inviteSession, const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
871          : mInviteSession(inviteSession),
872          mSessionToReplace(sessionToReplace),
873          mReferTo(referTo),
874          mReferSub(referSub)
875       {
876       }
877    
878       virtual void executeCommand()
879       {
880          mInviteSession.referCommand(mReferTo, mSessionToReplace, mReferSub);
881       }
882    
883       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
884       {
885          return strm << "InviteSessionReferExCommand";
886       }
887    
888    private:
889       InviteSession& mInviteSession;
890       InviteSessionHandle mSessionToReplace;
891       NameAddr mReferTo;
892       bool mReferSub;
893    };
894    
895  void  void
896  InviteSession::info(const Contents& contents)  InviteSession::referCommand(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
897  {  {
898     if (mNitState == NitComplete)     mDum.post(new InviteSessionReferExCommand(*this, referTo, sessionToReplace, referSub));
899    }
900    
901    void
902    InviteSession::info(const Contents& contents)
903     {     {
904        if (isConnected())  // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?        if (isConnected())  // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
905        {        {
906           mNitState = NitProceeding;        SharedPtr<SipMessage> info(new SipMessage());
907           SipMessage info;        mDialog.makeRequest(*info, INFO);
          mDialog.makeRequest(info, INFO);  
908           // !jf! handle multipart here           // !jf! handle multipart here
909           info.setContents(&contents);        info->setContents(&contents);
910           DumHelper::setOutgoingEncrptionLevel(info, mCurrentEncryptionLevel);        DumHelper::setOutgoingEncryptionLevel(*info, mCurrentEncryptionLevel);
911          if (mNitState == NitComplete)
912          {
913             mNitState = NitProceeding;
914           send(info);           send(info);
915             return;
916          }
917          mNITQueue.push(new QueuedNIT(info));
918          InfoLog(<< "info - queuing NIT:" << info->brief());
919          return;
920        }        }
921        else        else
922        {        {
# Line 556  Line 925 
925           throw UsageUseException("Can't send INFO before Connected", __FILE__, __LINE__);           throw UsageUseException("Can't send INFO before Connected", __FILE__, __LINE__);
926        }        }
927     }     }
928     else  
929    class InviteSessionInfoCommand : public DumCommandAdapter
930    {
931    public:
932       InviteSessionInfoCommand(InviteSession& inviteSession, const Contents& contents)
933          : mInviteSession(inviteSession),
934            mContents(contents.clone())
935       {
936       }
937    
938       virtual void executeCommand()
939       {
940          mInviteSession.info(*mContents);
941       }
942    
943       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
944     {     {
945        throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",        return strm << "InviteSessionInfoCommand";
                               __FILE__, __LINE__);  
946     }     }
947    private:
948       InviteSession& mInviteSession;
949       std::auto_ptr<Contents> mContents;
950    };
951    
952    void
953    InviteSession::infoCommand(const Contents& contents)
954    {
955       mDum.post(new InviteSessionInfoCommand(*this, contents));
956  }  }
957    
958  void  void
959  InviteSession::message(const Contents& contents)  InviteSession::message(const Contents& contents)
960  {  {
    if (mNitState == NitComplete)  
    {  
961        if (isConnected())  // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?        if (isConnected())  // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
962        {        {
963           mNitState = NitProceeding;        SharedPtr<SipMessage> message(new SipMessage());
964           SipMessage message;        mDialog.makeRequest(*message, MESSAGE);
          mDialog.makeRequest(message, MESSAGE);  
965           // !jf! handle multipart here           // !jf! handle multipart here
966           message.setContents(&contents);        message->setContents(&contents);
967           DumHelper::setOutgoingEncrptionLevel(message, mCurrentEncryptionLevel);        DumHelper::setOutgoingEncryptionLevel(*message, mCurrentEncryptionLevel);
          send(message);  
968           InfoLog (<< "Trying to send MESSAGE: " << message);           InfoLog (<< "Trying to send MESSAGE: " << message);
969          if (mNitState == NitComplete)
970          {
971             mNitState = NitProceeding;
972             send(message);
973             return;
974          }
975          mNITQueue.push(new QueuedNIT(message));
976          InfoLog(<< "message - queuing NIT:" << message->brief());
977          return;
978        }        }
979        else        else
980        {        {
# Line 586  Line 983 
983           throw UsageUseException("Can't send MESSAGE before Connected", __FILE__, __LINE__);           throw UsageUseException("Can't send MESSAGE before Connected", __FILE__, __LINE__);
984        }        }
985     }     }
986     else  
987    class InviteSessionMessageCommand : public DumCommandAdapter
988    {
989    public:
990       InviteSessionMessageCommand(InviteSession& inviteSession, const Contents& contents)
991          : mInviteSession(inviteSession),
992            mContents(contents.clone())
993       {
994       }
995    
996       virtual void executeCommand()
997     {     {
998        throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",        mInviteSession.message(*mContents);
                               __FILE__, __LINE__);  
999     }     }
1000    
1001       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1002       {
1003          return strm << "InviteSessionMessageCommand";
1004       }
1005    private:
1006       InviteSession& mInviteSession;
1007       std::auto_ptr<Contents> mContents;
1008    };
1009    
1010    
1011    void
1012    InviteSession::messageCommand(const Contents& contents)
1013    {
1014       mDum.post(new InviteSessionMessageCommand(*this, contents));
1015  }  }
1016    
1017  void  void
1018  InviteSession::dispatch(const SipMessage& msg)  InviteSession::dispatch(const SipMessage& msg)
1019  {  {
1020       // Look for 2xx retransmissions - resend ACK and filter out of state machine
1021       if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 100 == 2)
1022       {
1023          AckMap::iterator i = mAcks.find(msg.getTransactionId());
1024          if (i != mAcks.end())
1025          {
1026             send(i->second);  // resend ACK
1027             return;
1028          }
1029       }
1030    
1031     // !jf! do we need to handle 3xx here or is it handled elsewhere?     // !jf! do we need to handle 3xx here or is it handled elsewhere?
1032     switch (mState)     switch (mState)
1033     {     {
# Line 608  Line 1040 
1040        case SentReinvite:        case SentReinvite:
1041           dispatchSentReinvite(msg);           dispatchSentReinvite(msg);
1042           break;           break;
1043          case SentReinviteNoOffer:
1044             dispatchSentReinviteNoOffer(msg);
1045             break;
1046          case SentReinviteAnswered:
1047             dispatchSentReinviteAnswered(msg);
1048             break;
1049        case SentUpdateGlare:        case SentUpdateGlare:
1050        case SentReinviteGlare:        case SentReinviteGlare:
1051           // The behavior is the same except for timer which is handled in dispatch(Timer)           // The behavior is the same except for timer which is handled in dispatch(Timer)
1052           dispatchGlare(msg);           dispatchGlare(msg);
1053           break;           break;
1054          case SentReinviteNoOfferGlare:
1055             dispatchReinviteNoOfferGlare(msg);
1056             break;
1057        case ReceivedUpdate:        case ReceivedUpdate:
1058        case ReceivedReinvite:        case ReceivedReinvite:
1059        case ReceivedReinviteNoOffer:        case ReceivedReinviteNoOffer:
# Line 627  Line 1068 
1068        case WaitingToOffer:        case WaitingToOffer:
1069           dispatchWaitingToOffer(msg);           dispatchWaitingToOffer(msg);
1070           break;           break;
1071          case WaitingToRequestOffer:
1072             dispatchWaitingToRequestOffer(msg);
1073             break;
1074        case WaitingToTerminate:        case WaitingToTerminate:
1075           dispatchWaitingToTerminate(msg);           dispatchWaitingToTerminate(msg);
1076           break;           break;
# Line 650  Line 1094 
1094     {     {
1095        if (mCurrentRetransmit200)        if (mCurrentRetransmit200)
1096        {        {
1097           InfoLog (<< "Retransmitting: " << endl << mInvite200);           InfoLog (<< "Retransmitting: " << endl << mInvite200->brief());
1098           DumHelper::setOutgoingEncrptionLevel(mInvite200, mCurrentEncryptionLevel);           //DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
1099           send(mInvite200);           send(mInvite200);
1100           mCurrentRetransmit200 *= 2;           mCurrentRetransmit200 *= 2;
1101           mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(),  timeout.seq());           mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(),  timeout.seq());
# Line 661  Line 1105 
1105     {     {
1106        if(mCurrentRetransmit200)  // If retransmit200 timer is active then ACK is not received yet        if(mCurrentRetransmit200)  // If retransmit200 timer is active then ACK is not received yet
1107        {        {
1108             if (timeout.seq() == mLastRemoteSessionModification->header(h_CSeq).sequence())
1109             {
1110           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1111    
          // this is so the app can decided to ignore this. default implementation  
          // will call end next  
          mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());  
   
1112           // If we are waiting for an Ack and it times out, then end with a BYE           // If we are waiting for an Ack and it times out, then end with a BYE
1113           if(mState == UAS_WaitingToHangup ||           if(mState == UAS_WaitingToHangup ||
1114              mState == WaitingToHangup)              mState == WaitingToHangup)
1115           {           {
1116               sendBye();               sendBye();
1117               transition(Terminated);               transition(Terminated);
1118               mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);                 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1119           }           }
1120           else if(mState == ReceivedReinviteSentOffer)           else if(mState == ReceivedReinviteSentOffer)
1121           {           {
1122              transition(Connected);              transition(Connected);
1123              mProposedLocalSdp.release();                 mProposedLocalSdp.reset();
1124              mProposedEncryptionLevel = DialogUsageManager::None;              mProposedEncryptionLevel = DialogUsageManager::None;
1125              //!dcm! -- should this be onIllegalNegotiation?              //!dcm! -- should this be onIllegalNegotiation?
1126              mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);              mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
1127           }           }
1128           else if(mState == WaitingToOffer)              else if(mState == WaitingToOffer ||
1129                        mState == UAS_WaitingToOffer)
1130           {           {
1131              assert(mProposedLocalSdp.get());              assert(mProposedLocalSdp.get());
1132              //!dcm! -- should this be onIllegalNegotiation?                 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1133              mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);                 if(!isTerminated())  
             if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))  
1134             {             {
1135                 provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),                    provideProposedOffer();
1136                               mProposedEncryptionLevel,                 }
1137                               dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));              }
1138                else if(mState == WaitingToRequestOffer ||
1139                        mState == UAS_WaitingToRequestOffer)
1140                {
1141                   mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1142                   if(!isTerminated())  
1143                   {
1144                      requestOffer();
1145                   }
1146              }              }
1147              else              else
1148              {              {
1149                 provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);                 // this is so the app can decided to ignore this. default implementation
1150                   // will call end next
1151                   mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1152              }              }
1153           }           }
1154        }        }
1155     }     }
1156       else if (timeout.type() == DumTimeout::CanDiscardAck)
1157       {
1158          AckMap::iterator i = mAcks.find(timeout.transactionId());
1159          if (i != mAcks.end())
1160          {
1161             mAcks.erase(i);
1162          }
1163       }
1164     else if (timeout.type() == DumTimeout::Glare)     else if (timeout.type() == DumTimeout::Glare)
1165     {     {
1166        if (mState == SentUpdateGlare)        if (mState == SentUpdateGlare)
# Line 708  Line 1168 
1168           transition(SentUpdate);           transition(SentUpdate);
1169    
1170           InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");           InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
1171           send(mLastSessionModification);           mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);  // increments CSeq
1172             send(mLastLocalSessionModification);
1173        }        }
1174        else if (mState == SentReinviteGlare)        else if (mState == SentReinviteGlare)
1175        {        {
1176           transition(SentReinvite);           transition(SentReinvite);
1177    
1178           InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");           InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
1179           send(mLastSessionModification);           mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1180             startStaleReInviteTimer();
1181             send(mLastLocalSessionModification);
1182          }
1183          else if (mState == SentReinviteNoOfferGlare)
1184          {
1185             transition(SentReinviteNoOffer);
1186    
1187             InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
1188             mDialog.makeRequest(*mLastLocalSessionModification, INVITE);  // increments CSeq
1189             startStaleReInviteTimer();
1190             send(mLastLocalSessionModification);
1191          }
1192       }
1193       else if (timeout.type() == DumTimeout::StaleReInvite)
1194       {
1195          if(timeout.seq() == mStaleReInviteTimerSeq)
1196          {
1197             if(mState == WaitingToTerminate)
1198             {
1199                sendBye();
1200                transition(Terminated);
1201                mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1202             }
1203             else if(mState == SentReinvite ||
1204                     mState == SentReinviteNoOffer)
1205             {
1206                transition(Connected);
1207                mProposedLocalSdp.reset();
1208                mProposedEncryptionLevel = DialogUsageManager::None;
1209    
1210                // this is so the app can decide to ignore this. default implementation
1211                // will call end next - which will send a BYE
1212                mDum.mInviteSessionHandler->onStaleReInviteTimeout(getSessionHandle());
1213             }
1214        }        }
1215     }     }
1216     else if (timeout.type() == DumTimeout::SessionExpiration)     else if (timeout.type() == DumTimeout::SessionExpiration)
1217     {     {
1218        if(timeout.seq() == mSessionTimerSeq)        if(timeout.seq() == mSessionTimerSeq)
1219        {        {
1220           // this is so the app can decided to ignore this. default implementation           // this is so the app can decide to ignore this. default implementation
1221           // will call end next - which will send a BYE           // will call end next - which will send a BYE
1222           mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());           mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
1223        }        }
# Line 752  Line 1247 
1247     {     {
1248        case OnInvite:        case OnInvite:
1249        case OnInviteReliable:        case OnInviteReliable:
1250           mLastSessionModification = msg;           *mLastRemoteSessionModification = msg;
1251           transition(ReceivedReinviteNoOffer);           transition(ReceivedReinviteNoOffer);
          //handler->onDialogModified(getSessionHandle(), None, msg);  
1252           handler->onOfferRequired(getSessionHandle(), msg);           handler->onOfferRequired(getSessionHandle(), msg);
1253           break;           break;
1254    
1255        case OnInviteOffer:        case OnInviteOffer:
1256        case OnInviteReliableOffer:        case OnInviteReliableOffer:
1257           mLastSessionModification = msg;           *mLastRemoteSessionModification = msg;
1258           transition(ReceivedReinvite);           transition(ReceivedReinvite);
1259           mCurrentEncryptionLevel = getEncryptionLevel(msg);           mCurrentEncryptionLevel = getEncryptionLevel(msg);
1260           //handler->onDialogModified(getSessionHandle(), Offer, msg);           mProposedRemoteSdp = sdp;
1261           handler->onOffer(getSessionHandle(), msg, *sdp);  
1262             handler->onOffer(getSessionHandle(), msg, *mProposedRemoteSdp);
1263           break;           break;
1264    
1265        case On2xx:        case On2xx:
# Line 781  Line 1276 
1276           //  !kh!           //  !kh!
1277           //  Find out if it's an UPDATE requiring state change.           //  Find out if it's an UPDATE requiring state change.
1278           //  See rfc3311 5.2, 4th paragraph.           //  See rfc3311 5.2, 4th paragraph.
1279           mLastSessionModification = msg;           *mLastRemoteSessionModification = msg;
1280           mCurrentEncryptionLevel = getEncryptionLevel(msg);           mCurrentEncryptionLevel = getEncryptionLevel(msg);
1281           handler->onOffer(getSessionHandle(), msg, *sdp);           mProposedRemoteSdp = sdp;
1282             handler->onOffer(getSessionHandle(), msg, *mProposedRemoteSdp);
1283           break;           break;
1284    
1285        case OnUpdate:        case OnUpdate:
1286        {        {
1287           // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?           // ?slg? no sdp in update - just respond immediately (likely session timer) - do we need a callback?
1288           SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
1289           mLastSessionModification = msg;           *mLastRemoteSessionModification = msg;
1290           mDialog.makeResponse(response, mLastSessionModification, 200);           mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
1291           handleSessionTimerRequest(response, mLastSessionModification);           handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1292           BaseUsage::send(response);           send(response);
1293           break;           break;
1294        }        }
1295    
# Line 804  Line 1300 
1300           break;           break;
1301    
1302        case OnAck:        case OnAck:
1303          case OnAckAnswer: // .bwc. Don't drop ACK with SDP!
1304           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1305             handler->onAckReceived(getSessionHandle(), msg);
1306           break;           break;
1307    
1308        default:        default:
# Line 829  Line 1327 
1327        case OnUpdateOffer:        case OnUpdateOffer:
1328        {        {
1329           // glare           // glare
1330           SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
1331           mDialog.makeResponse(response, msg, 491);           mDialog.makeResponse(*response, msg, 491);
1332           BaseUsage::send(response);           send(response);
1333           break;           break;
1334        }        }
1335    
1336        case On200Update:        case On200Update:
1337           transition(Connected);           transition(Connected);
1338           handleSessionTimerResponse(msg);           handleSessionTimerResponse(msg);
1339           if (sdp.get())           if (sdp.get() && mProposedLocalSdp.get())
1340           {           {
1341              mCurrentEncryptionLevel = getEncryptionLevel(msg);              mCurrentEncryptionLevel = getEncryptionLevel(msg);
1342              setCurrentLocalSdp(msg);              setCurrentLocalSdp(msg);
1343              mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);  
1344              handler->onAnswer(getSessionHandle(), msg, *sdp);              mCurrentRemoteSdp = sdp;
1345                handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteSdp);
1346           }           }
1347           else if(mProposedLocalSdp.get())           else if(mProposedLocalSdp.get())
1348           {           {
1349              // If we sent an offer in the Update Request and no answer is received              // If we sent an offer in the Update Request and no answer is received
1350              handler->onIllegalNegotiation(getSessionHandle(), msg);              handler->onIllegalNegotiation(getSessionHandle(), msg);
1351              mProposedLocalSdp.release();              mProposedLocalSdp.reset();
1352              mProposedEncryptionLevel = DialogUsageManager::None;              mProposedEncryptionLevel = DialogUsageManager::None;
1353           }           }
1354           break;           break;
# Line 869  Line 1368 
1368           }           }
1369           else           else
1370           {           {
1371              // Response must contact Min_SE - if not - just ignore              // Response must contain Min_SE - if not - just ignore
1372              // ?slg? callback?              // ?slg? callback?
1373              transition(Connected);              transition(Connected);
1374              mProposedLocalSdp.release();              mProposedLocalSdp.reset();
1375              mProposedEncryptionLevel = DialogUsageManager::None;              mProposedEncryptionLevel = DialogUsageManager::None;
1376           }           }
1377           break;           break;
1378    
1379        case OnUpdateRejected:        case OnUpdateRejected:
          // !jf! - callback?  
          mProposedLocalSdp.release();  
          mProposedEncryptionLevel = DialogUsageManager::None;  
1380           transition(Connected);           transition(Connected);
1381             mProposedLocalSdp.reset();
1382             handler->onOfferRejected(getSessionHandle(), &msg);
1383           break;           break;
1384    
1385        case OnGeneralFailure:        case OnGeneralFailure:
1386           sendBye();           sendBye();
1387           transition(Terminated);           transition(Terminated);
1388           handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);           handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1389           break;           break;
1390    
1391        default:        default:
# Line 911  Line 1409 
1409        case OnUpdate:        case OnUpdate:
1410        case OnUpdateOffer:        case OnUpdateOffer:
1411        {        {
1412           SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
1413           mDialog.makeResponse(response, msg, 491);           mDialog.makeResponse(*response, msg, 491);
1414           BaseUsage::send(response);           send(response);
1415           break;           break;
1416        }        }
1417    
# Line 923  Line 1421 
1421           break;           break;
1422    
1423        case On2xxAnswer:        case On2xxAnswer:
1424        case On2xxOffer:        case On2xxOffer:  // .slg. doesn't really make sense
1425        {        {
1426             mStaleReInviteTimerSeq++;
1427           transition(Connected);           transition(Connected);
1428           handleSessionTimerResponse(msg);           handleSessionTimerResponse(msg);
1429           setCurrentLocalSdp(msg);           setCurrentLocalSdp(msg);
# Line 945  Line 1444 
1444    
1445              if (changed)              if (changed)
1446              {              {
1447                 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);                 mCurrentRemoteSdp = sdp;
1448                 handler->onRemoteSdpChanged(getSessionHandle(), msg, *sdp);                 handler->onRemoteSdpChanged(getSessionHandle(), msg, *mCurrentRemoteSdp);
1449              }              }
1450           }           }
1451           else           else
1452           {           {
1453              handler->onAnswer(getSessionHandle(), msg, *sdp);              mCurrentRemoteSdp = sdp;
1454                handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteSdp);
1455             }
1456            
1457             // !jf! do I need to allow a reINVITE overlapping the retransmission of
1458             // the ACK when a 200I is received? If yes, then I need to store all
1459             // ACK messages for 64*T1
1460             break;
1461          }
1462          case On2xx:
1463             mStaleReInviteTimerSeq++;
1464             sendAck();
1465             transition(Connected);
1466             handleSessionTimerResponse(msg);
1467             handler->onIllegalNegotiation(getSessionHandle(), msg);
1468             mProposedLocalSdp.reset();
1469             mProposedEncryptionLevel = DialogUsageManager::None;
1470             break;
1471    
1472          case On422Invite:
1473             mStaleReInviteTimerSeq++;
1474             if(msg.exists(h_MinSE))
1475             {
1476                // Change interval to min from 422 response
1477                mSessionInterval = msg.header(h_MinSE).value();
1478                mMinSE = mSessionInterval;
1479                sessionRefresh();
1480             }
1481             else
1482             {
1483                // Response must contact Min_SE - if not - just ignore
1484                // ?slg? callback?
1485                transition(Connected);
1486                mProposedLocalSdp.reset();
1487                mProposedEncryptionLevel = DialogUsageManager::None;
1488             }
1489             break;
1490    
1491          case On491Invite:
1492             mStaleReInviteTimerSeq++;
1493             transition(SentReinviteGlare);
1494             start491Timer();
1495             break;
1496    
1497          case OnGeneralFailure:
1498             mStaleReInviteTimerSeq++;
1499             sendBye();
1500             transition(Terminated);
1501             handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1502             break;
1503    
1504          case OnInviteFailure:
1505          case On487Invite:
1506             mStaleReInviteTimerSeq++;
1507             transition(Connected);
1508             mProposedLocalSdp.reset();
1509             handler->onOfferRejected(getSessionHandle(), &msg);
1510             break;
1511    
1512          default:
1513             dispatchOthers(msg);
1514             break;
1515       }
1516    }
1517    
1518    void
1519    InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1520    {
1521       InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1522       std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1523    
1524       switch (toEvent(msg, sdp.get()))
1525       {
1526          case OnInvite:
1527          case OnInviteReliable:
1528          case OnInviteOffer:
1529          case OnInviteReliableOffer:
1530          case OnUpdate:
1531          case OnUpdateOffer:
1532          {
1533             SharedPtr<SipMessage> response(new SipMessage);
1534             mDialog.makeResponse(*response, msg, 491);
1535             send(response);
1536             break;
1537           }           }
1538                    
1539           // !jf! do I need to allow a reINVITE overlapping the retransmission of        case On1xx:
1540           // the ACK when a 200I is received? If yes, then I need to store all        case On1xxEarly:
1541           // ACK messages for 64*T1           // Some UA's send a 100 response to a ReInvite - just ignore it
1542             break;
1543    
1544          case On2xxAnswer:  // .slg. doesn't really make sense
1545          case On2xxOffer:
1546          {
1547             mStaleReInviteTimerSeq++;
1548             transition(SentReinviteAnswered);
1549             handleSessionTimerResponse(msg);
1550             // mLastSessionModification = msg;   // ?slg? why are we storing 200's?
1551             mCurrentEncryptionLevel = getEncryptionLevel(msg);
1552             mProposedRemoteSdp = sdp;
1553             handler->onOffer(getSessionHandle(), msg, *mProposedRemoteSdp);
1554           break;           break;
1555        }        }
1556    
1557        case On2xx:        case On2xx:
1558             mStaleReInviteTimerSeq++;
1559           sendAck();           sendAck();
1560           transition(Connected);           transition(Connected);
1561           handleSessionTimerResponse(msg);           handleSessionTimerResponse(msg);
1562           handler->onIllegalNegotiation(getSessionHandle(), msg);           handler->onIllegalNegotiation(getSessionHandle(), msg);
1563           mProposedLocalSdp.release();           mProposedLocalSdp.reset();
1564           mProposedEncryptionLevel = DialogUsageManager::None;           mProposedEncryptionLevel = DialogUsageManager::None;
1565           break;           break;
1566    
1567        case On422Invite:        case On422Invite:
1568             mStaleReInviteTimerSeq++;
1569           if(msg.exists(h_MinSE))           if(msg.exists(h_MinSE))
1570           {           {
1571              // Change interval to min from 422 response              // Change interval to min from 422 response
# Line 981  Line 1578 
1578              // Response must contact Min_SE - if not - just ignore              // Response must contact Min_SE - if not - just ignore
1579              // ?slg? callback?              // ?slg? callback?
1580              transition(Connected);              transition(Connected);
1581              mProposedLocalSdp.release();              mProposedLocalSdp.reset();
1582              mProposedEncryptionLevel = DialogUsageManager::None;              mProposedEncryptionLevel = DialogUsageManager::None;
1583           }           }
1584           break;           break;
1585    
1586        case On491Invite:        case On491Invite:
1587           transition(SentReinviteGlare);           mStaleReInviteTimerSeq++;
1588             transition(SentReinviteNoOfferGlare);
1589           start491Timer();           start491Timer();
1590           break;           break;
1591    
1592        case OnGeneralFailure:        case OnGeneralFailure:
1593             mStaleReInviteTimerSeq++;
1594           sendBye();           sendBye();
1595           transition(Terminated);           transition(Terminated);
1596           handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);           handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1597           break;           break;
1598    
1599        case OnInviteFailure:        case OnInviteFailure:
1600        case On487Invite:        case On487Invite:
1601        case On489Invite:           mStaleReInviteTimerSeq++;
1602           transition(Connected);           transition(Connected);
1603           mProposedLocalSdp.release();           mProposedLocalSdp.reset();
1604           handler->onOfferRejected(getSessionHandle(), &msg);           handler->onOfferRejected(getSessionHandle(), &msg);
1605           break;           break;
1606    
# Line 1026  Line 1625 
1625        case OnUpdate:        case OnUpdate:
1626        case OnUpdateOffer:        case OnUpdateOffer:
1627        {        {
1628           SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
1629           mDialog.makeResponse(response, msg, 491);           mDialog.makeResponse(*response, msg, 491);
1630           BaseUsage::send(response);           send(response);
1631           break;           break;
1632        }        }
1633        case OnAckAnswer:        case OnAckAnswer:
1634           transition(Connected);           transition(Connected);
1635           setCurrentLocalSdp(msg);           setCurrentLocalSdp(msg);
1636           mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);           mCurrentRemoteSdp = sdp;
1637           mCurrentEncryptionLevel = getEncryptionLevel(msg);           mCurrentEncryptionLevel = getEncryptionLevel(msg);
1638           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1639                   handler->onAnswer(getSessionHandle(), msg, *sdp);                
1640             handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteSdp);
1641           break;                   break;        
1642        case OnAck:        case OnAck:
1643             if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
1644             {
1645                InfoLog(<< "dropped stale ACK");
1646             }
1647             else
1648             {
1649                InfoLog(<< "Got Ack with no answer");
1650           transition(Connected);           transition(Connected);
1651           mProposedLocalSdp.release();              mProposedLocalSdp.reset();
1652           mProposedEncryptionLevel = DialogUsageManager::None;           mProposedEncryptionLevel = DialogUsageManager::None;
1653           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer           mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1654                   //!dcm! -- should this be onIllegalNegotiation?                   //!dcm! -- should this be onIllegalNegotiation?
1655                   handler->onOfferRejected(getSessionHandle(), &msg);                   handler->onOfferRejected(getSessionHandle(), &msg);
1656             }
1657           break;           break;
1658        default:        default:
1659           dispatchOthers(msg);           dispatchOthers(msg);
# Line 1058  Line 1666 
1666  {  {
1667     InviteSessionHandler* handler = mDum.mInviteSessionHandler;     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1668     MethodTypes method = msg.header(h_CSeq).method();     MethodTypes method = msg.header(h_CSeq).method();
1669     if (method == INVITE && msg.isRequest())     if (msg.isRequest() && (method == INVITE || method == UPDATE))
1670     {     {
1671        // Received inbound reinvite, when waiting to resend outbound reinvite or update        DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1672        transition(ReceivedReinvite);        // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1673        handler->onOfferRejected(getSessionHandle(), &msg);        handler->onOfferRejected(getSessionHandle(), &msg);
1674          if(!isTerminated())   // make sure application didn't call end()
1675          {
1676             dispatchConnected(msg);  // act as if we received message in Connected state
1677     }     }
1678     else if (method == UPDATE && msg.isRequest())        else
1679     {     {
1680        // Received inbound update, when waiting to resend outbound reinvite or update           dispatchTerminated(msg);
1681        transition(ReceivedUpdate);        }
       handler->onOfferRejected(getSessionHandle(), &msg);  
1682     }     }
1683     else     else
1684     {     {
# Line 1077  Line 1687 
1687  }  }
1688    
1689  void  void
1690  InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)  InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1691  {  {
1692       InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1693     MethodTypes method = msg.header(h_CSeq).method();     MethodTypes method = msg.header(h_CSeq).method();
1694     if (method == INVITE || method == UPDATE)     if (msg.isRequest() && (method == INVITE || method == UPDATE))
1695       {
1696          // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1697          handler->onOfferRequestRejected(getSessionHandle(), msg);
1698          if(!isTerminated())   // make sure application didn't call end()
1699          {
1700             dispatchConnected(msg);  // act as if we received message in Connected state
1701          }
1702          else
1703          {
1704             dispatchTerminated(msg);
1705          }
1706       }
1707       else
1708       {
1709          dispatchOthers(msg);
1710       }
1711    }
1712    
1713    void
1714    InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1715    {
1716       InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1717       std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1718    
1719       switch (toEvent(msg, sdp.get()))
1720       {
1721          case OnInvite:
1722          case OnInviteReliable:
1723          case OnInviteOffer:
1724          case OnInviteReliableOffer:
1725          case OnUpdate:
1726          case OnUpdateOffer:
1727     {     {
1728        // Means that the UAC has sent us a second reINVITE or UPDATE before we        // Means that the UAC has sent us a second reINVITE or UPDATE before we
1729        // responded to the first one. Bastard!        // responded to the first one. Bastard!
1730        SipMessage response;           SharedPtr<SipMessage> response(new SipMessage);
1731        mDialog.makeResponse(response, msg, 500);           mDialog.makeResponse(*response, msg, 500);
1732        response.header(h_RetryAfter).value() = Random::getRandom() % 10;           response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1733        send(response);        send(response);
1734             break;
1735     }     }
1736     else        case OnBye:
1737     {     {
1738             // BYE received after a reINVITE, terminate the reINVITE transaction.
1739             SharedPtr<SipMessage> response(new SipMessage);
1740             mDialog.makeResponse(*response, *mLastRemoteSessionModification, 487); // Request Terminated
1741             handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1742             send(response);
1743    
1744             dispatchBye(msg);
1745             break;
1746          }
1747          default:
1748        dispatchOthers(msg);        dispatchOthers(msg);
1749             break;
1750     }     }
1751  }  }
1752    
# Line 1111  Line 1766 
1766  }  }
1767    
1768  void  void
1769    InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1770    {
1771       if (msg.isResponse() &&
1772           msg.header(h_CSeq).method() == INVITE &&
1773           msg.header(h_StatusLine).statusCode() / 200 == 1)
1774       {
1775          // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
1776          // called by the app - so just drop the retransmission
1777          return;
1778       }
1779       dispatchOthers(msg);
1780    }
1781    
1782    void
1783  InviteSession::dispatchWaitingToOffer(const SipMessage& msg)  InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1784  {  {
1785     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1786     {     {
1787        assert(mProposedLocalSdp.get());        assert(mProposedLocalSdp.get());
1788        mCurrentRetransmit200 = 0; // stop the 200 retransmit timer        mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1789        if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))        provideProposedOffer();
       {  
          provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),  
                        mProposedEncryptionLevel,  
                        dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));  
1790        }        }
1791        else        else
1792        {        {
1793           provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);        dispatchOthers(msg);
1794       }
1795        }        }
1796    
1797    void
1798    InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1799    {
1800       if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1801       {
1802          mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1803          requestOffer();
1804     }     }
1805     else     else
1806     {     {
# Line 1147  Line 1821 
1821        }        }
1822        sendBye();        sendBye();
1823        transition(Terminated);        transition(Terminated);
1824        mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);        mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1825       }
1826       else if(msg.isRequest())
1827       {
1828          if(msg.method() == BYE)
1829          {
1830             dispatchBye(msg);
1831          }
1832          else
1833          {
1834             SharedPtr<SipMessage> response(new SipMessage);
1835             mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
1836             send(response);
1837          }
1838     }     }
1839  }  }
1840    
# Line 1165  Line 1852 
1852    
1853           sendBye();           sendBye();
1854           transition(Terminated);           transition(Terminated);
1855           mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);           mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye);
1856           break;           break;
1857        }        }
1858                
# Line 1181  Line 1868 
1868    
1869     if (msg.isRequest())     if (msg.isRequest())
1870     {     {
1871        SipMessage response;        if (BYE == msg.header(h_CSeq).method())
1872        mDialog.makeResponse(response, msg, 481);        {
1873             SharedPtr<SipMessage> response(new SipMessage);
1874             mDialog.makeResponse(*response, msg, 200);
1875        send(response);        send(response);
1876          }
1877          else
1878          {
1879             SharedPtr<SipMessage> response(new SipMessage);
1880             mDialog.makeResponse(*response, msg, 481);
1881             send(response);
1882          }
1883    
1884        // !jf! means the peer sent BYE while we are waiting for response to BYE        // !jf! means the peer sent BYE while we are waiting for response to BYE
1885        //mDum.destroy(this);        //mDum.destroy(this);
# Line 1224  Line 1920 
1920           // handled in Dialog           // handled in Dialog
1921           WarningLog (<< "DUM delivered a "           WarningLog (<< "DUM delivered a "
1922                       << msg.header(h_CSeq).unknownMethodName()                       << msg.header(h_CSeq).unknownMethodName()
1923                       << " to the InviteSession "                       << " to the InviteSession in state: " << toData(mState)
1924                       << endl                       << endl
1925                       << msg);                       << msg);
1926           assert(0);           assert(0);
# Line 1240  Line 1936 
1936    
1937     // If we get an INVITE request from the wire and we are not in     // If we get an INVITE request from the wire and we are not in
1938     // Connected state, reject the request and send a BYE     // Connected state, reject the request and send a BYE
1939     SipMessage response;     SharedPtr<SipMessage> response(new SipMessage);
1940     mDialog.makeResponse(response, msg, 400); // !jf! what code to use?     mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
1941     InfoLog (<< "Sending " << response.brief());     InfoLog (<< "Sending " << response->brief());
1942     send(response);     send(response);
1943    
1944     sendBye();     sendBye();
1945     transition(Terminated);     transition(Terminated);
1946     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1947  }  }
1948    
1949  void  void
# Line 1256  Line 1952 
1952     assert(msg.header(h_CSeq).method() == PRACK);     assert(msg.header(h_CSeq).method() == PRACK);
1953     if(msg.isRequest())     if(msg.isRequest())
1954     {     {
1955        SipMessage rsp;        SharedPtr<SipMessage> rsp(new SipMessage);
1956        mDialog.makeResponse(rsp, msg, 481);        mDialog.makeResponse(*rsp, msg, 481);
1957        send(rsp);        send(rsp);
1958    
1959        sendBye();        sendBye();
1960        // !jf! should we make some other callback here        // !jf! should we make some other callback here
1961        transition(Terminated);        transition(Terminated);
1962        mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);        mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1963     }     }
1964     else     else
1965     {     {
# Line 1278  Line 1974 
1974     assert(msg.header(h_CSeq).method() == CANCEL);     assert(msg.header(h_CSeq).method() == CANCEL);
1975     if(msg.isRequest())     if(msg.isRequest())
1976     {     {
1977        SipMessage rsp;        SharedPtr<SipMessage> rsp(new SipMessage);
1978        mDialog.makeResponse(rsp, msg, 200);        mDialog.makeResponse(*rsp, msg, 200);
1979        send(rsp);        send(rsp);
1980    
1981        sendBye();        sendBye();
1982        // !jf! should we make some other callback here        // !jf! should we make some other callback here
1983        transition(Terminated);        transition(Terminated);
1984        handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);  
1985          handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteCancel, &msg);
1986     }     }
1987     else     else
1988     {     {
# Line 1301  Line 1998 
1998    
1999     if (msg.isRequest())     if (msg.isRequest())
2000     {     {
2001          // Check for any non-invite server transactions (e.g. INFO)
2002          // that have not been responded yet and terminate them.
2003          if (mServerNitState == NitProceeding)
2004          {
2005             mLastNitResponse->header(h_StatusLine).statusCode() = 487;  
2006             mLastNitResponse->setContents(0);
2007             Helper::getResponseCodeReason(487, mLastNitResponse->header(h_StatusLine).reason());
2008             send(mLastNitResponse);
2009             mServerNitState = NitComplete;
2010          }
2011    
2012        SipMessage rsp;        SharedPtr<SipMessage> rsp(new SipMessage);
2013        InfoLog (<< "Received " << msg.brief());        InfoLog (<< "Received " << msg.brief());
2014        mDialog.makeResponse(rsp, msg, 200);        mDialog.makeResponse(*rsp, msg, 200);
2015        send(rsp);        send(rsp);
2016    
2017        // !jf! should we make some other callback here        // !jf! should we make some other callback here
2018        transition(Terminated);        transition(Terminated);
2019        handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);  
2020          if (mDum.mDialogEventStateManager)
2021          {
2022             mDum.mDialogEventStateManager->onTerminated(mDialog, msg,
2023             InviteSessionHandler::RemoteBye);
2024          }
2025    
2026          handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
2027        mDum.destroy(this);        mDum.destroy(this);
2028     }     }
2029     else     else
# Line 1325  Line 2039 
2039     InviteSessionHandler* handler = mDum.mInviteSessionHandler;     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2040     if (msg.isRequest())     if (msg.isRequest())
2041     {     {
2042          if (mServerNitState == NitProceeding)
2043          {
2044             // Means that the UAC has sent us a second INFO before we
2045             // responded to the first one.
2046             SharedPtr<SipMessage> response(new SipMessage);
2047             mDialog.makeResponse(*response, msg, 500);
2048             response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2049             send(response);
2050          }
2051          else
2052          {
2053        InfoLog (<< "Received " << msg.brief());        InfoLog (<< "Received " << msg.brief());
2054        mDialog.makeResponse(mLastNitResponse, msg, 200);           mServerNitState = NitProceeding;
2055             mDialog.makeResponse(*mLastNitResponse, msg, 200);
2056        handler->onInfo(getSessionHandle(), msg);        handler->onInfo(getSessionHandle(), msg);
2057     }     }
2058       }
2059     else     else
2060     {     {
2061        assert(mNitState == NitProceeding);        assert(mNitState == NitProceeding);
       mNitState = NitComplete;  
2062        //!dcm! -- toss away 1xx to an info?        //!dcm! -- toss away 1xx to an info?
2063        if (msg.header(h_StatusLine).statusCode() >= 300)        if (msg.header(h_StatusLine).statusCode() >= 300)
2064        {        {
# Line 1342  Line 2068 
2068        {        {
2069           handler->onInfoSuccess(getSessionHandle(), msg);           handler->onInfoSuccess(getSessionHandle(), msg);
2070        }        }
2071          nitComplete();
2072     }     }
2073  }  }
2074    
2075  void  void
2076  InviteSession::acceptNIT(int statusCode)  InviteSession::acceptNIT(int statusCode, const Contents * contents)
2077  {  {
2078     if (statusCode / 100  != 2)     if (statusCode / 100  != 2)
2079     {     {
2080        throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);        throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2081     }     }
2082    
2083     mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;       if (mServerNitState != NitProceeding )
2084     Helper::getResponseCodeReason(statusCode, mLastNitResponse.header(h_StatusLine).reason());     {
2085     BaseUsage::send(mLastNitResponse);          throw UsageUseException("No transaction to accept", __FILE__, __LINE__);
2086       }
2087    
2088       mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;  
2089       mLastNitResponse->setContents(contents);
2090       Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2091       send(mLastNitResponse);  
2092       mServerNitState = NitComplete;
2093    }
2094    
2095    class InviteSessionAcceptNITCommand : public DumCommandAdapter
2096    {
2097    public:
2098       InviteSessionAcceptNITCommand(InviteSession& inviteSession, int statusCode, const Contents* contents)
2099          : mInviteSession(inviteSession),
2100            mStatusCode(statusCode),
2101            mContents(contents?contents->clone():0)
2102       {
2103    
2104       }
2105    
2106       virtual void executeCommand()
2107       {
2108          mInviteSession.acceptNITCommand(mStatusCode, mContents.get());
2109       }
2110    
2111       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2112       {
2113          return strm << "InviteSessionAcceptNITCommand";
2114       }
2115    private:
2116       InviteSession& mInviteSession;
2117       int mStatusCode;
2118       std::auto_ptr<Contents> mContents;
2119    };
2120    
2121    void
2122    InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
2123    {
2124       mDum.post(new InviteSessionAcceptNITCommand(*this, statusCode, contents));
2125  }  }
2126    
2127  void  void
# Line 1365  Line 2131 
2131     {     {
2132        throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);        throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2133     }     }
2134     mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;    
2135     Helper::getResponseCodeReason(statusCode, mLastNitResponse.header(h_StatusLine).reason());     if (mServerNitState != NitProceeding )
2136     BaseUsage::send(mLastNitResponse);     {
2137          throw UsageUseException("No transaction to reject", __FILE__, __LINE__);
2138       }
2139    
2140       mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;  
2141       mLastNitResponse->setContents(0);
2142       Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2143       send(mLastNitResponse);
2144       mServerNitState = NitComplete;
2145    }
2146    
2147    class InviteSessionRejectNITCommand : public DumCommandAdapter
2148    {
2149    public:
2150       InviteSessionRejectNITCommand(InviteSession& inviteSession, int statusCode)
2151          : mInviteSession(inviteSession),
2152          mStatusCode(statusCode)
2153       {
2154       }
2155    
2156       virtual void executeCommand()
2157       {
2158          mInviteSession.rejectNITCommand(mStatusCode);
2159       }
2160    
2161       virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2162       {
2163          return strm << "InviteSessionRejectNITCommand";
2164       }
2165    private:
2166       InviteSession& mInviteSession;
2167       int mStatusCode;
2168    };
2169    
2170    void
2171    InviteSession::rejectNITCommand(int statusCode)
2172    {
2173       mDum.post(new InviteSessionRejectNITCommand(*this, statusCode));
2174  }  }
2175    
2176  void  void
# Line 1376  Line 2179 
2179     InviteSessionHandler* handler = mDum.mInviteSessionHandler;     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2180     if (msg.isRequest())     if (msg.isRequest())
2181     {     {
2182          if (mServerNitState == NitProceeding)
2183          {
2184             // Means that the UAC has sent us a second NIT message before we
2185             // responded to the first one.
2186             SharedPtr<SipMessage> response(new SipMessage);
2187             mDialog.makeResponse(*response, msg, 500);
2188             response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2189             send(response);
2190          }
2191          else
2192          {
2193        InfoLog (<< "Received " << msg.brief());        InfoLog (<< "Received " << msg.brief());
2194        mDialog.makeResponse(mLastNitResponse, msg, 200);           mServerNitState = NitProceeding;
2195        mLastNitResponse.header(h_Contacts).clear();           mDialog.makeResponse(*mLastNitResponse, msg, 200);
2196             mLastNitResponse->header(h_Contacts).clear();
2197        handler->onMessage(getSessionHandle(), msg);        handler->onMessage(getSessionHandle(), msg);
2198     }     }
2199       }
2200     else     else
2201     {     {
2202        assert(mNitState == NitProceeding);        assert(mNitState == NitProceeding);
       mNitState = NitComplete;  
2203        //!dcm! -- toss away 1xx to an message?        //!dcm! -- toss away 1xx to an message?
2204        if (msg.header(h_StatusLine).statusCode() >= 300)        if (msg.header(h_StatusLine).statusCode() >= 300)
2205        {        {
# Line 1394  Line 2209 
2209        {        {
2210           handler->onMessageSuccess(getSessionHandle(), msg);           handler->onMessageSuccess(getSessionHandle(), msg);
2211        }        }
2212          nitComplete();
2213     }     }
2214  }  }
2215    
# Line 1401  Line 2217 
2217  InviteSession::startRetransmit200Timer()  InviteSession::startRetransmit200Timer()
2218  {  {
2219     mCurrentRetransmit200 = Timer::T1;     mCurrentRetransmit200 = Timer::T1;
2220     int seq = mLastSessionModification.header(h_CSeq).sequence();     unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
2221     mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);     mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
2222     mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);     mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
2223  }  }
2224    
2225    // RFC3261 section 14.1
2226    // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
2227    // a value T chosen as follows:
2228    //  1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
2229    //  chosen value between 2.1 and 4 seconds in units of 10 ms.
2230    //  2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
2231    //  randomly chosen value of between 0 and 2 seconds in units of 10 ms.
2232  void  void
2233  InviteSession::start491Timer()  InviteSession::start491Timer()
2234  {  {
2235     int seq = mLastSessionModification.header(h_CSeq).sequence();     unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
2236     int timer = Random::getRandom() % 4000;  
2237       if (dynamic_cast<ClientInviteSession*>(this))
2238       {
2239          int timer = Random::getRandom() % (4000 - 2100);
2240          timer += 2100;
2241          timer -= timer % 10;
2242          
2243          DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2244          mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2245       }
2246       else
2247       {
2248          int timer = Random::getRandom() % 2000;
2249          timer -= timer % 10;
2250          DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2251     mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);     mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2252  }  }
2253    }
2254    
2255    void
2256    InviteSession::startStaleReInviteTimer()
2257    {
2258       InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
2259       unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
2260      
2261       mDum.addTimer(DumTimeout::StaleReInvite,
2262                     when,
2263                     getBaseHandle(),
2264                     ++mStaleReInviteTimerSeq);
2265    }
2266    
2267  void  void
2268  InviteSession::setSessionTimerHeaders(SipMessage &msg)  InviteSession::setSessionTimerHeaders(SipMessage &msg)
# Line 1443  Line 2293 
2293     if (updateMethodSupported())     if (updateMethodSupported())
2294     {     {
2295        transition(SentUpdate);        transition(SentUpdate);
2296        mDialog.makeRequest(mLastSessionModification, UPDATE);        mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
2297        mLastSessionModification.releaseContents();  // Don't send SDP        mLastLocalSessionModification->setContents(0);  // Don't send SDP
2298     }     }
2299     else     else
2300     {     {
2301        transition(SentReinvite);        transition(SentReinvite);
2302        mDialog.makeRequest(mLastSessionModification, INVITE);        mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
2303        InviteSession::setSdp(mLastSessionModification, mCurrentLocalSdp.get());        startStaleReInviteTimer();
2304          InviteSession::setSdp(*mLastLocalSessionModification, mCurrentLocalSdp.get());
2305        mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);        mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
2306        mSessionRefreshReInvite = true;              mSessionRefreshReInvite = true;      
2307     }     }
2308     mLastSessionModification.remove(h_ProxyAuthorizations); // remove remote credentials.     setSessionTimerHeaders(*mLastLocalSessionModification);
    setSessionTimerHeaders(mLastSessionModification);  
2309    
2310     InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief());     InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
2311     DumHelper::setOutgoingEncrptionLevel(mLastSessionModification, mCurrentEncryptionLevel);     DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
2312     send(mLastSessionModification);     send(mLastLocalSessionModification);
2313  }  }
2314    
2315  void  void
# Line 1479  Line 2329 
2329     case Profile::PreferRemoteRefreshes:     case Profile::PreferRemoteRefreshes:
2330        mSessionRefresher = false;  // Default refresher is Remote        mSessionRefresher = false;  // Default refresher is Remote
2331        break;        break;
2332     case Profile::PreferUASRefreshes:       case Profile::PreferCalleeRefreshes:  
2333        mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee        mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is callee
2334        break;        break;
2335     case Profile::PreferUACRefreshes:     case Profile::PreferCallerRefreshes:
2336        mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller        mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is caller
2337        break;        break;
2338     }     }
2339  }  }
# Line 1502  Line 2352 
2352        else        else
2353        {        {
2354           // 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)           // 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)
2355           mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);           mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
2356        }        }
2357     }     }
2358     else  // Session Interval less than 90 - consider timers disabled     else  // Session Interval less than 90 - consider timers disabled
# Line 1516  Line 2366 
2366  {  {
2367     assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);     assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
2368    
2369       // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2370       if (msg.exists(h_PAssertedIdentities))
2371       {
2372           mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
2373       }
2374    
2375     // If session timers are locally supported then handle response     // If session timers are locally supported then handle response
2376     if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))     if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2377     {     {
# Line 1560  Line 2416 
2416  {  {
2417     assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);     assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
2418    
2419       // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2420       if (request.exists(h_PAssertedIdentities))
2421       {
2422           mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
2423       }
2424    
2425     // If session timers are locally supported then add necessary headers to response     // If session timers are locally supported then add necessary headers to response
2426     if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))     if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2427     {     {
# Line 1627  Line 2489 
2489           return "InviteSession::SentReinvite";           return "InviteSession::SentReinvite";
2490        case SentReinviteGlare:        case SentReinviteGlare:
2491           return "InviteSession::SentReinviteGlare";           return "InviteSession::SentReinviteGlare";
2492          case SentReinviteNoOffer:
2493             return "InviteSession::SentReinviteNoOffer";
2494          case SentReinviteAnswered:
2495             return "InviteSession::SentReinviteAnswered";
2496          case SentReinviteNoOfferGlare:
2497             return "InviteSession::SentReinviteNoOfferGlare";
2498        case ReceivedUpdate:        case ReceivedUpdate:
2499           return "InviteSession::ReceivedUpdate";           return "InviteSession::ReceivedUpdate";
2500        case ReceivedReinvite:        case ReceivedReinvite:
# Line 1639  Line 2507 
2507           return "InviteSession::Answered";           return "InviteSession::Answered";
2508        case WaitingToOffer:        case WaitingToOffer:
2509           return "InviteSession::WaitingToOffer";           return "InviteSession::WaitingToOffer";
2510          case WaitingToRequestOffer:
2511             return "InviteSession::WaitingToRequestOffer";
2512        case WaitingToTerminate:        case WaitingToTerminate:
2513           return "InviteSession::WaitingToTerminate";           return "InviteSession::WaitingToTerminate";
2514        case WaitingToHangup:        case WaitingToHangup:
# Line 1680  Line 2550 
2550           return "UAC_Answered";           return "UAC_Answered";
2551        case UAC_SentUpdateEarly:        case UAC_SentUpdateEarly:
2552           return "UAC_SentUpdateEarly";           return "UAC_SentUpdateEarly";
2553        case UAC_SentUpdateConnected:        case UAC_SentUpdateEarlyGlare:
2554           return "UAC_SentUpdateConnected";           return "UAC_SentUpdateEarlyGlare";
2555        case UAC_ReceivedUpdateEarly:        case UAC_ReceivedUpdateEarly:
2556           return "UAC_ReceivedUpdateEarly";           return "UAC_ReceivedUpdateEarly";
2557        case UAC_SentAnswer:        case UAC_SentAnswer:
# Line 1693  Line 2563 
2563    
2564        case UAS_Start:        case UAS_Start:
2565           return "UAS_Start";           return "UAS_Start";
2566        case UAS_OfferReliable:        case UAS_ReceivedOfferReliable:
2567           return "UAS_OfferReliable";           return "UAS_ReceivedOfferReliable";
2568        case UAS_NoOfferReliable:        case UAS_NoOfferReliable:
2569           return "UAS_NoOfferReliable";           return "UAS_NoOfferReliable";
2570        case UAS_FirstSentOfferReliable:        case UAS_FirstSentOfferReliable:
2571           return "UAS_FirstSentOfferReliable";           return "UAS_FirstSentOfferReliable";
2572        case UAS_FirstEarlyReliable:        case UAS_FirstSentAnswerReliable:
2573           return "UAS_FirstEarlyReliable";           return "UAS_FirstSentAnswerReliable";
2574        case UAS_EarlyReliable:        case UAS_NegotiatedReliable:
2575           return "UAS_EarlyReliable";           return "UAS_NegotiatedReliable";
2576        case UAS_SentUpdate:        case UAS_SentUpdate:
2577           return "UAS_SentUpdate";           return "UAS_SentUpdate";
2578        case UAS_SentUpdateAccepted:        case UAS_SentUpdateAccepted:
# Line 1715  Line 2585 
2585           return "UAS_WaitingToTerminate";           return "UAS_WaitingToTerminate";
2586        case UAS_WaitingToHangup:        case UAS_WaitingToHangup:
2587           return "UAS_WaitingToHangup";           return "UAS_WaitingToHangup";
2588          case UAS_WaitingToRequestOffer:
2589             return "UAS_WaitingToRequestOffer";
2590     }     }
2591     assert(0);     assert(0);
2592     return "Undefined";     return "Undefined";
# Line 1731  Line 2603 
2603  bool  bool
2604  InviteSession::isReliable(const SipMessage& msg)  InviteSession::isReliable(const SipMessage& msg)
2605  {  {
2606     // Ensure supported both locally and remotely     if(msg.method() != INVITE)
    return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&  
           mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));  
 }  
   
 std::auto_ptr<SdpContents>  
 InviteSession::getSdp(const SipMessage& msg)  
2607  {  {
2608     // !jf! this code doesn't yet work - definitely if USE_SSL=false        return false;
2609     //Helper::ContentsSecAttrs attrs = Helper::extractFromPkcs7(msg, mDum.getSecurity());     }
2610     //return std::auto_ptr<SdpContents>(dynamic_cast<SdpContents*>(attrs.mContents.get()));     if(msg.isRequest())
    SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());  
    if (sdp)  
2611     {     {
2612        SdpContents* cloned = static_cast<SdpContents*>(sdp->clone());        return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never
2613        return std::auto_ptr<SdpContents>(cloned);           && (msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel))
2614                 || msg.exists(h_Requires)   && msg.header(h_Requires).find(Token(Symbols::C100rel)));
2615     }     }
2616     else     else
2617     {     {
2618        static std::auto_ptr<SdpContents> empty;        return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never
2619        return empty;           && (msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel))
2620                 || (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
2621     }     }
2622  }  }
2623    
2624  std::auto_ptr<SdpContents>  std::auto_ptr<SdpContents>
2625    InviteSession::getSdp(const SipMessage& msg)
2626    {
2627       return Helper::getSdp(msg.getContents());
2628    }
2629    
2630    std::auto_ptr<SdpContents>
2631  InviteSession::makeSdp(const SdpContents& sdp)  InviteSession::makeSdp(const SdpContents& sdp)
2632  {  {
2633     return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));     return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
# Line 1805  Line 2677 
2677     msg.setContents(sdp);     msg.setContents(sdp);
2678  }  }
2679    
2680    void
2681    InviteSession::provideProposedOffer()
2682    {
2683       if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2684       {
2685          provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
2686                        mProposedEncryptionLevel,
2687                        dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
2688       }
2689       else
2690       {
2691          provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
2692       }
2693    }
2694    
2695  InviteSession::Event  InviteSession::Event
2696  InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)  InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
2697  {  {
2698     MethodTypes method = msg.header(h_CSeq).method();     MethodTypes method = msg.header(h_CSeq).method();
2699     int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;     int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2700      
2701       //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
2702       //responses, reiable provisionals should only be received if the invite was
2703       //sent reliably.  Spurious reliable provisional respnoses are dropped outside
2704       //the state machine.
2705     bool reliable = isReliable(msg);     bool reliable = isReliable(msg);
2706     bool sentOffer = mProposedLocalSdp.get();     bool sentOffer = mProposedLocalSdp.get();
2707    
# Line 1846  Line 2738 
2738           }           }
2739        }        }
2740     }     }
2741     else if (method == INVITE && code > 100 && code < 200)   // !kh! 100 is handled by transaction layer.     else if (method == INVITE && code > 100 && code < 200)
2742     {     {
2743        if (reliable)        if (reliable)
2744        {        {
# Line 1904  Line 2796 
2796     {     {
2797        return On487Invite;        return On487Invite;
2798     }     }
    else if (method == INVITE && code == 489)  
    {  
       return On489Invite;  
    }  
2799     else if (method == INVITE && code == 491)     else if (method == INVITE && code == 491)
2800     {     {
2801        return On491Invite;        return On491Invite;
# Line 1974  Line 2862 
2862     {     {
2863        return On422Update;        return On422Update;
2864     }     }
    else if (method == UPDATE && code == 489)  
    {  
       return On489Update;  
    }  
2865     else if (method == UPDATE && code == 491)     else if (method == UPDATE && code == 491)
2866     {     {
2867        return On491Update;        return On491Update;
# Line 1995  Line 2879 
2879    
2880  void InviteSession::sendAck(const SdpContents *sdp)  void InviteSession::sendAck(const SdpContents *sdp)
2881  {  {
2882     SipMessage ack;     SharedPtr<SipMessage> ack(new SipMessage);
2883     mDialog.makeRequest(ack, ACK);  
2884       assert(mAcks.count(mLastLocalSessionModification->getTransactionId()) == 0);
2885       SharedPtr<SipMessage> source;
2886      
2887       if (mLastLocalSessionModification->method() == UPDATE)
2888       {
2889          //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
2890          source = mDialog.mDialogSet.getCreator()->getLastRequest();
2891       }
2892       else
2893       {
2894          source = mLastLocalSessionModification;
2895       }
2896    
2897       mDialog.makeRequest(*ack, ACK);
2898    
2899       // Copy Authorization, Proxy Authorization headers and CSeq from original Invite
2900       if(source->exists(h_Authorizations))
2901       {
2902          ack->header(h_Authorizations) = source->header(h_Authorizations);
2903       }
2904       if(source->exists(h_ProxyAuthorizations))
2905       {
2906          ack->header(h_ProxyAuthorizations) = source->header(h_ProxyAuthorizations);
2907       }
2908       ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
2909    
2910     if(sdp != 0)     if(sdp != 0)
2911     {     {
2912        setSdp(ack, *sdp);        setSdp(*ack, *sdp);
2913     }     }
2914     InfoLog (<< "Sending " << ack.brief());     mAcks[source->getTransactionId()] = ack;
2915       mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(), 0, source->getTransactionId());
2916    
2917       InfoLog (<< "Sending " << ack->brief());
2918     send(ack);     send(ack);
2919  }  }
2920    
2921  void InviteSession::sendBye()  void InviteSession::sendBye()
2922  {  {
2923     SipMessage bye;     SharedPtr<SipMessage> bye(new SipMessage());
2924     mDialog.makeRequest(bye, BYE);     mDialog.makeRequest(*bye, BYE);
2925     Data reason;     Data txt;
2926     if (mEndReason != NotSpecified)     if (mEndReason != NotSpecified)
2927     {     {
2928        reason = getEndReasonString(mEndReason);        Token reason("SIP");
2929        bye.header(h_Reasons).push_back(Token(reason));              txt = getEndReasonString(mEndReason);
2930          reason.param(p_description) = txt;
2931          bye->header(h_Reasons).push_back(reason);      
2932       }
2933    
2934       if (mDum.mDialogEventStateManager)
2935       {
2936          mDum.mDialogEventStateManager->onTerminated(mDialog, *bye, InviteSessionHandler::LocalBye);
2937     }     }
2938        
2939     InfoLog (<< myAddr() << " Sending BYE " << reason);     InfoLog (<< myAddr() << " Sending BYE " << txt);
2940     send(bye);     send(bye);
2941  }  }
2942    
# Line 2054  Line 2974 
2974     {     {
2975        mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));        mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
2976     }     }
2977     mProposedLocalSdp.release();     mProposedLocalSdp.reset();  
2978  }  }
2979    
2980  void InviteSession::onReadyToSend(SipMessage& msg)  void InviteSession::onReadyToSend(SipMessage& msg)
# Line 2062  Line 2982 
2982     mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);     mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
2983  }  }
2984    
2985  void InviteSession::send(SipMessage& msg)  void InviteSession::referNoSub(const SipMessage& msg)
2986  {  {
2987     if (msg.isRequest())     assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
2988       mLastReferNoSubRequest = msg;
2989       mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
2990    }
2991    
2992    void
2993    InviteSession::acceptReferNoSub(int statusCode)
2994     {     {
2995        // give app an chance to adorn the message.     if (statusCode / 100  != 2)
2996        onReadyToSend(msg);     {
2997          throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2998       }
2999    
3000       SharedPtr<SipMessage> response(new SipMessage);
3001       mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
3002       response->header(h_ReferSub).value() = "false";
3003       //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
3004      
3005       send(response);
3006    }
3007    
3008    void
3009    InviteSession::rejectReferNoSub(int responseCode)
3010    {
3011       if (responseCode < 400)
3012       {
3013          throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
3014     }     }
3015    
3016     mDialog.send(msg);     SharedPtr<SipMessage> response(new SipMessage);
3017       mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
3018       send(response);
3019  }  }
3020    
3021  /* ====================================================================  /* ====================================================================
# Line 2124  Line 3069 
3069   *   *
3070   */   */
3071    
3072    
3073    

Legend:
Removed from v.5544  
changed lines
  Added in v.8690

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27