reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
DialogUsageManager.cxx
Go to the documentation of this file.
1
2#if defined(HAVE_CONFIG_H)
3 #include "config.h"
4#endif
5
27#include "resip/dum/Dialog.hxx"
64#include "rutil/ResipAssert.h"
65#include "rutil/Inserter.hxx"
66#include "rutil/Logger.hxx"
67#include "rutil/Random.hxx"
68#include "rutil/Mutex.hxx"
69#include "rutil/Timer.hxx"
71
72#ifdef USE_SSL
75#endif
76
77#include <utility>
78
79#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
80
81using namespace resip;
82using namespace std;
83
84#ifdef RESIP_DUM_THREAD_DEBUG
85#define threadCheck() \
86 do \
87 { \
88 if(mThreadDebugKey) \
89 { \
90 resip_assert(ThreadIf::tlsGetValue(mThreadDebugKey)); \
91 } \
92 } while (false)
93#else
94#define threadCheck() void()
95#endif
96
97
98DialogUsageManager::DialogUsageManager(SipStack& stack, bool createDefaultFeatures) :
99 TransactionUser(TransactionUser::DoNotRegisterForTransactionTermination,
100 TransactionUser::RegisterForConnectionTermination,
101 TransactionUser::RegisterForKeepAlivePongs),
102 mRedirectManager(new RedirectManager()),
103 mInviteSessionHandler(0),
104 mClientRegistrationHandler(0),
105 mServerRegistrationHandler(0),
106 mRedirectHandler(0),
107 mDialogSetHandler(0),
108 mRequestValidationHandler(0),
109 mRegistrationPersistenceManager(0),
110 mPublicationPersistenceManager(0),
111 mIsDefaultServerReferHandler(true),
112 mClientPagerMessageHandler(0),
113 mServerPagerMessageHandler(0),
114 mDialogEventStateManager(0),
115 mAppDialogSetFactory(new AppDialogSetFactory()),
116 mStack(stack),
117 mDumShutdownHandler(0),
118 mShutdownState(Running),
119 mThreadDebugKey(0),
120 mHiddenThreadDebugKey(0)
121{
122 //TODO -- create default features
123 mStack.registerTransactionUser(*this);
125
126 mFifo.setDescription("DialogUsageManager::mFifo");
127
128 mIncomingTarget = new IncomingTarget(*this);
129 mOutgoingTarget = new OutgoingTarget(*this);
130
131 if (createDefaultFeatures)
132 {
133 auto identity = std::make_shared<IdentityHandler>(*this, *mIncomingTarget);
134
135#if defined (USE_SSL)
136 auto encryptionIncoming = std::make_shared<EncryptionManager>(*this, *mIncomingTarget);
137 auto encryptionOutgoing = std::make_shared<EncryptionManager>(*this, *mOutgoingTarget);
138#endif
139
140 // default incoming features.
141 addIncomingFeature(identity);
142#if defined (USE_SSL)
143 addIncomingFeature(encryptionIncoming);
144#endif
145
146 // default outgoing features.
147#if defined (USE_SSL)
148 addOutgoingFeature(encryptionOutgoing);
149#endif
150 }
151}
152
154{
155 mShutdownState = Destroying;
156 //InfoLog ( << "~DialogUsageManager" );
157
158 if(!mDialogSetMap.empty())
159 {
160 DebugLog(<< "DialogUsageManager::mDialogSetMap has " << mDialogSetMap.size() << " DialogSets");
161 DialogSetMap::const_iterator ds = mDialogSetMap.begin();
162 for(; ds != mDialogSetMap.end(); ++ds)
163 {
164 DebugLog(<< "DialgSetId:" << ds->first);
165 DialogSet::DialogMap::const_iterator d = ds->second->mDialogs.begin();
166 for(; d != ds->second->mDialogs.end(); ++d)
167 {
168 //const Dialog* p = &(d->second);
169 DebugLog(<<"DialogId:" << d->first << ", " << *d->second);
170 }
171 }
172 }
173
174 while(!mDialogSetMap.empty())
175 {
176 DialogSet* ds = mDialogSetMap.begin()->second;
177 delete ds; // Deleting a dialog set removes itself from the map
178 }
179
180 if(mIsDefaultServerReferHandler)
181 {
182 delete mServerSubscriptionHandlers["refer"];
183 }
184
185 delete mIncomingTarget;
186 delete mOutgoingTarget;
187
188 // Delete Server Publications
189 while (!mServerPublications.empty())
190 {
191 delete mServerPublications.begin()->second; // Deleting a ServerPublication removes itself from the map
192 }
193
194 // Remove any lingering incoming feature chain memory
195 for(FeatureChainMap::iterator it = mIncomingFeatureChainMap.begin(); it != mIncomingFeatureChainMap.end(); it++)
196 {
197 delete it->second;
198 }
199
200 //InfoLog ( << "~DialogUsageManager done" );
201}
202
203const Data&
205{
206 static Data n("DialogUsageManager");
207 return n;
208}
209
210void
212 int port,
213 IpVersion version,
214 const Data& ipInterface,
215 const Data& sipDomainname, // only used
216 const Data& privateKeyPassPhrase,
218 unsigned transportFlags)
219{
220 mStack.addTransport(protocol, port, version, StunDisabled, ipInterface,
221 sipDomainname, privateKeyPassPhrase, sslType,
222 transportFlags);
223}
224
225SipStack&
227{
228 return mStack;
229}
230
231const SipStack&
233{
234 return mStack;
235}
236
239{
240 return mStack.getSecurity();
241}
242
243Data
245{
246 return mStack.getHostAddress();
247}
248
249void
251{
252 if (mDumShutdownHandler)
253 {
254 switch (mShutdownState)
255 {
256 case ShutdownRequested:
257 InfoLog (<< "DialogUsageManager::onAllHandlesDestroyed: removing TU");
258 //resip_assert(mHandleMap.empty());
259 mShutdownState = RemovingTransactionUser;
260 mStack.unregisterTransactionUser(*this);
261 break;
262 default:
263 break;
264 }
265 }
266}
267
268
269void
271{
272 InfoLog (<< "shutdown: dialogSets=" << mDialogSetMap.size());
273
274 mDumShutdownHandler = h;
275 mShutdownState = ShutdownRequested;
276 mStack.requestTransactionUserShutdown(*this);
278}
279
280// void
281// DialogUsageManager::shutdownIfNoUsages(DumShutdownHandler* h)
282// {
283// InfoLog (<< "shutdown when no usages");
284//
285// mDumShutdownHandler = h;
286// mShutdownState = ShutdownRequested;
287// resip_assert(0);
288// }
289
290void
292{
293 WarningLog (<< "force shutdown ");
294 dumpHandles();
295
296 mDumShutdownHandler = h;
297 //HandleManager::shutdown(); // clear out usages
298 mShutdownState = ShutdownRequested;
300}
301
302void DialogUsageManager::setAppDialogSetFactory(std::unique_ptr<AppDialogSetFactory> factory) noexcept
303{
304 mAppDialogSetFactory = std::move(factory);
305}
306
307std::shared_ptr<MasterProfile>&
309{
310 resip_assert(mMasterProfile.get());
311 return mMasterProfile;
312}
313
314std::shared_ptr<UserProfile>&
316{
317 resip_assert(mMasterUserProfile.get());
318 return mMasterUserProfile;
319}
320
321void DialogUsageManager::setMasterProfile(const std::shared_ptr<MasterProfile>& masterProfile)
322{
323 resip_assert(!mMasterProfile.get());
324 mMasterProfile = masterProfile;
325 mMasterUserProfile = masterProfile; // required so that we can return a reference to std::shared_ptr<UserProfile> in getMasterUserProfile
326}
327
328void DialogUsageManager::setKeepAliveManager(std::unique_ptr<KeepAliveManager> manager) noexcept
329{
330 mKeepAliveManager = std::move(manager);
331 mKeepAliveManager->setDialogUsageManager(this);
332}
333
334void DialogUsageManager::setRedirectManager(std::unique_ptr<RedirectManager> manager) noexcept
335{
336 mRedirectManager = std::move(manager);
337}
338
340{
341 mRedirectHandler = handler;
342}
343
345{
346 return mRedirectHandler;
347}
348
349void
350DialogUsageManager::setClientAuthManager(std::unique_ptr<ClientAuthManager> manager) noexcept
351{
352 mClientAuthManager = std::move(manager);
353}
354
355void
356DialogUsageManager::setServerAuthManager(std::shared_ptr<ServerAuthManager> manager)
357{
358 mIncomingFeatureList.emplace(std::begin(mIncomingFeatureList), manager);
359}
360
361void
363{
364 resip_assert(!mClientRegistrationHandler);
365 mClientRegistrationHandler = handler;
366}
367
368void
370{
371 resip_assert(!mServerRegistrationHandler);
372 mServerRegistrationHandler = handler;
373}
374
375void
377{
378 mDialogSetHandler = handler;
379}
380
381void
383{
384 resip_assert(!mInviteSessionHandler);
385 mInviteSessionHandler = handler;
386}
387
388void
390{
391 resip_assert(!mRequestValidationHandler);
392 mRequestValidationHandler = handler;
393}
394
395void
397{
398 resip_assert(!mRegistrationPersistenceManager);
399 mRegistrationPersistenceManager = manager;
400}
401
402void
404{
405 resip_assert(!mPublicationPersistenceManager);
406 mPublicationPersistenceManager = manager;
407}
408
409void
410DialogUsageManager::addTimer(DumTimeout::Type type, unsigned long duration,
411 BaseUsageHandle target, unsigned int cseq, unsigned int rseq)
412{
413 DumTimeout t(type, duration, target, cseq, rseq);
414 mStack.post(t, duration, this);
415}
416
417void
418DialogUsageManager::addTimerMs(DumTimeout::Type type, unsigned long duration,
419 BaseUsageHandle target, unsigned int cseq, unsigned int rseq,
420 const Data &transactionId /*= Data::Empty*/)
421{
422 DumTimeout t(type, duration, target, cseq, rseq, transactionId);
423 mStack.postMS(t, duration, this);
424}
425
426void
428{
429 resip_assert(handler);
430 resip_assert(mClientSubscriptionHandlers.find(eventType) == mClientSubscriptionHandlers.end());
431 mClientSubscriptionHandlers[eventType] = handler;
432}
433
434void
436{
437 resip_assert(handler);
438 //default do-nothing server side refer handler can be replaced
439 if (eventType == "refer")
440 {
441 auto it = mServerSubscriptionHandlers.find(eventType);
442 if (it != mServerSubscriptionHandlers.end())
443 {
444 delete it->second;
445 mIsDefaultServerReferHandler = false;
446 //mServerSubscriptionHandlers.erase(eventType);
447 }
448 }
449
450 mServerSubscriptionHandlers[eventType] = handler;
451}
452
453void
455{
456 resip_assert(handler);
457 resip_assert(mClientPublicationHandlers.find(eventType) == mClientPublicationHandlers.end());
458 mClientPublicationHandlers[eventType] = handler;
459}
460
461void
463{
464 resip_assert(handler);
465 resip_assert(mServerPublicationHandlers.find(eventType) == mServerPublicationHandlers.end());
466 mServerPublicationHandlers[eventType] = handler;
467}
468
469void
471{
472 resip_assert(handler);
473 resip_assert(mOutOfDialogHandlers.find(type) == mOutOfDialogHandlers.end());
474 mOutOfDialogHandlers[type] = handler;
475}
476
477void
479{
480 mClientPagerMessageHandler = handler;
481}
482
483void
485{
486 mServerPagerMessageHandler = handler;
487}
488
489void
491{
492 std::vector<ExternalMessageHandler*>::iterator found = std::find(mExternalMessageHandlers.begin(), mExternalMessageHandlers.end(), handler);
493 if (found == mExternalMessageHandlers.end())
494 {
495 mExternalMessageHandlers.push_back(handler);
496 }
497}
498
499void
501{
502 std::vector<ExternalMessageHandler*>::iterator found = std::find(mExternalMessageHandlers.begin(), mExternalMessageHandlers.end(), handler);
503 if (found != mExternalMessageHandlers.end())
504 {
505 mExternalMessageHandlers.erase(found);
506 }
507}
508
509void
511{
512 std::vector<ExternalMessageHandler*> empty;
513 empty.swap(mExternalMessageHandlers);
514}
515
516
518DialogUsageManager::makeUacDialogSet(BaseCreator* creator, AppDialogSet* appDs)
519{
520 threadCheck();
521 if (mDumShutdownHandler)
522 {
523 throw DumException("Cannot create new sessions when DUM is shutting down.", __FILE__, __LINE__);
524 }
525
526 if (appDs == 0)
527 {
528 appDs = new AppDialogSet(*this);
529 }
530 DialogSet* ds = new DialogSet(creator, *this);
531
532 appDs->mDialogSet = ds;
533 ds->mAppDialogSet = appDs;
534
535 StackLog ( << "************* Adding DialogSet ***************: " << ds->getId());
536 //StackLog ( << "Before: " << InserterP(mDialogSetMap) );
537 mDialogSetMap[ds->getId()] = ds;
538 StackLog ( << "DialogSetMap: " << InserterP(mDialogSetMap) );
539 return ds;
540}
541
542std::shared_ptr<SipMessage>
543DialogUsageManager::makeNewSession(BaseCreator* creator, AppDialogSet* appDs)
544{
545 makeUacDialogSet(creator, appDs);
546 return creator->getLastRequest();
547}
548
549void
550DialogUsageManager::makeResponse(SipMessage& response,
551 const SipMessage& request,
552 int responseCode,
553 const Data& reason) const
554{
555 resip_assert(request.isRequest());
556 Helper::makeResponse(response, request, responseCode, reason);
557}
558
559void
560DialogUsageManager::sendResponse(const SipMessage& response)
561{
562 resip_assert(response.isResponse());
563 mStack.send(response, this);
564}
565
566std::shared_ptr<SipMessage>
567DialogUsageManager::makeInviteSession(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, const Contents* initialOffer, AppDialogSet* appDs)
568{
569 return makeInviteSession(target, userProfile, initialOffer, None, nullptr, appDs);
570}
571
572std::shared_ptr<SipMessage>
573DialogUsageManager::makeInviteSession(const NameAddr& target, const Contents* initialOffer, AppDialogSet* appDs)
574{
575 return makeInviteSession(target, getMasterUserProfile(), initialOffer, None, nullptr, appDs);
576}
577
578std::shared_ptr<SipMessage>
580 const std::shared_ptr<UserProfile>& userProfile,
581 const Contents* initialOffer,
582 EncryptionLevel level,
583 const Contents* alternative,
584 AppDialogSet* appDs)
585{
586 auto inv = makeNewSession(new InviteSessionCreator(*this, target, userProfile, initialOffer, level, alternative), appDs);
588 return inv;
589}
590
591std::shared_ptr<SipMessage>
593 const Contents* initialOffer,
594 EncryptionLevel level,
595 const Contents* alternative,
596 AppDialogSet* appDs)
597{
598 return makeInviteSession(target, getMasterUserProfile(), initialOffer, level, alternative, appDs);
599}
600
601std::shared_ptr<SipMessage>
603 const DialogSetId& dialogSetId,
604 const std::shared_ptr<UserProfile>& userProfile,
605 const Contents* initialOffer,
606 EncryptionLevel level,
607 const Contents* alternative,
608 AppDialogSet* appDs)
609{
610 resip_assert(mDialogSetMap.find(dialogSetId) == mDialogSetMap.end());
611 BaseCreator* baseCreator(new InviteSessionCreator(*this, target, userProfile, initialOffer, level, alternative));
612 baseCreator->getLastRequest()->header(h_CallID).value() = dialogSetId.getCallId();
613 baseCreator->getLastRequest()->header(h_From).param(p_tag) = dialogSetId.getLocalTag();
614 auto inv = makeNewSession(baseCreator, appDs);
616 return inv;
617}
618
619std::shared_ptr<SipMessage>
621 InviteSessionHandle sessionToReplace,
622 const std::shared_ptr<UserProfile>& userProfile,
623 const Contents* initialOffer,
624 AppDialogSet* ads)
625{
626 auto inv = makeInviteSession(target, userProfile, initialOffer, ads);
627 // add replaces header
628 resip_assert(sessionToReplace.isValid());
629 if(sessionToReplace.isValid())
630 {
631 CallId replaces;
632 const DialogId& id = sessionToReplace->getDialogId();
633 replaces.value() = id.getCallId();
634 replaces.param(p_toTag) = id.getRemoteTag();
635 replaces.param(p_fromTag) = id.getLocalTag();
636 inv->header(h_Replaces) = replaces;
637 }
638 return inv;
639}
640
641std::shared_ptr<SipMessage>
643 InviteSessionHandle sessionToReplace,
644 const std::shared_ptr<UserProfile>& userProfile,
645 const Contents* initialOffer,
646 EncryptionLevel level,
647 const Contents* alternative,
648 AppDialogSet* ads)
649{
650 auto inv = makeInviteSession(target, userProfile, initialOffer, level, alternative, ads);
651 // add replaces header
652 resip_assert(sessionToReplace.isValid());
653 if(sessionToReplace.isValid())
654 {
655 CallId replaces;
656 const DialogId& id = sessionToReplace->getDialogId();
657 replaces.value() = id.getCallId();
658 replaces.param(p_toTag) = id.getRemoteTag();
659 replaces.param(p_fromTag) = id.getLocalTag();
660 inv->header(h_Replaces) = replaces;
661 }
662 return inv;
663}
664
665std::shared_ptr<SipMessage>
667 InviteSessionHandle sessionToReplace,
668 const Contents* initialOffer,
669 EncryptionLevel level,
670 const Contents* alternative ,
671 AppDialogSet* ads)
672{
673 auto inv = makeInviteSession(target, initialOffer, level, alternative, ads);
674 // add replaces header
675 resip_assert(sessionToReplace.isValid());
676 if(sessionToReplace.isValid())
677 {
678 CallId replaces;
679 const DialogId& id = sessionToReplace->getDialogId();
680 replaces.value() = id.getCallId();
681 replaces.param(p_toTag) = id.getRemoteTag();
682 replaces.param(p_fromTag) = id.getLocalTag();
683 inv->header(h_Replaces) = replaces;
684 }
685 return inv;
686}
687
688std::shared_ptr<SipMessage>
690 ServerSubscriptionHandle serverSub,
691 const Contents* initialOffer,
692 AppDialogSet* appDs)
693{
694 return makeInviteSessionFromRefer(refer, serverSub, initialOffer, None, 0, appDs);
695}
696
697std::shared_ptr<SipMessage>
699 const std::shared_ptr<UserProfile>& userProfile,
700 const Contents* initialOffer,
701 AppDialogSet* appDs)
702{
704 return makeInviteSessionFromRefer(refer, userProfile, empty, initialOffer, None, 0, appDs);
705}
706
707std::shared_ptr<SipMessage>
709 ServerSubscriptionHandle serverSub,
710 const Contents* initialOffer,
711 EncryptionLevel level,
712 const Contents* alternative,
713 AppDialogSet* appDs)
714{
715 return makeInviteSessionFromRefer(refer, serverSub.isValid() ? serverSub->mDialog.mDialogSet.getUserProfile() : getMasterUserProfile(), serverSub, initialOffer, level, alternative, appDs);
716}
717
718std::shared_ptr<SipMessage>
720 const std::shared_ptr<UserProfile>& userProfile,
721 ServerSubscriptionHandle serverSub,
722 const Contents* initialOffer,
723 EncryptionLevel level,
724 const Contents* alternative,
725 AppDialogSet* appDs)
726{
727 if (serverSub.isValid())
728 {
729 DebugLog(<< "implicit subscription");
730 //generate and send 100
731 SipFrag contents;
732 contents.message().header(h_StatusLine).statusCode() = 100;
733 contents.message().header(h_StatusLine).reason() = "Trying";
734 //will be cloned...ServerSub may not have the most efficient API possible
735 serverSub->setSubscriptionState(Active);
736 auto notify = serverSub->update(&contents);
737// mInviteSessionHandler->onReadyToSend(InviteSessionHandle::NotValid(), notify);
738 serverSub->send(notify);
739 }
740
741 //19.1.5
742 NameAddr target = refer.header(h_ReferTo);
743 target.uri().removeEmbedded();
744 target.uri().remove(p_method);
745
746 // !jf! this code assumes you have a UserProfile
747 auto inv = makeNewSession(new InviteSessionCreator(*this,
748 target,
749 userProfile,
750 initialOffer, level, alternative, serverSub), appDs);
752
753 //could pass dummy target, then apply merge rules from 19.1.5...or
754 //makeNewSession would use rules from 19.1.5
755 if (refer.exists(h_ReferredBy))
756 {
757 inv->header(h_ReferredBy) = refer.header(h_ReferredBy);
758 }
759
760 const Uri& referTo = refer.header(h_ReferTo).uri();
761 //19.1.5
762 if (referTo.hasEmbedded() && referTo.embedded().exists(h_Replaces))
763 {
764 inv->header(h_Replaces) = referTo.embedded().header(h_Replaces);
765 }
766
767 return inv;
768}
769
770std::shared_ptr<SipMessage>
771DialogUsageManager::makeRefer(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, const H_ReferTo::Type& referTo, AppDialogSet* appDs)
772{
773 return makeNewSession(new SubscriptionCreator(*this, target, userProfile, referTo), appDs);
774}
775
776std::shared_ptr<SipMessage>
777DialogUsageManager::makeRefer(const NameAddr& target, const H_ReferTo::Type& referTo, AppDialogSet* appDs)
778{
779 return makeNewSession(new SubscriptionCreator(*this, target, getMasterUserProfile(), referTo), appDs);
780}
781
782std::shared_ptr<SipMessage>
783DialogUsageManager::makeSubscription(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, const Data& eventType, AppDialogSet* appDs)
784{
785 resip_assert(userProfile.get());
786 return makeNewSession(new SubscriptionCreator(*this, target, userProfile, eventType, userProfile->getDefaultSubscriptionTime()), appDs);
787}
788
789std::shared_ptr<SipMessage>
790DialogUsageManager::makeSubscription(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, const Data& eventType,
791 uint32_t subscriptionTime, AppDialogSet* appDs)
792{
793 return makeNewSession(new SubscriptionCreator(*this, target, userProfile, eventType, subscriptionTime), appDs);
794}
795
796std::shared_ptr<SipMessage>
797DialogUsageManager::makeSubscription(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, const Data& eventType,
798 uint32_t subscriptionTime, int refreshInterval, AppDialogSet* appDs)
799{
800 return makeNewSession(new SubscriptionCreator(*this, target, userProfile, eventType, subscriptionTime, refreshInterval), appDs);
801}
802
803std::shared_ptr<SipMessage>
804DialogUsageManager::makeSubscription(const NameAddr& target, const Data& eventType, AppDialogSet* appDs)
805{
806 return makeNewSession(new SubscriptionCreator(*this, target, getMasterUserProfile(), eventType, getMasterProfile()->getDefaultSubscriptionTime()), appDs);
807}
808
809std::shared_ptr<SipMessage>
810DialogUsageManager::makeSubscription(const NameAddr& target, const Data& eventType,
811 uint32_t subscriptionTime, AppDialogSet* appDs)
812{
813 return makeNewSession(new SubscriptionCreator(*this, target, getMasterUserProfile(), eventType, subscriptionTime), appDs);
814}
815
816std::shared_ptr<SipMessage>
817DialogUsageManager::makeSubscription(const NameAddr& target, const Data& eventType,
818 uint32_t subscriptionTime, int refreshInterval, AppDialogSet* appDs)
819{
820 return makeNewSession(new SubscriptionCreator(*this, target, getMasterUserProfile(), eventType, subscriptionTime, refreshInterval), appDs);
821}
822
823std::shared_ptr<SipMessage>
824DialogUsageManager::makeRegistration(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, AppDialogSet* appDs)
825{
826 resip_assert(userProfile.get());
827 return makeNewSession(new RegistrationCreator(*this, target, userProfile, userProfile->getDefaultRegistrationTime()), appDs);
828}
829
830std::shared_ptr<SipMessage>
831DialogUsageManager::makeRegistration(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, uint32_t registrationTime, AppDialogSet* appDs)
832{
833 return makeNewSession(new RegistrationCreator(*this, target, userProfile, registrationTime), appDs);
834}
835
836std::shared_ptr<SipMessage>
838{
839 return makeNewSession(new RegistrationCreator(*this, target, getMasterUserProfile(), getMasterProfile()->getDefaultRegistrationTime()), appDs);
840}
841
842std::shared_ptr<SipMessage>
844{
845 return makeNewSession(new RegistrationCreator(*this, target, getMasterUserProfile(), registrationTime), appDs);
846}
847
848std::shared_ptr<SipMessage>
850 const std::shared_ptr<UserProfile>& userProfile,
851 const Contents& body,
852 const Data& eventType,
853 uint32_t expiresSeconds,
854 AppDialogSet* appDs)
855{
856 return makeNewSession(new PublicationCreator(*this, targetDocument, userProfile, body, eventType, expiresSeconds), appDs);
857}
858
859std::shared_ptr<SipMessage>
861 const Contents& body,
862 const Data& eventType,
863 uint32_t expiresSeconds,
864 AppDialogSet* appDs)
865{
866 return makeNewSession(new PublicationCreator(*this, targetDocument, getMasterUserProfile(), body, eventType, expiresSeconds), appDs);
867}
868
869std::shared_ptr<SipMessage>
870DialogUsageManager::makeOutOfDialogRequest(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, const MethodTypes meth, AppDialogSet* appDs)
871{
872 return makeNewSession(new OutOfDialogReqCreator(*this, meth, target, userProfile), appDs);
873}
874
875std::shared_ptr<SipMessage>
877{
878 return makeNewSession(new OutOfDialogReqCreator(*this, meth, target, getMasterUserProfile()), appDs);
879}
880
882DialogUsageManager::makePagerMessage(const NameAddr& target, const std::shared_ptr<UserProfile>& userProfile, AppDialogSet* appDs)
883{
884 if (!mClientPagerMessageHandler)
885 {
886 throw DumException("Cannot send MESSAGE messages without a ClientPagerMessageHandler", __FILE__, __LINE__);
887 }
888 DialogSet* ds = makeUacDialogSet(new PagerMessageCreator(*this, target, userProfile), appDs);
889 ClientPagerMessage* cpm = new ClientPagerMessage(*this, *ds);
890 ds->mClientPagerMessage = cpm;
891 return cpm->getHandle();
892}
893
896{
897 return makePagerMessage(target, getMasterUserProfile(), appDs);
898}
899
900void
901DialogUsageManager::send(std::shared_ptr<SipMessage> msg)
902{
903 // !slg! There is probably a more efficient way to get the userProfile here (pass it in?)
904 DialogSet* ds = findDialogSet(DialogSetId(*msg));
905 UserProfile* userProfile;
906 if (ds == 0)
907 {
908 userProfile = getMasterUserProfile().get();
909 }
910 else
911 {
912 userProfile = ds->getUserProfile().get();
913 }
914
915 resip_assert(userProfile);
916 if (!userProfile->isAnonymous() && userProfile->hasUserAgent())
917 {
918 msg->header(h_UserAgent).value() = userProfile->getUserAgent();
919 }
920 if (userProfile->isAnonymous())
921 {
922 msg->remove(h_ReplyTo);
923 msg->remove(h_UserAgent);
924 msg->remove(h_Organization);
925 msg->remove(h_Server);
926 msg->remove(h_Subject);
927 msg->remove(h_InReplyTo);
928
929 msg->remove(h_CallInfos);
930 msg->remove(h_Warnings);
931 }
932
933 resip_assert(userProfile);
934 if (msg->isRequest()
935 && userProfile->hasProxyRequires()
936 && msg->header(h_RequestLine).method() != ACK
937 && msg->header(h_RequestLine).method() != CANCEL)
938 {
939 msg->header(h_ProxyRequires) = userProfile->getProxyRequires();
940 }
941
942 // .bwc. This is to avoid leaving extra copies of the decorator in msg,
943 // when the caller of this function holds onto the reference (and this
944 // happens quite often in DUM). I would prefer to refactor such that we
945 // are operating on a copy in this function, but this would require a lot
946 // of work on the DumFeatureChain stuff (or, require an extra copy on top
947 // of the one we're doing when we send the message to the stack, which
948 // would chew up a lot of extra cycles).
949 msg->clearOutboundDecorators();
950
951 // Add outbound decorator from userprofile - note: it is important that this is
952 // done before the call to mClientAuthManager->addAuthentication, since the ClientAuthManager
953 // will install outbound decorators and we want these to run after the user provided ones, in
954 // case a user provided decorator modifies the message body used in auth.
955 const auto outboundDecorator = userProfile->getOutboundDecorator();
956 if (outboundDecorator)
957 {
958 msg->addOutboundDecorator(std::unique_ptr<MessageDecorator>(outboundDecorator->clone()));
959 }
960
961 if (msg->isRequest())
962 {
963 // We may not need to call reset() if makeRequest is always used.
964 if (msg->header(h_RequestLine).method() != CANCEL &&
965 msg->header(h_RequestLine).method() != ACK &&
966 msg->exists(h_Vias))
967 {
968 msg->header(h_Vias).front().param(p_branch).reset();
969 }
970
971 if (msg->exists(h_Vias))
972 {
973 if(userProfile->getRportEnabled())
974 {
975 msg->header(h_Vias).front().param(p_rport);
976 }
977 else
978 {
979 msg->header(h_Vias).front().remove(p_rport);
980 }
981 const int fixedTransportPort = userProfile->getFixedTransportPort();
982 if(fixedTransportPort != 0)
983 {
984 msg->header(h_Vias).front().sentPort() = fixedTransportPort;
985 }
986 const Data& fixedTransportInterface = userProfile->getFixedTransportInterface();
987 if(!fixedTransportInterface.empty())
988 {
989 msg->header(h_Vias).front().sentHost() = fixedTransportInterface;
990 }
991 }
992
993 if (mClientAuthManager.get() && msg->header(h_RequestLine).method() != ACK)
994 {
995 mClientAuthManager->addAuthentication(*msg);
996 }
997
998 if (msg->header(h_RequestLine).method() == INVITE)
999 {
1000 if (ds != 0)
1001 {
1002 if (mDialogEventStateManager)
1003 {
1004 Dialog* d = ds->findDialog(*msg);
1005 if (d == 0)
1006 {
1007 // If we don't have a dialog yet and we are sending an INVITE, this is a new outbound (UAC) INVITE
1008 mDialogEventStateManager->onTryingUac(*ds, *msg);
1009 }
1010 }
1011 }
1012 }
1013 }
1014
1015 DebugLog (<< "SEND: " << std::endl << std::endl << *msg);
1016
1017 OutgoingEvent* event = new OutgoingEvent(msg);
1018 outgoingProcess(std::unique_ptr<Message>(event));
1019}
1020
1021void
1022DialogUsageManager::sendCommand(std::shared_ptr<SipMessage> request)
1023{
1024 SendCommand* s=new SendCommand(request, *this);
1025 post(s);
1026}
1027
1028
1029void DialogUsageManager::outgoingProcess(std::unique_ptr<Message> message)
1030{
1031 Data tid = Data::Empty;
1032 {
1033 OutgoingEvent* sipMsg = dynamic_cast<OutgoingEvent*>(message.get());
1034 if (sipMsg)
1035 {
1036 tid = sipMsg->getTransactionId();
1037 }
1038
1039 DumFeatureMessage* featureMsg = dynamic_cast<DumFeatureMessage*>(message.get());
1040 if (featureMsg)
1041 {
1042 InfoLog(<<"Got a DumFeatureMessage" << featureMsg);
1043 tid = featureMsg->getTransactionId();
1044 }
1045 }
1046
1047 if (tid == Data::Empty && mOutgoingMessageInterceptor.get())
1048 {
1049 mOutgoingMessageInterceptor->process(message.get());
1050 return;
1051 }
1052 else if (tid != Data::Empty && !mOutgoingFeatureList.empty())
1053 {
1054 FeatureChainMap::iterator it;
1055 //efficiently find or create FeatureChain, should prob. be a utility template
1056 {
1057 FeatureChainMap::iterator lb = mOutgoingFeatureChainMap.lower_bound(tid);
1058 if (lb != mOutgoingFeatureChainMap.end() && !(mOutgoingFeatureChainMap.key_comp()(tid, lb->first)))
1059 {
1060 it = lb;
1061 }
1062 else
1063 {
1064 it = mOutgoingFeatureChainMap.insert(lb, FeatureChainMap::value_type(tid, new DumFeatureChain(*this, mOutgoingFeatureList, *mOutgoingTarget)));
1065 }
1066 }
1067
1068 DumFeatureChain::ProcessingResult res = it->second->process(message.get());
1069
1070 if (static_cast<unsigned int>(res) & DumFeatureChain::ChainDoneBit)
1071 {
1072 delete it->second;
1073 mOutgoingFeatureChainMap.erase(it);
1074 }
1075
1076 if (static_cast<unsigned int>(res) & DumFeatureChain::EventTakenBit)
1077 {
1078 message.release();
1079 return;
1080 }
1081 }
1082
1083 OutgoingEvent* event = dynamic_cast<OutgoingEvent*>(message.get());
1084 //resip_assert(event);
1085 //.dcm. a TID collision can cause a message to be delivered to a finished
1086 //chain. This is probably because pseudorandom was being used on Win32.
1087 if (event)
1088 {
1089 if (event->message()->isRequest())
1090 {
1091 DialogSet* ds = findDialogSet(DialogSetId(*event->message()));
1092 UserProfile* userProfile;
1093 if (ds == 0)
1094 {
1095 userProfile = getMasterUserProfile().get();
1096 }
1097 else
1098 {
1099 userProfile = ds->getUserProfile().get();
1100 }
1101
1102 resip_assert(userProfile);
1103
1105 //optimzation here. SharedPtr would have to be changed; would
1106 //throw/assert if not unique.
1107 std::unique_ptr<SipMessage> toSend(static_cast<SipMessage*>(event->message()->clone()));
1108
1109 // .bwc. Protect ourselves from garbage with an isWellFormed() check.
1110 // (Code in Dialog doesn't check for well-formedness in the
1111 // Record-Route stack, so bad stuff there can end up here)
1112 if (event->message()->exists(h_Routes) &&
1113 !event->message()->header(h_Routes).empty() &&
1114 event->message()->header(h_Routes).front().isWellFormed() &&
1115 !event->message()->header(h_Routes).front().uri().exists(p_lr))
1116 {
1118 sendUsingOutboundIfAppropriate(*userProfile, std::move(toSend));
1119 }
1120 else
1121 {
1122 sendUsingOutboundIfAppropriate(*userProfile, std::move(toSend));
1123 }
1124 }
1125 else
1126 {
1127 sendResponse(*event->message());
1128 }
1129 }
1130}
1131
1132void
1133DialogUsageManager::sendUsingOutboundIfAppropriate(UserProfile& userProfile, std::unique_ptr<SipMessage> msg)
1134{
1135 //a little inefficient, branch parameter might be better
1136 DialogId id(*msg);
1137 if (userProfile.hasOutboundProxy() &&
1138 (userProfile.getForceOutboundProxyOnAllRequestsEnabled() || !findDialog(id)))
1139 {
1140 if (userProfile.getExpressOutboundAsRouteSetEnabled())
1141 {
1142 // prepend the outbound proxy to the service route
1143 msg->header(h_Routes).push_front(NameAddr(userProfile.getOutboundProxy().uri()));
1144 if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0)
1145 {
1146 DebugLog(<< "Sending with OutboundProxy=" << userProfile.getOutboundProxy().uri() << " in route set, to FlowTuple=" << userProfile.mClientOutboundFlowTuple << ", FlowKey=" << userProfile.mClientOutboundFlowTuple.mFlowKey << ": " << msg->brief());
1147 mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this);
1148 }
1149 else
1150 {
1151 DebugLog(<< "Sending with OutboundProxy=" << userProfile.getOutboundProxy().uri() << " in route set: " << msg->brief());
1152 mStack.send(std::move(msg), this);
1153 }
1154 }
1155 else
1156 {
1157 if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0)
1158 {
1159 DebugLog(<< "Sending to FlowTuple=" << userProfile.mClientOutboundFlowTuple << ", FlowKey=" << userProfile.mClientOutboundFlowTuple.mFlowKey << ": " << msg->brief());
1160 mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this);
1161 }
1162 else
1163 {
1164 DebugLog(<< "Sending to OutboundProxy=" << userProfile.getOutboundProxy().uri() << ": " << msg->brief());
1165 mStack.sendTo(std::move(msg), userProfile.getOutboundProxy().uri(), this);
1166 }
1167 }
1168 }
1169 else
1170 {
1171 if(userProfile.clientOutboundEnabled() && userProfile.mClientOutboundFlowTuple.mFlowKey != 0)
1172 {
1173 DebugLog(<< "Sending to FlowTuple=" << userProfile.mClientOutboundFlowTuple << ", FlowKey=" << userProfile.mClientOutboundFlowTuple.mFlowKey << ": " << msg->brief());
1174 mStack.sendTo(std::move(msg), userProfile.mClientOutboundFlowTuple, this);
1175 }
1176 else
1177 {
1178 DebugLog(<< "Send: " << msg->brief());
1179 mStack.send(std::move(msg), this);
1180 }
1181 }
1182}
1183
1184
1185void
1187{
1188 DialogSet* ds = findDialogSet(setid);
1189 if (ds == 0)
1190 {
1191 throw Exception("Request no longer exists", __FILE__, __LINE__);
1192 }
1193 else
1194 {
1195 ds->end();
1196 }
1197}
1198
1199void
1200DialogUsageManager::destroy(const BaseUsage* usage)
1201{
1202 if (mShutdownState != Destroying)
1203 {
1204 post(new DestroyUsage(usage->mHandle));
1205 }
1206 else
1207 {
1208 InfoLog(<< "DialogUsageManager::destroy() not posting to stack");
1209 }
1210}
1211
1212void
1213DialogUsageManager::destroy(DialogSet* dset)
1214{
1215 if (mShutdownState != Destroying)
1216 {
1217 post(new DestroyUsage(dset));
1218 }
1219 else
1220 {
1221 InfoLog(<< "DialogUsageManager::destroy() not posting to stack");
1222 }
1223}
1224
1225void
1226DialogUsageManager::destroy(Dialog* d)
1227{
1228 if (mShutdownState != Destroying)
1229 {
1230 post(new DestroyUsage(d));
1231 }
1232 else
1233 {
1234 InfoLog(<< "DialogUsageManager::destroy() not posting to stack");
1235 }
1236}
1237
1238
1239Dialog*
1240DialogUsageManager::findDialog(const DialogId& id)
1241{
1242 DialogSet* ds = findDialogSet(id.getDialogSetId());
1243 if (ds)
1244 {
1245 return ds->findDialog(id);
1246 }
1247 else
1248 {
1249 return 0;
1250 }
1251}
1252
1253
1256{
1257 Dialog* dialog = findDialog(id);
1258 if (dialog && dialog->mInviteSession)
1259 {
1260 return dialog->mInviteSession->getSessionHandle();
1261 }
1262
1264}
1265
1266pair<InviteSessionHandle, int>
1268{
1269 //486/481/603 decision making logic where? App may not wish to keep track of
1270 //invitesession state
1271 //Logic is here for now.
1273 replaces.param(p_toTag),
1274 replaces.param(p_fromTag)));
1275 int ErrorStatusCode = 481; // Call/Transaction Does Not Exist
1276
1277 // If we matched a session - Do RFC3891 Section 3 Processing
1278 if(is.isValid())
1279 {
1280 // Note some missing checks are:
1281 // 1. If the Replaces header field matches more than one dialog, the UA must act as
1282 // if no match was found
1283 // 2. Verify that the initiator of the new Invite is authorized
1284 if(is->isTerminated())
1285 {
1286 ErrorStatusCode = 603; // Declined
1288 }
1289 else if(is->isConnected())
1290 {
1291 // Check if early-only flag is present in replaces header
1292 if(replaces.exists(p_earlyOnly))
1293 {
1294 ErrorStatusCode = 486; // Busy Here
1296 }
1297 }
1298 else if(!is->isEarly())
1299 {
1300 // replaces can't be used on early dialogs that were not initiated by this UA - ie. InviteSession::Proceeding state
1301 ErrorStatusCode = 481; // Call/Transaction Does Not Exist
1303 }
1304 }
1305 return make_pair(is, ErrorStatusCode);
1306}
1307
1309{
1310 Dialog* pDialog = findDialog(id);
1311
1312 if(pDialog && pDialog->mAppDialog)
1313 {
1314 return pDialog->mAppDialog->getHandle();
1315 }
1316
1317 // Return an invalid handle
1318 return AppDialogHandle();
1319}
1320
1322{
1323 DialogSet* pDialogSet = findDialogSet(id);
1324
1325 if(pDialogSet && pDialogSet->mAppDialogSet)
1326 {
1327 return pDialogSet->mAppDialogSet->getHandle();
1328 }
1329
1330 // Return an invalid handle
1331 return AppDialogSetHandle();
1332}
1333
1334void
1335DialogUsageManager::internalProcess(std::unique_ptr<Message> msg)
1336{
1337#ifdef RESIP_DUM_THREAD_DEBUG
1338 if(!mThreadDebugKey)
1339 {
1340 // .bwc. Probably means multiple threads are trying to give DUM cycles
1341 // simultaneously.
1342 resip_assert(!mHiddenThreadDebugKey);
1343 // No d'tor needed, since we're just going to use a pointer to this.
1344 if(!ThreadIf::tlsKeyCreate(mThreadDebugKey, 0))
1345 {
1346 // .bwc. We really could pass anything here, but for the sake of
1347 // passing a valid pointer, I have (completely arbitrarily) chosen a
1348 // pointer to the DUM. All that matters is that this value is non-null
1349 ThreadIf::tlsSetValue(mThreadDebugKey, this);
1350 }
1351 else
1352 {
1353 ErrLog(<< "ThreadIf::tlsKeyCreate() failed!");
1354 }
1355 }
1356#endif
1357
1358 threadCheck();
1359
1360 // After a Stack ShutdownMessage has been received, don't do anything else in dum
1361 if (mShutdownState == Shutdown)
1362 {
1363 return;
1364 }
1365
1366 {
1367 TransactionUserMessage* tuMsg = dynamic_cast<TransactionUserMessage*>(msg.get());
1368 if (tuMsg)
1369 {
1370 InfoLog (<< "TU unregistered ");
1371 resip_assert(mShutdownState == RemovingTransactionUser);
1373 mShutdownState = Shutdown;
1374 if (mDumShutdownHandler)
1375 {
1376 mDumShutdownHandler->onDumCanBeDeleted();
1377 mDumShutdownHandler = 0; // prevent mDumShutdownHandler getting called more than once
1378 }
1379 return;
1380 }
1381 }
1382
1383 {
1384 KeepAlivePong* pong = dynamic_cast<KeepAlivePong*>(msg.get());
1385 if (pong)
1386 {
1387 DebugLog(<< "keepalive pong received from " << pong->getFlow());
1388 if (mKeepAliveManager.get())
1389 {
1390 mKeepAliveManager->receivedPong(pong->getFlow());
1391 }
1392 return;
1393 }
1394 }
1395
1396 {
1397 DestroyUsage* destroyUsage = dynamic_cast<DestroyUsage*>(msg.get());
1398 if (destroyUsage)
1399 {
1400 //DebugLog(<< "Destroying usage" );
1401 destroyUsage->destroy();
1402 return;
1403 }
1404 }
1405
1406 {
1407 DumTimeout* dumMsg = dynamic_cast<DumTimeout*>(msg.get());
1408 if (dumMsg)
1409 {
1410 //DebugLog(<< "Timeout Message" );
1411 if (!dumMsg->getBaseUsage().isValid())
1412 {
1413 return;
1414 }
1415 dumMsg->getBaseUsage()->dispatch(*dumMsg);
1416 return;
1417 }
1418 }
1419
1420 {
1421 KeepAliveTimeout* keepAliveMsg = dynamic_cast<KeepAliveTimeout*>(msg.get());
1422 if (keepAliveMsg)
1423 {
1424 //DebugLog(<< "Keep Alive Message" );
1425 if (mKeepAliveManager.get())
1426 {
1427 mKeepAliveManager->process(*keepAliveMsg);
1428 }
1429 return;
1430 }
1431 }
1432
1433 {
1434 KeepAlivePongTimeout* keepAlivePongMsg = dynamic_cast<KeepAlivePongTimeout*>(msg.get());
1435 if (keepAlivePongMsg)
1436 {
1437 //DebugLog(<< "Keep Alive Pong Message" );
1438 if (mKeepAliveManager.get())
1439 {
1440 mKeepAliveManager->process(*keepAlivePongMsg);
1441 }
1442 return;
1443 }
1444 }
1445
1446 {
1447 ConnectionTerminated* terminated = dynamic_cast<ConnectionTerminated*>(msg.get());
1448 if (terminated)
1449 {
1450 // Notify all dialogSets, in case they need to react (ie. client outbound support)
1451 // First find all applicable dialogsets, since flow token in user profile will
1452 // be cleared by first dialogset we notify, then notify all dialogset's
1453 std::list<DialogSet*> dialogSetsToNotify;
1454 DialogSetMap::iterator it = mDialogSetMap.begin();
1455 for(; it != mDialogSetMap.end(); it++)
1456 {
1457 if(it->second->mUserProfile->clientOutboundEnabled() &&
1458 it->second->mUserProfile->getClientOutboundFlowTuple().mFlowKey == terminated->getFlow().mFlowKey && // Flow key is not part of Tuple operator=, check it first
1459 it->second->mUserProfile->getClientOutboundFlowTuple() == terminated->getFlow())
1460 {
1461 if(it->second->getClientRegistration().isValid())
1462 {
1463 // ensure client registrations are notified first
1464 dialogSetsToNotify.push_front(it->second);
1465 }
1466 else
1467 {
1468 dialogSetsToNotify.push_back(it->second);
1469 }
1470 }
1471 }
1472 // Now dispatch notification to all dialogsets found above
1473 std::list<DialogSet*>::iterator it2 = dialogSetsToNotify.begin();
1474 for(; it2 != dialogSetsToNotify.end();it2++)
1475 {
1476 (*it2)->flowTerminated(terminated->getFlow());
1477 }
1478
1479 DebugLog(<< *msg);
1480 if (mConnectionTerminatedEventDispatcher.dispatch(msg.get()))
1481 {
1482 // If EventDispatcher returns true, then it took ownership of msg, so we release it
1483 msg.release();
1484 }
1485 return;
1486 }
1487 }
1488
1489 {
1490 DumCommand* command = dynamic_cast<DumCommand*>(msg.get());
1491 if (command)
1492 {
1493 //DebugLog(<< "DumCommand" );
1494 command->executeCommand();
1495 return;
1496 }
1497 }
1498
1499 {
1500 ExternalMessageBase* externalMessage = dynamic_cast<ExternalMessageBase*>(msg.get());
1501 if (externalMessage)
1502 {
1503 processExternalMessage(externalMessage);
1504 return;
1505 }
1506 }
1507
1508 incomingProcess(std::move(msg));
1509}
1510
1511void
1512DialogUsageManager::processExternalMessage(ExternalMessageBase* externalMessage)
1513{
1514 bool handled = false;
1515 for(std::vector<ExternalMessageHandler*>::iterator i = mExternalMessageHandlers.begin();
1516 i != mExternalMessageHandlers.end(); ++i)
1517 {
1518 (*i)->onMessage(externalMessage, handled);
1519 if (handled)
1520 {
1521 break;
1522 }
1523 }
1524}
1525
1526void
1527DialogUsageManager::incomingProcess(std::unique_ptr<Message> msg)
1528{
1529 //call or create feature chain if appropriate
1530 Data tid = Data::Empty;
1531 {
1532 SipMessage* sipMsg = dynamic_cast<SipMessage*>(msg.get());
1533 if (sipMsg)
1534 {
1535 tid = sipMsg->getTransactionId();
1536 bool garbage=false;
1537 Data reason;
1538
1539 if(!sipMsg->header(h_From).isWellFormed())
1540 {
1541 garbage=true;
1542 reason.append("Malformed From, ",16);
1543 }
1544
1545 if(!sipMsg->header(h_To).isWellFormed())
1546 {
1547 garbage=true;
1548 reason.append("Malformed To, ",14);
1549 }
1550
1551 if(!sipMsg->header(h_CallId).isWellFormed())
1552 {
1553 garbage=true;
1554 reason.append("Malformed Call-Id, ",19);
1555 }
1556
1557 if(garbage)
1558 {
1559 if(sipMsg->isRequest() && sipMsg->method()!=ACK)
1560 {
1561 // .bwc. Either we need to trim the last comma off, or make this
1562 // a proper sentence fragment. This is more fun.
1563 reason.append("fix your code!",14);
1564 SipMessage failure;
1565 makeResponse(failure, *sipMsg, 400, reason);
1566 sendResponse(failure);
1567 }
1568
1569 InfoLog (<< "Malformed header in message (" << reason << ") - rejecting/discarding: " << *sipMsg);
1570
1571 // .bwc. Only forge a response when appropriate, but return in any
1572 // case.
1573 return;
1574 }
1575 }
1576
1577 DumFeatureMessage* featureMsg = dynamic_cast<DumFeatureMessage*>(msg.get());
1578 if (featureMsg)
1579 {
1580 //DebugLog(<<"Got a DumFeatureMessage" << featureMsg);
1581 tid = featureMsg->getTransactionId();
1582 }
1583 }
1584 if (tid != Data::Empty && !mIncomingFeatureList.empty())
1585 {
1586 FeatureChainMap::iterator it;
1587 //efficiently find or create FeatureChain, should prob. be a utility template
1588 {
1589 FeatureChainMap::iterator lb = mIncomingFeatureChainMap.lower_bound(tid);
1590 if (lb != mIncomingFeatureChainMap.end() && !(mIncomingFeatureChainMap.key_comp()(tid, lb->first)))
1591 {
1592 it = lb;
1593 }
1594 else
1595 {
1596 if(dynamic_cast<SipMessage*>(msg.get()))
1597 {
1598 it = mIncomingFeatureChainMap.insert(lb, FeatureChainMap::value_type(tid, new DumFeatureChain(*this, mIncomingFeatureList, *mIncomingTarget)));
1599 }
1600 else
1601 {
1602 // Certain messages from the wire (ie: CANCEL) can end a feature, however there may still be some
1603 // pending Async requests (non-SipMessages) that are coming in - just drop them if so
1604 return;
1605 }
1606 }
1607 }
1608
1609 DumFeatureChain::ProcessingResult res = it->second->process(msg.get());
1610
1611 if (static_cast<unsigned int>(res) & DumFeatureChain::ChainDoneBit)
1612 {
1613 delete it->second;
1614 mIncomingFeatureChainMap.erase(it);
1615 //DebugLog(<< "feature chain deleted" << endl);
1616 }
1617
1618 if (static_cast<unsigned int>(res) & DumFeatureChain::EventTakenBit)
1619 {
1620 msg.release();
1621 //DebugLog(<< "event taken");
1622 return;
1623 }
1624 }
1625
1626 try
1627 {
1628 DebugLog (<< "Got: " << msg->brief());
1629 DumDecrypted* decryptedMsg = dynamic_cast<DumDecrypted*>(msg.get());
1630 SipMessage* sipMsg = 0;
1631 if (decryptedMsg)
1632 {
1633 sipMsg = decryptedMsg->decrypted();
1634 }
1635 else
1636 {
1637 sipMsg = dynamic_cast<SipMessage*>(msg.get());
1638 }
1639
1640 if (sipMsg)
1641 {
1642 DebugLog ( << "DialogUsageManager::process: found SipMessage" );
1643 if (sipMsg->isRequest())
1644 {
1645 // Validate Request URI
1646 if( !validateRequestURI(*sipMsg) )
1647 {
1648 DebugLog (<< "Failed RequestURI validation " << *sipMsg);
1649 return;
1650 }
1651
1652 // Continue validation on all requests, except ACK and CANCEL
1653 if(sipMsg->header(h_RequestLine).method() != ACK &&
1654 sipMsg->header(h_RequestLine).method() != CANCEL)
1655 {
1656 if( !validateRequiredOptions(*sipMsg) )
1657 {
1658 DebugLog (<< "Failed required options validation " << *sipMsg);
1659 return;
1660 }
1661 if( !validate100RelSupport(*sipMsg) )
1662 {
1663 DebugLog (<< "Remote party does not support 100rel " << *sipMsg);
1664 return;
1665 }
1666 if( getMasterProfile()->validateContentEnabled() && !validateContent(*sipMsg) )
1667 {
1668 DebugLog (<< "Failed content validation " << *sipMsg);
1669 return;
1670 }
1671 if( getMasterProfile()->validateAcceptEnabled() && !validateAccept(*sipMsg) )
1672 {
1673 DebugLog (<< "Failed accept validation " << *sipMsg);
1674 return;
1675 }
1676 }
1677 if (sipMsg->header(h_From).exists(p_tag))
1678 {
1679 if (mergeRequest(*sipMsg) )
1680 {
1681 InfoLog (<< "Merged request: " << *sipMsg);
1682 return;
1683 }
1684 }
1685 processRequest(*sipMsg);
1686 }
1687 else
1688 {
1689 processResponse(*sipMsg);
1690 }
1691 }
1692 }
1693 catch(BaseException& e)
1694 {
1695 //unparseable, bad 403 w/ 2543 trans it from FWD, etc
1696 ErrLog(<<"Illegal message rejected: " << e.getMessage());
1697 }
1698}
1699
1700bool
1702{
1703 return mFifo.messageAvailable();
1704}
1705
1706// return true if there is more to do
1707bool
1709{
1710 if (mFifo.messageAvailable())
1711 {
1712 resip::PtrLock lock(mutex);
1713#ifdef RESIP_DUM_THREAD_DEBUG
1714 mThreadDebugKey=mHiddenThreadDebugKey;
1715#endif
1716 internalProcess(std::unique_ptr<Message>(mFifo.getNext()));
1717#ifdef RESIP_DUM_THREAD_DEBUG
1718 // .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
1719 // is using this mutex-locked process() call, we only enable thread-
1720 // checking while the mutex is locked. Accesses from another thread while
1721 // the mutex is not locked are probably intentional. However, if the app
1722 // accesses the DUM inappropriately anyway, we'll probably detect it if
1723 // it happens during the internalProcess() call.
1724 mHiddenThreadDebugKey=mThreadDebugKey;
1725 mThreadDebugKey=0;
1726#endif
1727 }
1728 return mFifo.messageAvailable();
1729}
1730
1731bool
1733{
1734 std::unique_ptr<Message> message;
1735
1736 if(timeoutMs == -1)
1737 {
1738 message.reset(mFifo.getNext());
1739 }
1740 else
1741 {
1742 message.reset(mFifo.getNext(timeoutMs));
1743 }
1744 if (message.get())
1745 {
1746 resip::PtrLock lock(mutex);
1747#ifdef RESIP_DUM_THREAD_DEBUG
1748 mThreadDebugKey=mHiddenThreadDebugKey;
1749#endif
1750 internalProcess(std::move(message));
1751#ifdef RESIP_DUM_THREAD_DEBUG
1752 // .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
1753 // is using this mutex-locked process() call, we only enable thread-
1754 // checking while the mutex is locked. Accesses from another thread while
1755 // the mutex is not locked are probably intentional. However, if the app
1756 // accesses the DUM inappropriately anyway, we'll probably detect it if
1757 // it happens during the internalProcess() call.
1758 mHiddenThreadDebugKey=mThreadDebugKey;
1759 mThreadDebugKey=0;
1760#endif
1761 }
1762 return mFifo.messageAvailable();
1763}
1764
1765// return true if there is more to do
1766bool
1768{
1769 if (mFifo.messageAvailable())
1770 {
1771 resip::RecursiveLock lock(mutex);
1772#ifdef RESIP_DUM_THREAD_DEBUG
1773 mThreadDebugKey = mHiddenThreadDebugKey;
1774#endif
1775 internalProcess(std::unique_ptr<Message>(mFifo.getNext()));
1776#ifdef RESIP_DUM_THREAD_DEBUG
1777 // .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
1778 // is using this mutex-locked process() call, we only enable thread-
1779 // checking while the mutex is locked. Accesses from another thread while
1780 // the mutex is not locked are probably intentional. However, if the app
1781 // accesses the DUM inappropriately anyway, we'll probably detect it if
1782 // it happens during the internalProcess() call.
1783 mHiddenThreadDebugKey = mThreadDebugKey;
1784 mThreadDebugKey = 0;
1785#endif
1786 }
1787 return mFifo.messageAvailable();
1788}
1789
1790bool
1792{
1793 std::unique_ptr<Message> message;
1794
1795 if (timeoutMs == -1)
1796 {
1797 message.reset(mFifo.getNext());
1798 }
1799 else
1800 {
1801 message.reset(mFifo.getNext(timeoutMs));
1802 }
1803 if (message.get())
1804 {
1805 resip::RecursiveLock lock(mutex);
1806#ifdef RESIP_DUM_THREAD_DEBUG
1807 mThreadDebugKey = mHiddenThreadDebugKey;
1808#endif
1809 internalProcess(std::move(message));
1810#ifdef RESIP_DUM_THREAD_DEBUG
1811 // .bwc. Thread checking is disabled if mThreadDebugKey is 0; if the app
1812 // is using this mutex-locked process() call, we only enable thread-
1813 // checking while the mutex is locked. Accesses from another thread while
1814 // the mutex is not locked are probably intentional. However, if the app
1815 // accesses the DUM inappropriately anyway, we'll probably detect it if
1816 // it happens during the internalProcess() call.
1817 mHiddenThreadDebugKey = mThreadDebugKey;
1818 mThreadDebugKey = 0;
1819#endif
1820 }
1821 return mFifo.messageAvailable();
1822}
1823
1824bool
1825DialogUsageManager::validateRequestURI(const SipMessage& request)
1826{
1827 // RFC3261 - 8.2.1
1828 if (!getMasterProfile()->isMethodSupported(request.header(h_RequestLine).getMethod()))
1829 {
1830 InfoLog (<< "Received an unsupported method: " << request.brief());
1831
1832 SipMessage failure;
1833 makeResponse(failure, request, 405);
1834 failure.header(h_Allows) = getMasterProfile()->getAllowedMethods();
1835 sendResponse(failure);
1836
1837 if(mRequestValidationHandler)
1838 mRequestValidationHandler->onInvalidMethod(request);
1839
1840 return false;
1841 }
1842
1843 // RFC3261 - 8.2.2
1844 if (!getMasterProfile()->isSchemeSupported(request.header(h_RequestLine).uri().scheme()))
1845 {
1846 InfoLog (<< "Received an unsupported scheme: " << request.brief());
1847 SipMessage failure;
1848 makeResponse(failure, request, 416);
1849 sendResponse(failure);
1850
1851 if(mRequestValidationHandler)
1852 mRequestValidationHandler->onInvalidScheme(request);
1853
1854 return false;
1855 }
1856
1857 return true;
1858}
1859
1860
1861bool
1862DialogUsageManager::validateRequiredOptions(const SipMessage& request)
1863{
1864 // RFC 2162 - 8.2.2
1865 if(request.exists(h_Requires) && // Don't check requires if method is ACK or CANCEL
1866 request.header(h_RequestLine).getMethod() != ACK &&
1867 request.header(h_RequestLine).getMethod() != CANCEL)
1868 {
1869 Tokens unsupported = getMasterProfile()->getUnsupportedOptionsTags(request.header(h_Requires));
1870 if (!unsupported.empty())
1871 {
1872 InfoLog (<< "Received an unsupported option tag(s): " << request.brief());
1873
1874 SipMessage failure;
1875 makeResponse(failure, request, 420);
1876 failure.header(h_Unsupporteds) = unsupported;
1877 sendResponse(failure);
1878
1879 if(mRequestValidationHandler)
1880 mRequestValidationHandler->onInvalidRequiredOptions(request);
1881
1882 return false;
1883 }
1884 }
1885
1886 return true;
1887}
1888
1889
1890bool
1891DialogUsageManager::validate100RelSupport(const SipMessage& request)
1892{
1893 if(request.header(h_RequestLine).getMethod() == INVITE)
1894 {
1895 if (getMasterProfile()->getUasReliableProvisionalMode() == MasterProfile::Required)
1896 {
1897 if (!((request.exists(h_Requires) && request.header(h_Requires).find(Token(Symbols::C100rel)))
1898 || (request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::C100rel)))))
1899 {
1900 SipMessage failure;
1901 makeResponse(failure, request, 421);
1902 failure.header(h_Requires).push_back(Token(Symbols::C100rel));
1903 sendResponse(failure);
1904
1905 if(mRequestValidationHandler)
1906 {
1907 mRequestValidationHandler->on100RelNotSupportedByRemote(request);
1908 }
1909
1910 return false;
1911 }
1912 }
1913 }
1914 return true;
1915}
1916
1917bool
1918DialogUsageManager::validateContent(const SipMessage& request)
1919{
1920 // RFC3261 - 8.2.3
1921 // Don't need to validate content headers if they are specified as optional in the content-disposition
1922 if (!(request.exists(h_ContentDisposition) &&
1923 request.header(h_ContentDisposition).isWellFormed() &&
1924 request.header(h_ContentDisposition).exists(p_handling) &&
1925 isEqualNoCase(request.header(h_ContentDisposition).param(p_handling), Symbols::Optional)))
1926 {
1927 if (request.exists(h_ContentType) && !getMasterProfile()->isMimeTypeSupported(request.header(h_RequestLine).method(), request.header(h_ContentType)))
1928 {
1929 InfoLog (<< "Received an unsupported mime type: " << request.header(h_ContentType) << " for " << request.brief());
1930
1931 SipMessage failure;
1932 makeResponse(failure, request, 415);
1933 failure.header(h_Accepts) = getMasterProfile()->getSupportedMimeTypes(request.header(h_RequestLine).method());
1934 sendResponse(failure);
1935
1936 if(mRequestValidationHandler)
1937 mRequestValidationHandler->onInvalidContentType(request);
1938
1939 return false;
1940 }
1941
1942 if (request.exists(h_ContentEncoding) && !getMasterProfile()->isContentEncodingSupported(request.header(h_ContentEncoding)))
1943 {
1944 InfoLog (<< "Received an unsupported content encoding: " << request.header(h_ContentEncoding) << " for " << request.brief());
1945 SipMessage failure;
1946 makeResponse(failure, request, 415);
1947 failure.header(h_AcceptEncodings) = getMasterProfile()->getSupportedEncodings();
1948 sendResponse(failure);
1949
1950 if(mRequestValidationHandler)
1951 mRequestValidationHandler->onInvalidContentEncoding(request);
1952
1953 return false;
1954 }
1955
1956 if (getMasterProfile()->validateContentLanguageEnabled() &&
1957 request.exists(h_ContentLanguages) && !getMasterProfile()->isLanguageSupported(request.header(h_ContentLanguages)))
1958 {
1959 InfoLog (<< "Received an unsupported language: " << request.header(h_ContentLanguages).front() << " for " << request.brief());
1960
1961 SipMessage failure;
1962 makeResponse(failure, request, 415);
1963 failure.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
1964 sendResponse(failure);
1965
1966 if(mRequestValidationHandler)
1967 mRequestValidationHandler->onInvalidContentLanguage(request);
1968
1969 return false;
1970 }
1971 }
1972
1973 return true;
1974}
1975
1976bool
1977DialogUsageManager::validateAccept(const SipMessage& request)
1978{
1979 MethodTypes method = request.header(h_RequestLine).method();
1980 // checks for Accept to comply with SFTF test case 216
1981 if(request.exists(h_Accepts))
1982 {
1983 for (Mimes::const_iterator i = request.header(h_Accepts).begin();
1984 i != request.header(h_Accepts).end(); i++)
1985 {
1986 if (getMasterProfile()->isMimeTypeSupported(method, *i))
1987 {
1988 return true; // Accept header passes validation if we support as least one of the mime types
1989 }
1990 }
1991 }
1992 // If no Accept header then application/sdp should be assumed for certain methods
1993 else if(method == INVITE ||
1994 method == OPTIONS ||
1995 method == PRACK ||
1996 method == UPDATE)
1997 {
1998 if (getMasterProfile()->isMimeTypeSupported(request.header(h_RequestLine).method(), Mime("application", "sdp")))
1999 {
2000 return true;
2001 }
2002 }
2003 else
2004 {
2005 // Other method without an Accept Header
2006 return true;
2007 }
2008
2009 InfoLog (<< "Received unsupported mime types in accept header: " << request.brief());
2010 SipMessage failure;
2011 makeResponse(failure, request, 406);
2012 failure.header(h_Accepts) = getMasterProfile()->getSupportedMimeTypes(method);
2013 sendResponse(failure);
2014
2015 if(mRequestValidationHandler)
2016 mRequestValidationHandler->onInvalidAccept(request);
2017
2018 return false;
2019}
2020
2021bool
2022DialogUsageManager::mergeRequest(const SipMessage& request)
2023{
2024 resip_assert(request.isRequest());
2025 resip_assert(request.isExternal());
2026
2027 if (!request.header(h_To).exists(p_tag))
2028 {
2029 if (mMergedRequests.find(MergedRequestKey(request, getMasterProfile()->checkReqUriInMergeDetectionEnabled())) != mMergedRequests.end())
2030 {
2031 SipMessage failure;
2032 makeResponse(failure, request, 482, "Merged Request");
2033 failure.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2034 sendResponse(failure);
2035 return true;
2036 }
2037 }
2038
2039 return false;
2040}
2041
2042void
2043DialogUsageManager::processRequest(const SipMessage& request)
2044{
2045 DebugLog ( << "DialogUsageManager::processRequest: " << request.brief());
2046
2047 if (mShutdownState != Running && mShutdownState != ShutdownRequested)
2048 {
2049 WarningLog (<< "Ignoring a request since we are shutting down " << request.brief());
2050
2051 SipMessage failure;
2052 makeResponse(failure, request, 480, "UAS is shutting down");
2053 sendResponse(failure);
2054 return;
2055 }
2056
2057 if (request.header(h_RequestLine).method() == PUBLISH)
2058 {
2059 processPublish(request);
2060 return;
2061 }
2062
2063 bool toTag = request.header(h_To).exists(p_tag);
2064 if(request.header(h_RequestLine).getMethod() == REGISTER && toTag && getMasterProfile()->allowBadRegistrationEnabled())
2065 {
2066 toTag = false;
2067 }
2068
2069 resip_assert(mAppDialogSetFactory.get());
2070 // !jf! note, the logic was reversed during ye great merge of March of Ought 5
2071 if (toTag ||
2072 findDialogSet(DialogSetId(request)))
2073 {
2074 switch (request.header(h_RequestLine).getMethod())
2075 {
2076 case REGISTER:
2077 {
2078 SipMessage failure;
2079 makeResponse(failure, request, 400, "Registration requests can't have To: tags.");
2080 failure.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2081 sendResponse(failure);
2082 break;
2083 }
2084
2085 default:
2086 {
2087 DialogSet* ds = findDialogSet(DialogSetId(request));
2088 if (ds == 0)
2089 {
2090 if (request.header(h_RequestLine).method() != ACK)
2091 {
2092 SipMessage failure;
2093 makeResponse(failure, request, 481);
2094 failure.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2095 InfoLog (<< "Rejected request (which was in a dialog) " << request.brief());
2096 sendResponse(failure);
2097 }
2098 else
2099 {
2100 InfoLog (<< "ACK doesn't match any dialog" << request.brief());
2101 }
2102 }
2103 else
2104 {
2105 InfoLog (<< "Handling in-dialog request: " << request.brief());
2106 ds->dispatch(request);
2107 }
2108 }
2109 }
2110 }
2111 else
2112 {
2113 switch (request.header(h_RequestLine).getMethod())
2114 {
2115 case ACK:
2116 DebugLog (<< "Discarding request: " << request.brief());
2117 break;
2118
2119 case PRACK:
2120 case BYE:
2121 case UPDATE:
2122 case INFO: // !rm! in an ideal world
2123 {
2124 SipMessage failure;
2125 makeResponse(failure, request, 481);
2126 failure.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2127 sendResponse(failure);
2128 break;
2129 }
2130 case CANCEL:
2131 {
2132 // find the appropropriate ServerInvSession
2133 CancelMap::iterator i = mCancelMap.find(request.getTransactionId());
2134 if (i != mCancelMap.end())
2135 {
2136 i->second->dispatch(request);
2137 }
2138 else
2139 {
2140 InfoLog (<< "Received a CANCEL on a non-existent transaction: tid=" << request.getTransactionId());
2141 SipMessage failure;
2142 makeResponse(failure, request, 481);
2143 sendResponse(failure);
2144 }
2145 break;
2146 }
2147 case PUBLISH:
2148 resip_assert(false);
2149 return;
2150 case SUBSCRIBE:
2151 if (!checkEventPackage(request))
2152 {
2153 InfoLog (<< "Rejecting request (unsupported package) "
2154 << request.brief());
2155 return;
2156 }
2157 /*FALLTHRU*/
2158 case NOTIFY : // handle unsolicited (illegal) NOTIFYs
2159 case INVITE: // new INVITE
2160 case REFER: // out-of-dialog REFER
2161 //case INFO : // handle non-dialog (illegal) INFOs
2162 case OPTIONS : // handle non-dialog OPTIONS
2163 case MESSAGE :
2164 case REGISTER:
2165 {
2166 {
2167 DialogSetId id(request);
2168 //cryptographically dangerous
2169 if(mDialogSetMap.find(id) != mDialogSetMap.end())
2170 {
2171 // this can only happen if someone sends us a request with the same callid and from tag as one
2172 // that is in the process of destroying - since this is bad endpoint behaviour - we will
2173 // reject the request with a 400 response
2174 SipMessage badrequest;
2175 makeResponse(badrequest, request, 400);
2176 badrequest.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2177 sendResponse(badrequest);
2178 return;
2179 }
2180 }
2181 if (mDumShutdownHandler)
2182 {
2183 SipMessage forbidden;
2184 makeResponse(forbidden, request, 480);
2185 forbidden.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2186 sendResponse(forbidden);
2187 return;
2188 }
2189 try
2190 {
2191 DialogSet* dset = new DialogSet(request, *this);
2192
2193 StackLog ( << "*********** Calling AppDialogSetFactory *************: " << dset->getId());
2194 AppDialogSet* appDs = mAppDialogSetFactory->createAppDialogSet(*this, request);
2195 appDs->mDialogSet = dset;
2196 dset->setUserProfile(appDs->selectUASUserProfile(request));
2197 dset->mAppDialogSet = appDs;
2198
2199 StackLog ( << "************* Adding DialogSet ***************: " << dset->getId());
2200 //StackLog ( << "Before: " << Inserter(mDialogSetMap) );
2201 mDialogSetMap[dset->getId()] = dset;
2202 StackLog ( << "DialogSetMap: " << InserterP(mDialogSetMap) );
2203
2204 dset->dispatch(request);
2205 }
2206 catch (BaseException& e)
2207 {
2208 SipMessage failure;
2209 makeResponse(failure, request, 400, e.getMessage());
2210 failure.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2211 sendResponse(failure);
2212 }
2213
2214 break;
2215 }
2216 case RESPONSE:
2217 case SERVICE:
2218 resip_assert(false);
2219 break;
2220 case UNKNOWN:
2221 case MAX_METHODS:
2222 resip_assert(false);
2223 break;
2224 }
2225 }
2226}
2227
2228void
2229DialogUsageManager::processResponse(const SipMessage& response)
2230{
2231 if (response.header(h_CSeq).method() != CANCEL)
2232 {
2233 DialogSet* ds = findDialogSet(DialogSetId(response));
2234
2235 if (ds)
2236 {
2237 DebugLog ( << "DialogUsageManager::processResponse: " << std::endl << std::endl << response.brief());
2238 ds->dispatch(response);
2239 }
2240 else
2241 {
2242 InfoLog (<< "Throwing away stray response: " << std::endl << std::endl << response.brief());
2243 }
2244 }
2245}
2246
2247void
2248DialogUsageManager::processPublish(const SipMessage& request)
2249{
2250 if (!checkEventPackage(request))
2251 {
2252 InfoLog(<< "Rejecting request (unsupported package) " << request.brief());
2253 return;
2254 }
2255
2256 if (request.exists(h_SIPIfMatch))
2257 {
2258 ServerPublications::iterator i = mServerPublications.find(request.header(h_SIPIfMatch).value());
2259 if (i != mServerPublications.end())
2260 {
2261 i->second->dispatch(request);
2262 }
2263 else
2264 {
2265 // Check if publication exists in PublicationDb - may have been sync'd over,
2266 // or exists from a restart. In this case, fabricate a new ServerSubcription
2267 // to handle this request.
2268 if (mPublicationPersistenceManager &&
2269 mPublicationPersistenceManager->documentExists(request.header(h_Event).value(), request.header(h_RequestLine).uri().getAor(), request.header(h_SIPIfMatch).value()))
2270 {
2271 ServerPublication* sp = new ServerPublication(*this, request.header(h_SIPIfMatch).value(), request);
2272 mServerPublications[request.header(h_SIPIfMatch).value()] = sp;
2273 sp->dispatch(request);
2274 }
2275 else
2276 {
2277 auto response = std::make_shared<SipMessage>();
2278 makeResponse(*response, request, 412);
2279 send(response);
2280 }
2281 }
2282 }
2283 else
2284 {
2286 while (mServerPublications.find(etag) != mServerPublications.end())
2287 {
2289 }
2290
2291 if (request.getContents())
2292 {
2293 ServerPublication* sp = new ServerPublication(*this, etag, request);
2294 mServerPublications[etag] = sp;
2295 sp->dispatch(request);
2296 }
2297 else
2298 {
2299 // per 3903 (sec 6.5), a PUB w/ no SIPIfMatch must have contents. .mjf.
2300 auto response = std::make_shared<SipMessage>();
2301 makeResponse(*response, request, 400);
2302 send(response);
2303 }
2304 }
2305}
2306
2307bool
2308DialogUsageManager::checkEventPackage(const SipMessage& request)
2309{
2310 int failureCode = 0;
2311 MethodTypes method = request.header(h_RequestLine).method();
2312
2313// || (method == NOTIFY && !request.exists(h_SubscriptionState)))
2314
2315 if (!request.exists(h_Event))
2316 {
2317 InfoLog (<< "No Event header in " << request.header(h_RequestLine).unknownMethodName());
2318 failureCode = 400;
2319 }
2320 else
2321 {
2322 switch(method)
2323 {
2324 case SUBSCRIBE:
2325 if (!getServerSubscriptionHandler(request.header(h_Event).value()))
2326 {
2327 InfoLog (<< "No handler for event package for SUBSCRIBE: "
2328 << request.header(h_Event).value());
2329 failureCode = 489;
2330 }
2331 break;
2332 case NOTIFY:
2333 if (!getClientSubscriptionHandler(request.header(h_Event).value()))
2334 {
2335 InfoLog (<< "No handler for event package for NOTIFY: "
2336 << request.header(h_Event).value());
2337 failureCode = 489;
2338 }
2339 break;
2340 case PUBLISH:
2341 if (!getServerPublicationHandler(request.header(h_Event).value()))
2342 {
2343 InfoLog (<< "No handler for event package for PUBLISH: "
2344 << request.header(h_Event).value());
2345 failureCode = 489;
2346 }
2347 break;
2348 default:
2349 resip_assert(0);
2350 }
2351 }
2352
2353 if (failureCode > 0)
2354 {
2355 auto response = std::make_shared<SipMessage>();
2356 makeResponse(*response, request, failureCode);
2357 if(failureCode == 489)
2358 {
2359 response->header(h_AllowEvents) = getMasterProfile()->getAllowedEvents();
2360 }
2361 send(response);
2362 return false;
2363 }
2364 return true;
2365}
2366
2367DialogSet*
2368DialogUsageManager::findDialogSet(const DialogSetId& id)
2369{
2370 threadCheck();
2371 StackLog ( << "Looking for dialogSet: " << id << " in map:");
2372 StackLog ( << "DialogSetMap: " << InserterP(mDialogSetMap) );
2373 DialogSetMap::const_iterator it = mDialogSetMap.find(id);
2374
2375 if (it == mDialogSetMap.end())
2376 {
2377 StackLog ( << "Not found" );
2378 return 0;
2379 }
2380 else
2381 {
2382 if(it->second->isDestroying())
2383 {
2384 StackLog ( << "isDestroying() == true" );
2385 return 0;
2386 }
2387 else
2388 {
2389 StackLog ( << "found" );
2390 return it->second;
2391 }
2392 }
2393}
2394
2396DialogUsageManager::findCreator(const DialogId& id)
2397{
2398 DialogSet* ds = findDialogSet(id.getDialogSetId());
2399 if (ds)
2400 {
2401 return ds->getCreator();
2402 }
2403 else
2404 {
2405 return 0;
2406 }
2407}
2408
2409void
2410DialogUsageManager::removeDialogSet(const DialogSetId& dsId)
2411{
2412 StackLog ( << "************* Removing DialogSet ***************: " << dsId);
2413 //StackLog ( << "Before: " << Inserter(mDialogSetMap) );
2414 mDialogSetMap.erase(dsId);
2415 StackLog ( << "DialogSetMap: " << InserterP(mDialogSetMap) );
2416 if (mRedirectManager)
2417 {
2418 mRedirectManager->removeDialogSet(dsId);
2419 }
2420}
2421
2424{
2425 map<Data, ClientSubscriptionHandler*>::iterator res = mClientSubscriptionHandlers.find(eventType);
2426 if (res != mClientSubscriptionHandlers.end())
2427 {
2428 return res->second;
2429 }
2430 else
2431 {
2432 return 0;
2433 }
2434}
2435
2438{
2439 map<Data, ServerSubscriptionHandler*>::iterator res = mServerSubscriptionHandlers.find(eventType);
2440 if (res != mServerSubscriptionHandlers.end())
2441 {
2442 return res->second;
2443 }
2444 else
2445 {
2446 return 0;
2447 }
2448}
2449
2452{
2453 map<Data, ClientPublicationHandler*>::iterator res = mClientPublicationHandlers.find(eventType);
2454 if (res != mClientPublicationHandlers.end())
2455 {
2456 return res->second;
2457 }
2458 else
2459 {
2460 return 0;
2461 }
2462}
2463
2466{
2467 map<Data, ServerPublicationHandler*>::iterator res = mServerPublicationHandlers.find(eventType);
2468 if (res != mServerPublicationHandlers.end())
2469 {
2470 return res->second;
2471 }
2472 else
2473 {
2474 return 0;
2475 }
2476}
2477
2479DialogUsageManager::getOutOfDialogHandler(const MethodTypes type)
2480{
2481 map<MethodTypes, OutOfDialogHandler*>::iterator res = mOutOfDialogHandlers.find(type);
2482 if (res != mOutOfDialogHandlers.end())
2483 {
2484 return res->second;
2485 }
2486 else
2487 {
2488 return 0;
2489 }
2490}
2491
2492void
2493DialogUsageManager::addIncomingFeature(std::shared_ptr<DumFeature> feat)
2494{
2495 mIncomingFeatureList.emplace_back(feat);
2496}
2497
2498void
2499DialogUsageManager::addOutgoingFeature(std::shared_ptr<DumFeature> feat)
2500{
2501 // make sure EncryptionManager is the last feature in the list.
2502 mOutgoingFeatureList.emplace(std::begin(mOutgoingFeatureList), feat);
2503}
2504
2505void
2506DialogUsageManager::setOutgoingMessageInterceptor(std::shared_ptr<DumFeature> feat) noexcept
2507{
2508 mOutgoingMessageInterceptor = feat;
2509}
2510
2511void
2513{
2514 resip_assert(functor);
2515 for (DialogSetMap::iterator it = mDialogSetMap.begin(); it != mDialogSetMap.end(); ++it)
2516 {
2517 for (DialogSet::DialogMap::iterator i = it->second->mDialogs.begin(); i != it->second->mDialogs.end(); ++i)
2518 {
2519 std::vector<ServerSubscriptionHandle> serverSubs = i->second->getServerSubscriptions();
2520 for (std::vector<ServerSubscriptionHandle>::iterator iss = serverSubs.begin(); iss != serverSubs.end(); ++iss)
2521 {
2522 functor->apply(*iss);
2523 }
2524 }
2525 }
2526}
2527
2528void
2530{
2531 resip_assert(functor);
2532 for (DialogSetMap::iterator it = mDialogSetMap.begin(); it != mDialogSetMap.end(); ++it)
2533 {
2534 for (DialogSet::DialogMap::iterator i = it->second->mDialogs.begin(); i != it->second->mDialogs.end(); ++i)
2535 {
2536 std::vector<ClientSubscriptionHandle> clientSubs = i->second->getClientSubscriptions();
2537 for (std::vector<ClientSubscriptionHandle>::iterator ics = clientSubs.begin(); ics != clientSubs.end(); ++ics)
2538 {
2539 functor->apply(*ics);
2540 }
2541 }
2542 }
2543}
2544
2545void
2547{
2548 // Make a copy of the map - since calling end can cause an immediate delete this on the subscription and thus cause
2549 // the object to remove itself from the mServerSubscriptions map, messing up our iterator
2550 ServerSubscriptions tempSubscriptions = mServerSubscriptions;
2551 ServerSubscriptions::iterator it = tempSubscriptions.begin();
2552 for (; it != tempSubscriptions.end(); it++)
2553 {
2554 it->second->end(reason);
2555 }
2556}
2557
2558void
2560{
2561 // Make a copy of the map - since calling end can cause an immediate delete this on the publication and thus cause
2562 // the object to remove itself from the mServerPublications map, messing up our iterator
2563 ServerPublications tempPublications = mServerPublications;
2564 ServerPublications::iterator it = tempPublications.begin();
2565 for (; it != tempPublications.end(); it++)
2566 {
2567 it->second->end();
2568 }
2569}
2570
2571void
2573{
2574 mConnectionTerminatedEventDispatcher.addListener(listener);
2575}
2576
2577void
2579{
2580 mConnectionTerminatedEventDispatcher.removeListener(listener);
2581}
2582
2583void
2584DialogUsageManager::requestMergedRequestRemoval(const MergedRequestKey& key)
2585{
2586 // Only post delayed merge request removal if running, if we are shutting down, then there is no need
2587 if (mShutdownState == Running)
2588 {
2589 DebugLog(<< "Got merged request removal request");
2590 MergedRequestRemovalCommand command(*this, key);
2591 mStack.postMS(command, Timer::TF, this);
2592 }
2593}
2594
2595void
2596DialogUsageManager::removeMergedRequest(const MergedRequestKey& key)
2597{
2598 DebugLog(<< "Merged request removed");
2599 mMergedRequests.erase(key);
2600}
2601
2604{
2605 return *mIncomingTarget;
2606}
2607
2610{
2611 return *mOutgoingTarget;
2612}
2613
2616{
2617 if(handler)
2618 {
2619 mDialogEventStateManager = new DialogEventStateManager();
2620 mDialogEventStateManager->mDialogEventHandler = handler;
2621 }
2622 else
2623 {
2624 delete mDialogEventStateManager;
2625 mDialogEventStateManager=0;
2626 }
2627 return mDialogEventStateManager;
2628}
2629
2630void
2631DialogUsageManager::setAdvertisedCapabilities(SipMessage& msg, const std::shared_ptr<UserProfile>& userProfile)
2632{
2633 if(userProfile->isAdvertisedCapability(Headers::Allow))
2634 {
2635 msg.header(h_Allows) = getMasterProfile()->getAllowedMethods();
2636 }
2637 if(userProfile->isAdvertisedCapability(Headers::AcceptEncoding))
2638 {
2639 msg.header(h_AcceptEncodings) = getMasterProfile()->getSupportedEncodings();
2640 }
2641 if(userProfile->isAdvertisedCapability(Headers::AcceptLanguage))
2642 {
2643 msg.header(h_AcceptLanguages) = getMasterProfile()->getSupportedLanguages();
2644 }
2645 if(userProfile->isAdvertisedCapability(Headers::AllowEvents))
2646 {
2647 msg.header(h_AllowEvents) = getMasterProfile()->getAllowedEvents();
2648 }
2649 if(userProfile->isAdvertisedCapability(Headers::Supported))
2650 {
2651 msg.header(h_Supporteds) = getMasterProfile()->getSupportedOptionTags();
2652 }
2653}
2654
2655/* ====================================================================
2656 * The Vovida Software License, Version 1.0
2657 *
2658 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2659 *
2660 * Redistribution and use in source and binary forms, with or without
2661 * modification, are permitted provided that the following conditions
2662 * are met:
2663 *
2664 * 1. Redistributions of source code must retain the above copyright
2665 * notice, this list of conditions and the following disclaimer.
2666 *
2667 * 2. Redistributions in binary form must reproduce the above copyright
2668 * notice, this list of conditions and the following disclaimer in
2669 * the documentation and/or other materials provided with the
2670 * distribution.
2671 *
2672 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2673 * and "Vovida Open Communication Application Library (VOCAL)" must
2674 * not be used to endorse or promote products derived from this
2675 * software without prior written permission. For written
2676 * permission, please contact vocal@vovida.org.
2677 *
2678 * 4. Products derived from this software may not be called "VOCAL", nor
2679 * may "VOCAL" appear in their name, without prior written
2680 * permission of Vovida Networks, Inc.
2681 *
2682 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2683 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2684 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2685 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2686 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2687 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2688 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2689 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2690 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2691 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2692 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2693 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2694 * DAMAGE.
2695 *
2696 * ====================================================================
2697 *
2698 * This software consists of voluntary contributions made by Vovida
2699 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2700 * Inc. For more information on Vovida Networks, Inc., please see
2701 * <http://www.vovida.org/>.
2702 *
2703 */
#define threadCheck()
#define DebugLog(args_)
Definition Logger.hxx:128
#define StackLog(args_)
Definition Logger.hxx:125
#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.
static Mimes empty
static void usage(void)
Definition adig.c:755
AppDialogSetHandle getHandle()
virtual std::shared_ptr< UserProfile > selectUASUserProfile(const SipMessage &)
AppDialogHandle getHandle()
Definition AppDialog.cxx:18
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)=0
Represents the "callid" element in the SIP grammar.
Definition CallId.hxx:18
bool exists(const Param< CallID > &paramType) const
Definition CallId.cxx:121
Data & value()
Definition CallId.cxx:75
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
ClientPagerMessageHandle getHandle()
virtual void apply(ClientSubscriptionHandle)=0
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
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
Data & append(const char *str, size_type len)
Appends the specified number of bytes to the end of this Data.
Definition Data.cxx:1058
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
Implements the FSM for dialog state as spec'd in RFC 4235.
const Data & getCallId() const
const Data & getLocalTag() const
BaseCreator * getCreator() const noexcept
void end(const Data &endReason)
void dispatch(const SipMessage &msg)
void setUserProfile(std::shared_ptr< UserProfile > userProfile)
std::shared_ptr< UserProfile > getUserProfile() const
DialogSetId getId() const
void addTransport(TransportType protocol, int port=0, IpVersion version=V4, const Data &ipInterface=Data::Empty, const Data &sipDomainname=Data::Empty, const Data &privateKeyPassPhrase=Data::Empty, SecurityTypes::SSLType sslType=SecurityTypes::DynamicTLS, unsigned transportFlags=0)
void setClientRegistrationHandler(ClientRegistrationHandler *)
If there is no such handler, calling makeRegistration will throw.
void addServerPublicationHandler(const Data &eventType, ServerPublicationHandler *)
void addOutOfDialogHandler(MethodTypes, OutOfDialogHandler *)
DialogEventStateManager * createDialogEventStateManager(DialogEventHandler *handler)
void send(std::shared_ptr< SipMessage > request)
void addExternalMessageHandler(ExternalMessageHandler *handler)
Add/Remove External Message Handler do following op when processing thread in not running.
void shutdown(DumShutdownHandler *)
virtual const Data & name() const
Return the name of this TransactionUser.
void applyToAllServerSubscriptions(ServerSubscriptionFunctor *)
void setInviteSessionHandler(InviteSessionHandler *)
If there is no such handler, calling makeInviteSession will throw and receiving an INVITE as a UAS wi...
void setClientAuthManager(std::unique_ptr< ClientAuthManager > client) noexcept
If there is no ClientAuthManager, when the client receives a 401/407, pass it up through the normal B...
std::shared_ptr< DumFeature > mOutgoingMessageInterceptor
void setServerPagerMessageHandler(ServerPagerMessageHandler *) noexcept
void addClientPublicationHandler(const Data &eventType, ClientPublicationHandler *)
If there is no such handler, calling makePublication will throw.
void setServerRegistrationHandler(ServerRegistrationHandler *)
If no such handler, UAS will respond to REGISTER with 405 Method Not Allowed.
void setRedirectManager(std::unique_ptr< RedirectManager > redirect) noexcept
std::shared_ptr< UserProfile > & getMasterUserProfile()
void removeExternalMessageHandler(ExternalMessageHandler *handler)
std::shared_ptr< SipMessage > makePublication(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, const Contents &body, const Data &eventType, uint32_t expiresSeconds, AppDialogSet *=nullptr)
bool process(Mutex *mutex=NULL)
void end(DialogSetId invSessionId)
std::shared_ptr< SipMessage > makeRefer(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, const H_ReferTo::Type &referTo, AppDialogSet *=nullptr)
void setServerAuthManager(std::shared_ptr< ServerAuthManager > server)
If there is no ServerAuthManager, the server does not authenticate requests.
void setDialogSetHandler(DialogSetHandler *handler) noexcept
void setRegistrationPersistenceManager(RegistrationPersistenceManager *)
Sets a manager to handle storage of registration or publication state.
DialogUsageManager(SipStack &stack, bool createDefaultFeatures=false)
std::shared_ptr< SipMessage > makeInviteSession(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, const Contents *initialOffer, AppDialogSet *ads=nullptr)
RedirectHandler * getRedirectHandler() const noexcept
ClientPublicationHandler * getClientPublicationHandler(const Data &eventType)
DumFeatureChain::FeatureList mOutgoingFeatureList
InviteSessionHandle findInviteSession(const DialogId &id)
std::shared_ptr< SipMessage > makeOutOfDialogRequest(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, MethodTypes meth, AppDialogSet *=nullptr)
ClientSubscriptionHandler * getClientSubscriptionHandler(const Data &eventType)
void registerForConnectionTermination(Postable *)
Note: Implementations of Postable must delete the message passed via post.
ServerPublicationHandler * getServerPublicationHandler(const Data &eventType)
AppDialogSetHandle findAppDialogSet(const DialogSetId &id)
TargetCommand::Target & dumOutgoingTarget()
void setMasterProfile(const std::shared_ptr< MasterProfile > &masterProfile)
void addIncomingFeature(std::shared_ptr< DumFeature > feat)
void sendCommand(std::shared_ptr< SipMessage > request)
TargetCommand::Target & dumIncomingTarget()
void endAllServerSubscriptions(TerminateReason reason=Deactivated)
void addOutgoingFeature(std::shared_ptr< DumFeature > feat)
void setClientPagerMessageHandler(ClientPagerMessageHandler *) noexcept
ClientPagerMessageHandle makePagerMessage(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, AppDialogSet *=nullptr)
void applyToAllClientSubscriptions(ClientSubscriptionFunctor *)
ServerSubscriptionHandler * getServerSubscriptionHandler(const Data &eventType)
void setAppDialogSetFactory(std::unique_ptr< AppDialogSetFactory >) noexcept
void setRequestValidationHandler(RequestValidationHandler *)
void setOutgoingMessageInterceptor(std::shared_ptr< DumFeature > feat) noexcept
void addServerSubscriptionHandler(const Data &eventType, ServerSubscriptionHandler *)
AppDialogHandle findAppDialog(const DialogId &id)
DumFeatureChain::FeatureList mIncomingFeatureList
void internalProcess(std::unique_ptr< Message > msg)
void setKeepAliveManager(std::unique_ptr< KeepAliveManager > keepAlive) noexcept
std::shared_ptr< SipMessage > makeInviteSessionFromRefer(const SipMessage &refer, ServerSubscriptionHandle, const Contents *initialOffer, AppDialogSet *=nullptr)
void setPublicationPersistenceManager(PublicationPersistenceManager *)
std::shared_ptr< MasterProfile > & getMasterProfile()
void unRegisterForConnectionTermination(Postable *)
void setAdvertisedCapabilities(SipMessage &msg, const std::shared_ptr< UserProfile > &userProfile)
void setRedirectHandler(RedirectHandler *handler) noexcept
std::shared_ptr< SipMessage > makeRegistration(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, AppDialogSet *=nullptr)
void forceShutdown(DumShutdownHandler *)
void addClientSubscriptionHandler(const Data &eventType, ClientSubscriptionHandler *)
If there is no such handler, calling makeSubscription will throw.
std::shared_ptr< SipMessage > makeSubscription(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, const Data &eventType, AppDialogSet *=nullptr)
const DialogId & getDialogId() const
dcm! – kill typedef std::list<DialogId> DialogIdSet;
Definition Dialog.hxx:29
virtual void executeCommand()=0
SipMessage * decrypted()
dcm! – what is the intent of ApplicationMessage, especially as used in
virtual const Data & getTransactionId() const
static void setOutgoingEncryptionLevel(SipMessage &message, DialogUsageManager::EncryptionLevel level)
Definition DumHelper.cxx:11
virtual void onDumCanBeDeleted()=0
BaseUsageHandle getBaseUsage() const
virtual void shutdownWhenEmpty()
virtual void dumpHandles() const
bool isValid() const
Definition Handle.hxx:25
static Handle< InviteSession > NotValid()
Definition Handle.hxx:84
static void processStrictRoute(SipMessage &request)
Definition Helper.cxx:1701
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.
Definition Helper.cxx:412
InviteSessionHandle getSessionHandle()
const Tuple & getFlow() const
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
Definition Message.cxx:16
Represents the "media-type" element in the RFC 3261 grammar.
Definition Mime.hxx:20
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
const Data & getTransactionId() const
bool empty() const
return true or false indicating whether the mParsers vector is empty or not
virtual const NameAddr & getOutboundProxy() const
Definition Profile.cxx:503
virtual bool getForceOutboundProxyOnAllRequestsEnabled() const noexcept
Definition Profile.cxx:539
virtual const Data & getUserAgent() const
Definition Profile.cxx:635
virtual std::shared_ptr< MessageDecorator > getOutboundDecorator() noexcept
Definition Profile.cxx:873
virtual const Tokens & getProxyRequires() const
Definition Profile.cxx:671
virtual bool hasUserAgent() const noexcept
Definition Profile.cxx:647
virtual int getFixedTransportPort() const noexcept
Definition Profile.cxx:771
virtual bool hasProxyRequires() const noexcept
Definition Profile.cxx:683
virtual bool getExpressOutboundAsRouteSetEnabled() const noexcept
Definition Profile.cxx:571
virtual const Data & getFixedTransportInterface() const
Definition Profile.cxx:803
virtual bool hasOutboundProxy() const noexcept
Definition Profile.cxx:515
virtual bool getRportEnabled() const noexcept
Definition Profile.cxx:603
Much like class Lock above, but takes pointer argument to Lockable, which may be NULL.
Definition Lock.hxx:57
Abstract interface of a datastore of all publication documents processed by DUM.
virtual bool documentExists(const Data &eventType, const Data &documentKey, const Data &eTag)=0
static Data getCryptoRandomHex(unsigned int numBytes)
Definition Random.cxx:394
This class creates registration requests on behalf of a client.
Abstract interface of a datastore of all registered endpoints processed by DUM.
MethodTypes getMethod() const
const Uri & uri() const
MethodTypes & method()
Handler used to know when an incoming request failed validation.
virtual void onInvalidContentType(const SipMessage &request)=0
virtual void onInvalidRequiredOptions(const SipMessage &request)=0
virtual void onInvalidMethod(const SipMessage &request)=0
virtual void onInvalidContentLanguage(const SipMessage &request)=0
virtual void on100RelNotSupportedByRemote(const SipMessage &request)=0
virtual void onInvalidScheme(const SipMessage &request)=0
virtual void onInvalidAccept(const SipMessage &request)=0
virtual void onInvalidContentEncoding(const SipMessage &request)=0
virtual void dispatch(const SipMessage &msg)
virtual void apply(ServerSubscriptionHandle)=0
void setSubscriptionState(SubscriptionState state)
std::shared_ptr< SipMessage > update(const Contents *document)
void send(std::shared_ptr< SipMessage > msg) override
SIP body type for holding SipFrag contents (MIME content-type message/sipfrag).
Definition SipFrag.hxx:22
SipMessage & message()
Definition SipFrag.cxx:82
Represents a SIP message.
bool isRequest() const
Returns true if message is a request, false otherwise.
Contents * getContents() const
Retrieves the body of a SIP message.
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
This is the primary point of interaction between the app-layer and the stack.
Definition SipStack.hxx:160
Security * getSecurity() const
Returns a pointer to the embedded Security object, 0 if not set.
void send(const SipMessage &msg, TransactionUser *tu=0)
allows a TU to send a message
Definition SipStack.cxx:867
Transport * addTransport(TransportType protocol, int port, IpVersion version=V4, StunSetting stun=StunDisabled, const Data &ipInterface=Data::Empty, const Data &sipDomainname=Data::Empty, const Data &privateKeyPassPhrase=Data::Empty, SecurityTypes::SSLType sslType=SecurityTypes::DynamicTLS, unsigned transportFlags=0, const Data &certificateFilename="", const Data &privateKeyFilename="", SecurityTypes::TlsClientVerificationMode cvm=SecurityTypes::None, bool useEmailAsSIP=false, std::shared_ptr< WsConnectionValidator >=nullptr, std::shared_ptr< WsCookieContextFactory >=nullptr, const Data &netNs=Data::Empty)
Used by the application to add in a new built-in transport.
Definition SipStack.cxx:362
void registerTransactionUser(TransactionUser &, const bool front=false)
add a TU to the TU selection chain
static Data getHostAddress()
Get one of the IP address for this host (calls through to gethostbyname) and is not threadsafe.
Definition SipStack.cxx:794
void post(std::unique_ptr< ApplicationMessage > message, unsigned int secondsLater, TransactionUser *tu=0)
Makes the message available to the TU at some later time, specified in seconds.
void sendTo(std::unique_ptr< SipMessage > msg, const Uri &uri, TransactionUser *tu=0)
this is only if you want to send to a destination not in the route.
Definition SipStack.cxx:898
void unregisterTransactionUser(TransactionUser &)
Removes a TU from the TU selection chain.
void requestTransactionUserShutdown(TransactionUser &)
Queue a shutdown request to the specified TU.
void postMS(std::unique_ptr< ApplicationMessage > message, unsigned int ms, TransactionUser *tu=0)
Makes the message available to the TU at some later time, specified in milli-seconds.
static const char * Optional
Definition Symbols.hxx:105
static const char * C100rel
Definition Symbols.hxx:107
static int tlsKeyCreate(TlsKey &key, TlsDestructor *destructor)
This function follows pthread_key_create() signature.
Definition ThreadIf.cxx:130
static int tlsSetValue(TlsKey key, const void *val)
This function follows pthread_setspecific() signature.
Definition ThreadIf.cxx:169
static unsigned long TF
Definition Timer.hxx:121
Represents the "token" element in the RFC 3261 grammar.
Definition Token.hxx:18
The base-class for an RFC 3261 Transaction User.
TimeLimitFifo< Message > mFifo
This TransactionUser's fifo.
void post(Message *msg)
Posts a Message to this TransactionUser's fifo.
FlowKey mFlowKey
This is a (largely) opaque key that subclasses of Transport will use to help record/find flows.
Definition Tuple.hxx:189
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
Data getAor() const
Definition Uri.cxx:1095
SipMessage & embedded()
Definition Uri.cxx:1586
Data & scheme()
Definition Uri.hxx:143
void removeEmbedded()
Definition Uri.cxx:350
bool hasEmbedded() const
Definition Uri.cxx:343
void remove(const Param< Uri > &paramType)
Definition Uri.cxx:1709
bool isAnonymous() const
virtual bool & clientOutboundEnabled() noexcept
SSLType
Note: Before adding to the SSLType enum, please see the comments about mTlsCtx in resip/stack/ssl/Sec...
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
Definition Headers.cxx:348
std::mutex Mutex
A semaphore that can be locked by only one thread at a time.
Definition Mutex.hxx:37
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
Handle< AppDialogSet > AppDialogSetHandle
Definition Handles.hxx:27
Handle< AppDialog > AppDialogHandle
Definition Handles.hxx:28
std::unique_lock< RecursiveMutex > RecursiveLock
Definition Lock.hxx:29
unsigned int uint32_t
Definition Stun.hxx:34
InserterPClass< T > InserterP(const T &t)
Templatized function to construct an instance of InserterClass for a container to be inserted.
Definition Inserter.hxx:558
TransportType
An enumeration of transport protocols.
RequestLineType h_RequestLine
Definition Headers.cxx:347
std::recursive_mutex RecursiveMutex
Definition Mutex.hxx:38
IpVersion
An enumeration of IP versions.
@ MAX_METHODS
H_AllowEventss h_AllowEvents
Definition Headers.cxx:143
H_CallId h_CallId
Definition Headers.cxx:266