Amxb_Ubus  3.3.1
Ambiorix Ubus API
amxb_ubus_register.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #include <amxc/amxc_string_split.h>
56 
57 #include "amxb_ubus.h"
58 
59 typedef struct _amxb_ubus_fcall {
60  struct ubus_request_data req;
62  uint64_t call_id;
63  amxc_llist_it_t it;
65 
66 static enum blobmsg_type amxb_ubus_var_type_to_ubus_type(int type) {
67  enum blobmsg_type converter[AMXC_VAR_ID_CUSTOM_BASE] = {
68  BLOBMSG_TYPE_UNSPEC,
69  BLOBMSG_TYPE_STRING,
70  BLOBMSG_TYPE_INT32,
71  BLOBMSG_TYPE_INT32,
72  BLOBMSG_TYPE_INT32,
73  BLOBMSG_TYPE_INT64,
74  BLOBMSG_TYPE_INT32,
75  BLOBMSG_TYPE_INT32,
76  BLOBMSG_TYPE_INT64,
77  BLOBMSG_TYPE_INT64,
78  BLOBMSG_TYPE_UNSPEC,
79  BLOBMSG_TYPE_DOUBLE,
80  BLOBMSG_TYPE_BOOL,
81  BLOBMSG_TYPE_ARRAY,
82  BLOBMSG_TYPE_TABLE,
83  BLOBMSG_TYPE_UNSPEC,
84  BLOBMSG_TYPE_UNSPEC,
85  };
86 
87  if(type <= AMXC_VAR_ID_ANY) {
88  return converter[type];
89  } else {
90  return BLOBMSG_TYPE_UNSPEC;
91  }
92 
93 }
94 
95 static int isdot(int c) {
96  return (c == '.') ? 1 : 0;
97 }
98 
99 static int amxb_ubus_amxd_to_ubus_status(amxd_status_t rv) {
100  int status[amxd_status_last] = {
101  UBUS_STATUS_OK, // amxd_status_ok
102  UBUS_STATUS_UNKNOWN_ERROR, // amxd_status_unknown_error
103  UBUS_STATUS_NOT_FOUND, // amxd_status_object_not_found
104  UBUS_STATUS_METHOD_NOT_FOUND, // amxd_status_function_not_found
105  UBUS_STATUS_NOT_FOUND, // amxd_status_parameter_not_found
106  UBUS_STATUS_NOT_SUPPORTED, // amxd_status_function_not_implemented
107  UBUS_STATUS_INVALID_COMMAND, // amxd_status_invalid_function
108  UBUS_STATUS_INVALID_ARGUMENT, // amxd_status_invalid_function_argument
109  UBUS_STATUS_INVALID_ARGUMENT, // amxd_status_invalid_name
110  UBUS_STATUS_INVALID_ARGUMENT, // amxd_status_invalid_attr
111  UBUS_STATUS_INVALID_ARGUMENT, // amxd_status_invalid_value
112  UBUS_STATUS_NOT_SUPPORTED, // amxd_status_invalid_action
113  UBUS_STATUS_INVALID_ARGUMENT, // amxd_status_invalid_type
114  UBUS_STATUS_UNKNOWN_ERROR, // amxd_status_duplicate
115  UBUS_STATUS_UNKNOWN_ERROR, // amxd_status_deferred
116  UBUS_STATUS_NOT_SUPPORTED, // amxd_status_read_only
117  UBUS_STATUS_INVALID_ARGUMENT, // amxd_status_missing_key
118  UBUS_STATUS_UNKNOWN_ERROR, // amxd_status_file_not_found
119  UBUS_STATUS_INVALID_ARGUMENT, // amxd_status_invalid_arg
120  UBUS_STATUS_UNKNOWN_ERROR, // amxd_status_out_of_mem
121  UBUS_STATUS_UNKNOWN_ERROR, // amxd_status_recursion
122  UBUS_STATUS_NOT_FOUND, // amxd_status_invalid_path
123  UBUS_STATUS_UNKNOWN_ERROR, // amxd_status_invalid_expr
124  };
125 
126  if(rv < sizeof(status) / sizeof(int)) {
127  return status[rv];
128  } else {
129  return UBUS_STATUS_UNKNOWN_ERROR;
130  }
131 }
132 
133 static void amxb_ubus_func_return(amxb_ubus_t* amxb_ubus_ctx,
134  amxc_var_t* ret) {
135  switch(amxc_var_type_of(ret)) {
136  case AMXC_VAR_ID_HTABLE:
137  amxb_ubus_format_blob_table(amxc_var_constcast(amxc_htable_t, ret),
138  &amxb_ubus_ctx->b);
139  break;
140  case AMXC_VAR_ID_LIST: {
141  void* c = blobmsg_open_array(&amxb_ubus_ctx->b, "retval");
142  amxb_ubus_format_blob_array(amxc_var_constcast(amxc_llist_t, ret),
143  &amxb_ubus_ctx->b);
144  blobmsg_close_array(&amxb_ubus_ctx->b, c);
145  }
146  break;
147  default:
148  amxb_ubus_format_blob(ret, "retval", &amxb_ubus_ctx->b);
149  break;
150  }
151 }
152 
154  amxc_var_t* ret,
155  amxc_var_t* args,
156  amxc_var_t* status) {
157  // Each ambiorix function must return 3 messages:
158  // 1. the function return value, this can be of any type
159  // 2. the function out arguments, this must be a hash table, if no out
160  // arguments are available, an empty hash table must be send. ubus doesn't
161  // support NULL or void
162  // 3. the amxd status code, in a hash table with name "amxd-error-code"
163 
164  if(args == NULL) {
165  amxc_var_new(&args);
166  amxc_var_set_type(args, AMXC_VAR_ID_HTABLE);
167  } else if(amxc_var_type_of(args) != AMXC_VAR_ID_HTABLE) {
168  amxc_var_set_type(args, AMXC_VAR_ID_HTABLE);
169  }
170 
171  blob_buf_init(&fcall->amxb_ubus_ctx->b, 0);
173  ubus_send_reply(fcall->amxb_ubus_ctx->ubus_ctx, &fcall->req, fcall->amxb_ubus_ctx->b.head);
174 
175  blob_buf_init(&fcall->amxb_ubus_ctx->b, 0);
176  amxb_ubus_func_return(fcall->amxb_ubus_ctx, args);
177  ubus_send_reply(fcall->amxb_ubus_ctx->ubus_ctx, &fcall->req, fcall->amxb_ubus_ctx->b.head);
178 
179  blob_buf_init(&fcall->amxb_ubus_ctx->b, 0);
180  amxb_ubus_format_blob(status, "amxd-error-code", &fcall->amxb_ubus_ctx->b);
181  ubus_send_reply(fcall->amxb_ubus_ctx->ubus_ctx, &fcall->req, fcall->amxb_ubus_ctx->b.head);
182 
183  amxc_var_take_it(args);
184  amxc_var_delete(&args);
185 }
186 
187 static void amxb_ubus_exec_done(const amxc_var_t* const data,
188  void* const priv) {
189  amxb_ubus_fcall_t* fcall = (amxb_ubus_fcall_t*) priv;
190 
191  amxc_var_t* ret = GET_ARG(data, "retval");
192  amxc_var_t* args = GET_ARG(data, "args");
193  amxc_var_t* status = GET_ARG(data, "status");
194 
195  int rv = amxb_ubus_amxd_to_ubus_status((amxd_status_t) GET_UINT32(status, NULL));
196  amxb_ubus_build_messages(fcall, ret, args, status);
197  ubus_complete_deferred_request(fcall->amxb_ubus_ctx->ubus_ctx, &fcall->req, rv);
198 
199  amxc_llist_it_take(&fcall->it);
200  free(fcall);
201 }
202 
203 static void amxb_ubus_call_func(const amxc_var_t* const data,
204  void* const priv) {
205  amxb_ubus_fcall_t* fcall = (amxb_ubus_fcall_t*) priv;
206  const char* method = GET_CHAR(data, "method");
207  const char* path = GET_CHAR(data, "path");
208  amxc_var_t* args = GET_ARG(data, "args");
209  amxb_ubus_t* amxb_ubus_ctx = fcall->amxb_ubus_ctx;
210  amxd_status_t retval = amxd_status_ok;
211  amxc_var_t status;
212 
213  amxd_object_t* root_obj = amxd_dm_get_root(amxb_ubus_ctx->dm);
214  amxd_object_t* dm_obj = amxd_object_findf(root_obj, "%s", path);
215 
216  amxc_var_t ret;
217  amxc_var_init(&ret);
218  amxc_var_init(&status);
219  retval = amxd_object_invoke_function(dm_obj, method, args, &ret);
220  amxc_var_set(uint32_t, &status, retval);
221 
222  switch(retval) {
223  default:
224  amxb_ubus_build_messages(fcall, &ret, args, &status);
225  ubus_complete_deferred_request(fcall->amxb_ubus_ctx->ubus_ctx,
226  &fcall->req,
228 
229  amxd_function_deferred_remove(fcall->call_id);
230  amxc_llist_it_take(&fcall->it);
231  free(fcall);
232  break;
233  case amxd_status_deferred: {
234  uint64_t call_id = amxc_var_constcast(uint64_t, &ret);
235  amxd_function_deferred_remove(fcall->call_id);
236 
237  fcall->call_id = call_id;
238 
239  amxd_function_set_deferred_cb(call_id, amxb_ubus_exec_done, fcall);
240  }
241  break;
242  }
243 
244  amxc_var_clean(&status);
245  amxc_var_clean(&ret);
246 }
247 
248 /*
249 ** UBus doesn't respect the order of processing incoming messages.
250 
251  When a process has sent a request (ubus message) to another process and is waiting
252  for response (synchronous) it is possible that other requests are received.
253 
254  These incoming requests are added to a queue and are handled after the response is
255  received, but before the synchronous ubus call returns. This can break the order in
256  which messages are processed.
257 
258  To ensure that all messages are handled in the correct order, all func handlers
259  are called deferred from the eventloop.
260 */
261 static int amxb_ubus_func_handler(struct ubus_context* ctx,
262  struct ubus_object* obj,
263  struct ubus_request_data* req,
264  const char* method,
265  struct blob_attr* msg) {
266  int status = UBUS_STATUS_OK;
267  amxb_ubus_object_t* amxb_ubus_obj = amxc_container_of(obj, amxb_ubus_object_t, ubus_obj);
268  amxb_ubus_t* amxb_ubus_ctx = amxb_ubus_obj->amxb_ubus_ctx;
269  amxb_ubus_fcall_t* fcall = NULL;
270  amxd_object_t* root_obj = amxd_dm_get_root(amxb_ubus_ctx->dm);
271  amxd_object_t* dm_obj = amxd_object_findf(root_obj, "%s", amxb_ubus_obj->ubus_path);
272  amxd_function_t* func = amxd_object_get_function(dm_obj, method);
273 
274  amxc_var_t data;
275  amxc_var_t ret;
276  amxc_var_t* args = NULL;
277  amxc_var_init(&data);
278  amxc_var_init(&ret);
279 
280  when_null_status(dm_obj, exit, status = UBUS_STATUS_NOT_FOUND);
281  when_null_status(func, exit, status = UBUS_STATUS_METHOD_NOT_FOUND);
282 
283  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
284 
285  amxc_var_add_key(cstring_t, &data, "method", method);
286  amxc_var_add_key(cstring_t, &data, "path", amxb_ubus_obj->ubus_path);
287  args = amxc_var_add_key(amxc_htable_t, &data, "args", NULL);
288  amxb_ubus_parse_blob_table(args, (struct blob_attr*) blob_data(msg), blob_len(msg));
289 
290  fcall = (amxb_ubus_fcall_t*) calloc(1, sizeof(amxb_ubus_fcall_t));
291  amxd_function_defer(func, &fcall->call_id, &ret, NULL, NULL);
292  fcall->amxb_ubus_ctx = amxb_ubus_ctx;
293  amxc_llist_append(&amxb_ubus_ctx->pending_reqs, &fcall->it);
294 
295  ubus_defer_request(ctx, req, &fcall->req);
296 
297  status = amxp_sigmngr_deferred_call(NULL, amxb_ubus_call_func, &data, fcall);
298 
299 exit:
300  amxc_var_clean(&data);
301  amxc_var_clean(&ret);
302  return status;
303 }
304 
305 static void amxb_register_add_function(amxd_object_t* const object,
306  const char* name,
307  struct ubus_method* ubus_method) {
308  amxd_function_t* func = amxd_object_get_function(object, name);
309  size_t n_args = 0;
310  int index = 0;
311  struct blobmsg_policy* args = NULL;
312 
313  when_null(func, exit);
314  when_null(ubus_method, exit);
315 
316  ubus_method->name = func->name;
317  ubus_method->handler = amxb_ubus_func_handler;
318 
319  n_args = amxc_llist_size(&func->args);
320  args = (struct blobmsg_policy*) calloc(n_args, sizeof(struct blobmsg_policy));
321  when_null(args, exit);
322 
323  amxc_llist_for_each(it, (&func->args)) {
324  amxd_func_arg_t* amxd_arg = amxc_llist_it_get_data(it, amxd_func_arg_t, it);
325  args[index].name = amxd_arg->name;
326  args[index].type = amxb_ubus_var_type_to_ubus_type(amxd_arg->type);
327  index++;
328  }
329 
330  ubus_method->policy = args;
331  ubus_method->n_policy = n_args;
332 
333 exit:
334  return;
335 }
336 
337 static bool amxb_ubus_filter_object(amxd_object_t* const object,
338  AMXB_UNUSED int32_t depth,
339  AMXB_UNUSED void* priv) {
340  bool retval = true;
341  amxd_object_t* parent = NULL;
342  when_true(amxd_object_get_type(object) == amxd_object_root, exit);
343 
344  if(amxd_object_is_attr_set(object, amxd_oattr_private)) {
345  retval = false;
346  goto exit;
347  }
348 
349  parent = amxd_object_get_parent(object);
350  if(amxd_object_get_type(object) != amxd_object_instance) {
351  if(amxd_object_get_type(parent) == amxd_object_template) {
352  retval = false;
353  goto exit;
354  }
355  }
356 
357 exit:
358  return retval;
359 }
360 
361 static void amxb_ubus_send_notification(const char* const sig_name,
362  const amxc_var_t* const data,
363  void* const priv) {
364  amxb_ubus_object_t* amxb_ubus_obj = (amxb_ubus_object_t*) priv;
365  amxb_ubus_t* amxb_ubus_ctx = amxb_ubus_obj->amxb_ubus_ctx;
366 
367  blob_buf_init(&amxb_ubus_ctx->b, 0);
368  amxb_ubus_format_blob_table(amxc_var_constcast(amxc_htable_t, data),
369  &amxb_ubus_ctx->b);
370  ubus_notify(amxb_ubus_ctx->ubus_ctx,
371  &amxb_ubus_obj->ubus_obj,
372  sig_name, amxb_ubus_ctx->b.head,
373  -1);
374 }
375 
376 static void amxb_ubus_subcribe(AMXB_UNUSED struct ubus_context* ctx,
377  struct ubus_object* obj) {
378  amxb_ubus_object_t* amxb_ubus_obj = amxc_container_of(obj,
380  ubus_obj);
381  amxb_ubus_t* amxb_ubus_ctx = amxb_ubus_obj->amxb_ubus_ctx;
382  amxd_object_t* root_obj = amxd_dm_get_root(amxb_ubus_ctx->dm);
383  amxd_object_t* dm_obj = amxd_object_findf(root_obj, "%s",
384  amxb_ubus_obj->ubus_path);
385  when_null(dm_obj, exit);
386 
387  if(amxb_ubus_obj->ubus_obj.has_subscribers) {
388  amxc_string_t expression;
389  char* path = amxd_object_get_path(dm_obj, AMXD_OBJECT_INDEXED);
390 
391  amxc_string_init(&expression, 0);
392  amxc_string_appendf(&expression, "path starts with \"%s.\"", path);
393  amxp_slot_connect_filtered(&amxb_ubus_ctx->dm->sigmngr,
394  ".*",
395  amxc_string_get(&expression, 0),
397  amxb_ubus_obj);
398  amxc_string_clean(&expression);
399  free(path);
400  } else {
401  amxp_slot_disconnect_with_priv(&amxb_ubus_ctx->dm->sigmngr,
403  amxb_ubus_obj);
404  }
405 
406 exit:
407  return;
408 }
409 
410 static void amxb_ubus_build_obj(amxb_ubus_t* amxb_ubus_ctx,
411  amxb_ubus_object_t* obj,
412  amxd_object_t* const object) {
413  struct ubus_method* methods = NULL;
414  const amxc_llist_t* lfuncs = NULL;
415  amxc_var_t funcs;
416  int index = 0;
417  amxc_var_init(&funcs);
418 
419  obj->ubus_obj.subscribe_cb = amxb_ubus_subcribe;
420  obj->amxb_ubus_ctx = amxb_ubus_ctx;
421  obj->ubus_path = amxd_object_get_path(object, AMXD_OBJECT_INDEXED);
422 
423  amxd_object_list_functions(object, &funcs, amxd_dm_access_protected);
424  lfuncs = amxc_var_constcast(amxc_llist_t, &funcs);
425 
426  obj->ubus_obj.name = obj->ubus_path;
427  obj->ubus_obj.n_methods = amxc_llist_size(lfuncs);
428  if(obj->ubus_obj.n_methods > 0) {
429  methods = (struct ubus_method*) calloc(obj->ubus_obj.n_methods, sizeof(struct ubus_method));
430  }
431  obj->ubus_obj.methods = methods;
432  obj->ubus_obj.type->name = obj->ubus_path;
433  obj->ubus_obj.type->id = 0;
434  obj->ubus_obj.type->n_methods = obj->ubus_obj.n_methods;
435  obj->ubus_obj.type->methods = obj->ubus_obj.methods;
436 
437  amxc_llist_for_each(it, lfuncs) {
438  const char* func_name = amxc_var_constcast(cstring_t, amxc_var_from_llist_it(it));
440  func_name,
441  &methods[index]);
442  index++;
443  }
444 
445  amxc_var_clean(&funcs);
446 }
447 
448 static void amxb_ubus_register_object(amxd_object_t* const object,
449  AMXB_UNUSED int32_t depth,
450  void* priv) {
451  amxb_ubus_object_t* obj = NULL;
452  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) priv;
453 
454  when_true(object->type == amxd_object_root, exit);
455 
456  obj = (amxb_ubus_object_t*) calloc(1, sizeof(amxb_ubus_object_t));
457  when_null(obj, exit);
458  obj->ubus_obj.type = (struct ubus_object_type*) calloc(1, sizeof(struct ubus_object_type));
459  if(obj->ubus_obj.type == NULL) {
460  free(obj);
461  goto exit;
462  }
463 
464  amxb_ubus_build_obj(amxb_ubus_ctx, obj, object);
465  if(ubus_add_object(amxb_ubus_ctx->ubus_ctx, &obj->ubus_obj) != UBUS_STATUS_OK) {
466  amxb_ubus_obj_it_free(&obj->it);
467  goto exit;
468  }
469 
470  amxc_llist_append(&amxb_ubus_ctx->registered_objs, &obj->it);
471 
472 exit:
473  return;
474 }
475 
476 static void amxb_ubus_register_add(const char* const sig_name,
477  const amxc_var_t* const data,
478  void* const priv) {
479  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) priv;
480  amxd_object_t* object = amxd_dm_signal_get_object(amxb_ubus_ctx->dm, data);
481 
482  if(strcmp(sig_name, "dm:instance-added") == 0) {
483  uint32_t index = amxc_var_constcast(uint32_t,
484  amxc_var_get_key(data, "index", 0));
485  object = amxd_object_get_instance(object, NULL, index);
486  }
487 
488  if(object != NULL) {
489  amxb_ubus_register_object(object, 0, amxb_ubus_ctx);
490  }
491 }
492 
493 static void amxb_ubus_register_tree(AMXB_UNUSED const char* const sig_name,
494  const amxc_var_t* const data,
495  void* const priv) {
496  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) priv;
497  amxd_object_t* object = amxd_dm_signal_get_object(amxb_ubus_ctx->dm, data);
498 
499  if(object != NULL) {
500  amxb_ubus_register_object(object, 0, amxb_ubus_ctx);
501  amxd_object_hierarchy_walk(object,
502  amxd_direction_down,
505  INT32_MAX,
506  amxb_ubus_ctx);
507  }
508 }
509 
510 static void amxb_ubus_register_remove(const char* const sig_name,
511  const amxc_var_t* const data,
512  void* const priv) {
513  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) priv;
514  amxd_dm_t* dm = amxb_ubus_ctx->dm;
515  const char* object_path = GET_CHAR(data, "path");
516  amxc_string_t full_path;
517 
518  amxc_string_init(&full_path, 0);
519  if(strcmp(sig_name, "dm:instance-removed") == 0) {
520  uint32_t index = amxc_var_constcast(uint32_t,
521  amxc_var_get_key(data, "index", 0));
522  amxc_string_setf(&full_path, "%s%d", object_path, index);
523  } else {
524  amxc_string_setf(&full_path, "%s", object_path);
525  amxc_string_trimr(&full_path, isdot);
526  }
527 
528  amxc_llist_for_each(it, (&amxb_ubus_ctx->registered_objs)) {
529  amxb_ubus_object_t* obj = amxc_llist_it_get_data(it,
531  it);
532  if(strcmp(obj->ubus_obj.name, amxc_string_get(&full_path, 0)) == 0) {
533  ubus_remove_object(amxb_ubus_ctx->ubus_ctx, &obj->ubus_obj);
534  amxp_slot_disconnect_with_priv(&dm->sigmngr, amxb_ubus_send_notification, obj);
536  break;
537  }
538  }
539 
540  amxc_string_clean(&full_path);
541 }
542 
543 static void amxb_ubus_register_dm(UNUSED const char* const sig_name,
544  UNUSED const amxc_var_t* const data,
545  void* const priv) {
546  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) priv;
547  amxd_dm_t* dm = amxb_ubus_ctx->dm;
548 
549  amxd_object_hierarchy_walk(amxd_dm_get_root(dm),
550  amxd_direction_down,
553  INT32_MAX,
554  amxb_ubus_ctx);
555 
556  amxp_slot_disconnect_with_priv(&dm->sigmngr, amxb_ubus_register_dm, amxb_ubus_ctx);
557 
558  amxp_slot_connect(&dm->sigmngr,
559  "dm:root-added",
560  NULL,
562  amxb_ubus_ctx);
563 
564  amxp_slot_connect(&dm->sigmngr,
565  "dm:root-removed",
566  NULL,
568  amxb_ubus_ctx);
569 
570  amxp_slot_connect(&dm->sigmngr,
571  "dm:object-added",
572  NULL,
574  amxb_ubus_ctx);
575  amxp_slot_connect(&dm->sigmngr,
576  "dm:instance-added",
577  NULL,
579  amxb_ubus_ctx);
580  amxp_slot_connect(&dm->sigmngr,
581  "dm:object-removed",
582  NULL,
584  amxb_ubus_ctx);
585  amxp_slot_connect(&dm->sigmngr,
586  "dm:instance-removed",
587  NULL,
589  amxb_ubus_ctx);
590 }
591 
592 void PRIVATE amxb_ubus_cancel_requests(amxb_ubus_t* amxb_ubus_ctx) {
593  amxc_var_t ret;
594  amxc_var_init(&ret);
595  amxc_llist_for_each(it, &amxb_ubus_ctx->pending_reqs) {
596  amxb_ubus_fcall_t* fcall = amxc_container_of(it, amxb_ubus_fcall_t, it);
597  blob_buf_init(&amxb_ubus_ctx->b, 0);
598  amxb_ubus_func_return(fcall->amxb_ubus_ctx, &ret);
599  ubus_send_reply(amxb_ubus_ctx->ubus_ctx, &fcall->req, amxb_ubus_ctx->b.head);
600 
601  ubus_complete_deferred_request(amxb_ubus_ctx->ubus_ctx,
602  &fcall->req,
603  UBUS_STATUS_UNKNOWN_ERROR);
604 
605  amxd_function_set_deferred_cb(fcall->call_id, NULL, NULL);
606  amxd_function_deferred_remove(fcall->call_id);
607  amxc_llist_it_take(it);
608  free(fcall);
609  }
610 
611  amxc_var_clean(&ret);
612 }
613 
614 void PRIVATE amxb_ubus_obj_it_free(amxc_llist_it_t* it) {
615  amxb_ubus_object_t* obj = amxc_llist_it_get_data(it,
617  it);
618  struct ubus_method* methods = (struct ubus_method*) obj->ubus_obj.methods;
619 
620  amxc_llist_it_take(it);
621  for(int i = 0; i < obj->ubus_obj.n_methods; i++) {
622  struct blobmsg_policy* policy =
623  (struct blobmsg_policy*) methods[i].policy;
624  free(policy);
625  methods[i].policy = NULL;
626  }
627 
628 
629  amxp_slot_disconnect_with_priv(&obj->amxb_ubus_ctx->dm->sigmngr,
631  obj);
632 
633  free(obj->ubus_path);
634  free(methods);
635  free(obj->ubus_obj.type);
636  free(obj);
637 }
638 
639 int PRIVATE amxb_ubus_register(void* const ctx,
640  amxd_dm_t* const dm) {
641  int status = UBUS_STATUS_UNKNOWN_ERROR;
642  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) ctx;
643  const amxc_var_t* cfg_ros = amxb_ubus_get_config_option("register-on-start-event");
644 
645  when_not_null(amxb_ubus_ctx->dm, exit);
646  amxb_ubus_ctx->dm = dm;
647 
648  if(amxc_var_dyncast(bool, cfg_ros)) {
649  amxp_slot_connect(&dm->sigmngr,
650  "app:start",
651  NULL,
653  amxb_ubus_ctx);
654  } else {
655  amxb_ubus_register_dm(NULL, NULL, ctx);
656  }
657 
658  status = UBUS_STATUS_OK;
659 
660 exit:
661  return status;
662 }
int PRIVATE amxb_ubus_format_blob_array(const amxc_llist_t *list, struct blob_buf *b)
int PRIVATE amxb_ubus_format_blob_table(const amxc_htable_t *table, struct blob_buf *b)
const amxc_var_t * amxb_ubus_get_config_option(const char *name)
Definition: amxb_ubus.c:218
int PRIVATE amxb_ubus_format_blob(amxc_var_t *data, const char *key, struct blob_buf *b)
int PRIVATE amxb_ubus_parse_blob_table(amxc_var_t *var, struct blob_attr *attr, int len)
void PRIVATE amxb_ubus_obj_it_free(amxc_llist_it_t *it)
static void amxb_ubus_register_object(amxd_object_t *const object, AMXB_UNUSED int32_t depth, void *priv)
static void amxb_ubus_register_dm(UNUSED const char *const sig_name, UNUSED const amxc_var_t *const data, void *const priv)
static void amxb_ubus_call_func(const amxc_var_t *const data, void *const priv)
static void amxb_ubus_exec_done(const amxc_var_t *const data, void *const priv)
static int amxb_ubus_amxd_to_ubus_status(amxd_status_t rv)
static void amxb_ubus_build_obj(amxb_ubus_t *amxb_ubus_ctx, amxb_ubus_object_t *obj, amxd_object_t *const object)
struct _amxb_ubus_fcall amxb_ubus_fcall_t
static bool amxb_ubus_filter_object(amxd_object_t *const object, AMXB_UNUSED int32_t depth, AMXB_UNUSED void *priv)
static void amxb_ubus_register_remove(const char *const sig_name, const amxc_var_t *const data, void *const priv)
static enum blobmsg_type amxb_ubus_var_type_to_ubus_type(int type)
static void amxb_ubus_send_notification(const char *const sig_name, const amxc_var_t *const data, void *const priv)
static void amxb_ubus_subcribe(AMXB_UNUSED struct ubus_context *ctx, struct ubus_object *obj)
static void amxb_ubus_func_return(amxb_ubus_t *amxb_ubus_ctx, amxc_var_t *ret)
static void amxb_ubus_register_add(const char *const sig_name, const amxc_var_t *const data, void *const priv)
int PRIVATE amxb_ubus_register(void *const ctx, amxd_dm_t *const dm)
static void amxb_ubus_build_messages(amxb_ubus_fcall_t *fcall, amxc_var_t *ret, amxc_var_t *args, amxc_var_t *status)
static void amxb_register_add_function(amxd_object_t *const object, const char *name, struct ubus_method *ubus_method)
static int amxb_ubus_func_handler(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg)
static int isdot(int c)
static void amxb_ubus_register_tree(AMXB_UNUSED const char *const sig_name, const amxc_var_t *const data, void *const priv)
void PRIVATE amxb_ubus_cancel_requests(amxb_ubus_t *amxb_ubus_ctx)
struct ubus_request_data req
amxc_llist_it_t it
amxb_ubus_t * amxb_ubus_ctx
struct ubus_object ubus_obj
Definition: amxb_ubus.h:101
amxc_llist_it_t it
Definition: amxb_ubus.h:99
amxb_ubus_t * amxb_ubus_ctx
Definition: amxb_ubus.h:102
amxc_llist_t pending_reqs
Definition: amxb_ubus.h:94
amxc_llist_t registered_objs
Definition: amxb_ubus.h:91
struct blob_buf b
Definition: amxb_ubus.h:89
struct ubus_context * ubus_ctx
Definition: amxb_ubus.h:87
amxd_dm_t * dm
Definition: amxb_ubus.h:95
static amxd_dm_t dm