xref: /openbmc/bmcweb/src/webserver_main.cpp (revision 4d92cbfe32ef6ee24547401cc06994baa84a24aa)
1 #include "crow/app.h"
2 #include "crow/ci_map.h"
3 #include "crow/common.h"
4 #include "crow/dumb_timer_queue.h"
5 #include "crow/http_connection.h"
6 #include "crow/http_parser_merged.h"
7 #include "crow/http_request.h"
8 #include "crow/http_response.h"
9 #include "crow/http_server.h"
10 #include "crow/json.h"
11 #include "crow/logging.h"
12 #include "crow/middleware.h"
13 #include "crow/middleware_context.h"
14 #include "crow/mustache.h"
15 #include "crow/parser.h"
16 #include "crow/query_string.h"
17 #include "crow/routing.h"
18 #include "crow/settings.h"
19 #include "crow/socket_adaptors.h"
20 #include "crow/utility.h"
21 #include "crow/websocket.h"
22 
23 #include "security_headers_middleware.hpp"
24 #include "ssl_key_handler.hpp"
25 #include "token_authorization_middleware.hpp"
26 #include "web_kvm.hpp"
27 #include "webassets.hpp"
28 
29 #include <boost/asio.hpp>
30 #include <boost/endian/arithmetic.hpp>
31 
32 #include <dbus/connection.hpp>
33 #include <dbus/endpoint.hpp>
34 #include <dbus/filter.hpp>
35 #include <dbus/match.hpp>
36 #include <dbus/message.hpp>
37 #include <dbus/utility.hpp>
38 
39 #include <iostream>
40 #include <memory>
41 #include <string>
42 #include <unordered_set>
43 
44 static std::shared_ptr<dbus::connection> system_bus;
45 static std::shared_ptr<dbus::match> sensor_match;
46 static std::shared_ptr<dbus::filter> sensor_filter;
47 static std::shared_ptr<dbus::filter> sensor_callback;
48 
49 std::unordered_set<crow::websocket::connection*> users;
50 
51 void on_sensor_update(boost::system::error_code ec, dbus::message s) {
52   std::string object_name;
53   std::vector<std::pair<std::string, dbus::dbus_variant>> values;
54   s.unpack(object_name).unpack(values);
55   crow::json::wvalue j;
56   for (auto& value : values) {
57     //std::cout << "Got sensor value for " << s.get_path() << "\n";
58     boost::apply_visitor([&](auto val) { j[s.get_path()] = val; },
59                          value.second);
60   }
61   for (auto conn : users) {
62     conn->send_text(crow::json::dump(j));
63   }
64   sensor_filter->async_dispatch(on_sensor_update);
65 };
66 
67 int main(int argc, char** argv) {
68   bool enable_ssl = true;
69   std::string ssl_pem_file("server.pem");
70 
71   if (enable_ssl) {
72     ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
73   }
74 
75   crow::App<crow::TokenAuthorizationMiddleware, crow::SecurityHeadersMiddleware>
76       app;
77 
78   crow::webassets::request_routes(app);
79   crow::kvm::request_routes(app);
80 
81   crow::logger::setLogLevel(crow::LogLevel::INFO);
82   CROW_ROUTE(app, "/systeminfo")
83   ([]() {
84 
85     crow::json::wvalue j;
86     j["device_id"] = 0x7B;
87     j["device_provides_sdrs"] = true;
88     j["device_revision"] = true;
89     j["device_available"] = true;
90     j["firmware_revision"] = "0.68";
91 
92     j["ipmi_revision"] = "2.0";
93     j["supports_chassis_device"] = true;
94     j["supports_bridge"] = true;
95     j["supports_ipmb_event_generator"] = true;
96     j["supports_ipmb_event_receiver"] = true;
97     j["supports_fru_inventory_device"] = true;
98     j["supports_sel_device"] = true;
99     j["supports_sdr_repository_device"] = true;
100     j["supports_sensor_device"] = true;
101 
102     j["firmware_aux_revision"] = "0.60.foobar";
103 
104     return j;
105   });
106 
107   CROW_ROUTE(app, "/sensorws")
108       .websocket()
109       .onopen([&](crow::websocket::connection& conn) {
110         system_bus = std::make_shared<dbus::connection>(conn.get_io_service(),
111                                                         dbus::bus::system);
112         sensor_match = std::make_shared<dbus::match>(
113             *system_bus,
114             "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
115 
116         sensor_filter =
117             std::make_shared<dbus::filter>(*system_bus, [](dbus::message& m) {
118               auto member = m.get_member();
119               return member == "PropertiesChanged";
120             });
121         /*
122         std::function<void(boost::system::error_code, dbus::message)>
123             sensor_callback = [&conn, sensor_callback](
124                 boost::system::error_code ec, dbus::message s) {
125               std::string object_name;
126               std::vector<std::pair<std::string, dbus::dbus_variant>> values;
127               s.unpack(object_name).unpack(values);
128               crow::json::wvalue j;
129               for (auto& value : values) {
130                 std::cout << "Got sensor value for " << s.get_path() << "\n";
131                 boost::apply_visitor([&](auto val) { j[s.get_path()] = val; },
132                                      value.second);
133               }
134               for (auto conn : users) {
135                 conn.send_text(crow::json::dump(j));
136               }
137               sensor_filter->async_dispatch(sensor_callback);
138             };
139             */
140         sensor_filter->async_dispatch(on_sensor_update);
141         users.insert(&conn);
142         ;
143       })
144       .onclose(
145           [&](crow::websocket::connection& conn, const std::string& reason) {
146             // TODO(ed) needs lock
147             users.erase(&conn);
148           })
149       .onmessage([&](crow::websocket::connection& conn, const std::string& data,
150                      bool is_binary) {
151         CROW_LOG_ERROR << "Got unexpected message from client on sensorws";
152       });
153 
154   CROW_ROUTE(app, "/sensortest")
155   ([](const crow::request& req, crow::response& res) {
156     crow::json::wvalue j;
157 
158     dbus::connection system_bus(*req.io_service, dbus::bus::system);
159     dbus::endpoint test_daemon("org.openbmc.Sensors",
160                                "/org/openbmc/sensors/tach",
161                                "org.freedesktop.DBus.Introspectable");
162     dbus::message m = dbus::message::new_call(test_daemon, "Introspect");
163     system_bus.async_send(
164         m,
165         [&j, &system_bus](const boost::system::error_code ec, dbus::message r) {
166           std::string xml;
167           r.unpack(xml);
168           std::vector<std::string> dbus_objects;
169           dbus::read_dbus_xml_names(xml, dbus_objects);
170 
171           for (auto& object : dbus_objects) {
172             dbus::endpoint test_daemon("org.openbmc.Sensors",
173                                        "/org/openbmc/sensors/tach/" + object,
174                                        "org.openbmc.SensorValue");
175             dbus::message m2 = dbus::message::new_call(test_daemon, "getValue");
176 
177             system_bus.async_send(
178                 m2, [&](const boost::system::error_code ec, dbus::message r) {
179                   int32_t value;
180                   r.unpack(value);
181                   // TODO(ed) if we ever go multithread, j needs a lock
182                   j[object] = value;
183                 });
184           }
185 
186         });
187 
188   });
189 
190   CROW_ROUTE(app, "/intel/firmwareupload")
191       .methods("POST"_method)([](const crow::request& req) {
192         // TODO(ed) handle errors here (file exists already and is locked, ect)
193         std::ofstream out(
194             "/tmp/fw_update_image",
195             std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
196         out << req.body;
197         out.close();
198 
199         crow::json::wvalue j;
200         j["status"] = "Upload Successfull";
201 
202         return j;
203       });
204 
205   std::cout << "Building SSL context\n";
206 
207   int port = 18080;
208 
209   std::cout << "Starting webserver on port " << port << "\n";
210   app.port(port);
211   if (enable_ssl) {
212     std::cout << "SSL Enabled\n";
213     auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
214     app.ssl(std::move(ssl_context));
215   }
216   // app.concurrency(4);
217   app.run();
218 }
219