2 * Copyright (C) 2015, 2016 IoT.bzh
3 * Author "Fulup Ar Foll"
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #define _GNU_SOURCE /* See feature_test_macros(7) */
22 #include <json-c/json.h>
24 #include <afb/afb-binding.h>
26 #include "utils-jbus.h"
28 static const char _added_[] = "added";
29 static const char _auto_[] = "auto";
30 static const char _continue_[] = "continue";
31 static const char _changed_[] = "changed";
32 static const char _detail_[] = "detail";
33 static const char _id_[] = "id";
34 static const char _install_[] = "install";
35 static const char _local_[] = "local";
36 static const char _mode_[] = "mode";
37 static const char _remote_[] = "remote";
38 static const char _runid_[] = "runid";
39 static const char _runnables_[] = "runnables";
40 static const char _runners_[] = "runners";
41 static const char _start_[] = "start";
42 static const char _state_[] = "state";
43 static const char _stop_[] = "stop";
44 static const char _terminate_[] = "terminate";
45 static const char _uninstall_[] = "uninstall";
46 static const char _uri_[] = "uri";
48 static const struct afb_binding_interface *binder;
50 static struct jbus *jbus;
53 * Structure for asynchronous call handling
57 struct afb_req request; /* the recorded request */
58 const char *method; /* the called method */
62 * Creates the memo for the 'request' and the 'method'.
63 * Returns the memo in case of success.
64 * In case of error, send a failure answer and returns NULL.
66 static struct memo *memo_create(struct afb_req request, const char *method)
68 struct memo *memo = malloc(sizeof *memo);
70 afb_req_fail(request, "failed", "out of memory");
72 memo->request = request;
73 memo->method = method;
74 afb_req_addref(request);
80 * Sends the asynchronous failed reply to the request recorded by 'memo'
81 * Then fress the resources.
83 static void memo_fail(struct memo *memo, const char *info)
85 afb_req_fail(memo->request, "failed", info);
86 afb_req_unref(memo->request);
91 * Sends the asynchronous success reply to the request recorded by 'memo'
92 * Then fress the resources.
94 static void memo_success(struct memo *memo, struct json_object *obj, const char *info)
96 afb_req_success(memo->request, obj, info);
97 afb_req_unref(memo->request);
102 * Broadcast the event "application-list-changed".
103 * This event is sent was the event "changed" is received from dbus.
105 static void application_list_changed(const char *data, void *closure)
107 afb_daemon_broadcast_event(binder->daemon, "application-list-changed", NULL);
111 * Builds if possible the json object having one field of name 'tag'
112 * whose value is 'obj' like here: { tag: obj } and returns it.
113 * In case of error or when 'tag'==NULL or 'obj'==NULL, 'obj' is returned.
114 * The reference count of 'obj' is not incremented.
116 static struct json_object *embed(const char *tag, struct json_object *obj)
118 struct json_object *result;
120 if (obj == NULL || tag == NULL)
123 result = json_object_new_object();
124 if (result == NULL) {
129 /* TODO why is json-c not returning a status? */
130 json_object_object_add(result, tag, obj);
137 * Callback for replies made by 'embed_call_void'.
139 static void embed_call_void_callback(int iserror, struct json_object *obj, struct memo *memo)
141 DEBUG(binder, "(afm-main-binding) %s(true) -> %s\n", memo->method,
142 obj ? json_object_to_json_string(obj) : "NULL");
145 memo_fail(memo, obj ? json_object_get_string(obj) : "framework daemon failure");
147 memo_success(memo, embed(memo->method, json_object_get(obj)), NULL);
152 * Calls with DBus the 'method' of the user daemon without arguments.
154 static void embed_call_void(struct afb_req request, const char *method)
158 /* store the request */
159 memo = memo_create(request, method);
163 if (jbus_call_sj(jbus, method, "true", (void*)embed_call_void_callback, memo) < 0)
164 memo_fail(memo, "dbus failure");
168 * Callback for replies made by 'call_appid' and 'call_runid'.
170 static void call_xxxid_callback(int iserror, struct json_object *obj, struct memo *memo)
172 DEBUG(binder, "(afm-main-binding) %s -> %s\n", memo->method,
173 obj ? json_object_to_json_string(obj) : "NULL");
176 memo_fail(memo, obj ? json_object_get_string(obj) : "framework daemon failure");
178 memo_success(memo, json_object_get(obj), NULL);
183 * Calls with DBus the 'method' of the user daemon with the argument "id".
185 static void call_appid(struct afb_req request, const char *method)
191 id = afb_req_value(request, _id_);
193 afb_req_fail(request, "bad-request", "missing 'id'");
197 memo = memo_create(request, method);
201 if (asprintf(&sid, "\"%s\"", id) <= 0) {
202 memo_fail(memo, "out of memory");
206 if (jbus_call_sj(jbus, method, sid, (void*)call_xxxid_callback, memo) < 0)
207 memo_fail(memo, "dbus failure");
212 static void call_runid(struct afb_req request, const char *method)
217 id = afb_req_value(request, _runid_);
219 afb_req_fail(request, "bad-request", "missing 'runid'");
223 memo = memo_create(request, method);
227 if (jbus_call_sj(jbus, method, id, (void*)call_xxxid_callback, memo) < 0)
228 memo_fail(memo, "dbus failure");
231 /************************** entries ******************************/
233 static void runnables(struct afb_req request)
235 embed_call_void(request, _runnables_);
238 static void detail(struct afb_req request)
240 call_appid(request, _detail_);
243 static void start_callback(int iserror, struct json_object *obj, struct memo *memo)
245 DEBUG(binder, "(afm-main-binding) %s -> %s\n", memo->method,
246 obj ? json_object_to_json_string(obj) : "NULL");
249 memo_fail(memo, obj ? json_object_get_string(obj) : "framework daemon failure");
251 obj = json_object_get(obj);
252 if (json_object_get_type(obj) == json_type_int)
253 obj = embed(_runid_, obj);
254 memo_success(memo, obj, NULL);
258 static void start(struct afb_req request)
261 const char *id, *mode;
266 id = afb_req_value(request, _id_);
268 afb_req_fail(request, "bad-request", "missing 'id'");
273 mode = afb_req_value(request, _mode_);
274 if (mode == NULL || !strcmp(mode, _auto_)) {
275 mode = binder->mode == AFB_MODE_REMOTE ? _remote_ : _local_;
278 /* prepares asynchronous request */
279 memo = memo_create(request, _start_);
283 /* create the query */
284 rc = asprintf(&query, "{\"id\":\"%s\",\"mode\":\"%s\"}", id, mode);
286 memo_fail(memo, "out of memory");
290 /* calls the service asynchronously */
291 if (jbus_call_sj(jbus, _start_, query, (void*)start_callback, memo) < 0)
292 memo_fail(memo, "dbus failure");
296 static void terminate(struct afb_req request)
298 call_runid(request, _terminate_);
301 static void stop(struct afb_req request)
303 call_runid(request, _stop_);
306 static void continue_(struct afb_req request)
308 call_runid(request, _continue_);
311 static void runners(struct afb_req request)
313 embed_call_void(request, _runners_);
316 static void state(struct afb_req request)
318 call_runid(request, _state_);
321 static void install_callback(int iserror, struct json_object *obj, struct memo *memo)
323 struct json_object *added;
326 memo_fail(memo, obj ? json_object_get_string(obj) : "framework daemon failure");
328 if (json_object_object_get_ex(obj, _added_, &added))
330 obj = json_object_get(obj);
331 obj = embed(_id_, obj);
332 memo_success(memo, obj, NULL);
335 static void install(struct afb_req request)
339 const char *filename;
342 /* get the argument */
343 arg = afb_req_get(request, "widget");
345 if (filename == NULL) {
346 afb_req_fail(request, "bad-request", "missing 'widget' file");
350 /* prepares asynchronous request */
351 memo = memo_create(request, _install_);
355 /* makes the query */
356 if (0 >= asprintf(&query, "\"%s\"", filename)) {
357 afb_req_fail(request, "server-error", "out of memory");
361 /* calls the service asynchronously */
362 if (jbus_call_sj(jbus, _install_, query, (void*)install_callback, memo) < 0)
363 memo_fail(memo, "dbus failure");
367 static void uninstall(struct afb_req request)
369 call_appid(request, _uninstall_);
372 static const struct afb_verb_desc_v1 verbs[] =
374 {_runnables_, AFB_SESSION_CHECK, runnables, "Get list of runnable applications"},
375 {_detail_ , AFB_SESSION_CHECK, detail, "Get the details for one application"},
376 {_start_ , AFB_SESSION_CHECK, start, "Start an application"},
377 {_terminate_, AFB_SESSION_CHECK, terminate, "Terminate a running application"},
378 {_stop_ , AFB_SESSION_CHECK, stop, "Stop (pause) a running application"},
379 {_continue_ , AFB_SESSION_CHECK, continue_, "Continue (resume) a stopped application"},
380 {_runners_ , AFB_SESSION_CHECK, runners, "Get the list of running applications"},
381 {_state_ , AFB_SESSION_CHECK, state, "Get the state of a running application"},
382 {_install_ , AFB_SESSION_CHECK, install, "Install an application using a widget file"},
383 {_uninstall_, AFB_SESSION_CHECK, uninstall, "Uninstall an application"},
384 { NULL, 0, NULL, NULL }
387 static const struct afb_binding plug_desc = {
388 .type = AFB_BINDING_VERSION_1,
390 .info = "Application Framework Master Service",
391 .prefix = "afm-main",
396 const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf)
401 /* records the interface */
402 assert (binder == NULL);
405 /* creates the jbus for accessing afm-user-daemon */
406 sbus = afb_daemon_get_user_bus(itf->daemon);
409 jbus = create_jbus(sbus, "/org/AGL/afm/user");
413 /* records the signal handler */
414 rc = jbus_on_signal_s(jbus, _changed_, application_list_changed, NULL);