blob: f47eb797a82f161579d1e40649b3a8b7a10c6d63 [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 Tanous0fdddb12017-02-28 11:06:34 -0800231
Ed Tanous99923322017-03-03 14:21:24 -0800232 std::string ssl_pem_file("server.pem");
233 ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
Ed Tanous0fdddb12017-02-28 11:06:34 -0800234
Ed Tanous7d3dba42017-04-05 13:04:39 -0700235 crow::App<crow::TokenAuthorizationMiddleware, crow::SecurityHeadersMiddleware>
236 app;
Ed Tanousb4d29f42017-03-24 16:39:25 -0700237
Ed Tanous99923322017-03-03 14:21:24 -0800238 crow::webassets::request_routes(app);
Ed Tanousc81ca422017-03-21 16:18:49 -0700239 crow::kvm::request_routes(app);
Ed Tanous0fdddb12017-02-28 11:06:34 -0800240
Ed Tanous9b65f1f2017-03-07 15:17:13 -0800241 crow::logger::setLogLevel(crow::LogLevel::INFO);
Ed Tanousc4771fb2017-03-13 13:39:49 -0700242 CROW_ROUTE(app, "/systeminfo")
243 ([]() {
244
245 crow::json::wvalue j;
246 j["device_id"] = 0x7B;
247 j["device_provides_sdrs"] = true;
248 j["device_revision"] = true;
249 j["device_available"] = true;
250 j["firmware_revision"] = "0.68";
251
252 j["ipmi_revision"] = "2.0";
253 j["supports_chassis_device"] = true;
254 j["supports_bridge"] = true;
255 j["supports_ipmb_event_generator"] = true;
256 j["supports_ipmb_event_receiver"] = true;
257 j["supports_fru_inventory_device"] = true;
258 j["supports_sel_device"] = true;
259 j["supports_sdr_repository_device"] = true;
260 j["supports_sensor_device"] = true;
261
262 j["firmware_aux_revision"] = "0.60.foobar";
263
264 return j;
265 });
266
Ed Tanousc4771fb2017-03-13 13:39:49 -0700267 CROW_ROUTE(app, "/ipmiws")
268 .websocket()
269 .onopen([&](crow::websocket::connection& conn) {
270
271 })
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700272 .onclose(
273 [&](crow::websocket::connection& conn, const std::string& reason) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700274
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700275 })
276 .onmessage([&](crow::websocket::connection& conn, const std::string& data,
277 bool is_binary) {
Ed Tanousc4771fb2017-03-13 13:39:49 -0700278 boost::asio::io_service io_service;
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700279 using boost::asio::ip::udp;
280 udp::resolver resolver(io_service);
281 udp::resolver::query query(udp::v4(), "10.243.48.31", "623");
282 udp::endpoint receiver_endpoint = *resolver.resolve(query);
283
284 udp::socket socket(io_service);
285 socket.open(udp::v4());
286
287 socket.send_to(boost::asio::buffer(data), receiver_endpoint);
288
289 std::array<char, 255> recv_buf;
290
291 udp::endpoint sender_endpoint;
292 size_t len =
293 socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
294 // TODO(ed) THis is ugly. Find a way to not make a copy (ie, use
Ed Tanous7d3dba42017-04-05 13:04:39 -0700295 // std::string::data() to
Ed Tanous1ccd57c2017-03-21 13:15:58 -0700296 std::string str(std::begin(recv_buf), std::end(recv_buf));
297 LOG(DEBUG) << "Got " << str << "back \n";
298 conn.send_binary(str);
299
Ed Tanousc4771fb2017-03-13 13:39:49 -0700300 });
Ed Tanouscc5a37f2017-05-11 10:27:23 -0700301
302 CROW_ROUTE(app, "/sensortest")
303 ([]() {
304 crow::json::wvalue j;
305 auto values = read_sensor_values();
306 for (auto& pair : values) {
307 j[pair.first] = pair.second;
308 }
309
310 return j;
311 });
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700312 LOG(DEBUG) << "Building SSL context";
Ed Tanous01250f22017-04-18 17:49:51 -0700313 auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700314 int port = 18080;
Ed Tanousf0226cd2017-05-16 12:35:38 -0700315
Ed Tanous4c3cbc62017-05-16 09:17:42 -0700316 LOG(DEBUG) << "Starting webserver on port " << port;
317 app.port(port)
Ed Tanous97099e72017-05-18 13:50:59 -0700318 .ssl(std::move(ssl_context))
Ed Tanous9140a672017-04-24 17:01:32 -0700319 //.concurrency(4)
320 .run();
Ed Tanous0fdddb12017-02-28 11:06:34 -0800321}