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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27