blob: e3061136a657e894df092da0cb17ccb3cc5e31ee [file] [log] [blame]
James Feist284a0f92018-04-05 15:28:16 -07001/*
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 <sdbusplus/message.hpp>
19#include <sdbusplus/utility/read_into_tuple.hpp>
20#include <sdbusplus/utility/type_traits.hpp>
21#include <sdbusplus/asio/detail/async_send_handler.hpp>
22#include <chrono>
23#include <string>
24#include <experimental/tuple>
25#include <boost/asio.hpp>
26#include <boost/callable_traits.hpp>
27
28namespace sdbusplus
29{
30
31namespace asio
32{
33
34/// Root D-Bus IO object
35/**
36 * A connection to a bus, through which messages may be sent or received.
37 */
38class connection : public sdbusplus::bus::bus
39{
40 public:
41 // default to system bus
42 connection(boost::asio::io_service& io) :
43 sdbusplus::bus::bus(sdbusplus::bus::new_system()), io_(io), socket(io_)
44 {
45 socket.assign(get_fd());
46 do_read();
47 }
48 connection(boost::asio::io_service& io, sd_bus* bus) :
49 sdbusplus::bus::bus(bus), io_(io), socket(io_)
50 {
51 socket.assign(get_fd());
52 do_read();
53 }
54 ~connection()
55 {
56 // The FD will be closed by the socket object, so assign null to the
57 // sd_bus object to avoid a double close() Ignore return codes here,
58 // because there's nothing we can do about errors
59 socket.release();
60 }
61
62 template <typename MessageHandler>
63 inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
64 void(boost::system::error_code,
65 message::message))
66 async_send(message::message& m, MessageHandler&& handler)
67 {
68 boost::asio::async_completion<
69 MessageHandler, void(boost::system::error_code, message::message)>
70 init(handler);
71 detail::async_send_handler<typename boost::asio::handler_type<
72 MessageHandler,
73 void(boost::system::error_code, message::message)>::type>(
74 std::move(init.completion_handler))(get(), m);
75 return init.result.get();
76 }
77
78 template <typename MessageHandler, typename... InputArgs>
79 auto async_method_call(MessageHandler handler, const std::string& service,
80 const std::string& objpath,
81 const std::string& interf, const std::string& method,
82 const InputArgs&... a)
83 {
84 message::message m = new_method_call(service.c_str(), objpath.c_str(),
85 interf.c_str(), method.c_str());
86 m.append(a...);
87 return async_send(m, [handler](boost::system::error_code ec,
88 message::message& r) {
89 using FunctionTuple =
90 boost::callable_traits::args_t<MessageHandler>;
91 using UnpackType = typename utility::strip_first_arg<
92 typename utility::decay_tuple<FunctionTuple>::type>::type;
93 UnpackType responseData;
94 if (!ec)
95 {
96 if (!utility::read_into_tuple(responseData, r))
97 {
98 // Set error code if not already set
99 ec = boost::system::errc::make_error_code(
100 boost::system::errc::invalid_argument);
101 }
102 }
103 // Note. Callback is called whether or not the unpack was
104 // sucessful to allow the user to implement their own handling
105 auto response = std::tuple_cat(std::make_tuple(ec), responseData);
106 std::experimental::apply(handler, response);
107 });
108 }
109
110 private:
111 boost::asio::io_service& io_;
112 boost::asio::posix::stream_descriptor socket;
113
114 void do_read(void)
115 {
116 socket.async_read_some(
117 boost::asio::null_buffers(),
118 [&](const boost::system::error_code& ec, std::size_t) {
119 process_discard();
120 do_read();
121 });
122 }
123};
124
125} // namespace asio
126
127} // namespace sdbusplus