170141561SBorawski.Lukasz /* 270141561SBorawski.Lukasz // Copyright (c) 2018 Intel Corporation 370141561SBorawski.Lukasz // 470141561SBorawski.Lukasz // Licensed under the Apache License, Version 2.0 (the "License"); 570141561SBorawski.Lukasz // you may not use this file except in compliance with the License. 670141561SBorawski.Lukasz // You may obtain a copy of the License at 770141561SBorawski.Lukasz // 870141561SBorawski.Lukasz // http://www.apache.org/licenses/LICENSE-2.0 970141561SBorawski.Lukasz // 1070141561SBorawski.Lukasz // Unless required by applicable law or agreed to in writing, software 1170141561SBorawski.Lukasz // distributed under the License is distributed on an "AS IS" BASIS, 1270141561SBorawski.Lukasz // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1370141561SBorawski.Lukasz // See the License for the specific language governing permissions and 1470141561SBorawski.Lukasz // limitations under the License. 1570141561SBorawski.Lukasz */ 1670141561SBorawski.Lukasz #pragma once 1770141561SBorawski.Lukasz 18*3a8a0088SKowalski, Kamil #include "error_messages.hpp" 1970141561SBorawski.Lukasz #include "node.hpp" 2070141561SBorawski.Lukasz 2170141561SBorawski.Lukasz namespace redfish { 2270141561SBorawski.Lukasz 23*3a8a0088SKowalski, Kamil enum NetworkProtocolUnitStructFields { 24*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_NAME, 25*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_DESC, 26*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_LOAD_STATE, 27*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_ACTIVE_STATE, 28*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_SUB_STATE, 29*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_DEVICE, 30*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_OBJ_PATH, 31*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_ALWAYS_0, 32*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_ALWAYS_EMPTY, 33*3a8a0088SKowalski, Kamil NET_PROTO_UNIT_ALWAYS_ROOT_PATH 34*3a8a0088SKowalski, Kamil }; 35*3a8a0088SKowalski, Kamil 36*3a8a0088SKowalski, Kamil enum NetworkProtocolListenResponseElements { 37*3a8a0088SKowalski, Kamil NET_PROTO_LISTEN_TYPE, 38*3a8a0088SKowalski, Kamil NET_PROTO_LISTEN_STREAM 39*3a8a0088SKowalski, Kamil }; 40*3a8a0088SKowalski, Kamil 41*3a8a0088SKowalski, Kamil /** 42*3a8a0088SKowalski, Kamil * @brief D-Bus Unit structure returned in array from ListUnits Method 43*3a8a0088SKowalski, Kamil */ 44*3a8a0088SKowalski, Kamil using UnitStruct = 45*3a8a0088SKowalski, Kamil std::tuple<std::string, std::string, std::string, std::string, std::string, 46*3a8a0088SKowalski, Kamil std::string, sdbusplus::message::object_path, uint32_t, 47*3a8a0088SKowalski, Kamil std::string, sdbusplus::message::object_path>; 48*3a8a0088SKowalski, Kamil 49*3a8a0088SKowalski, Kamil struct ServiceConfiguration { 50*3a8a0088SKowalski, Kamil std::string serviceName; 51*3a8a0088SKowalski, Kamil std::string socketPath; 52*3a8a0088SKowalski, Kamil }; 53*3a8a0088SKowalski, Kamil 54*3a8a0088SKowalski, Kamil class OnDemandNetworkProtocolProvider { 55*3a8a0088SKowalski, Kamil public: 56*3a8a0088SKowalski, Kamil template <typename CallbackFunc> 57*3a8a0088SKowalski, Kamil static void getServices(CallbackFunc&& callback) { 58*3a8a0088SKowalski, Kamil crow::connections::systemBus->async_method_call( 59*3a8a0088SKowalski, Kamil [callback{std::move(callback)}](const boost::system::error_code ec, 60*3a8a0088SKowalski, Kamil const std::vector<UnitStruct>& resp) { 61*3a8a0088SKowalski, Kamil if (ec) { 62*3a8a0088SKowalski, Kamil callback(false, resp); 63*3a8a0088SKowalski, Kamil } else { 64*3a8a0088SKowalski, Kamil callback(true, resp); 65*3a8a0088SKowalski, Kamil } 66*3a8a0088SKowalski, Kamil }, 67*3a8a0088SKowalski, Kamil "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 68*3a8a0088SKowalski, Kamil "org.freedesktop.systemd1.Manager", "ListUnits"); 69*3a8a0088SKowalski, Kamil } 70*3a8a0088SKowalski, Kamil 71*3a8a0088SKowalski, Kamil template <typename CallbackFunc> 72*3a8a0088SKowalski, Kamil static void getSocketListenPort(const std::string& path, 73*3a8a0088SKowalski, Kamil CallbackFunc&& callback) { 74*3a8a0088SKowalski, Kamil crow::connections::systemBus->async_method_call( 75*3a8a0088SKowalski, Kamil [callback{std::move(callback)}]( 76*3a8a0088SKowalski, Kamil const boost::system::error_code ec, 77*3a8a0088SKowalski, Kamil const sdbusplus::message::variant< 78*3a8a0088SKowalski, Kamil std::vector<std::tuple<std::string, std::string>>>& resp) { 79*3a8a0088SKowalski, Kamil if (ec) { 80*3a8a0088SKowalski, Kamil callback(false, false, 0); 81*3a8a0088SKowalski, Kamil } else { 82*3a8a0088SKowalski, Kamil auto responsePtr = mapbox::getPtr< 83*3a8a0088SKowalski, Kamil const std::vector<std::tuple<std::string, std::string>>>(resp); 84*3a8a0088SKowalski, Kamil 85*3a8a0088SKowalski, Kamil std::string listenStream = 86*3a8a0088SKowalski, Kamil std::get<NET_PROTO_LISTEN_STREAM>((*responsePtr)[0]); 87*3a8a0088SKowalski, Kamil auto lastColonPos = listenStream.rfind(":"); 88*3a8a0088SKowalski, Kamil if (lastColonPos != std::string::npos) { 89*3a8a0088SKowalski, Kamil std::string portStr = listenStream.substr(lastColonPos + 1); 90*3a8a0088SKowalski, Kamil char* endPtr; 91*3a8a0088SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 92*3a8a0088SKowalski, Kamil long port = std::strtol(portStr.c_str(), &endPtr, 10); 93*3a8a0088SKowalski, Kamil 94*3a8a0088SKowalski, Kamil if (*endPtr != '\0' || portStr.empty()) { 95*3a8a0088SKowalski, Kamil // Invalid value 96*3a8a0088SKowalski, Kamil callback(true, false, 0); 97*3a8a0088SKowalski, Kamil } else { 98*3a8a0088SKowalski, Kamil // Everything OK 99*3a8a0088SKowalski, Kamil callback(true, true, port); 100*3a8a0088SKowalski, Kamil } 101*3a8a0088SKowalski, Kamil } else { 102*3a8a0088SKowalski, Kamil // Not a port 103*3a8a0088SKowalski, Kamil callback(true, false, 0); 104*3a8a0088SKowalski, Kamil } 105*3a8a0088SKowalski, Kamil } 106*3a8a0088SKowalski, Kamil }, 107*3a8a0088SKowalski, Kamil "org.freedesktop.systemd1", path, "org.freedesktop.DBus.Properties", 108*3a8a0088SKowalski, Kamil "Get", "org.freedesktop.systemd1.Socket", "Listen"); 109*3a8a0088SKowalski, Kamil } 110*3a8a0088SKowalski, Kamil }; 111*3a8a0088SKowalski, Kamil 11270141561SBorawski.Lukasz class NetworkProtocol : public Node { 11370141561SBorawski.Lukasz public: 11470141561SBorawski.Lukasz NetworkProtocol(CrowApp& app) 1154b1b8683SBorawski.Lukasz : Node(app, "/redfish/v1/Managers/openbmc/NetworkProtocol") { 11670141561SBorawski.Lukasz Node::json["@odata.type"] = 11770141561SBorawski.Lukasz "#ManagerNetworkProtocol.v1_1_0.ManagerNetworkProtocol"; 11870141561SBorawski.Lukasz Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/NetworkProtocol"; 11970141561SBorawski.Lukasz Node::json["@odata.context"] = 12070141561SBorawski.Lukasz "/redfish/v1/$metadata#ManagerNetworkProtocol.ManagerNetworkProtocol"; 12170141561SBorawski.Lukasz Node::json["Id"] = "NetworkProtocol"; 12270141561SBorawski.Lukasz Node::json["Name"] = "Manager Network Protocol"; 12370141561SBorawski.Lukasz Node::json["Description"] = "Manager Network Service"; 12470141561SBorawski.Lukasz Node::json["Status"]["Health"] = "OK"; 12570141561SBorawski.Lukasz Node::json["Status"]["HealthRollup"] = "OK"; 12670141561SBorawski.Lukasz Node::json["Status"]["State"] = "Enabled"; 1273ebd75f7SEd Tanous 128*3a8a0088SKowalski, Kamil for (auto& protocol : protocolToDBus) { 129*3a8a0088SKowalski, Kamil Node::json[protocol.first]["ProtocolEnabled"] = false; 130*3a8a0088SKowalski, Kamil } 131*3a8a0088SKowalski, Kamil 1324b1b8683SBorawski.Lukasz entityPrivileges = { 1334b1b8683SBorawski.Lukasz {boost::beast::http::verb::get, {{"Login"}}}, 134e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 135e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 136e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 137e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 138e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 13970141561SBorawski.Lukasz } 14070141561SBorawski.Lukasz 14170141561SBorawski.Lukasz private: 14255c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 14370141561SBorawski.Lukasz const std::vector<std::string>& params) override { 144*3a8a0088SKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 145*3a8a0088SKowalski, Kamil 146*3a8a0088SKowalski, Kamil getData(asyncResp); 14770141561SBorawski.Lukasz } 14870141561SBorawski.Lukasz 14970141561SBorawski.Lukasz std::string getHostName() const { 15070141561SBorawski.Lukasz std::string hostName; 15170141561SBorawski.Lukasz 15270141561SBorawski.Lukasz std::array<char, HOST_NAME_MAX> hostNameCStr; 15370141561SBorawski.Lukasz if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0) { 15470141561SBorawski.Lukasz hostName = hostNameCStr.data(); 15570141561SBorawski.Lukasz } 15670141561SBorawski.Lukasz return hostName; 15770141561SBorawski.Lukasz } 15870141561SBorawski.Lukasz 159*3a8a0088SKowalski, Kamil void getData(const std::shared_ptr<AsyncResp>& asyncResp) { 160*3a8a0088SKowalski, Kamil Node::json["HostName"] = getHostName(); 161*3a8a0088SKowalski, Kamil asyncResp->res.jsonValue = Node::json; 162*3a8a0088SKowalski, Kamil 163*3a8a0088SKowalski, Kamil OnDemandNetworkProtocolProvider::getServices( 164*3a8a0088SKowalski, Kamil [&, asyncResp](const bool success, 165*3a8a0088SKowalski, Kamil const std::vector<UnitStruct>& resp) { 166*3a8a0088SKowalski, Kamil if (!success) { 167*3a8a0088SKowalski, Kamil asyncResp->res.jsonValue = nlohmann::json::object(); 168*3a8a0088SKowalski, Kamil messages::addMessageToErrorJson(asyncResp->res.jsonValue, 169*3a8a0088SKowalski, Kamil messages::internalError()); 170*3a8a0088SKowalski, Kamil asyncResp->res.result( 171*3a8a0088SKowalski, Kamil boost::beast::http::status::internal_server_error); 172*3a8a0088SKowalski, Kamil } 173*3a8a0088SKowalski, Kamil 174*3a8a0088SKowalski, Kamil for (auto& unit : resp) { 175*3a8a0088SKowalski, Kamil for (auto& kv : protocolToDBus) { 176*3a8a0088SKowalski, Kamil if (kv.second.serviceName == 177*3a8a0088SKowalski, Kamil std::get<NET_PROTO_UNIT_NAME>(unit)) { 178*3a8a0088SKowalski, Kamil std::string service = kv.first; 179*3a8a0088SKowalski, Kamil 180*3a8a0088SKowalski, Kamil // Process state 181*3a8a0088SKowalski, Kamil if (std::get<NET_PROTO_UNIT_SUB_STATE>(unit) == "running") { 182*3a8a0088SKowalski, Kamil asyncResp->res.jsonValue[service]["ProtocolEnabled"] = true; 18370141561SBorawski.Lukasz } else { 184*3a8a0088SKowalski, Kamil asyncResp->res.jsonValue[service]["ProtocolEnabled"] = false; 18570141561SBorawski.Lukasz } 18670141561SBorawski.Lukasz 187*3a8a0088SKowalski, Kamil // Process port 188*3a8a0088SKowalski, Kamil OnDemandNetworkProtocolProvider::getSocketListenPort( 189*3a8a0088SKowalski, Kamil kv.second.socketPath, 190*3a8a0088SKowalski, Kamil [&, asyncResp, service{std::move(service)} ]( 191*3a8a0088SKowalski, Kamil const bool fetchSuccess, const bool portAvailable, 192*3a8a0088SKowalski, Kamil const unsigned long port) { 193*3a8a0088SKowalski, Kamil if (fetchSuccess) { 194*3a8a0088SKowalski, Kamil if (portAvailable) { 195*3a8a0088SKowalski, Kamil asyncResp->res.jsonValue[service]["Port"] = port; 196*3a8a0088SKowalski, Kamil } else { 197*3a8a0088SKowalski, Kamil asyncResp->res.jsonValue[service]["Port"] = nullptr; 198*3a8a0088SKowalski, Kamil } 199*3a8a0088SKowalski, Kamil } else { 200*3a8a0088SKowalski, Kamil messages::addMessageToJson(asyncResp->res.jsonValue, 201*3a8a0088SKowalski, Kamil messages::internalError(), 202*3a8a0088SKowalski, Kamil "/" + service); 203*3a8a0088SKowalski, Kamil } 204*3a8a0088SKowalski, Kamil }); 205*3a8a0088SKowalski, Kamil break; 20670141561SBorawski.Lukasz } 20770141561SBorawski.Lukasz } 20870141561SBorawski.Lukasz } 209*3a8a0088SKowalski, Kamil }); 21070141561SBorawski.Lukasz } 21170141561SBorawski.Lukasz 212*3a8a0088SKowalski, Kamil boost::container::flat_map<std::string, ServiceConfiguration> protocolToDBus{ 213*3a8a0088SKowalski, Kamil {"SSH", 214*3a8a0088SKowalski, Kamil {"dropbear.service", 215*3a8a0088SKowalski, Kamil "/org/freedesktop/systemd1/unit/dropbear_2esocket"}}, 216*3a8a0088SKowalski, Kamil {"HTTPS", 217*3a8a0088SKowalski, Kamil {"phosphor-gevent.service", 218*3a8a0088SKowalski, Kamil "/org/freedesktop/systemd1/unit/phosphor_2dgevent_2esocket"}}, 219*3a8a0088SKowalski, Kamil {"IPMI", 220*3a8a0088SKowalski, Kamil {"phosphor-ipmi-net.service", 221*3a8a0088SKowalski, Kamil "/org/freedesktop/systemd1/unit/phosphor_2dipmi_2dnet_2esocket"}}}; 22270141561SBorawski.Lukasz }; 22370141561SBorawski.Lukasz 22470141561SBorawski.Lukasz } // namespace redfish 225