xref: /openbmc/phosphor-logging/phosphor-rsyslog-config/server-conf.cpp (revision 40a7406097c0b5b0670c5987f6fe8c902d65562d)
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