Commit 43ae66f2 authored by Simon Morlat's avatar Simon Morlat

Fix random crash and memory leak. Apparently, soci doesn't like when the...

Fix random crash and memory leak. Apparently, soci doesn't like when the rowset is used while the session is deleted.
parent 69b2ddbd
Pipeline #4633 failed with stages
in 6 minutes and 49 seconds
......@@ -146,55 +146,55 @@ void SociAuthDB::getPasswordWithPool(const string &id, const string &domain,
SociHelper sociHelper(*conn_pool);
try{
rowset<row> results = sociHelper.execute([&](session &sql){
return (sql.prepare << get_password_request, use(unescapedIdStr, "id"), use(domain, "domain"), use(authid, "authid"));
});
for (rowset<row>::const_iterator it = results.begin(); it != results.end(); it++) {
row const& r = *it;
passwd_algo_t pass;
/* If size == 1 then we only have the password so we assume MD5 */
if (r.size() == 1) {
pass.algo = "MD5";
if (hashed_passwd) {
pass.pass = r.get<string>(0);
} else {
string input = unescapedIdStr + ":" + domain + ":" + r.get<string>(0);
pass.pass = syncMd5(input.c_str(), 16);
}
} else if (r.size() > 1) {
string password = r.get<string>(0);
string algo = r.get<string>(1);
if (algo == "CLRTXT") {
if (passwd.empty()) {
sociHelper.execute([&](session &sql){
rowset<row> results = (sql.prepare << get_password_request, use(unescapedIdStr, "id"), use(domain, "domain"), use(authid, "authid"));
for (rowset<row>::const_iterator it = results.begin(); it != results.end(); it++) {
row const& r = *it;
passwd_algo_t pass;
/* If size == 1 then we only have the password so we assume MD5 */
if (r.size() == 1) {
pass.algo = "MD5";
if (hashed_passwd) {
pass.pass = r.get<string>(0);
} else {
string input = unescapedIdStr + ":" + domain + ":" + r.get<string>(0);
pass.pass = syncMd5(input.c_str(), 16);
}
} else if (r.size() > 1) {
string password = r.get<string>(0);
string algo = r.get<string>(1);
if (algo == "CLRTXT") {
if (passwd.empty()) {
pass.algo = algo;
pass.pass = password;
passwd.push_back(pass);
string input;
input = unescapedIdStr + ":" + domain + ":" + password;
pass.pass = syncMd5(input.c_str(), 16);
pass.algo = "MD5";
passwd.push_back(pass);
pass.pass = syncSha256(input.c_str(), 32);
pass.algo = "SHA-256";
passwd.push_back(pass);
break;
}
} else {
pass.algo = algo;
pass.pass = password;
passwd.push_back(pass);
string input;
input = unescapedIdStr + ":" + domain + ":" + password;
pass.pass = syncMd5(input.c_str(), 16);
pass.algo = "MD5";
passwd.push_back(pass);
pass.pass = syncSha256(input.c_str(), 32);
pass.algo = "SHA-256";
passwd.push_back(pass);
break;
}
} else {
pass.algo = algo;
pass.pass = password;
}
passwd.push_back(pass);
}
});
passwd.push_back(pass);
}
if (listener_ref) listener_ref->finishVerifyAlgos(passwd);
if (!passwd.empty()) cachePassword(createPasswordKey(id, authid), domain, passwd, mCacheExpire);
......@@ -213,7 +213,7 @@ void SociAuthDB::getUserWithPhoneWithPool(const string &phone, const string &dom
SociHelper sociHelper(*conn_pool);
if(get_user_with_phone_request != "") {
sociHelper.executeNoReturn([&](session &sql){
sociHelper.execute([&](session &sql){
sql << get_user_with_phone_request, into(user), use(phone, "phone");
});
} else {
......@@ -223,13 +223,14 @@ void SociAuthDB::getUserWithPhoneWithPool(const string &phone, const string &dom
s = s.replace(index, 7, phone);
index = s.find(":phones");
}
rowset<row> ret = sociHelper.execute([&](session &sql){
return (sql.prepare << s);
sociHelper.execute([&](session &sql){
rowset<row> ret = (sql.prepare << s);
for (rowset<row>::const_iterator it = ret.begin(); it != ret.end(); ++it) {
row const& row = *it;
user = row.get<string>(0);
}
});
for (rowset<row>::const_iterator it = ret.begin(); it != ret.end(); ++it) {
row const& row = *it;
user = row.get<string>(0);
}
}
if (!user.empty()) {
cacheUserWithPhone(phone, domain, user);
......@@ -272,30 +273,30 @@ void SociAuthDB::getUsersWithPhonesWithPool(list<tuple<string, string,AuthDbList
try {
SociHelper sociHelper(*conn_pool);
rowset<row> ret = sociHelper.execute([&](session &sql){
return (sql.prepare << s);
});
sociHelper.execute([&](session &sql){
rowset<row> ret = (sql.prepare << s);
for (rowset<row>::const_iterator it = ret.begin(); it != ret.end(); ++it) {
row const& row = *it;
string user = row.get<string>(0);
string domain = row.get<string>(1);
string phone = (row.size() > 2) ? row.get<string>(2) : "";
for (rowset<row>::const_iterator it = ret.begin(); it != ret.end(); ++it) {
row const& row = *it;
string user = row.get<string>(0);
string domain = row.get<string>(1);
string phone = (row.size() > 2) ? row.get<string>(2) : "";
bool domain_match = false;
if (check_domain_in_presence_results) {
domain_match = find(domains.begin(), domains.end(), domain) != domains.end();
}
bool domain_match = false;
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.empty()) {
cacheUserWithPhone(phone, domain, user);
presences.insert(make_pair(user, phone));
} else {
presences.insert(make_pair(user, user));
if (!check_domain_in_presence_results || domain_match) {
if (!phone.empty()) {
cacheUserWithPhone(phone, domain, user);
presences.insert(make_pair(user, phone));
} else {
presences.insert(make_pair(user, user));
}
}
}
}
});
notifyAllListeners(creds, presences);
} catch (SociHelper::DatabaseException &e) {
SLOGE << "[SOCI] MySQL request causing the error was : " << s;
......
......@@ -64,34 +64,29 @@ void ExternalListSubscription::getUsersList(const string &sqlRequest, belle_sip_
belle_sip_free(c_fromUri);
belle_sip_free(c_toUri);
soci::rowset<soci::row> ret = sociHelper.execute([&](soci::session &sql){
return (sql.prepare << sqlRequest, soci::use(fromUri, "from"), soci::use(toUri, "to"));
});
string addrStr;
for (const auto &row : ret) {
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;
sociHelper.execute([&](soci::session &sql){
soci::rowset<soci::row> ret = (sql.prepare << sqlRequest, soci::use(fromUri, "from"), soci::use(toUri, "to"));
string addrStr;
for (const auto &row : ret) {
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 *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
}
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
}
});
} catch (SociHelper::DatabaseException &e) {
}
......
......@@ -44,6 +44,7 @@ public:
SociHelper(soci::connection_pool &pool) : mPool(pool){};
// Execute the database query safely. The code to execute the query shall be provided in the lambda argument.
#if 0
template <typename _lambda>
soci::rowset<soci::row> execute(_lambda requestLambda){
std::chrono::steady_clock::time_point start;
......@@ -64,6 +65,7 @@ public:
auto ret = requestLambda(*sql);
stop = std::chrono::steady_clock::now();
LOGD("[SOCI] statement successfully executed in %lu ms", durationMs(start, stop));
if (sql) delete sql;
return ret;
} catch (soci::mysql_soci_error const &e) {
errorCount++;
......@@ -91,34 +93,31 @@ public:
if (sql) delete sql;
throw DatabaseException();
}
#endif
// Variant of the previous method for the case where no rowset is needed as return value.
// Probably it is possible to merge the two methods thanks std::enable_if (TODO later).
template <typename _lambda>
void executeNoReturn(_lambda requestLambda){
void execute(_lambda requestLambda){
std::chrono::steady_clock::time_point start;
std::chrono::steady_clock::time_point stop;
soci::session *sql = nullptr;
int errorCount = 0;
bool retry;
bool good = false;
do{
retry = false;
try{
// will grab a connection from the pool. This is thread safe.
if (!sql) {
start = std::chrono::steady_clock::now();
sql = new soci::session(mPool);
stop = std::chrono::steady_clock::now();
LOGD("[SOCI] Session acquired from pool in %lu ms", durationMs(start, stop));
start = stop;
}else{
start = std::chrono::steady_clock::now();
}
start = std::chrono::steady_clock::now();
sql = new soci::session(mPool);
stop = std::chrono::steady_clock::now();
LOGD("[SOCI] Session acquired from pool in %lu ms", durationMs(start, stop));
start = stop;
requestLambda(*sql);
stop = std::chrono::steady_clock::now();
LOGD("[SOCI] statement successfully executed in %lu ms", durationMs(start, stop));
return;
good = true;
} catch (soci::mysql_soci_error const &e) {
errorCount++;
stop = std::chrono::steady_clock::now();
......@@ -141,9 +140,9 @@ public:
SLOGE << "[SOCI] error after " << durationMs(start, stop) << " ms : " << e.what();
if (sql) reconnectSession(*sql);
}
if (sql) delete sql;
} while (retry);
if (sql) delete sql;
throw DatabaseException();
if (!good) throw DatabaseException();
}
private:
void reconnectSession(soci::session &session);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment