1 /* 2 * Copyright 2007-2020 CM4all GmbH 3 * All rights reserved. 4 * 5 * author: Max Kellermann <mk@cm4all.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * - Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 * OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #ifndef ODBUS_WATCH_HXX 34 #define ODBUS_WATCH_HXX 35 36 #include "Connection.hxx" 37 #include "event/SocketEvent.hxx" 38 #include "event/DeferEvent.hxx" 39 40 #include <dbus/dbus.h> 41 42 #include <map> 43 44 class EventLoop; 45 46 namespace ODBus { 47 48 class WatchManagerObserver { 49 public: 50 virtual void OnDBusClosed() noexcept = 0; 51 }; 52 53 /** 54 * Integrate a DBusConnection into the #EventLoop. 55 */ 56 class WatchManager { 57 WatchManagerObserver &observer; 58 59 Connection connection; 60 61 class Watch { 62 WatchManager &parent; 63 DBusWatch &watch; 64 SocketEvent event; 65 66 public: 67 Watch(EventLoop &event_loop, WatchManager &_parent, 68 DBusWatch &_watch) noexcept; 69 70 void Toggled() noexcept; 71 72 private: 73 void OnSocketReady(unsigned events) noexcept; 74 }; 75 76 std::map<DBusWatch *, Watch> watches; 77 78 DeferEvent defer_dispatch; 79 80 public: WatchManager(EventLoop & event_loop,WatchManagerObserver & _observer)81 WatchManager(EventLoop &event_loop, 82 WatchManagerObserver &_observer) noexcept 83 :observer(_observer), 84 defer_dispatch(event_loop, BIND_THIS_METHOD(Dispatch)) 85 { 86 } 87 88 template<typename C> WatchManager(EventLoop & event_loop,WatchManagerObserver & _observer,C && _connection)89 WatchManager(EventLoop &event_loop, WatchManagerObserver &_observer, 90 C &&_connection) noexcept 91 :WatchManager(event_loop, _observer) 92 { 93 SetConnection(std::forward<C>(_connection)); 94 } 95 ~WatchManager()96 ~WatchManager() noexcept { 97 Shutdown(); 98 } 99 100 WatchManager(const WatchManager &) = delete; 101 WatchManager &operator=(const WatchManager &) = delete; 102 103 void Shutdown() noexcept; 104 GetEventLoop() const105 auto &GetEventLoop() const noexcept { 106 return defer_dispatch.GetEventLoop(); 107 } 108 GetConnection()109 Connection &GetConnection() noexcept { 110 return connection; 111 } 112 113 template<typename C> SetConnection(C && _connection)114 void SetConnection(C &&_connection) noexcept { 115 Shutdown(); 116 117 connection = std::forward<C>(_connection); 118 119 if (connection) 120 dbus_connection_set_watch_functions(connection, 121 AddFunction, 122 RemoveFunction, 123 ToggledFunction, 124 (void *)this, 125 nullptr); 126 } 127 128 private: ScheduleDispatch()129 void ScheduleDispatch() noexcept { 130 defer_dispatch.Schedule(); 131 } 132 133 void Dispatch() noexcept; 134 135 bool Add(DBusWatch *watch) noexcept; 136 void Remove(DBusWatch *watch) noexcept; 137 void Toggled(DBusWatch *watch) noexcept; 138 AddFunction(DBusWatch * watch,void * data)139 static dbus_bool_t AddFunction(DBusWatch *watch, void *data) noexcept { 140 auto &wm = *(WatchManager *)data; 141 return wm.Add(watch); 142 } 143 RemoveFunction(DBusWatch * watch,void * data)144 static void RemoveFunction(DBusWatch *watch, void *data) noexcept { 145 auto &wm = *(WatchManager *)data; 146 wm.Remove(watch); 147 } 148 ToggledFunction(DBusWatch * watch,void * data)149 static void ToggledFunction(DBusWatch *watch, void *data) noexcept { 150 auto &wm = *(WatchManager *)data; 151 wm.Toggled(watch); 152 } 153 }; 154 155 } /* namespace ODBus */ 156 157 #endif 158