/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com) * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __ENGINE_H #define __ENGINE_H #include "resip/stack/SdpContents.hxx" #include "resip/stack/SipMessage.hxx" #include "resip/stack/ShutdownMessage.hxx" #include "resip/stack/SipStack.hxx" #include "resip/stack/InternalTransport.hxx" #include "resip/dum/ClientAuthManager.hxx" #include "resip/dum/ClientInviteSession.hxx" #include "resip/dum/ClientRegistration.hxx" #include "resip/dum/DialogUsageManager.hxx" #include "resip/dum/DumShutdownHandler.hxx" #include "resip/dum/InviteSessionHandler.hxx" #include "resip/dum/MasterProfile.hxx" #include "resip/dum/RegistrationHandler.hxx" #include "resip/dum/ServerInviteSession.hxx" #include "resip/dum/ServerOutOfDialogReq.hxx" #include "resip/dum/OutOfDialogHandler.hxx" #include "resip/dum/AppDialog.hxx" #include "resip/dum/AppDialogSet.hxx" #include "resip/dum/AppDialogSetFactory.hxx" #include "resip/dum/ClientPublication.hxx" #include "resip/dum/ClientSubscription.hxx" #include "resip/dum/SubscriptionHandler.hxx" #include "resip/dum/PagerMessageHandler.hxx" #include "resip/dum/PublicationHandler.hxx" #include "resip/dum/ClientPagerMessage.hxx" #include "resip/dum/ServerPagerMessage.hxx" #include "rutil/Log.hxx" #include "rutil/Logger.hxx" #include "rutil/Random.hxx" #include "rutil/WinLeakCheck.hxx" #include "rutil/DnsUtil.hxx" #include "resip/stack/DnsResult.hxx" #include "resip/stack/SipStack.hxx" #include "rutil/dns/RRVip.hxx" #include "rutil/dns/QueryTypes.hxx" #include "rutil/dns/DnsStub.hxx" #include "../ice/ICEBox.h" #include "../ice/ICETime.h" #include #include #include "../engine_config.h" #include "EP_Session.h" #include "EP_Observer.h" #include "EP_DataProvider.h" #include "../helper/HL_VariantMap.h" #include "../helper/HL_SocketHeap.h" #include "../helper/HL_Sync.h" #include "../helper/HL_ByteBuffer.h" #include "../media/MT_Stream.h" #define RESIPROCATE_SUBSYSTEM Subsystem::TEST using namespace std; enum { TransportType_Any, TransportType_Udp, TransportType_Tcp, TransportType_Tls }; enum { CONFIG_IPV4 = 0, // Use IP4 CONFIG_IPV6, // Use IP6. CONFIG_USERNAME, // Username. String value. CONFIG_DOMAIN, // Domain. String value. CONFIG_PASSWORD, // Password. String value. CONFIG_RINSTANCE, // Determines if SIP rinstance field has to be used during registration. Boolean value. CONFIG_INSTANCE_ID, // Instance id. It is alternative option to rinstance. CONFIG_DISPLAYNAME, // Optional user display name. String value. CONFIG_DOMAINPORT, // Optional domain port number. Integer value. CONFIG_REGISTERDURATION, // Wanted duration for registration. Integer value. It is MANDATORY value. CONFIG_RPORT, // Use SIP rport field. Recommended to set it to true. Boolean value. CONFIG_KEEPALIVETIME, // Interval between UDP keep-alive messages. Boolean value. CONFIG_RELAY, // Sets if TURN server must be used instead of STUN. Boolean value. CONFIG_ICETIMEOUT, // Optional timeout for ICE connectivity checks and candidate gathering. Integer value. CONFIG_ICEUSERNAME, // Optional username for TURN server. String value. CONFIG_ICEPASSWORD, // Optional password for TURN server. String value. CONFIG_SIPS, // Marks if account credentials are sips: scheme. Boolean value. CONFIG_STUNSERVER_IP, // Optional IP address of STUN/TURN server. String value. It is better to use CONFIG_STUNSERVER_NAME. CONFIG_STUNSERVER_NAME, // Host name of STUN/TURN server. stun.xten.com for example. String value. CONFIG_STUNSERVER_PORT, // Port number of STUN/TURN server. Integer value. CONFIG_USERAGENT, // Name of user agent in SIP headers. String value. CONFIG_ICEREQUIRED, // ICE MUST be present in remote peer offers and answers. Boolean value. CONFIG_TRANSPORT, // 0 - all transports, 1 - UDP, 2 - TCP, 3 - TLS, CONFIG_SUBSCRIPTION_TIME, // Subscription time (in seconds) CONFIG_SUBSCRIPTION_REFRESHTIME, // Refresh interval for subscriptions CONFIG_DNS_CACHE_TIME, // DNS cache time; default is 86400 seconds CONFIG_PRESENCE_ID, // Tuple ID used in presence publishing; determines source device CONFIG_ROOTCERT, // Additional root cert in PEM format; string. CONFIG_CACHECREDENTIALS, // Attempt to cache credentials that comes in response from PBX. Use them when possible to reduce number of steps of SIP transaction CONFIG_RTCP_ATTR, // Use "rtcp" attribute in sdp. Default value is true. CONFIG_MULTIPLEXING, // Do rtp/rtcp multiplexing CONFIG_DEFERRELAYED, // Defer relayed media path CONFIG_PROXY, // Proxy host name or IP address CONFIG_PROXYPORT, // Proxy port number CONFIG_CODEC_PRIORITY, // Another VariantMap with codec priorities, CONFIG_ACCOUNT, // VariantMap with account configuration CONFIG_EXTERNALIP, // Use external/public IP in outgoing requests CONFIG_OWN_DNS, // Use predefined DNS servers CONFIG_REGID // reg-id value from RFC5626 }; // Conntype parameter for OnSessionEstablished event enum { EV_SIP = 1, EV_ICE = 2 }; class UserAgent; // Define a type for asynchronous requests to user agent class SIPAction { public: virtual void Run(UserAgent& ua) = 0; }; typedef std::vector SIPActionVector; // Session termination reason enum { Error, Timeout, Replaced, LocalBye, RemoteBye, LocalCancel, RemoteCancel, Rejected, //Only as UAS, UAC has distinct onFailure callback Referred }; class UserAgent: public resip::ClientRegistrationHandler, public resip::InviteSessionHandler, public resip::DumShutdownHandler, public resip::ExternalLogger, public resip::DnsResultSink, public resip::ClientSubscriptionHandler, public resip::ServerSubscriptionHandler, public resip::ClientPagerMessageHandler, public resip::ServerPagerMessageHandler, public resip::ClientPublicationHandler //public resip::InternalTransport::TransportLogger { friend class Account; friend class Session; friend class ResipSession; friend class NATDecorator; friend class WatcherQueue; public: /* Compares two sip addresses. Returns true if they represent the same entity - user and domain are the same. Otherwise returns false. */ static bool compareSipAddresses(const std::string& sip1, const std::string& sip2); static std::string formatSipAddress(const std::string& sip); static bool isSipAddressValid(const std::string& sip); struct SipAddress { bool mValid; std::string mScheme; std::string mUsername; std::string mDomain; std::string mDisplayname; }; static SipAddress parseSipAddress(const std::string& sip); UserAgent(); virtual ~UserAgent(); /* Brings user agent online. Basically it creates a signalling socket(s). This is asynchronous method. */ void start(); /* Shutdowns user agent. It closes all sessions, tries to unregister from server and disconnects from it. This is asynchronous method. onStop() event will be called later */ void shutdown(); /* Emergency stop. Please always call shutdown() before this. Kills registration, sessions & presence - everything. onStop() is called in context of this method. */ void stop(); /* Checks if user agent is active (started). */ bool active(); /* Used to refresh existing registration(s), publication, subscriptions. */ void refresh(); /* Runs sip & ice stacks. Event handlers are called in its context. */ void process(); /* Adds root cert in PEM format. Usable after start() call. */ void addRootCert(const ByteBuffer& data); PAccount createAccount(PVariantMap config); void deleteAccount(PAccount account); /* Creates session. Returns session ID. */ PSession createSession(PAccount account); // Must be called when IP interface list is changed void updateInterfaceList(); // Called on new incoming session; providers shoukld virtual PDataProvider onProviderNeeded(const std::string& name) = 0; // Called on new session offer virtual void onNewSession(PSession s) = 0; // Called when session is terminated virtual void onSessionTerminated(PSession s, int responsecode, int reason) = 0; // Called when session is established ok i.e. after all ICE signalling is finished // Conntype is type of establish event - EV_SIP or EV_ICE virtual void onSessionEstablished(PSession s, int conntype, const RtpPair& p) = 0; // Called when client session gets virtual void onSessionProvisional(PSession s, int code) = 0; // Called when user agent started virtual void onStart(int errorcode) = 0; // Called when user agent stopped virtual void onStop() = 0; // Called when account registered virtual void onAccountStart(PAccount account) = 0; // Called when account removed or failed (non zero error code) virtual void onAccountStop(PAccount account, int error) = 0; // Called when connectivity checks failed. virtual void onConnectivityFailed(PSession s) = 0; // Called when new candidate is gathered virtual void onCandidateGathered(PSession s, const char* address); // Called when network change detected virtual void onNetworkChange(PSession s) = 0; // Called when all candidates are gathered virtual void onGathered(PSession s); // Called when new connectivity check is finished virtual void onCheckFinished(PSession s, const char* description); // Called when log message must be recorded virtual void onLog(const char* msg); // Called when problem with SIP connection(s) detected virtual void onSipConnectionFailed() = 0; // Subscribe/publish presence methods virtual void onPublicationSuccess(PAccount acc); virtual void onPublicationTerminated(PAccount acc, int code); virtual void onClientObserverStart(PClientObserver observer); virtual void onServerObserverStart(PServerObserver observer); virtual void onClientObserverStop(PClientObserver observer, int code); virtual void onServerObserverStop(PServerObserver observer, int code); virtual void onPresenceUpdate(PClientObserver observer, const std::string& peer, bool online, const std::string& content); virtual void onMessageArrived(PAccount account, const std::string& peer, const void* ptr, unsigned length); virtual void onMessageFailed(PAccount account, int id, const std::string& peer, int code, void* tag); virtual void onMessageSent(PAccount account, int id, const std::string& peer, void* tag); // Configuration methods VariantMap& config(); public: // InviteSessionHandler implementation #pragma region InviteSessionHandler implementation /// called when an initial INVITE or the intial response to an outoing invite virtual void onNewSession(resip::ClientInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) override; virtual void onNewSession(resip::ServerInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) override; /// Received a failure response from UAS virtual void onFailure(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) override; /// called when an in-dialog provisional response is received that contains an SDP body virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, const resip::SdpContents&) override; /// called when dialog enters the Early state - typically after getting 18x virtual void onProvisional(resip::ClientInviteSessionHandle, const resip::SipMessage&) override; /// called when a dialog initiated as a UAC enters the connected state virtual void onConnected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) override; /// called when a dialog initiated as a UAS enters the connected state virtual void onConnected(resip::InviteSessionHandle, const resip::SipMessage& msg) override; virtual void onTerminated(resip::InviteSessionHandle, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* related=0) override; /// called when a fork that was created through a 1xx never receives a 2xx /// because another fork answered and this fork was canceled by a proxy. virtual void onForkDestroyed(resip::ClientInviteSessionHandle) override; /// called when a 3xx with valid targets is encountered in an early dialog /// This is different then getting a 3xx in onTerminated, as another /// request will be attempted, so the DialogSet will not be destroyed. /// Basically an onTermintated that conveys more information. /// checking for 3xx respones in onTerminated will not work as there may /// be no valid targets. virtual void onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) override; /// called when an SDP answer is received - has nothing to do with user /// answering the call virtual void onAnswer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&) override; /// called when an SDP offer is received - must send an answer soon after this virtual void onOffer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&) override; /// called when an Invite w/out SDP is sent, or any other context which /// requires an SDP offer from the user virtual void onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called if an offer in a UPDATE or re-INVITE was rejected - not real /// useful. A SipMessage is provided if one is available virtual void onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg) override; /// called when INFO message is received virtual void onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called when response to INFO message is received virtual void onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) override; virtual void onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called when MESSAGE message is received virtual void onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called when response to MESSAGE message is received virtual void onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) override; virtual void onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called when an REFER message is received. The refer is accepted or /// rejected using the server subscription. If the offer is accepted, /// DialogUsageManager::makeInviteSessionFromRefer can be used to create an /// InviteSession that will send notify messages using the ServerSubscription virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg) override; virtual void onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called when an REFER message receives a failure response virtual void onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg) override; /// called when an REFER message receives an accepted response virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg) override; #pragma endregion // ClientRegistrationHandler implementation #pragma region ClientRegistrationHandler implementation /// Called when registraion succeeds or each time it is sucessfully /// refreshed. void onSuccess(resip::ClientRegistrationHandle, const resip::SipMessage& response) override; // Called when all of my bindings have been removed void onRemoved(resip::ClientRegistrationHandle, const resip::SipMessage& response) override; /// call on Retry-After failure. /// return values: -1 = fail, 0 = retry immediately, N = retry in N seconds int onRequestRetry(resip::ClientRegistrationHandle, int retrySeconds, const resip::SipMessage& response) override; /// Called if registration fails, usage will be destroyed (unless a /// Registration retry interval is enabled in the Profile) void onFailure(resip::ClientRegistrationHandle, const resip::SipMessage& response) override; #pragma endregion #pragma region ExternalLogger implementation /** return true to also do default logging, false to suppress default logging. */ virtual bool operator()(resip::Log::Level level, const resip::Subsystem& subsystem, const resip::Data& appName, const char* file, int line, const resip::Data& message, const resip::Data& messageWithHeaders, const resip::Data& instanceName) override; #pragma endregion #pragma region DnsResultSink implementation virtual void onDnsResult(const resip::DNSResult&) override; virtual void onDnsResult(const resip::DNSResult&) override; virtual void onDnsResult(const resip::DNSResult&) override; virtual void onDnsResult(const resip::DNSResult&) override; virtual void onDnsResult(const resip::DNSResult&) override; #pragma endregion #pragma region TransportLogger implementation void onSipMessage(int flow, const char* msg, unsigned int length, const sockaddr* addr, unsigned int addrlen); #pragma endregion #pragma region ClientPublicationHandler void onSuccess(resip::ClientPublicationHandle, const resip::SipMessage& status) override; void onRemove(resip::ClientPublicationHandle, const resip::SipMessage& status) override; void onFailure(resip::ClientPublicationHandle, const resip::SipMessage& status) override; int onRequestRetry(resip::ClientPublicationHandle, int retrySeconds, const resip::SipMessage& status) override; #pragma endregion #pragma region SubscriptionHandler void onUpdate(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify); void onUpdatePending(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override; void onUpdateActive(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override; //unknown Subscription-State value void onUpdateExtension(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override; int onRequestRetry(resip::ClientSubscriptionHandle, int retrySeconds, const resip::SipMessage& notify) override; //subscription can be ended through a notify or a failure response. void onTerminated(resip::ClientSubscriptionHandle, const resip::SipMessage* msg) override; //not sure if this has any value. void onNewSubscription(resip::ClientSubscriptionHandle, const resip::SipMessage& notify) override; /// called to allow app to adorn a message. void onReadyToSend(resip::ClientSubscriptionHandle, resip::SipMessage& msg) override; void onNotifyNotReceived(resip::ClientSubscriptionHandle) override; /// Called when a TCP or TLS flow to the server has terminated. This can be caused by socket /// errors, or missing CRLF keep alives pong responses from the server. // Called only if clientOutbound is enabled on the UserProfile and the first hop server /// supports RFC5626 (outbound). /// Default implementation is to re-form the subscription using a new flow void onFlowTerminated(resip::ClientSubscriptionHandle) override; void onNewSubscription(resip::ServerSubscriptionHandle, const resip::SipMessage& sub) override; void onTerminated(resip::ServerSubscriptionHandle) override; #pragma endregion #pragma region PagerHandler void onSuccess(resip::ClientPagerMessageHandle, const resip::SipMessage& status) override; void onFailure(resip::ClientPagerMessageHandle, const resip::SipMessage& status, std::unique_ptr contents) override; void onMessageArrived(resip::ServerPagerMessageHandle, const resip::SipMessage& message) override; #pragma endregion void onDumCanBeDeleted() override; protected: // Mutex to protect this instance Mutex mGuard; // Smart pointer to resiprocate's master profile instance. The stack configuration holds here. std::shared_ptr mProfile; // Resiprocate's SIP stack object pointer resip::SipStack* mStack; // Resiprocate's dialog usage manager object pointer resip::DialogUsageManager* mDum; // List of available transports. They are owned by SipStack - so there is no need to delete instances in UserAgent. std::vector mTransportList; typedef std::map SessionMap; // Session's map SessionMap mSessionMap; // Used configuration VariantMap mConfig; // Action vector SIPActionVector mActionVector; typedef std::map ClientObserverMap; ClientObserverMap mClientObserverMap; typedef std::map ServerObserverMap; ServerObserverMap mServerObserverMap; typedef std::set AccountSet; AccountSet mAccountSet; // Constructs and sends INVITE to remote peer. Remote peer address is stored inside session object. void sendOffer(Session* session); void internalStopSession(Session& session); void processWatchingList(); bool handleMultipartRelatedNotify(const resip::SipMessage& notify); PSession getUserSession(int sessionId); PAccount getAccount(const resip::NameAddr& myAddr); PAccount getAccount(Account* account); PAccount getAccount(int sessionId); }; #endif