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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt