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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3298 - (hide annotations) (download)
Thu Sep 2 00:54:04 2004 UTC (15 years, 3 months ago) by derek
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 27948 byte(s)
onDialogModified now resets Invite & Sdp state machines properly.
1 derek 3138 #include "resiprocate/SdpContents.hxx"
2 jason 2725 #include "resiprocate/SipMessage.hxx"
3     #include "resiprocate/dum/Dialog.hxx"
4     #include "resiprocate/dum/DialogUsageManager.hxx"
5     #include "resiprocate/dum/InviteSession.hxx"
6 jason 2846 #include "resiprocate/dum/InviteSessionHandler.hxx"
7 derek 3138 #include "resiprocate/dum/Profile.hxx"
8 derek 2961 #include "resiprocate/dum/UsageUseException.hxx"
9 jason 2856 #include "resiprocate/os/Logger.hxx"
10 derek 3255 #include "resiprocate/os/Timer.hxx"
11 derek 3295 #include "resiprocate/os/Inserter.hxx"
12 jason 2555
13 derek 3094 #if defined(WIN32) && defined(_DEBUG) &&defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio
14 derek 3092 #define _CRTDBG_MAP_ALLOC
15     #include <stdlib.h>
16     #include <crtdbg.h>
17     #define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
18     #endif // defined(WIN32) && defined(_DEBUG)
19 sgodin 3091
20 derek 3092
21 jason 2856 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
22 jason 2846
23 davidb 2603 using namespace resip;
24 derek 3255 using namespace std;
25 davidb 2603
26 derek 2976 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState)
27 derek 3089 : DialogUsage(dum, dialog),
28 derek 2976 mState(initialState),
29 derek 3255 mNitState(NitComplete),
30 jason 2846 mOfferState(Nothing),
31 jason 2725 mCurrentLocalSdp(0),
32     mCurrentRemoteSdp(0),
33     mProposedLocalSdp(0),
34 derek 2965 mProposedRemoteSdp(0),
35 derek 2990 mNextOfferOrAnswerSdp(0),
36 jason 3257 mUserConnected(false),
37 jason 3278 mQueuedBye(0),
38 jason 3147 mDestroyer(this),
39 jason 3278 mCurrentRetransmit200(Timer::T1)
40 jason 2555 {
41 jason 3156 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
42 jason 2846 assert(mDum.mInviteSessionHandler);
43 jason 2555 }
44    
45 derek 2858 InviteSession::~InviteSession()
46     {
47 jason 3156 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
48 derek 2965 delete mCurrentLocalSdp;
49     delete mCurrentRemoteSdp;
50     delete mProposedLocalSdp;
51     delete mProposedRemoteSdp;
52     delete mNextOfferOrAnswerSdp;
53 derek 3276 delete mQueuedBye;
54 derek 2858 mDialog.mInviteSession = 0;
55     }
56 jason 2846
57 derek 3064 SipMessage&
58     InviteSession::modifySession()
59     {
60 derek 3291 if (mNextOfferOrAnswerSdp == 0 || mState != Connected || mOfferState != Answered)
61 derek 3064 {
62     throw new UsageUseException("Must be in the connected state and have propsed an offer to call modifySession",
63     __FILE__, __LINE__);
64     }
65     mState = ReInviting;
66     mDialog.makeRequest(mLastRequest, INVITE);
67     return mLastRequest;
68     }
69    
70 derek 3255 SipMessage&
71     InviteSession::makeFinalResponse(int code)
72     {
73 derek 3289 int cseq = mLastIncomingRequest.header(h_CSeq).sequence();
74 derek 3255 SipMessage& finalResponse = mFinalResponseMap[cseq];
75 derek 3289 mDialog.makeResponse(finalResponse, mLastIncomingRequest, 200);
76 derek 3255 return finalResponse;
77     }
78 derek 3064
79     SipMessage&
80 derek 3291 InviteSession::acceptDialogModification(int statusCode)
81 derek 3064 {
82     if (mNextOfferOrAnswerSdp == 0 || mState != ReInviting)
83     {
84     throw new UsageUseException("Must be in the ReInviting state and have propsed an answer to call answerModifySession",
85     __FILE__, __LINE__);
86     }
87 derek 3255 mState = Connected;
88     return makeFinalResponse(statusCode);
89 derek 3064 }
90    
91 jason 2866 void
92     InviteSession::setOffer(const SdpContents* sdp)
93     {
94 derek 2965 if (mProposedRemoteSdp)
95     {
96     throw UsageUseException("Cannot set an offer with an oustanding remote offer", __FILE__, __LINE__);
97     }
98 sgodin 3091 assert(mNextOfferOrAnswerSdp == 0);
99 derek 2965 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
100 jason 2866 }
101    
102     void
103     InviteSession::setAnswer(const SdpContents* sdp)
104     {
105 derek 2965 if (mProposedLocalSdp )
106     {
107     throw UsageUseException("Cannot set an answer with an oustanding offer", __FILE__, __LINE__);
108     }
109 sgodin 3091 assert(mNextOfferOrAnswerSdp == 0);
110 derek 2965 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
111 jason 2866 }
112    
113 jason 2555 const SdpContents*
114     InviteSession::getLocalSdp()
115     {
116 jason 2725 return mCurrentLocalSdp;
117 jason 2555 }
118    
119     const SdpContents*
120     InviteSession::getRemoteSdp()
121     {
122 jason 2725 return mCurrentRemoteSdp;
123 jason 2555 }
124 davidb 2575
125 jason 2941 InviteSessionHandle
126     InviteSession::getSessionHandle()
127     {
128     return InviteSessionHandle(mDum, getBaseHandle().getId());
129     }
130    
131 jason 2856 void
132 derek 2990 InviteSession::dispatch(const DumTimeout& timeout)
133     {
134 derek 3138 Destroyer::Guard guard(mDestroyer);
135 derek 3255 if (timeout.type() == DumTimeout::Retransmit200)
136 derek 2990 {
137 derek 3255 CSeqToMessageMap::iterator it = mFinalResponseMap.find(timeout.seq());
138     if (it != mFinalResponseMap.end())
139     {
140     mDum.send(it->second);
141     mCurrentRetransmit200 *= 2;
142     mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
143     }
144 derek 2990 }
145 derek 3255 else if (timeout.type() == DumTimeout::WaitForAck)
146 derek 2990 {
147 derek 3255 CSeqToMessageMap::iterator it = mFinalResponseMap.find(timeout.seq());
148     if (it != mFinalResponseMap.end())
149     {
150     mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle(), it->second);
151     mFinalResponseMap.erase(it);
152     }
153 derek 2990 }
154 derek 3255 else if (timeout.type() == DumTimeout::CanDiscardAck)
155     {
156     assert(mAckMap.find(timeout.seq()) != mFinalResponseMap.end());
157     mAckMap.erase(timeout.seq());
158     }
159 derek 2990 }
160    
161     void
162 jason 2856 InviteSession::dispatch(const SipMessage& msg)
163     {
164 derek 3138 Destroyer::Guard guard(mDestroyer);
165 jason 2856 std::pair<OfferAnswerType, const SdpContents*> offans;
166     offans = InviteSession::getOfferOrAnswer(msg);
167 derek 3255
168     //ugly. non-invite-transactions(nit) don't interact with the invite
169     //transaction state machine(for now we have a separate INFO state machine)
170     //it's written as a gerneric NIT satet machine, but method isn't checked, and
171     //info is the only NIT so far. This should eventually live in Dialog, with a
172     //current method to determine valid responses.
173     if (msg.header(h_CSeq).method() == INFO)
174     {
175     if (msg.isRequest())
176     {
177 derek 3261 SipMessage response;
178     mDialog.makeResponse(response, msg, 200);
179     send(response);
180 derek 3255 mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
181     }
182     else
183     {
184     if (mNitState == NitProceeding)
185     {
186     int code = msg.header(h_StatusLine).statusCode();
187     if (code < 200)
188     {
189     //ignore
190     }
191     else if (code < 300)
192     {
193     mNitState = NitComplete;
194     mDum.mInviteSessionHandler->onInfoSuccess(getSessionHandle(), msg);
195     }
196     else
197     {
198     mNitState = NitComplete;
199     mDum.mInviteSessionHandler->onInfoFailure(getSessionHandle(), msg);
200     }
201     }
202     }
203     return;
204     }
205 jason 2856
206 derek 3255 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK &&
207     (mState == Connected || mState == ReInviting))
208     {
209     //quench 200 retransmissions
210     mFinalResponseMap.erase(msg.header(h_CSeq).sequence());
211 derek 3291 if (msg.header(h_CSeq).sequence() == mLastIncomingRequest.header(h_CSeq).sequence())
212     {
213     if (offans.first != None)
214     {
215     if (mOfferState == Answered)
216     {
217     //SDP in invite and in ACK.
218     mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg);
219     }
220     else
221     {
222     //delaying onConnected until late SDP
223     InviteSession::incomingSdp(msg, offans.second);
224     if (!mUserConnected)
225     {
226     mUserConnected = true;
227     mDum.mInviteSessionHandler->onConnected(getSessionHandle(), msg);
228     }
229     }
230     }
231     else if (mOfferState != Answered)
232 derek 3255 {
233 derek 3291 //no SDP in ACK when one is required
234 derek 3255 mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg);
235     }
236 derek 3291 }
237 derek 3255 }
238    
239 derek 2961 switch(mState)
240 jason 2856 {
241 derek 2961 case Terminated:
242 derek 2978 //!dcm! -- 481 behaviour here, should pretty much die on anything
243 derek 2997 //eventually 200 to BYE could be handled further out
244     if (msg.isResponse())
245 derek 2961 {
246 derek 2997 int code = msg.header(h_StatusLine).statusCode();
247     if ((code == 200 && msg.header(h_CSeq).method() == BYE) || code > 399)
248     {
249     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
250 derek 3138 guard.destroy();
251 derek 3006 return;
252 derek 2997 }
253 derek 2961 }
254 derek 3138 else
255     {
256     //make a function to do this & the occurences of this in DialogUsageManager
257     SipMessage failure;
258     mDum.makeResponse(failure, msg, 481);
259     failure.header(h_AcceptLanguages) = mDum.mProfile->getSupportedLanguages();
260     mDum.sendResponse(failure);
261     }
262 derek 2961 break;
263     case Connected:
264     if (msg.isRequest())
265     {
266     switch(msg.header(h_RequestLine).method())
267     {
268 sgodin 3091 // reINVITE
269 derek 2961 case INVITE:
270 derek 3255 {
271     if (mOfferState == Answered)
272 derek 2961 {
273 derek 3255 mState = ReInviting;
274     mDialog.update(msg);
275 derek 3289 mLastIncomingRequest = msg;
276 derek 3291 mDum.mInviteSessionHandler->onDialogModified(getSessionHandle(), offans.first, msg);
277 derek 3255 if (offans.first != None)
278     {
279     incomingSdp(msg, offans.second);
280     }
281 derek 3291 else
282     {
283     mDum.mInviteSessionHandler->onOfferRequired(getSessionHandle(), msg);
284     }
285 derek 2961 }
286 derek 3255 else
287     {
288     //4??
289     SipMessage failure;
290     mDialog.makeResponse(failure, msg, 491);
291     InfoLog (<< "Sending 491 - overlapping Invite transactions");
292     mDum.sendResponse(failure);
293     }
294     }
295     break;
296 derek 2961 case BYE:
297 derek 2978 mState = Terminated;
298     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
299     mDialog.makeResponse(mLastResponse, msg, 200);
300     send(mLastResponse);
301 derek 2961 break;
302 jason 2856
303 derek 2961 case UPDATE:
304     assert(0);
305     break;
306 jason 2856
307 derek 2961 case INFO:
308     mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
309 derek 3255 break;
310 derek 2961 case REFER:
311 derek 3101 //handled in Dialog
312     assert(0);
313 derek 2961 break;
314 jason 2856
315 derek 2961 default:
316     InfoLog (<< "Ignoring request in an INVITE dialog: " << msg.brief());
317     break;
318     }
319 derek 3006 }
320     else
321     {
322 derek 3255 if ( msg.header(h_StatusLine).statusCode() == 200 && msg.header(h_CSeq).method() == INVITE)
323 derek 3006 {
324 derek 3255 CSeqToMessageMap::iterator it = mAckMap.find(msg.header(h_CSeq).sequence());
325     if (it != mAckMap.end())
326     {
327 derek 3282 mDum.send(it->second);
328 derek 3255 }
329 derek 3006 }
330     }
331 derek 3064 break;
332     case ReInviting:
333 derek 3255 if (msg.header(h_CSeq).method() == INVITE)
334 derek 3064 {
335 derek 3255 if (msg.isResponse())
336 derek 3089 {
337 derek 3255 int code = msg.header(h_StatusLine).statusCode();
338     if (code < 200)
339 derek 3167 {
340 derek 3276 return;
341 derek 3255 }
342     else if (code < 300)
343     {
344     if (msg.header(h_CSeq).sequence() == mLastRequest.header(h_CSeq).sequence())
345     {
346     mState = Connected;
347 derek 3276 //user has called end, so no more callbacks relating to
348     //this usage other than onTerminated
349     if (mQueuedBye)
350     {
351     mLastRequest = *mQueuedBye;
352     delete mQueuedBye;
353     mQueuedBye = 0;
354     send(mLastRequest);
355     return;
356     }
357 derek 3255 if (offans.first != None)
358     {
359 derek 3291 if (offans.first == Answer)
360     {
361     //no late media required, so just send the ACK
362     send(makeAck());
363     }
364 derek 3295 incomingSdp(msg, offans.second);
365 derek 3255 }
366     else
367     {
368 derek 3295 //no offer or answer in 200, this will eventually be
369     //legal with PRACK/UPDATE
370     send(makeAck());
371 derek 3255 if (mOfferState != Answered)
372     {
373     //reset the sdp state machine
374     incomingSdp(msg, 0);
375     mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg);
376     }
377     }
378     }
379     else //200 retransmission that overlaps with this Invite transaction
380     {
381     CSeqToMessageMap::iterator it = mAckMap.find(msg.header(h_CSeq).sequence());
382     if (it != mAckMap.end())
383     {
384 derek 3282 mDum.send(it->second);
385 derek 3255 }
386     }
387 derek 3167 }
388 derek 3241 else
389     {
390 derek 3276 mState = Connected;
391     //user has called end, so no more callbacks relating to
392     //this usage other than onTerminated
393     if (mQueuedBye)
394     {
395     mLastRequest = *mQueuedBye;
396     delete mQueuedBye;
397     mQueuedBye = 0;
398     send(mLastRequest);
399     return;
400     }
401 derek 3291 //reset the sdp state machine
402     incomingSdp(msg, 0);
403 derek 3255 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
404 derek 3241 }
405 derek 3089 }
406 derek 3167 else
407     {
408 derek 3255 SipMessage failure;
409     mDialog.makeResponse(failure, msg, 491);
410     InfoLog (<< "Sending 491 - overlapping Invite transactions");
411     mDum.sendResponse(failure);
412     return;
413 derek 3167 }
414 derek 3064 }
415     else
416     {
417     ErrLog ( << "Spurious message sent to UAS " << msg );
418     return;
419     }
420     break;
421 derek 2961 default:
422 derek 3024 DebugLog ( << "Throwing away strange message: " << msg );
423     //throw message away
424     // assert(0); //all other cases should be handled in base classes
425    
426 jason 2856 }
427     }
428    
429 derek 2955 SipMessage&
430 derek 3255 InviteSession::makeInfo(auto_ptr<Contents> contents)
431     {
432     if (mNitState == NitProceeding)
433     {
434     throw new UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
435     __FILE__, __LINE__);
436     }
437     mNitState = NitProceeding;
438     mDialog.makeRequest(mLastNit, INFO);
439 derek 3293 mLastNit.releaseContents();
440 derek 3261 mLastNit.setContents(contents);
441 derek 3255 return mLastNit;
442     }
443    
444     SipMessage&
445 derek 3039 InviteSession::makeRefer(const NameAddr& referTo)
446 derek 2955 {
447 derek 3058 mDialog.makeRequest(mLastRequest, REFER);
448     mLastRequest.header(h_ReferTo) = referTo;
449 derek 3289 // mLastRequest.header(h_ReferTo).param(p_method) = getMethodName(INVITE);
450 derek 3058 return mLastRequest;
451 derek 2955 }
452 jason 2856
453 derek 3112 SipMessage&
454     InviteSession::makeRefer(const NameAddr& referTo, InviteSessionHandle sessionToReplace)
455     {
456     if (!sessionToReplace.isValid())
457     {
458     throw new UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
459     }
460    
461     mDialog.makeRequest(mLastRequest, REFER);
462     mLastRequest.header(h_ReferTo) = referTo;
463     CallId replaces;
464     DialogId id = sessionToReplace->mDialog.getId();
465     replaces.value() = id.getCallId();
466     replaces.param(p_toTag) = id.getRemoteTag();
467     replaces.param(p_fromTag) = id.getLocalTag();
468    
469     mLastRequest.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
470     return mLastRequest;
471     }
472    
473 jason 2809 SipMessage&
474 jason 2621 InviteSession::end()
475     {
476 derek 3006 InfoLog ( << "InviteSession::end, state: " << mState);
477 derek 2961 switch (mState)
478     {
479     case Terminated:
480 derek 2965 throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
481 derek 2961 break;
482     case Connected:
483 derek 3255 InfoLog ( << "InviteSession::end, Connected" );
484 derek 2961 mDialog.makeRequest(mLastRequest, BYE);
485 derek 2985 //new transaction
486     assert(mLastRequest.header(h_Vias).size() == 1);
487 derek 3079 // mLastRequest.header(h_Vias).front().param(p_branch).reset();
488 derek 2961 mState = Terminated;
489     return mLastRequest;
490     break;
491 derek 3276 case ReInviting:
492     mQueuedBye = new SipMessage(mLastRequest);
493     mDialog.makeRequest(*mQueuedBye, BYE);
494     return *mQueuedBye;
495     break;
496 derek 2961 default:
497     assert(0); // out of states
498     }
499 derek 2981 throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy
500 jason 2621 }
501    
502 jason 2809 // If sdp==0, it means the last offer failed
503 derek 2965 // !dcm! -- eventually handle confused UA's that send offers/answers at
504     // inappropriate times, probably with a different callback
505 jason 2846 void
506     InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp)
507 jason 2809 {
508     switch (mOfferState)
509     {
510 jason 2846 case Nothing:
511 jason 2809 assert(mCurrentLocalSdp == 0);
512     assert(mCurrentRemoteSdp == 0);
513 sgodin 3091 assert(mProposedLocalSdp == 0);
514     assert(mProposedRemoteSdp == 0);
515 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
516 jason 2809 mOfferState = Offerred;
517 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
518 jason 2809 break;
519    
520     case Offerred:
521 sgodin 3091 assert(mCurrentLocalSdp == 0);
522     assert(mCurrentRemoteSdp == 0);
523 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
524 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
525 sgodin 3091 delete mProposedRemoteSdp;
526 jason 2809 mProposedLocalSdp = 0;
527     mProposedRemoteSdp = 0;
528     mOfferState = Answered;
529 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
530 jason 2809 break;
531    
532     case Answered:
533     assert(mProposedLocalSdp == 0);
534     assert(mProposedRemoteSdp == 0);
535 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
536 jason 2809 mOfferState = CounterOfferred;
537 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
538 jason 2809 break;
539 derek 2965
540 jason 2809 case CounterOfferred:
541     assert(mCurrentLocalSdp);
542     assert(mCurrentRemoteSdp);
543 jason 2846 mOfferState = Answered;
544 sgodin 3071 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
545 jason 2809 {
546 derek 2965 delete mCurrentLocalSdp;
547     delete mCurrentRemoteSdp;
548 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
549 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
550 sgodin 3091 delete mProposedRemoteSdp;
551 derek 2965 mProposedLocalSdp = 0;
552     mProposedRemoteSdp = 0;
553     mOfferState = Answered;
554 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
555 jason 2809 }
556     else
557     {
558 sgodin 3091 delete mProposedLocalSdp;
559     delete mProposedRemoteSdp;
560 jason 2809 mProposedLocalSdp = 0;
561     mProposedRemoteSdp = 0;
562 jason 2846 // !jf! is this right?
563 derek 3291 // mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
564 jason 2809 }
565     break;
566     }
567     }
568    
569 derek 2965 void
570     InviteSession::send(SipMessage& msg)
571     {
572 derek 3138 Destroyer::Guard guard(mDestroyer);
573 derek 3293 //handle NITs separately
574     if (msg.header(h_CSeq).method() == INFO)
575     {
576     mDum.send(msg);
577     return;
578     }
579    
580 derek 3282 msg.releaseContents();
581 derek 3276 if (mQueuedBye && (mQueuedBye == &msg))
582     {
583     //queued
584     return;
585     }
586    
587 derek 2965 if (msg.isRequest())
588     {
589 derek 3089 switch(msg.header(h_RequestLine).getMethod())
590     {
591     case INVITE:
592     case UPDATE:
593 derek 3291 case ACK:
594 derek 3089 if (mNextOfferOrAnswerSdp)
595     {
596 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
597 derek 3089 sendSdp(mNextOfferOrAnswerSdp);
598     mNextOfferOrAnswerSdp = 0;
599     }
600     break;
601     default:
602     break;
603     }
604 derek 3282 mDum.send(msg);
605 derek 2965 }
606     else
607     {
608     int code = msg.header(h_StatusLine).statusCode();
609     //!dcm! -- probably kill this object earlier, handle 200 to bye in
610     //DialogUsageManager...very soon
611     if (msg.header(h_CSeq).method() == BYE && code == 200) //!dcm! -- not 2xx?
612    
613     {
614     mState = Terminated;
615     mDum.send(msg);
616 sgodin 3140 //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg); // This is actually called when recieving the BYE message so that the BYE message can be passed to onTerminated
617 derek 3138 guard.destroy();
618 derek 2965 }
619 derek 2978 else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
620 derek 2965 {
621 derek 3255 int seq = msg.header(h_CSeq).sequence();
622     mCurrentRetransmit200 = Timer::T1;
623     mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
624     mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
625 derek 2990
626     //!dcm! -- this should be mFinalResponse...maybe assign here in
627 derek 2965 //case the user wants to be very strange
628     if (mNextOfferOrAnswerSdp)
629     {
630 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
631 derek 2965 sendSdp(mNextOfferOrAnswerSdp);
632 derek 2997 mNextOfferOrAnswerSdp = 0;
633 derek 2978 }
634     mDum.send(msg);
635     }
636     else
637     {
638     mDum.send(msg);
639     }
640 derek 2965 }
641     }
642    
643 jason 2621 void
644 derek 2965 InviteSession::sendSdp(SdpContents* sdp)
645 jason 2809 {
646     switch (mOfferState)
647     {
648 jason 2846 case Nothing:
649 jason 2809 assert(mCurrentLocalSdp == 0);
650     assert(mCurrentRemoteSdp == 0);
651 derek 2965 mProposedLocalSdp = sdp;
652 jason 2809 mOfferState = Offerred;
653     break;
654    
655     case Offerred:
656 sgodin 3091 assert(mCurrentLocalSdp == 0);
657     assert(mCurrentRemoteSdp == 0);
658 derek 2965 mCurrentLocalSdp = sdp;
659 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
660 sgodin 3091 delete mProposedLocalSdp;
661 jason 2809 mProposedLocalSdp = 0;
662     mProposedRemoteSdp = 0;
663     mOfferState = Answered;
664     break;
665    
666     case Answered:
667     assert(mProposedLocalSdp == 0);
668     assert(mProposedRemoteSdp == 0);
669 derek 2965 mProposedLocalSdp = sdp;
670 jason 2809 mOfferState = CounterOfferred;
671     break;
672    
673     case CounterOfferred:
674     assert(mCurrentLocalSdp);
675     assert(mCurrentRemoteSdp);
676 derek 3298 if (sdp)
677 jason 2809 {
678 derek 3064 delete mCurrentLocalSdp;
679     delete mCurrentRemoteSdp;
680 sgodin 3091 mCurrentLocalSdp = sdp;
681 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
682 sgodin 3091 delete mProposedLocalSdp;
683     mProposedLocalSdp = 0;
684     mProposedRemoteSdp = 0;
685 jason 2809 }
686 sgodin 3091 else
687     {
688     delete mProposedLocalSdp;
689     delete mProposedRemoteSdp;
690     mProposedLocalSdp = 0;
691     mProposedRemoteSdp = 0;
692     }
693 jason 2809 mOfferState = Answered;
694     break;
695     }
696     }
697    
698 jason 2846 std::pair<InviteSession::OfferAnswerType, const SdpContents*>
699     InviteSession::getOfferOrAnswer(const SipMessage& msg) const
700     {
701     std::pair<InviteSession::OfferAnswerType, const SdpContents*> ret;
702     ret.first = None;
703    
704     const SdpContents* contents = dynamic_cast<const SdpContents*>(msg.getContents());
705     if (contents)
706     {
707     static Token c100rel(Symbols::C100rel);
708 derek 2976 if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 ||
709 jason 2846 msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(c100rel))
710     {
711     switch (mOfferState)
712     {
713     case None:
714     ret.first = Offer;
715     ret.second = contents;
716     break;
717    
718     case Offerred:
719     ret.first = Answer;
720     ret.second = contents;
721     break;
722    
723     case Answered:
724     ret.first = Offer;
725     ret.second = contents;
726     break;
727    
728     case CounterOfferred:
729     ret.first = Answer;
730     ret.second = contents;
731     break;
732     }
733     }
734 derek 3255 else if (msg.isResponse() &&
735     msg.header(h_StatusLine).responseCode() < 200 &&
736     msg.header(h_StatusLine).responseCode() >= 180)
737     {
738     ret.second = contents;
739     }
740 jason 2846 }
741     return ret;
742     }
743    
744 derek 2955 SipMessage&
745 derek 3291 InviteSession::rejectDialogModification(int statusCode)
746 derek 2965 {
747 derek 3101 if (statusCode < 400)
748     {
749     throw new UsageUseException("Must reject with a 4xx", __FILE__, __LINE__);
750     }
751 derek 3289 mDialog.makeResponse(mLastResponse, mLastIncomingRequest, statusCode);
752 derek 3298 mState = Connected;
753     sendSdp(0);
754 derek 2976 return mLastResponse;
755 derek 2965 }
756    
757     SipMessage&
758 derek 2955 InviteSession::targetRefresh(const NameAddr& localUri)
759     {
760     assert(0);
761 derek 2981 return mLastRequest;
762 derek 2955 }
763 davidb 2576
764 derek 3255 void
765     InviteSession::send()
766 derek 2981 {
767 derek 3295 InfoLog ( << "InviteSession::send(void)");
768     if (mOfferState == Answered || mState != Connected)
769 derek 3255 {
770     throw new UsageUseException("Cannot call send when there it no Offer/Answer negotiation to do", __FILE__, __LINE__);
771     }
772     send(makeAck());
773 derek 2981 }
774    
775 derek 3255 SipMessage&
776 derek 2965 InviteSession::makeAck()
777 derek 2849 {
778 derek 3255 InfoLog ( << "InviteSession::makeAck" );
779 derek 2992
780 derek 3255 int cseq = mLastRequest.header(h_CSeq).sequence();
781 derek 3295 if (mAckMap.find(cseq) != mAckMap.end())
782     {
783     InfoLog ( << "CSeq collision in ack map: " << Inserter(mAckMap) );
784     }
785    
786 derek 3255 assert(mAckMap.find(cseq) == mAckMap.end());
787     SipMessage& ack = mAckMap[cseq];
788     ack = mLastRequest;
789     mDialog.makeRequest(ack, ACK);
790     mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), cseq);
791 derek 2992
792 derek 3255 assert(ack.header(h_Vias).size() == 1);
793    
794 derek 3291 // if (mNextOfferOrAnswerSdp)
795     // {
796     // ack.setContents(mNextOfferOrAnswerSdp);
797     // sendSdp(mNextOfferOrAnswerSdp);
798     // mNextOfferOrAnswerSdp = 0;
799     // }
800 derek 3255 return ack;
801 derek 2849 }
802    
803 davidb 2575 /* ====================================================================
804     * The Vovida Software License, Version 1.0
805     *
806     * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
807     *
808     * Redistribution and use in source and binary forms, with or without
809     * modification, are permitted provided that the following conditions
810     * are met:
811     *
812     * 1. Redistributions of source code must retain the above copyright
813     * notice, this list of conditions and the following disclaimer.
814     *
815     * 2. Redistributions in binary form must reproduce the above copyright
816     * notice, this list of conditions and the following disclaimer in
817     * the documentation and/or other materials provided with the
818    
819     * distribution.
820     *
821     * 3. The names "VOCAL", "Vovida Open Communication Application Library",
822     * and "Vovida Open Communication Application Library (VOCAL)" must
823     * not be used to endorse or promote products derived from this
824     * software without prior written permission. For written
825     * permission, please contact vocal@vovida.org.
826     *
827     * 4. Products derived from this software may not be called "VOCAL", nor
828     * may "VOCAL" appear in their name, without prior written
829     * permission of Vovida Networks, Inc.
830     *
831     * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
832     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
833     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
834     * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
835     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
836     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
837     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
838     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
839     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
840     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
841     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
842     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
843     * DAMAGE.
844     *
845     * ====================================================================
846     *
847     * This software consists of voluntary contributions made by Vovida
848     * Networks, Inc. and many individuals on behalf of Vovida Networks,
849     * Inc. For more information on Vovida Networks, Inc., please see
850     * <http://www.vovida.org/>.
851     *
852     */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27