xref: /openbmc/boost-dbus/include/dbus/connection.hpp (revision 70f79f4d666ffe7361bf17294abf4fec9cf2c806)
191cdbe46SBenjamin Kietzman // Copyright (c) Benjamin Kietzman (github.com/bkietz)
291cdbe46SBenjamin Kietzman //
391cdbe46SBenjamin Kietzman // Distributed under the Boost Software License, Version 1.0. (See accompanying
491cdbe46SBenjamin Kietzman // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
591cdbe46SBenjamin Kietzman 
6fc79e461SBenjamin Kietzman #ifndef DBUS_CONNECTION_HPP
7fc79e461SBenjamin Kietzman #define DBUS_CONNECTION_HPP
8fc79e461SBenjamin Kietzman 
9da3eeb6aSEd Tanous #include <dbus/connection_service.hpp>
10a83e5951SBenjamin Kietzman #include <dbus/element.hpp>
11fc79e461SBenjamin Kietzman #include <dbus/message.hpp>
12da3eeb6aSEd Tanous #include <chrono>
13da3eeb6aSEd Tanous #include <string>
14da3eeb6aSEd Tanous #include <boost/asio.hpp>
15dae7063cSBenjamin Kietzman 
16dae7063cSBenjamin Kietzman namespace dbus {
17dae7063cSBenjamin Kietzman 
1817826fe7SBenjamin Kietzman class filter;
1917826fe7SBenjamin Kietzman class match;
2017826fe7SBenjamin Kietzman 
21dae7063cSBenjamin Kietzman /// Root D-Bus IO object
22dae7063cSBenjamin Kietzman /**
23dae7063cSBenjamin Kietzman  * A connection to a bus, through which messages may be sent or received.
24dae7063cSBenjamin Kietzman  */
25da3eeb6aSEd Tanous class connection : public boost::asio::basic_io_object<connection_service> {
26dae7063cSBenjamin Kietzman  public:
27cd8b76a3SBenjamin Kietzman   /// Open a connection to a specified address.
28dae7063cSBenjamin Kietzman   /**
29dae7063cSBenjamin Kietzman  * @param io_service The io_service object that the connection will use to
30dae7063cSBenjamin Kietzman  * wire D-Bus for asynchronous operation.
31dae7063cSBenjamin Kietzman  *
32dae7063cSBenjamin Kietzman  * @param address The address of the bus to connect to.
33dae7063cSBenjamin Kietzman  *
34dae7063cSBenjamin Kietzman  * @throws boost::system::system_error When opening the connection failed.
35dae7063cSBenjamin Kietzman  */
connection(boost::asio::io_service & io,const string & address)36da3eeb6aSEd Tanous   connection(boost::asio::io_service& io, const string& address)
37da3eeb6aSEd Tanous       : basic_io_object<connection_service>(io) {
38da3eeb6aSEd Tanous     this->get_service().open(this->get_implementation(), address);
39dae7063cSBenjamin Kietzman   }
40dae7063cSBenjamin Kietzman 
41dae7063cSBenjamin Kietzman   /// Open a connection to a well-known bus.
42dae7063cSBenjamin Kietzman   /**
43dae7063cSBenjamin Kietzman  * D-Bus connections are usually opened to well-known buses like the
44dae7063cSBenjamin Kietzman  * system or session bus.
45dae7063cSBenjamin Kietzman  *
46cd8b76a3SBenjamin Kietzman  * @param bus The well-known bus to connect to.
47dae7063cSBenjamin Kietzman  *
48dae7063cSBenjamin Kietzman  * @throws boost::system::system_error When opening the connection failed.
49dae7063cSBenjamin Kietzman  */
50dae7063cSBenjamin Kietzman   // TODO: change this unsigned to an enumeration
connection(boost::asio::io_service & io,const int bus)51da3eeb6aSEd Tanous   connection(boost::asio::io_service& io, const int bus)
52da3eeb6aSEd Tanous       : basic_io_object<connection_service>(io) {
53da3eeb6aSEd Tanous     this->get_service().open(this->get_implementation(), bus);
54dae7063cSBenjamin Kietzman   }
55dae7063cSBenjamin Kietzman 
56458a9c10SVernon Mauery   /// Request a name on the bus.
57458a9c10SVernon Mauery   /**
58458a9c10SVernon Mauery  * @param name The name requested on the bus
59458a9c10SVernon Mauery  *
60458a9c10SVernon Mauery  * @return
61458a9c10SVernon Mauery  *
62458a9c10SVernon Mauery  * @throws boost::system::system_error When the response timed out or
63458a9c10SVernon Mauery  * there was some other error.
64458a9c10SVernon Mauery  */
request_name(const string & name)65458a9c10SVernon Mauery   void request_name(const string& name) {
66458a9c10SVernon Mauery     this->get_implementation().request_name(name);
67458a9c10SVernon Mauery   }
68458a9c10SVernon Mauery 
get_unique_name()690d6f56d2SEd Tanous   std::string get_unique_name() {
700d6f56d2SEd Tanous     return this->get_implementation().get_unique_name();
710d6f56d2SEd Tanous   }
720d6f56d2SEd Tanous 
73458a9c10SVernon Mauery   /// Reply to a message.
74458a9c10SVernon Mauery   /**
75458a9c10SVernon Mauery  * @param m The message from which to create the reply
76458a9c10SVernon Mauery  *
77458a9c10SVernon Mauery  * @return The new reply message
78458a9c10SVernon Mauery  *
79458a9c10SVernon Mauery  * @throws boost::system::system_error When the response timed out or
80458a9c10SVernon Mauery  * there was some other error.
81458a9c10SVernon Mauery  */
reply(message & m)82458a9c10SVernon Mauery   message reply(message& m) {
83458a9c10SVernon Mauery     return this->get_implementation().new_method_return(m);
84458a9c10SVernon Mauery   }
85458a9c10SVernon Mauery 
860de54404SBenjamin Kietzman   /// Send a message.
870de54404SBenjamin Kietzman   /**
880de54404SBenjamin Kietzman  * @param m The message to send.
890de54404SBenjamin Kietzman  *
900de54404SBenjamin Kietzman  * @return The reply received.
910de54404SBenjamin Kietzman  *
920de54404SBenjamin Kietzman  * @throws boost::system::system_error When the response timed out or
930de54404SBenjamin Kietzman  * there was some other error.
940de54404SBenjamin Kietzman  */
send(message & m)95da3eeb6aSEd Tanous   message send(message& m) {
96da3eeb6aSEd Tanous     return this->get_service().send(this->get_implementation(), m);
970de54404SBenjamin Kietzman   }
98dae7063cSBenjamin Kietzman 
99dae7063cSBenjamin Kietzman   /// Send a message.
100dae7063cSBenjamin Kietzman   /**
101dae7063cSBenjamin Kietzman  * @param m The message to send.
102dae7063cSBenjamin Kietzman  *
103fc79e461SBenjamin Kietzman  * @param t Time to wait for a reply. Passing 0 as the timeout means
104dae7063cSBenjamin Kietzman  * that you wish to ignore the reply. (Or catch it later somehow...)
105dae7063cSBenjamin Kietzman  *
106dae7063cSBenjamin Kietzman  * @return The reply received.
107dae7063cSBenjamin Kietzman  *
1080de54404SBenjamin Kietzman  * @throws boost::system::system_error When the response timed out (if
1090de54404SBenjamin Kietzman  * timeout was not 0), or there was some other error.
110dae7063cSBenjamin Kietzman  */
111dae7063cSBenjamin Kietzman   template <typename Duration>
send(message & m,const Duration & t)112e62be329SEd Tanous   message send(message& m, const Duration& t) {
113da3eeb6aSEd Tanous     return this->get_service().send(this->get_implementation(), m, t);
114dae7063cSBenjamin Kietzman   }
115dae7063cSBenjamin Kietzman 
116a8b4eac4SEd Tanous   template <typename... InputArgs>
method_call(const dbus::endpoint & e,const InputArgs &...a)117a8b4eac4SEd Tanous   message method_call(const dbus::endpoint& e, const InputArgs&... a) {
118a8b4eac4SEd Tanous     message m = dbus::message::new_call(e);
119a8b4eac4SEd Tanous     m.pack(a...);
120a8b4eac4SEd Tanous     return this->get_service().send(this->get_implementation(), m,
121a8b4eac4SEd Tanous                                     std::chrono::seconds(30));
122a8b4eac4SEd Tanous   }
123a8b4eac4SEd Tanous 
124dae7063cSBenjamin Kietzman   /// Send a message asynchronously.
125dae7063cSBenjamin Kietzman   /**
126dae7063cSBenjamin Kietzman  * @param m The message to send.
127dae7063cSBenjamin Kietzman  *
128dae7063cSBenjamin Kietzman  * @param handler Handler for the reply.
129dae7063cSBenjamin Kietzman  *
130dae7063cSBenjamin Kietzman  * @return Asynchronous result
131dae7063cSBenjamin Kietzman  */
132e62be329SEd Tanous 
133dae7063cSBenjamin Kietzman   template <typename MessageHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,void (boost::system::error_code,message))134dae7063cSBenjamin Kietzman   inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
135dae7063cSBenjamin Kietzman                                        void(boost::system::error_code, message))
136da3eeb6aSEd Tanous       async_send(message& m, BOOST_ASIO_MOVE_ARG(MessageHandler) handler) {
137dae7063cSBenjamin Kietzman     return this->get_service().async_send(
138da3eeb6aSEd Tanous         this->get_implementation(), m,
139dae7063cSBenjamin Kietzman         BOOST_ASIO_MOVE_CAST(MessageHandler)(handler));
140dae7063cSBenjamin Kietzman   }
141dae7063cSBenjamin Kietzman 
142e62be329SEd Tanous   // Small helper class for stipping off the error code from the function
143e62be329SEd Tanous   // agrument definitions so unpack can be called appriately
144e62be329SEd Tanous   template <typename T>
145e62be329SEd Tanous   struct strip_first_arg {};
146e62be329SEd Tanous 
147e62be329SEd Tanous   template <typename FirstArg, typename... Rest>
148e62be329SEd Tanous   struct strip_first_arg<std::tuple<FirstArg, Rest...>> {
149e62be329SEd Tanous     typedef std::tuple<Rest...> type;
150e62be329SEd Tanous   };
151e62be329SEd Tanous 
152e62be329SEd Tanous   template <typename MessageHandler, typename... InputArgs>
async_method_call(MessageHandler handler,const dbus::endpoint & e,const InputArgs &...a)153a8b4eac4SEd Tanous   auto async_method_call(MessageHandler handler, const dbus::endpoint& e,
154e62be329SEd Tanous                          const InputArgs&... a) {
155e62be329SEd Tanous     message m = dbus::message::new_call(e);
156e62be329SEd Tanous     if (!m.pack(a...)) {
157e62be329SEd Tanous       // TODO(ed) Set error code?
158a8b4eac4SEd Tanous       std::cerr << "Pack error\n";
159e62be329SEd Tanous     } else {
160a8b4eac4SEd Tanous       // explicit copy of handler here.  At this time, not clear why a copy is
161a8b4eac4SEd Tanous       // needed
162a8b4eac4SEd Tanous       return async_send(
163a8b4eac4SEd Tanous           m, [handler](boost::system::error_code ec, dbus::message r) {
164e62be329SEd Tanous             // Make a copy of the error code so we can modify it
165e62be329SEd Tanous             typedef typename function_traits<MessageHandler>::decayed_arg_types
166e62be329SEd Tanous                 function_tuple;
167e62be329SEd Tanous             typedef typename strip_first_arg<function_tuple>::type unpack_type;
168e62be329SEd Tanous             unpack_type response_args;
169e62be329SEd Tanous             if (!ec) {
170e62be329SEd Tanous               if (!unpack_into_tuple(response_args, r)) {
171e62be329SEd Tanous                 // Set error code
172e62be329SEd Tanous                 ec = boost::system::errc::make_error_code(
173e62be329SEd Tanous                     boost::system::errc::invalid_argument);
174e62be329SEd Tanous               }
175e62be329SEd Tanous             }
176e62be329SEd Tanous             // Should this (the callback) be done in a try catch block?
177a8b4eac4SEd Tanous             // should throwing from a handler flow all the way to the
178a8b4eac4SEd Tanous             // io_service?
179e62be329SEd Tanous 
180e62be329SEd Tanous             // Note.  Callback is called whether or not the unpack was sucessful
181e62be329SEd Tanous             // to allow the user to implement their own handling
182a8b4eac4SEd Tanous             index_apply<std::tuple_size<unpack_type>{}>([&](auto... Is) {
183a8b4eac4SEd Tanous               handler(ec, std::get<Is>(response_args)...);
184a8b4eac4SEd Tanous             });
185e62be329SEd Tanous           });
186e62be329SEd Tanous     }
187e62be329SEd Tanous   }
188e62be329SEd Tanous 
flush(void)189*70f79f4dSJames Feist   void flush(void) { this->get_implementation().flush(); };
190*70f79f4dSJames Feist 
191dae7063cSBenjamin Kietzman   /// Create a new match.
new_match(match & m)192da3eeb6aSEd Tanous   void new_match(match& m) {
193da3eeb6aSEd Tanous     this->get_service().new_match(this->get_implementation(), m);
194cd8b76a3SBenjamin Kietzman   }
195cd8b76a3SBenjamin Kietzman 
196cd8b76a3SBenjamin Kietzman   /// Destroy a match.
delete_match(match & m)197da3eeb6aSEd Tanous   void delete_match(match& m) {
198da3eeb6aSEd Tanous     this->get_service().delete_match(this->get_implementation(), m);
199dae7063cSBenjamin Kietzman   }
200dae7063cSBenjamin Kietzman 
201dae7063cSBenjamin Kietzman   /// Create a new filter.
new_filter(filter & f)202da3eeb6aSEd Tanous   void new_filter(filter& f) {
203da3eeb6aSEd Tanous     this->get_service().new_filter(this->get_implementation(), f);
204dae7063cSBenjamin Kietzman   }
205dae7063cSBenjamin Kietzman 
20617826fe7SBenjamin Kietzman   /// Destroy a filter.
delete_filter(filter & f)207da3eeb6aSEd Tanous   void delete_filter(filter& f) {
208da3eeb6aSEd Tanous     this->get_service().delete_filter(this->get_implementation(), f);
209cd8b76a3SBenjamin Kietzman   }
210fc79e461SBenjamin Kietzman 
211da3eeb6aSEd Tanous   // FIXME the only way around this I see is to expose start() here, which seems
212da3eeb6aSEd Tanous   // ugly
2132003615dSBenjamin Kietzman   friend class filter;
214dae7063cSBenjamin Kietzman };
215dae7063cSBenjamin Kietzman 
216b573e22eSEd Tanous typedef std::shared_ptr<connection> connection_ptr;
217b573e22eSEd Tanous 
218dae7063cSBenjamin Kietzman }  // namespace dbus
219fc79e461SBenjamin Kietzman 
220fc79e461SBenjamin Kietzman #endif  // DBUS_CONNECTION_HPP
221