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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27