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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt