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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5586 - (show annotations) (download)
Fri Oct 28 21:01:13 2005 UTC (14 years, 1 month ago) by sgodin
File size: 69540 byte(s)
- modified ACK handling
  - mAckId is no longer tracked by Dialog.cxx - all logic is in InviteSession.cxx
  - Authorization and Proxy-Authorization headers are copied to acks from the InviteSession.cxx
  - 2xx retransmission is now detected and handled properly - no more incorrect handler callbacks
- DialogSet destruction bug fixed
- onStaleCallTimeout callback no has a default handler to send a BYE - app can override and send a CANCEL if desired
- 

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::setOutgoingEncryptionLevel(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::setOutgoingEncryptionLevel(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::setOutgoingEncryptionLevel(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::setOutgoingEncryptionLevel(response, mCurrentEncryptionLevel);
398 send(response);
399 break;
400 }
401
402 case SentReinviteAnswered:
403 transition(Connected);
404 sendAck(mLastSessionModification, &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::setOutgoingEncryptionLevel(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::setOutgoingEncryptionLevel(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 // Look for 2xx retransmissions - resend ACK and filter out of state machine
663 if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 200 == 1)
664 {
665 AckMap::iterator i = mAcks.find(msg.header(h_CSeq).sequence());
666 if (i != mAcks.end())
667 {
668 send(i->second); // resend ACK
669 return;
670 }
671 }
672
673 // !jf! do we need to handle 3xx here or is it handled elsewhere?
674 switch (mState)
675 {
676 case Connected:
677 dispatchConnected(msg);
678 break;
679 case SentUpdate:
680 dispatchSentUpdate(msg);
681 break;
682 case SentReinvite:
683 dispatchSentReinvite(msg);
684 break;
685 case SentReinviteNoOffer:
686 dispatchSentReinviteNoOffer(msg);
687 break;
688 case SentReinviteAnswered:
689 dispatchSentReinviteAnswered(msg);
690 break;
691 case SentUpdateGlare:
692 case SentReinviteGlare:
693 // The behavior is the same except for timer which is handled in dispatch(Timer)
694 dispatchGlare(msg);
695 break;
696 case SentReinviteNoOfferGlare:
697 dispatchReinviteNoOfferGlare(msg);
698 break;
699 case ReceivedUpdate:
700 case ReceivedReinvite:
701 case ReceivedReinviteNoOffer:
702 dispatchReceivedUpdateOrReinvite(msg);
703 break;
704 case ReceivedReinviteSentOffer:
705 dispatchReceivedReinviteSentOffer(msg);
706 break;
707 case Answered:
708 dispatchAnswered(msg);
709 break;
710 case WaitingToOffer:
711 dispatchWaitingToOffer(msg);
712 break;
713 case WaitingToRequestOffer:
714 dispatchWaitingToRequestOffer(msg);
715 break;
716 case WaitingToTerminate:
717 dispatchWaitingToTerminate(msg);
718 break;
719 case WaitingToHangup:
720 dispatchWaitingToHangup(msg);
721 break;
722 case Terminated:
723 dispatchTerminated(msg);
724 break;
725 case Undefined:
726 default:
727 assert(0);
728 break;
729 }
730 }
731
732 void
733 InviteSession::dispatch(const DumTimeout& timeout)
734 {
735 if (timeout.type() == DumTimeout::Retransmit200)
736 {
737 if (mCurrentRetransmit200)
738 {
739 InfoLog (<< "Retransmitting: " << endl << mInvite200);
740 DumHelper::setOutgoingEncryptionLevel(mInvite200, mCurrentEncryptionLevel);
741 send(mInvite200);
742 mCurrentRetransmit200 *= 2;
743 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
744 }
745 }
746 else if (timeout.type() == DumTimeout::WaitForAck)
747 {
748 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
749 {
750 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
751
752 // this is so the app can decided to ignore this. default implementation
753 // will call end next
754 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
755
756 // If we are waiting for an Ack and it times out, then end with a BYE
757 if(mState == UAS_WaitingToHangup ||
758 mState == WaitingToHangup)
759 {
760 sendBye();
761 transition(Terminated);
762 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
763 }
764 else if(mState == ReceivedReinviteSentOffer)
765 {
766 transition(Connected);
767 mProposedLocalSdp.reset();
768 mProposedEncryptionLevel = DialogUsageManager::None;
769 //!dcm! -- should this be onIllegalNegotiation?
770 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
771 }
772 else if(mState == WaitingToOffer)
773 {
774 assert(mProposedLocalSdp.get());
775 //!dcm! -- should this be onIllegalNegotiation?
776 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
777 provideProposedOffer();
778 }
779 }
780 }
781 else if (timeout.type() == DumTimeout::CanDiscardAck)
782 {
783 AckMap::iterator i = mAcks.find(timeout.seq());
784 if (i != mAcks.end())
785 {
786 mAcks.erase(i);
787 }
788 }
789 else if (timeout.type() == DumTimeout::Glare)
790 {
791 if (mState == SentUpdateGlare)
792 {
793 transition(SentUpdate);
794
795 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
796 send(mLastSessionModification);
797 }
798 else if (mState == SentReinviteGlare)
799 {
800 transition(SentReinvite);
801
802 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
803 send(mLastSessionModification);
804 }
805 else if (mState == SentReinviteNoOfferGlare)
806 {
807 transition(SentReinviteNoOffer);
808
809 InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
810 send(mLastSessionModification);
811 }
812 }
813 else if (timeout.type() == DumTimeout::SessionExpiration)
814 {
815 if(timeout.seq() == mSessionTimerSeq)
816 {
817 // this is so the app can decided to ignore this. default implementation
818 // will call end next - which will send a BYE
819 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
820 }
821 }
822 else if (timeout.type() == DumTimeout::SessionRefresh)
823 {
824 if(timeout.seq() == mSessionTimerSeq)
825 {
826 // Note: If not connected then we must be issueing a reinvite/update or
827 // receiving one - in either case the session timer stuff will get
828 // reset/renegotiated - thus just ignore this referesh
829 if(mState == Connected)
830 {
831 sessionRefresh();
832 }
833 }
834 }
835 }
836
837 void
838 InviteSession::dispatchConnected(const SipMessage& msg)
839 {
840 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
841 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
842
843 switch (toEvent(msg, sdp.get()))
844 {
845 case OnInvite:
846 case OnInviteReliable:
847 mLastSessionModification = msg;
848 transition(ReceivedReinviteNoOffer);
849 //handler->onDialogModified(getSessionHandle(), None, msg);
850 handler->onOfferRequired(getSessionHandle(), msg);
851 break;
852
853 case OnInviteOffer:
854 case OnInviteReliableOffer:
855 mLastSessionModification = msg;
856 transition(ReceivedReinvite);
857 mCurrentEncryptionLevel = getEncryptionLevel(msg);
858 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
859
860 //handler->onDialogModified(getSessionHandle(), Offer, msg);
861 handler->onOffer(getSessionHandle(), msg, *sdp);
862 break;
863
864 case On2xx:
865 case On2xxOffer:
866 case On2xxAnswer:
867 // retransmission of 200I
868 // !jf! Need to include the answer here.
869 sendAck(mLastSessionModification); // !slg! ????????? Look up ACK map???
870 break;
871
872 case OnUpdateOffer:
873 transition(ReceivedUpdate);
874
875 // !kh!
876 // Find out if it's an UPDATE requiring state change.
877 // See rfc3311 5.2, 4th paragraph.
878 mLastSessionModification = msg;
879 mCurrentEncryptionLevel = getEncryptionLevel(msg);
880 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
881 handler->onOffer(getSessionHandle(), msg, *sdp);
882 break;
883
884 case OnUpdate:
885 {
886 // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
887 SipMessage response;
888 mLastSessionModification = msg;
889 mDialog.makeResponse(response, mLastSessionModification, 200);
890 handleSessionTimerRequest(response, mLastSessionModification);
891 BaseUsage::send(response);
892 break;
893 }
894
895 case OnUpdateRejected:
896 case On200Update:
897 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
898 assert(0);
899 break;
900
901 case OnAck:
902 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
903 break;
904
905 default:
906 dispatchOthers(msg);
907 break;
908 }
909 }
910
911 void
912 InviteSession::dispatchSentUpdate(const SipMessage& msg)
913 {
914 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
915 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
916
917 switch (toEvent(msg, sdp.get()))
918 {
919 case OnInvite:
920 case OnInviteReliable:
921 case OnInviteOffer:
922 case OnInviteReliableOffer:
923 case OnUpdate:
924 case OnUpdateOffer:
925 {
926 // glare
927 SipMessage response;
928 mDialog.makeResponse(response, msg, 491);
929 BaseUsage::send(response);
930 break;
931 }
932
933 case On200Update:
934 transition(Connected);
935 handleSessionTimerResponse(msg);
936 if (sdp.get())
937 {
938 mCurrentEncryptionLevel = getEncryptionLevel(msg);
939 setCurrentLocalSdp(msg);
940 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
941 handler->onAnswer(getSessionHandle(), msg, *sdp);
942 }
943 else if(mProposedLocalSdp.get())
944 {
945 // If we sent an offer in the Update Request and no answer is received
946 handler->onIllegalNegotiation(getSessionHandle(), msg);
947 mProposedLocalSdp.reset();
948 mProposedEncryptionLevel = DialogUsageManager::None;
949 }
950 break;
951
952 case On491Update:
953 transition(SentUpdateGlare);
954 start491Timer();
955 break;
956
957 case On422Update: // session timer
958 if(msg.exists(h_MinSE))
959 {
960 // Change interval to min from 422 response
961 mSessionInterval = msg.header(h_MinSE).value();
962 mMinSE = mSessionInterval;
963 sessionRefresh();
964 }
965 else
966 {
967 // Response must contact Min_SE - if not - just ignore
968 // ?slg? callback?
969 transition(Connected);
970 mProposedLocalSdp.reset();
971 mProposedEncryptionLevel = DialogUsageManager::None;
972 }
973 break;
974
975 case OnUpdateRejected:
976 // !jf! - callback?
977 mProposedLocalSdp.reset();
978 mProposedEncryptionLevel = DialogUsageManager::None;
979 transition(Connected);
980 break;
981
982 case OnGeneralFailure:
983 sendBye();
984 transition(Terminated);
985 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
986 break;
987
988 default:
989 dispatchOthers(msg);
990 break;
991 }
992 }
993
994 void
995 InviteSession::dispatchSentReinvite(const SipMessage& msg)
996 {
997 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
998 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
999
1000 switch (toEvent(msg, sdp.get()))
1001 {
1002 case OnInvite:
1003 case OnInviteReliable:
1004 case OnInviteOffer:
1005 case OnInviteReliableOffer:
1006 case OnUpdate:
1007 case OnUpdateOffer:
1008 {
1009 SipMessage response;
1010 mDialog.makeResponse(response, msg, 491);
1011 BaseUsage::send(response);
1012 break;
1013 }
1014
1015 case On1xx:
1016 case On1xxEarly:
1017 // Some UA's send a 100 response to a ReInvite - just ignore it
1018 break;
1019
1020 case On2xxAnswer:
1021 case On2xxOffer: // !slg! doesn't really make sense
1022 {
1023 transition(Connected);
1024 handleSessionTimerResponse(msg);
1025 setCurrentLocalSdp(msg);
1026
1027 // !jf! I need to potentially include an answer in the ACK here
1028 sendAck(mLastSessionModification);
1029 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1030
1031 if (mSessionRefreshReInvite)
1032 {
1033 mSessionRefreshReInvite = false;
1034
1035 MD5Stream currentRemote;
1036 currentRemote<< *mCurrentRemoteSdp;
1037 MD5Stream newRemote;
1038 newRemote << *sdp;
1039 bool changed = currentRemote.getHex() != newRemote.getHex();
1040
1041 if (changed)
1042 {
1043 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
1044 handler->onRemoteSdpChanged(getSessionHandle(), msg, *sdp);
1045 }
1046 }
1047 else
1048 {
1049 handler->onAnswer(getSessionHandle(), msg, *sdp);
1050 }
1051
1052 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1053 // the ACK when a 200I is received? If yes, then I need to store all
1054 // ACK messages for 64*T1
1055 break;
1056 }
1057 case On2xx:
1058 sendAck(mLastSessionModification);
1059 transition(Connected);
1060 handleSessionTimerResponse(msg);
1061 handler->onIllegalNegotiation(getSessionHandle(), msg);
1062 mProposedLocalSdp.reset();
1063 mProposedEncryptionLevel = DialogUsageManager::None;
1064 break;
1065
1066 case On422Invite:
1067 if(msg.exists(h_MinSE))
1068 {
1069 // Change interval to min from 422 response
1070 mSessionInterval = msg.header(h_MinSE).value();
1071 mMinSE = mSessionInterval;
1072 sessionRefresh();
1073 }
1074 else
1075 {
1076 // Response must contact Min_SE - if not - just ignore
1077 // ?slg? callback?
1078 transition(Connected);
1079 mProposedLocalSdp.reset();
1080 mProposedEncryptionLevel = DialogUsageManager::None;
1081 }
1082 break;
1083
1084 case On491Invite:
1085 transition(SentReinviteGlare);
1086 start491Timer();
1087 break;
1088
1089 case OnGeneralFailure:
1090 sendBye();
1091 transition(Terminated);
1092 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1093 break;
1094
1095 case OnInviteFailure:
1096 case On487Invite:
1097 case On489Invite:
1098 transition(Connected);
1099 mProposedLocalSdp.reset();
1100 handler->onOfferRejected(getSessionHandle(), &msg);
1101 break;
1102
1103 default:
1104 dispatchOthers(msg);
1105 break;
1106 }
1107 }
1108
1109 void
1110 InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1111 {
1112 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1113 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1114
1115 switch (toEvent(msg, sdp.get()))
1116 {
1117 case OnInvite:
1118 case OnInviteReliable:
1119 case OnInviteOffer:
1120 case OnInviteReliableOffer:
1121 case OnUpdate:
1122 case OnUpdateOffer:
1123 {
1124 SipMessage response;
1125 mDialog.makeResponse(response, msg, 491);
1126 BaseUsage::send(response);
1127 break;
1128 }
1129
1130 case On1xx:
1131 case On1xxEarly:
1132 // Some UA's send a 100 response to a ReInvite - just ignore it
1133 break;
1134
1135 case On2xxAnswer: // !slg! doesn't really make sense
1136 case On2xxOffer:
1137 {
1138 transition(SentReinviteAnswered);
1139 handleSessionTimerResponse(msg);
1140 // mLastSessionModification = msg; // ?slg? why are we storing 200's?
1141 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1142 mProposedRemoteSdp = InviteSession::makeSdp(*sdp);
1143 handler->onOffer(getSessionHandle(), msg, *sdp);
1144
1145 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1146 // the ACK when a 200I is received? If yes, then I need to store all
1147 // ACK messages for 64*T1
1148 break;
1149 }
1150
1151 case On2xx:
1152 sendAck(mLastSessionModification);
1153 transition(Connected);
1154 handleSessionTimerResponse(msg);
1155 handler->onIllegalNegotiation(getSessionHandle(), msg);
1156 mProposedLocalSdp.reset();
1157 mProposedEncryptionLevel = DialogUsageManager::None;
1158 break;
1159
1160 case On422Invite:
1161 if(msg.exists(h_MinSE))
1162 {
1163 // Change interval to min from 422 response
1164 mSessionInterval = msg.header(h_MinSE).value();
1165 mMinSE = mSessionInterval;
1166 setSessionTimerHeaders(mLastSessionModification);
1167 send(mLastSessionModification);
1168 }
1169 else
1170 {
1171 // Response must contact Min_SE - if not - just ignore
1172 // ?slg? callback?
1173 transition(Connected);
1174 mProposedLocalSdp.reset();
1175 mProposedEncryptionLevel = DialogUsageManager::None;
1176 }
1177 break;
1178
1179 case On491Invite:
1180 transition(SentReinviteNoOfferGlare);
1181 start491Timer();
1182 break;
1183
1184 case OnGeneralFailure:
1185 sendBye();
1186 transition(Terminated);
1187 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1188 break;
1189
1190 case OnInviteFailure:
1191 case On487Invite:
1192 case On489Invite:
1193 transition(Connected);
1194 mProposedLocalSdp.reset();
1195 handler->onOfferRejected(getSessionHandle(), &msg);
1196 break;
1197
1198 default:
1199 dispatchOthers(msg);
1200 break;
1201 }
1202 }
1203
1204 void
1205 InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1206 {
1207 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1208 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1209
1210 switch (toEvent(msg, sdp.get()))
1211 {
1212 case OnInvite:
1213 case OnInviteReliable:
1214 case OnInviteOffer:
1215 case OnInviteReliableOffer:
1216 case OnUpdate:
1217 case OnUpdateOffer:
1218 {
1219 SipMessage response;
1220 mDialog.makeResponse(response, msg, 491);
1221 BaseUsage::send(response);
1222 break;
1223 }
1224 case OnAckAnswer:
1225 transition(Connected);
1226 setCurrentLocalSdp(msg);
1227 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
1228 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1229 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1230 handler->onAnswer(getSessionHandle(), msg, *sdp);
1231 break;
1232 case OnAck:
1233 transition(Connected);
1234 mProposedLocalSdp.reset();
1235 mProposedEncryptionLevel = DialogUsageManager::None;
1236 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1237 //!dcm! -- should this be onIllegalNegotiation?
1238 handler->onOfferRejected(getSessionHandle(), &msg);
1239 break;
1240 default:
1241 dispatchOthers(msg);
1242 break;
1243 }
1244 }
1245
1246 void
1247 InviteSession::dispatchGlare(const SipMessage& msg)
1248 {
1249 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1250 MethodTypes method = msg.header(h_CSeq).method();
1251 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1252 {
1253 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1254 handler->onOfferRejected(getSessionHandle(), &msg);
1255 dispatchConnected(msg); // act as if we received message in Connected state
1256 }
1257 else
1258 {
1259 dispatchOthers(msg);
1260 }
1261 }
1262
1263 void
1264 InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1265 {
1266 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1267 MethodTypes method = msg.header(h_CSeq).method();
1268 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1269 {
1270 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1271 handler->onOfferRequestRejected(getSessionHandle(), msg);
1272 dispatchConnected(msg); // act as if we received message in Connected state
1273 }
1274 else
1275 {
1276 dispatchOthers(msg);
1277 }
1278 }
1279
1280 void
1281 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1282 {
1283 MethodTypes method = msg.header(h_CSeq).method();
1284 if (method == INVITE || method == UPDATE)
1285 {
1286 // Means that the UAC has sent us a second reINVITE or UPDATE before we
1287 // responded to the first one. Bastard!
1288 SipMessage response;
1289 mDialog.makeResponse(response, msg, 500);
1290 response.header(h_RetryAfter).value() = Random::getRandom() % 10;
1291 send(response);
1292 }
1293 else
1294 {
1295 dispatchOthers(msg);
1296 }
1297 }
1298
1299
1300 void
1301 InviteSession::dispatchAnswered(const SipMessage& msg)
1302 {
1303 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1304 {
1305 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1306 transition(Connected);
1307 }
1308 else
1309 {
1310 dispatchOthers(msg);
1311 }
1312 }
1313
1314 void
1315 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1316 {
1317 dispatchOthers(msg);
1318 }
1319
1320 void
1321 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1322 {
1323 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1324 {
1325 assert(mProposedLocalSdp.get());
1326 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1327 provideProposedOffer();
1328 }
1329 else
1330 {
1331 dispatchOthers(msg);
1332 }
1333 }
1334
1335 void
1336 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1337 {
1338 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1339 {
1340 assert(mProposedLocalSdp.get());
1341 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1342 requestOffer();
1343 }
1344 else
1345 {
1346 dispatchOthers(msg);
1347 }
1348 }
1349
1350 void
1351 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1352 {
1353 if (msg.isResponse() &&
1354 msg.header(h_CSeq).method() == INVITE)
1355 {
1356 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1357 {
1358 // !jf! Need to include the answer here.
1359 sendAck(mLastSessionModification);
1360 }
1361 sendBye();
1362 transition(Terminated);
1363 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1364 }
1365 }
1366
1367 void
1368 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1369 {
1370 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
1371
1372 switch (toEvent(msg, sdp.get()))
1373 {
1374 case OnAck:
1375 case OnAckAnswer:
1376 {
1377 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1378
1379 sendBye();
1380 transition(Terminated);
1381 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
1382 break;
1383 }
1384
1385 default:
1386 break;
1387 }
1388 }
1389
1390 void
1391 InviteSession::dispatchTerminated(const SipMessage& msg)
1392 {
1393 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
1394
1395 if (msg.isRequest())
1396 {
1397 SipMessage response;
1398 mDialog.makeResponse(response, msg, 481);
1399 send(response);
1400
1401 // !jf! means the peer sent BYE while we are waiting for response to BYE
1402 //mDum.destroy(this);
1403 }
1404 else
1405 {
1406 mDum.destroy(this);
1407 }
1408 }
1409
1410 void
1411 InviteSession::dispatchOthers(const SipMessage& msg)
1412 {
1413 // handle OnGeneralFailure
1414 // handle OnRedirect
1415
1416 switch (msg.header(h_CSeq).method())
1417 {
1418 case PRACK:
1419 dispatchPrack(msg);
1420 break;
1421 case CANCEL:
1422 dispatchCancel(msg);
1423 break;
1424 case BYE:
1425 dispatchBye(msg);
1426 break;
1427 case INFO:
1428 dispatchInfo(msg);
1429 break;
1430 case MESSAGE:
1431 dispatchMessage(msg);
1432 break;
1433 case ACK:
1434 // Ignore duplicate ACKs from 2xx reTransmissions
1435 break;
1436 default:
1437 // handled in Dialog
1438 WarningLog (<< "DUM delivered a "
1439 << msg.header(h_CSeq).unknownMethodName()
1440 << " to the InviteSession "
1441 << endl
1442 << msg);
1443 assert(0);
1444 break;
1445 }
1446 }
1447
1448 void
1449 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
1450 {
1451 assert(msg.isRequest());
1452 assert(msg.header(h_CSeq).method() == INVITE);
1453
1454 // If we get an INVITE request from the wire and we are not in
1455 // Connected state, reject the request and send a BYE
1456 SipMessage response;
1457 mDialog.makeResponse(response, msg, 400); // !jf! what code to use?
1458 InfoLog (<< "Sending " << response.brief());
1459 send(response);
1460
1461 sendBye();
1462 transition(Terminated);
1463 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1464 }
1465
1466 void
1467 InviteSession::dispatchPrack(const SipMessage& msg)
1468 {
1469 assert(msg.header(h_CSeq).method() == PRACK);
1470 if(msg.isRequest())
1471 {
1472 SipMessage rsp;
1473 mDialog.makeResponse(rsp, msg, 481);
1474 send(rsp);
1475
1476 sendBye();
1477 // !jf! should we make some other callback here
1478 transition(Terminated);
1479 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1480 }
1481 else
1482 {
1483 // ignore. could be PRACK/200
1484 }
1485 }
1486
1487 void
1488 InviteSession::dispatchCancel(const SipMessage& msg)
1489 {
1490 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1491 assert(msg.header(h_CSeq).method() == CANCEL);
1492 if(msg.isRequest())
1493 {
1494 SipMessage rsp;
1495 mDialog.makeResponse(rsp, msg, 200);
1496 send(rsp);
1497
1498 sendBye();
1499 // !jf! should we make some other callback here
1500 transition(Terminated);
1501 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1502 }
1503 else
1504 {
1505 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1506 assert(0);
1507 }
1508 }
1509
1510 void
1511 InviteSession::dispatchBye(const SipMessage& msg)
1512 {
1513 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1514
1515 if (msg.isRequest())
1516 {
1517
1518 SipMessage rsp;
1519 InfoLog (<< "Received " << msg.brief());
1520 mDialog.makeResponse(rsp, msg, 200);
1521 send(rsp);
1522
1523 // !jf! should we make some other callback here
1524 transition(Terminated);
1525 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1526 mDum.destroy(this);
1527 }
1528 else
1529 {
1530 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1531 assert(0);
1532 }
1533 }
1534
1535 void
1536 InviteSession::dispatchInfo(const SipMessage& msg)
1537 {
1538 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1539 if (msg.isRequest())
1540 {
1541 InfoLog (<< "Received " << msg.brief());
1542 mDialog.makeResponse(mLastNitResponse, msg, 200);
1543 handler->onInfo(getSessionHandle(), msg);
1544 }
1545 else
1546 {
1547 assert(mNitState == NitProceeding);
1548 mNitState = NitComplete;
1549 //!dcm! -- toss away 1xx to an info?
1550 if (msg.header(h_StatusLine).statusCode() >= 300)
1551 {
1552 handler->onInfoFailure(getSessionHandle(), msg);
1553 }
1554 else if (msg.header(h_StatusLine).statusCode() >= 200)
1555 {
1556 handler->onInfoSuccess(getSessionHandle(), msg);
1557 }
1558 }
1559 }
1560
1561 void
1562 InviteSession::acceptNIT(int statusCode)
1563 {
1564 if (statusCode / 100 != 2)
1565 {
1566 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
1567 }
1568
1569 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1570 Helper::getResponseCodeReason(statusCode, mLastNitResponse.header(h_StatusLine).reason());
1571 BaseUsage::send(mLastNitResponse);
1572 }
1573
1574 void
1575 InviteSession::rejectNIT(int statusCode)
1576 {
1577 if (statusCode < 400)
1578 {
1579 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
1580 }
1581 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1582 Helper::getResponseCodeReason(statusCode, mLastNitResponse.header(h_StatusLine).reason());
1583 BaseUsage::send(mLastNitResponse);
1584 }
1585
1586 void
1587 InviteSession::dispatchMessage(const SipMessage& msg)
1588 {
1589 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1590 if (msg.isRequest())
1591 {
1592 InfoLog (<< "Received " << msg.brief());
1593 mDialog.makeResponse(mLastNitResponse, msg, 200);
1594 mLastNitResponse.header(h_Contacts).clear();
1595 handler->onMessage(getSessionHandle(), msg);
1596 }
1597 else
1598 {
1599 assert(mNitState == NitProceeding);
1600 mNitState = NitComplete;
1601 //!dcm! -- toss away 1xx to an message?
1602 if (msg.header(h_StatusLine).statusCode() >= 300)
1603 {
1604 handler->onMessageFailure(getSessionHandle(), msg);
1605 }
1606 else if (msg.header(h_StatusLine).statusCode() >= 200)
1607 {
1608 handler->onMessageSuccess(getSessionHandle(), msg);
1609 }
1610 }
1611 }
1612
1613 void
1614 InviteSession::startRetransmit200Timer()
1615 {
1616 mCurrentRetransmit200 = Timer::T1;
1617 int seq = mLastSessionModification.header(h_CSeq).sequence();
1618 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
1619 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
1620 }
1621
1622 void
1623 InviteSession::start491Timer()
1624 {
1625 int seq = mLastSessionModification.header(h_CSeq).sequence();
1626 int timer = Random::getRandom() % 4000;
1627 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1628 }
1629
1630 void
1631 InviteSession::setSessionTimerHeaders(SipMessage &msg)
1632 {
1633 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
1634 {
1635 msg.header(h_SessionExpires).value() = mSessionInterval;
1636 if(msg.isRequest())
1637 {
1638 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
1639 }
1640 else
1641 {
1642 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
1643 }
1644 msg.header(h_MinSE).value() = mMinSE;
1645 }
1646 else
1647 {
1648 msg.remove(h_SessionExpires);
1649 msg.remove(h_MinSE);
1650 }
1651 }
1652
1653 void
1654 InviteSession::sessionRefresh()
1655 {
1656 if (updateMethodSupported())
1657 {
1658 transition(SentUpdate);
1659 mDialog.makeRequest(mLastSessionModification, UPDATE);
1660 mLastSessionModification.releaseContents(); // Don't send SDP
1661 }
1662 else
1663 {
1664 transition(SentReinvite);
1665 mDialog.makeRequest(mLastSessionModification, INVITE);
1666 InviteSession::setSdp(mLastSessionModification, mCurrentLocalSdp.get());
1667 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
1668 mSessionRefreshReInvite = true;
1669 }
1670 mLastSessionModification.remove(h_ProxyAuthorizations); // remove remote credentials.
1671 setSessionTimerHeaders(mLastSessionModification);
1672
1673 InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief());
1674 DumHelper::setOutgoingEncryptionLevel(mLastSessionModification, mCurrentEncryptionLevel);
1675 send(mLastSessionModification);
1676 }
1677
1678 void
1679 InviteSession::setSessionTimerPreferences()
1680 {
1681 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
1682 if(mSessionInterval != 0)
1683 {
1684 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
1685 mSessionInterval = resipMax(mMinSE, mSessionInterval);
1686 }
1687 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1688 {
1689 case Profile::PreferLocalRefreshes:
1690 mSessionRefresher = true; // Default refresher is Local
1691 break;
1692 case Profile::PreferRemoteRefreshes:
1693 mSessionRefresher = false; // Default refresher is Remote
1694 break;
1695 case Profile::PreferUASRefreshes:
1696 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
1697 break;
1698 case Profile::PreferUACRefreshes:
1699 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
1700 break;
1701 }
1702 }
1703
1704 void
1705 InviteSession::startSessionTimer()
1706 {
1707 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
1708 {
1709 // Check if we are the refresher
1710 if(mSessionRefresher)
1711 {
1712 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
1713 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1714 }
1715 else
1716 {
1717 // 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)
1718 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1719 }
1720 }
1721 else // Session Interval less than 90 - consider timers disabled
1722 {
1723 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1724 }
1725 }
1726
1727 void
1728 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
1729 {
1730 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
1731
1732 // If session timers are locally supported then handle response
1733 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1734 {
1735 setSessionTimerPreferences();
1736
1737 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
1738 && !msg.exists(h_SessionExpires))
1739 {
1740 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
1741 mSessionInterval = 0;
1742 }
1743 // Process Session Timer headers
1744 else if(msg.exists(h_SessionExpires))
1745 {
1746 mSessionInterval = msg.header(h_SessionExpires).value();
1747 if(msg.header(h_SessionExpires).exists(p_refresher))
1748 {
1749 // Remote end specified refresher preference
1750 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
1751 }
1752 }
1753 else
1754 {
1755 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
1756 // - we are free to use our SessionInterval settings (set above as a default)
1757 // If far end doesn't support then refresher must be local
1758 mSessionRefresher = true;
1759 }
1760
1761 // Update MinSE if specified and longer than current value
1762 if(msg.exists(h_MinSE))
1763 {
1764 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
1765 }
1766
1767 startSessionTimer();
1768 }
1769 }
1770
1771 void
1772 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1773 {
1774 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1775
1776 // If session timers are locally supported then add necessary headers to response
1777 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1778 {
1779 setSessionTimerPreferences();
1780
1781 // Check if far-end supports
1782 bool farEndSupportsTimer = false;
1783 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
1784 {
1785 farEndSupportsTimer = true;
1786 if(request.exists(h_SessionExpires))
1787 {
1788 // Use Session Interval requested by remote - if none then use local settings
1789 mSessionInterval = request.header(h_SessionExpires).value();
1790 if(request.header(h_SessionExpires).exists(p_refresher))
1791 {
1792 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1793 }
1794 }
1795
1796 // Update MinSE if specified and longer than current value
1797 if(request.exists(h_MinSE))
1798 {
1799 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
1800 }
1801 }
1802 else
1803 {
1804 // If far end doesn't support then refresher must be local
1805 mSessionRefresher = true;
1806 }
1807
1808 // Add Session-Expires to response if required
1809 if(mSessionInterval >= 90)
1810 {
1811 if(farEndSupportsTimer)
1812 {
1813 // If far end supports session-timer then require it, if not already present
1814 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
1815 {
1816 response.header(h_Requires).push_back(Token(Symbols::Timer));
1817 }
1818 }
1819 setSessionTimerHeaders(response);
1820 }
1821
1822 startSessionTimer();
1823 }
1824 }
1825
1826 Data
1827 InviteSession::toData(State state)
1828 {
1829 switch (state)
1830 {
1831 case Undefined:
1832 return "InviteSession::Undefined";
1833 case Connected:
1834 return "InviteSession::Connected";
1835 case SentUpdate:
1836 return "InviteSession::SentUpdate";
1837 case SentUpdateGlare:
1838 return "InviteSession::SentUpdateGlare";
1839 case SentReinvite:
1840 return "InviteSession::SentReinvite";
1841 case SentReinviteGlare:
1842 return "InviteSession::SentReinviteGlare";
1843 case SentReinviteNoOffer:
1844 return "InviteSession::SentReinviteNoOffer";
1845 case SentReinviteAnswered:
1846 return "InviteSession::SentReinviteAnswered";
1847 case SentReinviteNoOfferGlare:
1848 return "InviteSession::SentReinviteNoOfferGlare";
1849 case ReceivedUpdate:
1850 return "InviteSession::ReceivedUpdate";
1851 case ReceivedReinvite:
1852 return "InviteSession::ReceivedReinvite";
1853 case ReceivedReinviteNoOffer:
1854 return "InviteSession::ReceivedReinviteNoOffer";
1855 case ReceivedReinviteSentOffer:
1856 return "InviteSession::ReceivedReinviteSentOffer";
1857 case Answered:
1858 return "InviteSession::Answered";
1859 case WaitingToOffer:
1860 return "InviteSession::WaitingToOffer";
1861 case WaitingToRequestOffer:
1862 return "InviteSession::WaitingToRequestOffer";
1863 case WaitingToTerminate:
1864 return "InviteSession::WaitingToTerminate";
1865 case WaitingToHangup:
1866 return "InviteSession::WaitingToHangup";
1867 case Terminated:
1868 return "InviteSession::Terminated";
1869
1870 case UAC_Start:
1871 return "UAC_Start";
1872 case UAS_Offer:
1873 return "UAS_Offer";
1874 case UAS_OfferProvidedAnswer:
1875 return "UAS_OfferProvidedAnswer";
1876 case UAS_EarlyOffer:
1877 return "UAS_EarlyOffer";
1878 case UAS_EarlyProvidedAnswer:
1879 return "UAS_EarlyProvidedAnswer";
1880 case UAS_NoOffer:
1881 return "UAS_NoOffer";
1882 case UAS_ProvidedOffer:
1883 return "UAS_ProvidedOffer";
1884 case UAS_EarlyNoOffer:
1885 return "UAS_EarlyNoOffer";
1886 case UAS_EarlyProvidedOffer:
1887 return "UAS_EarlyProvidedOffer";
1888 case UAS_Accepted:
1889 return "UAS_Accepted";
1890 case UAS_WaitingToOffer:
1891 return "UAS_WaitingToOffer";
1892 case UAS_AcceptedWaitingAnswer:
1893 return "UAS_AcceptedWaitingAnswer";
1894 case UAC_Early:
1895 return "UAC_Early";
1896 case UAC_EarlyWithOffer:
1897 return "UAC_EarlyWithOffer";
1898 case UAC_EarlyWithAnswer:
1899 return "UAC_EarlyWithAnswer";
1900 case UAC_Answered:
1901 return "UAC_Answered";
1902 case UAC_SentUpdateEarly:
1903 return "UAC_SentUpdateEarly";
1904 case UAC_SentUpdateConnected:
1905 return "UAC_SentUpdateConnected";
1906 case UAC_ReceivedUpdateEarly:
1907 return "UAC_ReceivedUpdateEarly";
1908 case UAC_SentAnswer:
1909 return "UAC_SentAnswer";
1910 case UAC_QueuedUpdate:
1911 return "UAC_QueuedUpdate";
1912 case UAC_Cancelled:
1913 return "UAC_Cancelled";
1914
1915 case UAS_Start:
1916 return "UAS_Start";
1917 case UAS_OfferReliable:
1918 return "UAS_OfferReliable";
1919 case UAS_NoOfferReliable:
1920 return "UAS_NoOfferReliable";
1921 case UAS_FirstSentOfferReliable:
1922 return "UAS_FirstSentOfferReliable";
1923 case UAS_FirstEarlyReliable:
1924 return "UAS_FirstEarlyReliable";
1925 case UAS_EarlyReliable:
1926 return "UAS_EarlyReliable";
1927 case UAS_SentUpdate:
1928 return "UAS_SentUpdate";
1929 case UAS_SentUpdateAccepted:
1930 return "UAS_SentUpdateAccepted";
1931 case UAS_ReceivedUpdate:
1932 return "UAS_ReceivedUpdate";
1933 case UAS_ReceivedUpdateWaitingAnswer:
1934 return "UAS_ReceivedUpdateWaitingAnswer";
1935 case UAS_WaitingToTerminate:
1936 return "UAS_WaitingToTerminate";
1937 case UAS_WaitingToHangup:
1938 return "UAS_WaitingToHangup";
1939 }
1940 assert(0);
1941 return "Undefined";
1942 }
1943
1944
1945 void
1946 InviteSession::transition(State target)
1947 {
1948 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1949 mState = target;
1950 }
1951
1952 bool
1953 InviteSession::isReliable(const SipMessage& msg)
1954 {
1955 // Ensure supported both locally and remotely
1956 return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&
1957 mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));
1958 }
1959
1960 std::auto_ptr<SdpContents>
1961 InviteSession::getSdp(const SipMessage& msg)
1962 {
1963 // !jf! this code doesn't yet work - definitely if USE_SSL=false
1964 //Helper::ContentsSecAttrs attrs = Helper::extractFromPkcs7(msg, mDum.getSecurity());
1965 //return std::auto_ptr<SdpContents>(dynamic_cast<SdpContents*>(attrs.mContents.get()));
1966 SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());
1967 if (sdp)
1968 {
1969 SdpContents* cloned = static_cast<SdpContents*>(sdp->clone());
1970 return std::auto_ptr<SdpContents>(cloned);
1971 }
1972 else
1973 {
1974 static std::auto_ptr<SdpContents> empty;
1975 return empty;
1976 }
1977 }
1978
1979 std::auto_ptr<SdpContents>
1980 InviteSession::makeSdp(const SdpContents& sdp)
1981 {
1982 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
1983 }
1984
1985 auto_ptr<Contents>
1986 InviteSession::makeSdp(const SdpContents& sdp,
1987 const SdpContents* alternative)
1988 {
1989 if (alternative)
1990 {
1991 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
1992 mac->parts().push_back(alternative->clone());
1993 mac->parts().push_back(sdp.clone());
1994 return auto_ptr<Contents>(mac);
1995 }
1996 else
1997 {
1998 return auto_ptr<Contents>(sdp.clone());
1999 }
2000 }
2001
2002 void
2003 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
2004 {
2005 // !jf! should deal with multipart here
2006
2007 // This will clone the sdp since the InviteSession also wants to keep its own
2008 // copy of the sdp around for the application to access
2009 if (alternative)
2010 {
2011 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2012 mac->parts().push_back(alternative->clone());
2013 mac->parts().push_back(sdp.clone());
2014 msg.setContents(auto_ptr<Contents>(mac));
2015 }
2016 else
2017 {
2018 msg.setContents(&sdp);
2019 }
2020 }
2021
2022 void
2023 InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
2024 {
2025 assert(sdp);
2026 msg.setContents(sdp);
2027 }
2028
2029 void
2030 InviteSession::provideProposedOffer()
2031 {
2032 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2033 {
2034 provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
2035 mProposedEncryptionLevel,
2036 dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
2037 }
2038 else
2039 {
2040 provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
2041 }
2042 }
2043
2044 InviteSession::Event
2045 InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
2046 {
2047 MethodTypes method = msg.header(h_CSeq).method();
2048 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2049 bool reliable = isReliable(msg);
2050 bool sentOffer = mProposedLocalSdp.get();
2051
2052 if (code == 481 || code == 408)
2053 {
2054 return OnGeneralFailure;
2055 }
2056 else if (code >= 300 && code <= 399)
2057 {
2058 return OnRedirect;
2059 }
2060 else if (method == INVITE && code == 0)
2061 {
2062 if (sdp)
2063 {
2064 if (reliable)
2065 {
2066 return OnInviteReliableOffer;
2067 }
2068 else
2069 {
2070 return OnInviteOffer;
2071 }
2072 }
2073 else
2074 {
2075 if (reliable)
2076 {
2077 return OnInviteReliable;
2078 }
2079 else
2080 {
2081 return OnInvite;
2082 }
2083 }
2084 }
2085 else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer.
2086 {
2087 if (reliable)
2088 {
2089 if (sdp)
2090 {
2091 if (sentOffer)
2092 {
2093 return On1xxAnswer;
2094 }
2095 else
2096 {
2097 return On1xxOffer;
2098 }
2099 }
2100 else
2101 {
2102 return On1xx;
2103 }
2104 }
2105 else
2106 {
2107 if (sdp)
2108 {
2109 return On1xxEarly;
2110 }
2111 else
2112 {
2113 return On1xx;
2114 }
2115 }
2116 }
2117 else if (method == INVITE && code >= 200 && code < 300)
2118 {
2119 if (sdp)
2120 {
2121 if (sentOffer)
2122 {
2123 return On2xxAnswer;
2124 }
2125 else
2126 {
2127 return On2xxOffer;
2128 }
2129 }
2130 else
2131 {
2132 return On2xx;
2133 }
2134 }
2135 else if (method == INVITE && code == 422)
2136 {
2137 return On422Invite;
2138 }
2139 else if (method == INVITE && code == 487)
2140 {
2141 return On487Invite;
2142 }
2143 else if (method == INVITE && code == 489)
2144 {
2145 return On489Invite;
2146 }
2147 else if (method == INVITE && code == 491)
2148 {
2149 return On491Invite;
2150 }
2151 else if (method == INVITE && code >= 400)
2152 {
2153 return OnInviteFailure;
2154 }
2155 else if (method == ACK)
2156 {
2157 if (sdp)
2158 {
2159 return OnAckAnswer;
2160 }
2161 else
2162 {
2163 return OnAck;
2164 }
2165 }
2166 else if (method == CANCEL && code == 0)
2167 {
2168 return OnCancel;
2169 }
2170 else if (method == CANCEL && code / 200 == 1)
2171 {
2172 return On200Cancel;
2173 }
2174 else if (method == CANCEL && code >= 400)
2175 {
2176 return OnCancelFailure;
2177 }
2178 else if (method == BYE && code == 0)
2179 {
2180 return OnBye;
2181 }
2182 else if (method == BYE && code / 200 == 1)
2183 {
2184 return On200Bye;
2185 }
2186 else if (method == PRACK && code == 0)
2187 {
2188 return OnPrack;
2189 }
2190 else if (method == PRACK && code / 200 == 1)
2191 {
2192 return On200Prack;
2193 }
2194 else if (method == UPDATE && code == 0)
2195 {
2196 if (sdp)
2197 {
2198 return OnUpdateOffer;
2199 }
2200 else
2201 {
2202 return OnUpdate;
2203 }
2204 }
2205 else if (method == UPDATE && code / 200 == 1)
2206 {
2207 return On200Update;
2208 }
2209 else if (method == UPDATE && code == 422)
2210 {
2211 return On422Update;
2212 }
2213 else if (method == UPDATE && code == 489)
2214 {
2215 return On489Update;
2216 }
2217 else if (method == UPDATE && code == 491)
2218 {
2219 return On491Update;
2220 }
2221 else if (method == UPDATE && code >= 400)
2222 {
2223 return OnUpdateRejected;
2224 }
2225 else
2226 {
2227 //assert(0); // dispatchOthers will throw if the message type is really unknown
2228 return Unknown;
2229 }
2230 }
2231
2232 void InviteSession::sendAck(SipMessage& originalInvite, const SdpContents *sdp)
2233 {
2234 SipMessage ack;
2235
2236 assert(mAcks.count(originalInvite.header(h_CSeq).sequence()) == 0);
2237
2238 mDialog.makeRequest(ack, ACK);
2239
2240 // Copy Authorization, Proxy Authorization headers and CSeq from original Invite
2241 if(originalInvite.exists(h_Authorizations))
2242 {
2243 ack.header(h_Authorizations) = originalInvite.header(h_Authorizations);
2244 }
2245 if(originalInvite.exists(h_ProxyAuthorizations))
2246 {
2247 ack.header(h_ProxyAuthorizations) = originalInvite.header(h_ProxyAuthorizations);
2248 }
2249 ack.header(h_CSeq).sequence() = originalInvite.header(h_CSeq).sequence();
2250
2251 if(sdp != 0)
2252 {
2253 setSdp(ack, *sdp);
2254 }
2255 mAcks[ack.header(h_CSeq).sequence()] = ack;
2256 mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack.header(h_CSeq).sequence());
2257
2258 InfoLog (<< "Sending " << ack.brief());
2259 send(ack);
2260 }
2261
2262 void InviteSession::sendBye()
2263 {
2264 SipMessage bye;
2265 mDialog.makeRequest(bye, BYE);
2266 Data reason;
2267 if (mEndReason != NotSpecified)
2268 {
2269 reason = getEndReasonString(mEndReason);
2270 bye.header(h_Reasons).push_back(Token(reason));
2271 }
2272
2273 InfoLog (<< myAddr() << " Sending BYE " << reason);
2274 send(bye);
2275 }
2276
2277 DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg)
2278 {
2279 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
2280 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
2281 if (secAttr)
2282 {
2283 SignatureStatus sig = secAttr->getSignatureStatus();
2284 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
2285 bool encrypted = secAttr->isEncrypted();
2286 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
2287 else if (encrypted) level = DialogUsageManager::Encrypt;
2288 else if (sign) level = DialogUsageManager::Sign;
2289 }
2290 return level;
2291 }
2292
2293 void InviteSession::setCurrentLocalSdp(const SipMessage& msg)
2294 {
2295 assert(mProposedLocalSdp.get());
2296 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
2297 {
2298 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
2299 {
2300 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone()));
2301 }
2302 else
2303 {
2304 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone()));
2305 }
2306 }
2307 else
2308 {
2309 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
2310 }
2311 mProposedLocalSdp.reset();
2312 }
2313
2314 void InviteSession::onReadyToSend(SipMessage& msg)
2315 {
2316 mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
2317 }
2318
2319 void InviteSession::send(SipMessage& msg)
2320 {
2321 if (msg.isRequest())
2322 {
2323 // give app an chance to adorn the message.
2324 onReadyToSend(msg);
2325 }
2326
2327 mDialog.send(msg);
2328 }
2329
2330 /* ====================================================================
2331 * The Vovida Software License, Version 1.0
2332 *
2333 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2334 *
2335 * Redistribution and use in source and binary forms, with or without
2336 * modification, are permitted provided that the following conditions
2337 * are met:
2338 *
2339 * 1. Redistributions of source code must retain the above copyright
2340 * notice, this list of conditions and the following disclaimer.
2341 *
2342 * 2. Redistributions in binary form must reproduce the above copyright
2343 * notice, this list of conditions and the following disclaimer in
2344 * the documentation and/or other materials provided with the
2345
2346 * distribution.
2347 *
2348 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2349 * and "Vovida Open Communication Application Library (VOCAL)" must
2350 * not be used to endorse or promote products derived from this
2351 * software without prior written permission. For written
2352 * permission, please contact vocal@vovida.org.
2353 *
2354 * 4. Products derived from this software may not be called "VOCAL", nor
2355 * may "VOCAL" appear in their name, without prior written
2356 * permission of Vovida Networks, Inc.
2357 *
2358 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2359 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2360 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2361 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2362 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2363 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2364 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2365 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2366 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2367 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2368 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2369 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2370 * DAMAGE.
2371 *
2372 * ====================================================================
2373 *
2374 * This software consists of voluntary contributions made by Vovida
2375 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2376 * Inc. For more information on Vovida Networks, Inc., please see
2377 * <http://www.vovida.org/>.
2378 *
2379 */
2380

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27