1 #include "config.h"
2 #include "snmp_conf_manager.hpp"
3 #include "snmp_serialize.hpp"
4 #include "snmp_util.hpp"
5 #include "xyz/openbmc_project/Common/error.hpp"
6 
7 #include <phosphor-logging/elog-errors.hpp>
8 #include <phosphor-logging/log.hpp>
9 
10 #include <experimental/filesystem>
11 
12 #include <arpa/inet.h>
13 
14 namespace phosphor
15 {
16 namespace network
17 {
18 namespace snmp
19 {
20 
21 using namespace phosphor::logging;
22 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
23 using Argument = xyz::openbmc_project::Common::InvalidArgument;
24 
25 ConfManager::ConfManager(sdbusplus::bus::bus& bus, const char* objPath) :
26     details::CreateIface(bus, objPath, true),
27     dbusPersistentLocation(SNMP_CONF_PERSIST_PATH), bus(bus),
28     objectPath(objPath)
29 {
30 }
31 
32 std::string ConfManager::client(std::string address, uint16_t port)
33 {
34     auto clientEntry = this->clients.find(address);
35     if (clientEntry != this->clients.end())
36     {
37         log<level::ERR>("Client already configured"),
38             entry("ADDRESS=%s", address.c_str());
39         elog<InternalFailure>();
40     }
41     try
42     {
43         // just to check whether given address is valid or not.
44         resolveAddress(address);
45     }
46     catch (InternalFailure& e)
47     {
48         log<level::ERR>("Not a valid address"),
49             entry("ADDRESS=%s", address.c_str());
50         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
51                               Argument::ARGUMENT_VALUE(address.c_str()));
52     }
53 
54     std::experimental::filesystem::path objPath;
55     objPath /= objectPath;
56     objPath /= generateId(address, port);
57     // create the D-Bus object
58     auto client = std::make_unique<phosphor::network::snmp::Client>(
59         bus, objPath.string().c_str(), *this, address, port);
60     // save the D-Bus object
61     serialize(*client, dbusPersistentLocation);
62 
63     this->clients.emplace(address, std::move(client));
64     return objPath.string();
65 }
66 
67 std::string ConfManager::generateId(const std::string& address, uint16_t port)
68 {
69     std::stringstream hexId;
70     std::string hashString = address;
71     hashString += std::to_string(port);
72 
73     // Only want 8 hex digits.
74     hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
75     return hexId.str();
76 }
77 
78 void ConfManager::deleteSNMPClient(const std::string& address)
79 {
80     auto it = clients.find(address);
81     if (it == clients.end())
82     {
83         log<level::ERR>("Unable to delete the snmp client.",
84                         entry("ADDRESS=%s", address.c_str()));
85         return;
86     }
87 
88     std::error_code ec;
89     // remove the persistent file
90     fs::path fileName = dbusPersistentLocation;
91     fileName /=
92         it->second->address() + SEPARATOR + std::to_string(it->second->port());
93 
94     if (fs::exists(fileName))
95     {
96         if (!fs::remove(fileName, ec))
97         {
98             log<level::ERR>("Unable to delete the file",
99                             entry("FILE=%s", fileName.c_str()),
100                             entry("ERROR=%d", ec.value()));
101         }
102     }
103     else
104     {
105         log<level::ERR>("File doesn't exist",
106                         entry("FILE=%s", fileName.c_str()));
107     }
108     // remove the D-Bus Object.
109     this->clients.erase(it);
110 }
111 
112 void ConfManager::restoreClients()
113 {
114     if (!fs::exists(dbusPersistentLocation) ||
115         fs::is_empty(dbusPersistentLocation))
116     {
117         return;
118     }
119 
120     for (auto& confFile :
121          fs::recursive_directory_iterator(dbusPersistentLocation))
122     {
123         if (!fs::is_regular_file(confFile))
124         {
125             continue;
126         }
127 
128         auto managerID = confFile.path().filename().string();
129         auto pos = managerID.find(SEPARATOR);
130         auto ipaddress = managerID.substr(0, pos);
131         auto port_str = managerID.substr(pos + 1);
132         uint16_t port = stoi(port_str, nullptr);
133 
134         fs::path objPath = objectPath;
135         objPath /= generateId(ipaddress, port);
136         auto manager =
137             std::make_unique<Client>(bus, objPath.string().c_str(), *this);
138         if (deserialize(confFile.path(), *manager))
139         {
140             manager->emit_object_added();
141             this->clients.emplace(ipaddress, std::move(manager));
142         }
143     }
144 }
145 
146 } // namespace snmp
147 } // namespace network
148 } // namespace phosphor
149