xref: /openbmc/bmcweb/src/webserver_main.cpp (revision ef915c26b0235afa181529cecd4cb080f15cb137)
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        .onmessage([&](crow::websocket::connection& conn, const std::string& data,
126                       bool is_binary) {
127          CROW_LOG_ERROR << "Got unexpected message from client on sensorws";
128        });
129  
130    CROW_ROUTE(app, "/intel/firmwareupload")
131        .methods("POST"_method)([](const crow::request& req) {
132          auto filepath = "/tmp/fw_update_image";
133          std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
134                                          std::ofstream::trunc);
135          out << req.body;
136          out.close();
137  
138          nlohmann::json j;
139          j["status"] = "Upload Successfull";
140  
141          dbus::endpoint fw_update_endpoint(
142              "xyz.openbmc_project.fwupdate1.server",
143              "/xyz/openbmc_project/fwupdate1", "xyz.openbmc_project.fwupdate1");
144  
145          auto m = dbus::message::new_call(fw_update_endpoint, "start");
146  
147          m.pack(std::string("file://") + filepath);
148          system_bus->send(m);
149  
150          return j;
151        });
152  
153    crow::logger::setLogLevel(crow::LogLevel::DEBUG);
154    auto test = app.get_routes();
155    app.debug_print();
156    std::cout << "Building SSL context\n";
157  
158    int port = 18080;
159  
160    std::cout << "Starting webserver on port " << port << "\n";
161    app.port(port);
162    if (enable_ssl) {
163      std::cout << "SSL Enabled\n";
164      auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
165      app.ssl(std::move(ssl_context));
166    }
167    // app.concurrency(4);
168  
169    // Start dbus connection
170    system_bus = std::make_shared<dbus::connection>(*io, dbus::bus::system);
171  
172    app.run();
173  }
174