diff options
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | crow/include/crow/http_response.h | 8 | ||||
-rw-r--r-- | crow/include/crow/http_server.h | 1 | ||||
-rw-r--r-- | crow/include/crow/websocket.h | 5 | ||||
-rw-r--r-- | include/pam_authenticate.hpp | 65 | ||||
-rw-r--r-- | include/security_headers_middleware.hpp | 37 | ||||
-rw-r--r-- | include/token_authorization_middleware.hpp | 130 | ||||
-rw-r--r-- | src/ast_video_puller_test.cpp | 2 | ||||
-rw-r--r-- | src/getvideo_main.cpp | 2 | ||||
-rw-r--r-- | src/security_headers_middleware.cpp | 39 | ||||
-rw-r--r-- | src/token_authorization_middleware.cpp | 192 | ||||
-rw-r--r-- | src/token_authorization_middleware_test.cpp | 13 | ||||
-rw-r--r-- | src/webserver_main.cpp | 91 |
13 files changed, 290 insertions, 299 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index db4df434e6..1c4435eec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,8 @@ HunterGate( project(bmc-webserver CXX C) +include( CTest ) + set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -184,8 +186,6 @@ endif() set(SRC_FILES - src/token_authorization_middleware.cpp - src/security_headers_middleware.cpp src/base64.cpp ${GENERATED_SRC_FILES} ) diff --git a/crow/include/crow/http_response.h b/crow/include/crow/http_response.h index c81446fb3d..07493bc3bf 100644 --- a/crow/include/crow/http_response.h +++ b/crow/include/crow/http_response.h @@ -47,18 +47,18 @@ struct response { } response(response&& r) { - CROW_LOG_WARNING << "Moving response containers"; + CROW_LOG_DEBUG << "Moving response containers"; *this = std::move(r); } ~response(){ - CROW_LOG_WARNING << "Destroying response"; + CROW_LOG_DEBUG << "Destroying response"; } response& operator=(const response& r) = delete; response& operator=(response&& r) noexcept { - CROW_LOG_WARNING << "Moving response containers"; + CROW_LOG_DEBUG << "Moving response containers"; body = std::move(r.body); json_value = std::move(r.json_value); code = r.code; @@ -70,7 +70,7 @@ struct response { bool is_completed() const noexcept { return completed_; } void clear() { - CROW_LOG_WARNING << "Clearing response containers"; + CROW_LOG_DEBUG << "Clearing response containers"; body.clear(); json_value.clear(); code = 200; diff --git a/crow/include/crow/http_server.h b/crow/include/crow/http_server.h index 2ead557a73..5ed2927635 100644 --- a/crow/include/crow/http_server.h +++ b/crow/include/crow/http_server.h @@ -113,7 +113,6 @@ class Server { timer.async_wait(handler); }; timer.async_wait(handler); - CROW_LOG_INFO << init_count; init_count++; try { io_service_pool_[i]->run(); diff --git a/crow/include/crow/websocket.h b/crow/include/crow/websocket.h index f29f13be1e..65a5836a36 100644 --- a/crow/include/crow/websocket.h +++ b/crow/include/crow/websocket.h @@ -18,6 +18,7 @@ struct connection { virtual void send_binary(const std::string& msg) = 0; virtual void send_text(const std::string& msg) = 0; virtual void close(const std::string& msg = "quit") = 0; + virtual boost::asio::io_service& get_io_service() = 0; virtual ~connection() {} void userdata(void* u) { userdata_ = u; } @@ -70,6 +71,10 @@ class Connection : public connection { adaptor_.get_io_service().post(handler); } + boost::asio::io_service& get_io_service(){ + return adaptor_.get_io_service(); + } + void send_pong(const std::string& msg) { dispatch([this, msg] { char buf[3] = "\x8A\x00"; diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp new file mode 100644 index 0000000000..153dbc74fc --- /dev/null +++ b/include/pam_authenticate.hpp @@ -0,0 +1,65 @@ +#include <security/pam_appl.h> + +// function used to get user input +inline int pam_function_conversation(int num_msg, + const struct pam_message** msg, + struct pam_response** resp, + void* appdata_ptr) { + char* pass = (char*)malloc(strlen((char*)appdata_ptr) + 1); + strcpy(pass, (char*)appdata_ptr); + + int i; + + *resp = (pam_response*)calloc(num_msg, sizeof(struct pam_response)); + + for (i = 0; i < num_msg; ++i) { + /* Ignore all PAM messages except prompting for hidden input */ + if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) continue; + + /* Assume PAM is only prompting for the password as hidden input */ + resp[i]->resp = pass; + } + + return PAM_SUCCESS; +} + +class PamAuthenticator { + public: + inline bool authenticate(const std::string& username, + const std::string& password) { + const struct pam_conv local_conversation = {pam_function_conversation, + (char*)password.c_str()}; + pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start + + int retval; + retval = pam_start("su", username.c_str(), &local_conversation, + &local_auth_handle); + + if (retval != PAM_SUCCESS) { + //printf("pam_start returned: %d\n ", retval); + return false; + } + + retval = pam_authenticate(local_auth_handle, + PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); + + if (retval != PAM_SUCCESS) { + if (retval == PAM_AUTH_ERR) { + //printf("Authentication failure.\n"); + } else { + //printf("pam_authenticate returned %d\n", retval); + } + return false; + } + + //printf("Authenticated.\n"); + retval = pam_end(local_auth_handle, retval); + + if (retval != PAM_SUCCESS) { + //printf("pam_end returned\n"); + return false; + } + + return true; + } +};
\ No newline at end of file diff --git a/include/security_headers_middleware.hpp b/include/security_headers_middleware.hpp index 7e8454365a..19644f45bd 100644 --- a/include/security_headers_middleware.hpp +++ b/include/security_headers_middleware.hpp @@ -4,12 +4,45 @@ #include <crow/http_response.h> namespace crow { +static const std::string strict_transport_security_key = + "Strict-Transport-Security"; +static const std::string strict_transport_security_value = + "max-age=31536000; includeSubdomains; preload"; + +static const std::string ua_compatability_key = "X-UA-Compatible"; +static const std::string ua_compatability_value = "IE=11"; + +static const std::string xframe_key = "X-Frame-Options"; +static const std::string xframe_value = "DENY"; + +static const std::string xss_key = "X-XSS-Protection"; +static const std::string xss_value = "1; mode=block"; + +static const std::string content_security_key = "X-Content-Security-Policy"; +static const std::string content_security_value = "default-src 'self'"; + struct SecurityHeadersMiddleware { struct context {}; - void before_handle(crow::request& req, response& res, context& ctx); + void before_handle(crow::request& req, + response& res, + context& ctx) {} - void after_handle(request& req, response& res, context& ctx); + void after_handle(request& /*req*/, + response& res, + context& ctx) { + /* + TODO(ed) these should really check content types. for example, + X-UA-Compatible header doesn't make sense when retrieving a JSON or + javascript file. It doesn't hurt anything, it's just ugly. + */ + res.add_header(strict_transport_security_key, + strict_transport_security_value); + res.add_header(ua_compatability_key, ua_compatability_value); + res.add_header(xframe_key, xframe_value); + res.add_header(xss_key, xss_value); + res.add_header(content_security_key, content_security_value); + } }; }
\ No newline at end of file diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp index 214fd93ab6..d333e6ce46 100644 --- a/include/token_authorization_middleware.hpp +++ b/include/token_authorization_middleware.hpp @@ -4,25 +4,145 @@ #include <crow/http_response.h> #include <boost/container/flat_set.hpp> +#include <base64.hpp> + +#include <pam_authenticate.hpp> + namespace crow { struct User {}; -struct TokenAuthorizationMiddleware { +using random_bytes_engine = + std::independent_bits_engine<std::default_random_engine, CHAR_BIT, + unsigned char>; + +template <class AuthenticationFunction> +struct TokenAuthorization { // TODO(ed) auth_token shouldn't really be passed to the context // it opens the possibility of exposure by and endpoint. // instead we should only pass some kind of "user" struct struct context { - //std::string auth_token; + // std::string auth_token; }; - TokenAuthorizationMiddleware(); + TokenAuthorization(){}; + + void before_handle(crow::request& req, response& res, context& ctx) { + auto return_unauthorized = [&req, &res]() { + res.code = 401; + res.end(); + }; + + auto return_bad_request = [&req, &res]() { + res.code = 400; + res.end(); + }; + + auto return_internal_error = [&req, &res]() { + res.code = 500; + res.end(); + }; + + if (req.url == "/" || boost::starts_with(req.url, "/static/")) { + // TODO this is total hackery to allow the login page to work before the + // user is authenticated. Also, it will be quite slow for all pages + // instead + // of a one time hit for the whitelist entries. Ideally, this should be + // done in the url router handler, with tagged routes for the whitelist + // entries. Another option would be to whitelist a minimal for based page + // that didn't + // load the full angular UI until after login + return; + } + + if (req.url == "/login") { + if (req.method != HTTPMethod::POST) { + return_unauthorized(); + return; + } else { + auto login_credentials = crow::json::load(req.body); + if (!login_credentials) { + return_bad_request(); + return; + } + if (!login_credentials.has("username") || + !login_credentials.has("password")) { + return_bad_request(); + return; + } + auto username = login_credentials["username"].s(); + auto password = login_credentials["password"].s(); + auto p = AuthenticationFunction(); + if (p.authenticate(username, password)) { + crow::json::wvalue x; - void before_handle(crow::request& req, response& res, context& ctx); + // TODO(ed) the RNG should be initialized at start, not every time we + // want a token + std::random_device rand; + random_bytes_engine rbe; + std::string token('a', 20); + // TODO(ed) for some reason clang-tidy finds a divide by zero error in + // cstdlibc here commented out for now. Needs investigation + std::generate(std::begin(token), std::end(token), std::ref(rbe)); // NOLINT + std::string encoded_token; + base64::base64_encode(token, encoded_token); + // ctx.auth_token = encoded_token; + this->auth_token2.insert(encoded_token); - void after_handle(request& req, response& res, context& ctx); + x["token"] = encoded_token; + + res.write(json::dump(x)); + res.add_header("Content-Type", "application/json"); + res.end(); + } else { + return_unauthorized(); + return; + } + } + + } else { // Normal, non login, non static file request + // Check to make sure we're logged in + if (this->auth_token2.empty()) { + return_unauthorized(); + return; + } + // Check for an authorization header, reject if not present + if (req.headers.count("Authorization") != 1) { + return_unauthorized(); + return; + } + + std::string auth_header = req.get_header_value("Authorization"); + // If the user is attempting any kind of auth other than token, reject + if (!boost::starts_with(auth_header, "Token ")) { + return_unauthorized(); + return; + } + std::string auth_key = auth_header.substr(6); + // TODO(ed), use span here instead of constructing a new string + if (this->auth_token2.find(auth_key) == this->auth_token2.end()) { + return_unauthorized(); + return; + } + + if (req.url == "/logout") { + this->auth_token2.erase(auth_key); + res.code = 200; + res.end(); + return; + } + + // else let the request continue unharmed + } + } + + void after_handle(request& req, response& res, context& ctx) { + // Do nothing + } private: boost::container::flat_set<std::string> auth_token2; }; + +using TokenAuthorizationMiddleware = TokenAuthorization<PamAuthenticator>; }
\ No newline at end of file diff --git a/src/ast_video_puller_test.cpp b/src/ast_video_puller_test.cpp index ef1cbe3b6d..b1f94e7579 100644 --- a/src/ast_video_puller_test.cpp +++ b/src/ast_video_puller_test.cpp @@ -14,7 +14,6 @@ #include <gtest/gtest.h> TEST(AstvideoPuller, BasicRead) { - std::cout << "Started\n"; AstVideo::RawVideoBuffer out; bool have_hardware = false; if (access("/dev/video", F_OK) != -1) { @@ -43,7 +42,6 @@ TEST(AstvideoPuller, BasicRead) { fwrite(out.buffer.data(), sizeof(char), out.buffer.size(), fp); AstVideo::AstJpegDecoder d; - std::cout << "MODE " << static_cast<int>(out.mode); d.decode(out.buffer, out.width, out.height, out.mode, out.y_selector, out.uv_selector); } diff --git a/src/getvideo_main.cpp b/src/getvideo_main.cpp index 33885ee117..2ab0c0e0c9 100644 --- a/src/getvideo_main.cpp +++ b/src/getvideo_main.cpp @@ -20,7 +20,6 @@ #include <ast_video_puller.hpp> int main() { - std::cout << "Started\n"; AstVideo::RawVideoBuffer out; bool have_hardware = false; if (access("/dev/video", F_OK) != -1) { @@ -49,7 +48,6 @@ int main() { fwrite(out.buffer.data(), sizeof(char), out.buffer.size(), fp); AstVideo::AstJpegDecoder d; - std::cout << "MODE " << static_cast<int>(out.mode); d.decode(out.buffer, out.width, out.height, out.mode, out.y_selector, out.uv_selector); #ifdef BUILD_CIMG diff --git a/src/security_headers_middleware.cpp b/src/security_headers_middleware.cpp deleted file mode 100644 index 265cda72a7..0000000000 --- a/src/security_headers_middleware.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include <security_headers_middleware.hpp> - -namespace crow { - -static const std::string strict_transport_security_key = - "Strict-Transport-Security"; -static const std::string strict_transport_security_value = - "max-age=31536000; includeSubdomains; preload"; - -static const std::string ua_compatability_key = "X-UA-Compatible"; -static const std::string ua_compatability_value = "IE=11"; - -static const std::string xframe_key = "X-Frame-Options"; -static const std::string xframe_value = "DENY"; - -static const std::string xss_key = "X-XSS-Protection"; -static const std::string xss_value = "1; mode=block"; - -static const std::string content_security_key = "X-Content-Security-Policy"; -static const std::string content_security_value = "default-src 'self'"; - -void SecurityHeadersMiddleware::before_handle(crow::request& req, response& res, - context& ctx) {} - -void SecurityHeadersMiddleware::after_handle(request& /*req*/, response& res, - context& ctx) { - /* - TODO(ed) these should really check content types. for example, - X-UA-Compatible header doesn't make sense when retrieving a JSON or - javascript file. It doesn't hurt anything, it's just ugly. - */ - res.add_header(strict_transport_security_key, - strict_transport_security_value); - res.add_header(ua_compatability_key, ua_compatability_value); - res.add_header(xframe_key, xframe_value); - res.add_header(xss_key, xss_value); - res.add_header(content_security_key, content_security_value); -} -} diff --git a/src/token_authorization_middleware.cpp b/src/token_authorization_middleware.cpp deleted file mode 100644 index 508bfd982c..0000000000 --- a/src/token_authorization_middleware.cpp +++ /dev/null @@ -1,192 +0,0 @@ -#include <random> -#include <unordered_map> -#include <boost/algorithm/string/predicate.hpp> - -#include <security/pam_appl.h> -#include <base64.hpp> -#include <token_authorization_middleware.hpp> -#include <crow/logging.h> - -namespace crow { - -using random_bytes_engine = - std::independent_bits_engine<std::default_random_engine, CHAR_BIT, - unsigned char>; - -// function used to get user input -int pam_function_conversation(int num_msg, const struct pam_message** msg, - struct pam_response** resp, void* appdata_ptr) { - char* pass = (char*)malloc(strlen((char*)appdata_ptr) + 1); - strcpy(pass, (char*)appdata_ptr); - - int i; - - *resp = (pam_response*)calloc(num_msg, sizeof(struct pam_response)); - - for (i = 0; i < num_msg; ++i) { - /* Ignore all PAM messages except prompting for hidden input */ - if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) continue; - - /* Assume PAM is only prompting for the password as hidden input */ - resp[i]->resp = pass; - } - - return PAM_SUCCESS; -} - -bool authenticate_user_pam(const std::string& username, - const std::string& password) { - const struct pam_conv local_conversation = {pam_function_conversation, - (char*)password.c_str()}; - pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start - - int retval; - retval = pam_start("su", username.c_str(), &local_conversation, - &local_auth_handle); - - if (retval != PAM_SUCCESS) { - printf("pam_start returned: %d\n ", retval); - return false; - } - - retval = pam_authenticate(local_auth_handle, - PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); - - if (retval != PAM_SUCCESS) { - if (retval == PAM_AUTH_ERR) { - printf("Authentication failure.\n"); - } else { - printf("pam_authenticate returned %d\n", retval); - } - return false; - } - - printf("Authenticated.\n"); - retval = pam_end(local_auth_handle, retval); - - if (retval != PAM_SUCCESS) { - printf("pam_end returned\n"); - return false; - } - - return true; -} - -TokenAuthorizationMiddleware::TokenAuthorizationMiddleware(){ -}; - -void TokenAuthorizationMiddleware::before_handle(crow::request& req, - response& res, context& ctx) { - auto return_unauthorized = [&req, &res]() { - res.code = 401; - res.end(); - }; - - auto return_bad_request = [&req, &res]() { - res.code = 400; - res.end(); - }; - - auto return_internal_error = [&req, &res]() { - res.code = 500; - res.end(); - }; - - if (req.url == "/" || boost::starts_with(req.url, "/static/")) { - // TODO this is total hackery to allow the login page to work before the - // user is authenticated. Also, it will be quite slow for all pages instead - // of a one time hit for the whitelist entries. Ideally, this should be - // done in the url router handler, with tagged routes for the whitelist - // entries. Another option would be to whitelist a minimal for based page - // that didn't - // load the full angular UI until after login - return; - } - - if (req.url == "/login") { - if (req.method != HTTPMethod::POST) { - return_unauthorized(); - return; - } else { - auto login_credentials = crow::json::load(req.body); - if (!login_credentials) { - return_bad_request(); - return; - } - if (!login_credentials.has("username") || - !login_credentials.has("password")) { - return_bad_request(); - return; - } - auto username = login_credentials["username"].s(); - auto password = login_credentials["password"].s(); - - // TODO(ed) pull real passwords from PAM - if (authenticate_user_pam(username, password)) { - crow::json::wvalue x; - - // TODO(ed) the RNG should be initialized at start, not every time we - // want a token - std::random_device rand; - random_bytes_engine rbe; - std::string token('a', 20); - // TODO(ed) for some reason clang-tidy finds a divide by zero error in - // cstdlibc here commented out for now. Needs investigation - std::generate(begin(token), end(token), std::ref(rbe)); // NOLINT - std::string encoded_token; - base64::base64_encode(token, encoded_token); - // ctx.auth_token = encoded_token; - this->auth_token2.insert(encoded_token); - - x["token"] = encoded_token; - - res.write(json::dump(x)); - res.add_header("Content-Type", "application/json"); - res.end(); - } else { - return_unauthorized(); - return; - } - } - - } else { // Normal, non login, non static file request - // Check to make sure we're logged in - if (this->auth_token2.empty()) { - return_unauthorized(); - return; - } - // Check for an authorization header, reject if not present - if (req.headers.count("Authorization") != 1) { - return_unauthorized(); - return; - } - - std::string auth_header = req.get_header_value("Authorization"); - // If the user is attempting any kind of auth other than token, reject - if (!boost::starts_with(auth_header, "Token ")) { - return_unauthorized(); - return; - } - std::string auth_key = auth_header.substr(6); - // TODO(ed), use span here instead of constructing a new string - if (this->auth_token2.find(auth_key) == this->auth_token2.end()) { - return_unauthorized(); - return; - } - - if (req.url == "/logout") { - this->auth_token2.erase(auth_key); - res.code = 200; - res.end(); - return; - } - - // else let the request continue unharmed - } -} - -void TokenAuthorizationMiddleware::after_handle(request& req, response& res, - context& ctx) { - // Do nothing -} -} diff --git a/src/token_authorization_middleware_test.cpp b/src/token_authorization_middleware_test.cpp index e82776533e..49933c9954 100644 --- a/src/token_authorization_middleware_test.cpp +++ b/src/token_authorization_middleware_test.cpp @@ -6,6 +6,14 @@ using namespace crow; using namespace std; +class KnownLoginAuthenticator { + public: + inline bool authenticate(const std::string& username, + const std::string& password) { + return (username == "dude") && (password == "foo"); + } +}; + // Tests that static urls are correctly passed TEST(TokenAuthentication, TestBasicReject) { App<crow::TokenAuthorizationMiddleware> app; @@ -177,9 +185,8 @@ TEST(TokenAuthentication, TestPostBadLoginUrl) { app.stop(); } -// Tests boundary conditions on login TEST(TokenAuthentication, TestSuccessfulLogin) { - App<crow::TokenAuthorizationMiddleware> app; + App<crow::TokenAuthorization<KnownLoginAuthenticator>> app; app.bindaddr("127.0.0.1").port(45451); CROW_ROUTE(app, "/")([]() { return 200; }); auto _ = async(launch::async, [&] { app.run(); }); @@ -215,7 +222,7 @@ TEST(TokenAuthentication, TestSuccessfulLogin) { // Test correct login credentials sendmsg = "POST /login\r\nContent-Length:40\r\n\r\n{\"username\": \"dude\", " - "\"password\": \"dude\"}\r\n"; + "\"password\": \"foo\"}\r\n"; { send_to_localhost(sendmsg); std::string response(std::begin(buf), std::end(buf)); diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp index 0c173dd947..3baf388a24 100644 --- a/src/webserver_main.cpp +++ b/src/webserver_main.cpp @@ -246,9 +246,20 @@ int main(int argc, char** argv) { return j; }); - CROW_ROUTE(app, "/ipmiws") + CROW_ROUTE(app, "/sensorws") .websocket() .onopen([&](crow::websocket::connection& conn) { + dbus::connection system_bus(conn.get_io_service(), dbus::bus::system); + dbus::match ma(system_bus, + "type='signal',sender='org.freedesktop.DBus', " + "interface='org.freedesktop.DBus.Properties',member=" + "'PropertiesChanged'"); + dbus::filter f(system_bus, [](dbus::message& m) { return true; }); + + f.async_dispatch([&](boost::system::error_code ec, dbus::message s) { + std::cout << "got event\n"; + //f.async_dispatch(event_handler); + }); }) .onclose( @@ -257,57 +268,43 @@ int main(int argc, char** argv) { }) .onmessage([&](crow::websocket::connection& conn, const std::string& data, bool is_binary) { - boost::asio::io_service io_service; - using boost::asio::ip::udp; - udp::resolver resolver(io_service); - udp::resolver::query query(udp::v4(), "10.243.48.31", "623"); - udp::endpoint receiver_endpoint = *resolver.resolve(query); - - udp::socket socket(io_service); - socket.open(udp::v4()); - - socket.send_to(boost::asio::buffer(data), receiver_endpoint); - - std::array<char, 255> recv_buf; - - udp::endpoint sender_endpoint; - size_t len = - socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint); - // TODO(ed) THis is ugly. Find a way to not make a copy (ie, use - // std::string::data() to - std::string str(std::begin(recv_buf), std::end(recv_buf)); - LOG(DEBUG) << "Got " << str << "back \n"; - conn.send_binary(str); }); CROW_ROUTE(app, "/sensortest") ([](const crow::request& req, crow::response& res) { - dbus::connection system_bus(*req.io_service, dbus::bus::system); - - dbus::endpoint test_daemon("org.freedesktop.DBus", "/", - "org.freedesktop.DBus"); - dbus::message m = dbus::message::new_call(test_daemon, "ListNames"); - system_bus.async_send(m, [&](const boost::system::error_code ec, - dbus::message r) { - std::vector<std::string> services; - //r.unpack(services); - for (auto& service : services) { - dbus::endpoint service_daemon(service, "/", - "org.freedesktop.DBus.Introspectable"); - dbus::message m = dbus::message::new_call(service_daemon, "Introspect"); - system_bus.async_send( - m, [&](const boost::system::error_code ec, dbus::message r) { - std::string xml; - r.unpack(xml); - std::vector<std::string> dbus_objects; - dbus::read_dbus_xml_names(xml, dbus_objects); - - - }); - } + crow::json::wvalue j; + auto values = read_sensor_values(); - }); + dbus::connection system_bus(*req.io_service, dbus::bus::system); + dbus::endpoint test_daemon("org.openbmc.Sensors", + "/org/openbmc/sensors/tach", + "org.freedesktop.DBus.Introspectable"); + dbus::message m = dbus::message::new_call(test_daemon, "Introspect"); + system_bus.async_send( + m, + [&j, &system_bus](const boost::system::error_code ec, dbus::message r) { + std::string xml; + r.unpack(xml); + std::vector<std::string> dbus_objects; + dbus::read_dbus_xml_names(xml, dbus_objects); + + for (auto& object : dbus_objects) { + dbus::endpoint test_daemon("org.openbmc.Sensors", + "/org/openbmc/sensors/tach/" + object, + "org.openbmc.SensorValue"); + dbus::message m2 = dbus::message::new_call(test_daemon, "getValue"); + + system_bus.async_send( + m2, [&](const boost::system::error_code ec, dbus::message r) { + int32_t value; + r.unpack(value); + // TODO(ed) if we ever go multithread, j needs a lock + j[object] = value; + }); + } + + }); }); @@ -337,6 +334,6 @@ int main(int argc, char** argv) { auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file); app.ssl(std::move(ssl_context)); } - app.concurrency(4); + //app.concurrency(4); app.run(); } |