ladishd: properly detect connect failures
[ladish.git] / proxies / app_supervisor_proxy.c
blob6d535b18095ee8cf2edc79d802f8f7e2616e8dce
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of code that interfaces
9 * app supervisor object through D-Bus
10 **************************************************************************
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "app_supervisor_proxy.h"
30 struct ladish_app_supervisor_proxy
32 char * service;
33 char * object;
34 uint64_t version;
36 void * context;
37 void (* app_added)(void * context, uint64_t id, const char * name, bool running, bool terminal, uint8_t level);
38 void (* app_state_changed)(void * context, uint64_t id, const char * name, bool running, bool terminal, uint8_t level);
39 void (* app_removed)(void * context, uint64_t id);
42 #define proxy_ptr ((struct ladish_app_supervisor_proxy *)context)
44 static void on_app_added(void * context, DBusMessage * message_ptr)
46 uint64_t new_list_version;
47 uint64_t id;
48 const char * name;
49 dbus_bool_t running;
50 dbus_bool_t terminal;
51 uint8_t level;
53 if (!dbus_message_get_args(
54 message_ptr,
55 &g_dbus_error,
56 DBUS_TYPE_UINT64, &new_list_version,
57 DBUS_TYPE_UINT64, &id,
58 DBUS_TYPE_STRING, &name,
59 DBUS_TYPE_BOOLEAN, &running,
60 DBUS_TYPE_BOOLEAN, &terminal,
61 DBUS_TYPE_BYTE, &level,
62 DBUS_TYPE_INVALID))
64 log_error("dbus_message_get_args() failed to extract AppAdded signal arguments (%s)", g_dbus_error.message);
65 dbus_error_free(&g_dbus_error);
66 return;
69 //log_info("AppAdded signal received. id=%"PRIu64", name='%s', %srunning, %s, level %u", id, name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level);
71 if (new_list_version <= proxy_ptr->version)
73 log_info("Ignoring signal for older version of the app list");
75 else
77 //log_info("got new list version %llu", (unsigned long long)version);
78 proxy_ptr->version = new_list_version;
79 proxy_ptr->app_added(proxy_ptr->context, id, name, running, terminal, level);
83 static void on_app_removed(void * context, DBusMessage * message_ptr)
85 uint64_t new_list_version;
86 uint64_t id;
88 if (!dbus_message_get_args(
89 message_ptr,
90 &g_dbus_error,
91 DBUS_TYPE_UINT64, &new_list_version,
92 DBUS_TYPE_UINT64, &id,
93 DBUS_TYPE_INVALID))
95 log_error("dbus_message_get_args() failed to extract AppRemoved signal arguments (%s)", g_dbus_error.message);
96 dbus_error_free(&g_dbus_error);
97 return;
100 //log_info("AppRemoved signal received, id=%"PRIu64, id);
101 if (new_list_version <= proxy_ptr->version)
103 log_info("Ignoring signal for older version of the app list");
105 else
107 //log_info("got new list version %llu", (unsigned long long)version);
108 proxy_ptr->version = new_list_version;
109 proxy_ptr->app_removed(proxy_ptr->context, id);
113 static void on_app_state_changed(void * context, DBusMessage * message_ptr)
115 uint64_t new_list_version;
116 uint64_t id;
117 const char * name;
118 dbus_bool_t running;
119 dbus_bool_t terminal;
120 uint8_t level;
122 if (!dbus_message_get_args(
123 message_ptr,
124 &g_dbus_error,
125 DBUS_TYPE_UINT64, &new_list_version,
126 DBUS_TYPE_UINT64, &id,
127 DBUS_TYPE_STRING, &name,
128 DBUS_TYPE_BOOLEAN, &running,
129 DBUS_TYPE_BOOLEAN, &terminal,
130 DBUS_TYPE_BYTE, &level,
131 DBUS_TYPE_INVALID))
133 log_error("dbus_message_get_args() failed to extract AppStateChanged signal arguments (%s)", g_dbus_error.message);
134 dbus_error_free(&g_dbus_error);
135 return;
138 //log_info("AppStateChanged signal received");
139 //log_info("AppRemoved signal received, id=%"PRIu64, id);
140 if (new_list_version <= proxy_ptr->version)
142 log_info("Ignoring signal for older version of the app list");
144 else
146 //log_info("got new list version %llu", (unsigned long long)version);
147 proxy_ptr->version = new_list_version;
148 proxy_ptr->app_state_changed(proxy_ptr->context, id, name, running, terminal, level);
152 #undef proxy_ptr
154 /* this must be static because it is referenced by the
155 * dbus helper layer when hooks are active */
156 static struct dbus_signal_hook g_signal_hooks[] =
158 {"AppAdded", on_app_added},
159 {"AppRemoved", on_app_removed},
160 {"AppStateChanged", on_app_state_changed},
161 {NULL, NULL}
164 static void refresh_internal(struct ladish_app_supervisor_proxy * proxy_ptr, bool force)
166 DBusMessage* reply_ptr;
167 DBusMessageIter iter;
168 dbus_uint64_t version;
169 const char * reply_signature;
170 DBusMessageIter array_iter;
171 DBusMessageIter struct_iter;
172 uint64_t id;
173 const char * name;
174 dbus_bool_t running;
175 dbus_bool_t terminal;
176 uint8_t level;
178 log_info("refresh_internal() called");
180 version = proxy_ptr->version;
182 if (!dbus_call(proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR, "GetAll", "t", &version, NULL, &reply_ptr))
184 log_error("GetAll() failed.");
185 return;
188 reply_signature = dbus_message_get_signature(reply_ptr);
190 if (strcmp(reply_signature, "ta(tsbby)") != 0)
192 log_error("GetAll() reply signature mismatch. '%s'", reply_signature);
193 goto unref;
196 dbus_message_iter_init(reply_ptr, &iter);
198 //log_info_msg("version " + (char)dbus_message_iter_get_arg_type(&iter));
199 dbus_message_iter_get_basic(&iter, &version);
200 dbus_message_iter_next(&iter);
202 if (!force && version <= proxy_ptr->version)
204 goto unref;
207 //log_info("got new list version %llu", (unsigned long long)version);
208 proxy_ptr->version = version;
210 for (dbus_message_iter_recurse(&iter, &array_iter);
211 dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID;
212 dbus_message_iter_next(&array_iter))
214 dbus_message_iter_recurse(&array_iter, &struct_iter);
216 dbus_message_iter_get_basic(&struct_iter, &id);
217 dbus_message_iter_next(&struct_iter);
219 dbus_message_iter_get_basic(&struct_iter, &name);
220 dbus_message_iter_next(&struct_iter);
222 dbus_message_iter_get_basic(&struct_iter, &running);
223 dbus_message_iter_next(&struct_iter);
225 dbus_message_iter_get_basic(&struct_iter, &terminal);
226 dbus_message_iter_next(&struct_iter);
228 dbus_message_iter_get_basic(&struct_iter, &level);
229 dbus_message_iter_next(&struct_iter);
231 //log_info("App id=%"PRIu64", name='%s', %srunning, %s, level %u", id, name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level);
232 proxy_ptr->app_added(proxy_ptr->context, id, name, running, terminal, level);
234 dbus_message_iter_next(&struct_iter);
237 unref:
238 dbus_message_unref(reply_ptr);
241 bool
242 ladish_app_supervisor_proxy_create(
243 const char * service,
244 const char * object,
245 void * context,
246 void (* app_added)(void * context, uint64_t id, const char * name, bool running, bool terminal, uint8_t level),
247 void (* app_state_changed)(void * context, uint64_t id, const char * name, bool running, bool terminal, uint8_t level),
248 void (* app_removed)(void * context, uint64_t id),
249 ladish_app_supervisor_proxy_handle * handle_ptr)
251 struct ladish_app_supervisor_proxy * proxy_ptr;
253 proxy_ptr = malloc(sizeof(struct ladish_app_supervisor_proxy));
254 if (proxy_ptr == NULL)
256 log_error("malloc() failed to allocate struct proxy");
257 goto fail;
260 proxy_ptr->service = strdup(service);
261 if (proxy_ptr->service == NULL)
263 log_error("strdup() failed too duplicate service name '%s'", service);
264 goto free_proxy;
267 proxy_ptr->object = strdup(object);
268 if (proxy_ptr->object == NULL)
270 log_error("strdup() failed too duplicate object name '%s'", object);
271 goto free_service;
274 proxy_ptr->version = 0;
276 proxy_ptr->context = context;
277 proxy_ptr->app_added = app_added;
278 proxy_ptr->app_state_changed = app_state_changed;
279 proxy_ptr->app_removed = app_removed;
281 if (!dbus_register_object_signal_hooks(
282 g_dbus_connection,
283 proxy_ptr->service,
284 proxy_ptr->object,
285 IFACE_APP_SUPERVISOR,
286 proxy_ptr,
287 g_signal_hooks))
289 log_error("dbus_register_object_signal_hooks() failed for app supervisor");
290 goto free_object;
293 refresh_internal(proxy_ptr, true);
295 *handle_ptr = (ladish_app_supervisor_proxy_handle)proxy_ptr;
297 return true;
299 free_object:
300 free(proxy_ptr->object);
301 free_service:
302 free(proxy_ptr->service);
303 free_proxy:
304 free(proxy_ptr);
305 fail:
306 return false;
309 #define proxy_ptr ((struct ladish_app_supervisor_proxy *)proxy)
311 void ladish_app_supervisor_proxy_destroy(ladish_app_supervisor_proxy_handle proxy)
313 dbus_unregister_object_signal_hooks(g_dbus_connection, proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR);
315 free(proxy_ptr->object);
316 free(proxy_ptr->service);
317 free(proxy_ptr);
320 bool
321 ladish_app_supervisor_proxy_run_custom(
322 ladish_app_supervisor_proxy_handle proxy,
323 const char * command,
324 const char * name,
325 bool run_in_terminal,
326 uint8_t level)
328 dbus_bool_t terminal;
330 terminal = run_in_terminal;
332 if (!dbus_call(proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR, "RunCustom", "bssy", &terminal, &command, &name, &level, ""))
334 log_error("RunCustom() failed.");
335 return false;
338 return true;
341 bool ladish_app_supervisor_proxy_start_app(ladish_app_supervisor_proxy_handle proxy, uint64_t id)
343 if (!dbus_call(proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR, "StartApp", "t", &id, ""))
345 log_error("StartApp() failed.");
346 return false;
349 return true;
352 bool ladish_app_supervisor_proxy_stop_app(ladish_app_supervisor_proxy_handle proxy, uint64_t id)
354 if (!dbus_call(proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR, "StopApp", "t", &id, ""))
356 log_error("StopApp() failed.");
357 return false;
360 return true;
363 bool ladish_app_supervisor_proxy_kill_app(ladish_app_supervisor_proxy_handle proxy, uint64_t id)
365 if (!dbus_call(proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR, "KillApp", "t", &id, ""))
367 log_error("KillApp() failed.");
368 return false;
371 return true;
374 bool ladish_app_supervisor_proxy_remove_app(ladish_app_supervisor_proxy_handle proxy, uint64_t id)
376 if (!dbus_call(proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR, "RemoveApp", "t", &id, ""))
378 log_error("RemoveApp() failed.");
379 return false;
382 return true;
385 bool
386 ladish_app_supervisor_get_app_properties(
387 ladish_app_supervisor_proxy_handle proxy,
388 uint64_t id,
389 char ** name_ptr_ptr,
390 char ** command_ptr_ptr,
391 bool * running_ptr,
392 bool * terminal_ptr,
393 uint8_t * level_ptr)
395 DBusMessage * reply_ptr;
396 const char * name;
397 const char * commandline;
398 dbus_bool_t running;
399 dbus_bool_t terminal;
400 uint8_t level;
401 char * name_buffer;
402 char * commandline_buffer;
404 if (!dbus_call(proxy_ptr->service, proxy_ptr->object, IFACE_APP_SUPERVISOR, "GetAppProperties", "t", &id, NULL, &reply_ptr))
406 log_error("GetAppProperties() failed.");
407 return false;
410 if (!dbus_message_get_args(
411 reply_ptr,
412 &g_dbus_error,
413 DBUS_TYPE_STRING, &name,
414 DBUS_TYPE_STRING, &commandline,
415 DBUS_TYPE_BOOLEAN, &running,
416 DBUS_TYPE_BOOLEAN, &terminal,
417 DBUS_TYPE_BYTE, &level,
418 DBUS_TYPE_INVALID))
420 dbus_message_unref(reply_ptr);
421 dbus_error_free(&g_dbus_error);
422 log_error("decoding reply of GetAppProperties failed.");
423 return false;
426 name_buffer = strdup(name);
427 if (name_buffer == NULL)
429 log_error("strdup() for app name failed.");
430 dbus_message_unref(reply_ptr);
431 return false;
434 commandline_buffer = strdup(commandline);
435 if (commandline_buffer == NULL)
437 log_error("strdup() for app commandline failed.");
438 free(name_buffer);
439 dbus_message_unref(reply_ptr);
440 return false;
443 *name_ptr_ptr = name_buffer;
444 *command_ptr_ptr = commandline_buffer;
445 *running_ptr = running;
446 *terminal_ptr = terminal;
447 *level_ptr = level;
449 return true;
452 bool
453 ladish_app_supervisor_set_app_properties(
454 ladish_app_supervisor_proxy_handle proxy,
455 uint64_t id,
456 const char * name,
457 const char * command,
458 bool run_in_terminal,
459 uint8_t level)
461 dbus_bool_t terminal;
463 terminal = run_in_terminal;
465 if (!dbus_call(
466 proxy_ptr->service,
467 proxy_ptr->object,
468 IFACE_APP_SUPERVISOR,
469 "SetAppProperties",
470 "tssby",
471 &id,
472 &name,
473 &command,
474 &terminal,
475 &level,
476 ""))
478 log_error("SetAppProperties() failed.");
479 return false;
482 return true;
485 #undef proxy_ptr