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 crow::openbmc_mapper::GetSubTreeType& 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 = 112 std::get<NET_PROTO_UNIT_NAME>(unit); 113 114 // find "." into unitsName 115 size_t lastCharPos = unitName.rfind('.'); 116 if (lastCharPos == std::string::npos) 117 { 118 continue; 119 } 120 121 // is unitsName end with ".socket" 122 std::string unitNameEnd = unitName.substr(lastCharPos); 123 if (unitNameEnd.compare(".socket") != 0) 124 { 125 continue; 126 } 127 128 // find "@" into unitsName 129 if (size_t atCharPos = unitName.rfind('@'); 130 atCharPos != std::string::npos) 131 { 132 lastCharPos = atCharPos; 133 } 134 135 // unitsName without "@eth(x).socket", only <xyz> 136 // unitsName without ".socket", only <xyz> 137 std::string unitNameStr = unitName.substr(0, lastCharPos); 138 139 // We are interested in services, which starts with 140 // mapped service name 141 if (unitNameStr != serviceName) 142 { 143 continue; 144 } 145 146 const std::string& socketPath = 147 std::get<NET_PROTO_UNIT_OBJ_PATH>(unit); 148 const std::string& unitState = 149 std::get<NET_PROTO_UNIT_SUB_STATE>(unit); 150 151 bool isProtocolEnabled = 152 ((unitState == "running") || (unitState == "listening")); 153 // We found service, return from inner loop. 154 callback(ec, socketPath, isProtocolEnabled); 155 return; 156 } 157 158 // no service foudn, throw error 159 boost::system::error_code ec1 = 160 boost::system::errc::make_error_code( 161 boost::system::errc::no_such_process); 162 // return error code 163 callback(ec1, "", false); 164 BMCWEB_LOG_ERROR << ec1; 165 }, 166 "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 167 "org.freedesktop.systemd1.Manager", "ListUnits"); 168 } 169 170 template <typename CallbackFunc> 171 void getPortNumber(const std::string& socketPath, CallbackFunc&& callback) 172 { 173 sdbusplus::asio::getProperty< 174 std::vector<std::tuple<std::string, std::string>>>( 175 *crow::connections::systemBus, "org.freedesktop.systemd1", socketPath, 176 "org.freedesktop.systemd1.Socket", "Listen", 177 [callback{std::forward<CallbackFunc>(callback)}]( 178 const boost::system::error_code ec, 179 const std::vector<std::tuple<std::string, std::string>>& resp) { 180 if (ec) 181 { 182 BMCWEB_LOG_ERROR << ec; 183 callback(ec, 0); 184 return; 185 } 186 if (resp.empty()) 187 { 188 // Network Protocol Listen Response Elements is empty 189 boost::system::error_code ec1 = 190 boost::system::errc::make_error_code( 191 boost::system::errc::bad_message); 192 // return error code 193 callback(ec1, 0); 194 BMCWEB_LOG_ERROR << ec1; 195 return; 196 } 197 const std::string& listenStream = 198 std::get<NET_PROTO_LISTEN_STREAM>(resp[0]); 199 const char* pa = &listenStream[listenStream.rfind(':') + 1]; 200 int port{0}; 201 if (auto [p, ec2] = std::from_chars(pa, nullptr, port); 202 ec2 != std::errc()) 203 { 204 // there is only two possibility invalid_argument and 205 // result_out_of_range 206 boost::system::error_code ec3 = 207 boost::system::errc::make_error_code( 208 boost::system::errc::invalid_argument); 209 if (ec2 == std::errc::result_out_of_range) 210 { 211 ec3 = boost::system::errc::make_error_code( 212 boost::system::errc::result_out_of_range); 213 } 214 // return error code 215 callback(ec3, 0); 216 BMCWEB_LOG_ERROR << ec3; 217 } 218 callback(ec, port); 219 }); 220 } 221 222 } // namespace redfish 223 #endif 224