xref: /openbmc/bmcweb/src/webserver_main.cpp (revision 5fceeb4563c08468e9623cef1e3d7f4de9373d2f)
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 
48 std::unordered_set<crow::websocket::connection*> users;
49 
50 void on_sensor_update(boost::system::error_code ec, dbus::message s) {
51   std::string object_name;
52   std::vector<std::pair<std::string, dbus::dbus_variant>> values;
53   s.unpack(object_name).unpack(values);
54   crow::json::wvalue j;
55   for (auto& value : values) {
56     // std::cout << "Got sensor value for " << s.get_path() << "\n";
57     boost::apply_visitor([&](auto val) { j[s.get_path()] = val; },
58                          value.second);
59   }
60   auto data_to_send = crow::json::dump(j);
61   for (auto conn : users) {
62     conn->send_text(data_to_send);
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           if (ec) {
153 
154           } else {
155             std::string xml;
156             r.unpack(xml);
157             std::vector<std::string> dbus_objects;
158             dbus::read_dbus_xml_names(xml, dbus_objects);
159 
160             for (auto& object : dbus_objects) {
161               dbus::endpoint test_daemon("org.openbmc.Sensors",
162                                          "/org/openbmc/sensors/tach/" + object,
163                                          "org.openbmc.SensorValue");
164               dbus::message m2 =
165                   dbus::message::new_call(test_daemon, "getValue");
166 
167               system_bus.async_send(
168                   m2, [&](const boost::system::error_code ec, dbus::message r) {
169                     int32_t value;
170                     r.unpack(value);
171                     // TODO(ed) if we ever go multithread, j needs a lock
172                     j[object] = value;
173                   });
174             }
175           }
176         });
177 
178   });
179 
180   CROW_ROUTE(app, "/intel/firmwareupload")
181       .methods("POST"_method)([](const crow::request& req) {
182         // TODO(ed) handle errors here (file exists already and is locked, ect)
183         std::ofstream out(
184             "/tmp/fw_update_image",
185             std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
186         out << req.body;
187         out.close();
188 
189         crow::json::wvalue j;
190         j["status"] = "Upload Successfull";
191 
192         return j;
193       });
194 
195   std::cout << "Building SSL context\n";
196 
197   int port = 18080;
198 
199   std::cout << "Starting webserver on port " << port << "\n";
200   app.port(port);
201   if (enable_ssl) {
202     std::cout << "SSL Enabled\n";
203     auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
204     app.ssl(std::move(ssl_context));
205   }
206   // app.concurrency(4);
207   app.run();
208 }
209