config: bus reconnect support
Add support for reconnecting to the bus when it restarts.
This commit is contained in:
parent
0c5dab5c8e
commit
4cba1a1ebf
131
config/config.c
131
config/config.c
|
@ -36,10 +36,10 @@
|
||||||
/* the above comment lies. there is no better way. */
|
/* the above comment lies. there is no better way. */
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "inputstr.h"
|
#include "inputstr.h"
|
||||||
#include "config.h"
|
#include "hotplug.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
#define MATCH_RULE "type='method_call',interface='org.x.config.input'"
|
#define CONFIG_MATCH_RULE "type='method_call',interface='org.x.config.input'"
|
||||||
|
|
||||||
#define MALFORMED_MSG "[config] malformed message, dropping"
|
#define MALFORMED_MSG "[config] malformed message, dropping"
|
||||||
#define MALFORMED_MESSAGE() { DebugF(MALFORMED_MSG "\n"); \
|
#define MALFORMED_MESSAGE() { DebugF(MALFORMED_MSG "\n"); \
|
||||||
|
@ -50,6 +50,9 @@
|
||||||
ret = BadValue; \
|
ret = BadValue; \
|
||||||
goto unwind; }
|
goto unwind; }
|
||||||
|
|
||||||
|
/* How often to attempt reconnecting when we get booted off the bus. */
|
||||||
|
#define RECONNECT_DELAY 10000 /* in ms */
|
||||||
|
|
||||||
struct config_data {
|
struct config_data {
|
||||||
int fd;
|
int fd;
|
||||||
DBusConnection *connection;
|
DBusConnection *connection;
|
||||||
|
@ -59,6 +62,8 @@ struct config_data {
|
||||||
|
|
||||||
static struct config_data *configData;
|
static struct config_data *configData;
|
||||||
|
|
||||||
|
static CARD32 configReconnect(OsTimerPtr timer, CARD32 time, pointer arg);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
configWakeupHandler(pointer blockData, int err, pointer pReadMask)
|
configWakeupHandler(pointer blockData, int err, pointer pReadMask)
|
||||||
{
|
{
|
||||||
|
@ -73,6 +78,18 @@ configBlockHandler(pointer data, struct timeval **tv, pointer pReadMask)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
configTeardown(void)
|
||||||
|
{
|
||||||
|
if (configData) {
|
||||||
|
RemoveGeneralSocket(configData->fd);
|
||||||
|
RemoveBlockAndWakeupHandlers(configBlockHandler, configWakeupHandler,
|
||||||
|
configData);
|
||||||
|
xfree(configData);
|
||||||
|
configData = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
configAddDevice(DBusMessage *message, DBusMessageIter *iter, DBusError *error)
|
configAddDevice(DBusMessage *message, DBusMessageIter *iter, DBusError *error)
|
||||||
{
|
{
|
||||||
|
@ -226,8 +243,6 @@ configMessage(DBusConnection *connection, DBusMessage *message, void *closure)
|
||||||
ret = configAddDevice(message, &iter, &error);
|
ret = configAddDevice(message, &iter, &error);
|
||||||
else if (strcmp(dbus_message_get_member(message), "remove") == 0)
|
else if (strcmp(dbus_message_get_member(message), "remove") == 0)
|
||||||
ret = configRemoveDevice(message, &iter, &error);
|
ret = configRemoveDevice(message, &iter, &error);
|
||||||
}
|
|
||||||
|
|
||||||
if (ret != BadDrawable && ret != BadAlloc) {
|
if (ret != BadDrawable && ret != BadAlloc) {
|
||||||
reply = dbus_message_new_method_return(message);
|
reply = dbus_message_new_method_return(message);
|
||||||
dbus_message_iter_init_append(reply, &iter);
|
dbus_message_iter_init_append(reply, &iter);
|
||||||
|
@ -244,6 +259,7 @@ configMessage(DBusConnection *connection, DBusMessage *message, void *closure)
|
||||||
|
|
||||||
dbus_message_unref(reply);
|
dbus_message_unref(reply);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dbus_error_free(&error);
|
dbus_error_free(&error);
|
||||||
|
|
||||||
|
@ -255,16 +271,40 @@ configMessage(DBusConnection *connection, DBusMessage *message, void *closure)
|
||||||
return DBUS_HANDLER_RESULT_HANDLED;
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/**
|
||||||
configInitialise()
|
* This is a filter, which only handles the disconnected signal, which
|
||||||
|
* doesn't go to the normal message handling function. This takes
|
||||||
|
* precedence over the message handling function, so have have to be
|
||||||
|
* careful to ignore anything we don't want to deal with here.
|
||||||
|
*
|
||||||
|
* Yes, this is brutally stupid.
|
||||||
|
*/
|
||||||
|
static DBusHandlerResult
|
||||||
|
configFilter(DBusConnection *connection, DBusMessage *message, void *closure)
|
||||||
|
{
|
||||||
|
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
|
||||||
|
"Disconnected")) {
|
||||||
|
ErrorF("[dbus] disconnected from bus\n");
|
||||||
|
TimerSet(NULL, 0, RECONNECT_DELAY, configReconnect, NULL);
|
||||||
|
configTeardown();
|
||||||
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
configSetup(void)
|
||||||
{
|
{
|
||||||
DBusError error;
|
DBusError error;
|
||||||
DBusObjectPathVTable vtable = { .message_function = configMessage };
|
DBusObjectPathVTable vtable = { .message_function = configMessage };
|
||||||
|
|
||||||
if (!configData)
|
if (!configData)
|
||||||
configData = (struct config_data *) xcalloc(sizeof(struct config_data), 1);
|
configData = (struct config_data *) xcalloc(sizeof(struct config_data), 1);
|
||||||
if (!configData)
|
if (!configData) {
|
||||||
return;
|
ErrorF("[dbus] failed to allocate data struct.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
dbus_error_init(&error);
|
dbus_error_init(&error);
|
||||||
configData->connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
|
configData->connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||||
|
@ -272,15 +312,20 @@ configInitialise()
|
||||||
ErrorF("[dbus] some kind of error occurred: %s (%s)\n", error.name,
|
ErrorF("[dbus] some kind of error occurred: %s (%s)\n", error.name,
|
||||||
error.message);
|
error.message);
|
||||||
dbus_error_free(&error);
|
dbus_error_free(&error);
|
||||||
return;
|
xfree(configData);
|
||||||
|
configData = NULL;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbus_connection_set_exit_on_disconnect(configData->connection, FALSE);
|
||||||
|
|
||||||
if (!dbus_connection_get_unix_fd(configData->connection, &configData->fd)) {
|
if (!dbus_connection_get_unix_fd(configData->connection, &configData->fd)) {
|
||||||
dbus_connection_unref(configData->connection);
|
dbus_connection_unref(configData->connection);
|
||||||
ErrorF("[dbus] couldn't get fd for bus\n");
|
ErrorF("[dbus] couldn't get fd for bus\n");
|
||||||
dbus_error_free(&error);
|
dbus_error_free(&error);
|
||||||
configData->fd = -1;
|
xfree(configData);
|
||||||
return;
|
configData = NULL;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(configData->busname, sizeof(configData->busname),
|
snprintf(configData->busname, sizeof(configData->busname),
|
||||||
|
@ -291,12 +336,13 @@ configInitialise()
|
||||||
error.name, error.message);
|
error.name, error.message);
|
||||||
dbus_error_free(&error);
|
dbus_error_free(&error);
|
||||||
dbus_connection_unref(configData->connection);
|
dbus_connection_unref(configData->connection);
|
||||||
configData->fd = -1;
|
xfree(configData);
|
||||||
return;
|
configData = NULL;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* blocks until we get a reply. */
|
/* blocks until we get a reply. */
|
||||||
dbus_bus_add_match(configData->connection, MATCH_RULE, &error);
|
dbus_bus_add_match(configData->connection, CONFIG_MATCH_RULE, &error);
|
||||||
if (dbus_error_is_set(&error)) {
|
if (dbus_error_is_set(&error)) {
|
||||||
ErrorF("[dbus] couldn't match X.Org rule: %s (%s)\n", error.name,
|
ErrorF("[dbus] couldn't match X.Org rule: %s (%s)\n", error.name,
|
||||||
error.message);
|
error.message);
|
||||||
|
@ -304,8 +350,25 @@ configInitialise()
|
||||||
dbus_bus_release_name(configData->connection, configData->busname,
|
dbus_bus_release_name(configData->connection, configData->busname,
|
||||||
&error);
|
&error);
|
||||||
dbus_connection_unref(configData->connection);
|
dbus_connection_unref(configData->connection);
|
||||||
configData->fd = -1;
|
xfree(configData);
|
||||||
return;
|
configData = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbus_connection_add_filter(configData->connection, configFilter,
|
||||||
|
configData, NULL)) {
|
||||||
|
|
||||||
|
ErrorF("[dbus] couldn't add signal filter: %s (%s)\n", error.name,
|
||||||
|
error.message);
|
||||||
|
dbus_error_free(&error);
|
||||||
|
dbus_bus_release_name(configData->connection, configData->busname,
|
||||||
|
&error);
|
||||||
|
dbus_bus_remove_match(configData->connection, CONFIG_MATCH_RULE,
|
||||||
|
&error);
|
||||||
|
dbus_connection_unref(configData->connection);
|
||||||
|
xfree(configData);
|
||||||
|
configData = NULL;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(configData->busobject, sizeof(configData->busobject),
|
snprintf(configData->busobject, sizeof(configData->busobject),
|
||||||
|
@ -314,13 +377,15 @@ configInitialise()
|
||||||
configData->busobject, &vtable,
|
configData->busobject, &vtable,
|
||||||
configData->connection)) {
|
configData->connection)) {
|
||||||
ErrorF("[dbus] couldn't register object path\n");
|
ErrorF("[dbus] couldn't register object path\n");
|
||||||
configData->fd = -1;
|
|
||||||
dbus_bus_release_name(configData->connection, configData->busname,
|
dbus_bus_release_name(configData->connection, configData->busname,
|
||||||
&error);
|
&error);
|
||||||
dbus_bus_remove_match(configData->connection, MATCH_RULE, &error);
|
dbus_bus_remove_match(configData->connection, CONFIG_MATCH_RULE,
|
||||||
|
&error);
|
||||||
dbus_connection_unref(configData->connection);
|
dbus_connection_unref(configData->connection);
|
||||||
dbus_error_free(&error);
|
dbus_error_free(&error);
|
||||||
return;
|
xfree(configData);
|
||||||
|
configData = NULL;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugF("[dbus] registered object path %s\n", configData->busobject);
|
DebugF("[dbus] registered object path %s\n", configData->busobject);
|
||||||
|
@ -330,6 +395,23 @@ configInitialise()
|
||||||
|
|
||||||
RegisterBlockAndWakeupHandlers(configBlockHandler, configWakeupHandler,
|
RegisterBlockAndWakeupHandlers(configBlockHandler, configWakeupHandler,
|
||||||
configData);
|
configData);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CARD32
|
||||||
|
configReconnect(OsTimerPtr timer, CARD32 time, pointer arg)
|
||||||
|
{
|
||||||
|
if (configSetup())
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return RECONNECT_DELAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
configInitialise()
|
||||||
|
{
|
||||||
|
TimerSet(NULL, 0, 1, configReconnect, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -341,16 +423,15 @@ configFini()
|
||||||
dbus_error_init(&error);
|
dbus_error_init(&error);
|
||||||
dbus_connection_unregister_object_path(configData->connection,
|
dbus_connection_unregister_object_path(configData->connection,
|
||||||
configData->busobject);
|
configData->busobject);
|
||||||
dbus_bus_remove_match(configData->connection, MATCH_RULE, &error);
|
dbus_connection_remove_filter(configData->connection, configFilter,
|
||||||
|
configData);
|
||||||
|
dbus_bus_remove_match(configData->connection, CONFIG_MATCH_RULE,
|
||||||
|
&error);
|
||||||
dbus_bus_release_name(configData->connection, configData->busname,
|
dbus_bus_release_name(configData->connection, configData->busname,
|
||||||
&error);
|
&error);
|
||||||
dbus_connection_unref(configData->connection);
|
dbus_connection_unref(configData->connection);
|
||||||
RemoveGeneralSocket(configData->fd);
|
|
||||||
RemoveBlockAndWakeupHandlers(configBlockHandler, configWakeupHandler,
|
|
||||||
configData);
|
|
||||||
xfree(configData);
|
|
||||||
configData = NULL;
|
|
||||||
dbus_error_free(&error);
|
dbus_error_free(&error);
|
||||||
|
configTeardown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue