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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3289 - (show 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 #include "resiprocate/SdpContents.hxx"
2 #include "resiprocate/SipMessage.hxx"
3 #include "resiprocate/dum/Dialog.hxx"
4 #include "resiprocate/dum/DialogUsageManager.hxx"
5 #include "resiprocate/dum/InviteSession.hxx"
6 #include "resiprocate/dum/InviteSessionHandler.hxx"
7 #include "resiprocate/dum/Profile.hxx"
8 #include "resiprocate/dum/UsageUseException.hxx"
9 #include "resiprocate/os/Logger.hxx"
10 #include "resiprocate/os/Timer.hxx"
11
12 #if defined(WIN32) && defined(_DEBUG) &&defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio
13 #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
19
20 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
21
22 using namespace resip;
23 using namespace std;
24
25 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState)
26 : DialogUsage(dum, dialog),
27 mState(initialState),
28 mNitState(NitComplete),
29 mOfferState(Nothing),
30 mCurrentLocalSdp(0),
31 mCurrentRemoteSdp(0),
32 mProposedLocalSdp(0),
33 mProposedRemoteSdp(0),
34 mNextOfferOrAnswerSdp(0),
35 mUserConnected(false),
36 mQueuedBye(0),
37 mDestroyer(this),
38 mCurrentRetransmit200(Timer::T1)
39 {
40 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
41 assert(mDum.mInviteSessionHandler);
42 }
43
44 InviteSession::~InviteSession()
45 {
46 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
47 delete mCurrentLocalSdp;
48 delete mCurrentRemoteSdp;
49 delete mProposedLocalSdp;
50 delete mProposedRemoteSdp;
51 delete mNextOfferOrAnswerSdp;
52 delete mQueuedBye;
53 mDialog.mInviteSession = 0;
54 }
55
56 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 SipMessage&
70 InviteSession::makeFinalResponse(int code)
71 {
72 int cseq = mLastIncomingRequest.header(h_CSeq).sequence();
73 SipMessage& finalResponse = mFinalResponseMap[cseq];
74 mDialog.makeResponse(finalResponse, mLastIncomingRequest, 200);
75 return finalResponse;
76 }
77
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 mState = Connected;
87 return makeFinalResponse(statusCode);
88 }
89
90 void
91 InviteSession::setOffer(const SdpContents* sdp)
92 {
93 if (mProposedRemoteSdp)
94 {
95 throw UsageUseException("Cannot set an offer with an oustanding remote offer", __FILE__, __LINE__);
96 }
97 assert(mNextOfferOrAnswerSdp == 0);
98 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
99 }
100
101 void
102 InviteSession::setAnswer(const SdpContents* sdp)
103 {
104 if (mProposedLocalSdp )
105 {
106 throw UsageUseException("Cannot set an answer with an oustanding offer", __FILE__, __LINE__);
107 }
108 assert(mNextOfferOrAnswerSdp == 0);
109 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
110 }
111
112 const SdpContents*
113 InviteSession::getLocalSdp()
114 {
115 return mCurrentLocalSdp;
116 }
117
118 const SdpContents*
119 InviteSession::getRemoteSdp()
120 {
121 return mCurrentRemoteSdp;
122 }
123
124 InviteSessionHandle
125 InviteSession::getSessionHandle()
126 {
127 return InviteSessionHandle(mDum, getBaseHandle().getId());
128 }
129
130 void
131 InviteSession::dispatch(const DumTimeout& timeout)
132 {
133 Destroyer::Guard guard(mDestroyer);
134 if (timeout.type() == DumTimeout::Retransmit200)
135 {
136 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 }
144 else if (timeout.type() == DumTimeout::WaitForAck)
145 {
146 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 }
153 else if (timeout.type() == DumTimeout::CanDiscardAck)
154 {
155 assert(mAckMap.find(timeout.seq()) != mFinalResponseMap.end());
156 mAckMap.erase(timeout.seq());
157 }
158 }
159
160 void
161 InviteSession::dispatch(const SipMessage& msg)
162 {
163 Destroyer::Guard guard(mDestroyer);
164 std::pair<OfferAnswerType, const SdpContents*> offans;
165 offans = InviteSession::getOfferOrAnswer(msg);
166
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 SipMessage response;
177 mDialog.makeResponse(response, msg, 200);
178 send(response);
179 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
205 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 switch(mState)
236 {
237 case Terminated:
238 //!dcm! -- 481 behaviour here, should pretty much die on anything
239 //eventually 200 to BYE could be handled further out
240 if (msg.isResponse())
241 {
242 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 guard.destroy();
247 return;
248 }
249 }
250 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 break;
259 case Connected:
260 if (msg.isRequest())
261 {
262 switch(msg.header(h_RequestLine).method())
263 {
264 // reINVITE
265 case INVITE:
266 {
267 if (mOfferState == Answered)
268 {
269 mState = ReInviting;
270 mDialog.update(msg);
271 mLastIncomingRequest = msg;
272 mDum.mInviteSessionHandler->onDialogModified(getSessionHandle(), msg);
273 if (offans.first != None)
274 {
275 incomingSdp(msg, offans.second);
276 }
277 }
278 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 case BYE:
289 mState = Terminated;
290 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
291 mDialog.makeResponse(mLastResponse, msg, 200);
292 send(mLastResponse);
293 break;
294
295 case UPDATE:
296 assert(0);
297 break;
298
299 case INFO:
300 mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
301 break;
302 case REFER:
303 //handled in Dialog
304 assert(0);
305 break;
306
307 default:
308 InfoLog (<< "Ignoring request in an INVITE dialog: " << msg.brief());
309 break;
310 }
311 }
312 else
313 {
314 if ( msg.header(h_StatusLine).statusCode() == 200 && msg.header(h_CSeq).method() == INVITE)
315 {
316 CSeqToMessageMap::iterator it = mAckMap.find(msg.header(h_CSeq).sequence());
317 if (it != mAckMap.end())
318 {
319 mDum.send(it->second);
320 }
321 }
322 }
323 break;
324 case ReInviting:
325 if (msg.header(h_CSeq).method() == INVITE)
326 {
327 if (msg.isResponse())
328 {
329 int code = msg.header(h_StatusLine).statusCode();
330 if (code < 200)
331 {
332 return;
333 }
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 //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 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 mDum.send(it->second);
370 }
371 }
372 }
373 else
374 {
375 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 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
387 }
388 }
389 else
390 {
391 SipMessage failure;
392 mDialog.makeResponse(failure, msg, 491);
393 InfoLog (<< "Sending 491 - overlapping Invite transactions");
394 mDum.sendResponse(failure);
395 return;
396 }
397 }
398 else
399 {
400 ErrLog ( << "Spurious message sent to UAS " << msg );
401 return;
402 }
403 break;
404 default:
405 DebugLog ( << "Throwing away strange message: " << msg );
406 //throw message away
407 // assert(0); //all other cases should be handled in base classes
408
409 }
410 }
411
412 SipMessage&
413 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 mLastNit.setContents(contents);
423 return mLastNit;
424 }
425
426 SipMessage&
427 InviteSession::makeRefer(const NameAddr& referTo)
428 {
429 mDialog.makeRequest(mLastRequest, REFER);
430 mLastRequest.header(h_ReferTo) = referTo;
431 // mLastRequest.header(h_ReferTo).param(p_method) = getMethodName(INVITE);
432 return mLastRequest;
433 }
434
435 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 SipMessage&
456 InviteSession::end()
457 {
458 InfoLog ( << "InviteSession::end, state: " << mState);
459 switch (mState)
460 {
461 case Terminated:
462 throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
463 break;
464 case Connected:
465 InfoLog ( << "InviteSession::end, Connected" );
466 mDialog.makeRequest(mLastRequest, BYE);
467 //new transaction
468 assert(mLastRequest.header(h_Vias).size() == 1);
469 // mLastRequest.header(h_Vias).front().param(p_branch).reset();
470 mState = Terminated;
471 return mLastRequest;
472 break;
473 case ReInviting:
474 mQueuedBye = new SipMessage(mLastRequest);
475 mDialog.makeRequest(*mQueuedBye, BYE);
476 return *mQueuedBye;
477 break;
478 default:
479 assert(0); // out of states
480 }
481 throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy
482 }
483
484 // If sdp==0, it means the last offer failed
485 // !dcm! -- eventually handle confused UA's that send offers/answers at
486 // inappropriate times, probably with a different callback
487 void
488 InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp)
489 {
490 switch (mOfferState)
491 {
492 case Nothing:
493 assert(mCurrentLocalSdp == 0);
494 assert(mCurrentRemoteSdp == 0);
495 assert(mProposedLocalSdp == 0);
496 assert(mProposedRemoteSdp == 0);
497 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
498 mOfferState = Offerred;
499 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
500 break;
501
502 case Offerred:
503 assert(mCurrentLocalSdp == 0);
504 assert(mCurrentRemoteSdp == 0);
505 mCurrentLocalSdp = mProposedLocalSdp;
506 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
507 delete mProposedRemoteSdp;
508 mProposedLocalSdp = 0;
509 mProposedRemoteSdp = 0;
510 mOfferState = Answered;
511 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
512 break;
513
514 case Answered:
515 assert(mProposedLocalSdp == 0);
516 assert(mProposedRemoteSdp == 0);
517 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
518 mOfferState = CounterOfferred;
519 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
520 break;
521
522 case CounterOfferred:
523 assert(mCurrentLocalSdp);
524 assert(mCurrentRemoteSdp);
525 mOfferState = Answered;
526 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
527 {
528 delete mCurrentLocalSdp;
529 delete mCurrentRemoteSdp;
530 mCurrentLocalSdp = mProposedLocalSdp;
531 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
532 delete mProposedRemoteSdp;
533 mProposedLocalSdp = 0;
534 mProposedRemoteSdp = 0;
535 mOfferState = Answered;
536 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
537 }
538 else
539 {
540 delete mProposedLocalSdp;
541 delete mProposedRemoteSdp;
542 mProposedLocalSdp = 0;
543 mProposedRemoteSdp = 0;
544 // !jf! is this right?
545 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
546 }
547 break;
548 }
549 }
550
551 void
552 InviteSession::send(SipMessage& msg)
553 {
554 Destroyer::Guard guard(mDestroyer);
555 msg.releaseContents();
556 if (mQueuedBye && (mQueuedBye == &msg))
557 {
558 //queued
559 return;
560 }
561
562 if (msg.isRequest())
563 {
564 switch(msg.header(h_RequestLine).getMethod())
565 {
566 case INVITE:
567 case UPDATE:
568 if (mNextOfferOrAnswerSdp)
569 {
570 msg.setContents(mNextOfferOrAnswerSdp);
571 sendSdp(mNextOfferOrAnswerSdp);
572 mNextOfferOrAnswerSdp = 0;
573 }
574 break;
575 default:
576 break;
577 }
578 mDum.send(msg);
579 }
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 //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 guard.destroy();
592 }
593 else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
594 {
595 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
600 //!dcm! -- this should be mFinalResponse...maybe assign here in
601 //case the user wants to be very strange
602 if (mNextOfferOrAnswerSdp)
603 {
604 msg.setContents(mNextOfferOrAnswerSdp);
605 sendSdp(mNextOfferOrAnswerSdp);
606 mNextOfferOrAnswerSdp = 0;
607 }
608 mDum.send(msg);
609 }
610 else
611 {
612 mDum.send(msg);
613 }
614 }
615 }
616
617 void
618 InviteSession::sendSdp(SdpContents* sdp)
619 {
620 switch (mOfferState)
621 {
622 case Nothing:
623 assert(mCurrentLocalSdp == 0);
624 assert(mCurrentRemoteSdp == 0);
625 mProposedLocalSdp = sdp;
626 mOfferState = Offerred;
627 break;
628
629 case Offerred:
630 assert(mCurrentLocalSdp == 0);
631 assert(mCurrentRemoteSdp == 0);
632 mCurrentLocalSdp = sdp;
633 mCurrentRemoteSdp = mProposedRemoteSdp;
634 delete mProposedLocalSdp;
635 mProposedLocalSdp = 0;
636 mProposedRemoteSdp = 0;
637 mOfferState = Answered;
638 break;
639
640 case Answered:
641 assert(mProposedLocalSdp == 0);
642 assert(mProposedRemoteSdp == 0);
643 mProposedLocalSdp = sdp;
644 mOfferState = CounterOfferred;
645 break;
646
647 case CounterOfferred:
648 assert(mCurrentLocalSdp);
649 assert(mCurrentRemoteSdp);
650 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
651 {
652 delete mCurrentLocalSdp;
653 delete mCurrentRemoteSdp;
654 mCurrentLocalSdp = sdp;
655 mCurrentRemoteSdp = mProposedRemoteSdp;
656 delete mProposedLocalSdp;
657 mProposedLocalSdp = 0;
658 mProposedRemoteSdp = 0;
659 }
660 else
661 {
662 delete mProposedLocalSdp;
663 delete mProposedRemoteSdp;
664 mProposedLocalSdp = 0;
665 mProposedRemoteSdp = 0;
666 }
667 mOfferState = Answered;
668 break;
669 }
670 }
671
672 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 if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 ||
683 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 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 }
715 return ret;
716 }
717
718 SipMessage&
719 InviteSession::rejectOffer(int statusCode)
720 {
721 if (statusCode < 400)
722 {
723 throw new UsageUseException("Must reject with a 4xx", __FILE__, __LINE__);
724 }
725 //sdp state change here--go to initial state?
726 mDialog.makeResponse(mLastResponse, mLastIncomingRequest, statusCode);
727 return mLastResponse;
728 }
729
730 SipMessage&
731 InviteSession::targetRefresh(const NameAddr& localUri)
732 {
733 assert(0);
734 return mLastRequest;
735 }
736
737 void
738 InviteSession::send()
739 {
740 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 }
746
747 SipMessage&
748 InviteSession::makeAck()
749 {
750 InfoLog ( << "InviteSession::makeAck" );
751
752 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
759 assert(ack.header(h_Vias).size() == 1);
760
761 if (mNextOfferOrAnswerSdp)
762 {
763 ack.setContents(mNextOfferOrAnswerSdp);
764 sendSdp(mNextOfferOrAnswerSdp);
765 mNextOfferOrAnswerSdp = 0;
766 }
767 return ack;
768 }
769
770 /* ====================================================================
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