1 // 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 17 namespace dbus { 18 namespace detail { 19 20 template <typename MessageHandler> 21 struct async_send_op { 22 boost::asio::io_service& io_; 23 message message_; 24 MessageHandler handler_; 25 async_send_op(boost::asio::io_service& io, 26 BOOST_ASIO_MOVE_ARG(MessageHandler) handler); 27 static void callback(DBusPendingCall* p, void* userdata); // for C API 28 void operator()(impl::connection& c, message& m); // initiate operation 29 void operator()(); // bound completion handler form 30 }; 31 32 template <typename MessageHandler> 33 async_send_op<MessageHandler>::async_send_op(boost::asio::io_service& io, 34 BOOST_ASIO_MOVE_ARG(MessageHandler) 35 handler) 36 : io_(io), handler_(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler)) {} 37 38 template <typename MessageHandler> 39 void async_send_op<MessageHandler>::operator()(impl::connection& c, 40 message& m) { 41 DBusPendingCall* p; 42 c.send_with_reply(m, &p, -1); 43 44 // We have to throw this onto the heap so that the 45 // C API can store it as `void *userdata` 46 async_send_op* op = 47 new async_send_op(BOOST_ASIO_MOVE_CAST(async_send_op)(*this)); 48 49 dbus_pending_call_set_notify(p, &callback, op, NULL); 50 51 // FIXME Race condition: another thread might have 52 // processed the pending call's reply before a notify 53 // function could be set. If so, the notify function 54 // will never trigger, so it must be called manually: 55 if (dbus_pending_call_get_completed(p)) { 56 // TODO: does this work, or might it call the notify 57 // function too many times? Might have to use steal_reply 58 // callback(p, op); 59 } 60 } 61 62 template <typename MessageHandler> 63 void async_send_op<MessageHandler>::callback(DBusPendingCall* p, 64 void* userdata) { 65 boost::scoped_ptr<async_send_op> op(static_cast<async_send_op*>(userdata)); 66 67 op->message_ = dbus_pending_call_steal_reply(p); 68 dbus_pending_call_unref(p); 69 70 op->io_.post(BOOST_ASIO_MOVE_CAST(async_send_op)(*op)); 71 } 72 73 template <typename MessageHandler> 74 void async_send_op<MessageHandler>::operator()() { 75 handler_(error(message_).error_code(), message_); 76 } 77 78 } // namespace detail 79 } // namespace dbus 80 81 #endif // DBUS_ASYNC_SEND_OP_HPP 82