Commit 359eb53e authored by Guillaume Roguez's avatar Guillaume Roguez Committed by Tristan Matthews

daemon: implement account factory design

Rationale:
ManagerImpl and others high level layers are polluted by sip/iax
API dependency. This violate various OOP design rules and
forbids easy future additions, code evolution and debugging.
To solve this issue, this patch implements a Factory design
to create generic Account instances without links to low-level
implementation (SIP/IAX).

Refs #52257
Change-Id: I65afdd80794b317e20f0c65f94246453da7d154f
parent b7f6d475
......@@ -74,6 +74,7 @@ libsflphone_la_CFLAGS = \
@DBUSCPP_CFLAGS@
libsflphone_la_SOURCES = conference.cpp \
account_factory.cpp \
preferences.cpp \
managerimpl.cpp \
manager.cpp \
......@@ -87,6 +88,7 @@ libsflphone_la_SOURCES = conference.cpp \
utf8_utils.cpp \
threadloop.h \
conference.h \
account factory.h \
voiplink.h \
preferences.h \
managerimpl.h \
......
/*
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
* Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
*
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* Author : Guillaume Roguez <guillaume.roguez@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
......@@ -29,6 +30,7 @@
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
......@@ -42,6 +44,7 @@
#include "logger.h"
#include "manager.h"
#include "voiplink.h"
#include "client/configurationmanager.h"
......@@ -75,8 +78,8 @@ using std::string;
using std::vector;
Account::Account(const string &accountID) :
accountID_(accountID)
Account::Account(const string &accountID)
: accountID_(accountID)
, username_()
, hostname_()
, alias_()
......@@ -105,6 +108,14 @@ Account::Account(const string &accountID) :
Account::~Account()
{}
void
Account::freeAccount()
{
for (const auto& call : getVoIPLink()->getCalls(accountID_))
Manager::instance().hangupCall(call->getCallId());
unregisterVoIPLink();
}
void Account::setRegistrationState(RegistrationState state)
{
if (state != registrationState_) {
......
......@@ -41,14 +41,11 @@
#include <string>
#include <vector>
#include <memory>
#include <map>
class Account;
class VoIPLink;
class Call;
/** Define a type for a AccountMap container */
typedef std::map<std::string, Account*> AccountMap;
/**
* @file account.h
* @brief Interface to protocol account (SIPAccount, IAXAccount)
......@@ -59,7 +56,6 @@ typedef std::map<std::string, Account*> AccountMap;
class Account : public Serializable {
public:
Account(const std::string& accountID);
/**
......@@ -67,6 +63,12 @@ class Account : public Serializable {
*/
virtual ~Account();
/**
* Free all ressources related to this account.
* ***Current calls using this account are HUNG-UP***
*/
void freeAccount();
virtual void setAccountDetails(const std::map<std::string, std::string> &details) = 0;
virtual std::map<std::string, std::string> getAccountDetails() const = 0;
......@@ -80,10 +82,17 @@ class Account : public Serializable {
* Get the account ID
* @return constant account id
*/
std::string getAccountID() const {
const std::string& getAccountID() const {
return accountID_;
}
virtual const char* getAccountType() const = 0;
/**
* Returns true if this is the IP2IP account
*/
virtual bool isIP2IP() const { return false; }
/**
* Get the voiplink pointer
* @return VoIPLink* the pointer or 0
......@@ -201,8 +210,7 @@ class Account : public Serializable {
mailBox_ = mb;
}
static std::vector<std::string>
split_string(std::string s);
static std::vector<std::string> split_string(std::string s);
static const char * const VIDEO_CODEC_ENABLED;
static const char * const VIDEO_CODEC_NAME;
......@@ -328,10 +336,9 @@ class Account : public Serializable {
bool hasCustomUserAgent_;
/**
* Account mail box
* Account mail box
*/
std::string mailBox_;
};
#endif
/*
* Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
* Author: Guillaume Roguez <guillaume.roguez@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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "account_factory.h"
#include "sip/sipaccount.h"
#if HAVE_IAX
#include "iax/iaxaccount.h"
#endif
#include "sip/sipvoiplink.h" // for SIPVoIPLink::loadIP2IPSettings
#include <stdexcept>
const char* const AccountFactory::DEFAULT_ACCOUNT_TYPE = SIPAccount::ACCOUNT_TYPE;
AccountFactory::AccountFactory()
{
auto sipfunc = [](const std::string& id){ return std::make_shared<SIPAccount>(id, true); };
generators_.insert(std::make_pair(SIPAccount::ACCOUNT_TYPE, sipfunc));
DEBUG("registered %s account", SIPAccount::ACCOUNT_TYPE);
#if HAVE_IAX
auto iaxfunc = [](const std::string& id){ return std::make_shared<IAXAccount>(id); };
generators_.insert(std::make_pair(IAXAccount::ACCOUNT_TYPE, iaxfunc));
DEBUG("registered %s account", IAXAccount::ACCOUNT_TYPE);
#endif
}
std::shared_ptr<Account>
AccountFactory::createAccount(const char* const accountType,
const std::string& id)
{
if (hasAccount(id)) {
ERROR("Existing account %s", id.c_str());
return nullptr;
}
std::shared_ptr<Account> account;
{
const auto& it = generators_.find(accountType);
if (it != generators_.cend())
account = it->second(id);
}
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
accountMaps_[accountType].insert(std::make_pair(id, account));
}
return account;
}
bool
AccountFactory::isSupportedType(const char* const name) const
{
return generators_.find(name) != generators_.cend();
}
void
AccountFactory::removeAccount(Account& account)
{
const auto account_type = account.getAccountType();
std::lock_guard<std::recursive_mutex> lock(mutex_);
const auto& id = account.getAccountID();
DEBUG("Removing account %s", id.c_str());
auto& map = accountMaps_.at(account.getAccountType());
map.erase(id);
DEBUG("Remaining %u %s account(s)", map.size(), account_type);
}
void
AccountFactory::removeAccount(const std::string& id)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (auto account = getAccount(id)) {
removeAccount(*account);
} else
ERROR("No account with ID %s", id.c_str());
}
template <> bool
AccountFactory::hasAccount(const std::string& id) const
{
std::lock_guard<std::recursive_mutex> lk(mutex_);
for (const auto& item : accountMaps_) {
const auto& map = item.second;
if (map.find(id) != map.cend())
return true;
}
return false;
}
template <> void
AccountFactory::clear()
{
std::lock_guard<std::recursive_mutex> lk(mutex_);
accountMaps_.clear();
}
template <>
std::vector<std::shared_ptr<Account> >
AccountFactory::getAllAccounts() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
std::vector<std::shared_ptr<Account> > v;
for (const auto& itemmap : accountMaps_) {
const auto& map = itemmap.second;
for (const auto item : map)
v.push_back(item.second);
}
v.shrink_to_fit();
return v;
}
template <>
std::shared_ptr<Account>
AccountFactory::getAccount(const std::string& id) const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
for (const auto& item : accountMaps_) {
const auto& map = item.second;
const auto& iter = map.find(id);
if (iter != map.cend())
return iter->second;
}
return nullptr;
}
template <>
bool
AccountFactory::empty() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
for (const auto& item : accountMaps_) {
const auto& map = item.second;
if (!map.empty())
return false;
}
return true;
}
template <>
std::size_t
AccountFactory::accountCount() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
std::size_t count = 0;
for (const auto& it : accountMaps_)
count += it.second.size();
return count;
}
std::shared_ptr<Account>
AccountFactory::getIP2IPAccount() const
{
return ip2ip_account_.lock();
}
void AccountFactory::initIP2IPAccount()
{
// cache this often used account using a weak_ptr
ip2ip_account_ = createAccount(SIPAccount::ACCOUNT_TYPE,
SIPAccount::IP2IP_PROFILE);
SIPVoIPLink::loadIP2IPSettings();
}
/*
* Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
* Author: Guillaume Roguez <guillaume.roguez@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 ACCOUNT_FACTORY_H
#define ACCOUNT_FACTORY_H
#include <string>
#include <map>
#include <vector>
#include <memory>
#include <mutex>
#include <utility>
class Account;
class AccountGeneratorBase;
template <class T> using AccountMap = std::map<std::string, std::shared_ptr<T> >;
class AccountFactory {
public:
static const char* const DEFAULT_ACCOUNT_TYPE;
AccountFactory();
bool isSupportedType(const char* const accountType) const;
std::shared_ptr<Account> createAccount(const char* const accountType,
const std::string& id);
void removeAccount(Account& account);
void removeAccount(const std::string& id);
template <class T=Account>
bool hasAccount(const std::string& id) const {
std::lock_guard<std::recursive_mutex> lk(mutex_);
const auto map = getMap_<T>();
return map and map->find(id) != map->cend();
}
template <class T=Account>
void clear() {
std::lock_guard<std::recursive_mutex> lk(mutex_);
auto map = getMap_<T>();
if (!map) return;
map->clear();
}
template <class T=Account>
bool empty() const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
const auto map = getMap_<T>();
return map and map->empty();
}
template <class T=Account>
std::size_t accountCount() const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
const auto map = getMap_<T>();
if (!map) return 0;
return map->size();
}
template <class T=Account>
std::shared_ptr<T>
getAccount(const std::string& id) const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
const auto map = getMap_<T>();
if (!map) return nullptr;
const auto& it = map->find(id);
if (it == map->cend())
return nullptr;
return std::static_pointer_cast<T>(it->second);
}
template <class T=Account>
std::vector<std::shared_ptr<T> > getAllAccounts() const {
std::lock_guard<std::recursive_mutex> lock(mutex_);
std::vector<std::shared_ptr<T> > v;
const auto map = getMap_<T>();
if (map) {
for (const auto& it : *map)
v.push_back(std::static_pointer_cast<T>(it.second));
}
v.shrink_to_fit();
return v;
}
std::shared_ptr<Account> getIP2IPAccount() const;
void initIP2IPAccount();
private:
mutable std::recursive_mutex mutex_ = {};
std::map<std::string, std::function<std::shared_ptr<Account>(const std::string&)> > generators_ = {};
std::map<std::string, AccountMap<Account> > accountMaps_ = {};
std::weak_ptr<Account> ip2ip_account_ = {}; //! cached pointer on IP2IP account
template <class T>
const AccountMap<Account>* getMap_() const {
const auto& itermap = accountMaps_.find(T::ACCOUNT_TYPE);
if (itermap != accountMaps_.cend())
return &itermap->second;
return nullptr;
}
};
template <>
bool
AccountFactory::hasAccount(const std::string& id) const;
template <>
void
AccountFactory::clear();
template <>
std::vector<std::shared_ptr<Account> >
AccountFactory::getAllAccounts() const;
template <>
std::shared_ptr<Account>
AccountFactory::getAccount(const std::string& accountId) const;
template <>
bool
AccountFactory::empty() const;
template <>
std::size_t
AccountFactory::accountCount() const;
#endif // ACCOUNT_FACTORY_H
......@@ -42,7 +42,6 @@
#include "sip/sdp.h"
#include "sip/sipcall.h"
#include "sip/sipaccount.h"
#include "sip/sdes_negotiator.h"
#include "logger.h"
namespace sfl {
......@@ -65,11 +64,11 @@ void AudioRtpFactory::initConfig()
const std::string accountId(call_->getAccountId());
SIPAccount *account = Manager::instance().getSipAccount(accountId);
const auto sipaccount = Manager::instance().getAccount<SIPAccount>(accountId);
if (account) {
srtpEnabled_ = account->getSrtpEnabled();
std::string key(account->getSrtpKeyExchange());
if (sipaccount) {
srtpEnabled_ = sipaccount->getSrtpEnabled();
std::string key(sipaccount->getSrtpKeyExchange());
if (srtpEnabled_) {
#if HAVE_ZRTP
......@@ -86,7 +85,7 @@ void AudioRtpFactory::initConfig()
keyExchangeProtocol_ = NONE;
}
helloHashEnabled_ = account->getZrtpHelloHash();
helloHashEnabled_ = sipaccount->getZrtpHelloHash();
} else {
srtpEnabled_ = false;
keyExchangeProtocol_ = NONE;
......
......@@ -28,12 +28,13 @@
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#include "call.h"
#include "account.h"
#include "manager.h"
#include "audio/mainbuffer.h"
#include "history/historyitem.h"
#include "sip/sipaccount.h"
#include "sip/sip_utils.h"
#include "ip_utils.h"
#include "array_size.h"
......
......@@ -40,7 +40,6 @@
#include "configurationmanager.h"
#include "account_schema.h"
#include "manager.h"
#include "sip/sipvoiplink.h"
#if HAVE_TLS
#include "sip/tlsvalidation.h"
#endif
......@@ -53,7 +52,8 @@
std::map<std::string, std::string> ConfigurationManager::getIp2IpDetails()
{
SIPAccount *sipaccount = Manager::instance().getIP2IPAccount();
const auto account = Manager::instance().getIP2IPAccount();
const auto sipaccount = static_cast<SIPAccount *>(account.get());
if (!sipaccount) {
ERROR("Could not find IP2IP account");
......@@ -96,7 +96,8 @@ std::map<std::string, std::string> ConfigurationManager::getTlsSettings()
{
std::map<std::string, std::string> tlsSettings;
SIPAccount *sipaccount = Manager::instance().getIP2IPAccount();
const auto account = Manager::instance().getIP2IPAccount();
const auto sipaccount = static_cast<SIPAccount *>(account.get());
if (!sipaccount)
return tlsSettings;
......@@ -106,7 +107,8 @@ std::map<std::string, std::string> ConfigurationManager::getTlsSettings()
void ConfigurationManager::setTlsSettings(const std::map<std::string, std::string>& details)
{
SIPAccount *sipaccount = Manager::instance().getIP2IPAccount();
const auto account = Manager::instance().getIP2IPAccount();
const auto sipaccount = static_cast<SIPAccount *>(account.get());
if (!sipaccount) {
DEBUG("No valid account in set TLS settings");
......@@ -195,9 +197,7 @@ std::vector<std::string> ConfigurationManager::getAudioCodecDetails(const int32_
std::vector<int32_t> ConfigurationManager::getActiveAudioCodecList(const std::string& accountID)
{
Account *acc = Manager::instance().getAccount(accountID);
if (acc)
if (const auto acc = Manager::instance().getAccount(accountID))
return acc->getActiveAudioCodecs();
else {
ERROR("Could not find account %s, returning default", accountID.c_str());
......@@ -207,9 +207,7 @@ std::vector<int32_t> ConfigurationManager::getActiveAudioCodecList(const std::st
void ConfigurationManager::setActiveAudioCodecList(const std::vector<std::string>& list, const std::string& accountID)
{
Account *acc = Manager::instance().getAccount(accountID);
if (acc) {
if (auto acc = Manager::instance().getAccount(accountID)) {
acc->setActiveAudioCodecs(list);
Manager::instance().saveConfig();
} else {
......@@ -527,21 +525,23 @@ void ConfigurationManager::setShortcuts(
std::vector<std::map<std::string, std::string> > ConfigurationManager::getCredentials(
const std::string& accountID)
{
SIPAccount *account = Manager::instance().getSipAccount(accountID);
const auto sipaccount = Manager::instance().getAccount<SIPAccount>(accountID);
std::vector<std::map<std::string, std::string> > credentialInformation;
if (!account)
if (!sipaccount)
return credentialInformation;
else
return account->getCredentials();
return sipaccount->getCredentials();
}
void ConfigurationManager::setCredentials(const std::string& accountID,
const std::vector<std::map<std::string, std::string> >& details)
{
SIPAccount *account = Manager::instance().getSipAccount(accountID);
if (account)
account->setCredentials(details);
const auto sipaccount = Manager::instance().getAccount<SIPAccount>(accountID);
if (sipaccount)
sipaccount->setCredentials(details);
}
bool ConfigurationManager::checkForPrivateKey(const std::string& pemPath)
......
......@@ -38,8 +38,8 @@
#include <sstream>
#include "logger.h"
#include "sip/sipaccount.h"
#include "manager.h"
#include "sip/sipaccount.h"
#include "sip/sippresence.h"
#include "sip/pres_sub_client.h"
......@@ -54,13 +54,15 @@ constexpr static const char* OFFLINE_KEY = "Offline";
void
PresenceManager::subscribeBuddy(const std::string& accountID, const std::string& uri, const bool& flag)
{
SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID);
const auto sipaccount = Manager::instance().getAccount<SIPAccount>(accountID);
if (!sipaccount) {
ERROR("Could not find account %s",accountID.c_str());
ERROR("Could not find account %s", accountID.c_str());
return;
}
SIPPresence *pres = sipaccount->getPresence();
auto pres = sipaccount->getPresence();
if (pres and pres->isEnabled() and pres->isSupported(PRESENCE_FUNCTION_SUBSCRIBE)) {
DEBUG("%subscribePresence (acc:%s, buddy:%s)", flag ? "S" : "Uns",
accountID.c_str(), uri.c_str());
......@@ -75,13 +77,15 @@ PresenceManager::subscribeBuddy(const std::string& accountID, const std::string&
void
PresenceManager::publish(const std::string& accountID, const bool& status, const std::string& note)
{
SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID);
const auto sipaccount = Manager::instance().getAccount<SIPAccount>(accountID);
if (!sipaccount) {
ERROR("Could not find account %s.",accountID.c_str());
ERROR("Could not find account %s.", accountID.c_str());
return;
}
SIPPresence *pres = sipaccount->getPresence();
auto pres = sipaccount->getPresence();
if (pres and pres->isEnabled() and pres->isSupported(PRESENCE_FUNCTION_PUBLISH)) {
DEBUG("Send Presence (acc:%s, status %s).", accountID.c_str(),
status ? "online" : "offline");
......@@ -95,7 +99,9 @@ PresenceManager::publish(const std::string& accountID, const bool& status, const
void
PresenceManager::answerServerRequest(const std::string& uri, const bool& flag)
{
SIPAccount *sipaccount = Manager::instance().getIP2IPAccount();
const auto account = Manager::instance().getIP2IPAccount();
const auto sipaccount = static_cast<SIPAccount *>(account.get());
if (!sipaccount) {
ERROR("Could not find account IP2IP");
return;
......@@ -103,7 +109,15 @@ PresenceManager::answerServerRequest(const std::string& uri, const bool& flag)
DEBUG("Approve presence (acc:IP2IP, serv:%s, flag:%s)", uri.c_str(),
flag ? "true" : "false");
sipaccount->getPresence()->approvePresSubServer(uri, flag);
auto pres = sipaccount->getPresence();
if (!pres) {
ERROR("Presence not initialized");
return;