xref: /openbmc/bmcweb/src/webserver_main.cpp (revision 7b4e3dae0477703143b8cb28b3a6abc9d4d0d83b)
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         if (!system_bus) {
111           system_bus = std::make_shared<dbus::connection>(conn.get_io_service(),
112                                                           dbus::bus::system);
113         }
114         if (!sensor_match) {
115           sensor_match = std::make_shared<dbus::match>(
116               *system_bus,
117               "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
118         }
119         if (!sensor_filter) {
120           sensor_filter =
121               std::make_shared<dbus::filter>(*system_bus, [](dbus::message& m) {
122                 auto member = m.get_member();
123                 return member == "PropertiesChanged";
124               });
125           sensor_filter->async_dispatch(on_sensor_update);
126         }
127 
128         users.insert(&conn);
129       })
130       .onclose(
131           [&](crow::websocket::connection& conn, const std::string& reason) {
132             // TODO(ed) needs lock
133             users.erase(&conn);
134           })
135       .onmessage([&](crow::websocket::connection& conn, const std::string& data,
136                      bool is_binary) {
137         CROW_LOG_ERROR << "Got unexpected message from client on sensorws";
138       });
139 
140   CROW_ROUTE(app, "/sensortest")
141   ([](const crow::request& req, crow::response& res) {
142     crow::json::wvalue j;
143 
144     dbus::connection system_bus(*req.io_service, dbus::bus::system);
145     dbus::endpoint test_daemon("org.openbmc.Sensors",
146                                "/org/openbmc/sensors/tach",
147                                "org.freedesktop.DBus.Introspectable");
148     dbus::message m = dbus::message::new_call(test_daemon, "Introspect");
149     system_bus.async_send(
150         m,
151         [&j, &system_bus](const boost::system::error_code ec, dbus::message r) {
152           std::string xml;
153           r.unpack(xml);
154           std::vector<std::string> dbus_objects;
155           dbus::read_dbus_xml_names(xml, dbus_objects);
156 
157           for (auto& object : dbus_objects) {
158             dbus::endpoint test_daemon("org.openbmc.Sensors",
159                                        "/org/openbmc/sensors/tach/" + object,
160                                        "org.openbmc.SensorValue");
161             dbus::message m2 = dbus::message::new_call(test_daemon, "getValue");
162 
163             system_bus.async_send(
164                 m2, [&](const boost::system::error_code ec, dbus::message r) {
165                   int32_t value;
166                   r.unpack(value);
167                   // TODO(ed) if we ever go multithread, j needs a lock
168                   j[object] = value;
169                 });
170           }
171 
172         });
173 
174   });
175 
176   CROW_ROUTE(app, "/intel/firmwareupload")
177       .methods("POST"_method)([](const crow::request& req) {
178         // TODO(ed) handle errors here (file exists already and is locked, ect)
179         std::ofstream out(
180             "/tmp/fw_update_image",
181             std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
182         out << req.body;
183         out.close();
184 
185         crow::json::wvalue j;
186         j["status"] = "Upload Successfull";
187 
188         return j;
189       });
190 
191   std::cout << "Building SSL context\n";
192 
193   int port = 18080;
194 
195   std::cout << "Starting webserver on port " << port << "\n";
196   app.port(port);
197   if (enable_ssl) {
198     std::cout << "SSL Enabled\n";
199     auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
200     app.ssl(std::move(ssl_context));
201   }
202   // app.concurrency(4);
203   app.run();
204 }
205