1 /*
2 // Copyright (c) 2018 Intel 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 #pragma once
17 
18 #include <systemd/sd-bus.h>
19 
20 #include <boost/system/error_code.hpp>
21 #include <sdbusplus/bus.hpp>
22 #include <sdbusplus/message.hpp>
23 
24 namespace sdbusplus
25 {
26 namespace asio
27 {
28 namespace detail
29 {
30 
31 /* Class meant for converting a static callback, and void* userdata from sd-bus
32  * back into a structured class to be returned to the user.
33  */
34 template <typename CompletionToken>
35 struct unpack_userdata
36 {
37     CompletionToken handler_;
38 
do_unpacksdbusplus::asio::detail::unpack_userdata39     static int do_unpack(sd_bus_message* mesg, void* userdata,
40                          sd_bus_error* /*error*/)
41     {
42         if (userdata == nullptr)
43         {
44             return -EINVAL;
45         }
46 
47         // Take RAII ownership of the pointer again
48         using self_t = unpack_userdata<CompletionToken>;
49         std::unique_ptr<self_t> context(static_cast<self_t*>(userdata));
50 
51         if (mesg == nullptr)
52         {
53             return -EINVAL;
54         }
55         message_t message(mesg);
56         auto ec = make_error_code(
57             static_cast<boost::system::errc::errc_t>(message.get_errno()));
58         context->handler_(ec, message);
59         return 0;
60     }
61 
unpack_userdatasdbusplus::asio::detail::unpack_userdata62     explicit unpack_userdata(CompletionToken&& handler) :
63         handler_(std::forward<CompletionToken>(handler))
64     {}
65 };
66 
67 class async_send_handler
68 {
69     sd_bus* bus;
70     message_t& mesg;
71     uint64_t timeout;
72 
73   public:
74     template <typename CompletionToken>
operator ()(CompletionToken && token)75     void operator()(CompletionToken&& token)
76     {
77         using unpack_t = unpack_userdata<CompletionToken>;
78         auto context = std::make_unique<unpack_t>(std::move(token));
79         int ec =
80             sd_bus_call_async(bus, nullptr, mesg.get(), &unpack_t::do_unpack,
81                               context.get(), timeout);
82         if (ec < 0)
83         {
84             auto err =
85                 make_error_code(static_cast<boost::system::errc::errc_t>(ec));
86             context->handler_(err, mesg);
87             return;
88         }
89         // If the call succeeded, sd-bus owns the pointer now, so release it
90         // without freeing.
91         context.release();
92     }
93 
async_send_handler(sd_bus * busIn,message_t & mesgIn,uint64_t timeoutIn)94     async_send_handler(sd_bus* busIn, message_t& mesgIn, uint64_t timeoutIn) :
95         bus(busIn), mesg(mesgIn), timeout(timeoutIn)
96     {}
97 };
98 } // namespace detail
99 } // namespace asio
100 } // namespace sdbusplus
101