mainloop.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * D-Bus helper library
  5. *
  6. * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org>
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <glib.h>
  14. #include <dbus/dbus.h>
  15. #include "gdbus.h"
  16. #define info(fmt...)
  17. #define error(fmt...)
  18. #define debug(fmt...)
  19. struct timeout_handler {
  20. guint id;
  21. DBusTimeout *timeout;
  22. };
  23. struct watch_info {
  24. guint id;
  25. DBusWatch *watch;
  26. DBusConnection *conn;
  27. };
  28. struct disconnect_data {
  29. GDBusWatchFunction function;
  30. void *user_data;
  31. };
  32. static gboolean disconnected_signal(DBusConnection *conn,
  33. DBusMessage *msg, void *data)
  34. {
  35. struct disconnect_data *dc_data = data;
  36. error("Got disconnected from the system message bus");
  37. dc_data->function(conn, dc_data->user_data);
  38. dbus_connection_unref(conn);
  39. return TRUE;
  40. }
  41. static gboolean message_dispatch(void *data)
  42. {
  43. DBusConnection *conn = data;
  44. /* Dispatch messages */
  45. while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS);
  46. dbus_connection_unref(conn);
  47. return FALSE;
  48. }
  49. static inline void queue_dispatch(DBusConnection *conn,
  50. DBusDispatchStatus status)
  51. {
  52. if (status == DBUS_DISPATCH_DATA_REMAINS)
  53. g_idle_add(message_dispatch, dbus_connection_ref(conn));
  54. }
  55. static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
  56. {
  57. struct watch_info *info = data;
  58. unsigned int flags = 0;
  59. DBusDispatchStatus status;
  60. DBusConnection *conn;
  61. if (cond & G_IO_IN) flags |= DBUS_WATCH_READABLE;
  62. if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
  63. if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
  64. if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
  65. /* Protect connection from being destroyed by dbus_watch_handle */
  66. conn = dbus_connection_ref(info->conn);
  67. dbus_watch_handle(info->watch, flags);
  68. status = dbus_connection_get_dispatch_status(conn);
  69. queue_dispatch(conn, status);
  70. dbus_connection_unref(conn);
  71. return TRUE;
  72. }
  73. static void watch_info_free(void *data)
  74. {
  75. struct watch_info *info = data;
  76. if (info->id > 0) {
  77. g_source_remove(info->id);
  78. info->id = 0;
  79. }
  80. dbus_connection_unref(info->conn);
  81. g_free(info);
  82. }
  83. static dbus_bool_t add_watch(DBusWatch *watch, void *data)
  84. {
  85. DBusConnection *conn = data;
  86. GIOCondition cond = G_IO_HUP | G_IO_ERR;
  87. GIOChannel *chan;
  88. struct watch_info *info;
  89. unsigned int flags;
  90. int fd;
  91. if (!dbus_watch_get_enabled(watch))
  92. return TRUE;
  93. info = g_new0(struct watch_info, 1);
  94. fd = dbus_watch_get_unix_fd(watch);
  95. chan = g_io_channel_unix_new(fd);
  96. info->watch = watch;
  97. info->conn = dbus_connection_ref(conn);
  98. dbus_watch_set_data(watch, info, watch_info_free);
  99. flags = dbus_watch_get_flags(watch);
  100. if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
  101. if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
  102. info->id = g_io_add_watch(chan, cond, watch_func, info);
  103. g_io_channel_unref(chan);
  104. return TRUE;
  105. }
  106. static void remove_watch(DBusWatch *watch, void *data)
  107. {
  108. if (dbus_watch_get_enabled(watch))
  109. return;
  110. /* will trigger watch_info_free() */
  111. dbus_watch_set_data(watch, NULL, NULL);
  112. }
  113. static void watch_toggled(DBusWatch *watch, void *data)
  114. {
  115. /* Because we just exit on OOM, enable/disable is
  116. * no different from add/remove */
  117. if (dbus_watch_get_enabled(watch))
  118. add_watch(watch, data);
  119. else
  120. remove_watch(watch, data);
  121. }
  122. static gboolean timeout_handler_dispatch(gpointer data)
  123. {
  124. struct timeout_handler *handler = data;
  125. handler->id = 0;
  126. /* if not enabled should not be polled by the main loop */
  127. if (!dbus_timeout_get_enabled(handler->timeout))
  128. return FALSE;
  129. dbus_timeout_handle(handler->timeout);
  130. return FALSE;
  131. }
  132. static void timeout_handler_free(void *data)
  133. {
  134. struct timeout_handler *handler = data;
  135. if (handler->id > 0) {
  136. g_source_remove(handler->id);
  137. handler->id = 0;
  138. }
  139. g_free(handler);
  140. }
  141. static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
  142. {
  143. int interval = dbus_timeout_get_interval(timeout);
  144. struct timeout_handler *handler;
  145. if (!dbus_timeout_get_enabled(timeout))
  146. return TRUE;
  147. handler = g_new0(struct timeout_handler, 1);
  148. handler->timeout = timeout;
  149. dbus_timeout_set_data(timeout, handler, timeout_handler_free);
  150. handler->id = g_timeout_add(interval, timeout_handler_dispatch,
  151. handler);
  152. return TRUE;
  153. }
  154. static void remove_timeout(DBusTimeout *timeout, void *data)
  155. {
  156. /* will trigger timeout_handler_free() */
  157. dbus_timeout_set_data(timeout, NULL, NULL);
  158. }
  159. static void timeout_toggled(DBusTimeout *timeout, void *data)
  160. {
  161. if (dbus_timeout_get_enabled(timeout))
  162. add_timeout(timeout, data);
  163. else
  164. remove_timeout(timeout, data);
  165. }
  166. static void dispatch_status(DBusConnection *conn,
  167. DBusDispatchStatus status, void *data)
  168. {
  169. if (!dbus_connection_get_is_connected(conn))
  170. return;
  171. queue_dispatch(conn, status);
  172. }
  173. static inline void setup_dbus_with_main_loop(DBusConnection *conn)
  174. {
  175. dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
  176. watch_toggled, conn, NULL);
  177. dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
  178. timeout_toggled, NULL, NULL);
  179. dbus_connection_set_dispatch_status_function(conn, dispatch_status,
  180. NULL, NULL);
  181. }
  182. static gboolean setup_bus(DBusConnection *conn, const char *name,
  183. DBusError *error)
  184. {
  185. gboolean result;
  186. DBusDispatchStatus status;
  187. if (name != NULL) {
  188. result = g_dbus_request_name(conn, name, error);
  189. if (error != NULL) {
  190. if (dbus_error_is_set(error) == TRUE)
  191. return FALSE;
  192. }
  193. if (result == FALSE)
  194. return FALSE;
  195. }
  196. setup_dbus_with_main_loop(conn);
  197. status = dbus_connection_get_dispatch_status(conn);
  198. queue_dispatch(conn, status);
  199. return TRUE;
  200. }
  201. DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
  202. DBusError *error)
  203. {
  204. DBusConnection *conn;
  205. conn = dbus_bus_get(type, error);
  206. if (error != NULL) {
  207. if (dbus_error_is_set(error) == TRUE)
  208. return NULL;
  209. }
  210. if (conn == NULL)
  211. return NULL;
  212. if (setup_bus(conn, name, error) == FALSE) {
  213. dbus_connection_unref(conn);
  214. return NULL;
  215. }
  216. return conn;
  217. }
  218. DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
  219. DBusError *error)
  220. {
  221. DBusConnection *conn;
  222. conn = dbus_bus_get_private(type, error);
  223. if (error != NULL) {
  224. if (dbus_error_is_set(error) == TRUE)
  225. return NULL;
  226. }
  227. if (conn == NULL)
  228. return NULL;
  229. if (setup_bus(conn, name, error) == FALSE) {
  230. dbus_connection_close(conn);
  231. dbus_connection_unref(conn);
  232. return NULL;
  233. }
  234. return conn;
  235. }
  236. gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
  237. DBusError *error)
  238. {
  239. int result;
  240. result = dbus_bus_request_name(connection, name,
  241. DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
  242. if (error != NULL) {
  243. if (dbus_error_is_set(error) == TRUE)
  244. return FALSE;
  245. }
  246. if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
  247. if (error != NULL)
  248. dbus_set_error(error, name, "Name already in use");
  249. return FALSE;
  250. }
  251. return TRUE;
  252. }
  253. gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
  254. GDBusWatchFunction function,
  255. void *user_data, DBusFreeFunction destroy)
  256. {
  257. struct disconnect_data *dc_data;
  258. dc_data = g_new0(struct disconnect_data, 1);
  259. dc_data->function = function;
  260. dc_data->user_data = user_data;
  261. dbus_connection_set_exit_on_disconnect(connection, FALSE);
  262. if (g_dbus_add_signal_watch(connection, NULL, NULL,
  263. DBUS_INTERFACE_LOCAL, "Disconnected",
  264. disconnected_signal, dc_data, g_free) == 0) {
  265. error("Failed to add watch for D-Bus Disconnected signal");
  266. g_free(dc_data);
  267. return FALSE;
  268. }
  269. return TRUE;
  270. }