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