xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

dbus-core.c (6776B)


      1 /*
      2  * Copyright © 2006-2007 Daniel Stone
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  *
     23  * Author: Daniel Stone <daniel@fooishbar.org>
     24  */
     25 
     26 #ifdef HAVE_DIX_CONFIG_H
     27 #include <dix-config.h>
     28 #endif
     29 
     30 #include <dbus/dbus.h>
     31 #include <sys/select.h>
     32 
     33 #include "dix.h"
     34 #include "os.h"
     35 #include "dbus-core.h"
     36 
     37 /* How often to attempt reconnecting when we get booted off the bus. */
     38 #define RECONNECT_DELAY (10 * 1000)     /* in ms */
     39 
     40 struct dbus_core_info {
     41     int fd;
     42     DBusConnection *connection;
     43     OsTimerPtr timer;
     44     struct dbus_core_hook *hooks;
     45 };
     46 static struct dbus_core_info bus_info = { .fd = -1 };
     47 
     48 static CARD32 reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg);
     49 
     50 static void
     51 socket_handler(int fd, int ready, void *data)
     52 {
     53     struct dbus_core_info *info = data;
     54 
     55     if (info->connection) {
     56         do {
     57             dbus_connection_read_write_dispatch(info->connection, 0);
     58         } while (info->connection &&
     59                  dbus_connection_get_is_connected(info->connection) &&
     60                  dbus_connection_get_dispatch_status(info->connection) ==
     61                  DBUS_DISPATCH_DATA_REMAINS);
     62     }
     63 }
     64 
     65 /**
     66  * Disconnect (if we haven't already been forcefully disconnected), clean up
     67  * after ourselves, and call all registered disconnect hooks.
     68  */
     69 static void
     70 teardown(void)
     71 {
     72     struct dbus_core_hook *hook;
     73 
     74     if (bus_info.timer) {
     75         TimerFree(bus_info.timer);
     76         bus_info.timer = NULL;
     77     }
     78 
     79     /* We should really have pre-disconnect hooks and run them here, for
     80      * completeness.  But then it gets awkward, given that you can't
     81      * guarantee that they'll be called ... */
     82     if (bus_info.connection)
     83         dbus_connection_unref(bus_info.connection);
     84 
     85     if (bus_info.fd != -1)
     86         RemoveNotifyFd(bus_info.fd);
     87     bus_info.fd = -1;
     88     bus_info.connection = NULL;
     89 
     90     for (hook = bus_info.hooks; hook; hook = hook->next) {
     91         if (hook->disconnect)
     92             hook->disconnect(hook->data);
     93     }
     94 }
     95 
     96 /**
     97  * This is a filter, which only handles the disconnected signal, which
     98  * doesn't go to the normal message handling function.  This takes
     99  * precedence over the message handling function, so have have to be
    100  * careful to ignore anything we don't want to deal with here.
    101  */
    102 static DBusHandlerResult
    103 message_filter(DBusConnection * connection, DBusMessage * message, void *data)
    104 {
    105     /* If we get disconnected, then take everything down, and attempt to
    106      * reconnect immediately (assuming it's just a restart).  The
    107      * connection isn't valid at this point, so throw it out immediately. */
    108     if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
    109         DebugF("[dbus-core] disconnected from bus\n");
    110         bus_info.connection = NULL;
    111         teardown();
    112 
    113         if (bus_info.timer)
    114             TimerFree(bus_info.timer);
    115         bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
    116 
    117         return DBUS_HANDLER_RESULT_HANDLED;
    118     }
    119 
    120     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    121 }
    122 
    123 /**
    124  * Attempt to connect to the system bus, and set a filter to deal with
    125  * disconnection (see message_filter above).
    126  *
    127  * @return 1 on success, 0 on failure.
    128  */
    129 static int
    130 connect_to_bus(void)
    131 {
    132     DBusError error;
    133     struct dbus_core_hook *hook;
    134 
    135     dbus_error_init(&error);
    136     bus_info.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
    137     if (!bus_info.connection || dbus_error_is_set(&error)) {
    138         LogMessage(X_ERROR, "dbus-core: error connecting to system bus: %s (%s)\n",
    139                error.name, error.message);
    140         goto err_begin;
    141     }
    142 
    143     /* Thankyou.  Really, thankyou. */
    144     dbus_connection_set_exit_on_disconnect(bus_info.connection, FALSE);
    145 
    146     if (!dbus_connection_get_unix_fd(bus_info.connection, &bus_info.fd)) {
    147         ErrorF("[dbus-core] couldn't get fd for system bus\n");
    148         goto err_unref;
    149     }
    150 
    151     if (!dbus_connection_add_filter(bus_info.connection, message_filter,
    152                                     &bus_info, NULL)) {
    153         ErrorF("[dbus-core] couldn't add filter: %s (%s)\n", error.name,
    154                error.message);
    155         goto err_fd;
    156     }
    157 
    158     dbus_error_free(&error);
    159     SetNotifyFd(bus_info.fd, socket_handler, X_NOTIFY_READ, &bus_info);
    160 
    161     for (hook = bus_info.hooks; hook; hook = hook->next) {
    162         if (hook->connect)
    163             hook->connect(bus_info.connection, hook->data);
    164     }
    165 
    166     return 1;
    167 
    168  err_fd:
    169     bus_info.fd = -1;
    170  err_unref:
    171     dbus_connection_unref(bus_info.connection);
    172     bus_info.connection = NULL;
    173  err_begin:
    174     dbus_error_free(&error);
    175 
    176     return 0;
    177 }
    178 
    179 static CARD32
    180 reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg)
    181 {
    182     if (connect_to_bus()) {
    183         TimerFree(bus_info.timer);
    184         bus_info.timer = NULL;
    185         return 0;
    186     }
    187     else {
    188         return RECONNECT_DELAY;
    189     }
    190 }
    191 
    192 int
    193 dbus_core_add_hook(struct dbus_core_hook *hook)
    194 {
    195     struct dbus_core_hook **prev;
    196 
    197     for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next);
    198 
    199     hook->next = NULL;
    200     *prev = hook;
    201 
    202     /* If we're already connected, call the connect hook. */
    203     if (bus_info.connection)
    204         hook->connect(bus_info.connection, hook->data);
    205 
    206     return 1;
    207 }
    208 
    209 void
    210 dbus_core_remove_hook(struct dbus_core_hook *hook)
    211 {
    212     struct dbus_core_hook **prev;
    213 
    214     for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next) {
    215         if (*prev == hook) {
    216             *prev = hook->next;
    217             break;
    218         }
    219     }
    220 }
    221 
    222 int
    223 dbus_core_init(void)
    224 {
    225     memset(&bus_info, 0, sizeof(bus_info));
    226     bus_info.fd = -1;
    227     bus_info.hooks = NULL;
    228     if (!connect_to_bus())
    229         bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
    230 
    231     return 1;
    232 }
    233 
    234 void
    235 dbus_core_fini(void)
    236 {
    237     teardown();
    238 }