Amxb_Ubus  3.3.1
Ambiorix Ubus API
amxb_ubus.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 <stdlib.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <unistd.h>
59 
60 #include <amxc/amxc_string_split.h>
61 
63 
64 #include "amxb_ubus.h"
65 #include <amxb_ubus_version.h>
66 
67 static const amxc_var_t* config_opts = NULL;
68 static amxp_timer_t* wait_timer = NULL;
69 static amxc_llist_t avaiable_paths;
70 
71 static void amxb_ubus_remove_sub(AMXB_UNUSED const char* key,
72  amxc_htable_it_t* it) {
73  amxb_ubus_sub_t* sub = amxc_htable_it_get_data(it, amxb_ubus_sub_t, it);
74  amxp_timer_delete(&sub->reactivate);
75  free(sub);
76 }
77 
78 static int amxb_ubus_set_config(amxc_var_t* const configuration) {
79  struct stat sb;
80  amxc_var_t* uris = GET_ARG(configuration, "uris");
81 
82  config_opts = configuration;
83 
84  if((configuration != NULL) && (uris == NULL)) {
85  uris = amxc_var_add_key(amxc_llist_t, configuration, "uris", NULL);
86  }
87 
88  if(stat("/var/run/ubus.sock", &sb) == 0) {
89  amxc_var_add(cstring_t, uris, "ubus:/var/run/ubus.sock");
90  }
91  if(stat("/var/run/ubus/ubus.sock", &sb) == 0) {
92  amxc_var_add(cstring_t, uris, "ubus:/var/run/ubus/ubus.sock");
93  }
94 
95  return 0;
96 }
97 
98 static void amxb_ubus_remove_connections(amxc_llist_it_t* lit) {
99  amxb_bus_ctx_t* bus_ctx = amxc_llist_it_get_data(lit, amxb_bus_ctx_t, it);
100  amxb_disconnect(bus_ctx);
101 }
102 
103 static void amxb_ubus_reactivate_subscription(UNUSED amxp_timer_t* timer, void* priv) {
104  amxb_ubus_sub_t* amxb_ubus_sub = (amxb_ubus_sub_t*) priv;
105  amxc_htable_t* subscribers = NULL;
106  amxb_ubus_t* amxb_ubus_ctx = NULL;
107  const char* path = NULL;
108  int ret = 0;
109 
110  subscribers = container_of(amxb_ubus_sub->it.ait->array, amxc_htable_t, table);
111  amxb_ubus_ctx = container_of(subscribers, amxb_ubus_t, subscribers);
112  path = amxc_htable_it_get_key(&amxb_ubus_sub->it);
113 
114  amxc_htable_it_take(&amxb_ubus_sub->it);
115  ret = ubus_unregister_subscriber(amxb_ubus_ctx->ubus_ctx, &amxb_ubus_sub->sub);
116  when_failed(ret, exit);
117  amxb_ubus_subscribe(amxb_ubus_ctx, path);
118 
119 exit:
120  amxp_timer_delete(&amxb_ubus_sub->reactivate);
121  amxc_htable_it_clean(&amxb_ubus_sub->it, NULL);
122  free(amxb_ubus_sub);
123 }
124 
125 static void amxb_ubus_watcher(UNUSED struct ubus_context* ctx,
126  struct ubus_event_handler* ev,
127  UNUSED const char* type,
128  struct blob_attr* msg) {
129  amxb_ubus_t* amxb_ubus_ctx = container_of(ev, amxb_ubus_t, watcher);
130  amxc_var_t watch_event;
131  amxc_htable_it_t* it = NULL;
132  const char* p = NULL;
133  amxb_ubus_sub_t* amxb_ubus_sub = NULL;
134  amxc_string_t signal_name;
135 
136  amxc_string_init(&signal_name, 0);
137  amxc_var_init(&watch_event);
138  amxc_var_set_type(&watch_event, AMXC_VAR_ID_HTABLE);
139  amxb_ubus_parse_blob_table(&watch_event,
140  (struct blob_attr*) blob_data(msg),
141  blob_len(msg));
142 
143  p = GET_CHAR(&watch_event, "path");
144  amxc_string_setf(&signal_name, "wait:%s.", p);
145  amxp_sigmngr_trigger_signal(NULL, amxc_string_get(&signal_name, 0), NULL);
146 
147  it = amxc_htable_get(&amxb_ubus_ctx->subscribers, p);
148  when_null(it, exit);
149  amxb_ubus_sub = amxc_container_of(it, amxb_ubus_sub_t, it);
150 
151  if(amxb_ubus_sub->reactivate == NULL) {
152  amxp_timer_new(&amxb_ubus_sub->reactivate,
154  amxb_ubus_sub);
155  }
156  amxp_timer_start(amxb_ubus_sub->reactivate, 100);
157 
158 exit:
159  amxc_string_clean(&signal_name);
160  amxc_var_clean(&watch_event);
161 }
162 
163 static void amxb_ubus_object_available(UNUSED amxp_timer_t* timer, UNUSED void* priv) {
164  amxc_llist_for_each(it, &avaiable_paths) {
165  amxc_string_t* path = amxc_string_from_llist_it(it);
166  amxp_sigmngr_emit_signal(NULL, amxc_string_get(path, 0), NULL);
167  amxc_string_delete(&path);
168  }
169 
170  amxp_timer_delete(&wait_timer);
171 }
172 
173 static void amxb_ubus_wait_watcher(UNUSED struct ubus_context* ctx,
174  UNUSED struct ubus_event_handler* ev,
175  UNUSED const char* type,
176  struct blob_attr* msg) {
177  amxc_var_t watch_event;
178  amxc_string_t* sig_name = NULL;
179 
180  amxc_var_init(&watch_event);
181  amxc_var_set_type(&watch_event, AMXC_VAR_ID_HTABLE);
182  amxb_ubus_parse_blob_table(&watch_event,
183  (struct blob_attr*) blob_data(msg),
184  blob_len(msg));
185 
186  amxc_string_new(&sig_name, 0);
187  amxc_string_setf(sig_name, "wait:%s.", GET_CHAR(&watch_event, "path"));
188  if(amxp_sigmngr_find_signal(NULL, amxc_string_get(sig_name, 0)) != NULL) {
189  amxc_llist_append(&avaiable_paths, &sig_name->it);
190  if(wait_timer == NULL) {
191  amxp_timer_new(&wait_timer, amxb_ubus_object_available, NULL);
192  }
193  amxp_timer_start(wait_timer, 100);
194  } else {
195  amxc_string_delete(&sig_name);
196  }
197  amxc_var_clean(&watch_event);
198 }
199 
200 static void amxb_ubus_config_changed(UNUSED const char* const sig_name,
201  UNUSED const amxc_var_t* const data,
202  void* const priv) {
203  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) priv;
204  if(GET_BOOL(config_opts, "watch-ubus-events")) {
205  if(amxb_ubus_ctx->watcher.cb == NULL) {
206  amxb_ubus_ctx->watcher.cb = amxb_ubus_watcher;
207  ubus_register_event_handler(amxb_ubus_ctx->ubus_ctx,
208  &amxb_ubus_ctx->watcher, "ubus.object.add");
209  }
210  } else {
211  if(amxb_ubus_ctx->watcher.cb != NULL) {
212  ubus_unregister_event_handler(amxb_ubus_ctx->ubus_ctx, &amxb_ubus_ctx->watcher);
213  amxb_ubus_ctx->watcher.cb = NULL;
214  }
215  }
216 }
217 
218 const amxc_var_t* amxb_ubus_get_config_option(const char* name) {
219  return GET_ARG(config_opts, name);
220 }
221 
222 void* PRIVATE amxb_ubus_connect(const char* host,
223  const char* port,
224  const char* path,
225  amxp_signal_mngr_t* sigmngr) {
226  amxb_ubus_t* amxb_ubus_ctx = NULL;
227 
228  when_not_null(host, exit);
229  when_not_null(port, exit);
230 
231  amxb_ubus_ctx = (amxb_ubus_t*) calloc(1, sizeof(amxb_ubus_t));
232  when_null(amxb_ubus_ctx, exit);
233 
234  amxb_ubus_ctx->ubus_ctx = ubus_connect(path);
235  if(amxb_ubus_ctx->ubus_ctx == NULL) {
236  free(amxb_ubus_ctx);
237  amxb_ubus_ctx = NULL;
238  goto exit;
239  }
240 
241  amxc_htable_init(&amxb_ubus_ctx->subscribers, 5);
242  blob_buf_init(&amxb_ubus_ctx->b, 0);
243  amxb_ubus_ctx->sigmngr = sigmngr;
244  amxc_llist_init(&amxb_ubus_ctx->registered_objs);
245  amxc_llist_init(&amxb_ubus_ctx->pending_reqs);
246 
247  if(GET_BOOL(config_opts, "watch-ubus-events")) {
248  amxb_ubus_ctx->watcher.cb = amxb_ubus_watcher;
249  ubus_register_event_handler(amxb_ubus_ctx->ubus_ctx,
250  &amxb_ubus_ctx->watcher, "ubus.object.add");
251  }
252  amxp_slot_connect(NULL,
253  "config:changed",
254  NULL,
256  amxb_ubus_ctx);
257 
258 exit:
259  return amxb_ubus_ctx;
260 }
261 
262 int PRIVATE amxb_ubus_disconnect(void* ctx) {
263  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) ctx;
264 
265  when_null(amxb_ubus_ctx, exit);
266  when_null(amxb_ubus_ctx->ubus_ctx, exit);
267 
268  amxp_slot_disconnect_with_priv(NULL,
270  amxb_ubus_ctx);
271 
272  amxc_htable_clean(&amxb_ubus_ctx->subscribers, amxb_ubus_remove_sub);
273  amxb_ubus_cancel_requests(amxb_ubus_ctx);
274  ubus_free(amxb_ubus_ctx->ubus_ctx);
275  blob_buf_free(&amxb_ubus_ctx->b);
276  amxb_ubus_ctx->ubus_ctx = NULL;
277 
278 exit:
279  return 0;
280 }
281 
282 int PRIVATE amxb_ubus_get_fd(void* ctx) {
283  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) ctx;
284  int fd = -1;
285 
286  when_null(amxb_ubus_ctx, exit);
287  when_null(amxb_ubus_ctx->ubus_ctx, exit);
288 
289  fd = amxb_ubus_ctx->ubus_ctx->sock.fd;
290 
291 exit:
292  return fd;
293 }
294 
295 int PRIVATE amxb_ubus_read(void* ctx) {
296  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) ctx;
297  struct ubus_context* ubus_ctx = NULL;
298  int retval = -1;
299 
300  when_null(amxb_ubus_ctx, exit);
301  when_null(amxb_ubus_ctx->ubus_ctx, exit);
302 
303  ubus_ctx = amxb_ubus_ctx->ubus_ctx;
304  ubus_ctx->sock.cb(&ubus_ctx->sock, ULOOP_READ);
305 
306  if(ubus_ctx->sock.eof) {
307  retval = -1;
308  } else {
309  retval = 0;
310  }
311 
312 exit:
313  return retval;
314 }
315 
316 void PRIVATE amxb_ubus_free(void* ctx) {
317  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) ctx;
318 
319  when_null(amxb_ubus_ctx, exit);
320  amxc_llist_clean(&amxb_ubus_ctx->registered_objs, amxb_ubus_obj_it_free);
321  free(amxb_ubus_ctx);
322 
323 exit:
324  return;
325 }
326 
327 static void amxb_ubus_wait_for_done(UNUSED const char* const sig_name,
328  UNUSED const amxc_var_t* const d,
329  void* const priv) {
330  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) priv;
331  if(amxb_ubus_ctx->wait_watcher.cb != NULL) {
332  ubus_unregister_event_handler(amxb_ubus_ctx->ubus_ctx, &amxb_ubus_ctx->wait_watcher);
333  amxb_ubus_ctx->wait_watcher.cb = NULL;
334  amxp_slot_disconnect_with_priv(NULL, amxb_ubus_wait_for_done, amxb_ubus_ctx);
335  }
336 }
337 
338 static int amxb_ubus_wait_for(void* const ctx, UNUSED const char* object) {
339  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) ctx;
340  int retval = -1;
341 
342  when_null(amxb_ubus_ctx, exit);
343  if(amxb_ubus_ctx->wait_watcher.cb == NULL) {
344  amxb_ubus_ctx->wait_watcher.cb = amxb_ubus_wait_watcher;
345  ubus_register_event_handler(amxb_ubus_ctx->ubus_ctx,
346  &amxb_ubus_ctx->wait_watcher, "ubus.object.add");
347  amxp_slot_connect(NULL, "wait:done", NULL, amxb_ubus_wait_for_done, amxb_ubus_ctx);
348  }
349 
350  retval = 0;
351 
352 exit:
353  return retval;
354 }
355 
356 static uint32_t amxb_ubus_capabilities(UNUSED void* ctx) {
357  return AMXB_BE_DISCOVER | AMXB_BE_DISCOVER_RESOLVE;
358 }
359 
360 static bool amxb_ubus_has(void* ctx, const char* object) {
361  amxb_ubus_t* amxb_ubus_ctx = (amxb_ubus_t*) ctx;
362  int retval = -1;
363  bool has_object = false;
364  uint32_t id = 0;
365  when_null(object, exit);
366 
367  retval = ubus_lookup_id(amxb_ubus_ctx->ubus_ctx, object, &id);
368 
369  when_failed(retval, exit);
370 
371  has_object = (id != 0);
372 
373 exit:
374  return has_object;
375 }
376 
377 static amxb_be_funcs_t amxb_ubus_impl = {
378  .it = { .ait = NULL, .key = NULL, .next = NULL },
379  .handle = NULL,
380  .connections = { .head = NULL, .tail = NULL },
381  .name = "ubus",
382  .size = sizeof(amxb_be_funcs_t),
383  .connect = amxb_ubus_connect,
384  .disconnect = amxb_ubus_disconnect,
385  .get_fd = amxb_ubus_get_fd,
386  .read = amxb_ubus_read,
387  .new_invoke = NULL,
388  .free_invoke = NULL,
389  .invoke = amxb_ubus_invoke,
390  .async_invoke = amxb_ubus_async_invoke,
391  .close_request = amxb_ubus_close_request,
392  .wait_request = amxb_ubus_wait_request,
393  .subscribe = amxb_ubus_subscribe,
394  .unsubscribe = amxb_ubus_unsubscribe,
395  .free = amxb_ubus_free,
396  .register_dm = amxb_ubus_register,
397  .get = NULL,
398  .set = NULL,
399  .add = NULL,
400  .del = NULL,
401  .get_supported = NULL,
402  .set_config = amxb_ubus_set_config,
403  .describe = NULL,
404  .list = amxb_ubus_list,
405  .listen = NULL,
406  .accept = NULL,
407  .read_raw = NULL,
408  .wait_for = amxb_ubus_wait_for,
409  .capabilities = amxb_ubus_capabilities,
410  .has = amxb_ubus_has,
411  .get_instances = NULL,
412  .get_filtered = NULL,
413 };
414 
415 static amxb_version_t sup_min_lib_version = {
416  .major = 4,
417  .minor = 8,
418  .build = 0
419 };
420 
421 static amxb_version_t sup_max_lib_version = {
422  .major = 4,
423  .minor = -1,
424  .build = -1
425 };
426 
427 static amxb_version_t ubus_be_version = {
428  .major = AMXB_UBUS_VERSION_MAJOR,
429  .minor = AMXB_UBUS_VERSION_MINOR,
430  .build = AMXB_UBUS_VERSION_BUILD,
431 };
432 
433 amxb_be_info_t amxb_ubus_be_info = {
434  .min_supported = &sup_min_lib_version,
435  .max_supported = &sup_max_lib_version,
436  .be_version = &ubus_be_version,
437  .name = "ubus",
438  .description = "AMXB Backend for UBUS (Openwrt/Prplwrt)",
439  .funcs = &amxb_ubus_impl,
440 };
441 
442 amxb_be_info_t* amxb_be_info(void) {
443  return &amxb_ubus_be_info;
444 }
445 
446 int amxb_be_ubus_init(void) {
447  return amxb_be_register(&amxb_ubus_impl);
448 }
449 
451  amxc_llist_clean(&amxb_ubus_impl.connections, amxb_ubus_remove_connections);
452 
453  return amxb_be_unregister(&amxb_ubus_impl);
454 }
int PRIVATE amxb_ubus_disconnect(void *ctx)
Definition: amxb_ubus.c:262
static void amxb_ubus_remove_sub(AMXB_UNUSED const char *key, amxc_htable_it_t *it)
Definition: amxb_ubus.c:71
static int amxb_ubus_set_config(amxc_var_t *const configuration)
Definition: amxb_ubus.c:78
static int amxb_ubus_wait_for(void *const ctx, UNUSED const char *object)
Definition: amxb_ubus.c:338
static void amxb_ubus_remove_connections(amxc_llist_it_t *lit)
Definition: amxb_ubus.c:98
static const amxc_var_t * config_opts
Definition: amxb_ubus.c:67
static void amxb_ubus_reactivate_subscription(UNUSED amxp_timer_t *timer, void *priv)
Definition: amxb_ubus.c:103
amxb_be_info_t * amxb_be_info(void)
Definition: amxb_ubus.c:442
void PRIVATE amxb_ubus_free(void *ctx)
Definition: amxb_ubus.c:316
static amxb_version_t ubus_be_version
Definition: amxb_ubus.c:427
amxb_be_info_t amxb_ubus_be_info
Definition: amxb_ubus.c:433
static uint32_t amxb_ubus_capabilities(UNUSED void *ctx)
Definition: amxb_ubus.c:356
static void amxb_ubus_watcher(UNUSED struct ubus_context *ctx, struct ubus_event_handler *ev, UNUSED const char *type, struct blob_attr *msg)
Definition: amxb_ubus.c:125
static void amxb_ubus_config_changed(UNUSED const char *const sig_name, UNUSED const amxc_var_t *const data, void *const priv)
Definition: amxb_ubus.c:200
int amxb_be_ubus_clean(void)
Definition: amxb_ubus.c:450
static amxp_timer_t * wait_timer
Definition: amxb_ubus.c:68
int PRIVATE amxb_ubus_read(void *ctx)
Definition: amxb_ubus.c:295
static bool amxb_ubus_has(void *ctx, const char *object)
Definition: amxb_ubus.c:360
int amxb_be_ubus_init(void)
Definition: amxb_ubus.c:446
int PRIVATE amxb_ubus_get_fd(void *ctx)
Definition: amxb_ubus.c:282
const amxc_var_t * amxb_ubus_get_config_option(const char *name)
Definition: amxb_ubus.c:218
static void amxb_ubus_object_available(UNUSED amxp_timer_t *timer, UNUSED void *priv)
Definition: amxb_ubus.c:163
static void amxb_ubus_wait_watcher(UNUSED struct ubus_context *ctx, UNUSED struct ubus_event_handler *ev, UNUSED const char *type, struct blob_attr *msg)
Definition: amxb_ubus.c:173
void *PRIVATE amxb_ubus_connect(const char *host, const char *port, const char *path, amxp_signal_mngr_t *sigmngr)
Definition: amxb_ubus.c:222
static amxc_llist_t avaiable_paths
Definition: amxb_ubus.c:69
static amxb_be_funcs_t amxb_ubus_impl
Definition: amxb_ubus.c:377
static amxb_version_t sup_max_lib_version
Definition: amxb_ubus.c:421
static void amxb_ubus_wait_for_done(UNUSED const char *const sig_name, UNUSED const amxc_var_t *const d, void *const priv)
Definition: amxb_ubus.c:327
static amxb_version_t sup_min_lib_version
Definition: amxb_ubus.c:415
void PRIVATE amxb_ubus_obj_it_free(amxc_llist_it_t *it)
int PRIVATE amxb_ubus_wait_request(void *const ctx, amxb_request_t *request, int timeout)
int PRIVATE amxb_ubus_close_request(void *const ctx, amxb_request_t *request)
int PRIVATE amxb_ubus_invoke(void *const ctx, amxb_invoke_t *invoke_ctx, amxc_var_t *args, amxb_request_t *request, int timeout)
int PRIVATE amxb_ubus_list(void *const bus_ctx, const char *object, uint32_t flags, uint32_t access, amxb_request_t *request)
int PRIVATE amxb_ubus_unsubscribe(void *const ctx, const char *object)
int PRIVATE amxb_ubus_subscribe(void *const ctx, const char *object)
int PRIVATE amxb_ubus_register(void *const ctx, amxd_dm_t *const dm)
int PRIVATE amxb_ubus_parse_blob_table(amxc_var_t *var, struct blob_attr *attr, int len)
int PRIVATE amxb_ubus_async_invoke(void *const ctx, amxb_invoke_t *invoke_ctx, amxc_var_t *args, amxb_request_t *request)
void PRIVATE amxb_ubus_cancel_requests(amxb_ubus_t *amxb_ubus_ctx)
amxp_timer_t * reactivate
Definition: amxb_ubus.h:83
amxc_htable_it_t it
Definition: amxb_ubus.h:81
struct ubus_subscriber sub
Definition: amxb_ubus.h:82
struct ubus_event_handler wait_watcher
Definition: amxb_ubus.h:93
amxc_htable_t subscribers
Definition: amxb_ubus.h:88
amxc_llist_t pending_reqs
Definition: amxb_ubus.h:94
struct ubus_event_handler watcher
Definition: amxb_ubus.h:92
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
amxp_signal_mngr_t * sigmngr
Definition: amxb_ubus.h:90
static amxp_signal_mngr_t * sigmngr
static amxb_bus_ctx_t * bus_ctx