blob: ba31a757b403322e1c5a29b85fb00c10d0d0f01b [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"
29#include "webassets.hpp"
Ed Tanousb4d29f42017-03-24 16:39:25 -070030
31#include <boost/asio.hpp>
32#include <boost/endian/arithmetic.hpp>
33
Ed Tanouscc5a37f2017-05-11 10:27:23 -070034#include <dbus/dbus.h>
35#include <boost/iostreams/stream.hpp>
36#include <boost/property_tree/ptree.hpp>
37#include <boost/property_tree/xml_parser.hpp>
38
Ed Tanous0fdddb12017-02-28 11:06:34 -080039#include <iostream>
Ed Tanousc4771fb2017-03-13 13:39:49 -070040#include <memory>
Ed Tanous0fdddb12017-02-28 11:06:34 -080041#include <string>
Ed Tanousc4771fb2017-03-13 13:39:49 -070042#include <unordered_set>
Ed Tanous9b65f1f2017-03-07 15:17:13 -080043
Ed Tanouscc5a37f2017-05-11 10:27:23 -070044using sensor_values = std::vector<std::pair<std::string, int32_t>>;
45
46std::vector<std::string> read_dbus_xml_names(std::string& xml_data) {
47 std::vector<std::string> values;
48 // populate tree structure pt
49 using boost::property_tree::ptree;
50 ptree pt;
51 boost::iostreams::stream<boost::iostreams::array_source> stream(
52 xml_data.c_str(), xml_data.size());
53 read_xml(stream, pt);
54
55 // traverse node to find other nodes
56 for (const auto& interface : pt.get_child("node")) {
57 if (interface.first == "node") {
58 auto t = interface.second.get<std::string>("<xmlattr>", "default");
59 for (const auto& subnode : interface.second.get_child("<xmlattr>")) {
60 if (subnode.first == "name") {
61 auto t = subnode.second.get("", "unknown");
62 values.emplace_back(std::move(t));
63 }
64 }
65 }
66 }
67 return values;
68}
69
70sensor_values read_sensor_values() {
71 sensor_values values;
72 DBusError err;
73
74 int ret;
75 bool stat;
76 dbus_uint32_t level;
77
78 // initialiset the errors
79 dbus_error_init(&err);
80
81 // connect to the system bus and check for errors
82 DBusConnection* conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
83 if (dbus_error_is_set(&err)) {
84 fprintf(stderr, "Connection Error (%s)\n", err.message);
85 dbus_error_free(&err);
86 }
87 if (NULL == conn) {
88 exit(1);
89 }
90
91 // create a new method call and check for errors
92 DBusMessage* msg = dbus_message_new_method_call(
93 "org.openbmc.Sensors", // target for the method call
94 "/org/openbmc/sensors/tach", // object to call on
95 "org.freedesktop.DBus.Introspectable", // interface to call on
96 "Introspect"); // method name
97 if (NULL == msg) {
98 fprintf(stderr, "Message Null\n");
99 exit(1);
100 }
101
102 DBusPendingCall* pending;
103 // send message and get a handle for a reply
104 if (!dbus_connection_send_with_reply(conn, msg, &pending,
105 -1)) { // -1 is default timeout
106 fprintf(stderr, "Out Of Memory!\n");
107 exit(1);
108 }
109 if (NULL == pending) {
110 fprintf(stderr, "Pending Call Null\n");
111 exit(1);
112 }
113 dbus_connection_flush(conn);
114
115 // free message
116 dbus_message_unref(msg);
117
118 // block until we recieve a reply
119 dbus_pending_call_block(pending);
120
121 // get the reply message
122 msg = dbus_pending_call_steal_reply(pending);
123 if (NULL == msg) {
124 fprintf(stderr, "Reply Null\n");
125 exit(1);
126 }
127 // free the pending message handle
128 dbus_pending_call_unref(pending);
129
130 // read the parameters
131 DBusMessageIter args;
132 char* xml_struct = NULL;
133 if (!dbus_message_iter_init(msg, &args)) {
134 fprintf(stderr, "Message has no arguments!\n");
135 }
136
137 // read the arguments
138 if (!dbus_message_iter_init(msg, &args)) {
139 fprintf(stderr, "Message has no arguments!\n");
140 } else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) {
141 fprintf(stderr, "Argument is not string!\n");
142 } else {
143 dbus_message_iter_get_basic(&args, &xml_struct);
144 }
145 std::vector<std::string> methods;
146 if (xml_struct != NULL) {
147 std::string xml_data(xml_struct);
148 methods = read_dbus_xml_names(xml_data);
149 }
150
Ed Tanousf0226cd2017-05-16 12:35:38 -0700151 fprintf(stdout, "Found %zd sensors \n", methods.size());
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700152
153 for (auto& method : methods) {
154 // TODO(Ed) make sure sensor exposes SensorValue interface
155 // create a new method call and check for errors
156 DBusMessage* msg = dbus_message_new_method_call(
157 "org.openbmc.Sensors", // target for the method call
158 ("/org/openbmc/sensors/tach/" + method).c_str(), // object to call on
159 "org.openbmc.SensorValue", // interface to call on
160 "getValue"); // method name
161 if (NULL == msg) {
162 fprintf(stderr, "Message Null\n");
163 exit(1);
164 }
165
166 DBusPendingCall* pending;
167 // send message and get a handle for a reply
168 if (!dbus_connection_send_with_reply(conn, msg, &pending,
169 -1)) { // -1 is default timeout
170 fprintf(stderr, "Out Of Memory!\n");
171 exit(1);
172 }
173 if (NULL == pending) {
174 fprintf(stderr, "Pending Call Null\n");
175 exit(1);
176 }
177 dbus_connection_flush(conn);
178
179 // free message
180 dbus_message_unref(msg);
181
182 // block until we recieve a reply
183 dbus_pending_call_block(pending);
184
185 // get the reply message
186 msg = dbus_pending_call_steal_reply(pending);
187 if (NULL == msg) {
188 fprintf(stderr, "Reply Null\n");
189 exit(1);
190 }
191 // free the pending message handle
192 dbus_pending_call_unref(pending);
193
194 // read the parameters
195 DBusMessageIter args;
196 int32_t value;
197 if (!dbus_message_iter_init(msg, &args)) {
198 fprintf(stderr, "Message has no arguments!\n");
199 }
200
201 // read the arguments
202 if (!dbus_message_iter_init(msg, &args)) {
203 fprintf(stderr, "Message has no arguments!\n");
204 } else if (DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type(&args)) {
205 fprintf(stderr, "Argument is not string!\n");
206 } else {
207 DBusMessageIter sub;
208 dbus_message_iter_recurse(&args, &sub);
209 auto type = dbus_message_iter_get_arg_type(&sub);
210 if (DBUS_TYPE_INT32 != type) {
211 fprintf(stderr, "Variant subType is not int32 it is %d\n", type);
212 } else {
213 dbus_message_iter_get_basic(&sub, &value);
214 values.emplace_back(method.c_str(), value);
215 }
216 }
217 }
218
219 // free reply and close connection
220 dbus_message_unref(msg);
221 return values;
222}
223
Ed Tanous99923322017-03-03 14:21:24 -0800224int main(int argc, char** argv) {
Ed Tanous9b65f1f2017-03-07 15:17:13 -0800225 auto worker(g3::LogWorker::createLogWorker());
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700226 std::string logger_name("bmcweb");
227 std::string folder("/tmp/");
228 auto handle = worker->addDefaultLogger(logger_name, folder);
Ed Tanous99923322017-03-03 14:21:24 -0800229 g3::initializeLogging(worker.get());
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700230 auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(),
231 &crow::ColorCoutSink::ReceiveLogMessage);
Ed Tanous0fdddb12017-02-28 11:06:34 -0800232
Ed Tanous99923322017-03-03 14:21:24 -0800233 std::string ssl_pem_file("server.pem");
234 ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
Ed Tanous0fdddb12017-02-28 11:06:34 -0800235
Ed Tanous7d3dba42017-04-05 13:04:39 -0700236 crow::App<crow::TokenAuthorizationMiddleware, crow::SecurityHeadersMiddleware>
237 app;
Ed Tanousb4d29f42017-03-24 16:39:25 -0700238
Ed Tanous99923322017-03-03 14:21:24 -0800239 crow::webassets::request_routes(app);
Ed Tanousc81ca422017-03-21 16:18:49 -0700240 crow::kvm::request_routes(app);
Ed Tanous0fdddb12017-02-28 11:06:34 -0800241
Ed Tanous9b65f1f2017-03-07 15:17:13 -0800242 crow::logger::setLogLevel(crow::LogLevel::INFO);
Ed Tanousc4771fb2017-03-13 13:39:49 -0700243 CROW_ROUTE(app, "/systeminfo")
244 ([]() {
245
246 crow::json::wvalue j;
247 j["device_id"] = 0x7B;
248 j["device_provides_sdrs"] = true;
249 j["device_revision"] = true;
250 j["device_available"] = true;
251 j["firmware_revision"] = "0.68";
252
253 j["ipmi_revision"] = "2.0";
254 j["supports_chassis_device"] = true;
255 j["supports_bridge"] = true;
256 j["supports_ipmb_event_generator"] = true;
257 j["supports_ipmb_event_receiver"] = true;
258 j["supports_fru_inventory_device"] = true;
259 j["supports_sel_device"] = true;
260 j["supports_sdr_repository_device"] = true;
261 j["supports_sensor_device"] = true;
262
263 j["firmware_aux_revision"] = "0.60.foobar";
264
265 return j;
266 });
267
Ed Tanousc4771fb2017-03-13 13:39:49 -0700268 CROW_ROUTE(app, "/ipmiws")
269 .websocket()
270 .onopen([&](crow::websocket::connection& conn) {
271
272 })
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700273 .onclose(
274 [&](crow::websocket::connection& conn, const std::string& reason) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700275
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700276 })
277 .onmessage([&](crow::websocket::connection& conn, const std::string& data,
278 bool is_binary) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700279 boost::asio::io_service io_service;
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700280 using boost::asio::ip::udp;
281 udp::resolver resolver(io_service);
282 udp::resolver::query query(udp::v4(), "10.243.48.31", "623");
283 udp::endpoint receiver_endpoint = *resolver.resolve(query);
284
285 udp::socket socket(io_service);
286 socket.open(udp::v4());
287
288 socket.send_to(boost::asio::buffer(data), receiver_endpoint);
289
290 std::array<char, 255> recv_buf;
291
292 udp::endpoint sender_endpoint;
293 size_t len =
294 socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
295 // TODO(ed) THis is ugly. Find a way to not make a copy (ie, use
Ed Tanous7d3dba42017-04-05 13:04:39 -0700296 // std::string::data() to
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700297 std::string str(std::begin(recv_buf), std::end(recv_buf));
298 LOG(DEBUG) << "Got " << str << "back \n";
299 conn.send_binary(str);
300
Ed Tanousc4771fb2017-03-13 13:39:49 -0700301 });
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700302
303 CROW_ROUTE(app, "/sensortest")
304 ([]() {
305 crow::json::wvalue j;
306 auto values = read_sensor_values();
307 for (auto& pair : values) {
308 j[pair.first] = pair.second;
309 }
310
311 return j;
312 });
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700313 LOG(DEBUG) << "Building SSL context";
Ed Tanous01250f22017-04-18 17:49:51 -0700314 auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700315 int port = 18080;
Ed Tanousf0226cd2017-05-16 12:35:38 -0700316
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700317 LOG(DEBUG) << "Starting webserver on port " << port;
318 app.port(port)
Ed Tanous97099e72017-05-18 13:50:59 -0700319 .ssl(std::move(ssl_context))
Ed Tanous9140a672017-04-24 17:01:32 -0700320 //.concurrency(4)
321 .run();
Ed Tanous0fdddb12017-02-28 11:06:34 -0800322}