xref: /openbmc/bmcweb/include/openbmc_dbus_rest.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
4b9b2e0b2SEd Tanous 
55b4aa86bSJames Feist #pragma once
63ccb3adbSEd Tanous #include "app.hpp"
73ccb3adbSEd Tanous #include "async_resp.hpp"
895c6307aSEd Tanous #include "boost_formatters.hpp"
93ccb3adbSEd Tanous #include "dbus_singleton.hpp"
107a1dbc48SGeorge Liu #include "dbus_utility.hpp"
11d5c80ad9SNan Zhou #include "http_request.hpp"
12d5c80ad9SNan Zhou #include "http_response.hpp"
1395c6307aSEd Tanous #include "json_formatters.hpp"
14d5c80ad9SNan Zhou #include "logging.hpp"
151aa0c2b8SEd Tanous #include "parsing.hpp"
1650ebd4afSEd Tanous #include "str_utility.hpp"
17d5c80ad9SNan Zhou 
18d5c80ad9SNan Zhou #include <systemd/sd-bus-protocol.h>
19d5c80ad9SNan Zhou #include <systemd/sd-bus.h>
20911ac317SEd Tanous #include <tinyxml2.h>
211abe55efSEd Tanous 
22*d7857201SEd Tanous #include <boost/beast/http/field.hpp>
23d5c80ad9SNan Zhou #include <boost/beast/http/status.hpp>
24d5c80ad9SNan Zhou #include <boost/beast/http/verb.hpp>
25d5c80ad9SNan Zhou #include <boost/container/flat_map.hpp>
26e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
27d5c80ad9SNan Zhou #include <nlohmann/json.hpp>
28d5c80ad9SNan Zhou #include <sdbusplus/asio/connection.hpp>
29d5c80ad9SNan Zhou #include <sdbusplus/message.hpp>
30d5c80ad9SNan Zhou #include <sdbusplus/message/native_types.hpp>
311214b7e7SGunnar Mills 
32d5c80ad9SNan Zhou #include <algorithm>
33d5c80ad9SNan Zhou #include <array>
34d5c80ad9SNan Zhou #include <cerrno>
35d5c80ad9SNan Zhou #include <cstdint>
36d5c80ad9SNan Zhou #include <cstring>
374418c7f0SJames Feist #include <filesystem>
38d5c80ad9SNan Zhou #include <functional>
39d5c80ad9SNan Zhou #include <initializer_list>
40d5c80ad9SNan Zhou #include <limits>
41d5c80ad9SNan Zhou #include <map>
42d5c80ad9SNan Zhou #include <memory>
433544d2a7SEd Tanous #include <ranges>
44d9207047SRamesh Iyyar #include <regex>
45d5c80ad9SNan Zhou #include <string>
46d5c80ad9SNan Zhou #include <string_view>
47d5c80ad9SNan Zhou #include <type_traits>
48b5a76932SEd Tanous #include <utility>
49d5c80ad9SNan Zhou #include <variant>
50d5c80ad9SNan Zhou #include <vector>
51d5c80ad9SNan Zhou 
521abe55efSEd Tanous namespace crow
531abe55efSEd Tanous {
541abe55efSEd Tanous namespace openbmc_mapper
551abe55efSEd Tanous {
5623a21a1cSEd Tanous const constexpr char* notFoundMsg = "404 Not Found";
5723a21a1cSEd Tanous const constexpr char* badReqMsg = "400 Bad Request";
5823a21a1cSEd Tanous const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
5923a21a1cSEd Tanous const constexpr char* forbiddenMsg = "403 Forbidden";
601aa0c2b8SEd Tanous const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
6123a21a1cSEd Tanous const constexpr char* methodFailedMsg = "500 Method Call Failed";
6223a21a1cSEd Tanous const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
6323a21a1cSEd Tanous const constexpr char* notFoundDesc =
642ae60096SMatt Spinler     "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
6523a21a1cSEd Tanous const constexpr char* propNotFoundDesc =
6623a21a1cSEd Tanous     "The specified property cannot be found";
6723a21a1cSEd Tanous const constexpr char* noJsonDesc = "No JSON object could be decoded";
681aa0c2b8SEd Tanous const constexpr char* invalidContentType =
691aa0c2b8SEd Tanous     "Content-type header is missing or invalid";
7023a21a1cSEd Tanous const constexpr char* methodNotFoundDesc =
7123a21a1cSEd Tanous     "The specified method cannot be found";
7223a21a1cSEd Tanous const constexpr char* methodNotAllowedDesc = "Method not allowed";
7323a21a1cSEd Tanous const constexpr char* forbiddenPropDesc =
7423a21a1cSEd Tanous     "The specified property cannot be created";
7523a21a1cSEd Tanous const constexpr char* forbiddenResDesc =
7623a21a1cSEd Tanous     "The specified resource cannot be created";
772ae60096SMatt Spinler 
validateFilename(const std::string & filename)78482c45a5SJosh Lehan inline bool validateFilename(const std::string& filename)
79482c45a5SJosh Lehan {
804b242749SEd Tanous     static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
81482c45a5SJosh Lehan 
82482c45a5SJosh Lehan     return std::regex_match(filename, validFilename);
83482c45a5SJosh Lehan }
84482c45a5SJosh Lehan 
setErrorResponse(crow::Response & res,boost::beast::http::status result,const std::string & desc,std::string_view msg)8523a21a1cSEd Tanous inline void setErrorResponse(crow::Response& res,
8623a21a1cSEd Tanous                              boost::beast::http::status result,
8726ccae32SEd Tanous                              const std::string& desc, std::string_view msg)
882ae60096SMatt Spinler {
892ae60096SMatt Spinler     res.result(result);
901476687dSEd Tanous     res.jsonValue["data"]["description"] = desc;
911476687dSEd Tanous     res.jsonValue["message"] = msg;
921476687dSEd Tanous     res.jsonValue["status"] = "error";
932ae60096SMatt Spinler }
942ae60096SMatt Spinler 
introspectObjects(const std::string & processName,const std::string & objectPath,const std::shared_ptr<bmcweb::AsyncResp> & transaction)95bd79bce8SPatrick Williams inline void introspectObjects(
96bd79bce8SPatrick Williams     const std::string& processName, const std::string& objectPath,
97b5a76932SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& transaction)
981abe55efSEd Tanous {
99e3cb5a31SEd Tanous     if (transaction->res.jsonValue.is_null())
100e3cb5a31SEd Tanous     {
1011476687dSEd Tanous         transaction->res.jsonValue["status"] = "ok";
1021476687dSEd Tanous         transaction->res.jsonValue["bus_name"] = processName;
1031476687dSEd Tanous         transaction->res.jsonValue["objects"] = nlohmann::json::array();
104e3cb5a31SEd Tanous     }
105e3cb5a31SEd Tanous 
10655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
107e3cb5a31SEd Tanous         [transaction, processName{std::string(processName)},
108e3cb5a31SEd Tanous          objectPath{std::string(objectPath)}](
1095e7e2dc5SEd Tanous             const boost::system::error_code& ec,
11081ce609eSEd Tanous             const std::string& introspectXml) {
1111abe55efSEd Tanous             if (ec)
1121abe55efSEd Tanous             {
11362598e31SEd Tanous                 BMCWEB_LOG_ERROR(
11462598e31SEd Tanous                     "Introspect call failed with error: {} on process: {} path: {}",
11562598e31SEd Tanous                     ec.message(), processName, objectPath);
116e3cb5a31SEd Tanous                 return;
1171abe55efSEd Tanous             }
1181476687dSEd Tanous             nlohmann::json::object_t object;
1191476687dSEd Tanous             object["path"] = objectPath;
1201476687dSEd Tanous 
121bd79bce8SPatrick Williams             transaction->res.jsonValue["objects"].emplace_back(
122bd79bce8SPatrick Williams                 std::move(object));
123911ac317SEd Tanous 
124911ac317SEd Tanous             tinyxml2::XMLDocument doc;
125911ac317SEd Tanous 
12681ce609eSEd Tanous             doc.Parse(introspectXml.c_str());
127911ac317SEd Tanous             tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1281abe55efSEd Tanous             if (pRoot == nullptr)
1291abe55efSEd Tanous             {
130bd79bce8SPatrick Williams                 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
131bd79bce8SPatrick Williams                                  processName, objectPath);
1321abe55efSEd Tanous             }
1331abe55efSEd Tanous             else
1341abe55efSEd Tanous             {
135e3cb5a31SEd Tanous                 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
1361abe55efSEd Tanous                 while (node != nullptr)
1371abe55efSEd Tanous                 {
138e3cb5a31SEd Tanous                     const char* childPath = node->Attribute("name");
139e3cb5a31SEd Tanous                     if (childPath != nullptr)
140e3cb5a31SEd Tanous                     {
141911ac317SEd Tanous                         std::string newpath;
1421abe55efSEd Tanous                         if (objectPath != "/")
1431abe55efSEd Tanous                         {
14455c7b7a2SEd Tanous                             newpath += objectPath;
145911ac317SEd Tanous                         }
146e3cb5a31SEd Tanous                         newpath += std::string("/") + childPath;
14764530018SEd Tanous                         // introspect the subobjects as well
148e3cb5a31SEd Tanous                         introspectObjects(processName, newpath, transaction);
149e3cb5a31SEd Tanous                     }
150911ac317SEd Tanous 
151911ac317SEd Tanous                     node = node->NextSiblingElement("node");
152911ac317SEd Tanous                 }
153911ac317SEd Tanous             }
154911ac317SEd Tanous         },
155e3cb5a31SEd Tanous         processName, objectPath, "org.freedesktop.DBus.Introspectable",
1561abe55efSEd Tanous         "Introspect");
157911ac317SEd Tanous }
15864530018SEd Tanous 
getPropertiesForEnumerate(const std::string & objectPath,const std::string & service,const std::string & interface,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)15923a21a1cSEd Tanous inline void getPropertiesForEnumerate(
16023a21a1cSEd Tanous     const std::string& objectPath, const std::string& service,
161b5a76932SEd Tanous     const std::string& interface,
162b5a76932SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1632df1e7dbSMatt Spinler {
16462598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
16562598e31SEd Tanous                      interface);
1662df1e7dbSMatt Spinler 
167deae6a78SEd Tanous     dbus::utility::getAllProperties(
168deae6a78SEd Tanous         service, objectPath, interface,
169b9d36b47SEd Tanous         [asyncResp, objectPath, service,
1705e7e2dc5SEd Tanous          interface](const boost::system::error_code& ec,
171b9d36b47SEd Tanous                     const dbus::utility::DBusPropertiesMap& propertiesList) {
1722df1e7dbSMatt Spinler             if (ec)
1732df1e7dbSMatt Spinler             {
17462598e31SEd Tanous                 BMCWEB_LOG_ERROR(
17562598e31SEd Tanous                     "GetAll on path {} iface {} service {} failed with code {}",
17662598e31SEd Tanous                     objectPath, interface, service, ec);
1772df1e7dbSMatt Spinler                 return;
1782df1e7dbSMatt Spinler             }
1792df1e7dbSMatt Spinler 
1802df1e7dbSMatt Spinler             nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
1812df1e7dbSMatt Spinler             nlohmann::json& objectJson = dataJson[objectPath];
1822df1e7dbSMatt Spinler             if (objectJson.is_null())
1832df1e7dbSMatt Spinler             {
1842df1e7dbSMatt Spinler                 objectJson = nlohmann::json::object();
1852df1e7dbSMatt Spinler             }
1862df1e7dbSMatt Spinler 
1872df1e7dbSMatt Spinler             for (const auto& [name, value] : propertiesList)
1882df1e7dbSMatt Spinler             {
1892df1e7dbSMatt Spinler                 nlohmann::json& propertyJson = objectJson[name];
190e3648032SEd Tanous                 std::visit([&propertyJson](auto&& val) { propertyJson = val; },
191abf2add6SEd Tanous                            value);
1922df1e7dbSMatt Spinler             }
193c1343bf6SKrzysztof Grobelny         });
1942df1e7dbSMatt Spinler }
1952df1e7dbSMatt Spinler 
1962df1e7dbSMatt Spinler // Find any results that weren't picked up by ObjectManagers, to be
1972df1e7dbSMatt Spinler // called after all ObjectManagers are searched for and called.
findRemainingObjectsForEnumerate(const std::string & objectPath,const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> & subtree,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)19823a21a1cSEd Tanous inline void findRemainingObjectsForEnumerate(
199b5a76932SEd Tanous     const std::string& objectPath,
200b9d36b47SEd Tanous     const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
201b5a76932SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2022df1e7dbSMatt Spinler {
20362598e31SEd Tanous     BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
2042df1e7dbSMatt Spinler     const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
2052df1e7dbSMatt Spinler 
2062df1e7dbSMatt Spinler     for (const auto& [path, interface_map] : *subtree)
2072df1e7dbSMatt Spinler     {
2082df1e7dbSMatt Spinler         if (path == objectPath)
2092df1e7dbSMatt Spinler         {
2102df1e7dbSMatt Spinler             // An enumerate does not return the target path's properties
2112df1e7dbSMatt Spinler             continue;
2122df1e7dbSMatt Spinler         }
2132df1e7dbSMatt Spinler         if (dataJson.find(path) == dataJson.end())
2142df1e7dbSMatt Spinler         {
2152df1e7dbSMatt Spinler             for (const auto& [service, interfaces] : interface_map)
2162df1e7dbSMatt Spinler             {
2172df1e7dbSMatt Spinler                 for (const auto& interface : interfaces)
2182df1e7dbSMatt Spinler                 {
21911ba3979SEd Tanous                     if (!interface.starts_with("org.freedesktop.DBus"))
2202df1e7dbSMatt Spinler                     {
2212df1e7dbSMatt Spinler                         getPropertiesForEnumerate(path, service, interface,
2222df1e7dbSMatt Spinler                                                   asyncResp);
2232df1e7dbSMatt Spinler                     }
2242df1e7dbSMatt Spinler                 }
2252df1e7dbSMatt Spinler             }
2262df1e7dbSMatt Spinler         }
2272df1e7dbSMatt Spinler     }
2282df1e7dbSMatt Spinler }
2292df1e7dbSMatt Spinler 
2303ae4ba7bSMatt Spinler struct InProgressEnumerateData
2313ae4ba7bSMatt Spinler {
InProgressEnumerateDatacrow::openbmc_mapper::InProgressEnumerateData2328d1b46d7Szhanghch05     InProgressEnumerateData(
2338d1b46d7Szhanghch05         const std::string& objectPathIn,
2348d1b46d7Szhanghch05         const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
235bd79bce8SPatrick Williams         objectPath(objectPathIn), asyncResp(asyncRespIn)
2361214b7e7SGunnar Mills     {}
2373ae4ba7bSMatt Spinler 
~InProgressEnumerateDatacrow::openbmc_mapper::InProgressEnumerateData2383ae4ba7bSMatt Spinler     ~InProgressEnumerateData()
2393ae4ba7bSMatt Spinler     {
24024b2fe81SEd Tanous         try
24124b2fe81SEd Tanous         {
2422df1e7dbSMatt Spinler             findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
2433ae4ba7bSMatt Spinler         }
24424b2fe81SEd Tanous         catch (...)
24524b2fe81SEd Tanous         {
24662598e31SEd Tanous             BMCWEB_LOG_CRITICAL(
24762598e31SEd Tanous                 "findRemainingObjectsForEnumerate threw exception");
24824b2fe81SEd Tanous         }
24924b2fe81SEd Tanous     }
2503ae4ba7bSMatt Spinler 
251ecd6a3a2SEd Tanous     InProgressEnumerateData(const InProgressEnumerateData&) = delete;
252ecd6a3a2SEd Tanous     InProgressEnumerateData(InProgressEnumerateData&&) = delete;
253ecd6a3a2SEd Tanous     InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
254ecd6a3a2SEd Tanous     InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
2553ae4ba7bSMatt Spinler     const std::string objectPath;
256b9d36b47SEd Tanous     std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
2573ae4ba7bSMatt Spinler     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
2583ae4ba7bSMatt Spinler };
2593ae4ba7bSMatt Spinler 
getManagedObjectsForEnumerate(const std::string & objectName,const std::string & objectManagerPath,const std::string & connectionName,const std::shared_ptr<InProgressEnumerateData> & transaction)26023a21a1cSEd Tanous inline void getManagedObjectsForEnumerate(
26181ce609eSEd Tanous     const std::string& objectName, const std::string& objectManagerPath,
26281ce609eSEd Tanous     const std::string& connectionName,
263b5a76932SEd Tanous     const std::shared_ptr<InProgressEnumerateData>& transaction)
2641abe55efSEd Tanous {
26562598e31SEd Tanous     BMCWEB_LOG_DEBUG(
26662598e31SEd Tanous         "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
26762598e31SEd Tanous         objectName, objectManagerPath, connectionName);
2685eb468daSGeorge Liu     sdbusplus::message::object_path path(objectManagerPath);
2695eb468daSGeorge Liu     dbus::utility::getManagedObjects(
2705eb468daSGeorge Liu         connectionName, path,
27181ce609eSEd Tanous         [transaction, objectName,
2725e7e2dc5SEd Tanous          connectionName](const boost::system::error_code& ec,
2735b4aa86bSJames Feist                          const dbus::utility::ManagedObjectType& objects) {
2741abe55efSEd Tanous             if (ec)
2751abe55efSEd Tanous             {
27662598e31SEd Tanous                 BMCWEB_LOG_ERROR(
27762598e31SEd Tanous                     "GetManagedObjects on path {} on connection {} failed with code {}",
27862598e31SEd Tanous                     objectName, connectionName, ec);
279049a0515SEd Tanous                 return;
2801abe55efSEd Tanous             }
281aa2e59c1SEd Tanous 
2823ae4ba7bSMatt Spinler             nlohmann::json& dataJson =
2833ae4ba7bSMatt Spinler                 transaction->asyncResp->res.jsonValue["data"];
284049a0515SEd Tanous 
285049a0515SEd Tanous             for (const auto& objectPath : objects)
2861abe55efSEd Tanous             {
28711ba3979SEd Tanous                 if (objectPath.first.str.starts_with(objectName))
288049a0515SEd Tanous                 {
28962598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
290049a0515SEd Tanous                     nlohmann::json& objectJson = dataJson[objectPath.first.str];
2911abe55efSEd Tanous                     if (objectJson.is_null())
2921abe55efSEd Tanous                     {
29355c7b7a2SEd Tanous                         objectJson = nlohmann::json::object();
294aa2e59c1SEd Tanous                     }
2951abe55efSEd Tanous                     for (const auto& interface : objectPath.second)
2961abe55efSEd Tanous                     {
2971abe55efSEd Tanous                         for (const auto& property : interface.second)
2981abe55efSEd Tanous                         {
2991abe55efSEd Tanous                             nlohmann::json& propertyJson =
3001abe55efSEd Tanous                                 objectJson[property.first];
301d1a64814SEd Tanous                             std::visit(
302d1a64814SEd Tanous                                 [&propertyJson](auto&& val) {
303bd79bce8SPatrick Williams                                     if constexpr (
304bd79bce8SPatrick Williams                                         std::is_same_v<
305d1a64814SEd Tanous                                             std::decay_t<decltype(val)>,
306d1a64814SEd Tanous                                             sdbusplus::message::unix_fd>)
307d1a64814SEd Tanous                                     {
308d1a64814SEd Tanous                                         propertyJson = val.fd;
309d1a64814SEd Tanous                                     }
310d1a64814SEd Tanous                                     else
311d1a64814SEd Tanous                                     {
312d1a64814SEd Tanous                                         propertyJson = val;
313d1a64814SEd Tanous                                     }
314d1a64814SEd Tanous                                 },
31564530018SEd Tanous                                 property.second);
31664530018SEd Tanous                         }
31764530018SEd Tanous                     }
31864530018SEd Tanous                 }
319049a0515SEd Tanous                 for (const auto& interface : objectPath.second)
3201abe55efSEd Tanous                 {
321049a0515SEd Tanous                     if (interface.first == "org.freedesktop.DBus.ObjectManager")
322049a0515SEd Tanous                     {
323bd79bce8SPatrick Williams                         getManagedObjectsForEnumerate(
324bd79bce8SPatrick Williams                             objectPath.first.str, objectPath.first.str,
32581ce609eSEd Tanous                             connectionName, transaction);
326049a0515SEd Tanous                     }
327049a0515SEd Tanous                 }
32864530018SEd Tanous             }
3295eb468daSGeorge Liu         });
330e3cb5a31SEd Tanous }
331e3cb5a31SEd Tanous 
findObjectManagerPathForEnumerate(const std::string & objectName,const std::string & connectionName,const std::shared_ptr<InProgressEnumerateData> & transaction)33223a21a1cSEd Tanous inline void findObjectManagerPathForEnumerate(
33381ce609eSEd Tanous     const std::string& objectName, const std::string& connectionName,
334b5a76932SEd Tanous     const std::shared_ptr<InProgressEnumerateData>& transaction)
335e3cb5a31SEd Tanous {
33662598e31SEd Tanous     BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
33762598e31SEd Tanous                      objectName, connectionName);
338e3cb5a31SEd Tanous     crow::connections::systemBus->async_method_call(
33981ce609eSEd Tanous         [transaction, objectName, connectionName](
3405e7e2dc5SEd Tanous             const boost::system::error_code& ec,
341b9d36b47SEd Tanous             const dbus::utility::MapperGetAncestorsResponse& objects) {
342e3cb5a31SEd Tanous             if (ec)
343e3cb5a31SEd Tanous             {
34462598e31SEd Tanous                 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
34562598e31SEd Tanous                                  objectName, ec);
346e3cb5a31SEd Tanous                 return;
347e3cb5a31SEd Tanous             }
348e3cb5a31SEd Tanous 
349f254ba77SEd Tanous             for (const auto& pathGroup : objects)
350e3cb5a31SEd Tanous             {
351f254ba77SEd Tanous                 for (const auto& connectionGroup : pathGroup.second)
352e3cb5a31SEd Tanous                 {
35381ce609eSEd Tanous                     if (connectionGroup.first == connectionName)
354e3cb5a31SEd Tanous                     {
355e3cb5a31SEd Tanous                         // Found the object manager path for this resource.
356bd79bce8SPatrick Williams                         getManagedObjectsForEnumerate(
357bd79bce8SPatrick Williams                             objectName, pathGroup.first, connectionName,
358bd79bce8SPatrick Williams                             transaction);
359e3cb5a31SEd Tanous                         return;
360e3cb5a31SEd Tanous                     }
361e3cb5a31SEd Tanous                 }
362e3cb5a31SEd Tanous             }
363e3cb5a31SEd Tanous         },
364e3cb5a31SEd Tanous         "xyz.openbmc_project.ObjectMapper",
365e3cb5a31SEd Tanous         "/xyz/openbmc_project/object_mapper",
36681ce609eSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
367e3cb5a31SEd Tanous         std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
368aa2e59c1SEd Tanous }
36964530018SEd Tanous 
3707c09162aSEd Tanous // Uses GetObject to add the object info about the target /enumerate path to
3717c09162aSEd Tanous // the results of GetSubTree, as GetSubTree will not return info for the
3723ae4ba7bSMatt Spinler // target path, and then continues on enumerating the rest of the tree.
getObjectAndEnumerate(const std::shared_ptr<InProgressEnumerateData> & transaction)373b5a76932SEd Tanous inline void getObjectAndEnumerate(
374b5a76932SEd Tanous     const std::shared_ptr<InProgressEnumerateData>& transaction)
3753ae4ba7bSMatt Spinler {
3762b73119cSGeorge Liu     dbus::utility::getDbusObject(
3772b73119cSGeorge Liu         transaction->objectPath, {},
3782b73119cSGeorge Liu         [transaction](const boost::system::error_code& ec,
379b9d36b47SEd Tanous                       const dbus::utility::MapperGetObject& objects) {
3803ae4ba7bSMatt Spinler             if (ec)
3813ae4ba7bSMatt Spinler             {
38262598e31SEd Tanous                 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
38362598e31SEd Tanous                                  transaction->objectPath, ec);
3843ae4ba7bSMatt Spinler                 return;
3853ae4ba7bSMatt Spinler             }
3863ae4ba7bSMatt Spinler 
38762598e31SEd Tanous             BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
38862598e31SEd Tanous                              transaction->objectPath, objects.size());
3893ae4ba7bSMatt Spinler             if (!objects.empty())
3903ae4ba7bSMatt Spinler             {
3913ae4ba7bSMatt Spinler                 transaction->subtree->emplace_back(transaction->objectPath,
3923ae4ba7bSMatt Spinler                                                    objects);
3933ae4ba7bSMatt Spinler             }
3943ae4ba7bSMatt Spinler 
3953ae4ba7bSMatt Spinler             // Map indicating connection name, and the path where the object
3963ae4ba7bSMatt Spinler             // manager exists
39718f8f608SEd Tanous             boost::container::flat_map<
39818f8f608SEd Tanous                 std::string, std::string, std::less<>,
39918f8f608SEd Tanous                 std::vector<std::pair<std::string, std::string>>>
40018f8f608SEd Tanous                 connections;
4013ae4ba7bSMatt Spinler 
4023ae4ba7bSMatt Spinler             for (const auto& object : *(transaction->subtree))
4033ae4ba7bSMatt Spinler             {
4043ae4ba7bSMatt Spinler                 for (const auto& connection : object.second)
4053ae4ba7bSMatt Spinler                 {
4063ae4ba7bSMatt Spinler                     for (const auto& interface : connection.second)
4073ae4ba7bSMatt Spinler                     {
408bd79bce8SPatrick Williams                         BMCWEB_LOG_DEBUG("{} has interface {}",
409bd79bce8SPatrick Williams                                          connection.first, interface);
4103ae4ba7bSMatt Spinler                         if (interface == "org.freedesktop.DBus.ObjectManager")
4113ae4ba7bSMatt Spinler                         {
41262598e31SEd Tanous                             BMCWEB_LOG_DEBUG("found object manager path {}",
41362598e31SEd Tanous                                              object.first);
414f8fe53e7SEd Tanous                             connections[connection.first] = object.first;
4153ae4ba7bSMatt Spinler                         }
4163ae4ba7bSMatt Spinler                     }
4173ae4ba7bSMatt Spinler                 }
4183ae4ba7bSMatt Spinler             }
41962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
4203ae4ba7bSMatt Spinler 
4213ae4ba7bSMatt Spinler             for (const auto& connection : connections)
4223ae4ba7bSMatt Spinler             {
4237c09162aSEd Tanous                 // If we already know where the object manager is, we don't
4247c09162aSEd Tanous                 // need to search for it, we can call directly in to
4253ae4ba7bSMatt Spinler                 // getManagedObjects
4263ae4ba7bSMatt Spinler                 if (!connection.second.empty())
4273ae4ba7bSMatt Spinler                 {
428bd79bce8SPatrick Williams                     getManagedObjectsForEnumerate(
429bd79bce8SPatrick Williams                         transaction->objectPath, connection.second,
4303ae4ba7bSMatt Spinler                         connection.first, transaction);
4313ae4ba7bSMatt Spinler                 }
4323ae4ba7bSMatt Spinler                 else
4333ae4ba7bSMatt Spinler                 {
4347c09162aSEd Tanous                     // otherwise we need to find the object manager path
4357c09162aSEd Tanous                     // before we can continue
4363ae4ba7bSMatt Spinler                     findObjectManagerPathForEnumerate(
4373ae4ba7bSMatt Spinler                         transaction->objectPath, connection.first, transaction);
4383ae4ba7bSMatt Spinler                 }
4393ae4ba7bSMatt Spinler             }
4402b73119cSGeorge Liu         });
4413ae4ba7bSMatt Spinler }
44264530018SEd Tanous 
443d4bb9bbdSEd Tanous // Structure for storing data on an in progress action
4441abe55efSEd Tanous struct InProgressActionData
4451abe55efSEd Tanous {
InProgressActionDatacrow::openbmc_mapper::InProgressActionData44628dd5ca1SLei YU     explicit InProgressActionData(
447bd79bce8SPatrick Williams         const std::shared_ptr<bmcweb::AsyncResp>& res) : asyncResp(res)
44823a21a1cSEd Tanous     {}
~InProgressActionDatacrow::openbmc_mapper::InProgressActionData4491abe55efSEd Tanous     ~InProgressActionData()
4501abe55efSEd Tanous     {
45116caaee1SMatt Spinler         // Methods could have been called across different owners
45216caaee1SMatt Spinler         // and interfaces, where some calls failed and some passed.
45316caaee1SMatt Spinler         //
45416caaee1SMatt Spinler         // The rules for this are:
45516caaee1SMatt Spinler         // * if no method was called - error
45616caaee1SMatt Spinler         // * if a method failed and none passed - error
45716caaee1SMatt Spinler         //   (converse: if at least one method passed - OK)
45816caaee1SMatt Spinler         // * for the method output:
45916caaee1SMatt Spinler         //   * if output processing didn't fail, return the data
46016caaee1SMatt Spinler 
46116caaee1SMatt Spinler         // Only deal with method returns if nothing failed earlier
46228dd5ca1SLei YU         if (asyncResp->res.result() == boost::beast::http::status::ok)
46316caaee1SMatt Spinler         {
46416caaee1SMatt Spinler             if (!methodPassed)
46516caaee1SMatt Spinler             {
46606b1b63cSMatt Spinler                 if (!methodFailed)
4671abe55efSEd Tanous                 {
46828dd5ca1SLei YU                     setErrorResponse(asyncResp->res,
46928dd5ca1SLei YU                                      boost::beast::http::status::not_found,
4706db06242SMatt Spinler                                      methodNotFoundDesc, notFoundMsg);
471d4bb9bbdSEd Tanous                 }
47216caaee1SMatt Spinler             }
47316caaee1SMatt Spinler             else
47416caaee1SMatt Spinler             {
47516caaee1SMatt Spinler                 if (outputFailed)
47616caaee1SMatt Spinler                 {
47716caaee1SMatt Spinler                     setErrorResponse(
47828dd5ca1SLei YU                         asyncResp->res,
47928dd5ca1SLei YU                         boost::beast::http::status::internal_server_error,
48016caaee1SMatt Spinler                         "Method output failure", methodOutputFailedMsg);
48116caaee1SMatt Spinler                 }
48216caaee1SMatt Spinler                 else
48316caaee1SMatt Spinler                 {
48428dd5ca1SLei YU                     asyncResp->res.jsonValue["status"] = "ok";
48528dd5ca1SLei YU                     asyncResp->res.jsonValue["message"] = "200 OK";
48628dd5ca1SLei YU                     asyncResp->res.jsonValue["data"] = methodResponse;
48716caaee1SMatt Spinler                 }
48816caaee1SMatt Spinler             }
48916caaee1SMatt Spinler         }
490d4bb9bbdSEd Tanous     }
491ecd6a3a2SEd Tanous     InProgressActionData(const InProgressActionData&) = delete;
492ecd6a3a2SEd Tanous     InProgressActionData(InProgressActionData&&) = delete;
493ecd6a3a2SEd Tanous     InProgressActionData& operator=(const InProgressActionData&) = delete;
494ecd6a3a2SEd Tanous     InProgressActionData& operator=(InProgressActionData&&) = delete;
495d4bb9bbdSEd Tanous 
setErrorStatuscrow::openbmc_mapper::InProgressActionData4966db06242SMatt Spinler     void setErrorStatus(const std::string& desc)
4971abe55efSEd Tanous     {
49828dd5ca1SLei YU         setErrorResponse(asyncResp->res,
49928dd5ca1SLei YU                          boost::beast::http::status::bad_request, desc,
500c0eb9bd9SMatt Spinler                          badReqMsg);
501d4bb9bbdSEd Tanous     }
50228dd5ca1SLei YU     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
503d4bb9bbdSEd Tanous     std::string path;
504d76323e5SEd Tanous     std::string methodName;
505de81881fSMatt Spinler     std::string interfaceName;
50616caaee1SMatt Spinler     bool methodPassed = false;
50716caaee1SMatt Spinler     bool methodFailed = false;
50816caaee1SMatt Spinler     bool outputFailed = false;
50939a4e39fSMatt Spinler     bool convertedToArray = false;
51016caaee1SMatt Spinler     nlohmann::json methodResponse;
511d4bb9bbdSEd Tanous     nlohmann::json arguments;
512d4bb9bbdSEd Tanous };
513d4bb9bbdSEd Tanous 
dbusArgSplit(const std::string & string)51423a21a1cSEd Tanous inline std::vector<std::string> dbusArgSplit(const std::string& string)
5151abe55efSEd Tanous {
516d4bb9bbdSEd Tanous     std::vector<std::string> ret;
5171abe55efSEd Tanous     if (string.empty())
5181abe55efSEd Tanous     {
519d4bb9bbdSEd Tanous         return ret;
520d4bb9bbdSEd Tanous     }
5210f0353b6SEd Tanous     ret.emplace_back("");
522d76323e5SEd Tanous     int containerDepth = 0;
52375db20e9SEd Tanous 
52475db20e9SEd Tanous     for (std::string::const_iterator character = string.begin();
5251abe55efSEd Tanous          character != string.end(); character++)
5261abe55efSEd Tanous     {
52775db20e9SEd Tanous         ret.back() += *character;
5281abe55efSEd Tanous         switch (*character)
5291abe55efSEd Tanous         {
530d4bb9bbdSEd Tanous             case ('a'):
531d4bb9bbdSEd Tanous                 break;
532d4bb9bbdSEd Tanous             case ('('):
533d4bb9bbdSEd Tanous             case ('{'):
534d76323e5SEd Tanous                 containerDepth++;
535d4bb9bbdSEd Tanous                 break;
536d4bb9bbdSEd Tanous             case ('}'):
537d4bb9bbdSEd Tanous             case (')'):
538d76323e5SEd Tanous                 containerDepth--;
5391abe55efSEd Tanous                 if (containerDepth == 0)
5401abe55efSEd Tanous                 {
5411abe55efSEd Tanous                     if (character + 1 != string.end())
5421abe55efSEd Tanous                     {
5430f0353b6SEd Tanous                         ret.emplace_back("");
544d4bb9bbdSEd Tanous                     }
545d4bb9bbdSEd Tanous                 }
546d4bb9bbdSEd Tanous                 break;
547d4bb9bbdSEd Tanous             default:
5481abe55efSEd Tanous                 if (containerDepth == 0)
5491abe55efSEd Tanous                 {
5501abe55efSEd Tanous                     if (character + 1 != string.end())
5511abe55efSEd Tanous                     {
5520f0353b6SEd Tanous                         ret.emplace_back("");
553d4bb9bbdSEd Tanous                     }
554d4bb9bbdSEd Tanous                 }
555d4bb9bbdSEd Tanous                 break;
556d4bb9bbdSEd Tanous         }
557d4bb9bbdSEd Tanous     }
5584ae611d9SMatt Spinler 
5594ae611d9SMatt Spinler     return ret;
560d4bb9bbdSEd Tanous }
561d4bb9bbdSEd Tanous 
convertJsonToDbus(sd_bus_message * m,const std::string & argType,const nlohmann::json & inputJson)56281ce609eSEd Tanous inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
56381ce609eSEd Tanous                              const nlohmann::json& inputJson)
5641abe55efSEd Tanous {
565d4bb9bbdSEd Tanous     int r = 0;
566296579beSEd Tanous     BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
56781ce609eSEd Tanous     const std::vector<std::string> argTypes = dbusArgSplit(argType);
568d4bb9bbdSEd Tanous 
569d4bb9bbdSEd Tanous     // Assume a single object for now.
57081ce609eSEd Tanous     const nlohmann::json* j = &inputJson;
57181ce609eSEd Tanous     nlohmann::json::const_iterator jIt = inputJson.begin();
572d4bb9bbdSEd Tanous 
573e3cb5a31SEd Tanous     for (const std::string& argCode : argTypes)
5741abe55efSEd Tanous     {
5751abe55efSEd Tanous         // If we are decoding multiple objects, grab the pointer to the
5761abe55efSEd Tanous         // iterator, and increment it for the next loop
5771abe55efSEd Tanous         if (argTypes.size() > 1)
5781abe55efSEd Tanous         {
57981ce609eSEd Tanous             if (jIt == inputJson.end())
5801abe55efSEd Tanous             {
581d4bb9bbdSEd Tanous                 return -2;
582d4bb9bbdSEd Tanous             }
583d76323e5SEd Tanous             j = &*jIt;
584d76323e5SEd Tanous             jIt++;
585d4bb9bbdSEd Tanous         }
586e3cb5a31SEd Tanous         const int64_t* intValue = j->get_ptr<const int64_t*>();
587e3cb5a31SEd Tanous         const std::string* stringValue = j->get_ptr<const std::string*>();
588e3cb5a31SEd Tanous         const double* doubleValue = j->get_ptr<const double*>();
589d4bb9bbdSEd Tanous         const bool* b = j->get_ptr<const bool*>();
590d4bb9bbdSEd Tanous         int64_t v = 0;
591d4bb9bbdSEd Tanous         double d = 0.0;
592d4bb9bbdSEd Tanous 
5931abe55efSEd Tanous         // Do some basic type conversions that make sense.  uint can be
5941abe55efSEd Tanous         // converted to int.  int and uint can be converted to double
59566664f25SEd Tanous         if (intValue == nullptr)
59666664f25SEd Tanous         {
59766664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
59866664f25SEd Tanous             if (uintValue != nullptr)
5991abe55efSEd Tanous             {
600e3cb5a31SEd Tanous                 v = static_cast<int64_t>(*uintValue);
601e3cb5a31SEd Tanous                 intValue = &v;
602d4bb9bbdSEd Tanous             }
60366664f25SEd Tanous         }
60466664f25SEd Tanous         if (doubleValue == nullptr)
60566664f25SEd Tanous         {
60666664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
60766664f25SEd Tanous             if (uintValue != nullptr)
6081abe55efSEd Tanous             {
609e3cb5a31SEd Tanous                 d = static_cast<double>(*uintValue);
610e3cb5a31SEd Tanous                 doubleValue = &d;
611d4bb9bbdSEd Tanous             }
61266664f25SEd Tanous         }
61366664f25SEd Tanous         if (doubleValue == nullptr)
61466664f25SEd Tanous         {
61566664f25SEd Tanous             if (intValue != nullptr)
6161abe55efSEd Tanous             {
617e3cb5a31SEd Tanous                 d = static_cast<double>(*intValue);
618e3cb5a31SEd Tanous                 doubleValue = &d;
619d4bb9bbdSEd Tanous             }
62066664f25SEd Tanous         }
621d4bb9bbdSEd Tanous 
622e3cb5a31SEd Tanous         if (argCode == "s")
6231abe55efSEd Tanous         {
624e3cb5a31SEd Tanous             if (stringValue == nullptr)
6251abe55efSEd Tanous             {
626d4bb9bbdSEd Tanous                 return -1;
627d4bb9bbdSEd Tanous             }
628271584abSEd Tanous             r = sd_bus_message_append_basic(
629271584abSEd Tanous                 m, argCode[0], static_cast<const void*>(stringValue->data()));
6301abe55efSEd Tanous             if (r < 0)
6311abe55efSEd Tanous             {
632d4bb9bbdSEd Tanous                 return r;
633d4bb9bbdSEd Tanous             }
6341abe55efSEd Tanous         }
635e3cb5a31SEd Tanous         else if (argCode == "i")
6361abe55efSEd Tanous         {
637e3cb5a31SEd Tanous             if (intValue == nullptr)
6381abe55efSEd Tanous             {
639d4bb9bbdSEd Tanous                 return -1;
640d4bb9bbdSEd Tanous             }
641c66c859cSAdriana Kobylak             if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
642c66c859cSAdriana Kobylak                 (*intValue > std::numeric_limits<int32_t>::max()))
643c66c859cSAdriana Kobylak             {
644c66c859cSAdriana Kobylak                 return -ERANGE;
645c66c859cSAdriana Kobylak             }
646e3cb5a31SEd Tanous             int32_t i = static_cast<int32_t>(*intValue);
647e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &i);
6481abe55efSEd Tanous             if (r < 0)
6491abe55efSEd Tanous             {
650d4bb9bbdSEd Tanous                 return r;
651d4bb9bbdSEd Tanous             }
6521abe55efSEd Tanous         }
653e3cb5a31SEd Tanous         else if (argCode == "b")
6541abe55efSEd Tanous         {
655d4bb9bbdSEd Tanous             // lots of ways bool could be represented here.  Try them all
656e662eae8SEd Tanous             int boolInt = 0;
657e3cb5a31SEd Tanous             if (intValue != nullptr)
6581abe55efSEd Tanous             {
659c66c859cSAdriana Kobylak                 if (*intValue == 1)
660c66c859cSAdriana Kobylak                 {
661e662eae8SEd Tanous                     boolInt = 1;
662c66c859cSAdriana Kobylak                 }
663c66c859cSAdriana Kobylak                 else if (*intValue == 0)
664c66c859cSAdriana Kobylak                 {
665e662eae8SEd Tanous                     boolInt = 0;
666c66c859cSAdriana Kobylak                 }
667c66c859cSAdriana Kobylak                 else
668c66c859cSAdriana Kobylak                 {
669c66c859cSAdriana Kobylak                     return -ERANGE;
670c66c859cSAdriana Kobylak                 }
6711abe55efSEd Tanous             }
6721abe55efSEd Tanous             else if (b != nullptr)
6731abe55efSEd Tanous             {
674a2f02638SMatt Spinler                 boolInt = *b ? 1 : 0;
6751abe55efSEd Tanous             }
676e3cb5a31SEd Tanous             else if (stringValue != nullptr)
6771abe55efSEd Tanous             {
67818f8f608SEd Tanous                 if (!stringValue->empty())
67918f8f608SEd Tanous                 {
68018f8f608SEd Tanous                     if (stringValue->front() == 't' ||
68118f8f608SEd Tanous                         stringValue->front() == 'T')
68218f8f608SEd Tanous                     {
68318f8f608SEd Tanous                         boolInt = 1;
68418f8f608SEd Tanous                     }
68518f8f608SEd Tanous                 }
6861abe55efSEd Tanous             }
6871abe55efSEd Tanous             else
6881abe55efSEd Tanous             {
689d4bb9bbdSEd Tanous                 return -1;
690d4bb9bbdSEd Tanous             }
691e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
6921abe55efSEd Tanous             if (r < 0)
6931abe55efSEd Tanous             {
694d4bb9bbdSEd Tanous                 return r;
695d4bb9bbdSEd Tanous             }
6961abe55efSEd Tanous         }
697e3cb5a31SEd Tanous         else if (argCode == "n")
6981abe55efSEd Tanous         {
699e3cb5a31SEd Tanous             if (intValue == nullptr)
7001abe55efSEd Tanous             {
701d4bb9bbdSEd Tanous                 return -1;
702d4bb9bbdSEd Tanous             }
703c66c859cSAdriana Kobylak             if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
704c66c859cSAdriana Kobylak                 (*intValue > std::numeric_limits<int16_t>::max()))
705c66c859cSAdriana Kobylak             {
706c66c859cSAdriana Kobylak                 return -ERANGE;
707c66c859cSAdriana Kobylak             }
708e3cb5a31SEd Tanous             int16_t n = static_cast<int16_t>(*intValue);
709e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &n);
7101abe55efSEd Tanous             if (r < 0)
7111abe55efSEd Tanous             {
712d4bb9bbdSEd Tanous                 return r;
713d4bb9bbdSEd Tanous             }
7141abe55efSEd Tanous         }
715e3cb5a31SEd Tanous         else if (argCode == "x")
7161abe55efSEd Tanous         {
717e3cb5a31SEd Tanous             if (intValue == nullptr)
7181abe55efSEd Tanous             {
719d4bb9bbdSEd Tanous                 return -1;
720d4bb9bbdSEd Tanous             }
721e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], intValue);
7221abe55efSEd Tanous             if (r < 0)
7231abe55efSEd Tanous             {
724d4bb9bbdSEd Tanous                 return r;
725d4bb9bbdSEd Tanous             }
7261abe55efSEd Tanous         }
727e3cb5a31SEd Tanous         else if (argCode == "y")
7281abe55efSEd Tanous         {
72966664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
730e3cb5a31SEd Tanous             if (uintValue == nullptr)
7311abe55efSEd Tanous             {
732d4bb9bbdSEd Tanous                 return -1;
733d4bb9bbdSEd Tanous             }
73423a21a1cSEd Tanous             if (*uintValue > std::numeric_limits<uint8_t>::max())
735c66c859cSAdriana Kobylak             {
736c66c859cSAdriana Kobylak                 return -ERANGE;
737c66c859cSAdriana Kobylak             }
738e3cb5a31SEd Tanous             uint8_t y = static_cast<uint8_t>(*uintValue);
739e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &y);
7401abe55efSEd Tanous         }
741e3cb5a31SEd Tanous         else if (argCode == "q")
7421abe55efSEd Tanous         {
74366664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
744e3cb5a31SEd Tanous             if (uintValue == nullptr)
7451abe55efSEd Tanous             {
746d4bb9bbdSEd Tanous                 return -1;
747d4bb9bbdSEd Tanous             }
74823a21a1cSEd Tanous             if (*uintValue > std::numeric_limits<uint16_t>::max())
749c66c859cSAdriana Kobylak             {
750c66c859cSAdriana Kobylak                 return -ERANGE;
751c66c859cSAdriana Kobylak             }
752e3cb5a31SEd Tanous             uint16_t q = static_cast<uint16_t>(*uintValue);
753e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &q);
7541abe55efSEd Tanous         }
755e3cb5a31SEd Tanous         else if (argCode == "u")
7561abe55efSEd Tanous         {
75766664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
758e3cb5a31SEd Tanous             if (uintValue == nullptr)
7591abe55efSEd Tanous             {
760d4bb9bbdSEd Tanous                 return -1;
761d4bb9bbdSEd Tanous             }
76223a21a1cSEd Tanous             if (*uintValue > std::numeric_limits<uint32_t>::max())
763c66c859cSAdriana Kobylak             {
764c66c859cSAdriana Kobylak                 return -ERANGE;
765c66c859cSAdriana Kobylak             }
766e3cb5a31SEd Tanous             uint32_t u = static_cast<uint32_t>(*uintValue);
767e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &u);
7681abe55efSEd Tanous         }
769e3cb5a31SEd Tanous         else if (argCode == "t")
7701abe55efSEd Tanous         {
77166664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
772e3cb5a31SEd Tanous             if (uintValue == nullptr)
7731abe55efSEd Tanous             {
774d4bb9bbdSEd Tanous                 return -1;
775d4bb9bbdSEd Tanous             }
776e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], uintValue);
7771abe55efSEd Tanous         }
778e3cb5a31SEd Tanous         else if (argCode == "d")
7791abe55efSEd Tanous         {
780c66c859cSAdriana Kobylak             if (doubleValue == nullptr)
781c66c859cSAdriana Kobylak             {
782c66c859cSAdriana Kobylak                 return -1;
783c66c859cSAdriana Kobylak             }
784c66c859cSAdriana Kobylak             if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
785c66c859cSAdriana Kobylak                 (*doubleValue > std::numeric_limits<double>::max()))
786c66c859cSAdriana Kobylak             {
787c66c859cSAdriana Kobylak                 return -ERANGE;
788c66c859cSAdriana Kobylak             }
78907900817SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
79007900817SEd Tanous             if (r < 0)
79107900817SEd Tanous             {
79207900817SEd Tanous                 return r;
79307900817SEd Tanous             }
7941abe55efSEd Tanous         }
79511ba3979SEd Tanous         else if (argCode.starts_with("a"))
7961abe55efSEd Tanous         {
797e3cb5a31SEd Tanous             std::string containedType = argCode.substr(1);
798d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
799e3cb5a31SEd Tanous                                               containedType.c_str());
8001abe55efSEd Tanous             if (r < 0)
8011abe55efSEd Tanous             {
802d4bb9bbdSEd Tanous                 return r;
803d4bb9bbdSEd Tanous             }
804d4bb9bbdSEd Tanous 
8050dfeda62SEd Tanous             for (const auto& it : *j)
8061abe55efSEd Tanous             {
8070dfeda62SEd Tanous                 r = convertJsonToDbus(m, containedType, it);
8081abe55efSEd Tanous                 if (r < 0)
8091abe55efSEd Tanous                 {
810d4bb9bbdSEd Tanous                     return r;
811d4bb9bbdSEd Tanous                 }
812d4bb9bbdSEd Tanous             }
813d4bb9bbdSEd Tanous             sd_bus_message_close_container(m);
8141abe55efSEd Tanous         }
81511ba3979SEd Tanous         else if (argCode.starts_with("v"))
8161abe55efSEd Tanous         {
817e3cb5a31SEd Tanous             std::string containedType = argCode.substr(1);
81862598e31SEd Tanous             BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
81962598e31SEd Tanous                              argCode, containedType);
820d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
821e3cb5a31SEd Tanous                                               containedType.c_str());
8221abe55efSEd Tanous             if (r < 0)
8231abe55efSEd Tanous             {
824d4bb9bbdSEd Tanous                 return r;
825d4bb9bbdSEd Tanous             }
826d4bb9bbdSEd Tanous 
82781ce609eSEd Tanous             r = convertJsonToDbus(m, containedType, inputJson);
8281abe55efSEd Tanous             if (r < 0)
8291abe55efSEd Tanous             {
830d4bb9bbdSEd Tanous                 return r;
831d4bb9bbdSEd Tanous             }
832d4bb9bbdSEd Tanous 
833d4bb9bbdSEd Tanous             r = sd_bus_message_close_container(m);
8341abe55efSEd Tanous             if (r < 0)
8351abe55efSEd Tanous             {
836d4bb9bbdSEd Tanous                 return r;
837d4bb9bbdSEd Tanous             }
8381abe55efSEd Tanous         }
83911ba3979SEd Tanous         else if (argCode.starts_with("(") && argCode.ends_with(")"))
8401abe55efSEd Tanous         {
841f3477566SMikhail Zhvakin             std::string containedType = argCode.substr(1, argCode.size() - 2);
842d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
843e3cb5a31SEd Tanous                                               containedType.c_str());
844f1eebf06SEd Tanous             if (r < 0)
845f1eebf06SEd Tanous             {
846f1eebf06SEd Tanous                 return r;
847f1eebf06SEd Tanous             }
848f1eebf06SEd Tanous 
849d4bb9bbdSEd Tanous             nlohmann::json::const_iterator it = j->begin();
850f3477566SMikhail Zhvakin             for (const std::string& argCode2 : dbusArgSplit(containedType))
8511abe55efSEd Tanous             {
8521abe55efSEd Tanous                 if (it == j->end())
8531abe55efSEd Tanous                 {
854d4bb9bbdSEd Tanous                     return -1;
855d4bb9bbdSEd Tanous                 }
856cb13a392SEd Tanous                 r = convertJsonToDbus(m, argCode2, *it);
8571abe55efSEd Tanous                 if (r < 0)
8581abe55efSEd Tanous                 {
859d4bb9bbdSEd Tanous                     return r;
860d4bb9bbdSEd Tanous                 }
861d4bb9bbdSEd Tanous                 it++;
862d4bb9bbdSEd Tanous             }
863d4bb9bbdSEd Tanous             r = sd_bus_message_close_container(m);
8641abe55efSEd Tanous         }
86511ba3979SEd Tanous         else if (argCode.starts_with("{") && argCode.ends_with("}"))
8661abe55efSEd Tanous         {
867f3477566SMikhail Zhvakin             std::string containedType = argCode.substr(1, argCode.size() - 2);
868d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
869e3cb5a31SEd Tanous                                               containedType.c_str());
870f1eebf06SEd Tanous             if (r < 0)
871f1eebf06SEd Tanous             {
872f1eebf06SEd Tanous                 return r;
873f1eebf06SEd Tanous             }
874f1eebf06SEd Tanous 
875e3cb5a31SEd Tanous             std::vector<std::string> codes = dbusArgSplit(containedType);
8761abe55efSEd Tanous             if (codes.size() != 2)
8771abe55efSEd Tanous             {
878d4bb9bbdSEd Tanous                 return -1;
879d4bb9bbdSEd Tanous             }
8802c70f800SEd Tanous             const std::string& keyType = codes[0];
8812c70f800SEd Tanous             const std::string& valueType = codes[1];
8820bdda665SEd Tanous             const nlohmann::json::object_t* arr =
8830bdda665SEd Tanous                 j->get_ptr<const nlohmann::json::object_t*>();
8840bdda665SEd Tanous             if (arr == nullptr)
8851abe55efSEd Tanous             {
8860bdda665SEd Tanous                 return -1;
8870bdda665SEd Tanous             }
8880bdda665SEd Tanous             for (const auto& it : *arr)
8890bdda665SEd Tanous             {
8900bdda665SEd Tanous                 r = convertJsonToDbus(m, keyType, it.first);
8911abe55efSEd Tanous                 if (r < 0)
8921abe55efSEd Tanous                 {
893d4bb9bbdSEd Tanous                     return r;
89475db20e9SEd Tanous                 }
895d4bb9bbdSEd Tanous 
8960bdda665SEd Tanous                 r = convertJsonToDbus(m, valueType, it.second);
8971abe55efSEd Tanous                 if (r < 0)
8981abe55efSEd Tanous                 {
899d4bb9bbdSEd Tanous                     return r;
900d4bb9bbdSEd Tanous                 }
901d4bb9bbdSEd Tanous             }
902d4bb9bbdSEd Tanous             r = sd_bus_message_close_container(m);
9031abe55efSEd Tanous         }
9041abe55efSEd Tanous         else
9051abe55efSEd Tanous         {
906d4bb9bbdSEd Tanous             return -2;
907d4bb9bbdSEd Tanous         }
9081abe55efSEd Tanous         if (r < 0)
9091abe55efSEd Tanous         {
910d4bb9bbdSEd Tanous             return r;
911d4bb9bbdSEd Tanous         }
912d4bb9bbdSEd Tanous 
9131abe55efSEd Tanous         if (argTypes.size() > 1)
9141abe55efSEd Tanous         {
915d76323e5SEd Tanous             jIt++;
916d4bb9bbdSEd Tanous         }
917d4bb9bbdSEd Tanous     }
918127ea546SMatt Spinler 
919127ea546SMatt Spinler     return r;
920d4bb9bbdSEd Tanous }
921d4bb9bbdSEd Tanous 
922d22a7131SMatt Spinler template <typename T>
readMessageItem(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)92359d494eeSPatrick Williams int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
924d22a7131SMatt Spinler                     nlohmann::json& data)
925d22a7131SMatt Spinler {
926d22a7131SMatt Spinler     T value;
927f79ce6a8SEd Tanous     // When T == char*, this warning fires.  Unclear how to resolve
928f79ce6a8SEd Tanous     // Given that sd-bus takes a void pointer to a char*, and that's
929f79ce6a8SEd Tanous     // Not something we can fix.
930f79ce6a8SEd Tanous     // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
931d22a7131SMatt Spinler     int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
932d22a7131SMatt Spinler     if (r < 0)
933d22a7131SMatt Spinler     {
93462598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
93562598e31SEd Tanous                          typeCode);
936d22a7131SMatt Spinler         return r;
937d22a7131SMatt Spinler     }
938d22a7131SMatt Spinler 
939d22a7131SMatt Spinler     data = value;
940d22a7131SMatt Spinler     return 0;
941d22a7131SMatt Spinler }
942d22a7131SMatt Spinler 
94359d494eeSPatrick Williams int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
94459d494eeSPatrick Williams                       nlohmann::json& response);
9456df8f990SMatt Spinler 
readDictEntryFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & object)94623a21a1cSEd Tanous inline int readDictEntryFromMessage(const std::string& typeCode,
94759d494eeSPatrick Williams                                     sdbusplus::message_t& m,
9486df8f990SMatt Spinler                                     nlohmann::json& object)
9496df8f990SMatt Spinler {
9506df8f990SMatt Spinler     std::vector<std::string> types = dbusArgSplit(typeCode);
9516df8f990SMatt Spinler     if (types.size() != 2)
9526df8f990SMatt Spinler     {
95362598e31SEd Tanous         BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
95462598e31SEd Tanous                          types.size());
9556df8f990SMatt Spinler         return -1;
9566df8f990SMatt Spinler     }
9576df8f990SMatt Spinler 
9586df8f990SMatt Spinler     int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
9596df8f990SMatt Spinler                                            typeCode.c_str());
9606df8f990SMatt Spinler     if (r < 0)
9616df8f990SMatt Spinler     {
96262598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
9636df8f990SMatt Spinler         return r;
9646df8f990SMatt Spinler     }
9656df8f990SMatt Spinler 
9666df8f990SMatt Spinler     nlohmann::json key;
9676df8f990SMatt Spinler     r = convertDBusToJSON(types[0], m, key);
9686df8f990SMatt Spinler     if (r < 0)
9696df8f990SMatt Spinler     {
9706df8f990SMatt Spinler         return r;
9716df8f990SMatt Spinler     }
9726df8f990SMatt Spinler 
9736df8f990SMatt Spinler     const std::string* keyPtr = key.get_ptr<const std::string*>();
9746df8f990SMatt Spinler     if (keyPtr == nullptr)
9756df8f990SMatt Spinler     {
9766df8f990SMatt Spinler         // json doesn't support non-string keys.  If we hit this condition,
9776df8f990SMatt Spinler         // convert the result to a string so we can proceed
97871f52d96SEd Tanous         key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
9796df8f990SMatt Spinler         keyPtr = key.get_ptr<const std::string*>();
9807c09162aSEd Tanous         // in theory this can't fail now, but lets be paranoid about it
9817c09162aSEd Tanous         // anyway
9826df8f990SMatt Spinler         if (keyPtr == nullptr)
9836df8f990SMatt Spinler         {
9846df8f990SMatt Spinler             return -1;
9856df8f990SMatt Spinler         }
9866df8f990SMatt Spinler     }
9876df8f990SMatt Spinler     nlohmann::json& value = object[*keyPtr];
9886df8f990SMatt Spinler 
9896df8f990SMatt Spinler     r = convertDBusToJSON(types[1], m, value);
9906df8f990SMatt Spinler     if (r < 0)
9916df8f990SMatt Spinler     {
9926df8f990SMatt Spinler         return r;
9936df8f990SMatt Spinler     }
9946df8f990SMatt Spinler 
9956df8f990SMatt Spinler     r = sd_bus_message_exit_container(m.get());
9966df8f990SMatt Spinler     if (r < 0)
9976df8f990SMatt Spinler     {
99862598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
9996df8f990SMatt Spinler         return r;
10006df8f990SMatt Spinler     }
10016df8f990SMatt Spinler 
10026df8f990SMatt Spinler     return 0;
10036df8f990SMatt Spinler }
10046df8f990SMatt Spinler 
readArrayFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)100523a21a1cSEd Tanous inline int readArrayFromMessage(const std::string& typeCode,
100659d494eeSPatrick Williams                                 sdbusplus::message_t& m, nlohmann::json& data)
10076df8f990SMatt Spinler {
10086df8f990SMatt Spinler     if (typeCode.size() < 2)
10096df8f990SMatt Spinler     {
101062598e31SEd Tanous         BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
10116df8f990SMatt Spinler         return -1;
10126df8f990SMatt Spinler     }
10136df8f990SMatt Spinler 
10146df8f990SMatt Spinler     std::string containedType = typeCode.substr(1);
10156df8f990SMatt Spinler 
10166df8f990SMatt Spinler     int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
10176df8f990SMatt Spinler                                            containedType.c_str());
10186df8f990SMatt Spinler     if (r < 0)
10196df8f990SMatt Spinler     {
102062598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
10216df8f990SMatt Spinler         return r;
10226df8f990SMatt Spinler     }
10236df8f990SMatt Spinler 
102411ba3979SEd Tanous     bool dict = containedType.starts_with("{") && containedType.ends_with("}");
10256df8f990SMatt Spinler 
10266df8f990SMatt Spinler     if (dict)
10276df8f990SMatt Spinler     {
10286df8f990SMatt Spinler         // Remove the { }
10296df8f990SMatt Spinler         containedType = containedType.substr(1, containedType.size() - 2);
10306df8f990SMatt Spinler         data = nlohmann::json::object();
10316df8f990SMatt Spinler     }
10326df8f990SMatt Spinler     else
10336df8f990SMatt Spinler     {
10346df8f990SMatt Spinler         data = nlohmann::json::array();
10356df8f990SMatt Spinler     }
10366df8f990SMatt Spinler 
10376df8f990SMatt Spinler     while (true)
10386df8f990SMatt Spinler     {
1039e662eae8SEd Tanous         r = sd_bus_message_at_end(m.get(), 0);
10406df8f990SMatt Spinler         if (r < 0)
10416df8f990SMatt Spinler         {
104262598e31SEd Tanous             BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
10436df8f990SMatt Spinler             return r;
10446df8f990SMatt Spinler         }
10456df8f990SMatt Spinler 
10466df8f990SMatt Spinler         if (r > 0)
10476df8f990SMatt Spinler         {
10486df8f990SMatt Spinler             break;
10496df8f990SMatt Spinler         }
10506df8f990SMatt Spinler 
10516df8f990SMatt Spinler         // Dictionaries are only ever seen in an array
10526df8f990SMatt Spinler         if (dict)
10536df8f990SMatt Spinler         {
10546df8f990SMatt Spinler             r = readDictEntryFromMessage(containedType, m, data);
10556df8f990SMatt Spinler             if (r < 0)
10566df8f990SMatt Spinler             {
10576df8f990SMatt Spinler                 return r;
10586df8f990SMatt Spinler             }
10596df8f990SMatt Spinler         }
10606df8f990SMatt Spinler         else
10616df8f990SMatt Spinler         {
10626df8f990SMatt Spinler             data.push_back(nlohmann::json());
10636df8f990SMatt Spinler 
10646df8f990SMatt Spinler             r = convertDBusToJSON(containedType, m, data.back());
10656df8f990SMatt Spinler             if (r < 0)
10666df8f990SMatt Spinler             {
10676df8f990SMatt Spinler                 return r;
10686df8f990SMatt Spinler             }
10696df8f990SMatt Spinler         }
10706df8f990SMatt Spinler     }
10716df8f990SMatt Spinler 
10726df8f990SMatt Spinler     r = sd_bus_message_exit_container(m.get());
10736df8f990SMatt Spinler     if (r < 0)
10746df8f990SMatt Spinler     {
107562598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
10766df8f990SMatt Spinler         return r;
10776df8f990SMatt Spinler     }
10786df8f990SMatt Spinler 
10796df8f990SMatt Spinler     return 0;
10806df8f990SMatt Spinler }
10816df8f990SMatt Spinler 
readStructFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)108223a21a1cSEd Tanous inline int readStructFromMessage(const std::string& typeCode,
108359d494eeSPatrick Williams                                  sdbusplus::message_t& m, nlohmann::json& data)
108475c6c67fSMatt Spinler {
108575c6c67fSMatt Spinler     if (typeCode.size() < 3)
108675c6c67fSMatt Spinler     {
108762598e31SEd Tanous         BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
108875c6c67fSMatt Spinler         return -1;
108975c6c67fSMatt Spinler     }
109075c6c67fSMatt Spinler 
109175c6c67fSMatt Spinler     std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
109275c6c67fSMatt Spinler     std::vector<std::string> types = dbusArgSplit(containedTypes);
109375c6c67fSMatt Spinler 
109475c6c67fSMatt Spinler     int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
109575c6c67fSMatt Spinler                                            containedTypes.c_str());
109675c6c67fSMatt Spinler     if (r < 0)
109775c6c67fSMatt Spinler     {
109862598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
109975c6c67fSMatt Spinler         return r;
110075c6c67fSMatt Spinler     }
110175c6c67fSMatt Spinler 
110275c6c67fSMatt Spinler     for (const std::string& type : types)
110375c6c67fSMatt Spinler     {
110475c6c67fSMatt Spinler         data.push_back(nlohmann::json());
110575c6c67fSMatt Spinler         r = convertDBusToJSON(type, m, data.back());
110675c6c67fSMatt Spinler         if (r < 0)
110775c6c67fSMatt Spinler         {
110875c6c67fSMatt Spinler             return r;
110975c6c67fSMatt Spinler         }
111075c6c67fSMatt Spinler     }
111175c6c67fSMatt Spinler 
111275c6c67fSMatt Spinler     r = sd_bus_message_exit_container(m.get());
111375c6c67fSMatt Spinler     if (r < 0)
111475c6c67fSMatt Spinler     {
111562598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
111675c6c67fSMatt Spinler         return r;
111775c6c67fSMatt Spinler     }
111875c6c67fSMatt Spinler     return 0;
111975c6c67fSMatt Spinler }
112075c6c67fSMatt Spinler 
readVariantFromMessage(sdbusplus::message_t & m,nlohmann::json & data)112159d494eeSPatrick Williams inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
112289c1970bSMatt Spinler {
1123543f4400SEd Tanous     const char* containerType = nullptr;
112499131cd0SEd Tanous     int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
112589c1970bSMatt Spinler     if (r < 0)
112689c1970bSMatt Spinler     {
112762598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
112889c1970bSMatt Spinler         return r;
112989c1970bSMatt Spinler     }
113089c1970bSMatt Spinler 
113189c1970bSMatt Spinler     r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
113289c1970bSMatt Spinler                                        containerType);
113389c1970bSMatt Spinler     if (r < 0)
113489c1970bSMatt Spinler     {
113562598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
113689c1970bSMatt Spinler         return r;
113789c1970bSMatt Spinler     }
113889c1970bSMatt Spinler 
113989c1970bSMatt Spinler     r = convertDBusToJSON(containerType, m, data);
114089c1970bSMatt Spinler     if (r < 0)
114189c1970bSMatt Spinler     {
114289c1970bSMatt Spinler         return r;
114389c1970bSMatt Spinler     }
114489c1970bSMatt Spinler 
114589c1970bSMatt Spinler     r = sd_bus_message_exit_container(m.get());
114689c1970bSMatt Spinler     if (r < 0)
114789c1970bSMatt Spinler     {
114862598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
114989c1970bSMatt Spinler         return r;
115089c1970bSMatt Spinler     }
115189c1970bSMatt Spinler 
115289c1970bSMatt Spinler     return 0;
115389c1970bSMatt Spinler }
115489c1970bSMatt Spinler 
convertDBusToJSON(const std::string & returnType,sdbusplus::message_t & m,nlohmann::json & response)115523a21a1cSEd Tanous inline int convertDBusToJSON(const std::string& returnType,
115659d494eeSPatrick Williams                              sdbusplus::message_t& m, nlohmann::json& response)
115716caaee1SMatt Spinler {
1158d22a7131SMatt Spinler     int r = 0;
1159d22a7131SMatt Spinler     const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1160d22a7131SMatt Spinler 
1161d22a7131SMatt Spinler     for (const std::string& typeCode : returnTypes)
1162d22a7131SMatt Spinler     {
1163f39420c7SMatt Spinler         nlohmann::json* thisElement = &response;
1164f39420c7SMatt Spinler         if (returnTypes.size() > 1)
1165d22a7131SMatt Spinler         {
1166d22a7131SMatt Spinler             response.push_back(nlohmann::json{});
1167f39420c7SMatt Spinler             thisElement = &response.back();
1168d22a7131SMatt Spinler         }
1169d22a7131SMatt Spinler 
1170d4d25793SEd Tanous         if (typeCode == "s" || typeCode == "g" || typeCode == "o")
1171d22a7131SMatt Spinler         {
1172f39420c7SMatt Spinler             r = readMessageItem<char*>(typeCode, m, *thisElement);
1173d22a7131SMatt Spinler             if (r < 0)
1174d22a7131SMatt Spinler             {
1175d22a7131SMatt Spinler                 return r;
1176d22a7131SMatt Spinler             }
1177d22a7131SMatt Spinler         }
1178d22a7131SMatt Spinler         else if (typeCode == "b")
1179d22a7131SMatt Spinler         {
1180f39420c7SMatt Spinler             r = readMessageItem<int>(typeCode, m, *thisElement);
1181d22a7131SMatt Spinler             if (r < 0)
1182d22a7131SMatt Spinler             {
1183d22a7131SMatt Spinler                 return r;
1184d22a7131SMatt Spinler             }
1185d22a7131SMatt Spinler 
1186f39420c7SMatt Spinler             *thisElement = static_cast<bool>(thisElement->get<int>());
1187d22a7131SMatt Spinler         }
1188d22a7131SMatt Spinler         else if (typeCode == "u")
1189d22a7131SMatt Spinler         {
1190f39420c7SMatt Spinler             r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
1191d22a7131SMatt Spinler             if (r < 0)
1192d22a7131SMatt Spinler             {
1193d22a7131SMatt Spinler                 return r;
1194d22a7131SMatt Spinler             }
1195d22a7131SMatt Spinler         }
1196d22a7131SMatt Spinler         else if (typeCode == "i")
1197d22a7131SMatt Spinler         {
1198f39420c7SMatt Spinler             r = readMessageItem<int32_t>(typeCode, m, *thisElement);
1199d22a7131SMatt Spinler             if (r < 0)
1200d22a7131SMatt Spinler             {
1201d22a7131SMatt Spinler                 return r;
1202d22a7131SMatt Spinler             }
1203d22a7131SMatt Spinler         }
1204d22a7131SMatt Spinler         else if (typeCode == "x")
1205d22a7131SMatt Spinler         {
1206f39420c7SMatt Spinler             r = readMessageItem<int64_t>(typeCode, m, *thisElement);
1207d22a7131SMatt Spinler             if (r < 0)
1208d22a7131SMatt Spinler             {
1209d22a7131SMatt Spinler                 return r;
1210d22a7131SMatt Spinler             }
1211d22a7131SMatt Spinler         }
1212d22a7131SMatt Spinler         else if (typeCode == "t")
1213d22a7131SMatt Spinler         {
1214f39420c7SMatt Spinler             r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
1215d22a7131SMatt Spinler             if (r < 0)
1216d22a7131SMatt Spinler             {
1217d22a7131SMatt Spinler                 return r;
1218d22a7131SMatt Spinler             }
1219d22a7131SMatt Spinler         }
1220d22a7131SMatt Spinler         else if (typeCode == "n")
1221d22a7131SMatt Spinler         {
1222f39420c7SMatt Spinler             r = readMessageItem<int16_t>(typeCode, m, *thisElement);
1223d22a7131SMatt Spinler             if (r < 0)
1224d22a7131SMatt Spinler             {
1225d22a7131SMatt Spinler                 return r;
1226d22a7131SMatt Spinler             }
1227d22a7131SMatt Spinler         }
1228d22a7131SMatt Spinler         else if (typeCode == "q")
1229d22a7131SMatt Spinler         {
1230f39420c7SMatt Spinler             r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
1231d22a7131SMatt Spinler             if (r < 0)
1232d22a7131SMatt Spinler             {
1233d22a7131SMatt Spinler                 return r;
1234d22a7131SMatt Spinler             }
1235d22a7131SMatt Spinler         }
1236d22a7131SMatt Spinler         else if (typeCode == "y")
1237d22a7131SMatt Spinler         {
1238f39420c7SMatt Spinler             r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
1239d22a7131SMatt Spinler             if (r < 0)
1240d22a7131SMatt Spinler             {
1241d22a7131SMatt Spinler                 return r;
1242d22a7131SMatt Spinler             }
1243d22a7131SMatt Spinler         }
1244d22a7131SMatt Spinler         else if (typeCode == "d")
1245d22a7131SMatt Spinler         {
1246f39420c7SMatt Spinler             r = readMessageItem<double>(typeCode, m, *thisElement);
1247d22a7131SMatt Spinler             if (r < 0)
1248d22a7131SMatt Spinler             {
1249d22a7131SMatt Spinler                 return r;
1250d22a7131SMatt Spinler             }
1251d22a7131SMatt Spinler         }
1252d22a7131SMatt Spinler         else if (typeCode == "h")
1253d22a7131SMatt Spinler         {
1254f39420c7SMatt Spinler             r = readMessageItem<int>(typeCode, m, *thisElement);
1255d22a7131SMatt Spinler             if (r < 0)
1256d22a7131SMatt Spinler             {
1257d22a7131SMatt Spinler                 return r;
1258d22a7131SMatt Spinler             }
1259d22a7131SMatt Spinler         }
126011ba3979SEd Tanous         else if (typeCode.starts_with("a"))
12616df8f990SMatt Spinler         {
1262f39420c7SMatt Spinler             r = readArrayFromMessage(typeCode, m, *thisElement);
12636df8f990SMatt Spinler             if (r < 0)
12646df8f990SMatt Spinler             {
12656df8f990SMatt Spinler                 return r;
12666df8f990SMatt Spinler             }
12676df8f990SMatt Spinler         }
126811ba3979SEd Tanous         else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
126975c6c67fSMatt Spinler         {
1270f39420c7SMatt Spinler             r = readStructFromMessage(typeCode, m, *thisElement);
127175c6c67fSMatt Spinler             if (r < 0)
127275c6c67fSMatt Spinler             {
127375c6c67fSMatt Spinler                 return r;
127475c6c67fSMatt Spinler             }
127575c6c67fSMatt Spinler         }
127611ba3979SEd Tanous         else if (typeCode.starts_with("v"))
127789c1970bSMatt Spinler         {
1278f39420c7SMatt Spinler             r = readVariantFromMessage(m, *thisElement);
127989c1970bSMatt Spinler             if (r < 0)
128089c1970bSMatt Spinler             {
128189c1970bSMatt Spinler                 return r;
128289c1970bSMatt Spinler             }
128389c1970bSMatt Spinler         }
1284d22a7131SMatt Spinler         else
1285d22a7131SMatt Spinler         {
128662598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
1287d22a7131SMatt Spinler             return -2;
1288d22a7131SMatt Spinler         }
1289d22a7131SMatt Spinler     }
1290d22a7131SMatt Spinler 
129116caaee1SMatt Spinler     return 0;
129216caaee1SMatt Spinler }
129316caaee1SMatt Spinler 
handleMethodResponse(const std::shared_ptr<InProgressActionData> & transaction,sdbusplus::message_t & m,const std::string & returnType)1294b5a76932SEd Tanous inline void handleMethodResponse(
1295b5a76932SEd Tanous     const std::shared_ptr<InProgressActionData>& transaction,
129659d494eeSPatrick Williams     sdbusplus::message_t& m, const std::string& returnType)
129716caaee1SMatt Spinler {
129839a4e39fSMatt Spinler     nlohmann::json data;
129939a4e39fSMatt Spinler 
130039a4e39fSMatt Spinler     int r = convertDBusToJSON(returnType, m, data);
130139a4e39fSMatt Spinler     if (r < 0)
130239a4e39fSMatt Spinler     {
130339a4e39fSMatt Spinler         transaction->outputFailed = true;
130439a4e39fSMatt Spinler         return;
130539a4e39fSMatt Spinler     }
130639a4e39fSMatt Spinler 
130739a4e39fSMatt Spinler     if (data.is_null())
130839a4e39fSMatt Spinler     {
130939a4e39fSMatt Spinler         return;
131039a4e39fSMatt Spinler     }
131139a4e39fSMatt Spinler 
131239a4e39fSMatt Spinler     if (transaction->methodResponse.is_null())
131339a4e39fSMatt Spinler     {
131439a4e39fSMatt Spinler         transaction->methodResponse = std::move(data);
131539a4e39fSMatt Spinler         return;
131639a4e39fSMatt Spinler     }
131739a4e39fSMatt Spinler 
131839a4e39fSMatt Spinler     // If they're both dictionaries or arrays, merge into one.
131939a4e39fSMatt Spinler     // Otherwise, make the results an array with every result
132039a4e39fSMatt Spinler     // an entry.  Could also just fail in that case, but it
132139a4e39fSMatt Spinler     // seems better to get the data back somehow.
13220bdda665SEd Tanous     nlohmann::json::object_t* dataobj =
13230bdda665SEd Tanous         data.get_ptr<nlohmann::json::object_t*>();
13240bdda665SEd Tanous     if (transaction->methodResponse.is_object() && dataobj != nullptr)
132539a4e39fSMatt Spinler     {
13260bdda665SEd Tanous         for (auto& obj : *dataobj)
132739a4e39fSMatt Spinler         {
132839a4e39fSMatt Spinler             // Note: Will overwrite the data for a duplicate key
13290bdda665SEd Tanous             transaction->methodResponse.emplace(obj.first,
13300bdda665SEd Tanous                                                 std::move(obj.second));
133139a4e39fSMatt Spinler         }
133239a4e39fSMatt Spinler         return;
133339a4e39fSMatt Spinler     }
133439a4e39fSMatt Spinler 
13350bdda665SEd Tanous     nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
13360bdda665SEd Tanous     if (transaction->methodResponse.is_array() && dataarr != nullptr)
133739a4e39fSMatt Spinler     {
13380bdda665SEd Tanous         for (auto& obj : *dataarr)
133939a4e39fSMatt Spinler         {
1340b2ba3072SPatrick Williams             transaction->methodResponse.emplace_back(std::move(obj));
134139a4e39fSMatt Spinler         }
134239a4e39fSMatt Spinler         return;
134339a4e39fSMatt Spinler     }
134439a4e39fSMatt Spinler 
134539a4e39fSMatt Spinler     if (!transaction->convertedToArray)
134639a4e39fSMatt Spinler     {
134739a4e39fSMatt Spinler         // They are different types. May as well turn them into an array
134839a4e39fSMatt Spinler         nlohmann::json j = std::move(transaction->methodResponse);
134939a4e39fSMatt Spinler         transaction->methodResponse = nlohmann::json::array();
1350b2ba3072SPatrick Williams         transaction->methodResponse.emplace_back(std::move(j));
1351b2ba3072SPatrick Williams         transaction->methodResponse.emplace_back(std::move(data));
135239a4e39fSMatt Spinler         transaction->convertedToArray = true;
135339a4e39fSMatt Spinler     }
135439a4e39fSMatt Spinler     else
135539a4e39fSMatt Spinler     {
1356b2ba3072SPatrick Williams         transaction->methodResponse.emplace_back(std::move(data));
135739a4e39fSMatt Spinler     }
135816caaee1SMatt Spinler }
135916caaee1SMatt Spinler 
findActionOnInterface(const std::shared_ptr<InProgressActionData> & transaction,const std::string & connectionName)1360b5a76932SEd Tanous inline void findActionOnInterface(
1361b5a76932SEd Tanous     const std::shared_ptr<InProgressActionData>& transaction,
13621abe55efSEd Tanous     const std::string& connectionName)
13631abe55efSEd Tanous {
136462598e31SEd Tanous     BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
136555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
13661abe55efSEd Tanous         [transaction, connectionName{std::string(connectionName)}](
13675e7e2dc5SEd Tanous             const boost::system::error_code& ec,
136881ce609eSEd Tanous             const std::string& introspectXml) {
136962598e31SEd Tanous             BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
13701abe55efSEd Tanous             if (ec)
13711abe55efSEd Tanous             {
137262598e31SEd Tanous                 BMCWEB_LOG_ERROR(
137362598e31SEd Tanous                     "Introspect call failed with error: {} on process: {}",
137462598e31SEd Tanous                     ec.message(), connectionName);
1375318bd892SMatt Spinler                 return;
13761abe55efSEd Tanous             }
1377d4bb9bbdSEd Tanous             tinyxml2::XMLDocument doc;
1378d4bb9bbdSEd Tanous 
137981ce609eSEd Tanous             doc.Parse(introspectXml.data(), introspectXml.size());
1380d4bb9bbdSEd Tanous             tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
13811abe55efSEd Tanous             if (pRoot == nullptr)
13821abe55efSEd Tanous             {
1383bd79bce8SPatrick Williams                 BMCWEB_LOG_ERROR("XML document failed to parse {}",
1384bd79bce8SPatrick Williams                                  connectionName);
1385e3cb5a31SEd Tanous                 return;
13861abe55efSEd Tanous             }
1387e3cb5a31SEd Tanous             tinyxml2::XMLElement* interfaceNode =
1388d4bb9bbdSEd Tanous                 pRoot->FirstChildElement("interface");
1389e3cb5a31SEd Tanous             while (interfaceNode != nullptr)
13901abe55efSEd Tanous             {
1391bd79bce8SPatrick Williams                 const char* thisInterfaceName =
1392bd79bce8SPatrick Williams                     interfaceNode->Attribute("name");
1393e3cb5a31SEd Tanous                 if (thisInterfaceName != nullptr)
13941abe55efSEd Tanous                 {
1395de81881fSMatt Spinler                     if (!transaction->interfaceName.empty() &&
1396de81881fSMatt Spinler                         (transaction->interfaceName != thisInterfaceName))
1397de81881fSMatt Spinler                     {
1398de81881fSMatt Spinler                         interfaceNode =
1399de81881fSMatt Spinler                             interfaceNode->NextSiblingElement("interface");
1400de81881fSMatt Spinler                         continue;
1401de81881fSMatt Spinler                     }
1402de81881fSMatt Spinler 
1403e3cb5a31SEd Tanous                     tinyxml2::XMLElement* methodNode =
1404e3cb5a31SEd Tanous                         interfaceNode->FirstChildElement("method");
1405e3cb5a31SEd Tanous                     while (methodNode != nullptr)
1406e3cb5a31SEd Tanous                     {
1407bd79bce8SPatrick Williams                         const char* thisMethodName =
1408bd79bce8SPatrick Williams                             methodNode->Attribute("name");
140962598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
1410e3cb5a31SEd Tanous                         if (thisMethodName != nullptr &&
1411e3cb5a31SEd Tanous                             thisMethodName == transaction->methodName)
14121abe55efSEd Tanous                         {
141362598e31SEd Tanous                             BMCWEB_LOG_DEBUG(
141462598e31SEd Tanous                                 "Found method named {} on interface {}",
141562598e31SEd Tanous                                 thisMethodName, thisInterfaceName);
141659d494eeSPatrick Williams                             sdbusplus::message_t m =
1417318bd892SMatt Spinler                                 crow::connections::systemBus->new_method_call(
14181abe55efSEd Tanous                                     connectionName.c_str(),
1419bd79bce8SPatrick Williams                                     transaction->path.c_str(),
1420bd79bce8SPatrick Williams                                     thisInterfaceName,
1421d76323e5SEd Tanous                                     transaction->methodName.c_str());
1422d4bb9bbdSEd Tanous 
1423e3cb5a31SEd Tanous                             tinyxml2::XMLElement* argumentNode =
1424e3cb5a31SEd Tanous                                 methodNode->FirstChildElement("arg");
1425d4bb9bbdSEd Tanous 
142616caaee1SMatt Spinler                             std::string returnType;
142716caaee1SMatt Spinler 
142816caaee1SMatt Spinler                             // Find the output type
142916caaee1SMatt Spinler                             while (argumentNode != nullptr)
143016caaee1SMatt Spinler                             {
143116caaee1SMatt Spinler                                 const char* argDirection =
143216caaee1SMatt Spinler                                     argumentNode->Attribute("direction");
143316caaee1SMatt Spinler                                 const char* argType =
143416caaee1SMatt Spinler                                     argumentNode->Attribute("type");
1435bd79bce8SPatrick Williams                                 if (argDirection != nullptr &&
1436bd79bce8SPatrick Williams                                     argType != nullptr &&
143716caaee1SMatt Spinler                                     std::string(argDirection) == "out")
143816caaee1SMatt Spinler                                 {
143916caaee1SMatt Spinler                                     returnType = argType;
144016caaee1SMatt Spinler                                     break;
144116caaee1SMatt Spinler                                 }
144216caaee1SMatt Spinler                                 argumentNode =
144316caaee1SMatt Spinler                                     argumentNode->NextSiblingElement("arg");
144416caaee1SMatt Spinler                             }
144516caaee1SMatt Spinler 
1446b2ec0ce5SNan Zhou                             auto argIt = transaction->arguments.begin();
1447d4bb9bbdSEd Tanous 
144816caaee1SMatt Spinler                             argumentNode = methodNode->FirstChildElement("arg");
144916caaee1SMatt Spinler 
1450e3cb5a31SEd Tanous                             while (argumentNode != nullptr)
14511abe55efSEd Tanous                             {
1452e3cb5a31SEd Tanous                                 const char* argDirection =
1453e3cb5a31SEd Tanous                                     argumentNode->Attribute("direction");
1454e3cb5a31SEd Tanous                                 const char* argType =
1455e3cb5a31SEd Tanous                                     argumentNode->Attribute("type");
1456bd79bce8SPatrick Williams                                 if (argDirection != nullptr &&
1457bd79bce8SPatrick Williams                                     argType != nullptr &&
1458e3cb5a31SEd Tanous                                     std::string(argDirection) == "in")
14591abe55efSEd Tanous                                 {
1460318bd892SMatt Spinler                                     if (argIt == transaction->arguments.end())
14611abe55efSEd Tanous                                     {
14626db06242SMatt Spinler                                         transaction->setErrorStatus(
14636db06242SMatt Spinler                                             "Invalid method args");
1464d4bb9bbdSEd Tanous                                         return;
1465d4bb9bbdSEd Tanous                                     }
1466318bd892SMatt Spinler                                     if (convertJsonToDbus(m.get(),
1467318bd892SMatt Spinler                                                           std::string(argType),
1468e3cb5a31SEd Tanous                                                           *argIt) < 0)
14691abe55efSEd Tanous                                     {
14706db06242SMatt Spinler                                         transaction->setErrorStatus(
14716db06242SMatt Spinler                                             "Invalid method arg type");
1472d4bb9bbdSEd Tanous                                         return;
1473d4bb9bbdSEd Tanous                                     }
1474d4bb9bbdSEd Tanous 
1475e3cb5a31SEd Tanous                                     argIt++;
1476d4bb9bbdSEd Tanous                                 }
1477e3cb5a31SEd Tanous                                 argumentNode =
14784d72dcc3SAppaRao Puli                                     argumentNode->NextSiblingElement("arg");
1479d4bb9bbdSEd Tanous                             }
1480e3cb5a31SEd Tanous 
148155c7b7a2SEd Tanous                             crow::connections::systemBus->async_send(
14825a39f77aSPatrick Williams                                 m, [transaction, returnType](
14835a39f77aSPatrick Williams                                        const boost::system::error_code& ec2,
148459d494eeSPatrick Williams                                        sdbusplus::message_t& m2) {
148523a21a1cSEd Tanous                                     if (ec2)
14861abe55efSEd Tanous                                     {
148716caaee1SMatt Spinler                                         transaction->methodFailed = true;
148823a21a1cSEd Tanous                                         const sd_bus_error* e = m2.get_error();
148906b1b63cSMatt Spinler 
1490e662eae8SEd Tanous                                         if (e != nullptr)
149106b1b63cSMatt Spinler                                         {
149206b1b63cSMatt Spinler                                             setErrorResponse(
149328dd5ca1SLei YU                                                 transaction->asyncResp->res,
1494bd79bce8SPatrick Williams                                                 boost::beast::http::status::
1495bd79bce8SPatrick Williams                                                     bad_request,
149606b1b63cSMatt Spinler                                                 e->name, e->message);
149706b1b63cSMatt Spinler                                         }
149806b1b63cSMatt Spinler                                         else
149906b1b63cSMatt Spinler                                         {
150006b1b63cSMatt Spinler                                             setErrorResponse(
150128dd5ca1SLei YU                                                 transaction->asyncResp->res,
1502bd79bce8SPatrick Williams                                                 boost::beast::http::status::
1503bd79bce8SPatrick Williams                                                     bad_request,
1504bd79bce8SPatrick Williams                                                 "Method call failed",
1505bd79bce8SPatrick Williams                                                 methodFailedMsg);
150606b1b63cSMatt Spinler                                         }
1507d4bb9bbdSEd Tanous                                         return;
1508d4bb9bbdSEd Tanous                                     }
150916caaee1SMatt Spinler                                     transaction->methodPassed = true;
151016caaee1SMatt Spinler 
1511bd79bce8SPatrick Williams                                     handleMethodResponse(transaction, m2,
1512bd79bce8SPatrick Williams                                                          returnType);
1513d4bb9bbdSEd Tanous                                 });
1514d4bb9bbdSEd Tanous                             break;
1515d4bb9bbdSEd Tanous                         }
1516318bd892SMatt Spinler                         methodNode = methodNode->NextSiblingElement("method");
1517d4bb9bbdSEd Tanous                     }
1518d4bb9bbdSEd Tanous                 }
1519318bd892SMatt Spinler                 interfaceNode = interfaceNode->NextSiblingElement("interface");
1520d4bb9bbdSEd Tanous             }
1521d4bb9bbdSEd Tanous         },
15221abe55efSEd Tanous         connectionName, transaction->path,
15231abe55efSEd Tanous         "org.freedesktop.DBus.Introspectable", "Introspect");
1524d4bb9bbdSEd Tanous }
1525d4bb9bbdSEd Tanous 
handleAction(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,const std::string & methodName)15268d1b46d7Szhanghch05 inline void handleAction(const crow::Request& req,
15278d1b46d7Szhanghch05                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
152823a21a1cSEd Tanous                          const std::string& objectPath,
152923a21a1cSEd Tanous                          const std::string& methodName)
15301abe55efSEd Tanous {
153162598e31SEd Tanous     BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
153262598e31SEd Tanous                      methodName);
15331aa0c2b8SEd Tanous     nlohmann::json requestDbusData;
1534d4bb9bbdSEd Tanous 
15351aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
15361aa0c2b8SEd Tanous     if (ret == JsonParseResult::BadContentType)
15371aa0c2b8SEd Tanous     {
15381aa0c2b8SEd Tanous         setErrorResponse(asyncResp->res,
15391aa0c2b8SEd Tanous                          boost::beast::http::status::unsupported_media_type,
15401aa0c2b8SEd Tanous                          invalidContentType, unsupportedMediaMsg);
15411aa0c2b8SEd Tanous         return;
15421aa0c2b8SEd Tanous     }
15431aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
15441abe55efSEd Tanous     {
15458d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
15468d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
15478d1b46d7Szhanghch05                          badReqMsg);
1548d4bb9bbdSEd Tanous         return;
1549d4bb9bbdSEd Tanous     }
1550e3cb5a31SEd Tanous     nlohmann::json::iterator data = requestDbusData.find("data");
1551e3cb5a31SEd Tanous     if (data == requestDbusData.end())
1552e3cb5a31SEd Tanous     {
15538d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
15548d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
15558d1b46d7Szhanghch05                          badReqMsg);
1556e3cb5a31SEd Tanous         return;
1557e3cb5a31SEd Tanous     }
1558e3cb5a31SEd Tanous 
1559e3cb5a31SEd Tanous     if (!data->is_array())
15601abe55efSEd Tanous     {
15618d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
15628d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
15638d1b46d7Szhanghch05                          badReqMsg);
1564d4bb9bbdSEd Tanous         return;
1565d4bb9bbdSEd Tanous     }
156628dd5ca1SLei YU     auto transaction = std::make_shared<InProgressActionData>(asyncResp);
1567d4bb9bbdSEd Tanous 
1568d76323e5SEd Tanous     transaction->path = objectPath;
1569d76323e5SEd Tanous     transaction->methodName = methodName;
1570e3cb5a31SEd Tanous     transaction->arguments = std::move(*data);
15712b73119cSGeorge Liu     dbus::utility::getDbusObject(
15722b73119cSGeorge Liu         objectPath, {},
1573d4bb9bbdSEd Tanous         [transaction](
15742b73119cSGeorge Liu             const boost::system::error_code& ec,
15751214b7e7SGunnar Mills             const std::vector<std::pair<std::string, std::vector<std::string>>>&
15761214b7e7SGunnar Mills                 interfaceNames) {
157726f6976fSEd Tanous             if (ec || interfaceNames.empty())
15781abe55efSEd Tanous             {
157962598e31SEd Tanous                 BMCWEB_LOG_ERROR("Can't find object");
158028dd5ca1SLei YU                 setErrorResponse(transaction->asyncResp->res,
15816db06242SMatt Spinler                                  boost::beast::http::status::not_found,
15826db06242SMatt Spinler                                  notFoundDesc, notFoundMsg);
1583d4bb9bbdSEd Tanous                 return;
1584d4bb9bbdSEd Tanous             }
1585d4bb9bbdSEd Tanous 
158662598e31SEd Tanous             BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
158762598e31SEd Tanous                              interfaceNames.size());
1588d4bb9bbdSEd Tanous 
1589bd79bce8SPatrick Williams             for (const std::pair<std::string, std::vector<std::string>>&
1590bd79bce8SPatrick Williams                      object : interfaceNames)
15911abe55efSEd Tanous             {
1592d76323e5SEd Tanous                 findActionOnInterface(transaction, object.first);
1593d4bb9bbdSEd Tanous             }
15942b73119cSGeorge Liu         });
1595d4bb9bbdSEd Tanous }
1596d4bb9bbdSEd Tanous 
handleDelete(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath)15978d1b46d7Szhanghch05 inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15988d1b46d7Szhanghch05                          const std::string& objectPath)
1599de81881fSMatt Spinler {
160062598e31SEd Tanous     BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
1601de81881fSMatt Spinler 
16022b73119cSGeorge Liu     dbus::utility::getDbusObject(
16032b73119cSGeorge Liu         objectPath, {},
16048d1b46d7Szhanghch05         [asyncResp, objectPath](
16052b73119cSGeorge Liu             const boost::system::error_code& ec,
16061214b7e7SGunnar Mills             const std::vector<std::pair<std::string, std::vector<std::string>>>&
16071214b7e7SGunnar Mills                 interfaceNames) {
160826f6976fSEd Tanous             if (ec || interfaceNames.empty())
1609de81881fSMatt Spinler             {
161062598e31SEd Tanous                 BMCWEB_LOG_ERROR("Can't find object");
16118d1b46d7Szhanghch05                 setErrorResponse(asyncResp->res,
161262d2e8b6SMatt Spinler                                  boost::beast::http::status::method_not_allowed,
161362d2e8b6SMatt Spinler                                  methodNotAllowedDesc, methodNotAllowedMsg);
1614de81881fSMatt Spinler                 return;
1615de81881fSMatt Spinler             }
1616de81881fSMatt Spinler 
1617bd79bce8SPatrick Williams             auto transaction =
1618bd79bce8SPatrick Williams                 std::make_shared<InProgressActionData>(asyncResp);
1619de81881fSMatt Spinler             transaction->path = objectPath;
1620de81881fSMatt Spinler             transaction->methodName = "Delete";
1621de81881fSMatt Spinler             transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1622de81881fSMatt Spinler 
1623bd79bce8SPatrick Williams             for (const std::pair<std::string, std::vector<std::string>>&
1624bd79bce8SPatrick Williams                      object : interfaceNames)
1625de81881fSMatt Spinler             {
1626de81881fSMatt Spinler                 findActionOnInterface(transaction, object.first);
1627de81881fSMatt Spinler             }
16282b73119cSGeorge Liu         });
1629de81881fSMatt Spinler }
1630de81881fSMatt Spinler 
handleList(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,int32_t depth=0)16318d1b46d7Szhanghch05 inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16328d1b46d7Szhanghch05                        const std::string& objectPath, int32_t depth = 0)
16331abe55efSEd Tanous {
16347a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
16357a1dbc48SGeorge Liu         objectPath, depth, {},
1636b9d36b47SEd Tanous         [asyncResp](
16377a1dbc48SGeorge Liu             const boost::system::error_code& ec,
1638b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
16391abe55efSEd Tanous             if (ec)
16401abe55efSEd Tanous             {
16418d1b46d7Szhanghch05                 setErrorResponse(asyncResp->res,
16428d1b46d7Szhanghch05                                  boost::beast::http::status::not_found,
1643d6091dddSMatt Spinler                                  notFoundDesc, notFoundMsg);
16441abe55efSEd Tanous             }
16451abe55efSEd Tanous             else
16461abe55efSEd Tanous             {
16471476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
16481476687dSEd Tanous                 asyncResp->res.jsonValue["message"] = "200 OK";
16491476687dSEd Tanous                 asyncResp->res.jsonValue["data"] = objectPaths;
1650d4bb9bbdSEd Tanous             }
16517a1dbc48SGeorge Liu         });
1652d4bb9bbdSEd Tanous }
1653d4bb9bbdSEd Tanous 
handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath)16548d1b46d7Szhanghch05 inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16558d1b46d7Szhanghch05                             const std::string& objectPath)
16561abe55efSEd Tanous {
165762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
1658049a0515SEd Tanous 
16591476687dSEd Tanous     asyncResp->res.jsonValue["message"] = "200 OK";
16601476687dSEd Tanous     asyncResp->res.jsonValue["status"] = "ok";
16611476687dSEd Tanous     asyncResp->res.jsonValue["data"] = nlohmann::json::object();
1662d4bb9bbdSEd Tanous 
1663e99073f5SGeorge Liu     dbus::utility::getSubTree(
1664e99073f5SGeorge Liu         objectPath, 0, {},
1665b9d36b47SEd Tanous         [objectPath, asyncResp](
1666e99073f5SGeorge Liu             const boost::system::error_code& ec,
1667b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& objectNames) {
1668bd79bce8SPatrick Williams             auto transaction = std::make_shared<InProgressEnumerateData>(
1669bd79bce8SPatrick Williams                 objectPath, asyncResp);
16703ae4ba7bSMatt Spinler 
16713ae4ba7bSMatt Spinler             transaction->subtree =
1672b9d36b47SEd Tanous                 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1673b9d36b47SEd Tanous                     objectNames);
16743ae4ba7bSMatt Spinler 
1675049a0515SEd Tanous             if (ec)
1676049a0515SEd Tanous             {
167762598e31SEd Tanous                 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
167862598e31SEd Tanous                                  transaction->objectPath);
16792ae60096SMatt Spinler                 setErrorResponse(transaction->asyncResp->res,
16802ae60096SMatt Spinler                                  boost::beast::http::status::not_found,
16812ae60096SMatt Spinler                                  notFoundDesc, notFoundMsg);
168264530018SEd Tanous                 return;
168364530018SEd Tanous             }
168464530018SEd Tanous 
16853ae4ba7bSMatt Spinler             // Add the data for the path passed in to the results
16863ae4ba7bSMatt Spinler             // as if GetSubTree returned it, and continue on enumerating
16873ae4ba7bSMatt Spinler             getObjectAndEnumerate(transaction);
1688e99073f5SGeorge Liu         });
168964530018SEd Tanous }
1690911ac317SEd Tanous 
handleGet(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string & objectPath,std::string & destProperty)16918d1b46d7Szhanghch05 inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16928d1b46d7Szhanghch05                       std::string& objectPath, std::string& destProperty)
16931abe55efSEd Tanous {
169462598e31SEd Tanous     BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
1695e3cb5a31SEd Tanous     std::shared_ptr<std::string> propertyName =
1696d76323e5SEd Tanous         std::make_shared<std::string>(std::move(destProperty));
169775db20e9SEd Tanous 
169875db20e9SEd Tanous     std::shared_ptr<std::string> path =
1699d76323e5SEd Tanous         std::make_shared<std::string>(std::move(objectPath));
170075db20e9SEd Tanous 
17012b73119cSGeorge Liu     dbus::utility::getDbusObject(
17022b73119cSGeorge Liu         *path, {},
1703b9d36b47SEd Tanous         [asyncResp, path,
17042b73119cSGeorge Liu          propertyName](const boost::system::error_code& ec,
1705b9d36b47SEd Tanous                        const dbus::utility::MapperGetObject& objectNames) {
170626f6976fSEd Tanous             if (ec || objectNames.empty())
17071abe55efSEd Tanous             {
17088d1b46d7Szhanghch05                 setErrorResponse(asyncResp->res,
17098d1b46d7Szhanghch05                                  boost::beast::http::status::not_found,
1710dc2f9f11SMatt Spinler                                  notFoundDesc, notFoundMsg);
1711d4bb9bbdSEd Tanous                 return;
1712d4bb9bbdSEd Tanous             }
1713d4bb9bbdSEd Tanous             std::shared_ptr<nlohmann::json> response =
1714d4bb9bbdSEd Tanous                 std::make_shared<nlohmann::json>(nlohmann::json::object());
171523a21a1cSEd Tanous             for (const std::pair<std::string, std::vector<std::string>>&
171681ce609eSEd Tanous                      connection : objectNames)
17171abe55efSEd Tanous             {
1718bd79bce8SPatrick Williams                 const std::vector<std::string>& interfaceNames =
1719bd79bce8SPatrick Williams                     connection.second;
1720d4bb9bbdSEd Tanous 
172126f6976fSEd Tanous                 if (interfaceNames.empty())
17221abe55efSEd Tanous                 {
172365622a5dSLei YU                     // mapper allows empty interfaces in case an
172465622a5dSLei YU                     // object does not implement any interface.
172565622a5dSLei YU                     continue;
1726d4bb9bbdSEd Tanous                 }
1727d4bb9bbdSEd Tanous 
17281abe55efSEd Tanous                 for (const std::string& interface : interfaceNames)
17291abe55efSEd Tanous                 {
173059d494eeSPatrick Williams                     sdbusplus::message_t m =
1731fe7e97d3SMatt Spinler                         crow::connections::systemBus->new_method_call(
1732fe7e97d3SMatt Spinler                             connection.first.c_str(), path->c_str(),
1733fe7e97d3SMatt Spinler                             "org.freedesktop.DBus.Properties", "GetAll");
1734fe7e97d3SMatt Spinler                     m.append(interface);
1735fe7e97d3SMatt Spinler                     crow::connections::systemBus->async_send(
17368d1b46d7Szhanghch05                         m, [asyncResp, response,
17375e7e2dc5SEd Tanous                             propertyName](const boost::system::error_code& ec2,
173859d494eeSPatrick Williams                                           sdbusplus::message_t& msg) {
173923a21a1cSEd Tanous                             if (ec2)
17401abe55efSEd Tanous                             {
1741bd79bce8SPatrick Williams                                 BMCWEB_LOG_ERROR("Bad dbus request error: {}",
1742bd79bce8SPatrick Williams                                                  ec2);
17431abe55efSEd Tanous                             }
1744984a4c2bSEd Tanous                             else
1745984a4c2bSEd Tanous                             {
1746fe7e97d3SMatt Spinler                                 nlohmann::json properties;
1747bd79bce8SPatrick Williams                                 int r =
1748bd79bce8SPatrick Williams                                     convertDBusToJSON("a{sv}", msg, properties);
1749fe7e97d3SMatt Spinler                                 if (r < 0)
17501abe55efSEd Tanous                                 {
1751bd79bce8SPatrick Williams                                     BMCWEB_LOG_ERROR(
1752bd79bce8SPatrick Williams                                         "convertDBusToJSON failed");
1753fe7e97d3SMatt Spinler                                 }
1754fe7e97d3SMatt Spinler                                 else
1755fe7e97d3SMatt Spinler                                 {
17560bdda665SEd Tanous                                     nlohmann::json::object_t* obj =
1757bd79bce8SPatrick Williams                                         properties.get_ptr<
1758bd79bce8SPatrick Williams                                             nlohmann::json::object_t*>();
17590bdda665SEd Tanous                                     if (obj == nullptr)
17600bdda665SEd Tanous                                     {
17610bdda665SEd Tanous                                         return;
17620bdda665SEd Tanous                                     }
17630bdda665SEd Tanous                                     for (auto& prop : *obj)
1764fe7e97d3SMatt Spinler                                     {
17657c09162aSEd Tanous                                         // if property name is empty, or
17667c09162aSEd Tanous                                         // matches our search query, add it
17677c09162aSEd Tanous                                         // to the response json
1768d4bb9bbdSEd Tanous 
1769e3cb5a31SEd Tanous                                         if (propertyName->empty())
17701abe55efSEd Tanous                                         {
17710bdda665SEd Tanous                                             (*response)[prop.first] =
17720bdda665SEd Tanous                                                 std::move(prop.second);
17731abe55efSEd Tanous                                         }
17740bdda665SEd Tanous                                         else if (prop.first == *propertyName)
17751abe55efSEd Tanous                                         {
17760bdda665SEd Tanous                                             *response = std::move(prop.second);
1777fe7e97d3SMatt Spinler                                         }
1778d4bb9bbdSEd Tanous                                     }
1779d4bb9bbdSEd Tanous                                 }
1780984a4c2bSEd Tanous                             }
17811abe55efSEd Tanous                             if (response.use_count() == 1)
17821abe55efSEd Tanous                             {
1783dc2f9f11SMatt Spinler                                 if (!propertyName->empty() && response->empty())
1784dc2f9f11SMatt Spinler                                 {
1785dc2f9f11SMatt Spinler                                     setErrorResponse(
17868d1b46d7Szhanghch05                                         asyncResp->res,
1787dc2f9f11SMatt Spinler                                         boost::beast::http::status::not_found,
1788dc2f9f11SMatt Spinler                                         propNotFoundDesc, notFoundMsg);
1789dc2f9f11SMatt Spinler                                 }
1790dc2f9f11SMatt Spinler                                 else
1791dc2f9f11SMatt Spinler                                 {
17921476687dSEd Tanous                                     asyncResp->res.jsonValue["status"] = "ok";
1793bd79bce8SPatrick Williams                                     asyncResp->res.jsonValue["message"] =
1794bd79bce8SPatrick Williams                                         "200 OK";
1795bd79bce8SPatrick Williams                                     asyncResp->res.jsonValue["data"] =
1796bd79bce8SPatrick Williams                                         *response;
1797dc2f9f11SMatt Spinler                                 }
1798d4bb9bbdSEd Tanous                             }
1799fe7e97d3SMatt Spinler                         });
1800d4bb9bbdSEd Tanous                 }
1801d4bb9bbdSEd Tanous             }
18022b73119cSGeorge Liu         });
1803d4bb9bbdSEd Tanous }
1804d4bb9bbdSEd Tanous 
18051abe55efSEd Tanous struct AsyncPutRequest
18061abe55efSEd Tanous {
AsyncPutRequestcrow::openbmc_mapper::AsyncPutRequest18074e23a444SEd Tanous     explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
18088d1b46d7Szhanghch05         asyncResp(resIn)
18091214b7e7SGunnar Mills     {}
~AsyncPutRequestcrow::openbmc_mapper::AsyncPutRequest18101abe55efSEd Tanous     ~AsyncPutRequest()
18111abe55efSEd Tanous     {
18128d1b46d7Szhanghch05         if (asyncResp->res.jsonValue.empty())
18131abe55efSEd Tanous         {
18148d1b46d7Szhanghch05             setErrorResponse(asyncResp->res,
18158d1b46d7Szhanghch05                              boost::beast::http::status::forbidden,
1816fbc19ea6SMatt Spinler                              forbiddenMsg, forbiddenPropDesc);
1817d4bb9bbdSEd Tanous         }
1818d4bb9bbdSEd Tanous     }
1819d4bb9bbdSEd Tanous 
1820ecd6a3a2SEd Tanous     AsyncPutRequest(const AsyncPutRequest&) = delete;
1821ecd6a3a2SEd Tanous     AsyncPutRequest(AsyncPutRequest&&) = delete;
1822ecd6a3a2SEd Tanous     AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1823ecd6a3a2SEd Tanous     AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1824ecd6a3a2SEd Tanous 
setErrorStatuscrow::openbmc_mapper::AsyncPutRequest1825fbc19ea6SMatt Spinler     void setErrorStatus(const std::string& desc)
18261abe55efSEd Tanous     {
18278d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
18288d1b46d7Szhanghch05                          boost::beast::http::status::internal_server_error,
1829fbc19ea6SMatt Spinler                          desc, badReqMsg);
1830d4bb9bbdSEd Tanous     }
1831d4bb9bbdSEd Tanous 
18328d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
1833d4bb9bbdSEd Tanous     std::string objectPath;
1834d4bb9bbdSEd Tanous     std::string propertyName;
1835d4bb9bbdSEd Tanous     nlohmann::json propertyValue;
1836d4bb9bbdSEd Tanous };
1837d4bb9bbdSEd Tanous 
handlePut(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,const std::string & destProperty)18388d1b46d7Szhanghch05 inline void handlePut(const crow::Request& req,
18398d1b46d7Szhanghch05                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
184023a21a1cSEd Tanous                       const std::string& objectPath,
184123a21a1cSEd Tanous                       const std::string& destProperty)
18421abe55efSEd Tanous {
1843fbc19ea6SMatt Spinler     if (destProperty.empty())
1844fbc19ea6SMatt Spinler     {
18458d1b46d7Szhanghch05         setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
1846fbc19ea6SMatt Spinler                          forbiddenResDesc, forbiddenMsg);
1847fbc19ea6SMatt Spinler         return;
1848fbc19ea6SMatt Spinler     }
18491aa0c2b8SEd Tanous     nlohmann::json requestDbusData;
1850fbc19ea6SMatt Spinler 
18511aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
18521aa0c2b8SEd Tanous     if (ret == JsonParseResult::BadContentType)
18531aa0c2b8SEd Tanous     {
18541aa0c2b8SEd Tanous         setErrorResponse(asyncResp->res,
18551aa0c2b8SEd Tanous                          boost::beast::http::status::unsupported_media_type,
18561aa0c2b8SEd Tanous                          invalidContentType, unsupportedMediaMsg);
18571aa0c2b8SEd Tanous         return;
18581aa0c2b8SEd Tanous     }
1859d4bb9bbdSEd Tanous 
18601aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
18611abe55efSEd Tanous     {
18628d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
18638d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
18648d1b46d7Szhanghch05                          badReqMsg);
1865d4bb9bbdSEd Tanous         return;
1866d4bb9bbdSEd Tanous     }
1867d4bb9bbdSEd Tanous 
1868b2ec0ce5SNan Zhou     auto propertyIt = requestDbusData.find("data");
18691abe55efSEd Tanous     if (propertyIt == requestDbusData.end())
18701abe55efSEd Tanous     {
18718d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
18728d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
18738d1b46d7Szhanghch05                          badReqMsg);
1874d4bb9bbdSEd Tanous         return;
1875d4bb9bbdSEd Tanous     }
1876d76323e5SEd Tanous     const nlohmann::json& propertySetValue = *propertyIt;
18778d1b46d7Szhanghch05     auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
1878d4bb9bbdSEd Tanous     transaction->objectPath = objectPath;
1879d4bb9bbdSEd Tanous     transaction->propertyName = destProperty;
1880d4bb9bbdSEd Tanous     transaction->propertyValue = propertySetValue;
1881d4bb9bbdSEd Tanous 
18822b73119cSGeorge Liu     dbus::utility::getDbusObject(
18832b73119cSGeorge Liu         transaction->objectPath, {},
18842b73119cSGeorge Liu         [transaction](const boost::system::error_code& ec2,
1885b9d36b47SEd Tanous                       const dbus::utility::MapperGetObject& objectNames) {
188626f6976fSEd Tanous             if (!ec2 && objectNames.empty())
18871abe55efSEd Tanous             {
18888d1b46d7Szhanghch05                 setErrorResponse(transaction->asyncResp->res,
1889fbc19ea6SMatt Spinler                                  boost::beast::http::status::not_found,
1890fbc19ea6SMatt Spinler                                  propNotFoundDesc, notFoundMsg);
1891d4bb9bbdSEd Tanous                 return;
1892d4bb9bbdSEd Tanous             }
1893d4bb9bbdSEd Tanous 
189423a21a1cSEd Tanous             for (const std::pair<std::string, std::vector<std::string>>&
189581ce609eSEd Tanous                      connection : objectNames)
18961abe55efSEd Tanous             {
1897d4bb9bbdSEd Tanous                 const std::string& connectionName = connection.first;
1898d4bb9bbdSEd Tanous 
189955c7b7a2SEd Tanous                 crow::connections::systemBus->async_method_call(
19001abe55efSEd Tanous                     [connectionName{std::string(connectionName)},
19015e7e2dc5SEd Tanous                      transaction](const boost::system::error_code& ec3,
1902d4bb9bbdSEd Tanous                                   const std::string& introspectXml) {
190323a21a1cSEd Tanous                         if (ec3)
19041abe55efSEd Tanous                         {
190562598e31SEd Tanous                             BMCWEB_LOG_ERROR(
190662598e31SEd Tanous                                 "Introspect call failed with error: {} on process: {}",
190762598e31SEd Tanous                                 ec3.message(), connectionName);
1908fbc19ea6SMatt Spinler                             transaction->setErrorStatus("Unexpected Error");
1909d4bb9bbdSEd Tanous                             return;
1910d4bb9bbdSEd Tanous                         }
1911d4bb9bbdSEd Tanous                         tinyxml2::XMLDocument doc;
1912d4bb9bbdSEd Tanous 
1913d4bb9bbdSEd Tanous                         doc.Parse(introspectXml.c_str());
1914bd79bce8SPatrick Williams                         tinyxml2::XMLNode* pRoot =
1915bd79bce8SPatrick Williams                             doc.FirstChildElement("node");
19161abe55efSEd Tanous                         if (pRoot == nullptr)
19171abe55efSEd Tanous                         {
191862598e31SEd Tanous                             BMCWEB_LOG_ERROR("XML document failed to parse: {}",
191962598e31SEd Tanous                                              introspectXml);
1920fbc19ea6SMatt Spinler                             transaction->setErrorStatus("Unexpected Error");
1921d4bb9bbdSEd Tanous                             return;
1922d4bb9bbdSEd Tanous                         }
1923d4bb9bbdSEd Tanous                         tinyxml2::XMLElement* ifaceNode =
1924d4bb9bbdSEd Tanous                             pRoot->FirstChildElement("interface");
19251abe55efSEd Tanous                         while (ifaceNode != nullptr)
19261abe55efSEd Tanous                         {
1927bd79bce8SPatrick Williams                             const char* interfaceName =
1928bd79bce8SPatrick Williams                                 ifaceNode->Attribute("name");
1929bd79bce8SPatrick Williams                             BMCWEB_LOG_DEBUG("found interface {}",
1930bd79bce8SPatrick Williams                                              interfaceName);
1931d4bb9bbdSEd Tanous                             tinyxml2::XMLElement* propNode =
1932d4bb9bbdSEd Tanous                                 ifaceNode->FirstChildElement("property");
19331abe55efSEd Tanous                             while (propNode != nullptr)
19341abe55efSEd Tanous                             {
1935bd79bce8SPatrick Williams                                 const char* propertyName =
1936bd79bce8SPatrick Williams                                     propNode->Attribute("name");
1937b0b6152cSEd Tanous                                 if (propertyName == nullptr)
1938b0b6152cSEd Tanous                                 {
1939bd79bce8SPatrick Williams                                     BMCWEB_LOG_DEBUG(
1940bd79bce8SPatrick Williams                                         "Couldn't find name property");
1941b0b6152cSEd Tanous                                     continue;
1942b0b6152cSEd Tanous                                 }
1943bd79bce8SPatrick Williams                                 BMCWEB_LOG_DEBUG("Found property {}",
1944bd79bce8SPatrick Williams                                                  propertyName);
19451abe55efSEd Tanous                                 if (propertyName == transaction->propertyName)
19461abe55efSEd Tanous                                 {
1947bd79bce8SPatrick Williams                                     const char* argType =
1948bd79bce8SPatrick Williams                                         propNode->Attribute("type");
19491abe55efSEd Tanous                                     if (argType != nullptr)
19501abe55efSEd Tanous                                     {
195159d494eeSPatrick Williams                                         sdbusplus::message_t m =
19521abe55efSEd Tanous                                             crow::connections::systemBus
19531abe55efSEd Tanous                                                 ->new_method_call(
1954d4bb9bbdSEd Tanous                                                     connectionName.c_str(),
1955bd79bce8SPatrick Williams                                                     transaction->objectPath
1956bd79bce8SPatrick Williams                                                         .c_str(),
19571abe55efSEd Tanous                                                     "org.freedesktop.DBus."
19581abe55efSEd Tanous                                                     "Properties",
19591abe55efSEd Tanous                                                     "Set");
19601abe55efSEd Tanous                                         m.append(interfaceName,
19611abe55efSEd Tanous                                                  transaction->propertyName);
1962d4bb9bbdSEd Tanous                                         int r = sd_bus_message_open_container(
1963bd79bce8SPatrick Williams                                             m.get(), SD_BUS_TYPE_VARIANT,
1964bd79bce8SPatrick Williams                                             argType);
19651abe55efSEd Tanous                                         if (r < 0)
19661abe55efSEd Tanous                                         {
1967fbc19ea6SMatt Spinler                                             transaction->setErrorStatus(
1968fbc19ea6SMatt Spinler                                                 "Unexpected Error");
1969d4bb9bbdSEd Tanous                                             return;
1970d4bb9bbdSEd Tanous                                         }
19711abe55efSEd Tanous                                         r = convertJsonToDbus(
19721abe55efSEd Tanous                                             m.get(), argType,
1973d4bb9bbdSEd Tanous                                             transaction->propertyValue);
19741abe55efSEd Tanous                                         if (r < 0)
19751abe55efSEd Tanous                                         {
1976c66c859cSAdriana Kobylak                                             if (r == -ERANGE)
1977c66c859cSAdriana Kobylak                                             {
1978c66c859cSAdriana Kobylak                                                 transaction->setErrorStatus(
1979c66c859cSAdriana Kobylak                                                     "Provided property value "
1980c66c859cSAdriana Kobylak                                                     "is out of range for the "
1981c66c859cSAdriana Kobylak                                                     "property type");
1982c66c859cSAdriana Kobylak                                             }
1983c66c859cSAdriana Kobylak                                             else
1984c66c859cSAdriana Kobylak                                             {
1985fbc19ea6SMatt Spinler                                                 transaction->setErrorStatus(
1986fbc19ea6SMatt Spinler                                                     "Invalid arg type");
1987c66c859cSAdriana Kobylak                                             }
1988d4bb9bbdSEd Tanous                                             return;
1989d4bb9bbdSEd Tanous                                         }
1990bd79bce8SPatrick Williams                                         r = sd_bus_message_close_container(
1991bd79bce8SPatrick Williams                                             m.get());
19921abe55efSEd Tanous                                         if (r < 0)
19931abe55efSEd Tanous                                         {
1994fbc19ea6SMatt Spinler                                             transaction->setErrorStatus(
1995fbc19ea6SMatt Spinler                                                 "Unexpected Error");
1996d4bb9bbdSEd Tanous                                             return;
1997d4bb9bbdSEd Tanous                                         }
1998bd79bce8SPatrick Williams                                         crow::connections::systemBus
1999bd79bce8SPatrick Williams                                             ->async_send(
2000bd79bce8SPatrick Williams                                                 m,
2001bd79bce8SPatrick Williams                                                 [transaction](
2002bd79bce8SPatrick Williams                                                     const boost::system::
2003bd79bce8SPatrick Williams                                                         error_code& ec,
200459d494eeSPatrick Williams                                                     sdbusplus::message_t& m2) {
200562598e31SEd Tanous                                                     BMCWEB_LOG_DEBUG("sent");
20061abe55efSEd Tanous                                                     if (ec)
20071abe55efSEd Tanous                                                     {
2008bd79bce8SPatrick Williams                                                         const sd_bus_error* e =
2009bd79bce8SPatrick Williams                                                             m2.get_error();
2010fbc19ea6SMatt Spinler                                                         setErrorResponse(
2011bd79bce8SPatrick Williams                                                             transaction
2012bd79bce8SPatrick Williams                                                                 ->asyncResp
2013bd79bce8SPatrick Williams                                                                 ->res,
2014bd79bce8SPatrick Williams                                                             boost::beast::http::
2015bd79bce8SPatrick Williams                                                                 status::
2016fbc19ea6SMatt Spinler                                                                     forbidden,
2017e662eae8SEd Tanous                                                             (e) != nullptr
2018e662eae8SEd Tanous                                                                 ? e->name
2019bd79bce8SPatrick Williams                                                                 : ec.category()
2020bd79bce8SPatrick Williams                                                                       .name(),
2021bd79bce8SPatrick Williams                                                             (e) != nullptr
2022bd79bce8SPatrick Williams                                                                 ? e->message
202306b1b63cSMatt Spinler                                                                 : ec.message());
2024fbc19ea6SMatt Spinler                                                     }
2025fbc19ea6SMatt Spinler                                                     else
2026fbc19ea6SMatt Spinler                                                     {
2027bd79bce8SPatrick Williams                                                         transaction->asyncResp
2028bd79bce8SPatrick Williams                                                             ->res.jsonValue
2029bd79bce8SPatrick Williams                                                                 ["status"] =
2030bd79bce8SPatrick Williams                                                             "ok";
2031bd79bce8SPatrick Williams                                                         transaction->asyncResp
2032bd79bce8SPatrick Williams                                                             ->res.jsonValue
2033bd79bce8SPatrick Williams                                                                 ["message"] =
2034bd79bce8SPatrick Williams                                                             "200 OK";
2035bd79bce8SPatrick Williams                                                         transaction->asyncResp
2036bd79bce8SPatrick Williams                                                             ->res
2037bd79bce8SPatrick Williams                                                             .jsonValue["data"] =
2038bd79bce8SPatrick Williams                                                             nullptr;
2039d4bb9bbdSEd Tanous                                                     }
2040d4bb9bbdSEd Tanous                                                 });
2041d4bb9bbdSEd Tanous                                     }
2042d4bb9bbdSEd Tanous                                 }
2043bd79bce8SPatrick Williams                                 propNode =
2044bd79bce8SPatrick Williams                                     propNode->NextSiblingElement("property");
2045d4bb9bbdSEd Tanous                             }
2046bd79bce8SPatrick Williams                             ifaceNode =
2047bd79bce8SPatrick Williams                                 ifaceNode->NextSiblingElement("interface");
2048d4bb9bbdSEd Tanous                         }
2049d4bb9bbdSEd Tanous                     },
2050d4bb9bbdSEd Tanous                     connectionName, transaction->objectPath,
2051d4bb9bbdSEd Tanous                     "org.freedesktop.DBus.Introspectable", "Introspect");
2052d4bb9bbdSEd Tanous             }
20532b73119cSGeorge Liu         });
2054d4bb9bbdSEd Tanous }
2055d4bb9bbdSEd Tanous 
handleDBusUrl(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string & objectPath)20568d1b46d7Szhanghch05 inline void handleDBusUrl(const crow::Request& req,
20578d1b46d7Szhanghch05                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2058049a0515SEd Tanous                           std::string& objectPath)
2059049a0515SEd Tanous {
2060049a0515SEd Tanous     // If accessing a single attribute, fill in and update objectPath,
2061049a0515SEd Tanous     // otherwise leave destProperty blank
2062e05aec50SEd Tanous     std::string destProperty;
2063049a0515SEd Tanous     const char* attrSeperator = "/attr/";
2064049a0515SEd Tanous     size_t attrPosition = objectPath.find(attrSeperator);
206571d5d8dbSEd Tanous     if (attrPosition != std::string::npos)
2066049a0515SEd Tanous     {
2067049a0515SEd Tanous         destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2068049a0515SEd Tanous                                          objectPath.length());
20697f57f195SEd Tanous         objectPath.resize(attrPosition);
2070049a0515SEd Tanous     }
2071049a0515SEd Tanous 
2072b41187faSEd Tanous     if (req.method() == boost::beast::http::verb::post)
2073049a0515SEd Tanous     {
2074049a0515SEd Tanous         constexpr const char* actionSeperator = "/action/";
2075049a0515SEd Tanous         size_t actionPosition = objectPath.find(actionSeperator);
207671d5d8dbSEd Tanous         if (actionPosition != std::string::npos)
2077049a0515SEd Tanous         {
2078049a0515SEd Tanous             std::string postProperty =
2079049a0515SEd Tanous                 objectPath.substr((actionPosition + strlen(actionSeperator)),
2080049a0515SEd Tanous                                   objectPath.length());
20817f57f195SEd Tanous             objectPath.resize(actionPosition);
20828d1b46d7Szhanghch05             handleAction(req, asyncResp, objectPath, postProperty);
2083049a0515SEd Tanous             return;
2084049a0515SEd Tanous         }
2085049a0515SEd Tanous     }
2086b41187faSEd Tanous     else if (req.method() == boost::beast::http::verb::get)
2087049a0515SEd Tanous     {
208811ba3979SEd Tanous         if (objectPath.ends_with("/enumerate"))
2089049a0515SEd Tanous         {
2090049a0515SEd Tanous             objectPath.erase(objectPath.end() - sizeof("enumerate"),
2091049a0515SEd Tanous                              objectPath.end());
20928d1b46d7Szhanghch05             handleEnumerate(asyncResp, objectPath);
2093049a0515SEd Tanous         }
209411ba3979SEd Tanous         else if (objectPath.ends_with("/list"))
2095049a0515SEd Tanous         {
2096049a0515SEd Tanous             objectPath.erase(objectPath.end() - sizeof("list"),
2097049a0515SEd Tanous                              objectPath.end());
20988d1b46d7Szhanghch05             handleList(asyncResp, objectPath);
2099049a0515SEd Tanous         }
2100049a0515SEd Tanous         else
2101049a0515SEd Tanous         {
2102f839dfeeSEd Tanous             // Trim any trailing "/" at the end
210311ba3979SEd Tanous             if (objectPath.ends_with("/"))
2104f839dfeeSEd Tanous             {
2105f839dfeeSEd Tanous                 objectPath.pop_back();
21068d1b46d7Szhanghch05                 handleList(asyncResp, objectPath, 1);
2107f839dfeeSEd Tanous             }
2108f839dfeeSEd Tanous             else
2109f839dfeeSEd Tanous             {
21108d1b46d7Szhanghch05                 handleGet(asyncResp, objectPath, destProperty);
2111049a0515SEd Tanous             }
2112f839dfeeSEd Tanous         }
2113049a0515SEd Tanous         return;
2114049a0515SEd Tanous     }
2115b41187faSEd Tanous     else if (req.method() == boost::beast::http::verb::put)
2116049a0515SEd Tanous     {
21178d1b46d7Szhanghch05         handlePut(req, asyncResp, objectPath, destProperty);
2118049a0515SEd Tanous         return;
2119049a0515SEd Tanous     }
2120b41187faSEd Tanous     else if (req.method() == boost::beast::http::verb::delete_)
2121de81881fSMatt Spinler     {
21228d1b46d7Szhanghch05         handleDelete(asyncResp, objectPath);
2123de81881fSMatt Spinler         return;
2124de81881fSMatt Spinler     }
2125049a0515SEd Tanous 
21268d1b46d7Szhanghch05     setErrorResponse(asyncResp->res,
21278d1b46d7Szhanghch05                      boost::beast::http::status::method_not_allowed,
2128c4e8d21dSMatt Spinler                      methodNotAllowedDesc, methodNotAllowedMsg);
2129049a0515SEd Tanous }
2130049a0515SEd Tanous 
handleBusSystemPost(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & processName,const std::string & requestedPath)2131bd79bce8SPatrick Williams inline void handleBusSystemPost(
2132bd79bce8SPatrick Williams     const crow::Request& req,
21331656b296SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2134bd79bce8SPatrick Williams     const std::string& processName, const std::string& requestedPath)
21351656b296SEd Tanous {
21361656b296SEd Tanous     std::vector<std::string> strs;
213750ebd4afSEd Tanous 
213850ebd4afSEd Tanous     bmcweb::split(strs, requestedPath, '/');
21391656b296SEd Tanous     std::string objectPath;
21401656b296SEd Tanous     std::string interfaceName;
21411656b296SEd Tanous     std::string methodName;
21421656b296SEd Tanous     auto it = strs.begin();
21431656b296SEd Tanous     if (it == strs.end())
21441656b296SEd Tanous     {
21451656b296SEd Tanous         objectPath = "/";
21461656b296SEd Tanous     }
21471656b296SEd Tanous     while (it != strs.end())
21481656b296SEd Tanous     {
21491656b296SEd Tanous         // Check if segment contains ".".  If it does, it must be an
21501656b296SEd Tanous         // interface
21511656b296SEd Tanous         if (it->find(".") != std::string::npos)
21521656b296SEd Tanous         {
21531656b296SEd Tanous             break;
21541656b296SEd Tanous             // This check is necessary as the trailing slash gets
21551656b296SEd Tanous             // parsed as part of our <path> specifier above, which
21561656b296SEd Tanous             // causes the normal trailing backslash redirector to
21571656b296SEd Tanous             // fail.
21581656b296SEd Tanous         }
21591656b296SEd Tanous         if (!it->empty())
21601656b296SEd Tanous         {
21611656b296SEd Tanous             objectPath += "/" + *it;
21621656b296SEd Tanous         }
21631656b296SEd Tanous         it++;
21641656b296SEd Tanous     }
21651656b296SEd Tanous     if (it != strs.end())
21661656b296SEd Tanous     {
21671656b296SEd Tanous         interfaceName = *it;
21681656b296SEd Tanous         it++;
21691656b296SEd Tanous 
21701656b296SEd Tanous         // after interface, we might have a method name
21711656b296SEd Tanous         if (it != strs.end())
21721656b296SEd Tanous         {
21731656b296SEd Tanous             methodName = *it;
21741656b296SEd Tanous             it++;
21751656b296SEd Tanous         }
21761656b296SEd Tanous     }
21771656b296SEd Tanous     if (it != strs.end())
21781656b296SEd Tanous     {
21791656b296SEd Tanous         // if there is more levels past the method name, something
21801656b296SEd Tanous         // went wrong, return not found
21811656b296SEd Tanous         asyncResp->res.result(boost::beast::http::status::not_found);
21821656b296SEd Tanous         return;
21831656b296SEd Tanous     }
21841656b296SEd Tanous     if (interfaceName.empty())
21851656b296SEd Tanous     {
21861656b296SEd Tanous         crow::connections::systemBus->async_method_call(
21871656b296SEd Tanous             [asyncResp, processName,
21885e7e2dc5SEd Tanous              objectPath](const boost::system::error_code& ec,
21891656b296SEd Tanous                          const std::string& introspectXml) {
21901656b296SEd Tanous                 if (ec)
21911656b296SEd Tanous                 {
219262598e31SEd Tanous                     BMCWEB_LOG_ERROR(
219362598e31SEd Tanous                         "Introspect call failed with error: {} on process: {} path: {}",
219462598e31SEd Tanous                         ec.message(), processName, objectPath);
21951656b296SEd Tanous                     return;
21961656b296SEd Tanous                 }
21971656b296SEd Tanous                 tinyxml2::XMLDocument doc;
21981656b296SEd Tanous 
21991656b296SEd Tanous                 doc.Parse(introspectXml.c_str());
22001656b296SEd Tanous                 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
22011656b296SEd Tanous                 if (pRoot == nullptr)
22021656b296SEd Tanous                 {
220362598e31SEd Tanous                     BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
220462598e31SEd Tanous                                      processName, objectPath);
22051476687dSEd Tanous                     asyncResp->res.jsonValue["status"] = "XML parse error";
22061656b296SEd Tanous                     asyncResp->res.result(
22071656b296SEd Tanous                         boost::beast::http::status::internal_server_error);
22081656b296SEd Tanous                     return;
22091656b296SEd Tanous                 }
22101656b296SEd Tanous 
221162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("{}", introspectXml);
22121476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
22131476687dSEd Tanous                 asyncResp->res.jsonValue["bus_name"] = processName;
22141476687dSEd Tanous                 asyncResp->res.jsonValue["object_path"] = objectPath;
22151476687dSEd Tanous 
22161656b296SEd Tanous                 nlohmann::json& interfacesArray =
22171656b296SEd Tanous                     asyncResp->res.jsonValue["interfaces"];
22181656b296SEd Tanous                 interfacesArray = nlohmann::json::array();
22191656b296SEd Tanous                 tinyxml2::XMLElement* interface =
22201656b296SEd Tanous                     pRoot->FirstChildElement("interface");
22211656b296SEd Tanous 
22221656b296SEd Tanous                 while (interface != nullptr)
22231656b296SEd Tanous                 {
22241656b296SEd Tanous                     const char* ifaceName = interface->Attribute("name");
22251656b296SEd Tanous                     if (ifaceName != nullptr)
22261656b296SEd Tanous                     {
22278a592810SEd Tanous                         nlohmann::json::object_t interfaceObj;
22288a592810SEd Tanous                         interfaceObj["name"] = ifaceName;
2229b2ba3072SPatrick Williams                         interfacesArray.emplace_back(std::move(interfaceObj));
22301656b296SEd Tanous                     }
22311656b296SEd Tanous 
22321656b296SEd Tanous                     interface = interface->NextSiblingElement("interface");
22331656b296SEd Tanous                 }
22341656b296SEd Tanous             },
22351656b296SEd Tanous             processName, objectPath, "org.freedesktop.DBus.Introspectable",
22361656b296SEd Tanous             "Introspect");
22371656b296SEd Tanous     }
22381656b296SEd Tanous     else if (methodName.empty())
22391656b296SEd Tanous     {
22401656b296SEd Tanous         crow::connections::systemBus->async_method_call(
22411656b296SEd Tanous             [asyncResp, processName, objectPath,
22425e7e2dc5SEd Tanous              interfaceName](const boost::system::error_code& ec,
22431656b296SEd Tanous                             const std::string& introspectXml) {
22441656b296SEd Tanous                 if (ec)
22451656b296SEd Tanous                 {
224662598e31SEd Tanous                     BMCWEB_LOG_ERROR(
224762598e31SEd Tanous                         "Introspect call failed with error: {} on process: {} path: {}",
224862598e31SEd Tanous                         ec.message(), processName, objectPath);
22491656b296SEd Tanous                     return;
22501656b296SEd Tanous                 }
22511656b296SEd Tanous                 tinyxml2::XMLDocument doc;
22521656b296SEd Tanous 
22531656b296SEd Tanous                 doc.Parse(introspectXml.data(), introspectXml.size());
22541656b296SEd Tanous                 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
22551656b296SEd Tanous                 if (pRoot == nullptr)
22561656b296SEd Tanous                 {
225762598e31SEd Tanous                     BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
225862598e31SEd Tanous                                      processName, objectPath);
22591656b296SEd Tanous                     asyncResp->res.result(
22601656b296SEd Tanous                         boost::beast::http::status::internal_server_error);
22611656b296SEd Tanous                     return;
22621656b296SEd Tanous                 }
22631476687dSEd Tanous 
22641476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
22651476687dSEd Tanous                 asyncResp->res.jsonValue["bus_name"] = processName;
22661476687dSEd Tanous                 asyncResp->res.jsonValue["interface"] = interfaceName;
22671476687dSEd Tanous                 asyncResp->res.jsonValue["object_path"] = objectPath;
22681656b296SEd Tanous 
2269bd79bce8SPatrick Williams                 nlohmann::json& methodsArray =
2270bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["methods"];
22711656b296SEd Tanous                 methodsArray = nlohmann::json::array();
22721656b296SEd Tanous 
2273bd79bce8SPatrick Williams                 nlohmann::json& signalsArray =
2274bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["signals"];
22751656b296SEd Tanous                 signalsArray = nlohmann::json::array();
22761656b296SEd Tanous 
22771656b296SEd Tanous                 nlohmann::json& propertiesObj =
22781656b296SEd Tanous                     asyncResp->res.jsonValue["properties"];
22791656b296SEd Tanous                 propertiesObj = nlohmann::json::object();
22801656b296SEd Tanous 
22811656b296SEd Tanous                 // if we know we're the only call, build the
22821656b296SEd Tanous                 // json directly
22831656b296SEd Tanous                 tinyxml2::XMLElement* interface =
22841656b296SEd Tanous                     pRoot->FirstChildElement("interface");
22851656b296SEd Tanous                 while (interface != nullptr)
22861656b296SEd Tanous                 {
22871656b296SEd Tanous                     const char* ifaceName = interface->Attribute("name");
22881656b296SEd Tanous 
22891656b296SEd Tanous                     if (ifaceName != nullptr && ifaceName == interfaceName)
22901656b296SEd Tanous                     {
22911656b296SEd Tanous                         break;
22921656b296SEd Tanous                     }
22931656b296SEd Tanous 
22941656b296SEd Tanous                     interface = interface->NextSiblingElement("interface");
22951656b296SEd Tanous                 }
22961656b296SEd Tanous                 if (interface == nullptr)
22971656b296SEd Tanous                 {
22981656b296SEd Tanous                     // if we got to the end of the list and
22991656b296SEd Tanous                     // never found a match, throw 404
2300bd79bce8SPatrick Williams                     asyncResp->res.result(
2301bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
23021656b296SEd Tanous                     return;
23031656b296SEd Tanous                 }
23041656b296SEd Tanous 
23051656b296SEd Tanous                 tinyxml2::XMLElement* methods =
23061656b296SEd Tanous                     interface->FirstChildElement("method");
23071656b296SEd Tanous                 while (methods != nullptr)
23081656b296SEd Tanous                 {
23091656b296SEd Tanous                     nlohmann::json argsArray = nlohmann::json::array();
2310bd79bce8SPatrick Williams                     tinyxml2::XMLElement* arg =
2311bd79bce8SPatrick Williams                         methods->FirstChildElement("arg");
23121656b296SEd Tanous                     while (arg != nullptr)
23131656b296SEd Tanous                     {
23141656b296SEd Tanous                         nlohmann::json thisArg;
23151656b296SEd Tanous                         for (const char* fieldName : std::array<const char*, 3>{
23161656b296SEd Tanous                                  "name", "direction", "type"})
23171656b296SEd Tanous                         {
23181656b296SEd Tanous                             const char* fieldValue = arg->Attribute(fieldName);
23191656b296SEd Tanous                             if (fieldValue != nullptr)
23201656b296SEd Tanous                             {
23211656b296SEd Tanous                                 thisArg[fieldName] = fieldValue;
23221656b296SEd Tanous                             }
23231656b296SEd Tanous                         }
2324b2ba3072SPatrick Williams                         argsArray.emplace_back(std::move(thisArg));
23251656b296SEd Tanous                         arg = arg->NextSiblingElement("arg");
23261656b296SEd Tanous                     }
23271656b296SEd Tanous 
23281656b296SEd Tanous                     const char* name = methods->Attribute("name");
23291656b296SEd Tanous                     if (name != nullptr)
23301656b296SEd Tanous                     {
23311656b296SEd Tanous                         std::string uri;
2332bd79bce8SPatrick Williams                         uri.reserve(14 + processName.size() +
2333bd79bce8SPatrick Williams                                     objectPath.size() + interfaceName.size() +
2334bd79bce8SPatrick Williams                                     strlen(name));
23351656b296SEd Tanous                         uri += "/bus/system/";
23361656b296SEd Tanous                         uri += processName;
23371656b296SEd Tanous                         uri += objectPath;
23381656b296SEd Tanous                         uri += "/";
23391656b296SEd Tanous                         uri += interfaceName;
23401656b296SEd Tanous                         uri += "/";
23411656b296SEd Tanous                         uri += name;
23421476687dSEd Tanous 
23431476687dSEd Tanous                         nlohmann::json::object_t object;
23441476687dSEd Tanous                         object["name"] = name;
23451476687dSEd Tanous                         object["uri"] = std::move(uri);
23461476687dSEd Tanous                         object["args"] = argsArray;
23471476687dSEd Tanous 
2348b2ba3072SPatrick Williams                         methodsArray.emplace_back(std::move(object));
23491656b296SEd Tanous                     }
23501656b296SEd Tanous                     methods = methods->NextSiblingElement("method");
23511656b296SEd Tanous                 }
23521656b296SEd Tanous                 tinyxml2::XMLElement* signals =
23531656b296SEd Tanous                     interface->FirstChildElement("signal");
23541656b296SEd Tanous                 while (signals != nullptr)
23551656b296SEd Tanous                 {
23561656b296SEd Tanous                     nlohmann::json argsArray = nlohmann::json::array();
23571656b296SEd Tanous 
2358bd79bce8SPatrick Williams                     tinyxml2::XMLElement* arg =
2359bd79bce8SPatrick Williams                         signals->FirstChildElement("arg");
23601656b296SEd Tanous                     while (arg != nullptr)
23611656b296SEd Tanous                     {
23621656b296SEd Tanous                         const char* name = arg->Attribute("name");
23631656b296SEd Tanous                         const char* type = arg->Attribute("type");
23641656b296SEd Tanous                         if (name != nullptr && type != nullptr)
23651656b296SEd Tanous                         {
236620fa6a2cSEd Tanous                             nlohmann::json::object_t params;
236720fa6a2cSEd Tanous                             params["name"] = name;
236820fa6a2cSEd Tanous                             params["type"] = type;
236920fa6a2cSEd Tanous                             argsArray.push_back(std::move(params));
23701656b296SEd Tanous                         }
23711656b296SEd Tanous                         arg = arg->NextSiblingElement("arg");
23721656b296SEd Tanous                     }
23731656b296SEd Tanous                     const char* name = signals->Attribute("name");
23741656b296SEd Tanous                     if (name != nullptr)
23751656b296SEd Tanous                     {
23761476687dSEd Tanous                         nlohmann::json::object_t object;
23771476687dSEd Tanous                         object["name"] = name;
23781476687dSEd Tanous                         object["args"] = argsArray;
2379b2ba3072SPatrick Williams                         signalsArray.emplace_back(std::move(object));
23801656b296SEd Tanous                     }
23811656b296SEd Tanous 
23821656b296SEd Tanous                     signals = signals->NextSiblingElement("signal");
23831656b296SEd Tanous                 }
23841656b296SEd Tanous 
23851656b296SEd Tanous                 tinyxml2::XMLElement* property =
23861656b296SEd Tanous                     interface->FirstChildElement("property");
23871656b296SEd Tanous                 while (property != nullptr)
23881656b296SEd Tanous                 {
23891656b296SEd Tanous                     const char* name = property->Attribute("name");
23901656b296SEd Tanous                     const char* type = property->Attribute("type");
23911656b296SEd Tanous                     if (type != nullptr && name != nullptr)
23921656b296SEd Tanous                     {
239359d494eeSPatrick Williams                         sdbusplus::message_t m =
23941656b296SEd Tanous                             crow::connections::systemBus->new_method_call(
23951656b296SEd Tanous                                 processName.c_str(), objectPath.c_str(),
23961656b296SEd Tanous                                 "org.freedesktop."
23971656b296SEd Tanous                                 "DBus."
23981656b296SEd Tanous                                 "Properties",
23991656b296SEd Tanous                                 "Get");
24001656b296SEd Tanous                         m.append(interfaceName, name);
24011656b296SEd Tanous                         nlohmann::json& propertyItem = propertiesObj[name];
24021656b296SEd Tanous                         crow::connections::systemBus->async_send(
24031656b296SEd Tanous                             m, [&propertyItem,
24048b24275dSEd Tanous                                 asyncResp](const boost::system::error_code& ec2,
240559d494eeSPatrick Williams                                            sdbusplus::message_t& msg) {
24068b24275dSEd Tanous                                 if (ec2)
24071656b296SEd Tanous                                 {
24081656b296SEd Tanous                                     return;
24091656b296SEd Tanous                                 }
24101656b296SEd Tanous 
2411bd79bce8SPatrick Williams                                 int r =
2412bd79bce8SPatrick Williams                                     convertDBusToJSON("v", msg, propertyItem);
241307900817SEd Tanous                                 if (r < 0)
241407900817SEd Tanous                                 {
2415bd79bce8SPatrick Williams                                     BMCWEB_LOG_ERROR(
2416bd79bce8SPatrick Williams                                         "Couldn't convert vector to json");
241707900817SEd Tanous                                 }
24181656b296SEd Tanous                             });
24191656b296SEd Tanous                     }
24201656b296SEd Tanous                     property = property->NextSiblingElement("property");
24211656b296SEd Tanous                 }
24221656b296SEd Tanous             },
24231656b296SEd Tanous             processName, objectPath, "org.freedesktop.DBus.Introspectable",
24241656b296SEd Tanous             "Introspect");
24251656b296SEd Tanous     }
24261656b296SEd Tanous     else
24271656b296SEd Tanous     {
24281656b296SEd Tanous         if (req.method() != boost::beast::http::verb::post)
24291656b296SEd Tanous         {
24301656b296SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
24311656b296SEd Tanous             return;
24321656b296SEd Tanous         }
24331656b296SEd Tanous 
24341aa0c2b8SEd Tanous         nlohmann::json requestDbusData;
24351aa0c2b8SEd Tanous         JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
24361aa0c2b8SEd Tanous         if (ret == JsonParseResult::BadContentType)
24371656b296SEd Tanous         {
24381aa0c2b8SEd Tanous             setErrorResponse(asyncResp->res,
24391aa0c2b8SEd Tanous                              boost::beast::http::status::unsupported_media_type,
24401aa0c2b8SEd Tanous                              invalidContentType, unsupportedMediaMsg);
24411656b296SEd Tanous             return;
24421656b296SEd Tanous         }
24431aa0c2b8SEd Tanous         if (ret != JsonParseResult::Success)
24441aa0c2b8SEd Tanous         {
24451aa0c2b8SEd Tanous             setErrorResponse(asyncResp->res,
24461aa0c2b8SEd Tanous                              boost::beast::http::status::bad_request,
24471aa0c2b8SEd Tanous                              noJsonDesc, badReqMsg);
24481aa0c2b8SEd Tanous             return;
24491aa0c2b8SEd Tanous         }
24501aa0c2b8SEd Tanous 
24511656b296SEd Tanous         if (!requestDbusData.is_array())
24521656b296SEd Tanous         {
24531656b296SEd Tanous             asyncResp->res.result(boost::beast::http::status::bad_request);
24541656b296SEd Tanous             return;
24551656b296SEd Tanous         }
245628dd5ca1SLei YU         auto transaction = std::make_shared<InProgressActionData>(asyncResp);
24571656b296SEd Tanous 
24581656b296SEd Tanous         transaction->path = objectPath;
24591656b296SEd Tanous         transaction->methodName = methodName;
24601656b296SEd Tanous         transaction->arguments = std::move(requestDbusData);
24611656b296SEd Tanous 
24621656b296SEd Tanous         findActionOnInterface(transaction, processName);
24631656b296SEd Tanous     }
24641656b296SEd Tanous }
24651656b296SEd Tanous 
requestRoutes(App & app)246623a21a1cSEd Tanous inline void requestRoutes(App& app)
24671abe55efSEd Tanous {
246855c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/bus/")
2469432a890cSEd Tanous         .privileges({{"Login"}})
2470b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
24718d1b46d7Szhanghch05             [](const crow::Request&,
24728d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
24731476687dSEd Tanous                 nlohmann::json::array_t buses;
24741476687dSEd Tanous                 nlohmann::json& bus = buses.emplace_back();
24751476687dSEd Tanous                 bus["name"] = "system";
24761476687dSEd Tanous                 asyncResp->res.jsonValue["busses"] = std::move(buses);
24771476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
2478911ac317SEd Tanous             });
2479911ac317SEd Tanous 
248055c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/bus/system/")
2481432a890cSEd Tanous         .privileges({{"Login"}})
2482b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
24838d1b46d7Szhanghch05             [](const crow::Request&,
24848d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2485bd79bce8SPatrick Williams                 auto myCallback = [asyncResp](
2486bd79bce8SPatrick Williams                                       const boost::system::error_code& ec,
2487aa2e59c1SEd Tanous                                       std::vector<std::string>& names) {
24881abe55efSEd Tanous                     if (ec)
24891abe55efSEd Tanous                     {
249062598e31SEd Tanous                         BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
24918d1b46d7Szhanghch05                         asyncResp->res.result(
24921abe55efSEd Tanous                             boost::beast::http::status::internal_server_error);
24931abe55efSEd Tanous                     }
24941abe55efSEd Tanous                     else
24951abe55efSEd Tanous                     {
24963544d2a7SEd Tanous                         std::ranges::sort(names);
24971476687dSEd Tanous                         asyncResp->res.jsonValue["status"] = "ok";
24988d1b46d7Szhanghch05                         auto& objectsSub = asyncResp->res.jsonValue["objects"];
249902cad96eSEd Tanous                         for (const auto& name : names)
25001abe55efSEd Tanous                         {
25011476687dSEd Tanous                             nlohmann::json::object_t object;
25021476687dSEd Tanous                             object["name"] = name;
2503b2ba3072SPatrick Williams                             objectsSub.emplace_back(std::move(object));
2504911ac317SEd Tanous                         }
2505911ac317SEd Tanous                     }
2506aa2e59c1SEd Tanous                 };
250755c7b7a2SEd Tanous                 crow::connections::systemBus->async_method_call(
2508aa2e59c1SEd Tanous                     std::move(myCallback), "org.freedesktop.DBus", "/",
2509aa2e59c1SEd Tanous                     "org.freedesktop.DBus", "ListNames");
2510911ac317SEd Tanous             });
2511911ac317SEd Tanous 
251255c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/list/")
2513432a890cSEd Tanous         .privileges({{"Login"}})
2514b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
25158d1b46d7Szhanghch05             [](const crow::Request&,
25168d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
25178d1b46d7Szhanghch05                 handleList(asyncResp, "/");
2518ba9f9a6cSEd Tanous             });
2519ba9f9a6cSEd Tanous 
252055c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/xyz/<path>")
2521432a890cSEd Tanous         .privileges({{"Login"}})
25228d1b46d7Szhanghch05         .methods(boost::beast::http::verb::get)(
25238d1b46d7Szhanghch05             [](const crow::Request& req,
25248d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2525f00032dbSTanous                const std::string& path) {
2526f00032dbSTanous                 std::string objectPath = "/xyz/" + path;
25278d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2528f00032dbSTanous             });
2529f00032dbSTanous 
2530f00032dbSTanous     BMCWEB_ROUTE(app, "/xyz/<path>")
2531432a890cSEd Tanous         .privileges({{"ConfigureComponents", "ConfigureManager"}})
2532b41187faSEd Tanous         .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2533b41187faSEd Tanous                  boost::beast::http::verb::delete_)(
25348d1b46d7Szhanghch05             [](const crow::Request& req,
25358d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2536ba9f9a6cSEd Tanous                const std::string& path) {
2537d76323e5SEd Tanous                 std::string objectPath = "/xyz/" + path;
25388d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2539049a0515SEd Tanous             });
2540a4e18f2aSEd Tanous 
2541049a0515SEd Tanous     BMCWEB_ROUTE(app, "/org/<path>")
2542432a890cSEd Tanous         .privileges({{"Login"}})
25438d1b46d7Szhanghch05         .methods(boost::beast::http::verb::get)(
25448d1b46d7Szhanghch05             [](const crow::Request& req,
25458d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2546f00032dbSTanous                const std::string& path) {
2547e1281403SEd Tanous                 std::string objectPath = "/org/" + path;
25488d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2549f00032dbSTanous             });
2550f00032dbSTanous 
2551f00032dbSTanous     BMCWEB_ROUTE(app, "/org/<path>")
2552432a890cSEd Tanous         .privileges({{"ConfigureComponents", "ConfigureManager"}})
2553b41187faSEd Tanous         .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2554b41187faSEd Tanous                  boost::beast::http::verb::delete_)(
25558d1b46d7Szhanghch05             [](const crow::Request& req,
25568d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2557049a0515SEd Tanous                const std::string& path) {
2558e1281403SEd Tanous                 std::string objectPath = "/org/" + path;
25598d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2560ba9f9a6cSEd Tanous             });
256100b92f79Sshiyilei 
256255c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/download/dump/<str>/")
2563432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
25648d1b46d7Szhanghch05         .methods(boost::beast::http::verb::get)(
25658d1b46d7Szhanghch05             [](const crow::Request&,
25668d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2567d4bb9bbdSEd Tanous                const std::string& dumpId) {
2568482c45a5SJosh Lehan                 if (!validateFilename(dumpId))
25691abe55efSEd Tanous                 {
2570bd79bce8SPatrick Williams                     asyncResp->res.result(
2571bd79bce8SPatrick Williams                         boost::beast::http::status::bad_request);
2572d4bb9bbdSEd Tanous                     return;
2573d4bb9bbdSEd Tanous                 }
2574bd79bce8SPatrick Williams                 std::filesystem::path loc(
2575bd79bce8SPatrick Williams                     "/var/lib/phosphor-debug-collector/dumps");
2576d4bb9bbdSEd Tanous 
2577ad18f070SEd Tanous                 loc /= dumpId;
2578d4bb9bbdSEd Tanous 
2579f6150403SJames Feist                 if (!std::filesystem::exists(loc) ||
2580f6150403SJames Feist                     !std::filesystem::is_directory(loc))
25811abe55efSEd Tanous                 {
258262598e31SEd Tanous                     BMCWEB_LOG_ERROR("{}Not found", loc.string());
2583bd79bce8SPatrick Williams                     asyncResp->res.result(
2584bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
2585d4bb9bbdSEd Tanous                     return;
2586d4bb9bbdSEd Tanous                 }
2587f6150403SJames Feist                 std::filesystem::directory_iterator files(loc);
2588ad18f070SEd Tanous 
25899eb808c1SEd Tanous                 for (const auto& file : files)
25901abe55efSEd Tanous                 {
2591d51c61b4SMyung Bae                     if (asyncResp->res.openFile(file) !=
2592d51c61b4SMyung Bae                         crow::OpenCode::Success)
25931abe55efSEd Tanous                     {
2594d4bb9bbdSEd Tanous                         continue;
2595d4bb9bbdSEd Tanous                     }
2596d9207047SRamesh Iyyar 
2597bd79bce8SPatrick Williams                     asyncResp->res.addHeader(
2598bd79bce8SPatrick Williams                         boost::beast::http::field::content_type,
25998d1b46d7Szhanghch05                         "application/octet-stream");
2600d9207047SRamesh Iyyar 
26018d1b46d7Szhanghch05                     // Assuming only one dump file will be present in the dump
26028d1b46d7Szhanghch05                     // id directory
2603d9207047SRamesh Iyyar                     std::string dumpFileName = file.path().filename().string();
2604d9207047SRamesh Iyyar 
2605d9207047SRamesh Iyyar                     // Filename should be in alphanumeric, dot and underscore
26068d1b46d7Szhanghch05                     // Its based on phosphor-debug-collector application
26078d1b46d7Szhanghch05                     // dumpfile format
26084b242749SEd Tanous                     static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2609d9207047SRamesh Iyyar                     if (!std::regex_match(dumpFileName, dumpFileRegex))
2610d9207047SRamesh Iyyar                     {
2611bd79bce8SPatrick Williams                         BMCWEB_LOG_ERROR("Invalid dump filename {}",
2612bd79bce8SPatrick Williams                                          dumpFileName);
2613bd79bce8SPatrick Williams                         asyncResp->res.result(
2614bd79bce8SPatrick Williams                             boost::beast::http::status::not_found);
2615d9207047SRamesh Iyyar                         return;
2616d9207047SRamesh Iyyar                     }
2617bd79bce8SPatrick Williams                     std::string contentDispositionParam =
2618bd79bce8SPatrick Williams                         "attachment; filename=\"" + dumpFileName + "\"";
2619d9207047SRamesh Iyyar 
2620d9f6c621SEd Tanous                     asyncResp->res.addHeader(
2621d9f6c621SEd Tanous                         boost::beast::http::field::content_disposition,
26228d1b46d7Szhanghch05                         contentDispositionParam);
2623d9207047SRamesh Iyyar 
2624ad18f070SEd Tanous                     return;
2625d4bb9bbdSEd Tanous                 }
26268d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::not_found);
2627d4bb9bbdSEd Tanous                 return;
2628d4bb9bbdSEd Tanous             });
2629d4bb9bbdSEd Tanous 
2630e3cb5a31SEd Tanous     BMCWEB_ROUTE(app, "/bus/system/<str>/")
2631432a890cSEd Tanous         .privileges({{"Login"}})
2632b41187faSEd Tanous 
2633b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
26348d1b46d7Szhanghch05             [](const crow::Request&,
26358d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
263681ce609eSEd Tanous                const std::string& connection) {
263772374eb7SNan Zhou                 introspectObjects(connection, "/", asyncResp);
2638e3cb5a31SEd Tanous             });
2639e3cb5a31SEd Tanous 
2640e3cb5a31SEd Tanous     BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
2641432a890cSEd Tanous         .privileges({{"ConfigureComponents", "ConfigureManager"}})
26421656b296SEd Tanous         .methods(boost::beast::http::verb::get,
26431656b296SEd Tanous                  boost::beast::http::verb::post)(handleBusSystemPost);
2644d4bb9bbdSEd Tanous }
2645911ac317SEd Tanous } // namespace openbmc_mapper
2646911ac317SEd Tanous } // namespace crow
2647