• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/lib/ubus.c

  1 /*
  2  * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 #include <unistd.h>
 18 #include <libubus.h>
 19 #include <libubox/blobmsg.h>
 20 
 21 #include "ucode/module.h"
 22 
 23 #define err_return(err, ...) do { set_error(err, __VA_ARGS__); return NULL; } while(0)
 24 
 25 static struct {
 26         enum ubus_msg_status code;
 27         char *msg;
 28 } last_error;
 29 
 30 __attribute__((format(printf, 2, 3))) static void
 31 set_error(int errcode, const char *fmt, ...)
 32 {
 33         va_list ap;
 34 
 35         free(last_error.msg);
 36 
 37         last_error.code = errcode;
 38         last_error.msg = NULL;
 39 
 40         if (fmt) {
 41                 va_start(ap, fmt);
 42                 xvasprintf(&last_error.msg, fmt, ap);
 43                 va_end(ap);
 44         }
 45 }
 46 
 47 static char *
 48 _arg_type(uc_type_t type)
 49 {
 50         switch (type) {
 51         case UC_INTEGER:   return "an integer value";
 52         case UC_BOOLEAN:   return "a boolean value";
 53         case UC_STRING:    return "a string value";
 54         case UC_DOUBLE:    return "a double value";
 55         case UC_ARRAY:     return "an array";
 56         case UC_OBJECT:    return "an object";
 57         case UC_REGEXP:    return "a regular expression";
 58         case UC_CLOSURE:   return "a function";
 59         default:           return "the expected type";
 60         }
 61 }
 62 
 63 static bool
 64 _args_get(uc_vm_t *vm, size_t nargs, ...)
 65 {
 66         uc_value_t **ptr, *arg;
 67         uc_type_t type, t;
 68         const char *name;
 69         size_t index = 0;
 70         va_list ap;
 71         bool opt;
 72 
 73         va_start(ap, nargs);
 74 
 75         while (true) {
 76                 name = va_arg(ap, const char *);
 77 
 78                 if (!name)
 79                         break;
 80 
 81                 arg = uc_fn_arg(index++);
 82 
 83                 type = va_arg(ap, uc_type_t);
 84                 opt = va_arg(ap, int);
 85                 ptr = va_arg(ap, uc_value_t **);
 86 
 87                 if (!opt && !arg)
 88                         err_return(UBUS_STATUS_INVALID_ARGUMENT, "Argument %s is required", name);
 89 
 90                 t = ucv_type(arg);
 91 
 92                 if (t == UC_CFUNCTION)
 93                         t = UC_CLOSURE;
 94 
 95                 if (arg && t != type)
 96                         err_return(UBUS_STATUS_INVALID_ARGUMENT, "Argument %s is not %s", name, _arg_type(type));
 97 
 98                 *ptr = arg;
 99         }
100 
101         va_end(ap);
102 
103         return true;
104 }
105 
106 #define args_get(vm, nargs, ...) do { if (!_args_get(vm, nargs, __VA_ARGS__, NULL)) return NULL; } while(0)
107 
108 static uc_resource_type_t *subscriber_type;
109 static uc_resource_type_t *listener_type;
110 static uc_resource_type_t *request_type;
111 static uc_resource_type_t *notify_type;
112 static uc_resource_type_t *object_type;
113 static uc_resource_type_t *defer_type;
114 static uc_resource_type_t *conn_type;
115 
116 static uint64_t n_cb_active;
117 static bool have_own_uloop;
118 
119 static struct blob_buf buf;
120 
121 typedef struct {
122         int timeout;
123         struct blob_buf buf;
124         struct ubus_context *ctx;
125 } uc_ubus_connection_t;
126 
127 typedef struct {
128         struct ubus_request request;
129         struct uloop_timeout timeout;
130         struct ubus_context *ctx;
131         size_t registry_index;
132         bool complete;
133         uc_vm_t *vm;
134         uc_value_t *callback;
135         uc_value_t *response;
136 } uc_ubus_deferred_t;
137 
138 typedef struct {
139         struct ubus_object obj;
140         struct ubus_context *ctx;
141         size_t registry_index;
142         uc_vm_t *vm;
143 } uc_ubus_object_t;
144 
145 typedef struct {
146         struct ubus_request_data req;
147         struct uloop_timeout timeout;
148         struct ubus_context *ctx;
149         size_t registry_index;
150         bool replied;
151         uc_vm_t *vm;
152 } uc_ubus_request_t;
153 
154 typedef struct {
155         struct ubus_notify_request req;
156         struct ubus_context *ctx;
157         size_t registry_index;
158         bool complete;
159         uc_vm_t *vm;
160 } uc_ubus_notify_t;
161 
162 typedef struct {
163         struct ubus_event_handler ev;
164         struct ubus_context *ctx;
165         size_t registry_index;
166         uc_vm_t *vm;
167 } uc_ubus_listener_t;
168 
169 typedef struct {
170         struct ubus_subscriber sub;
171         struct ubus_context *ctx;
172         size_t registry_index;
173         uc_vm_t *vm;
174 } uc_ubus_subscriber_t;
175 
176 static uc_value_t *
177 uc_ubus_error(uc_vm_t *vm, size_t nargs)
178 {
179         uc_value_t *numeric = uc_fn_arg(0), *rv;
180         uc_stringbuf_t *buf;
181         const char *s;
182 
183         if (last_error.code == 0)
184                 return NULL;
185 
186         if (ucv_is_truish(numeric)) {
187                 rv = ucv_int64_new(last_error.code);
188         }
189         else {
190                 buf = ucv_stringbuf_new();
191 
192                 if (last_error.code == UBUS_STATUS_UNKNOWN_ERROR && last_error.msg) {
193                         ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg));
194                 }
195                 else {
196                         s = ubus_strerror(last_error.code);
197 
198                         ucv_stringbuf_addstr(buf, s, strlen(s));
199 
200                         if (last_error.msg)
201                                 ucv_stringbuf_printf(buf, ": %s", last_error.msg);
202                 }
203 
204                 rv = ucv_stringbuf_finish(buf);
205         }
206 
207         set_error(0, NULL);
208 
209         return rv;
210 }
211 
212 static void
213 _uc_reg_get(uc_vm_t *vm, const char *key, size_t idx, size_t nptrs, ...)
214 {
215         uc_value_t *reg = uc_vm_registry_get(vm, key), **val;
216         va_list ap;
217         size_t i;
218 
219         va_start(ap, nptrs);
220 
221         for (i = 0; i < nptrs; i++) {
222                 val = va_arg(ap, uc_value_t **);
223 
224                 if (val)
225                         *val = ucv_array_get(reg, idx + i);
226         }
227 
228         va_end(ap);
229 }
230 
231 static size_t
232 _uc_reg_add(uc_vm_t *vm, const char *key, size_t nptrs, ...)
233 {
234         uc_value_t *reg = uc_vm_registry_get(vm, key);
235         size_t idx, i;
236         va_list ap;
237 
238         if (!reg) {
239                 reg = ucv_array_new(vm);
240                 uc_vm_registry_set(vm, key, reg);
241         }
242 
243         va_start(ap, nptrs);
244 
245         for (idx = 0;; idx += nptrs) {
246                 if (ucv_array_get(reg, idx) == NULL) {
247                         for (i = 0; i < nptrs; i++)
248                                 ucv_array_set(reg, idx + i, va_arg(ap, uc_value_t *));
249 
250                         break;
251                 }
252         }
253 
254         va_end(ap);
255 
256         return idx;
257 }
258 
259 static void
260 _uc_reg_clear(uc_vm_t *vm, const char *key, size_t idx, size_t nptrs)
261 {
262         uc_value_t *reg = uc_vm_registry_get(vm, key);
263 
264         while (nptrs > 0) {
265                 nptrs--;
266                 ucv_array_set(reg, idx + nptrs, NULL);
267         }
268 }
269 
270 
271 #define request_reg_add(vm, request, cb, conn) \
272         _uc_reg_add(vm, "ubus.requests", 3, request, cb, conn)
273 
274 #define request_reg_get(vm, idx, request, cb) \
275         _uc_reg_get(vm, "ubus.requests", idx, 2, request, cb)
276 
277 #define request_reg_clear(vm, idx) \
278         _uc_reg_clear(vm, "ubus.requests", idx, 3)
279 
280 
281 #define object_reg_add(vm, obj, msg, cb) \
282         _uc_reg_add(vm, "ubus.objects", 3, obj, msg, cb)
283 
284 #define object_reg_get(vm, idx, obj, msg, cb) \
285         _uc_reg_get(vm, "ubus.objects", idx, 3, obj, msg, cb)
286 
287 #define object_reg_clear(vm, idx) \
288         _uc_reg_clear(vm, "ubus.objects", idx, 3)
289 
290 
291 #define notify_reg_add(vm, notify, dcb, scb, ccb) \
292         _uc_reg_add(vm, "ubus.notifications", 4, notify, dcb, scb, ccb)
293 
294 #define notify_reg_get(vm, idx, notify, dcb, scb, ccb) \
295         _uc_reg_get(vm, "ubus.notifications", idx, 4, notify, dcb, scb, ccb)
296 
297 #define notify_reg_clear(vm, idx) \
298         _uc_reg_clear(vm, "ubus.notifications", idx, 4)
299 
300 
301 #define listener_reg_add(vm, listener, cb) \
302         _uc_reg_add(vm, "ubus.listeners", 2, listener, cb)
303 
304 #define listener_reg_get(vm, idx, listener, cb) \
305         _uc_reg_get(vm, "ubus.listeners", idx, 2, listener, cb)
306 
307 #define listener_reg_clear(vm, idx) \
308         _uc_reg_clear(vm, "ubus.listeners", idx, 2)
309 
310 
311 #define subscriber_reg_add(vm, subscriber, ncb, rcb) \
312         _uc_reg_add(vm, "ubus.subscribers", 3, subscriber, ncb, rcb)
313 
314 #define subscriber_reg_get(vm, idx, subscriber, ncb, rcb) \
315         _uc_reg_get(vm, "ubus.subscribers", idx, 3, subscriber, ncb, rcb)
316 
317 #define subscriber_reg_clear(vm, idx) \
318         _uc_reg_clear(vm, "ubus.subscribers", idx, 3)
319 
320 
321 static uc_value_t *
322 blob_to_ucv(uc_vm_t *vm, struct blob_attr *attr, bool table, const char **name);
323 
324 static uc_value_t *
325 blob_array_to_ucv(uc_vm_t *vm, struct blob_attr *attr, size_t len, bool table)
326 {
327         uc_value_t *o = table ? ucv_object_new(vm) : ucv_array_new(vm);
328         uc_value_t *v;
329         struct blob_attr *pos;
330         size_t rem = len;
331         const char *name;
332 
333         if (!o)
334                 return NULL;
335 
336         __blob_for_each_attr(pos, attr, rem) {
337                 name = NULL;
338                 v = blob_to_ucv(vm, pos, table, &name);
339 
340                 if (table && name)
341                         ucv_object_add(o, name, v);
342                 else if (!table)
343                         ucv_array_push(o, v);
344                 else
345                         ucv_put(v);
346         }
347 
348         return o;
349 }
350 
351 static uc_value_t *
352 blob_to_ucv(uc_vm_t *vm, struct blob_attr *attr, bool table, const char **name)
353 {
354         void *data;
355         int len;
356 
357         if (!blobmsg_check_attr(attr, false))
358                 return NULL;
359 
360         if (table && blobmsg_name(attr)[0])
361                 *name = blobmsg_name(attr);
362 
363         data = blobmsg_data(attr);
364         len = blobmsg_data_len(attr);
365 
366         switch (blob_id(attr)) {
367         case BLOBMSG_TYPE_BOOL:
368                 return ucv_boolean_new(*(uint8_t *)data);
369 
370         case BLOBMSG_TYPE_INT16:
371                 return ucv_int64_new((int16_t)be16_to_cpu(*(uint16_t *)data));
372 
373         case BLOBMSG_TYPE_INT32:
374                 return ucv_int64_new((int32_t)be32_to_cpu(*(uint32_t *)data));
375 
376         case BLOBMSG_TYPE_INT64:
377                 return ucv_int64_new((int64_t)be64_to_cpu(*(uint64_t *)data));
378 
379         case BLOBMSG_TYPE_DOUBLE:
380                 ;
381                 union {
382                         double d;
383                         uint64_t u64;
384                 } v;
385 
386                 v.u64 = be64_to_cpu(*(uint64_t *)data);
387 
388                 return ucv_double_new(v.d);
389 
390         case BLOBMSG_TYPE_STRING:
391                 return ucv_string_new(data);
392 
393         case BLOBMSG_TYPE_ARRAY:
394                 return blob_array_to_ucv(vm, data, len, false);
395 
396         case BLOBMSG_TYPE_TABLE:
397                 return blob_array_to_ucv(vm, data, len, true);
398 
399         default:
400                 return NULL;
401         }
402 }
403 
404 static void
405 ucv_array_to_blob(uc_value_t *val, struct blob_buf *blob);
406 
407 static void
408 ucv_object_to_blob(uc_value_t *val, struct blob_buf *blob);
409 
410 static void
411 ucv_to_blob(const char *name, uc_value_t *val, struct blob_buf *blob)
412 {
413         int64_t n;
414         void *c;
415 
416         switch (ucv_type(val)) {
417         case UC_NULL:
418                 blobmsg_add_field(blob, BLOBMSG_TYPE_UNSPEC, name, NULL, 0);
419                 break;
420 
421         case UC_BOOLEAN:
422                 blobmsg_add_u8(blob, name, ucv_boolean_get(val));
423                 break;
424 
425         case UC_INTEGER:
426                 n = ucv_int64_get(val);
427 
428                 if (errno == ERANGE)
429                         blobmsg_add_u64(blob, name, ucv_uint64_get(val));
430                 else if (n >= INT32_MIN && n <= INT32_MAX)
431                         blobmsg_add_u32(blob, name, n);
432                 else
433                         blobmsg_add_u64(blob, name, n);
434 
435                 break;
436 
437         case UC_DOUBLE:
438                 blobmsg_add_double(blob, name, ucv_double_get(val));
439                 break;
440 
441         case UC_STRING:
442                 blobmsg_add_string(blob, name, ucv_string_get(val));
443                 break;
444 
445         case UC_ARRAY:
446                 c = blobmsg_open_array(blob, name);
447                 ucv_array_to_blob(val, blob);
448                 blobmsg_close_array(blob, c);
449                 break;
450 
451         case UC_OBJECT:
452                 c = blobmsg_open_table(blob, name);
453                 ucv_object_to_blob(val, blob);
454                 blobmsg_close_table(blob, c);
455                 break;
456 
457         default:
458                 break;
459         }
460 }
461 
462 static void
463 ucv_array_to_blob(uc_value_t *val, struct blob_buf *blob)
464 {
465         size_t i;
466 
467         for (i = 0; i < ucv_array_length(val); i++)
468                 ucv_to_blob(NULL, ucv_array_get(val, i), blob);
469 }
470 
471 static void
472 ucv_object_to_blob(uc_value_t *val, struct blob_buf *blob)
473 {
474         ucv_object_foreach(val, k, v)
475                 ucv_to_blob(k, v, blob);
476 }
477 
478 
479 static uc_value_t *
480 uc_ubus_connect(uc_vm_t *vm, size_t nargs)
481 {
482         uc_value_t *socket, *timeout;
483         uc_ubus_connection_t *c;
484 
485         args_get(vm, nargs,
486                  "socket", UC_STRING, true, &socket,
487                  "timeout", UC_INTEGER, true, &timeout);
488 
489         c = xalloc(sizeof(*c));
490         c->ctx = ubus_connect(socket ? ucv_string_get(socket) : NULL);
491         c->timeout = timeout ? ucv_int64_get(timeout) : 30;
492 
493         if (!c->ctx) {
494                 free(c);
495                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to connect to ubus socket");
496         }
497 
498         if (c->timeout < 0)
499                 c->timeout = 30;
500 
501         ubus_add_uloop(c->ctx);
502 
503         return uc_resource_new(conn_type, c);
504 }
505 
506 static void
507 uc_ubus_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
508 {
509         uc_value_t *arr = p;
510         uc_value_t *sig;
511 
512         if (!o->signature)
513                 return;
514 
515         sig = blob_array_to_ucv(NULL, blob_data(o->signature), blob_len(o->signature), true);
516 
517         if (sig)
518                 ucv_array_push(arr, sig);
519 }
520 
521 static void
522 uc_ubus_objects_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
523 {
524         uc_value_t *arr = p;
525 
526         ucv_array_push(arr, ucv_string_new(o->path));
527 }
528 
529 static uc_value_t *
530 uc_ubus_list(uc_vm_t *vm, size_t nargs)
531 {
532         uc_ubus_connection_t **c = uc_fn_this("ubus.connection");
533         uc_value_t *objname, *res = NULL;
534         enum ubus_msg_status rv;
535 
536         if (!c || !*c || !(*c)->ctx)
537                 err_return(UBUS_STATUS_CONNECTION_FAILED, NULL);
538 
539         args_get(vm, nargs,
540                  "object name", UC_STRING, true, &objname);
541 
542         res = ucv_array_new(vm);
543 
544         rv = ubus_lookup((*c)->ctx,
545                          objname ? ucv_string_get(objname) : NULL,
546                          objname ? uc_ubus_signatures_cb : uc_ubus_objects_cb,
547                          res);
548 
549         if (rv != UBUS_STATUS_OK) {
550                 ucv_put(res);
551                 err_return(rv, NULL);
552         }
553 
554         return res;
555 }
556 
557 static void
558 uc_ubus_call_cb(struct ubus_request *req, int type, struct blob_attr *msg)
559 {
560         uc_value_t **res = (uc_value_t **)req->priv;
561 
562         *res = msg ? blob_array_to_ucv(NULL, blob_data(msg), blob_len(msg), true) : NULL;
563 }
564 
565 static void
566 uc_ubus_call_user_cb(uc_ubus_deferred_t *defer, int ret, uc_value_t *reply)
567 {
568         uc_value_t *this, *func;
569 
570         request_reg_get(defer->vm, defer->registry_index, &this, &func);
571 
572         if (ucv_is_callable(func)) {
573                 uc_vm_stack_push(defer->vm, ucv_get(this));
574                 uc_vm_stack_push(defer->vm, ucv_get(func));
575                 uc_vm_stack_push(defer->vm, ucv_int64_new(ret));
576                 uc_vm_stack_push(defer->vm, ucv_get(reply));
577 
578                 if (uc_vm_call(defer->vm, true, 2) == EXCEPTION_NONE)
579                         ucv_put(uc_vm_stack_pop(defer->vm));
580         }
581 
582         request_reg_clear(defer->vm, defer->registry_index);
583 
584         n_cb_active--;
585 
586         if (have_own_uloop && n_cb_active == 0)
587                 uloop_end();
588 }
589 
590 static void
591 uc_ubus_call_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
592 {
593         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
594 
595         if (defer->response == NULL)
596                 defer->response = blob_array_to_ucv(defer->vm, blob_data(msg), blob_len(msg), true);
597 }
598 
599 static void
600 uc_ubus_call_done_cb(struct ubus_request *req, int ret)
601 {
602         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
603 
604         if (defer->complete)
605                 return;
606 
607         defer->complete = true;
608         uloop_timeout_cancel(&defer->timeout);
609 
610         uc_ubus_call_user_cb(defer, ret, defer->response);
611 }
612 
613 static void
614 uc_ubus_call_timeout_cb(struct uloop_timeout *timeout)
615 {
616         uc_ubus_deferred_t *defer = container_of(timeout, uc_ubus_deferred_t, timeout);
617 
618         if (defer->complete)
619                 return;
620 
621         defer->complete = true;
622         ubus_abort_request(defer->ctx, &defer->request);
623 
624         uc_ubus_call_user_cb(defer, UBUS_STATUS_TIMEOUT, NULL);
625 }
626 
627 static bool
628 uc_ubus_have_uloop(void)
629 {
630         bool prev = uloop_cancelled;
631         bool active;
632 
633         uloop_cancelled = true;
634         active = uloop_cancelling();
635         uloop_cancelled = prev;
636 
637         return active;
638 }
639 
640 static bool
641 _conn_get(uc_vm_t *vm, uc_ubus_connection_t ***conn)
642 {
643         *conn = uc_fn_this("ubus.connection");
644 
645         if (!*conn || !**conn)
646                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid connection context");
647 
648         if (!(**conn)->ctx)
649                 err_return(UBUS_STATUS_CONNECTION_FAILED, "Connection is closed");
650 
651         return true;
652 }
653 
654 #define conn_get(vm, ptr) do { if (!_conn_get(vm, ptr)) return NULL; } while(0)
655 
656 static uc_value_t *
657 uc_ubus_call(uc_vm_t *vm, size_t nargs)
658 {
659         uc_value_t *objname, *funname, *funargs, *res = NULL;
660         uc_ubus_connection_t **c;
661         enum ubus_msg_status rv;
662         uint32_t id;
663 
664         conn_get(vm, &c);
665 
666         args_get(vm, nargs,
667                  "object name", UC_STRING, false, &objname,
668                  "function name", UC_STRING, false, &funname,
669                  "function arguments", UC_OBJECT, true, &funargs);
670 
671         blob_buf_init(&(*c)->buf, 0);
672 
673         if (funargs)
674                 ucv_object_to_blob(funargs, &(*c)->buf);
675 
676         rv = ubus_lookup_id((*c)->ctx, ucv_string_get(objname), &id);
677 
678         if (rv != UBUS_STATUS_OK)
679                 err_return(rv, "Failed to resolve object name '%s'",
680                            ucv_string_get(objname));
681 
682         rv = ubus_invoke((*c)->ctx, id, ucv_string_get(funname), (*c)->buf.head,
683                          uc_ubus_call_cb, &res, (*c)->timeout * 1000);
684 
685         if (rv != UBUS_STATUS_OK)
686                 err_return(rv, "Failed to invoke function '%s' on object '%s'",
687                            ucv_string_get(funname), ucv_string_get(objname));
688 
689         return res;
690 }
691 
692 static uc_value_t *
693 uc_ubus_defer(uc_vm_t *vm, size_t nargs)
694 {
695         uc_value_t *objname, *funname, *funargs, *replycb, *conn, *res = NULL;
696         uc_ubus_deferred_t *defer;
697         uc_ubus_connection_t **c;
698         enum ubus_msg_status rv;
699         uint32_t id;
700 
701         conn_get(vm, &c);
702 
703         args_get(vm, nargs,
704                  "object name", UC_STRING, false, &objname,
705                  "function name", UC_STRING, false, &funname,
706                  "function arguments", UC_OBJECT, true, &funargs,
707                  "reply callback", UC_CLOSURE, true, &replycb);
708 
709         blob_buf_init(&(*c)->buf, 0);
710 
711         if (funargs)
712                 ucv_object_to_blob(funargs, &(*c)->buf);
713 
714         rv = ubus_lookup_id((*c)->ctx, ucv_string_get(objname), &id);
715 
716         if (rv != UBUS_STATUS_OK)
717                 err_return(rv, "Failed to resolve object name '%s'",
718                            ucv_string_get(objname));
719 
720         defer = xalloc(sizeof(*defer));
721 
722         rv = ubus_invoke_async((*c)->ctx, id, ucv_string_get(funname),
723                                (*c)->buf.head, &defer->request);
724 
725         if (rv == UBUS_STATUS_OK) {
726                 defer->vm = vm;
727                 defer->ctx = (*c)->ctx;
728 
729                 defer->request.data_cb = uc_ubus_call_data_cb;
730                 defer->request.complete_cb = uc_ubus_call_done_cb;
731                 ubus_complete_request_async((*c)->ctx, &defer->request);
732 
733                 defer->timeout.cb = uc_ubus_call_timeout_cb;
734                 uloop_timeout_set(&defer->timeout, (*c)->timeout * 1000);
735 
736                 res = uc_resource_new(defer_type, defer);
737                 conn = uc_vector_last(&vm->callframes)->ctx;
738 
739                 defer->registry_index = request_reg_add(vm, ucv_get(res), ucv_get(replycb), ucv_get(conn));
740 
741                 if (!uc_ubus_have_uloop()) {
742                         have_own_uloop = true;
743                         uloop_run();
744                 }
745         }
746         else {
747                 uc_vm_stack_push(vm, ucv_get(replycb));
748                 uc_vm_stack_push(vm, ucv_int64_new(rv));
749 
750                 if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE)
751                         ucv_put(uc_vm_stack_pop(vm));
752                 else
753                         uloop_end();
754 
755                 free(defer);
756         }
757 
758         if (rv != UBUS_STATUS_OK)
759                 err_return(rv, "Failed to invoke function '%s' on object '%s'",
760                            ucv_string_get(funname), ucv_string_get(objname));
761 
762         return res;
763 }
764 
765 
766 /*
767  * ubus object request context functions
768  * --------------------------------------------------------------------------
769  */
770 
771 static void
772 uc_ubus_request_finish(uc_ubus_request_t *callctx, int code, uc_value_t *reply)
773 {
774         if (callctx->replied)
775                 return;
776 
777         if (reply) {
778                 blob_buf_init(&buf, 0);
779                 ucv_object_to_blob(reply, &buf);
780                 ubus_send_reply(callctx->ctx, &callctx->req, buf.head);
781         }
782 
783         callctx->replied = true;
784 
785         ubus_complete_deferred_request(callctx->ctx, &callctx->req, code);
786         request_reg_clear(callctx->vm, callctx->registry_index);
787 }
788 
789 static void
790 uc_ubus_request_timeout(struct uloop_timeout *timeout)
791 {
792         uc_ubus_request_t *callctx = container_of(timeout, uc_ubus_request_t, timeout);
793 
794         uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT, NULL);
795 }
796 
797 static uc_value_t *
798 uc_ubus_request_reply(uc_vm_t *vm, size_t nargs)
799 {
800         uc_ubus_request_t **callctx = uc_fn_this("ubus.request");
801         int64_t code = UBUS_STATUS_OK;
802         uc_value_t *reply, *rcode;
803 
804         if (!callctx || !*callctx)
805                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
806 
807         args_get(vm, nargs,
808                  "reply", UC_OBJECT, true, &reply,
809                  "rcode", UC_INTEGER, true, &rcode);
810 
811         if ((*callctx)->replied)
812                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
813 
814         if (rcode) {
815                 code = ucv_int64_get(rcode);
816 
817                 if (errno == ERANGE || code < 0 || code > __UBUS_STATUS_LAST)
818                         code = UBUS_STATUS_UNKNOWN_ERROR;
819         }
820 
821         uc_ubus_request_finish(*callctx, code, reply);
822 
823         return ucv_boolean_new(true);
824 }
825 
826 static uc_value_t *
827 uc_ubus_request_error(uc_vm_t *vm, size_t nargs)
828 {
829         uc_ubus_request_t **callctx = uc_fn_this("ubus.request");
830         uc_value_t *rcode = uc_fn_arg(0);
831         int64_t code;
832 
833         if (!callctx || !*callctx)
834                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
835 
836         args_get(vm, nargs,
837                  "rcode", UC_INTEGER, false, &rcode);
838 
839         if ((*callctx)->replied)
840                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
841 
842         code = ucv_int64_get(rcode);
843 
844         if (errno == ERANGE || code < 0 || code > __UBUS_STATUS_LAST)
845                 code = UBUS_STATUS_UNKNOWN_ERROR;
846 
847         uc_ubus_request_finish(*callctx, code, NULL);
848 
849         return ucv_boolean_new(true);
850 }
851 
852 
853 /*
854  * ubus object notify
855  * --------------------------------------------------------------------------
856  */
857 
858 static uc_value_t *
859 uc_ubus_notify_completed(uc_vm_t *vm, size_t nargs)
860 {
861         uc_ubus_notify_t **notifyctx = uc_fn_this("ubus.notify");
862 
863         if (!notifyctx || !*notifyctx)
864                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid notify context");
865 
866         return ucv_boolean_new((*notifyctx)->complete);
867 }
868 
869 static uc_value_t *
870 uc_ubus_notify_abort(uc_vm_t *vm, size_t nargs)
871 {
872         uc_ubus_notify_t **notifyctx = uc_fn_this("ubus.notify");
873 
874         if (!notifyctx || !*notifyctx)
875                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid notify context");
876 
877         if ((*notifyctx)->complete)
878                 return ucv_boolean_new(false);
879 
880         ubus_abort_request((*notifyctx)->ctx, &(*notifyctx)->req.req);
881         (*notifyctx)->complete = true;
882 
883         return ucv_boolean_new(true);
884 }
885 
886 static void
887 uc_ubus_object_notify_data_cb(struct ubus_notify_request *req, int type, struct blob_attr *msg)
888 {
889         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
890         uc_value_t *this, *func;
891 
892         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, &func, NULL, NULL);
893 
894         if (ucv_is_callable(func)) {
895                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
896                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
897                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(type));
898                 uc_vm_stack_push(notifyctx->vm, blob_array_to_ucv(notifyctx->vm, blob_data(msg), blob_len(msg), true));
899 
900                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
901                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
902                 else
903                         uloop_end();
904         }
905 }
906 
907 static void
908 uc_ubus_object_notify_status_cb(struct ubus_notify_request *req, int idx, int ret)
909 {
910         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
911         uc_value_t *this, *func;
912 
913         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, NULL, &func, NULL);
914 
915         if (ucv_is_callable(func)) {
916                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
917                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
918                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(idx));
919                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(ret));
920 
921                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
922                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
923                 else
924                         uloop_end();
925         }
926 }
927 
928 static void
929 uc_ubus_object_notify_complete_cb(struct ubus_notify_request *req, int idx, int ret)
930 {
931         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
932         uc_value_t *this, *func;
933 
934         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, NULL, NULL, &func);
935 
936         if (ucv_is_callable(func)) {
937                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
938                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
939                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(idx));
940                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(ret));
941 
942                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
943                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
944                 else
945                         uloop_end();
946         }
947 
948         notifyctx->complete = true;
949 
950         notify_reg_clear(notifyctx->vm, notifyctx->registry_index);
951 }
952 
953 static uc_value_t *
954 uc_ubus_object_notify(uc_vm_t *vm, size_t nargs)
955 {
956         uc_value_t *typename, *message, *data_cb, *status_cb, *complete_cb, *timeout;
957         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
958         uc_ubus_notify_t *notifyctx;
959         uc_value_t *res;
960         int64_t t;
961         int rv;
962 
963         if (!uuobj || !*uuobj)
964                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
965 
966         args_get(vm, nargs,
967                  "typename", UC_STRING, false, &typename,
968                  "message", UC_OBJECT, true, &message,
969                  "data callback", UC_CLOSURE, true, &data_cb,
970                  "status callback", UC_CLOSURE, true, &status_cb,
971                  "completion callback", UC_CLOSURE, true, &complete_cb,
972                  "timeout", UC_INTEGER, true, &timeout);
973 
974         t = timeout ? ucv_int64_get(timeout) : -1;
975 
976         if (errno)
977                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
978                            "Invalid timeout value: %s", strerror(errno));
979 
980         notifyctx = xalloc(sizeof(*notifyctx));
981         notifyctx->vm = vm;
982         notifyctx->ctx = (*uuobj)->ctx;
983 
984         blob_buf_init(&buf, 0);
985 
986         if (message)
987                 ucv_object_to_blob(message, &buf);
988 
989         rv = ubus_notify_async((*uuobj)->ctx, &(*uuobj)->obj,
990                                ucv_string_get(typename), buf.head,
991                                &notifyctx->req);
992 
993         if (rv != UBUS_STATUS_OK) {
994                 free(notifyctx);
995                 err_return(rv, "Failed to send notification");
996         }
997 
998         notifyctx->req.data_cb = uc_ubus_object_notify_data_cb;
999         notifyctx->req.status_cb = uc_ubus_object_notify_status_cb;
1000         notifyctx->req.complete_cb = uc_ubus_object_notify_complete_cb;
1001 
1002         res = uc_resource_new(notify_type, notifyctx);
1003 
1004         notifyctx->registry_index = notify_reg_add(vm,
1005                 ucv_get(res), ucv_get(data_cb), ucv_get(status_cb), ucv_get(complete_cb));
1006 
1007         if (t >= 0) {
1008                 rv = ubus_complete_request((*uuobj)->ctx, &notifyctx->req.req, t);
1009 
1010                 notify_reg_clear(vm, notifyctx->registry_index);
1011 
1012                 ucv_put(res);
1013 
1014                 return ucv_int64_new(rv);
1015         }
1016 
1017         ubus_complete_request_async((*uuobj)->ctx, &notifyctx->req.req);
1018 
1019         return res;
1020 }
1021 
1022 
1023 /*
1024  * ubus object remove
1025  * --------------------------------------------------------------------------
1026  */
1027 
1028 static int
1029 uc_ubus_object_remove_common(uc_ubus_object_t *uuobj)
1030 {
1031         int rv = ubus_remove_object(uuobj->ctx, &uuobj->obj);
1032 
1033         if (rv == UBUS_STATUS_OK)
1034                 object_reg_clear(uuobj->vm, uuobj->registry_index);
1035 
1036         return rv;
1037 }
1038 
1039 static uc_value_t *
1040 uc_ubus_object_remove(uc_vm_t *vm, size_t nargs)
1041 {
1042         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1043         int rv;
1044 
1045         if (!uuobj || !*uuobj)
1046                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1047 
1048         rv = uc_ubus_object_remove_common(*uuobj);
1049 
1050         if (rv != UBUS_STATUS_OK)
1051                 err_return(rv, "Failed to remove object");
1052 
1053         return ucv_boolean_new(true);
1054 }
1055 
1056 
1057 /*
1058  * ubus object subscription status
1059  */
1060 
1061 static uc_value_t *
1062 uc_ubus_object_subscribed(uc_vm_t *vm, size_t nargs)
1063 {
1064         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1065 
1066         if (!uuobj || !*uuobj)
1067                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1068 
1069         return ucv_boolean_new((*uuobj)->obj.has_subscribers);
1070 }
1071 
1072 
1073 /*
1074  * ubus object method call handling
1075  * --------------------------------------------------------------------------
1076  */
1077 
1078 static int
1079 uc_ubus_object_call_args(struct ubus_object *obj, const char *ubus_method_name,
1080                          struct blob_attr *msg, uc_value_t **res)
1081 {
1082         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1083         const struct ubus_method *method = NULL;
1084         const struct blobmsg_hdr *hdr;
1085         struct blob_attr *attr;
1086         size_t len;
1087         bool found;
1088         int i;
1089 
1090         for (i = 0; i < obj->n_methods; i++) {
1091                 if (!strcmp(obj->methods[i].name, ubus_method_name)) {
1092                         method = &obj->methods[i];
1093                         break;
1094                 }
1095         }
1096 
1097         if (!method)
1098                 return UBUS_STATUS_METHOD_NOT_FOUND;
1099 
1100         len = blob_len(msg);
1101 
1102         __blob_for_each_attr(attr, blob_data(msg), len) {
1103                 if (!blobmsg_check_attr_len(attr, false, len))
1104                         return UBUS_STATUS_INVALID_ARGUMENT;
1105 
1106                 if (!blob_is_extended(attr))
1107                         return UBUS_STATUS_INVALID_ARGUMENT;
1108 
1109                 hdr = blob_data(attr);
1110                 found = false;
1111 
1112                 for (i = 0; i < method->n_policy; i++) {
1113                         if (blobmsg_namelen(hdr) != strlen(method->policy[i].name))
1114                                 continue;
1115 
1116                         if (strcmp(method->policy[i].name, (char *)hdr->name))
1117                                 continue;
1118 
1119                         /* named argument found but wrong type */
1120                         if (blob_id(attr) != method->policy[i].type)
1121                                 goto inval;
1122 
1123                         found = true;
1124                         break;
1125                 }
1126 
1127                 /* named argument not found in policy */
1128                 if (!found)
1129                         goto inval;
1130         }
1131 
1132         *res = blob_array_to_ucv(uuobj->vm, blob_data(msg), blob_len(msg), true);
1133 
1134         return UBUS_STATUS_OK;
1135 
1136 inval:
1137         *res = NULL;
1138 
1139         return UBUS_STATUS_INVALID_ARGUMENT;
1140 }
1141 
1142 static uc_value_t *
1143 uc_ubus_object_call_info(uc_vm_t *vm,
1144                          struct ubus_context *ctx, struct ubus_request_data *req,
1145                          struct ubus_object *obj, const char *ubus_method_name)
1146 {
1147         uc_value_t *info, *o;
1148 
1149         info = ucv_object_new(vm);
1150 
1151         o = ucv_object_new(vm);
1152 
1153         ucv_object_add(o, "user", ucv_string_new(req->acl.user));
1154         ucv_object_add(o, "group", ucv_string_new(req->acl.group));
1155 
1156         if (req->acl.object)
1157                 ucv_object_add(o, "object", ucv_string_new(req->acl.object));
1158 
1159         ucv_object_add(info, "acl", o);
1160 
1161         o = ucv_object_new(vm);
1162 
1163         ucv_object_add(o, "id", ucv_int64_new(obj->id));
1164 
1165         if (obj->name)
1166                 ucv_object_add(o, "name", ucv_string_new(obj->name));
1167 
1168         if (obj->path)
1169                 ucv_object_add(o, "path", ucv_string_new(obj->path));
1170 
1171         ucv_object_add(info, "object", o);
1172 
1173         if (ubus_method_name)
1174                 ucv_object_add(info, "method", ucv_string_new(ubus_method_name));
1175 
1176         return info;
1177 }
1178 
1179 static int
1180 uc_ubus_handle_reply_common(struct ubus_context *ctx,
1181                               struct ubus_request_data *req,
1182                               uc_vm_t *vm, uc_value_t *this, uc_value_t *func,
1183                               uc_value_t *reqproto)
1184 {
1185         uc_ubus_request_t *callctx;
1186         uc_value_t *reqobj, *res;
1187         int rv;
1188 
1189         /* allocate deferred method call context */
1190         callctx = xalloc(sizeof(*callctx));
1191         callctx->ctx = ctx;
1192         callctx->vm = vm;
1193 
1194         ubus_defer_request(ctx, req, &callctx->req);
1195 
1196         /* create ucode request type object and set properties */
1197         reqobj = uc_resource_new(request_type, callctx);
1198 
1199         if (reqproto)
1200                 ucv_prototype_set(ucv_prototype_get(reqobj), reqproto);
1201 
1202         /* push object context, handler and request object onto stack */
1203         uc_vm_stack_push(vm, ucv_get(this));
1204         uc_vm_stack_push(vm, ucv_get(func));
1205         uc_vm_stack_push(vm, ucv_get(reqobj));
1206 
1207         /* execute request handler function */
1208         switch (uc_vm_call(vm, true, 1)) {
1209         case EXCEPTION_NONE:
1210                 res = uc_vm_stack_pop(vm);
1211 
1212                 /* The handler function invoked a nested aync ubus request and returned it */
1213                 if (ucv_resource_dataptr(res, "ubus.deferred")) {
1214                         /* Install guard timer in case the reply callback is never called */
1215                         callctx->timeout.cb = uc_ubus_request_timeout;
1216                         uloop_timeout_set(&callctx->timeout, 10000 /* FIXME */);
1217 
1218                         /* Add wrapped request context into registry to prevent GC'ing
1219                          * until reply or timeout occurred */
1220                         callctx->registry_index = request_reg_add(vm, ucv_get(reqobj), NULL, NULL);
1221                 }
1222 
1223                 /* Otherwise, when the function returned an object, treat it as
1224                 * reply data and conclude deferred request immediately */
1225                 else if (ucv_type(res) == UC_OBJECT) {
1226                         blob_buf_init(&buf, 0);
1227                         ucv_object_to_blob(res, &buf);
1228                         ubus_send_reply(ctx, &callctx->req, buf.head);
1229 
1230                         ubus_complete_deferred_request(ctx, &callctx->req, UBUS_STATUS_OK);
1231                         callctx->replied = true;
1232                 }
1233 
1234                 /* If neither a deferred ubus request, nor a plain object were
1235                  * returned and if reqobj.reply() hasn't been called, immediately
1236                  * finish deferred request with UBUS_STATUS_NO_DATA. */
1237                 else if (!callctx->replied) {
1238                         rv = UBUS_STATUS_NO_DATA;
1239 
1240                         if (ucv_type(res) == UC_INTEGER) {
1241                                 rv = (int)ucv_int64_get(res);
1242 
1243                                 if (rv < 0 || rv > __UBUS_STATUS_LAST)
1244                                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1245                         }
1246 
1247                         ubus_complete_deferred_request(ctx, &callctx->req, rv);
1248                         callctx->replied = true;
1249                 }
1250 
1251                 ucv_put(res);
1252                 break;
1253 
1254         /* if the handler function invoked exit(), forward exit status as ubus
1255          * return code, map out of range values to UBUS_STATUS_UNKNOWN_ERROR. */
1256         case EXCEPTION_EXIT:
1257                 rv = vm->arg.s32;
1258 
1259                 if (rv < UBUS_STATUS_OK || rv >= __UBUS_STATUS_LAST)
1260                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1261 
1262                 ubus_complete_deferred_request(ctx, &callctx->req, rv);
1263                 callctx->replied = true;
1264                 break;
1265 
1266         /* treat other exceptions as fatal and halt uloop */
1267         default:
1268                 ubus_complete_deferred_request(ctx, &callctx->req, UBUS_STATUS_UNKNOWN_ERROR);
1269                 uloop_end();
1270                 callctx->replied = true;
1271                 break;
1272         }
1273 
1274         /* release request object */
1275         ucv_put(reqobj);
1276 
1277         /* garbage collect */
1278         ucv_gc(vm);
1279 
1280         return UBUS_STATUS_OK;
1281 }
1282 
1283 static int
1284 uc_ubus_object_call_cb(struct ubus_context *ctx, struct ubus_object *obj,
1285                        struct ubus_request_data *req, const char *ubus_method_name,
1286                        struct blob_attr *msg)
1287 {
1288         uc_value_t *this, *func, *args = NULL, *reqproto, *methods;
1289         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1290         int rv;
1291 
1292         object_reg_get(uuobj->vm, uuobj->registry_index, &this, &methods, NULL);
1293 
1294         func = ucv_object_get(ucv_object_get(methods, ubus_method_name, NULL), "call", NULL);
1295 
1296         if (!ucv_is_callable(func))
1297                 return UBUS_STATUS_METHOD_NOT_FOUND;
1298 
1299         rv = uc_ubus_object_call_args(obj, ubus_method_name, msg, &args);
1300 
1301         if (rv != UBUS_STATUS_OK)
1302                 return rv;
1303 
1304         reqproto = ucv_object_new(uuobj->vm);
1305 
1306         ucv_object_add(reqproto, "args", args);
1307         ucv_object_add(reqproto, "info",
1308                 uc_ubus_object_call_info(uuobj->vm, ctx, req, obj, ubus_method_name));
1309 
1310         return uc_ubus_handle_reply_common(ctx, req, uuobj->vm, this, func, reqproto);
1311 }
1312 
1313 
1314 /*
1315  * ubus object registration
1316  * --------------------------------------------------------------------------
1317  */
1318 
1319 static void
1320 uc_ubus_object_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
1321 {
1322         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1323         uc_value_t *this, *func;
1324 
1325         object_reg_get(uuobj->vm, uuobj->registry_index, &this, NULL, &func);
1326 
1327         uc_vm_stack_push(uuobj->vm, ucv_get(this));
1328         uc_vm_stack_push(uuobj->vm, ucv_get(func));
1329 
1330         if (uc_vm_call(uuobj->vm, true, 0) == EXCEPTION_NONE)
1331                 ucv_put(uc_vm_stack_pop(uuobj->vm));
1332         else
1333                 uloop_end();
1334 }
1335 
1336 static bool
1337 uc_ubus_object_methods_validate(uc_value_t *methods)
1338 {
1339         uc_value_t *func, *args;
1340 
1341         ucv_object_foreach(methods, ubus_method_name, ubus_method_definition) {
1342                 (void)ubus_method_name;
1343 
1344                 func = ucv_object_get(ubus_method_definition, "call", NULL);
1345                 args = ucv_object_get(ubus_method_definition, "args", NULL);
1346 
1347                 if (!ucv_is_callable(func))
1348                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1349                                    "Method '%s' field 'call' is not a function value",
1350                                    ubus_method_name);
1351 
1352                 if (args) {
1353                         if (ucv_type(args) != UC_OBJECT)
1354                                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
1355                                            "Method '%s' field 'args' is not an object value",
1356                                            ubus_method_name);
1357 
1358                         ucv_object_foreach(args, ubus_argument_name, ubus_argument_typehint) {
1359                                 (void)ubus_argument_name;
1360 
1361                                 switch (ucv_type(ubus_argument_typehint)) {
1362                                 case UC_BOOLEAN:
1363                                 case UC_INTEGER:
1364                                 case UC_DOUBLE:
1365                                 case UC_STRING:
1366                                 case UC_ARRAY:
1367                                 case UC_OBJECT:
1368                                         continue;
1369 
1370                                 default:
1371                                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1372                                                    "Method '%s' field 'args' argument '%s' hint has unsupported type %s",
1373                                                    ubus_method_name, ubus_argument_name,
1374                                                    ucv_typename(ubus_argument_typehint));
1375                                 }
1376                         }
1377                 }
1378         }
1379 
1380         return true;
1381 }
1382 
1383 static bool
1384 uc_ubus_object_method_register(struct ubus_method *method, const char *ubus_method_name,
1385                                uc_value_t *ubus_method_arguments)
1386 {
1387         struct blobmsg_policy *policy;
1388         enum blobmsg_type type;
1389 
1390         method->name = strdup(ubus_method_name);
1391         method->policy = calloc(ucv_object_length(ubus_method_arguments), sizeof(*method->policy));
1392         method->handler = uc_ubus_object_call_cb;
1393 
1394         if (!method->name || !method->policy)
1395                 return false;
1396 
1397         ucv_object_foreach(ubus_method_arguments, ubus_argument_name, ubus_argument_typehint) {
1398                 switch (ucv_type(ubus_argument_typehint)) {
1399                 case UC_BOOLEAN:
1400                         type = BLOBMSG_TYPE_INT8;
1401                         break;
1402 
1403                 case UC_INTEGER:
1404                         switch (ucv_int64_get(ubus_argument_typehint)) {
1405                         case 8:
1406                                 type = BLOBMSG_TYPE_INT8;
1407                                 break;
1408 
1409                         case 16:
1410                                 type = BLOBMSG_TYPE_INT16;
1411                                 break;
1412 
1413                         case 64:
1414                                 type = BLOBMSG_TYPE_INT64;
1415                                 break;
1416 
1417                         default:
1418                                 type = BLOBMSG_TYPE_INT32;
1419                                 break;
1420                         }
1421 
1422                         break;
1423 
1424                 case UC_DOUBLE:
1425                         type = BLOBMSG_TYPE_DOUBLE;
1426                         break;
1427 
1428                 case UC_ARRAY:
1429                         type = BLOBMSG_TYPE_ARRAY;
1430                         break;
1431 
1432                 case UC_OBJECT:
1433                         type = BLOBMSG_TYPE_TABLE;
1434                         break;
1435 
1436                 default:
1437                         type = BLOBMSG_TYPE_STRING;
1438                         break;
1439                 }
1440 
1441                 policy = (struct blobmsg_policy *)&method->policy[method->n_policy++];
1442                 policy->type = type;
1443                 policy->name = strdup(ubus_argument_name);
1444 
1445                 if (!policy->name)
1446                         return false;
1447         }
1448 
1449         return true;
1450 }
1451 
1452 static uc_ubus_object_t *
1453 uc_ubus_object_register(struct ubus_context *ctx, const char *ubus_object_name,
1454                         uc_value_t *ubus_object_methods)
1455 {
1456         const struct blobmsg_policy *policy;
1457         uc_ubus_object_t *uuobj = NULL;
1458         int rv = UBUS_STATUS_UNKNOWN_ERROR;
1459         char *tptr, *tnptr, *onptr, *mptr;
1460         struct ubus_method *method;
1461         struct ubus_object *obj;
1462         size_t typelen, namelen;
1463         uc_value_t *args;
1464 
1465         namelen = strlen(ubus_object_name);
1466         typelen = strlen("ucode-ubus-") + namelen;
1467 
1468         uuobj = calloc_a(sizeof(*uuobj),
1469                          &onptr, namelen + 1,
1470                          &mptr, ucv_object_length(ubus_object_methods) * sizeof(struct ubus_method),
1471                          &tptr, sizeof(struct ubus_object_type),
1472                          &tnptr, typelen + 1);
1473 
1474         if (!uuobj)
1475                 err_return(rv, "Out of memory");
1476 
1477         snprintf(tnptr, typelen, "ucode-ubus-%s", ubus_object_name);
1478 
1479         method = (struct ubus_method *)mptr;
1480 
1481         obj = &uuobj->obj;
1482         obj->name = memcpy(onptr, ubus_object_name, namelen);
1483         obj->methods = method;
1484 
1485         if (ubus_object_methods) {
1486                 ucv_object_foreach(ubus_object_methods, ubus_method_name, ubus_method_definition) {
1487                         args = ucv_object_get(ubus_method_definition, "args", NULL);
1488 
1489                         if (!uc_ubus_object_method_register(&method[obj->n_methods++], ubus_method_name, args))
1490                                 goto out;
1491                 }
1492         }
1493 
1494         obj->type = (struct ubus_object_type *)tptr;
1495         obj->type->name = tnptr;
1496         obj->type->methods = obj->methods;
1497         obj->type->n_methods = obj->n_methods;
1498 
1499         rv = ubus_add_object(ctx, obj);
1500 
1501         if (rv == UBUS_STATUS_OK)
1502                 return uuobj;
1503 
1504 out:
1505         for (; obj->n_methods > 0; method++, obj->n_methods--) {
1506                 for (policy = method->policy; method->n_policy > 0; policy++, method->n_policy--)
1507                         free((char *)policy->name);
1508 
1509                 free((char *)method->name);
1510                 free((char *)method->policy);
1511         }
1512 
1513         free(uuobj);
1514 
1515         err_return(rv, "Unable to add ubus object");
1516 }
1517 
1518 static uc_value_t *
1519 uc_ubus_publish(uc_vm_t *vm, size_t nargs)
1520 {
1521         uc_value_t *objname, *methods, *subscribecb;
1522         uc_ubus_connection_t **c;
1523         uc_ubus_object_t *uuobj;
1524         uc_value_t *res;
1525 
1526         conn_get(vm, &c);
1527 
1528         args_get(vm, nargs,
1529                  "object name", UC_STRING, false, &objname,
1530                  "object methods", UC_OBJECT, true, &methods,
1531                  "subscribe callback", UC_CLOSURE, true, &subscribecb);
1532 
1533         if (!methods && !subscribecb)
1534                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either methods or subscribe callback required");
1535 
1536         if (methods && !uc_ubus_object_methods_validate(methods))
1537                 return NULL;
1538 
1539         uuobj = uc_ubus_object_register((*c)->ctx, ucv_string_get(objname), methods);
1540 
1541         if (!uuobj)
1542                 return NULL;
1543 
1544         if (subscribecb)
1545                 uuobj->obj.subscribe_cb = uc_ubus_object_subscribe_cb;
1546 
1547         res = uc_resource_new(object_type, uuobj);
1548 
1549         uuobj->vm = vm;
1550         uuobj->ctx = (*c)->ctx;
1551         uuobj->registry_index = object_reg_add(vm, ucv_get(res), ucv_get(methods), ucv_get(subscribecb));
1552 
1553         return res;
1554 }
1555 
1556 
1557 /*
1558  * ubus events
1559  * --------------------------------------------------------------------------
1560  */
1561 
1562 static int
1563 uc_ubus_listener_remove_common(uc_ubus_listener_t *uul)
1564 {
1565         int rv = ubus_unregister_event_handler(uul->ctx, &uul->ev);
1566 
1567         if (rv == UBUS_STATUS_OK)
1568                 listener_reg_clear(uul->vm, uul->registry_index);
1569 
1570         return rv;
1571 }
1572 
1573 static uc_value_t *
1574 uc_ubus_listener_remove(uc_vm_t *vm, size_t nargs)
1575 {
1576         uc_ubus_listener_t **uul = uc_fn_this("ubus.listener");
1577         int rv;
1578 
1579         if (!uul || !*uul)
1580                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid listener context");
1581 
1582         rv = uc_ubus_listener_remove_common(*uul);
1583 
1584         if (rv != UBUS_STATUS_OK)
1585                 err_return(rv, "Failed to remove listener object");
1586 
1587         return ucv_boolean_new(true);
1588 }
1589 
1590 static void
1591 uc_ubus_listener_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
1592                     const char *type, struct blob_attr *msg)
1593 {
1594         uc_ubus_listener_t *uul = (uc_ubus_listener_t *)ev;
1595         uc_value_t *this, *func;
1596 
1597         listener_reg_get(uul->vm, uul->registry_index, &this, &func);
1598 
1599         uc_vm_stack_push(uul->vm, ucv_get(this));
1600         uc_vm_stack_push(uul->vm, ucv_get(func));
1601         uc_vm_stack_push(uul->vm, ucv_string_new(type));
1602         uc_vm_stack_push(uul->vm, blob_array_to_ucv(uul->vm, blob_data(msg), blob_len(msg), true));
1603 
1604         if (uc_vm_call(uul->vm, true, 2) == EXCEPTION_NONE)
1605                 ucv_put(uc_vm_stack_pop(uul->vm));
1606         else
1607                 uloop_end();
1608 }
1609 
1610 static uc_value_t *
1611 uc_ubus_listener(uc_vm_t *vm, size_t nargs)
1612 {
1613         uc_value_t *cb, *pattern;
1614         uc_ubus_connection_t **c;
1615         uc_ubus_listener_t *uul;
1616         uc_value_t *res;
1617         int rv;
1618 
1619         conn_get(vm, &c);
1620 
1621         args_get(vm, nargs,
1622                  "event type pattern", UC_STRING, false, &pattern,
1623                  "event callback", UC_CLOSURE, false, &cb);
1624 
1625         uul = xalloc(sizeof(*uul));
1626         uul->vm = vm;
1627         uul->ctx = (*c)->ctx;
1628         uul->ev.cb = uc_ubus_listener_cb;
1629 
1630         rv = ubus_register_event_handler((*c)->ctx, &uul->ev,
1631                                          ucv_string_get(pattern));
1632 
1633         if (rv != UBUS_STATUS_OK) {
1634                 free(uul);
1635                 err_return(rv, "Failed to register listener object");
1636         }
1637 
1638         res = uc_resource_new(listener_type, uul);
1639 
1640         uul->registry_index = listener_reg_add(vm, ucv_get(res), ucv_get(cb));
1641 
1642         return res;
1643 }
1644 
1645 static uc_value_t *
1646 uc_ubus_event(uc_vm_t *vm, size_t nargs)
1647 {
1648         uc_value_t *eventtype, *eventdata;
1649         uc_ubus_connection_t **c;
1650         int rv;
1651 
1652         conn_get(vm, &c);
1653 
1654         args_get(vm, nargs,
1655                  "event id", UC_STRING, false, &eventtype,
1656                  "event data", UC_OBJECT, true, &eventdata);
1657 
1658         blob_buf_init(&buf, 0);
1659 
1660         if (eventdata)
1661                 ucv_object_to_blob(eventdata, &buf);
1662 
1663         rv = ubus_send_event((*c)->ctx, ucv_string_get(eventtype), buf.head);
1664 
1665         if (rv != UBUS_STATUS_OK)
1666                 err_return(rv, "Unable to send event");
1667 
1668         return ucv_boolean_new(true);
1669 }
1670 
1671 
1672 /*
1673  * ubus subscriptions
1674  * --------------------------------------------------------------------------
1675  */
1676 
1677 static int
1678 uc_ubus_subscriber_notify_cb(struct ubus_context *ctx, struct ubus_object *obj,
1679                                  struct ubus_request_data *req, const char *method,
1680                                  struct blob_attr *msg)
1681 {
1682         struct ubus_subscriber *sub = container_of(obj, struct ubus_subscriber, obj);
1683         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
1684         uc_value_t *this, *func, *reqproto;
1685 
1686         subscriber_reg_get(uusub->vm, uusub->registry_index, &this, &func, NULL);
1687 
1688         if (!ucv_is_callable(func))
1689                 return UBUS_STATUS_METHOD_NOT_FOUND;
1690 
1691         reqproto = ucv_object_new(uusub->vm);
1692 
1693         ucv_object_add(reqproto, "type", ucv_string_new(method));
1694 
1695         ucv_object_add(reqproto, "data",
1696                 blob_array_to_ucv(uusub->vm, blob_data(msg), blob_len(msg), true));
1697 
1698         ucv_object_add(reqproto, "info",
1699                 uc_ubus_object_call_info(uusub->vm, ctx, req, obj, NULL));
1700 
1701         return uc_ubus_handle_reply_common(ctx, req, uusub->vm, this, func, reqproto);
1702 }
1703 
1704 static void
1705 uc_ubus_subscriber_remove_cb(struct ubus_context *ctx,
1706                              struct ubus_subscriber *sub, uint32_t id)
1707 {
1708         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
1709         uc_value_t *this, *func;
1710 
1711         subscriber_reg_get(uusub->vm, uusub->registry_index, &this, NULL, &func);
1712 
1713         if (!ucv_is_callable(func))
1714                 return;
1715 
1716         uc_vm_stack_push(uusub->vm, ucv_get(this));
1717         uc_vm_stack_push(uusub->vm, ucv_get(func));
1718         uc_vm_stack_push(uusub->vm, ucv_uint64_new(id));
1719 
1720         if (uc_vm_call(uusub->vm, true, 1) == EXCEPTION_NONE)
1721                 ucv_put(uc_vm_stack_pop(uusub->vm));
1722         else
1723                 uloop_end();
1724 }
1725 
1726 static uc_value_t *
1727 uc_ubus_subscriber_subunsub_common(uc_vm_t *vm, size_t nargs, bool subscribe)
1728 {
1729         uc_ubus_subscriber_t **uusub = uc_fn_this("ubus.subscriber");
1730         uc_value_t *objname;
1731         uint32_t id;
1732         int rv;
1733 
1734         if (!uusub || !*uusub)
1735                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
1736 
1737         args_get(vm, nargs,
1738                  "object name", UC_STRING, false, &objname);
1739 
1740         rv = ubus_lookup_id((*uusub)->ctx, ucv_string_get(objname), &id);
1741 
1742         if (rv != UBUS_STATUS_OK)
1743                 err_return(rv, "Failed to resolve object name '%s'",
1744                            ucv_string_get(objname));
1745 
1746         if (subscribe)
1747                 rv = ubus_subscribe((*uusub)->ctx, &(*uusub)->sub, id);
1748         else
1749                 rv = ubus_unsubscribe((*uusub)->ctx, &(*uusub)->sub, id);
1750 
1751         if (rv != UBUS_STATUS_OK)
1752                 err_return(rv, "Failed to %s object '%s'",
1753                            subscribe ? "subscribe" : "unsubscribe",
1754                            ucv_string_get(objname));
1755 
1756         return ucv_boolean_new(true);
1757 }
1758 
1759 static uc_value_t *
1760 uc_ubus_subscriber_subscribe(uc_vm_t *vm, size_t nargs)
1761 {
1762         return uc_ubus_subscriber_subunsub_common(vm, nargs, true);
1763 }
1764 
1765 static uc_value_t *
1766 uc_ubus_subscriber_unsubscribe(uc_vm_t *vm, size_t nargs)
1767 {
1768         return uc_ubus_subscriber_subunsub_common(vm, nargs, false);
1769 }
1770 
1771 static int
1772 uc_ubus_subscriber_remove_common(uc_ubus_subscriber_t *uusub)
1773 {
1774         int rv = ubus_unregister_subscriber(uusub->ctx, &uusub->sub);
1775 
1776         if (rv == UBUS_STATUS_OK)
1777                 subscriber_reg_clear(uusub->vm, uusub->registry_index);
1778 
1779         return rv;
1780 }
1781 
1782 static uc_value_t *
1783 uc_ubus_subscriber_remove(uc_vm_t *vm, size_t nargs)
1784 {
1785         uc_ubus_subscriber_t **uusub = uc_fn_this("ubus.subscriber");
1786         int rv;
1787 
1788         if (!uusub || !*uusub)
1789                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
1790 
1791         rv = uc_ubus_subscriber_remove_common(*uusub);
1792 
1793         if (rv != UBUS_STATUS_OK)
1794                 err_return(rv, "Failed to remove subscriber object");
1795 
1796         return ucv_boolean_new(true);
1797 }
1798 
1799 static uc_value_t *
1800 uc_ubus_subscriber(uc_vm_t *vm, size_t nargs)
1801 {
1802         uc_value_t *notify_cb, *remove_cb;
1803         uc_ubus_subscriber_t *uusub;
1804         uc_ubus_connection_t **c;
1805         uc_value_t *res;
1806         int rv;
1807 
1808         conn_get(vm, &c);
1809 
1810         args_get(vm, nargs,
1811                  "notify callback", UC_CLOSURE, true, &notify_cb,
1812                  "remove callback", UC_CLOSURE, true, &remove_cb);
1813 
1814         if (!notify_cb && !remove_cb)
1815                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either notify or remove callback required");
1816 
1817         uusub = xalloc(sizeof(*uusub));
1818         uusub->vm = vm;
1819         uusub->ctx = (*c)->ctx;
1820 
1821         rv = ubus_register_subscriber((*c)->ctx, &uusub->sub);
1822 
1823         if (rv != UBUS_STATUS_OK) {
1824                 free(uusub);
1825                 err_return(rv, "Failed to register subscriber object");
1826         }
1827 
1828         if (notify_cb)
1829                 uusub->sub.cb = uc_ubus_subscriber_notify_cb;
1830 
1831         if (remove_cb)
1832                 uusub->sub.remove_cb = uc_ubus_subscriber_remove_cb;
1833 
1834         res = uc_resource_new(subscriber_type, uusub);
1835 
1836         uusub->registry_index = subscriber_reg_add(vm,
1837                 ucv_get(res), ucv_get(notify_cb), ucv_get(remove_cb));
1838 
1839         return res;
1840 }
1841 
1842 
1843 /*
1844  * connection methods
1845  * --------------------------------------------------------------------------
1846  */
1847 
1848 static uc_value_t *
1849 uc_ubus_remove(uc_vm_t *vm, size_t nargs)
1850 {
1851         uc_ubus_subscriber_t **uusub;
1852         uc_ubus_connection_t **c;
1853         uc_ubus_object_t **uuobj;
1854         uc_ubus_listener_t **uul;
1855         int rv;
1856 
1857         conn_get(vm, &c);
1858 
1859         uusub = (uc_ubus_subscriber_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.subscriber");
1860         uuobj = (uc_ubus_object_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.object");
1861         uul = (uc_ubus_listener_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.listener");
1862 
1863         if (uusub && *uusub) {
1864                 if ((*uusub)->ctx != (*c)->ctx)
1865                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1866                                    "Subscriber belongs to different connection");
1867 
1868                 rv = uc_ubus_subscriber_remove_common(*uusub);
1869 
1870                 if (rv != UBUS_STATUS_OK)
1871                         err_return(rv, "Unable to remove subscriber");
1872         }
1873         else if (uuobj && *uuobj) {
1874                 if ((*uuobj)->ctx != (*c)->ctx)
1875                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1876                                    "Object belongs to different connection");
1877 
1878                 rv = uc_ubus_object_remove_common(*uuobj);
1879 
1880                 if (rv != UBUS_STATUS_OK)
1881                         err_return(rv, "Unable to remove object");
1882         }
1883         else if (uul && *uul) {
1884                 if ((*uul)->ctx != (*c)->ctx)
1885                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1886                                    "Listener belongs to different connection");
1887 
1888                 rv = uc_ubus_listener_remove_common(*uul);
1889 
1890                 if (rv != UBUS_STATUS_OK)
1891                         err_return(rv, "Unable to remove listener");
1892         }
1893         else {
1894                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Unhandled resource type");
1895         }
1896 
1897         return ucv_boolean_new(true);
1898 }
1899 
1900 
1901 static uc_value_t *
1902 uc_ubus_disconnect(uc_vm_t *vm, size_t nargs)
1903 {
1904         uc_ubus_connection_t **c;
1905 
1906         conn_get(vm, &c);
1907 
1908         ubus_free((*c)->ctx);
1909         (*c)->ctx = NULL;
1910 
1911         return ucv_boolean_new(true);
1912 }
1913 
1914 static uc_value_t *
1915 uc_ubus_defer_completed(uc_vm_t *vm, size_t nargs)
1916 {
1917         uc_ubus_deferred_t **d = uc_fn_this("ubus.deferred");
1918 
1919         if (!d || !*d)
1920                 return NULL;
1921 
1922         return ucv_boolean_new((*d)->complete);
1923 }
1924 
1925 static uc_value_t *
1926 uc_ubus_defer_abort(uc_vm_t *vm, size_t nargs)
1927 {
1928         uc_ubus_deferred_t **d = uc_fn_this("ubus.deferred");
1929 
1930         if (!d || !*d)
1931                 return NULL;
1932 
1933         if ((*d)->complete)
1934                 return ucv_boolean_new(false);
1935 
1936         ubus_abort_request((*d)->ctx, &(*d)->request);
1937         uloop_timeout_cancel(&(*d)->timeout);
1938 
1939         request_reg_clear((*d)->vm, (*d)->registry_index);
1940 
1941         n_cb_active--;
1942 
1943         if (have_own_uloop && n_cb_active == 0)
1944                 uloop_end();
1945 
1946         (*d)->complete = true;
1947 
1948         return ucv_boolean_new(true);
1949 }
1950 
1951 
1952 static const uc_function_list_t global_fns[] = {
1953         { "error",                      uc_ubus_error },
1954         { "connect",            uc_ubus_connect },
1955 };
1956 
1957 static const uc_function_list_t conn_fns[] = {
1958         { "list",                       uc_ubus_list },
1959         { "call",                       uc_ubus_call },
1960         { "defer",                      uc_ubus_defer },
1961         { "publish",            uc_ubus_publish },
1962         { "remove",                     uc_ubus_remove },
1963         { "listener",           uc_ubus_listener },
1964         { "subscriber",         uc_ubus_subscriber },
1965         { "event",                      uc_ubus_event },
1966         { "error",                      uc_ubus_error },
1967         { "disconnect",         uc_ubus_disconnect },
1968 };
1969 
1970 static const uc_function_list_t defer_fns[] = {
1971         { "completed",          uc_ubus_defer_completed },
1972         { "abort",                      uc_ubus_defer_abort },
1973 };
1974 
1975 static const uc_function_list_t object_fns[] = {
1976         { "subscribed",         uc_ubus_object_subscribed },
1977         { "notify",                     uc_ubus_object_notify },
1978         { "remove",                     uc_ubus_object_remove },
1979 };
1980 
1981 static const uc_function_list_t request_fns[] = {
1982         { "reply",                      uc_ubus_request_reply },
1983         { "error",                      uc_ubus_request_error },
1984 };
1985 
1986 static const uc_function_list_t notify_fns[] = {
1987         { "completed",          uc_ubus_notify_completed },
1988         { "abort",                      uc_ubus_notify_abort },
1989 };
1990 
1991 static const uc_function_list_t listener_fns[] = {
1992         { "remove",                     uc_ubus_listener_remove },
1993 };
1994 
1995 static const uc_function_list_t subscriber_fns[] = {
1996         { "subscribe",          uc_ubus_subscriber_subscribe },
1997         { "unsubscribe",        uc_ubus_subscriber_unsubscribe },
1998         { "remove",                     uc_ubus_subscriber_remove },
1999 };
2000 
2001 static void free_connection(void *ud) {
2002         uc_ubus_connection_t *conn = ud;
2003 
2004         blob_buf_free(&conn->buf);
2005 
2006         if (conn->ctx)
2007                 ubus_free(conn->ctx);
2008 
2009         free(conn);
2010 }
2011 
2012 static void free_deferred(void *ud) {
2013         uc_ubus_deferred_t *defer = ud;
2014 
2015         uloop_timeout_cancel(&defer->timeout);
2016         ucv_put(defer->response);
2017         free(defer);
2018 }
2019 
2020 static void free_object(void *ud) {
2021         uc_ubus_object_t *uuobj = ud;
2022         struct ubus_object *obj = &uuobj->obj;
2023         int i, j;
2024 
2025         for (i = 0; i < obj->n_methods; i++) {
2026                 for (j = 0; j < obj->methods[i].n_policy; j++)
2027                         free((char *)obj->methods[i].policy[j].name);
2028 
2029                 free((char *)obj->methods[i].name);
2030                 free((char *)obj->methods[i].policy);
2031         }
2032 
2033         free(uuobj);
2034 }
2035 
2036 static void free_request(void *ud) {
2037         uc_ubus_request_t *callctx = ud;
2038 
2039         uloop_timeout_cancel(&callctx->timeout);
2040         free(callctx);
2041 }
2042 
2043 static void free_notify(void *ud) {
2044         uc_ubus_notify_t *notifyctx = ud;
2045 
2046         free(notifyctx);
2047 }
2048 
2049 static void free_listener(void *ud) {
2050         uc_ubus_listener_t *listener = ud;
2051 
2052         free(listener);
2053 }
2054 
2055 static void free_subscriber(void *ud) {
2056         uc_ubus_subscriber_t *subscriber = ud;
2057 
2058         free(subscriber);
2059 }
2060 
2061 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
2062 {
2063         uc_function_list_register(scope, global_fns);
2064 
2065 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(UBUS_##x))
2066         ADD_CONST(STATUS_OK);
2067         ADD_CONST(STATUS_INVALID_COMMAND);
2068         ADD_CONST(STATUS_INVALID_ARGUMENT);
2069         ADD_CONST(STATUS_METHOD_NOT_FOUND);
2070         ADD_CONST(STATUS_NOT_FOUND);
2071         ADD_CONST(STATUS_NO_DATA);
2072         ADD_CONST(STATUS_PERMISSION_DENIED);
2073         ADD_CONST(STATUS_TIMEOUT);
2074         ADD_CONST(STATUS_NOT_SUPPORTED);
2075         ADD_CONST(STATUS_UNKNOWN_ERROR);
2076         ADD_CONST(STATUS_CONNECTION_FAILED);
2077 
2078 #ifdef HAVE_NEW_UBUS_STATUS_CODES
2079         ADD_CONST(STATUS_NO_MEMORY);
2080         ADD_CONST(STATUS_PARSE_ERROR);
2081         ADD_CONST(STATUS_SYSTEM_ERROR);
2082 #endif
2083 
2084         conn_type = uc_type_declare(vm, "ubus.connection", conn_fns, free_connection);
2085         defer_type = uc_type_declare(vm, "ubus.deferred", defer_fns, free_deferred);
2086         object_type = uc_type_declare(vm, "ubus.object", object_fns, free_object);
2087         notify_type = uc_type_declare(vm, "ubus.notify", notify_fns, free_notify);
2088         request_type = uc_type_declare(vm, "ubus.request", request_fns, free_request);
2089         listener_type = uc_type_declare(vm, "ubus.listener", listener_fns, free_listener);
2090         subscriber_type = uc_type_declare(vm, "ubus.subscriber", subscriber_fns, free_subscriber);
2091 }
2092 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt