<commit_before>#ifndef INCLUDE_ACKWARD_CORE_DETAIL_TUPLE_HPP
#define INCLUDE_ACKWARD_CORE_DETAIL_TUPLE_HPP

#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/python/extract.hpp>

#include <ackward/core/Util.hpp>

namespace ackward {
namespace core {
namespace detail {

/* These are the details of the tuple conversion process. See
 * ackward/core/Tuple.hpp for the public functions.
 */

template <typename T, int Length>
class ConvertTuple {};

template <typename T>
struct ConvertTuple<T, 2>
{
    T operator()(boost::python::tuple t)
        {
            return boost::make_tuple(
                boost::python::extract<typename boost::tuples::element<0, T>::type>(
                    t[0])(),
                boost::python::extract<typename boost::tuples::element<1, T>::type>(
                    t[1])());
        }

    boost::python::tuple operator()(const T& t)
        {
            return boost::python::make_tuple(
                boost::tuples::get<0>(t),
                boost::tuples::get<1>(t));
        }
};

template <typename T>
struct ConvertTuple<T, 3>
{
    T operator()(boost::python::tuple t)
        {
            return boost::make_tuple(
                boost::python::extract<typename boost::tuples::element<0, T>::type>(
                    t[0])(),
                boost::python::extract<typename boost::tuples::element<1, T>::type>(
                    t[1])(),
                boost::python::extract<typename boost::tuples::element<2, T>::type>(
                    t[2])());
        }

    boost::python::tuple operator()(const T& t)
        {
            return boost::python::make_tuple(
                boost::tuples::get<0>(t),
                boost::tuples::get<1>(t),
                boost::tuples::get<2>(t));
        }
};

template <typename T>
struct ConvertTuple<T, 6>
{
    T operator()(boost::python::tuple t)
        {
            return boost::make_tuple(
                boost::python::extract<typename boost::tuples::element<0, T>::type>(
                    t[0])(),
                boost::python::extract<typename boost::tuples::element<1, T>::type>(
                    t[1])(),
                boost::python::extract<typename boost::tuples::element<2, T>::type>(
                    t[2])(),
                boost::python::extract<typename boost::tuples::element<3, T>::type>(
                    t[3])(),
                boost::python::extract<typename boost::tuples::element<4, T>::type>(
                    t[4])(),
                boost::python::extract<typename boost::tuples::element<5, T>::type>(
                    t[5])());
        }

    boost::python::tuple operator()(const T& t)
        {
            return boost::python::make_tuple(
                boost::tuples::get<0>(t),
                boost::tuples::get<1>(t),
                boost::tuples::get<2>(t),
                boost::tuples::get<3>(t),
                boost::tuples::get<4>(t),
                boost::tuples::get<5>(t));
        }
};

template <typename Tuple, int Size>
struct convert_tuple {
    static PyObject* convert(const Tuple& t);
};

#define ACKWARD_CORE_TUPLE_CONVERT_ELEMENT_TO(z, n, _) boost::get<n>(t)

#define ACKWARD_CORE_TUPLE_CHECK_ELEMENT_CONVERTIBLE(z, n, _) \
    {                                                         \
        PyObject* elem_ptr = PyTuple_GetItem(obj_ptr, n);               \
                                                                        \
        if (!fromPythonConvertible<typename boost::tuples::element<n, Tuple>::type>(elem_ptr)) \
            return 0;                                                   \
    }

#define ACKWARD_CORE_TUPLE_CONVERT_ELEMENT_FROM(z, n, _)                \
extract<typename boost::tuples::element<n, Tuple>::type>(object(handle<>(borrowed(PyTuple_GetItem(obj_ptr, n)))))

#define ACKWARD_CORE_CONVERT_TUPLE(z, size, _)                          \
template <typename Tuple>                                               \
struct convert_tuple<Tuple, size> {                                     \
    static PyObject* convert(const Tuple& t) {                          \
        using namespace boost::python;                                  \
                                                                        \
        tuple rval =                                                    \
            make_tuple(                                                 \
                BOOST_PP_ENUM(size, ACKWARD_CORE_TUPLE_CONVERT_ELEMENT_TO, _) \
                );                                                      \
                                                                        \
        return incref(rval.ptr());                                      \
    }                                                                   \
                                                                        \
    static void* convertible(PyObject* obj_ptr) {                       \
        using namespace boost::python;                                  \
                                                                        \
        if (!PyTuple_Check(obj_ptr)) return 0;                          \
        if (!PyTuple_Size(obj_ptr) == size) return 0;                   \
                                                                        \
        BOOST_PP_REPEAT(size, ACKWARD_CORE_TUPLE_CHECK_ELEMENT_CONVERTIBLE, _) \
                                                                        \
            return obj_ptr;                                             \
    }                                                                   \
                                                                        \
    static void construct(                                              \
        PyObject* obj_ptr,                                              \
        boost::python::converter::rvalue_from_python_stage1_data* data) \
        {                                                               \
            using namespace boost::python;                              \
                                                                        \
            void* storage = (                                           \
                (converter::rvalue_from_python_storage<Tuple>*)         \
                data)->storage.bytes;                                   \
                                                                        \
            new (storage) Tuple(                                        \
                BOOST_PP_ENUM(size, ACKWARD_CORE_TUPLE_CONVERT_ELEMENT_FROM, _) \
                );                                                      \
                                                                        \
            data->convertible = storage;                                \
        }                                                               \
};

#ifndef ACKWARD_CORE_TUPLE_CONVERTER_SIZE_LIMIT
#define ACKWARD_CORE_TUPLE_CONVERTER_SIZE_LIMIT 11
#endif

BOOST_PP_REPEAT_FROM_TO(1, ACKWARD_CORE_TUPLE_CONVERTER_SIZE_LIMIT, ACKWARD_CORE_CONVERT_TUPLE, _)

} // namespace detail
} // namespace core
} // namespace ackward

#endif
<commit_msg>cleanup<commit_after>#ifndef INCLUDE_ACKWARD_CORE_DETAIL_TUPLE_HPP
#define INCLUDE_ACKWARD_CORE_DETAIL_TUPLE_HPP

#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/python/extract.hpp>

#include <ackward/core/Util.hpp>

namespace ackward {
namespace core {
namespace detail {

#ifndef ACKWARD_CORE_TUPLE_CONVERTER_SIZE_LIMIT
#define ACKWARD_CORE_TUPLE_CONVERTER_SIZE_LIMIT 11
#endif

#define ACKWARD_CORE_DETAIL_TUPLE_CONVERT_ELEMENT_FROM_PYOBJECT(z, n, _) \
extract<typename boost::tuples::element<n, Tuple>::type>(object(handle<>(borrowed(PyTuple_GetItem(obj_ptr, n)))))

#define ACKWARD_CORE_DETAIL_GET_TUPLE_ELEMENT_CPP(z, n, _) boost::get<n>(t)

/* These are the details of the tuple conversion process. See
 * ackward/core/Tuple.hpp for the public functions.
 */

template <typename T, int Length>
class ConvertTuple {};

template <typename T>
struct ConvertTuple<T, 2>
{
    T operator()(boost::python::tuple t)
        {
            return boost::make_tuple(
                boost::python::extract<typename boost::tuples::element<0, T>::type>(
                    t[0])(),
                boost::python::extract<typename boost::tuples::element<1, T>::type>(
                    t[1])());
        }

    boost::python::tuple operator()(const T& t)
        {
            return boost::python::make_tuple(
                boost::tuples::get<0>(t),
                boost::tuples::get<1>(t));
        }
};

template <typename T>
struct ConvertTuple<T, 3>
{
    T operator()(boost::python::tuple t)
        {
            return boost::make_tuple(
                boost::python::extract<typename boost::tuples::element<0, T>::type>(
                    t[0])(),
                boost::python::extract<typename boost::tuples::element<1, T>::type>(
                    t[1])(),
                boost::python::extract<typename boost::tuples::element<2, T>::type>(
                    t[2])());
        }

    boost::python::tuple operator()(const T& t)
        {
            return boost::python::make_tuple(
                boost::tuples::get<0>(t),
                boost::tuples::get<1>(t),
                boost::tuples::get<2>(t));
        }
};

template <typename T>
struct ConvertTuple<T, 6>
{
    T operator()(boost::python::tuple t)
        {
            return boost::make_tuple(
                boost::python::extract<typename boost::tuples::element<0, T>::type>(
                    t[0])(),
                boost::python::extract<typename boost::tuples::element<1, T>::type>(
                    t[1])(),
                boost::python::extract<typename boost::tuples::element<2, T>::type>(
                    t[2])(),
                boost::python::extract<typename boost::tuples::element<3, T>::type>(
                    t[3])(),
                boost::python::extract<typename boost::tuples::element<4, T>::type>(
                    t[4])(),
                boost::python::extract<typename boost::tuples::element<5, T>::type>(
                    t[5])());
        }

    boost::python::tuple operator()(const T& t)
        {
            return boost::python::make_tuple(
                boost::tuples::get<0>(t),
                boost::tuples::get<1>(t),
                boost::tuples::get<2>(t),
                boost::tuples::get<3>(t),
                boost::tuples::get<4>(t),
                boost::tuples::get<5>(t));
        }
};

template <typename Tuple, int Size>
struct convert_tuple {
    static PyObject* convert(const Tuple& t);
};

#define ACKWARD_CORE_DETAIL_TUPLE_CHECK_ELEMENT_CONVERTIBLE(z, n, _) \
    {                                                         \
        PyObject* elem_ptr = PyTuple_GetItem(obj_ptr, n);               \
                                                                        \
        if (!fromPythonConvertible<typename boost::tuples::element<n, Tuple>::type>(elem_ptr)) \
            return 0;                                                   \
    }

#define ACKWARD_CORE_DETAIL_AUTO_CONVERT_TUPLE(z, size, _)                          \
template <typename Tuple>                                               \
struct convert_tuple<Tuple, size> {                                     \
    static PyObject* convert(const Tuple& t) {                          \
        using namespace boost::python;                                  \
                                                                        \
        tuple rval =                                                    \
            make_tuple(                                                 \
                BOOST_PP_ENUM(size, ACKWARD_CORE_DETAIL_GET_TUPLE_ELEMENT_CPP, _) \
                );                                                      \
                                                                        \
        return incref(rval.ptr());                                      \
    }                                                                   \
                                                                        \
    static void* convertible(PyObject* obj_ptr) {                       \
        using namespace boost::python;                                  \
                                                                        \
        if (!PyTuple_Check(obj_ptr)) return 0;                          \
        if (!PyTuple_Size(obj_ptr) == size) return 0;                   \
                                                                        \
        BOOST_PP_REPEAT(size, ACKWARD_CORE_DETAIL_TUPLE_CHECK_ELEMENT_CONVERTIBLE, _) \
                                                                        \
            return obj_ptr;                                             \
    }                                                                   \
                                                                        \
    static void construct(                                              \
        PyObject* obj_ptr,                                              \
        boost::python::converter::rvalue_from_python_stage1_data* data) \
        {                                                               \
            using namespace boost::python;                              \
                                                                        \
            void* storage = (                                           \
                (converter::rvalue_from_python_storage<Tuple>*)         \
                data)->storage.bytes;                                   \
                                                                        \
            new (storage) Tuple(                                        \
                BOOST_PP_ENUM(size, ACKWARD_CORE_DETAIL_TUPLE_CONVERT_ELEMENT_FROM_PYOBJECT, _) \
                );                                                      \
                                                                        \
            data->convertible = storage;                                \
        }                                                               \
};

BOOST_PP_REPEAT_FROM_TO(1, ACKWARD_CORE_TUPLE_CONVERTER_SIZE_LIMIT, ACKWARD_CORE_DETAIL_AUTO_CONVERT_TUPLE, _)

} // namespace detail
} // namespace core
} // namespace ackward

#endif
<|endoftext|>


<commit_before>/*	opendatacon
 *
 *	Copyright (c) 2014:
 *
 *		DCrip3fJguWgVCLrZFfA7sIGgvx1Ou3fHfCxnrz4svAi
 *		yxeOtDhDCXf1Z4ApgXvX5ahqQmzRfJ2DoX8S05SqHA==
 *
 *	Licensed under the Apache License, Version 2.0 (the "License");
 *	you may not use this file except in compliance with the License.
 *	You may obtain a copy of the License at
 *
 *		http://www.apache.org/licenses/LICENSE-2.0
 *
 *	Unless required by applicable law or agreed to in writing, software
 *	distributed under the License is distributed on an "AS IS" BASIS,
 *	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *	See the License for the specific language governing permissions and
 *	limitations under the License.
 */
/*
 * DataConcentrator.cpp
 *
 *  Created on: 15/07/2014
 *      Author: Neil Stephens <dearknarl@gmail.com>
 */

#include <dlfcn.h>
#include <thread>
#include <asio.hpp>
#include <opendnp3/LogLevels.h>

#include "DataConcentrator.h"
#include "Console.h"

#include <asiodnp3/ConsoleLogger.h>
#include "logging_cmds.h"
#include "DNP3OutstationPort.h"
#include "DNP3MasterPort.h"
#include "../JSONPort/JSONClientPort.h"
#include "NullPort.h"

DataConcentrator::DataConcentrator(std::string FileName):
	DNP3Mgr(std::thread::hardware_concurrency()),
	LOG_LEVEL(opendnp3::levels::NORMAL),
	AdvConsoleLog(asiodnp3::ConsoleLogger::Instance(),LOG_LEVEL),
	FileLog("datacon_log"),
	AdvFileLog(FileLog,LOG_LEVEL),
	IOS(std::thread::hardware_concurrency()),
	ios_working(new asio::io_service::work(IOS))
{
	//fire up some worker threads
	for(size_t i=0; i < std::thread::hardware_concurrency(); ++i)
		std::thread([&](){IOS.run();}).detach();

	AdvConsoleLog.AddIngoreAlways(".*"); //silence all console messages by default
	DNP3Mgr.AddLogSubscriber(&AdvConsoleLog);
	DNP3Mgr.AddLogSubscriber(&AdvFileLog);

	//Parse the configs and create all the ports and connections
	ProcessFile(FileName);

	for(auto& port : DataPorts)
	{
		port.second->AddLogSubscriber(&AdvConsoleLog);
		port.second->AddLogSubscriber(&AdvFileLog);
		port.second->SetIOS(&IOS);
		port.second->SetLogLevel(LOG_LEVEL);
	}
	for(auto& conn : DataConnectors)
	{
		conn.second->AddLogSubscriber(&AdvConsoleLog);
		conn.second->AddLogSubscriber(&AdvFileLog);
		conn.second->SetIOS(&IOS);
		conn.second->SetLogLevel(LOG_LEVEL);
	}
}
DataConcentrator::~DataConcentrator()
{
	//turn everything off
	this->Shutdown();
	DNP3Mgr.Shutdown();
	//tell the io service to let it's run functions return once there's no handlers left (letting our threads end)
	ios_working.reset();
	//help finish any work
	IOS.run();
}

void DataConcentrator::ProcessElements(const Json::Value& JSONRoot)
{
	if(!JSONRoot["LogFileSizekB"].isNull())
		FileLog.SetLogFileSizekB(JSONRoot["LogFileSizekB"].asUInt());

	if(!JSONRoot["NumLogFiles"].isNull())
		FileLog.SetNumLogFiles(JSONRoot["NumLogFiles"].asUInt());

	if(!JSONRoot["LogName"].isNull())
		FileLog.SetLogName(JSONRoot["LogName"].asString());

	if(!JSONRoot["LOG_LEVEL"].isNull())
	{
		std::string value = JSONRoot["LOG_LEVEL"].asString();
		if(value == "ALL")
			LOG_LEVEL = opendnp3::levels::ALL;
		else if(value == "ALL_COMMS")
			LOG_LEVEL = opendnp3::levels::ALL_COMMS;
		else if(value == "NORMAL")
			LOG_LEVEL = opendnp3::levels::NORMAL;
		else if(value == "NOTHING")
			LOG_LEVEL = opendnp3::levels::NOTHING;
		else
			std::cout << "Warning: invalid LOG_LEVEL setting: '" << value << "' : ignoring and using 'NORMAL' log level." << std::endl;
		AdvFileLog.SetLogLevel(LOG_LEVEL);
		AdvConsoleLog.SetLogLevel(LOG_LEVEL);
	}

	if(!JSONRoot["Ports"].isNull())
	{
		const Json::Value Ports = JSONRoot["Ports"];

		for(Json::Value::ArrayIndex n = 0; n < Ports.size(); ++n)
		{
			if(Ports[n]["Type"].isNull() || Ports[n]["Name"].isNull() || Ports[n]["ConfFilename"].isNull())
			{
				std::cout<<"Warning: invalid port config: need at least Type, Name, ConfFilename: \n'"<<Ports[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
			if(Ports[n]["Type"].asString() == "DNP3Outstation")
			{
				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new DNP3OutstationPort(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
			else if(Ports[n]["Type"].asString() == "DNP3Master")
			{
				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new DNP3MasterPort(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
			else if(Ports[n]["Type"].asString() == "Null")
			{
				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new NullPort(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
			else
			{
				std::string libname;
				if(Ports[n]["Library"].isNull())
				{
					libname = "lib"+Ports[n]["Type"].asString()+"Port.so";
				}
				else
				{
					libname = "lib"+Ports[n]["Library"].asString()+".so";
				}

				void* portlib = dlopen(libname.c_str(),RTLD_LAZY);
				if(portlib == nullptr)
				{
					std::cout << "Warning: failed to load library '"<<libname<<"' skipping port..."<<std::endl;
					continue;
				}
				std::string new_funcname = "new_"+Ports[n]["Type"].asString()+"Port";
				auto new_port_func = (DataPort*(*)(std::string,std::string,std::string))dlsym(portlib, new_funcname.c_str());
				if(new_port_func == nullptr)
				{
					std::cout << "Warning: failed to load symbol '"<<new_funcname<<"' for port type '"<<Ports[n]["Type"].asString()<<"' skipping port..."<<std::endl;
					continue;
				}

				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new_port_func(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
		}
	}

	if(!JSONRoot["Connectors"].isNull())
	{
		const Json::Value Connectors = JSONRoot["Connectors"];

		for(Json::Value::ArrayIndex n = 0; n < Connectors.size(); ++n)
		{
			if(Connectors[n]["Name"].isNull() || Connectors[n]["ConfFilename"].isNull())
			{
				std::cout<<"Warning: invalid Connector config: need at least Name, ConfFilename: \n'"<<Connectors[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
			DataConnectors[Connectors[n]["Name"].asString()] = std::unique_ptr<DataConnector>(new DataConnector(Connectors[n]["Name"].asString(), Connectors[n]["ConfFilename"].asString(), Connectors[n]["ConfOverrides"].asString()));
		}
	}
}
void DataConcentrator::BuildOrRebuild()
{
	for(auto& Name_n_Port : DataPorts)
	{
		Name_n_Port.second->BuildOrRebuild(DNP3Mgr,LOG_LEVEL);
	}
	for(auto& Name_n_Conn : DataConnectors)
	{
		Name_n_Conn.second->BuildOrRebuild(DNP3Mgr,LOG_LEVEL);
	}
}
void DataConcentrator::Run()
{
	for(auto& Name_n_Conn : DataConnectors)
	{
		IOS.post([=]()
		{
			Name_n_Conn.second->Enable();
		});
	}
	for(auto& Name_n_Port : DataPorts)
	{
		IOS.post([=]()
		{
			Name_n_Port.second->Enable();
		});
	}

	Console console("odc> ");

	std::function<void (std::stringstream&)> bound_func;

	//console logging control
	bound_func = std::bind(cmd_ignore_message,std::placeholders::_1,std::ref(AdvConsoleLog));
	console.AddCmd("ignore_message",bound_func,"Enter regex to silence matching messages from the console logger.");
	bound_func = std::bind(cmd_unignore_message,std::placeholders::_1,std::ref(AdvConsoleLog));
	console.AddCmd("unignore_message",bound_func,"Enter regex to remove from the console ignore list.");
	bound_func = std::bind(cmd_show_ignored,std::placeholders::_1,std::ref(AdvConsoleLog));
	console.AddCmd("show_ignored",bound_func,"Shows all console message ignore regexes and how many messages they've matched.");

	//file logging control
	bound_func = std::bind(cmd_ignore_message,std::placeholders::_1,std::ref(AdvFileLog));
	console.AddCmd("ignore_file_message",bound_func,"Enter regex to silence matching messages from the file logger.");
	bound_func = std::bind(cmd_unignore_message,std::placeholders::_1,std::ref(AdvFileLog));
	console.AddCmd("unignore_file_message",bound_func,"Enter regex to remove from the file ignore list.");
	bound_func = std::bind(cmd_show_ignored,std::placeholders::_1,std::ref(AdvFileLog));
	console.AddCmd("show_file_ignored",bound_func,"Shows all file message ignore regexes and how many messages they've matched.");

	console.run();
	Shutdown();
}
void DataConcentrator::Shutdown()
{
	for(auto& Name_n_Port : DataPorts)
	{
		Name_n_Port.second->Disable();
	}
	for(auto& Name_n_Conn : DataConnectors)
	{
		Name_n_Conn.second->Disable();
	}
}
<commit_msg>Added some comments to the dynamic loading of DataPort libs<commit_after>/*	opendatacon
 *
 *	Copyright (c) 2014:
 *
 *		DCrip3fJguWgVCLrZFfA7sIGgvx1Ou3fHfCxnrz4svAi
 *		yxeOtDhDCXf1Z4ApgXvX5ahqQmzRfJ2DoX8S05SqHA==
 *
 *	Licensed under the Apache License, Version 2.0 (the "License");
 *	you may not use this file except in compliance with the License.
 *	You may obtain a copy of the License at
 *
 *		http://www.apache.org/licenses/LICENSE-2.0
 *
 *	Unless required by applicable law or agreed to in writing, software
 *	distributed under the License is distributed on an "AS IS" BASIS,
 *	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *	See the License for the specific language governing permissions and
 *	limitations under the License.
 */
/*
 * DataConcentrator.cpp
 *
 *  Created on: 15/07/2014
 *      Author: Neil Stephens <dearknarl@gmail.com>
 */

#include <dlfcn.h>
#include <thread>
#include <asio.hpp>
#include <opendnp3/LogLevels.h>

#include "DataConcentrator.h"
#include "Console.h"

#include <asiodnp3/ConsoleLogger.h>
#include "logging_cmds.h"
#include "DNP3OutstationPort.h"
#include "DNP3MasterPort.h"
#include "../JSONPort/JSONClientPort.h"
#include "NullPort.h"

DataConcentrator::DataConcentrator(std::string FileName):
	DNP3Mgr(std::thread::hardware_concurrency()),
	LOG_LEVEL(opendnp3::levels::NORMAL),
	AdvConsoleLog(asiodnp3::ConsoleLogger::Instance(),LOG_LEVEL),
	FileLog("datacon_log"),
	AdvFileLog(FileLog,LOG_LEVEL),
	IOS(std::thread::hardware_concurrency()),
	ios_working(new asio::io_service::work(IOS))
{
	//fire up some worker threads
	for(size_t i=0; i < std::thread::hardware_concurrency(); ++i)
		std::thread([&](){IOS.run();}).detach();

	AdvConsoleLog.AddIngoreAlways(".*"); //silence all console messages by default
	DNP3Mgr.AddLogSubscriber(&AdvConsoleLog);
	DNP3Mgr.AddLogSubscriber(&AdvFileLog);

	//Parse the configs and create all the ports and connections
	ProcessFile(FileName);

	for(auto& port : DataPorts)
	{
		port.second->AddLogSubscriber(&AdvConsoleLog);
		port.second->AddLogSubscriber(&AdvFileLog);
		port.second->SetIOS(&IOS);
		port.second->SetLogLevel(LOG_LEVEL);
	}
	for(auto& conn : DataConnectors)
	{
		conn.second->AddLogSubscriber(&AdvConsoleLog);
		conn.second->AddLogSubscriber(&AdvFileLog);
		conn.second->SetIOS(&IOS);
		conn.second->SetLogLevel(LOG_LEVEL);
	}
}
DataConcentrator::~DataConcentrator()
{
	//turn everything off
	this->Shutdown();
	DNP3Mgr.Shutdown();
	//tell the io service to let it's run functions return once there's no handlers left (letting our threads end)
	ios_working.reset();
	//help finish any work
	IOS.run();
}

void DataConcentrator::ProcessElements(const Json::Value& JSONRoot)
{
	if(!JSONRoot["LogFileSizekB"].isNull())
		FileLog.SetLogFileSizekB(JSONRoot["LogFileSizekB"].asUInt());

	if(!JSONRoot["NumLogFiles"].isNull())
		FileLog.SetNumLogFiles(JSONRoot["NumLogFiles"].asUInt());

	if(!JSONRoot["LogName"].isNull())
		FileLog.SetLogName(JSONRoot["LogName"].asString());

	if(!JSONRoot["LOG_LEVEL"].isNull())
	{
		std::string value = JSONRoot["LOG_LEVEL"].asString();
		if(value == "ALL")
			LOG_LEVEL = opendnp3::levels::ALL;
		else if(value == "ALL_COMMS")
			LOG_LEVEL = opendnp3::levels::ALL_COMMS;
		else if(value == "NORMAL")
			LOG_LEVEL = opendnp3::levels::NORMAL;
		else if(value == "NOTHING")
			LOG_LEVEL = opendnp3::levels::NOTHING;
		else
			std::cout << "Warning: invalid LOG_LEVEL setting: '" << value << "' : ignoring and using 'NORMAL' log level." << std::endl;
		AdvFileLog.SetLogLevel(LOG_LEVEL);
		AdvConsoleLog.SetLogLevel(LOG_LEVEL);
	}

	if(!JSONRoot["Ports"].isNull())
	{
		const Json::Value Ports = JSONRoot["Ports"];

		for(Json::Value::ArrayIndex n = 0; n < Ports.size(); ++n)
		{
			if(Ports[n]["Type"].isNull() || Ports[n]["Name"].isNull() || Ports[n]["ConfFilename"].isNull())
			{
				std::cout<<"Warning: invalid port config: need at least Type, Name, ConfFilename: \n'"<<Ports[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
			if(Ports[n]["Type"].asString() == "DNP3Outstation")
			{
				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new DNP3OutstationPort(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
			else if(Ports[n]["Type"].asString() == "DNP3Master")
			{
				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new DNP3MasterPort(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
			else if(Ports[n]["Type"].asString() == "Null")
			{
				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new NullPort(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
			else
			{
				//Looks for a specific library (for libs that implement more than one class)
				std::string libname;
				if(!Ports[n]["Library"].isNull())
				{
					libname = "lib"+Ports[n]["Library"].asString()+".so";
				}
				//Otherwise use the naming convention lib<Type>Port.so to find the default lib that implements a type of port
				else
				{
					libname = "lib"+Ports[n]["Type"].asString()+"Port.so";
				}

				//try to load the lib
				void* portlib = dlopen(libname.c_str(),RTLD_LAZY);
				if(portlib == nullptr)
				{
					std::cout << "Warning: failed to load library '"<<libname<<"' skipping port..."<<std::endl;
					continue;
				}

				//Our API says the library should export a creation function: DataPort* new_<Type>Port(Name, Filename, Overrides)
				//it should return a pointer to a heap allocated instance of a descendant of DataPort
				std::string new_funcname = "new_"+Ports[n]["Type"].asString()+"Port";
				auto new_port_func = (DataPort*(*)(std::string,std::string,std::string))dlsym(portlib, new_funcname.c_str());
				if(new_port_func == nullptr)
				{
					std::cout << "Warning: failed to load symbol '"<<new_funcname<<"' for port type '"<<Ports[n]["Type"].asString()<<"' skipping port..."<<std::endl;
					continue;
				}

				//call the creation function and wrap the returned pointer to a new port
				DataPorts[Ports[n]["Name"].asString()] = std::unique_ptr<DataPort>(new_port_func(Ports[n]["Name"].asString(), Ports[n]["ConfFilename"].asString(), Ports[n]["ConfOverrides"].asString()));
			}
		}
	}

	if(!JSONRoot["Connectors"].isNull())
	{
		const Json::Value Connectors = JSONRoot["Connectors"];

		for(Json::Value::ArrayIndex n = 0; n < Connectors.size(); ++n)
		{
			if(Connectors[n]["Name"].isNull() || Connectors[n]["ConfFilename"].isNull())
			{
				std::cout<<"Warning: invalid Connector config: need at least Name, ConfFilename: \n'"<<Connectors[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
			DataConnectors[Connectors[n]["Name"].asString()] = std::unique_ptr<DataConnector>(new DataConnector(Connectors[n]["Name"].asString(), Connectors[n]["ConfFilename"].asString(), Connectors[n]["ConfOverrides"].asString()));
		}
	}
}
void DataConcentrator::BuildOrRebuild()
{
	for(auto& Name_n_Port : DataPorts)
	{
		Name_n_Port.second->BuildOrRebuild(DNP3Mgr,LOG_LEVEL);
	}
	for(auto& Name_n_Conn : DataConnectors)
	{
		Name_n_Conn.second->BuildOrRebuild(DNP3Mgr,LOG_LEVEL);
	}
}
void DataConcentrator::Run()
{
	for(auto& Name_n_Conn : DataConnectors)
	{
		IOS.post([=]()
		{
			Name_n_Conn.second->Enable();
		});
	}
	for(auto& Name_n_Port : DataPorts)
	{
		IOS.post([=]()
		{
			Name_n_Port.second->Enable();
		});
	}

	Console console("odc> ");

	std::function<void (std::stringstream&)> bound_func;

	//console logging control
	bound_func = std::bind(cmd_ignore_message,std::placeholders::_1,std::ref(AdvConsoleLog));
	console.AddCmd("ignore_message",bound_func,"Enter regex to silence matching messages from the console logger.");
	bound_func = std::bind(cmd_unignore_message,std::placeholders::_1,std::ref(AdvConsoleLog));
	console.AddCmd("unignore_message",bound_func,"Enter regex to remove from the console ignore list.");
	bound_func = std::bind(cmd_show_ignored,std::placeholders::_1,std::ref(AdvConsoleLog));
	console.AddCmd("show_ignored",bound_func,"Shows all console message ignore regexes and how many messages they've matched.");

	//file logging control
	bound_func = std::bind(cmd_ignore_message,std::placeholders::_1,std::ref(AdvFileLog));
	console.AddCmd("ignore_file_message",bound_func,"Enter regex to silence matching messages from the file logger.");
	bound_func = std::bind(cmd_unignore_message,std::placeholders::_1,std::ref(AdvFileLog));
	console.AddCmd("unignore_file_message",bound_func,"Enter regex to remove from the file ignore list.");
	bound_func = std::bind(cmd_show_ignored,std::placeholders::_1,std::ref(AdvFileLog));
	console.AddCmd("show_file_ignored",bound_func,"Shows all file message ignore regexes and how many messages they've matched.");

	console.run();
	Shutdown();
}
void DataConcentrator::Shutdown()
{
	for(auto& Name_n_Port : DataPorts)
	{
		Name_n_Port.second->Disable();
	}
	for(auto& Name_n_Conn : DataConnectors)
	{
		Name_n_Conn.second->Disable();
	}
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "rvdbg.h"

BOOLEAN tDSend;

static void HandleSSE()
{
	if (r_registers.bxmm0 == 1)
		__asm movsd xmm0, r_registers.dxmm0;
	else if (r_registers.bxmm0 == 2)
		__asm movss xmm0, r_registers.xmm0;

	if (r_registers.bxmm1)
		__asm movsd xmm1, r_registers.dxmm1;
	else if (r_registers.bxmm1 == 2)
		__asm movss xmm1, r_registers.xmm1;

	if (r_registers.bxmm2)
		__asm movsd xmm2, r_registers.dxmm2;
	else if (r_registers.bxmm2 == 2)
		__asm movss xmm2, r_registers.xmm2;

	if (r_registers.bxmm3)
		__asm movsd xmm3, r_registers.dxmm3;
	else if (r_registers.bxmm3 == 2)
		__asm movss xmm3, r_registers.xmm3;

	if (r_registers.bxmm4)
		__asm movsd xmm4, r_registers.dxmm4;
	else if (r_registers.bxmm4 == 2)
		__asm movss xmm4, r_registers.xmm4;

	if (r_registers.bxmm5)
		__asm movsd xmm5, r_registers.dxmm5;
	else if (r_registers.bxmm5 == 2)
		__asm movss xmm5, r_registers.xmm5;

	if (r_registers.bxmm6)
		__asm movsd xmm6, r_registers.dxmm6;
	else if (r_registers.bxmm6 == 2)
		__asm movss xmm6, r_registers.xmm6;

	if (r_registers.bxmm7)
		__asm movsd xmm7, r_registers.dxmm7;
	else if (r_registers.bxmm7 == 2)
		__asm movss xmm7, r_registers.xmm7;
	r_registers.bxmm0 = 0;
	r_registers.bxmm1 = 0;
	r_registers.bxmm2 = 0;
	r_registers.bxmm3 = 0;
	r_registers.bxmm4 = 0;
	r_registers.bxmm5 = 0;
	r_registers.bxmm6 = 0;
	r_registers.bxmm7 = 0;
}

static PVOID CallChain()
{
	size_t ExceptionElement = SearchSector(Sector, 128, ExceptionComparator);

	if (ExceptionElement > 128)
	{
		if (ExceptionMode == 2)
		{
			SuspendThreads(GetCurrentProcessId(), GetCurrentThreadId());
			DWORD swap_ad = SwapAccess(AccessException, AccessException);

			if (!swap_ad)
			{
				ChunkExecutable = FALSE;
				return NULL;
			}

			Swaps.push_back((PVOID)swap_ad);
			return (PVOID)swap_ad;
		}
		return NULL;
	}

	SuspendThreads(GetCurrentProcessId(), GetCurrentThreadId());
	Debugger = TRUE;
	tDSend = TRUE;

	for (size_t iterator = 0; iterator < sizeof(Threads); iterator++)
	{
		if (Threads[iterator] != NULL)
			ResumeThread(Threads[iterator]);
	}

	Sector[ExceptionElement].ExceptionCode = ExceptionCode;
	PVOID ReturnException = HandleException(Sector[ExceptionElement], Sector[ExceptionElement].ModuleName);
	r_registers.eip = ReturnException;

	Sector[ExceptionElement].Thread = GetCurrentThread();
	Sector[ExceptionElement].IsAEHPresent = TRUE;
	Sector[ExceptionElement].ReturnAddress = r_registers.ReturnAddress;

	CurrentPool = Sector[ExceptionElement];

	EnterCriticalSection(&RunLock);
	SleepConditionVariableCS(&Runnable, &RunLock, INFINITE);
	LeaveCriticalSection(&RunLock);

	ResumeThreads(GetCurrentProcessId(), GetCurrentThreadId());
	UnlockSector(Sector, ExceptionElement);
	return r_registers.eip;
}

static __declspec(naked) VOID NTAPI KiUserExceptionDispatcher(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT Context)
{
	__asm
	{
		movss r_registers.xmm0, xmm0;
		movss r_registers.xmm1, xmm1;
		movss r_registers.xmm2, xmm2;
		movss r_registers.xmm3, xmm3;
		movss r_registers.xmm4, xmm4;
		movss r_registers.xmm5, xmm5;
		movss r_registers.xmm6, xmm6;
		movss r_registers.xmm7, xmm7;
		movsd r_registers.dxmm0, xmm0;
		movsd r_registers.dxmm1, xmm1;
		movsd r_registers.dxmm2, xmm2;
		movsd r_registers.dxmm3, xmm3;
		movsd r_registers.dxmm4, xmm4;
		movsd r_registers.dxmm5, xmm5;
		movsd r_registers.dxmm6, xmm6;
		movsd r_registers.dxmm7, xmm7;
		mov r_registers.eax, eax;
		mov r_registers.ebx, ebx;
		mov r_registers.ecx, ecx;
		mov r_registers.edx, edx;
		mov r_registers.esi, esi;
		mov r_registers.edi, edi;
		mov r_registers.ebp, ebp;

		mov eax, [esp + 0x11c]; // Reserved former esp
		mov r_registers.esp, eax;

		mov eax, [eax];
		mov r_registers.ReturnAddress, eax;

		mov eax, [esp + 0x14]; // [esp + 0x14] contains the exception address
		mov[ExceptionComparator], eax; // move into the exception comparator, aka the address to be compared with the exception address
		mov eax, [esp + 0x08]; // [esp + 0x0C] contains the exception code
		mov[ExceptionCode], eax; // move into the ExceptionCode global.
		mov eax, [esp + 20]; // when access exceptions are enabled, move the accessed memoryh ere
		mov[AccessException], eax;
	}

	Decision = (PVOID)CallChain(); // Initiate the CallChain function

	if (!Decision) // if the decision is null, then jump back to the real dispatcher
	{
		__asm
		{
			mov eax, r_registers.eax;
			mov ecx, [esp + 04];
			mov ebx, [esp];
			jmp KiUserRealDispatcher;
		}
	}
	if (r_registers.SSESet == TRUE)
		HandleSSE();
	r_registers.SSESet = FALSE;
	__asm
	{
		mov eax, r_registers.eax;
		mov ebx, r_registers.ebx;
		mov ecx, r_registers.ecx;
		mov edx, r_registers.edx;
		mov esi, r_registers.esi;
		mov edi, r_registers.edi;
		mov esp, r_registers.esp; // [esp + 0x11c] contains stack initation information such as the return address, arguments, etc...
		jmp Decision; // jump to the catch block
	}

}

static void SetKiUser()
{
	KiUser = (PVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"), "KiUserExceptionDispatcher"); // Hook, tampered exception dispatcher later
	KiUserRealDispatcher = (PVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"), "KiUserExceptionDispatcher"); // If something fails, will jump back to the real dispatcher

	DWORD KiUserRealDispatcher2 = (DWORD)KiUserRealDispatcher + 8;
	DWORD KiUser2 = (DWORD)KiUser + 1;

	KiUser = (PVOID)KiUser2;
	KiUserRealDispatcher = (PVOID)KiUserRealDispatcher2;
}

static IMP_AT GetIAT(LPCSTR ModuleName)
{
	HMODULE mod = GetModuleHandleA(ModuleName);

	PIMAGE_DOS_HEADER img_dos_headers = (PIMAGE_DOS_HEADER)mod;
	PIMAGE_NT_HEADERS img_nt_headers = (PIMAGE_NT_HEADERS)((BYTE*)img_dos_headers + img_dos_headers->e_lfanew);

	PIMAGE_IMPORT_DESCRIPTOR img_import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE*)img_dos_headers +
		img_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

	DWORD IATSize = (img_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size * 4);

	IMP_AT Retn;
	Retn.Size = IATSize;
	Retn.Address = (PVOID)((DWORD)mod + img_import_desc->FirstThunk - 0x1DC);
	return Retn;
}

static void SetImportAddressTable(const char* ModuleName)
{
	DWORD OldProtect;
	MEMORY_BASIC_INFORMATION inf;
	IMP_AT CopyModule = GetIAT(0);
	IMP_AT SelfModule = GetIAT(ModuleName);
	printf("_iat: %p\n", CopyModule.Address);
	printf("iat: %p\n", SelfModule.Address);
	VirtualProtect(SelfModule.Address, 1, PAGE_EXECUTE_READWRITE, &OldProtect);
	printf("Error1: %d\n", GetLastError());
	VirtualQuery(SelfModule.Address, &inf, sizeof(inf));
	memcpy(SelfModule.Address, CopyModule.Address, inf.RegionSize);
	VirtualProtect(SelfModule.Address, 1, OldProtect, &OldProtect);
}

int WaitOptModule(const char* OptModuleName)
{
	if (!UseModule)
		return -1;
	volatile PVOID ModPtr = NULL;
	while (!ModPtr)
		ModPtr = (PVOID)GetModuleHandleA(OptModuleName);
	SetImportAddressTable(OptModuleName);
	return 0;
}

void SetModule(BOOLEAN use)
{
	UseModule = use;
}

int AssignThread(HANDLE Thread)
{
	for (size_t iterator = 0; iterator < sizeof(Threads); iterator++)
	{
		if (Threads[iterator] == NULL)
		{
			Threads[iterator] = Thread;
			return iterator;
		}
	}
	return -1;
}

void RemoveThread(HANDLE Thread)
{
	for (size_t iterator = 0; iterator < sizeof(Threads); iterator++)
	{
		if (Threads[iterator] == Thread)
		{
			CloseHandle(Threads[iterator]);
			Threads[iterator] = NULL;
			return;
		}
	}
}

void AttachRVDbg()
{
	InitializeConditionVariable(&Runnable);
	InitializeCriticalSection(&RunLock);
	SetKiUser();
	HookFunction(KiUser, (PVOID)KiUserExceptionDispatcher, "ntdll.dll:KiUserExceptionDispatcher");
}

void DetachRVDbg()
{
	UnhookFunction(KiUser, (PVOID)KiUserExceptionDispatcher, "ntdll.dll:KiUserExceptionDispatcher");
}

void ContinueDebugger()
{
	WakeConditionVariable(&Runnable);
}

BOOLEAN IsAEHPresent()
{
	return CurrentPool.IsAEHPresent;
}

void SetRegister(DWORD Register, DWORD Value)
{
	switch (Register)
	{
	case GPRegisters::EAX:
		r_registers.eax = Value;
		return;
	case GPRegisters::EBX:
		r_registers.ebx = Value;
		return;
	case GPRegisters::ECX:
		r_registers.ecx = Value;
		return;
	case GPRegisters::EDX:
		r_registers.edx = Value;
		return;
	case GPRegisters::ESI:
		r_registers.esi = Value;
		return;
	case GPRegisters::EDI:
		r_registers.edi = Value;
		return;
	case GPRegisters::EBP:
		r_registers.ebp = Value;
		return;
	case GPRegisters::ESP:
		r_registers.esp = Value;
		return;
	case GPRegisters::EIP:
		r_registers.eip = (PVOID)Value;
	}
}

void SetRegisterFP(DWORD Register, BOOLEAN Precision, double Value)
{
	r_registers.SSESet = TRUE;
	switch (Register)
	{
	case SSERegisters::xmm0:
		if (Precision)
		{
			r_registers.bxmm0 = 1;
			r_registers.dxmm0 = Value;
			return;
		}
		r_registers.bxmm0 = 2;
		r_registers.xmm0 = (float)Value;
		return;
	case SSERegisters::xmm1:
		if (Precision)
		{
			r_registers.bxmm1 = 1;
			r_registers.dxmm1 = Value;
			return;
		}
		r_registers.bxmm1 = 2;
		r_registers.xmm1 = (float)Value;
		return;
	case SSERegisters::xmm2:
		if (Precision)
		{
			r_registers.bxmm2 = 1;
			r_registers.dxmm2 = Value;
			return;
		}
		r_registers.bxmm2 = 2;
		r_registers.xmm2 = (float)Value;
		return;
	case SSERegisters::xmm3:
		if (Precision)
		{
			r_registers.bxmm3 = 1;
			r_registers.dxmm3 = Value;
			return;
		}
		r_registers.bxmm3 = 2;
		r_registers.xmm3 = (float)Value;
		return;
	case SSERegisters::xmm4:
		if (Precision)
		{
			r_registers.bxmm4 = 1;
			r_registers.dxmm4 = Value;
			return;
		}
		r_registers.bxmm4 = 2;
		r_registers.xmm4 = (float)Value;
		return;
	case SSERegisters::xmm5:
		if (Precision)
		{
			r_registers.bxmm5 = 1;
			r_registers.dxmm5 = Value;
			return;
		}
		r_registers.bxmm5 = 2;
		r_registers.xmm5 = (float)Value;
		return;
	case SSERegisters::xmm6:
		if (Precision)
		{
			r_registers.bxmm6 = 1;
			r_registers.dxmm6 = Value;
			return;
		}
		r_registers.bxmm6 = 2;
		r_registers.xmm6 = (float)Value;
		return;
	case SSERegisters::xmm7:
		if (Precision)
		{
			r_registers.bxmm7 = 1;
			r_registers.dxmm7 = Value;
			return;
		}
		r_registers.bxmm7 = 2;
		r_registers.xmm7 = (float)Value;
		return;
	}
}

void SetExceptionMode(BOOLEAN lExceptionMode)
{
	ExceptionMode = lExceptionMode;
}

BOOLEAN GetExceptionMode()
{
	return ExceptionMode;
}

DWORD GetExceptionAddress()
{
	return CurrentPool.ExceptionAddress;
}

VirtualRegisters GetRegisters()
{
	return r_registers;
}

PoolSect GetPool()
{
	return CurrentPool;
}

PoolSect* GetSector()
{
	return Sector;
}

int GetSectorSize()
{
	return sizeof(Sector) / sizeof(PoolSect);
}

<commit_msg>Update rvdbg.cpp<commit_after>#include "stdafx.h"
#include "rvdbg.h"

BOOLEAN tDSend;
CRITICAL_SECTION repr;
CONDITION_VARIABLE reprcondition;

static void HandleSSE()
{
	if (r_registers.bxmm0 == 1)
		__asm movsd xmm0, r_registers.dxmm0;
	else if (r_registers.bxmm0 == 2)
		__asm movss xmm0, r_registers.xmm0;

	if (r_registers.bxmm1)
		__asm movsd xmm1, r_registers.dxmm1;
	else if (r_registers.bxmm1 == 2)
		__asm movss xmm1, r_registers.xmm1;

	if (r_registers.bxmm2)
		__asm movsd xmm2, r_registers.dxmm2;
	else if (r_registers.bxmm2 == 2)
		__asm movss xmm2, r_registers.xmm2;

	if (r_registers.bxmm3)
		__asm movsd xmm3, r_registers.dxmm3;
	else if (r_registers.bxmm3 == 2)
		__asm movss xmm3, r_registers.xmm3;

	if (r_registers.bxmm4)
		__asm movsd xmm4, r_registers.dxmm4;
	else if (r_registers.bxmm4 == 2)
		__asm movss xmm4, r_registers.xmm4;

	if (r_registers.bxmm5)
		__asm movsd xmm5, r_registers.dxmm5;
	else if (r_registers.bxmm5 == 2)
		__asm movss xmm5, r_registers.xmm5;

	if (r_registers.bxmm6)
		__asm movsd xmm6, r_registers.dxmm6;
	else if (r_registers.bxmm6 == 2)
		__asm movss xmm6, r_registers.xmm6;

	if (r_registers.bxmm7)
		__asm movsd xmm7, r_registers.dxmm7;
	else if (r_registers.bxmm7 == 2)
		__asm movss xmm7, r_registers.xmm7;
	r_registers.bxmm0 = 0;
	r_registers.bxmm1 = 0;
	r_registers.bxmm2 = 0;
	r_registers.bxmm3 = 0;
	r_registers.bxmm4 = 0;
	r_registers.bxmm5 = 0;
	r_registers.bxmm6 = 0;
	r_registers.bxmm7 = 0;
}

static PVOID CallChain()
{
	size_t ExceptionElement = SearchSector(Sector, 128, ExceptionComparator);

	if (ExceptionElement > 128)
	{
		if (ExceptionMode == 2)
		{
			SuspendThreads(GetCurrentProcessId(), GetCurrentThreadId());
			DWORD swap_ad = SwapAccess(AccessException, AccessException);

			if (!swap_ad)
			{
				ChunkExecutable = FALSE;
				return NULL;
			}

			Swaps.push_back((PVOID)swap_ad);
			return (PVOID)swap_ad;
		}
		return NULL;
	}

	SuspendThreads(GetCurrentProcessId(), GetCurrentThreadId());
	Debugger = TRUE;
	tDSend = TRUE;

	for (size_t iterator = 0; iterator < sizeof(Threads); iterator++)
	{
		if (Threads[iterator] != NULL)
			ResumeThread(Threads[iterator]);
	}

	Sector[ExceptionElement].ExceptionCode = ExceptionCode;
	PVOID ReturnException = HandleException(Sector[ExceptionElement], Sector[ExceptionElement].ModuleName);
	r_registers.eip = ReturnException;

	Sector[ExceptionElement].Thread = GetCurrentThread();
	Sector[ExceptionElement].IsAEHPresent = TRUE;
	Sector[ExceptionElement].ReturnAddress = r_registers.ReturnAddress;

	CurrentPool = Sector[ExceptionElement];

	EnterCriticalSection(&RunLock);
	SleepConditionVariableCS(&Runnable, &RunLock, INFINITE);
	LeaveCriticalSection(&RunLock);

	ResumeThreads(GetCurrentProcessId(), GetCurrentThreadId());
	UnlockSector(Sector, ExceptionElement);
	return r_registers.eip;
}

static __declspec(naked) VOID NTAPI KiUserExceptionDispatcher(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT Context)
{
	__asm
	{
		movss r_registers.xmm0, xmm0;
		movss r_registers.xmm1, xmm1;
		movss r_registers.xmm2, xmm2;
		movss r_registers.xmm3, xmm3;
		movss r_registers.xmm4, xmm4;
		movss r_registers.xmm5, xmm5;
		movss r_registers.xmm6, xmm6;
		movss r_registers.xmm7, xmm7;
		movsd r_registers.dxmm0, xmm0;
		movsd r_registers.dxmm1, xmm1;
		movsd r_registers.dxmm2, xmm2;
		movsd r_registers.dxmm3, xmm3;
		movsd r_registers.dxmm4, xmm4;
		movsd r_registers.dxmm5, xmm5;
		movsd r_registers.dxmm6, xmm6;
		movsd r_registers.dxmm7, xmm7;
		mov r_registers.eax, eax;
		mov r_registers.ebx, ebx;
		mov r_registers.ecx, ecx;
		mov r_registers.edx, edx;
		mov r_registers.esi, esi;
		mov r_registers.edi, edi;
		mov r_registers.ebp, ebp;

		mov eax, [esp + 0x11c]; // Reserved former esp
		mov r_registers.esp, eax;

		mov eax, [eax];
		mov r_registers.ReturnAddress, eax;

		mov eax, [esp + 0x14]; // [esp + 0x14] contains the exception address
		mov[ExceptionComparator], eax; // move into the exception comparator, aka the address to be compared with the exception address
		mov eax, [esp + 0x08]; // [esp + 0x0C] contains the exception code
		mov[ExceptionCode], eax; // move into the ExceptionCode global.
		mov eax, [esp + 20]; // when access exceptions are enabled, move the accessed memoryh ere
		mov[AccessException], eax;
	}

	Decision = (PVOID)CallChain(); // Initiate the CallChain function

	if (!Decision) // if the decision is null, then jump back to the real dispatcher
	{
		__asm
		{
			mov eax, r_registers.eax;
			mov ecx, [esp + 04];
			mov ebx, [esp];
			jmp KiUserRealDispatcher;
		}
	}
	if (r_registers.SSESet == TRUE)
		HandleSSE();
	r_registers.SSESet = FALSE;
	__asm
	{
		mov eax, r_registers.eax;
		mov ebx, r_registers.ebx;
		mov ecx, r_registers.ecx;
		mov edx, r_registers.edx;
		mov esi, r_registers.esi;
		mov edi, r_registers.edi;
		mov esp, r_registers.esp; // [esp + 0x11c] contains stack initation information such as the return address, arguments, etc...
		jmp Decision; // jump to the catch block
	}

}

static void SetKiUser()
{
	KiUser = (PVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"), "KiUserExceptionDispatcher"); // Hook, tampered exception dispatcher later
	KiUserRealDispatcher = (PVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"), "KiUserExceptionDispatcher"); // If something fails, will jump back to the real dispatcher

	DWORD KiUserRealDispatcher2 = (DWORD)KiUserRealDispatcher + 8;
	DWORD KiUser2 = (DWORD)KiUser + 1;

	KiUser = (PVOID)KiUser2;
	KiUserRealDispatcher = (PVOID)KiUserRealDispatcher2;
}

static IMP_AT GetIAT(LPCSTR ModuleName)
{
	HMODULE mod = GetModuleHandleA(ModuleName);

	PIMAGE_DOS_HEADER img_dos_headers = (PIMAGE_DOS_HEADER)mod;
	PIMAGE_NT_HEADERS img_nt_headers = (PIMAGE_NT_HEADERS)((BYTE*)img_dos_headers + img_dos_headers->e_lfanew);

	PIMAGE_IMPORT_DESCRIPTOR img_import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE*)img_dos_headers +
		img_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

	DWORD IATSize = (img_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size * 4);

	IMP_AT Retn;
	Retn.Size = IATSize;
	Retn.Address = (PVOID)((DWORD)mod + img_import_desc->FirstThunk - 0x1DC);
	return Retn;
}

static void SetImportAddressTable(const char* ModuleName)
{
	DWORD OldProtect;
	MEMORY_BASIC_INFORMATION inf;
	IMP_AT CopyModule = GetIAT(0);
	IMP_AT SelfModule = GetIAT(ModuleName);
	printf("_iat: %p\n", CopyModule.Address);
	printf("iat: %p\n", SelfModule.Address);
	VirtualProtect(SelfModule.Address, 1, PAGE_EXECUTE_READWRITE, &OldProtect);
	printf("Error1: %d\n", GetLastError());
	VirtualQuery(SelfModule.Address, &inf, sizeof(inf));
	memcpy(SelfModule.Address, CopyModule.Address, inf.RegionSize);
	VirtualProtect(SelfModule.Address, 1, OldProtect, &OldProtect);
}

int WaitOptModule(const char* OptModuleName)
{
	if (!UseModule)
		return -1;
	volatile PVOID ModPtr = NULL;
	while (!ModPtr)
		ModPtr = (PVOID)GetModuleHandleA(OptModuleName);
	SetImportAddressTable(OptModuleName);
	return 0;
}

void SetModule(BOOLEAN use)
{
	UseModule = use;
}

int AssignThread(HANDLE Thread)
{
	for (size_t iterator = 0; iterator < sizeof(Threads); iterator++)
	{
		if (Threads[iterator] == NULL)
		{
			Threads[iterator] = Thread;
			return iterator;
		}
	}
	return -1;
}

void RemoveThread(HANDLE Thread)
{
	for (size_t iterator = 0; iterator < sizeof(Threads); iterator++)
	{
		if (Threads[iterator] == Thread)
		{
			CloseHandle(Threads[iterator]);
			Threads[iterator] = NULL;
			return;
		}
	}
}

void AttachRVDbg()
{
	InitializeConditionVariable(&Runnable);
	InitializeCriticalSection(&RunLock);
	SetKiUser();
	HookFunction(KiUser, (PVOID)KiUserExceptionDispatcher, "ntdll.dll:KiUserExceptionDispatcher");
}

void DetachRVDbg()
{
	UnhookFunction(KiUser, (PVOID)KiUserExceptionDispatcher, "ntdll.dll:KiUserExceptionDispatcher");
}

void ContinueDebugger()
{
	WakeConditionVariable(&Runnable);
}

BOOLEAN IsAEHPresent()
{
	return CurrentPool.IsAEHPresent;
}

void SetRegister(DWORD Register, DWORD Value)
{
	switch (Register)
	{
	case GPRegisters::EAX:
		r_registers.eax = Value;
		return;
	case GPRegisters::EBX:
		r_registers.ebx = Value;
		return;
	case GPRegisters::ECX:
		r_registers.ecx = Value;
		return;
	case GPRegisters::EDX:
		r_registers.edx = Value;
		return;
	case GPRegisters::ESI:
		r_registers.esi = Value;
		return;
	case GPRegisters::EDI:
		r_registers.edi = Value;
		return;
	case GPRegisters::EBP:
		r_registers.ebp = Value;
		return;
	case GPRegisters::ESP:
		r_registers.esp = Value;
		return;
	case GPRegisters::EIP:
		r_registers.eip = (PVOID)Value;
	}
}

void SetRegisterFP(DWORD Register, BOOLEAN Precision, double Value)
{
	r_registers.SSESet = TRUE;
	switch (Register)
	{
	case SSERegisters::xmm0:
		if (Precision)
		{
			r_registers.bxmm0 = 1;
			r_registers.dxmm0 = Value;
			return;
		}
		r_registers.bxmm0 = 2;
		r_registers.xmm0 = (float)Value;
		return;
	case SSERegisters::xmm1:
		if (Precision)
		{
			r_registers.bxmm1 = 1;
			r_registers.dxmm1 = Value;
			return;
		}
		r_registers.bxmm1 = 2;
		r_registers.xmm1 = (float)Value;
		return;
	case SSERegisters::xmm2:
		if (Precision)
		{
			r_registers.bxmm2 = 1;
			r_registers.dxmm2 = Value;
			return;
		}
		r_registers.bxmm2 = 2;
		r_registers.xmm2 = (float)Value;
		return;
	case SSERegisters::xmm3:
		if (Precision)
		{
			r_registers.bxmm3 = 1;
			r_registers.dxmm3 = Value;
			return;
		}
		r_registers.bxmm3 = 2;
		r_registers.xmm3 = (float)Value;
		return;
	case SSERegisters::xmm4:
		if (Precision)
		{
			r_registers.bxmm4 = 1;
			r_registers.dxmm4 = Value;
			return;
		}
		r_registers.bxmm4 = 2;
		r_registers.xmm4 = (float)Value;
		return;
	case SSERegisters::xmm5:
		if (Precision)
		{
			r_registers.bxmm5 = 1;
			r_registers.dxmm5 = Value;
			return;
		}
		r_registers.bxmm5 = 2;
		r_registers.xmm5 = (float)Value;
		return;
	case SSERegisters::xmm6:
		if (Precision)
		{
			r_registers.bxmm6 = 1;
			r_registers.dxmm6 = Value;
			return;
		}
		r_registers.bxmm6 = 2;
		r_registers.xmm6 = (float)Value;
		return;
	case SSERegisters::xmm7:
		if (Precision)
		{
			r_registers.bxmm7 = 1;
			r_registers.dxmm7 = Value;
			return;
		}
		r_registers.bxmm7 = 2;
		r_registers.xmm7 = (float)Value;
		return;
	}
}

void SetExceptionMode(BOOLEAN lExceptionMode)
{
	ExceptionMode = lExceptionMode;
}

BOOLEAN GetExceptionMode()
{
	return ExceptionMode;
}

DWORD GetExceptionAddress()
{
	return CurrentPool.ExceptionAddress;
}

VirtualRegisters GetRegisters()
{
	return r_registers;
}

PoolSect GetPool()
{
	return CurrentPool;
}

PoolSect* GetSector()
{
	return Sector;
}

int GetSectorSize()
{
	return sizeof(Sector) / sizeof(PoolSect);
}

<|endoftext|>


<commit_before>#include "server/user_manage.h"

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <sstream>
#include "common/logging.h"
#include "common/timer.h"
#include "leveldb/write_batch.h"
#include "storage/utils.h"

namespace galaxy {
namespace ins {

const std::string user_dbname = "userdb";
const std::string root_name = "root";

std::string UserManager::CalcUuid(const std::string& name) {
    boost::uuids::uuid uuid_namespace = boost::uuids::random_generator()();
    boost::uuids::uuid uuid = boost::uuids::name_generator(uuid_namespace)(name);
    std::stringstream uuids;
    uuids << uuid;
    return uuids.str();
}

UserManager::UserManager(const std::string& data_dir,
                         const UserInfo& root) : data_dir_(data_dir) {
    bool ok = ins_common::Mkdirs(data_dir.c_str());
    if (!ok) {
        LOG(FATAL, "failed to create dir :%s", data_dir.c_str());
        abort();
    }
    std::string full_name = data_dir + "/" + user_dbname;
    leveldb::Options options;
    options.create_if_missing = true;
    leveldb::Status status = leveldb::DB::Open(options, full_name, &user_db_);
    assert(status.ok());
    if (root.has_username() && root.has_passwd()) {
        assert(WriteToDatabase(root));
    }
    RecoverFromDatabase();
}

Status UserManager::Login(const std::string& name,
                          const std::string& password,
                          std::string* uuid) {
    MutexLock lock(&mu_);
    std::map<std::string, UserInfo>::iterator user_it = user_list_.find(name);
    if (user_it == user_list_.end()) {
        LOG(WARNING, "Inexist user tried to login :%s", name.c_str());
        return kUnknownUser;
    }
    if (user_it->second.passwd() != password) {
        LOG(WARNING, "Password error for logging :%s", name.c_str());
        return kPasswordError;
    }

    const std::string& newuuid = CalcUuid(name);
    logged_users_[newuuid] = name;
    if (uuid != NULL) {
        *uuid = newuuid;
    }
    return kOk;
}

Status UserManager::Logout(const std::string& uuid) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::iterator online_it = logged_users_.find(uuid);
    if (online_it == logged_users_.end()) {
        LOG(WARNING, "Logout for an inexist user :%s", uuid.c_str());
        return kUnknownUser;
    }

    logged_users_.erase(online_it);
    return kOk;
}

Status UserManager::Register(const std::string& name, const std::string& password) {
    MutexLock lock(&mu_);
    if (name.empty()) {
        LOG(WARNING, "Cannot register a user without username");
        // Return `exist' status since empty user is consider as default in storage
        return kUserExists;
    }
    std::map<std::string, UserInfo>::iterator user_it = user_list_.find(name);
    if (user_it != user_list_.end()) {
        LOG(WARNING, "Try to register an exist user :%s", name.c_str());
        return kUserExists;
    }
    if (!WriteToDatabase(name, password)) {
        return kError;
    }
    user_list_[name].set_username(name);
    user_list_[name].set_passwd(password);
    return kOk;
}

Status UserManager::ForceOffline(const std::string& myid, const std::string& name) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
    if (online_it == logged_users_.end()) {
        return kUnknownUser;
    }
    std::map<std::string, UserInfo>::const_iterator user_it = user_list_.find(name);
    if (user_it == user_list_.end()) {
        return kUnknownUser;
    }
    if (online_it->second != root_name && online_it->second != name) {
        return kPermissionDenied;
    }

    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second == name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    return kOk;
}

Status UserManager::DeleteUser(const std::string& myid, const std::string& name) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
    if (online_it == logged_users_.end()) {
        return kUnknownUser;
    }
    if (online_it->second != root_name && online_it->second != name) {
        return kPermissionDenied;
    }
    std::map<std::string, UserInfo>::iterator user_it = user_list_.find(name);
    if (user_it == user_list_.end()) {
        LOG(WARNING, "Try to delete an inexist user :%s", name.c_str());
        return kNotFound;
    }
    if (!DeleteUserFromDatabase(name)) {
        return kError;
    }

    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second == name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    user_list_.erase(user_it);
    return kOk;
}

bool UserManager::IsLoggedIn(const std::string& uuid) {
    MutexLock lock(&mu_);
    return logged_users_.find(uuid) != logged_users_.end();
}

bool UserManager::IsValidUser(const std::string& name) {
    MutexLock lock(&mu_);
    return user_list_.find(name) != user_list_.end();
}

Status UserManager::TruncateOnlineUsers(const std::string& myid) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
    if (online_it == logged_users_.end()) {
        return kUnknownUser;
    }
    if (online_it->second != root_name) {
        return kPermissionDenied;
    }
    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second != root_name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    return kOk;
}

Status UserManager::TruncateAllUsers(const std::string& myid) {
    UserInfo root;
    root.set_username(root_name);
    {
        MutexLock lock(&mu_);
        std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
        if (online_it == logged_users_.end()) {
            return kUnknownUser;
        }
        if (online_it->second != root_name) {
            return kPermissionDenied;
        }
        root.set_passwd(user_list_[root_name].passwd());
    }
    if (!TruncateDatabase()) {
        return kError;
    }
    if (!WriteToDatabase(root)) {
        return kError;
    }
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second != root_name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    user_list_.clear();
    user_list_[root_name].set_username(root_name);
    user_list_[root_name].set_passwd(root.passwd());
    return kOk;
}

std::string UserManager::GetUsernameFromUuid(const std::string& uuid) {
    if (IsLoggedIn(uuid)) {
        return logged_users_[uuid];
    }
    return "";
}

bool UserManager::WriteToDatabase(const UserInfo& user) {
    if (!user.has_username() || !user.has_passwd()) {
     return false;
    }
    leveldb::Status status = user_db_->Put(leveldb::WriteOptions(),
                                           user.username(),
                                           user.passwd());
    return status.ok();
}

bool UserManager::WriteToDatabase(const std::string& name, const std::string& password) {
    leveldb::Status status = user_db_->Put(leveldb::WriteOptions(), name, password);
    return status.ok();
}

bool UserManager::DeleteUserFromDatabase(const std::string& name) {
    leveldb::Status status = user_db_->Delete(leveldb::WriteOptions(), name);
    return status.ok();
}

bool UserManager::TruncateDatabase() {
    leveldb::Iterator* it = user_db_->NewIterator(leveldb::ReadOptions());
    leveldb::WriteBatch batch;
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        batch.Delete(it->key().ToString());
    }
    if (!it->status().ok()) {
        return false;
    }
    leveldb::Status status = user_db_->Write(leveldb::WriteOptions(), &batch);
    return status.ok();
}

bool UserManager::RecoverFromDatabase() {
    leveldb::Iterator* it = user_db_->NewIterator(leveldb::ReadOptions());
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        const std::string& name = it->key().ToString();
        user_list_[name].set_username(name);
        user_list_[name].set_passwd(it->value().ToString());
    }
    return it->status().ok();
}

}
}
<commit_msg>add log for register, fix lock miss<commit_after>#include "server/user_manage.h"

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <sstream>
#include "common/logging.h"
#include "common/timer.h"
#include "leveldb/write_batch.h"
#include "storage/utils.h"

namespace galaxy {
namespace ins {

const std::string user_dbname = "userdb";
const std::string root_name = "root";

std::string UserManager::CalcUuid(const std::string& name) {
    boost::uuids::uuid uuid_namespace = boost::uuids::random_generator()();
    boost::uuids::uuid uuid = boost::uuids::name_generator(uuid_namespace)(name);
    std::stringstream uuids;
    uuids << uuid;
    return uuids.str();
}

UserManager::UserManager(const std::string& data_dir,
                         const UserInfo& root) : data_dir_(data_dir) {
    bool ok = ins_common::Mkdirs(data_dir.c_str());
    if (!ok) {
        LOG(FATAL, "failed to create dir :%s", data_dir.c_str());
        abort();
    }
    std::string full_name = data_dir + "/" + user_dbname;
    leveldb::Options options;
    options.create_if_missing = true;
    leveldb::Status status = leveldb::DB::Open(options, full_name, &user_db_);
    assert(status.ok());
    if (root.has_username() && root.has_passwd()) {
        assert(WriteToDatabase(root));
    }
    RecoverFromDatabase();
}

Status UserManager::Login(const std::string& name,
                          const std::string& password,
                          std::string* uuid) {
    MutexLock lock(&mu_);
    std::map<std::string, UserInfo>::iterator user_it = user_list_.find(name);
    if (user_it == user_list_.end()) {
        LOG(WARNING, "Inexist user tried to login :%s", name.c_str());
        return kUnknownUser;
    }
    if (user_it->second.passwd() != password) {
        LOG(WARNING, "Password error for logging :%s", name.c_str());
        return kPasswordError;
    }

    const std::string& newuuid = CalcUuid(name);
    logged_users_[newuuid] = name;
    if (uuid != NULL) {
        *uuid = newuuid;
    }
    return kOk;
}

Status UserManager::Logout(const std::string& uuid) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::iterator online_it = logged_users_.find(uuid);
    if (online_it == logged_users_.end()) {
        LOG(WARNING, "Logout for an inexist user :%s", uuid.c_str());
        return kUnknownUser;
    }

    logged_users_.erase(online_it);
    return kOk;
}

Status UserManager::Register(const std::string& name, const std::string& password) {
    MutexLock lock(&mu_);
    if (name.empty()) {
        LOG(WARNING, "Cannot register a user without username");
        // Return `exist' status since empty user is consider as default in storage
        return kUserExists;
    }
    std::map<std::string, UserInfo>::iterator user_it = user_list_.find(name);
    if (user_it != user_list_.end()) {
        LOG(WARNING, "Try to register an exist user :%s", name.c_str());
        return kUserExists;
    }
    if (!WriteToDatabase(name, password)) {
        return kError;
    }
    user_list_[name].set_username(name);
    user_list_[name].set_passwd(password);
    LOG(INFO, "%s registered ok.", name.c_str());
    return kOk;
}

Status UserManager::ForceOffline(const std::string& myid, const std::string& name) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
    if (online_it == logged_users_.end()) {
        return kUnknownUser;
    }
    std::map<std::string, UserInfo>::const_iterator user_it = user_list_.find(name);
    if (user_it == user_list_.end()) {
        return kUnknownUser;
    }
    if (online_it->second != root_name && online_it->second != name) {
        return kPermissionDenied;
    }

    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second == name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    return kOk;
}

Status UserManager::DeleteUser(const std::string& myid, const std::string& name) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
    if (online_it == logged_users_.end()) {
        return kUnknownUser;
    }
    if (online_it->second != root_name && online_it->second != name) {
        return kPermissionDenied;
    }
    std::map<std::string, UserInfo>::iterator user_it = user_list_.find(name);
    if (user_it == user_list_.end()) {
        LOG(WARNING, "Try to delete an inexist user :%s", name.c_str());
        return kNotFound;
    }
    if (!DeleteUserFromDatabase(name)) {
        return kError;
    }

    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second == name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    user_list_.erase(user_it);
    return kOk;
}

bool UserManager::IsLoggedIn(const std::string& uuid) {
    MutexLock lock(&mu_);
    return logged_users_.find(uuid) != logged_users_.end();
}

bool UserManager::IsValidUser(const std::string& name) {
    MutexLock lock(&mu_);
    return user_list_.find(name) != user_list_.end();
}

Status UserManager::TruncateOnlineUsers(const std::string& myid) {
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
    if (online_it == logged_users_.end()) {
        return kUnknownUser;
    }
    if (online_it->second != root_name) {
        return kPermissionDenied;
    }
    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second != root_name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    return kOk;
}

Status UserManager::TruncateAllUsers(const std::string& myid) {
    UserInfo root;
    root.set_username(root_name);
    {
        MutexLock lock(&mu_);
        std::map<std::string, std::string>::const_iterator online_it = logged_users_.find(myid);
        if (online_it == logged_users_.end()) {
            return kUnknownUser;
        }
        if (online_it->second != root_name) {
            return kPermissionDenied;
        }
        root.set_passwd(user_list_[root_name].passwd());
    }
    if (!TruncateDatabase()) {
        return kError;
    }
    if (!WriteToDatabase(root)) {
        return kError;
    }
    MutexLock lock(&mu_);
    std::map<std::string, std::string>::iterator it = logged_users_.begin();
    while (it != logged_users_.end()) {
        if (it->second != root_name) {
            logged_users_.erase(it++);
        } else {
            ++it;
        }
    }
    user_list_.clear();
    user_list_[root_name].set_username(root_name);
    user_list_[root_name].set_passwd(root.passwd());
    return kOk;
}

std::string UserManager::GetUsernameFromUuid(const std::string& uuid) {
    MutexLock lock(&mu_);
    if (logged_users_.find(uuid) != logged_users_.end()){
        return logged_users_[uuid];
    }
    return "";
}

bool UserManager::WriteToDatabase(const UserInfo& user) {
    if (!user.has_username() || !user.has_passwd()) {
     return false;
    }
    leveldb::Status status = user_db_->Put(leveldb::WriteOptions(),
                                           user.username(),
                                           user.passwd());
    return status.ok();
}

bool UserManager::WriteToDatabase(const std::string& name, const std::string& password) {
    leveldb::Status status = user_db_->Put(leveldb::WriteOptions(), name, password);
    return status.ok();
}

bool UserManager::DeleteUserFromDatabase(const std::string& name) {
    leveldb::Status status = user_db_->Delete(leveldb::WriteOptions(), name);
    return status.ok();
}

bool UserManager::TruncateDatabase() {
    leveldb::Iterator* it = user_db_->NewIterator(leveldb::ReadOptions());
    leveldb::WriteBatch batch;
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        batch.Delete(it->key().ToString());
    }
    if (!it->status().ok()) {
        return false;
    }
    leveldb::Status status = user_db_->Write(leveldb::WriteOptions(), &batch);
    return status.ok();
}

bool UserManager::RecoverFromDatabase() {
    leveldb::Iterator* it = user_db_->NewIterator(leveldb::ReadOptions());
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        const std::string& name = it->key().ToString();
        user_list_[name].set_username(name);
        user_list_[name].set_passwd(it->value().ToString());
    }
    return it->status().ok();
}

}
}
<|endoftext|>