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 ¬ifyctx->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, ¬ifyctx->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, ¬ifyctx->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, ¬ify_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