ladishd: fix jack graph filtering on save
[ladish.git] / proxies / conf_proxy.c
blob276a1452d16883f701bf05056554a3714fdf8cc5
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
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"
36 struct pair
38 struct list_head siblings;
40 uint64_t version;
42 char * key;
43 char * value;
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)
62 return pair_ptr;
66 return NULL;
69 static void on_value_changed(struct pair * pair_ptr, const char * value, uint64_t version, bool announce)
71 size_t len;
73 log_info("'%s' <- '%s' (%"PRIu64")", pair_ptr->key, value, version);
75 pair_ptr->version = version;
77 len = strlen(value);
78 if (len < pair_ptr->value_buffer_size)
80 memcpy(pair_ptr->value, value, len + 1);
82 else
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;
103 if (appeared)
105 log_info("confd activatation detected.");
107 else
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)
121 const char * key;
122 const char * value;
123 dbus_uint64_t version;
124 struct pair * pair_ptr;
126 if (!dbus_message_get_args(
127 message_ptr,
128 &g_dbus_error,
129 DBUS_TYPE_STRING, &key,
130 DBUS_TYPE_STRING, &value,
131 DBUS_TYPE_UINT64, &version,
132 DBUS_TYPE_INVALID))
134 log_error("Invalid parameters of \"changed\" signal: %s", g_dbus_error.message);
135 dbus_error_free(&g_dbus_error);
136 return;
139 pair_ptr = find_pair(key);
140 if (pair_ptr == NULL)
142 /* we dont care about this key */
143 return;
146 if (pair_ptr->version >= version)
148 /* signal for either already known version of the key or a older one */
149 return;
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 */
156 return;
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},
167 {NULL, NULL}
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");
177 return false;
180 if (!dbus_register_object_signal_hooks(
181 g_dbus_connection,
182 CONF_SERVICE_NAME,
183 CONF_OBJECT_PATH,
184 CONF_IFACE,
185 NULL,
186 g_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");
190 return false;
193 return true;
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);
202 bool
203 conf_register(
204 const char * key,
205 void (* callback)(void * context, const char * key, const char * value),
206 void * callback_context)
208 const char * value;
209 uint64_t version;
210 struct pair * pair_ptr;
212 pair_ptr = find_pair(key);
213 if (pair_ptr != NULL)
215 log_error("key '%s' already registered", key);
216 ASSERT_NO_PASS;
217 return false;
220 if (!dbus_call(0, CONF_SERVICE_NAME, CONF_OBJECT_PATH, CONF_IFACE, "get", "s", &key, "st", &value, &version))
222 //log_error("conf::get() failed.");
223 version = 0;
224 value = NULL;
227 pair_ptr = malloc(sizeof(struct pair));
228 if (pair_ptr == NULL)
230 log_error("malloc() failed to allocate memory for pair struct");
231 return false;
234 pair_ptr->key = strdup(key);
235 if (pair_ptr->key == NULL)
237 log_error("strdup(\"%s\") failed for key", key);
238 free(pair_ptr);
239 return false;
242 if (value != NULL)
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);
250 free(pair_ptr->key);
251 free(pair_ptr);
252 return false;
254 memcpy(pair_ptr->value, value, pair_ptr->value_buffer_size);
256 else
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);
273 return true;
276 bool conf_set(const char * key, const char * value)
278 uint64_t version;
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(0, CONF_SERVICE_NAME, CONF_OBJECT_PATH, CONF_IFACE, "set", "ss", &key, &value, "t", &version))
289 log_error("conf::set() failed.");
290 return false;
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);
299 return true;
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 */
310 return false;
313 if (pair_ptr->value == NULL)
315 return false; /* malloc() failed */
318 *value_ptr = pair_ptr->value;
319 return true;
322 bool conf_string2bool(const char * value)
324 if (value[0] == 0 ||
325 strcasecmp(value, "false") == 0 ||
326 strcmp(value, "0") == 0)
328 return false;
331 return true;
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)
346 const char * str;
348 if (!conf_get(key, &str))
350 return false;
353 *value_ptr = conf_string2bool(str);
355 return true;