/[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 3241 by derek, Tue Aug 10 21:29:00 2004 UTC revision 3255 by derek, Fri Aug 13 17:14:26 2004 UTC
# Line 7  Line 7 
7  #include "resiprocate/dum/Profile.hxx"  #include "resiprocate/dum/Profile.hxx"
8  #include "resiprocate/dum/UsageUseException.hxx"  #include "resiprocate/dum/UsageUseException.hxx"
9  #include "resiprocate/os/Logger.hxx"  #include "resiprocate/os/Logger.hxx"
10    #include "resiprocate/os/Timer.hxx"
11    
12  #if defined(WIN32) && defined(_DEBUG) &&defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio  #if defined(WIN32) && defined(_DEBUG) &&defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio
13  #define _CRTDBG_MAP_ALLOC  #define _CRTDBG_MAP_ALLOC
# Line 19  Line 20 
20  #define RESIPROCATE_SUBSYSTEM Subsystem::DUM  #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
21    
22  using namespace resip;  using namespace resip;
23    using namespace std;
 unsigned long  
 InviteSession::T1 = 500;  
   
 unsigned long  
 InviteSession::T2 = 8 * T1;  
   
 unsigned long  
 InviteSession::TimerH = 64 * T1;  
24    
25  InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState)  InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState)
26     : DialogUsage(dum, dialog),     : DialogUsage(dum, dialog),
27       mState(initialState),       mState(initialState),
28         mNitState(NitComplete),
29       mOfferState(Nothing),       mOfferState(Nothing),
30       mCurrentLocalSdp(0),       mCurrentLocalSdp(0),
31       mCurrentRemoteSdp(0),       mCurrentRemoteSdp(0),
# Line 39  Line 33 
33       mProposedRemoteSdp(0),       mProposedRemoteSdp(0),
34       mNextOfferOrAnswerSdp(0),       mNextOfferOrAnswerSdp(0),
35       mDestroyer(this),       mDestroyer(this),
36       mCurrentRetransmit200(0)       mCurrentRetransmit200(Timer::T1),
37         mUserConnected(false)
38  {  {
39     DebugLog ( << "^^^ InviteSession::InviteSession " << this);       DebugLog ( << "^^^ InviteSession::InviteSession " << this);  
40     assert(mDum.mInviteSessionHandler);     assert(mDum.mInviteSessionHandler);
# Line 69  Line 64 
64     return mLastRequest;     return mLastRequest;
65  }  }
66    
67    SipMessage&
68    InviteSession::makeFinalResponse(int code)
69    {
70       int cseq = mLastRequest.header(h_CSeq).sequence();
71       SipMessage& finalResponse = mFinalResponseMap[cseq];
72       mDialog.makeResponse(finalResponse, mLastRequest, 200);
73       return finalResponse;
74    }
75    
76  SipMessage&  SipMessage&
77  InviteSession::acceptOffer(int statusCode)  InviteSession::acceptOffer(int statusCode)
# Line 78  Line 81 
81        throw new UsageUseException("Must be in the ReInviting state and have propsed an answer to call answerModifySession",        throw new UsageUseException("Must be in the ReInviting state and have propsed an answer to call answerModifySession",
82                                    __FILE__, __LINE__);                                    __FILE__, __LINE__);
83     }     }
84     mState = AcceptingReInvite;     mState = Connected;
85     mDialog.makeResponse(mFinalResponse, mLastRequest, statusCode);     return makeFinalResponse(statusCode);
    return mFinalResponse;  
86  }  }
87    
88  void  void
# Line 123  Line 125 
125     return InviteSessionHandle(mDum, getBaseHandle().getId());     return InviteSessionHandle(mDum, getBaseHandle().getId());
126  }  }
127    
   
128  void  void
129  InviteSession::dispatch(const DumTimeout& timeout)  InviteSession::dispatch(const DumTimeout& timeout)
130  {  {
131     Destroyer::Guard guard(mDestroyer);     Destroyer::Guard guard(mDestroyer);
132     if (timeout.type() == DumTimeout::Retransmit200 && (mState == Accepting || mState == AcceptingReInvite ))     if (timeout.type() == DumTimeout::Retransmit200)
133     {     {
134        mDum.send(mFinalResponse);              CSeqToMessageMap::iterator it = mFinalResponseMap.find(timeout.seq());
135        mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(T2, mCurrentRetransmit200*2), getBaseHandle(),  0);        if (it != mFinalResponseMap.end())
136          {
137             mDum.send(it->second);
138             mCurrentRetransmit200 *= 2;
139             mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(),  timeout.seq());
140          }
141     }     }
142     else if (timeout.type() == DumTimeout::WaitForAck && mState != Connected)     else if (timeout.type() == DumTimeout::WaitForAck)
143     {     {
144        mDialog.makeResponse(mLastResponse, mLastRequest, 408);        CSeqToMessageMap::iterator it = mFinalResponseMap.find(timeout.seq());
145        mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), mLastResponse);              if (it != mFinalResponseMap.end())
146        guard.destroy();              {
147             mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle(), it->second);
148             mFinalResponseMap.erase(it);
149          }
150       }
151       else if (timeout.type() == DumTimeout::CanDiscardAck)
152       {
153          assert(mAckMap.find(timeout.seq()) != mFinalResponseMap.end());
154          mAckMap.erase(timeout.seq());
155     }     }
156  }  }
157    
# Line 148  Line 162 
162     std::pair<OfferAnswerType, const SdpContents*> offans;     std::pair<OfferAnswerType, const SdpContents*> offans;
163     offans = InviteSession::getOfferOrAnswer(msg);     offans = InviteSession::getOfferOrAnswer(msg);
164    
165       //ugly. non-invite-transactions(nit) don't interact with the invite
166       //transaction state machine(for now we have a separate INFO state machine)
167       //it's written as a gerneric NIT satet machine, but method isn't checked, and
168       //info is the only NIT so far. This should eventually live in Dialog, with a
169       //current method to determine valid responses.
170       if (msg.header(h_CSeq).method() == INFO)
171       {
172          if (msg.isRequest())
173          {
174             mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
175          }
176          else
177          {
178             if (mNitState == NitProceeding)
179             {            
180                int code = msg.header(h_StatusLine).statusCode();            
181                if (code < 200)
182                {
183                   //ignore
184                }
185                else if (code < 300)
186                {
187                   mNitState = NitComplete;
188                   mDum.mInviteSessionHandler->onInfoSuccess(getSessionHandle(), msg);
189                }
190                else
191                {
192                   mNitState = NitComplete;
193                   mDum.mInviteSessionHandler->onInfoFailure(getSessionHandle(), msg);
194                }
195             }
196          }      
197          return;
198       }        
199    
200       if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK &&
201           (mState == Connected || mState == ReInviting))
202       {
203          //quench 200 retransmissions
204          mFinalResponseMap.erase(msg.header(h_CSeq).sequence());
205          if (offans.first != None)
206          {                    
207             if (mOfferState == Answered)
208             {
209                //SDP in invite and in ACK.
210                mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg);
211             }
212             else
213             {
214                //delaying onConnected until late SDP
215                InviteSession::incomingSdp(msg, offans.second);
216                if (!mUserConnected)
217                {
218                   mUserConnected = true;
219                   mDum.mInviteSessionHandler->onConnected(getSessionHandle(), msg);
220                }
221             }
222          }
223          else if (mOfferState != Answered)
224          {
225             //no SDP in ACK when one is required
226             mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg);
227          }
228       }
229    
230     switch(mState)     switch(mState)
231     {     {
232        case Terminated:        case Terminated:
# Line 179  Line 258 
258              {              {
259                         // reINVITE                         // reINVITE
260                 case INVITE:                 case INVITE:
261                   {
262                      if (mOfferState == Answered)
263                      {
264                    mState = ReInviting;                    mState = ReInviting;
265                    mDialog.update(msg);                    mDialog.update(msg);
266                                    mLastRequest = msg; // !slg!                                    mLastRequest = msg; // !slg!
# Line 187  Line 269 
269                    {                    {
270                       incomingSdp(msg, offans.second);                       incomingSdp(msg, offans.second);
271                    }                    }
272                      }
273                      else
274                      {
275                         //4??
276                         SipMessage failure;
277                         mDialog.makeResponse(failure, msg, 491);
278                         InfoLog (<< "Sending 491 - overlapping Invite transactions");
279                         mDum.sendResponse(failure);
280                      }
281                   }  
282                    break;                    break;
   
283                 case BYE:                 case BYE:
284                    mState = Terminated;                    mState = Terminated;
285                    mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);                    mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
# Line 203  Line 294 
294                 case INFO:                 case INFO:
295                    mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);                    mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
296                    break;                    break;
                     
297                 case REFER:                 case REFER:
298                    //handled in Dialog                    //handled in Dialog
299                    assert(0);                                      assert(0);                  
# Line 216  Line 306 
306           }           }
307           else           else
308           {           {
309              //!dcm! -- need to change this logic for when we don't have an ACK yet              if ( msg.header(h_StatusLine).statusCode() == 200 && msg.header(h_CSeq).method() == INVITE)
310              if ( msg.header(h_StatusLine).statusCode() == 200)              {
311                   CSeqToMessageMap::iterator it = mAckMap.find(msg.header(h_CSeq).sequence());
312                   if (it != mAckMap.end())
313              {              {
314                 //retransmist ack                    send(it->second);
315                 mDum.send(mAck);                 }
316              }              }
317           }           }
318           break;           break;
319        case ReInviting:        case ReInviting:
320           if (msg.isResponse() && msg.header(h_CSeq).method() == INVITE)           if (msg.header(h_CSeq).method() == INVITE)
321             {
322                if (msg.isResponse())
323           {           {
324              int code = msg.header(h_StatusLine).statusCode();              int code = msg.header(h_StatusLine).statusCode();
325              if (code >=200 && code < 300)                 if (code < 200)
326                   {
327                      //ignore
328                   }                  
329                   else if (code < 300)
330                   {
331                      if (msg.header(h_CSeq).sequence() == mLastRequest.header(h_CSeq).sequence())
332              {              {
333                 mState = Connected;                 mState = Connected;
334                 send(ackConnection());                       send(makeAck());
335                 if (offans.first != None)                 if (offans.first != None)
336                 {                 {
337                    incomingSdp(msg, offans.second);                    incomingSdp(msg, offans.second);
338                 }                 }
339                 else                 else
340                 {                 {
341                            if (mOfferState != Answered)
342                            {
343                    //reset the sdp state machine                    //reset the sdp state machine
344                    incomingSdp(msg, 0);                    incomingSdp(msg, 0);
345                               mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg);
346                 }                 }
347              }              }
348              else                    }
349                      else //200 retransmission that overlaps with this Invite transaction
350              {              {
351                 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);                       CSeqToMessageMap::iterator it = mAckMap.find(msg.header(h_CSeq).sequence());
352                 mState = Connected;                                     if (it != mAckMap.end())
353                         {
354                            send(it->second);
355              }              }
356           }           }
          else  
          {  
             ErrLog ( << "Spurious message sent to UAS " << msg );              
             return;              
357           }           }
358           break;                 else
       case Accepting:  
          if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)  
359           {           {
360                      mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
361              mState = Connected;              mState = Connected;
             mDum.mInviteSessionHandler->onConnected(getSessionHandle(), msg);  
             if (offans.first != None)  
             {  
                InviteSession::incomingSdp(msg, offans.second);  
362              }              }
363           }           }
364           else           else
365           {           {
366              ErrLog ( << "Spurious message sent to UAS " << msg );                             SipMessage failure;
367                   mDialog.makeResponse(failure, msg, 491);
368                   InfoLog (<< "Sending 491 - overlapping Invite transactions");
369                   mDum.sendResponse(failure);
370              return;                          return;            
371           }           }
          break;          
       case AcceptingReInvite:  
          if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)  
          {  
             mState = Connected;              
             //this shouldn't happen, but it may be allowed(DUM API doesn't  
             //support this for re-invite)  
             if (offans.first != None)  
             {  
                InviteSession::incomingSdp(msg, offans.second);  
             }  
372           }           }
373           else           else
374           {           {
# Line 287  Line 376 
376              return;                          return;            
377           }           }
378           break;                   break;        
   
                     
379        default:        default:
380           DebugLog ( << "Throwing away strange message: " << msg );           DebugLog ( << "Throwing away strange message: " << msg );
381           //throw message away           //throw message away
# Line 298  Line 385 
385  }  }
386    
387  SipMessage&  SipMessage&
388    InviteSession::makeInfo(auto_ptr<Contents> contents)
389    {
390       if (mNitState == NitProceeding)
391       {
392          throw new UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
393                                      __FILE__, __LINE__);
394       }
395       mNitState = NitProceeding;
396       mDialog.makeRequest(mLastNit, INFO);
397       mLastRequest.setContents(contents);
398       return mLastNit;  
399    }
400    
401    SipMessage&
402  InviteSession::makeRefer(const NameAddr& referTo)  InviteSession::makeRefer(const NameAddr& referTo)
403  {  {
404     mDialog.makeRequest(mLastRequest, REFER);     mDialog.makeRequest(mLastRequest, REFER);
# Line 335  Line 436 
436           throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);           throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
437           break;           break;
438        case Connected:        case Connected:
439        case Accepting:           InfoLog ( << "InviteSession::end, Connected" );  
          InfoLog ( << "InviteSession::end, connected or Accepting" );    
440           mDialog.makeRequest(mLastRequest, BYE);           mDialog.makeRequest(mLastRequest, BYE);
441           //new transaction           //new transaction
442           assert(mLastRequest.header(h_Vias).size() == 1);           assert(mLastRequest.header(h_Vias).size() == 1);
# Line 465  Line 565 
565        }        }
566        else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)        else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
567        {        {
568           assert(&msg == &mFinalResponse);           int seq = msg.header(h_CSeq).sequence();
569           mCurrentRetransmit200 = T1;                   mCurrentRetransmit200 = Timer::T1;        
570           mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(),  0);           mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
571           mDum.addTimerMs(DumTimeout::WaitForAck, TimerH, getBaseHandle(),  0);           mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
572                            
573           //!dcm! -- this should be mFinalResponse...maybe assign here in           //!dcm! -- this should be mFinalResponse...maybe assign here in
574           //case the user wants to be very strange           //case the user wants to be very strange
# Line 579  Line 679 
679                 break;                 break;
680           }           }
681        }        }
682     }        else if (msg.isResponse() &&
683     return ret;                 msg.header(h_StatusLine).responseCode() < 200 &&
684  }                 msg.header(h_StatusLine).responseCode() >= 180)
   
 void  
 InviteSession::copyAuthorizations(SipMessage& request)  
685  {  {
686  #if 0           ret.second = contents;
    if (mLastRequest.exists(h_ProxyAuthorizations))  
    {  
       // should make the next auth (change nextNonce)  
       request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);  
687     }     }
    if (mLastRequest.exists(h_ProxyAuthorizations))  
    {  
       // should make the next auth (change nextNonce)  
       request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);  
688     }     }
689  #endif     return ret;
690  }  }
691    
692  SipMessage&  SipMessage&
# Line 619  Line 708 
708     return mLastRequest;     return mLastRequest;
709  }  }
710    
711  SipMessage&  void
712  InviteSession::ackConnection()  InviteSession::send()
713  {  {
714     //if not a reinvite, and a pending offer exists, throw     if (mOfferState == Answered)
715     makeAck();     {
716     //new transaction        throw new UsageUseException("Cannot call send when there it no Offer/Answer negotiation to do", __FILE__, __LINE__);
717     assert(mAck.header(h_Vias).size() == 1);     }
718  //   mAck.header(h_Vias).front().param(p_branch).reset();     send(makeAck());
    return mAck;  
719  }  }
720    
721  void  SipMessage&
722  InviteSession::makeAck()  InviteSession::makeAck()
723  {  {
724     mAck = mLastRequest;     InfoLog ( << "InviteSession::makeAck" );
725    
726       int cseq = mLastRequest.header(h_CSeq).sequence();
727       assert(mAckMap.find(cseq) == mAckMap.end());
728       SipMessage& ack = mAckMap[cseq];
729       ack = mLastRequest;
730       mDialog.makeRequest(ack, ACK);
731       mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), cseq);
732    
733     InfoLog ( << "InviteSession::makeAck:before: " << mAck );       assert(ack.header(h_Vias).size() == 1);
734    
    mDialog.makeRequest(mAck, ACK);  
735     if (mNextOfferOrAnswerSdp)     if (mNextOfferOrAnswerSdp)
736     {     {
737        mAck.setContents(mNextOfferOrAnswerSdp);        ack.setContents(mNextOfferOrAnswerSdp);
738        sendSdp(mNextOfferOrAnswerSdp);        sendSdp(mNextOfferOrAnswerSdp);
739        mNextOfferOrAnswerSdp = 0;        mNextOfferOrAnswerSdp = 0;
740     }     }
741       return ack;
    InfoLog ( << "InviteSession::makeAck:after: " << mAck );    
742  }  }
743    
744  /* ====================================================================  /* ====================================================================

Legend:
Removed from v.3241  
changed lines
  Added in v.3255

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27