24#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
32 mId(
"INVALID",
"INVALID",
"INVALID"),
33 mClientSubscriptions(),
34 mServerSubscriptions(),
41 mPendingRemoteTargetCSeq(0),
45 mCallId(msg.header(h_CallID)),
48 mReUseDialogSet(false)
56 mNetworkAssociation.
setDum(&dum);
78 if (request.
exists(h_RecordRoutes))
80 mRouteSet = request.
header(h_RecordRoutes);
93 mRemoteNameAddr = request.
header(h_From);
94 mLocalNameAddr = request.
header(h_To);
96 if (request.
exists(h_Contacts) && request.
header(h_Contacts).size() == 1)
103 mRemoteTarget = contact;
106 if(mDialogSet.mUserProfile->hasUserAgentCapabilities())
108 mLocalContact = mDialogSet.mUserProfile->getUserAgentCapabilities();
110 if(!mDialogSet.mUserProfile->isAnonymous() && mDialogSet.mUserProfile->hasPublicGruu())
112 mLocalContact.
uri() = mDialogSet.mUserProfile->getPublicGruu();
114 else if(mDialogSet.mUserProfile->isAnonymous() && mDialogSet.mUserProfile->hasTempGruu())
116 mLocalContact.
uri() = mDialogSet.mUserProfile->getTempGruu();
120 if (mDialogSet.mUserProfile->hasOverrideHostAndPort())
122 mLocalContact.
uri() = mDialogSet.mUserProfile->getOverrideHostAndPort();
153 const Data& instanceId = mDialogSet.mUserProfile->getInstanceId();
156 mLocalContact.
param(p_Instance) = instanceId;
159 if(mDialogSet.mUserProfile->clientOutboundEnabled())
167 InfoLog(<<
"Got an INVITE or SUBSCRIBE with invalid scheme");
169 throw Exception(
"Invalid scheme in request", __FILE__, __LINE__);
174 InfoLog (<<
"Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
176 throw Exception(
"Too many (or no contact) contacts in request", __FILE__, __LINE__);
183 mRemoteCSeq = request.
header(h_CSeq).sequence();
192 mLocalCSeq = creator->
getLastRequest()->header(h_CSeq).sequence();
199 DebugLog ( <<
"************** Created Dialog as UAS **************" );
200 DebugLog ( <<
"mRemoteNameAddr: " << mRemoteNameAddr );
201 DebugLog ( <<
"mLocalNameAddr: " << mLocalNameAddr );
202 DebugLog ( <<
"mLocalContact: " << mLocalContact );
203 DebugLog ( <<
"mRemoteTarget: " << mRemoteTarget );
209 mRemoteNameAddr = response.
header(h_To);
210 mLocalNameAddr = response.
header(h_From);
220 mType = Subscription;
227 if (response.
exists(h_RecordRoutes))
229 mRouteSet = response.
header(h_RecordRoutes).reverse();
241 if (response.
exists(h_Contacts) && response.
header(h_Contacts).size() == 1)
250 ErrLog(<<
"BaseCreator is null for DialogSet");
252 throw Exception(
"BaseCreator is null for DialogSet", __FILE__, __LINE__);
258 !lastRequest->exists(h_Contacts) ||
259 lastRequest->header(h_Contacts).empty())
261 InfoLog(<<
"lastRequest does not contain a valid contact");
263 throw Exception(
"lastRequest does not contain a valid contact.", __FILE__, __LINE__);
265 mLocalContact = lastRequest->header(h_Contacts).front();
266 mRemoteTarget = contact;
270 InfoLog (<<
"Got an INVITE or SUBSCRIBE with invalid scheme");
272 throw Exception(
"Bad scheme in contact in response", __FILE__, __LINE__);
277 InfoLog (<<
"Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
279 throw Exception(
"Too many contacts (or no contact) in response", __FILE__, __LINE__);
287 mLocalCSeq = response.
header(h_CSeq).sequence();
289 DebugLog ( <<
"************** Created Dialog as UAC **************" );
290 DebugLog ( <<
"mRemoteNameAddr: " << mRemoteNameAddr );
291 DebugLog ( <<
"mLocalNameAddr: " << mLocalNameAddr );
292 DebugLog ( <<
"mLocalContact: " << mLocalContact );
293 DebugLog ( <<
"mRemoteTarget: " << mRemoteTarget );
296 DebugLog ( <<
"Dialog::Dialog " << mId);
305 while (!mClientSubscriptions.empty())
307 delete *mClientSubscriptions.begin();
310 while (!mServerSubscriptions.empty())
312 delete *mServerSubscriptions.begin();
315 delete mInviteSession;
316 mDialogSet.mDialogs.erase(this->
getId());
320 mDialogSet.possiblyDie();
333 return mLocalNameAddr;
339 return mLocalContact;
345 return mRemoteNameAddr;
351 return mRemoteTarget;
357 return mPendingRemoteTarget;
382 if (endReasons.
size() > 0)
384 mInviteSession->
end(endReasons);
387 else if (endReason.
size() > 0)
389 mInviteSession->
end(endReason);
393 mInviteSession->
end();
400 for (list<ClientSubscription*>::iterator it(mClientSubscriptions.begin());
401 it != mClientSubscriptions.end();)
408 for (list<ServerSubscription*>::iterator it2(mServerSubscriptions.begin());
409 it2 != mServerSubscriptions.end();)
418Dialog::handleTargetRefresh(
const SipMessage& msg)
420 if (msg.
exists(h_Contacts))
435 if (!(mRemoteTarget == msg.
header(h_Contacts).front()))
437 mPendingRemoteTarget = msg.
header(h_Contacts).front();
438 mPendingRemoteTargetCSeq = msg.
header(h_CSeq).sequence();
443 mRemoteTarget = msg.
header(h_Contacts).front();
454Dialog::handlePendingTargetRefresh(
const SipMessage& msg)
460 if (mPendingRemoteTargetCSeq == msg.
header(h_CSeq).sequence())
466 mRemoteTarget = mPendingRemoteTarget;
470 mPendingRemoteTargetCSeq = 0;
486 msg.
header(h_Vias).front().transport());
487 int keepAliveTime = 0;
490 keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream();
494 keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForDatagram();
497 if(keepAliveTime > 0)
499 mNetworkAssociation.
update(msg, keepAliveTime,
false );
503 handleTargetRefresh(msg);
510 if (mInviteSession == 0)
512 DebugLog ( <<
"Dialog::dispatch -- Created new server invite session" << msg.
brief());
513 mInviteSession = makeServerInviteSession(request);
519 if (mInviteSession == 0)
530 if (mInviteSession == 0)
532 InfoLog ( <<
"Spurious UPDATE" );
541 if (mInviteSession == 0)
543 InfoLog ( <<
"Spurious INFO" );
552 if (mInviteSession == 0)
554 InfoLog ( <<
"Spurious MESSAGE" );
563 if (mInviteSession == 0)
565 InfoLog ( <<
"Spurious OPTIONS" );
574 if (mInviteSession == 0)
576 InfoLog ( <<
"Spurious PRACK" );
586 if (mInviteSession == 0)
588 InfoLog (<<
"Drop stray ACK or CANCEL in dialog on the floor");
605 if (request.
exists(h_Event) && request.
header(h_Event).value() ==
"refer")
607 InfoLog (<<
"Received a subscribe to a non-existent refer subscription: " << request.
brief());
610 mDum.sendResponse(failure);
615 if (mDum.checkEventPackage(request))
617 server = makeServerSubscription(request);
618 mServerSubscriptions.push_back(server);
627 if (!request.
exists(h_ReferTo))
629 InfoLog (<<
"Received refer w/out a Refer-To: " << request.
brief());
632 mDum.sendResponse(failure);
637 if ((request.
exists(h_ReferSub) &&
639 request.
header(h_ReferSub).value()==
"false") ||
640 (request.
exists(h_Requires) &&
641 request.
header(h_Requires).find(
Token(
"norefersub"))))
643 if (mInviteSession == 0)
645 InfoLog(<<
"Received an in dialog refer with no subscription in a non-invite dialog: " << request.
brief());
648 mDum.sendResponse(failure);
664 server = makeServerSubscription(request);
665 mServerSubscriptions.push_back(server);
684 client->dispatch(request);
694 mClientSubscriptions.push_back(sub);
695 sub->dispatch(request);
699 if (mInviteSession != 0 && (!msg.
exists(h_Event) || msg.
header(h_Event).value() ==
"refer") &&
702 DebugLog (<<
"Making subscription from NOTIFY: " << msg);
704 mClientSubscriptions.push_back(sub);
707 sub->dispatch(request);
711 auto response = std::make_shared<SipMessage>();
731 RequestMap::iterator r = mRequests.find(msg.
header(h_CSeq).sequence());
732 if (r != mRequests.end())
734 bool handledByAuth =
false;
735 if (mDum.mClientAuthManager.get() &&
736 mDum.mClientAuthManager->handle(*mDialogSet.mUserProfile, *r->second, msg))
738 InfoLog( <<
"about to re-send request with digest credentials" << r->second->brief());
744 handledByAuth =
true;
747 if (handledByAuth)
return;
755 if (creator && (creator->
getLastRequest()->header(h_CSeq) == response.
header(h_CSeq)) && code >=200 && code < 300)
757 if (response.
exists(h_RecordRoutes))
759 mRouteSet = response.
header(h_RecordRoutes).reverse();
786 if (mInviteSession == 0)
788 DebugLog ( <<
"Dialog::dispatch -- Created new client invite session" << msg.
brief());
790 mInviteSession = makeClientInviteSession(response);
797 ErrLog( <<
"Dialog::dispatch -- Unable to create invite session from response" << msg.
brief());
831 ((msg.
exists(h_ReferSub) && msg.
header(h_ReferSub).value()==
"false") ||
834 DebugLog(<<
"refer accepted with norefersub");
849 client->dispatch(response);
867 mClientSubscriptions.push_back(sub);
868 sub->dispatch(response);
885 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
886 it != mServerSubscriptions.end(); )
895 else if (code >= 200)
913Dialog::findMatchingServerSub(
const SipMessage& msg)
915 for (std::list<ServerSubscription*>::iterator i=mServerSubscriptions.begin();
916 i != mServerSubscriptions.end(); ++i)
918 if ((*i)->matches(msg))
927Dialog::findMatchingClientSub(
const SipMessage& msg)
929 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
930 i != mClientSubscriptions.end(); ++i)
932 if ((*i)->matches(msg))
953std::vector<ClientSubscriptionHandle>
956 std::vector<ClientSubscriptionHandle> handles;
958 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
959 i != mClientSubscriptions.end(); ++i)
961 if ( (*i)->getEventType() == event)
963 handles.push_back((*i)->getHandle());
969std::vector<ServerSubscriptionHandle>
972 std::vector<ServerSubscriptionHandle> handles;
974 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
975 i != mServerSubscriptions.end(); ++i)
977 if ( (*i)->getEventType() == event)
979 handles.push_back((*i)->getHandle());
985std::vector<ClientSubscriptionHandle>
988 std::vector<ClientSubscriptionHandle> handles;
990 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
991 i != mClientSubscriptions.end(); ++i)
993 handles.push_back((*i)->getHandle());
999std::vector<ServerSubscriptionHandle>
1002 std::vector<ServerSubscriptionHandle> handles;
1004 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
1005 i != mServerSubscriptions.end(); ++i)
1007 handles.push_back((*i)->getHandle());
1017 if (!mClientSubscriptions.empty() || !mServerSubscriptions.empty())
1026 cInv->handleRedirect(msg);
1027 mReUseDialogSet =
true;
1037 rLine.
uri() = mRemoteTarget.
uri();
1040 request.
header(h_To) = mRemoteNameAddr;
1042 request.
header(h_From) = mLocalNameAddr;
1047 request.
remove(h_RecordRoutes);
1048 request.
remove(h_Replaces);
1050 request.
remove(h_Contacts);
1051 request.
header(h_Contacts).push_front(mLocalContact);
1054 request.
header(h_MaxForwards).value() = 70;
1057 if (method != CANCEL)
1059 request.
header(h_Routes) = mRouteSet;
1062 via.
param(p_branch);
1063 request.
header(h_Vias).push_front(via);
1071 if (method != ACK && method != CANCEL)
1081 request.
remove(h_Accepts);
1082 request.
remove(h_AcceptEncodings);
1083 request.
remove(h_AcceptLanguages);
1084 request.
remove(h_Allows);
1085 request.
remove(h_Requires);
1086 request.
remove(h_ProxyRequires);
1087 request.
remove(h_Supporteds);
1092 if(method == INVITE || method == UPDATE)
1098 if (mDialogSet.mUserProfile->isAnonymous())
1100 request.
remove(h_Privacys);
1104 DebugLog ( <<
"Dialog::makeRequest: " << std::endl << std::endl << request );
1111 response.
remove(h_Contacts);
1112 if (code < 300 && code > 100)
1137 && code >= 200 && code < 300)
1149 DebugLog ( <<
"Dialog::makeResponse: " << std::endl << std::endl << response);
1156 request.
header(h_CSeq).sequence() = ++mLocalCSeq;
1160Dialog::makeClientInviteSession(
const SipMessage& response)
1174Dialog::makeClientSubscription(
const SipMessage& request)
1180Dialog::makeServerInviteSession(
const SipMessage& request)
1186Dialog::makeServerSubscription(
const SipMessage& request)
1200 if (msg->isRequest() && msg->header(h_CSeq).method() != ACK)
1202 mRequests[msg->header(h_CSeq).sequence()] = msg;
1204 handlePendingTargetRefresh(*msg);
1214 uac->onForkAccepted();
1219Dialog::possiblyDie()
1223 if (mClientSubscriptions.empty() &&
1224 mServerSubscriptions.empty() &&
1234Dialog::flowTerminated()
1237 mNetworkAssociation.
clear();
1240 std::list<ServerSubscription*> tempServerList = mServerSubscriptions;
1241 for (std::list<ServerSubscription*>::iterator is=tempServerList.begin();
1242 is != tempServerList.end(); ++is)
1244 (*is)->flowTerminated();
1248 std::list<ClientSubscription*> tempClientList = mClientSubscriptions;
1249 for (std::list<ClientSubscription*>::iterator ic=tempClientList.begin();
1250 ic != tempClientList.end(); ++ic)
1252 (*ic)->flowTerminated();
1266 <<
"mClientSubscriptions("
1267 << dialog.mClientSubscriptions.size()
1269 <<
"mServerSubscriptions("
1270 << dialog.mServerSubscriptions.size()
websocketpp::client< websocketpp::config::asio_client > client
#define resip_assert(x)
This file needs to work for both C and C++ code.
std::shared_ptr< SipMessage > getLastRequest() const noexcept
The abstract base-class for all exceptions thrown by resip code.
dcm! – update contact in dialog if required
ClientSubscriptionHandle getHandle()
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
static const Data Empty
Constant that represents a zero-length data.
bool empty() const noexcept
Checks whether the Data is empty.
size_type size() const noexcept
Returns the number of bytes in this Data.
const Data & getLocalTag() const
BaseCreator * getCreator() const noexcept
DialogSetId getId() const
void send(std::shared_ptr< SipMessage > request)
ClientSubscriptionHandler * getClientSubscriptionHandler(const Data &eventType)
void setAdvertisedCapabilities(SipMessage &msg, const std::shared_ptr< UserProfile > &userProfile)
Exception(const Data &msg, const Data &file, int line)
dcm! – kill typedef std::list<DialogId> DialogIdSet;
Dialog(DialogUsageManager &dum, const SipMessage &msg, DialogSet &ds)
friend class ClientSubscription
const NameAddr & getRemoteNameAddr() const noexcept
std::vector< ClientSubscriptionHandle > findClientSubscriptions(const Data &event)
const NameAddr & getRemoteTarget() const noexcept
const NameAddr & getLocalNameAddr() const noexcept
void redirected(const SipMessage &msg)
const NameAddr & getLocalContact() const noexcept
void makeRequest(SipMessage &request, MethodTypes method, bool incrementCSeq=true)
void end(const Data &endReason, const ParserContainer< Token > &endReasons)
const DialogId & getId() const noexcept
const NameAddrs & getRouteSet() const noexcept
void setRequestNextCSeq(SipMessage &request)
friend class ServerSubscription
InviteSessionHandle getInviteSession()
std::vector< ServerSubscriptionHandle > getServerSubscriptions()
std::vector< ServerSubscriptionHandle > findServerSubscriptions(const Data &event)
void dispatch(const SipMessage &msg)
void makeResponse(SipMessage &response, const SipMessage &request, int responseCode)
friend class ClientInviteSession
const NameAddr & getPendingRemoteTarget() const
std::vector< ClientSubscriptionHandle > getClientSubscriptions()
friend class ServerInviteSession
void send(std::shared_ptr< SipMessage > msg)
static Handle< T > NotValid()
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.
ServerSubscriptionHandle getServerSubscription()
const Contents * getInitialOffer() const
DialogUsageManager::EncryptionLevel getEncryptionLevel() const
virtual void onReferRejected(InviteSessionHandle, const SipMessage &msg)=0
called when an REFER message receives a failure response
virtual void onRefer(InviteSessionHandle, ServerSubscriptionHandle, const SipMessage &msg)=0
called when an REFER message is received.
virtual void onReferAccepted(InviteSessionHandle, ClientSubscriptionHandle, const SipMessage &msg)=0
called when an REFER message receives an accepted response
virtual void flowTerminated()
virtual void end(const Data &userReason)
Makes the specific dialog end.
InviteSessionHandle getSessionHandle()
void referNoSub(const SipMessage &msg)
void dispatch(const SipMessage &msg) override
bool isWellFormed() const
Returns true iff this element was parsed successfully, according to the implementation of parse().
virtual Brief brief() const
return a facet for brief encoding of message
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
void setDum(DialogUsageManager *dum)
bool update(const SipMessage &msg, int keepAliveInterval, bool targetSupportsOutbound)
void clear()
clear the mParsers vector
size_t size() const
return the size of the mParsers vector
Represents the "token" element in the RFC 3261 grammar.
Represents the "Request-Line" element in the RFC 3261 grammar.
MethodTypes getMethod() const
dcm! – no Subscription State expires parameter generation yet.
void dispatch(const SipMessage &msg) override
void end(TerminateReason reason, const Contents *document=0, int retryAfter=0)
ServerSubscriptionHandle getHandle() const
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 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 isFromWire() const
Check if SipMessage came off the wire.
void remove(const HeaderBase &headerType)
Prevents a header field from being present when the message is prepared for sending to a transport.
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.
bool isUserRelevant() const
Checks if this URI's scheme has sip:/sips:/tel: user-part semantics, i.e.
bool exists(const Param< Uri > ¶mType) const
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
Represents the "via-parm" element in the RFC 3261 grammar.
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
bool isEqualNoCase(const Data &left, const Data &right)
TransportType toTransportType(const resip::Data &transportName)
TransportType
An enumeration of transport protocols.
RequestLineType h_RequestLine
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)
bool isReliable(TransportType type)
Returns true if passed in transport type is a reliable transport protocol.