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.size() == 0) 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, 98 callback{std::move(callback)}](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 crow::connections::systemBus->async_method_call( 174 [callback{std::move(callback)}]( 175 const boost::system::error_code ec, 176 const dbus::utility::DbusVariantType& 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