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 #ifndef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS 17 #pragma once 18 19 namespace redfish 20 { 21 22 enum NetworkProtocolUnitStructFields 23 { 24 NET_PROTO_UNIT_NAME, 25 NET_PROTO_UNIT_DESC, 26 NET_PROTO_UNIT_LOAD_STATE, 27 NET_PROTO_UNIT_ACTIVE_STATE, 28 NET_PROTO_UNIT_SUB_STATE, 29 NET_PROTO_UNIT_DEVICE, 30 NET_PROTO_UNIT_OBJ_PATH, 31 NET_PROTO_UNIT_ALWAYS_0, 32 NET_PROTO_UNIT_ALWAYS_EMPTY, 33 NET_PROTO_UNIT_ALWAYS_ROOT_PATH 34 }; 35 36 enum NetworkProtocolListenResponseElements 37 { 38 NET_PROTO_LISTEN_TYPE, 39 NET_PROTO_LISTEN_STREAM 40 }; 41 42 /** 43 * @brief D-Bus Unit structure returned in array from ListUnits Method 44 */ 45 using UnitStruct = 46 std::tuple<std::string, std::string, std::string, std::string, std::string, 47 std::string, sdbusplus::message::object_path, uint32_t, 48 std::string, sdbusplus::message::object_path>; 49 50 template <typename CallbackFunc> 51 void getMainChassisId(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 52 CallbackFunc&& callback) 53 { 54 // Find managed chassis 55 crow::connections::systemBus->async_method_call( 56 [callback, 57 asyncResp](const boost::system::error_code ec, 58 const crow::openbmc_mapper::GetSubTreeType& subtree) { 59 if (ec) 60 { 61 BMCWEB_LOG_ERROR << ec; 62 return; 63 } 64 if (subtree.size() == 0) 65 { 66 BMCWEB_LOG_DEBUG << "Can't find chassis!"; 67 return; 68 } 69 70 std::size_t idPos = subtree[0].first.rfind('/'); 71 if (idPos == std::string::npos || 72 (idPos + 1) >= subtree[0].first.size()) 73 { 74 messages::internalError(asyncResp->res); 75 BMCWEB_LOG_DEBUG << "Can't parse chassis ID!"; 76 return; 77 } 78 std::string chassisId = subtree[0].first.substr(idPos + 1); 79 BMCWEB_LOG_DEBUG << "chassisId = " << chassisId; 80 callback(chassisId, asyncResp); 81 }, 82 "xyz.openbmc_project.ObjectMapper", 83 "/xyz/openbmc_project/object_mapper", 84 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 85 "/xyz/openbmc_project/inventory", 0, 86 std::array<const char*, 2>{ 87 "xyz.openbmc_project.Inventory.Item.Board", 88 "xyz.openbmc_project.Inventory.Item.Chassis"}); 89 } 90 91 template <typename CallbackFunc> 92 void getPortStatusAndPath(const std::string& serviceName, 93 CallbackFunc&& callback) 94 { 95 crow::connections::systemBus->async_method_call( 96 [serviceName, 97 callback{std::move(callback)}](const boost::system::error_code ec, 98 const std::vector<UnitStruct>& r) { 99 if (ec) 100 { 101 BMCWEB_LOG_ERROR << ec; 102 // return error code 103 callback(ec, "", false); 104 return; 105 } 106 107 for (const UnitStruct& unit : r) 108 { 109 // Only traverse through <xyz>.socket units 110 const std::string& unitName = 111 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.compare(".socket") != 0) 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 = 159 boost::system::errc::make_error_code( 160 boost::system::errc::no_such_process); 161 // return error code 162 callback(ec1, "", false); 163 BMCWEB_LOG_ERROR << ec1; 164 }, 165 "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 166 "org.freedesktop.systemd1.Manager", "ListUnits"); 167 } 168 169 template <typename CallbackFunc> 170 void getPortNumber(const std::string& socketPath, CallbackFunc&& callback) 171 { 172 crow::connections::systemBus->async_method_call( 173 [callback{std::move(callback)}]( 174 const boost::system::error_code ec, 175 const std::variant< 176 std::vector<std::tuple<std::string, std::string>>>& resp) { 177 if (ec) 178 { 179 BMCWEB_LOG_ERROR << ec; 180 callback(ec, 0); 181 return; 182 } 183 const std::vector< 184 std::tuple<std::string, std::string>>* responsePtr = 185 std::get_if<std::vector<std::tuple<std::string, std::string>>>( 186 &resp); 187 if (responsePtr == nullptr || responsePtr->size() < 1) 188 { 189 // Network Protocol Listen Response Elements is empty 190 boost::system::error_code ec1 = 191 boost::system::errc::make_error_code( 192 boost::system::errc::bad_message); 193 // return error code 194 callback(ec1, 0); 195 BMCWEB_LOG_ERROR << ec1; 196 return; 197 } 198 const std::string& listenStream = 199 std::get<NET_PROTO_LISTEN_STREAM>((*responsePtr)[0]); 200 const char* pa = &listenStream[listenStream.rfind(':') + 1]; 201 int port{0}; 202 if (auto [p, ec2] = std::from_chars(pa, nullptr, port); 203 ec2 != std::errc()) 204 { 205 // there is only two possibility invalid_argument and 206 // result_out_of_range 207 boost::system::error_code ec3 = 208 boost::system::errc::make_error_code( 209 boost::system::errc::invalid_argument); 210 if (ec2 == std::errc::result_out_of_range) 211 { 212 ec3 = boost::system::errc::make_error_code( 213 boost::system::errc::result_out_of_range); 214 } 215 // return error code 216 callback(ec3, 0); 217 BMCWEB_LOG_ERROR << ec3; 218 } 219 callback(ec, port); 220 }, 221 "org.freedesktop.systemd1", socketPath, 222 "org.freedesktop.DBus.Properties", "Get", 223 "org.freedesktop.systemd1.Socket", "Listen"); 224 } 225 226 } // namespace redfish 227 #endif 228