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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27