#include "../include/Server.h" #include "../include/Config.h" #include "../include/base64.h" #include using namespace boost::asio; using ip::tcp; /*************** * con_handler * ***************/ con_handler::con_handler(basic_socket_acceptor::executor_type &io_service, boost::asio::ssl::context &context) : sock(io_service), sslsock(sock, context), usessl(Config::getValue("SSLenabled") == "true"), buf(max_length), jsonCommander(fileManager) { // disable indentation for json this->jsonStringBuilder.settings_["indentation"] = ""; // init reader to parse json Json::CharReaderBuilder builder; jsonReader = std::unique_ptr(builder.newCharReader()); } con_handler::~con_handler() {} con_handler::pointer con_handler::create(basic_socket_acceptor::executor_type &io_service, boost::asio::ssl::context &context) { return pointer(new con_handler(io_service, context)); } tcp::socket &con_handler::socket() { return sock; } bool con_handler::handshake() { boost::system::error_code err; sslsock.handshake(boost::asio::ssl::stream_base::server, err); if (err) { std::cerr << "SSL handshake failed: " << err.message() << std::endl; close_sock(); return false; } return true; } void con_handler::close_sock() { sock.close(); } void con_handler::start() { if (usessl) { if (handshake()) read(&con_handler::handle_read_version); } else read(&con_handler::handle_read_version); } void con_handler::handle_read_version(const boost::system::error_code &err, size_t bytes_transferred) { if (!err) { // set up json stuff Json::Value root = parseMessage(); JsonCommander::Response response = this->jsonCommander.testVersion(root); switch (response.action) { case JsonCommander::Action::send: read(&con_handler::handle_read_login); sendJson(response.json); break; case JsonCommander::Action::closeAndSend: sendJson(response.json); default: close_sock(); } } else { std::cerr << __PRETTY_FUNCTION__ << " error: " << err.message() << std::endl; close_sock(); } } void con_handler::handle_read_login(const boost::system::error_code &err, size_t bytes_transferred) { if (!err) { // set up json stuff Json::Value root = parseMessage(); JsonCommander::Response response = this->jsonCommander.checkLogin(root); switch (response.action) { case JsonCommander::Action::send: read(&con_handler::handle_read_command); sendJson(response.json); break; case JsonCommander::Action::closeAndSend: sendJson(response.json); default: close_sock(); } } else { std::cerr << __PRETTY_FUNCTION__ << " error: " << err.message() << std::endl; close_sock(); } } void con_handler::handle_read_command(const boost::system::error_code &err, size_t bytes_transferred) { if (!err) { // set up json stuff Json::Value root = parseMessage(); JsonCommander::Response response = this->jsonCommander.execute(root); switch (response.action) { case JsonCommander::Action::send: read(&con_handler::handle_read_command); sendJson(response.json); break; case JsonCommander::Action::closeAndSend: sendJson(response.json); default: close_sock(); } } else { std::cerr << __PRETTY_FUNCTION__ << " error: " << err.message() << std::endl; close_sock(); } } void con_handler::handle_write(const boost::system::error_code &err, size_t bytes_transferred) { if (err) { std::cerr << __PRETTY_FUNCTION__ << " error: " << err.message() << std::endl; close_sock(); } } void con_handler::read(void (con_handler::*handler)(const boost::system::error_code &err, size_t bytes_transferred)) { if (usessl) async_read_until(sslsock, buf, '\n', bind(handler, shared_from_this(), placeholders::error, placeholders::bytes_transferred)); else async_read_until(sock, buf, '\n', bind(handler, shared_from_this(), placeholders::error, placeholders::bytes_transferred)); } void con_handler::sendJson(const Json::Value &json) { std::string jsonString = Json::writeString(jsonStringBuilder, json); jsonString.append("\n"); if (usessl) sslsock.async_write_some(buffer(jsonString, max_length), boost::bind(&con_handler::handle_write, shared_from_this(), placeholders::error, placeholders::bytes_transferred)); else sock.async_write_some(buffer(jsonString, max_length), boost::bind(&con_handler::handle_write, shared_from_this(), placeholders::error, placeholders::bytes_transferred)); } Json::Value con_handler::parseMessage() { const char *data = buffer_cast(buf.data()); std::string dataStr(data, buf.size()); const int lineEnd = dataStr.find('\n'); JSONCPP_STRING err; Json::Value root; // parse data if (!this->jsonReader->parse(data, data + lineEnd, &root, &err)) { std::cerr << "Json error: " << err << std::endl << "data: " << data; close_sock(); } buf.consume(lineEnd + 1); return root; } /********** * Server * **********/ void Server::start_accept() { auto executor = acceptor_.get_executor(); con_handler::pointer connection = con_handler::create(executor, context_); acceptor_.async_accept(connection->socket(), boost::bind(&Server::handle_accept, this, connection, placeholders::error)); } Server::Server(io_service &io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), std::stoi(Config::getValue("port")))), context_(boost::asio::ssl::context::sslv23) { if (Config::getValue("SSLenabled") == "true") { context_.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); context_.use_certificate_chain_file(Config::getValue("SSLcertificate")); context_.use_private_key_file(Config::getValue("SSLprivatekey"), boost::asio::ssl::context::pem); context_.use_tmp_dh_file(Config::getValue("SSLdhparams")); } start_accept(); } Server::~Server() {} void Server::handle_accept(con_handler::pointer connection, const boost::system::error_code &err) { if (!err) { connection->start(); } start_accept(); }