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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3289 - (hide annotations) (download)
Wed Aug 25 23:09:43 2004 UTC (15 years, 3 months ago) by derek
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 26669 byte(s)
added UserAgent to profile
Gracefully deal with illegal(no subscription state) NOTIFY messages with event package refer
mLastRequest in InivteSession is for outgoing only, mIncomingLastRequest has been added.
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 derek 3289 int cseq = mLastIncomingRequest.header(h_CSeq).sequence();
73 derek 3255 SipMessage& finalResponse = mFinalResponseMap[cseq];
74 derek 3289 mDialog.makeResponse(finalResponse, mLastIncomingRequest, 200);
75 derek 3255 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 derek 3289 mLastIncomingRequest = msg;
272 derek 3255 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 derek 3289 // mLastRequest.header(h_ReferTo).param(p_method) = getMethodName(INVITE);
432 derek 3058 return mLastRequest;
433 derek 2955 }
434 jason 2856
435 derek 3112 SipMessage&
436     InviteSession::makeRefer(const NameAddr& referTo, InviteSessionHandle sessionToReplace)
437     {
438     if (!sessionToReplace.isValid())
439     {
440     throw new UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
441     }
442    
443     mDialog.makeRequest(mLastRequest, REFER);
444     mLastRequest.header(h_ReferTo) = referTo;
445     CallId replaces;
446     DialogId id = sessionToReplace->mDialog.getId();
447     replaces.value() = id.getCallId();
448     replaces.param(p_toTag) = id.getRemoteTag();
449     replaces.param(p_fromTag) = id.getLocalTag();
450    
451     mLastRequest.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
452     return mLastRequest;
453     }
454    
455 jason 2809 SipMessage&
456 jason 2621 InviteSession::end()
457     {
458 derek 3006 InfoLog ( << "InviteSession::end, state: " << mState);
459 derek 2961 switch (mState)
460     {
461     case Terminated:
462 derek 2965 throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
463 derek 2961 break;
464     case Connected:
465 derek 3255 InfoLog ( << "InviteSession::end, Connected" );
466 derek 2961 mDialog.makeRequest(mLastRequest, BYE);
467 derek 2985 //new transaction
468     assert(mLastRequest.header(h_Vias).size() == 1);
469 derek 3079 // mLastRequest.header(h_Vias).front().param(p_branch).reset();
470 derek 2961 mState = Terminated;
471     return mLastRequest;
472     break;
473 derek 3276 case ReInviting:
474     mQueuedBye = new SipMessage(mLastRequest);
475     mDialog.makeRequest(*mQueuedBye, BYE);
476     return *mQueuedBye;
477     break;
478 derek 2961 default:
479     assert(0); // out of states
480     }
481 derek 2981 throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy
482 jason 2621 }
483    
484 jason 2809 // If sdp==0, it means the last offer failed
485 derek 2965 // !dcm! -- eventually handle confused UA's that send offers/answers at
486     // inappropriate times, probably with a different callback
487 jason 2846 void
488     InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp)
489 jason 2809 {
490     switch (mOfferState)
491     {
492 jason 2846 case Nothing:
493 jason 2809 assert(mCurrentLocalSdp == 0);
494     assert(mCurrentRemoteSdp == 0);
495 sgodin 3091 assert(mProposedLocalSdp == 0);
496     assert(mProposedRemoteSdp == 0);
497 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
498 jason 2809 mOfferState = Offerred;
499 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
500 jason 2809 break;
501    
502     case Offerred:
503 sgodin 3091 assert(mCurrentLocalSdp == 0);
504     assert(mCurrentRemoteSdp == 0);
505 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
506 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
507 sgodin 3091 delete mProposedRemoteSdp;
508 jason 2809 mProposedLocalSdp = 0;
509     mProposedRemoteSdp = 0;
510     mOfferState = Answered;
511 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
512 jason 2809 break;
513    
514     case Answered:
515     assert(mProposedLocalSdp == 0);
516     assert(mProposedRemoteSdp == 0);
517 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
518 jason 2809 mOfferState = CounterOfferred;
519 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
520 jason 2809 break;
521 derek 2965
522 jason 2809 case CounterOfferred:
523     assert(mCurrentLocalSdp);
524     assert(mCurrentRemoteSdp);
525 jason 2846 mOfferState = Answered;
526 sgodin 3071 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
527 jason 2809 {
528 derek 2965 delete mCurrentLocalSdp;
529     delete mCurrentRemoteSdp;
530 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
531 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
532 sgodin 3091 delete mProposedRemoteSdp;
533 derek 2965 mProposedLocalSdp = 0;
534     mProposedRemoteSdp = 0;
535     mOfferState = Answered;
536 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
537 jason 2809 }
538     else
539     {
540 sgodin 3091 delete mProposedLocalSdp;
541     delete mProposedRemoteSdp;
542 jason 2809 mProposedLocalSdp = 0;
543     mProposedRemoteSdp = 0;
544 jason 2846 // !jf! is this right?
545     mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
546 jason 2809 }
547     break;
548     }
549     }
550    
551 derek 2965 void
552     InviteSession::send(SipMessage& msg)
553     {
554 derek 3138 Destroyer::Guard guard(mDestroyer);
555 derek 3282 msg.releaseContents();
556 derek 3276 if (mQueuedBye && (mQueuedBye == &msg))
557     {
558     //queued
559     return;
560     }
561    
562 derek 2965 if (msg.isRequest())
563     {
564 derek 3089 switch(msg.header(h_RequestLine).getMethod())
565     {
566     case INVITE:
567     case UPDATE:
568     if (mNextOfferOrAnswerSdp)
569     {
570 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
571 derek 3089 sendSdp(mNextOfferOrAnswerSdp);
572     mNextOfferOrAnswerSdp = 0;
573     }
574     break;
575     default:
576     break;
577     }
578 derek 3282 mDum.send(msg);
579 derek 2965 }
580     else
581     {
582     int code = msg.header(h_StatusLine).statusCode();
583     //!dcm! -- probably kill this object earlier, handle 200 to bye in
584     //DialogUsageManager...very soon
585     if (msg.header(h_CSeq).method() == BYE && code == 200) //!dcm! -- not 2xx?
586    
587     {
588     mState = Terminated;
589     mDum.send(msg);
590 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
591 derek 3138 guard.destroy();
592 derek 2965 }
593 derek 2978 else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
594 derek 2965 {
595 derek 3255 int seq = msg.header(h_CSeq).sequence();
596     mCurrentRetransmit200 = Timer::T1;
597     mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
598     mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
599 derek 2990
600     //!dcm! -- this should be mFinalResponse...maybe assign here in
601 derek 2965 //case the user wants to be very strange
602     if (mNextOfferOrAnswerSdp)
603     {
604 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
605 derek 2965 sendSdp(mNextOfferOrAnswerSdp);
606 derek 2997 mNextOfferOrAnswerSdp = 0;
607 derek 2978 }
608     mDum.send(msg);
609     }
610     else
611     {
612     mDum.send(msg);
613     }
614 derek 2965 }
615     }
616    
617 jason 2621 void
618 derek 2965 InviteSession::sendSdp(SdpContents* sdp)
619 jason 2809 {
620     switch (mOfferState)
621     {
622 jason 2846 case Nothing:
623 jason 2809 assert(mCurrentLocalSdp == 0);
624     assert(mCurrentRemoteSdp == 0);
625 derek 2965 mProposedLocalSdp = sdp;
626 jason 2809 mOfferState = Offerred;
627     break;
628    
629     case Offerred:
630 sgodin 3091 assert(mCurrentLocalSdp == 0);
631     assert(mCurrentRemoteSdp == 0);
632 derek 2965 mCurrentLocalSdp = sdp;
633 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
634 sgodin 3091 delete mProposedLocalSdp;
635 jason 2809 mProposedLocalSdp = 0;
636     mProposedRemoteSdp = 0;
637     mOfferState = Answered;
638     break;
639    
640     case Answered:
641     assert(mProposedLocalSdp == 0);
642     assert(mProposedRemoteSdp == 0);
643 derek 2965 mProposedLocalSdp = sdp;
644 jason 2809 mOfferState = CounterOfferred;
645     break;
646    
647     case CounterOfferred:
648     assert(mCurrentLocalSdp);
649     assert(mCurrentRemoteSdp);
650 sgodin 3071 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
651 jason 2809 {
652 derek 3064 delete mCurrentLocalSdp;
653     delete mCurrentRemoteSdp;
654 sgodin 3091 mCurrentLocalSdp = sdp;
655 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
656 sgodin 3091 delete mProposedLocalSdp;
657     mProposedLocalSdp = 0;
658     mProposedRemoteSdp = 0;
659 jason 2809 }
660 sgodin 3091 else
661     {
662     delete mProposedLocalSdp;
663     delete mProposedRemoteSdp;
664     mProposedLocalSdp = 0;
665     mProposedRemoteSdp = 0;
666     }
667 jason 2809 mOfferState = Answered;
668     break;
669     }
670     }
671    
672 jason 2846 std::pair<InviteSession::OfferAnswerType, const SdpContents*>
673     InviteSession::getOfferOrAnswer(const SipMessage& msg) const
674     {
675     std::pair<InviteSession::OfferAnswerType, const SdpContents*> ret;
676     ret.first = None;
677    
678     const SdpContents* contents = dynamic_cast<const SdpContents*>(msg.getContents());
679     if (contents)
680     {
681     static Token c100rel(Symbols::C100rel);
682 derek 2976 if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 ||
683 jason 2846 msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(c100rel))
684     {
685     switch (mOfferState)
686     {
687     case None:
688     ret.first = Offer;
689     ret.second = contents;
690     break;
691    
692     case Offerred:
693     ret.first = Answer;
694     ret.second = contents;
695     break;
696    
697     case Answered:
698     ret.first = Offer;
699     ret.second = contents;
700     break;
701    
702     case CounterOfferred:
703     ret.first = Answer;
704     ret.second = contents;
705     break;
706     }
707     }
708 derek 3255 else if (msg.isResponse() &&
709     msg.header(h_StatusLine).responseCode() < 200 &&
710     msg.header(h_StatusLine).responseCode() >= 180)
711     {
712     ret.second = contents;
713     }
714 jason 2846 }
715     return ret;
716     }
717    
718 derek 2955 SipMessage&
719 derek 2965 InviteSession::rejectOffer(int statusCode)
720     {
721 derek 3101 if (statusCode < 400)
722     {
723     throw new UsageUseException("Must reject with a 4xx", __FILE__, __LINE__);
724     }
725 derek 3069 //sdp state change here--go to initial state?
726 derek 3289 mDialog.makeResponse(mLastResponse, mLastIncomingRequest, statusCode);
727 derek 2976 return mLastResponse;
728 derek 2965 }
729    
730     SipMessage&
731 derek 2955 InviteSession::targetRefresh(const NameAddr& localUri)
732     {
733     assert(0);
734 derek 2981 return mLastRequest;
735 derek 2955 }
736 davidb 2576
737 derek 3255 void
738     InviteSession::send()
739 derek 2981 {
740 derek 3255 if (mOfferState == Answered)
741     {
742     throw new UsageUseException("Cannot call send when there it no Offer/Answer negotiation to do", __FILE__, __LINE__);
743     }
744     send(makeAck());
745 derek 2981 }
746    
747 derek 3255 SipMessage&
748 derek 2965 InviteSession::makeAck()
749 derek 2849 {
750 derek 3255 InfoLog ( << "InviteSession::makeAck" );
751 derek 2992
752 derek 3255 int cseq = mLastRequest.header(h_CSeq).sequence();
753     assert(mAckMap.find(cseq) == mAckMap.end());
754     SipMessage& ack = mAckMap[cseq];
755     ack = mLastRequest;
756     mDialog.makeRequest(ack, ACK);
757     mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), cseq);
758 derek 2992
759 derek 3255 assert(ack.header(h_Vias).size() == 1);
760    
761 derek 2965 if (mNextOfferOrAnswerSdp)
762     {
763 derek 3255 ack.setContents(mNextOfferOrAnswerSdp);
764 derek 2965 sendSdp(mNextOfferOrAnswerSdp);
765 derek 2997 mNextOfferOrAnswerSdp = 0;
766 derek 2992 }
767 derek 3255 return ack;
768 derek 2849 }
769    
770 davidb 2575 /* ====================================================================
771     * The Vovida Software License, Version 1.0
772     *
773     * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
774     *
775     * Redistribution and use in source and binary forms, with or without
776     * modification, are permitted provided that the following conditions
777     * are met:
778     *
779     * 1. Redistributions of source code must retain the above copyright
780     * notice, this list of conditions and the following disclaimer.
781     *
782     * 2. Redistributions in binary form must reproduce the above copyright
783     * notice, this list of conditions and the following disclaimer in
784     * the documentation and/or other materials provided with the
785    
786     * distribution.
787     *
788     * 3. The names "VOCAL", "Vovida Open Communication Application Library",
789     * and "Vovida Open Communication Application Library (VOCAL)" must
790     * not be used to endorse or promote products derived from this
791     * software without prior written permission. For written
792     * permission, please contact vocal@vovida.org.
793     *
794     * 4. Products derived from this software may not be called "VOCAL", nor
795     * may "VOCAL" appear in their name, without prior written
796     * permission of Vovida Networks, Inc.
797     *
798     * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
799     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
800     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
801     * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
802     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
803     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
804     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
805     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
806     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
807     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
808     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
809     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
810     * DAMAGE.
811     *
812     * ====================================================================
813     *
814     * This software consists of voluntary contributions made by Vovida
815     * Networks, Inc. and many individuals on behalf of Vovida Networks,
816     * Inc. For more information on Vovida Networks, Inc., please see
817     * <http://www.vovida.org/>.
818     *
819     */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27