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>
1979ccaf77SBrad Bishop #include <algorithm>
20101d837cSSaqib Khan #include <phosphor-logging/log.hpp>
2149aefb31SBrad Bishop #include "manager.hpp"
2279ccaf77SBrad Bishop #include "errors.hpp"
2349aefb31SBrad Bishop 
2424424983SBrad Bishop using namespace std::literals::chrono_literals;
2524424983SBrad Bishop 
2649aefb31SBrad Bishop namespace phosphor
2749aefb31SBrad Bishop {
2849aefb31SBrad Bishop namespace inventory
2949aefb31SBrad Bishop {
3049aefb31SBrad Bishop namespace manager
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);
4548547a85SBrad Bishop         mgr.handleEvent(
4668c80839SBrad Bishop             msg,
4712f8a3c8SBrad Bishop             static_cast<const 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 Manager::Manager(
6049aefb31SBrad Bishop     sdbusplus::bus::bus&& bus,
6149aefb31SBrad Bishop     const char* busname,
6249aefb31SBrad Bishop     const char* root,
6349aefb31SBrad Bishop     const char* iface) :
6412f8a3c8SBrad Bishop     ServerObject<ManagerIface>(bus, root),
6549aefb31SBrad Bishop     _shutdown(false),
6649aefb31SBrad Bishop     _root(root),
6749aefb31SBrad Bishop     _bus(std::move(bus)),
689b86483fSBrad Bishop     _manager(_bus, root)
6949aefb31SBrad Bishop {
7068c80839SBrad Bishop     for (auto& group : _events)
7168c80839SBrad Bishop     {
7212f8a3c8SBrad Bishop         for (auto pEvent : std::get<std::vector<EventBasePtr>>(
7348547a85SBrad Bishop                  group))
7468c80839SBrad Bishop         {
754f20a3e3SBrad Bishop             if (pEvent->type !=
7612f8a3c8SBrad Bishop                 Event::Type::DBUS_SIGNAL)
777b33777bSBrad Bishop             {
784f20a3e3SBrad Bishop                 continue;
797b33777bSBrad Bishop             }
804f20a3e3SBrad Bishop 
8168c80839SBrad Bishop             // Create a callback context for this event group.
8212f8a3c8SBrad Bishop             auto dbusEvent = static_cast<DbusSignal*>(
8368c80839SBrad Bishop                                  pEvent.get());
8468c80839SBrad Bishop 
8568c80839SBrad Bishop             // Go ahead and store an iterator pointing at
8668c80839SBrad Bishop             // the event data to avoid lookups later since
8768c80839SBrad Bishop             // additional signal callbacks aren't added
8868c80839SBrad Bishop             // after the manager is constructed.
8949aefb31SBrad Bishop             _sigargs.emplace_back(
9049aefb31SBrad Bishop                 std::make_unique<SigArg>(
9149aefb31SBrad Bishop                     this,
9268c80839SBrad Bishop                     dbusEvent,
931ab880a1SBrad Bishop                     &group));
9468c80839SBrad Bishop 
9549aefb31SBrad Bishop             // Register our callback and the context for
9668c80839SBrad Bishop             // each signal event.
9749aefb31SBrad Bishop             _matches.emplace_back(
9849aefb31SBrad Bishop                 _bus,
9948547a85SBrad Bishop                 dbusEvent->signature,
10012f8a3c8SBrad Bishop                 _signal,
1011ab880a1SBrad Bishop                 _sigargs.back().get());
10249aefb31SBrad Bishop         }
10368c80839SBrad Bishop     }
10449aefb31SBrad Bishop 
10549aefb31SBrad Bishop     _bus.request_name(busname);
10649aefb31SBrad Bishop }
10749aefb31SBrad Bishop 
10849aefb31SBrad Bishop void Manager::shutdown() noexcept
10949aefb31SBrad Bishop {
11049aefb31SBrad Bishop     _shutdown = true;
11149aefb31SBrad Bishop }
11249aefb31SBrad Bishop 
11349aefb31SBrad Bishop void Manager::run() noexcept
11449aefb31SBrad Bishop {
1153e4a19a3SBrad Bishop     sdbusplus::message::message unusedMsg{nullptr};
1163e4a19a3SBrad Bishop 
1173e4a19a3SBrad Bishop     // Run startup events.
1183e4a19a3SBrad Bishop     for (auto& group : _events)
1193e4a19a3SBrad Bishop     {
12012f8a3c8SBrad Bishop         for (auto pEvent : std::get<std::vector<EventBasePtr>>(
1213e4a19a3SBrad Bishop                  group))
1223e4a19a3SBrad Bishop         {
1233e4a19a3SBrad Bishop             if (pEvent->type ==
12412f8a3c8SBrad Bishop                 Event::Type::STARTUP)
1253e4a19a3SBrad Bishop             {
1263e4a19a3SBrad Bishop                 handleEvent(unusedMsg, *pEvent, group);
1273e4a19a3SBrad Bishop             }
1283e4a19a3SBrad Bishop         }
1293e4a19a3SBrad Bishop     }
1303e4a19a3SBrad Bishop 
1317b33777bSBrad Bishop     while (!_shutdown)
1327b33777bSBrad Bishop     {
1337b33777bSBrad Bishop         try
1347b33777bSBrad Bishop         {
13549aefb31SBrad Bishop             _bus.process_discard();
13624424983SBrad Bishop             _bus.wait((5000000us).count());
13749aefb31SBrad Bishop         }
1387b33777bSBrad Bishop         catch (const std::exception& e)
1397b33777bSBrad Bishop         {
14049aefb31SBrad Bishop             std::cerr << e.what() << std::endl;
14149aefb31SBrad Bishop         }
14249aefb31SBrad Bishop     }
14349aefb31SBrad Bishop }
14449aefb31SBrad Bishop 
14579ccaf77SBrad Bishop void Manager::updateInterfaces(
14679ccaf77SBrad Bishop     const sdbusplus::message::object_path& path,
14779ccaf77SBrad Bishop     const Object& interfaces,
14879ccaf77SBrad Bishop     ObjectReferences::iterator pos,
14979ccaf77SBrad Bishop     bool newObject)
15079ccaf77SBrad Bishop {
15179ccaf77SBrad Bishop     auto& refaces = pos->second;
15279ccaf77SBrad Bishop     auto ifaceit = interfaces.cbegin();
15379ccaf77SBrad Bishop     auto opsit = _makers.cbegin();
15479ccaf77SBrad Bishop     auto refaceit = refaces.begin();
15579ccaf77SBrad Bishop     std::vector<std::string> signals;
15679ccaf77SBrad Bishop 
15779ccaf77SBrad Bishop     while (ifaceit != interfaces.cend())
15879ccaf77SBrad Bishop     {
15979ccaf77SBrad Bishop         try
16079ccaf77SBrad Bishop         {
16179ccaf77SBrad Bishop             // Find the binding ops for this interface.
16279ccaf77SBrad Bishop             opsit = std::lower_bound(
16379ccaf77SBrad Bishop                         opsit,
16479ccaf77SBrad Bishop                         _makers.cend(),
16579ccaf77SBrad Bishop                         ifaceit->first,
16679ccaf77SBrad Bishop                         compareFirst(_makers.key_comp()));
16779ccaf77SBrad Bishop 
16879ccaf77SBrad Bishop             if (opsit == _makers.cend() || opsit->first != ifaceit->first)
16979ccaf77SBrad Bishop             {
17079ccaf77SBrad Bishop                 // This interface is not supported.
17179ccaf77SBrad Bishop                 throw InterfaceError(
17279ccaf77SBrad Bishop                     "Encountered unsupported interface.",
17379ccaf77SBrad Bishop                     ifaceit->first);
17479ccaf77SBrad Bishop             }
17579ccaf77SBrad Bishop 
17679ccaf77SBrad Bishop             // Find the binding insertion point or the binding to update.
17779ccaf77SBrad Bishop             refaceit = std::lower_bound(
17879ccaf77SBrad Bishop                            refaceit,
17979ccaf77SBrad Bishop                            refaces.end(),
18079ccaf77SBrad Bishop                            ifaceit->first,
18179ccaf77SBrad Bishop                            compareFirst(refaces.key_comp()));
18279ccaf77SBrad Bishop 
18379ccaf77SBrad Bishop             if (refaceit == refaces.end() || refaceit->first != ifaceit->first)
18479ccaf77SBrad Bishop             {
18579ccaf77SBrad Bishop                 // Add the new interface.
18679ccaf77SBrad Bishop                 auto& ctor = std::get<MakerType>(opsit->second);
18779ccaf77SBrad Bishop                 refaceit = refaces.insert(
18879ccaf77SBrad Bishop                                refaceit,
18979ccaf77SBrad Bishop                                std::make_pair(
19079ccaf77SBrad Bishop                                    ifaceit->first,
19179ccaf77SBrad Bishop                                    ctor(
19279ccaf77SBrad Bishop                                        _bus,
19379ccaf77SBrad Bishop                                        path.str.c_str(),
19479ccaf77SBrad Bishop                                        ifaceit->second)));
19579ccaf77SBrad Bishop                 signals.push_back(ifaceit->first);
19679ccaf77SBrad Bishop             }
19779ccaf77SBrad Bishop             else
19879ccaf77SBrad Bishop             {
19979ccaf77SBrad Bishop                 // Set the new property values.
20079ccaf77SBrad Bishop                 auto& assign = std::get<AssignerType>(opsit->second);
20179ccaf77SBrad Bishop                 assign(ifaceit->second, refaceit->second);
20279ccaf77SBrad Bishop             }
20379ccaf77SBrad Bishop         }
20479ccaf77SBrad Bishop         catch (const InterfaceError& e)
20579ccaf77SBrad Bishop         {
20679ccaf77SBrad Bishop             // Reset the binding ops iterator since we are
20779ccaf77SBrad Bishop             // at the end.
20879ccaf77SBrad Bishop             opsit = _makers.cbegin();
20979ccaf77SBrad Bishop             e.log();
21079ccaf77SBrad Bishop         }
21179ccaf77SBrad Bishop 
21279ccaf77SBrad Bishop         ++ifaceit;
21379ccaf77SBrad Bishop     }
21479ccaf77SBrad Bishop 
21579ccaf77SBrad Bishop     if (newObject)
21679ccaf77SBrad Bishop     {
21779ccaf77SBrad Bishop         _bus.emit_object_added(path.str.c_str());
21879ccaf77SBrad Bishop     }
21979ccaf77SBrad Bishop     else if (!signals.empty())
22079ccaf77SBrad Bishop     {
221*a8ff8154SGunnar Mills         _bus.emit_interfaces_added(path.str.c_str(), signals);
22279ccaf77SBrad Bishop     }
22379ccaf77SBrad Bishop }
22479ccaf77SBrad Bishop 
22579ccaf77SBrad Bishop void Manager::updateObjects(
22679ccaf77SBrad Bishop     const std::map<sdbusplus::message::object_path, Object>& objs)
22779ccaf77SBrad Bishop {
22879ccaf77SBrad Bishop     auto objit = objs.cbegin();
22979ccaf77SBrad Bishop     auto refit = _refs.begin();
23079ccaf77SBrad Bishop     std::string absPath;
23179ccaf77SBrad Bishop     bool newObj;
23279ccaf77SBrad Bishop 
23379ccaf77SBrad Bishop     while (objit != objs.cend())
23479ccaf77SBrad Bishop     {
23579ccaf77SBrad Bishop         // Find the insertion point or the object to update.
23679ccaf77SBrad Bishop         refit = std::lower_bound(
23779ccaf77SBrad Bishop                     refit,
23879ccaf77SBrad Bishop                     _refs.end(),
23979ccaf77SBrad Bishop                     objit->first,
24079ccaf77SBrad Bishop                     compareFirst(RelPathCompare(_root)));
24179ccaf77SBrad Bishop 
24279ccaf77SBrad Bishop         absPath.assign(_root);
24379ccaf77SBrad Bishop         absPath.append(objit->first);
24479ccaf77SBrad Bishop 
24579ccaf77SBrad Bishop         newObj = false;
24679ccaf77SBrad Bishop         if (refit == _refs.end() || refit->first != absPath)
24779ccaf77SBrad Bishop         {
24879ccaf77SBrad Bishop             refit = _refs.insert(
24979ccaf77SBrad Bishop                         refit,
25079ccaf77SBrad Bishop                         std::make_pair(
25179ccaf77SBrad Bishop                             absPath,
25279ccaf77SBrad Bishop                             decltype(_refs)::mapped_type()));
25379ccaf77SBrad Bishop             newObj = true;
25479ccaf77SBrad Bishop         }
25579ccaf77SBrad Bishop 
25679ccaf77SBrad Bishop         updateInterfaces(absPath, objit->second, refit, newObj);
25779ccaf77SBrad Bishop         ++objit;
25879ccaf77SBrad Bishop     }
25979ccaf77SBrad Bishop }
26079ccaf77SBrad Bishop 
26103f4cd95SBrad Bishop void Manager::notify(std::map<sdbusplus::message::object_path, Object> objs)
26249aefb31SBrad Bishop {
263cda036f7SBrad Bishop     updateObjects(objs);
26449aefb31SBrad Bishop }
26549aefb31SBrad Bishop 
26648547a85SBrad Bishop void Manager::handleEvent(
26768c80839SBrad Bishop     sdbusplus::message::message& msg,
26812f8a3c8SBrad Bishop     const Event& event,
26968c80839SBrad Bishop     const EventInfo& info)
27049aefb31SBrad Bishop {
27168c80839SBrad Bishop     auto& actions = std::get<1>(info);
2723d57f507SBrad Bishop 
27348547a85SBrad Bishop     for (auto& f : event)
2747b33777bSBrad Bishop     {
27507934a64SBrad Bishop         if (!f(_bus, msg, *this))
276064c94a6SBrad Bishop         {
277064c94a6SBrad Bishop             return;
278064c94a6SBrad Bishop         }
279064c94a6SBrad Bishop     }
2809007432aSBrad Bishop     for (auto& action : actions)
2817b33777bSBrad Bishop     {
28207934a64SBrad Bishop         action(_bus, *this);
2833d57f507SBrad Bishop     }
28449aefb31SBrad Bishop }
28549aefb31SBrad Bishop 
2867b7e712cSBrad Bishop void Manager::destroyObjects(
2877b7e712cSBrad Bishop     const std::vector<const char*>& paths)
2887b7e712cSBrad Bishop {
289a5cc34c2SBrad Bishop     std::string p;
290a5cc34c2SBrad Bishop 
2917b7e712cSBrad Bishop     for (const auto& path : paths)
292656a7d00SBrad Bishop     {
293a5cc34c2SBrad Bishop         p.assign(_root);
294a5cc34c2SBrad Bishop         p.append(path);
295a5cc34c2SBrad Bishop         _bus.emit_object_removed(p.c_str());
296a5cc34c2SBrad Bishop         _refs.erase(p);
297656a7d00SBrad Bishop     }
2987b7e712cSBrad Bishop }
299656a7d00SBrad Bishop 
300eb68a687SBrad Bishop void Manager::createObjects(
301eb68a687SBrad Bishop     const std::map<sdbusplus::message::object_path, Object>& objs)
302eb68a687SBrad Bishop {
303cda036f7SBrad Bishop     updateObjects(objs);
304eb68a687SBrad Bishop }
305eb68a687SBrad Bishop 
306150147aeSBrad Bishop any_ns::any& Manager::getInterfaceHolder(
307b83a21eaSBrad Bishop     const char* path, const char* interface)
308b83a21eaSBrad Bishop {
309150147aeSBrad Bishop     return const_cast<any_ns::any&>(
310150147aeSBrad Bishop                const_cast<const Manager*>(
311150147aeSBrad Bishop                    this)->getInterfaceHolder(path, interface));
312b83a21eaSBrad Bishop }
313b83a21eaSBrad Bishop 
314150147aeSBrad Bishop const any_ns::any& Manager::getInterfaceHolder(
315b83a21eaSBrad Bishop     const char* path, const char* interface) const
316b83a21eaSBrad Bishop {
317b83a21eaSBrad Bishop     std::string p{path};
318b83a21eaSBrad Bishop     auto oit = _refs.find(_root + p);
319b83a21eaSBrad Bishop     if (oit == _refs.end())
320b83a21eaSBrad Bishop         throw std::runtime_error(
321b83a21eaSBrad Bishop             _root + p + " was not found");
322b83a21eaSBrad Bishop 
323b83a21eaSBrad Bishop     auto& obj = oit->second;
324b83a21eaSBrad Bishop     auto iit = obj.find(interface);
325b83a21eaSBrad Bishop     if (iit == obj.end())
326b83a21eaSBrad Bishop         throw std::runtime_error(
327b83a21eaSBrad Bishop             "interface was not found");
328b83a21eaSBrad Bishop 
329150147aeSBrad Bishop     return iit->second;
330b83a21eaSBrad Bishop }
331b83a21eaSBrad Bishop 
33249aefb31SBrad Bishop } // namespace manager
33349aefb31SBrad Bishop } // namespace inventory
33449aefb31SBrad Bishop } // namespace phosphor
33549aefb31SBrad Bishop 
33649aefb31SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
337