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