reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ServerInviteSession.cxx
Go to the documentation of this file.
13#include "rutil/Random.hxx"
14#include "rutil/Logger.hxx"
15#include "rutil/compat.hxx"
17
18#include <utility>
19
20using namespace resip;
21
22#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
23
25 : InviteSession(dum, dialog),
26 mFirstRequest(request),
27 m1xx(new SipMessage),
28 mCurrentRetransmit1xxSeq(0),
29 mLocalRSeq(0),
30 mAnswerSentReliably(false)
31{
32 resip_assert(request.isRequest());
33 mState = UAS_Start;
34}
35
41
42void
43ServerInviteSession::redirect(const NameAddrs& contacts, int code)
44{
45 InfoLog (<< toData(mState) << ": redirect(" << code << ")"); // -> " << contacts);
46
47 switch (mState)
48 {
50 case UAS_EarlyOffer:
56 case UAS_NoOffer:
62 case UAS_Offer:
67 case UAS_SentUpdate:
68 {
69 // !jf! the cleanup for 3xx may be a bit strange if we are in the middle of
70 // an offer/answer exchange with PRACK.
71 // e.g. we sent 183 reliably and then 302 before PRACK was received. Ideally,
72 // we should send 200PRACK
73 auto response = std::make_shared<SipMessage>();
74 mDialog.makeResponse(*response, mFirstRequest, code);
75 response->header(h_Contacts) = contacts;
76 send(response);
77
78 if (mDum.mDialogEventStateManager)
79 {
80 mDum.mDialogEventStateManager->onTerminated(mDialog, *response, InviteSessionHandler::Rejected);
81 }
82
84
86 mDum.destroy(this);
87 break;
88 }
89
90 case UAS_Accepted:
96 case UAS_Start:
97 default:
98 resip_assert(0);
99 throw UsageUseException("Can't redirect after accepted", __FILE__, __LINE__);
100 break;
101 }
102}
103
105{
106public:
107 ServerInviteSessionRedirectCommand(const ServerInviteSessionHandle& serverInviteSessionHandle, const NameAddrs& contacts, int code)
108 : mServerInviteSessionHandle(serverInviteSessionHandle),
109 mContacts(contacts),
110 mCode(code)
111 {
112
113 }
114
115 void executeCommand() override
116 {
117 if(mServerInviteSessionHandle.isValid())
118 {
119 mServerInviteSessionHandle->redirect(mContacts, mCode);
120 }
121 }
122
123 EncodeStream& encodeBrief(EncodeStream& strm) const override
124 {
125 return strm << "ServerInviteSessionRedirectCommand";
126 }
127private:
128 ServerInviteSessionHandle mServerInviteSessionHandle;
129 NameAddrs mContacts;
130 int mCode;
131};
132
133void
135{
137}
138
139void
140ServerInviteSession::provisional(int code, bool earlyFlag)
141{
142 InfoLog (<< toData(mState) << ": provisional(" << code << ")");
143
144 switch (mState)
145 {
146 case UAS_Offer:
148 sendProvisional(code, earlyFlag);
149 break;
150
154 sendProvisional(code, earlyFlag);
155 break;
156
160 sendProvisional(code, earlyFlag);
161 break;
162
163 case UAS_EarlyOffer:
165 sendProvisional(code, earlyFlag);
166 break;
167
168 case UAS_NoOffer:
169 case UAS_EarlyNoOffer:
171 sendProvisional(code, earlyFlag);
172 break;
173
179 if(mUnacknowledgedReliableProvisional.get())
180 {
181 InfoLog (<< "Waiting for PRACK. queued provisional, code=" << code << ", early=" << (earlyFlag ? "YES" : "NO") );
182 queueResponse(code, earlyFlag);
183 }
184 else
185 {
186 sendProvisional(code, earlyFlag);
187 }
188 break;
189
191 case UAS_OfferReliable:
192 if(sendProvisional(code, earlyFlag))
193 {
194 // If sent reliably then change state
196 }
197 break;
198
200 if(sendProvisional(code, earlyFlag))
201 {
202 // If sent reliably then change state
204 }
205 break;
206
208 if(mUnacknowledgedReliableProvisional.get()) // First 18x may not have contained answer and still be outstanding
209 {
210 InfoLog (<< "Waiting for PRACK. queued provisional, code=" << code << ", early=" << (earlyFlag ? "YES" : "NO") );
211 queueResponse(code, earlyFlag);
212 }
213 else if(sendProvisional(code, earlyFlag) && earlyFlag)
214 {
215 // If sent reliably and earlyFlag set (answer actually sent) then change state
217 }
218 break;
219
220 case UAS_Accepted:
225 case UAS_SentUpdate:
227 case UAS_Start:
229 default:
230 resip_assert(0);
231 break;
232 }
233}
234
236{
237public:
238 ServerInviteSessionProvisionalCommand(const ServerInviteSessionHandle& serverInviteSessionHandle, int statusCode, bool earlyFlag)
239 : mServerInviteSessionHandle(serverInviteSessionHandle),
240 mStatusCode(statusCode),
241 mEarlyFlag(earlyFlag)
242 {
243 }
244
245 void executeCommand() override
246 {
247 if(mServerInviteSessionHandle.isValid())
248 {
249 mServerInviteSessionHandle->provisional(mStatusCode, mEarlyFlag);
250 }
251 }
252
253 EncodeStream& encodeBrief(EncodeStream& strm) const override
254 {
255 return strm << "ServerInviteSessionProvisionalCommand";
256 }
257private:
258 ServerInviteSessionHandle mServerInviteSessionHandle;
259 int mStatusCode;
260 bool mEarlyFlag;
261};
262
263void
264ServerInviteSession::provisionalCommand(int statusCode, bool earlyFlag)
265{
266 mDum.post(new ServerInviteSessionProvisionalCommand(getHandle(), statusCode, earlyFlag));
267}
268
269void
272 const Contents* alternative,
273 bool sendOfferAtAccept)
274{
275 InfoLog (<< toData(mState) << ": provideOffer");
276 switch (mState)
277 {
278 case UAS_NoOffer:
282 break;
283
284 case UAS_EarlyNoOffer:
288 break;
289
294 break;
295
299 if (sendOfferAtAccept)
300 {
302 }
303 else
304 {
306 sendUpdate(offer);
307 }
308 break;
309
310 case UAS_Accepted:
311 // queue the offer to be sent after the ACK is received
315 break;
316
318 InviteSession::provideOffer(offer, level, alternative);
319 break;
320
322 // Queue up offer to be sent after PRACK arrives
325 break;
326
330 case UAS_Offer:
331 case UAS_EarlyOffer:
332 case UAS_OfferReliable:
338 case UAS_SentUpdate:
340 case UAS_Start:
344 WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
345 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
346 break;
347 default:
348 InviteSession::provideOffer(offer, level, alternative);
349 break;
350 }
351}
352
353void
356 const Contents* alternative)
357{
358 this->provideOffer(offer, level, alternative, false);
359}
360
361void
363 bool sendOfferAtAccept)
364{
365 this->provideOffer(offer, mCurrentEncryptionLevel, 0, sendOfferAtAccept);
366}
367
368void
370{
371 this->provideOffer(offer, mCurrentEncryptionLevel, 0, false);
372}
373
374void
376{
377 InfoLog (<< toData(mState) << ": requestOffer");
378 switch (mState)
379 {
380 case UAS_Accepted:
381 // queue the request to be sent after the ACK is received
383 break;
384
387 break;
388
389 default:
391 break;
392 }
393}
394
395void
397{
398 InfoLog (<< toData(mState) << ": provideAnswer");
399 mAnswerSentReliably = false;
400 switch (mState)
401 {
402 case UAS_Offer:
406 break;
407
408 case UAS_EarlyOffer:
412 break;
413
414 case UAS_OfferReliable:
418 break;
419
421 // Store answer and wait for PRACK
424 break;
425
427 {
429
430 // Send answer in 200/Update
431 auto response = std::make_shared<SipMessage>();
433 InviteSession::setOfferAnswer(*response, answer, 0);
436 InfoLog (<< "Sending " << response->brief());
438 send(response);
439 }
440 break;
441
443 {
444 auto response = std::make_shared<SipMessage>();
446 InviteSession::setOfferAnswer(*response, answer, 0);
449 InfoLog (<< "Sending " << response->brief());
451 send(response);
452
453 // send the queued 200/Invite
454 updateCheckQueue();
455 }
456 break;
457
462 break;
463
464 // If we received an offer in a PRACK then we transition to NegotiateReliable and expect
465 // provideAnswer to be called to send the 200/Prack containing the answer.
467 if (mPrackWithOffer)
468 {
471 auto p200 = std::make_shared<SipMessage>();
472 mDialog.makeResponse(*p200, *mPrackWithOffer, 200);
474 mAnswerSentReliably = true;
475 mPrackWithOffer.reset();
476 send(p200);
477 }
478 else
479 {
480 resip_assert(0);
481 }
482 break;
483
484 case UAS_Accepted:
487 case UAS_EarlyNoOffer:
492 case UAS_NoOffer:
497 case UAS_SentUpdate:
499 case UAS_Start:
502 WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
503 throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
504 break;
505 default:
507 break;
508 }
509}
510
511void
516
517void
519{
520 mUserEndReason = userReason;
522}
523
524void
530
531void
533{
534 InfoLog (<< toData(mState) << ": end");
536 {
537 mEndReason = reason;
538 }
539
540 switch (mState)
541 {
542 case UAS_EarlyNoOffer:
543 case UAS_EarlyOffer:
546 case UAS_NoOffer:
547 case UAS_Offer:
551 reject(480);
552 break;
553
554 case UAS_OfferReliable:
562 case UAS_ReceivedUpdate: // !slg! todo: send 488U
563 case UAS_ReceivedUpdateWaitingAnswer: // !slg! todo: send 488U
564 case UAS_SentUpdate:
567 reject(480);
568 break;
569
570 case UAS_Start:
571 resip_assert(0);
572 break;
573
574 case UAS_Accepted:
578 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet - wait for it
579 {
581 }
582 else
583 {
584 // ACK has likely timed out - hangup immediately
585 const auto msg = sendBye();
587 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
588 }
589 break;
590
591 case UAS_WaitingToHangup: // This can happen if we are waiting for an ACK to hangup and the ACK timesout
592 break;
593
594 default:
595 InviteSession::end(reason);
596 break;
597 }
598}
599
600void
602{
603 reject(code, nullptr, warning);
604}
605
606void
607ServerInviteSession::reject(int code, const Contents* contents, WarningCategory *warning)
608{
609 InfoLog (<< toData(mState) << ": reject(" << code << ")");
610
611 switch (mState)
612 {
613 case UAS_EarlyNoOffer:
614 case UAS_EarlyOffer:
617 case UAS_NoOffer:
618 case UAS_Offer:
622
630 case UAS_OfferReliable:
632 case UAS_ReceivedUpdate: // Note: This rejects the entire InviteSession - there is no way right now to reject only the Offer that was received via an Update
633 case UAS_ReceivedUpdateWaitingAnswer: // yes it's wrong to call reject after accept - however we can get here from end() as well. We haven't sent our 200/Inv on the wire yet, so we can just reject the Invite session to end it
634 case UAS_SentUpdate:
636 case UAS_SentUpdateAccepted: // yes it's wrong to call reject after accept - however we can get here from end() as well. We haven't sent our 200/Inv on the wire yet, so we can just reject the Invite session to end it
637 {
638 // !jf! the cleanup for 3xx may be a bit strange if we are in the middle of
639 // an offer/answer exchange with PRACK.
640 // e.g. we sent 183 reliably and then 302 before PRACK was received. Ideally,
641 // we should send 200PRACK
642 auto response = std::make_shared<SipMessage>();
643 mDialog.makeResponse(*response, mFirstRequest, code);
644 // In case we wanted to reject the request by including content
645 if (contents)
646 {
647 response->setContents(contents);
648 }
649 if(warning)
650 {
651 response->header(h_Warnings).push_back(*warning);
652 }
653 send(response);
654
655 if (mDum.mDialogEventStateManager)
656 {
657 mDum.mDialogEventStateManager->onTerminated(mDialog, *response, InviteSessionHandler::Rejected);
658 }
659
662 mDum.destroy(this);
663 break;
664 }
665
666 case UAS_Accepted:
669 case UAS_Start:
671 resip_assert(0);
672 break;
673
674 default:
675 InviteSession::reject(code, contents, warning);
676 break;
677 }
678}
679
680void
682{
683 InfoLog (<< toData(mState) << ": accept(" << code << ")");
684 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
685 switch (mState)
686 {
687 case UAS_Offer:
688 case UAS_EarlyOffer:
690 resip_assert(0);
691 break;
692
696 sendAccept(code, mCurrentLocalOfferAnswer.get());
698 break;
699
700 case UAS_NoOffer:
701 case UAS_EarlyNoOffer:
702 resip_assert(0);
703 break;
704
709 sendAccept(code, mProposedLocalOfferAnswer.get());
710 break;
711
712 case UAS_Accepted:
715 resip_assert(0); // Already Accepted
716 break;
717
720 // queue 2xx
721 // waiting for PRACK
722 InfoLog (<< "Waiting for PRACK. queued 200 OK" );
723 queueResponse(code, false);
724 break;
725
727 if (mUnacknowledgedReliableProvisional)
728 {
729 InfoLog (<< "Waiting for PRACK. queued provisional" );
730 queueResponse(code, false);
731 }
732 else
733 {
735 sendAccept(code, 0);
737 }
738 break;
739
742 sendAccept(code, mCurrentLocalOfferAnswer.get());
744 break;
745
746 case UAS_SentUpdate:
748 queueResponse(code, false);
749 break;
750
753 queueResponse(code, false);
754 break;
755
758 case UAS_OfferReliable:
761 case UAS_Start:
763 default:
764 resip_assert(0);
765 break;
766 }
767}
768
770{
771public:
772 ServerInviteSessionAcceptCommand(const ServerInviteSessionHandle& serverInviteSessionHandle, int statusCode)
773 : mServerInviteSessionHandle(serverInviteSessionHandle),
774 mStatusCode(statusCode)
775 {
776 }
777
778 void executeCommand() override
779 {
780 if(mServerInviteSessionHandle.isValid())
781 {
782 mServerInviteSessionHandle->accept(mStatusCode);
783 }
784 }
785
786 EncodeStream& encodeBrief(EncodeStream& strm) const override
787 {
788 return strm << "ServerInviteSessionAcceptCommand";
789 }
790private:
791 ServerInviteSessionHandle mServerInviteSessionHandle;
792 int mStatusCode;
793};
794
795void
800
801void
802ServerInviteSession::dispatch(const SipMessage& msg)
803{
804 if (msg.isRequest())
805 {
806 if (msg.header(h_RequestLine).method() == INFO)
807 {
809 return;
810 }
811 if (msg.header(h_RequestLine).method() == MESSAGE)
812 {
814 return;
815 }
816 }
817
818 switch (mState)
819 {
820 case UAS_Start:
821 dispatchStart(msg);
822 break;
823
824 case UAS_Offer:
825 case UAS_EarlyOffer:
827 case UAS_NoOffer:
830 case UAS_EarlyNoOffer:
836 dispatchOfferOrEarly(msg);
837 break;
839 dispatchOfferReliableProvidedAnswer(msg);
840 break;
841 case UAS_Accepted:
842 dispatchAccepted(msg);
843 break;
845 dispatchWaitingToOffer(msg);
846 break;
848 dispatchWaitingToRequestOffer(msg);
849 break;
851 dispatchAcceptedWaitingAnswer(msg);
852 break;
854 dispatchFirstSentAnswerReliable(msg);
855 break;
857 dispatchNoAnswerReliableWaitingPrack(msg);
858 break;
860 dispatchFirstSentOfferReliable(msg);
861 break;
863 dispatchReceivedUpdate(msg);
864 break;
866 dispatchReceivedUpdateWaitingAnswer(msg);
867 break;
868 case UAS_SentUpdate:
869 dispatchSentUpdate(msg);
870 break;
872 dispatchSentUpdateGlare(msg);
873 break;
875 dispatchWaitingToHangup(msg);
876 break;
878 dispatchSentUpdateAccepted(msg);
879 break;
881 dispatchNegotiatedReliable(msg);
882 break;
883 default:
885 break;
886 }
887}
888
889void
890ServerInviteSession::dispatch(const DumTimeout& timeout)
891{
892 if (timeout.type() == DumTimeout::Retransmit1xx)
893 {
894 if (timeout.seq() == mCurrentRetransmit1xxSeq) // If timer isn't stopped and this timer is for last 1xx sent, then resend
895 {
896 send(m1xx);
897 startRetransmit1xxTimer();
898 }
899 }
900 else if (timeout.type() == DumTimeout::Resubmit1xxRel)
901 {
902 if (timeout.seq() == mCurrentRetransmit1xxSeq) // If timer isn't stopped and this timer is for last 1xx sent, then resend
903 {
904 // This is not a retransmission, it is a resubmission - ensure the RSeq number is incremented
905 if(m1xx->exists(h_RSeq))
906 {
907 // increment RSeq
908 m1xx->header(h_RSeq).value()++;
909
910 // Remove any body/sdp
911 m1xx->setContents(0);
912
913 mUnacknowledgedReliableProvisional = m1xx;
914 send(m1xx);
915 startResubmit1xxRelTimer();
916 }
917 }
918 }
919 else if (timeout.type() == DumTimeout::Retransmit1xxRel)
920 {
921 if (mUnacknowledgedReliableProvisional.get() &&
922 mUnacknowledgedReliableProvisional->header(h_RSeq).value() == timeout.seq())
923 {
924 unsigned int duration = 2*timeout.secondarySeq();
925 if(duration>=64*Timer::T1)
926 {
927 InfoLog (<< "Reliable provisional timeout, duration=" << duration );
928 auto i504 = std::make_shared<SipMessage>();
929 mDialog.makeResponse(*i504, mFirstRequest, 504);
930 send(i504);
931
933
934 if (mDum.mDialogEventStateManager)
935 {
936 SipMessage msg; // should onTerminated require this msg?
937 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::Timeout);
938 }
939
941 mDum.destroy(this);
942 return;
943 }
944 else
945 {
946 InfoLog (<< "Reliable provisional retransmit, duration=" << duration );
947 send(mUnacknowledgedReliableProvisional);
948 mDum.addTimerMs(DumTimeout::Retransmit1xxRel, duration, getBaseHandle(), timeout.seq(), duration);
949 }
950 }
951 }
952 else if (timeout.type() == DumTimeout::Glare)
953 {
955 {
957 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
958 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE); // increments CSeq
960 }
961 else
962 {
964 }
965 }
966 else
967 {
969 }
970}
971
972void
973ServerInviteSession::dispatchStart(const SipMessage& msg)
974{
975 resip_assert(msg.isRequest());
976 resip_assert(msg.header(h_CSeq).method() == INVITE);
977
978 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
979 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
981
982 if (mDum.mDialogEventStateManager)
983 {
984 mDum.mDialogEventStateManager->onTryingUas(mDialog, msg);
985 }
986
987 switch (toEvent(msg, offerAnswer.get()))
988 {
989 case OnInviteOffer:
995 if(!isTerminated())
996 {
997 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
998 }
999 break;
1000 case OnInvite:
1003 handler->onNewSession(getHandle(), InviteSession::None, msg);
1004 if(!isTerminated())
1005 {
1006 handler->onOfferRequired(getSessionHandle(), msg);
1007 }
1008 break;
1015 if(!isTerminated())
1016 {
1017 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
1018 }
1019 break;
1020 case OnInviteReliable:
1023 handler->onNewSession(getHandle(), InviteSession::None, msg);
1024 if(!isTerminated())
1025 {
1026 handler->onOfferRequired(getSessionHandle(), msg);
1027 }
1028 break;
1029 default:
1030 resip_assert(0);
1031 break;
1032 }
1033}
1034
1035// UAS_Offer, UAS_EarlyOffer, UAS_EarlyProvidedAnswer, UAS_NoOffer, UAS_ProvidedOffer,
1036// UAS_ProvidedOfferReliable, UAS_EarlyNoOffer, UAS_EarlyProvidedOffer, UAS_OfferProvidedAnswer,
1037// UAS_NoOfferReliable, UAS_OfferReliable, UAS_NoAnswerReliable
1038void
1039ServerInviteSession::dispatchOfferOrEarly(const SipMessage& msg)
1040{
1041 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1042 switch (toEvent(msg, offerAnswer.get()))
1043 {
1044 case OnCancel:
1045 dispatchCancel(msg);
1046 break;
1047 case OnBye:
1048 dispatchBye(msg);
1049 break;
1050 case OnUpdate:
1051 {
1052 // Update with no SDP is a target refresh ?slg? just respond immediately - do we need a callback?
1053 // Note: target refresh handling is in Dialog::handleTargetRefresh
1054 auto response = std::make_shared<SipMessage>();
1055 mDialog.makeResponse(*response, msg, 200);
1056 send(response);
1057 break;
1058 }
1059 default:
1060 if(msg.isRequest())
1061 {
1062 dispatchUnknown(msg);
1063 }
1064 break;
1065 }
1066}
1067
1068void
1069ServerInviteSession::dispatchAccepted(const SipMessage& msg)
1070{
1071 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1072 std::unique_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1073 InfoLog (<< "dispatchAccepted: " << msg.brief());
1074
1075 switch (toEvent(msg, offerAnswer.get()))
1076 {
1077 case OnInvite:
1078 case OnInviteReliable:
1079 case OnInviteOffer:
1081 case OnUpdate:
1082 case OnUpdateOffer:
1083 {
1084 auto response = std::make_shared<SipMessage>();
1085 mDialog.makeResponse(*response, msg, 491);
1086 send(response);
1087 break;
1088 }
1089
1090 case OnAck:
1091 case OnAckAnswer: // .bwc. unsolicited body in ACK; it would probably make sense to just ignore.
1092 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1094 handler->onConnectedConfirmed(getSessionHandle(), msg);
1095 break;
1096
1097 case OnCancel:
1098 {
1099 // Cancel and 200 crossed
1100 auto c200 = std::make_shared<SipMessage>();
1101 mDialog.makeResponse(*c200, msg, 200);
1102 send(c200);
1103 break;
1104 }
1105
1106 case OnBye:
1107 {
1108 auto b200 = std::make_shared<SipMessage>();
1109 mDialog.makeResponse(*b200, msg, 200);
1110 send(b200);
1111
1114 mDum.destroy(this);
1115 break;
1116 }
1117
1118 case OnPrack:
1119 {
1120 // should never get a prack here - we always queue up our 200/Inv response
1121 InfoLog (<< "spurious PRACK in state=" << toData(mState));
1122 auto p481 = std::make_shared<SipMessage>();
1123 mDialog.makeResponse(*p481, msg, 481);
1124 send(p481);
1125 break;
1126 }
1127
1128 default:
1129 if(msg.isRequest())
1130 {
1131 dispatchUnknown(msg);
1132 }
1133 break;
1134 }
1135}
1136
1137void
1138ServerInviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1139{
1140 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1141 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1142 InfoLog (<< "dispatchWaitingToOffer: " << msg.brief());
1143
1144 switch (toEvent(msg, offerAnswer.get()))
1145 {
1146 case OnInvite:
1147 case OnInviteReliable:
1148 case OnInviteOffer:
1150 case OnUpdate:
1151 case OnUpdateOffer:
1152 {
1153 auto response = std::make_shared<SipMessage>();
1154 mDialog.makeResponse(*response, msg, 491);
1155 send(response);
1156 break;
1157 }
1158
1159 case OnAck:
1161 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1163 break;
1164
1165 case OnAckAnswer:
1166 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1167 sendBye();
1170 break;
1171
1172 case OnCancel:
1173 {
1174 // Cancel and 200 crossed
1175 auto c200 = std::make_shared<SipMessage>();
1176 mDialog.makeResponse(*c200, msg, 200);
1177 send(c200);
1178 break;
1179 }
1180
1181 case OnBye:
1182 {
1183 auto b200 = std::make_shared<SipMessage>();
1184 mDialog.makeResponse(*b200, msg, 200);
1185 send(b200);
1186
1189 mDum.destroy(this);
1190 break;
1191 }
1192
1193 default:
1194 if(msg.isRequest())
1195 {
1196 dispatchUnknown(msg);
1197 }
1198 break;
1199 }
1200}
1201
1202void
1203ServerInviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1204{
1205 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1206 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1207 InfoLog (<< "dispatchWaitingToRequestOffer: " << msg.brief());
1208
1209 switch (toEvent(msg, offerAnswer.get()))
1210 {
1211 case OnInvite:
1212 case OnInviteReliable:
1213 case OnInviteOffer:
1215 case OnUpdate:
1216 case OnUpdateOffer:
1217 {
1218 auto response = std::make_shared<SipMessage>();
1219 mDialog.makeResponse(*response, msg, 491);
1220 send(response);
1221 break;
1222 }
1223
1224 case OnAck:
1225 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1226 requestOffer();
1227 break;
1228
1229 case OnAckAnswer:
1230 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1231 sendBye();
1234 break;
1235
1236 case OnCancel:
1237 {
1238 // Cancel and 200 crossed
1239 auto c200 = std::make_shared<SipMessage>();
1240 mDialog.makeResponse(*c200, msg, 200);
1241 send(c200);
1242 break;
1243 }
1244
1245 case OnBye:
1246 {
1247 auto b200 = std::make_shared<SipMessage>();
1248 mDialog.makeResponse(*b200, msg, 200);
1249 send(b200);
1250
1253 mDum.destroy(this);
1254 break;
1255 }
1256
1257 default:
1258 if(msg.isRequest())
1259 {
1260 dispatchUnknown(msg);
1261 }
1262 break;
1263 }
1264}
1265
1266void
1267ServerInviteSession::dispatchAcceptedWaitingAnswer(const SipMessage& msg)
1268{
1269 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1270 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1271
1272 switch (toEvent(msg, offerAnswer.get()))
1273 {
1274 case OnInvite:
1275 case OnInviteReliable:
1276 case OnInviteOffer:
1278 case OnUpdate:
1279 case OnUpdateOffer:
1280 {
1281 auto response = std::make_shared<SipMessage>();
1282 mDialog.makeResponse(*response, msg, 491);
1283 send(response);
1284 break;
1285 }
1286
1287 case OnAckAnswer:
1288 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1293 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
1294 if(!isTerminated()) // onAnswer callback may call end() or reject()
1295 {
1296 handler->onConnected(getSessionHandle(), msg);
1297 }
1298 break;
1299
1300 case OnAck:
1301 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1303 sendBye();
1306 break;
1307
1308 case OnCancel:
1309 {
1310 // no transition
1311 auto c200 = std::make_shared<SipMessage>();
1312 mDialog.makeResponse(*c200, msg, 200);
1313 send(c200);
1314 break;
1315 }
1316
1317 case OnPrack:
1318 {
1319 // should never get a prack here - we always queue up our 200/Inv response
1320 InfoLog (<< "spurious PRACK in state=" << toData(mState));
1321 auto p481 = std::make_shared<SipMessage>();
1322 mDialog.makeResponse(*p481, msg, 481);
1323 send(p481);
1324 break;
1325 }
1326
1327 default:
1328 if(msg.isRequest())
1329 {
1330 dispatchUnknown(msg);
1331 }
1332 break;
1333 }
1334}
1335
1336void
1337ServerInviteSession::dispatchFirstSentOfferReliable(const SipMessage& msg)
1338{
1339 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1340 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1341
1342 switch (toEvent(msg, offerAnswer.get()))
1343 {
1344 case OnCancel:
1345 dispatchCancel(msg);
1346 break;
1347
1348 case OnBye:
1349 dispatchBye(msg);
1350 break;
1351
1352 case OnUpdate:
1353 {
1354 // Update with no SDP is a target refresh ?slg? just respond immediately - do we need a callback?
1355 // Note: target refresh handling is in Dialog::handleTargetRefresh
1356 auto response = std::make_shared<SipMessage>();
1357 mDialog.makeResponse(*response, msg, 200);
1358 send(response);
1359 break;
1360 }
1361
1362 case OnPrack:
1363 if(handlePrack(msg))
1364 {
1365 if (offerAnswer) // Answer
1366 {
1368 auto p200 = std::make_shared<SipMessage>();
1369 mDialog.makeResponse(*p200, msg, 200);
1370 send(p200);
1371
1375 handler->onPrack(getHandle(), msg);
1376 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
1377 }
1378 else
1379 {
1383
1384 // 406 the Prack
1385 auto p406 = std::make_shared<SipMessage>();
1386 mDialog.makeResponse(*p406, msg, 406);
1387 send(p406);
1388
1389 // 406 the Invite
1390 auto i406 = std::make_shared<SipMessage>();
1391 mDialog.makeResponse(*i406, mFirstRequest, 406);
1392 send(i406);
1393
1394 mDum.destroy(this);
1395 }
1396 }
1397 break;
1398
1399 default:
1400 if(msg.isRequest())
1401 {
1402 dispatchUnknown(msg);
1403 }
1404 break;
1405 }
1406}
1407
1408bool
1409ServerInviteSession::handlePrack(const SipMessage& msg)
1410{
1411 InfoLog (<< "handlePrack");
1412
1413 if(mUnacknowledgedReliableProvisional.get() &&
1414 mUnacknowledgedReliableProvisional->header(h_RSeq).value() == msg.header(h_RAck).rSequence() &&
1415 mUnacknowledgedReliableProvisional->header(h_CSeq).sequence() == msg.header(h_RAck).cSequence() &&
1416 mUnacknowledgedReliableProvisional->header(h_CSeq).method() == msg.header(h_RAck).method())
1417 {
1418 mUnacknowledgedReliableProvisional.reset(); // Clear storage we have received our PRACK
1419
1420 InfoLog (<< "Found matching provisional for PRACK.");
1421 return true;
1422 }
1423
1424 InfoLog (<< "spurious PRACK in state=" << toData(mState));
1425 auto p481 = std::make_shared<SipMessage>();
1426 mDialog.makeResponse(*p481, msg, 481);
1427 send(p481);
1428 return false;
1429}
1430
1431void
1432ServerInviteSession::prackCheckQueue()
1433{
1434 InfoLog (<< "prackCheckQueue: " << mQueuedResponses.size() );
1435 if (!mQueuedResponses.empty() && mQueuedResponses.front().first < 200)
1436 {
1437 InfoLog (<< "Sending queued provisional" );
1438 sendProvisional(mQueuedResponses.front().first, mQueuedResponses.front().second);
1439 mQueuedResponses.pop_front();
1440 }
1441 else if (!mQueuedResponses.empty() && mQueuedResponses.front().first < 300)
1442 {
1443 InfoLog (<< "Sending queued 200 OK" );
1444 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1446 Contents* sdp = 0;
1447 if( !mAnswerSentReliably && mCurrentLocalOfferAnswer.get())
1448 {
1449 sdp = mCurrentLocalOfferAnswer.get();
1450 }
1451 sendAccept(mQueuedResponses.front().first, sdp);
1453 mQueuedResponses.clear(); // shouldn't be any provisionals or 200's behind us in queue - just clear the entire queue
1454 }
1455}
1456
1457void
1458ServerInviteSession::updateCheckQueue()
1459{
1460 // TODO - should we be skipping over or ignoring any provisionals in the queue?
1461 InfoLog (<< "updateCheckQueue: " << mQueuedResponses.size() );
1462 if (!mQueuedResponses.empty() &&
1463 mQueuedResponses.front().first >= 200 &&
1464 mQueuedResponses.front().first < 300)
1465 {
1466 InfoLog (<< "Sending queued 200 OK" );
1467 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1469 sendAccept(mQueuedResponses.front().first, 0);
1471 mQueuedResponses.pop_front();
1472 }
1473}
1474
1475void
1476ServerInviteSession::dispatchOfferReliableProvidedAnswer(const SipMessage& msg)
1477{
1478 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1479 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1480
1481 switch (toEvent(msg, offerAnswer.get()))
1482 {
1483 case OnCancel:
1484 dispatchCancel(msg);
1485 break;
1486
1487 case OnBye:
1488 dispatchBye(msg);
1489 break;
1490
1491 case OnUpdate:
1492 {
1493 // Update with no SDP is a target refresh ?slg? just respond immediately - do we need a callback?
1494 // Note: target refresh handling is in Dialog::handleTargetRefresh
1495 auto response = std::make_shared<SipMessage>();
1496 mDialog.makeResponse(*response, msg, 200);
1497 send(response);
1498 break;
1499 }
1500
1501 case OnPrack:
1502 if(handlePrack(msg))
1503 {
1504 if (offerAnswer)
1505 {
1506 // 2nd offer, we haven't answered the first one - log error an proceed by igoring body
1507 ErrLog (<< "PRACK with new offer when in state=" << toData(mState));
1508
1512
1513 // 406 the Prack
1514 auto p406 = std::make_shared<SipMessage>();
1515 mDialog.makeResponse(*p406, msg, 406);
1516 send(p406);
1517
1518 // 406 the Invite
1519 auto i406 = std::make_shared<SipMessage>();
1520 mDialog.makeResponse(*i406, mFirstRequest, 406);
1521 send(i406);
1522
1523 mDum.destroy(this);
1524 }
1525 else
1526 {
1527 // Send 200/PRACK
1528 auto p200 = std::make_shared<SipMessage>();
1529 mDialog.makeResponse(*p200, msg, 200);
1530 send(p200);
1531
1532 // If we have a provisional to send with answer then transition to UAS_FirstSentAnswerReliable
1533 if (!mQueuedResponses.empty() &&
1534 mQueuedResponses.front().first < 200 &&
1535 mQueuedResponses.front().second) // Early flag is on
1536 {
1538 }
1539 handler->onPrack(getHandle(), msg);
1540 prackCheckQueue();
1541 }
1542 }
1543 break;
1544
1545 default:
1546 if(msg.isRequest())
1547 {
1548 dispatchUnknown(msg);
1549 }
1550 break;
1551 }
1552}
1553
1554void
1555ServerInviteSession::dispatchFirstSentAnswerReliable(const SipMessage& msg)
1556{
1557 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1558 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1559
1560 switch (toEvent(msg, offerAnswer.get()))
1561 {
1562 case OnCancel:
1563 dispatchCancel(msg);
1564 break;
1565
1566 case OnBye:
1567 dispatchBye(msg);
1568 break;
1569
1570 case OnUpdate:
1571 {
1572 // Update with no SDP is a target refresh ?slg? just respond immediately - do we need a callback?
1573 // Note: target refresh handling is in Dialog::handleTargetRefresh
1574 auto response = std::make_shared<SipMessage>();
1575 mDialog.makeResponse(*response, msg, 200);
1576 send(response);
1577 break;
1578 }
1579
1580 case OnPrack:
1581 if(handlePrack(msg))
1582 {
1583 if (offerAnswer) // New offer
1584 {
1585 // If we have an offer in the prack and the dum user also tried to provide a new offer, then
1586 // reject the dum api offer and pass the one from the wire to the application
1588 {
1590 handler->onOfferRejected(getSessionHandle(), 0);
1591 }
1592 // dispatch offer here and respond with 200OK in provideAnswer
1594 mPrackWithOffer = std::make_shared<SipMessage>(msg);
1597 handler->onPrack(getHandle(), msg);
1598 if(!isTerminated())
1599 {
1600 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
1601 }
1602 }
1603 else
1604 {
1605 auto p200 = std::make_shared<SipMessage>();
1606 mDialog.makeResponse(*p200, msg, 200);
1607 send(p200);
1608 // check if we have a queued up offer then sent it - if not check prack queue
1610 {
1612 handler->onPrack(getHandle(), msg);
1613 sendUpdate(*mProposedLocalOfferAnswer);
1614 }
1615 else
1616 {
1618 handler->onPrack(getHandle(), msg);
1619 prackCheckQueue();
1620 }
1621 }
1622 }
1623 break;
1624
1625 default:
1626 if(msg.isRequest())
1627 {
1628 dispatchUnknown(msg);
1629 }
1630 break;
1631 }
1632}
1633
1634void
1635ServerInviteSession::dispatchNoAnswerReliableWaitingPrack(const SipMessage& msg)
1636{
1637 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1638 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1639
1640 switch (toEvent(msg, offerAnswer.get()))
1641 {
1642 case OnCancel:
1643 dispatchCancel(msg);
1644 break;
1645
1646 case OnBye:
1647 dispatchBye(msg);
1648 break;
1649
1650 case OnUpdate:
1651 {
1652 // Update with no SDP is a target refresh ?slg? just respond immediately - do we need a callback?
1653 // Note: target refresh handling is in Dialog::handleTargetRefresh
1654 auto response = std::make_shared<SipMessage>();
1655 mDialog.makeResponse(*response, msg, 200);
1656 send(response);
1657 break;
1658 }
1659
1660 case OnPrack:
1661 if(handlePrack(msg))
1662 {
1663 if (offerAnswer)
1664 {
1665 // 2nd offer, we haven't answered the first one - log error an proceed by ignoring body
1666 ErrLog (<< "PRACK with new offer when in state=" << toData(mState));
1667
1671
1672 // 406 the Prack
1673 auto p406 = std::make_shared<SipMessage>();
1674 mDialog.makeResponse(*p406, msg, 406);
1675 send(p406);
1676
1677 // 406 the Invite
1678 auto i406 = std::make_shared<SipMessage>();
1679 mDialog.makeResponse(*i406, mFirstRequest, 406);
1680 send(i406);
1681
1682 mDum.destroy(this);
1683 }
1684 else
1685 {
1686 // Send 200/PRACK
1687 auto p200 = std::make_shared<SipMessage>();
1688 mDialog.makeResponse(*p200, msg, 200);
1689 send(p200);
1690
1692 handler->onPrack(getHandle(), msg);
1693
1694 // If we have a provisional to send with answer then transition to UAS_FirstSentAnswerReliable,
1695 // otherwise if there is no answer, go to UAS_NoAnswerReliableWaitingPrack.
1696 if (!mQueuedResponses.empty() && mQueuedResponses.front().first < 200)
1697 {
1698 if (mQueuedResponses.front().second) // Early flag is on
1699 {
1701 }
1702 else
1703 {
1705 }
1706 }
1707 prackCheckQueue();
1708 }
1709 }
1710 break;
1711
1712 default:
1713 if(msg.isRequest())
1714 {
1715 dispatchUnknown(msg);
1716 }
1717 break;
1718 }
1719}
1720
1721void
1722ServerInviteSession::dispatchSentUpdate(const SipMessage& msg)
1723{
1724 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1725 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1726
1727 switch (toEvent(msg, offerAnswer.get()))
1728 {
1729 case OnCancel:
1730 dispatchCancel(msg);
1731 break;
1732
1733 case OnBye:
1734 dispatchBye(msg);
1735 break;
1736
1737 case OnUpdate:
1738 case OnUpdateOffer:
1739 {
1740 // Glare
1741 auto response = std::make_shared<SipMessage>();
1742 mDialog.makeResponse(*response, msg, 491);
1743 send(response);
1744 break;
1745 }
1746
1747 case On200Update:
1749 if (offerAnswer)
1750 {
1754 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
1755 }
1756 prackCheckQueue(); // needed for when provideOffer then accept are both called in FirstSentAnswerReliable
1757 break;
1758
1759 case OnUpdateRejected:
1760 case OnGeneralFailure: // handle 481 or 408 responses
1763 handler->onOfferRejected(getSessionHandle(), &msg);
1764 prackCheckQueue(); // needed for when provideOffer then accept are both called in FirstSentAnswerReliable
1765 break;
1766
1767 case On491Update:
1769 start491Timer();
1770 break;
1771
1772 default:
1773 if(msg.isRequest())
1774 {
1775 dispatchUnknown(msg);
1776 }
1777 break;
1778 }
1779}
1780
1781void
1782ServerInviteSession::dispatchSentUpdateGlare(const SipMessage& msg)
1783{
1784 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1785 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1786
1787 switch (toEvent(msg, offerAnswer.get()))
1788 {
1789 case OnCancel:
1790 dispatchCancel(msg);
1791 break;
1792
1793 case OnBye:
1794 dispatchBye(msg);
1795 break;
1796
1797 case OnUpdate:
1798 case OnUpdateOffer:
1799 handler->onOfferRejected(getSessionHandle(), &msg);
1800 // handle as if we received in NegotiatedReliable
1801 dispatchNegotiatedReliable(msg);
1802 break;
1803
1804 default:
1805 if(msg.isRequest())
1806 {
1807 dispatchUnknown(msg);
1808 }
1809 break;
1810 }
1811}
1812
1813void
1814ServerInviteSession::dispatchSentUpdateAccepted(const SipMessage& msg)
1815{
1816 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1817 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1818
1819 switch (toEvent(msg, offerAnswer.get()))
1820 {
1821 case OnCancel:
1822 dispatchCancel(msg);
1823 break;
1824
1825 case OnBye:
1826 dispatchBye(msg);
1827 break;
1828
1829 case OnUpdate:
1830 {
1831 // Update with no SDP is a target refresh ?slg? just respond immediately - do we need a callback?
1832 // Note: target refresh handling is in Dialog::handleTargetRefresh
1833 auto response = std::make_shared<SipMessage>();
1834 mDialog.makeResponse(*response, msg, 200);
1835 send(response);
1836 break;
1837 }
1838
1839 case On200Update:
1841 if (offerAnswer)
1842 {
1846 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
1847 }
1848 updateCheckQueue();
1849 break;
1850
1851 case OnUpdateRejected:
1852 case OnGeneralFailure: // handle 481 or 408 responses
1855 handler->onOfferRejected(getSessionHandle(), &msg);
1856 updateCheckQueue();
1857 break;
1858
1859 case On491Update:
1860 // strange case - we send an offer then called accept and the offer/update got 491'd - treating the same as any offer error
1863 handler->onOfferRejected(getSessionHandle(), &msg);
1864 updateCheckQueue();
1865 break;
1866
1867 default:
1868 if(msg.isRequest())
1869 {
1870 dispatchUnknown(msg);
1871 }
1872 break;
1873 }
1874}
1875
1876void
1877ServerInviteSession::dispatchReceivedUpdate(const SipMessage& msg)
1878{
1879 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1880
1881 switch (toEvent(msg, offerAnswer.get()))
1882 {
1883 case OnCancel:
1884 dispatchCancel(msg);
1885 break;
1886
1887 case OnBye:
1888 dispatchBye(msg);
1889 break;
1890
1891 case OnUpdate:
1892 case OnUpdateOffer:
1893 // If we receive an UPDATE before we have generated a final response to a previous UPDATE on the
1894 // same dialog, then we MUST return a 500 response with a Retry-After header (random duration 0-10 seconds)
1895 {
1896 auto u500 = std::make_shared<SipMessage>();
1897 mDialog.makeResponse(*u500, msg, 500);
1898 u500->header(h_RetryAfter).value() = Random::getRandom() % 10;
1899 send(u500);
1900 }
1901 break;
1902
1903 default:
1904 if(msg.isRequest())
1905 {
1906 dispatchUnknown(msg);
1907 }
1908 break;
1909 }
1910}
1911
1912void
1913ServerInviteSession::dispatchReceivedUpdateWaitingAnswer(const SipMessage& msg)
1914{
1915 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1916
1917 switch (toEvent(msg, offerAnswer.get()))
1918 {
1919 case OnCancel:
1920 dispatchCancel(msg);
1921 break;
1922
1923 case OnBye:
1924 dispatchBye(msg);
1925 break;
1926
1927 case OnUpdate:
1928 case OnUpdateOffer:
1929 // A UAS that receives an UPDATE before it has generated a final response to a previous UPDATE on the
1930 // same dialog MUST return a 500 response
1931 {
1932 auto u500 = std::make_shared<SipMessage>();
1933 mDialog.makeResponse(*u500, msg, 500);
1934 send(u500);
1935 }
1936 break;
1937
1938 default:
1939 if(msg.isRequest())
1940 {
1941 dispatchUnknown(msg);
1942 }
1943 break;
1944 }
1945}
1946
1947void
1948ServerInviteSession::dispatchNegotiatedReliable(const SipMessage& msg)
1949{
1950 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1951 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
1952
1953 switch (toEvent(msg, offerAnswer.get()))
1954 {
1955 case OnCancel:
1956 dispatchCancel(msg);
1957 break;
1958
1959 case OnBye:
1960 dispatchBye(msg);
1961 break;
1962
1963 case OnPrack:
1964 if(handlePrack(msg))
1965 {
1966 if (offerAnswer) // New offer
1967 {
1968 // dispatch offer here and respond with 200OK in provideAnswer
1969 mPrackWithOffer = std::make_shared<SipMessage>(msg);
1972 handler->onPrack(getHandle(), msg);
1973 if(!isTerminated())
1974 {
1975 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
1976 }
1977 }
1978 else
1979 {
1980 auto p200 = std::make_shared<SipMessage>();
1981 mDialog.makeResponse(*p200, msg, 200);
1982 send(p200);
1983 handler->onPrack(getHandle(), msg);
1984 prackCheckQueue();
1985 }
1986 }
1987 break;
1988
1989 case OnUpdateOffer:
1994 if(!isTerminated())
1995 {
1996 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
1997 }
1998 break;
1999
2000 case OnUpdate:
2001 {
2002 // Update with no SDP is a target refresh ?slg? just respond immediately - do we need a callback?
2003 // Note: target refresh handling is in Dialog::handleTargetRefresh
2004 auto response = std::make_shared<SipMessage>();
2005 mDialog.makeResponse(*response, msg, 200);
2006 send(response);
2007 break;
2008 }
2009
2010 default:
2011 if(msg.isRequest())
2012 {
2013 dispatchUnknown(msg);
2014 }
2015 break;
2016 }
2017}
2018
2019void
2020ServerInviteSession::dispatchWaitingToHangup(const SipMessage& msg)
2021{
2022 const auto offerAnswer = InviteSession::getOfferAnswer(msg);
2023
2024 switch (toEvent(msg, offerAnswer.get()))
2025 {
2026 case OnAck:
2027 case OnAckAnswer:
2028 {
2029 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
2030
2031 const auto msg = sendBye();
2033 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
2034 break;
2035 }
2036
2037 default:
2038 break;
2039 }
2040}
2041
2042void
2043ServerInviteSession::dispatchCancel(const SipMessage& msg)
2044{
2045 auto c200 = std::make_shared<SipMessage>();
2046 mDialog.makeResponse(*c200, msg, 200);
2047 send(c200);
2048
2049 auto i487 = std::make_shared<SipMessage>();
2050 mDialog.makeResponse(*i487, mFirstRequest, 487);
2051 send(i487);
2052
2054
2055 if (mDum.mDialogEventStateManager)
2056 {
2057 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::RemoteCancel);
2058 }
2059
2061 mDum.destroy(this);
2062}
2063
2064void
2065ServerInviteSession::dispatchBye(const SipMessage& msg)
2066{
2067 auto b200 = std::make_shared<SipMessage>();
2068 mDialog.makeResponse(*b200, msg, 200);
2069 send(b200);
2070// !dcm! -- pretty sure we shouldn't 487 after the BYE/200
2071 auto i487 = std::make_shared<SipMessage>();
2072 mDialog.makeResponse(*i487, mFirstRequest, 487);
2073 send(i487);
2074
2076
2077 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
2078 mDum.destroy(this);
2079}
2080
2081void
2082ServerInviteSession::dispatchUnknown(const SipMessage& msg)
2083{
2084 InfoLog (<< "Unknown request (" << msg.brief() << ") received in state=" << toData(mState) << ", rejecting request and terminating call.");
2085
2086 auto r500 = std::make_shared<SipMessage>();
2087 mDialog.makeResponse(*r500, msg, 500);
2088 send(r500);
2089
2090 auto i400 = std::make_shared<SipMessage>();
2091 mDialog.makeResponse(*i400, mFirstRequest, 400);
2092 send(i400);
2093
2095 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2096 mDum.destroy(this);
2097}
2098
2099void
2100ServerInviteSession::startRetransmit1xxTimer()
2101{
2102 // RFC3261 13.3.1 says the UAS must send a non-100 provisional response every minute, to handle the posiblity of lost provisional responses
2103 int retransmissionTime = mDialog.mDialogSet.getUserProfile()->get1xxRetransmissionTime();
2104 if(retransmissionTime > 0 && m1xx->header(resip::h_StatusLine).statusCode() > 100)
2105 {
2106 mDum.addTimer(DumTimeout::Retransmit1xx, retransmissionTime, getBaseHandle(), ++mCurrentRetransmit1xxSeq);
2107 }
2108}
2109
2110void
2111ServerInviteSession::startResubmit1xxRelTimer()
2112{
2113 // RFC3262 section says the UAS SHOULD send reliable provisional responses once every two and half minutes
2114 int resubmitTime = mDialog.mDialogSet.getUserProfile()->get1xxRelResubmitTime();
2115 if(resubmitTime > 0 && m1xx->header(resip::h_StatusLine).statusCode() > 100)
2116 {
2117 mDum.addTimer(DumTimeout::Resubmit1xxRel, resubmitTime, getBaseHandle(), ++mCurrentRetransmit1xxSeq); // This timer serves the same purpose at the unreliable retransmit timer - use the same sequence number
2118 }
2119}
2120
2121void
2122ServerInviteSession::startRetransmit1xxRelTimer()
2123{
2124 unsigned int seq = m1xx->header(h_RSeq).value();
2126}
2127
2128bool
2129ServerInviteSession::sendProvisional(int code, bool earlyFlag)
2130{
2131 m1xx->setContents(0);
2132 mDialog.makeResponse(*m1xx, mFirstRequest, code);
2133
2134 bool sendReliably = code > 100 && // Must be a non-100 response
2135 ((mFirstRequest.exists(h_Requires) && mFirstRequest.header(h_Requires).find(Token(Symbols::C100rel))) || // Far end requires it (note: we must at least support it or the invite would have been rejected already)
2136 mDum.getMasterProfile()->getUasReliableProvisionalMode() == MasterProfile::Required || // OR we require it (note: far end must at least support it or the invite would have been rejected)
2137 (mFirstRequest.exists(h_Supporteds) && mFirstRequest.header(h_Supporteds).find(Token(Symbols::C100rel)) && // OR far ends supports it and we support it
2138 mDum.getMasterProfile()->getUasReliableProvisionalMode() == MasterProfile::Supported)); // (note: SupportedEssential is not trapped here, cases for it are added below)
2139
2140 switch (mState)
2141 {
2144 if (code > 100 && earlyFlag && mCurrentLocalOfferAnswer.get()) // early media
2145 {
2147 }
2148 break;
2149
2150 case UAS_FirstSentAnswerReliable: // This is possible if someone called provisional() from the onPrack callback (since we change states after we call onPrack)
2151 case UAS_OfferReliableProvidedAnswer: // MAY send answer in reliable response - send only if earlyFlag is set
2152 if (code > 100 && earlyFlag && !mAnswerSentReliably && mCurrentLocalOfferAnswer.get()) // early media
2153 {
2155 mAnswerSentReliably = true;
2156 sendReliably = true; // If UasReliableProvisionalMode is SupportEssential this may flip sendReliably to true
2157 }
2158 break;
2159
2161 if(sendReliably)
2162 {
2163 // Invite requires reliable responses - since there was no offer in the INVITE we MUST
2164 // provide an offer in the first reliable response. We would be in the ProvidedOfferReliable
2165 // state if that was the case. Looks like provisional was called too early!
2166 DebugLog( << "Sending a reliable provisional after receiving an INVITE with no offer, requires provideOffer to be called first (RFC3262-Section 5).");
2167 resip_assert(false);
2168 return false;
2169 }
2170 break;
2171
2173 // ignore early flag if we must sendReliably, since first reliable 1xx MUST contain Offer
2174 if (code > 100 && (earlyFlag || sendReliably) && mProposedLocalOfferAnswer.get())
2175 {
2177 sendReliably = true; // If UasReliableProvisionalMode is SupportEssential this may flip sendReliably to true
2178 }
2179 break;
2180
2181 case UAS_ProvidedOffer:
2183 if (code > 100 && earlyFlag && mProposedLocalOfferAnswer.get())
2184 {
2186 }
2187 break;
2188
2189 default:
2190 break;
2191 }
2193
2194 if(sendReliably)
2195 {
2196 DebugLog ( << "Sending provisional reliably" );
2197 if (!m1xx->exists(h_Requires) ||
2198 !m1xx->header(h_Requires).find(Token(Symbols::C100rel)))
2199 {
2200 m1xx->header(h_Requires).push_back(Token(Symbols::C100rel));
2201 }
2202 m1xx->header(h_RSeq).value() = ++mLocalRSeq;
2203
2204 // We are supposed to advertised our Allow header in reliable provisionals - Add Advertised
2205 // Capabilities - allows UAC to detect UPDATE support before 200 response
2207
2208 resip_assert(!mUnacknowledgedReliableProvisional.get());
2209 mUnacknowledgedReliableProvisional = m1xx;
2210 startRetransmit1xxRelTimer(); // handles retransmissions until PRACK arrives
2211 startResubmit1xxRelTimer(); // handles - RFC3262 section says the UAS SHOULD send provisional reliable responses once every two and half minutes
2212 }
2213 else
2214 {
2215 // Make sure there is no RSeq or Requires 100rel
2216 if(m1xx->exists(h_RSeq))
2217 {
2218 m1xx->remove(h_RSeq);
2219 }
2220 if(m1xx->exists(h_Requires))
2221 {
2222 ParserContainer<Token>::iterator it = m1xx->header(h_Requires).begin();
2223 for(; it != m1xx->header(h_Requires).end(); it++)
2224 {
2225 if((*it) == Token(Symbols::C100rel))
2226 {
2227 m1xx->header(h_Requires).erase(it);
2228 break;
2229 }
2230 }
2231 }
2232 startRetransmit1xxTimer();
2233 }
2234
2235 if (mDum.mDialogEventStateManager)
2236 {
2237 mDum.mDialogEventStateManager->onEarly(mDialog, getSessionHandle());
2238 }
2239
2240 send(m1xx);
2241 return sendReliably;
2242}
2243
2244void
2245ServerInviteSession::queueResponse(int code, bool earlyFlag)
2246{
2247 InfoLog (<< "Response " << code << " queued." );
2248 mQueuedResponses.emplace_back(std::make_pair(code, earlyFlag));
2249}
2250
2251void
2252ServerInviteSession::sendAccept(int code, Contents* offerAnswer)
2253{
2254 mDialog.makeResponse(*mInvite200, mFirstRequest, code);
2255 handleSessionTimerRequest(*mInvite200, mFirstRequest);
2256 if (offerAnswer && !mAnswerSentReliably )
2257 {
2258 setOfferAnswer(*mInvite200, offerAnswer);
2259 mAnswerSentReliably = true;
2260 }
2261 mCurrentRetransmit1xxSeq++; // Stop the 1xx timer - causes timer to be ignored on expiry
2262 startRetransmit200Timer(); // 2xx timer
2264
2265 if (mDum.mDialogEventStateManager)
2266 {
2267 mDum.mDialogEventStateManager->onConfirmed(mDialog, getSessionHandle());
2268 }
2269
2271}
2272
2273void
2274ServerInviteSession::sendUpdate(const Contents& offerAnswer)
2275{
2277 {
2282 }
2283 else
2284 {
2285 throw UsageUseException("Can't send UPDATE to peer", __FILE__, __LINE__);
2286 }
2287}
2288
2289/* ====================================================================
2290 * The Vovida Software License, Version 1.0
2291 *
2292 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2293 *
2294 * Redistribution and use in source and binary forms, with or without
2295 * modification, are permitted provided that the following conditions
2296 * are met:
2297 *
2298 * 1. Redistributions of source code must retain the above copyright
2299 * notice, this list of conditions and the following disclaimer.
2300 *
2301 * 2. Redistributions in binary form must reproduce the above copyright
2302 * notice, this list of conditions and the following disclaimer in
2303 * the documentation and/or other materials provided with the
2304
2305 * distribution.
2306 *
2307 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2308 * and "Vovida Open Communication Application Library (VOCAL)" must
2309 * not be used to endorse or promote products derived from this
2310 * software without prior written permission. For written
2311 * permission, please contact vocal@vovida.org.
2312 *
2313 * 4. Products derived from this software may not be called "VOCAL", nor
2314 * may "VOCAL" appear in their name, without prior written
2315 * permission of Vovida Networks, Inc.
2316 *
2317 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2318 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2319 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2320 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2321 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2322 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2323 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2324 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2325 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2326 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2327 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2328 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2329 * DAMAGE.
2330 *
2331 * ====================================================================
2332 *
2333 * This software consists of voluntary contributions made by Vovida
2334 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2335 * Inc. For more information on Vovida Networks, Inc., please see
2336 * <http://www.vovida.org/>.
2337 *
2338 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ServerInviteSessionAcceptCommand(const ServerInviteSessionHandle &serverInviteSessionHandle, int statusCode)
ServerInviteSessionProvisionalCommand(const ServerInviteSessionHandle &serverInviteSessionHandle, int statusCode, bool earlyFlag)
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ServerInviteSessionRedirectCommand(const ServerInviteSessionHandle &serverInviteSessionHandle, const NameAddrs &contacts, int code)
BaseUsageHandle getBaseHandle() const
Definition BaseUsage.cxx:36
DialogUsageManager & mDum
Definition BaseUsage.hxx:43
Base class for all SIP body types.
Definition Contents.hxx:51
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
std::shared_ptr< UserProfile > getUserProfile() const
std::shared_ptr< MasterProfile > & getMasterProfile()
void setAdvertisedCapabilities(SipMessage &msg, const std::shared_ptr< UserProfile > &userProfile)
virtual void send(std::shared_ptr< SipMessage > msg)
dcm! – kill typedef std::list<DialogId> DialogIdSet;
Definition Dialog.hxx:29
void makeRequest(SipMessage &request, MethodTypes method, bool incrementCSeq=true)
Definition Dialog.cxx:1033
void makeResponse(SipMessage &response, const SipMessage &request, int responseCode)
Definition Dialog.cxx:1108
static void setOutgoingEncryptionLevel(SipMessage &message, DialogUsageManager::EncryptionLevel level)
Definition DumHelper.cxx:11
Type type() const
unsigned int seq() const
unsigned int secondarySeq() const
virtual void onOfferRejected(InviteSessionHandle, const SipMessage *msg)=0
called if an offer in a UPDATE or re-INVITE was rejected - not real useful.
virtual void onAnswer(InviteSessionHandle, const SipMessage &msg, const SdpContents &)=0
called when an answer is received - has nothing to do with user answering the call
virtual void onOfferRequired(InviteSessionHandle, const SipMessage &msg)=0
called when an Invite w/out offer is sent, or any other context which requires an offer from the user
virtual void onConnectedConfirmed(InviteSessionHandle, const SipMessage &msg)
called when ACK (with out an answer) is received for initial invite (UAS)
virtual void onPrack(ServerInviteSessionHandle, const SipMessage &msg)
called when PRACK is received for a reliable provisional answer (UAS)
virtual void onTerminated(InviteSessionHandle, InviteSessionHandler::TerminatedReason reason, const SipMessage *related=0)=0
virtual void onOffer(InviteSessionHandle, const SipMessage &msg, const SdpContents &)=0
called when an offer is received - must send an answer soon after this
virtual void onNewSession(ClientInviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage &msg)=0
called when an initial INVITE or the intial response to an outoing invite
@ Referred
slg! - This is really Redirected - not sure why it is called Referred. Only gets used when we send a ...
virtual void onConnected(ClientInviteSessionHandle, const SipMessage &msg)=0
called when a dialog initiated as a UAC enters the connected state
Base class for class ClientInviteSession and class ServerInviteSession.
std::unique_ptr< Contents > getOfferAnswer(const SipMessage &msg)
void transition(State target)
void setCurrentLocalOfferAnswer(const SipMessage &msg)
std::shared_ptr< SipMessage > sendBye()
virtual void reject(int statusCode, WarningCategory *warning=0)
Rejects an offer at the SIP level.
std::shared_ptr< SipMessage > mInvite200
std::unique_ptr< Contents > mProposedRemoteOfferAnswer
std::unique_ptr< Contents > mProposedLocalOfferAnswer
std::unique_ptr< Contents > mCurrentLocalOfferAnswer
std::shared_ptr< SipMessage > mLastRemoteSessionModification
std::shared_ptr< SipMessage > mLastLocalSessionModification
virtual void requestOffer()
Called to request that the far end provide an offer.
virtual void end() override
static std::unique_ptr< Contents > makeOfferAnswer(const Contents &offerAnswer)
DialogUsageManager::EncryptionLevel mProposedEncryptionLevel
unsigned long mCurrentRetransmit200
void storePeerCapabilities(const SipMessage &msg)
InviteSessionHandle getSessionHandle()
virtual void provideAnswer(const Contents &answer)
Similar to provideOffer - called to set the answer to be signaled to the peer.
void dispatchMessage(const SipMessage &msg)
bool updateMethodSupported() const
static void setOfferAnswer(SipMessage &msg, const Contents &offerAnswer, const Contents *alternative=0)
std::unique_ptr< Contents > mCurrentRemoteOfferAnswer
void dispatchInfo(const SipMessage &msg)
void dispatch(const SipMessage &msg) override
Event toEvent(const SipMessage &msg, const Contents *offeranswer)
void handleSessionTimerRequest(SipMessage &response, const SipMessage &request)
DialogUsageManager::EncryptionLevel getEncryptionLevel(const SipMessage &msg)
virtual void provideOffer(const Contents &offer)
Called to set the offer that will be used in the next message that sends an offer.
static Data toData(State state)
ParserContainer< Token > mUserEndReasons
DialogUsageManager::EncryptionLevel mCurrentEncryptionLevel
virtual Brief brief() const
return a facet for brief encoding of message
Definition Message.cxx:16
An iterator class (bidirectional)
static int getRandom()
Returns a postive integer (31 bits) of randomness.
Definition Random.cxx:261
MethodTypes & method()
void redirect(const NameAddrs &contacts, int code=302)
send a 3xx
void redirectCommand(const NameAddrs &contacts, int code=302)
Provide asynchronous method access by using command.
virtual void reject(int statusCode, WarningCategory *warning=0)
Rejects an offer at the SIP level.
void accept(int statusCode=200)
accept an initial invite (2xx) - this is only applicable to the UAS
virtual void provideAnswer(const Contents &answer)
Similar to provideOffer - called to set the answer to be signaled to the peer.
ServerInviteSession(const ServerInviteSession &)=delete
void acceptCommand(int statusCode=200)
virtual void provideOffer(const Contents &offer)
Called to set the offer that will be used in the next message that sends an offer.
virtual void requestOffer()
Called to request that the far end provide an offer.
void provisionalCommand(int code=180, bool earlyFlag=true)
void provisional(int code=180, bool earlyFlag=true)
send a 1xx - provisional response.
Handle< ServerInviteSession > ServerInviteSessionHandle
ServerInviteSessionHandle getHandle()
Represents a SIP message.
bool isRequest() const
Returns true if message is a request, false otherwise.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
static const char * C100rel
Definition Symbols.hxx:107
static unsigned long T1
Definition Timer.hxx:114
Represents the "token" element in the RFC 3261 grammar.
Definition Token.hxx:18
void post(Message *msg)
Posts a Message to this TransactionUser's fifo.
Represents the "warning-value" element in the RFC 3261 grammar.
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
Definition Headers.cxx:348
RequestLineType h_RequestLine
Definition Headers.cxx:347
#define EncodeStream