diff --git a/daemon/src/sip/Makefile.am b/daemon/src/sip/Makefile.am index 629a9d514a0cfee8cb086de30c1ef0978de5b884..323d944f0f8eee1fb3d62d11af9c7cb49dde0be7 100644 --- a/daemon/src/sip/Makefile.am +++ b/daemon/src/sip/Makefile.am @@ -4,11 +4,13 @@ noinst_LTLIBRARIES = libsiplink.la libsiplink_la_CXXFLAGS = @CXXFLAGS@ libsiplink_la_SOURCES = \ + sipaccountbase.cpp \ sdp.cpp \ sipaccount.cpp \ sipcall.cpp \ sipvoiplink.cpp \ siptransport.cpp \ + sipaccountbase.h \ sdp.h \ sipaccount.h \ sipcall.h \ diff --git a/daemon/src/sip/pres_sub_server.cpp b/daemon/src/sip/pres_sub_server.cpp index 5a07295be121e51fa78a1cd7160d615a52d8565e..fea6a2257362b2f546a35acf491e930871d6e52a 100644 --- a/daemon/src/sip/pres_sub_server.cpp +++ b/daemon/src/sip/pres_sub_server.cpp @@ -32,6 +32,7 @@ #include "pjsip/sip_multipart.h" +#include "sipaccount.h" #include "sipvoiplink.h" #include "manager.h" #include "sippresence.h" diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp index 67b3b76e25843ab89e941a6af131a8251c85152f..f18032c5e5e19cf7553795aca335a6755c1f0b03 100644 --- a/daemon/src/sip/sipaccount.cpp +++ b/daemon/src/sip/sipaccount.cpp @@ -75,9 +75,6 @@ static const char *const VALID_TLS_METHODS[] = {"Default", "TLSv1", "SSLv3", "SS static const char *const VALID_SRTP_KEY_EXCHANGES[] = {"", "sdes", "zrtp"}; constexpr const char * const SIPAccount::ACCOUNT_TYPE; -// we force RTP ports to be even, so we only need HALF_MAX_PORT booleans -bool SIPAccount::portsInUse_[HALF_MAX_PORT]; - static void registration_cb(pjsip_regc_cbparam *param) { @@ -96,30 +93,16 @@ registration_cb(pjsip_regc_cbparam *param) } SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled) - : Account(accountID) + : SIPAccountBase(accountID) , auto_rereg_() , credentials_() - , transport_(nullptr) - , tlsListener_(nullptr) , regc_(nullptr) , bRegister_(false) , registrationExpire_(MIN_REGISTRATION_TIME) - , interface_("default") - , publishedSameasLocal_(true) - , publishedIp_() - , publishedIpAddress_() - , localPort_(DEFAULT_SIP_PORT) - , publishedPort_(DEFAULT_SIP_PORT) , serviceRoute_() - , tlsListenerPort_(DEFAULT_SIP_TLS_PORT) - , transportType_(PJSIP_TRANSPORT_UNSPECIFIED) , cred_() , tlsSetting_() , ciphers_(100) - , stunServerName_() - , stunPort_(PJ_STUN_PORT) - , dtmfType_(OVERRTP_STR) - , tlsEnable_(false) , tlsCaListFile_() , tlsCertificateFile_() , tlsPrivateKeyFile_() @@ -131,11 +114,6 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled) , tlsVerifyClient_(true) , tlsRequireClientCertificate_(true) , tlsNegotiationTimeoutSec_("2") - , stunServer_("") - , stunEnabled_(false) - , srtpEnabled_(false) - , srtpKeyExchange_("") - , srtpFallback_(false) , zrtpDisplaySas_(true) , zrtpDisplaySasOnce_(false) , zrtpHelloHash_(true) @@ -144,7 +122,6 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled) , keepAliveEnabled_(false) , keepAliveTimer_() , keepAliveTimerActive_(false) - , link_(getSIPVoIPLink()) , receivedParameter_("") , rPort_(-1) , via_addr_() @@ -155,10 +132,6 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled) , allowContactRewrite_(1) , contactOverwritten_(false) , via_tp_(nullptr) - , audioPortRange_({16384, 32766}) -#ifdef SFL_VIDEO - , videoPortRange_({49152, (MAX_PORT) - 2}) -#endif #ifdef SFL_PRESENCE , presence_(presenceEnabled ? new SIPPresence(this) : nullptr) #endif @@ -220,7 +193,6 @@ unserializeRange(const Conf::YamlNode &mapNode, const char *minKey, const char * updateRange(tmpMin, tmpMax, range); } -template <> std::shared_ptr<SIPCall> SIPAccount::newIncomingCall(const std::string& id) { @@ -235,6 +207,8 @@ SIPAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) std::string toUri; int family; + auto call = Manager::instance().callFactory.newCall<SIPCall, SIPAccount>(*this, id, Call::OUTGOING); + if (isIP2IP()) { bool ipv6 = false; #if HAVE_IPV6 @@ -262,8 +236,6 @@ SIPAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) DEBUG("UserAgent: New registered account call to %s", toUrl.c_str()); } - auto call = Manager::instance().callFactory.newCall<SIPCall, SIPAccount>(*this, id, Call::OUTGOING); - call->setIPToIP(isIP2IP()); call->setPeerNumber(toUri); call->initRecFilename(to); @@ -403,9 +375,6 @@ SIPAccount::SIPStartCall(std::shared_ptr<SIPCall>& call) void SIPAccount::serialize(Conf::YamlEmitter &emitter) { using namespace Conf; - using std::vector; - using std::string; - using std::map; MappingNode accountmap(nullptr); MappingNode srtpmap(nullptr); MappingNode zrtpmap(nullptr); @@ -962,16 +931,7 @@ static std::string retrievePassword(const std::map<std::string, std::string>& ma return ""; } -void -addRangeToDetails(std::map<std::string, std::string> &a, const char *minKey, const char *maxKey, const std::pair<uint16_t, uint16_t> &range) -{ - std::ostringstream os; - os << range.first; - a[minKey] = os.str(); - os.str(""); - os << range.second; - a[maxKey] = os.str(); -} + std::map<std::string, std::string> SIPAccount::getAccountDetails() const { @@ -2080,41 +2040,6 @@ SIPAccount::matches(const std::string &userName, const std::string &server, } } -// returns even number in range [lower, upper] -uint16_t -SIPAccount::getRandomEvenNumber(const std::pair<uint16_t, uint16_t> &range) -{ - const uint16_t halfUpper = range.second * 0.5; - const uint16_t halfLower = range.first * 0.5; - uint16_t result; - do { - result = 2 * (halfLower + rand() % (halfUpper - halfLower + 1)); - } while (portsInUse_[result / 2]); - - portsInUse_[result / 2] = true; - return result; -} - -void -SIPAccount::releasePort(uint16_t port) -{ - portsInUse_[port / 2] = false; -} - -uint16_t -SIPAccount::generateAudioPort() const -{ - return getRandomEvenNumber(audioPortRange_); -} - -#ifdef SFL_VIDEO -uint16_t -SIPAccount::generateVideoPort() const -{ - return getRandomEvenNumber(videoPortRange_); -} -#endif - void SIPAccount::destroyRegistrationInfo() { diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h index 20a26302f97d02a26fae97c1758296a040cc06b4..56cdd166b2fadbeb80f6ce14434b70771921d0df 100644 --- a/daemon/src/sip/sipaccount.h +++ b/daemon/src/sip/sipaccount.h @@ -39,10 +39,9 @@ #include "config.h" #endif +#include "sipaccountbase.h" #include "siptransport.h" -#include "account.h" #include "noncopyable.h" -#include "ip_utils.h" #include "sfl_types.h" // enable_if_base_of #include <pjsip/sip_transport_tls.h> @@ -55,64 +54,9 @@ typedef std::vector<pj_ssl_cipher> CipherArray; namespace Conf { - class YamlEmitter; - class MappingNode; - // SIP specific configuration keys - const char *const INTERFACE_KEY = "interface"; - const char *const PORT_KEY = "port"; - const char *const PUBLISH_ADDR_KEY = "publishAddr"; - const char *const PUBLISH_PORT_KEY = "publishPort"; - const char *const SAME_AS_LOCAL_KEY = "sameasLocal"; - const char *const DTMF_TYPE_KEY = "dtmfType"; - const char *const SERVICE_ROUTE_KEY = "serviceRoute"; const char *const KEEP_ALIVE_ENABLED = "keepAlive"; - const char *const PRESENCE_ENABLED_KEY = "presenceEnabled"; - const char *const PRESENCE_PUBLISH_SUPPORTED_KEY = "presencePublishSupported"; - const char *const PRESENCE_SUBSCRIBE_SUPPORTED_KEY = "presenceSubscribeSupported"; - const char *const PRESENCE_STATUS_KEY = "presenceStatus"; - const char *const PRESENCE_NOTE_KEY = "presenceNote"; - - // TODO: write an object to store credential which implement serializable - const char *const SRTP_KEY = "srtp"; - const char *const SRTP_ENABLE_KEY = "enable"; - const char *const KEY_EXCHANGE_KEY = "keyExchange"; - const char *const RTP_FALLBACK_KEY = "rtpFallback"; - - // TODO: wirte an object to store zrtp params wich implement serializable - const char *const ZRTP_KEY = "zrtp"; - const char *const DISPLAY_SAS_KEY = "displaySas"; - const char *const DISPLAY_SAS_ONCE_KEY = "displaySasOnce"; - const char *const HELLO_HASH_ENABLED_KEY = "helloHashEnabled"; - const char *const NOT_SUPP_WARNING_KEY = "notSuppWarning"; - - // TODO: write an object to store tls params which implement serializable - const char *const TLS_KEY = "tls"; - const char *const TLS_PORT_KEY = "tlsPort"; - const char *const CERTIFICATE_KEY = "certificate"; - const char *const CALIST_KEY = "calist"; - const char *const CIPHERS_KEY = "ciphers"; - const char *const TLS_ENABLE_KEY = "enable"; - const char *const METHOD_KEY = "method"; - const char *const TIMEOUT_KEY = "timeout"; - const char *const TLS_PASSWORD_KEY = "password"; - const char *const PRIVATE_KEY_KEY = "privateKey"; - const char *const REQUIRE_CERTIF_KEY = "requireCertif"; - const char *const SERVER_KEY = "server"; - const char *const VERIFY_CLIENT_KEY = "verifyClient"; - const char *const VERIFY_SERVER_KEY = "verifyServer"; - - const char *const STUN_ENABLED_KEY = "stunEnabled"; - const char *const STUN_SERVER_KEY = "stunServer"; - const char *const CRED_KEY = "credential"; - const char *const AUDIO_PORT_MIN_KEY = "audioPortMin"; - const char *const AUDIO_PORT_MAX_KEY = "audioPortMax"; -#ifdef SFL_VIDEO - const char *const VIDEO_PORT_MIN_KEY = "videoPortMin"; - const char *const VIDEO_PORT_MAX_KEY = "videoPortMax"; -#endif } -class SIPVoIPLink; class SIPPresence; class SIPCall; @@ -120,15 +64,9 @@ class SIPCall; * @file sipaccount.h * @brief A SIP Account specify SIP specific functions and object = SIPCall/SIPVoIPLink) */ -enum {MAX_PORT = 65536}; -enum {HALF_MAX_PORT = MAX_PORT / 2}; -enum class MatchRank {NONE, PARTIAL, FULL}; - -class SIPAccount : public Account { +class SIPAccount : public SIPAccountBase { public: constexpr static const char * const IP2IP_PROFILE = "IP2IP"; - constexpr static const char * const OVERRTP_STR = "overrtp"; - constexpr static const char * const SIPINFO_STR = "sipinfo"; constexpr static const char * const ACCOUNT_TYPE = "SIP"; /** @@ -160,9 +98,6 @@ class SIPAccount : public Account { */ bool isIP2IP() const; - static void - releasePort(uint16_t port); - /** * Serialize internal state of this account for configuration * @param YamlEmitter the configuration engine which generate the configuration file @@ -416,83 +351,6 @@ class SIPAccount : public Account { */ pj_str_t getContactHeader(); - /** - * Get the local interface name on which this account is bound. - */ - const std::string& getLocalInterface() const { - return interface_; - } - - /** - * Get a flag which determine the usage in sip headers of either the local - * IP address and port (_localAddress and localPort_) or to an address set - * manually (_publishedAddress and publishedPort_). - */ - bool getPublishedSameasLocal() const { - return publishedSameasLocal_; - } - - /** - * Get the port on which the transport/listener should use, or is - * actually using. - * @return pj_uint16 The port used for that account - */ - pj_uint16_t getLocalPort() const { - return localPort_; - } - - /** - * Set the new port on which this account is running over. - * @pram port The port used by this account. - */ - void setLocalPort(pj_uint16_t port) { - localPort_ = port; - } - - /** - * Get the published port, which is the port to be advertised as the port - * for the chosen SIP transport. - * @return pj_uint16 The port used for that account - */ - pj_uint16_t getPublishedPort() const { - return (pj_uint16_t) publishedPort_; - } - - /** - * Set the published port, which is the port to be advertised as the port - * for the chosen SIP transport. - * @pram port The port used by this account. - */ - void setPublishedPort(pj_uint16_t port) { - publishedPort_ = port; - } - - /** - * Get the local port for TLS listener. - * @return pj_uint16 The port used for that account - */ - pj_uint16_t getTlsListenerPort() const { - return tlsListenerPort_; - } - - /** - * Get the public IP address set by the user for this account. - * If this setting is not provided, the local bound adddress - * will be used. - * @return std::string The public IPv4 or IPv6 address formatted in standard notation. - */ - std::string getPublishedAddress() const { - return publishedIpAddress_; - } - - IpAddr getPublishedIpAddress() const { - return publishedIp_; - } - - void setPublishedAddress(const IpAddr& ip_addr) { - publishedIp_ = ip_addr; - publishedIpAddress_ = ip_addr.toString(); - } std::string getServiceRoute() const { return serviceRoute_; @@ -500,21 +358,6 @@ class SIPAccount : public Account { bool hasServiceRoute() const { return not serviceRoute_.empty(); } - std::string getDtmfType() const { - return dtmfType_; - } - - bool getSrtpEnabled() const { - return srtpEnabled_; - } - - std::string getSrtpKeyExchange() const { - return srtpKeyExchange_; - } - - bool getSrtpFallback() const { - return srtpFallback_; - } bool getZrtpHelloHash() const { return zrtpHelloHash_; @@ -557,23 +400,8 @@ class SIPAccount : public Account { return keepAliveEnabled_; } - inline pjsip_transport* getTransport() { - return transport_; - } - void setTransport(pjsip_transport* transport = nullptr, pjsip_tpfactory* lis = nullptr); - inline pjsip_transport_type_e getTransportType() const { - return transportType_; - } - - /** - * Shortcut for SipTransport::getTransportSelector(account.getTransport()). - */ - inline pjsip_tpselector getTransportSelector() { - return SipTransport::getTransportSelector(transport_); - } - /* Returns true if the username and/or hostname match this account */ MatchRank matches(const std::string &username, const std::string &hostname, pjsip_endpoint *endpt, pj_pool_t *pool) const; @@ -596,12 +424,6 @@ class SIPAccount : public Account { void supportPresence(int function, bool enable); #endif -// unsigned generateAudioPort() const; - uint16_t generateAudioPort() const; -#ifdef SFL_VIDEO - uint16_t generateVideoPort() const; -#endif - void scheduleReregistration(pjsip_endpoint *endpt); /** @@ -630,8 +452,7 @@ class SIPAccount : public Account { * The type of this instance is given in template argument. * This type can be any base class of SIPCall class (included). */ - template <class T=SIPCall> - std::shared_ptr<enable_if_base_of<T, SIPCall> > + std::shared_ptr<SIPCall> newIncomingCall(const std::string& id); void onRegister(pjsip_regc_cbparam *param); @@ -675,16 +496,6 @@ class SIPAccount : public Account { */ std::vector< std::map<std::string, std::string > > credentials_; - /** - * Pointer to the transport used by this acccount - */ - pjsip_transport* transport_; - - /** - * If a TLS tranport, pointer to the tls listener. - */ - pjsip_tpfactory* tlsListener_; - #if HAVE_TLS /** * Maps a string description of the SSL method @@ -735,51 +546,11 @@ class SIPAccount : public Account { */ int registrationExpire_; - /** - * interface name on which this account is bound - */ - std::string interface_; - - /** - * Flag which determine if localIpAddress_ or publishedIpAddress_ is used in - * sip headers - */ - bool publishedSameasLocal_; - - /** - * Published IP address, used only if defined by the user in account - * configuration - */ - IpAddr publishedIp_; - std::string publishedIpAddress_; - - /** - * Local port to whih this account is bound - */ - pj_uint16_t localPort_; - - /** - * Published port, used only if defined by the user - */ - pj_uint16_t publishedPort_; - /** * Optional list of SIP service this */ std::string serviceRoute_; - /** - * The global TLS listener port which can be configured through the IP2IP_PROFILE - */ - pj_uint16_t tlsListenerPort_; - - /** - * Transport type used for this sip account. Currently supported types: - * PJSIP_TRANSPORT_UNSPECIFIED - * PJSIP_TRANSPORT_UDP - * PJSIP_TRANSPORT_TLS - */ - pjsip_transport_type_e transportType_; /** * Credential information stored for further registration. @@ -797,25 +568,28 @@ class SIPAccount : public Account { CipherArray ciphers_; /** - * The STUN server name (hostname) + * Determine if STUN public address resolution is required to register this account. In this case a + * STUN server hostname must be specified. */ - pj_str_t stunServerName_; + bool stunEnabled_ {false}; /** - * The STUN server port + * The stun server hostname (optional), used to provide the public IP address in case the softphone + * stay behind a NAT. */ - pj_uint16_t stunPort_; + std::string stunServer_ {}; /** - * DTMF type used for this account SIPINFO or RTP + * The STUN server name (hostname) */ - std::string dtmfType_; + pj_str_t stunServerName_ {}; /** - * Determine if TLS is enabled for this account. TLS provides a secured channel for - * SIP signalization. It is independant than the media encription provided by SRTP or ZRTP. + * The STUN server port */ - bool tlsEnable_; + pj_uint16_t stunPort_ {PJ_STUN_PORT}; + + /** * Certificate autority file @@ -832,37 +606,6 @@ class SIPAccount : public Account { bool tlsRequireClientCertificate_; std::string tlsNegotiationTimeoutSec_; - /** - * The stun server hostname (optional), used to provide the public IP address in case the softphone - * stay behind a NAT. - */ - std::string stunServer_; - - /** - * Determine if STUN public address resolution is required to register this account. In this case a - * STUN server hostname must be specified. - */ - bool stunEnabled_; - - /** - * Determine if SRTP is enabled for this account, SRTP and ZRTP are mutually exclusive - * This only determine if the media channel is secured. One could only enable TLS - * with no secured media channel. - */ - bool srtpEnabled_; - - /** - * Specifies the type of key exchange usd for SRTP (sdes/zrtp) - */ - std::string srtpKeyExchange_; - - /** - * Determine if the softphone should fallback on non secured media channel if SRTP negotiation fails. - * Make sure other SIP endpoints share the same behavior since it could result in encrypted data to be - * played through the audio device. - */ - bool srtpFallback_; - /** * Determine if the SAS sould be displayed on client side. SAS is a 4-charcter string * that end users should verbaly validate to ensure the channel is secured. Used especially @@ -901,11 +644,6 @@ class SIPAccount : public Account { */ bool keepAliveTimerActive_; - /** - * Voice over IP Link contains a listener thread and calls - */ - std::shared_ptr<SIPVoIPLink> link_; - /** * Optional: "received" parameter from VIA header */ @@ -930,27 +668,12 @@ class SIPAccount : public Account { bool contactOverwritten_; pjsip_transport *via_tp_; - /* - * Port range for audio RTP ports - */ - std::pair<uint16_t, uint16_t> audioPortRange_; - -#ifdef SFL_VIDEO - /** - * Port range for video RTP ports - */ - std::pair<uint16_t, uint16_t> videoPortRange_; -#endif - #ifdef SFL_PRESENCE /** * Presence data structure */ SIPPresence * presence_; #endif - - static bool portsInUse_[HALF_MAX_PORT]; - static uint16_t getRandomEvenNumber(const std::pair<uint16_t, uint16_t> &range); }; #endif diff --git a/daemon/src/sip/sipaccountbase.cpp b/daemon/src/sip/sipaccountbase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32cc48b4600964a7e2e0f9b404a3fb1ab827ad5c --- /dev/null +++ b/daemon/src/sip/sipaccountbase.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 Savoir-Faire Linux Inc. + * + * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include "sipaccountbase.h" +#include "sipvoiplink.h" + +bool SIPAccountBase::portsInUse_[HALF_MAX_PORT]; + +SIPAccountBase::SIPAccountBase(const std::string& accountID) + : Account(accountID), link_(getSIPVoIPLink()) +{} + + +void +SIPAccountBase::setTransport(pjsip_transport* transport, pjsip_tpfactory* lis) +{ + // release old transport + if (transport_ && transport_ != transport) { + pjsip_transport_dec_ref(transport_); + } + if (tlsListener_ && tlsListener_ != lis) + tlsListener_->destroy(tlsListener_); + // set new transport + transport_ = transport; + tlsListener_ = lis; +} + +// returns even number in range [lower, upper] +uint16_t +SIPAccountBase::getRandomEvenNumber(const std::pair<uint16_t, uint16_t> &range) +{ + const uint16_t halfUpper = range.second * 0.5; + const uint16_t halfLower = range.first * 0.5; + uint16_t result; + do { + result = 2 * (halfLower + rand() % (halfUpper - halfLower + 1)); + } while (portsInUse_[result / 2]); + + portsInUse_[result / 2] = true; + return result; +} + +void +SIPAccountBase::releasePort(uint16_t port) +{ + portsInUse_[port / 2] = false; +} + +uint16_t +SIPAccountBase::generateAudioPort() const +{ + return getRandomEvenNumber(audioPortRange_); +} + +#ifdef SFL_VIDEO +uint16_t +SIPAccountBase::generateVideoPort() const +{ + return getRandomEvenNumber(videoPortRange_); +} +#endif diff --git a/daemon/src/sip/sipaccountbase.h b/daemon/src/sip/sipaccountbase.h new file mode 100644 index 0000000000000000000000000000000000000000..3a0da287cd7fef98ab675fdde74d3031215426b7 --- /dev/null +++ b/daemon/src/sip/sipaccountbase.h @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2014 Savoir-Faire Linux Inc. + * + * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef SIPACCOUNTBASE_H +#define SIPACCOUNTBASE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "siptransport.h" +#include "account.h" +#include "noncopyable.h" +#include "ip_utils.h" +//#include "sfl_types.h" // enable_if_base_of + +#include "global.h" + +#include <pjsip/sip_transport_tls.h> +#include <pjsip/sip_types.h> + +#include <vector> +#include <map> + +typedef std::vector<pj_ssl_cipher> CipherArray; + +namespace Conf { + class YamlEmitter; + class MappingNode; + // SIP specific configuration keys + const char *const INTERFACE_KEY = "interface"; + const char *const PORT_KEY = "port"; + const char *const PUBLISH_ADDR_KEY = "publishAddr"; + const char *const PUBLISH_PORT_KEY = "publishPort"; + const char *const SAME_AS_LOCAL_KEY = "sameasLocal"; + const char *const DTMF_TYPE_KEY = "dtmfType"; + const char *const SERVICE_ROUTE_KEY = "serviceRoute"; + const char *const PRESENCE_ENABLED_KEY = "presenceEnabled"; + const char *const PRESENCE_PUBLISH_SUPPORTED_KEY = "presencePublishSupported"; + const char *const PRESENCE_SUBSCRIBE_SUPPORTED_KEY = "presenceSubscribeSupported"; + const char *const PRESENCE_STATUS_KEY = "presenceStatus"; + const char *const PRESENCE_NOTE_KEY = "presenceNote"; + + // TODO: write an object to store credential which implement serializable + const char *const SRTP_KEY = "srtp"; + const char *const SRTP_ENABLE_KEY = "enable"; + const char *const KEY_EXCHANGE_KEY = "keyExchange"; + const char *const RTP_FALLBACK_KEY = "rtpFallback"; + + // TODO: wirte an object to store zrtp params wich implement serializable + const char *const ZRTP_KEY = "zrtp"; + const char *const DISPLAY_SAS_KEY = "displaySas"; + const char *const DISPLAY_SAS_ONCE_KEY = "displaySasOnce"; + const char *const HELLO_HASH_ENABLED_KEY = "helloHashEnabled"; + const char *const NOT_SUPP_WARNING_KEY = "notSuppWarning"; + + // TODO: write an object to store tls params which implement serializable + const char *const TLS_KEY = "tls"; + const char *const TLS_PORT_KEY = "tlsPort"; + const char *const CERTIFICATE_KEY = "certificate"; + const char *const CALIST_KEY = "calist"; + const char *const CIPHERS_KEY = "ciphers"; + const char *const TLS_ENABLE_KEY = "enable"; + const char *const METHOD_KEY = "method"; + const char *const TIMEOUT_KEY = "timeout"; + const char *const TLS_PASSWORD_KEY = "password"; + const char *const PRIVATE_KEY_KEY = "privateKey"; + const char *const REQUIRE_CERTIF_KEY = "requireCertif"; + const char *const SERVER_KEY = "server"; + const char *const VERIFY_CLIENT_KEY = "verifyClient"; + const char *const VERIFY_SERVER_KEY = "verifyServer"; + + const char *const STUN_ENABLED_KEY = "stunEnabled"; + const char *const STUN_SERVER_KEY = "stunServer"; + const char *const CRED_KEY = "credential"; + const char *const AUDIO_PORT_MIN_KEY = "audioPortMin"; + const char *const AUDIO_PORT_MAX_KEY = "audioPortMax"; +#ifdef SFL_VIDEO + const char *const VIDEO_PORT_MIN_KEY = "videoPortMin"; + const char *const VIDEO_PORT_MAX_KEY = "videoPortMax"; +#endif +} + +class SIPVoIPLink; +class SIPCall; + +/** + * @file sipaccount.h + * @brief A SIP Account specify SIP specific functions and object = SIPCall/SIPVoIPLink) + */ +enum {MAX_PORT = 65536}; +enum {HALF_MAX_PORT = MAX_PORT / 2}; +enum class MatchRank {NONE, PARTIAL, FULL}; + +class SIPAccountBase : public Account { +public: + constexpr static const char * const OVERRTP_STR = "overrtp"; + constexpr static const char * const SIPINFO_STR = "sipinfo"; + + /** + * Constructor + * @param accountID The account identifier + */ + SIPAccountBase(const std::string& accountID); + + virtual ~SIPAccountBase() = default; + + /** + * Create incoming SIPCall. + * @param[in] id The ID of the call + * @return std::shared_ptr<T> A shared pointer on the created call. + * The type of this instance is given in template argument. + * This type can be any base class of SIPCall class (included). + */ + virtual std::shared_ptr<SIPCall> + newIncomingCall(const std::string& id) = 0; + + virtual bool isStunEnabled() const { + return false; + } + + virtual pj_str_t getStunServerName() const { return pj_str_t {}; }; + + virtual pj_uint16_t getStunPort() const { return 0; }; + + virtual std::string getDtmfType() const { + return dtmfType_; + } + + bool isTlsEnabled() const { + return tlsEnable_; + } + + virtual pjsip_tls_setting * getTlsSetting() { + return nullptr; + } + + /** + * Get the local port for TLS listener. + * @return pj_uint16 The port used for that account + */ + pj_uint16_t getTlsListenerPort() const { + return tlsListenerPort_; + } + + /** + * Get the public IP address set by the user for this account. + * If this setting is not provided, the local bound adddress + * will be used. + * @return std::string The public IPv4 or IPv6 address formatted in standard notation. + */ + std::string getPublishedAddress() const { + return publishedIpAddress_; + } + + IpAddr getPublishedIpAddress() const { + return publishedIp_; + } + + void setPublishedAddress(const IpAddr& ip_addr) { + publishedIp_ = ip_addr; + publishedIpAddress_ = ip_addr.toString(); + } + + /** + * Get the local interface name on which this account is bound. + */ + const std::string& getLocalInterface() const { + return interface_; + } + + /** + * Get a flag which determine the usage in sip headers of either the local + * IP address and port (_localAddress and localPort_) or to an address set + * manually (_publishedAddress and publishedPort_). + */ + bool getPublishedSameasLocal() const { + return publishedSameasLocal_; + } + + /** + * Get the port on which the transport/listener should use, or is + * actually using. + * @return pj_uint16 The port used for that account + */ + pj_uint16_t getLocalPort() const { + return localPort_; + } + + /** + * Set the new port on which this account is running over. + * @pram port The port used by this account. + */ + void setLocalPort(pj_uint16_t port) { + localPort_ = port; + } + + /** + * Get the published port, which is the port to be advertised as the port + * for the chosen SIP transport. + * @return pj_uint16 The port used for that account + */ + pj_uint16_t getPublishedPort() const { + return (pj_uint16_t) publishedPort_; + } + + /** + * Set the published port, which is the port to be advertised as the port + * for the chosen SIP transport. + * @pram port The port used by this account. + */ + void setPublishedPort(pj_uint16_t port) { + publishedPort_ = port; + } + + bool getSrtpEnabled() const { + return srtpEnabled_; + } + + std::string getSrtpKeyExchange() const { + return srtpKeyExchange_; + } + + bool getSrtpFallback() const { + return srtpFallback_; + } + + /** + * Get the contact header for + * @return pj_str_t The contact header based on account information + */ + virtual pj_str_t getContactHeader() = 0; + + virtual std::string getToUri(const std::string& username) const = 0; + + virtual std::string getServerUri() const = 0; + + uint16_t generateAudioPort() const; +#ifdef SFL_VIDEO + uint16_t generateVideoPort() const; +#endif + static void releasePort(uint16_t port); + + inline pjsip_transport* getTransport() { + return transport_; + } + + virtual void setTransport(pjsip_transport* transport = nullptr, pjsip_tpfactory* lis = nullptr); + + inline pjsip_transport_type_e getTransportType() const { + return transportType_; + } + + /** + * Shortcut for SipTransport::getTransportSelector(account.getTransport()). + */ + inline pjsip_tpselector getTransportSelector() { + return SipTransport::getTransportSelector(transport_); + } + + +protected: + /** + * Voice over IP Link contains a listener thread and calls + */ + std::shared_ptr<SIPVoIPLink> link_; + + /** + * Pointer to the transport used by this acccount + */ + pjsip_transport* transport_ {nullptr}; + + /** + * Transport type used for this sip account. Currently supported types: + * PJSIP_TRANSPORT_UNSPECIFIED + * PJSIP_TRANSPORT_UDP + * PJSIP_TRANSPORT_TLS + */ + pjsip_transport_type_e transportType_ {PJSIP_TRANSPORT_UNSPECIFIED}; + + /** + * interface name on which this account is bound + */ + std::string interface_ {"default"}; + + /** + * Flag which determine if localIpAddress_ or publishedIpAddress_ is used in + * sip headers + */ + bool publishedSameasLocal_ {true}; + + /** + * Published IP address, used only if defined by the user in account + * configuration + */ + IpAddr publishedIp_ {}; + std::string publishedIpAddress_ {}; + + /** + * Local port to whih this account is bound + */ + pj_uint16_t localPort_ {DEFAULT_SIP_PORT}; + + /** + * Published port, used only if defined by the user + */ + pj_uint16_t publishedPort_ {DEFAULT_SIP_PORT}; + + /** + * If a TLS tranport, pointer to the tls listener. + */ + pjsip_tpfactory* tlsListener_ {nullptr}; + + /** + * The global TLS listener port which can be configured through the IP2IP_PROFILE + */ + pj_uint16_t tlsListenerPort_ {DEFAULT_SIP_TLS_PORT}; + + /** + * DTMF type used for this account SIPINFO or RTP + */ + std::string dtmfType_ {OVERRTP_STR}; + + /** + * Determine if TLS is enabled for this account. TLS provides a secured channel for + * SIP signalization. It is independant than the media encription provided by SRTP or ZRTP. + */ + bool tlsEnable_ {false}; + + /** + * Determine if SRTP is enabled for this account, SRTP and ZRTP are mutually exclusive + * This only determine if the media channel is secured. One could only enable TLS + * with no secured media channel. + */ + bool srtpEnabled_ {false}; + + /** + * Specifies the type of key exchange usd for SRTP (sdes/zrtp) + */ + std::string srtpKeyExchange_ {""}; + + /** + * Determine if the softphone should fallback on non secured media channel if SRTP negotiation fails. + * Make sure other SIP endpoints share the same behavior since it could result in encrypted data to be + * played through the audio device. + */ + bool srtpFallback_ {}; + + /* + * Port range for audio RTP ports + */ + std::pair<uint16_t, uint16_t> audioPortRange_ {16384, 32766}; + +#ifdef SFL_VIDEO + /** + * Port range for video RTP ports + */ + std::pair<uint16_t, uint16_t> videoPortRange_ {49152, (MAX_PORT) - 2}; +#endif + + static bool portsInUse_[HALF_MAX_PORT]; + static uint16_t getRandomEvenNumber(const std::pair<uint16_t, uint16_t> &range); + + static void + addRangeToDetails(std::map<std::string, std::string> &a, const char *minKey, const char *maxKey, const std::pair<uint16_t, uint16_t> &range) + { + std::ostringstream os; + os << range.first; + a[minKey] = os.str(); + os.str(""); + os << range.second; + a[maxKey] = os.str(); + } + +private: + NON_COPYABLE(SIPAccountBase); + +}; + +#endif diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp index 0726ba6ab7eb26284f3e2279ab1fcadb06b2eaff..1c680ded9da4170159c620f3e2000979dfd620c8 100644 --- a/daemon/src/sip/sipcall.cpp +++ b/daemon/src/sip/sipcall.cpp @@ -34,6 +34,8 @@ #include "call_factory.h" #include "sipcall.h" +#include "sipaccount.h" // for SIPAccount::ACCOUNT_TYPE +#include "sipaccountbase.h" #include "sipvoiplink.h" #include "sip_utils.h" #include "logger.h" // for _debug @@ -96,7 +98,7 @@ dtmfSend(SIPCall &call, char code, const std::string &dtmf) call.sendSIPInfo(dtmf_body, "dtmf-relay"); } -SIPCall::SIPCall(SIPAccount& account, const std::string& id, +SIPCall::SIPCall(SIPAccountBase& account, const std::string& id, Call::CallType type) : Call(account, id, type) , audiortp_(this) @@ -138,10 +140,10 @@ SIPCall::stopRtpIfCurrent() } } -SIPAccount& +SIPAccountBase& SIPCall::getSIPAccount() const { - return static_cast<SIPAccount&>(getAccount()); + return static_cast<SIPAccountBase&>(getAccount()); } void diff --git a/daemon/src/sip/sipcall.h b/daemon/src/sip/sipcall.h index a1a93ca1d0b740b401089f6925a19ea9b768393f..6191eba23da672c75765ff039fdabb2594ca08cf 100644 --- a/daemon/src/sip/sipcall.h +++ b/daemon/src/sip/sipcall.h @@ -56,7 +56,7 @@ struct pj_pool_t; struct pjsip_inv_session; class Sdp; -class SIPAccount; +class SIPAccountBase; /** * @file sipcall.h @@ -74,7 +74,7 @@ class SIPCall : public Call * @param type The type of the call. Could be Incoming * Outgoing */ - SIPCall(SIPAccount& account, const std::string& id, Call::CallType type); + SIPCall(SIPAccountBase& account, const std::string& id, Call::CallType type); public: /** @@ -147,7 +147,7 @@ class SIPCall : public Call const std::string& from); #endif - SIPAccount& getSIPAccount() const; + SIPAccountBase& getSIPAccount() const; void updateSDPFromSTUN(); diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp index aad81aa0749de497d6b5fa6e9cf122529086448f..da4a2c6200ef4a618b937be70a15936071834fd7 100644 --- a/daemon/src/sip/siptransport.cpp +++ b/daemon/src/sip/siptransport.cpp @@ -146,7 +146,7 @@ SipTransport::waitForReleased(pjsip_transport* tp, std::function<void(bool)> rel } void -SipTransport::createSipTransport(SIPAccount &account) +SipTransport::createSipTransport(SIPAccountBase &account) { // Remove any existing transport from the account account.setTransport(); @@ -241,7 +241,7 @@ SipTransport::createUdpTransport(const std::string &interface, pj_uint16_t port, #if HAVE_TLS pjsip_tpfactory* -SipTransport::createTlsListener(SIPAccount &account, pj_uint16_t family) +SipTransport::createTlsListener(SIPAccountBase &account, pj_uint16_t family) { RETURN_IF_FAIL(account.getTlsSetting() != nullptr, nullptr, "TLS settings not specified"); @@ -271,7 +271,7 @@ SipTransport::createTlsListener(SIPAccount &account, pj_uint16_t family) } pjsip_transport * -SipTransport::createTlsTransport(SIPAccount &account) +SipTransport::createTlsTransport(SIPAccountBase &account) { std::string remoteSipUri(account.getServerUri()); static const char SIPS_PREFIX[] = "<sips:"; @@ -362,7 +362,7 @@ SipTransport::_cleanupTransports() } std::vector<pj_sockaddr> -SipTransport::getSTUNAddresses(const SIPAccount &account, +SipTransport::getSTUNAddresses(const SIPAccountBase &account, std::vector<long> &socketDescriptors) const { const pj_str_t serverName = account.getStunServerName(); diff --git a/daemon/src/sip/siptransport.h b/daemon/src/sip/siptransport.h index e513383ac4b80f609de8ad3cdcc7e8239f13d7f3..a592b03ba351af90c774958bb29fe4b3ca23e131 100644 --- a/daemon/src/sip/siptransport.h +++ b/daemon/src/sip/siptransport.h @@ -54,7 +54,7 @@ #include <vector> #include <memory> -class SIPAccount; +class SIPAccountBase; class SipTransport { @@ -67,7 +67,7 @@ class SipTransport { * transport type specified in account settings * @param account The account for which a transport must be created. */ - void createSipTransport(SIPAccount &account); + void createSipTransport(SIPAccountBase &account); /** * Initialize the transport selector @@ -82,7 +82,7 @@ class SipTransport { /** * This function returns a list of STUN mapped sockets for * a given set of socket file descriptors */ - std::vector<pj_sockaddr> getSTUNAddresses(const SIPAccount &account, std::vector<long> &socks) const; + std::vector<pj_sockaddr> getSTUNAddresses(const SIPAccountBase &account, std::vector<long> &socks) const; /** * Get the correct address to use (ie advertised) from @@ -122,7 +122,7 @@ class SipTransport { * @param the account that is creating the TLS transport */ pjsip_transport * - createTlsTransport(SIPAccount &account); + createTlsTransport(SIPAccountBase &account); /** * Create The default TLS listener which is global to the application. This means that @@ -132,7 +132,7 @@ class SipTransport { * @return a pointer to the new listener */ pjsip_tpfactory * - createTlsListener(SIPAccount &account, pj_uint16_t family = pj_AF_UNSPEC()); + createTlsListener(SIPAccountBase &account, pj_uint16_t family = pj_AF_UNSPEC()); #endif /** diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index bebe0ae1a4988f062524660240dd18eea8d48804..b5ba5624c20a57a3a95fb44fc30995adc61c1b07 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -40,6 +40,7 @@ #include "sdp.h" #include "sipcall.h" +#include "sipaccount.h" #include "sip_utils.h" #include "call_factory.h" @@ -225,9 +226,12 @@ transaction_request_cb(pjsip_rx_data *rdata) return PJ_FALSE; } std::string toUsername(sip_to_uri->user.ptr, sip_to_uri->user.slen); + std::string toHost(sip_to_uri->host.ptr, sip_to_uri->host.slen); std::string viaHostname(sip_via.host.ptr, sip_via.host.slen); + const std::string remote_user(sip_from_uri->user.ptr, sip_from_uri->user.slen); + const std::string remote_hostname(sip_from_uri->host.ptr, sip_from_uri->host.slen); - auto sipaccount(getSIPVoIPLink()->guessAccountFromNameAndServer(toUsername, viaHostname)); + auto sipaccount(getSIPVoIPLink()->guessAccount(toUsername, viaHostname, remote_hostname)); if (!sipaccount) { ERROR("NULL account"); return PJ_FALSE; @@ -283,7 +287,7 @@ transaction_request_cb(pjsip_rx_data *rdata) Manager::instance().hookPreference.runHook(rdata->msg_info.msg); - auto call = sipaccount->newIncomingCall<SIPCall>(Manager::instance().getNewCallID()); + auto call = sipaccount->newIncomingCall(Manager::instance().getNewCallID()); // FIXME : for now, use the same address family as the SIP tranport auto family = pjsip_transport_type_get_af(sipaccount->getTransportType()); @@ -300,9 +304,6 @@ transaction_request_cb(pjsip_rx_data *rdata) std::string peerNumber(tmp, std::min(length, sizeof tmp)); sip_utils::stripSipUriPrefix(peerNumber); - const std::string remote_user(sip_from_uri->user.ptr, sip_from_uri->user.slen); - const std::string remote_hostname(sip_from_uri->host.ptr, sip_from_uri->host.slen); - if (not remote_user.empty() and not remote_hostname.empty()) peerNumber = remote_user + "@" + remote_hostname; @@ -616,14 +617,15 @@ SIPVoIPLink::~SIPVoIPLink() pj_shutdown(); } -std::shared_ptr<SIPAccount> -SIPVoIPLink::guessAccountFromNameAndServer(const std::string &userName, - const std::string &server) const +std::shared_ptr<SIPAccountBase> +SIPVoIPLink::guessAccount(const std::string& userName, + const std::string& server, + const std::string& fromUri) const { - DEBUG("username = %s, server = %s", userName.c_str(), server.c_str()); + DEBUG("username = %s, server = %s, from = %s", userName.c_str(), server.c_str(), fromUri.c_str()); // Try to find the account id from username and server name by full match - auto result = std::static_pointer_cast<SIPAccount>(Manager::instance().getIP2IPAccount()); // default result + auto result = std::static_pointer_cast<SIPAccountBase>(Manager::instance().getIP2IPAccount()); // default result MatchRank best = MatchRank::NONE; for (const auto& sipaccount : Manager::instance().getAllAccounts<SIPAccount>()) { @@ -634,7 +636,7 @@ SIPVoIPLink::guessAccountFromNameAndServer(const std::string &userName, // return right away if this is a full match if (match == MatchRank::FULL) { - return sipaccount; + return std::static_pointer_cast<SIPAccountBase>(sipaccount); } else if (match > best) { best = match; result = sipaccount; diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h index 6c259648dd35db1155914060bac4cf43d969b329..209cdf3b543231e9c1c0fe4ac6a0a97e7c11f1c1 100644 --- a/daemon/src/sip/sipvoiplink.h +++ b/daemon/src/sip/sipvoiplink.h @@ -42,7 +42,6 @@ #endif #include "sfl_types.h" -#include "sipaccount.h" #include "siptransport.h" #include <pjsip.h> @@ -60,7 +59,8 @@ #include <memory> class SIPCall; -class SIPAccount; +class SIPAccountBase; +class SIPVoIPLink; typedef std::map<std::string, std::shared_ptr<SIPCall> > SipCallMap; @@ -107,13 +107,6 @@ class SIPVoIPLink { */ void cancelKeepAliveTimer(pj_timer_entry& timer); - /** - * Start a new SIP call using the IP2IP profile - * @param The call id - * @param The target sip uri - */ - std::shared_ptr<Call> SIPNewIpToIpCall(const std::string& id, const std::string& to); - /** * Get the memory pool factory since each calls has its own memory pool */ @@ -139,9 +132,14 @@ class SIPVoIPLink { static void enqueueKeyframeRequest(const std::string &callID); #endif - std::shared_ptr<SIPAccount> - guessAccountFromNameAndServer(const std::string &userName, - const std::string &server) const; + /** + * Guess the account related to an incoming SIP call. + */ + std::shared_ptr<SIPAccountBase> + guessAccount(const std::string& userName, + const std::string& server, + const std::string& fromUri) const; + int getModId(); pjsip_endpoint * getEndpoint(); pjsip_module * getMod();