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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5001 - (show annotations) (download)
Tue Jun 28 18:54:52 2005 UTC (14 years, 5 months ago) by sgodin
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 48882 byte(s)
- fixed inaccurate use of !slg! in comments
- removed UIntHash64 from project files
1 #include "resiprocate/MultipartMixedContents.hxx"
2 #include "resiprocate/SdpContents.hxx"
3 #include "resiprocate/SipMessage.hxx"
4 #include "resiprocate/Helper.hxx"
5 #include "resiprocate/dum/Dialog.hxx"
6 #include "resiprocate/dum/DialogUsageManager.hxx"
7 #include "resiprocate/dum/InviteSession.hxx"
8 #include "resiprocate/dum/ServerInviteSession.hxx"
9 #include "resiprocate/dum/ClientSubscription.hxx"
10 #include "resiprocate/dum/ServerSubscription.hxx"
11 #include "resiprocate/dum/ClientInviteSession.hxx"
12 #include "resiprocate/dum/InviteSessionHandler.hxx"
13 #include "resiprocate/dum/MasterProfile.hxx"
14 #include "resiprocate/dum/UsageUseException.hxx"
15 #include "resiprocate/os/Inserter.hxx"
16 #include "resiprocate/os/Logger.hxx"
17 #include "resiprocate/os/Timer.hxx"
18 #include "resiprocate/os/Random.hxx"
19 #include "resiprocate/os/compat.hxx"
20 #include "resiprocate/os/WinLeakCheck.hxx"
21
22 // Remove warning about 'this' use in initiator list - pointer is only stored
23 #if defined(WIN32)
24 #pragma warning( disable : 4355 ) // using this in base member initializer list
25 #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
26 #endif
27
28 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
29 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
30
31 using namespace resip;
32 using namespace std;
33
34 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
35 : DialogUsage(dum, dialog),
36 mState(Undefined),
37 mNitState(NitComplete),
38 mCurrentRetransmit200(0),
39 mSessionInterval(0),
40 mMinSE(90),
41 mSessionRefresher(false),
42 mSessionTimerSeq(0),
43 mSentRefer(false)
44 {
45 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
46 assert(mDum.mInviteSessionHandler);
47 }
48
49 InviteSession::~InviteSession()
50 {
51 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
52 mDialog.mInviteSession = 0;
53 }
54
55 void
56 InviteSession::dialogDestroyed(const SipMessage& msg)
57 {
58 assert(0);
59
60 // !jf! Is this correct? Merged from main...
61 // !jf! what reason - guessed for now?
62 //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);
63 //delete this;
64 }
65
66 const SdpContents&
67 InviteSession::getLocalSdp() const
68 {
69 return *mCurrentLocalSdp;
70 }
71
72 const SdpContents&
73 InviteSession::getRemoteSdp() const
74 {
75 return *mCurrentRemoteSdp;
76 }
77
78 const Data&
79 InviteSession::getDialogId() const
80 {
81 return mDialog.getId().getCallId();
82 }
83
84 InviteSessionHandle
85 InviteSession::getSessionHandle()
86 {
87 return InviteSessionHandle(mDum, getBaseHandle().getId());
88 }
89
90 void InviteSession::storePeerCapabilities(const SipMessage& msg)
91 {
92 // !slg! ToDo - add methods to get this data, App may be interested
93 if (msg.exists(h_Allows))
94 {
95 mPeerSupportedMethods = msg.header(h_Allows);
96 }
97 if (msg.exists(h_Supporteds))
98 {
99 mPeerSupportedOptionTags = msg.header(h_Supporteds);
100 }
101 if (msg.exists(h_AcceptEncodings))
102 {
103 mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
104 }
105 if (msg.exists(h_AcceptLanguages))
106 {
107 mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
108 }
109 if (msg.exists(h_Accepts))
110 {
111 mPeerSupportedMimeTypes = msg.header(h_Accepts);
112 }
113 }
114
115 bool
116 InviteSession::updateMethodSupported() const
117 {
118 // Check if Update is supported locally
119 if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
120 {
121 // Check if peer supports UPDATE
122 return mPeerSupportedMethods.find(Token("UPDATE"));
123 }
124 return false;
125 }
126
127 const NameAddr&
128 InviteSession::myAddr() const
129 {
130 return mDialog.mLocalNameAddr;
131 }
132
133 const NameAddr&
134 InviteSession::peerAddr() const
135 {
136 return mDialog.mRemoteNameAddr;
137 }
138
139 bool
140 InviteSession::isConnected() const
141 {
142 switch (mState)
143 {
144 case Connected:
145 case SentUpdate:
146 case SentUpdateGlare:
147 case SentReinvite:
148 case SentReinviteGlare:
149 case ReceivedUpdate:
150 case ReceivedReinvite:
151 case ReceivedReinviteNoOffer:
152 case Answered:
153 case WaitingToOffer:
154 return true;
155
156 default:
157 return false;
158 }
159 }
160
161 bool
162 InviteSession::isEarly() const
163 {
164 switch (mState)
165 {
166 case UAC_Start:
167 case UAC_Early:
168 case UAC_EarlyWithOffer:
169 case UAC_EarlyWithAnswer:
170 //case UAC_Answered:
171 //case UAC_Terminated:
172 case UAC_SentUpdateEarly:
173 case UAC_SentUpdateConnected:
174 case UAC_ReceivedUpdateEarly:
175 //case UAC_SentAnswer:
176 case UAC_QueuedUpdate:
177 return true;
178
179 default:
180 return false;
181 }
182 }
183
184
185 bool
186 InviteSession::isTerminated() const
187 {
188 switch (mState)
189 {
190 case Terminated:
191 case WaitingToTerminate:
192 case UAC_Cancelled:
193 case UAS_WaitingToTerminate:
194 case UAS_WaitingToHangup:
195 return true;
196 default:
197 return false;
198 }
199 }
200
201 std::ostream&
202 InviteSession::dump(std::ostream& strm) const
203 {
204 strm << "INVITE: " << mId
205 << " " << toData(mState)
206 << " ADDR=" << myAddr()
207 << " PEER=" << peerAddr();
208 return strm;
209 }
210
211 void
212 InviteSession::provideOffer(const SdpContents& offer)
213 {
214 switch (mState)
215 {
216 case Connected:
217 case WaitingToOffer:
218 case UAS_WaitingToOffer:
219 if (updateMethodSupported())
220 {
221 transition(SentUpdate);
222 mDialog.makeRequest(mLastSessionModification, UPDATE);
223 }
224 else
225 {
226 transition(SentReinvite);
227 mDialog.makeRequest(mLastSessionModification, INVITE);
228 }
229 setSessionTimerHeaders(mLastSessionModification);
230
231 InfoLog (<< "Sending " << mLastSessionModification.brief());
232 InviteSession::setSdp(mLastSessionModification, offer);
233 mProposedLocalSdp = InviteSession::makeSdp(offer);
234 mDialog.send(mLastSessionModification);
235 break;
236
237 case Answered:
238 // queue the offer to be sent after the ACK is received
239 transition(WaitingToOffer);
240 mProposedLocalSdp = InviteSession::makeSdp(offer);
241 break;
242
243 // ?slg? Can we handle all of the states listed in isConnected() ???
244 default:
245 WarningLog (<< "Can't provideOffer when not in Connected state");
246 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
247 }
248 }
249
250 void
251 InviteSession::provideAnswer(const SdpContents& answer)
252 {
253 switch (mState)
254 {
255 case ReceivedReinvite:
256 transition(Connected);
257 mDialog.makeResponse(mInvite200, mLastSessionModification, 200);
258 handleSessionTimerRequest(mInvite200, mLastSessionModification);
259 InviteSession::setSdp(mInvite200, answer);
260 mCurrentLocalSdp = InviteSession::makeSdp(answer);
261 mCurrentRemoteSdp = mProposedRemoteSdp;
262 InfoLog (<< "Sending " << mInvite200.brief());
263 mDialog.send(mInvite200);
264 startRetransmit200Timer();
265 break;
266
267 case ReceivedUpdate: // same as ReceivedReinvite case.
268 {
269 transition(Connected);
270
271 SipMessage response;
272 mDialog.makeResponse(response, mLastSessionModification, 200);
273 handleSessionTimerRequest(response, mLastSessionModification);
274 InviteSession::setSdp(response, answer);
275 mCurrentLocalSdp = InviteSession::makeSdp(answer);
276 mCurrentRemoteSdp = mProposedRemoteSdp;
277 InfoLog (<< "Sending " << response.brief());
278 mDialog.send(response);
279 break;
280 }
281
282 default:
283 WarningLog (<< "Can't provideAnswer when not in Connected state");
284 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
285 }
286 }
287
288 void
289 InviteSession::end()
290 {
291 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
292
293 switch (mState)
294 {
295 case Connected:
296 {
297 // !jf! do we need to store the BYE somewhere?
298 sendBye();
299 transition(Terminated);
300 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
301 break;
302 }
303
304 case SentUpdate:
305 sendBye();
306 transition(Terminated);
307 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
308 break;
309
310 case SentReinvite:
311 transition(WaitingToTerminate);
312 break;
313
314 case ReceivedUpdate:
315 case ReceivedReinvite:
316 case ReceivedReinviteNoOffer:
317 {
318 SipMessage response;
319 mDialog.makeResponse(response, mLastSessionModification, 488);
320 InfoLog (<< "Sending " << response.brief());
321 mDialog.send(response);
322
323 sendBye();
324 transition(Terminated);
325 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
326 break;
327 }
328
329 case WaitingToTerminate:
330 {
331 sendBye();
332 transition(Terminated);
333 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
334 break;
335 }
336
337 case Terminated:
338 // no-op.
339 break;
340
341 default:
342 assert(0);
343 break;
344 }
345 }
346
347 void
348 InviteSession::reject(int statusCode, WarningCategory *warning)
349 {
350 switch (mState)
351 {
352 case ReceivedUpdate:
353 case ReceivedReinvite:
354 case ReceivedReinviteNoOffer:
355 {
356 transition(Connected);
357
358 SipMessage response;
359 mDialog.makeResponse(response, mLastSessionModification, statusCode);
360 if(warning)
361 {
362 response.header(h_Warnings).push_back(*warning);
363 }
364 InfoLog (<< "Sending " << response.brief());
365 mDialog.send(response);
366 break;
367 }
368
369 default:
370 assert(0);
371 break;
372 }
373 }
374
375 void
376 InviteSession::targetRefresh(const NameAddr& localUri)
377 {
378 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
379 {
380 // !jf! add interface to Dialog
381 //mDialog.setLocalContact(localUri);
382 provideOffer(*mCurrentLocalSdp);
383 }
384 else
385 {
386 WarningLog (<< "Can't targetRefresh before Connected");
387 assert(0);
388 throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
389 }
390 }
391
392 void
393 InviteSession::refer(const NameAddr& referTo)
394 {
395 if (mSentRefer)
396 {
397 throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
398 }
399
400 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
401 {
402 mSentRefer = true;
403 SipMessage refer;
404 mDialog.makeRequest(refer, REFER);
405 refer.header(h_ReferTo) = referTo;
406 refer.header(h_ReferredBy) = mDialog.mLocalContact; // !slg! is it ok to do this - should it be an option?
407 mDialog.send(refer);
408 }
409 else
410 {
411 WarningLog (<< "Can't refer before Connected");
412 assert(0);
413 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
414 }
415 }
416
417 void
418 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace)
419 {
420 if (!sessionToReplace.isValid())
421 {
422 throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
423 }
424
425 if (mSentRefer)
426 {
427 throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
428 }
429
430 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
431 {
432 mSentRefer = true;
433 SipMessage refer;
434 mDialog.makeRequest(refer, REFER);
435
436 refer.header(h_ReferTo) = referTo;
437 refer.header(h_ReferredBy) = mDialog.mLocalContact; // ?slg? is it ok to do this - should it be an option?
438 CallId replaces;
439 DialogId id = sessionToReplace->mDialog.getId();
440 replaces.value() = id.getCallId();
441 replaces.param(p_toTag) = id.getRemoteTag();
442 replaces.param(p_fromTag) = id.getLocalTag();
443
444 refer.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
445 mDialog.send(refer);
446 }
447 else
448 {
449 WarningLog (<< "Can't refer before Connected");
450 assert(0);
451 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
452 }
453 }
454
455 void
456 InviteSession::info(const Contents& contents)
457 {
458 if (mNitState == NitComplete)
459 {
460 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
461 {
462 mNitState = NitProceeding;
463 SipMessage info;
464 mDialog.makeRequest(info, INFO);
465 // !jf! handle multipart here
466 info.setContents(&contents);
467 mDialog.send(info);
468 }
469 else
470 {
471 WarningLog (<< "Can't send INFO before Connected");
472 assert(0);
473 throw UsageUseException("Can't send INFO before Connected", __FILE__, __LINE__);
474 }
475 }
476 else
477 {
478 throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
479 __FILE__, __LINE__);
480 }
481 }
482
483 void
484 InviteSession::dispatch(const SipMessage& msg)
485 {
486 // !jf! do we need to handle 3xx here or is it handled elsewhere?
487 switch (mState)
488 {
489 case Connected:
490 dispatchConnected(msg);
491 break;
492 case SentUpdate:
493 dispatchSentUpdate(msg);
494 break;
495 case SentReinvite:
496 dispatchSentReinvite(msg);
497 break;
498 case SentUpdateGlare:
499 case SentReinviteGlare:
500 // The behavior is the same except for timer which is handled in dispatch(Timer)
501 dispatchGlare(msg);
502 break;
503 case ReceivedUpdate:
504 case ReceivedReinvite:
505 case ReceivedReinviteNoOffer:
506 dispatchReceivedUpdateOrReinvite(msg);
507 break;
508 case Answered:
509 dispatchAnswered(msg);
510 break;
511 case WaitingToOffer:
512 dispatchWaitingToOffer(msg);
513 break;
514 case WaitingToTerminate:
515 dispatchWaitingToTerminate(msg);
516 break;
517 case Terminated:
518 dispatchTerminated(msg);
519 break;
520 case Undefined:
521 default:
522 assert(0);
523 break;
524 }
525 }
526
527 void
528 InviteSession::dispatch(const DumTimeout& timeout)
529 {
530 if (timeout.type() == DumTimeout::Retransmit200)
531 {
532 if (mCurrentRetransmit200)
533 {
534 InfoLog (<< "Retransmitting: " << endl << mInvite200);
535 mDialog.send(mInvite200);
536 mCurrentRetransmit200 *= 2;
537 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
538 }
539 }
540 else if (timeout.type() == DumTimeout::WaitForAck)
541 {
542 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
543 {
544 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
545
546 // this is so the app can decided to ignore this. default implementation
547 // will call end next
548 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
549
550 // If we are waiting for an Ack and it times out, then end with a BYE
551 if(mState == UAS_WaitingToHangup)
552 {
553 sendBye();
554 transition(Terminated);
555 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
556 }
557 }
558 }
559 else if (timeout.type() == DumTimeout::Glare)
560 {
561 if (mState == SentUpdateGlare)
562 {
563 transition(SentUpdate);
564
565 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
566 mDialog.send(mLastSessionModification);
567 }
568 else if (mState == SentReinviteGlare)
569 {
570 transition(SentReinvite);
571
572 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
573 mDialog.send(mLastSessionModification);
574 }
575 }
576 else if (timeout.type() == DumTimeout::SessionExpiration)
577 {
578 if(timeout.seq() == mSessionTimerSeq)
579 {
580 // this is so the app can decided to ignore this. default implementation
581 // will call end next
582 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
583 }
584 }
585 else if (timeout.type() == DumTimeout::SessionRefresh)
586 {
587 if(timeout.seq() == mSessionTimerSeq)
588 {
589 if(mState == Connected) // Note: If not connected then we must be issueing a reinvite/update or receiving one - in either case the session timer stuff will get reset/renegotiated - thus just ignore this referesh
590 {
591 sessionRefresh();
592 }
593 }
594 }
595 }
596
597
598 void
599 InviteSession::dispatchConnected(const SipMessage& msg)
600 {
601 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
602 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
603
604 switch (toEvent(msg, sdp.get()))
605 {
606 case OnInvite:
607 case OnInviteReliable:
608 mLastSessionModification = msg;
609 transition(ReceivedReinviteNoOffer);
610 //handler->onDialogModified(getSessionHandle(), None, msg);
611 handler->onOfferRequired(getSessionHandle(), msg);
612 break;
613
614 case OnInviteOffer:
615 case OnInviteReliableOffer:
616 mLastSessionModification = msg;
617 transition(ReceivedReinvite);
618 //handler->onDialogModified(getSessionHandle(), Offer, msg);
619 handler->onOffer(getSessionHandle(), msg, *sdp);
620 break;
621
622 case On2xx:
623 case On2xxOffer:
624 case On2xxAnswer:
625 // retransmission of 200I
626 // !jf! Need to include the answer here.
627 sendAck();
628 break;
629
630 case OnUpdateOffer:
631 transition(ReceivedUpdate);
632
633 // !kh!
634 // Find out if it's an UPDATE requiring state change.
635 // See rfc3311 5.2, 4th paragraph.
636 mLastSessionModification = msg;
637 handler->onOffer(getSessionHandle(), msg, *sdp);
638 break;
639
640 case OnUpdate:
641 {
642 // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
643 SipMessage response;
644 mLastSessionModification = msg;
645 mDialog.makeResponse(response, mLastSessionModification, 200);
646 handleSessionTimerRequest(response, mLastSessionModification);
647 send(response);
648 break;
649 }
650
651 case OnUpdateRejected:
652 case On200Update:
653 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
654 assert(0);
655 break;
656
657 case OnAck:
658 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
659 break;
660
661 default:
662 dispatchOthers(msg);
663 break;
664 }
665 }
666
667
668
669 void
670 InviteSession::dispatchSentUpdate(const SipMessage& msg)
671 {
672 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
673 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
674
675 switch (toEvent(msg, sdp.get()))
676 {
677 case OnInvite:
678 case OnInviteReliable:
679 case OnInviteOffer:
680 case OnInviteReliableOffer:
681 case OnUpdate:
682 case OnUpdateOffer:
683 {
684 // glare
685 SipMessage response;
686 mDialog.makeResponse(response, msg, 491);
687 send(response);
688 break;
689 }
690
691 case On200Update:
692 transition(Connected);
693 handleSessionTimerResponse(msg);
694 if (sdp.get())
695 {
696 mCurrentLocalSdp = mProposedLocalSdp;
697 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
698 handler->onAnswer(getSessionHandle(), msg, *sdp);
699 }
700 else if(mProposedLocalSdp.get())
701 {
702 // If we sent an offer in the Update Request and no answer is received
703 handler->onIllegalNegotiation(getSessionHandle(), msg);
704 mProposedLocalSdp.release();
705 }
706 break;
707
708 case On491Update:
709 transition(SentUpdateGlare);
710 start491Timer();
711 break;
712
713 case On422Update:
714 if(msg.exists(h_MinSE))
715 {
716 // Change interval to min from 422 response
717 mSessionInterval = msg.header(h_MinSE).value();
718 mMinSE = mSessionInterval;
719 sessionRefresh();
720 }
721 else
722 {
723 // Response must contact Min_SE - if not - just ignore
724 // ?slg? callback?
725 transition(Connected);
726 mProposedLocalSdp.release();
727 }
728 break;
729
730 case OnUpdateRejected:
731 // !jf! - callback?
732 mProposedLocalSdp.release();
733 transition(Connected);
734 break;
735
736 case OnGeneralFailure:
737 sendBye();
738 transition(Terminated);
739 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
740 break;
741
742 default:
743 dispatchOthers(msg);
744 break;
745 }
746 }
747
748 void
749 InviteSession::dispatchSentReinvite(const SipMessage& msg)
750 {
751 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
752 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
753
754 switch (toEvent(msg, sdp.get()))
755 {
756 case OnInvite:
757 case OnInviteReliable:
758 case OnInviteOffer:
759 case OnInviteReliableOffer:
760 case OnUpdate:
761 case OnUpdateOffer:
762 {
763 SipMessage response;
764 mDialog.makeResponse(response, msg, 491);
765 send(response);
766 break;
767 }
768
769 case On1xx:
770 case On1xxEarly:
771 // Some UA's send a 100 response to a ReInvite - just ignore it
772 break;
773
774 case On2xxAnswer:
775 case On2xxOffer:
776 {
777 transition(Connected);
778 handleSessionTimerResponse(msg);
779 mCurrentLocalSdp = mProposedLocalSdp;
780 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
781 // !jf! I need to potentially include an answer in the ACK here
782 sendAck();
783 handler->onAnswer(getSessionHandle(), msg, *sdp);
784
785
786 // !jf! do I need to allow a reINVITE overlapping the retransmission of
787 // the ACK when a 200I is received? If yes, then I need to store all
788 // ACK messages for 64*T1
789 break;
790 }
791 case On2xx:
792 sendAck();
793 transition(Connected);
794 handleSessionTimerResponse(msg);
795 handler->onIllegalNegotiation(getSessionHandle(), msg);
796 mProposedLocalSdp.release();
797 break;
798
799 case On422Invite:
800 if(msg.exists(h_MinSE))
801 {
802 // Change interval to min from 422 response
803 mSessionInterval = msg.header(h_MinSE).value();
804 mMinSE = mSessionInterval;
805 sessionRefresh();
806 }
807 else
808 {
809 // Response must contact Min_SE - if not - just ignore
810 // ?slg? callback?
811 transition(Connected);
812 mProposedLocalSdp.release();
813 }
814 break;
815
816 case On491Invite:
817 transition(SentReinviteGlare);
818 start491Timer();
819 break;
820
821 case OnGeneralFailure:
822 sendBye();
823 transition(Terminated);
824 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
825 break;
826
827 case OnInviteFailure:
828 transition(Connected);
829 mProposedLocalSdp.release();
830 handler->onOfferRejected(getSessionHandle(), msg);
831 break;
832
833 default:
834 dispatchOthers(msg);
835 break;
836 }
837 }
838
839 void
840 InviteSession::dispatchGlare(const SipMessage& msg)
841 {
842 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
843 MethodTypes method = msg.header(h_CSeq).method();
844 if (method == INVITE && msg.isRequest())
845 {
846 // Received inbound reinvite, when waiting to resend outbound reinvite or update
847 transition(ReceivedReinvite);
848 handler->onOfferRejected(getSessionHandle(), msg);
849 }
850 else if (method == UPDATE && msg.isRequest())
851 {
852 // Received inbound update, when waiting to resend outbound reinvite or update
853 transition(ReceivedUpdate);
854 handler->onOfferRejected(getSessionHandle(), msg);
855 }
856 else
857 {
858 dispatchOthers(msg);
859 }
860 }
861
862 void
863 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
864 {
865 MethodTypes method = msg.header(h_CSeq).method();
866 if (method == INVITE || method == UPDATE)
867 {
868 // Means that the UAC has sent us a second reINVITE or UPDATE before we
869 // responded to the first one. Bastard!
870 SipMessage response;
871 mDialog.makeResponse(response, msg, 500);
872 response.header(h_RetryAfter).value() = Random::getRandom() % 10;
873 mDialog.send(response);
874 }
875 else
876 {
877 dispatchOthers(msg);
878 }
879 }
880
881
882 void
883 InviteSession::dispatchAnswered(const SipMessage& msg)
884 {
885 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
886 {
887 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
888 transition(Connected);
889 }
890 else
891 {
892 dispatchOthers(msg);
893 }
894 }
895
896 void
897 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
898 {
899 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
900 {
901 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
902 provideOffer(*mProposedLocalSdp);
903 }
904 else
905 {
906 dispatchOthers(msg);
907 }
908 }
909
910 void
911 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
912 {
913 if (msg.isResponse() &&
914 msg.header(h_CSeq).method() == INVITE)
915 {
916 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
917 {
918 // !jf! Need to include the answer here.
919 sendAck();
920 }
921 sendBye();
922 transition(Terminated);
923 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
924 }
925 }
926
927 void
928 InviteSession::dispatchTerminated(const SipMessage& msg)
929 {
930 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
931
932 if (msg.isRequest())
933 {
934 SipMessage response;
935 mDialog.makeResponse(response, msg, 481);
936 mDialog.send(response);
937
938 // !jf! means the peer sent BYE while we are waiting for response to BYE
939 //mDum.destroy(this);
940 }
941 else
942 {
943 mDum.destroy(this);
944 }
945 }
946
947 void
948 InviteSession::dispatchOthers(const SipMessage& msg)
949 {
950 // handle OnGeneralFailure
951 // handle OnRedirect
952
953 switch (msg.header(h_CSeq).method())
954 {
955 case PRACK:
956 dispatchPrack(msg);
957 break;
958 case CANCEL:
959 dispatchCancel(msg);
960 break;
961 case BYE:
962 dispatchBye(msg);
963 break;
964 case INFO:
965 dispatchInfo(msg);
966 break;
967 case ACK:
968 // Ignore duplicate ACKs from 2xx reTransmissions
969 break;
970 default:
971 // handled in Dialog
972 WarningLog (<< "DUM delivered a "
973 << msg.header(h_CSeq).unknownMethodName()
974 << " to the InviteSession "
975 << endl
976 << msg);
977 assert(0);
978 break;
979 }
980 }
981
982 void
983 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
984 {
985 assert(msg.isRequest());
986 assert(msg.header(h_CSeq).method() == INVITE);
987
988 // If we get an INVITE request from the wire and we are not in
989 // Connected state, reject the request and send a BYE
990 SipMessage response;
991 mDialog.makeResponse(response, msg, 400); // !jf! what code to use?
992 InfoLog (<< "Sending " << response.brief());
993 mDialog.send(response);
994
995 sendBye();
996 transition(Terminated);
997 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
998 }
999
1000 void
1001 InviteSession::dispatchPrack(const SipMessage& msg)
1002 {
1003 assert(msg.header(h_CSeq).method() == PRACK);
1004 if(msg.isRequest())
1005 {
1006 SipMessage rsp;
1007 mDialog.makeResponse(rsp, msg, 481);
1008 mDialog.send(rsp);
1009
1010 sendBye();
1011 // !jf! should we make some other callback here
1012 transition(Terminated);
1013 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1014 }
1015 else
1016 {
1017 // ignore. could be PRACK/200
1018 }
1019 }
1020
1021 void
1022 InviteSession::dispatchCancel(const SipMessage& msg)
1023 {
1024 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1025 assert(msg.header(h_CSeq).method() == CANCEL);
1026 if(msg.isRequest())
1027 {
1028 SipMessage rsp;
1029 mDialog.makeResponse(rsp, msg, 200);
1030 mDialog.send(rsp);
1031
1032 sendBye();
1033 // !jf! should we make some other callback here
1034 transition(Terminated);
1035 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1036 }
1037 else
1038 {
1039 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1040 assert(0);
1041 }
1042 }
1043
1044 void
1045 InviteSession::dispatchBye(const SipMessage& msg)
1046 {
1047 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1048
1049 if (msg.isRequest())
1050 {
1051
1052 SipMessage rsp;
1053 InfoLog (<< "Received " << msg.brief());
1054 mDialog.makeResponse(rsp, msg, 200);
1055 mDialog.send(rsp);
1056
1057 // !jf! should we make some other callback here
1058 transition(Terminated);
1059 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1060 mDum.destroy(this);
1061 }
1062 else
1063 {
1064 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1065 assert(0);
1066 }
1067 }
1068
1069 void
1070 InviteSession::dispatchInfo(const SipMessage& msg)
1071 {
1072 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1073 if (msg.isRequest())
1074 {
1075 InfoLog (<< "Received " << msg.brief());
1076 mDialog.makeResponse(mLastNitResponse, msg, 200);
1077 handler->onInfo(getSessionHandle(), msg);
1078 }
1079 else
1080 {
1081 assert(mNitState == NitProceeding);
1082 mNitState = NitComplete;
1083 //!dcm! -- toss away 1xx to an info?
1084 if (msg.header(h_StatusLine).statusCode() >= 300)
1085 {
1086 handler->onInfoFailure(getSessionHandle(), msg);
1087 }
1088 else if (msg.header(h_StatusLine).statusCode() >= 200)
1089 {
1090 handler->onInfoSuccess(getSessionHandle(), msg);
1091 }
1092 }
1093 }
1094
1095 void
1096 InviteSession::acceptInfo(int statusCode)
1097 {
1098 if (statusCode / 100 != 2)
1099 {
1100 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
1101 }
1102
1103 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1104 send(mLastNitResponse);
1105 }
1106
1107 void
1108 InviteSession::rejectInfo(int statusCode)
1109 {
1110 if (statusCode < 400)
1111 {
1112 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
1113 }
1114 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1115 send(mLastNitResponse);
1116 }
1117
1118 void
1119 InviteSession::startRetransmit200Timer()
1120 {
1121 mCurrentRetransmit200 = Timer::T1;
1122 int seq = mLastSessionModification.header(h_CSeq).sequence();
1123 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
1124 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
1125 }
1126
1127 void
1128 InviteSession::start491Timer()
1129 {
1130 int seq = mLastSessionModification.header(h_CSeq).sequence();
1131 int timer = Random::getRandom() % 4000;
1132 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1133 }
1134
1135 void
1136 InviteSession::setSessionTimerHeaders(SipMessage &msg)
1137 {
1138 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
1139 {
1140 msg.header(h_SessionExpires).value() = mSessionInterval;
1141 if(msg.isRequest())
1142 {
1143 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
1144 }
1145 else
1146 {
1147 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
1148 }
1149 msg.header(h_MinSE).value() = mMinSE;
1150 }
1151 else
1152 {
1153 msg.remove(h_SessionExpires);
1154 msg.remove(h_MinSE);
1155 }
1156 }
1157
1158 void
1159 InviteSession::sessionRefresh()
1160 {
1161 if (updateMethodSupported())
1162 {
1163 transition(SentUpdate);
1164 mDialog.makeRequest(mLastSessionModification, UPDATE);
1165 mLastSessionModification.releaseContents(); // Don't send SDP
1166 }
1167 else
1168 {
1169 transition(SentReinvite);
1170 mDialog.makeRequest(mLastSessionModification, INVITE);
1171 InviteSession::setSdp(mLastSessionModification, *mCurrentLocalSdp);
1172 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp);
1173 }
1174 setSessionTimerHeaders(mLastSessionModification);
1175
1176 InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief());
1177 mDialog.send(mLastSessionModification);
1178 }
1179
1180 void
1181 InviteSession::setSessionTimerPreferences()
1182 {
1183 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
1184 if(mSessionInterval != 0)
1185 {
1186 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
1187 mSessionInterval = resipMax(mMinSE, mSessionInterval);
1188 }
1189 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1190 {
1191 case Profile::PreferLocalRefreshes:
1192 mSessionRefresher = true; // Default refresher is Local
1193 break;
1194 case Profile::PreferRemoteRefreshes:
1195 mSessionRefresher = false; // Default refresher is Remote
1196 break;
1197 case Profile::PreferUASRefreshes:
1198 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
1199 break;
1200 case Profile::PreferUACRefreshes:
1201 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
1202 break;
1203 }
1204 }
1205
1206 void
1207 InviteSession::startSessionTimer()
1208 {
1209 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
1210 {
1211 // Check if we are the refresher
1212 if(mSessionRefresher)
1213 {
1214 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
1215 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1216 }
1217 else
1218 {
1219 // Start Session-Expiration Timer to mSessionInterval - BYE should be sent a minimum of 32 and one third of the SessionInterval, seconds before the session expires (recommended by RFC4028)
1220 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1221 }
1222 }
1223 else // Session Interval less than 90 - consider timers disabled
1224 {
1225 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1226 }
1227 }
1228
1229 void
1230 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
1231 {
1232 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
1233
1234 // If session timers are locally supported then handle response
1235 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1236 {
1237 setSessionTimerPreferences();
1238
1239 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
1240 && !msg.exists(h_SessionExpires))
1241 {
1242 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
1243 mSessionInterval = 0;
1244 }
1245 // Process Session Timer headers
1246 else if(msg.exists(h_SessionExpires))
1247 {
1248 mSessionInterval = msg.header(h_SessionExpires).value();
1249 if(msg.header(h_SessionExpires).exists(p_refresher))
1250 {
1251 // Remote end specified refresher preference
1252 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
1253 }
1254 }
1255 else
1256 {
1257 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
1258 // - we are free to use our SessionInterval settings (set above as a default)
1259 // If far end doesn't support then refresher must be local
1260 mSessionRefresher = true;
1261 }
1262
1263 // Update MinSE if specified and longer than current value
1264 if(msg.exists(h_MinSE))
1265 {
1266 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
1267 }
1268
1269 startSessionTimer();
1270 }
1271 }
1272
1273 void
1274 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1275 {
1276 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1277
1278 // If session timers are locally supported then add necessary headers to response
1279 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1280 {
1281 setSessionTimerPreferences();
1282
1283 // Check if far-end supports
1284 bool farEndSupportsTimer = false;
1285 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
1286 {
1287 farEndSupportsTimer = true;
1288 if(request.exists(h_SessionExpires))
1289 {
1290 // Use Session Interval requested by remote - if none then use local settings
1291 mSessionInterval = request.header(h_SessionExpires).value();
1292 if(request.header(h_SessionExpires).exists(p_refresher))
1293 {
1294 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1295 }
1296 }
1297
1298 // Update MinSE if specified and longer than current value
1299 if(request.exists(h_MinSE))
1300 {
1301 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
1302 }
1303 }
1304 else
1305 {
1306 // If far end doesn't support then refresher must be local
1307 mSessionRefresher = true;
1308 }
1309
1310 // Add Session-Expires to response if required
1311 if(mSessionInterval >= 90)
1312 {
1313 if(farEndSupportsTimer)
1314 {
1315 // If far end supports session-timer then require it, if not already present
1316 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
1317 {
1318 response.header(h_Requires).push_back(Token(Symbols::Timer));
1319 }
1320 }
1321 setSessionTimerHeaders(response);
1322 }
1323
1324 startSessionTimer();
1325 }
1326 }
1327
1328 Data
1329 InviteSession::toData(State state)
1330 {
1331 switch (state)
1332 {
1333 case Undefined:
1334 return "InviteSession::Undefined";
1335 case Connected:
1336 return "InviteSession::Connected";
1337 case SentUpdate:
1338 return "InviteSession::SentUpdate";
1339 case SentUpdateGlare:
1340 return "InviteSession::SentUpdateGlare";
1341 case SentReinvite:
1342 return "InviteSession::SentReinvite";
1343 case SentReinviteGlare:
1344 return "InviteSession::SentReinviteGlare";
1345 case ReceivedUpdate:
1346 return "InviteSession::ReceivedUpdate";
1347 case ReceivedReinvite:
1348 return "InviteSession::ReceivedReinvite";
1349 case ReceivedReinviteNoOffer:
1350 return "InviteSession::ReceivedReinviteNoOffer";
1351 case Answered:
1352 return "InviteSession::Answered";
1353 case WaitingToOffer:
1354 return "InviteSession::WaitingToOffer";
1355 case WaitingToTerminate:
1356 return "InviteSession::WaitingToTerminate";
1357 case Terminated:
1358 return "InviteSession::Terminated";
1359
1360 case UAC_Start:
1361 return "UAC_Start";
1362 case UAS_Offer:
1363 return "UAS_Offer";
1364 case UAS_OfferProvidedAnswer:
1365 return "UAS_OfferProvidedAnswer";
1366 case UAS_EarlyOffer:
1367 return "UAS_EarlyOffer";
1368 case UAS_EarlyProvidedAnswer:
1369 return "UAS_EarlyProvidedAnswer";
1370 case UAS_NoOffer:
1371 return "UAS_NoOffer";
1372 case UAS_ProvidedOffer:
1373 return "UAS_ProvidedOffer";
1374 case UAS_EarlyNoOffer:
1375 return "UAS_EarlyNoOffer";
1376 case UAS_EarlyProvidedOffer:
1377 return "UAS_EarlyProvidedOffer";
1378 case UAS_Accepted:
1379 return "UAS_Accepted";
1380 case UAS_WaitingToOffer:
1381 return "UAS_WaitingToOffer";
1382 case UAS_AcceptedWaitingAnswer:
1383 return "UAS_AcceptedWaitingAnswer";
1384 case UAC_Early:
1385 return "UAC_Early";
1386 case UAC_EarlyWithOffer:
1387 return "UAC_EarlyWithOffer";
1388 case UAC_EarlyWithAnswer:
1389 return "UAC_EarlyWithAnswer";
1390 case UAC_Answered:
1391 return "UAC_Answered";
1392 case UAC_SentUpdateEarly:
1393 return "UAC_SentUpdateEarly";
1394 case UAC_SentUpdateConnected:
1395 return "UAC_SentUpdateConnected";
1396 case UAC_ReceivedUpdateEarly:
1397 return "UAC_ReceivedUpdateEarly";
1398 case UAC_SentAnswer:
1399 return "UAC_SentAnswer";
1400 case UAC_QueuedUpdate:
1401 return "UAC_QueuedUpdate";
1402 case UAC_Cancelled:
1403 return "UAC_Cancelled";
1404
1405 case UAS_Start:
1406 return "UAS_Start";
1407 case UAS_OfferReliable:
1408 return "UAS_OfferReliable";
1409 case UAS_NoOfferReliable:
1410 return "UAS_NoOfferReliable";
1411 case UAS_FirstSentOfferReliable:
1412 return "UAS_FirstSentOfferReliable";
1413 case UAS_FirstEarlyReliable:
1414 return "UAS_FirstEarlyReliable";
1415 case UAS_EarlyReliable:
1416 return "UAS_EarlyReliable";
1417 case UAS_SentUpdate:
1418 return "UAS_SentUpdate";
1419 case UAS_SentUpdateAccepted:
1420 return "UAS_SentUpdateAccepted";
1421 case UAS_ReceivedUpdate:
1422 return "UAS_ReceivedUpdate";
1423 case UAS_ReceivedUpdateWaitingAnswer:
1424 return "UAS_ReceivedUpdateWaitingAnswer";
1425 case UAS_WaitingToTerminate:
1426 return "UAS_WaitingToTerminate";
1427 case UAS_WaitingToHangup:
1428 return "UAS_WaitingToHangup";
1429 }
1430 assert(0);
1431 return "Undefined";
1432 }
1433
1434
1435 void
1436 InviteSession::transition(State target)
1437 {
1438 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1439 mState = target;
1440 }
1441
1442 bool
1443 InviteSession::isReliable(const SipMessage& msg)
1444 {
1445 // Ensure supported both locally and remotely
1446 return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&
1447 mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));
1448 }
1449
1450 std::auto_ptr<SdpContents>
1451 InviteSession::getSdp(const SipMessage& msg)
1452 {
1453 // !jf! this code doesn't yet work - definitely if USE_SSL=false
1454 //Helper::ContentsSecAttrs attrs = Helper::extractFromPkcs7(msg, mDum.getSecurity());
1455 //return std::auto_ptr<SdpContents>(dynamic_cast<SdpContents*>(attrs.mContents.get()));
1456 SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());
1457 if (sdp)
1458 {
1459 SdpContents* cloned = static_cast<SdpContents*>(sdp->clone());
1460 return std::auto_ptr<SdpContents>(cloned);
1461 }
1462 else
1463 {
1464 static std::auto_ptr<SdpContents> empty;
1465 return empty;
1466 }
1467 }
1468
1469 std::auto_ptr<SdpContents>
1470 InviteSession::makeSdp(const SdpContents& sdp)
1471 {
1472 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
1473 }
1474
1475 void
1476 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp)
1477 {
1478 // !jf! should deal with multipart here
1479
1480 // This will clone the sdp since the InviteSession also wants to keep its own
1481 // copy of the sdp around for the application to access
1482 msg.setContents(&sdp);
1483 }
1484
1485 InviteSession::Event
1486 InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
1487 {
1488 MethodTypes method = msg.header(h_CSeq).method();
1489 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
1490 bool reliable = isReliable(msg);
1491 bool sentOffer = mProposedLocalSdp.get();
1492
1493 if (code == 481 || code == 408)
1494 {
1495 return OnGeneralFailure;
1496 }
1497 else if (code >= 300 && code <= 399)
1498 {
1499 return OnRedirect;
1500 }
1501 else if (method == INVITE && code == 0)
1502 {
1503 if (sdp)
1504 {
1505 if (reliable)
1506 {
1507 return OnInviteReliableOffer;
1508 }
1509 else
1510 {
1511 return OnInviteOffer;
1512 }
1513 }
1514 else
1515 {
1516 if (reliable)
1517 {
1518 return OnInviteReliable;
1519 }
1520 else
1521 {
1522 return OnInvite;
1523 }
1524 }
1525 }
1526 else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer.
1527 {
1528 if (reliable)
1529 {
1530 if (sdp)
1531 {
1532 if (sentOffer)
1533 {
1534 return On1xxAnswer;
1535 }
1536 else
1537 {
1538 return On1xxOffer;
1539 }
1540 }
1541 else
1542 {
1543 return On1xx;
1544 }
1545 }
1546 else
1547 {
1548 if (sdp)
1549 {
1550 return On1xxEarly;
1551 }
1552 else
1553 {
1554 return On1xx;
1555 }
1556 }
1557 }
1558 else if (method == INVITE && code >= 200 && code < 300)
1559 {
1560 if (sdp)
1561 {
1562 if (sentOffer)
1563 {
1564 return On2xxAnswer;
1565 }
1566 else
1567 {
1568 return On2xxOffer;
1569 }
1570 }
1571 else
1572 {
1573 return On2xx;
1574 }
1575 }
1576 else if (method == INVITE && code == 422)
1577 {
1578 return On422Invite;
1579 }
1580 else if (method == INVITE && code == 487)
1581 {
1582 return On487Invite;
1583 }
1584 else if (method == INVITE && code == 489)
1585 {
1586 return On489Invite;
1587 }
1588 else if (method == INVITE && code == 491)
1589 {
1590 return On491Invite;
1591 }
1592 else if (method == INVITE && code >= 400)
1593 {
1594 return OnInviteFailure;
1595 }
1596 else if (method == ACK)
1597 {
1598 if (sdp)
1599 {
1600 return OnAckAnswer;
1601 }
1602 else
1603 {
1604 return OnAck;
1605 }
1606 }
1607 else if (method == CANCEL && code == 0)
1608 {
1609 return OnCancel;
1610 }
1611 else if (method == CANCEL && code / 200 == 1)
1612 {
1613 return On200Cancel;
1614 }
1615 else if (method == CANCEL && code >= 400)
1616 {
1617 return OnCancelFailure;
1618 }
1619 else if (method == BYE && code == 0)
1620 {
1621 return OnBye;
1622 }
1623 else if (method == BYE && code / 200 == 1)
1624 {
1625 return On200Bye;
1626 }
1627 else if (method == PRACK && code == 0)
1628 {
1629 return OnPrack;
1630 }
1631 else if (method == PRACK && code / 200 == 1)
1632 {
1633 return On200Prack;
1634 }
1635 else if (method == UPDATE && code == 0)
1636 {
1637 if (sdp)
1638 {
1639 return OnUpdateOffer;
1640 }
1641 else
1642 {
1643 return OnUpdate;
1644 }
1645 }
1646 else if (method == UPDATE && code / 200 == 1)
1647 {
1648 return On200Update;
1649 }
1650 else if (method == UPDATE && code == 422)
1651 {
1652 return On422Update;
1653 }
1654 else if (method == UPDATE && code == 489)
1655 {
1656 return On489Update;
1657 }
1658 else if (method == UPDATE && code == 491)
1659 {
1660 return On491Update;
1661 }
1662 else if (method == UPDATE && code >= 400)
1663 {
1664 return OnUpdateRejected;
1665 }
1666 else
1667 {
1668 assert(0);
1669 return Unknown;
1670 }
1671 }
1672
1673 void InviteSession::sendAck(const SdpContents *sdp)
1674 {
1675 SipMessage ack;
1676 mDialog.makeRequest(ack, ACK);
1677 if(sdp != 0)
1678 {
1679 setSdp(ack, *sdp);
1680 }
1681 InfoLog (<< "Sending " << ack.brief());
1682 mDialog.send(ack);
1683 }
1684
1685 void InviteSession::sendBye()
1686 {
1687 SipMessage bye;
1688 mDialog.makeRequest(bye, BYE);
1689 InfoLog (<< "Sending " << bye.brief());
1690 mDialog.send(bye);
1691 }
1692
1693
1694 /* ====================================================================
1695 * The Vovida Software License, Version 1.0
1696 *
1697 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1698 *
1699 * Redistribution and use in source and binary forms, with or without
1700 * modification, are permitted provided that the following conditions
1701 * are met:
1702 *
1703 * 1. Redistributions of source code must retain the above copyright
1704 * notice, this list of conditions and the following disclaimer.
1705 *
1706 * 2. Redistributions in binary form must reproduce the above copyright
1707 * notice, this list of conditions and the following disclaimer in
1708 * the documentation and/or other materials provided with the
1709
1710 * distribution.
1711 *
1712 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1713 * and "Vovida Open Communication Application Library (VOCAL)" must
1714 * not be used to endorse or promote products derived from this
1715 * software without prior written permission. For written
1716 * permission, please contact vocal@vovida.org.
1717 *
1718 * 4. Products derived from this software may not be called "VOCAL", nor
1719 * may "VOCAL" appear in their name, without prior written
1720 * permission of Vovida Networks, Inc.
1721 *
1722 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1723 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1724 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1725 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1726 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1727 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1728 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1729 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1730 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1731 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1732 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1733 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1734 * DAMAGE.
1735 *
1736 * ====================================================================
1737 *
1738 * This software consists of voluntary contributions made by Vovida
1739 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1740 * Inc. For more information on Vovida Networks, Inc., please see
1741 * <http://www.vovida.org/>.
1742 *
1743 */

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27