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