• 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         uc_callframe_t *frame;
728         uint32_t id;
729 
730         conn_get(vm, &c);
731 
732         args_get(vm, nargs,
733                  "object name", UC_STRING, false, &objname,
734                  "function name", UC_STRING, false, &funname,
735                  "function arguments", UC_OBJECT, true, &funargs,
736                  "reply callback", UC_CLOSURE, true, &replycb);
737 
738         blob_buf_init(&c->buf, 0);
739 
740         if (funargs)
741                 ucv_object_to_blob(funargs, &c->buf);
742 
743         rv = ubus_lookup_id(&c->ctx, ucv_string_get(objname), &id);
744 
745         if (rv != UBUS_STATUS_OK)
746                 err_return(rv, "Failed to resolve object name '%s'",
747                            ucv_string_get(objname));
748 
749         defer = xalloc(sizeof(*defer));
750 
751         rv = ubus_invoke_async(&c->ctx, id, ucv_string_get(funname),
752                                c->buf.head, &defer->request);
753 
754         if (rv == UBUS_STATUS_OK) {
755                 defer->vm = vm;
756                 defer->ctx = &c->ctx;
757 
758                 defer->request.data_cb = uc_ubus_call_data_cb;
759                 defer->request.complete_cb = uc_ubus_call_done_cb;
760                 ubus_complete_request_async(&c->ctx, &defer->request);
761 
762                 defer->timeout.cb = uc_ubus_call_timeout_cb;
763                 uloop_timeout_set(&defer->timeout, c->timeout * 1000);
764 
765                 res = uc_resource_new(defer_type, defer);
766                 frame = uc_vector_last(&vm->callframes);
767                 conn = frame ? frame->ctx : NULL;
768 
769                 defer->registry_index = request_reg_add(vm, ucv_get(res), ucv_get(replycb), ucv_get(conn));
770 
771                 if (!uc_ubus_have_uloop()) {
772                         have_own_uloop = true;
773                         uloop_run();
774                 }
775         }
776         else {
777                 uc_vm_stack_push(vm, ucv_get(replycb));
778                 uc_vm_stack_push(vm, ucv_int64_new(rv));
779 
780                 if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE)
781                         ucv_put(uc_vm_stack_pop(vm));
782                 else
783                         uloop_end();
784 
785                 free(defer);
786         }
787 
788         if (rv != UBUS_STATUS_OK)
789                 err_return(rv, "Failed to invoke function '%s' on object '%s'",
790                            ucv_string_get(funname), ucv_string_get(objname));
791 
792         ok_return(res);
793 }
794 
795 
796 /*
797  * ubus object request context functions
798  * --------------------------------------------------------------------------
799  */
800 
801 static void
802 uc_ubus_request_finish(uc_ubus_request_t *callctx, int code, uc_value_t *reply)
803 {
804         if (callctx->replied)
805                 return;
806 
807         if (reply) {
808                 blob_buf_init(&buf, 0);
809                 ucv_object_to_blob(reply, &buf);
810                 ubus_send_reply(callctx->ctx, &callctx->req, buf.head);
811         }
812 
813         callctx->replied = true;
814 
815         ubus_complete_deferred_request(callctx->ctx, &callctx->req, code);
816         request_reg_clear(callctx->vm, callctx->registry_index);
817 }
818 
819 static void
820 uc_ubus_request_timeout(struct uloop_timeout *timeout)
821 {
822         uc_ubus_request_t *callctx = container_of(timeout, uc_ubus_request_t, timeout);
823 
824         uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT, NULL);
825 }
826 
827 static uc_value_t *
828 uc_ubus_request_reply(uc_vm_t *vm, size_t nargs)
829 {
830         uc_ubus_request_t **callctx = uc_fn_this("ubus.request");
831         int64_t code = UBUS_STATUS_OK;
832         uc_value_t *reply, *rcode;
833 
834         if (!callctx || !*callctx)
835                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
836 
837         args_get(vm, nargs,
838                  "reply", UC_OBJECT, true, &reply,
839                  "rcode", UC_INTEGER, true, &rcode);
840 
841         if ((*callctx)->replied)
842                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
843 
844         if (rcode) {
845                 code = ucv_int64_get(rcode);
846 
847                 if (errno == ERANGE || code < 0 || code > __UBUS_STATUS_LAST)
848                         code = UBUS_STATUS_UNKNOWN_ERROR;
849         }
850 
851         uc_ubus_request_finish(*callctx, code, reply);
852 
853         ok_return(ucv_boolean_new(true));
854 }
855 
856 static uc_value_t *
857 uc_ubus_request_defer(uc_vm_t *vm, size_t nargs)
858 {
859         uc_ubus_request_t *callctx = uc_fn_thisval("ubus.request");
860 
861         if (!callctx)
862                 return NULL;
863 
864         callctx->deferred = true;
865         return ucv_boolean_new(true);
866 }
867 
868 static uc_value_t *
869 uc_ubus_request_error(uc_vm_t *vm, size_t nargs)
870 {
871         uc_ubus_request_t **callctx = uc_fn_this("ubus.request");
872         uc_value_t *rcode = uc_fn_arg(0);
873         int64_t code;
874 
875         if (!callctx || !*callctx)
876                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid call context");
877 
878         args_get(vm, nargs,
879                  "rcode", UC_INTEGER, false, &rcode);
880 
881         if ((*callctx)->replied)
882                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Reply has already been sent");
883 
884         code = ucv_int64_get(rcode);
885 
886         if (errno == ERANGE || code < 0 || code > __UBUS_STATUS_LAST)
887                 code = UBUS_STATUS_UNKNOWN_ERROR;
888 
889         uc_ubus_request_finish(*callctx, code, NULL);
890 
891         ok_return(ucv_boolean_new(true));
892 }
893 
894 
895 /*
896  * ubus object notify
897  * --------------------------------------------------------------------------
898  */
899 
900 static uc_value_t *
901 uc_ubus_notify_completed(uc_vm_t *vm, size_t nargs)
902 {
903         uc_ubus_notify_t **notifyctx = uc_fn_this("ubus.notify");
904 
905         if (!notifyctx || !*notifyctx)
906                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid notify context");
907 
908         ok_return(ucv_boolean_new((*notifyctx)->complete));
909 }
910 
911 static uc_value_t *
912 uc_ubus_notify_abort(uc_vm_t *vm, size_t nargs)
913 {
914         uc_ubus_notify_t **notifyctx = uc_fn_this("ubus.notify");
915 
916         if (!notifyctx || !*notifyctx)
917                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid notify context");
918 
919         if ((*notifyctx)->complete)
920                 ok_return(ucv_boolean_new(false));
921 
922         ubus_abort_request((*notifyctx)->ctx, &(*notifyctx)->req.req);
923         (*notifyctx)->complete = true;
924 
925         ok_return(ucv_boolean_new(true));
926 }
927 
928 static void
929 uc_ubus_object_notify_data_cb(struct ubus_notify_request *req, int type, struct blob_attr *msg)
930 {
931         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
932         uc_value_t *this, *func;
933 
934         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, &func, NULL, NULL);
935 
936         if (ucv_is_callable(func)) {
937                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
938                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
939                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(type));
940                 uc_vm_stack_push(notifyctx->vm, blob_array_to_ucv(notifyctx->vm, blob_data(msg), blob_len(msg), true));
941 
942                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
943                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
944                 else
945                         uloop_end();
946         }
947 }
948 
949 static void
950 uc_ubus_object_notify_status_cb(struct ubus_notify_request *req, int idx, int ret)
951 {
952         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
953         uc_value_t *this, *func;
954 
955         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, NULL, &func, NULL);
956 
957         if (ucv_is_callable(func)) {
958                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
959                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
960                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(idx));
961                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(ret));
962 
963                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
964                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
965                 else
966                         uloop_end();
967         }
968 }
969 
970 static void
971 uc_ubus_object_notify_complete_cb(struct ubus_notify_request *req, int idx, int ret)
972 {
973         uc_ubus_notify_t *notifyctx = (uc_ubus_notify_t *)req;
974         uc_value_t *this, *func;
975 
976         notify_reg_get(notifyctx->vm, notifyctx->registry_index, &this, NULL, NULL, &func);
977 
978         if (ucv_is_callable(func)) {
979                 uc_vm_stack_push(notifyctx->vm, ucv_get(this));
980                 uc_vm_stack_push(notifyctx->vm, ucv_get(func));
981                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(idx));
982                 uc_vm_stack_push(notifyctx->vm, ucv_int64_new(ret));
983 
984                 if (uc_vm_call(notifyctx->vm, true, 2) == EXCEPTION_NONE)
985                         ucv_put(uc_vm_stack_pop(notifyctx->vm));
986                 else
987                         uloop_end();
988         }
989 
990         notifyctx->complete = true;
991 
992         notify_reg_clear(notifyctx->vm, notifyctx->registry_index);
993 }
994 
995 static uc_value_t *
996 uc_ubus_object_notify(uc_vm_t *vm, size_t nargs)
997 {
998         uc_value_t *typename, *message, *data_cb, *status_cb, *complete_cb, *timeout;
999         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1000         uc_ubus_notify_t *notifyctx;
1001         uc_value_t *res;
1002         int64_t t;
1003         int rv;
1004 
1005         if (!uuobj || !*uuobj)
1006                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1007 
1008         args_get(vm, nargs,
1009                  "typename", UC_STRING, false, &typename,
1010                  "message", UC_OBJECT, true, &message,
1011                  "data callback", UC_CLOSURE, true, &data_cb,
1012                  "status callback", UC_CLOSURE, true, &status_cb,
1013                  "completion callback", UC_CLOSURE, true, &complete_cb,
1014                  "timeout", UC_INTEGER, true, &timeout);
1015 
1016         t = timeout ? ucv_int64_get(timeout) : -1;
1017 
1018         if (errno)
1019                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
1020                            "Invalid timeout value: %s", strerror(errno));
1021 
1022         notifyctx = xalloc(sizeof(*notifyctx));
1023         notifyctx->vm = vm;
1024         notifyctx->ctx = (*uuobj)->ctx;
1025 
1026         blob_buf_init(&buf, 0);
1027 
1028         if (message)
1029                 ucv_object_to_blob(message, &buf);
1030 
1031         rv = ubus_notify_async((*uuobj)->ctx, &(*uuobj)->obj,
1032                                ucv_string_get(typename), buf.head,
1033                                &notifyctx->req);
1034 
1035         if (rv != UBUS_STATUS_OK) {
1036                 free(notifyctx);
1037                 err_return(rv, "Failed to send notification");
1038         }
1039 
1040         notifyctx->req.data_cb = uc_ubus_object_notify_data_cb;
1041         notifyctx->req.status_cb = uc_ubus_object_notify_status_cb;
1042         notifyctx->req.complete_cb = uc_ubus_object_notify_complete_cb;
1043 
1044         res = uc_resource_new(notify_type, notifyctx);
1045 
1046         notifyctx->registry_index = notify_reg_add(vm,
1047                 ucv_get(res), ucv_get(data_cb), ucv_get(status_cb), ucv_get(complete_cb));
1048 
1049         if (t >= 0) {
1050                 rv = ubus_complete_request((*uuobj)->ctx, &notifyctx->req.req, t);
1051 
1052                 notify_reg_clear(vm, notifyctx->registry_index);
1053 
1054                 ucv_put(res);
1055 
1056                 ok_return(ucv_int64_new(rv));
1057         }
1058 
1059         ubus_complete_request_async((*uuobj)->ctx, &notifyctx->req.req);
1060 
1061         ok_return(res);
1062 }
1063 
1064 
1065 /*
1066  * ubus object remove
1067  * --------------------------------------------------------------------------
1068  */
1069 
1070 static int
1071 uc_ubus_object_remove_common(uc_ubus_object_t *uuobj)
1072 {
1073         int rv = ubus_remove_object(uuobj->ctx, &uuobj->obj);
1074 
1075         if (rv == UBUS_STATUS_OK)
1076                 object_reg_clear(uuobj->vm, uuobj->registry_index);
1077 
1078         return rv;
1079 }
1080 
1081 static uc_value_t *
1082 uc_ubus_object_remove(uc_vm_t *vm, size_t nargs)
1083 {
1084         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1085         int rv;
1086 
1087         if (!uuobj || !*uuobj)
1088                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1089 
1090         rv = uc_ubus_object_remove_common(*uuobj);
1091 
1092         if (rv != UBUS_STATUS_OK)
1093                 err_return(rv, "Failed to remove object");
1094 
1095         ok_return(ucv_boolean_new(true));
1096 }
1097 
1098 
1099 /*
1100  * ubus object subscription status
1101  */
1102 
1103 static uc_value_t *
1104 uc_ubus_object_subscribed(uc_vm_t *vm, size_t nargs)
1105 {
1106         uc_ubus_object_t **uuobj = uc_fn_this("ubus.object");
1107 
1108         if (!uuobj || !*uuobj)
1109                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid object context");
1110 
1111         ok_return(ucv_boolean_new((*uuobj)->obj.has_subscribers));
1112 }
1113 
1114 
1115 /*
1116  * ubus object method call handling
1117  * --------------------------------------------------------------------------
1118  */
1119 
1120 static int
1121 uc_ubus_object_call_args(struct ubus_object *obj, const char *ubus_method_name,
1122                          struct blob_attr *msg, uc_value_t **res)
1123 {
1124         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1125         const struct ubus_method *method = NULL;
1126         const struct blobmsg_hdr *hdr;
1127         struct blob_attr *attr;
1128         size_t len;
1129         bool found;
1130         int i;
1131 
1132         for (i = 0; i < obj->n_methods; i++) {
1133                 if (!strcmp(obj->methods[i].name, ubus_method_name)) {
1134                         method = &obj->methods[i];
1135                         break;
1136                 }
1137         }
1138 
1139         if (!method)
1140                 return UBUS_STATUS_METHOD_NOT_FOUND;
1141 
1142         len = blob_len(msg);
1143 
1144         __blob_for_each_attr(attr, blob_data(msg), len) {
1145                 if (!blobmsg_check_attr_len(attr, false, len))
1146                         return UBUS_STATUS_INVALID_ARGUMENT;
1147 
1148                 if (!blob_is_extended(attr))
1149                         return UBUS_STATUS_INVALID_ARGUMENT;
1150 
1151                 hdr = blob_data(attr);
1152                 found = false;
1153 
1154                 for (i = 0; i < method->n_policy; i++) {
1155                         if (blobmsg_namelen(hdr) != strlen(method->policy[i].name))
1156                                 continue;
1157 
1158                         if (strcmp(method->policy[i].name, (char *)hdr->name))
1159                                 continue;
1160 
1161                         /* named argument found but wrong type */
1162                         if (blob_id(attr) != method->policy[i].type)
1163                                 goto inval;
1164 
1165                         found = true;
1166                         break;
1167                 }
1168 
1169                 /* named argument not found in policy */
1170                 if (!found)
1171                         goto inval;
1172         }
1173 
1174         *res = blob_array_to_ucv(uuobj->vm, blob_data(msg), blob_len(msg), true);
1175 
1176         return UBUS_STATUS_OK;
1177 
1178 inval:
1179         *res = NULL;
1180 
1181         return UBUS_STATUS_INVALID_ARGUMENT;
1182 }
1183 
1184 static uc_value_t *
1185 uc_ubus_object_call_info(uc_vm_t *vm,
1186                          struct ubus_context *ctx, struct ubus_request_data *req,
1187                          struct ubus_object *obj, const char *ubus_method_name)
1188 {
1189         uc_value_t *info, *o;
1190 
1191         info = ucv_object_new(vm);
1192 
1193         o = ucv_object_new(vm);
1194 
1195         ucv_object_add(o, "user", ucv_string_new(req->acl.user));
1196         ucv_object_add(o, "group", ucv_string_new(req->acl.group));
1197 
1198         if (req->acl.object)
1199                 ucv_object_add(o, "object", ucv_string_new(req->acl.object));
1200 
1201         ucv_object_add(info, "acl", o);
1202 
1203         o = ucv_object_new(vm);
1204 
1205         ucv_object_add(o, "id", ucv_int64_new(obj->id));
1206 
1207         if (obj->name)
1208                 ucv_object_add(o, "name", ucv_string_new(obj->name));
1209 
1210         if (obj->path)
1211                 ucv_object_add(o, "path", ucv_string_new(obj->path));
1212 
1213         ucv_object_add(info, "object", o);
1214 
1215         if (ubus_method_name)
1216                 ucv_object_add(info, "method", ucv_string_new(ubus_method_name));
1217 
1218         return info;
1219 }
1220 
1221 static int
1222 uc_ubus_handle_reply_common(struct ubus_context *ctx,
1223                               struct ubus_request_data *req,
1224                               uc_vm_t *vm, uc_value_t *this, uc_value_t *func,
1225                               uc_value_t *reqproto)
1226 {
1227         uc_ubus_request_t *callctx;
1228         uc_value_t *reqobj, *res;
1229         int rv;
1230 
1231         /* allocate deferred method call context */
1232         callctx = xalloc(sizeof(*callctx));
1233         callctx->ctx = ctx;
1234         callctx->vm = vm;
1235 
1236         ubus_defer_request(ctx, req, &callctx->req);
1237 
1238         /* create ucode request type object and set properties */
1239         reqobj = uc_resource_new(request_type, callctx);
1240 
1241         if (reqproto)
1242                 ucv_prototype_set(ucv_prototype_get(reqobj), reqproto);
1243 
1244         /* push object context, handler and request object onto stack */
1245         uc_vm_stack_push(vm, ucv_get(this));
1246         uc_vm_stack_push(vm, ucv_get(func));
1247         uc_vm_stack_push(vm, ucv_get(reqobj));
1248 
1249         /* execute request handler function */
1250         switch (uc_vm_call(vm, true, 1)) {
1251         case EXCEPTION_NONE:
1252                 res = uc_vm_stack_pop(vm);
1253 
1254                 /* The handler function invoked a nested aync ubus request and returned it */
1255                 if (ucv_resource_dataptr(res, "ubus.deferred")) {
1256                         /* Install guard timer in case the reply callback is never called */
1257                         callctx->timeout.cb = uc_ubus_request_timeout;
1258                         uloop_timeout_set(&callctx->timeout, 10000 /* FIXME */);
1259 
1260                         /* Add wrapped request context into registry to prevent GC'ing
1261                          * until reply or timeout occurred */
1262                         callctx->registry_index = request_reg_add(vm, ucv_get(reqobj), NULL, NULL);
1263                 }
1264 
1265                 /* Otherwise, when the function returned an object, treat it as
1266                 * reply data and conclude deferred request immediately */
1267                 else if (ucv_type(res) == UC_OBJECT) {
1268                         blob_buf_init(&buf, 0);
1269                         ucv_object_to_blob(res, &buf);
1270                         ubus_send_reply(ctx, &callctx->req, buf.head);
1271 
1272                         ubus_complete_deferred_request(ctx, &callctx->req, UBUS_STATUS_OK);
1273                         callctx->replied = true;
1274                 }
1275 
1276                 /* If neither a deferred ubus request, nor a plain object were
1277                  * returned and if reqobj.reply() hasn't been called, immediately
1278                  * finish deferred request with UBUS_STATUS_NO_DATA. */
1279                 else if (!callctx->replied && !callctx->deferred) {
1280                         rv = UBUS_STATUS_NO_DATA;
1281 
1282                         if (ucv_type(res) == UC_INTEGER) {
1283                                 rv = (int)ucv_int64_get(res);
1284 
1285                                 if (rv < 0 || rv > __UBUS_STATUS_LAST)
1286                                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1287                         }
1288 
1289                         ubus_complete_deferred_request(ctx, &callctx->req, rv);
1290                         callctx->replied = true;
1291                 }
1292 
1293                 ucv_put(res);
1294                 break;
1295 
1296         /* if the handler function invoked exit(), forward exit status as ubus
1297          * return code, map out of range values to UBUS_STATUS_UNKNOWN_ERROR. */
1298         case EXCEPTION_EXIT:
1299                 rv = vm->arg.s32;
1300 
1301                 if (rv < UBUS_STATUS_OK || rv >= __UBUS_STATUS_LAST)
1302                         rv = UBUS_STATUS_UNKNOWN_ERROR;
1303 
1304                 ubus_complete_deferred_request(ctx, &callctx->req, rv);
1305                 callctx->replied = true;
1306                 break;
1307 
1308         /* treat other exceptions as fatal and halt uloop */
1309         default:
1310                 ubus_complete_deferred_request(ctx, &callctx->req, UBUS_STATUS_UNKNOWN_ERROR);
1311                 uloop_end();
1312                 callctx->replied = true;
1313                 break;
1314         }
1315 
1316         /* release request object */
1317         ucv_put(reqobj);
1318 
1319         /* garbage collect */
1320         ucv_gc(vm);
1321 
1322         return UBUS_STATUS_OK;
1323 }
1324 
1325 static int
1326 uc_ubus_object_call_cb(struct ubus_context *ctx, struct ubus_object *obj,
1327                        struct ubus_request_data *req, const char *ubus_method_name,
1328                        struct blob_attr *msg)
1329 {
1330         uc_value_t *this, *func, *args = NULL, *reqproto, *methods;
1331         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1332         int rv;
1333 
1334         object_reg_get(uuobj->vm, uuobj->registry_index, &this, &methods, NULL);
1335 
1336         func = ucv_object_get(ucv_object_get(methods, ubus_method_name, NULL), "call", NULL);
1337 
1338         if (!ucv_is_callable(func))
1339                 return UBUS_STATUS_METHOD_NOT_FOUND;
1340 
1341         rv = uc_ubus_object_call_args(obj, ubus_method_name, msg, &args);
1342 
1343         if (rv != UBUS_STATUS_OK)
1344                 return rv;
1345 
1346         reqproto = ucv_object_new(uuobj->vm);
1347 
1348         ucv_object_add(reqproto, "args", args);
1349         ucv_object_add(reqproto, "info",
1350                 uc_ubus_object_call_info(uuobj->vm, ctx, req, obj, ubus_method_name));
1351 
1352         return uc_ubus_handle_reply_common(ctx, req, uuobj->vm, this, func, reqproto);
1353 }
1354 
1355 
1356 /*
1357  * ubus object registration
1358  * --------------------------------------------------------------------------
1359  */
1360 
1361 static void
1362 uc_ubus_object_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
1363 {
1364         uc_ubus_object_t *uuobj = (uc_ubus_object_t *)obj;
1365         uc_value_t *this, *func;
1366 
1367         object_reg_get(uuobj->vm, uuobj->registry_index, &this, NULL, &func);
1368 
1369         uc_vm_stack_push(uuobj->vm, ucv_get(this));
1370         uc_vm_stack_push(uuobj->vm, ucv_get(func));
1371 
1372         if (uc_vm_call(uuobj->vm, true, 0) == EXCEPTION_NONE)
1373                 ucv_put(uc_vm_stack_pop(uuobj->vm));
1374         else
1375                 uloop_end();
1376 }
1377 
1378 static bool
1379 uc_ubus_object_methods_validate(uc_value_t *methods)
1380 {
1381         uc_value_t *func, *args;
1382 
1383         ucv_object_foreach(methods, ubus_method_name, ubus_method_definition) {
1384                 (void)ubus_method_name;
1385 
1386                 func = ucv_object_get(ubus_method_definition, "call", NULL);
1387                 args = ucv_object_get(ubus_method_definition, "args", NULL);
1388 
1389                 if (!ucv_is_callable(func))
1390                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1391                                    "Method '%s' field 'call' is not a function value",
1392                                    ubus_method_name);
1393 
1394                 if (args) {
1395                         if (ucv_type(args) != UC_OBJECT)
1396                                 err_return(UBUS_STATUS_INVALID_ARGUMENT,
1397                                            "Method '%s' field 'args' is not an object value",
1398                                            ubus_method_name);
1399 
1400                         ucv_object_foreach(args, ubus_argument_name, ubus_argument_typehint) {
1401                                 (void)ubus_argument_name;
1402 
1403                                 switch (ucv_type(ubus_argument_typehint)) {
1404                                 case UC_BOOLEAN:
1405                                 case UC_INTEGER:
1406                                 case UC_DOUBLE:
1407                                 case UC_STRING:
1408                                 case UC_ARRAY:
1409                                 case UC_OBJECT:
1410                                         continue;
1411 
1412                                 default:
1413                                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1414                                                    "Method '%s' field 'args' argument '%s' hint has unsupported type %s",
1415                                                    ubus_method_name, ubus_argument_name,
1416                                                    ucv_typename(ubus_argument_typehint));
1417                                 }
1418                         }
1419                 }
1420         }
1421 
1422         ok_return(true);
1423 }
1424 
1425 static bool
1426 uc_ubus_object_method_register(struct ubus_method *method, const char *ubus_method_name,
1427                                uc_value_t *ubus_method_arguments)
1428 {
1429         struct blobmsg_policy *policy;
1430         enum blobmsg_type type;
1431 
1432         method->name = strdup(ubus_method_name);
1433         method->policy = calloc(ucv_object_length(ubus_method_arguments), sizeof(*method->policy));
1434         method->handler = uc_ubus_object_call_cb;
1435 
1436         if (!method->name || !method->policy)
1437                 return false;
1438 
1439         ucv_object_foreach(ubus_method_arguments, ubus_argument_name, ubus_argument_typehint) {
1440                 switch (ucv_type(ubus_argument_typehint)) {
1441                 case UC_BOOLEAN:
1442                         type = BLOBMSG_TYPE_INT8;
1443                         break;
1444 
1445                 case UC_INTEGER:
1446                         switch (ucv_int64_get(ubus_argument_typehint)) {
1447                         case 8:
1448                                 type = BLOBMSG_TYPE_INT8;
1449                                 break;
1450 
1451                         case 16:
1452                                 type = BLOBMSG_TYPE_INT16;
1453                                 break;
1454 
1455                         case 64:
1456                                 type = BLOBMSG_TYPE_INT64;
1457                                 break;
1458 
1459                         default:
1460                                 type = BLOBMSG_TYPE_INT32;
1461                                 break;
1462                         }
1463 
1464                         break;
1465 
1466                 case UC_DOUBLE:
1467                         type = BLOBMSG_TYPE_DOUBLE;
1468                         break;
1469 
1470                 case UC_ARRAY:
1471                         type = BLOBMSG_TYPE_ARRAY;
1472                         break;
1473 
1474                 case UC_OBJECT:
1475                         type = BLOBMSG_TYPE_TABLE;
1476                         break;
1477 
1478                 default:
1479                         type = BLOBMSG_TYPE_STRING;
1480                         break;
1481                 }
1482 
1483                 policy = (struct blobmsg_policy *)&method->policy[method->n_policy++];
1484                 policy->type = type;
1485                 policy->name = strdup(ubus_argument_name);
1486 
1487                 if (!policy->name)
1488                         return false;
1489         }
1490 
1491         return true;
1492 }
1493 
1494 static uc_ubus_object_t *
1495 uc_ubus_object_register(struct ubus_context *ctx, const char *ubus_object_name,
1496                         uc_value_t *ubus_object_methods)
1497 {
1498         const struct blobmsg_policy *policy;
1499         uc_ubus_object_t *uuobj = NULL;
1500         int rv = UBUS_STATUS_UNKNOWN_ERROR;
1501         char *tptr, *tnptr, *onptr, *mptr;
1502         struct ubus_method *method;
1503         struct ubus_object *obj;
1504         size_t typelen, namelen;
1505         uc_value_t *args;
1506 
1507         namelen = strlen(ubus_object_name);
1508         typelen = strlen("ucode-ubus-") + namelen;
1509 
1510         uuobj = calloc_a(sizeof(*uuobj),
1511                          &onptr, namelen + 1,
1512                          &mptr, ucv_object_length(ubus_object_methods) * sizeof(struct ubus_method),
1513                          &tptr, sizeof(struct ubus_object_type),
1514                          &tnptr, typelen + 1);
1515 
1516         if (!uuobj)
1517                 err_return(rv, "Out of memory");
1518 
1519         snprintf(tnptr, typelen, "ucode-ubus-%s", ubus_object_name);
1520 
1521         method = (struct ubus_method *)mptr;
1522 
1523         obj = &uuobj->obj;
1524         obj->name = memcpy(onptr, ubus_object_name, namelen);
1525         obj->methods = method;
1526 
1527         if (ubus_object_methods) {
1528                 ucv_object_foreach(ubus_object_methods, ubus_method_name, ubus_method_definition) {
1529                         args = ucv_object_get(ubus_method_definition, "args", NULL);
1530 
1531                         if (!uc_ubus_object_method_register(&method[obj->n_methods++], ubus_method_name, args))
1532                                 goto out;
1533                 }
1534         }
1535 
1536         obj->type = (struct ubus_object_type *)tptr;
1537         obj->type->name = tnptr;
1538         obj->type->methods = obj->methods;
1539         obj->type->n_methods = obj->n_methods;
1540 
1541         rv = ubus_add_object(ctx, obj);
1542 
1543         if (rv == UBUS_STATUS_OK)
1544                 return uuobj;
1545 
1546 out:
1547         for (; obj->n_methods > 0; method++, obj->n_methods--) {
1548                 for (policy = method->policy; method->n_policy > 0; policy++, method->n_policy--)
1549                         free((char *)policy->name);
1550 
1551                 free((char *)method->name);
1552                 free((char *)method->policy);
1553         }
1554 
1555         free(uuobj);
1556 
1557         err_return(rv, "Unable to add ubus object");
1558 }
1559 
1560 static uc_value_t *
1561 uc_ubus_publish(uc_vm_t *vm, size_t nargs)
1562 {
1563         uc_value_t *objname, *methods, *subscribecb;
1564         uc_ubus_connection_t *c;
1565         uc_ubus_object_t *uuobj;
1566         uc_value_t *res;
1567 
1568         conn_get(vm, &c);
1569 
1570         args_get(vm, nargs,
1571                  "object name", UC_STRING, false, &objname,
1572                  "object methods", UC_OBJECT, true, &methods,
1573                  "subscribe callback", UC_CLOSURE, true, &subscribecb);
1574 
1575         if (!methods && !subscribecb)
1576                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either methods or subscribe callback required");
1577 
1578         if (methods && !uc_ubus_object_methods_validate(methods))
1579                 return NULL;
1580 
1581         uuobj = uc_ubus_object_register(&c->ctx, ucv_string_get(objname), methods);
1582 
1583         if (!uuobj)
1584                 return NULL;
1585 
1586         if (subscribecb)
1587                 uuobj->obj.subscribe_cb = uc_ubus_object_subscribe_cb;
1588 
1589         res = uc_resource_new(object_type, uuobj);
1590 
1591         uuobj->vm = vm;
1592         uuobj->ctx = &c->ctx;
1593         uuobj->registry_index = object_reg_add(vm, ucv_get(res), ucv_get(methods), ucv_get(subscribecb));
1594 
1595         ok_return(res);
1596 }
1597 
1598 
1599 /*
1600  * ubus events
1601  * --------------------------------------------------------------------------
1602  */
1603 
1604 static int
1605 uc_ubus_listener_remove_common(uc_ubus_listener_t *uul)
1606 {
1607         int rv = ubus_unregister_event_handler(uul->ctx, &uul->ev);
1608 
1609         if (rv == UBUS_STATUS_OK)
1610                 listener_reg_clear(uul->vm, uul->registry_index);
1611 
1612         return rv;
1613 }
1614 
1615 static uc_value_t *
1616 uc_ubus_listener_remove(uc_vm_t *vm, size_t nargs)
1617 {
1618         uc_ubus_listener_t **uul = uc_fn_this("ubus.listener");
1619         int rv;
1620 
1621         if (!uul || !*uul)
1622                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid listener context");
1623 
1624         rv = uc_ubus_listener_remove_common(*uul);
1625 
1626         if (rv != UBUS_STATUS_OK)
1627                 err_return(rv, "Failed to remove listener object");
1628 
1629         ok_return(ucv_boolean_new(true));
1630 }
1631 
1632 static void
1633 uc_ubus_listener_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
1634                     const char *type, struct blob_attr *msg)
1635 {
1636         uc_ubus_listener_t *uul = (uc_ubus_listener_t *)ev;
1637         uc_value_t *this, *func;
1638 
1639         listener_reg_get(uul->vm, uul->registry_index, &this, &func);
1640 
1641         uc_vm_stack_push(uul->vm, ucv_get(this));
1642         uc_vm_stack_push(uul->vm, ucv_get(func));
1643         uc_vm_stack_push(uul->vm, ucv_string_new(type));
1644         uc_vm_stack_push(uul->vm, blob_array_to_ucv(uul->vm, blob_data(msg), blob_len(msg), true));
1645 
1646         if (uc_vm_call(uul->vm, true, 2) == EXCEPTION_NONE)
1647                 ucv_put(uc_vm_stack_pop(uul->vm));
1648         else
1649                 uloop_end();
1650 }
1651 
1652 static uc_value_t *
1653 uc_ubus_listener(uc_vm_t *vm, size_t nargs)
1654 {
1655         uc_value_t *cb, *pattern;
1656         uc_ubus_connection_t *c;
1657         uc_ubus_listener_t *uul;
1658         uc_value_t *res;
1659         int rv;
1660 
1661         conn_get(vm, &c);
1662 
1663         args_get(vm, nargs,
1664                  "event type pattern", UC_STRING, false, &pattern,
1665                  "event callback", UC_CLOSURE, false, &cb);
1666 
1667         uul = xalloc(sizeof(*uul));
1668         uul->vm = vm;
1669         uul->ctx = &c->ctx;
1670         uul->ev.cb = uc_ubus_listener_cb;
1671 
1672         rv = ubus_register_event_handler(&c->ctx, &uul->ev,
1673                                          ucv_string_get(pattern));
1674 
1675         if (rv != UBUS_STATUS_OK) {
1676                 free(uul);
1677                 err_return(rv, "Failed to register listener object");
1678         }
1679 
1680         res = uc_resource_new(listener_type, uul);
1681 
1682         uul->registry_index = listener_reg_add(vm, ucv_get(res), ucv_get(cb));
1683 
1684         ok_return(res);
1685 }
1686 
1687 static uc_value_t *
1688 uc_ubus_event(uc_vm_t *vm, size_t nargs)
1689 {
1690         uc_value_t *eventtype, *eventdata;
1691         uc_ubus_connection_t *c;
1692         int rv;
1693 
1694         conn_get(vm, &c);
1695 
1696         args_get(vm, nargs,
1697                  "event id", UC_STRING, false, &eventtype,
1698                  "event data", UC_OBJECT, true, &eventdata);
1699 
1700         blob_buf_init(&buf, 0);
1701 
1702         if (eventdata)
1703                 ucv_object_to_blob(eventdata, &buf);
1704 
1705         rv = ubus_send_event(&c->ctx, ucv_string_get(eventtype), buf.head);
1706 
1707         if (rv != UBUS_STATUS_OK)
1708                 err_return(rv, "Unable to send event");
1709 
1710         ok_return(ucv_boolean_new(true));
1711 }
1712 
1713 
1714 /*
1715  * ubus subscriptions
1716  * --------------------------------------------------------------------------
1717  */
1718 
1719 static int
1720 uc_ubus_subscriber_notify_cb(struct ubus_context *ctx, struct ubus_object *obj,
1721                                  struct ubus_request_data *req, const char *method,
1722                                  struct blob_attr *msg)
1723 {
1724         struct ubus_subscriber *sub = container_of(obj, struct ubus_subscriber, obj);
1725         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
1726         uc_value_t *this, *func, *reqproto;
1727 
1728         subscriber_reg_get(uusub->vm, uusub->registry_index, &this, &func, NULL);
1729 
1730         if (!ucv_is_callable(func))
1731                 return UBUS_STATUS_METHOD_NOT_FOUND;
1732 
1733         reqproto = ucv_object_new(uusub->vm);
1734 
1735         ucv_object_add(reqproto, "type", ucv_string_new(method));
1736 
1737         ucv_object_add(reqproto, "data",
1738                 blob_array_to_ucv(uusub->vm, blob_data(msg), blob_len(msg), true));
1739 
1740         ucv_object_add(reqproto, "info",
1741                 uc_ubus_object_call_info(uusub->vm, ctx, req, obj, NULL));
1742 
1743         return uc_ubus_handle_reply_common(ctx, req, uusub->vm, this, func, reqproto);
1744 }
1745 
1746 static void
1747 uc_ubus_subscriber_remove_cb(struct ubus_context *ctx,
1748                              struct ubus_subscriber *sub, uint32_t id)
1749 {
1750         uc_ubus_subscriber_t *uusub = container_of(sub, uc_ubus_subscriber_t, sub);
1751         uc_value_t *this, *func;
1752 
1753         subscriber_reg_get(uusub->vm, uusub->registry_index, &this, NULL, &func);
1754 
1755         if (!ucv_is_callable(func))
1756                 return;
1757 
1758         uc_vm_stack_push(uusub->vm, ucv_get(this));
1759         uc_vm_stack_push(uusub->vm, ucv_get(func));
1760         uc_vm_stack_push(uusub->vm, ucv_uint64_new(id));
1761 
1762         if (uc_vm_call(uusub->vm, true, 1) == EXCEPTION_NONE)
1763                 ucv_put(uc_vm_stack_pop(uusub->vm));
1764         else
1765                 uloop_end();
1766 }
1767 
1768 static uc_value_t *
1769 uc_ubus_subscriber_subunsub_common(uc_vm_t *vm, size_t nargs, bool subscribe)
1770 {
1771         uc_ubus_subscriber_t **uusub = uc_fn_this("ubus.subscriber");
1772         uc_value_t *objname;
1773         uint32_t id;
1774         int rv;
1775 
1776         if (!uusub || !*uusub)
1777                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
1778 
1779         args_get(vm, nargs,
1780                  "object name", UC_STRING, false, &objname);
1781 
1782         rv = ubus_lookup_id((*uusub)->ctx, ucv_string_get(objname), &id);
1783 
1784         if (rv != UBUS_STATUS_OK)
1785                 err_return(rv, "Failed to resolve object name '%s'",
1786                            ucv_string_get(objname));
1787 
1788         if (subscribe)
1789                 rv = ubus_subscribe((*uusub)->ctx, &(*uusub)->sub, id);
1790         else
1791                 rv = ubus_unsubscribe((*uusub)->ctx, &(*uusub)->sub, id);
1792 
1793         if (rv != UBUS_STATUS_OK)
1794                 err_return(rv, "Failed to %s object '%s'",
1795                            subscribe ? "subscribe" : "unsubscribe",
1796                            ucv_string_get(objname));
1797 
1798         ok_return(ucv_boolean_new(true));
1799 }
1800 
1801 static uc_value_t *
1802 uc_ubus_subscriber_subscribe(uc_vm_t *vm, size_t nargs)
1803 {
1804         return uc_ubus_subscriber_subunsub_common(vm, nargs, true);
1805 }
1806 
1807 static uc_value_t *
1808 uc_ubus_subscriber_unsubscribe(uc_vm_t *vm, size_t nargs)
1809 {
1810         return uc_ubus_subscriber_subunsub_common(vm, nargs, false);
1811 }
1812 
1813 static int
1814 uc_ubus_subscriber_remove_common(uc_ubus_subscriber_t *uusub)
1815 {
1816         int rv = ubus_unregister_subscriber(uusub->ctx, &uusub->sub);
1817 
1818         if (rv == UBUS_STATUS_OK)
1819                 subscriber_reg_clear(uusub->vm, uusub->registry_index);
1820 
1821         return rv;
1822 }
1823 
1824 static uc_value_t *
1825 uc_ubus_subscriber_remove(uc_vm_t *vm, size_t nargs)
1826 {
1827         uc_ubus_subscriber_t **uusub = uc_fn_this("ubus.subscriber");
1828         int rv;
1829 
1830         if (!uusub || !*uusub)
1831                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid subscriber context");
1832 
1833         rv = uc_ubus_subscriber_remove_common(*uusub);
1834 
1835         if (rv != UBUS_STATUS_OK)
1836                 err_return(rv, "Failed to remove subscriber object");
1837 
1838         ok_return(ucv_boolean_new(true));
1839 }
1840 
1841 static uc_value_t *
1842 uc_ubus_subscriber(uc_vm_t *vm, size_t nargs)
1843 {
1844         uc_value_t *notify_cb, *remove_cb;
1845         uc_ubus_subscriber_t *uusub;
1846         uc_ubus_connection_t *c;
1847         uc_value_t *res;
1848         int rv;
1849 
1850         conn_get(vm, &c);
1851 
1852         args_get(vm, nargs,
1853                  "notify callback", UC_CLOSURE, true, &notify_cb,
1854                  "remove callback", UC_CLOSURE, true, &remove_cb);
1855 
1856         if (!notify_cb && !remove_cb)
1857                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Either notify or remove callback required");
1858 
1859         uusub = xalloc(sizeof(*uusub));
1860         uusub->vm = vm;
1861         uusub->ctx = &c->ctx;
1862 
1863         rv = ubus_register_subscriber(&c->ctx, &uusub->sub);
1864 
1865         if (rv != UBUS_STATUS_OK) {
1866                 free(uusub);
1867                 err_return(rv, "Failed to register subscriber object");
1868         }
1869 
1870         if (notify_cb)
1871                 uusub->sub.cb = uc_ubus_subscriber_notify_cb;
1872 
1873         if (remove_cb)
1874                 uusub->sub.remove_cb = uc_ubus_subscriber_remove_cb;
1875 
1876         res = uc_resource_new(subscriber_type, uusub);
1877 
1878         uusub->registry_index = subscriber_reg_add(vm,
1879                 ucv_get(res), ucv_get(notify_cb), ucv_get(remove_cb));
1880 
1881         ok_return(res);
1882 }
1883 
1884 
1885 /*
1886  * connection methods
1887  * --------------------------------------------------------------------------
1888  */
1889 
1890 static uc_value_t *
1891 uc_ubus_remove(uc_vm_t *vm, size_t nargs)
1892 {
1893         uc_ubus_subscriber_t **uusub;
1894         uc_ubus_connection_t *c;
1895         uc_ubus_object_t **uuobj;
1896         uc_ubus_listener_t **uul;
1897         int rv;
1898 
1899         conn_get(vm, &c);
1900 
1901         uusub = (uc_ubus_subscriber_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.subscriber");
1902         uuobj = (uc_ubus_object_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.object");
1903         uul = (uc_ubus_listener_t **)ucv_resource_dataptr(uc_fn_arg(0), "ubus.listener");
1904 
1905         if (uusub && *uusub) {
1906                 if ((*uusub)->ctx != &c->ctx)
1907                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1908                                    "Subscriber belongs to different connection");
1909 
1910                 rv = uc_ubus_subscriber_remove_common(*uusub);
1911 
1912                 if (rv != UBUS_STATUS_OK)
1913                         err_return(rv, "Unable to remove subscriber");
1914         }
1915         else if (uuobj && *uuobj) {
1916                 if ((*uuobj)->ctx != &c->ctx)
1917                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1918                                    "Object belongs to different connection");
1919 
1920                 rv = uc_ubus_object_remove_common(*uuobj);
1921 
1922                 if (rv != UBUS_STATUS_OK)
1923                         err_return(rv, "Unable to remove object");
1924         }
1925         else if (uul && *uul) {
1926                 if ((*uul)->ctx != &c->ctx)
1927                         err_return(UBUS_STATUS_INVALID_ARGUMENT,
1928                                    "Listener belongs to different connection");
1929 
1930                 rv = uc_ubus_listener_remove_common(*uul);
1931 
1932                 if (rv != UBUS_STATUS_OK)
1933                         err_return(rv, "Unable to remove listener");
1934         }
1935         else {
1936                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Unhandled resource type");
1937         }
1938 
1939         ok_return(ucv_boolean_new(true));
1940 }
1941 
1942 
1943 static uc_value_t *
1944 uc_ubus_disconnect(uc_vm_t *vm, size_t nargs)
1945 {
1946         uc_ubus_connection_t *c;
1947 
1948         conn_get(vm, &c);
1949 
1950         ubus_shutdown(&c->ctx);
1951         c->ctx.sock.fd = -1;
1952 
1953         ok_return(ucv_boolean_new(true));
1954 }
1955 
1956 static uc_value_t *
1957 uc_ubus_defer_completed(uc_vm_t *vm, size_t nargs)
1958 {
1959         uc_ubus_deferred_t **d = uc_fn_this("ubus.deferred");
1960 
1961         if (!d || !*d)
1962                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
1963 
1964         ok_return(ucv_boolean_new((*d)->complete));
1965 }
1966 
1967 static uc_value_t *
1968 uc_ubus_defer_abort(uc_vm_t *vm, size_t nargs)
1969 {
1970         uc_ubus_deferred_t **d = uc_fn_this("ubus.deferred");
1971 
1972         if (!d || !*d)
1973                 err_return(UBUS_STATUS_INVALID_ARGUMENT, "Invalid deferred context");
1974 
1975         if ((*d)->complete)
1976                 ok_return(ucv_boolean_new(false));
1977 
1978         ubus_abort_request((*d)->ctx, &(*d)->request);
1979         uloop_timeout_cancel(&(*d)->timeout);
1980 
1981         request_reg_clear((*d)->vm, (*d)->registry_index);
1982 
1983         n_cb_active--;
1984 
1985         if (have_own_uloop && n_cb_active == 0)
1986                 uloop_end();
1987 
1988         (*d)->complete = true;
1989 
1990         ok_return(ucv_boolean_new(true));
1991 }
1992 
1993 
1994 static const uc_function_list_t global_fns[] = {
1995         { "error",                      uc_ubus_error },
1996         { "connect",            uc_ubus_connect },
1997 };
1998 
1999 static const uc_function_list_t conn_fns[] = {
2000         { "list",                       uc_ubus_list },
2001         { "call",                       uc_ubus_call },
2002         { "defer",                      uc_ubus_defer },
2003         { "publish",            uc_ubus_publish },
2004         { "remove",                     uc_ubus_remove },
2005         { "listener",           uc_ubus_listener },
2006         { "subscriber",         uc_ubus_subscriber },
2007         { "event",                      uc_ubus_event },
2008         { "error",                      uc_ubus_error },
2009         { "disconnect",         uc_ubus_disconnect },
2010 };
2011 
2012 static const uc_function_list_t defer_fns[] = {
2013         { "completed",          uc_ubus_defer_completed },
2014         { "abort",                      uc_ubus_defer_abort },
2015 };
2016 
2017 static const uc_function_list_t object_fns[] = {
2018         { "subscribed",         uc_ubus_object_subscribed },
2019         { "notify",                     uc_ubus_object_notify },
2020         { "remove",                     uc_ubus_object_remove },
2021 };
2022 
2023 static const uc_function_list_t request_fns[] = {
2024         { "reply",                      uc_ubus_request_reply },
2025         { "error",                      uc_ubus_request_error },
2026         { "defer",                      uc_ubus_request_defer },
2027 };
2028 
2029 static const uc_function_list_t notify_fns[] = {
2030         { "completed",          uc_ubus_notify_completed },
2031         { "abort",                      uc_ubus_notify_abort },
2032 };
2033 
2034 static const uc_function_list_t listener_fns[] = {
2035         { "remove",                     uc_ubus_listener_remove },
2036 };
2037 
2038 static const uc_function_list_t subscriber_fns[] = {
2039         { "subscribe",          uc_ubus_subscriber_subscribe },
2040         { "unsubscribe",        uc_ubus_subscriber_unsubscribe },
2041         { "remove",                     uc_ubus_subscriber_remove },
2042 };
2043 
2044 static void free_connection(void *ud) {
2045         uc_ubus_connection_t *conn = ud;
2046 
2047         blob_buf_free(&conn->buf);
2048 
2049         if (conn->ctx.sock.fd >= 0)
2050                 ubus_shutdown(&conn->ctx);
2051 
2052         free(conn);
2053 }
2054 
2055 static void free_deferred(void *ud) {
2056         uc_ubus_deferred_t *defer = ud;
2057 
2058         uloop_timeout_cancel(&defer->timeout);
2059         ucv_put(defer->response);
2060         free(defer);
2061 }
2062 
2063 static void free_object(void *ud) {
2064         uc_ubus_object_t *uuobj = ud;
2065         struct ubus_object *obj = &uuobj->obj;
2066         int i, j;
2067 
2068         for (i = 0; i < obj->n_methods; i++) {
2069                 for (j = 0; j < obj->methods[i].n_policy; j++)
2070                         free((char *)obj->methods[i].policy[j].name);
2071 
2072                 free((char *)obj->methods[i].name);
2073                 free((char *)obj->methods[i].policy);
2074         }
2075 
2076         free(uuobj);
2077 }
2078 
2079 static void free_request(void *ud) {
2080         uc_ubus_request_t *callctx = ud;
2081 
2082         uc_ubus_request_finish(callctx, UBUS_STATUS_TIMEOUT, NULL);
2083         uloop_timeout_cancel(&callctx->timeout);
2084         free(callctx);
2085 }
2086 
2087 static void free_notify(void *ud) {
2088         uc_ubus_notify_t *notifyctx = ud;
2089 
2090         free(notifyctx);
2091 }
2092 
2093 static void free_listener(void *ud) {
2094         uc_ubus_listener_t *listener = ud;
2095 
2096         free(listener);
2097 }
2098 
2099 static void free_subscriber(void *ud) {
2100         uc_ubus_subscriber_t *subscriber = ud;
2101 
2102         free(subscriber);
2103 }
2104 
2105 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
2106 {
2107         uc_function_list_register(scope, global_fns);
2108 
2109 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(UBUS_##x))
2110         ADD_CONST(STATUS_OK);
2111         ADD_CONST(STATUS_INVALID_COMMAND);
2112         ADD_CONST(STATUS_INVALID_ARGUMENT);
2113         ADD_CONST(STATUS_METHOD_NOT_FOUND);
2114         ADD_CONST(STATUS_NOT_FOUND);
2115         ADD_CONST(STATUS_NO_DATA);
2116         ADD_CONST(STATUS_PERMISSION_DENIED);
2117         ADD_CONST(STATUS_TIMEOUT);
2118         ADD_CONST(STATUS_NOT_SUPPORTED);
2119         ADD_CONST(STATUS_UNKNOWN_ERROR);
2120         ADD_CONST(STATUS_CONNECTION_FAILED);
2121 
2122 #ifdef HAVE_NEW_UBUS_STATUS_CODES
2123         ADD_CONST(STATUS_NO_MEMORY);
2124         ADD_CONST(STATUS_PARSE_ERROR);
2125         ADD_CONST(STATUS_SYSTEM_ERROR);
2126 #endif
2127 
2128         conn_type = uc_type_declare(vm, "ubus.connection", conn_fns, free_connection);
2129         defer_type = uc_type_declare(vm, "ubus.deferred", defer_fns, free_deferred);
2130         object_type = uc_type_declare(vm, "ubus.object", object_fns, free_object);
2131         notify_type = uc_type_declare(vm, "ubus.notify", notify_fns, free_notify);
2132         request_type = uc_type_declare(vm, "ubus.request", request_fns, free_request);
2133         listener_type = uc_type_declare(vm, "ubus.listener", listener_fns, free_listener);
2134         subscriber_type = uc_type_declare(vm, "ubus.subscriber", subscriber_fns, free_subscriber);
2135 }
2136 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt