1 #include "server-conf.hpp" 2 3 #include "utils.hpp" 4 #include "xyz/openbmc_project/Common/error.hpp" 5 6 #include <fstream> 7 #include <phosphor-logging/elog.hpp> 8 #if __has_include("../../usr/include/phosphor-logging/elog-errors.hpp") 9 #include "../../usr/include/phosphor-logging/elog-errors.hpp" 10 #else 11 #include <phosphor-logging/elog-errors.hpp> 12 #endif 13 #include <arpa/inet.h> 14 #include <netdb.h> 15 16 #include <string> 17 18 #if __has_include(<filesystem>) 19 #include <filesystem> 20 #elif __has_include(<experimental/filesystem>) 21 #include <experimental/filesystem> 22 namespace std 23 { 24 // splice experimental::filesystem into std 25 namespace filesystem = std::experimental::filesystem; 26 } // namespace std 27 #else 28 #error filesystem not available 29 #endif 30 31 namespace phosphor 32 { 33 namespace rsyslog_config 34 { 35 36 namespace utils = phosphor::rsyslog_utils; 37 using namespace phosphor::logging; 38 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 39 namespace fs = std::filesystem; 40 41 std::string Server::address(std::string value) 42 { 43 using Argument = xyz::openbmc_project::Common::InvalidArgument; 44 std::string result{}; 45 46 try 47 { 48 auto serverAddress = address(); 49 if (serverAddress == value) 50 { 51 return serverAddress; 52 } 53 54 if (!value.empty() && !addressValid(value)) 55 { 56 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"), 57 Argument::ARGUMENT_VALUE(value.c_str())); 58 } 59 60 writeConfig(value, port(), configFilePath.c_str()); 61 result = std::move(NetworkClient::address(value)); 62 } 63 catch (const InvalidArgument& e) 64 { 65 throw; 66 } 67 catch (const InternalFailure& e) 68 { 69 throw; 70 } 71 catch (const std::exception& e) 72 { 73 log<level::ERR>(e.what()); 74 elog<InternalFailure>(); 75 } 76 77 return result; 78 } 79 80 uint16_t Server::port(uint16_t value) 81 { 82 uint16_t result{}; 83 84 try 85 { 86 auto serverPort = port(); 87 if (serverPort == value) 88 { 89 return serverPort; 90 } 91 92 writeConfig(address(), value, configFilePath.c_str()); 93 result = NetworkClient::port(value); 94 } 95 catch (const InternalFailure& e) 96 { 97 throw; 98 } 99 catch (const std::exception& e) 100 { 101 log<level::ERR>(e.what()); 102 elog<InternalFailure>(); 103 } 104 105 return result; 106 } 107 108 void Server::writeConfig(const std::string& serverAddress, uint16_t serverPort, 109 const char* filePath) 110 { 111 fs::create_directory(fs::path(filePath).parent_path()); 112 std::fstream stream(filePath, std::fstream::out); 113 114 if (serverPort && !serverAddress.empty()) 115 { 116 // write '*.* @@<remote-host>:<port>' 117 stream << "*.* @@" << serverAddress << ":" << serverPort; 118 } 119 else // this is a disable request 120 { 121 fs::remove(filePath); 122 } 123 124 restart(); 125 } 126 127 bool Server::addressValid(const std::string& address) 128 { 129 addrinfo hints{}; 130 addrinfo* res = nullptr; 131 hints.ai_family = AF_UNSPEC; 132 hints.ai_socktype = SOCK_STREAM; 133 hints.ai_flags |= AI_CANONNAME; 134 135 auto result = getaddrinfo(address.c_str(), nullptr, &hints, &res); 136 if (result) 137 { 138 log<level::ERR>("bad address", entry("ADDRESS=%s", address.c_str()), 139 entry("ERRNO=%d", result)); 140 return false; 141 } 142 return true; 143 } 144 145 void Server::restore(const char* filePath) 146 { 147 if (!fs::exists(filePath)) 148 { 149 return; 150 } 151 152 std::fstream stream(filePath, std::fstream::in); 153 std::string line; 154 155 std::getline(stream, line); 156 157 // Ignore if line is commented 158 if ('#' != line.at(0)) 159 { 160 auto pos = line.find(':'); 161 if (pos != std::string::npos) 162 { 163 //"*.* @@<address>:<port>" 164 constexpr auto start = 6; // Skip "*.* @@" 165 auto serverAddress = line.substr(start, pos - start); 166 auto serverPort = line.substr(pos + 1); 167 NetworkClient::address(std::move(serverAddress)); 168 NetworkClient::port(std::stoul(serverPort)); 169 } 170 } 171 } 172 173 void Server::restart() 174 { 175 utils::restart(); 176 } 177 178 } // namespace rsyslog_config 179 } // namespace phosphor 180