dbus_common.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * wpa_supplicant D-Bus control interface - common functionality
  3. * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  4. * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  5. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  6. *
  7. * This software may be distributed under the terms of the BSD license.
  8. * See README for more details.
  9. */
  10. #include "utils/includes.h"
  11. #include <dbus/dbus.h>
  12. #include "utils/common.h"
  13. #include "utils/eloop.h"
  14. #include "dbus_common.h"
  15. #include "dbus_common_i.h"
  16. #include "dbus_new.h"
  17. #include "dbus_old.h"
  18. #ifndef SIGPOLL
  19. #ifdef SIGIO
  20. /*
  21. * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
  22. * FreeBSD.
  23. */
  24. #define SIGPOLL SIGIO
  25. #endif
  26. #endif
  27. static void dispatch_data(DBusConnection *con)
  28. {
  29. while (dbus_connection_get_dispatch_status(con) ==
  30. DBUS_DISPATCH_DATA_REMAINS)
  31. dbus_connection_dispatch(con);
  32. }
  33. /**
  34. * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
  35. * claiming bus name
  36. * @eloop_ctx: the DBusConnection to dispatch on
  37. * @timeout_ctx: unused
  38. *
  39. * If clients are quick to notice that service claimed its bus name,
  40. * there may have been messages that came in before initialization was
  41. * all finished. Dispatch those here.
  42. */
  43. static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
  44. {
  45. DBusConnection *con = eloop_ctx;
  46. dispatch_data(con);
  47. }
  48. static void process_watch(struct wpas_dbus_priv *priv,
  49. DBusWatch *watch, eloop_event_type type)
  50. {
  51. dbus_connection_ref(priv->con);
  52. priv->should_dispatch = 0;
  53. if (type == EVENT_TYPE_READ)
  54. dbus_watch_handle(watch, DBUS_WATCH_READABLE);
  55. else if (type == EVENT_TYPE_WRITE)
  56. dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
  57. else if (type == EVENT_TYPE_EXCEPTION)
  58. dbus_watch_handle(watch, DBUS_WATCH_ERROR);
  59. if (priv->should_dispatch) {
  60. dispatch_data(priv->con);
  61. priv->should_dispatch = 0;
  62. }
  63. dbus_connection_unref(priv->con);
  64. }
  65. static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
  66. {
  67. process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
  68. }
  69. static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
  70. {
  71. process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
  72. }
  73. static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
  74. {
  75. process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
  76. }
  77. static dbus_bool_t add_watch(DBusWatch *watch, void *data)
  78. {
  79. struct wpas_dbus_priv *priv = data;
  80. unsigned int flags;
  81. int fd;
  82. if (!dbus_watch_get_enabled(watch))
  83. return TRUE;
  84. flags = dbus_watch_get_flags(watch);
  85. fd = dbus_watch_get_unix_fd(watch);
  86. eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
  87. priv, watch);
  88. if (flags & DBUS_WATCH_READABLE) {
  89. eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
  90. priv, watch);
  91. }
  92. if (flags & DBUS_WATCH_WRITABLE) {
  93. eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
  94. priv, watch);
  95. }
  96. dbus_watch_set_data(watch, priv, NULL);
  97. return TRUE;
  98. }
  99. static void remove_watch(DBusWatch *watch, void *data)
  100. {
  101. unsigned int flags;
  102. int fd;
  103. flags = dbus_watch_get_flags(watch);
  104. fd = dbus_watch_get_unix_fd(watch);
  105. eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
  106. if (flags & DBUS_WATCH_READABLE)
  107. eloop_unregister_sock(fd, EVENT_TYPE_READ);
  108. if (flags & DBUS_WATCH_WRITABLE)
  109. eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
  110. dbus_watch_set_data(watch, NULL, NULL);
  111. }
  112. static void watch_toggled(DBusWatch *watch, void *data)
  113. {
  114. if (dbus_watch_get_enabled(watch))
  115. add_watch(watch, data);
  116. else
  117. remove_watch(watch, data);
  118. }
  119. static void process_timeout(void *eloop_ctx, void *sock_ctx)
  120. {
  121. DBusTimeout *timeout = sock_ctx;
  122. dbus_timeout_handle(timeout);
  123. }
  124. static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
  125. {
  126. struct wpas_dbus_priv *priv = data;
  127. if (!dbus_timeout_get_enabled(timeout))
  128. return TRUE;
  129. eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
  130. process_timeout, priv, timeout);
  131. dbus_timeout_set_data(timeout, priv, NULL);
  132. return TRUE;
  133. }
  134. static void remove_timeout(DBusTimeout *timeout, void *data)
  135. {
  136. struct wpas_dbus_priv *priv = data;
  137. eloop_cancel_timeout(process_timeout, priv, timeout);
  138. dbus_timeout_set_data(timeout, NULL, NULL);
  139. }
  140. static void timeout_toggled(DBusTimeout *timeout, void *data)
  141. {
  142. if (dbus_timeout_get_enabled(timeout))
  143. add_timeout(timeout, data);
  144. else
  145. remove_timeout(timeout, data);
  146. }
  147. static void process_wakeup_main(int sig, void *signal_ctx)
  148. {
  149. struct wpas_dbus_priv *priv = signal_ctx;
  150. if (sig != SIGPOLL || !priv->con)
  151. return;
  152. if (dbus_connection_get_dispatch_status(priv->con) !=
  153. DBUS_DISPATCH_DATA_REMAINS)
  154. return;
  155. /* Only dispatch once - we do not want to starve other events */
  156. dbus_connection_ref(priv->con);
  157. dbus_connection_dispatch(priv->con);
  158. dbus_connection_unref(priv->con);
  159. }
  160. /**
  161. * wakeup_main - Attempt to wake our mainloop up
  162. * @data: dbus control interface private data
  163. *
  164. * Try to wake up the main eloop so it will process
  165. * dbus events that may have happened.
  166. */
  167. static void wakeup_main(void *data)
  168. {
  169. struct wpas_dbus_priv *priv = data;
  170. /* Use SIGPOLL to break out of the eloop select() */
  171. raise(SIGPOLL);
  172. priv->should_dispatch = 1;
  173. }
  174. /**
  175. * integrate_with_eloop - Register our mainloop integration with dbus
  176. * @connection: connection to the system message bus
  177. * @priv: a dbus control interface data structure
  178. * Returns: 0 on success, -1 on failure
  179. */
  180. static int integrate_with_eloop(struct wpas_dbus_priv *priv)
  181. {
  182. if (!dbus_connection_set_watch_functions(priv->con, add_watch,
  183. remove_watch, watch_toggled,
  184. priv, NULL) ||
  185. !dbus_connection_set_timeout_functions(priv->con, add_timeout,
  186. remove_timeout,
  187. timeout_toggled, priv,
  188. NULL)) {
  189. wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
  190. "functions");
  191. return -1;
  192. }
  193. if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv))
  194. return -1;
  195. dbus_connection_set_wakeup_main_function(priv->con, wakeup_main,
  196. priv, NULL);
  197. return 0;
  198. }
  199. static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
  200. {
  201. DBusError error;
  202. int ret = 0;
  203. /* Get a reference to the system bus */
  204. dbus_error_init(&error);
  205. priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
  206. if (!priv->con) {
  207. wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
  208. "bus: %s - %s", error.name, error.message);
  209. ret = -1;
  210. }
  211. dbus_error_free(&error);
  212. return ret;
  213. }
  214. static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
  215. {
  216. /* Tell dbus about our mainloop integration functions */
  217. integrate_with_eloop(priv);
  218. /*
  219. * Dispatch initial DBus messages that may have come in since the bus
  220. * name was claimed above. Happens when clients are quick to notice the
  221. * service.
  222. *
  223. * FIXME: is there a better solution to this problem?
  224. */
  225. eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
  226. priv->con, NULL);
  227. return 0;
  228. }
  229. static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
  230. {
  231. if (priv->con) {
  232. eloop_cancel_timeout(dispatch_initial_dbus_messages,
  233. priv->con, NULL);
  234. dbus_connection_set_watch_functions(priv->con, NULL, NULL,
  235. NULL, NULL, NULL);
  236. dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
  237. NULL, NULL, NULL);
  238. dbus_connection_unref(priv->con);
  239. }
  240. os_free(priv);
  241. }
  242. struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
  243. {
  244. struct wpas_dbus_priv *priv;
  245. priv = os_zalloc(sizeof(*priv));
  246. if (priv == NULL)
  247. return NULL;
  248. priv->global = global;
  249. if (wpas_dbus_init_common(priv) < 0) {
  250. wpas_dbus_deinit(priv);
  251. return NULL;
  252. }
  253. #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
  254. if (wpas_dbus_ctrl_iface_init(priv) < 0) {
  255. wpas_dbus_deinit(priv);
  256. return NULL;
  257. }
  258. #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
  259. #ifdef CONFIG_CTRL_IFACE_DBUS
  260. if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
  261. wpas_dbus_deinit(priv);
  262. return NULL;
  263. }
  264. #endif /* CONFIG_CTRL_IFACE_DBUS */
  265. if (wpas_dbus_init_common_finish(priv) < 0) {
  266. wpas_dbus_deinit(priv);
  267. return NULL;
  268. }
  269. return priv;
  270. }
  271. void wpas_dbus_deinit(struct wpas_dbus_priv *priv)
  272. {
  273. if (priv == NULL)
  274. return;
  275. #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
  276. wpas_dbus_ctrl_iface_deinit(priv);
  277. #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
  278. #ifdef CONFIG_CTRL_IFACE_DBUS
  279. /* TODO: is any deinit needed? */
  280. #endif /* CONFIG_CTRL_IFACE_DBUS */
  281. wpas_dbus_deinit_common(priv);
  282. }