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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27