選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

dbus_common.c 8.5KB

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