blob: 996a4e7d60994d36c87b71d48c5efbea3cd0a543 [file] [log] [blame]
Ed Tanousc9b55212017-06-12 13:25:51 -07001// Copyright (c) Benjamin Kietzman (github.com/bkietz)
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef DBUS_ASYNC_SEND_OP_HPP
7#define DBUS_ASYNC_SEND_OP_HPP
8
9#include <boost/scoped_ptr.hpp>
10
11#include <dbus/dbus.h>
12#include <dbus/error.hpp>
13#include <dbus/message.hpp>
14
15#include <dbus/impl/connection.ipp>
16
17namespace dbus {
18namespace detail {
19
20template <typename MessageHandler>
21struct async_send_op {
22 boost::asio::io_service& io_;
23 message message_;
24 MessageHandler handler_;
25 async_send_op(boost::asio::io_service& io,BOOST_ASIO_MOVE_ARG(MessageHandler) handler);
26 static void callback(DBusPendingCall* p, void* userdata); // for C API
27 void operator()(impl::connection& c, message& m); // initiate operation
28 void operator()(); // bound completion handler form
29};
30
31template <typename MessageHandler>
32async_send_op<MessageHandler>::async_send_op(boost::asio::io_service& io,BOOST_ASIO_MOVE_ARG(MessageHandler)handler)
33 : io_(io), handler_(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler)) {}
34
35template <typename MessageHandler>
36void async_send_op<MessageHandler>::operator()(impl::connection& c,
37 message& m) {
38 DBusPendingCall* p;
39 c.send_with_reply(m, &p, -1);
40
41 // We have to throw this onto the heap so that the
42 // C API can store it as `void *userdata`
43 async_send_op* op =
44 new async_send_op(BOOST_ASIO_MOVE_CAST(async_send_op)(*this));
45
46 dbus_pending_call_set_notify(p, &callback, op, NULL);
47
48 // FIXME Race condition: another thread might have
49 // processed the pending call's reply before a notify
50 // function could be set. If so, the notify function
51 // will never trigger, so it must be called manually:
52 if (dbus_pending_call_get_completed(p)) {
53 // TODO: does this work, or might it call the notify
54 // function too many times? Might have to use steal_reply
55 // callback(p, op);
56 }
57}
58
59template <typename MessageHandler>
60void async_send_op<MessageHandler>::callback(DBusPendingCall* p,
61 void* userdata) {
62 boost::scoped_ptr<async_send_op> op(static_cast<async_send_op*>(userdata));
63
64 op->message_ = dbus_pending_call_steal_reply(p);
65 dbus_pending_call_unref(p);
66
67 op->io_.post(BOOST_ASIO_MOVE_CAST(async_send_op)(*op));
68}
69
70template <typename MessageHandler>
71void async_send_op<MessageHandler>::operator()() {
72 handler_(error(message_).error_code(), message_);
73}
74
75} // namespace detail
76} // namespace dbus
77
78#endif // DBUS_ASYNC_SEND_OP_HPP