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);
4568c80839SBrad Bishop         mgr.signal(
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     {
7468c80839SBrad Bishop         for (auto pEvent : std::get<0>(group))
7568c80839SBrad Bishop         {
764f20a3e3SBrad Bishop             if (pEvent->type !=
774f20a3e3SBrad Bishop                 details::Event::Type::DBUS_SIGNAL)
787b33777bSBrad Bishop             {
794f20a3e3SBrad Bishop                 continue;
807b33777bSBrad Bishop             }
814f20a3e3SBrad Bishop 
8268c80839SBrad Bishop             // Create a callback context for this event group.
8368c80839SBrad Bishop             auto dbusEvent = static_cast<details::DbusSignal*>(
8468c80839SBrad Bishop                                  pEvent.get());
8568c80839SBrad Bishop 
8668c80839SBrad Bishop             // Go ahead and store an iterator pointing at
8768c80839SBrad Bishop             // the event data to avoid lookups later since
8868c80839SBrad Bishop             // additional signal callbacks aren't added
8968c80839SBrad Bishop             // after the manager is constructed.
9049aefb31SBrad Bishop             _sigargs.emplace_back(
9149aefb31SBrad Bishop                 std::make_unique<SigArg>(
9249aefb31SBrad Bishop                     this,
9368c80839SBrad Bishop                     dbusEvent,
941ab880a1SBrad Bishop                     &group));
9568c80839SBrad Bishop 
9649aefb31SBrad Bishop             // Register our callback and the context for
9768c80839SBrad Bishop             // each signal event.
9849aefb31SBrad Bishop             _matches.emplace_back(
9949aefb31SBrad Bishop                 _bus,
10068c80839SBrad Bishop                 std::get<0>(*dbusEvent),
10149aefb31SBrad Bishop                 details::_signal,
1021ab880a1SBrad Bishop                 _sigargs.back().get());
10349aefb31SBrad Bishop         }
10468c80839SBrad Bishop     }
10549aefb31SBrad Bishop 
10649aefb31SBrad Bishop     _bus.request_name(busname);
10749aefb31SBrad Bishop }
10849aefb31SBrad Bishop 
10949aefb31SBrad Bishop void Manager::shutdown() noexcept
11049aefb31SBrad Bishop {
11149aefb31SBrad Bishop     _shutdown = true;
11249aefb31SBrad Bishop }
11349aefb31SBrad Bishop 
11449aefb31SBrad Bishop void Manager::run() noexcept
11549aefb31SBrad Bishop {
1167b33777bSBrad Bishop     while (!_shutdown)
1177b33777bSBrad Bishop     {
1187b33777bSBrad Bishop         try
1197b33777bSBrad Bishop         {
12049aefb31SBrad Bishop             _bus.process_discard();
12124424983SBrad Bishop             _bus.wait((5000000us).count());
12249aefb31SBrad Bishop         }
1237b33777bSBrad Bishop         catch (const std::exception& e)
1247b33777bSBrad Bishop         {
12549aefb31SBrad Bishop             std::cerr << e.what() << std::endl;
12649aefb31SBrad Bishop         }
12749aefb31SBrad Bishop     }
12849aefb31SBrad Bishop }
12949aefb31SBrad Bishop 
1309aa5e2f2SBrad Bishop void Manager::notify(sdbusplus::message::object_path path, Object object)
13149aefb31SBrad Bishop {
1327b33777bSBrad Bishop     try
1337b33777bSBrad Bishop     {
1349aa5e2f2SBrad Bishop 
13549aefb31SBrad Bishop         if (object.cbegin() == object.cend())
13649aefb31SBrad Bishop             throw std::runtime_error(
1379aa5e2f2SBrad Bishop                 "No interfaces in " + path.str);
13849aefb31SBrad Bishop 
1399aa5e2f2SBrad Bishop         path.str.insert(0, _root);
14049aefb31SBrad Bishop 
14149aefb31SBrad Bishop         auto obj = _refs.find(path);
14249aefb31SBrad Bishop         if (obj != _refs.end())
14349aefb31SBrad Bishop             throw std::runtime_error(
14449aefb31SBrad Bishop                 obj->first + " already exists");
14549aefb31SBrad Bishop 
14649aefb31SBrad Bishop         // Create an interface holder for each interface
14749aefb31SBrad Bishop         // provided by the client and group them into
14849aefb31SBrad Bishop         // a container.
14949aefb31SBrad Bishop         InterfaceComposite ref;
15049aefb31SBrad Bishop 
1516676c12dSBrad Bishop         auto i = object.size();
1527b33777bSBrad Bishop         for (auto& x : object)
1537b33777bSBrad Bishop         {
1546676c12dSBrad Bishop             // Defer sending any signals until the last interface.
1556676c12dSBrad Bishop             auto deferSignals = --i != 0;
1565fbaa7feSBrad Bishop             auto maker = _makers.find(x.first.c_str());
15749aefb31SBrad Bishop 
1585fbaa7feSBrad Bishop             if (maker == _makers.end())
15949aefb31SBrad Bishop                 throw std::runtime_error(
16049aefb31SBrad Bishop                     "Unimplemented interface: " + x.first);
16149aefb31SBrad Bishop 
1621ab880a1SBrad Bishop             ref.emplace(x.first,
1636676c12dSBrad Bishop                         (maker->second)(_bus, path.str.c_str(), deferSignals));
16449aefb31SBrad Bishop         }
16549aefb31SBrad Bishop 
1669d10fb21SBrad Bishop         if (!ref.empty())
1679d10fb21SBrad Bishop         {
16849aefb31SBrad Bishop             // Hang on to a reference to the object (interfaces)
16949aefb31SBrad Bishop             // so it stays on the bus, and so we can make calls
17049aefb31SBrad Bishop             // to it if needed.
17149aefb31SBrad Bishop             _refs.emplace(
1721ab880a1SBrad Bishop                 path, std::move(ref));
17349aefb31SBrad Bishop         }
1749d10fb21SBrad Bishop     }
1757b33777bSBrad Bishop     catch (const std::exception& e)
1767b33777bSBrad Bishop     {
17749aefb31SBrad Bishop         std::cerr << e.what() << std::endl;
17849aefb31SBrad Bishop     }
17949aefb31SBrad Bishop }
18049aefb31SBrad Bishop 
18168c80839SBrad Bishop void Manager::signal(
18268c80839SBrad Bishop     sdbusplus::message::message& msg,
18368c80839SBrad Bishop     const details::DbusSignal& event,
18468c80839SBrad Bishop     const EventInfo& info)
18549aefb31SBrad Bishop {
186*064c94a6SBrad Bishop     auto& filters = std::get<1>(event);
18768c80839SBrad Bishop     auto& actions = std::get<1>(info);
1883d57f507SBrad Bishop 
189*064c94a6SBrad Bishop     for (auto& f : filters)
1907b33777bSBrad Bishop     {
191*064c94a6SBrad Bishop         if (!(*f)(msg, *this))
192*064c94a6SBrad Bishop         {
193*064c94a6SBrad Bishop             return;
194*064c94a6SBrad Bishop         }
195*064c94a6SBrad Bishop     }
1969007432aSBrad Bishop     for (auto& action : actions)
1977b33777bSBrad Bishop     {
1989007432aSBrad Bishop         (*action)(*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