reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
UserAgent.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include "UserAgent.hxx"
7#include "UserAgentCmds.hxx"
12#include "ReconSubsystem.hxx"
13
14#include "MediaStackAdapter.hxx"
15
17
19
20#include <rutil/Log.hxx>
21#include <rutil/Logger.hxx>
35#if defined(USE_SSL)
36#ifdef WIN32
38#else
40#endif
41#endif
43#include <rutil/Random.hxx>
44
45#include <utility>
46
47using namespace recon;
48using namespace resip;
49using namespace std;
50
51#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
52
53UserAgent::UserAgent(ConversationManager* conversationManager, std::shared_ptr<UserAgentMasterProfile> profile, AfterSocketCreationFuncPtr socketFunc) :
54 mCurrentSubscriptionHandle(1),
55 mCurrentConversationProfileHandle(1),
56 mDefaultOutgoingConversationProfileHandle(0),
57 mConversationManager(conversationManager),
58 mProfile(profile),
59#if defined(USE_SSL)
60#ifdef WIN32
61 mSecurity(new WinSecurity(mProfile->certPath())),
62#else
63 mSecurity(new Security(mProfile->certPath())),
64#endif
65#else
66 mSecurity(0),
67#endif
68 mPollGrp(FdPollGrp::create()),
69 mEventInterruptor(new EventThreadInterruptor(*mPollGrp)),
70 mStack(mSecurity, mProfile->getAdditionalDnsServers(), mEventInterruptor, false /* stateless */, socketFunc, 0, mPollGrp),
71 mDum(mStack),
72 mStackThread(mStack, *mEventInterruptor, *mPollGrp),
73 mDumShutdown(false),
74 mUserAgentShutdown(false)
75{
76#if defined(USE_SSL)
77 const std::vector<Data>& rootCertDirectories = mProfile->rootCertDirectories();
78 std::vector<Data>::const_iterator ci = rootCertDirectories.begin();
79 for(;ci != rootCertDirectories.end();ci++)
80 {
82 }
83 const std::vector<Data>& rootCertBundles = mProfile->rootCertBundles();
84 ci = rootCertBundles.begin();
85 for(;ci != rootCertBundles.end();ci++)
86 {
88 }
89#endif
92
93 mStack.setTransportSipMessageLoggingHandler(mProfile->getTransportSipMessageLoggingHandler());
95
97
98 // Set Enum Suffixes
99 mStack.setEnumSuffixes(mProfile->getEnumSuffixes());
100
101 // Enable/Disable Statistics Manager
102 mStack.statisticsManagerEnabled() = mProfile->statisticsManagerEnabled();
103
104 // Install Handlers
108 mDum.setClientAuthManager(std::unique_ptr<ClientAuthManager>(new ClientAuthManager));
109 mDum.setKeepAliveManager(std::unique_ptr<KeepAliveManager>(new KeepAliveManager));
119
120 //mDum.addClientSubscriptionHandler(Symbols::Presence, this);
121 //mDum.addClientPublicationHandler(Symbols::Presence, this);
122 //mDum.addOutOfDialogHandler(NOTIFY, this);
123 //mDum.addServerSubscriptionHandler("message-summary", this);
124
125 // Set AppDialogSetFactory
126 std::unique_ptr<AppDialogSetFactory> dsf(new UserAgentDialogSetFactory(*mConversationManager));
127 mDum.setAppDialogSetFactory(std::move(dsf));
128
129 if (profile->serverAuthManagerEnabled())
130 {
131 // Set UserAgentServerAuthManager
132 mDum.setServerAuthManager(std::make_shared<UserAgentServerAuthManager>(*this));
133 }
134}
135
140
141void
146
153
154void
156{
157 mSubscriptions[subscription->getSubscriptionHandle()] = subscription;
158}
159
160void
165
172
173void
175{
176 mPublications[publication->getPublicationHandle()] = publication;
177}
178
179void
184
191
192void
194{
195 mRegistrations[registration->getConversationProfileHandle()] = registration;
196}
197
198void
203
204void
205UserAgent::process(int timeoutMs)
206{
207 mDum.process(timeoutMs);
208 mConversationManager->process();
209}
210
211void
213{
215 {
217 mDum.post(cmd);
218
219 InfoLog(<< "UserAgent::shutdown: posted UserAgentShutdownCmd, waiting for DUM to shutdown...");
220
221 // Wait for Dum to shutdown
222 while (!mDumShutdown)
223 {
224 process(100);
225 }
226
227 InfoLog(<< "UserAgent::shutdown: DUM shutdown, shutting down StackThread...");
228
231
232 InfoLog(<< "UserAgent::shutdown: StackThread shutdown.");
233 mUserAgentShutdown = true;
234 }
235}
236
237void
242
243void
248
249void
250UserAgent::post(ApplicationMessage& message, std::chrono::duration<double> duration)
251{
252 if(duration > std::chrono::milliseconds::zero())
253 {
254 mStack.post(message, duration, &mDum);
255 }
256 else
257 {
258 mDum.post(&message);
259 }
260}
261
262void
264{
265 switch(subsystem)
266 {
267 case SubsystemAll:
268 Log::setLevel(level);
269 break;
272 break;
273 case SubsystemDns:
275 break;
276 case SubsystemDum:
278 break;
279 case SubsystemSdp:
281 break;
282 case SubsystemSip:
284 break;
287 break;
290 break;
291 case SubsystemStats:
293 break;
294 case SubsystemRecon:
296 break;
299 break;
300 case SubsystemReTurn:
302 break;
303 }
304}
305
307UserAgent::addConversationProfile(std::shared_ptr<ConversationProfile> conversationProfile, bool defaultOutgoing)
308{
310 AddConversationProfileCmd* cmd = new AddConversationProfileCmd(this, handle, conversationProfile, defaultOutgoing);
311 mDum.post(cmd);
312 return handle;
313}
314
315void
321
322void
328
330UserAgent::createSubscription(const Data& eventType, const NameAddr& target, unsigned int subscriptionTime, const Mime& mimeType)
331{
333 CreateSubscriptionCmd* cmd = new CreateSubscriptionCmd(this, handle, eventType, target, subscriptionTime, mimeType);
334 mDum.post(cmd);
335 return handle;
336}
337
338void
344
346UserAgent::createPublication(const Data& eventType, const NameAddr& target, const Data& status, unsigned int publicationTime, const Mime& mimeType)
347{
349 CreatePublicationCmd* cmd = new CreatePublicationCmd(this, handle, status, eventType, target, publicationTime, mimeType);
350 mDum.post(cmd);
351
352 return handle;
353}
354
355void
361
362std::shared_ptr<ConversationProfile>
364{
366 {
368 }
369 else
370 {
371 resip_assert(false);
372 ErrLog( << "getDefaultOutgoingConversationProfile: something is wrong - no profiles to return");
373 return nullptr;
374 }
375}
376
377std::shared_ptr<ConversationProfile>
379{
380 resip_assert(!mediaAddress.empty());
381
382 ConversationProfileMap::iterator conIt;
383 for(conIt = mConversationProfiles.begin(); conIt != mConversationProfiles.end(); conIt++)
384 {
385 auto cp = conIt->second;
386 if(cp->sessionCaps().session().origin().getAddress() == mediaAddress)
387 {
388 return cp;
389 }
390 }
391 return nullptr;
392}
393
394std::shared_ptr<ConversationProfile>
396{
397 resip_assert(msg.isRequest());
398
399 // Examine the sip message, and select the most appropriate conversation profile
400
401 // Check if request uri matches registration contact
402 const Uri& requestUri = msg.header(h_RequestLine).uri();
403 RegistrationMap::iterator regIt;
404 for(regIt = mRegistrations.begin(); regIt != mRegistrations.end(); regIt++)
405 {
406 const NameAddrs& contacts = regIt->second->getContactAddresses();
407 NameAddrs::const_iterator naIt;
408 for(naIt = contacts.begin(); naIt != contacts.end(); naIt++)
409 {
410 if ((*naIt).uri() == requestUri && // uri's match
411 (!requestUri.exists(p_rinstance) || // and request Uri doesn't have rinstance parameter OR
412 ((*naIt).uri().exists(p_rinstance) && requestUri.param(p_rinstance) == (*naIt).uri().param(p_rinstance)))) // rinstance parameter matches
413 {
414 ConversationProfileMap::iterator conIt = mConversationProfiles.find(regIt->first);
415 if(conIt != mConversationProfiles.end())
416 {
417 InfoLog(<< "getIncomingConversationProfile: comparing requestUri=" << requestUri << " to contactUri=" << (*naIt).uri() << " - MATCHED!");
418 return conIt->second;
419 }
420 else
421 {
422 InfoLog(<< "getIncomingConversationProfile: comparing requestUri=" << requestUri << " to contactUri=" << (*naIt).uri() << " - matched, but conversation profile not found");
423 }
424 }
425 else
426 {
427 InfoLog(<< "getIncomingConversationProfile: comparing requestUri=" << requestUri << " to contactUri=" << (*naIt).uri() << " - no match");
428 }
429 }
430 }
431
432 // Check if To header matches default from
433 Data toAor = msg.header(h_To).uri().getAor();
434 ConversationProfileMap::iterator conIt;
435 for(conIt = mConversationProfiles.begin(); conIt != mConversationProfiles.end(); conIt++)
436 {
437 if(isEqualNoCase(toAor, conIt->second->getDefaultFrom().uri().getAor()))
438 {
439 InfoLog(<< "getIncomingConversationProfile: comparing toAor=" << toAor << " to defaultFromAor=" << conIt->second->getDefaultFrom().uri().getAor() << " - MATCHED!");
440 return conIt->second;
441 }
442 else
443 {
444 InfoLog(<< "getIncomingConversationProfile: comparing toAor=" << toAor << " to defaultFromAor=" << conIt->second->getDefaultFrom().uri().getAor() << " - no match");
445 }
446 }
447
448 // If can't find any matches, then return the default outgoing profile
449 InfoLog( << "getIncomingConversationProfile: no matching profile found, falling back to default outgoing profile");
451}
452
453std::shared_ptr<UserAgentMasterProfile>
455{
456 return mProfile;
457}
458
464
470
471void
473{
474 InfoLog(<< "UserAgent::onDumCanBeDeleted called.");
475 mDumShutdown = true;
476}
477
478void
480{
481 // This get's posted to from the Dum thread - so we have no threading concerns
482 ConnectionTerminated* pTerminated = dynamic_cast<ConnectionTerminated*>(pMsg);
483 if (pTerminated)
484 {
485 InfoLog(<< "ConnectionTerminated seen for " << pTerminated->getFlow() << " refreshing registrations");
486
487 // Iterate through registrations and see if any match this connection. If so, then force an immediate
488 // refresh so that we can detect server failure and re-register sooner.
489 RegistrationMap::iterator regIt;
490 for (regIt = mRegistrations.begin(); regIt != mRegistrations.end(); regIt++)
491 {
492 if (regIt->second->getLastServerTuple().getFlowKey() == pTerminated->getFlow().getFlowKey())
493 {
494 regIt->second->forceRefresh();
495 }
496 }
497 }
498 delete pMsg;
499}
500
501void
503{
504 std::vector<UserAgentMasterProfile::TransportInfo>& transports = mProfile->getTransports();
505 std::vector<UserAgentMasterProfile::TransportInfo>::iterator i;
506 int lastActualPort = 0;
507 for(i = transports.begin(); i != transports.end(); i++)
508 {
510 try
511 {
512#ifdef USE_SSL
513 // Make sure certificate material available before trying to instantiate Transport
514 if(isSecure(ti.mProtocol))
515 {
516 // FIXME: see comments about repro / CertificatePath
517 if(!ti.mTlsCertificate.empty())
518 {
520 }
521 if(!ti.mTlsPrivateKey.empty())
522 {
524 }
525 }
526#endif
527
529 ti.mPort == -1 ? lastActualPort : ti.mPort, // Port as -1 is special designation that we should use the actual port from the last transport added
530 ti.mIPVersion,
532 ti.mIPInterface, // interface to bind to
534 ti.mTlsPrivateKeyPassPhrase, // private key passphrase
535 ti.mSslType, // sslType
536 0, // transport flags
538 ti.mCvm, // tls client verification mode
539 ti.mUseEmailAsSIP);
540
541 if (t)
542 {
543 int rcvBufLen = ti.mRcvBufLen;
544 if (rcvBufLen >0 )
545 {
546#if defined(RESIP_SIPSTACK_HAVE_FDPOLL)
547 // this new method is part of the epoll changeset,
548 // which isn't commited yet.
549 t->setRcvBufLen(rcvBufLen);
550#else
551 resip_assert(0);
552#endif
553 }
554
555 // Fill in actual port used
556 ti.mActualPort = t->getTuple().getPort();
557 // Store last actual port, incase next transport uses special port of -1 to indicate use of last actual port
558 lastActualPort = ti.mActualPort;
559 }
560 }
561 catch (BaseException& e)
562 {
563 WarningLog (<< "Caught: " << e);
564 WarningLog (<< "Failed to add " << Tuple::toData(ti.mProtocol) << " transport on " << ti.mPort);
565 }
566 }
567}
568
569void
570UserAgent::startApplicationTimer(unsigned int timerId, std::chrono::duration<double> duration, unsigned int seqNumber)
571{
572 UserAgentTimeout t(*this, timerId, duration, seqNumber);
573 post(t, duration);
574}
575
576void
577UserAgent::onApplicationTimer(unsigned int timerId, std::chrono::duration<double> duration, unsigned int seqNumber)
578{
579 // Default implementation is to do nothing - application should override this
580}
581
582void
584{
585 // Default implementation is to do nothing - application should override this
586}
587
588void
590{
591 // Default implementation is to do nothing - application should override this
592}
593
594void
596{
597 InfoLog(<< "UserAgent::shutdownImpl shutting down DUM...");
598 mDum.shutdown(this);
599
600 // End all subscriptions
601 InfoLog(<< "UserAgent::shutdownImpl ending " << mSubscriptions.size() << " subscriptions...");
602 SubscriptionMap tempSubs = mSubscriptions; // Create copy for safety, since ending Subscriptions can immediately remove themselves from map
603 SubscriptionMap::iterator i;
604 for(i = tempSubs.begin(); i != tempSubs.end(); i++)
605 {
606 i->second->end();
607 }
608
609 // Unregister all registrations
610 InfoLog(<< "UserAgent::shutdownImpl ending " << mRegistrations.size() << " registrations...");
611 RegistrationMap tempRegs = mRegistrations; // Create copy for safety, since ending can immediately remove themselves from map
612 RegistrationMap::iterator j;
613 for(j = tempRegs.begin(); j != tempRegs.end(); j++)
614 {
615 j->second->end();
616 }
617
618 mConversationManager->shutdown();
619}
620
621void
622UserAgent::addConversationProfileImpl(ConversationProfileHandle handle, std::shared_ptr<ConversationProfile> conversationProfile, bool defaultOutgoing)
623{
624 // Store new profile
625 mConversationProfiles[handle] = conversationProfile;
626 conversationProfile->setHandle(handle);
627
628#ifdef USE_SSL
629 // If this is the first profile ever set - then use the aor defined in it as the aor used in
630 // the DTLS certificate for the DtlsFactory - TODO - improve this sometime so that we can change the aor in
631 // the cert at runtime to equal the aor in the default conversation profile
633 {
634 mConversationManager->getMediaStackAdapter().initializeDtlsFactory(conversationProfile->getDefaultFrom().uri().getAor());
635 }
636#endif
637
638 // Set the default outgoing if requested to do so, or we don't have one yet
639 if(defaultOutgoing || mDefaultOutgoingConversationProfileHandle == 0)
640 {
642 }
643
644 // Register new profile
645 if(conversationProfile->getDefaultRegistrationTime() != 0)
646 {
647 UserAgentRegistration *registration = new UserAgentRegistration(*this, mDum, handle);
648 mDum.send(mDum.makeRegistration(conversationProfile->getDefaultFrom(), conversationProfile, registration));
649 }
650}
651
652void
657
658void
660{
661 // Remove matching registration if found
662 RegistrationMap::iterator it = mRegistrations.find(handle);
663 if(it != mRegistrations.end())
664 {
665 it->second->end();
666 }
667
668 // Remove from ConversationProfile map
669 mConversationProfiles.erase(handle);
670
671 // If this Conversation Profile was the default - select the first item in the map as the new default
673 {
674 ConversationProfileMap::iterator it = mConversationProfiles.begin();
675 if(it != mConversationProfiles.end())
676 {
678 }
679 else
680 {
682 }
683 }
684}
685
686void
687UserAgent::createSubscriptionImpl(SubscriptionHandle handle, const Data& eventType, const NameAddr& target, unsigned int subscriptionTime, const Mime& mimeType)
688{
689 // Ensure we have a client subscription handler for this event type
690 if(!mDum.getClientSubscriptionHandler(eventType))
691 {
692 mDum.addClientSubscriptionHandler(eventType, this);
693 }
694 // Ensure that the request Mime type is supported in the dum profile
695 if(!mProfile->isMimeTypeSupported(NOTIFY, mimeType))
696 {
697 mProfile->addSupportedMimeType(NOTIFY, mimeType);
698 }
699
700 UserAgentClientSubscription *subscription = new UserAgentClientSubscription(*this, mDum, handle);
701 mDum.send(mDum.makeSubscription(target, getDefaultOutgoingConversationProfile(), eventType, subscriptionTime, subscription));
702}
703
704void
706{
707 SubscriptionMap::iterator it = mSubscriptions.find(handle);
708 if(it != mSubscriptions.end())
709 {
710 it->second->end();
711 }
712}
713
714void
715UserAgent::createPublicationImpl(PublicationHandle handle, const Data& status, const Data& eventType, const NameAddr& target, unsigned int publicationTime, const Mime& mimeType)
716{
717 // Ensure we have a client publication handler for this event type
718 if(!mDum.getClientPublicationHandler(eventType))
719 {
720 mDum.addClientPublicationHandler(eventType, this);
721 }
722
723 Data note;
724 if(status == "dnd")
725 {
726 note = Data("Busy (DND)");
727 }
728 else if(status == "available")
729 {
730 note = Data("Online");
731 }
732 else if(status == "away")
733 {
734 note = Data("Away");
735 }
736
737 // Adding rpid defined at RFC 4480 https://tools.ietf.org/html/rfc4480#page-7
739 gPidf.setSimplePresenceTupleNode(Data(string("ID-") + Random::getRandomHex(3).c_str()), true, Data::Empty, note, target.uri().getAorNoReally(), Data(1.0));
740
742 dm->mNamespacePrefix = Data("dm:");
743 dm->mTag = "person";
744 dm->mAttributes["id"] = Data(string("ID-") + Random::getRandomHex(3).c_str());
745
747 rpid->mNamespacePrefix = Data("rpid:");
748 rpid->mTag = "activities";
749 dm->mChildren.push_back(rpid);
750
751 if(status != "available")
752 {
754 st->mNamespacePrefix = Data("rpid:");
755 st->mTag = status;
756 rpid->mChildren.push_back(st);
757 }
758
760 rootNodes.push_back(dm);
761 gPidf.setRootNodes(rootNodes);
762
763 gPidf.setEntity(target.uri());
764 gPidf.addNamespace(Data("urn:ietf:params:xml:ns:pidf:data-model"), Data("dm"));
765 gPidf.addNamespace(Data("urn:ietf:params:xml:ns:pidf:rpid"), Data("rpid"));
766
767 DebugLog( << "generated final gPidf : " << endl << gPidf );
768
769 UserAgentClientPublication *publication = new UserAgentClientPublication(*this, mDum, handle);
770 mDum.send(mDum.makePublication(target, getDefaultOutgoingConversationProfile(), gPidf, eventType, publicationTime, publication));
771}
772
773void
775{
776 PublicationMap::iterator it = mPublications.find(handle);
777 if(it != mPublications.end())
778 {
779 it->second->end();
780 }
781}
782
784// Registration Handler ////////////////////////////////////////////////////////
786void
788{
789 dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onSuccess(h, msg);
790}
791
792void
794{
795 dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onFailure(h, msg);
796}
797
798void
800{
801 dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onRemoved(h, msg);
802}
803
804int
806{
807 return dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onRequestRetry(h, retryMinimum, msg);
808}
809
811// ClientSubscriptionHandler ///////////////////////////////////////////////////
813void
815{
816 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onUpdatePending(h, msg, outOfOrder);
817}
818
819void
821{
822 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onUpdateActive(h, msg, outOfOrder);
823}
824
825void
827{
828 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onUpdateExtension(h, msg, outOfOrder);
829}
830
831void
833{
834 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onTerminated(h, msg);
835}
836
837void
839{
840 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onNewSubscription(h, msg);
841}
842
843int
845{
846 return dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onRequestRetry(h, retryMinimum, msg);
847}
848
850// ClientPublicationHandler ////////////////////////////////////////////////////
852void
854{
855 dynamic_cast<UserAgentClientPublication *>(h->getAppDialogSet().get())->onSuccess(h, status);
856}
857
858void
860{
861 dynamic_cast<UserAgentClientPublication *>(h->getAppDialogSet().get())->onRemove(h, status);
862}
863
864int
866{
867 return dynamic_cast<UserAgentClientPublication *>(h->getAppDialogSet().get())->onRequestRetry(h, retrySeconds, status);
868}
869
870void
872{
873 dynamic_cast<UserAgentClientPublication *>(h->getAppDialogSet().get())->onFailure(h, status);
874}
875
876/* ====================================================================
877
878 Copyright (c) 2021, Daniel Pocock https://danielpocock.com
879 Copyright (c) 2007-2008, Plantronics, Inc.
880 Copyright (c) 2016-2026, SIP Spectrum, Inc. https://www.sipspectrum.com
881
882 All rights reserved.
883
884 Redistribution and use in source and binary forms, with or without
885 modification, are permitted provided that the following conditions are
886 met:
887
888 1. Redistributions of source code must retain the above copyright
889 notice, this list of conditions and the following disclaimer.
890
891 2. Redistributions in binary form must reproduce the above copyright
892 notice, this list of conditions and the following disclaimer in the
893 documentation and/or other materials provided with the distribution.
894
895 3. Neither the name of Plantronics nor the names of its contributors
896 may be used to endorse or promote products derived from this
897 software without specific prior written permission.
898
899 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
900 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
901 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
902 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
903 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
904 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
905 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
906 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
907 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
908 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
909 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
910
911 ==================================================================== */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
static FlowManagerSubsystem FLOWMANAGER
static ReTurnSubsystem RETURN
static ReconSubsystem RECON
This class is one of two main classes of concern to an application using the UserAgent library.
virtual void setUserAgent(UserAgent *userAgent)
MediaStackAdapter & getMediaStackAdapter()
virtual void setRTCPEventLoggingHandler(std::shared_ptr< flowmanager::RTCPEventLoggingHandler > h)
This class is used to manage active client publications.
This class is used to manage active client subscriptions.
This class is used to manage the creation of RemoteParticipant objects.
resip::SecurityTypes::TlsClientVerificationMode mCvm
This class is used to manage active SIP registrations.
ConversationProfileHandle getConversationProfileHandle()
The classes defined here are used to pass commands from the application thread to the UserAgent threa...
virtual void onSubscriptionNotify(SubscriptionHandle handle, const resip::Data &notifyData)
Callback used when a subscription has received an event notification from the server.
void unregisterSubscription(UserAgentClientSubscription *)
volatile bool mDumShutdown
std::shared_ptr< UserAgentMasterProfile > mProfile
friend class UserAgentClientSubscription
std::map< ConversationProfileHandle, UserAgentRegistration * > RegistrationMap
friend class DestroyConversationProfileCmd
friend class CreatePublicationCmd
std::map< SubscriptionHandle, UserAgentClientSubscription * > SubscriptionMap
friend class DestroySubscriptionCmd
virtual void onApplicationTimer(unsigned int timerId, std::chrono::duration< double > duration, unsigned int seqNumber)
Callback used when an application timer expires.
std::shared_ptr< ConversationProfile > getDefaultOutgoingConversationProfile()
virtual void process(int timeoutMs)
This should be called in a loop to give process cycles to the UserAgent.
void shutdown()
Used to initiate a shutdown of the useragent.
virtual void onUpdateExtension(resip::ClientSubscriptionHandle, const resip::SipMessage &notify, bool outOfOrder)
resip::DialogUsageManager & getDialogUsageManager()
virtual std::shared_ptr< ConversationProfile > getIncomingConversationProfile(const resip::SipMessage &msg)
void setDefaultOutgoingConversationProfile(ConversationProfileHandle handle)
Sets an existing Conversation Profile to the default profile to use for outbound calls.
static void setLogLevel(resip::Log::Level level, LoggingSubsystem subsystem=SubsystemAll)
Static method that sets the logging level for a particular subsystem, or all subsystems.
resip::Mutex mSubscriptionHandleMutex
std::shared_ptr< UserAgentMasterProfile > getUserAgentMasterProfile() const noexcept
ConversationManager * mConversationManager
SubscriptionMap mSubscriptions
void destroyPublication(PublicationHandle handle)
resip::EventStackThread mStackThread
resip::SipStack mStack
void registerRegistration(UserAgentRegistration *)
void startup()
Starts the SIP stack thread.
resip::Mutex mPublicationHandleMutex
virtual void onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage &response)
Called when registration succeeds or each time it is successfully refreshed (manual refreshes only).
void destroyConversationProfile(ConversationProfileHandle handle)
Destroys an existing Conversation Profile.
void logDnsCache()
Used to initiate a snapshot of the existing DNS entries in the cache to the logging subsystem.
RegistrationMap mRegistrations
PublicationHandle mCurrentPublicationHandle
UserAgent(ConversationManager *conversationManager, std::shared_ptr< UserAgentMasterProfile > masterProfile, resip::AfterSocketCreationFuncPtr socketFunc=0)
Constructor.
Definition UserAgent.cxx:53
ConversationProfileHandle addConversationProfile(std::shared_ptr< ConversationProfile > conversationProfile, bool defaultOutgoing=true)
Adds a Conversation Profile to be managed, by the user agent.
void destroySubscription(SubscriptionHandle handle)
Destroys an existing subscriptions.
resip::Mutex mConversationProfileHandleMutex
friend class DestroyPublicationCmd
friend class UserAgentRegistration
PublicationHandle createPublication(const resip::Data &eventType, const resip::NameAddr &target, const resip::Data &status, unsigned int publicationTime, const resip::Mime &mimeType)
void unregisterPublication(UserAgentClientPublication *)
virtual void onUpdatePending(resip::ClientSubscriptionHandle h, const resip::SipMessage &notify, bool outOfOrder)
ConversationProfileHandle getNewConversationProfileHandle()
void registerSubscription(UserAgentClientSubscription *)
SubscriptionHandle createSubscription(const resip::Data &eventType, const resip::NameAddr &target, unsigned int subscriptionTime, const resip::Mime &mimeType)
Requests that the user agent create and manage an event subscription.
void unregisterRegistration(UserAgentRegistration *)
resip::DialogUsageManager mDum
virtual void onNewSubscription(resip::ClientSubscriptionHandle h, const resip::SipMessage &notify)
friend class AddConversationProfileCmd
ConversationProfileMap mConversationProfiles
virtual ~UserAgent()
void clearDnsCache()
Used to clear the existing DNS entries in the cache.
friend class UserAgentShutdownCmd
friend class CreateSubscriptionCmd
friend class UserAgentClientPublication
void addConversationProfileImpl(ConversationProfileHandle handle, std::shared_ptr< ConversationProfile > conversationProfile, bool defaultOutgoing=true)
std::shared_ptr< ConversationProfile > getConversationProfileByMediaAddress(const resip::Data &mediaAddress)
virtual void post(resip::Message *msg)
volatile bool mUserAgentShutdown
ConversationManager * getConversationManager()
Retrieves the ConversationManager passed in the constructor.
virtual void startApplicationTimer(unsigned int timerId, std::chrono::duration< double > duration, unsigned int seqNumber)
Used by an application to start a timer that is managed by the useragent.
PublicationMap mPublications
virtual void onRemove(resip::ClientPublicationHandle h, const resip::SipMessage &status)
PublicationHandle getNewPublicationHandle()
void destroySubscriptionImpl(SubscriptionHandle handle)
virtual void onTerminated(resip::ClientSubscriptionHandle h, const resip::SipMessage *notify)
SubscriptionHandle mCurrentSubscriptionHandle
ConversationProfileHandle mCurrentConversationProfileHandle
SubscriptionHandle getNewSubscriptionHandle()
void setDefaultOutgoingConversationProfileImpl(ConversationProfileHandle handle)
friend class SetDefaultOutgoingConversationProfileCmd
void registerPublication(UserAgentClientPublication *)
void createPublicationImpl(PublicationHandle handle, const resip::Data &status, const resip::Data &eventType, const resip::NameAddr &target, unsigned int publicationTime, const resip::Mime &mimeType)
resip::Security * mSecurity
ConversationProfileHandle mDefaultOutgoingConversationProfileHandle
void onDumCanBeDeleted()
virtual int onRequestRetry(resip::ClientRegistrationHandle h, int retryMinimum, const resip::SipMessage &msg)
call on Retry-After failure.
virtual void onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage &response)
virtual void onUpdateActive(resip::ClientSubscriptionHandle h, const resip::SipMessage &notify, bool outOfOrder)
virtual void onSubscriptionTerminated(SubscriptionHandle handle, unsigned int statusCode)
Callback used when a subscription is terminated.
void destroyPublicationImpl(PublicationHandle handle)
void createSubscriptionImpl(SubscriptionHandle handle, const resip::Data &eventType, const resip::NameAddr &target, unsigned int subscriptionTime, const resip::Mime &mimeType)
virtual void onFailure(resip::ClientRegistrationHandle h, const resip::SipMessage &response)
Called if registration fails, usage will be destroyed (unless a Registration retry interval is enable...
void destroyConversationProfileImpl(ConversationProfileHandle handle)
A base-class for messages used by applications.
The abstract base-class for all exceptions thrown by resip code.
void addDomainPrivateKeyPEM(const Data &domainName, const Data &privateKeyPEM, const Data &privateKeyPassPhrase=Data::Empty)
void addDomainCertPEM(const Data &domainName, const Data &certPEM)
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
static Data fromFile(const Data &filename)
Definition Data.cxx:2539
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
void setClientRegistrationHandler(ClientRegistrationHandler *)
If there is no such handler, calling makeRegistration will throw.
void addOutOfDialogHandler(MethodTypes, OutOfDialogHandler *)
void send(std::shared_ptr< SipMessage > request)
void shutdown(DumShutdownHandler *)
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...
void setServerPagerMessageHandler(ServerPagerMessageHandler *) noexcept
void addClientPublicationHandler(const Data &eventType, ClientPublicationHandler *)
If there is no such handler, calling makePublication will throw.
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 setServerAuthManager(std::shared_ptr< ServerAuthManager > server)
If there is no ServerAuthManager, the server does not authenticate requests.
void setDialogSetHandler(DialogSetHandler *handler) noexcept
ClientPublicationHandler * getClientPublicationHandler(const Data &eventType)
ClientSubscriptionHandler * getClientSubscriptionHandler(const Data &eventType)
void registerForConnectionTermination(Postable *)
Note: Implementations of Postable must delete the message passed via post.
void setMasterProfile(const std::shared_ptr< MasterProfile > &masterProfile)
void setClientPagerMessageHandler(ClientPagerMessageHandler *) noexcept
void setAppDialogSetFactory(std::unique_ptr< AppDialogSetFactory >) noexcept
void addServerSubscriptionHandler(const Data &eventType, ServerSubscriptionHandler *)
void setKeepAliveManager(std::unique_ptr< KeepAliveManager > keepAlive) noexcept
void setRedirectHandler(RedirectHandler *handler) noexcept
std::shared_ptr< SipMessage > makeRegistration(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, AppDialogSet *=nullptr)
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)
SIP body type for holding PIDF contents (MIME content-type application/pidf+xml).
void setRootNodes(const NodeList &nodeList)
void setSimplePresenceTupleNode(const Data &id, bool online, const Data &timestamp=Data::Empty, const Data &note=Data::Empty, const Data &contact=Data::Empty, const Data &contactPriority=Data::Empty)
const NodeList & getRootNodes() const
void addNamespace(const Data &uri, const Data &prefix)
void setEntity(const Uri &entity)
static void setLevel(Level level)
Set logging level for current thread.
Definition Log.cxx:423
The base-class used for message-passing.
Definition Message.hxx:21
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
iterator end()
Returns an iterator pointing to the last header field value.
iterator begin()
Returns an iterator pointing to the first header field value.
bool find(const T &rhs) const
Finds the first header field value that matches rhs.
static Data getRandomHex(unsigned int numBytes)
Definition Random.cxx:382
const Uri & uri() const
void loadCAFile(const Data &fileName)
Definition Security.cxx:259
void loadCADirectory(const Data &directoryName)
Definition Security.cxx:232
Represents a SIP message.
bool isRequest() const
Returns true if message is a request, false otherwise.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
void clearDnsCache()
Clear the DNS Cache.
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 logDnsCache()
Log the DNS Cache to WarningLog for Debugging.
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 setTransportSipMessageLoggingHandler(std::shared_ptr< Transport::SipMessageLoggingHandler > handler)
Used by the application to provide a handler that will get called for all inbound and outbound SIP me...
Definition SipStack.cxx:332
static Subsystem TRANSPORT
Definition Subsystem.hxx:50
static Subsystem STATS
Definition Subsystem.hxx:51
static Subsystem SDP
Definition Subsystem.hxx:46
static Subsystem DNS
Definition Subsystem.hxx:39
static Subsystem CONTENTS
Definition Subsystem.hxx:38
static Subsystem SIP
Definition Subsystem.hxx:47
static Subsystem DUM
Definition Subsystem.hxx:40
static Subsystem TRANSACTION
Definition Subsystem.hxx:49
virtual void run()
Definition ThreadIf.cxx:75
void post(Message *msg)
Posts a Message to this TransactionUser's fifo.
The base class for Transport classes.
Definition Transport.hxx:83
const Tuple & getTuple() const
virtual void setRcvBufLen(int buflen)
static const Data & toData(TransportType)
Converts the TransportType to a string representation of the transport type, e.g.
Definition Tuple.cxx:927
int getPort() const
Definition Tuple.cxx:466
FlowKey getFlowKey() const
Definition Tuple.hxx:126
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
Data getAor() const
Definition Uri.cxx:1095
bool exists(const Param< Uri > &paramType) const
Definition Uri.cxx:1701
Data getAorNoReally() const
Definition Uri.hxx:57
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
WARNING - This class is only appropriate for client TLS connections, as it only loads root certs.
volatile bool & statisticsManagerEnabled()
Enable Statistics Manager.
void setEnumSuffixes(const std::vector< Data > &suffixes)
Specify which enum domains will be searched when sending.
unsigned int ConversationProfileHandle
unsigned int SubscriptionHandle
unsigned int PublicationHandle
dcm! – add UnusedChecking(_enum) below;
void(* AfterSocketCreationFuncPtr)(Socket s, int transportType, const char *file, int line)
Definition Socket.hxx:107
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
Definition Lock.hxx:28
bool isSecure(TransportType type)
Returns true if passed in transport type is a secure transport protocol.
RequestLineType h_RequestLine
Definition Headers.cxx:347