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