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,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 31 template <typename MessageHandler> 32 async_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 35 template <typename MessageHandler> 36 void 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 59 template <typename MessageHandler> 60 void 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 70 template <typename MessageHandler> 71 void 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 79