30#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
40 mId(*creator->getLastRequest()),
44 mClientRegistration(0),
45 mServerRegistration(0),
46 mClientPublication(0),
47 mClientOutOfDialogRequests(),
48 mServerOutOfDialogRequest(0),
49 mClientPagerMessage(0),
50 mServerPagerMessage(0)
54 DebugLog ( <<
" ************* Created DialogSet(UAC) -- " << mId <<
"*************" );
59 mMergeKey(request, dum.getMasterProfile()->checkReqUriInMergeDetectionEnabled()),
66 mClientRegistration(0),
67 mServerRegistration(0),
68 mClientPublication(0),
69 mClientOutOfDialogRequests(),
70 mServerOutOfDialogRequest(0),
71 mClientPagerMessage(0),
72 mServerPagerMessage(0)
76 mDum.mMergedRequests.insert(mMergeKey);
81 auto it = mDum.mCancelMap.find(mCancelKey);
82 if (it != mDum.mCancelMap.end())
84 WarningLog ( <<
"An endpoint is using the same tid in multiple INVITE requests, ability to match CANCEL requests correctly may be comprimised, tid=" << mCancelKey );
89 mDum.mCancelMap[mCancelKey] =
this;
92 DebugLog ( <<
" ************* Created DialogSet(UAS) *************: " << mId);
97 if (mDum.mClientAuthManager)
99 mDum.mClientAuthManager->dialogSetDestroyed(
getId());
104 mDum.requestMergedRequestRemoval(mMergeKey);
107 if (!mCancelKey.
empty())
109 mDum.mCancelMap.erase(mCancelKey);
113 while(!mDialogs.empty())
115 delete mDialogs.begin()->second;
118 delete mClientRegistration;
119 delete mServerRegistration;
120 delete mClientPublication;
121 delete mServerOutOfDialogRequest;
122 delete mClientPagerMessage;
123 delete mServerPagerMessage;
125 while (!mClientOutOfDialogRequests.empty())
127 delete *mClientOutOfDialogRequests.begin();
130 DebugLog ( <<
" ********** DialogSet::~DialogSet: " << mId <<
"*************" );
133 mDum.removeDialogSet(this->
getId());
140void DialogSet::possiblyDie()
142 if(mState != Destroying &&
150 (
getCreator() == 0 || (mState != Initial && mState != ReceivedProvisional)) &&
151 mClientOutOfDialogRequests.empty() &&
152 !(mClientPublication ||
153 mServerOutOfDialogRequest ||
154 mClientPagerMessage ||
155 mServerPagerMessage ||
156 mClientRegistration ||
157 mServerRegistration))
173 mDialogs[dialog->
getId()] = dialog;
195 return mDialogs.empty();
199DialogSet::handledByAuthOrRedirect(
const SipMessage& msg)
201 if (msg.
isResponse() && !(mState == Terminating ||
202 mState == WaitingToEnd ||
203 mState == Destroying ||
204 mState == Cancelling))
210 if (mDum.mClientAuthManager)
215 DebugLog( <<
"about to re-send request with digest credentials" );
225 if (mDum.mRedirectManager && mState != Established)
227 if (mDum.mRedirectManager->handle(*
this, *
getCreator()->getLastRequest(), msg))
234 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end();)
236 (it++)->second->redirected(msg);
239 if (mDialogs.empty())
241 if (mDum.mDialogEventStateManager)
247 InfoLog( <<
"about to re-send request to redirect destination" );
262 InfoLog( <<
"about to re-send request with new session expiration time" );
296 mDum.sendResponse(err);
301 ErrLog(<<
"Response came in, but no AppDialogSet! Dropping this is very "
302 "likely to cause leaks, but continuing to process it is "
303 "likely to cause a core. Taking the lesser of two evils...");
310 if (mState == WaitingToEnd)
330 mState = ReceivedProvisional;
333 else if (code / 100 == 2)
335 Dialog dialog(mDum, msg, *
this);
337 auto ack = std::make_shared<SipMessage>();
339 ack->header(h_CSeq).sequence() = msg.
header(h_CSeq).sequence();
342 auto bye = std::make_shared<SipMessage>();
344 addEndReasonToMessage(*bye);
347 if (mDum.mDialogEventStateManager)
355 if (mDum.mDialogEventStateManager)
370 Dialog dialog(mDum, msg, *
this);
372 auto unsubscribe = std::make_shared<SipMessage>(*
getCreator()->getLastRequest());
374 unsubscribe->header(h_Expires).value() = 0;
375 dialog.
send(unsubscribe);
392 Dialog dialog(mDum, msg, *
this);
394 auto unpublish = std::make_shared<SipMessage>(*
getCreator()->getLastRequest());
396 unpublish->header(h_Expires).value() = 0;
397 dialog.
send(unpublish);
416 auto response = std::make_shared<SipMessage>();
417 mDum.makeResponse(*response, msg, 481);
422 else if(mState == Cancelling)
444 else if (code / 100 == 2)
446 Dialog dialog(mDum, msg, *
this);
448 auto ack = std::make_shared<SipMessage>();
450 ack->header(h_CSeq).sequence() = msg.
header(h_CSeq).sequence();
453 auto bye = std::make_shared<SipMessage>();
455 addEndReasonToMessage(*bye);
469 auto response = std::make_shared<SipMessage>();
470 mDum.makeResponse(*response, msg, 481);
476 if (handledByAuthOrRedirect(msg))
484 DialogMap::iterator i = mDialogs.find(
DialogId(msg));
485 if (i != mDialogs.end())
496 StackLog (<<
"Matching dialog is destroying, sending 481 " << endl << msg);
497 auto response = std::make_shared<SipMessage>();
498 mDum.makeResponse(*response, msg, 481);
503 StackLog (<<
"Matching dialog is destroying, dropping response message " << endl << msg);
509 DebugLog (<<
"Found matching dialog " << *dialog <<
" for " << endl << endl << msg);
514 StackLog (<<
"No matching dialog for " << endl << endl << msg);
532 auto response = std::make_shared<SipMessage>();
533 mDum.makeResponse(*response, msg, 400,
"New dialog UAS request received in UAC DialogSet");
549 auto response = std::make_shared<SipMessage>();
550 mDum.makeResponse(*response, msg, 481);
559 DebugLog(<<
"in dialog refer request");
562 else if (request.
header(h_To).exists(p_tag))
565 auto response = std::make_shared<SipMessage>();
566 mDum.makeResponse(*response, msg, 481);
571 else if((request.
exists(h_ReferSub) &&
573 request.
header(h_ReferSub).value()==
"false") ||
574 (request.
exists(h_Requires) &&
575 request.
header(h_Requires).find(
Token(
"norefersub"))))
578 DebugLog(<<
"out of dialog refer request with norefersub");
580 mServerOutOfDialogRequest = makeServerOutOfDialog(request);
581 mServerOutOfDialogRequest->
dispatch(request);
586 DebugLog(<<
"out of dialog refer request with refer sub");
596 else if (request.
header(h_To).exists(p_tag))
599 auto response = std::make_shared<SipMessage>();
600 mDum.makeResponse(*response, msg, 481);
609 mServerOutOfDialogRequest = makeServerOutOfDialog(request);
610 mServerOutOfDialogRequest->
dispatch(request);
621 if (mServerRegistration == 0)
623 mServerRegistration = makeServerRegistration(request);
625 mServerRegistration->
dispatch(request);
632 mServerPagerMessage = makeServerPagerMessage(request);
633 mServerPagerMessage->
dispatch(request);
641 DebugLog(<<
"in dialog options request");
648 DebugLog ( <<
"In DialogSet::dispatch, default(ServerOutOfDialogRequest), msg: " << msg );
651 mServerOutOfDialogRequest = makeServerOutOfDialog(request);
652 mServerOutOfDialogRequest->
dispatch(request);
663 && msg.
exists(h_MinExpires)
669 DebugLog( <<
"Re sending inital(dialog forming) SUBSCRIBE due to 423, MinExpires is: " << msg.
header(h_MinExpires).value());
683 mState = ReceivedProvisional;
687 mState = Established;
691 mState = Established;
692 if (!mDialogs.empty())
694 dispatchToAllDialogs(msg);
699 case ReceivedProvisional:
706 mState = Established;
707 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
709 if (it->second != dialog)
711 it->second->onForkAccepted();
717 mState = Established;
718 if (!mDialogs.empty())
720 dispatchToAllDialogs(msg);
733 if (mDum.mDialogSetHandler)
752 mClientPublication = makeClientPublication(response);
754 if (mClientPublication)
756 mClientPublication->
dispatch(response);
763 mClientRegistration = makeClientRegistration(response);
765 if (mClientRegistration)
767 mClientRegistration->
dispatch(response);
776 else if (mClientPagerMessage)
778 mClientPagerMessage->
dispatch(response);
813 InfoLog(<<
"Cannot create a ClientOutOfDialogReq, initial dialog request is missing or cseq does not match, ignoring.");
816 req = makeClientOutOfDialogReq(response);
817 mClientOutOfDialogRequests.push_back(req);
829 if(!mDialogs.empty())
831 dispatchToAllDialogs(msg);
835 DebugLog ( <<
"In DialogSet::dispatch, CANCEL received but no dialogs to dispatch to - respond with 481, msg: " << msg );
838 auto response = std::make_shared<SipMessage>();
839 mDum.makeResponse(*response, msg, 481);
850 if (lastRequest && !(lastRequest->header(h_CSeq) == msg.
header(h_CSeq)))
852 InfoLog(<<
"Cannot create a dialog, cseq does not match initial dialog request (illegal mid-dialog fork? see 3261 14.1).");
858 ErrLog(<<
"Can't create a dialog, on a UAS response.");
864 if (code > 100 && code < 200 &&
865 (!msg.
exists(h_Contacts) ||
868 InfoLog ( <<
"Cannot create a dialog, no Contact or To tag in 1xx." );
869 if (mDum.mDialogSetHandler)
871 if (mDum.mDialogEventStateManager)
873 mDum.mDialogEventStateManager->onProceedingUac(*
this, msg);
880 else if (code >= 300 && !mDialogs.empty())
882 dispatchToAllDialogs(msg);
887 DebugLog ( <<
"mState == " << mState <<
" Creating a new Dialog from msg: " << std::endl << std::endl <<msg);
891 dialog =
new Dialog(mDum, msg, *
this);
900 if(mDialogs.empty() &&
904 if (mDum.mDialogEventStateManager)
917 auto response = std::make_shared<SipMessage>();
918 mDum.makeResponse(*response, msg, 400);
922 if (mDum.mDialogEventStateManager)
934 DebugLog ( <<
"### Calling CreateAppDialog ###: " << std::endl << std::endl <<msg);
936 dialog->mAppDialog = appDialog;
937 appDialog->mDialog = dialog;
948DialogSet::findMatchingClientOutOfDialogReq(
const SipMessage& msg)
950 for (std::list<ClientOutOfDialogReq*>::iterator i=mClientOutOfDialogRequests.begin();
951 i != mClientOutOfDialogRequests.end(); ++i)
953 if ((*i)->matches(msg))
962DialogSet::findDialog(
const DialogId id)
966 DialogMap::iterator i = mDialogs.find(
id);
967 if (i == mDialogs.end())
973 if(i->second->isDestroying())
987 mEndReason = endReason;
994 mEndReasons = endReasons;
999DialogSet::addEndReasonToMessage(
SipMessage& msg)
1001 if (mEndReasons.
size() > 0)
1003 msg.
header(h_Reasons) = mEndReasons;
1005 else if (mEndReason.
size() > 0)
1007 Token reason(
"SIP");
1008 reason.param(p_text) = mEndReason;
1010 reason.getParameterByEnum(ParameterTypes::text)->setQuoted(
true);
1011 msg.
header(h_Reasons).push_back(reason);
1021 mState = WaitingToEnd;
1025 case ReceivedProvisional:
1029 mState = Terminating;
1032 addEndReasonToMessage(*cancel);
1035 if (mDum.mDialogEventStateManager)
1040 if (mDialogs.empty())
1042 mState = Cancelling;
1048 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
1052 it->second->cancel();
1064 if (mDialogs.empty())
1066 mState = WaitingToEnd;
1070 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); ++it)
1074 it->second->end(mEndReason, mEndReasons);
1081 mState = Terminating;
1088 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); ++it)
1092 it->second->end(mEndReason, mEndReasons);
1099 mState = Terminating;
1105 DebugLog (<<
"DialogSet::end() called on a DialogSet that is already Terminating");
1114 if (mClientRegistration)
1116 return mClientRegistration->
getHandle();
1127 if (mServerRegistration)
1129 return mServerRegistration->
getHandle();
1140 if (mClientPublication)
1151DialogSet::makeClientRegistration(
const SipMessage& response)
1159DialogSet::makeClientPublication(
const SipMessage& response)
1167DialogSet::makeClientOutOfDialogReq(
const SipMessage& response)
1175DialogSet::makeServerRegistration(
const SipMessage& request)
1181DialogSet::makeServerOutOfDialog(
const SipMessage& request)
1187DialogSet::makeServerPagerMessage(
const SipMessage& request)
1195 if (mServerOutOfDialogRequest)
1197 return mServerOutOfDialogRequest->
getHandle();
1205void DialogSet::dispatchToAllDialogs(
const SipMessage& msg)
1207 if (!mDialogs.empty())
1209 for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
1211 it->second->dispatch(msg);
1216std::shared_ptr<UserProfile>
1227 mUserProfile = userProfile;
1231DialogSet::flowTerminated(
const Tuple& flow)
1234 mUserProfile->clearClientOutboundFlowTuple();
1240 if(mClientRegistration)
1242 mClientRegistration->flowTerminated();
1245 for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
1247 it->second->flowTerminated();
1255 strm <<
"state=" << ds.mState;
#define WarningLog(args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
virtual AppDialog * createAppDialog(const SipMessage &)
AppDialogSetHandle getHandle()
std::shared_ptr< UserProfile > getUserProfile() const noexcept
std::shared_ptr< SipMessage > getLastRequest() const noexcept
The abstract base-class for all exceptions thrown by resip code.
const Data & getMessage() const noexcept
virtual void dispatch(const SipMessage &msg)
void dispatch(const SipMessage &msg) override
ClientPublicationHandle getHandle()
dcm! – shutdown/deletion API – end?
ClientRegistrationHandle getHandle()
void dispatch(const SipMessage &msg) override
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
bool empty() const noexcept
Checks whether the Data is empty.
size_type size() const noexcept
Returns the number of bytes in this Data.
virtual void onTrying(AppDialogSetHandle, const SipMessage &msg)=0
virtual void onNonDialogCreatingProvisional(AppDialogSetHandle, const SipMessage &msg)=0
friend class ClientOutOfDialogReq
friend class ServerRegistration
ClientPublicationHandle getClientPublication()
friend class ClientRegistration
BaseCreator * getCreator() const noexcept
friend class ClientPublication
ServerRegistrationHandle getServerRegistration()
ServerOutOfDialogReqHandle getServerOutOfDialog()
friend class ServerOutOfDialogReq
void dispatch(const SipMessage &msg)
void setUserProfile(std::shared_ptr< UserProfile > userProfile)
bool empty() const noexcept
ClientRegistrationHandle getClientRegistration()
friend class ServerPagerMessage
DialogSet(BaseCreator *creator, DialogUsageManager &dum)
std::shared_ptr< UserProfile > getUserProfile() const
DialogSetId getId() const
void send(std::shared_ptr< SipMessage > request)
std::shared_ptr< UserProfile > & getMasterUserProfile()
dcm! – kill typedef std::list<DialogId> DialogIdSet;
void makeRequest(SipMessage &request, MethodTypes method, bool incrementCSeq=true)
bool isDestroying() const noexcept
const DialogId & getId() const noexcept
void dispatch(const SipMessage &msg)
void send(std::shared_ptr< SipMessage > msg)
static Handle< T > NotValid()
static SipMessage * makeCancel(const SipMessage &request)
Make a new Cancel request for the specified request.
static void makeResponse(SipMessage &response, const SipMessage &request, int responseCode, const Data &reason=Data::Empty, const Data &hostname=Data::Empty, const Data &warning=Data::Empty)
Make a response to a provided request.
bool isWellFormed() const
Returns true iff this element was parsed successfully, according to the implementation of parse().
static const MergedRequestKey Empty
size_t size() const
return the size of the mParsers vector
Container class for ParserCategory, used by SipMessage to represent multi-valued headers (Contact,...
ServerOutOfDialogReqHandle getHandle()
void dispatch(const SipMessage &msg) override
ServerRegistrationHandle getHandle()
void dispatch(const SipMessage &msg) override
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.
virtual const Data & getTransactionId() const
Returns the transaction id from the branch or if 2543, the computed hash.
bool isResponse() const
Returns true if message is a response, false otherwise.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
bool isExternal() const
Check if SipMessage is to be treated as it came off the wire.
resip::MethodTypes method() const
returns the method type of the message
Represents the "token" element in the RFC 3261 grammar.
Represents a network address.
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
InserterPClass< T > InserterP(const T &t)
Templatized function to construct an instance of InserterClass for a container to be inserted.
RequestLineType h_RequestLine
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)