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