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 "color_cout_g3_sink.hpp" 24 #include "security_headers_middleware.hpp" 25 #include "ssl_key_handler.hpp" 26 #include "token_authorization_middleware.hpp" 27 #include "web_kvm.hpp" 28 #include "webassets.hpp" 29 30 #include <boost/asio.hpp> 31 #include <boost/endian/arithmetic.hpp> 32 33 #include <dbus/connection.hpp> 34 #include <dbus/endpoint.hpp> 35 #include <dbus/filter.hpp> 36 #include <dbus/match.hpp> 37 #include <dbus/message.hpp> 38 #include <dbus/utility.hpp> 39 40 #include <iostream> 41 #include <memory> 42 #include <string> 43 #include <unordered_set> 44 45 using sensor_values = std::vector<std::pair<std::string, int32_t>>; 46 47 sensor_values read_sensor_values() { 48 sensor_values values; 49 DBusError err; 50 51 int ret; 52 bool stat; 53 dbus_uint32_t level; 54 55 // initialiset the errors 56 dbus_error_init(&err); 57 58 // connect to the system bus and check for errors 59 DBusConnection* conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); 60 if (dbus_error_is_set(&err)) { 61 fprintf(stderr, "Connection Error (%s)\n", err.message); 62 dbus_error_free(&err); 63 } 64 if (NULL == conn) { 65 exit(1); 66 } 67 68 // create a new method call and check for errors 69 DBusMessage* msg = dbus_message_new_method_call( 70 "org.openbmc.Sensors", // target for the method call 71 "/org/openbmc/sensors/tach", // object to call on 72 "org.freedesktop.DBus.Introspectable", // interface to call on 73 "Introspect"); // method name 74 if (NULL == msg) { 75 fprintf(stderr, "Message Null\n"); 76 exit(1); 77 } 78 79 DBusPendingCall* pending; 80 // send message and get a handle for a reply 81 if (!dbus_connection_send_with_reply(conn, msg, &pending, 82 -1)) { // -1 is default timeout 83 fprintf(stderr, "Out Of Memory!\n"); 84 exit(1); 85 } 86 if (NULL == pending) { 87 fprintf(stderr, "Pending Call Null\n"); 88 exit(1); 89 } 90 dbus_connection_flush(conn); 91 92 // free message 93 dbus_message_unref(msg); 94 95 // block until we recieve a reply 96 dbus_pending_call_block(pending); 97 98 // get the reply message 99 msg = dbus_pending_call_steal_reply(pending); 100 if (NULL == msg) { 101 fprintf(stderr, "Reply Null\n"); 102 exit(1); 103 } 104 // free the pending message handle 105 dbus_pending_call_unref(pending); 106 107 // read the parameters 108 DBusMessageIter args; 109 char* xml_struct = NULL; 110 if (!dbus_message_iter_init(msg, &args)) { 111 fprintf(stderr, "Message has no arguments!\n"); 112 } 113 114 // read the arguments 115 if (!dbus_message_iter_init(msg, &args)) { 116 fprintf(stderr, "Message has no arguments!\n"); 117 } else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) { 118 fprintf(stderr, "Argument is not string!\n"); 119 } else { 120 dbus_message_iter_get_basic(&args, &xml_struct); 121 } 122 std::vector<std::string> methods; 123 if (xml_struct != NULL) { 124 std::string xml_data(xml_struct); 125 std::vector<std::string> names; 126 dbus::read_dbus_xml_names(xml_data, methods); 127 } 128 129 fprintf(stdout, "Found %zd sensors \n", methods.size()); 130 131 for (auto& method : methods) { 132 // TODO(Ed) make sure sensor exposes SensorValue interface 133 // create a new method call and check for errors 134 DBusMessage* msg = dbus_message_new_method_call( 135 "org.openbmc.Sensors", // target for the method call 136 ("/org/openbmc/sensors/tach/" + method).c_str(), // object to call on 137 "org.openbmc.SensorValue", // interface to call on 138 "getValue"); // method name 139 if (NULL == msg) { 140 fprintf(stderr, "Message Null\n"); 141 exit(1); 142 } 143 144 DBusPendingCall* pending; 145 // send message and get a handle for a reply 146 if (!dbus_connection_send_with_reply(conn, msg, &pending, 147 -1)) { // -1 is default timeout 148 fprintf(stderr, "Out Of Memory!\n"); 149 exit(1); 150 } 151 if (NULL == pending) { 152 fprintf(stderr, "Pending Call Null\n"); 153 exit(1); 154 } 155 dbus_connection_flush(conn); 156 157 // free message 158 dbus_message_unref(msg); 159 160 // block until we recieve a reply 161 dbus_pending_call_block(pending); 162 163 // get the reply message 164 msg = dbus_pending_call_steal_reply(pending); 165 if (NULL == msg) { 166 fprintf(stderr, "Reply Null\n"); 167 exit(1); 168 } 169 // free the pending message handle 170 dbus_pending_call_unref(pending); 171 172 // read the parameters 173 DBusMessageIter args; 174 int32_t value; 175 if (!dbus_message_iter_init(msg, &args)) { 176 fprintf(stderr, "Message has no arguments!\n"); 177 } 178 179 // read the arguments 180 if (!dbus_message_iter_init(msg, &args)) { 181 fprintf(stderr, "Message has no arguments!\n"); 182 } else if (DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type(&args)) { 183 fprintf(stderr, "Argument is not string!\n"); 184 } else { 185 DBusMessageIter sub; 186 dbus_message_iter_recurse(&args, &sub); 187 auto type = dbus_message_iter_get_arg_type(&sub); 188 if (DBUS_TYPE_INT32 != type) { 189 fprintf(stderr, "Variant subType is not int32 it is %d\n", type); 190 } else { 191 dbus_message_iter_get_basic(&sub, &value); 192 values.emplace_back(method.c_str(), value); 193 } 194 } 195 } 196 197 // free reply and close connection 198 dbus_message_unref(msg); 199 return values; 200 } 201 202 int main(int argc, char** argv) { 203 auto worker(g3::LogWorker::createLogWorker()); 204 if (false) { 205 auto handle = worker->addDefaultLogger("bmcweb", "/tmp/"); 206 } 207 g3::initializeLogging(worker.get()); 208 auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(), 209 &crow::ColorCoutSink::ReceiveLogMessage); 210 bool enable_ssl = true; 211 std::string ssl_pem_file("server.pem"); 212 213 if (enable_ssl) { 214 ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file); 215 } 216 217 crow::App<crow::TokenAuthorizationMiddleware, crow::SecurityHeadersMiddleware> 218 app; 219 220 crow::webassets::request_routes(app); 221 crow::kvm::request_routes(app); 222 223 crow::logger::setLogLevel(crow::LogLevel::INFO); 224 CROW_ROUTE(app, "/systeminfo") 225 ([]() { 226 227 crow::json::wvalue j; 228 j["device_id"] = 0x7B; 229 j["device_provides_sdrs"] = true; 230 j["device_revision"] = true; 231 j["device_available"] = true; 232 j["firmware_revision"] = "0.68"; 233 234 j["ipmi_revision"] = "2.0"; 235 j["supports_chassis_device"] = true; 236 j["supports_bridge"] = true; 237 j["supports_ipmb_event_generator"] = true; 238 j["supports_ipmb_event_receiver"] = true; 239 j["supports_fru_inventory_device"] = true; 240 j["supports_sel_device"] = true; 241 j["supports_sdr_repository_device"] = true; 242 j["supports_sensor_device"] = true; 243 244 j["firmware_aux_revision"] = "0.60.foobar"; 245 246 return j; 247 }); 248 249 CROW_ROUTE(app, "/sensorws") 250 .websocket() 251 .onopen([&](crow::websocket::connection& conn) { 252 dbus::connection system_bus(conn.get_io_service(), dbus::bus::system); 253 dbus::match ma(system_bus, 254 "type='signal',sender='org.freedesktop.DBus', " 255 "interface='org.freedesktop.DBus.Properties',member=" 256 "'PropertiesChanged'"); 257 dbus::filter f(system_bus, [](dbus::message& m) { return true; }); 258 259 f.async_dispatch([&](boost::system::error_code ec, dbus::message s) { 260 std::cout << "got event\n"; 261 //f.async_dispatch(event_handler); 262 }); 263 264 }) 265 .onclose( 266 [&](crow::websocket::connection& conn, const std::string& reason) { 267 268 }) 269 .onmessage([&](crow::websocket::connection& conn, const std::string& data, 270 bool is_binary) { 271 272 }); 273 274 CROW_ROUTE(app, "/sensortest") 275 ([](const crow::request& req, crow::response& res) { 276 crow::json::wvalue j; 277 auto values = read_sensor_values(); 278 279 dbus::connection system_bus(*req.io_service, dbus::bus::system); 280 dbus::endpoint test_daemon("org.openbmc.Sensors", 281 "/org/openbmc/sensors/tach", 282 "org.freedesktop.DBus.Introspectable"); 283 dbus::message m = dbus::message::new_call(test_daemon, "Introspect"); 284 system_bus.async_send( 285 m, 286 [&j, &system_bus](const boost::system::error_code ec, dbus::message r) { 287 std::string xml; 288 r.unpack(xml); 289 std::vector<std::string> dbus_objects; 290 dbus::read_dbus_xml_names(xml, dbus_objects); 291 292 for (auto& object : dbus_objects) { 293 dbus::endpoint test_daemon("org.openbmc.Sensors", 294 "/org/openbmc/sensors/tach/" + object, 295 "org.openbmc.SensorValue"); 296 dbus::message m2 = dbus::message::new_call(test_daemon, "getValue"); 297 298 system_bus.async_send( 299 m2, [&](const boost::system::error_code ec, dbus::message r) { 300 int32_t value; 301 r.unpack(value); 302 // TODO(ed) if we ever go multithread, j needs a lock 303 j[object] = value; 304 }); 305 } 306 307 }); 308 309 }); 310 311 CROW_ROUTE(app, "/intel/firmwareupload") 312 .methods("POST"_method)([](const crow::request& req) { 313 // TODO(ed) handle errors here (file exists already and is locked, ect) 314 std::ofstream out("/tmp/fw_update_image", std::ofstream::out | 315 std::ofstream::binary | 316 std::ofstream::trunc); 317 out << req.body; 318 out.close(); 319 320 crow::json::wvalue j; 321 j["status"] = "Upload Successfull"; 322 323 return j; 324 }); 325 326 LOG(DEBUG) << "Building SSL context"; 327 328 int port = 18080; 329 330 LOG(DEBUG) << "Starting webserver on port " << port; 331 app.port(port); 332 if (enable_ssl) { 333 LOG(DEBUG) << "SSL Enabled"; 334 auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file); 335 app.ssl(std::move(ssl_context)); 336 } 337 //app.concurrency(4); 338 app.run(); 339 } 340