1 /* 2 // Copyright (c) 2019 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 #ifndef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS 18 19 #include <dbus_utility.hpp> 20 namespace redfish 21 { 22 23 enum NetworkProtocolUnitStructFields 24 { 25 NET_PROTO_UNIT_NAME, 26 NET_PROTO_UNIT_DESC, 27 NET_PROTO_UNIT_LOAD_STATE, 28 NET_PROTO_UNIT_ACTIVE_STATE, 29 NET_PROTO_UNIT_SUB_STATE, 30 NET_PROTO_UNIT_DEVICE, 31 NET_PROTO_UNIT_OBJ_PATH, 32 NET_PROTO_UNIT_ALWAYS_0, 33 NET_PROTO_UNIT_ALWAYS_EMPTY, 34 NET_PROTO_UNIT_ALWAYS_ROOT_PATH 35 }; 36 37 enum NetworkProtocolListenResponseElements 38 { 39 NET_PROTO_LISTEN_TYPE, 40 NET_PROTO_LISTEN_STREAM 41 }; 42 43 /** 44 * @brief D-Bus Unit structure returned in array from ListUnits Method 45 */ 46 using UnitStruct = 47 std::tuple<std::string, std::string, std::string, std::string, std::string, 48 std::string, sdbusplus::message::object_path, uint32_t, 49 std::string, sdbusplus::message::object_path>; 50 51 template <typename CallbackFunc> 52 void getMainChassisId(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 53 CallbackFunc&& callback) 54 { 55 // Find managed chassis 56 crow::connections::systemBus->async_method_call( 57 [callback, 58 asyncResp](const boost::system::error_code ec, 59 const dbus::utility::MapperGetSubTreeResponse& subtree) { 60 if (ec) 61 { 62 BMCWEB_LOG_ERROR << ec; 63 return; 64 } 65 if (subtree.empty()) 66 { 67 BMCWEB_LOG_DEBUG << "Can't find chassis!"; 68 return; 69 } 70 71 std::size_t idPos = subtree[0].first.rfind('/'); 72 if (idPos == std::string::npos || 73 (idPos + 1) >= subtree[0].first.size()) 74 { 75 messages::internalError(asyncResp->res); 76 BMCWEB_LOG_DEBUG << "Can't parse chassis ID!"; 77 return; 78 } 79 std::string chassisId = subtree[0].first.substr(idPos + 1); 80 BMCWEB_LOG_DEBUG << "chassisId = " << chassisId; 81 callback(chassisId, asyncResp); 82 }, 83 "xyz.openbmc_project.ObjectMapper", 84 "/xyz/openbmc_project/object_mapper", 85 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 86 "/xyz/openbmc_project/inventory", 0, 87 std::array<const char*, 2>{ 88 "xyz.openbmc_project.Inventory.Item.Board", 89 "xyz.openbmc_project.Inventory.Item.Chassis"}); 90 } 91 92 template <typename CallbackFunc> 93 void getPortStatusAndPath(const std::string& serviceName, 94 CallbackFunc&& callback) 95 { 96 crow::connections::systemBus->async_method_call( 97 [serviceName, callback{std::forward<CallbackFunc>(callback)}]( 98 const boost::system::error_code ec, 99 const std::vector<UnitStruct>& r) { 100 if (ec) 101 { 102 BMCWEB_LOG_ERROR << ec; 103 // return error code 104 callback(ec, "", false); 105 return; 106 } 107 108 for (const UnitStruct& unit : r) 109 { 110 // Only traverse through <xyz>.socket units 111 const std::string& unitName = std::get<NET_PROTO_UNIT_NAME>(unit); 112 113 // find "." into unitsName 114 size_t lastCharPos = unitName.rfind('.'); 115 if (lastCharPos == std::string::npos) 116 { 117 continue; 118 } 119 120 // is unitsName end with ".socket" 121 std::string unitNameEnd = unitName.substr(lastCharPos); 122 if (unitNameEnd != ".socket") 123 { 124 continue; 125 } 126 127 // find "@" into unitsName 128 if (size_t atCharPos = unitName.rfind('@'); 129 atCharPos != std::string::npos) 130 { 131 lastCharPos = atCharPos; 132 } 133 134 // unitsName without "@eth(x).socket", only <xyz> 135 // unitsName without ".socket", only <xyz> 136 std::string unitNameStr = unitName.substr(0, lastCharPos); 137 138 // We are interested in services, which starts with 139 // mapped service name 140 if (unitNameStr != serviceName) 141 { 142 continue; 143 } 144 145 const std::string& socketPath = 146 std::get<NET_PROTO_UNIT_OBJ_PATH>(unit); 147 const std::string& unitState = 148 std::get<NET_PROTO_UNIT_SUB_STATE>(unit); 149 150 bool isProtocolEnabled = 151 ((unitState == "running") || (unitState == "listening")); 152 // We found service, return from inner loop. 153 callback(ec, socketPath, isProtocolEnabled); 154 return; 155 } 156 157 // no service foudn, throw error 158 boost::system::error_code ec1 = boost::system::errc::make_error_code( 159 boost::system::errc::no_such_process); 160 // return error code 161 callback(ec1, "", false); 162 BMCWEB_LOG_ERROR << ec1; 163 }, 164 "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 165 "org.freedesktop.systemd1.Manager", "ListUnits"); 166 } 167 168 template <typename CallbackFunc> 169 void getPortNumber(const std::string& socketPath, CallbackFunc&& callback) 170 { 171 sdbusplus::asio::getProperty< 172 std::vector<std::tuple<std::string, std::string>>>( 173 *crow::connections::systemBus, "org.freedesktop.systemd1", socketPath, 174 "org.freedesktop.systemd1.Socket", "Listen", 175 [callback{std::forward<CallbackFunc>(callback)}]( 176 const boost::system::error_code ec, 177 const std::vector<std::tuple<std::string, std::string>>& resp) { 178 if (ec) 179 { 180 BMCWEB_LOG_ERROR << ec; 181 callback(ec, 0); 182 return; 183 } 184 if (resp.empty()) 185 { 186 // Network Protocol Listen Response Elements is empty 187 boost::system::error_code ec1 = 188 boost::system::errc::make_error_code( 189 boost::system::errc::bad_message); 190 // return error code 191 callback(ec1, 0); 192 BMCWEB_LOG_ERROR << ec1; 193 return; 194 } 195 const std::string& listenStream = 196 std::get<NET_PROTO_LISTEN_STREAM>(resp[0]); 197 const char* pa = &listenStream[listenStream.rfind(':') + 1]; 198 int port{0}; 199 if (auto [p, ec2] = std::from_chars(pa, nullptr, port); 200 ec2 != std::errc()) 201 { 202 // there is only two possibility invalid_argument and 203 // result_out_of_range 204 boost::system::error_code ec3 = 205 boost::system::errc::make_error_code( 206 boost::system::errc::invalid_argument); 207 if (ec2 == std::errc::result_out_of_range) 208 { 209 ec3 = boost::system::errc::make_error_code( 210 boost::system::errc::result_out_of_range); 211 } 212 // return error code 213 callback(ec3, 0); 214 BMCWEB_LOG_ERROR << ec3; 215 } 216 callback(ec, port); 217 }); 218 } 219 220 } // namespace redfish 221 #endif 222