// Copyright (c) Benjamin Kietzman (github.com/bkietz) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef DBUS_WATCH_TIMEOUT_HPP #define DBUS_WATCH_TIMEOUT_HPP #include #include #include #include namespace dbus { namespace detail { static void watch_toggled(DBusWatch *dbus_watch, void *data); struct watch_handler { DBusWatchFlags flags; DBusWatch *dbus_watch; watch_handler(DBusWatchFlags f, DBusWatch *w) : flags(f), dbus_watch(w) {} void operator()(boost::system::error_code ec, size_t) { if (ec) return; dbus_watch_handle(dbus_watch, flags); auto data = dbus_watch_get_data(dbus_watch); if (data != nullptr) { boost::asio::generic::stream_protocol::socket &socket = *static_cast(data); watch_toggled(dbus_watch, &socket.get_io_service()); } } }; static void watch_toggled(DBusWatch *dbus_watch, void *data) { void *watch_data = dbus_watch_get_data(dbus_watch); if (watch_data == nullptr) { return; } auto socket = static_cast(watch_data); if (dbus_watch_get_enabled(dbus_watch)) { if (dbus_watch_get_flags(dbus_watch) & DBUS_WATCH_READABLE) socket->async_read_some(boost::asio::null_buffers(), watch_handler(DBUS_WATCH_READABLE, dbus_watch)); if (dbus_watch_get_flags(dbus_watch) & DBUS_WATCH_WRITABLE) socket->async_write_some(boost::asio::null_buffers(), watch_handler(DBUS_WATCH_WRITABLE, dbus_watch)); } else { socket->cancel(); } } static dbus_bool_t add_watch(DBusWatch *dbus_watch, void *data) { if (!dbus_watch_get_enabled(dbus_watch)) { return TRUE; } boost::asio::io_service &io = *static_cast(data); int fd = dbus_watch_get_unix_fd(dbus_watch); if (fd == -1) // socket based watches fd = dbus_watch_get_socket(dbus_watch); boost::asio::generic::stream_protocol::socket &socket = *new boost::asio::generic::stream_protocol::socket(io); socket.assign(boost::asio::generic::stream_protocol(0, 0), fd); dbus_watch_set_data(dbus_watch, &socket, NULL); watch_toggled(dbus_watch, &io); return TRUE; } static void remove_watch(DBusWatch *dbus_watch, void *data) { delete static_cast( dbus_watch_get_data(dbus_watch)); } struct timeout_handler { DBusTimeout *dbus_timeout; timeout_handler(DBusTimeout *t) : dbus_timeout(t) {} void operator()(boost::system::error_code ec) { if (ec) return; dbus_timeout_handle(dbus_timeout); } }; static void timeout_toggled(DBusTimeout *dbus_timeout, void *data) { boost::asio::steady_timer &timer = *static_cast( dbus_timeout_get_data(dbus_timeout)); if (dbus_timeout_get_enabled(dbus_timeout)) { boost::asio::steady_timer::duration interval = std::chrono::milliseconds(dbus_timeout_get_interval(dbus_timeout)); timer.expires_from_now(interval); timer.cancel(); timer.async_wait(timeout_handler(dbus_timeout)); } else { timer.cancel(); } } static dbus_bool_t add_timeout(DBusTimeout *dbus_timeout, void *data) { if (!dbus_timeout_get_enabled(dbus_timeout)) return TRUE; boost::asio::io_service &io = *static_cast(data); boost::asio::steady_timer &timer = *new boost::asio::steady_timer(io); dbus_timeout_set_data(dbus_timeout, &timer, NULL); timeout_toggled(dbus_timeout, &io); return TRUE; } static void remove_timeout(DBusTimeout *dbus_timeout, void *data) { delete static_cast( dbus_timeout_get_data(dbus_timeout)); } struct dispatch_handler { boost::asio::io_service &io; DBusConnection *conn; dispatch_handler(boost::asio::io_service &i, DBusConnection *c) : io(i), conn(c) {} void operator()() { if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS) io.post(dispatch_handler(io, conn)); } }; static void dispatch_status(DBusConnection *conn, DBusDispatchStatus new_status, void *data) { boost::asio::io_service &io = *static_cast(data); if (new_status == DBUS_DISPATCH_DATA_REMAINS) io.post(dispatch_handler(io, conn)); } static void set_watch_timeout_dispatch_functions(DBusConnection *conn, boost::asio::io_service &io) { dbus_connection_set_watch_functions(conn, &add_watch, &remove_watch, &watch_toggled, &io, NULL); dbus_connection_set_timeout_functions(conn, &add_timeout, &remove_timeout, &timeout_toggled, &io, NULL); dbus_connection_set_dispatch_status_function(conn, &dispatch_status, &io, NULL); } } // namespace detail } // namespace dbus #endif // DBUS_WATCH_TIMEOUT_HPP