blob: e6052f13b57796825cbb7be1524b7d50d3941a75 [file] [log] [blame]
Ed Tanous911ac312017-08-15 09:37:42 -07001#include <crow/app.h>
2
3#include <tinyxml2.h>
Ed Tanous911ac312017-08-15 09:37:42 -07004#include <dbus_singleton.hpp>
Ed Tanouse0d918b2018-03-27 17:41:04 -07005#include <boost/algorithm/string.hpp>
Ed Tanous64530012018-02-06 17:08:16 -08006#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -07007
8namespace crow {
9namespace openbmc_mapper {
Ed Tanousba9f9a62017-10-11 16:40:35 -070010
Ed Tanous911ac312017-08-15 09:37:42 -070011void introspect_objects(crow::response &res, std::string process_name,
Ed Tanous64530012018-02-06 17:08:16 -080012 std::string path,
13 std::shared_ptr<nlohmann::json> transaction) {
Ed Tanous911ac312017-08-15 09:37:42 -070014 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -070015 [
16 &res, transaction, process_name{std::move(process_name)},
17 object_path{std::move(path)}
18 ](const boost::system::error_code ec, const std::string &introspect_xml) {
Ed Tanous911ac312017-08-15 09:37:42 -070019 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -080020 CROW_LOG_ERROR << "Introspect call failed with error: "
21 << ec.message() << " on process: " << process_name
22 << " path: " << object_path << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070023
24 } else {
Ed Tanous64530012018-02-06 17:08:16 -080025 transaction->push_back({{"path", object_path}});
Ed Tanous911ac312017-08-15 09:37:42 -070026
27 tinyxml2::XMLDocument doc;
28
29 doc.Parse(introspect_xml.c_str());
30 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
31 if (pRoot == nullptr) {
Ed Tanous64530012018-02-06 17:08:16 -080032 CROW_LOG_ERROR << "XML document failed to parse " << process_name
Ed Tanousaa2e59c2018-04-12 12:17:20 -070033 << " " << object_path << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070034
35 } else {
36 tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
37 while (node != nullptr) {
38 std::string child_path = node->Attribute("name");
39 std::string newpath;
40 if (object_path != "/") {
41 newpath += object_path;
42 }
43 newpath += "/" + child_path;
Ed Tanous64530012018-02-06 17:08:16 -080044 // introspect the subobjects as well
45 introspect_objects(res, process_name, newpath, transaction);
Ed Tanous911ac312017-08-15 09:37:42 -070046
47 node = node->NextSiblingElement("node");
48 }
49 }
50 }
51 // if we're the last outstanding caller, finish the request
Ed Tanous64530012018-02-06 17:08:16 -080052 if (transaction.use_count() == 1) {
53 res.json_value = {{"status", "ok"},
54 {"bus_name", process_name},
55 {"objects", *transaction}};
Ed Tanous911ac312017-08-15 09:37:42 -070056 res.end();
57 }
58 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -070059 process_name, path, "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -070060}
Ed Tanous64530012018-02-06 17:08:16 -080061
Ed Tanousaa2e59c2018-04-12 12:17:20 -070062// A smattering of common types to unpack. TODO(ed) this should really iterate
63// the sdbusplus object directly and build the json response
64using DbusRestVariantType = sdbusplus::message::variant<
65 std::vector<std::tuple<std::string, std::string, std::string>>, std::string,
66 int64_t, uint64_t, double, int32_t, uint32_t, int16_t, uint16_t, uint8_t,
67 bool>;
68
69using ManagedObjectType = std::vector<std::pair<
70 sdbusplus::message::object_path,
71 boost::container::flat_map<
72 std::string,
73 boost::container::flat_map<std::string, DbusRestVariantType>>>>;
74
75void get_managed_objects_for_enumerate(
Ed Tanous64530012018-02-06 17:08:16 -080076 const std::string &object_name, const std::string &connection_name,
77 crow::response &res, std::shared_ptr<nlohmann::json> transaction) {
78 crow::connections::system_bus->async_method_call(
79 [&res, transaction](const boost::system::error_code ec,
80 const ManagedObjectType &objects) {
81 if (ec) {
82 CROW_LOG_ERROR << ec;
83 } else {
84 nlohmann::json &data_json = *transaction;
Ed Tanousaa2e59c2018-04-12 12:17:20 -070085
Ed Tanous64530012018-02-06 17:08:16 -080086 for (auto &object_path : objects) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -070087 CROW_LOG_DEBUG << "Reading object "
88 << static_cast<const std::string&>(object_path.first);
89 nlohmann::json &object_json =
90 data_json[static_cast<const std::string&>(object_path.first)];
91 if (object_json.is_null()) {
92 object_json = nlohmann::json::object();
93 }
Ed Tanous64530012018-02-06 17:08:16 -080094 for (const auto &interface : object_path.second) {
95 for (const auto &property : interface.second) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -070096 nlohmann::json &property_json = object_json[property.first];
97 mapbox::util::apply_visitor(
98 [&property_json](auto &&val) { property_json = val; },
Ed Tanous64530012018-02-06 17:08:16 -080099 property.second);
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700100
101 // dbus-rest represents booleans as 1 or 0, implement to match
102 // TODO(ed) see if dbus-rest should be changed
103 const bool *property_bool =
104 property_json.get_ptr<const bool *>();
105 if (property_bool != nullptr) {
106 property_json = *property_bool ? 1 : 0;
107 }
Ed Tanous64530012018-02-06 17:08:16 -0800108 }
109 }
110 }
111 }
112
113 if (transaction.use_count() == 1) {
114 res.json_value = {{"message", "200 OK"},
115 {"status", "ok"},
116 {"data", std::move(*transaction)}};
117 res.end();
118 }
119 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700120 connection_name, object_name, "org.freedesktop.DBus.ObjectManager",
121 "GetManagedObjects");
122}
Ed Tanous64530012018-02-06 17:08:16 -0800123
124using GetSubTreeType = std::vector<
125 std::pair<std::string,
126 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
127
128void handle_enumerate(crow::response &res, const std::string &object_path) {
129 crow::connections::system_bus->async_method_call(
130 [&res, object_path{std::string(object_path)} ](
131 const boost::system::error_code ec,
132 const GetSubTreeType &object_names) {
133 if (ec) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700134 res.result(boost::beast::http::status::internal_server_error);
Ed Tanous64530012018-02-06 17:08:16 -0800135 res.end();
136 return;
137 }
138
139 boost::container::flat_set<std::string> connections;
140
141 for (const auto &object : object_names) {
142 for (const auto &connection : object.second) {
143 connections.insert(connection.first);
144 }
145 }
146
147 if (connections.size() <= 0) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700148 res.result(boost::beast::http::status::not_found);
Ed Tanous64530012018-02-06 17:08:16 -0800149 res.end();
150 return;
151 }
152 auto transaction =
153 std::make_shared<nlohmann::json>(nlohmann::json::object());
154 for (const std::string &connection : connections) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700155 get_managed_objects_for_enumerate(object_path, connection, res,
156 transaction);
Ed Tanous64530012018-02-06 17:08:16 -0800157 }
158
159 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700160 "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
161 "xyz.openbmc_project.ObjectMapper", "GetSubTree", object_path, (int32_t)0,
162 std::array<std::string, 0>());
Ed Tanous64530012018-02-06 17:08:16 -0800163}
Ed Tanous911ac312017-08-15 09:37:42 -0700164
165template <typename... Middlewares>
166void request_routes(Crow<Middlewares...> &app) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700167 CROW_ROUTE(app, "/bus/")
168 .methods("GET"_method)([](const crow::request &req, crow::response &res) {
169 res.json_value = {{"busses", {{{"name", "system"}}}}, {"status", "ok"}};
170 });
Ed Tanous911ac312017-08-15 09:37:42 -0700171
172 CROW_ROUTE(app, "/bus/system/")
173 .methods("GET"_method)([](const crow::request &req, crow::response &res) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700174
175 auto myCallback = [&res](const boost::system::error_code ec,
176 std::vector<std::string> &names) {
177 if (ec) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700178 res.result(boost::beast::http::status::internal_server_error);
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700179 } else {
180 std::sort(names.begin(), names.end());
181 nlohmann::json j{{"status", "ok"}};
182 auto &objects_sub = j["objects"];
183 for (auto &name : names) {
184 objects_sub.push_back({{"name", name}});
185 }
186 res.json_value = std::move(j);
187 }
188 res.end();
189 };
Ed Tanous911ac312017-08-15 09:37:42 -0700190 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700191 std::move(myCallback), "org.freedesktop.DBus", "/",
192 "org.freedesktop.DBus", "ListNames");
Ed Tanous911ac312017-08-15 09:37:42 -0700193 });
194
Ed Tanousba9f9a62017-10-11 16:40:35 -0700195 CROW_ROUTE(app, "/list/")
196 .methods("GET"_method)([](const crow::request &req, crow::response &res) {
197 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700198 [&res](const boost::system::error_code ec,
199 const std::vector<std::string> &object_paths) {
Ed Tanousba9f9a62017-10-11 16:40:35 -0700200 if (ec) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700201 res.result(boost::beast::http::status::internal_server_error);
Ed Tanousba9f9a62017-10-11 16:40:35 -0700202 } else {
Ed Tanous64530012018-02-06 17:08:16 -0800203 res.json_value = {{"status", "ok"},
204 {"message", "200 OK"},
205 {"data", std::move(object_paths)}};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700206 }
207 res.end();
208 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700209 "xyz.openbmc_project.ObjectMapper",
210 "/xyz/openbmc_project/object_mapper",
211 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "",
212 static_cast<int32_t>(99), std::array<std::string, 0>());
Ed Tanousba9f9a62017-10-11 16:40:35 -0700213 });
214
Ed Tanous64530012018-02-06 17:08:16 -0800215 CROW_ROUTE(app, "/xyz/<path>")
shiyilei00b92f72017-11-12 16:21:16 +0800216 .methods("GET"_method,
217 "PUT"_method)([](const crow::request &req, crow::response &res,
Ed Tanousba9f9a62017-10-11 16:40:35 -0700218 const std::string &path) {
Ed Tanous64530012018-02-06 17:08:16 -0800219 std::shared_ptr<nlohmann::json> transaction =
220 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanousba9f9a62017-10-11 16:40:35 -0700221 using GetObjectType =
222 std::vector<std::pair<std::string, std::vector<std::string>>>;
shiyilei00b92f72017-11-12 16:21:16 +0800223 std::string object_path;
224 std::string dest_property;
225 std::string property_set_value;
226 size_t attr_position = path.find("/attr/");
Ed Tanous64530012018-02-06 17:08:16 -0800227 if (attr_position == path.npos) {
shiyilei00b92f72017-11-12 16:21:16 +0800228 object_path = "/xyz/" + path;
Ed Tanous64530012018-02-06 17:08:16 -0800229 } else {
shiyilei00b92f72017-11-12 16:21:16 +0800230 object_path = "/xyz/" + path.substr(0, attr_position);
231 dest_property =
232 path.substr((attr_position + strlen("/attr/")), path.length());
233 auto request_dbus_data =
234 nlohmann::json::parse(req.body, nullptr, false);
235 if (request_dbus_data.is_discarded()) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700236 res.result(boost::beast::http::status::unauthorized);
shiyilei00b92f72017-11-12 16:21:16 +0800237 res.end();
238 return;
239 }
Ed Tanousba9f9a62017-10-11 16:40:35 -0700240
shiyilei00b92f72017-11-12 16:21:16 +0800241 auto property_value_it = request_dbus_data.find("data");
242 if (property_value_it == request_dbus_data.end()) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700243 res.result(boost::beast::http::status::unauthorized);
shiyilei00b92f72017-11-12 16:21:16 +0800244 res.end();
245 return;
246 }
247
248 property_set_value = property_value_it->get<const std::string>();
249 if (property_set_value.empty()) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700250 res.result(boost::beast::http::status::unauthorized);
shiyilei00b92f72017-11-12 16:21:16 +0800251 res.end();
252 return;
253 }
254 }
255
Ed Tanous64530012018-02-06 17:08:16 -0800256 if (boost::ends_with(object_path, "/enumerate")) {
257 object_path.erase(object_path.end() - 10, object_path.end());
258 handle_enumerate(res, object_path);
259 return;
260 }
261
Ed Tanousba9f9a62017-10-11 16:40:35 -0700262 crow::connections::system_bus->async_method_call(
shiyilei00b92f72017-11-12 16:21:16 +0800263 [
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700264 &res, &req, object_path{std::move(object_path)},
265 dest_property{std::move(dest_property)},
266 property_set_value{std::move(property_set_value)}, transaction
shiyilei00b92f72017-11-12 16:21:16 +0800267 ](const boost::system::error_code ec,
268 const GetObjectType &object_names) {
Ed Tanousba9f9a62017-10-11 16:40:35 -0700269 if (ec) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700270 res.result(boost::beast::http::status::internal_server_error);
Ed Tanousba9f9a62017-10-11 16:40:35 -0700271 res.end();
272 return;
273 }
274 if (object_names.size() != 1) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700275 res.result(boost::beast::http::status::not_found);
Ed Tanousba9f9a62017-10-11 16:40:35 -0700276 res.end();
277 return;
278 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700279 if (req.method() == "GET"_method) {
shiyilei00b92f72017-11-12 16:21:16 +0800280 for (auto &interface : object_names[0].second) {
shiyilei00b92f72017-11-12 16:21:16 +0800281 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700282 [&res, transaction](
283 const boost::system::error_code ec,
shiyilei00b92f72017-11-12 16:21:16 +0800284 const std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700285 std::string, DbusRestVariantType>> &properties) {
shiyilei00b92f72017-11-12 16:21:16 +0800286 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800287 CROW_LOG_ERROR << "Bad dbus request error: " << ec;
shiyilei00b92f72017-11-12 16:21:16 +0800288 } else {
289 for (auto &property : properties) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700290 nlohmann::json &it = (*transaction)[property.first];
291 mapbox::util::apply_visitor(
292 [&it](auto &&val) { it = val; },
shiyilei00b92f72017-11-12 16:21:16 +0800293 property.second);
294 }
295 }
Ed Tanous64530012018-02-06 17:08:16 -0800296 if (transaction.use_count() == 1) {
297 res.json_value = {{"status", "ok"},
298 {"message", "200 OK"},
299 {"data", *transaction}};
300
shiyilei00b92f72017-11-12 16:21:16 +0800301 res.end();
shiyilei00b92f72017-11-12 16:21:16 +0800302 }
303 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700304 object_names[0].first, object_path,
305 "org.freedesktop.DBus.Properties", "GetAll", interface);
shiyilei00b92f72017-11-12 16:21:16 +0800306 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700307 } else if (req.method() == "PUT"_method) {
shiyilei00b92f72017-11-12 16:21:16 +0800308 for (auto &interface : object_names[0].second) {
shiyilei00b92f72017-11-12 16:21:16 +0800309 crow::connections::system_bus->async_method_call(
310 [
311 &, interface{std::move(interface)},
312 object_names{std::move(object_names)},
313 object_path{std::move(object_path)},
314 dest_property{std::move(dest_property)},
Ed Tanous64530012018-02-06 17:08:16 -0800315 property_set_value{std::move(property_set_value)},
316 transaction
shiyilei00b92f72017-11-12 16:21:16 +0800317 ](const boost::system::error_code ec,
Ed Tanous64530012018-02-06 17:08:16 -0800318 const boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700319 std::string, DbusRestVariantType> &properties) {
shiyilei00b92f72017-11-12 16:21:16 +0800320 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800321 CROW_LOG_ERROR << "Bad dbus request error: " << ec;
shiyilei00b92f72017-11-12 16:21:16 +0800322 } else {
Ed Tanous64530012018-02-06 17:08:16 -0800323 auto it = properties.find(dest_property);
324 if (it != properties.end()) {
325 // find the matched property in the interface
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700326 DbusRestVariantType property_value(
327 property_set_value);
328 // create the dbus variant for dbus call
Ed Tanous64530012018-02-06 17:08:16 -0800329 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700330 [transaction](
331 const boost::system::error_code ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800332 // use the method "Set" to set the property
333 // value
334 if (ec) {
335 CROW_LOG_ERROR << "Bad dbus request error: "
336 << ec;
337 }
338 // find the matched property and send the
339 // response
340 *transaction = {{"status", "ok"},
341 {"message", "200 OK"},
342 {"data", nullptr}};
343
344 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700345 object_names[0].first, object_path,
346 "org.freedesktop.DBus.Properties", "Set",
Ed Tanous64530012018-02-06 17:08:16 -0800347 interface, dest_property, property_value);
shiyilei00b92f72017-11-12 16:21:16 +0800348 }
Ed Tanous64530012018-02-06 17:08:16 -0800349 }
350 // if we are the last caller, finish the transaction
351 if (transaction.use_count() == 1) {
352 // if nobody filled in the property, all calls either
353 // errored, or failed
354 if (transaction == nullptr) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700355 res.result(boost::beast::http::status::forbidden);
Ed Tanous64530012018-02-06 17:08:16 -0800356 res.json_value = {{"status", "error"},
357 {"message", "403 Forbidden"},
358 {"data",
359 {{"message",
360 "The specified property "
361 "cannot be created: " +
362 dest_property}}}};
363
364 } else {
365 res.json_value = *transaction;
shiyilei00b92f72017-11-12 16:21:16 +0800366 }
Ed Tanous64530012018-02-06 17:08:16 -0800367
368 res.end();
369 return;
Ed Tanousba9f9a62017-10-11 16:40:35 -0700370 }
shiyilei00b92f72017-11-12 16:21:16 +0800371 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700372 object_names[0].first, object_path,
373 "org.freedesktop.DBus.Properties", "GetAll", interface);
shiyilei00b92f72017-11-12 16:21:16 +0800374 }
Ed Tanousba9f9a62017-10-11 16:40:35 -0700375 }
376 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700377 "xyz.openbmc_project.ObjectMapper",
378 "/xyz/openbmc_project/object_mapper",
379 "xyz.openbmc_project.ObjectMapper", "GetObject", object_path,
380 std::array<std::string, 0>());
Ed Tanousba9f9a62017-10-11 16:40:35 -0700381 });
shiyilei00b92f72017-11-12 16:21:16 +0800382
Ed Tanous911ac312017-08-15 09:37:42 -0700383 CROW_ROUTE(app, "/bus/system/<str>/")
384 .methods("GET"_method)([](const crow::request &req, crow::response &res,
385 const std::string &connection) {
Ed Tanous64530012018-02-06 17:08:16 -0800386 std::shared_ptr<nlohmann::json> transaction;
387 introspect_objects(res, connection, "/", transaction);
Ed Tanous911ac312017-08-15 09:37:42 -0700388 });
389
390 CROW_ROUTE(app, "/bus/system/<str>/<path>")
391 .methods("GET"_method)([](const crow::request &req, crow::response &res,
392 const std::string &process_name,
393 const std::string &requested_path) {
394
395 std::vector<std::string> strs;
396 boost::split(strs, requested_path, boost::is_any_of("/"));
397 std::string object_path;
398 std::string interface_name;
399 std::string method_name;
400 auto it = strs.begin();
401 if (it == strs.end()) {
402 object_path = "/";
403 }
404 while (it != strs.end()) {
405 // Check if segment contains ".". If it does, it must be an
406 // interface
407 if ((*it).find(".") != std::string::npos) {
408 break;
Ed Tanousba9f9a62017-10-11 16:40:35 -0700409 // THis check is neccesary as the trailing slash gets parsed as
Ed Tanous64530012018-02-06 17:08:16 -0800410 // part of our <path> specifier above, which causes the normal
411 // trailing backslash redirector to fail.
Ed Tanous911ac312017-08-15 09:37:42 -0700412 } else if (!it->empty()) {
413 object_path += "/" + *it;
414 }
415 it++;
416 }
417 if (it != strs.end()) {
418 interface_name = *it;
419 it++;
420
421 // after interface, we might have a method name
422 if (it != strs.end()) {
423 method_name = *it;
424 it++;
425 }
426 }
427 if (it != strs.end()) {
428 // if there is more levels past the method name, something went
429 // wrong, throw an error
Ed Tanouse0d918b2018-03-27 17:41:04 -0700430 res.result(boost::beast::http::status::not_found);
Ed Tanous911ac312017-08-15 09:37:42 -0700431 res.end();
432 return;
433 }
Ed Tanous911ac312017-08-15 09:37:42 -0700434 if (interface_name.empty()) {
435 crow::connections::system_bus->async_method_call(
436 [
437 &, process_name{std::move(process_name)},
438 object_path{std::move(object_path)}
439 ](const boost::system::error_code ec,
440 const std::string &introspect_xml) {
441 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800442 CROW_LOG_ERROR
Ed Tanous911ac312017-08-15 09:37:42 -0700443 << "Introspect call failed with error: " << ec.message()
444 << " on process: " << process_name
445 << " path: " << object_path << "\n";
446
447 } else {
448 tinyxml2::XMLDocument doc;
449
450 doc.Parse(introspect_xml.c_str());
451 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
452 if (pRoot == nullptr) {
Ed Tanous64530012018-02-06 17:08:16 -0800453 CROW_LOG_ERROR << "XML document failed to parse "
454 << process_name << " " << object_path
455 << "\n";
Ed Tanouse0d918b2018-03-27 17:41:04 -0700456 res.json_value = {{"status", "XML parse error"}};
457 res.result(
458 boost::beast::http::status::internal_server_error);
Ed Tanous911ac312017-08-15 09:37:42 -0700459 } else {
460 nlohmann::json interfaces_array = nlohmann::json::array();
461 tinyxml2::XMLElement *interface =
462 pRoot->FirstChildElement("interface");
463
464 while (interface != nullptr) {
465 std::string iface_name = interface->Attribute("name");
466 interfaces_array.push_back({{"name", iface_name}});
467
468 interface = interface->NextSiblingElement("interface");
469 }
Ed Tanous64530012018-02-06 17:08:16 -0800470 res.json_value = {{"status", "ok"},
471 {"bus_name", process_name},
472 {"interfaces", interfaces_array},
473 {"object_path", object_path}};
Ed Tanous911ac312017-08-15 09:37:42 -0700474 }
475 }
476 res.end();
477 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700478 process_name, object_path, "org.freedesktop.DBus.Introspectable",
479 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700480 } else {
481 crow::connections::system_bus->async_method_call(
482 [
483 &, process_name{std::move(process_name)},
484 interface_name{std::move(interface_name)},
485 object_path{std::move(object_path)}
486 ](const boost::system::error_code ec,
487 const std::string &introspect_xml) {
488 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800489 CROW_LOG_ERROR
Ed Tanous911ac312017-08-15 09:37:42 -0700490 << "Introspect call failed with error: " << ec.message()
491 << " on process: " << process_name
492 << " path: " << object_path << "\n";
493
494 } else {
495 tinyxml2::XMLDocument doc;
496
497 doc.Parse(introspect_xml.c_str());
498 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
499 if (pRoot == nullptr) {
Ed Tanous64530012018-02-06 17:08:16 -0800500 CROW_LOG_ERROR << "XML document failed to parse "
501 << process_name << " " << object_path
502 << "\n";
Ed Tanouse0d918b2018-03-27 17:41:04 -0700503 res.result(
504 boost::beast::http::status::internal_server_error);
Ed Tanous911ac312017-08-15 09:37:42 -0700505
506 } else {
507 tinyxml2::XMLElement *node =
508 pRoot->FirstChildElement("node");
509
510 // if we know we're the only call, build the json directly
511 nlohmann::json methods_array = nlohmann::json::array();
512 nlohmann::json signals_array = nlohmann::json::array();
513 tinyxml2::XMLElement *interface =
514 pRoot->FirstChildElement("interface");
515
516 while (interface != nullptr) {
517 std::string iface_name = interface->Attribute("name");
518
519 if (iface_name == interface_name) {
520 tinyxml2::XMLElement *methods =
521 interface->FirstChildElement("method");
522 while (methods != nullptr) {
523 nlohmann::json args_array = nlohmann::json::array();
524 tinyxml2::XMLElement *arg =
525 methods->FirstChildElement("arg");
526 while (arg != nullptr) {
527 args_array.push_back(
528 {{"name", arg->Attribute("name")},
529 {"type", arg->Attribute("type")},
530 {"direction", arg->Attribute("direction")}});
531 arg = arg->NextSiblingElement("arg");
532 }
533 methods_array.push_back(
534 {{"name", methods->Attribute("name")},
Ed Tanous64530012018-02-06 17:08:16 -0800535 {"uri", "/bus/system/" + process_name +
536 object_path + "/" + interface_name +
537 "/" + methods->Attribute("name")},
Ed Tanous911ac312017-08-15 09:37:42 -0700538 {"args", args_array}});
539 methods = methods->NextSiblingElement("method");
540 }
541 tinyxml2::XMLElement *signals =
542 interface->FirstChildElement("signal");
543 while (signals != nullptr) {
544 nlohmann::json args_array = nlohmann::json::array();
545
546 tinyxml2::XMLElement *arg =
547 signals->FirstChildElement("arg");
548 while (arg != nullptr) {
549 std::string name = arg->Attribute("name");
550 std::string type = arg->Attribute("type");
551 args_array.push_back({
Ed Tanous64530012018-02-06 17:08:16 -0800552 {"name", name},
553 {"type", type},
Ed Tanous911ac312017-08-15 09:37:42 -0700554 });
555 arg = arg->NextSiblingElement("arg");
556 }
557 signals_array.push_back(
558 {{"name", signals->Attribute("name")},
559 {"args", args_array}});
560 signals = signals->NextSiblingElement("signal");
561 }
562
563 nlohmann::json j{
564 {"status", "ok"},
565 {"bus_name", process_name},
566 {"interface", interface_name},
567 {"methods", methods_array},
568 {"object_path", object_path},
569 {"properties", nlohmann::json::object()},
570 {"signals", signals_array}};
571
572 res.write(j.dump());
573 break;
574 }
575
576 interface = interface->NextSiblingElement("interface");
577 }
578 if (interface == nullptr) {
579 // if we got to the end of the list and never found a
580 // match, throw 404
Ed Tanouse0d918b2018-03-27 17:41:04 -0700581 res.result(boost::beast::http::status::not_found);
Ed Tanous911ac312017-08-15 09:37:42 -0700582 }
583 }
584 }
585 res.end();
586 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700587 process_name, object_path, "org.freedesktop.DBus.Introspectable",
588 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700589 }
590
591 });
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700592} // namespace openbmc_mapper
Ed Tanous911ac312017-08-15 09:37:42 -0700593} // namespace openbmc_mapper
594} // namespace crow