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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27