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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3308 - (show annotations) (download)
Fri Sep 10 17:07:28 2004 UTC (15 years, 3 months ago) by derek
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 28206 byte(s)
added setOverrideHostAndPort for NAT traversal
if there is no to tag in a response, tid is used to dispatch to the correct dialog if one exists
temproary fix on onIllegalNegotiation; re-invite state machine needs tweaking

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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27