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 namespace dbus { 16 namespace detail { 17 18 template<typename MessageHandler> 19 struct async_send_op 20 { 21 typedef async_send_op<MessageHandler> op_type; 22 io_service& io_; 23 message message_; 24 MessageHandler handler_; 25 async_send_op(io_service& io, BOOST_ASIO_MOVE_ARG(MessageHandler) handler); 26 static void callback(DBusPendingCall *p, void *userdata); // for C API 27 void operator()(DBusConnection *& 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(io_service& io, 33 BOOST_ASIO_MOVE_ARG(MessageHandler) handler) 34 : io_(io), 35 handler_(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler)) 36 { 37 } 38 39 template<typename MessageHandler> 40 void async_send_op<MessageHandler>::operator()(DBusConnection *& c, message& m) 41 { 42 DBusPendingCall *p; 43 dbus_connection_send_with_reply(c, 44 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