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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5459 - (show annotations) (download)
Sat Sep 24 19:44:50 2005 UTC (14 years, 2 months ago) by jason
File size: 59850 byte(s)
added support for Allowed-Events header

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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27