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/lg2.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_t& 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     try
40     {
41         // just to check whether given address is valid or not.
42         resolveAddress(address);
43     }
44     catch (const InternalFailure& e)
45     {
46         lg2::error("{ADDRESS} is not a valid address", "ADDRESS", address);
47         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
48                               Argument::ARGUMENT_VALUE(address.c_str()));
49     }
50 
51     lastClientId++;
52     // create the D-Bus object
53     std::filesystem::path objPath;
54     objPath /= objectPath;
55     objPath /= std::to_string(lastClientId);
56 
57     auto client = std::make_unique<phosphor::network::snmp::Client>(
58         bus, objPath.string().c_str(), *this, address, port);
59 
60     // save the D-Bus object
61     serialize(lastClientId, *client, dbusPersistentLocation);
62 
63     this->clients.emplace(lastClientId, std::move(client));
64     return objPath.string();
65 }
66 
67 void ConfManager::checkClientConfigured(const std::string& address,
68                                         uint16_t port)
69 {
70     if (address.empty())
71     {
72         lg2::error("{ADDRESS} is not a valid address", "ADDRESS", address);
73         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ADDRESS"),
74                               Argument::ARGUMENT_VALUE(address.c_str()));
75     }
76 
77     for (const auto& val : clients)
78     {
79         if (val.second.get()->address() == address &&
80             val.second.get()->port() == port)
81         {
82             lg2::error("Client already exist");
83             // TODO Add the error(Object already exist) in the D-Bus interface
84             // then make the change here,meanwhile send the Internal Failure.
85             elog<InvalidArgument>(
86                 Argument::ARGUMENT_NAME("ADDRESS"),
87                 Argument::ARGUMENT_VALUE("Client already exist."));
88         }
89     }
90 }
91 
92 void ConfManager::deleteSNMPClient(Id id)
93 {
94     auto it = clients.find(id);
95     if (it == clients.end())
96     {
97         lg2::error("Unable to delete the snmp client: {ID}", "ID", id);
98         return;
99     }
100 
101     std::error_code ec;
102     // remove the persistent file
103     fs::path fileName = dbusPersistentLocation;
104     fileName /= std::to_string(id);
105 
106     if (fs::exists(fileName))
107     {
108         if (!fs::remove(fileName, ec))
109         {
110             lg2::error("Unable to delete {FILE}: {EC}", "FILE", fileName, "EC",
111                        ec.value());
112         }
113     }
114     else
115     {
116         lg2::error("{FILE} doesn't exist", "FILE", fileName);
117     }
118     // remove the D-Bus Object.
119     this->clients.erase(it);
120 }
121 
122 void ConfManager::restoreClients()
123 {
124     if (!fs::exists(dbusPersistentLocation) ||
125         fs::is_empty(dbusPersistentLocation))
126     {
127         return;
128     }
129 
130     for (auto& confFile :
131          fs::recursive_directory_iterator(dbusPersistentLocation))
132     {
133         if (!fs::is_regular_file(confFile))
134         {
135             continue;
136         }
137 
138         auto managerID = confFile.path().filename().string();
139         Id idNum = std::stol(managerID);
140 
141         fs::path objPath = objectPath;
142         objPath /= managerID;
143         auto manager =
144             std::make_unique<Client>(bus, objPath.string().c_str(), *this);
145         if (deserialize(confFile.path(), *manager))
146         {
147             manager->emit_object_added();
148             this->clients.emplace(idNum, std::move(manager));
149             if (idNum > lastClientId)
150             {
151                 lastClientId = idNum;
152             }
153         }
154     }
155 }
156 
157 } // namespace snmp
158 } // namespace network
159 } // namespace phosphor
160