1 #pragma once
2
3 #ifndef BOOST_COROUTINES_NO_DEPRECATION_WARNING
4 // users should define this if they directly include boost/asio/spawn.hpp,
5 // but by defining it here, warnings won't cause problems with a compile
6 #define BOOST_COROUTINES_NO_DEPRECATION_WARNING
7 #endif
8
9 #ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
10 #include <boost/asio/spawn.hpp>
11 #endif
12 #include <sdbusplus/asio/connection.hpp>
13 #include <sdbusplus/exception.hpp>
14 #include <sdbusplus/message/read.hpp>
15 #include <sdbusplus/message/types.hpp>
16 #include <sdbusplus/server.hpp>
17 #include <sdbusplus/utility/tuple_to_array.hpp>
18 #include <sdbusplus/utility/type_traits.hpp>
19
20 #include <any>
21 #include <functional>
22 #include <optional>
23 #include <utility>
24 #include <vector>
25
26 namespace sdbusplus
27 {
28 namespace asio
29 {
30
31 enum class SetPropertyReturnValue
32 {
33 fail = 0,
34 valueUpdated,
35 sameValueUpdated,
36 };
37
38 class dbus_interface;
39
40 class property_callback
41 {
42 public:
property_callback(dbus_interface & parent,const std::string & name,std::function<int (message_t &)> && on_get,std::function<SetPropertyReturnValue (message_t &)> && on_set_message,std::function<SetPropertyReturnValue (const std::any &)> && on_set_value,const char * signature,decltype(vtable_t::flags)flags)43 property_callback(
44 dbus_interface& parent, const std::string& name,
45 std::function<int(message_t&)>&& on_get,
46 std::function<SetPropertyReturnValue(message_t&)>&& on_set_message,
47 std::function<SetPropertyReturnValue(const std::any&)>&& on_set_value,
48 const char* signature, decltype(vtable_t::flags) flags) :
49 interface_(parent), name_(name), on_get_(std::move(on_get)),
50 on_set_message_(std::move(on_set_message)),
51 on_set_value_(std::move(on_set_value)), signature_(signature),
52 flags_(flags)
53 {}
54 dbus_interface& interface_;
55 std::string name_;
56 std::function<int(message_t&)> on_get_;
57 std::function<SetPropertyReturnValue(message_t&)> on_set_message_;
58 std::function<SetPropertyReturnValue(const std::any&)> on_set_value_;
59 const char* signature_;
60 decltype(vtable_t::flags) flags_;
61 };
62
63 class method_callback
64 {
65 public:
method_callback(const std::string & name,std::function<int (message_t &)> && call,const char * arg_signature,const char * return_signature,decltype(vtable_t::flags)flags)66 method_callback(const std::string& name,
67 std::function<int(message_t&)>&& call,
68 const char* arg_signature, const char* return_signature,
69 decltype(vtable_t::flags) flags) :
70 name_(name), call_(std::move(call)), arg_signature_(arg_signature),
71 return_signature_(return_signature), flags_(flags)
72 {}
73 std::string name_;
74 std::function<int(message_t&)> call_;
75 const char* arg_signature_;
76 const char* return_signature_;
77 decltype(vtable_t::flags) flags_;
78 };
79
80 class signal
81 {
82 public:
signal(const std::string & name,const char * signature)83 signal(const std::string& name, const char* signature) :
84 name_(name), signature_(signature)
85 {}
86
87 std::string name_;
88 const char* signature_;
89 };
90
91 #ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
92 template <typename T>
93 inline const bool FirstArgIsYield_v =
94 std::is_same_v<utility::get_first_arg_t<utility::decay_tuple_t<
95 boost::callable_traits::args_t<T>>>,
96 boost::asio::yield_context>;
97
98 #else
99 template <typename T>
100 inline const bool FirstArgIsYield_v = false;
101 #endif
102
103 template <typename T>
104 inline const bool FirstArgIsMessage_v =
105 std::is_same_v<utility::get_first_arg_t<utility::decay_tuple_t<
106 boost::callable_traits::args_t<T>>>,
107 message_t>;
108
109 template <typename T>
110 inline const bool SecondArgIsMessage_v = std::is_same_v<
111 utility::get_first_arg_t<utility::strip_first_arg_t<
112 utility::decay_tuple_t<boost::callable_traits::args_t<T>>>>,
113 message_t>;
114
115 template <typename T>
116 static constexpr bool callbackWantsMessage =
117 FirstArgIsMessage_v<T> || SecondArgIsMessage_v<T>;
118
119 namespace details
120 {
121 // small helper class to count the number of non-dbus arguments
122 // to a registered dbus function (like message_t or yield_context)
123 // so the registered signature can omit them
124 template <typename FirstArg, typename... Rest>
125 struct NonDbusArgsCount;
126
127 template <>
128 struct NonDbusArgsCount<std::tuple<>>
129 {
130 constexpr static std::size_t size()
131 {
132 return 0;
133 }
134 };
135 template <typename FirstArg, typename... OtherArgs>
136 struct NonDbusArgsCount<std::tuple<FirstArg, OtherArgs...>>
137 {
sizesdbusplus::asio::details::NonDbusArgsCount138 constexpr static std::size_t size()
139 {
140 #ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
141 if constexpr (std::is_same_v<FirstArg, message_t> ||
142 std::is_same_v<FirstArg, boost::asio::yield_context>)
143 {
144 return 1 + NonDbusArgsCount<std::tuple<OtherArgs...>>::size();
145 }
146 else
147 #endif
148 {
149 return NonDbusArgsCount<std::tuple<OtherArgs...>>::size();
150 }
151 }
152 };
153
154 template <typename PropertyType>
nop_get_value(const PropertyType & value)155 PropertyType nop_get_value(const PropertyType& value)
156 {
157 return value;
158 }
159
160 template <typename PropertyType>
nop_set_value(const PropertyType & req,PropertyType & old)161 bool nop_set_value(const PropertyType& req, PropertyType& old)
162 {
163 old = req;
164 return true;
165 }
166
167 } // namespace details
168
169 template <typename InputArgs, typename Callback>
callFunction(message_t & m,InputArgs & inputArgs,Callback && callback)170 void callFunction(message_t& m, InputArgs& inputArgs, Callback&& callback)
171 {
172 using ResultType = boost::callable_traits::return_type_t<Callback>;
173 if constexpr (std::is_void_v<ResultType>)
174 {
175 std::apply(callback, inputArgs);
176 }
177 else
178 {
179 auto r = std::apply(callback, inputArgs);
180 m.append(r);
181 }
182 }
183
184 template <typename CallbackType>
185 class callback_method_instance
186 {
187 private:
188 using CallbackSignature = boost::callable_traits::args_t<CallbackType>;
189 using InputTupleType = utility::decay_tuple_t<CallbackSignature>;
190
191 CallbackType func_;
192
193 public:
callback_method_instance(CallbackType && func)194 callback_method_instance(CallbackType&& func) : func_(func) {}
195
operator ()(message_t & m)196 int operator()(message_t& m)
197 {
198 using DbusTupleType = utility::strip_first_n_args_t<
199 details::NonDbusArgsCount<InputTupleType>::size(), InputTupleType>;
200
201 DbusTupleType dbusArgs;
202 if (!utility::read_into_tuple(dbusArgs, m))
203 {
204 return -EINVAL;
205 }
206 auto ret = m.new_method_return();
207 if constexpr (callbackWantsMessage<CallbackType>)
208 {
209 InputTupleType inputArgs =
210 std::tuple_cat(std::forward_as_tuple(std::move(m)), dbusArgs);
211 callFunction(ret, inputArgs, func_);
212 }
213 else
214 {
215 callFunction(ret, dbusArgs, func_);
216 }
217 ret.method_return();
218 return 1;
219 }
220 };
221
222 #ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
223 template <typename CallbackType>
224 class coroutine_method_instance
225 {
226 public:
227 using self_t = coroutine_method_instance<CallbackType>;
coroutine_method_instance(boost::asio::io_context & io,CallbackType && func)228 coroutine_method_instance(boost::asio::io_context& io,
229 CallbackType&& func) : io_(io), func_(func)
230 {}
231
operator ()(message_t & m)232 int operator()(message_t& m)
233 {
234 // make a copy of m to move into the coroutine
235 message_t b{m};
236
237 // spawn off a new coroutine to handle the method call
238 boost::asio::spawn(io_, std::bind_front(&self_t::after_spawn, this, b));
239 return 1;
240 }
241
242 private:
243 boost::asio::io_context& io_;
244 CallbackType func_;
after_spawn(message_t b,boost::asio::yield_context yield)245 void after_spawn(message_t b, boost::asio::yield_context yield)
246 {
247 using CallbackSignature = boost::callable_traits::args_t<CallbackType>;
248 using InputTupleType = utility::decay_tuple_t<CallbackSignature>;
249 using DbusTupleType = utility::strip_first_n_args_t<
250 details::NonDbusArgsCount<InputTupleType>::size(), InputTupleType>;
251 DbusTupleType dbusArgs;
252 try
253 {
254 utility::read_into_tuple(dbusArgs, b);
255 }
256 catch (const exception::SdBusError& e)
257 {
258 auto ret = b.new_method_errno(e.get_errno(), e.get_error());
259 ret.method_return();
260 return;
261 }
262
263 try
264 {
265 auto ret = b.new_method_return();
266 if constexpr (callbackWantsMessage<CallbackType>)
267 {
268 InputTupleType inputArgs = std::tuple_cat(
269 std::forward_as_tuple(std::move(yield)),
270 std::forward_as_tuple(std::move(b)), dbusArgs);
271 callFunction(ret, inputArgs, func_);
272 }
273 else
274 {
275 InputTupleType inputArgs = std::tuple_cat(
276 std::forward_as_tuple(std::move(yield)), dbusArgs);
277 callFunction(ret, inputArgs, func_);
278 }
279 ret.method_return();
280 }
281 catch (const sdbusplus::exception::SdBusError& e)
282 {
283 // Catch D-Bus error explicitly called by method handler
284 message_t err = b.new_method_errno(e.get_errno(), e.get_error());
285 err.method_return();
286 }
287 catch (const sdbusplus::exception_t& e)
288 {
289 message_t err = b.new_method_error(e);
290 err.method_return();
291 }
292 catch (...)
293 {
294 message_t err = b.new_method_errno(-EIO);
295 err.method_return();
296 }
297 }
298 };
299 #endif
300
301 template <typename PropertyType, typename CallbackType>
302 class callback_get_instance
303 {
304 public:
callback_get_instance(const std::shared_ptr<PropertyType> & value,CallbackType && func)305 callback_get_instance(const std::shared_ptr<PropertyType>& value,
306 CallbackType&& func) :
307 value_(value), func_(std::forward<CallbackType>(func))
308 {}
operator ()(message_t & m)309 int operator()(message_t& m)
310 {
311 *value_ = func_(*value_);
312 m.append(*value_);
313 return 1;
314 }
315
316 private:
317 std::shared_ptr<PropertyType> value_;
318 CallbackType func_;
319 };
320
321 template <typename PropertyType>
322 class callback_set_message_instance
323 {
324 public:
callback_set_message_instance(const std::shared_ptr<PropertyType> & value,std::function<bool (const PropertyType &,PropertyType &)> && func)325 callback_set_message_instance(
326 const std::shared_ptr<PropertyType>& value,
327 std::function<bool(const PropertyType&, PropertyType&)>&& func) :
328 value_(value), func_(std::move(func))
329 {}
operator ()(message_t & m)330 SetPropertyReturnValue operator()(message_t& m)
331 {
332 PropertyType input;
333 m.read(input);
334 PropertyType oldValue = *value_;
335 if (!func_(input, *value_))
336 {
337 return SetPropertyReturnValue::fail;
338 }
339 if (oldValue == *value_)
340 {
341 return SetPropertyReturnValue::sameValueUpdated;
342 }
343 return SetPropertyReturnValue::valueUpdated;
344 }
345
346 private:
347 std::shared_ptr<PropertyType> value_;
348 std::function<bool(const PropertyType&, PropertyType&)> func_;
349 };
350
351 template <typename PropertyType>
352 class callback_set_value_instance
353 {
354 public:
callback_set_value_instance(const std::shared_ptr<PropertyType> & value,std::function<bool (const PropertyType &,PropertyType &)> && func)355 callback_set_value_instance(
356 const std::shared_ptr<PropertyType>& value,
357 std::function<bool(const PropertyType&, PropertyType&)>&& func) :
358 value_(value), func_(std::move(func))
359 {}
operator ()(const std::any & value)360 SetPropertyReturnValue operator()(const std::any& value)
361 {
362 const PropertyType& newValue = std::any_cast<PropertyType>(value);
363 PropertyType oldValue = *value_;
364 if (func_(newValue, *value_) == false)
365 {
366 return SetPropertyReturnValue::fail;
367 }
368 if (oldValue == *value_)
369 {
370 return SetPropertyReturnValue::sameValueUpdated;
371 }
372 return SetPropertyReturnValue::valueUpdated;
373 }
374
375 private:
376 std::shared_ptr<PropertyType> value_;
377 std::function<bool(const PropertyType&, PropertyType&)> func_;
378 };
379
380 enum class PropertyPermission
381 {
382 readOnly,
383 readWrite
384 };
385
386 class dbus_interface
387 {
388 public:
dbus_interface(std::shared_ptr<sdbusplus::asio::connection> conn,const std::string & path,const std::string & name)389 dbus_interface(std::shared_ptr<sdbusplus::asio::connection> conn,
390 const std::string& path, const std::string& name) :
391 conn_(conn), path_(path), name_(name)
392
393 {}
394
395 dbus_interface(const dbus_interface&) = delete;
396 dbus_interface& operator=(const dbus_interface&) = delete;
397 dbus_interface(dbus_interface&&) = delete;
398 dbus_interface& operator=(dbus_interface&&) = delete;
399
~dbus_interface()400 ~dbus_interface()
401 {
402 conn_->emit_interfaces_removed(path_.c_str(),
403 std::vector<std::string>{name_});
404 }
405
406 template <typename PropertyType, typename CallbackTypeGet>
register_property_r(const std::string & name,const PropertyType & property,decltype(vtable_t::flags)flags,CallbackTypeGet && getFunction)407 bool register_property_r(const std::string& name,
408 const PropertyType& property,
409 decltype(vtable_t::flags) flags,
410 CallbackTypeGet&& getFunction)
411 {
412 // can only register once
413 if (is_initialized())
414 {
415 return false;
416 }
417 if (sd_bus_member_name_is_valid(name.c_str()) != 1)
418 {
419 return false;
420 }
421 static const auto type =
422 utility::tuple_to_array(message::types::type_id<PropertyType>());
423
424 auto propertyPtr = std::make_shared<PropertyType>(property);
425
426 property_callbacks_.emplace_back(
427 *this, name,
428 callback_get_instance<PropertyType, CallbackTypeGet>(
429 propertyPtr, std::move(getFunction)),
430 nullptr,
431 callback_set_value_instance<PropertyType>(
432 propertyPtr, details::nop_set_value<PropertyType>),
433 type.data(), flags);
434
435 return true;
436 }
437
438 template <typename PropertyType, typename CallbackTypeGet>
register_property_r(const std::string & name,decltype(vtable_t::flags)flags,CallbackTypeGet && getFunction)439 bool register_property_r(const std::string& name,
440 decltype(vtable_t::flags) flags,
441 CallbackTypeGet&& getFunction)
442 {
443 return register_property_r(name, PropertyType{}, flags,
444 std::forward<CallbackTypeGet>(getFunction));
445 }
446
447 template <typename PropertyType, typename CallbackTypeSet,
448 typename CallbackTypeGet>
register_property_rw(const std::string & name,const PropertyType & property,decltype(vtable_t::flags)flags,CallbackTypeSet && setFunction,CallbackTypeGet && getFunction)449 bool register_property_rw(
450 const std::string& name, const PropertyType& property,
451 decltype(vtable_t::flags) flags, CallbackTypeSet&& setFunction,
452 CallbackTypeGet&& getFunction)
453 {
454 // can only register once
455 if (is_initialized())
456 {
457 return false;
458 }
459 if (sd_bus_member_name_is_valid(name.c_str()) != 1)
460 {
461 return false;
462 }
463 static const auto type =
464 utility::tuple_to_array(message::types::type_id<PropertyType>());
465
466 auto propertyPtr = std::make_shared<PropertyType>(property);
467
468 property_callbacks_.emplace_back(
469 *this, name,
470 callback_get_instance<PropertyType, CallbackTypeGet>(
471 propertyPtr, std::move(getFunction)),
472 callback_set_message_instance<PropertyType>(
473 propertyPtr, CallbackTypeSet(setFunction)),
474 callback_set_value_instance<PropertyType>(propertyPtr,
475 std::move(setFunction)),
476
477 type.data(), flags);
478
479 return true;
480 }
481
482 template <typename PropertyType, typename CallbackTypeSet,
483 typename CallbackTypeGet>
register_property_rw(const std::string & name,decltype(vtable_t::flags)flags,CallbackTypeSet && setFunction,CallbackTypeGet && getFunction)484 bool register_property_rw(const std::string& name,
485 decltype(vtable_t::flags) flags,
486 CallbackTypeSet&& setFunction,
487 CallbackTypeGet&& getFunction)
488 {
489 return register_property_rw(name, PropertyType{}, flags,
490 std::forward<CallbackTypeSet>(setFunction),
491 std::forward<CallbackTypeGet>(getFunction));
492 }
493
494 // default getter and setter
495 template <typename PropertyType>
register_property(const std::string & name,const PropertyType & property,PropertyPermission access=PropertyPermission::readOnly)496 bool register_property(
497 const std::string& name, const PropertyType& property,
498 PropertyPermission access = PropertyPermission::readOnly)
499 {
500 if (access == PropertyPermission::readOnly)
501 {
502 return register_property_r(name, property,
503 vtable::property_::emits_change,
504 details::nop_get_value<PropertyType>);
505 }
506 else
507 {
508 return register_property_rw(
509 name, property, vtable::property_::emits_change,
510 details::nop_set_value<PropertyType>,
511 details::nop_get_value<PropertyType>);
512 }
513 }
514
515 // custom setter, sets take an input property and respond with an int status
516 template <typename PropertyType, typename CallbackTypeSet>
register_property(const std::string & name,const PropertyType & property,CallbackTypeSet && setFunction)517 bool register_property(const std::string& name,
518 const PropertyType& property,
519 CallbackTypeSet&& setFunction)
520 {
521 return register_property_rw(
522 name, property, vtable::property_::emits_change,
523 std::forward<CallbackTypeSet>(setFunction),
524 details::nop_get_value<PropertyType>);
525 }
526
527 // custom getter and setter, gets take an input of void and respond with a
528 // property. property is only passed for type deduction
529 template <typename PropertyType, typename CallbackTypeSet,
530 typename CallbackTypeGet>
register_property(const std::string & name,const PropertyType & property,CallbackTypeSet && setFunction,CallbackTypeGet && getFunction)531 bool register_property(const std::string& name,
532 const PropertyType& property,
533 CallbackTypeSet&& setFunction,
534 CallbackTypeGet&& getFunction)
535 {
536 return register_property_rw(
537 name, property, vtable::property_::emits_change,
538 std::forward<CallbackTypeSet>(setFunction),
539 std::forward<CallbackTypeGet>(getFunction));
540 }
541
542 template <typename PropertyType, bool changesOnly = false>
set_property(const std::string & name,const PropertyType & value)543 bool set_property(const std::string& name, const PropertyType& value)
544 {
545 if (!is_initialized())
546 {
547 return false;
548 }
549 auto func = std::find_if(
550 property_callbacks_.begin(), property_callbacks_.end(),
551 [&name](const auto& element) { return element.name_ == name; });
552 if (func != property_callbacks_.end())
553 {
554 SetPropertyReturnValue status = func->on_set_value_(value);
555 if ((status == SetPropertyReturnValue::valueUpdated) ||
556 (status == SetPropertyReturnValue::sameValueUpdated))
557 {
558 if (status != SetPropertyReturnValue::sameValueUpdated)
559 {
560 signal_property(name);
561 return true;
562 }
563 if constexpr (!changesOnly)
564 {
565 return true;
566 }
567 }
568 }
569 return false;
570 }
571
572 template <typename... SignalSignature>
register_signal(const std::string & name)573 bool register_signal(const std::string& name)
574 {
575 if (is_initialized())
576 {
577 return false;
578 }
579 if (sd_bus_member_name_is_valid(name.c_str()) != 1)
580 {
581 return false;
582 }
583
584 static constexpr auto signature = utility::tuple_to_array(
585 message::types::type_id<SignalSignature...>());
586
587 signals_.emplace_back(name, signature.data());
588 return true;
589 }
590
591 template <typename CallbackType>
register_method(const std::string & name,CallbackType && handler,decltype(vtable_t::flags)flags=0)592 bool register_method(const std::string& name, CallbackType&& handler,
593 decltype(vtable_t::flags) flags = 0)
594 {
595 using ActualSignature = boost::callable_traits::args_t<CallbackType>;
596 using CallbackSignature = utility::strip_first_n_args_t<
597 details::NonDbusArgsCount<ActualSignature>::size(),
598 ActualSignature>;
599 using InputTupleType = utility::decay_tuple_t<CallbackSignature>;
600 using ResultType = boost::callable_traits::return_type_t<CallbackType>;
601
602 if (is_initialized())
603 {
604 return false;
605 }
606 static const auto argType = utility::strip_ends(
607 utility::tuple_to_array(message::types::type_id<InputTupleType>()));
608 static const auto resultType =
609 utility::tuple_to_array(message::types::type_id<ResultType>());
610
611 std::function<int(message_t&)> func;
612 if constexpr (FirstArgIsYield_v<CallbackType>)
613 {
614 func = coroutine_method_instance<CallbackType>(
615 conn_->get_io_context(), std::move(handler));
616 }
617 else
618 {
619 func = callback_method_instance<CallbackType>(std::move(handler));
620 }
621 method_callbacks_.emplace_back(name, std::move(func), argType.data(),
622 resultType.data(), flags);
623
624 return true;
625 }
626
get_handler(sd_bus *,const char *,const char *,const char *,sd_bus_message * reply,void * userdata,sd_bus_error * error)627 static int get_handler(sd_bus* /*bus*/, const char* /*path*/,
628 const char* /*interface*/, const char* /*property*/,
629 sd_bus_message* reply, void* userdata,
630 sd_bus_error* error)
631 {
632 property_callback* func = static_cast<property_callback*>(userdata);
633 auto mesg = message_t(reply);
634 #ifdef __EXCEPTIONS
635 try
636 {
637 #endif
638 return func->on_get_(mesg);
639 #ifdef __EXCEPTIONS
640 }
641
642 catch (const sdbusplus::exception_t& e)
643 {
644 return e.set_error(error);
645 }
646 catch (...)
647 {
648 // hit default error below
649 }
650 #endif
651 return sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS,
652 nullptr);
653 }
654
set_handler(sd_bus *,const char *,const char *,const char *,sd_bus_message * value,void * userdata,sd_bus_error * error)655 static int set_handler(sd_bus* /*bus*/, const char* /*path*/,
656 const char* /*interface*/, const char* /*property*/,
657 sd_bus_message* value, void* userdata,
658 sd_bus_error* error)
659 {
660 property_callback* func = static_cast<property_callback*>(userdata);
661
662 auto mesg = message_t(value);
663 #ifdef __EXCEPTIONS
664 try
665 {
666 #endif
667 SetPropertyReturnValue status = func->on_set_message_(mesg);
668 if ((status == SetPropertyReturnValue::valueUpdated) ||
669 (status == SetPropertyReturnValue::sameValueUpdated))
670 {
671 if (status != SetPropertyReturnValue::sameValueUpdated)
672 {
673 func->interface_.signal_property(func->name_);
674 }
675 // There shouldn't be any other callbacks that want to
676 // handle the message so just return a positive integer.
677 return 1;
678 }
679 #ifdef __EXCEPTIONS
680 }
681
682 catch (const sdbusplus::exception_t& e)
683 {
684 return e.set_error(error);
685 }
686 catch (...)
687 {
688 // hit default error below
689 }
690 #endif
691 return sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS,
692 nullptr);
693 }
694
method_handler(sd_bus_message * m,void * userdata,sd_bus_error * error)695 static int method_handler(sd_bus_message* m, void* userdata,
696 sd_bus_error* error)
697 {
698 method_callback* func = static_cast<method_callback*>(userdata);
699 auto mesg = message_t(m);
700 #ifdef __EXCEPTIONS
701 try
702 {
703 #endif
704 int status = func->call_(mesg);
705 if (status == 1)
706 {
707 return status;
708 }
709 #ifdef __EXCEPTIONS
710 }
711
712 catch (const sdbusplus::exception_t& e)
713 {
714 return e.set_error(error);
715 }
716 catch (...)
717 {
718 // hit default error below
719 }
720 #endif
721 return sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS,
722 nullptr);
723 }
724
725 /** @brief Create a new signal message.
726 *
727 * @param[in] member - The signal name to create.
728 */
new_signal(const char * member)729 auto new_signal(const char* member)
730 {
731 if (!is_initialized())
732 {
733 return message_t(nullptr);
734 }
735 return interface_->new_signal(member);
736 }
737
initialize(const bool skipPropertyChangedSignal=false)738 bool initialize(const bool skipPropertyChangedSignal = false)
739 {
740 // can only register once
741 if (is_initialized())
742 {
743 return false;
744 }
745 vtable_.reserve(2 + property_callbacks_.size() +
746 method_callbacks_.size() + signals_.size());
747 vtable_.emplace_back(vtable::start());
748 property_callbacks_.shrink_to_fit();
749 for (auto& element : property_callbacks_)
750 {
751 if (element.on_set_message_)
752 {
753 vtable_.emplace_back(vtable::property_o(
754 element.name_.c_str(), element.signature_, get_handler,
755 set_handler, reinterpret_cast<size_t>(&element),
756 element.flags_ | SD_BUS_VTABLE_ABSOLUTE_OFFSET));
757 }
758 else
759 {
760 vtable_.emplace_back(vtable::property_o(
761 element.name_.c_str(), element.signature_, get_handler,
762 reinterpret_cast<size_t>(&element),
763 element.flags_ | SD_BUS_VTABLE_ABSOLUTE_OFFSET));
764 }
765 }
766
767 method_callbacks_.shrink_to_fit();
768 for (auto& element : method_callbacks_)
769 {
770 vtable_.emplace_back(vtable::method_o(
771 element.name_.c_str(), element.arg_signature_,
772 element.return_signature_, method_handler,
773 reinterpret_cast<size_t>(&element),
774 element.flags_ | SD_BUS_VTABLE_ABSOLUTE_OFFSET));
775 }
776
777 signals_.shrink_to_fit();
778 for (const auto& element : signals_)
779 {
780 vtable_.emplace_back(
781 vtable::signal(element.name_.c_str(), element.signature_));
782 }
783
784 vtable_.emplace_back(vtable::end());
785 vtable_.shrink_to_fit();
786
787 interface_.emplace(static_cast<sdbusplus::bus_t&>(*conn_),
788 path_.c_str(), name_.c_str(),
789 static_cast<const sd_bus_vtable*>(&vtable_[0]),
790 nullptr);
791 conn_->emit_interfaces_added(path_.c_str(),
792 std::vector<std::string>{name_});
793 if (!skipPropertyChangedSignal)
794 {
795 for (const auto& element : property_callbacks_)
796 {
797 signal_property(element.name_);
798 }
799 }
800 return true;
801 }
802
is_initialized()803 bool is_initialized()
804 {
805 return interface_.has_value();
806 }
807
signal_property(const std::string & name)808 bool signal_property(const std::string& name)
809 {
810 if (!is_initialized())
811 {
812 return false;
813 }
814 interface_->property_changed(name.c_str());
815 return true;
816 }
817
get_object_path(void)818 std::string get_object_path(void)
819 {
820 return path_;
821 }
822
get_interface_name(void)823 std::string get_interface_name(void)
824 {
825 return name_;
826 }
827
828 private:
829 std::shared_ptr<sdbusplus::asio::connection> conn_;
830 std::string path_;
831 std::string name_;
832
833 std::vector<signal> signals_;
834 std::vector<property_callback> property_callbacks_;
835 std::vector<method_callback> method_callbacks_;
836
837 std::vector<sd_bus_vtable> vtable_;
838 std::optional<sdbusplus::server::interface_t> interface_;
839 };
840
841 class object_server
842 {
843 public:
object_server(const std::shared_ptr<sdbusplus::asio::connection> & conn,const bool skipManager=false)844 object_server(const std::shared_ptr<sdbusplus::asio::connection>& conn,
845 const bool skipManager = false) : conn_(conn)
846 {
847 if (!skipManager)
848 {
849 add_manager("/");
850 }
851 }
852
853 std::shared_ptr<dbus_interface>
add_interface(const std::string & path,const std::string & name)854 add_interface(const std::string& path, const std::string& name)
855 {
856 auto dbusIface = std::make_shared<dbus_interface>(conn_, path, name);
857 interfaces_.emplace_back(dbusIface);
858 return dbusIface;
859 }
860
861 std::unique_ptr<dbus_interface>
add_unique_interface(const std::string & path,const std::string & name)862 add_unique_interface(const std::string& path, const std::string& name)
863 {
864 return std::make_unique<dbus_interface>(conn_, path, name);
865 }
866
867 /**
868 @brief creates initialized dbus_interface
869 @param path a string path to interface
870 @param name a string name of the interface
871 @param initializer a functor (void (dbus_interface&)) to be called before
872 call to dbus_interface::initialize
873 @return an unique_ptr to initialized dbus_interface
874 */
875 template <class Initializer>
876 std::unique_ptr<dbus_interface>
add_unique_interface(const std::string & path,const std::string & name,Initializer && initializer)877 add_unique_interface(const std::string& path, const std::string& name,
878 Initializer&& initializer)
879 {
880 auto dbusIface = std::make_unique<dbus_interface>(conn_, path, name);
881 initializer(*dbusIface);
882 dbusIface->initialize();
883 return dbusIface;
884 }
885
add_manager(const std::string & path)886 void add_manager(const std::string& path)
887 {
888 managers_.emplace_back(static_cast<sdbusplus::bus_t&>(*conn_),
889 path.c_str());
890 }
891
remove_interface(const std::shared_ptr<dbus_interface> & iface)892 bool remove_interface(const std::shared_ptr<dbus_interface>& iface)
893 {
894 auto findIface =
895 std::find(interfaces_.begin(), interfaces_.end(), iface);
896 if (findIface != interfaces_.end())
897 {
898 interfaces_.erase(findIface);
899 return true;
900 }
901 return false;
902 }
903
904 private:
905 std::shared_ptr<sdbusplus::asio::connection> conn_;
906 std::vector<std::shared_ptr<dbus_interface>> interfaces_;
907 std::vector<server::manager_t> managers_;
908 };
909
910 } // namespace asio
911 } // namespace sdbusplus
912