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