Commit 0740f3cb authored by Benjamin REIS's avatar Benjamin REIS

Feature/notify list subscribe without body

parent 3bb7b931
# Change Log
All notable changes to this project will be documented in this file.
Group changes to describe their impact on the project, as follows:
Added for new features.
Changed for changes in existing functionality.
Deprecated for once-stable features removed in upcoming releases.
Removed for deprecated features removed in this release.
Fixed for any bug fixes.
Security to invite users to upgrade in case of vulnerabilities.
## [Unreleased]
### [Added]
- [Presence server] Support of bodyless subscription.
......@@ -60,6 +60,11 @@ The "flexisip-rpm" ./prepare.py target can be used to generate rpm packages for
./prepare.py flexisip-rpm -DENABLE_REDIS=ON -DENABLE_BC_HIREDIS=ON
make
## Docker
A docker image can be build from sources with command:
docker build -f docker/flex-from-src -t flexisip .
## Macos X
The cmake scripts of flexisip can be used to develop with Flexisip in Xcode.
......
FROM debian
MAINTAINER Jehan Monnier <jehan.monnier@linphone.org>
# Prepare dependencies
RUN apt-get update
RUN apt-get install -y xsdcxx gdb
RUN apt-get install -y nasm patch python-pip python-pystache graphviz intltool libtool python-dev doxygen g++ make cmake git pkg-config libpulse-dev libssl-dev default-libmysqlclient-dev build-essential
#get source code
RUN git clone https://gitlab.linphone.org/BC/public/flexisip.git -b feature/notify_list_subscribe_without_body --recursive --depth 1
RUN cd flexisip && ./prepare.py flexisip -DENABLE_TRANSCODER=ON -DCMAKE_PREFIX_PATH=/opt/belledonne-communications -DCMAKE_INSTALL_PREFIX=/opt/belledonne-communications -DSYSCONF_INSTALL_DIR=/etc && make
RUN mkdir -p /etc/opt/belledonne-communications/flexisip
RUN mkdir -p /var/opt/belledonne-communications/log/flexisip
RUN ln -s /etc/opt/belledonne-communications/flexisip /etc/flexisip
# Add it to the default path
ENV PATH=$PATH:/opt/belledonne-communications/bin
WORKDIR /opt/belledonne-communications
# Generate a default configuration
RUN flexisip --dump-default all > /etc/flexisip/flexisip.conf
VOLUME /etc/opt/belledonne-communications/flexisip
VOLUME /var/opt/belledonne-communications/log/flexisip
COPY docker/flexisip-entrypoint.sh /
COPY docker/backtrace.gdb /
RUN chmod a+x /flexisip-entrypoint.sh
# Script to wait db before launch flexisip [Licence Apache2]
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.2.1/wait /wait
RUN chmod +x /wait
#cleanup
RUN apt-get remove -y nasm patch python-pip python-pystache graphviz intltool libtool python-dev doxygen g++ make cmake git pkg-config libpulse-dev libssl-dev default-libmysqlclient-dev build-essential
RUN rm -rf flexisip
RUN apt-get clean all
ENTRYPOINT ["/flexisip-entrypoint.sh"]
CMD flexisip
......@@ -182,8 +182,10 @@ if(ENABLE_PRESENCE)
presence/etag-manager.hh
presence/file-resource-list-manager.cc
presence/file-resource-list-manager.hh
presence/list-subscription.cc
presence/list-subscription.hh
presence/list-subscription/body-list-subscription.cc
presence/list-subscription/body-list-subscription.hh
presence/list-subscription/list-subscription.cc
presence/list-subscription/list-subscription.hh
presence/presence-configmanager.cc
presence/presence-configmanager.hh
presence/presence-longterm.cc
......@@ -208,6 +210,12 @@ if(ENABLE_PRESENCE)
xml/xml.cc
xml/xml.hh
)
if(ENABLE_SOCI)
list(APPEND FLEXISIP_SOURCES
presence/list-subscription/external-list-subscription.cc
presence/list-subscription/external-list-subscription.hh
)
endif()
endif()
if(ENABLE_CONFERENCE)
......
......@@ -85,7 +85,7 @@ void SociAuthDB::declareConfig(GenericStruct *mc) {
"Please refer to the Soci documentation of your backend, for intance: "
"http://soci.sourceforge.net/doc/3.2/backends/mysql.html",
"db=mydb user=myuser password='mypass' host=myhost.com"},
{Integer, "soci-max-queue-size",
"Amount of queries that will be allowed to be queued before bailing password "
"requests.\n This value should be chosen accordingly with 'soci-poolsize', so "
......@@ -128,7 +128,7 @@ SociAuthDB::SociAuthDB() : conn_pool(NULL) {
SLOGE << "[SOCI] connection pool open MySQL error: " << e.err_num_ << " " << e.what() << endl;
} catch (exception const &e) {
SLOGE << "[SOCI] connection pool open error: " << e.what() << endl;
}
}
}
SociAuthDB::~SociAuthDB() {
......@@ -151,8 +151,8 @@ void SociAuthDB::reconnectSession(soci::session &session) {
#define DURATION_MS(start, stop) (unsigned long) duration_cast<milliseconds>((stop) - (start)).count()
void SociAuthDB::getPasswordWithPool(const std::string &id, const std::string &domain,
const std::string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
void SociAuthDB::getPasswordWithPool(const string &id, const string &domain,
const string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
steady_clock::time_point start;
steady_clock::time_point stop;
......@@ -160,7 +160,7 @@ void SociAuthDB::getPasswordWithPool(const std::string &id, const std::string &d
vector<passwd_algo_t> passwd;
int errorCount = 0;
bool retry = false;
while (errorCount < 2) {
retry = false;
try {
......@@ -222,9 +222,9 @@ void SociAuthDB::getPasswordWithPool(const std::string &id, const std::string &d
passwd.push_back(pass);
}
if(listener_ref) listener_ref->finishVerifyAlgos(passwd);
stop = steady_clock::now();
SLOGD << "[SOCI] Got pass for " << id << " in " << DURATION_MS(start, stop) << "ms";
cachePassword(createPasswordKey(id, authid), domain, passwd, mCacheExpire);
......@@ -237,7 +237,7 @@ void SociAuthDB::getPasswordWithPool(const std::string &id, const std::string &d
stop = steady_clock::now();
SLOGE << "[SOCI] getPasswordWithPool MySQL error after " << DURATION_MS(start, stop) << "ms : " << e.err_num_ << " " << e.what();
if (sql) reconnectSession(*sql);
if ((e.err_num_ == 2014 || e.err_num_ == 2006) && errorCount == 1){
/* 2014 is the infamous "Commands out of sync; you can't run this command now" mysql error,
* which is retryable.
......@@ -264,10 +264,10 @@ void SociAuthDB::getPasswordWithPool(const std::string &id, const std::string &d
}
}
void SociAuthDB::getUserWithPhoneWithPool(const std::string &phone, const std::string &domain, AuthDbListener *listener) {
void SociAuthDB::getUserWithPhoneWithPool(const string &phone, const string &domain, AuthDbListener *listener) {
steady_clock::time_point start;
steady_clock::time_point stop;
std::string user;
string user;
session *sql = NULL;
try {
......@@ -319,48 +319,49 @@ void SociAuthDB::getUserWithPhoneWithPool(const std::string &phone, const std::s
if (sql) delete sql;
}
void SociAuthDB::getUsersWithPhonesWithPool(list<tuple<std::string,std::string,AuthDbListener*>> &creds, AuthDbListener *listener) {
void SociAuthDB::getUsersWithPhonesWithPool(list<tuple<string, string,AuthDbListener*>> &creds, AuthDbListener *listener) {
steady_clock::time_point start;
steady_clock::time_point stop;
set<pair<string, string>> presences;
std::ostringstream in;
ostringstream in;
session *sql = NULL;
list<std::string> phones;
list<std::string> domains;
list<string> phones;
list<string> domains;
bool first = true;
for(tuple<std::string,std::string,AuthDbListener*> cred : creds) {
phones.push_back(std::get<0>(cred));
for(const auto &cred : creds) {
const auto &phone = std::get<0>(cred);
phones.push_back(phone);
domains.push_back(std::get<1>(cred));
if (first) {
if(first) {
first = false;
in << "'" << std::get<0>(cred) << "'";
in << "'" << phone << "'";
} else {
in << ",'" << std::get<0>(cred) << "'";
in << ",'" << phone << "'";
}
}
string s = get_users_with_phones_request;
int index = s.find(":phones");
while(index > -1) {
s = s.replace(index, 7, in.str());
index = s.find(":phones");
}
try {
start = steady_clock::now();
// will grab a connection from the pool. This is thread safe
sql = new session(*conn_pool); //this may raise a soci_error exception, so keep it in the try block.
stop = steady_clock::now();
SLOGD << "[SOCI] Pool acquired in " << DURATION_MS(start, stop) << "ms";
start = stop;
rowset<row> ret = (sql->prepare << s);
stop = steady_clock::now();
SLOGD << "[SOCI] Got users in " << DURATION_MS(start, stop) << "ms";
for (rowset<row>::const_iterator it = ret.begin(); it != ret.end(); ++it) {
row const& row = *it;
string user = row.get<string>(0);
......@@ -371,9 +372,9 @@ void SociAuthDB::getUsersWithPhonesWithPool(list<tuple<std::string,std::string,A
if (check_domain_in_presence_results) {
domain_match = find(domains.begin(), domains.end(), domain) != domains.end();
}
if (!check_domain_in_presence_results || domain_match) {
if (phone != "") {
if (!phone.empty()) {
cacheUserWithPhone(phone, domain, user);
presences.insert(make_pair(user, phone));
} else {
......@@ -382,18 +383,17 @@ void SociAuthDB::getUsersWithPhonesWithPool(list<tuple<std::string,std::string,A
}
}
if (listener){
if (listener)
listener->onResults(phones, presences);
}
} catch (mysql_soci_error const &e) {
stop = steady_clock::now();
SLOGE << "[SOCI] getUsersWithPhonesWithPool MySQL error after " << DURATION_MS(start, stop) << "ms : " << e.err_num_ << " " << e.what();
SLOGE << "[SOCI] MySQL request causing the error was : " << s;
presences.clear();
if (listener) listener->onResults(phones, presences);
if (sql) reconnectSession(*sql);
} catch (exception const &e) {
stop = steady_clock::now();
SLOGE << "[SOCI] getUsersWithPhonesWithPool error after " << DURATION_MS(start, stop) << "ms : " << e.what();
......@@ -408,8 +408,8 @@ void SociAuthDB::getUsersWithPhonesWithPool(list<tuple<std::string,std::string,A
#pragma mark - Inherited virtuals
#endif
void SociAuthDB::getPasswordFromBackend(const std::string &id, const std::string &domain,
const std::string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
void SociAuthDB::getPasswordFromBackend(const string &id, const string &domain,
const string &authid, AuthDbListener *listener, AuthDbListener *listener_ref) {
// create a thread to grab a pool connection and use it to retrieve the auth information
auto func = bind(&SociAuthDB::getPasswordWithPool, this, id, domain, authid, listener, listener_ref);
......@@ -436,11 +436,11 @@ void SociAuthDB::getUserWithPhoneFromBackend(const string &phone, const string &
}
}
void SociAuthDB::getUsersWithPhonesFromBackend(list<tuple<std::string,std::string,AuthDbListener*>> &creds, AuthDbListener *listener) {
void SociAuthDB::getUsersWithPhonesFromBackend(list<tuple<string, string, AuthDbListener*>> &creds, AuthDbListener *listener) {
// create a thread to grab a pool connection and use it to retrieve the auth information
auto func = bind(&SociAuthDB::getUsersWithPhonesWithPool, this, creds, listener);
bool success = thread_pool->Enqueue(func);
if (success == FALSE) {
// Enqueue() can fail when the queue is full, so we have to act on that
......
......@@ -893,7 +893,7 @@ GenericManager::GenericManager()
"HIGH:!SSLv2:!SSLv3:!TLSv1:!EXP:!ADH:!RC4:!3DES:!aNULL:!eNULL"},
{Integer, "idle-timeout", "Time interval in seconds after which inactive connections are closed.", "3600"},
{Integer, "keepalive-interval", "Time interval in seconds for sending \"\\r\\n\\r\\n\" keepalives packets on inbound and outbound connections. "
"A value of zero stands for no keepalive. The main purpose of sending keepalives is to keep connection alive accross NATs, but it also"
"A value of zero stands for no keepalive. The main purpose of sending keepalives is to keep connection alive accross NATs, but it also"
" helps in detecting silently broken connections which can reduce the number socket descriptors used by flexisip.", "1800"},
{Integer, "proxy-to-proxy-keepalive-interval", "Time interval in seconds for sending \"\\r\\n\\r\\n\" keepalives packets specifically for proxy "
"to proxy connections. Indeed, while it is undesirable to send frequent keepalives to mobile clients because it drains their battery,"
......
......@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define MAX_LEN 1024
#define MAX_LEN 2048
#include <sys/stat.h>
......
......@@ -79,15 +79,15 @@ private:
bool isMessageAPresenceMessage(shared_ptr<RequestSipEvent> &ev) {
sip_t *sip = ev->getSip();
if (sip->sip_request->rq_method == sip_method_subscribe) {
sip_require_t *require;
bool require_recipient_list_subscribe_found = false;
for (require = (sip_require_t *)sip->sip_require; require != NULL;
require = (sip_require_t *)require->k_next) {
if (*require->k_items && strcasecmp((const char *)*require->k_items, "recipient-list-subscribe") == 0) {
require_recipient_list_subscribe_found = true;
sip_supported_t *supported;
bool support_list_subscription = false;
for (supported = (sip_supported_t *)sip->sip_supported; supported != NULL;
supported = (sip_supported_t *)supported->k_next) {
if (*supported->k_items && strcasecmp((const char *)*supported->k_items, "eventlist") == 0) {
support_list_subscription = true;
}
}
return (!mOnlyListSubscription->eval(ev->getSip()) || require_recipient_list_subscribe_found) &&
return (!mOnlyListSubscription->eval(ev->getSip()) || support_list_subscription) &&
sip->sip_event && strcmp(sip->sip_event->o_type, "presence") == 0;
} else if (sip->sip_request->rq_method == sip_method_publish) {
return !sip->sip_content_type || (
......
......@@ -15,8 +15,11 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bellesip-signaling-exception.hh"
#include "belle-sip/belle-sip.h"
#include "bellesip-signaling-exception.hh"
namespace flexisip {
BelleSipSignalingException::BelleSipSignalingException(int code, std::list<belle_sip_header_t *> headers)
......
......@@ -19,8 +19,10 @@
#ifndef BELLESIPSIGNALINGEXCEPTION_HH_
#define BELLESIPSIGNALINGEXCEPTION_HH_
#include "utils/signaling-exception.hh"
#include <list>
#include "utils/signaling-exception.hh"
typedef struct _belle_sip_header belle_sip_header_t;
namespace flexisip {
......
......@@ -18,6 +18,7 @@
#ifndef ETAG_MANAGER_HH_
#define ETAG_MANAGER_HH_
#include "string"
#include "utils/flexisip-exception.hh"
......
/*
Flexisip, a flexible SIP proxy server with media capabilities.
Copyright (C) 2010-2015 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bellesip-signaling-exception.hh"
#include "body-list-subscription.hh"
#include "resource-lists.hh"
using namespace std;
namespace flexisip {
BodyListSubscription::BodyListSubscription (
unsigned int expires,
belle_sip_server_transaction_t *ist,
belle_sip_provider_t *aProv,
size_t maxPresenceInfoNotifiedAtATime,
function<void(shared_ptr<ListSubscription>)> listAvailable
) : ListSubscription(expires, ist, aProv, maxPresenceInfoNotifiedAtATime, listAvailable) {
belle_sip_request_t *request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(ist));
if (!belle_sip_message_get_body(BELLE_SIP_MESSAGE(request))) {
throw BELLESIP_SIGNALING_EXCEPTION_1(400, belle_sip_header_create("Warning", "Empty body")) << "Empty body";
}
unique_ptr<Xsd::ResourceLists::ResourceLists> resource_list_body;
try {
istringstream data(belle_sip_message_get_body(BELLE_SIP_MESSAGE(request)));
resource_list_body = Xsd::ResourceLists::parseResourceLists(data, Xsd::XmlSchema::Flags::dont_validate);
} catch (const Xsd::XmlSchema::Exception &e) {
ostringstream os;
os << "Cannot parse body caused by [" << e << "]";
// todo check error code
throw BELLESIP_SIGNALING_EXCEPTION_1(400, belle_sip_header_create("Warning", os.str().c_str())) << os.str();
}
for (const auto &list : resource_list_body->getList()) {
for (const auto &entry : list.getEntry()) {
belle_sip_uri_t *uri = belle_sip_fast_uri_parse(entry.getUri().c_str());
if (!uri || !belle_sip_uri_get_host(uri) || !belle_sip_uri_get_user(uri)) {
ostringstream os;
os << "Cannot parse list entry [" << entry.getUri() << "]";
throw BELLESIP_SIGNALING_EXCEPTION_1(400, belle_sip_header_create("Warning", os.str().c_str())) << os.str();
}
if (entry.getUri().find(";user=phone") != string::npos) {
belle_sip_uri_set_user_param(uri,"phone");
}
mListeners.push_back(make_shared<PresentityResourceListener>(*this, uri));
belle_sip_object_unref(uri);
}
}
finishCreation(ist);
}
} // namespace flexisip
/*
Flexisip, a flexible SIP proxy server with media capabilities.
Copyright (C) 2010-2015 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef flexisip_rls_body_subscription_hh
#define flexisip_rls_body_subscription_hh
#include "list-subscription.hh"
typedef struct _belle_sip_uri belle_sip_uri_t;
typedef struct belle_sip_server_transaction belle_sip_server_transaction_t;
namespace flexisip {
/*
* This class manage a subscription for a list of presentities.
*/
class BodyListSubscription : public ListSubscription {
public:
BodyListSubscription(
unsigned int expires,
belle_sip_server_transaction_t *ist,
belle_sip_provider_t *aProv,
size_t maxPresenceInfoNotifiedAtATime,
std::function<void(std::shared_ptr<ListSubscription>)> listAvailable
);
};
} // namespace flexisip
#endif // flexisip_rls_body_subscription_hh
/*
Flexisip, a flexible SIP proxy server with media capabilities.
Copyright (C) 2010-2015 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <chrono>
#include <thread>
#include "belle-sip/message.h"
#include "soci/mysql/soci-mysql.h"
#include "bellesip-signaling-exception.hh"
#include "external-list-subscription.hh"
#include "log/logmanager.hh"
using namespace soci;
using namespace std;
using namespace chrono;
namespace flexisip {
ExternalListSubscription::ExternalListSubscription(
unsigned int expires,
belle_sip_server_transaction_t *ist,
belle_sip_provider_t *aProv,
size_t maxPresenceInfoNotifiedAtATime,
function<void(shared_ptr<ListSubscription>)> listAvailable,
const string &sqlRequest,
connection_pool *connPool,
ThreadPool *threadPool
) : ListSubscription(expires, ist, aProv, maxPresenceInfoNotifiedAtATime, listAvailable), mConnPool(connPool) {
// create a thread to grab a pool connection and use it to retrieve the auth information
auto func = bind(&ExternalListSubscription::getUsersList, this, sqlRequest, ist);
bool success = threadPool->Enqueue(func);
if (!success) // Enqueue() can fail when the queue is full, so we have to act on that
SLOGE << "[SOCI] Auth queue is full, cannot fullfil user request for list subscription";
}
#define DURATION_MS(start, stop) (unsigned long) duration_cast<milliseconds>((stop) - (start)).count()
void ExternalListSubscription::reconnectSession(session &session) {
try {
SLOGE << "[SOCI] Trying close/reconnect session";
session.close();
session.reconnect();
SLOGD << "[SOCI] Session " << session.get_backend_name() << " successfully reconnected";
} catch (mysql_soci_error const & e) {
SLOGE << "[SOCI] reconnectSession MySQL error: " << e.err_num_ << " " << e.what() << endl;
} catch (exception const &e) {
SLOGE << "[SOCI] reconnectSession error: " << e.what() << endl;
}
}
void ExternalListSubscription::getUsersList(const string &sqlRequest, belle_sip_server_transaction_t *ist) {
steady_clock::time_point start;
steady_clock::time_point stop;
session *sql = nullptr;
try {
start = steady_clock::now();
// will grab a connection from the pool. This is thread safe
sql = new session(*mConnPool); //this may raise a soci_error exception, so keep it in the try block.
stop = steady_clock::now();
SLOGD << "[SOCI] Pool acquired in " << DURATION_MS(start, stop) << "ms";
start = stop;
belle_sip_request_t *request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(ist));
belle_sip_header_to_t *toHeader = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_to_t);
belle_sip_header_from_t *fromHeader = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_from_t);
char *toUri = belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(toHeader)));
char *fromUri = belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(fromHeader)));
string modifiedRequest = sqlRequest;
int index = modifiedRequest.find(":from");
while(index > -1) {
modifiedRequest = modifiedRequest.replace(index, 5, fromUri);
index = modifiedRequest.find(":from");
}
index = modifiedRequest.find(":to");
while(index > -1) {
modifiedRequest = modifiedRequest.replace(index, 3, toUri);
index = modifiedRequest.find(":to");
}
belle_sip_free(toUri);
belle_sip_free(fromUri);
rowset<row> ret = (sql->prepare << modifiedRequest);
string addrStr;
for (rowset<row>::const_iterator it = ret.begin(); it != ret.end(); ++it) {
const row &row = *it;
addrStr = row.get<string>(0);
belle_sip_header_address_t *addr = belle_sip_header_address_parse(addrStr.c_str());
if (!addr) {
ostringstream os;
os << "Cannot parse list entry [" << addrStr << "]";
continue;
}
belle_sip_uri_t *uri = belle_sip_header_address_get_uri(addr);
if (!uri || !belle_sip_uri_get_host(uri) || !belle_sip_uri_get_user(uri)) {
ostringstream os;
os << "Cannot parse list entry [" << addrStr << "]";
continue;
}
const char *user_param = belle_sip_uri_get_user_param(uri);
if (user_param && strcasecmp(user_param, "phone") == 0) {
belle_sip_uri_set_user_param(uri,"phone");
}
const char *name = belle_sip_header_address_get_displayname(addr);
mListeners.push_back(make_shared<PresentityResourceListener>(*this, uri, name ? name : ""));
belle_sip_object_unref(uri); // Because PresentityResourceListener takes its own ref
}
stop = steady_clock::now();
} catch (mysql_soci_error const &e) {
stop = steady_clock::now();
SLOGE << "[SOCI] getUsersList MySQL error after " << DURATION_MS(start, stop) << "ms : " << e.err_num_ << " " << e.what();
if (sql)
reconnectSession(*sql);
} catch (exception const &e) {
stop = steady_clock::now();
SLOGE << "[SOCI] getUsersList error after " << DURATION_MS(start, stop) << "ms : " << e.what();
if (sql)
reconnectSession(*sql);
}
if (sql)
delete sql;
finishCreation(ist);
}
} // namespace flexisip
/*
Flexisip, a flexible SIP proxy server with media capabilities.
Copyright (C) 2010-2015 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef flexisip_rls_external_subscription_hh
#define flexisip_rls_external_subscription_hh
#include "soci/soci.h"
#include "list-subscription.hh"
#include "utils/threadpool.hh"
typedef struct _belle_sip_uri belle_sip_uri_t;
typedef struct belle_sip_server_transaction belle_sip_server_transaction_t;
namespace flexisip {
/*
* This class manage a subscription for a list of presentities.
*/
class ExternalListSubscription : public ListSubscription {
public:
ExternalListSubscription(
unsigned int expires,
belle_sip_server_transaction_t *ist,
belle_sip_provider_t *aProv,
size_t maxPresenceInfoNotifiedAtATime,
std::function<void(std::shared_ptr<ListSubscription>)> listAvailable,
const std::string &sqlRequest,
soci::connection_pool *connPool,
ThreadPool *threadPool
);
private:
void getUsersList(const std::string &sqlRequest, belle_sip_server_transaction_t *ist);
void reconnectSession(soci::session &session);
soci::connection_pool *mConnPool;
};
} // namespace flexisip
#endif // flexisip_rls_external_subscription_hh
......@@ -18,13 +18,18 @@
#ifndef flexisip_rls_subscription_hh
#define flexisip_rls_subscription_hh
#include "subscription.hh"
#include "rlmi+xml.hh"
#include <unordered_map>
#include <chrono>
#include <unordered_map>