2
* @file geis_dbus_locator.c
3
* @brief Implementation of the GEIS DBus locator.
7
* Copyright 2011 Canonical Ltd.
9
* This library is free software; you can redistribute it and/or modify it under
10
* the terms of the GNU Lesser General Public License as published by the Free
11
* Software Foundation; either version 3 of the License, or (at your option) any
14
* This library is distributed in the hope that it will be useful, but WITHOUT
15
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19
* You should have received a copy of the GNU General Public License
20
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include "geis_config.h"
23
#include "geis_dbus_locator.h"
25
#include <dbus/dbus.h>
26
#include "geis_dbus.h"
27
#include "geis_logging.h"
33
typedef enum GeisDBusLocatorState
35
GEIS_DBUS_LOCATOR_STATE_INITIALIZING,
36
GEIS_DBUS_LOCATOR_STATE_LOCATING,
37
GEIS_DBUS_LOCATOR_STATE_WAITING,
38
GEIS_DBUS_LOCATOR_STATE_FINALIZING
39
} GeisDBusLocatorState;
42
struct GeisDBusLocator
44
GeisDBusClient client;
45
GeisDBusLocatorState state;
46
DBusConnection *session_bus;
53
* Performs the act of actually locating the server.
56
_locator_find_server(GeisDBusLocator locator)
58
locator->state = GEIS_DBUS_LOCATOR_STATE_LOCATING;
59
DBusMessage *msg = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
60
GEIS_DBUS_SERVICE_PATH,
61
GEIS_DBUS_SERVICE_INTERFACE,
62
GEIS_DBUS_GET_SERVER_ADDRESS);
63
dbus_connection_send(locator->session_bus, msg, &locator->serial);
64
dbus_message_unref(msg);
69
* A generic message handler function.
71
static DBusHandlerResult
72
_locator_message_handler(DBusConnection *connection GEIS_UNUSED,
76
DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
77
GeisDBusLocator locator = (GeisDBusLocator)user_data;
78
int type = dbus_message_get_type(message);
80
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
85
dbus_message_get_args(message, NULL,
86
DBUS_TYPE_STRING, &name,
87
DBUS_TYPE_STRING, &old_owner,
88
DBUS_TYPE_STRING, &new_owner,
90
if (strlen(old_owner))
92
geis_debug("%s has gone away", name);
93
geis_dbus_client_server_dislocated(locator->client);
94
result = DBUS_HANDLER_RESULT_HANDLED;
96
else if (strlen(new_owner))
98
geis_debug("%s has appeared", name);
99
_locator_find_server(locator);
100
result = DBUS_HANDLER_RESULT_HANDLED;
103
else if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN)
105
if (locator->serial == dbus_message_get_reply_serial(message))
107
const char *s = NULL;
108
dbus_message_get_args(message, NULL,
109
DBUS_TYPE_STRING, &s,
111
locator->server_address = strdup(s);
112
geis_dbus_client_server_located(locator->client);
113
result = DBUS_HANDLER_RESULT_HANDLED;
116
else if (type == DBUS_MESSAGE_TYPE_ERROR)
118
if (dbus_message_is_error(message, DBUS_ERROR_SERVICE_UNKNOWN))
120
geis_warning("server not found!");
121
geis_dbus_client_server_dislocated(locator->client);
122
result = DBUS_HANDLER_RESULT_HANDLED;
126
const char *str = NULL;
127
dbus_message_get_args(message, NULL,
128
DBUS_TYPE_STRING, &str,
130
geis_warning("error %s: %s", dbus_message_get_error_name(message), str);
139
* Adds the locator watches to the dispatcher watch list.
142
_locator_add_watch(DBusWatch *watch, void *data)
144
dbus_bool_t status = TRUE;
145
GeisDBusLocator locator = (GeisDBusLocator)data;
146
GeisDBusDispatcher dispatcher = geis_dbus_client_dispatcher(locator->client);
148
geis_dbus_dispatcher_register(dispatcher, locator->session_bus, watch);
154
* Toggles the enabled/disabled status of the locator watches.
157
_locator_toggle_watch(DBusWatch *watch, void *data)
159
GeisDBusLocator locator = (GeisDBusLocator)data;
160
GeisDBusDispatcher dispatcher = geis_dbus_client_dispatcher(locator->client);
162
geis_dbus_dispatcher_toggle_watch(dispatcher, watch);
167
* Removes the locator watches from the dispatcher watch list.
170
_locator_remove_watch(DBusWatch *watch, void *data)
172
GeisDBusLocator locator = (GeisDBusLocator)data;
173
GeisDBusDispatcher dispatcher = geis_dbus_client_dispatcher(locator->client);
175
geis_dbus_dispatcher_unregister(dispatcher, watch);
180
* Creates a new GeisDBusLocator object.
183
geis_dbus_locator_new(GeisDBusClient client)
185
GeisDBusLocator locator = NULL;
187
/* Fail to locate Geis on the DBus if there is no DBus session. */
188
if (NULL == getenv("DBUS_SESSION_BUS_ADDRESS"))
193
locator = calloc(1, sizeof(struct GeisDBusLocator));
199
locator->client = client;
200
locator->state = GEIS_DBUS_LOCATOR_STATE_INITIALIZING;
202
/* Connect to the DBus session bus. */
203
DBusError error = DBUS_ERROR_INIT;
204
locator->session_bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
205
if (!locator->session_bus || dbus_error_is_set(&error))
208
snprintf(msg, sizeof(msg), "error %s connecting to session bus: %s",
209
error.name, error.message);
210
geis_error("%s", msg);
214
/* Integrate with the app event loop via the GEIS multiplexor. */
215
dbus_connection_set_watch_functions(locator->session_bus,
217
_locator_remove_watch,
218
_locator_toggle_watch,
221
/* Look for server-connect and server-disconnect messages. */
222
dbus_bus_add_match(locator->session_bus,
223
"type='signal',sender='" DBUS_SERVICE_DBUS "'," \
224
"interface='" DBUS_INTERFACE_DBUS "'," \
225
"member='NameOwnerChanged'," \
226
"arg0='" GEIS_DBUS_SERVICE_INTERFACE "'",
228
if (dbus_error_is_set(&error))
231
snprintf(msg, sizeof(msg), "error %s adding match to session bus: %s",
232
error.name, error.message);
233
geis_error("%s", msg);
237
/* Install a handler for any and all messages. */
238
dbus_connection_add_filter(locator->session_bus,
239
_locator_message_handler,
243
_locator_find_server(locator);
246
dbus_error_free(&error);
253
* Destroys a %GeisDBusLocator object.
256
geis_dbus_locator_delete(GeisDBusLocator locator)
260
if (locator->server_address)
262
free(locator->server_address);
264
if (locator->session_bus)
266
dbus_connection_set_watch_functions(locator->session_bus,
271
dbus_connection_remove_filter(locator->session_bus,
272
_locator_message_handler,
274
dbus_connection_unref(locator->session_bus);
282
geis_dbus_locator_server_address(GeisDBusLocator locator)
284
return locator->server_address;