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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt