blob: 0c173dd947b771d959adee37529dc377bf9e234e [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 Tanousc9b55212017-06-12 13:25:51 -070033#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>
Ed Tanouscc5a37f2017-05-11 10:27:23 -070039
Ed Tanous0fdddb12017-02-28 11:06:34 -080040#include <iostream>
Ed Tanousc4771fb2017-03-13 13:39:49 -070041#include <memory>
Ed Tanous0fdddb12017-02-28 11:06:34 -080042#include <string>
Ed Tanousc4771fb2017-03-13 13:39:49 -070043#include <unordered_set>
Ed Tanous9b65f1f2017-03-07 15:17:13 -080044
Ed Tanouscc5a37f2017-05-11 10:27:23 -070045using sensor_values = std::vector<std::pair<std::string, int32_t>>;
46
Ed Tanouscc5a37f2017-05-11 10:27:23 -070047sensor_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);
Ed Tanousc9b55212017-06-12 13:25:51 -0700125 std::vector<std::string> names;
126 dbus::read_dbus_xml_names(xml_data, methods);
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700127 }
128
Ed Tanousf0226cd2017-05-16 12:35:38 -0700129 fprintf(stdout, "Found %zd sensors \n", methods.size());
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700130
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
Ed Tanous99923322017-03-03 14:21:24 -0800202int main(int argc, char** argv) {
Ed Tanous9b65f1f2017-03-07 15:17:13 -0800203 auto worker(g3::LogWorker::createLogWorker());
Ed Tanouscfbe25d2017-05-23 16:34:35 -0700204 if (false) {
205 auto handle = worker->addDefaultLogger("bmcweb", "/tmp/");
206 }
Ed Tanous99923322017-03-03 14:21:24 -0800207 g3::initializeLogging(worker.get());
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700208 auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(),
209 &crow::ColorCoutSink::ReceiveLogMessage);
Ed Tanous4758d5b2017-06-06 15:28:13 -0700210 bool enable_ssl = true;
Ed Tanous99923322017-03-03 14:21:24 -0800211 std::string ssl_pem_file("server.pem");
Ed Tanous0fdddb12017-02-28 11:06:34 -0800212
Ed Tanous4758d5b2017-06-06 15:28:13 -0700213 if (enable_ssl) {
214 ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
215 }
216
Ed Tanousc9b55212017-06-12 13:25:51 -0700217 crow::App<crow::TokenAuthorizationMiddleware, crow::SecurityHeadersMiddleware>
Ed Tanous7d3dba42017-04-05 13:04:39 -0700218 app;
Ed Tanousb4d29f42017-03-24 16:39:25 -0700219
Ed Tanous99923322017-03-03 14:21:24 -0800220 crow::webassets::request_routes(app);
Ed Tanousc81ca422017-03-21 16:18:49 -0700221 crow::kvm::request_routes(app);
Ed Tanous0fdddb12017-02-28 11:06:34 -0800222
Ed Tanous9b65f1f2017-03-07 15:17:13 -0800223 crow::logger::setLogLevel(crow::LogLevel::INFO);
Ed Tanousc4771fb2017-03-13 13:39:49 -0700224 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
Ed Tanousc4771fb2017-03-13 13:39:49 -0700249 CROW_ROUTE(app, "/ipmiws")
250 .websocket()
251 .onopen([&](crow::websocket::connection& conn) {
252
253 })
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700254 .onclose(
255 [&](crow::websocket::connection& conn, const std::string& reason) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700256
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700257 })
258 .onmessage([&](crow::websocket::connection& conn, const std::string& data,
259 bool is_binary) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700260 boost::asio::io_service io_service;
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700261 using boost::asio::ip::udp;
262 udp::resolver resolver(io_service);
263 udp::resolver::query query(udp::v4(), "10.243.48.31", "623");
264 udp::endpoint receiver_endpoint = *resolver.resolve(query);
265
266 udp::socket socket(io_service);
267 socket.open(udp::v4());
268
269 socket.send_to(boost::asio::buffer(data), receiver_endpoint);
270
271 std::array<char, 255> recv_buf;
272
273 udp::endpoint sender_endpoint;
274 size_t len =
275 socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
276 // TODO(ed) THis is ugly. Find a way to not make a copy (ie, use
Ed Tanous7d3dba42017-04-05 13:04:39 -0700277 // std::string::data() to
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700278 std::string str(std::begin(recv_buf), std::end(recv_buf));
279 LOG(DEBUG) << "Got " << str << "back \n";
280 conn.send_binary(str);
281
Ed Tanousc4771fb2017-03-13 13:39:49 -0700282 });
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700283
284 CROW_ROUTE(app, "/sensortest")
Ed Tanousc9b55212017-06-12 13:25:51 -0700285 ([](const crow::request& req, crow::response& res) {
286 dbus::connection system_bus(*req.io_service, dbus::bus::system);
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700287
Ed Tanousc9b55212017-06-12 13:25:51 -0700288 dbus::endpoint test_daemon("org.freedesktop.DBus", "/",
289 "org.freedesktop.DBus");
290 dbus::message m = dbus::message::new_call(test_daemon, "ListNames");
291 system_bus.async_send(m, [&](const boost::system::error_code ec,
292 dbus::message r) {
293 std::vector<std::string> services;
294 //r.unpack(services);
295 for (auto& service : services) {
296 dbus::endpoint service_daemon(service, "/",
297 "org.freedesktop.DBus.Introspectable");
298 dbus::message m = dbus::message::new_call(service_daemon, "Introspect");
299 system_bus.async_send(
300 m, [&](const boost::system::error_code ec, dbus::message r) {
301 std::string xml;
302 r.unpack(xml);
303 std::vector<std::string> dbus_objects;
304 dbus::read_dbus_xml_names(xml, dbus_objects);
305
306
307 });
308 }
309
310 });
311
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700312 });
Ed Tanous4758d5b2017-06-06 15:28:13 -0700313
314 CROW_ROUTE(app, "/intel/firmwareupload")
315 .methods("POST"_method)([](const crow::request& req) {
316 // TODO(ed) handle errors here (file exists already and is locked, ect)
Ed Tanousc9b55212017-06-12 13:25:51 -0700317 std::ofstream out("/tmp/fw_update_image", std::ofstream::out |
318 std::ofstream::binary |
319 std::ofstream::trunc);
Ed Tanous4758d5b2017-06-06 15:28:13 -0700320 out << req.body;
321 out.close();
322
323 crow::json::wvalue j;
324 j["status"] = "Upload Successfull";
325
326 return j;
327 });
328
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700329 LOG(DEBUG) << "Building SSL context";
Ed Tanous4758d5b2017-06-06 15:28:13 -0700330
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700331 int port = 18080;
Ed Tanousf0226cd2017-05-16 12:35:38 -0700332
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700333 LOG(DEBUG) << "Starting webserver on port " << port;
Ed Tanous4758d5b2017-06-06 15:28:13 -0700334 app.port(port);
335 if (enable_ssl) {
336 LOG(DEBUG) << "SSL Enabled";
337 auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
338 app.ssl(std::move(ssl_context));
339 }
340 app.concurrency(4);
341 app.run();
Ed Tanous0fdddb12017-02-28 11:06:34 -0800342}