blob: 404e15cd126a611cc33c7d06437efb402896172c [file] [log] [blame]
Ed Tanousf9273472017-02-28 16:05:13 -08001#include "crow/app.h"
Ed Tanousc4771fb2017-03-13 13:39:49 -07002#include "crow/ci_map.h"
Ed Tanousf9273472017-02-28 16:05:13 -08003#include "crow/common.h"
4#include "crow/dumb_timer_queue.h"
5#include "crow/http_connection.h"
Ed Tanousc4771fb2017-03-13 13:39:49 -07006#include "crow/http_parser_merged.h"
Ed Tanousf9273472017-02-28 16:05:13 -08007#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"
Ed Tanousc4771fb2017-03-13 13:39:49 -070016#include "crow/query_string.h"
Ed Tanousf9273472017-02-28 16:05:13 -080017#include "crow/routing.h"
Ed Tanous0fdddb12017-02-28 11:06:34 -080018#include "crow/settings.h"
19#include "crow/socket_adaptors.h"
Ed Tanous0fdddb12017-02-28 11:06:34 -080020#include "crow/utility.h"
Ed Tanous0fdddb12017-02-28 11:06:34 -080021#include "crow/websocket.h"
Ed Tanous0fdddb12017-02-28 11:06:34 -080022
Ed Tanous5f34a9c2017-02-28 12:35:13 -080023#include "color_cout_g3_sink.hpp"
Ed Tanous7d3dba42017-04-05 13:04:39 -070024#include "security_headers_middleware.hpp"
Ed Tanous9140a672017-04-24 17:01:32 -070025#include "ssl_key_handler.hpp"
Ed Tanous7d3dba42017-04-05 13:04:39 -070026#include "token_authorization_middleware.hpp"
Ed Tanous9140a672017-04-24 17:01:32 -070027#include "web_kvm.hpp"
28#include "webassets.hpp"
Ed Tanousb4d29f42017-03-24 16:39:25 -070029
30#include <boost/asio.hpp>
31#include <boost/endian/arithmetic.hpp>
32
Ed Tanouscc5a37f2017-05-11 10:27:23 -070033#include <dbus/dbus.h>
34#include <boost/iostreams/stream.hpp>
35#include <boost/property_tree/ptree.hpp>
36#include <boost/property_tree/xml_parser.hpp>
37
Ed Tanous0fdddb12017-02-28 11:06:34 -080038#include <iostream>
Ed Tanousc4771fb2017-03-13 13:39:49 -070039#include <memory>
Ed Tanous0fdddb12017-02-28 11:06:34 -080040#include <string>
Ed Tanousc4771fb2017-03-13 13:39:49 -070041#include <unordered_set>
Ed Tanous9b65f1f2017-03-07 15:17:13 -080042
Ed Tanouscc5a37f2017-05-11 10:27:23 -070043using sensor_values = std::vector<std::pair<std::string, int32_t>>;
44
45std::vector<std::string> read_dbus_xml_names(std::string& xml_data) {
46 std::vector<std::string> values;
47 // populate tree structure pt
48 using boost::property_tree::ptree;
49 ptree pt;
50 boost::iostreams::stream<boost::iostreams::array_source> stream(
51 xml_data.c_str(), xml_data.size());
52 read_xml(stream, pt);
53
54 // traverse node to find other nodes
55 for (const auto& interface : pt.get_child("node")) {
56 if (interface.first == "node") {
57 auto t = interface.second.get<std::string>("<xmlattr>", "default");
58 for (const auto& subnode : interface.second.get_child("<xmlattr>")) {
59 if (subnode.first == "name") {
60 auto t = subnode.second.get("", "unknown");
61 values.emplace_back(std::move(t));
62 }
63 }
64 }
65 }
66 return values;
67}
68
69sensor_values read_sensor_values() {
70 sensor_values values;
71 DBusError err;
72
73 int ret;
74 bool stat;
75 dbus_uint32_t level;
76
77 // initialiset the errors
78 dbus_error_init(&err);
79
80 // connect to the system bus and check for errors
81 DBusConnection* conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
82 if (dbus_error_is_set(&err)) {
83 fprintf(stderr, "Connection Error (%s)\n", err.message);
84 dbus_error_free(&err);
85 }
86 if (NULL == conn) {
87 exit(1);
88 }
89
90 // create a new method call and check for errors
91 DBusMessage* msg = dbus_message_new_method_call(
92 "org.openbmc.Sensors", // target for the method call
93 "/org/openbmc/sensors/tach", // object to call on
94 "org.freedesktop.DBus.Introspectable", // interface to call on
95 "Introspect"); // method name
96 if (NULL == msg) {
97 fprintf(stderr, "Message Null\n");
98 exit(1);
99 }
100
101 DBusPendingCall* pending;
102 // send message and get a handle for a reply
103 if (!dbus_connection_send_with_reply(conn, msg, &pending,
104 -1)) { // -1 is default timeout
105 fprintf(stderr, "Out Of Memory!\n");
106 exit(1);
107 }
108 if (NULL == pending) {
109 fprintf(stderr, "Pending Call Null\n");
110 exit(1);
111 }
112 dbus_connection_flush(conn);
113
114 // free message
115 dbus_message_unref(msg);
116
117 // block until we recieve a reply
118 dbus_pending_call_block(pending);
119
120 // get the reply message
121 msg = dbus_pending_call_steal_reply(pending);
122 if (NULL == msg) {
123 fprintf(stderr, "Reply Null\n");
124 exit(1);
125 }
126 // free the pending message handle
127 dbus_pending_call_unref(pending);
128
129 // read the parameters
130 DBusMessageIter args;
131 char* xml_struct = NULL;
132 if (!dbus_message_iter_init(msg, &args)) {
133 fprintf(stderr, "Message has no arguments!\n");
134 }
135
136 // read the arguments
137 if (!dbus_message_iter_init(msg, &args)) {
138 fprintf(stderr, "Message has no arguments!\n");
139 } else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) {
140 fprintf(stderr, "Argument is not string!\n");
141 } else {
142 dbus_message_iter_get_basic(&args, &xml_struct);
143 }
144 std::vector<std::string> methods;
145 if (xml_struct != NULL) {
146 std::string xml_data(xml_struct);
147 methods = read_dbus_xml_names(xml_data);
148 }
149
Ed Tanousf0226cd2017-05-16 12:35:38 -0700150 fprintf(stdout, "Found %zd sensors \n", methods.size());
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700151
152 for (auto& method : methods) {
153 // TODO(Ed) make sure sensor exposes SensorValue interface
154 // create a new method call and check for errors
155 DBusMessage* msg = dbus_message_new_method_call(
156 "org.openbmc.Sensors", // target for the method call
157 ("/org/openbmc/sensors/tach/" + method).c_str(), // object to call on
158 "org.openbmc.SensorValue", // interface to call on
159 "getValue"); // method name
160 if (NULL == msg) {
161 fprintf(stderr, "Message Null\n");
162 exit(1);
163 }
164
165 DBusPendingCall* pending;
166 // send message and get a handle for a reply
167 if (!dbus_connection_send_with_reply(conn, msg, &pending,
168 -1)) { // -1 is default timeout
169 fprintf(stderr, "Out Of Memory!\n");
170 exit(1);
171 }
172 if (NULL == pending) {
173 fprintf(stderr, "Pending Call Null\n");
174 exit(1);
175 }
176 dbus_connection_flush(conn);
177
178 // free message
179 dbus_message_unref(msg);
180
181 // block until we recieve a reply
182 dbus_pending_call_block(pending);
183
184 // get the reply message
185 msg = dbus_pending_call_steal_reply(pending);
186 if (NULL == msg) {
187 fprintf(stderr, "Reply Null\n");
188 exit(1);
189 }
190 // free the pending message handle
191 dbus_pending_call_unref(pending);
192
193 // read the parameters
194 DBusMessageIter args;
195 int32_t value;
196 if (!dbus_message_iter_init(msg, &args)) {
197 fprintf(stderr, "Message has no arguments!\n");
198 }
199
200 // read the arguments
201 if (!dbus_message_iter_init(msg, &args)) {
202 fprintf(stderr, "Message has no arguments!\n");
203 } else if (DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type(&args)) {
204 fprintf(stderr, "Argument is not string!\n");
205 } else {
206 DBusMessageIter sub;
207 dbus_message_iter_recurse(&args, &sub);
208 auto type = dbus_message_iter_get_arg_type(&sub);
209 if (DBUS_TYPE_INT32 != type) {
210 fprintf(stderr, "Variant subType is not int32 it is %d\n", type);
211 } else {
212 dbus_message_iter_get_basic(&sub, &value);
213 values.emplace_back(method.c_str(), value);
214 }
215 }
216 }
217
218 // free reply and close connection
219 dbus_message_unref(msg);
220 return values;
221}
222
Ed Tanous99923322017-03-03 14:21:24 -0800223int main(int argc, char** argv) {
Ed Tanous9b65f1f2017-03-07 15:17:13 -0800224 auto worker(g3::LogWorker::createLogWorker());
Ed Tanouscfbe25d2017-05-23 16:34:35 -0700225 if (false) {
226 auto handle = worker->addDefaultLogger("bmcweb", "/tmp/");
227 }
Ed Tanous99923322017-03-03 14:21:24 -0800228 g3::initializeLogging(worker.get());
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700229 auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(),
230 &crow::ColorCoutSink::ReceiveLogMessage);
Ed Tanous4758d5b2017-06-06 15:28:13 -0700231 bool enable_ssl = true;
Ed Tanous99923322017-03-03 14:21:24 -0800232 std::string ssl_pem_file("server.pem");
Ed Tanous0fdddb12017-02-28 11:06:34 -0800233
Ed Tanous4758d5b2017-06-06 15:28:13 -0700234 if (enable_ssl) {
235 ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
236 }
237
238 crow::App<
239 crow::TokenAuthorizationMiddleware, crow::SecurityHeadersMiddleware>
Ed Tanous7d3dba42017-04-05 13:04:39 -0700240 app;
Ed Tanousb4d29f42017-03-24 16:39:25 -0700241
Ed Tanous99923322017-03-03 14:21:24 -0800242 crow::webassets::request_routes(app);
Ed Tanousc81ca422017-03-21 16:18:49 -0700243 crow::kvm::request_routes(app);
Ed Tanous0fdddb12017-02-28 11:06:34 -0800244
Ed Tanous9b65f1f2017-03-07 15:17:13 -0800245 crow::logger::setLogLevel(crow::LogLevel::INFO);
Ed Tanousc4771fb2017-03-13 13:39:49 -0700246 CROW_ROUTE(app, "/systeminfo")
247 ([]() {
248
249 crow::json::wvalue j;
250 j["device_id"] = 0x7B;
251 j["device_provides_sdrs"] = true;
252 j["device_revision"] = true;
253 j["device_available"] = true;
254 j["firmware_revision"] = "0.68";
255
256 j["ipmi_revision"] = "2.0";
257 j["supports_chassis_device"] = true;
258 j["supports_bridge"] = true;
259 j["supports_ipmb_event_generator"] = true;
260 j["supports_ipmb_event_receiver"] = true;
261 j["supports_fru_inventory_device"] = true;
262 j["supports_sel_device"] = true;
263 j["supports_sdr_repository_device"] = true;
264 j["supports_sensor_device"] = true;
265
266 j["firmware_aux_revision"] = "0.60.foobar";
267
268 return j;
269 });
270
Ed Tanousc4771fb2017-03-13 13:39:49 -0700271 CROW_ROUTE(app, "/ipmiws")
272 .websocket()
273 .onopen([&](crow::websocket::connection& conn) {
274
275 })
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700276 .onclose(
277 [&](crow::websocket::connection& conn, const std::string& reason) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700278
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700279 })
280 .onmessage([&](crow::websocket::connection& conn, const std::string& data,
281 bool is_binary) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700282 boost::asio::io_service io_service;
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700283 using boost::asio::ip::udp;
284 udp::resolver resolver(io_service);
285 udp::resolver::query query(udp::v4(), "10.243.48.31", "623");
286 udp::endpoint receiver_endpoint = *resolver.resolve(query);
287
288 udp::socket socket(io_service);
289 socket.open(udp::v4());
290
291 socket.send_to(boost::asio::buffer(data), receiver_endpoint);
292
293 std::array<char, 255> recv_buf;
294
295 udp::endpoint sender_endpoint;
296 size_t len =
297 socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
298 // TODO(ed) THis is ugly. Find a way to not make a copy (ie, use
Ed Tanous7d3dba42017-04-05 13:04:39 -0700299 // std::string::data() to
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700300 std::string str(std::begin(recv_buf), std::end(recv_buf));
301 LOG(DEBUG) << "Got " << str << "back \n";
302 conn.send_binary(str);
303
Ed Tanousc4771fb2017-03-13 13:39:49 -0700304 });
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700305
306 CROW_ROUTE(app, "/sensortest")
307 ([]() {
308 crow::json::wvalue j;
309 auto values = read_sensor_values();
310 for (auto& pair : values) {
311 j[pair.first] = pair.second;
312 }
313
314 return j;
315 });
Ed Tanous4758d5b2017-06-06 15:28:13 -0700316
317 CROW_ROUTE(app, "/intel/firmwareupload")
318 .methods("POST"_method)([](const crow::request& req) {
319 // TODO(ed) handle errors here (file exists already and is locked, ect)
320 std::ofstream out(
321 "/tmp/fw_update_image",
322 std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
323 out << req.body;
324 out.close();
325
326 crow::json::wvalue j;
327 j["status"] = "Upload Successfull";
328
329 return j;
330 });
331
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700332 LOG(DEBUG) << "Building SSL context";
Ed Tanous4758d5b2017-06-06 15:28:13 -0700333
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700334 int port = 18080;
Ed Tanousf0226cd2017-05-16 12:35:38 -0700335
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700336 LOG(DEBUG) << "Starting webserver on port " << port;
Ed Tanous4758d5b2017-06-06 15:28:13 -0700337 app.port(port);
338 if (enable_ssl) {
339 LOG(DEBUG) << "SSL Enabled";
340 auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
341 app.ssl(std::move(ssl_context));
342 }
343 app.concurrency(4);
344 app.run();
Ed Tanous0fdddb12017-02-28 11:06:34 -0800345}