dbus_common.c
Go to the documentation of this file.
00001 /*
00002  * wpa_supplicant D-Bus control interface - common functionality
00003  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
00004  * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
00005  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License version 2 as
00009  * published by the Free Software Foundation.
00010  *
00011  * Alternatively, this software may be distributed under the terms of BSD
00012  * license.
00013  *
00014  * See README and COPYING for more details.
00015  */
00016 
00017 #include "utils/includes.h"
00018 #include <dbus/dbus.h>
00019 
00020 #include "utils/common.h"
00021 #include "utils/eloop.h"
00022 #include "dbus_common.h"
00023 #include "dbus_common_i.h"
00024 #include "dbus_new.h"
00025 #include "dbus_old.h"
00026 
00027 
00028 #ifndef SIGPOLL
00029 #ifdef SIGIO
00030 /*
00031  * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
00032  * FreeBSD.
00033  */
00034 #define SIGPOLL SIGIO
00035 #endif
00036 #endif
00037 
00038 
00039 static void dispatch_data(DBusConnection *con)
00040 {
00041         while (dbus_connection_get_dispatch_status(con) ==
00042                DBUS_DISPATCH_DATA_REMAINS)
00043                 dbus_connection_dispatch(con);
00044 }
00045 
00046 
00057 static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
00058 {
00059         DBusConnection *con = eloop_ctx;
00060         dispatch_data(con);
00061 }
00062 
00063 
00064 static void process_watch(struct wpas_dbus_priv *priv,
00065                           DBusWatch *watch, eloop_event_type type)
00066 {
00067         dbus_connection_ref(priv->con);
00068 
00069         priv->should_dispatch = 0;
00070 
00071         if (type == EVENT_TYPE_READ)
00072                 dbus_watch_handle(watch, DBUS_WATCH_READABLE);
00073         else if (type == EVENT_TYPE_WRITE)
00074                 dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
00075         else if (type == EVENT_TYPE_EXCEPTION)
00076                 dbus_watch_handle(watch, DBUS_WATCH_ERROR);
00077 
00078         if (priv->should_dispatch) {
00079                 dispatch_data(priv->con);
00080                 priv->should_dispatch = 0;
00081         }
00082 
00083         dbus_connection_unref(priv->con);
00084 }
00085 
00086 
00087 static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
00088 {
00089         process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
00090 }
00091 
00092 
00093 static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
00094 {
00095         process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
00096 }
00097 
00098 
00099 static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
00100 {
00101         process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
00102 }
00103 
00104 
00105 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
00106 {
00107         struct wpas_dbus_priv *priv = data;
00108         unsigned int flags;
00109         int fd;
00110 
00111         if (!dbus_watch_get_enabled(watch))
00112                 return TRUE;
00113 
00114         flags = dbus_watch_get_flags(watch);
00115         fd = dbus_watch_get_unix_fd(watch);
00116 
00117         eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
00118                             priv, watch);
00119 
00120         if (flags & DBUS_WATCH_READABLE) {
00121                 eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
00122                                     priv, watch);
00123         }
00124         if (flags & DBUS_WATCH_WRITABLE) {
00125                 eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
00126                                     priv, watch);
00127         }
00128 
00129         dbus_watch_set_data(watch, priv, NULL);
00130 
00131         return TRUE;
00132 }
00133 
00134 
00135 static void remove_watch(DBusWatch *watch, void *data)
00136 {
00137         unsigned int flags;
00138         int fd;
00139 
00140         flags = dbus_watch_get_flags(watch);
00141         fd = dbus_watch_get_unix_fd(watch);
00142 
00143         eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
00144 
00145         if (flags & DBUS_WATCH_READABLE)
00146                 eloop_unregister_sock(fd, EVENT_TYPE_READ);
00147         if (flags & DBUS_WATCH_WRITABLE)
00148                 eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
00149 
00150         dbus_watch_set_data(watch, NULL, NULL);
00151 }
00152 
00153 
00154 static void watch_toggled(DBusWatch *watch, void *data)
00155 {
00156         if (dbus_watch_get_enabled(watch))
00157                 add_watch(watch, data);
00158         else
00159                 remove_watch(watch, data);
00160 }
00161 
00162 
00163 static void process_timeout(void *eloop_ctx, void *sock_ctx)
00164 {
00165         DBusTimeout *timeout = sock_ctx;
00166         dbus_timeout_handle(timeout);
00167 }
00168 
00169 
00170 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
00171 {
00172         struct wpas_dbus_priv *priv = data;
00173         if (!dbus_timeout_get_enabled(timeout))
00174                 return TRUE;
00175 
00176         eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
00177                                process_timeout, priv, timeout);
00178 
00179         dbus_timeout_set_data(timeout, priv, NULL);
00180 
00181         return TRUE;
00182 }
00183 
00184 
00185 static void remove_timeout(DBusTimeout *timeout, void *data)
00186 {
00187         struct wpas_dbus_priv *priv = data;
00188         eloop_cancel_timeout(process_timeout, priv, timeout);
00189         dbus_timeout_set_data(timeout, NULL, NULL);
00190 }
00191 
00192 
00193 static void timeout_toggled(DBusTimeout *timeout, void *data)
00194 {
00195         if (dbus_timeout_get_enabled(timeout))
00196                 add_timeout(timeout, data);
00197         else
00198                 remove_timeout(timeout, data);
00199 }
00200 
00201 
00202 static void process_wakeup_main(int sig, void *signal_ctx)
00203 {
00204         struct wpas_dbus_priv *priv = signal_ctx;
00205 
00206         if (sig != SIGPOLL || !priv->con)
00207                 return;
00208 
00209         if (dbus_connection_get_dispatch_status(priv->con) !=
00210             DBUS_DISPATCH_DATA_REMAINS)
00211                 return;
00212 
00213         /* Only dispatch once - we do not want to starve other events */
00214         dbus_connection_ref(priv->con);
00215         dbus_connection_dispatch(priv->con);
00216         dbus_connection_unref(priv->con);
00217 }
00218 
00219 
00227 static void wakeup_main(void *data)
00228 {
00229         struct wpas_dbus_priv *priv = data;
00230 
00231         /* Use SIGPOLL to break out of the eloop select() */
00232         raise(SIGPOLL);
00233         priv->should_dispatch = 1;
00234 }
00235 
00236 
00243 static int integrate_with_eloop(struct wpas_dbus_priv *priv)
00244 {
00245         if (!dbus_connection_set_watch_functions(priv->con, add_watch,
00246                                                  remove_watch, watch_toggled,
00247                                                  priv, NULL) ||
00248             !dbus_connection_set_timeout_functions(priv->con, add_timeout,
00249                                                    remove_timeout,
00250                                                    timeout_toggled, priv,
00251                                                    NULL)) {
00252                 wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
00253                            "functions");
00254                 return -1;
00255         }
00256 
00257         if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv))
00258                 return -1;
00259         dbus_connection_set_wakeup_main_function(priv->con, wakeup_main,
00260                                                  priv, NULL);
00261 
00262         return 0;
00263 }
00264 
00265 
00266 static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
00267 {
00268         DBusError error;
00269         int ret = 0;
00270 
00271         /* Get a reference to the system bus */
00272         dbus_error_init(&error);
00273         priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
00274         if (!priv->con) {
00275                 wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
00276                            "bus: %s - %s", error.name, error.message);
00277                 ret = -1;
00278         }
00279         dbus_error_free(&error);
00280 
00281         return ret;
00282 }
00283 
00284 
00285 static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
00286 {
00287         /* Tell dbus about our mainloop integration functions */
00288         integrate_with_eloop(priv);
00289 
00290         /*
00291          * Dispatch initial DBus messages that may have come in since the bus
00292          * name was claimed above. Happens when clients are quick to notice the
00293          * service.
00294          *
00295          * FIXME: is there a better solution to this problem?
00296          */
00297         eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
00298                                priv->con, NULL);
00299 
00300         return 0;
00301 }
00302 
00303 
00304 static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
00305 {
00306         if (priv->con) {
00307                 eloop_cancel_timeout(dispatch_initial_dbus_messages,
00308                                      priv->con, NULL);
00309                 dbus_connection_set_watch_functions(priv->con, NULL, NULL,
00310                                                     NULL, NULL, NULL);
00311                 dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
00312                                                       NULL, NULL, NULL);
00313                 dbus_connection_unref(priv->con);
00314         }
00315 
00316         os_free(priv);
00317 }
00318 
00319 
00320 struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
00321 {
00322         struct wpas_dbus_priv *priv;
00323 
00324         priv = os_zalloc(sizeof(*priv));
00325         if (priv == NULL)
00326                 return NULL;
00327         priv->global = global;
00328 
00329         if (wpas_dbus_init_common(priv) < 0) {
00330                 wpas_dbus_deinit(priv);
00331                 return NULL;
00332         }
00333 
00334 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
00335         if (wpas_dbus_ctrl_iface_init(priv) < 0) {
00336                 wpas_dbus_deinit(priv);
00337                 return NULL;
00338         }
00339 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
00340 
00341 #ifdef CONFIG_CTRL_IFACE_DBUS
00342         if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
00343                 wpas_dbus_deinit(priv);
00344                 return NULL;
00345         }
00346 #endif /* CONFIG_CTRL_IFACE_DBUS */
00347 
00348         if (wpas_dbus_init_common_finish(priv) < 0) {
00349                 wpas_dbus_deinit(priv);
00350                 return NULL;
00351         }
00352 
00353         return priv;
00354 }
00355 
00356 
00357 void wpas_dbus_deinit(struct wpas_dbus_priv *priv)
00358 {
00359         if (priv == NULL)
00360                 return;
00361 
00362 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
00363         wpas_dbus_ctrl_iface_deinit(priv);
00364 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
00365 
00366 #ifdef CONFIG_CTRL_IFACE_DBUS
00367         /* TODO: is any deinit needed? */
00368 #endif /* CONFIG_CTRL_IFACE_DBUS */
00369 
00370         wpas_dbus_deinit_common(priv);
00371 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:36