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

Sources/ucode/lib/ubus.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt