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

Sources/ucode/lib/ubus.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt