• 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 <limits.h>
 19 #include <libubus.h>
 20 #include <libubox/blobmsg.h>
 21 
 22 #include "ucode/module.h"
 23 
 24 #define ok_return(expr) do { set_error(0, NULL); return (expr); } while(0)
 25 #define err_return(err, ...) do { set_error(err, __VA_ARGS__); return NULL; } while(0)
 26 #define errval_return(err, ...) do { set_error(err, __VA_ARGS__); return err; } while(0)
 27 
 28 #define REQUIRED        0
 29 #define OPTIONAL        1
 30 #define NAMED           2
 31 
 32 static struct {
 33         enum ubus_msg_status code;
 34         char *msg;
 35 } last_error;
 36 
 37 __attribute__((format(printf, 2, 3))) static void
 38 set_error(int errcode, const char *fmt, ...)
 39 {
 40         va_list ap;
 41 
 42         free(last_error.msg);
 43 
 44         last_error.code = errcode;
 45         last_error.msg = NULL;
 46 
 47         if (fmt) {
 48                 va_start(ap, fmt);
 49                 xvasprintf(&last_error.msg, fmt, ap);
 50                 va_end(ap);
 51         }
 52 }
 53 
 54 static char *
 55 _arg_type(uc_type_t type)
 56 {
 57         switch (type) {
 58         case UC_INTEGER:   return "an integer value";
 59         case UC_BOOLEAN:   return "a boolean value";
 60         case UC_STRING:    return "a string value";
 61         case UC_DOUBLE:    return "a double value";
 62         case UC_ARRAY:     return "an array";
 63         case UC_OBJECT:    return "an object";
 64         case UC_REGEXP:    return "a regular expression";
 65         case UC_CLOSURE:   return "a function";
 66         default:           return "the expected type";
 67         }
 68 }
 69 
 70 static bool
 71 _args_get(uc_vm_t *vm, bool named, size_t nargs, ...)
 72 {
 73         uc_value_t **ptr, *arg, *obj = NULL;
 74         uc_type_t type, t;
 75         const char *name;
 76         size_t index = 0;
 77         va_list ap;
 78         int opt;
 79 
 80         if (named) {
 81                 obj = uc_fn_arg(0);
 82 
 83                 if (nargs != 1 || ucv_type(obj) != UC_OBJECT)
 84                         named = false;
 85         }
 86 
 87         va_start(ap, nargs);
 88 
 89         while (true) {
 90                 name = va_arg(ap, const char *);
 91 
 92                 if (!name)
 93                         break;
 94 
 95                 type = va_arg(ap, uc_type_t);
 96                 opt = va_arg(ap, int);
 97                 ptr = va_arg(ap, uc_value_t **);
 98 
 99                 if (named)
100                         arg = ucv_object_get(obj, name, NULL);
101                 else if (opt != NAMED)
102                         arg = uc_fn_arg(index++);
103                 else
104                         arg = NULL;
105 
106                 if (opt == REQUIRED && !arg)
107                         err_return(UBUS_STATUS_INVALID_ARGUMENT, "Argument %s is required", name);
108 
109                 t = ucv_type(arg);
110 
111                 if (t == UC_CFUNCTION)
112                         t = UC_CLOSURE;
113 
114                 if (arg && type && t != type)
115                         err_return(UBUS_STATUS_INVALID_ARGUMENT, "Argument %s is not %s", name, _arg_type(type));
116 
117                 *ptr = arg;
118         }
119 
120         va_end(ap);
121 
122         ok_return(true);
123 }
124 
125 #define args_get_named(vm, nargs, ...) do { if (!_args_get(vm, true, nargs, __VA_ARGS__, NULL)) return NULL; } while(0)
126 #define args_get(vm, nargs, ...) do { if (!_args_get(vm, false, nargs, __VA_ARGS__, NULL)) return NULL; } while(0)
127 
128 static uc_resource_type_t *subscriber_type;
129 static uc_resource_type_t *listener_type;
130 static uc_resource_type_t *request_type;
131 static uc_resource_type_t *notify_type;
132 static uc_resource_type_t *object_type;
133 static uc_resource_type_t *defer_type;
134 static uc_resource_type_t *conn_type;
135 static uc_resource_type_t *chan_type;
136 
137 static struct blob_buf buf;
138 
139 typedef struct {
140         struct ubus_context ctx;
141         struct blob_buf buf;
142         int timeout;
143 
144         uc_vm_t *vm;
145         int registry_index;
146 } uc_ubus_connection_t;
147 
148 typedef struct {
149         struct ubus_request request;
150         struct uloop_timeout timeout;
151         struct ubus_context *ctx;
152         size_t registry_index;
153         bool complete;
154         uc_vm_t *vm;
155         uc_value_t *callback;
156         uc_value_t *response;
157 } uc_ubus_deferred_t;
158 
159 typedef struct {
160         struct ubus_object obj;
161         struct ubus_context *ctx;
162         size_t registry_index;
163         uc_vm_t *vm;
164 } uc_ubus_object_t;
165 
166 typedef struct {
167         struct ubus_request_data req;
168         struct uloop_timeout timeout;
169         struct ubus_context *ctx;
170         size_t registry_index;
171         bool deferred;
172         bool replied;
173         uc_vm_t *vm;
174 } uc_ubus_request_t;
175 
176 typedef struct {
177         struct ubus_notify_request req;
178         struct ubus_context *ctx;
179         size_t registry_index;
180         bool complete;
181         uc_vm_t *vm;
182 } uc_ubus_notify_t;
183 
184 typedef struct {
185         struct ubus_event_handler ev;
186         struct ubus_context *ctx;
187         size_t registry_index;
188         uc_vm_t *vm;
189 } uc_ubus_listener_t;
190 
191 typedef struct {
192         struct ubus_subscriber sub;
193         struct ubus_context *ctx;
194         size_t registry_index;
195         uc_vm_t *vm;
196 } uc_ubus_subscriber_t;
197 
198 typedef struct {
199         bool mret;
200         uc_value_t *res;
201 } uc_ubus_call_res_t;
202 
203 static uc_value_t *
204 uc_ubus_error(uc_vm_t *vm, size_t nargs)
205 {
206         uc_value_t *numeric = uc_fn_arg(0), *rv;
207         uc_stringbuf_t *buf;
208         const char *s;
209 
210         if (last_error.code == 0)
211                 return NULL;
212 
213         if (ucv_is_truish(numeric)) {
214                 rv = ucv_int64_new(last_error.code);
215         }
216         else {
217                 buf = ucv_stringbuf_new();
218 
219                 if (last_error.code == UBUS_STATUS_UNKNOWN_ERROR && last_error.msg) {
220                         ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg));
221                 }
222                 else {
223                         s = ubus_strerror(last_error.code);
224 
225                         ucv_stringbuf_addstr(buf, s, strlen(s));
226 
227                         if (last_error.msg)
228                                 ucv_stringbuf_printf(buf, ": %s", last_error.msg);
229                 }
230 
231                 rv = ucv_stringbuf_finish(buf);
232         }
233 
234         set_error(0, NULL);
235 
236         return rv;
237 }
238 
239 static void
240 _uc_reg_get(uc_vm_t *vm, const char *key, size_t idx, size_t nptrs, ...)
241 {
242         uc_value_t *reg = uc_vm_registry_get(vm, key), **val;
243         va_list ap;
244         size_t i;
245 
246         va_start(ap, nptrs);
247 
248         for (i = 0; i < nptrs; i++) {
249                 val = va_arg(ap, uc_value_t **);
250 
251                 if (val)
252                         *val = ucv_array_get(reg, idx + i);
253         }
254 
255         va_end(ap);
256 }
257 
258 static size_t
259 _uc_reg_add(uc_vm_t *vm, const char *key, size_t nptrs, ...)
260 {
261         uc_value_t *reg = uc_vm_registry_get(vm, key);
262         size_t idx, i;
263         va_list ap;
264 
265         if (!reg) {
266                 reg = ucv_array_new(vm);
267                 uc_vm_registry_set(vm, key, reg);
268         }
269 
270         va_start(ap, nptrs);
271 
272         for (idx = 0;; idx += nptrs) {
273                 if (ucv_array_get(reg, idx) == NULL) {
274                         for (i = 0; i < nptrs; i++)
275                                 ucv_array_set(reg, idx + i, va_arg(ap, uc_value_t *));
276 
277                         break;
278                 }
279         }
280 
281         va_end(ap);
282 
283         return idx;
284 }
285 
286 static void
287 _uc_reg_clear(uc_vm_t *vm, const char *key, size_t idx, size_t nptrs)
288 {
289         uc_value_t *reg = uc_vm_registry_get(vm, key);
290 
291         while (nptrs > 0) {
292                 nptrs--;
293                 ucv_array_set(reg, idx + nptrs, NULL);
294         }
295 }
296 
297 
298 #define connection_reg_add(vm, conn, cb, disconnect_cb, fd) \
299         _uc_reg_add(vm, "ubus.connections", 4, conn, cb, disconnect_cb, fd)
300 
301 #define connection_reg_get(vm, idx, conn, cb, disconnect_cb) \
302         _uc_reg_get(vm, "ubus.connections", idx, 3, conn, cb, disconnect_cb)
303 
304 #define connection_reg_clear(vm, idx) \
305         _uc_reg_clear(vm, "ubus.connections", idx, 4)
306 
307 
308 #define request_reg_add(vm, request, cb, datacb, fdcb, conn, fd) \
309         _uc_reg_add(vm, "ubus.requests", 6, request, cb, datacb, fdcb, conn, fd)
310 
311 #define request_reg_get(vm, idx, request, cb, datacb, fdcb) \
312         _uc_reg_get(vm, "ubus.requests", idx, 4, request, cb, datacb, fdcb)
313 
314 #define request_reg_clear(vm, idx) \
315         _uc_reg_clear(vm, "ubus.requests", idx, 6)
316 
317 
318 #define object_reg_add(vm, obj, msg, cb) \
319         _uc_reg_add(vm, "ubus.objects", 3, obj, msg, cb)
320 
321 #define object_reg_get(vm, idx, obj, msg, cb) \
322         _uc_reg_get(vm, "ubus.objects", idx, 3, obj, msg, cb)
323 
324 #define object_reg_clear(vm, idx) \
325         _uc_reg_clear(vm, "ubus.objects", idx, 3)
326 
327 
328 #define notify_reg_add(vm, notify, dcb, scb, ccb) \
329         _uc_reg_add(vm, "ubus.notifications", 4, notify, dcb, scb, ccb)
330 
331 #define notify_reg_get(vm, idx, notify, dcb, scb, ccb) \
332         _uc_reg_get(vm, "ubus.notifications", idx, 4, notify, dcb, scb, ccb)
333 
334 #define notify_reg_clear(vm, idx) \
335         _uc_reg_clear(vm, "ubus.notifications", idx, 4)
336 
337 
338 #define listener_reg_add(vm, listener, cb) \
339         _uc_reg_add(vm, "ubus.listeners", 2, listener, cb)
340 
341 #define listener_reg_get(vm, idx, listener, cb) \
342         _uc_reg_get(vm, "ubus.listeners", idx, 2, listener, cb)
343 
344 #define listener_reg_clear(vm, idx) \
345         _uc_reg_clear(vm, "ubus.listeners", idx, 2)
346 
347 
348 #define subscriber_reg_add(vm, subscriber, ncb, rcb) \
349         _uc_reg_add(vm, "ubus.subscribers", 3, subscriber, ncb, rcb)
350 
351 #define subscriber_reg_get(vm, idx, subscriber, ncb, rcb) \
352         _uc_reg_get(vm, "ubus.subscribers", idx, 3, subscriber, ncb, rcb)
353 
354 #define subscriber_reg_clear(vm, idx) \
355         _uc_reg_clear(vm, "ubus.subscribers", idx, 3)
356 
357 
358 static uc_value_t *
359 blob_to_ucv(uc_vm_t *vm, struct blob_attr *attr, bool table, const char **name);
360 
361 static uc_value_t *
362 blob_array_to_ucv(uc_vm_t *vm, struct blob_attr *attr, size_t len, bool table)
363 {
364         uc_value_t *o = table ? ucv_object_new(vm) : ucv_array_new(vm);
365         uc_value_t *v;
366         struct blob_attr *pos;
367         size_t rem = len;
368         const char *name;
369 
370         if (!o)
371                 return NULL;
372 
373         __blob_for_each_attr(pos, attr, rem) {
374                 name = NULL;
375                 v = blob_to_ucv(vm, pos, table, &name);
376 
377                 if (table && name)
378                         ucv_object_add(o, name, v);
379                 else if (!table)
380                         ucv_array_push(o, v);
381                 else
382                         ucv_put(v);
383         }
384 
385         return o;
386 }
387 
388 static uc_value_t *
389 blob_to_ucv(uc_vm_t *vm, struct blob_attr *attr, bool table, const char **name)
390 {
391         void *data;
392         int len;
393 
394         if (!blobmsg_check_attr(attr, false))
395                 return NULL;
396 
397         if (table && blobmsg_name(attr)[0])
398                 *name = blobmsg_name(attr);
399 
400         data = blobmsg_data(attr);
401         len = blobmsg_data_len(attr);
402 
403         switch (blob_id(attr)) {
404         case BLOBMSG_TYPE_BOOL:
405                 return ucv_boolean_new(*(uint8_t *)data);
406 
407         case BLOBMSG_TYPE_INT16:
408                 return ucv_int64_new((int16_t)be16_to_cpu(*(uint16_t *)data));
409 
410         case BLOBMSG_TYPE_INT32:
411                 return ucv_int64_new((int32_t)be32_to_cpu(*(uint32_t *)data));
412 
413         case BLOBMSG_TYPE_INT64:
414                 return ucv_int64_new((int64_t)be64_to_cpu(*(uint64_t *)data));
415 
416         case BLOBMSG_TYPE_DOUBLE:
417                 ;
418                 union {
419                         double d;
420                         uint64_t u64;
421                 } v;
422 
423                 v.u64 = be64_to_cpu(*(uint64_t *)data);
424 
425                 return ucv_double_new(v.d);
426 
427         case BLOBMSG_TYPE_STRING:
428                 return ucv_string_new_length(data, len - 1);
429 
430         case BLOBMSG_TYPE_ARRAY:
431                 return blob_array_to_ucv(vm, data, len, false);
432 
433         case BLOBMSG_TYPE_TABLE:
434                 return blob_array_to_ucv(vm, data, len, true);
435 
436         default:
437                 return NULL;
438         }
439 }
440 
441 static void
442 ucv_array_to_blob(uc_value_t *val, struct blob_buf *blob);
443 
444 static void
445 ucv_object_to_blob(uc_value_t *val, struct blob_buf *blob);
446 
447 static void
448 ucv_to_blob(const char *name, uc_value_t *val, struct blob_buf *blob)
449 {
450         int64_t n;
451         void *c;
452 
453         switch (ucv_type(val)) {
454         case UC_NULL:
455                 blobmsg_add_field(blob, BLOBMSG_TYPE_UNSPEC, name, NULL, 0);
456                 break;
457 
458         case UC_BOOLEAN:
459                 blobmsg_add_u8(blob, name, ucv_boolean_get(val));
460                 break;
461 
462         case UC_INTEGER:
463                 n = ucv_int64_get(val);
464 
465                 if (errno == ERANGE)
466                         blobmsg_add_u64(blob, name, ucv_uint64_get(val));
467                 else if (n >= INT32_MIN && n <= INT32_MAX)
468                         blobmsg_add_u32(blob, name, n);
469                 else
470                         blobmsg_add_u64(blob, name, n);
471 
472                 break;
473 
474         case UC_DOUBLE:
475                 blobmsg_add_double(blob, name, ucv_double_get(val));
476                 break;
477 
478         case UC_STRING:
479                 blobmsg_add_field(blob, BLOBMSG_TYPE_STRING, name,
480                                   ucv_string_get(val), ucv_string_length(val) + 1);
481                 break;
482 
483         case UC_ARRAY:
484                 c = blobmsg_open_array(blob, name);
485                 ucv_array_to_blob(val, blob);
486                 blobmsg_close_array(blob, c);
487                 break;
488 
489         case UC_OBJECT:
490                 c = blobmsg_open_table(blob, name);
491                 ucv_object_to_blob(val, blob);
492                 blobmsg_close_table(blob, c);
493                 break;
494 
495         default:
496                 break;
497         }
498 }
499 
500 static void
501 ucv_array_to_blob(uc_value_t *val, struct blob_buf *blob)
502 {
503         size_t i;
504 
505         for (i = 0; i < ucv_array_length(val); i++)
506                 ucv_to_blob(NULL, ucv_array_get(val, i), blob);
507 }
508 
509 static void
510 ucv_object_to_blob(uc_value_t *val, struct blob_buf *blob)
511 {
512         ucv_object_foreach(val, k, v)
513                 ucv_to_blob(k, v, blob);
514 }
515 
516 
517 static uc_value_t *
518 uc_ubus_connect(uc_vm_t *vm, size_t nargs)
519 {
520         uc_value_t *socket, *timeout;
521         uc_ubus_connection_t *c;
522 
523         args_get(vm, nargs,
524                  "socket", UC_STRING, true, &socket,
525                  "timeout", UC_INTEGER, true, &timeout);
526 
527         c = xalloc(sizeof(*c));
528         c->registry_index = -1;
529         c->timeout = timeout ? ucv_int64_get(timeout) : 30;
530 
531         if (ubus_connect_ctx(&c->ctx, socket ? ucv_string_get(socket) : NULL)) {
532                 free(c);
533                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to connect to ubus socket");
534         }
535 
536         if (c->timeout < 0)
537                 c->timeout = 30;
538 
539         ubus_add_uloop(&c->ctx);
540 
541         ok_return(uc_resource_new(conn_type, c));
542 }
543 
544 static void
545 uc_ubus_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
546 {
547         uc_value_t *arr = p;
548         uc_value_t *sig;
549 
550         if (!o->signature)
551                 return;
552 
553         sig = blob_array_to_ucv(NULL, blob_data(o->signature), blob_len(o->signature), true);
554 
555         if (sig)
556                 ucv_array_push(arr, sig);
557 }
558 
559 static void
560 uc_ubus_objects_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
561 {
562         uc_value_t *arr = p;
563 
564         ucv_array_push(arr, ucv_string_new(o->path));
565 }
566 
567 static bool
568 _conn_get(uc_vm_t *vm, uc_ubus_connection_t **conn)
569 {
570         uc_ubus_connection_t *c = uc_fn_thisval("ubus.connection");
571 
572         if (!c)
573                 c = uc_fn_thisval("ubus.channel");
574         if (!c)
575                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid connection context");
576 
577         if (c->ctx.sock.fd < 0)
578                 err_return(UBUS_STATUS_CONNECTION_FAILED, "Connection is closed");
579 
580         *conn = c;
581 
582         ok_return(true);
583 }
584 
585 #define conn_get(vm, ptr) do { if (!_conn_get(vm, ptr)) return NULL; } while(0)
586 
587 static uc_value_t *
588 uc_ubus_list(uc_vm_t *vm, size_t nargs)
589 {
590         uc_ubus_connection_t *c;
591         uc_value_t *objname, *res = NULL;
592         enum ubus_msg_status rv;
593 
594         conn_get(vm, &c);
595 
596         args_get(vm, nargs,
597                  "object name", UC_STRING, true, &objname);
598 
599         res = ucv_array_new(vm);
600 
601         rv = ubus_lookup(&c->ctx,
602                          objname ? ucv_string_get(objname) : NULL,
603                          objname ? uc_ubus_signatures_cb : uc_ubus_objects_cb,
604                          res);
605 
606         if (rv != UBUS_STATUS_OK) {
607                 ucv_put(res);
608                 err_return(rv, NULL);
609         }
610 
611         ok_return(res);
612 }
613 
614 static void
615 uc_ubus_call_cb(struct ubus_request *req, int type, struct blob_attr *msg)
616 {
617         uc_ubus_call_res_t *res = req->priv;
618         uc_value_t *val;
619 
620         val = msg ? blob_array_to_ucv(NULL, blob_data(msg), blob_len(msg), true) : NULL;
621 
622         if (res->mret) {
623                 if (!res->res)
624                         res->res = ucv_array_new(NULL);
625 
626                 ucv_array_push(res->res, val);
627         }
628         else if (!res->res) {
629                 res->res = val;
630         }
631 }
632 
633 static void
634 uc_ubus_call_user_cb(uc_ubus_deferred_t *defer, int ret, uc_value_t *reply)
635 {
636         uc_value_t *this, *func;
637 
638         request_reg_get(defer->vm, defer->registry_index, &this, &func, NULL, NULL);
639 
640         if (ucv_is_callable(func)) {
641                 uc_vm_stack_push(defer->vm, ucv_get(this));
642                 uc_vm_stack_push(defer->vm, ucv_get(func));
643                 uc_vm_stack_push(defer->vm, ucv_int64_new(ret));
644                 uc_vm_stack_push(defer->vm, ucv_get(reply));
645 
646                 if (uc_vm_call(defer->vm, true, 2) == EXCEPTION_NONE)
647                         ucv_put(uc_vm_stack_pop(defer->vm));
648         }
649 
650         request_reg_clear(defer->vm, defer->registry_index);
651 }
652 
653 static void
654 uc_ubus_call_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
655 {
656         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
657 
658         if (defer->response == NULL)
659                 defer->response = blob_array_to_ucv(defer->vm, blob_data(msg), blob_len(msg), true);
660 }
661 
662 static void
663 uc_ubus_call_data_user_cb(struct ubus_request *req, int type, struct blob_attr *msg)
664 {
665         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
666         uc_value_t *this, *func, *reply;
667 
668         request_reg_get(defer->vm, defer->registry_index, &this, NULL, &func, NULL);
669 
670         if (ucv_is_callable(func)) {
671                 reply = blob_array_to_ucv(defer->vm, blob_data(msg), blob_len(msg), true);
672 
673                 uc_vm_stack_push(defer->vm, ucv_get(this));
674                 uc_vm_stack_push(defer->vm, ucv_get(func));
675                 uc_vm_stack_push(defer->vm, ucv_get(reply));
676 
677                 if (uc_vm_call(defer->vm, true, 1) == EXCEPTION_NONE)
678                         ucv_put(uc_vm_stack_pop(defer->vm));
679                 else
680                         uloop_end();
681         }
682 }
683 
684 static void
685 uc_ubus_call_fd_cb(struct ubus_request *req, int fd)
686 {
687         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
688         uc_value_t *this, *func;
689 
690         if (defer->complete)
691                 return;
692 
693         request_reg_get(defer->vm, defer->registry_index, &this, NULL, NULL, &func);
694 
695         if (ucv_is_callable(func)) {
696                 uc_vm_stack_push(defer->vm, ucv_get(this));
697                 uc_vm_stack_push(defer->vm, ucv_get(func));
698                 uc_vm_stack_push(defer->vm, ucv_int64_new(fd));
699 
700                 if (uc_vm_call(defer->vm, true, 1) == EXCEPTION_NONE)
701                         ucv_put(uc_vm_stack_pop(defer->vm));
702                 else
703                         uloop_end();
704         }
705 }
706 
707 static void
708 uc_ubus_call_done_cb(struct ubus_request *req, int ret)
709 {
710         uc_ubus_deferred_t *defer = container_of(req, uc_ubus_deferred_t, request);
711 
712         if (defer->complete)
713                 return;
714 
715         defer->complete = true;
716         uloop_timeout_cancel(&defer->timeout);
717 
718         uc_ubus_call_user_cb(defer, ret, defer->response);
719 }
720 
721 static void
722 uc_ubus_call_timeout_cb(struct uloop_timeout *timeout)
723 {
724         uc_ubus_deferred_t *defer = container_of(timeout, uc_ubus_deferred_t, timeout);
725 
726         if (defer->complete)
727                 return;
728 
729         defer->complete = true;
730         ubus_abort_request(defer->ctx, &defer->request);
731 
732         uc_ubus_call_user_cb(defer, UBUS_STATUS_TIMEOUT, NULL);
733 }
734 
735 static int
736 get_fd(uc_vm_t *vm, uc_value_t *val)
737 {
738         uc_value_t *fn;
739         int64_t n;
740 
741         fn = ucv_property_get(val, "fileno");
742 
743         if (ucv_is_callable(fn)) {
744                 uc_vm_stack_push(vm, ucv_get(val));
745                 uc_vm_stack_push(vm, ucv_get(fn));
746 
747                 if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE)
748                         return -1;
749 
750                 val = uc_vm_stack_pop(vm);
751                 n = ucv_int64_get(val);
752                 ucv_put(val);
753         }
754         else {
755                 n = ucv_int64_get(val);
756         }
757 
758         if (errno || n < 0 || n > (int64_t)INT_MAX)
759                 return -1;
760 
761         return (int)n;
762 }
763 
764 static int
765 uc_ubus_call_common(uc_vm_t *vm, uc_ubus_connection_t *c, uc_ubus_call_res_t *res,
766                     uint32_t id, uc_value_t *funname, uc_value_t *funargs,
767                     uc_value_t *fd, uc_value_t *fdcb, uc_value_t *mret)
768 {
769         uc_ubus_deferred_t defer = {};
770         enum ubus_msg_status rv;
771         int fd_val = -1;
772 
773         enum {
774                 RET_MODE_SINGLE,
775                 RET_MODE_MULTIPLE,
776                 RET_MODE_IGNORE,
777         } ret_mode = RET_MODE_SINGLE;
778 
779         const char * const ret_modes[] = {
780                 [RET_MODE_SINGLE] = "single",
781                 [RET_MODE_MULTIPLE] = "multiple",
782                 [RET_MODE_IGNORE] = "ignore",
783         };
784 
785         if (ucv_type(mret) == UC_STRING) {
786                 const char *str = ucv_string_get(mret);
787                 size_t i;
788 
789                 for (i = 0; i < ARRAY_SIZE(ret_modes); i++)
790                         if (!strcmp(str, ret_modes[i]))
791                                 break;
792 
793                 if (i == ARRAY_SIZE(ret_modes))
794                         errval_return(UBUS_STATUS_INVALID_ARGUMENT,
795                                       "Invalid return mode argument");
796 
797                 ret_mode = i;
798         }
799         else if (ucv_type(mret) == UC_BOOLEAN) {
800                 ret_mode = ucv_boolean_get(mret);
801         }
802         else if (ret_mode) {
803                 errval_return(UBUS_STATUS_INVALID_ARGUMENT,
804                               "Invalid return mode argument");
805         }
806 
807         blob_buf_init(&c->buf, 0);
808 
809         if (funargs)
810                 ucv_object_to_blob(funargs, &c->buf);
811 
812         if (fd) {
813                 fd_val = get_fd(vm, fd);
814 
815                 if (fd_val < 0)
816                         errval_return(UBUS_STATUS_INVALID_ARGUMENT,
817                                       "Invalid file descriptor argument");
818         }
819 
820         res->mret = (ret_mode == RET_MODE_MULTIPLE);
821 
822         rv = ubus_invoke_async_fd(&c->ctx, id, ucv_string_get(funname),
823                                   c->buf.head, &defer.request, fd_val);
824 
825         defer.vm = vm;
826         defer.ctx = &c->ctx;
827         defer.request.data_cb = uc_ubus_call_cb;
828         defer.request.priv = res;
829 
830         if (ucv_is_callable(fdcb)) {
831                 defer.request.fd_cb = uc_ubus_call_fd_cb;
832                 defer.registry_index = request_reg_add(vm, NULL, NULL, NULL, ucv_get(fdcb), NULL, NULL);
833         }
834 
835         if (rv == UBUS_STATUS_OK) {
836                 if (ret_mode == RET_MODE_IGNORE)
837                         ubus_abort_request(&c->ctx, &defer.request);
838                 else
839                         rv = ubus_complete_request(&c->ctx, &defer.request, c->timeout * 1000);
840         }
841 
842         if (defer.request.fd_cb)
843                 request_reg_clear(vm, defer.registry_index);
844 
845         return rv;
846 }
847 
848 static uc_value_t *
849 uc_ubus_call(uc_vm_t *vm, size_t nargs)
850 {
851         uc_value_t *obj, *funname, *funargs, *fd, *fdcb, *mret = NULL;
852         uc_ubus_call_res_t res = { 0 };
853         uc_ubus_connection_t *c;
854         enum ubus_msg_status rv;
855         uint32_t id;
856 
857         args_get_named(vm, nargs,
858                        "object", 0, REQUIRED, &obj,
859                        "method", UC_STRING, REQUIRED, &funname,
860                        "data", UC_OBJECT, OPTIONAL, &funargs,
861                        "return", 0, OPTIONAL, &mret,
862                        "fd", 0, NAMED, &fd,
863                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
864 
865         conn_get(vm, &c);
866 
867         if (ucv_type(obj) == UC_INTEGER) {
868                 id = ucv_int64_get(obj);
869         }
870         else if (ucv_type(obj) == UC_STRING) {
871                 rv = ubus_lookup_id(&c->ctx, ucv_string_get(obj), &id);
872 
873                 if (rv != UBUS_STATUS_OK)
874                         err_return(rv, "Failed to resolve object name '%s'",
875                                    ucv_string_get(obj));
876         }
877         else {
878                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
879                            "Argument object is not string or integer");
880         }
881 
882         rv = uc_ubus_call_common(vm, c, &res, id, funname, funargs, fd, fdcb, mret);
883 
884         if (rv != UBUS_STATUS_OK) {
885                 if (ucv_type(obj) == UC_STRING)
886                         err_return(rv, "Failed to invoke function '%s' on object '%s'",
887                                    ucv_string_get(funname), ucv_string_get(obj));
888                 else
889                         err_return(rv, "Failed to invoke function '%s' on system object %d",
890                                    ucv_string_get(funname), (int)ucv_int64_get(obj));
891         }
892 
893         ok_return(res.res);
894 }
895 
896 static uc_value_t *
897 uc_ubus_chan_request(uc_vm_t *vm, size_t nargs)
898 {
899         uc_value_t *funname, *funargs, *fd, *fdcb, *mret = NULL;
900         uc_ubus_call_res_t res = { 0 };
901         uc_ubus_connection_t *c;
902         enum ubus_msg_status rv;
903 
904         args_get_named(vm, nargs,
905                        "method", UC_STRING, REQUIRED, &funname,
906                        "data", UC_OBJECT, OPTIONAL, &funargs,
907                        "return", 0, OPTIONAL, &mret,
908                        "fd", 0, NAMED, &fd,
909                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
910 
911         conn_get(vm, &c);
912 
913         rv = uc_ubus_call_common(vm, c, &res, 0, funname, funargs, fd, fdcb, mret);
914 
915         if (rv != UBUS_STATUS_OK)
916                 err_return(rv, "Failed to send request '%s' on channel",
917                            ucv_string_get(funname));
918 
919         ok_return(res.res);
920 }
921 
922 static int
923 uc_ubus_defer_common(uc_vm_t *vm, uc_ubus_connection_t *c, uc_ubus_call_res_t *res,
924                      uint32_t id, uc_value_t *funname, uc_value_t *funargs,
925                      uc_value_t *fd, uc_value_t *fdcb, uc_value_t *replycb,
926                      uc_value_t *datacb)
927 {
928         uc_ubus_deferred_t *defer;
929         enum ubus_msg_status rv;
930         uc_callframe_t *frame;
931         uc_value_t *conn;
932         int fd_val = -1;
933 
934         blob_buf_init(&c->buf, 0);
935 
936         if (funargs)
937                 ucv_object_to_blob(funargs, &c->buf);
938 
939         if (fd) {
940                 fd_val = get_fd(vm, fd);
941 
942                 if (fd_val < 0)
943                         errval_return(UBUS_STATUS_INVALID_ARGUMENT,
944                                       "Invalid file descriptor argument");
945         }
946 
947         defer = xalloc(sizeof(*defer));
948 
949         rv = ubus_invoke_async_fd(&c->ctx, id, ucv_string_get(funname),
950                                   c->buf.head, &defer->request, fd_val);
951 
952         if (rv == UBUS_STATUS_OK) {
953                 defer->vm = vm;
954                 defer->ctx = &c->ctx;
955 
956                 if (ucv_is_callable(datacb))
957                         defer->request.data_cb = uc_ubus_call_data_user_cb;
958                 else
959                         defer->request.data_cb = uc_ubus_call_data_cb;
960 
961                 if (ucv_is_callable(fdcb))
962                         defer->request.fd_cb = uc_ubus_call_fd_cb;
963 
964                 defer->request.complete_cb = uc_ubus_call_done_cb;
965 
966                 ubus_complete_request_async(&c->ctx, &defer->request);
967 
968                 defer->timeout.cb = uc_ubus_call_timeout_cb;
969                 uloop_timeout_set(&defer->timeout, c->timeout * 1000);
970 
971                 res->res = uc_resource_new(defer_type, defer);
972                 frame = uc_vector_last(&vm->callframes);
973                 conn = frame ? frame->ctx : NULL;
974 
975                 defer->registry_index = request_reg_add(vm, ucv_get(res->res), ucv_get(replycb), ucv_get(datacb),
976                                                         ucv_get(fdcb), ucv_get(conn), ucv_get(fd));
977         }
978         else {
979                 uc_vm_stack_push(vm, ucv_get(replycb));
980                 uc_vm_stack_push(vm, ucv_int64_new(rv));
981 
982                 if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE)
983                         ucv_put(uc_vm_stack_pop(vm));
984                 else
985                         uloop_end();
986 
987                 free(defer);
988         }
989 
990         return rv;
991 }
992 
993 static uc_value_t *
994 uc_ubus_defer(uc_vm_t *vm, size_t nargs)
995 {
996         uc_value_t *objname, *funname, *funargs, *replycb, *datacb, *fd, *fdcb = NULL;
997         uc_ubus_call_res_t res = { 0 };
998         uc_ubus_connection_t *c;
999         uint32_t id;
1000         int rv;
1001 
1002         conn_get(vm, &c);
1003 
1004         args_get_named(vm, nargs,
1005                        "object", UC_STRING, REQUIRED, &objname,
1006                        "method", UC_STRING, REQUIRED, &funname,
1007                        "data", UC_OBJECT, OPTIONAL, &funargs,
1008                        "cb", UC_CLOSURE, OPTIONAL, &replycb,
1009                        "data_cb", UC_CLOSURE, OPTIONAL, &datacb,
1010                        "fd", 0, NAMED, &fd,
1011                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
1012 
1013         rv = ubus_lookup_id(&c->ctx, ucv_string_get(objname), &id);
1014 
1015         if (rv != UBUS_STATUS_OK)
1016                 err_return(rv, "Failed to resolve object name '%s'",
1017                            ucv_string_get(objname));
1018 
1019         rv = uc_ubus_defer_common(vm, c, &res, id, funname, funargs, fd, fdcb, replycb, datacb);
1020 
1021         if (rv != UBUS_STATUS_OK)
1022                 err_return(rv, "Failed to invoke function '%s' on object '%s'",
1023                            ucv_string_get(funname), ucv_string_get(objname));
1024 
1025         ok_return(res.res);
1026 }
1027 
1028 static uc_value_t *
1029 uc_ubus_chan_defer(uc_vm_t *vm, size_t nargs)
1030 {
1031         uc_value_t *funname, *funargs, *replycb, *datacb, *fd, *fdcb = NULL;
1032         uc_ubus_call_res_t res = { 0 };
1033         uc_ubus_connection_t *c;
1034         int rv;
1035 
1036         conn_get(vm, &c);
1037 
1038         args_get_named(vm, nargs,
1039                        "method", UC_STRING, REQUIRED, &funname,
1040                        "data", UC_OBJECT, OPTIONAL, &funargs,
1041                        "cb", UC_CLOSURE, OPTIONAL, &replycb,
1042                        "data_cb", UC_CLOSURE, OPTIONAL, &datacb,
1043                        "fd", 0, NAMED, &fd,
1044                        "fd_cb", UC_CLOSURE, NAMED, &fdcb);
1045 
1046         rv = uc_ubus_defer_common(vm, c, &res, 0, funname, funargs, fd, fdcb, replycb, datacb);
1047 
1048         if (rv != UBUS_STATUS_OK)
1049                 err_return(rv, "Failed to invoke function '%s' on channel",
1050                            ucv_string_get(funname));
1051 
1052         ok_return(res.res);
1053 }
1054 
1055 
1056 /*
1057  * ubus object request context functions
1058  * --------------------------------------------------------------------------
1059  */
1060 
1061 static void
1062 uc_ubus_request_finish_common(uc_ubus_request_t *callctx, int code)
1063 {
1064         int fd;
1065 
1066         fd = ubus_request_get_caller_fd(&callctx->req);
1067 
1068         if (fd >= 0)
1069                 close(fd);
1070 
1071         callctx->replied = true;
1072         ubus_complete_deferred_request(callctx->ctx, &callctx->req, code);
1073 }
1074 
1075 static void
1076 uc_ubus_request_send_reply(uc_ubus_request_t *callctx, uc_value_t *reply)
1077 {
1078         if (!reply)
1079                 return;
1080 
1081         blob_buf_init(&buf, 0);
1082         ucv_object_to_blob(reply, &buf);
1083         ubus_send_reply(callctx->ctx, &callctx->req, buf.head);
1084 }
1085 
1086 static void
1087 uc_ubus_request_finish(uc_ubus_request_t *callctx, int code)
1088 {
1089         if (callctx->replied)
1090                 return;
1091 
1092         uc_ubus_request_finish_common(callctx, code);
1093         request_reg_clear(callctx->vm, callctx->registry_index);
1094 }
1095 
1096 static void
1097 uc_ubus_request_timeout(struct uloop_timeout *timeout)
1098 {
1099         uc_ubus_request_t *callctx = container_of(timeout, uc_ubus_request_t, timeout);
1100 
1101         uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT);
1102 }
1103 
1104 static uc_value_t *
1105 uc_ubus_request_reply(uc_vm_t *vm, size_t nargs)
1106 {
1107         uc_ubus_request_t **callctx = uc_fn_this("ubus.request");
1108         int64_t code = UBUS_STATUS_OK;
1109         uc_value_t *reply, *rcode;
1110         bool more = false;
1111 
1112         if (!callctx || !*callctx)
1113                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
1114 
1115         args_get(vm, nargs,
1116                  "reply", UC_OBJECT, true, &reply,
1117                  "rcode", UC_INTEGER, true, &rcode);
1118 
1119         if ((*callctx)->replied)
1120                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
1121 
1122         if (rcode) {
1123                 code = ucv_int64_get(rcode);
1124 
1125                 if (errno == ERANGE || code < -1 || code > __UBUS_STATUS_LAST)
1126                         code = UBUS_STATUS_UNKNOWN_ERROR;
1127 
1128                 if (code < 0)
1129                         more = true;
1130         }
1131 
1132         uc_ubus_request_send_reply(*callctx, reply);
1133 
1134         if (!more)
1135                 uc_ubus_request_finish(*callctx, code);
1136 
1137         ok_return(ucv_boolean_new(true));
1138 }
1139 
1140 static uc_value_t *
1141 uc_ubus_request_defer(uc_vm_t *vm, size_t nargs)
1142 {
1143         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1144 
1145         if (!callctx)
1146                 return NULL;
1147 
1148         callctx->deferred = true;
1149         return ucv_boolean_new(true);
1150 }
1151 
1152 static uc_value_t *
1153 uc_ubus_request_get_fd(uc_vm_t *vm, size_t nargs)
1154 {
1155         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1156 
1157         if (!callctx)
1158                 return NULL;
1159 
1160         return ucv_int64_new(ubus_request_get_caller_fd(&callctx->req));
1161 }
1162 
1163 static uc_value_t *
1164 uc_ubus_request_set_fd(uc_vm_t *vm, size_t nargs)
1165 {
1166         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
1167         int fd;
1168 
1169         if (!callctx)
1170                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
1171 
1172         fd = get_fd(vm, uc_fn_arg(0));
1173 
1174         if (fd < 0)
1175                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor");
1176 
1177         ubus_request_set_fd(callctx->ctx, &callctx->req, fd);
1178 
1179         return ucv_boolean_new(true);
1180 }
1181 
1182 static uc_value_t *
1183 uc_ubus_request_error(uc_vm_t *vm, size_t nargs)
1184 {
1185         uc_ubus_request_t **callctx = uc_fn_this("ubus.request");
1186         uc_value_t *rcode = uc_fn_arg(0);
1187         int64_t code;
1188 
1189         if (!callctx || !*callctx)
1190                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
1191 
1192         args_get(vm, nargs,
1193                  "rcode", UC_INTEGER, false, &rcode);
1194 
1195         if ((*callctx)->replied)
1196                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
1197 
1198         code = ucv_int64_get(rcode);
1199 
1200         if (errno == ERANGE || code < 0 || code > __UBUS_STATUS_LAST)
1201                 code = UBUS_STATUS_UNKNOWN_ERROR;
1202 
1203         uc_ubus_request_finish(*callctx, code);
1204 
1205         ok_return(ucv_boolean_new(true));
1206 }
1207 
1208 
1209 /*
1210  * ubus object notify
1211  * --------------------------------------------------------------------------
1212  */
1213 
1214 static uc_value_t *
1215 uc_ubus_notify_completed(uc_vm_t *vm, size_t nargs)
1216 {
1217         uc_ubus_notify_t **notifyctx = uc_fn_this("ubus.notify");
1218 
1219         if (!notifyctx || !*notifyctx)
1220                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid notify context");
1221 
1222         ok_return(ucv_boolean_new((*notifyctx)->complete));
1223 }
1224 
1225 static uc_value_t *
1226 uc_ubus_notify_abort(uc_vm_t *vm, size_t nargs)
1227 {
1228         uc_ubus_notify_t **notifyctx = uc_fn_this("ubus.notify");
1229 
1230         if (!notifyctx || !*notifyctx)
1231                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid notify context");
1232 
1233         if ((*notifyctx)->complete)
1234                 ok_return(ucv_boolean_new(false));
1235 
1236         ubus_abort_request((*notifyctx)->ctx, &(*notifyctx)->req.req);
1237         (*notifyctx)->complete = true;
1238 
1239         ok_return(ucv_boolean_new(true));
1240 }
1241 
1242 static void
1243 uc_ubus_object_notify_data_cb(struct ubus_notify_request *req, int type, struct blob_attr *msg)
1244 {
1245         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
1246         uc_value_t *this, *func;
1247 
1248         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, &func, NULL, NULL);
1249 
1250         if (ucv_is_callable(func)) {
1251                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
1252                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
1253                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(type));
1254                 uc_vm_stack_push(notifyctx->vm, blob_array_to_ucv(notifyctx->vm, blob_data(msg), blob_len(msg), true));
1255 
1256                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
1257                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
1258                 else
1259                         uloop_end();
1260         }
1261 }
1262 
1263 static void
1264 uc_ubus_object_notify_status_cb(struct ubus_notify_request *req, int idx, int ret)
1265 {
1266         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
1267         uc_value_t *this, *func;
1268 
1269         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, NULL, &func, NULL);
1270 
1271         if (ucv_is_callable(func)) {
1272                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
1273                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
1274                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(idx));
1275                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(ret));
1276 
1277                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
1278                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
1279                 else
1280                         uloop_end();
1281         }
1282 }
1283 
1284 static void
1285 uc_ubus_object_notify_complete_cb(struct ubus_notify_request *req, int idx, int ret)
1286 {
1287         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
1288         uc_value_t *this, *func;
1289 
1290         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, NULL, NULL, &func);
1291 
1292         if (ucv_is_callable(func)) {
1293                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
1294                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
1295                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(idx));
1296                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(ret));
1297 
1298                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
1299                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
1300                 else
1301                         uloop_end();
1302         }
1303 
1304         notifyctx->complete = true;
1305 
1306         notify_reg_clear(notifyctx->vm, notifyctx->registry_index);
1307 }
1308 
1309 static uc_value_t *
1310 uc_ubus_object_notify(uc_vm_t *vm, size_t nargs)
1311 {
1312         uc_value_t *typename, *message, *data_cb, *status_cb, *complete_cb, *timeout;
1313         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1314         uc_ubus_notify_t *notifyctx;
1315         uc_value_t *res;
1316         int64_t t;
1317         int rv;
1318 
1319         if (!uuobj || !*uuobj)
1320                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1321 
1322         args_get_named(vm, nargs,
1323                       "type", UC_STRING, REQUIRED, &typename,
1324                       "data", UC_OBJECT, OPTIONAL, &message,
1325                       "data_cb", UC_CLOSURE, OPTIONAL, &data_cb,
1326                       "status_cb", UC_CLOSURE, OPTIONAL, &status_cb,
1327                       "cb", UC_CLOSURE, OPTIONAL, &complete_cb,
1328                       "timeout", UC_INTEGER, OPTIONAL, &timeout);
1329 
1330         t = timeout ? ucv_int64_get(timeout) : -1;
1331 
1332         if (errno)
1333                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
1334                            "Invalid timeout value: %s", strerror(errno));
1335 
1336         notifyctx = xalloc(sizeof(*notifyctx));
1337         notifyctx->vm = vm;
1338         notifyctx->ctx = (*uuobj)->ctx;
1339 
1340         blob_buf_init(&buf, 0);
1341 
1342         if (message)
1343                 ucv_object_to_blob(message, &buf);
1344 
1345         rv = ubus_notify_async((*uuobj)->ctx, &(*uuobj)->obj,
1346                                ucv_string_get(typename), buf.head,
1347                                &notifyctx->req);
1348 
1349         if (rv != UBUS_STATUS_OK) {
1350                 free(notifyctx);
1351                 err_return(rv, "Failed to send notification");
1352         }
1353 
1354         notifyctx->req.data_cb = uc_ubus_object_notify_data_cb;
1355         notifyctx->req.status_cb = uc_ubus_object_notify_status_cb;
1356         notifyctx->req.complete_cb = uc_ubus_object_notify_complete_cb;
1357 
1358         res = uc_resource_new(notify_type, notifyctx);
1359 
1360         notifyctx->registry_index = notify_reg_add(vm,
1361                 ucv_get(res), ucv_get(data_cb), ucv_get(status_cb), ucv_get(complete_cb));
1362 
1363         if (t >= 0) {
1364                 rv = ubus_complete_request((*uuobj)->ctx, &notifyctx->req.req, t);
1365 
1366                 notify_reg_clear(vm, notifyctx->registry_index);
1367 
1368                 ucv_put(res);
1369 
1370                 ok_return(ucv_int64_new(rv));
1371         }
1372 
1373         ubus_complete_request_async((*uuobj)->ctx, &notifyctx->req.req);
1374 
1375         ok_return(res);
1376 }
1377 
1378 
1379 /*
1380  * ubus object remove
1381  * --------------------------------------------------------------------------
1382  */
1383 
1384 static int
1385 uc_ubus_object_remove_common(uc_ubus_object_t *uuobj)
1386 {
1387         int rv = ubus_remove_object(uuobj->ctx, &uuobj->obj);
1388 
1389         if (rv == UBUS_STATUS_OK)
1390                 object_reg_clear(uuobj->vm, uuobj->registry_index);
1391 
1392         return rv;
1393 }
1394 
1395 static uc_value_t *
1396 uc_ubus_object_remove(uc_vm_t *vm, size_t nargs)
1397 {
1398         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1399         int rv;
1400 
1401         if (!uuobj || !*uuobj)
1402                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1403 
1404         rv = uc_ubus_object_remove_common(*uuobj);
1405 
1406         if (rv != UBUS_STATUS_OK)
1407                 err_return(rv, "Failed to remove object");
1408 
1409         ok_return(ucv_boolean_new(true));
1410 }
1411 
1412 
1413 /*
1414  * ubus object subscription status
1415  */
1416 
1417 static uc_value_t *
1418 uc_ubus_object_subscribed(uc_vm_t *vm, size_t nargs)
1419 {
1420         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1421 
1422         if (!uuobj || !*uuobj)
1423                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1424 
1425         ok_return(ucv_boolean_new((*uuobj)->obj.has_subscribers));
1426 }
1427 
1428 
1429 /*
1430  * ubus object method call handling
1431  * --------------------------------------------------------------------------
1432  */
1433 
1434 static int
1435 uc_ubus_object_call_args(struct ubus_object *obj, const char *ubus_method_name,
1436                          struct blob_attr *msg, uc_value_t **res)
1437 {
1438         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1439         const struct ubus_method *method = NULL;
1440         const struct blobmsg_hdr *hdr;
1441         struct blob_attr *attr;
1442         size_t len;
1443         bool found;
1444         int i;
1445 
1446         for (i = 0; i < obj->n_methods; i++) {
1447                 if (!strcmp(obj->methods[i].name, ubus_method_name)) {
1448                         method = &obj->methods[i];
1449                         break;
1450                 }
1451         }
1452 
1453         if (!method)
1454                 return UBUS_STATUS_METHOD_NOT_FOUND;
1455 
1456         len = blob_len(msg);
1457 
1458         __blob_for_each_attr(attr, blob_data(msg), len) {
1459                 if (!blobmsg_check_attr_len(attr, false, len))
1460                         return UBUS_STATUS_INVALID_ARGUMENT;
1461 
1462                 if (!blob_is_extended(attr))
1463                         return UBUS_STATUS_INVALID_ARGUMENT;
1464 
1465                 hdr = blob_data(attr);
1466                 found = false;
1467 
1468                 for (i = 0; i < method->n_policy; i++) {
1469                         if (blobmsg_namelen(hdr) != strlen(method->policy[i].name))
1470                                 continue;
1471 
1472                         if (strcmp(method->policy[i].name, (char *)hdr->name))
1473                                 continue;
1474 
1475                         /* named argument found but wrong type */
1476                         if (blob_id(attr) != method->policy[i].type)
1477                                 goto inval;
1478 
1479                         found = true;
1480                         break;
1481                 }
1482 
1483                 /* named argument not found in policy */
1484                 if (!found)
1485                         goto inval;
1486         }
1487 
1488         *res = blob_array_to_ucv(uuobj->vm, blob_data(msg), blob_len(msg), true);
1489 
1490         return UBUS_STATUS_OK;
1491 
1492 inval:
1493         *res = NULL;
1494 
1495         return UBUS_STATUS_INVALID_ARGUMENT;
1496 }
1497 
1498 static uc_value_t *
1499 uc_ubus_object_call_info(uc_vm_t *vm,
1500                          struct ubus_context *ctx, struct ubus_request_data *req,
1501                          struct ubus_object *obj, const char *ubus_method_name)
1502 {
1503         uc_value_t *info, *o;
1504 
1505         info = ucv_object_new(vm);
1506 
1507         o = ucv_object_new(vm);
1508 
1509         ucv_object_add(o, "user", ucv_string_new(req->acl.user));
1510         ucv_object_add(o, "group", ucv_string_new(req->acl.group));
1511 
1512         if (req->acl.object)
1513                 ucv_object_add(o, "object", ucv_string_new(req->acl.object));
1514 
1515         ucv_object_add(info, "acl", o);
1516 
1517         o = ucv_object_new(vm);
1518 
1519         ucv_object_add(o, "id", ucv_int64_new(obj->id));
1520 
1521         if (obj->name)
1522                 ucv_object_add(o, "name", ucv_string_new(obj->name));
1523 
1524         if (obj->path)
1525                 ucv_object_add(o, "path", ucv_string_new(obj->path));
1526 
1527         ucv_object_add(info, "object", o);
1528 
1529         if (ubus_method_name)
1530                 ucv_object_add(info, "method", ucv_string_new(ubus_method_name));
1531 
1532         return info;
1533 }
1534 
1535 static int
1536 uc_ubus_handle_reply_common(struct ubus_context *ctx,
1537                               struct ubus_request_data *req,
1538                               uc_vm_t *vm, uc_value_t *this, uc_value_t *func,
1539                               uc_value_t *reqproto)
1540 {
1541         uc_ubus_request_t *callctx;
1542         uc_value_t *reqobj, *res;
1543         int rv;
1544 
1545         /* allocate deferred method call context */
1546         callctx = xalloc(sizeof(*callctx));
1547         callctx->ctx = ctx;
1548         callctx->vm = vm;
1549 
1550         ubus_defer_request(ctx, req, &callctx->req);
1551 
1552         /* fd is copied to deferred request. ensure it does not get closed early */
1553         ubus_request_get_caller_fd(req);
1554 
1555         /* create ucode request type object and set properties */
1556         reqobj = uc_resource_new(request_type, callctx);
1557 
1558         if (reqproto)
1559                 ucv_prototype_set(ucv_prototype_get(reqobj), reqproto);
1560 
1561         /* push object context, handler and request object onto stack */
1562         uc_vm_stack_push(vm, ucv_get(this));
1563         uc_vm_stack_push(vm, ucv_get(func));
1564         uc_vm_stack_push(vm, ucv_get(reqobj));
1565 
1566         /* execute request handler function */
1567         switch (uc_vm_call(vm, true, 1)) {
1568         case EXCEPTION_NONE:
1569                 res = uc_vm_stack_pop(vm);
1570 
1571                 /* The handler function invoked a nested aync ubus request and returned it */
1572                 if (ucv_resource_dataptr(res, "ubus.deferred")) {
1573                         /* Install guard timer in case the reply callback is never called */
1574                         callctx->timeout.cb = uc_ubus_request_timeout;
1575                         uloop_timeout_set(&callctx->timeout, 10000 /* FIXME */);
1576 
1577                         /* Add wrapped request context into registry to prevent GC'ing
1578                          * until reply or timeout occurred */
1579                         callctx->registry_index = request_reg_add(vm, ucv_get(reqobj), NULL, NULL, NULL, NULL, NULL);
1580                 }
1581 
1582                 /* Otherwise, when the function returned an object, treat it as
1583                 * reply data and conclude deferred request immediately */
1584                 else if (ucv_type(res) == UC_OBJECT) {
1585                         blob_buf_init(&buf, 0);
1586                         ucv_object_to_blob(res, &buf);
1587                         ubus_send_reply(ctx, &callctx->req, buf.head);
1588 
1589                         uc_ubus_request_finish_common(callctx, UBUS_STATUS_OK);
1590                 }
1591 
1592                 /* If neither a deferred ubus request, nor a plain object were
1593                  * returned and if reqobj.reply() hasn't been called, immediately
1594                  * finish deferred request with UBUS_STATUS_NO_DATA. */
1595                 else if (!callctx->replied && !callctx->deferred) {
1596                         rv = UBUS_STATUS_NO_DATA;
1597 
1598                         if (ucv_type(res) == UC_INTEGER) {
1599                                 rv = (int)ucv_int64_get(res);
1600 
1601                                 if (rv < 0 || rv > __UBUS_STATUS_LAST)
1602                                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1603                         }
1604 
1605                         uc_ubus_request_finish_common(callctx, rv);
1606                 }
1607 
1608                 ucv_put(res);
1609                 break;
1610 
1611         /* if the handler function invoked exit(), forward exit status as ubus
1612          * return code, map out of range values to UBUS_STATUS_UNKNOWN_ERROR. */
1613         case EXCEPTION_EXIT:
1614                 rv = vm->arg.s32;
1615 
1616                 if (rv < UBUS_STATUS_OK || rv >= __UBUS_STATUS_LAST)
1617                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1618 
1619                 uc_ubus_request_finish_common(callctx, rv);
1620                 break;
1621 
1622         /* treat other exceptions as fatal and halt uloop */
1623         default:
1624                 uc_ubus_request_finish_common(callctx, UBUS_STATUS_UNKNOWN_ERROR);
1625                 uloop_end();
1626                 break;
1627         }
1628 
1629         /* release request object */
1630         ucv_put(reqobj);
1631 
1632         /* garbage collect */
1633         ucv_gc(vm);
1634 
1635         return UBUS_STATUS_OK;
1636 }
1637 
1638 static int
1639 uc_ubus_object_call_cb(struct ubus_context *ctx, struct ubus_object *obj,
1640                        struct ubus_request_data *req, const char *ubus_method_name,
1641                        struct blob_attr *msg)
1642 {
1643         uc_value_t *this, *func, *args = NULL, *reqproto, *methods;
1644         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1645         int rv;
1646 
1647         object_reg_get(uuobj->vm, uuobj->registry_index, &this, &methods, NULL);
1648 
1649         func = ucv_object_get(ucv_object_get(methods, ubus_method_name, NULL), "call", NULL);
1650 
1651         if (!ucv_is_callable(func))
1652                 return UBUS_STATUS_METHOD_NOT_FOUND;
1653 
1654         rv = uc_ubus_object_call_args(obj, ubus_method_name, msg, &args);
1655 
1656         if (rv != UBUS_STATUS_OK)
1657                 return rv;
1658 
1659         reqproto = ucv_object_new(uuobj->vm);
1660 
1661         ucv_object_add(reqproto, "args", args);
1662         ucv_object_add(reqproto, "info",
1663                 uc_ubus_object_call_info(uuobj->vm, ctx, req, obj, ubus_method_name));
1664 
1665         return uc_ubus_handle_reply_common(ctx, req, uuobj->vm, this, func, reqproto);
1666 }
1667 
1668 
1669 /*
1670  * ubus object registration
1671  * --------------------------------------------------------------------------
1672  */
1673 
1674 static void
1675 uc_ubus_object_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
1676 {
1677         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1678         uc_value_t *this, *func;
1679 
1680         object_reg_get(uuobj->vm, uuobj->registry_index, &this, NULL, &func);
1681 
1682         uc_vm_stack_push(uuobj->vm, ucv_get(this));
1683         uc_vm_stack_push(uuobj->vm, ucv_get(func));
1684 
1685         if (uc_vm_call(uuobj->vm, true, 0) == EXCEPTION_NONE)
1686                 ucv_put(uc_vm_stack_pop(uuobj->vm));
1687         else
1688                 uloop_end();
1689 }
1690 
1691 static bool
1692 uc_ubus_object_methods_validate(uc_value_t *methods)
1693 {
1694         uc_value_t *func, *args;
1695 
1696         ucv_object_foreach(methods, ubus_method_name, ubus_method_definition) {
1697                 (void)ubus_method_name;
1698 
1699                 func = ucv_object_get(ubus_method_definition, "call", NULL);
1700                 args = ucv_object_get(ubus_method_definition, "args", NULL);
1701 
1702                 if (!ucv_is_callable(func))
1703                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1704                                    "Method '%s' field 'call' is not a function value",
1705                                    ubus_method_name);
1706 
1707                 if (args) {
1708                         if (ucv_type(args) != UC_OBJECT)
1709                                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
1710                                            "Method '%s' field 'args' is not an object value",
1711                                            ubus_method_name);
1712 
1713                         ucv_object_foreach(args, ubus_argument_name, ubus_argument_typehint) {
1714                                 (void)ubus_argument_name;
1715 
1716                                 switch (ucv_type(ubus_argument_typehint)) {
1717                                 case UC_BOOLEAN:
1718                                 case UC_INTEGER:
1719                                 case UC_DOUBLE:
1720                                 case UC_STRING:
1721                                 case UC_ARRAY:
1722                                 case UC_OBJECT:
1723                                         continue;
1724 
1725                                 default:
1726                                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1727                                                    "Method '%s' field 'args' argument '%s' hint has unsupported type %s",
1728                                                    ubus_method_name, ubus_argument_name,
1729                                                    ucv_typename(ubus_argument_typehint));
1730                                 }
1731                         }
1732                 }
1733         }
1734 
1735         ok_return(true);
1736 }
1737 
1738 static bool
1739 uc_ubus_object_method_register(struct ubus_method *method, const char *ubus_method_name,
1740                                uc_value_t *ubus_method_arguments)
1741 {
1742         struct blobmsg_policy *policy;
1743         enum blobmsg_type type;
1744 
1745         method->name = strdup(ubus_method_name);
1746         method->policy = calloc(ucv_object_length(ubus_method_arguments), sizeof(*method->policy));
1747         method->handler = uc_ubus_object_call_cb;
1748 
1749         if (!method->name || !method->policy)
1750                 return false;
1751 
1752         ucv_object_foreach(ubus_method_arguments, ubus_argument_name, ubus_argument_typehint) {
1753                 switch (ucv_type(ubus_argument_typehint)) {
1754                 case UC_BOOLEAN:
1755                         type = BLOBMSG_TYPE_INT8;
1756                         break;
1757 
1758                 case UC_INTEGER:
1759                         switch (ucv_int64_get(ubus_argument_typehint)) {
1760                         case 8:
1761                                 type = BLOBMSG_TYPE_INT8;
1762                                 break;
1763 
1764                         case 16:
1765                                 type = BLOBMSG_TYPE_INT16;
1766                                 break;
1767 
1768                         case 64:
1769                                 type = BLOBMSG_TYPE_INT64;
1770                                 break;
1771 
1772                         default:
1773                                 type = BLOBMSG_TYPE_INT32;
1774                                 break;
1775                         }
1776 
1777                         break;
1778 
1779                 case UC_DOUBLE:
1780                         type = BLOBMSG_TYPE_DOUBLE;
1781                         break;
1782 
1783                 case UC_ARRAY:
1784                         type = BLOBMSG_TYPE_ARRAY;
1785                         break;
1786 
1787                 case UC_OBJECT:
1788                         type = BLOBMSG_TYPE_TABLE;
1789                         break;
1790 
1791                 default:
1792                         type = BLOBMSG_TYPE_STRING;
1793                         break;
1794                 }
1795 
1796                 policy = (struct blobmsg_policy *)&method->policy[method->n_policy++];
1797                 policy->type = type;
1798                 policy->name = strdup(ubus_argument_name);
1799 
1800                 if (!policy->name)
1801                         return false;
1802         }
1803 
1804         return true;
1805 }
1806 
1807 static uc_ubus_object_t *
1808 uc_ubus_object_register(struct ubus_context *ctx, const char *ubus_object_name,
1809                         uc_value_t *ubus_object_methods)
1810 {
1811         const struct blobmsg_policy *policy;
1812         uc_ubus_object_t *uuobj = NULL;
1813         int rv = UBUS_STATUS_UNKNOWN_ERROR;
1814         char *tptr, *tnptr, *onptr, *mptr;
1815         struct ubus_method *method;
1816         struct ubus_object *obj;
1817         size_t typelen, namelen;
1818         uc_value_t *args;
1819 
1820         namelen = strlen(ubus_object_name);
1821         typelen = strlen("ucode-ubus-") + namelen;
1822 
1823         uuobj = calloc_a(sizeof(*uuobj),
1824                          &onptr, namelen + 1,
1825                          &mptr, ucv_object_length(ubus_object_methods) * sizeof(struct ubus_method),
1826                          &tptr, sizeof(struct ubus_object_type),
1827                          &tnptr, typelen + 1);
1828 
1829         if (!uuobj)
1830                 err_return(rv, "Out of memory");
1831 
1832         snprintf(tnptr, typelen, "ucode-ubus-%s", ubus_object_name);
1833 
1834         method = (struct ubus_method *)mptr;
1835 
1836         obj = &uuobj->obj;
1837         obj->name = memcpy(onptr, ubus_object_name, namelen);
1838         obj->methods = method;
1839 
1840         if (ubus_object_methods) {
1841                 ucv_object_foreach(ubus_object_methods, ubus_method_name, ubus_method_definition) {
1842                         args = ucv_object_get(ubus_method_definition, "args", NULL);
1843 
1844                         if (!uc_ubus_object_method_register(&method[obj->n_methods++], ubus_method_name, args))
1845                                 goto out;
1846                 }
1847         }
1848 
1849         obj->type = (struct ubus_object_type *)tptr;
1850         obj->type->name = tnptr;
1851         obj->type->methods = obj->methods;
1852         obj->type->n_methods = obj->n_methods;
1853 
1854         rv = ubus_add_object(ctx, obj);
1855 
1856         if (rv == UBUS_STATUS_OK)
1857                 return uuobj;
1858 
1859 out:
1860         for (; obj->n_methods > 0; method++, obj->n_methods--) {
1861                 for (policy = method->policy; method->n_policy > 0; policy++, method->n_policy--)
1862                         free((char *)policy->name);
1863 
1864                 free((char *)method->name);
1865                 free((char *)method->policy);
1866         }
1867 
1868         free(uuobj);
1869 
1870         err_return(rv, "Unable to add ubus object");
1871 }
1872 
1873 static uc_value_t *
1874 uc_ubus_publish(uc_vm_t *vm, size_t nargs)
1875 {
1876         uc_value_t *objname, *methods, *subscribecb;
1877         uc_ubus_connection_t *c;
1878         uc_ubus_object_t *uuobj;
1879         uc_value_t *res;
1880 
1881         conn_get(vm, &c);
1882 
1883         args_get(vm, nargs,
1884                  "object name", UC_STRING, false, &objname,
1885                  "object methods", UC_OBJECT, true, &methods,
1886                  "subscribe callback", UC_CLOSURE, true, &subscribecb);
1887 
1888         if (!methods && !subscribecb)
1889                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either methods or subscribe callback required");
1890 
1891         if (methods && !uc_ubus_object_methods_validate(methods))
1892                 return NULL;
1893 
1894         uuobj = uc_ubus_object_register(&c->ctx, ucv_string_get(objname), methods);
1895 
1896         if (!uuobj)
1897                 return NULL;
1898 
1899         if (subscribecb)
1900                 uuobj->obj.subscribe_cb = uc_ubus_object_subscribe_cb;
1901 
1902         res = uc_resource_new(object_type, uuobj);
1903 
1904         uuobj->vm = vm;
1905         uuobj->ctx = &c->ctx;
1906         uuobj->registry_index = object_reg_add(vm, ucv_get(res), ucv_get(methods), ucv_get(subscribecb));
1907 
1908         ok_return(res);
1909 }
1910 
1911 
1912 /*
1913  * ubus events
1914  * --------------------------------------------------------------------------
1915  */
1916 
1917 static int
1918 uc_ubus_listener_remove_common(uc_ubus_listener_t *uul)
1919 {
1920         int rv = ubus_unregister_event_handler(uul->ctx, &uul->ev);
1921 
1922         if (rv == UBUS_STATUS_OK)
1923                 listener_reg_clear(uul->vm, uul->registry_index);
1924 
1925         return rv;
1926 }
1927 
1928 static uc_value_t *
1929 uc_ubus_listener_remove(uc_vm_t *vm, size_t nargs)
1930 {
1931         uc_ubus_listener_t **uul = uc_fn_this("ubus.listener");
1932         int rv;
1933 
1934         if (!uul || !*uul)
1935                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid listener context");
1936 
1937         rv = uc_ubus_listener_remove_common(*uul);
1938 
1939         if (rv != UBUS_STATUS_OK)
1940                 err_return(rv, "Failed to remove listener object");
1941 
1942         ok_return(ucv_boolean_new(true));
1943 }
1944 
1945 static void
1946 uc_ubus_listener_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
1947                     const char *type, struct blob_attr *msg)
1948 {
1949         uc_ubus_listener_t *uul = (uc_ubus_listener_t *)ev;
1950         uc_value_t *this, *func;
1951 
1952         listener_reg_get(uul->vm, uul->registry_index, &this, &func);
1953 
1954         uc_vm_stack_push(uul->vm, ucv_get(this));
1955         uc_vm_stack_push(uul->vm, ucv_get(func));
1956         uc_vm_stack_push(uul->vm, ucv_string_new(type));
1957         uc_vm_stack_push(uul->vm, blob_array_to_ucv(uul->vm, blob_data(msg), blob_len(msg), true));
1958 
1959         if (uc_vm_call(uul->vm, true, 2) == EXCEPTION_NONE)
1960                 ucv_put(uc_vm_stack_pop(uul->vm));
1961         else
1962                 uloop_end();
1963 }
1964 
1965 static uc_value_t *
1966 uc_ubus_listener(uc_vm_t *vm, size_t nargs)
1967 {
1968         uc_value_t *cb, *pattern;
1969         uc_ubus_connection_t *c;
1970         uc_ubus_listener_t *uul;
1971         uc_value_t *res;
1972         int rv;
1973 
1974         conn_get(vm, &c);
1975 
1976         args_get(vm, nargs,
1977                  "event type pattern", UC_STRING, false, &pattern,
1978                  "event callback", UC_CLOSURE, false, &cb);
1979 
1980         uul = xalloc(sizeof(*uul));
1981         uul->vm = vm;
1982         uul->ctx = &c->ctx;
1983         uul->ev.cb = uc_ubus_listener_cb;
1984 
1985         rv = ubus_register_event_handler(&c->ctx, &uul->ev,
1986                                          ucv_string_get(pattern));
1987 
1988         if (rv != UBUS_STATUS_OK) {
1989                 free(uul);
1990                 err_return(rv, "Failed to register listener object");
1991         }
1992 
1993         res = uc_resource_new(listener_type, uul);
1994 
1995         uul->registry_index = listener_reg_add(vm, ucv_get(res), ucv_get(cb));
1996 
1997         ok_return(res);
1998 }
1999 
2000 static uc_value_t *
2001 uc_ubus_event(uc_vm_t *vm, size_t nargs)
2002 {
2003         uc_value_t *eventtype, *eventdata;
2004         uc_ubus_connection_t *c;
2005         int rv;
2006 
2007         conn_get(vm, &c);
2008 
2009         args_get(vm, nargs,
2010                  "event id", UC_STRING, false, &eventtype,
2011                  "event data", UC_OBJECT, true, &eventdata);
2012 
2013         blob_buf_init(&buf, 0);
2014 
2015         if (eventdata)
2016                 ucv_object_to_blob(eventdata, &buf);
2017 
2018         rv = ubus_send_event(&c->ctx, ucv_string_get(eventtype), buf.head);
2019 
2020         if (rv != UBUS_STATUS_OK)
2021                 err_return(rv, "Unable to send event");
2022 
2023         ok_return(ucv_boolean_new(true));
2024 }
2025 
2026 
2027 /*
2028  * ubus subscriptions
2029  * --------------------------------------------------------------------------
2030  */
2031 
2032 static int
2033 uc_ubus_subscriber_notify_cb(struct ubus_context *ctx, struct ubus_object *obj,
2034                                  struct ubus_request_data *req, const char *method,
2035                                  struct blob_attr *msg)
2036 {
2037         struct ubus_subscriber *sub = container_of(obj, struct ubus_subscriber, obj);
2038         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
2039         uc_value_t *this, *func, *reqproto;
2040 
2041         subscriber_reg_get(uusub->vm, uusub->registry_index, &this, &func, NULL);
2042 
2043         if (!ucv_is_callable(func))
2044                 return UBUS_STATUS_METHOD_NOT_FOUND;
2045 
2046         reqproto = ucv_object_new(uusub->vm);
2047 
2048         ucv_object_add(reqproto, "type", ucv_string_new(method));
2049 
2050         ucv_object_add(reqproto, "data",
2051                 blob_array_to_ucv(uusub->vm, blob_data(msg), blob_len(msg), true));
2052 
2053         ucv_object_add(reqproto, "info",
2054                 uc_ubus_object_call_info(uusub->vm, ctx, req, obj, NULL));
2055 
2056         return uc_ubus_handle_reply_common(ctx, req, uusub->vm, this, func, reqproto);
2057 }
2058 
2059 static void
2060 uc_ubus_subscriber_remove_cb(struct ubus_context *ctx,
2061                              struct ubus_subscriber *sub, uint32_t id)
2062 {
2063         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
2064         uc_value_t *this, *func;
2065 
2066         subscriber_reg_get(uusub->vm, uusub->registry_index, &this, NULL, &func);
2067 
2068         if (!ucv_is_callable(func))
2069                 return;
2070 
2071         uc_vm_stack_push(uusub->vm, ucv_get(this));
2072         uc_vm_stack_push(uusub->vm, ucv_get(func));
2073         uc_vm_stack_push(uusub->vm, ucv_uint64_new(id));
2074 
2075         if (uc_vm_call(uusub->vm, true, 1) == EXCEPTION_NONE)
2076                 ucv_put(uc_vm_stack_pop(uusub->vm));
2077         else
2078                 uloop_end();
2079 }
2080 
2081 static uc_value_t *
2082 uc_ubus_subscriber_subunsub_common(uc_vm_t *vm, size_t nargs, bool subscribe)
2083 {
2084         uc_ubus_subscriber_t **uusub = uc_fn_this("ubus.subscriber");
2085         uc_value_t *objname;
2086         uint32_t id;
2087         int rv;
2088 
2089         if (!uusub || !*uusub)
2090                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
2091 
2092         args_get(vm, nargs,
2093                  "object name", UC_STRING, false, &objname);
2094 
2095         rv = ubus_lookup_id((*uusub)->ctx, ucv_string_get(objname), &id);
2096 
2097         if (rv != UBUS_STATUS_OK)
2098                 err_return(rv, "Failed to resolve object name '%s'",
2099                            ucv_string_get(objname));
2100 
2101         if (subscribe)
2102                 rv = ubus_subscribe((*uusub)->ctx, &(*uusub)->sub, id);
2103         else
2104                 rv = ubus_unsubscribe((*uusub)->ctx, &(*uusub)->sub, id);
2105 
2106         if (rv != UBUS_STATUS_OK)
2107                 err_return(rv, "Failed to %s object '%s'",
2108                            subscribe ? "subscribe" : "unsubscribe",
2109                            ucv_string_get(objname));
2110 
2111         ok_return(ucv_boolean_new(true));
2112 }
2113 
2114 static uc_value_t *
2115 uc_ubus_subscriber_subscribe(uc_vm_t *vm, size_t nargs)
2116 {
2117         return uc_ubus_subscriber_subunsub_common(vm, nargs, true);
2118 }
2119 
2120 static uc_value_t *
2121 uc_ubus_subscriber_unsubscribe(uc_vm_t *vm, size_t nargs)
2122 {
2123         return uc_ubus_subscriber_subunsub_common(vm, nargs, false);
2124 }
2125 
2126 static int
2127 uc_ubus_subscriber_remove_common(uc_ubus_subscriber_t *uusub)
2128 {
2129         int rv = ubus_unregister_subscriber(uusub->ctx, &uusub->sub);
2130 
2131         if (rv == UBUS_STATUS_OK)
2132                 subscriber_reg_clear(uusub->vm, uusub->registry_index);
2133 
2134         return rv;
2135 }
2136 
2137 static uc_value_t *
2138 uc_ubus_subscriber_remove(uc_vm_t *vm, size_t nargs)
2139 {
2140         uc_ubus_subscriber_t **uusub = uc_fn_this("ubus.subscriber");
2141         int rv;
2142 
2143         if (!uusub || !*uusub)
2144                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
2145 
2146         rv = uc_ubus_subscriber_remove_common(*uusub);
2147 
2148         if (rv != UBUS_STATUS_OK)
2149                 err_return(rv, "Failed to remove subscriber object");
2150 
2151         ok_return(ucv_boolean_new(true));
2152 }
2153 
2154 static uc_value_t *
2155 uc_ubus_subscriber(uc_vm_t *vm, size_t nargs)
2156 {
2157         uc_value_t *notify_cb, *remove_cb;
2158         uc_ubus_subscriber_t *uusub;
2159         uc_ubus_connection_t *c;
2160         uc_value_t *res;
2161         int rv;
2162 
2163         conn_get(vm, &c);
2164 
2165         args_get(vm, nargs,
2166                  "notify callback", UC_CLOSURE, true, &notify_cb,
2167                  "remove callback", UC_CLOSURE, true, &remove_cb);
2168 
2169         if (!notify_cb && !remove_cb)
2170                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either notify or remove callback required");
2171 
2172         uusub = xalloc(sizeof(*uusub));
2173         uusub->vm = vm;
2174         uusub->ctx = &c->ctx;
2175 
2176         rv = ubus_register_subscriber(&c->ctx, &uusub->sub);
2177 
2178         if (rv != UBUS_STATUS_OK) {
2179                 free(uusub);
2180                 err_return(rv, "Failed to register subscriber object");
2181         }
2182 
2183         if (notify_cb)
2184                 uusub->sub.cb = uc_ubus_subscriber_notify_cb;
2185 
2186         if (remove_cb)
2187                 uusub->sub.remove_cb = uc_ubus_subscriber_remove_cb;
2188 
2189         res = uc_resource_new(subscriber_type, uusub);
2190 
2191         uusub->registry_index = subscriber_reg_add(vm,
2192                 ucv_get(res), ucv_get(notify_cb), ucv_get(remove_cb));
2193 
2194         ok_return(res);
2195 }
2196 
2197 
2198 /*
2199  * connection methods
2200  * --------------------------------------------------------------------------
2201  */
2202 
2203 static uc_value_t *
2204 uc_ubus_remove(uc_vm_t *vm, size_t nargs)
2205 {
2206         uc_ubus_subscriber_t **uusub;
2207         uc_ubus_connection_t *c;
2208         uc_ubus_object_t **uuobj;
2209         uc_ubus_listener_t **uul;
2210         int rv;
2211 
2212         conn_get(vm, &c);
2213 
2214         uusub = (uc_ubus_subscriber_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.subscriber");
2215         uuobj = (uc_ubus_object_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.object");
2216         uul = (uc_ubus_listener_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.listener");
2217 
2218         if (uusub && *uusub) {
2219                 if ((*uusub)->ctx != &c->ctx)
2220                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
2221                                    "Subscriber belongs to different connection");
2222 
2223                 rv = uc_ubus_subscriber_remove_common(*uusub);
2224 
2225                 if (rv != UBUS_STATUS_OK)
2226                         err_return(rv, "Unable to remove subscriber");
2227         }
2228         else if (uuobj && *uuobj) {
2229                 if ((*uuobj)->ctx != &c->ctx)
2230                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
2231                                    "Object belongs to different connection");
2232 
2233                 rv = uc_ubus_object_remove_common(*uuobj);
2234 
2235                 if (rv != UBUS_STATUS_OK)
2236                         err_return(rv, "Unable to remove object");
2237         }
2238         else if (uul && *uul) {
2239                 if ((*uul)->ctx != &c->ctx)
2240                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
2241                                    "Listener belongs to different connection");
2242 
2243                 rv = uc_ubus_listener_remove_common(*uul);
2244 
2245                 if (rv != UBUS_STATUS_OK)
2246                         err_return(rv, "Unable to remove listener");
2247         }
2248         else {
2249                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Unhandled resource type");
2250         }
2251 
2252         ok_return(ucv_boolean_new(true));
2253 }
2254 
2255 
2256 static uc_value_t *
2257 uc_ubus_disconnect(uc_vm_t *vm, size_t nargs)
2258 {
2259         uc_ubus_connection_t *c;
2260 
2261         conn_get(vm, &c);
2262 
2263         ubus_shutdown(&c->ctx);
2264         c->ctx.sock.fd = -1;
2265 
2266         ok_return(ucv_boolean_new(true));
2267 }
2268 
2269 static uc_value_t *
2270 uc_ubus_defer_completed(uc_vm_t *vm, size_t nargs)
2271 {
2272         uc_ubus_deferred_t **d = uc_fn_this("ubus.deferred");
2273 
2274         if (!d || !*d)
2275                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
2276 
2277         ok_return(ucv_boolean_new((*d)->complete));
2278 }
2279 
2280 static uc_value_t *
2281 uc_ubus_defer_await(uc_vm_t *vm, size_t nargs)
2282 {
2283         uc_ubus_deferred_t *d = uc_fn_thisval("ubus.deferred");
2284         int64_t remaining;
2285 
2286         if (!d)
2287                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
2288 
2289         if (d->complete)
2290                 ok_return(ucv_boolean_new(false));
2291 
2292 #ifdef HAVE_ULOOP_TIMEOUT_REMAINING64
2293         remaining = uloop_timeout_remaining64(&d->timeout);
2294 #else
2295         remaining = uloop_timeout_remaining(&d->timeout);
2296 #endif
2297 
2298         ubus_complete_request(d->ctx, &d->request, remaining);
2299 
2300         ok_return(ucv_boolean_new(true));
2301 }
2302 
2303 static uc_value_t *
2304 uc_ubus_defer_abort(uc_vm_t *vm, size_t nargs)
2305 {
2306         uc_ubus_deferred_t **d = uc_fn_this("ubus.deferred");
2307 
2308         if (!d || !*d)
2309                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
2310 
2311         if ((*d)->complete)
2312                 ok_return(ucv_boolean_new(false));
2313 
2314         ubus_abort_request((*d)->ctx, &(*d)->request);
2315         uloop_timeout_cancel(&(*d)->timeout);
2316 
2317         request_reg_clear((*d)->vm, (*d)->registry_index);
2318 
2319         (*d)->complete = true;
2320 
2321         ok_return(ucv_boolean_new(true));
2322 }
2323 
2324 /*
2325  * channel related methods
2326  * --------------------------------------------------------------------------
2327  */
2328 
2329 #ifdef HAVE_UBUS_CHANNEL_SUPPORT
2330 static int
2331 uc_ubus_channel_req_cb(struct ubus_context *ctx, struct ubus_object *obj,
2332                        struct ubus_request_data *req, const char *method,
2333                        struct blob_attr *msg)
2334 {
2335         uc_ubus_connection_t *c = container_of(ctx, uc_ubus_connection_t, ctx);
2336         uc_value_t *this, *func, *args, *reqproto;
2337 
2338         connection_reg_get(c->vm, c->registry_index, &this, &func, NULL);
2339 
2340         if (!ucv_is_callable(func))
2341                 return UBUS_STATUS_METHOD_NOT_FOUND;
2342 
2343         args = blob_array_to_ucv(c->vm, blob_data(msg), blob_len(msg), true);
2344         reqproto = ucv_object_new(c->vm);
2345         ucv_object_add(reqproto, "args", ucv_get(args));
2346 
2347         if (method)
2348                 ucv_object_add(reqproto, "type", ucv_get(ucv_string_new(method)));
2349 
2350         return uc_ubus_handle_reply_common(ctx, req, c->vm, this, func, reqproto);
2351 }
2352 
2353 static void
2354 uc_ubus_channel_disconnect_cb(struct ubus_context *ctx)
2355 {
2356         uc_ubus_connection_t *c = container_of(ctx, uc_ubus_connection_t, ctx);
2357         uc_value_t *this, *func;
2358 
2359         connection_reg_get(c->vm, c->registry_index, &this, NULL, &func);
2360 
2361         if (ucv_is_callable(func)) {
2362                 uc_vm_stack_push(c->vm, ucv_get(this));
2363                 uc_vm_stack_push(c->vm, ucv_get(func));
2364 
2365                 if (uc_vm_call(c->vm, true, 0) == EXCEPTION_NONE)
2366                         ucv_put(uc_vm_stack_pop(c->vm));
2367                 else
2368                         uloop_end();
2369         }
2370 
2371         blob_buf_free(&c->buf);
2372 
2373         if (c->ctx.sock.fd >= 0) {
2374                 ubus_shutdown(&c->ctx);
2375                 c->ctx.sock.fd = -1;
2376         }
2377 
2378         if (c->registry_index >= 0)
2379                 connection_reg_clear(c->vm, c->registry_index);
2380 }
2381 
2382 static uc_value_t *
2383 uc_ubus_channel_add(uc_vm_t *vm, uc_ubus_connection_t *c, uc_value_t *cb,
2384                     uc_value_t *disconnect_cb, uc_value_t *fd)
2385 {
2386         uc_value_t *chan;
2387 
2388         c->vm = vm;
2389 
2390         if (c->timeout < 0)
2391                 c->timeout = 30;
2392 
2393         chan = uc_resource_new(chan_type, c);
2394         c->registry_index = connection_reg_add(vm, ucv_get(chan), ucv_get(cb), ucv_get(disconnect_cb), ucv_get(fd));
2395         c->ctx.connection_lost = uc_ubus_channel_disconnect_cb;
2396         ubus_add_uloop(&c->ctx);
2397 
2398         ok_return(chan);
2399 }
2400 #endif
2401 
2402 static uc_value_t *
2403 uc_ubus_request_new_channel(uc_vm_t *vm, size_t nargs)
2404 {
2405 #ifdef HAVE_UBUS_CHANNEL_SUPPORT
2406         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
2407         uc_value_t *cb, *disconnect_cb, *timeout;
2408         uc_ubus_connection_t *c;
2409         int fd;
2410 
2411         if (!callctx)
2412                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
2413 
2414         args_get(vm, nargs,
2415                  "cb", UC_CLOSURE, true, &cb,
2416                  "disconnect_cb", UC_CLOSURE, true, &disconnect_cb,
2417                  "timeout", UC_INTEGER, true, &timeout);
2418 
2419         c = xalloc(sizeof(*c));
2420         c->timeout = timeout ? ucv_int64_get(timeout) : 30;
2421 
2422         if (ubus_channel_create(&c->ctx, &fd, cb ? uc_ubus_channel_req_cb : NULL)) {
2423                 free(c);
2424                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to create ubus channel");
2425         }
2426 
2427         ubus_request_set_fd(callctx->ctx, &callctx->req, fd);
2428 
2429         return uc_ubus_channel_add(vm, c, cb, disconnect_cb, NULL);
2430 #else
2431         err_return(UBUS_STATUS_NOT_SUPPORTED, "No ubus channel support");
2432 #endif
2433 }
2434 
2435 
2436 static uc_value_t *
2437 uc_ubus_channel_connect(uc_vm_t *vm, size_t nargs)
2438 {
2439 #ifdef HAVE_UBUS_CHANNEL_SUPPORT
2440         uc_value_t *fd, *cb, *disconnect_cb, *timeout;
2441         uc_ubus_connection_t *c;
2442         int fd_val;
2443 
2444         args_get(vm, nargs,
2445                  "fd", UC_NULL, false, &fd,
2446                  "cb", UC_CLOSURE, true, &cb,
2447                  "disconnect_cb", UC_CLOSURE, true, &disconnect_cb,
2448                  "timeout", UC_INTEGER, true, &timeout);
2449 
2450         fd_val = get_fd(vm, fd);
2451 
2452         if (fd_val < 0)
2453                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid file descriptor argument");
2454 
2455         c = xalloc(sizeof(*c));
2456         c->timeout = timeout ? ucv_int64_get(timeout) : 30;
2457 
2458         if (ubus_channel_connect(&c->ctx, fd_val, cb ? uc_ubus_channel_req_cb : NULL)) {
2459                 free(c);
2460                 err_return(UBUS_STATUS_UNKNOWN_ERROR, "Unable to create ubus channel");
2461         }
2462 
2463         return uc_ubus_channel_add(vm, c, cb, disconnect_cb, fd);
2464 #else
2465         err_return(UBUS_STATUS_NOT_SUPPORTED, "No ubus channel support");
2466 #endif
2467 }
2468 
2469 
2470 static const uc_function_list_t global_fns[] = {
2471         { "error",                      uc_ubus_error },
2472         { "connect",            uc_ubus_connect },
2473         { "open_channel",       uc_ubus_channel_connect },
2474 };
2475 
2476 static const uc_function_list_t conn_fns[] = {
2477         { "list",                       uc_ubus_list },
2478         { "call",                       uc_ubus_call },
2479         { "defer",                      uc_ubus_defer },
2480         { "publish",            uc_ubus_publish },
2481         { "remove",                     uc_ubus_remove },
2482         { "listener",           uc_ubus_listener },
2483         { "subscriber",         uc_ubus_subscriber },
2484         { "event",                      uc_ubus_event },
2485         { "error",                      uc_ubus_error },
2486         { "disconnect",         uc_ubus_disconnect },
2487 };
2488 
2489 static const uc_function_list_t chan_fns[] = {
2490         { "request",            uc_ubus_chan_request },
2491         { "defer",                      uc_ubus_chan_defer },
2492         { "error",                      uc_ubus_error },
2493         { "disconnect",         uc_ubus_disconnect },
2494 };
2495 
2496 static const uc_function_list_t defer_fns[] = {
2497         { "await",                      uc_ubus_defer_await },
2498         { "completed",          uc_ubus_defer_completed },
2499         { "abort",                      uc_ubus_defer_abort },
2500 };
2501 
2502 static const uc_function_list_t object_fns[] = {
2503         { "subscribed",         uc_ubus_object_subscribed },
2504         { "notify",                     uc_ubus_object_notify },
2505         { "remove",                     uc_ubus_object_remove },
2506 };
2507 
2508 static const uc_function_list_t request_fns[] = {
2509         { "reply",                      uc_ubus_request_reply },
2510         { "error",                      uc_ubus_request_error },
2511         { "defer",                      uc_ubus_request_defer },
2512         { "get_fd",                     uc_ubus_request_get_fd },
2513         { "set_fd",                     uc_ubus_request_set_fd },
2514         { "new_channel",        uc_ubus_request_new_channel },
2515 };
2516 
2517 static const uc_function_list_t notify_fns[] = {
2518         { "completed",          uc_ubus_notify_completed },
2519         { "abort",                      uc_ubus_notify_abort },
2520 };
2521 
2522 static const uc_function_list_t listener_fns[] = {
2523         { "remove",                     uc_ubus_listener_remove },
2524 };
2525 
2526 static const uc_function_list_t subscriber_fns[] = {
2527         { "subscribe",          uc_ubus_subscriber_subscribe },
2528         { "unsubscribe",        uc_ubus_subscriber_unsubscribe },
2529         { "remove",                     uc_ubus_subscriber_remove },
2530 };
2531 
2532 static void free_connection(void *ud) {
2533         uc_ubus_connection_t *conn = ud;
2534 
2535         blob_buf_free(&conn->buf);
2536 
2537         if (conn->ctx.sock.fd >= 0)
2538                 ubus_shutdown(&conn->ctx);
2539         if (conn->registry_index >= 0)
2540                 connection_reg_clear(conn->vm, conn->registry_index);
2541 
2542         free(conn);
2543 }
2544 
2545 static void free_deferred(void *ud) {
2546         uc_ubus_deferred_t *defer = ud;
2547 
2548         uloop_timeout_cancel(&defer->timeout);
2549         ucv_put(defer->response);
2550         free(defer);
2551 }
2552 
2553 static void free_object(void *ud) {
2554         uc_ubus_object_t *uuobj = ud;
2555         struct ubus_object *obj = &uuobj->obj;
2556         int i, j;
2557 
2558         for (i = 0; i < obj->n_methods; i++) {
2559                 for (j = 0; j < obj->methods[i].n_policy; j++)
2560                         free((char *)obj->methods[i].policy[j].name);
2561 
2562                 free((char *)obj->methods[i].name);
2563                 free((char *)obj->methods[i].policy);
2564         }
2565 
2566         free(uuobj);
2567 }
2568 
2569 static void free_request(void *ud) {
2570         uc_ubus_request_t *callctx = ud;
2571 
2572         uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT);
2573         uloop_timeout_cancel(&callctx->timeout);
2574         free(callctx);
2575 }
2576 
2577 static void free_notify(void *ud) {
2578         uc_ubus_notify_t *notifyctx = ud;
2579 
2580         free(notifyctx);
2581 }
2582 
2583 static void free_listener(void *ud) {
2584         uc_ubus_listener_t *listener = ud;
2585 
2586         free(listener);
2587 }
2588 
2589 static void free_subscriber(void *ud) {
2590         uc_ubus_subscriber_t *subscriber = ud;
2591 
2592         free(subscriber);
2593 }
2594 
2595 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
2596 {
2597         uc_function_list_register(scope, global_fns);
2598 
2599 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(UBUS_##x))
2600         ADD_CONST(STATUS_OK);
2601         ADD_CONST(STATUS_INVALID_COMMAND);
2602         ADD_CONST(STATUS_INVALID_ARGUMENT);
2603         ADD_CONST(STATUS_METHOD_NOT_FOUND);
2604         ADD_CONST(STATUS_NOT_FOUND);
2605         ADD_CONST(STATUS_NO_DATA);
2606         ADD_CONST(STATUS_PERMISSION_DENIED);
2607         ADD_CONST(STATUS_TIMEOUT);
2608         ADD_CONST(STATUS_NOT_SUPPORTED);
2609         ADD_CONST(STATUS_UNKNOWN_ERROR);
2610         ADD_CONST(STATUS_CONNECTION_FAILED);
2611 
2612 #ifdef HAVE_NEW_UBUS_STATUS_CODES
2613         ADD_CONST(STATUS_NO_MEMORY);
2614         ADD_CONST(STATUS_PARSE_ERROR);
2615         ADD_CONST(STATUS_SYSTEM_ERROR);
2616 #endif
2617 
2618         /* virtual status code for reply */
2619 #define UBUS_STATUS_CONTINUE -1
2620         ADD_CONST(STATUS_CONTINUE);
2621 
2622         ADD_CONST(SYSTEM_OBJECT_ACL);
2623 
2624         conn_type = uc_type_declare(vm, "ubus.connection", conn_fns, free_connection);
2625         chan_type = uc_type_declare(vm, "ubus.channel", chan_fns, free_connection);
2626         defer_type = uc_type_declare(vm, "ubus.deferred", defer_fns, free_deferred);
2627         object_type = uc_type_declare(vm, "ubus.object", object_fns, free_object);
2628         notify_type = uc_type_declare(vm, "ubus.notify", notify_fns, free_notify);
2629         request_type = uc_type_declare(vm, "ubus.request", request_fns, free_request);
2630         listener_type = uc_type_declare(vm, "ubus.listener", listener_fns, free_listener);
2631         subscriber_type = uc_type_declare(vm, "ubus.subscriber", subscriber_fns, free_subscriber);
2632 }
2633 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt