/[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 2809 by jason, Sat May 29 02:56:14 2004 UTC revision 3079 by derek, Thu Jul 8 21:44:19 2004 UTC
# Line 1  Line 1 
1  #include "resiprocate/SipMessage.hxx"  #include "resiprocate/SipMessage.hxx"
2    #include "resiprocate/SdpContents.hxx"
3  #include "resiprocate/dum/Dialog.hxx"  #include "resiprocate/dum/Dialog.hxx"
4  #include "resiprocate/dum/DialogUsageManager.hxx"  #include "resiprocate/dum/DialogUsageManager.hxx"
5  #include "resiprocate/dum/InviteSession.hxx"  #include "resiprocate/dum/InviteSession.hxx"
6    #include "resiprocate/dum/InviteSessionHandler.hxx"
7    #include "resiprocate/dum/UsageUseException.hxx"
8    #include "resiprocate/os/Logger.hxx"
9    
10    #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
11    
12  using namespace resip;  using namespace resip;
13    
14  InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)  unsigned long
15    InviteSession::T1 = 500;
16    
17    unsigned long
18    InviteSession::T2 = 8 * T1;
19    
20    unsigned long
21    InviteSession::TimerH = 64 * T1;
22    
23    InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState)
24     : BaseUsage(dum, dialog),     : BaseUsage(dum, dialog),
25       mOfferState(None),       mState(initialState),
26         mOfferState(Nothing),
27       mCurrentLocalSdp(0),       mCurrentLocalSdp(0),
28       mCurrentRemoteSdp(0),       mCurrentRemoteSdp(0),
29       mProposedLocalSdp(0),       mProposedLocalSdp(0),
30       mProposedRemoteSdp(0)       mProposedRemoteSdp(0),
31         mNextOfferOrAnswerSdp(0),
32         mCurrentRetransmit200(0)      
33    
34    {
35       InfoLog ( << "^^^ InviteSession::InviteSession " << this);  
36       assert(mDum.mInviteSessionHandler);
37    }
38    
39    InviteSession::~InviteSession()
40  {  {
41       InfoLog ( << "^^^ InviteSession::~InviteSession " << this);  
42       delete mCurrentLocalSdp;
43       delete mCurrentRemoteSdp;
44       delete mProposedLocalSdp;
45       delete mProposedRemoteSdp;
46       delete mNextOfferOrAnswerSdp;
47       mDialog.mInviteSession = 0;
48  }  }
49    
50  SipMessage&  SipMessage&
51  InviteSession::getOfferOrAnswer()  InviteSession::modifySession()
52    {
53       if (mNextOfferOrAnswerSdp == 0 || mState != Connected)
54  {  {
55          throw new UsageUseException("Must be in the connected state and have propsed an offer to call modifySession",
56                                      __FILE__, __LINE__);
57       }
58       mState = ReInviting;
59       mDialog.makeRequest(mLastRequest, INVITE);
60     return mLastRequest;     return mLastRequest;
61  }  }
62    
63    
64    SipMessage&
65    InviteSession::acceptOffer(int statusCode)
66    {
67       if (mNextOfferOrAnswerSdp == 0 || mState != ReInviting)
68       {
69          throw new UsageUseException("Must be in the ReInviting state and have propsed an answer to call answerModifySession",
70                                      __FILE__, __LINE__);
71       }
72       mState = AcceptingReInvite;
73       mDialog.makeResponse(mLastResponse, mLastRequest, statusCode);
74       return mLastResponse;
75    }
76    
77    void
78    InviteSession::setOffer(const SdpContents* sdp)
79    {
80       if (mProposedRemoteSdp)
81       {
82          throw UsageUseException("Cannot set an offer with an oustanding remote offer", __FILE__, __LINE__);
83       }
84       mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
85    }
86    
87    void
88    InviteSession::setAnswer(const SdpContents* sdp)
89    {
90       if (mProposedLocalSdp )
91       {
92          throw UsageUseException("Cannot set an answer with an oustanding offer", __FILE__, __LINE__);
93       }
94       mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
95    }
96    
97  const SdpContents*  const SdpContents*
98  InviteSession::getLocalSdp()  InviteSession::getLocalSdp()
99  {  {
# Line 33  Line 106 
106     return mCurrentRemoteSdp;     return mCurrentRemoteSdp;
107  }  }
108    
109    InviteSessionHandle
110    InviteSession::getSessionHandle()
111    {
112       return InviteSessionHandle(mDum, getBaseHandle().getId());
113    }
114    
115    
116    void
117    InviteSession::dispatch(const DumTimeout& timeout)
118    {
119       if (timeout.type() == DumTimeout::Retransmit200 && (mState == Accepting || mState == AcceptingReInvite ))
120       {
121          mDum.send(mFinalResponse);      
122          mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(T2, mCurrentRetransmit200*2), getBaseHandle(),  0);
123       }
124       else if (timeout.type() == DumTimeout::WaitForAck && mState != Connected)
125       {
126          mDialog.makeResponse(mLastResponse, mLastRequest, 408);
127          mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), mLastResponse);      
128          delete this;      
129       }
130    }
131    
132    void
133    InviteSession::dispatch(const SipMessage& msg)
134    {
135       std::pair<OfferAnswerType, const SdpContents*> offans;
136       offans = InviteSession::getOfferOrAnswer(msg);
137    
138       switch(mState)
139       {
140          case Terminated:
141             //!dcm! -- 481 behaviour here, should pretty much die on anything
142             //eventually 200 to BYE could be handled further out
143             if (msg.isResponse())
144             {
145                int code = msg.header(h_StatusLine).statusCode();
146                if ((code  == 200 && msg.header(h_CSeq).method() == BYE) || code > 399)
147                {
148                   mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);      
149                   delete this;
150                   return;
151                }
152             }
153             break;
154          case Connected:
155             // reINVITE
156             if (msg.isRequest())
157             {
158                switch(msg.header(h_RequestLine).method())
159                {
160                   case INVITE:
161                      mState = AcceptingReInvite;
162                      mDialog.update(msg);
163                                      mLastRequest = msg; // !slg!
164                      mDum.mInviteSessionHandler->onDialogModified(getSessionHandle(), msg);
165                      if (offans.first != None)
166                      {
167                         incomingSdp(msg, offans.second);
168                      }
169                      break;
170    
171                   case BYE:
172                      mState = Terminated;
173                      mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
174                      mDialog.makeResponse(mLastResponse, msg, 200);
175                      send(mLastResponse);
176                      break;
177    
178                   case UPDATE:
179                      assert(0);
180                      break;
181                      
182                   case INFO:
183                      mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
184                      break;
185                      
186                   case REFER:
187                      assert(0); // !jf!
188                      mDum.mInviteSessionHandler->onRefer(getSessionHandle(), msg);
189                      break;
190                      
191                   default:
192                      InfoLog (<< "Ignoring request in an INVITE dialog: " << msg.brief());
193                      break;
194                }
195             }
196             else
197             {
198                //!dcm! -- need to change this logic for when we don't have an ACK yet
199                if ( msg.header(h_StatusLine).statusCode() == 200)
200                {
201                   //retransmist ack
202                   mDum.send(mAck);
203                }
204             }
205             break;
206          case ReInviting:
207             if (msg.isResponse() && msg.header(h_StatusLine).statusCode() == 200)
208             {
209                mState = AcceptingReInvite;
210                send(ackConnection());
211             }
212             else
213             {
214                ErrLog ( << "Spurious message sent to UAS " << msg );            
215                return;            
216             }
217             break;
218          case Accepting:
219             if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
220             {
221                mState = Connected;
222                mDum.mInviteSessionHandler->onConnected(getSessionHandle(), msg);
223                if (offans.first != None)
224                {
225                   InviteSession::incomingSdp(msg, offans.second);
226                }
227             }
228             else
229             {
230                ErrLog ( << "Spurious message sent to UAS " << msg );            
231                return;            
232             }
233             break;        
234          case AcceptingReInvite:
235             if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
236             {
237                mState = Connected;            
238                //this shouldn't happen, but it may be allowed(DUM API doesn't
239                //support this for re-invite)
240                if (offans.first != None)
241                {
242                   InviteSession::incomingSdp(msg, offans.second);
243                }
244             }
245             else
246             {
247                ErrLog ( << "Spurious message sent to UAS " << msg );            
248                return;            
249             }
250             break;        
251    
252                      
253          default:
254             DebugLog ( << "Throwing away strange message: " << msg );
255             //throw message away
256    //         assert(0);  //all other cases should be handled in base classes
257    
258       }
259    }
260    
261  SipMessage&  SipMessage&
262  InviteSession::end()  InviteSession::makeRefer(const NameAddr& referTo)
263  {  {
264     //assert(mState == Connected);     mDialog.makeRequest(mLastRequest, REFER);
265       mLastRequest.header(h_ReferTo) = referTo;
266       return mLastRequest;  
267    }
268    
269  #if 0  SipMessage&
270     // no way for the application to modify the BYE yet  InviteSession::end()
271     SipMessage bye;  {
272     mDialog.makeBye(bye);     InfoLog ( << "InviteSession::end, state: " << mState);  
273     copyAuthorizations(bye);     switch (mState)
274     //mDum.send(bye);     {
275  #endif        case Terminated:
276             throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
277             break;
278          case Connected:
279          case Accepting:
280             InfoLog ( << "InviteSession::end, connected or Accepting" );  
281             mDialog.makeRequest(mLastRequest, BYE);
282             //new transaction
283             assert(mLastRequest.header(h_Vias).size() == 1);
284    //         mLastRequest.header(h_Vias).front().param(p_branch).reset();
285             mState = Terminated;
286     return mLastRequest;     return mLastRequest;
287             break;
288          default:
289             assert(0); // out of states
290       }
291       throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy
292  }  }
293    
294  // If sdp==0, it means the last offer failed  // If sdp==0, it means the last offer failed
295    // !dcm! -- eventually handle confused UA's that send offers/answers at
296    // inappropriate times, probably with a different callback
297  void  void
298  InviteSession::incomingSdp(SdpContents* sdp)  InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp)
299  {  {
300     switch (mOfferState)     switch (mOfferState)
301     {     {
302        case None:        case Nothing:
303           assert(mCurrentLocalSdp == 0);           assert(mCurrentLocalSdp == 0);
304           assert(mCurrentRemoteSdp == 0);           assert(mCurrentRemoteSdp == 0);
305           mProposedRemoteSdp = sdp;           mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
306           mOfferState = Offerred;           mOfferState = Offerred;
307             mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
308           break;           break;
309                    
310        case Offerred:        case Offerred:
311           mCurrentLocalSdp = mProposedLocalSdp;           mCurrentLocalSdp = mProposedLocalSdp;
312           mCurrentRemoteSdp = sdp;           mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
313           mProposedLocalSdp = 0;           mProposedLocalSdp = 0;
314           mProposedRemoteSdp = 0;           mProposedRemoteSdp = 0;
315           mOfferState = Answered;           mOfferState = Answered;
316             mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
317           break;           break;
318    
319        case Answered:        case Answered:
320           assert(mProposedLocalSdp == 0);           assert(mProposedLocalSdp == 0);
321           assert(mProposedRemoteSdp == 0);           assert(mProposedRemoteSdp == 0);
322           mProposedRemoteSdp = sdp;           mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
323           mOfferState = CounterOfferred;           mOfferState = CounterOfferred;
324             mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
325           break;           break;
326                    
           
327        case CounterOfferred:        case CounterOfferred:
328           assert(mCurrentLocalSdp);           assert(mCurrentLocalSdp);
329           assert(mCurrentRemoteSdp);           assert(mCurrentRemoteSdp);
330           if (sdp)           mOfferState = Answered;
331             if (sdp)  // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
332           {           {
333                delete mCurrentLocalSdp;
334                delete mCurrentRemoteSdp;
335              mCurrentLocalSdp = mProposedLocalSdp;              mCurrentLocalSdp = mProposedLocalSdp;
336              mCurrentRemoteSdp = sdp;              mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
337                mProposedLocalSdp = 0;
338                mProposedRemoteSdp = 0;
339                mOfferState = Answered;
340                mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
341           }           }
342           else           else
343           {           {
344              mProposedLocalSdp = 0;              mProposedLocalSdp = 0;
345              mProposedRemoteSdp = 0;              mProposedRemoteSdp = 0;
346                // !jf! is this right?
347                mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
348           }           }
          mOfferState = Answered;  
349           break;           break;
350     }     }
351  }  }
352    
353  void  void
354    InviteSession::send(SipMessage& msg)
355    {
356       if (msg.isRequest())
357       {
358          //unless the message is an ACK(in which case it is mAck)
359          //strip out the SDP after sending
360          if (msg.header(h_RequestLine).getMethod() == ACK)
361          {
362             mDum.send(msg);
363          }
364          else
365          {
366             mDum.send(msg);
367             msg.releaseContents();
368          }
369       }
370       else
371       {
372          int code = msg.header(h_StatusLine).statusCode();
373          //!dcm! -- probably kill this object earlier, handle 200 to bye in
374          //DialogUsageManager...very soon
375          if (msg.header(h_CSeq).method() == BYE && code == 200) //!dcm! -- not 2xx?
376    
377          {
378             mState = Terminated;
379             mDum.send(msg);
380             delete this;
381          }
382          else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
383          {
384             assert(&msg == &mFinalResponse);
385             mCurrentRetransmit200 = T1;        
386             mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(),  0);
387             mDum.addTimerMs(DumTimeout::WaitForAck, TimerH, getBaseHandle(),  0);
388                
389             //!dcm! -- this should be mFinalResponse...maybe assign here in
390             //case the user wants to be very strange
391             if (mNextOfferOrAnswerSdp)
392             {
393                msg.setContents(static_cast<SdpContents*>(mNextOfferOrAnswerSdp->clone()));
394                sendSdp(mNextOfferOrAnswerSdp);
395                mNextOfferOrAnswerSdp = 0;            
396             }
397             mDum.send(msg);
398          }
399          else
400          {
401             mDum.send(msg);
402             msg.releaseContents();
403          }
404       }      
405    }
406    
407    void
408  InviteSession::sendSdp(SdpContents* sdp)  InviteSession::sendSdp(SdpContents* sdp)
409  {  {
410     switch (mOfferState)     switch (mOfferState)
411     {     {
412        case None:        case Nothing:
413           assert(mCurrentLocalSdp == 0);           assert(mCurrentLocalSdp == 0);
414           assert(mCurrentRemoteSdp == 0);           assert(mCurrentRemoteSdp == 0);
415           mProposedLocalSdp = sdp;           mProposedLocalSdp = sdp;
# Line 122  Line 431 
431           mOfferState = CounterOfferred;           mOfferState = CounterOfferred;
432           break;           break;
433                    
           
434        case CounterOfferred:        case CounterOfferred:
435           assert(mCurrentLocalSdp);           assert(mCurrentLocalSdp);
436           assert(mCurrentRemoteSdp);           assert(mCurrentRemoteSdp);
437           if (sdp)           if (sdp)  // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
438           {           {
439              mCurrentLocalSdp = sdp;              delete mCurrentLocalSdp;
440                delete mCurrentRemoteSdp;
441                mCurrentLocalSdp = static_cast<SdpContents*>(sdp->clone());
442              mCurrentRemoteSdp = mProposedRemoteSdp;              mCurrentRemoteSdp = mProposedRemoteSdp;
443           }           }
          else  
          {  
444              mProposedLocalSdp = 0;              mProposedLocalSdp = 0;
445              mProposedRemoteSdp = 0;              mProposedRemoteSdp = 0;
          }  
446           mOfferState = Answered;           mOfferState = Answered;
447           break;           break;
448     }     }
449  }  }
450    
451    std::pair<InviteSession::OfferAnswerType, const SdpContents*>
452    InviteSession::getOfferOrAnswer(const SipMessage& msg) const
453    {
454       std::pair<InviteSession::OfferAnswerType, const SdpContents*> ret;
455       ret.first = None;
456      
457       const SdpContents* contents = dynamic_cast<const SdpContents*>(msg.getContents());
458       if (contents)
459       {
460          static Token c100rel(Symbols::C100rel);
461          if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 ||
462              msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(c100rel))
463          {
464             switch (mOfferState)
465             {
466                case None:
467                   ret.first = Offer;
468                   ret.second = contents;
469                   break;
470                  
471                case Offerred:
472                   ret.first = Answer;
473                   ret.second = contents;
474                   break;
475    
476                case Answered:
477                   ret.first = Offer;
478                   ret.second = contents;
479                   break;
480                  
481                case CounterOfferred:
482                   ret.first = Answer;
483                   ret.second = contents;
484                   break;
485             }
486          }
487       }
488       return ret;
489    }
490    
491  void  void
492  InviteSession::copyAuthorizations(SipMessage& request)  InviteSession::copyAuthorizations(SipMessage& request)
493  {  {
# Line 158  Line 505 
505  #endif  #endif
506  }  }
507    
508  InviteSession::Handle::Handle(DialogUsageManager& dum)  SipMessage&
509     : BaseUsage::Handle(dum)  InviteSession::rejectOffer(int statusCode)
510  {}  {
511       //sdp state change here--go to initial state?
512       mDialog.makeResponse(mLastResponse, mLastRequest, statusCode);
513       return mLastResponse;
514    }
515    
516  InviteSession*  SipMessage&
517  InviteSession::Handle::operator->()  InviteSession::targetRefresh(const NameAddr& localUri)
518  {  {
519     return static_cast<InviteSession*>(get());     assert(0);
520       return mLastRequest;
521    }
522    
523    SipMessage&
524    InviteSession::ackConnection()
525    {
526       //if not a reinvite, and a pending offer exists, throw
527       makeAck();
528       //new transaction
529       assert(mAck.header(h_Vias).size() == 1);
530    //   mAck.header(h_Vias).front().param(p_branch).reset();
531       return mAck;
532    }
533    
534    void
535    InviteSession::makeAck()
536    {
537       mAck = mLastRequest;
538    
539       InfoLog ( << "InviteSession::makeAck:before: " << mAck );  
540    
541       mDialog.makeRequest(mAck, ACK);
542       if (mNextOfferOrAnswerSdp)
543       {
544          mAck.setContents(static_cast<SdpContents*>(mNextOfferOrAnswerSdp->clone()));
545          sendSdp(mNextOfferOrAnswerSdp);
546          mNextOfferOrAnswerSdp = 0;
547       }
548    
549       InfoLog ( << "InviteSession::makeAck:after: " << mAck );  
550  }  }
551    
552  /* ====================================================================  /* ====================================================================

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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27