#include #include #include #include #include "server/server.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include "terminal_api_driver.h" #include "version.h" #include "auth/resources.h" #include "auth/jwt.h" #include "auth/utils.h" namespace ssl = boost::asio::ssl; // from constexpr const char* REBOOT_COMMAND = "web-action reboot"; constexpr const char* UPGRADE_COMMAND = "web-action upgrade"; constexpr const char* FIRMWARE_LOCATION = "/tmp/firmware.zip"; namespace mime_types = http::server::mime_types; void init_logging() { namespace log = boost::log; namespace keywords = log::keywords; namespace expressions = log::expressions; namespace attributes = log::attributes; log::register_simple_formatter_factory("Severity"); #ifdef USE_DEBUG log::add_console_log(std::clog, keywords::format = "%TimeStamp%: [%Severity%] %Message%"); #else log::add_file_log( keywords::file_name = "http_server_%N.log", keywords::rotation_size = 10 * 1024 * 1024, keywords::time_based_rotation = log::sinks::file::rotation_at_time_point(0, 0, 0), keywords::format = "%TimeStamp%: [%Severity%] %Message%", keywords::open_mode = std::ios_base::app, keywords::auto_flush = true ); #endif log::core::get()->set_filter(log::trivial::severity >= log::trivial::info); log::add_common_attributes(); } class ServerResources { std::unique_ptr sf; std::unique_ptr api; http::auth::AuthProvider auth{}; bool upgradeOrRebootRunning = false; static void onUploadFirmware(const http::server::Request& req) { std::ofstream f(FIRMWARE_LOCATION, std::ios::binary); if (f.is_open()) { f.write(req.payload.data(), static_cast(req.payload.size())); f.close(); } else { throw std::runtime_error("File is not open"); } } void doTerminalUpgrade() const { api->executeInApi([](TSID sid) { CP_SetDmaDebug(sid, "begin_save_config", ""); std::string cmd(UPGRADE_COMMAND); cmd += " "; cmd += FIRMWARE_LOCATION; system(cmd.c_str()); CP_SetDmaDebug(sid, "save_config", ""); }); } #ifdef MODEM_IS_TDMA void doTerminalUpgradeOta() const { api->executeInApi([&](TSID sid) { CP_SetDmaDebug(sid, "begin_save_config", ""); std::string cmd(UPGRADE_COMMAND); cmd += " "; cmd += api->getOtaFileLocation(); system(cmd.c_str()); CP_SetDmaDebug(sid, "save_config", ""); }); } #endif public: #if defined(MODEM_IS_TDMA) static constexpr const char* INDEX_HTML = "/main-tdma.html"; #elif defined(MODEM_IS_SCPC) static constexpr const char* INDEX_HTML = "/main-scpc.html"; #else #error "Modem type not defined!" #endif static constexpr const char* LOGIN_HTML = "/login.html"; static constexpr const char* DEV_HTML = "/dev.html"; // картинки, их даже можно кешировать static constexpr const char* FAVICON_ICO = "/favicon.ico"; static constexpr const char* VUE_JS = "/js/vue.js"; // это тоже можно кешировать static constexpr const char* CHARTJS = "/js/chart.js"; static constexpr const char* MOMENT_JS = "/js/moment.js"; static constexpr const char* CHARTJS_ADAPTER_MOMENT = "/js/chartjs-adapter-moment.js"; // а эти стили нельзя кешировать в отладочной версии static constexpr const char* STYLE_CSS = "/style.css"; static constexpr const char* FIELDS_CSS = "/fields.css"; static constexpr const char* INTERNET_JPG = "/internet.jpg"; ServerResources(const ServerResources&) = delete; explicit ServerResources(const std::string& staticFilesPath): sf(std::make_unique()), api(std::make_unique()) { api->startDaemon(); auth.users.emplace_back(std::make_shared("admin", "", http::auth::User::WATCH_STATISTICS | http::auth::User::RESET_PACKET_STATISTICS | http::auth::User::WATCH_SETTINGS | http::auth::User::EDIT_SETTINGS | http::auth::User::UPDATE_FIRMWARE | http::auth::User::SETUP_QOS)); // пароль fuckyou123 auth.users.emplace_back(std::make_shared("developer", "10628cfc434fb87f31d675d37e0402c2d824cfe8393aff7a61ee57aaa7d909c3", http::auth::User::SUPERUSER)); sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true); sf->registerFile(staticFilesPath + CHARTJS, CHARTJS, mime_types::javascript, true); sf->registerFile(staticFilesPath + MOMENT_JS, MOMENT_JS, mime_types::javascript, true); sf->registerFile(staticFilesPath + CHARTJS_ADAPTER_MOMENT, CHARTJS_ADAPTER_MOMENT, mime_types::javascript, true); #ifdef USE_DEBUG sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true); #else sf->registerFile(staticFilesPath + "/js/vue.prod.js", VUE_JS, mime_types::javascript, true); #endif sf->registerFile(staticFilesPath + STYLE_CSS, STYLE_CSS, mime_types::text_css, true); sf->registerFile(staticFilesPath + FIELDS_CSS, FIELDS_CSS, mime_types::text_css, true); sf->registerFile(staticFilesPath + INDEX_HTML, INDEX_HTML, mime_types::text_html, false); sf->registerFile(staticFilesPath + DEV_HTML, DEV_HTML, mime_types::text_html, false); sf->registerFile(staticFilesPath + LOGIN_HTML, LOGIN_HTML, mime_types::text_html, true); sf->registerFile(staticFilesPath + INTERNET_JPG, INTERNET_JPG, mime_types::image_jpeg, true); } void registerResources(http::server::Server& s) { s.resources.emplace_back(std::make_unique("/", [this](const auto& req, auto& rep) { auto user = auth.getSession(req, rep); if (user == nullptr) { http::server::httpRedirect(rep, "/login"); } else { sf->serve(INDEX_HTML, rep); } })); s.resources.emplace_back(std::make_unique("/login", [this](const auto& req, auto& rep) { if (req.method == "GET") { auto user = auth.getSession(req, rep); if (user == nullptr) { sf->serve(LOGIN_HTML, rep); } else { http::server::httpRedirect(rep, "/"); } } else if (req.method == "POST") { rep.status = http::server::ok; rep.headers.clear(); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); try { std::istringstream is(std::string(req.payload.data(), req.payload.size())); boost::property_tree::ptree pt; read_json(is, pt); auto u = auth.doAuth(pt.get("username"), pt.get("password"), req, rep); if (u == nullptr) { throw std::runtime_error("invalid session"); } std::string result = R"({"redirect":"/"})"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception &e) { BOOST_LOG_TRIVIAL(error) << e.what() << std::endl; std::string result = R"({"error":"Неверный логин или пароль"})"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } } else { http::server::stockReply(http::server::bad_request, rep); } })); s.resources.emplace_back(std::make_unique("/logout", [](const auto& req, auto& rep) { if (req.method == "GET") { http::server::httpRedirect(rep, "/login"); rep.headers.push_back({.name = "Set-Cookie", .value = http::auth::jwt::EMPTY_AUTH_COOKIE}); } else { http::server::stockReply(http::server::bad_request, rep); } })); s.resources.emplace_back(std::make_unique(FAVICON_ICO, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FAVICON_ICO, rep); })); s.resources.emplace_back(std::make_unique(STYLE_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(STYLE_CSS, rep); })); s.resources.emplace_back(std::make_unique(FIELDS_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FIELDS_CSS, rep); })); s.resources.emplace_back(std::make_unique(VUE_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(VUE_JS, rep); })); s.resources.emplace_back(std::make_unique(CHARTJS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(CHARTJS, rep); })); s.resources.emplace_back(std::make_unique(MOMENT_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(MOMENT_JS, rep); })); s.resources.emplace_back(std::make_unique(CHARTJS_ADAPTER_MOMENT, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(CHARTJS_ADAPTER_MOMENT, rep); })); s.resources.emplace_back(std::make_unique(INTERNET_JPG, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(INTERNET_JPG, rep); })); s.resources.emplace_back(std::make_unique("/api/get/statistics", this->auth, http::auth::User::WATCH_STATISTICS, [this](const auto& req, auto& rep) { if (req.method != "GET") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); std::string result = R"({"mainState":)"; result += api->loadTerminalState(); result += R"(,"sysinfo":)"; result += api->loadSysInfo(); result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); })); s.resources.emplace_back(std::make_unique("/api/get/settings", this->auth, http::auth::User::WATCH_SETTINGS, [this](const auto& req, auto& rep) { if (req.method != "GET") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); std::string result = R"({"settings":)"; result += api->loadSettings(); result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); })); s.resources.emplace_back(std::make_unique("/api/get/aboutFirmware", this->auth, 0, [this](const auto& req, auto& rep) { if (req.method != "GET") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); const auto result = api->loadFirmwareVersion(); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); })); s.resources.emplace_back(std::make_unique("/api/resetPacketStatistics", this->auth, http::auth::User::RESET_PACKET_STATISTICS, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } api->resetPacketStatistics(); rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); const std::string result = R"({"status":"ok")"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); })); s.resources.emplace_back(std::make_unique("/api/set/qos", this->auth, http::auth::User::SETUP_QOS, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); try { std::stringstream ss; ss.str(std::string(req.payload.begin(), req.payload.end())); boost::property_tree::ptree pt; read_json(ss, pt); api->setQosSettings(pt); std::string result = R"({"status":"ok","settings":)"; result += api->loadSettings(); result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/qos): Can't set QoS settings: " << e.what(); const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } })); s.resources.emplace_back(std::make_unique("/api/set/buclnb", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); try { std::stringstream ss; ss.str(std::string(req.payload.begin(), req.payload.end())); boost::property_tree::ptree pt; read_json(ss, pt); api->setBucLnbSettings(pt); std::string result = R"({"status":"ok","settings":)"; result += api->loadSettings(); result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/buclnb): Can't set BUC LNB settings: " << e.what(); const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } })); s.resources.emplace_back(std::make_unique("/api/set/dpdi", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); try { std::stringstream ss; ss.str(std::string(req.payload.begin(), req.payload.end())); boost::property_tree::ptree pt; read_json(ss, pt); api->setDpdiSettings(pt); std::string result = R"({"status":"ok","settings":)"; result += api->loadSettings(); result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/dpdi): Can't set DPDI settings: " << e.what(); const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } })); s.resources.emplace_back(std::make_unique("/api/set/rxtx", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); try { std::stringstream ss; ss.str(std::string(req.payload.begin(), req.payload.end())); boost::property_tree::ptree pt; read_json(ss, pt); api->setRxTxSettings(pt); std::string result = R"({"status":"ok","settings":)"; result += api->loadSettings(); result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what(); const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } })); s.resources.emplace_back(std::make_unique("/api/set/network", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); try { std::stringstream ss; ss.str(std::string(req.payload.begin(), req.payload.end())); boost::property_tree::ptree pt; read_json(ss, pt); api->setNetworkSettings(pt); std::string result = R"({"status":"ok","settings":)"; result += api->loadSettings(); result += "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/network): Can't set network settings: " << e.what(); const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); } })); s.resources.emplace_back(std::make_unique("/api/reboot", this->auth, 0, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); const std::string result = R"({"status":"ok"})"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); this->upgradeOrRebootRunning = true; system(REBOOT_COMMAND); })); s.resources.emplace_back(std::make_unique("/api/resetSettings", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); const std::string result = R"({"status":"ok"})"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); api->resetDefaultSettings(); system(REBOOT_COMMAND); })); s.resources.emplace_back(std::make_unique("/api/firmwareUpdate", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) { if (req.method != "PUT") { http::server::stockReply(http::server::bad_request, rep); return; } this->upgradeOrRebootRunning = true; onUploadFirmware(req); rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); std::string result = R"({"status":"ok","fwsize":)"; result += std::to_string(req.payload.size()); result += R"(,"sha256":")"; result += http::utils::sha256(req.payload.data(), req.payload.size()); result += "\"}"; rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); this->upgradeOrRebootRunning = false; })); s.resources.emplace_back(std::make_unique("/api/doFirmwareUpgrade", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } this->upgradeOrRebootRunning = true; #ifdef MODEM_IS_TDMA if (req.url->params.find("ota") != req.url->params.end()) { doTerminalUpgradeOta(); } else { doTerminalUpgrade(); } #else doTerminalUpgrade(); #endif rep.status = http::server::ok; rep.headers.clear(); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); const auto result = api->loadFirmwareVersion(); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); })); s.resources.emplace_back(std::make_unique("/dev", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(DEV_HTML, rep); })); s.resources.emplace_back(std::make_unique("/dev/cpapicall", this->auth, http::auth::User::DEVELOPER, [this](const http::server::Request& req, auto& rep) { if (req.method != "POST") { http::server::stockReply(http::server::bad_request, rep); return; } if (req.url->params.find("f") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; } const auto func = req.url->params["f"]; std::string result = R"({"status":"ok"})"; if (func == "SetDmaDebug") { if (req.url->params.find("param") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; } if (req.url->params.find("value") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; } this->api->executeInApi([&](auto sid) { CP_SetDmaDebug(sid, req.url->params["param"].c_str(), req.url->params["value"]); }); } else if (func == "GetDmaDebug") { if (req.url->params.find("param") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; } this->api->executeInApi([&](auto sid) { std::string tmp{}; CP_GetDmaDebug(sid, req.url->params["param"].c_str(), &tmp); result = R"({"status":"ok","result":)"; result += api_driver::buildEscapedString(tmp); result += "}"; }); } else { http::server::stockReply(http::server::not_implemented, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); })); #ifdef MODEM_IS_SCPC s.resources.emplace_back(std::make_unique("/dev/settings", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) { std::string result; if (req.method == "GET") { result = R"({"status":"ok","logstat":)"; result += this->api->getLoggingStatisticsSettings(); result += "}"; } else if (req.method == "POST") { std::stringstream ss; ss.str(std::string(req.payload.begin(), req.payload.end())); boost::property_tree::ptree pt; read_json(ss, pt); api->setLoggingStatisticsSettings(pt); result = R"({"status":"ok","logstat":)"; result += this->api->getLoggingStatisticsSettings(); result += "}"; } else { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); })); s.resources.emplace_back(std::make_unique("/dev/logs.csv", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) { if (req.method != "GET") { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::ok; rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_plain)}); rep.content.clear(); http::resource::loadFile("/tmp/weblog-statistics.csv", rep.content); })); #endif } ~ServerResources() = default; }; int main(int argc, char *argv[]) { try { prctl(PR_SET_NAME, "main", 0, 0, 0); // Check command line arguments. if (argc != 4 && argc != 5) { std::cerr << "Usage: http_server
[static files directory]\n"; std::cerr << " For IPv4, try:\n"; std::cerr << " receiver nossl 0.0.0.0 80 .\n"; std::cerr << " For IPv6, try:\n"; std::cerr << " receiver nossl 0::0 80 .\n"; return 1; } if (strcmp(argv[1], "nossl") != 0 && strcmp(argv[1], "ssl") != 0) { std::cerr << "Unsupported ssl mode: " << argv[1] << std::endl; return 1; } int serverPort; try { size_t idx = 0; serverPort = std::stoi(std::string(argv[3]), &idx); if (serverPort < 0 || serverPort > 0xffff) { throw std::invalid_argument("Out of range"); } if (idx != strlen(argv[3])) { throw std::invalid_argument("Invalid number"); } } catch (std::exception& e) { std::cerr << "Wrong server port `" << argv[3] << "`: " << e.what() << std::endl; return 1; } init_logging(); boost::log::core::get()->add_thread_attribute("Scope", boost::log::attributes::named_scope()); #ifdef USE_DEBUG BOOST_LOG_TRIVIAL(info) << "Starting DEBUG " << argv[0]; #else BOOST_LOG_TRIVIAL(info) << "Starting RELEASE " << argv[0]; #endif BOOST_LOG_TRIVIAL(info) << ("Build time: " PROJECT_BUILD_TIME); BOOST_LOG_TRIVIAL(info) << ("Git version: " PROJECT_GIT_REVISION); #ifdef USE_DEBUG http::auth::jwt::secretKey = "^}u'ZKyQ%;+:lnh^GS7!=G~nRK?7[{``"; BOOST_LOG_TRIVIAL(info) << "DEBUG build use pre-created key " << http::auth::jwt::secretKey; #else http::auth::jwt::generateSecretKey(); BOOST_LOG_TRIVIAL(info) << "Generated new secret key " << http::auth::jwt::secretKey; #endif const std::string staticFilesPath = (argc == 5 ? argv[4]: "."); BOOST_LOG_TRIVIAL(info) << "Use static files path: " << staticFilesPath << "/"; ServerResources resources(staticFilesPath); // Initialise the server. std::unique_ptr s; if (strcmp(argv[1], "nossl") == 0) { BOOST_LOG_TRIVIAL(info) << "Run server on " << argv[2] << ":" << serverPort; s = std::make_unique(argv[2], serverPort); resources.registerResources(*s); s->run(); } else { std::vector cert; http::resource::loadFile("cert.pem", cert); std::vector key; http::resource::loadFile("key.pem", key); std::vector dh; http::resource::loadFile("dh.pem", dh); auto ctx = std::make_shared(ssl::context::tlsv12); ctx->set_password_callback( [](std::size_t, ssl::context_base::password_purpose) { return "test"; }); ctx->set_options(ssl::context::default_workarounds | ssl::context::no_sslv2 | ssl::context::single_dh_use); ctx->use_certificate_chain(boost::asio::buffer(cert)); ctx->use_private_key(boost::asio::buffer(key), ssl::context::file_format::pem); ctx->use_tmp_dh(boost::asio::buffer(dh)); BOOST_LOG_TRIVIAL(info) << "Run server on " << argv[2] << ":" << serverPort; s = std::make_unique(argv[2], serverPort, ctx); resources.registerResources(*s); s->run(); } } catch (std::exception &e) { BOOST_LOG_TRIVIAL(error) << e.what() << std::endl; return -1; } return 0; }