<commit_before>/*
    Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2014  Belledonne Communications SARL.

    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 "monitor.hh"
#include "configmanager.hh"
#include "authdb.hh"
#include <sofia-sip/su_md5.h>
#include <ortp/rtpsession.h>

using namespace std;

Monitor::Init Monitor::sInit;
const string Monitor::SCRIPT_PATH = "./flexisip_monitor.py";
const string Monitor::CALLER_PREFIX = "monitor-caller";
const string Monitor::CALLEE_PREFIX = "monitor-callee";
const int Monitor::PASSWORD_CACHE_EXPIRE = INT_MAX/2;

Monitor::Init::Init() {
	ConfigItemDescriptor items[] = {
		{ Boolean   , "enabled"        , "Enable or disable the Flexisip monitor daemon", "false" },
		{ Integer   , "test-interval" , "Time between two consecutive tests", "30"},
		{ String    , "logfile"       , "Path to the log file", "/etc/flexisip/flexisip_monitor.log"},
		{ Integer   , "switch-port"   , "Port to open/close folowing the test succeed or not", "12345"},
		{ String    , "password-salt" , "Salt used to generate the passwords of each test account", "" },
		config_item_end
	};

	GenericStruct *s = new GenericStruct("monitor", "Flexisip monitor parameters", 0);
	GenericManager::get()->getRoot()->addChild(s);
	s->addChildrenValues(items);
}

void Monitor::exec(int socket) {
	// Create a temporary agent to load all modules
	su_root_t *root = NULL;
	shared_ptr<Agent> a = make_shared<Agent>(root);
	GenericManager::get()->loadStrict();

	GenericStruct *monitorParams = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
	GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
	string interval = monitorParams->get<ConfigValue>("test-interval")->get();
	string logfile = monitorParams->get<ConfigString>("logfile")->read();
	string port = monitorParams->get<ConfigValue>("switch-port")->get();
	string salt = monitorParams->get<ConfigString>("password-salt")->read();
	list<string> nodes = cluster->get<ConfigStringList>("nodes")->read();

	string domain;
	try {
		domain = findDomain();
	} catch(const FlexisipException &e) {
		LOGF("Monitor: cannot find domain. %s", e.str().c_str());
		exit(-1);
	}

	if(salt.empty()) {
		LOGF("Monitor: no salt set");
		exit(-1);
	}

	if(nodes.empty()) {
		LOGF("Monitor: no nodes declared in the cluster section");
		exit(-1);
	}

	char **args = new char *[9 + nodes.size() + 1];
	args[0] = strdup(SCRIPT_PATH.c_str());
	args[1] = strdup("--interval");
	args[2] = strdup(interval.c_str());
	args[3] = strdup("--log");
	args[4] = strdup(logfile.c_str());
	args[5] = strdup("--port");
	args[6] = strdup(port.c_str());
	args[7] = strdup(domain.c_str());
	args[8] = strdup(salt.c_str());
	int i = 9;
	for(string node : nodes) {
		args[i] = strdup(node.c_str());
		i++;
	}
	args[i] = NULL;

	if(write(socket, "ok", 3) == -1) {
		exit(-1);
	}
	close(socket);

	execvp(args[0], args);
}

string Monitor::findLocalAddress(const list<string> &nodes) {
	RtpSession *session = rtp_session_new(RTP_SESSION_RECVONLY);
	for(const string & node : nodes) {
		if(rtp_session_set_local_addr(session, node.c_str(), 0, 0) != -1) {
			rtp_session_destroy(session);
			return node;
		}
	}
	return "";
}

void Monitor::createAccounts() {
	url_t url;
	memset(&url, 0, sizeof(url_t));
	AuthDb *authDb = AuthDb::get();
	GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
	GenericStruct *monitorConf = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
	string salt = monitorConf->get<ConfigString>("password-salt")->read();
	list<string> nodes = cluster->get<ConfigStringList>("nodes")->read();

	string domaine = findDomain();
	url.url_host = domaine.c_str();

	string localIP = findLocalAddress(nodes);
	if(localIP == "") {
		SLOGA << "Could not find local IP address";
		exit(-1);
	}

	string password = generatePassword(localIP, salt).c_str();
	string username = generateUsername(CALLER_PREFIX, localIP);
	url.url_user = username.c_str();
	authDb->createAccount(&url, url.url_user, password.c_str(), PASSWORD_CACHE_EXPIRE);

	username = generateUsername(CALLEE_PREFIX, localIP).c_str();
	url.url_user = username.c_str();
	authDb->createAccount(&url, url.url_user, password.c_str(), PASSWORD_CACHE_EXPIRE);<commit_msg>Substitute C++11 foreach loops by iterators<commit_after>/*
    Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2014  Belledonne Communications SARL.

    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 "monitor.hh"
#include "configmanager.hh"
#include "authdb.hh"
#include <sofia-sip/su_md5.h>
#include <ortp/rtpsession.h>

using namespace std;

Monitor::Init Monitor::sInit;
const string Monitor::SCRIPT_PATH = "./flexisip_monitor.py";
const string Monitor::CALLER_PREFIX = "monitor-caller";
const string Monitor::CALLEE_PREFIX = "monitor-callee";
const int Monitor::PASSWORD_CACHE_EXPIRE = INT_MAX/2;

Monitor::Init::Init() {
	ConfigItemDescriptor items[] = {
		{ Boolean   , "enabled"        , "Enable or disable the Flexisip monitor daemon", "false" },
		{ Integer   , "test-interval" , "Time between two consecutive tests", "30"},
		{ String    , "logfile"       , "Path to the log file", "/etc/flexisip/flexisip_monitor.log"},
		{ Integer   , "switch-port"   , "Port to open/close folowing the test succeed or not", "12345"},
		{ String    , "password-salt" , "Salt used to generate the passwords of each test account", "" },
		config_item_end
	};

	GenericStruct *s = new GenericStruct("monitor", "Flexisip monitor parameters", 0);
	GenericManager::get()->getRoot()->addChild(s);
	s->addChildrenValues(items);
}

void Monitor::exec(int socket) {
	// Create a temporary agent to load all modules
	su_root_t *root = NULL;
	shared_ptr<Agent> a = make_shared<Agent>(root);
	GenericManager::get()->loadStrict();

	GenericStruct *monitorParams = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
	GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
	string interval = monitorParams->get<ConfigValue>("test-interval")->get();
	string logfile = monitorParams->get<ConfigString>("logfile")->read();
	string port = monitorParams->get<ConfigValue>("switch-port")->get();
	string salt = monitorParams->get<ConfigString>("password-salt")->read();
	list<string> nodes = cluster->get<ConfigStringList>("nodes")->read();

	string domain;
	try {
		domain = findDomain();
	} catch(const FlexisipException &e) {
		LOGF("Monitor: cannot find domain. %s", e.str().c_str());
		exit(-1);
	}

	if(salt.empty()) {
		LOGF("Monitor: no salt set");
		exit(-1);
	}

	if(nodes.empty()) {
		LOGF("Monitor: no nodes declared in the cluster section");
		exit(-1);
	}

	char **args = new char *[9 + nodes.size() + 1];
	args[0] = strdup(SCRIPT_PATH.c_str());
	args[1] = strdup("--interval");
	args[2] = strdup(interval.c_str());
	args[3] = strdup("--log");
	args[4] = strdup(logfile.c_str());
	args[5] = strdup("--port");
	args[6] = strdup(port.c_str());
	args[7] = strdup(domain.c_str());
	args[8] = strdup(salt.c_str());
	int i = 9;
	for(list<string>::const_iterator it=nodes.cbegin(); it!=nodes.cend(); it++) {
		args[i] = strdup((*it).c_str());
		i++;
	}
	args[i] = NULL;

	if(write(socket, "ok", 3) == -1) {
		exit(-1);
	}
	close(socket);

	execvp(args[0], args);
}

string Monitor::findLocalAddress(const list<string> &nodes) {
	RtpSession *session = rtp_session_new(RTP_SESSION_RECVONLY);
	for(list<string>::const_iterator it=nodes.cbegin(); it!=nodes.cend(); it++) {
		if(rtp_session_set_local_addr(session, (*it).c_str(), 0, 0) != -1) {
			rtp_session_destroy(session);
			return *it;
		}
	}
	return "";
}

void Monitor::createAccounts() {
	url_t url;
	memset(&url, 0, sizeof(url_t));
	AuthDb *authDb = AuthDb::get();
	GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
	GenericStruct *monitorConf = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
	string salt = monitorConf->get<ConfigString>("password-salt")->read();
	list<string> nodes = cluster->get<ConfigStringList>("nodes")->read();

	string domaine = findDomain();
	url.url_host = domaine.c_str();

	string localIP = findLocalAddress(nodes);
	if(localIP == "") {
		SLOGA << "Could not find local IP address";
		exit(-1);
	}

	string password = generatePassword(localIP, salt).c_str();
	string username = generateUsername(CALLER_PREFIX, localIP);
	url.url_user = username.c_str();
	authDb->createAccount(&url, url.url_user, password.c_str(), PASSWORD_CACHE_EXPIRE);

	username = generateUsername(CALLEE_PREFIX, localIP).c_str();
	url.url_user = username.c_str();
	authDb->createAccount(&url, url.url_user, password.c_str(), PASSWORD_CACHE_EXPIRE);
{'fraction_non_alphanumeric': 0.1591840815918408, 'fraction_numerical': 0.007999200079992, 'mean_word_length': 4.9892215568862275, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5345644', 'n_tokens_mistral': 3385, 'n_tokens_neox': 3264, 'n_words': 825}