149aefb31SBrad Bishop /**
249aefb31SBrad Bishop  * Copyright © 2016 IBM Corporation
349aefb31SBrad Bishop  *
449aefb31SBrad Bishop  * Licensed under the Apache License, Version 2.0 (the "License");
549aefb31SBrad Bishop  * you may not use this file except in compliance with the License.
649aefb31SBrad Bishop  * You may obtain a copy of the License at
749aefb31SBrad Bishop  *
849aefb31SBrad Bishop  *     http://www.apache.org/licenses/LICENSE-2.0
949aefb31SBrad Bishop  *
1049aefb31SBrad Bishop  * Unless required by applicable law or agreed to in writing, software
1149aefb31SBrad Bishop  * distributed under the License is distributed on an "AS IS" BASIS,
1249aefb31SBrad Bishop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349aefb31SBrad Bishop  * See the License for the specific language governing permissions and
1449aefb31SBrad Bishop  * limitations under the License.
1549aefb31SBrad Bishop  */
1649aefb31SBrad Bishop #include <iostream>
1749aefb31SBrad Bishop #include <exception>
1824424983SBrad Bishop #include <chrono>
1949aefb31SBrad Bishop #include "manager.hpp"
2049aefb31SBrad Bishop 
2124424983SBrad Bishop using namespace std::literals::chrono_literals;
2224424983SBrad Bishop 
2349aefb31SBrad Bishop namespace phosphor
2449aefb31SBrad Bishop {
2549aefb31SBrad Bishop namespace inventory
2649aefb31SBrad Bishop {
2749aefb31SBrad Bishop namespace manager
2849aefb31SBrad Bishop {
2949aefb31SBrad Bishop namespace details
3049aefb31SBrad Bishop {
3149aefb31SBrad Bishop 
3249aefb31SBrad Bishop /** @brief Fowrarding signal callback.
3349aefb31SBrad Bishop  *
3449aefb31SBrad Bishop  *  Extracts per-signal specific context and forwards the call to the manager
3549aefb31SBrad Bishop  *  instance.
3649aefb31SBrad Bishop  */
3749aefb31SBrad Bishop auto _signal(sd_bus_message* m, void* data, sd_bus_error* e) noexcept
3849aefb31SBrad Bishop {
397b33777bSBrad Bishop     try
407b33777bSBrad Bishop     {
4149aefb31SBrad Bishop         auto msg = sdbusplus::message::message(m);
4249aefb31SBrad Bishop         auto& args = *static_cast<Manager::SigArg*>(data);
4349aefb31SBrad Bishop         sd_bus_message_ref(m);
4449aefb31SBrad Bishop         auto& mgr = *std::get<0>(args);
45*48547a85SBrad Bishop         mgr.handleEvent(
4668c80839SBrad Bishop             msg,
4768c80839SBrad Bishop             static_cast<const details::DbusSignal&>(
4868c80839SBrad Bishop                 *std::get<1>(args)),
4968c80839SBrad Bishop             *std::get<2>(args));
5049aefb31SBrad Bishop     }
517b33777bSBrad Bishop     catch (const std::exception& e)
527b33777bSBrad Bishop     {
5349aefb31SBrad Bishop         std::cerr << e.what() << std::endl;
5449aefb31SBrad Bishop     }
5549aefb31SBrad Bishop 
5649aefb31SBrad Bishop     return 0;
5749aefb31SBrad Bishop }
5849aefb31SBrad Bishop 
5949aefb31SBrad Bishop } // namespace details
6049aefb31SBrad Bishop 
6149aefb31SBrad Bishop Manager::Manager(
6249aefb31SBrad Bishop     sdbusplus::bus::bus&& bus,
6349aefb31SBrad Bishop     const char* busname,
6449aefb31SBrad Bishop     const char* root,
6549aefb31SBrad Bishop     const char* iface) :
66451f8d93SBrad Bishop     details::ServerObject<details::ManagerIface>(bus, root),
6749aefb31SBrad Bishop     _shutdown(false),
6849aefb31SBrad Bishop     _root(root),
6949aefb31SBrad Bishop     _bus(std::move(bus)),
7049aefb31SBrad Bishop     _manager(sdbusplus::server::manager::manager(_bus, root))
7149aefb31SBrad Bishop {
7268c80839SBrad Bishop     for (auto& group : _events)
7368c80839SBrad Bishop     {
74*48547a85SBrad Bishop         for (auto pEvent : std::get<std::vector<details::EventBasePtr>>(
75*48547a85SBrad Bishop                  group))
7668c80839SBrad Bishop         {
774f20a3e3SBrad Bishop             if (pEvent->type !=
784f20a3e3SBrad Bishop                 details::Event::Type::DBUS_SIGNAL)
797b33777bSBrad Bishop             {
804f20a3e3SBrad Bishop                 continue;
817b33777bSBrad Bishop             }
824f20a3e3SBrad Bishop 
8368c80839SBrad Bishop             // Create a callback context for this event group.
8468c80839SBrad Bishop             auto dbusEvent = static_cast<details::DbusSignal*>(
8568c80839SBrad Bishop                                  pEvent.get());
8668c80839SBrad Bishop 
8768c80839SBrad Bishop             // Go ahead and store an iterator pointing at
8868c80839SBrad Bishop             // the event data to avoid lookups later since
8968c80839SBrad Bishop             // additional signal callbacks aren't added
9068c80839SBrad Bishop             // after the manager is constructed.
9149aefb31SBrad Bishop             _sigargs.emplace_back(
9249aefb31SBrad Bishop                 std::make_unique<SigArg>(
9349aefb31SBrad Bishop                     this,
9468c80839SBrad Bishop                     dbusEvent,
951ab880a1SBrad Bishop                     &group));
9668c80839SBrad Bishop 
9749aefb31SBrad Bishop             // Register our callback and the context for
9868c80839SBrad Bishop             // each signal event.
9949aefb31SBrad Bishop             _matches.emplace_back(
10049aefb31SBrad Bishop                 _bus,
101*48547a85SBrad Bishop                 dbusEvent->signature,
10249aefb31SBrad Bishop                 details::_signal,
1031ab880a1SBrad Bishop                 _sigargs.back().get());
10449aefb31SBrad Bishop         }
10568c80839SBrad Bishop     }
10649aefb31SBrad Bishop 
10749aefb31SBrad Bishop     _bus.request_name(busname);
10849aefb31SBrad Bishop }
10949aefb31SBrad Bishop 
11049aefb31SBrad Bishop void Manager::shutdown() noexcept
11149aefb31SBrad Bishop {
11249aefb31SBrad Bishop     _shutdown = true;
11349aefb31SBrad Bishop }
11449aefb31SBrad Bishop 
11549aefb31SBrad Bishop void Manager::run() noexcept
11649aefb31SBrad Bishop {
1177b33777bSBrad Bishop     while (!_shutdown)
1187b33777bSBrad Bishop     {
1197b33777bSBrad Bishop         try
1207b33777bSBrad Bishop         {
12149aefb31SBrad Bishop             _bus.process_discard();
12224424983SBrad Bishop             _bus.wait((5000000us).count());
12349aefb31SBrad Bishop         }
1247b33777bSBrad Bishop         catch (const std::exception& e)
1257b33777bSBrad Bishop         {
12649aefb31SBrad Bishop             std::cerr << e.what() << std::endl;
12749aefb31SBrad Bishop         }
12849aefb31SBrad Bishop     }
12949aefb31SBrad Bishop }
13049aefb31SBrad Bishop 
1319aa5e2f2SBrad Bishop void Manager::notify(sdbusplus::message::object_path path, Object object)
13249aefb31SBrad Bishop {
1337b33777bSBrad Bishop     try
1347b33777bSBrad Bishop     {
1359aa5e2f2SBrad Bishop 
13649aefb31SBrad Bishop         if (object.cbegin() == object.cend())
13749aefb31SBrad Bishop             throw std::runtime_error(
1389aa5e2f2SBrad Bishop                 "No interfaces in " + path.str);
13949aefb31SBrad Bishop 
1409aa5e2f2SBrad Bishop         path.str.insert(0, _root);
14149aefb31SBrad Bishop 
14249aefb31SBrad Bishop         auto obj = _refs.find(path);
14349aefb31SBrad Bishop         if (obj != _refs.end())
14449aefb31SBrad Bishop             throw std::runtime_error(
14549aefb31SBrad Bishop                 obj->first + " already exists");
14649aefb31SBrad Bishop 
14749aefb31SBrad Bishop         // Create an interface holder for each interface
14849aefb31SBrad Bishop         // provided by the client and group them into
14949aefb31SBrad Bishop         // a container.
15049aefb31SBrad Bishop         InterfaceComposite ref;
15149aefb31SBrad Bishop 
1526676c12dSBrad Bishop         auto i = object.size();
1537b33777bSBrad Bishop         for (auto& x : object)
1547b33777bSBrad Bishop         {
1556676c12dSBrad Bishop             // Defer sending any signals until the last interface.
1566676c12dSBrad Bishop             auto deferSignals = --i != 0;
1575fbaa7feSBrad Bishop             auto maker = _makers.find(x.first.c_str());
15849aefb31SBrad Bishop 
1595fbaa7feSBrad Bishop             if (maker == _makers.end())
16049aefb31SBrad Bishop                 throw std::runtime_error(
16149aefb31SBrad Bishop                     "Unimplemented interface: " + x.first);
16249aefb31SBrad Bishop 
1631ab880a1SBrad Bishop             ref.emplace(x.first,
1646676c12dSBrad Bishop                         (maker->second)(_bus, path.str.c_str(), deferSignals));
16549aefb31SBrad Bishop         }
16649aefb31SBrad Bishop 
1679d10fb21SBrad Bishop         if (!ref.empty())
1689d10fb21SBrad Bishop         {
16949aefb31SBrad Bishop             // Hang on to a reference to the object (interfaces)
17049aefb31SBrad Bishop             // so it stays on the bus, and so we can make calls
17149aefb31SBrad Bishop             // to it if needed.
17249aefb31SBrad Bishop             _refs.emplace(
1731ab880a1SBrad Bishop                 path, std::move(ref));
17449aefb31SBrad Bishop         }
1759d10fb21SBrad Bishop     }
1767b33777bSBrad Bishop     catch (const std::exception& e)
1777b33777bSBrad Bishop     {
17849aefb31SBrad Bishop         std::cerr << e.what() << std::endl;
17949aefb31SBrad Bishop     }
18049aefb31SBrad Bishop }
18149aefb31SBrad Bishop 
182*48547a85SBrad Bishop void Manager::handleEvent(
18368c80839SBrad Bishop     sdbusplus::message::message& msg,
184*48547a85SBrad Bishop     const details::Event& event,
18568c80839SBrad Bishop     const EventInfo& info)
18649aefb31SBrad Bishop {
18768c80839SBrad Bishop     auto& actions = std::get<1>(info);
1883d57f507SBrad Bishop 
189*48547a85SBrad Bishop     for (auto& f : event)
1907b33777bSBrad Bishop     {
19123719000SBrad Bishop         if (!(*f)(_bus, msg, *this))
192064c94a6SBrad Bishop         {
193064c94a6SBrad Bishop             return;
194064c94a6SBrad Bishop         }
195064c94a6SBrad Bishop     }
1969007432aSBrad Bishop     for (auto& action : actions)
1977b33777bSBrad Bishop     {
19823719000SBrad Bishop         (*action)(_bus, *this);
1993d57f507SBrad Bishop     }
20049aefb31SBrad Bishop }
20149aefb31SBrad Bishop 
2027b7e712cSBrad Bishop void Manager::destroyObjects(
2037b7e712cSBrad Bishop     const std::vector<const char*>& paths)
2047b7e712cSBrad Bishop {
2057b7e712cSBrad Bishop     for (const auto& path : paths)
206656a7d00SBrad Bishop     {
207656a7d00SBrad Bishop         std::string p{path};
208656a7d00SBrad Bishop         _refs.erase(_root + p);
209656a7d00SBrad Bishop     }
2107b7e712cSBrad Bishop }
211656a7d00SBrad Bishop 
212b83a21eaSBrad Bishop details::holder::Base& Manager::getInterfaceHolder(
213b83a21eaSBrad Bishop     const char* path, const char* interface)
214b83a21eaSBrad Bishop {
215b83a21eaSBrad Bishop     return const_cast<const Manager*>(
216b83a21eaSBrad Bishop                this)->getInterfaceHolder(path, interface);
217b83a21eaSBrad Bishop }
218b83a21eaSBrad Bishop 
219b83a21eaSBrad Bishop details::holder::Base& Manager::getInterfaceHolder(
220b83a21eaSBrad Bishop     const char* path, const char* interface) const
221b83a21eaSBrad Bishop {
222b83a21eaSBrad Bishop     std::string p{path};
223b83a21eaSBrad Bishop     auto oit = _refs.find(_root + p);
224b83a21eaSBrad Bishop     if (oit == _refs.end())
225b83a21eaSBrad Bishop         throw std::runtime_error(
226b83a21eaSBrad Bishop             _root + p + " was not found");
227b83a21eaSBrad Bishop 
228b83a21eaSBrad Bishop     auto& obj = oit->second;
229b83a21eaSBrad Bishop     auto iit = obj.find(interface);
230b83a21eaSBrad Bishop     if (iit == obj.end())
231b83a21eaSBrad Bishop         throw std::runtime_error(
232b83a21eaSBrad Bishop             "interface was not found");
233b83a21eaSBrad Bishop 
234b83a21eaSBrad Bishop     return *iit->second;
235b83a21eaSBrad Bishop }
236b83a21eaSBrad Bishop 
23749aefb31SBrad Bishop } // namespace manager
23849aefb31SBrad Bishop } // namespace inventory
23949aefb31SBrad Bishop } // namespace phosphor
24049aefb31SBrad Bishop 
24149aefb31SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
242