1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of code that interfaces ladiconfd through D-Bus
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 /* This implementation subscribes for changes of all values.
28 * It is suboptimal in general because of the increased overhead.
29 * A smarter implementation will subscribe using filter based on arg0 (key).
30 * Such smarter implementation seems to not be worth becase of
31 * the limited key set that ladish uses.
34 #include "conf_proxy.h"
38 struct list_head siblings
;
44 size_t value_buffer_size
;
46 void (* callback
)(void * context
, const char * key
, const char * value
);
47 void * callback_context
;
50 static struct list_head g_pairs
;
52 static struct pair
* find_pair(const char * key
)
54 struct list_head
* node_ptr
;
55 struct pair
* pair_ptr
;
57 list_for_each(node_ptr
, &g_pairs
)
59 pair_ptr
= list_entry(node_ptr
, struct pair
, siblings
);
60 if (strcmp(pair_ptr
->key
, key
) == 0)
69 static void on_value_changed(struct pair
* pair_ptr
, const char * value
, uint64_t version
, bool announce
)
73 log_info("'%s' <- '%s' (%"PRIu64
")", pair_ptr
->key
, value
, version
);
75 pair_ptr
->version
= version
;
78 if (len
< pair_ptr
->value_buffer_size
)
80 memcpy(pair_ptr
->value
, value
, len
+ 1);
84 free(pair_ptr
->value
);
85 pair_ptr
->value
= strdup(value
);
86 if (pair_ptr
->value
== NULL
)
88 log_error("strdup(\"%s\") failed for key \"%s\" value", value
, pair_ptr
->key
);
92 if (announce
&& pair_ptr
->callback
!= NULL
)
94 pair_ptr
->callback(pair_ptr
->callback_context
, pair_ptr
->key
, value
);
98 static void on_life_status_changed(bool appeared
)
100 struct list_head
* node_ptr
;
101 struct pair
* pair_ptr
;
105 log_info("confd activatation detected.");
109 log_info("confd deactivatation detected.");
111 list_for_each(node_ptr
, &g_pairs
)
113 pair_ptr
= list_entry(node_ptr
, struct pair
, siblings
);
114 pair_ptr
->version
= 0;
119 static void on_conf_changed(void * context
, DBusMessage
* message_ptr
)
123 dbus_uint64_t version
;
124 struct pair
* pair_ptr
;
126 if (!dbus_message_get_args(
129 DBUS_TYPE_STRING
, &key
,
130 DBUS_TYPE_STRING
, &value
,
131 DBUS_TYPE_UINT64
, &version
,
134 log_error("Invalid parameters of \"changed\" signal: %s", g_dbus_error
.message
);
135 dbus_error_free(&g_dbus_error
);
139 pair_ptr
= find_pair(key
);
140 if (pair_ptr
== NULL
)
142 /* we dont care about this key */
146 if (pair_ptr
->version
>= version
)
148 /* signal for either already known version of the key or a older one */
152 if (pair_ptr
->value
!= NULL
&& strcmp(value
, pair_ptr
->value
) == 0)
154 /* the conf service should not send the signal when value is not changed,
155 but in case that it does, ignore it. This can happen when confd is restarted */
159 on_value_changed(pair_ptr
, value
, version
, true);
162 /* this must be static because it is referenced by the
163 * dbus helper layer when hooks are active */
164 static struct dbus_signal_hook g_signal_hooks
[] =
166 {"changed", on_conf_changed
},
170 bool conf_proxy_init(void)
172 INIT_LIST_HEAD(&g_pairs
);
174 if (!dbus_register_service_lifetime_hook(g_dbus_connection
, CONF_SERVICE_NAME
, on_life_status_changed
))
176 log_error("dbus_register_service_lifetime_hook() failed for confd service");
180 if (!dbus_register_object_signal_hooks(
188 dbus_unregister_service_lifetime_hook(g_dbus_connection
, CONF_SERVICE_NAME
);
189 log_error("dbus_register_object_signal_hooks() failed for conf interface");
196 void conf_proxy_uninit(void)
198 dbus_unregister_object_signal_hooks(g_dbus_connection
, CONF_SERVICE_NAME
, CONF_OBJECT_PATH
, CONF_IFACE
);
199 dbus_unregister_service_lifetime_hook(g_dbus_connection
, CONF_SERVICE_NAME
);
205 void (* callback
)(void * context
, const char * key
, const char * value
),
206 void * callback_context
)
210 struct pair
* pair_ptr
;
212 pair_ptr
= find_pair(key
);
213 if (pair_ptr
!= NULL
)
215 log_error("key '%s' already registered", key
);
220 if (!dbus_call(CONF_SERVICE_NAME
, CONF_OBJECT_PATH
, CONF_IFACE
, "get", "s", &key
, "st", &value
, &version
))
222 //log_error("conf::get() failed.");
227 pair_ptr
= malloc(sizeof(struct pair
));
228 if (pair_ptr
== NULL
)
230 log_error("malloc() failed to allocate memory for pair struct");
234 pair_ptr
->key
= strdup(key
);
235 if (pair_ptr
->key
== NULL
)
237 log_error("strdup(\"%s\") failed for key", key
);
244 pair_ptr
->value_buffer_size
= strlen(value
) + 1;
246 pair_ptr
->value
= malloc(pair_ptr
->value_buffer_size
);
247 if (pair_ptr
->value
== NULL
)
249 log_error("malloc(%zu) failed for value \"%s\"", pair_ptr
->value_buffer_size
, value
);
254 memcpy(pair_ptr
->value
, value
, pair_ptr
->value_buffer_size
);
258 pair_ptr
->value
= NULL
;
259 pair_ptr
->value_buffer_size
= 0;
262 pair_ptr
->version
= version
;
263 pair_ptr
->callback
= callback
;
264 pair_ptr
->callback_context
= callback_context
;
266 list_add_tail(&pair_ptr
->siblings
, &g_pairs
);
268 if (callback
!= NULL
)
270 callback(callback_context
, key
, value
);
276 bool conf_set(const char * key
, const char * value
)
279 struct pair
* pair_ptr
;
281 pair_ptr
= find_pair(key
);
282 if (pair_ptr
!= NULL
&& pair_ptr
->value
!= NULL
&& strcmp(value
, pair_ptr
->value
) == 0)
284 return true; /* not changed */
287 if (!dbus_call(CONF_SERVICE_NAME
, CONF_OBJECT_PATH
, CONF_IFACE
, "set", "ss", &key
, &value
, "t", &version
))
289 log_error("conf::set() failed.");
293 if (pair_ptr
!= NULL
&& pair_ptr
->value
!= NULL
&& strcmp(value
, pair_ptr
->value
) != 0)
295 /* record the new version and dont call the callback */
296 on_value_changed(pair_ptr
, value
, version
, false);
302 bool conf_get(const char * key
, const char ** value_ptr
)
304 struct pair
* pair_ptr
;
306 pair_ptr
= find_pair(key
);
307 if (pair_ptr
== NULL
)
309 ASSERT_NO_PASS
; /* call conf_register() first */
313 if (pair_ptr
->value
== NULL
)
315 return false; /* malloc() failed */
318 *value_ptr
= pair_ptr
->value
;
322 bool conf_string2bool(const char * value
)
325 strcasecmp(value
, "false") == 0 ||
326 strcmp(value
, "0") == 0)
334 const char * conf_bool2string(bool value
)
336 return value
? "true" : "false";
339 bool conf_set_bool(const char * key
, bool value
)
341 return conf_set(key
, conf_bool2string(value
));
344 bool conf_get_bool(const char * key
, bool * value_ptr
)
348 if (!conf_get(key
, &str
))
353 *value_ptr
= conf_string2bool(str
);