dbus_common.c 9.5 KB

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