xref: /openbmc/bmcweb/src/webserver_main.cpp (revision 3dac749b85f04453d594764d59cef9015c731cdd)
1 #include <boost/asio.hpp>
2 #include <boost/container/flat_map.hpp>
3 #include <boost/container/stable_vector.hpp>
4 
5 #include "crow/app.h"
6 #include "crow/ci_map.h"
7 #include "crow/common.h"
8 #include "crow/dumb_timer_queue.h"
9 #include "crow/http_connection.h"
10 #include "crow/http_parser_merged.h"
11 #include "crow/http_request.h"
12 #include "crow/http_response.h"
13 #include "crow/http_server.h"
14 #include "crow/logging.h"
15 #include "crow/middleware.h"
16 #include "crow/middleware_context.h"
17 #include "crow/mustache.h"
18 #include "crow/parser.h"
19 #include "crow/query_string.h"
20 #include "crow/routing.h"
21 #include "crow/settings.h"
22 #include "crow/socket_adaptors.h"
23 #include "crow/utility.h"
24 #include "crow/websocket.h"
25 
26 #include "redfish_v1.hpp"
27 #include "security_headers_middleware.hpp"
28 #include "ssl_key_handler.hpp"
29 #include "token_authorization_middleware.hpp"
30 #include "web_kvm.hpp"
31 #include "webassets.hpp"
32 
33 #include "nlohmann/json.hpp"
34 
35 #include <dbus/connection.hpp>
36 #include <dbus/endpoint.hpp>
37 #include <dbus/filter.hpp>
38 #include <dbus/match.hpp>
39 #include <dbus/message.hpp>
40 
41 #include <chrono>
42 #include <iostream>
43 #include <memory>
44 #include <string>
45 #include <unordered_set>
46 
47 static std::shared_ptr<dbus::connection> system_bus;
48 static std::vector<dbus::match> dbus_matches;
49 static std::shared_ptr<dbus::filter> sensor_filter;
50 
51 struct DbusWebsocketSession {
52   std::vector<dbus::match> matches;
53   std::vector<dbus::filter> filters;
54 };
55 
56 static boost::container::flat_map<crow::websocket::connection*,
57                                   DbusWebsocketSession>
58     sessions;
59 
60 void on_property_update(dbus::filter& filter, boost::system::error_code ec,
61                         dbus::message s) {
62   std::string object_name;
63   std::vector<std::pair<std::string, dbus::dbus_variant>> values;
64   s.unpack(object_name).unpack(values);
65   nlohmann::json j;
66   for (auto& value : values) {
67     boost::apply_visitor([&](auto val) { j[s.get_path()] = val; },
68                          value.second);
69   }
70   auto data_to_send = j.dump();
71 
72   for (auto& session : sessions) {
73     session.first->send_text(data_to_send);
74   }
75   filter.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
76     on_property_update(filter, ec, s);;
77   });
78 };
79 
80 int main(int argc, char** argv) {
81   // Build an io_service (there should only be 1)
82   auto io = std::make_shared<boost::asio::io_service>();
83 
84   bool enable_ssl = true;
85   std::string ssl_pem_file("server.pem");
86 
87   if (enable_ssl) {
88     ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
89   }
90 
91   crow::App<
92       /*crow::TokenAuthorizationMiddleware, */ crow::SecurityHeadersMiddleware>
93       app(io);
94 
95   crow::webassets::request_routes(app);
96   crow::kvm::request_routes(app);
97   crow::redfish::request_routes(app);
98 
99   crow::logger::setLogLevel(crow::LogLevel::INFO);
100 
101   CROW_ROUTE(app, "/dbus_monitor")
102       .websocket()
103       .onopen([&](crow::websocket::connection& conn) {
104         sessions[&conn] = DbusWebsocketSession();
105 
106         sessions[&conn].matches.emplace_back(
107             system_bus,
108             "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
109 
110         sessions[&conn].filters.emplace_back(system_bus, [](dbus::message m) {
111           auto member = m.get_member();
112           return member == "PropertiesChanged";
113         });
114         auto& this_filter = sessions[&conn].filters.back();
115         this_filter.async_dispatch(
116             [&](boost::system::error_code ec, dbus::message s) {
117               on_property_update(this_filter, ec, s);;
118             });
119 
120       })
121       .onclose(
122           [&](crow::websocket::connection& conn, const std::string& reason) {
123             sessions.erase(&conn);
124 
125           })
126       .onmessage([&](crow::websocket::connection& conn, const std::string& data,
127                      bool is_binary) {
128         CROW_LOG_ERROR << "Got unexpected message from client on sensorws";
129       });
130 
131   CROW_ROUTE(app, "/intel/firmwareupload")
132       .methods("POST"_method)([](const crow::request& req) {
133         auto filepath = "/tmp/fw_update_image";
134         std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
135                                         std::ofstream::trunc);
136         out << req.body;
137         out.close();
138 
139         nlohmann::json j;
140         j["status"] = "Upload Successfull";
141 
142         dbus::endpoint fw_update_endpoint(
143             "xyz.openbmc_project.fwupdate1.server",
144             "/xyz/openbmc_project/fwupdate1", "xyz.openbmc_project.fwupdate1");
145 
146         auto m = dbus::message::new_call(fw_update_endpoint, "start");
147 
148         m.pack(std::string("file://") + filepath);
149         system_bus->send(m);
150 
151         return j;
152       });
153 
154   crow::logger::setLogLevel(crow::LogLevel::DEBUG);
155   auto test = app.get_routes();
156   app.debug_print();
157   std::cout << "Building SSL context\n";
158 
159   int port = 18080;
160 
161   std::cout << "Starting webserver on port " << port << "\n";
162   app.port(port);
163   if (enable_ssl) {
164     std::cout << "SSL Enabled\n";
165     auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
166     app.ssl(std::move(ssl_context));
167   }
168   // app.concurrency(4);
169 
170   // Start dbus connection
171   system_bus = std::make_shared<dbus::connection>(*io, dbus::bus::system);
172 
173   app.run();
174 }
175