1 /** 2 * Copyright © 2016 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include <iostream> 17 #include <exception> 18 #include "manager.hpp" 19 20 namespace phosphor 21 { 22 namespace inventory 23 { 24 namespace manager 25 { 26 namespace details 27 { 28 29 /** @brief Fowrarding signal callback. 30 * 31 * Extracts per-signal specific context and forwards the call to the manager 32 * instance. 33 */ 34 auto _signal(sd_bus_message *m, void *data, sd_bus_error *e) noexcept 35 { 36 try { 37 auto msg = sdbusplus::message::message(m); 38 auto &args = *static_cast<Manager::SigArg*>(data); 39 sd_bus_message_ref(m); 40 auto &mgr = *std::get<0>(args); 41 mgr.signal( 42 msg, 43 static_cast<const details::DbusSignal &>( 44 *std::get<1>(args)), 45 *std::get<2>(args)); 46 } 47 catch (const std::exception &e) { 48 std::cerr << e.what() << std::endl; 49 } 50 51 return 0; 52 } 53 54 } // namespace details 55 56 Manager::Manager( 57 sdbusplus::bus::bus &&bus, 58 const char *busname, 59 const char *root, 60 const char *iface) : 61 details::ServerObject<details::ManagerIface>(bus, root), 62 _shutdown(false), 63 _root(root), 64 _bus(std::move(bus)), 65 _manager(sdbusplus::server::manager::manager(_bus, root)) 66 { 67 for (auto &group: _events) 68 { 69 for (auto pEvent: std::get<0>(group)) 70 { 71 if (pEvent->type != 72 details::Event::Type::DBUS_SIGNAL) 73 continue; 74 75 // Create a callback context for this event group. 76 auto dbusEvent = static_cast<details::DbusSignal *>( 77 pEvent.get()); 78 79 // Go ahead and store an iterator pointing at 80 // the event data to avoid lookups later since 81 // additional signal callbacks aren't added 82 // after the manager is constructed. 83 _sigargs.emplace_back( 84 std::make_unique<SigArg>( 85 this, 86 dbusEvent, 87 &group)); 88 89 // Register our callback and the context for 90 // each signal event. 91 _matches.emplace_back( 92 _bus, 93 std::get<0>(*dbusEvent), 94 details::_signal, 95 _sigargs.back().get()); 96 } 97 } 98 99 _bus.request_name(busname); 100 } 101 102 void Manager::shutdown() noexcept 103 { 104 _shutdown = true; 105 } 106 107 void Manager::run() noexcept 108 { 109 while(!_shutdown) { 110 try { 111 _bus.process_discard(); 112 _bus.wait(5000000); 113 } 114 catch (const std::exception &e) { 115 std::cerr << e.what() << std::endl; 116 } 117 } 118 } 119 120 void Manager::notify(std::string path, Object object) 121 { 122 try { 123 if(object.cbegin() == object.cend()) 124 throw std::runtime_error( 125 "No interfaces in " + path); 126 127 path.insert(0, _root); 128 129 auto obj = _refs.find(path); 130 if(obj != _refs.end()) 131 throw std::runtime_error( 132 obj->first + " already exists"); 133 134 // Create an interface holder for each interface 135 // provided by the client and group them into 136 // a container. 137 InterfaceComposite ref; 138 139 for (auto &x: object) { 140 auto maker = _makers.find(x.first.c_str()); 141 142 if(maker == _makers.end()) 143 throw std::runtime_error( 144 "Unimplemented interface: " + x.first); 145 146 ref.emplace(x.first, 147 (maker->second)(_bus, path.c_str())); 148 } 149 150 // Hang on to a reference to the object (interfaces) 151 // so it stays on the bus, and so we can make calls 152 // to it if needed. 153 _refs.emplace( 154 path, std::move(ref)); 155 } 156 catch (const std::exception &e) { 157 std::cerr << e.what() << std::endl; 158 } 159 } 160 161 void Manager::signal( 162 sdbusplus::message::message &msg, 163 const details::DbusSignal &event, 164 const EventInfo &info) 165 { 166 auto &filter = *std::get<1>(event); 167 auto &actions = std::get<1>(info); 168 169 if(filter(msg, *this)) { 170 for (auto &action: actions) 171 (*action)(*this); 172 } 173 } 174 175 void Manager::destroyObject(const char *path) 176 { 177 std::string p{path}; 178 _refs.erase(_root + p); 179 } 180 181 details::holder::Base& Manager::getInterfaceHolder( 182 const char *path, const char *interface) 183 { 184 return const_cast<const Manager *>( 185 this)->getInterfaceHolder(path, interface); 186 } 187 188 details::holder::Base& Manager::getInterfaceHolder( 189 const char *path, const char *interface) const 190 { 191 std::string p{path}; 192 auto oit = _refs.find(_root + p); 193 if(oit == _refs.end()) 194 throw std::runtime_error( 195 _root + p + " was not found"); 196 197 auto &obj = oit->second; 198 auto iit = obj.find(interface); 199 if(iit == obj.end()) 200 throw std::runtime_error( 201 "interface was not found"); 202 203 return *iit->second; 204 } 205 206 } // namespace manager 207 } // namespace inventory 208 } // namespace phosphor 209 210 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 211