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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27