1 /* 2 * Copyright (C) 2012 Jo-Philipp Wich <jow@openwrt.org> 3 * Copyright (C) 2012 John Crispin <blogic@openwrt.org> 4 * Copyright (C) 2016 Iain Fraser <iainf@netduma.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License version 2.1 8 * as published by the Free Software Foundation 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16 #include <unistd.h> 17 #include <libubus.h> 18 #include <libubox/blobmsg.h> 19 #include <libubox/blobmsg_json.h> 20 #include <lauxlib.h> 21 #include <lua.h> 22 23 #define MODNAME "ubus" 24 #define METANAME MODNAME ".meta" 25 26 static lua_State *state; 27 28 struct ubus_lua_connection { 29 int timeout; 30 struct blob_buf buf; 31 struct ubus_context *ctx; 32 }; 33 34 struct ubus_lua_object { 35 struct ubus_object o; 36 int r; 37 int rsubscriber; 38 }; 39 40 struct ubus_lua_event { 41 struct ubus_event_handler e; 42 int r; 43 }; 44 45 struct ubus_lua_subscriber { 46 struct ubus_subscriber s; 47 int rnotify; 48 int rremove; 49 }; 50 51 static int 52 ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table); 53 54 static int 55 ubus_lua_parse_blob_array(lua_State *L, struct blob_attr *attr, size_t len, bool table) 56 { 57 int rv; 58 int idx = 1; 59 size_t rem = len; 60 struct blob_attr *pos; 61 62 lua_newtable(L); 63 64 __blob_for_each_attr(pos, attr, rem) 65 { 66 rv = ubus_lua_parse_blob(L, pos, table); 67 68 if (rv > 1) 69 lua_rawset(L, -3); 70 else if (rv > 0) 71 lua_rawseti(L, -2, idx++); 72 } 73 74 return 1; 75 } 76 77 static int 78 ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table) 79 { 80 int len; 81 int off = 0; 82 void *data; 83 84 if (!blobmsg_check_attr(attr, false)) 85 return 0; 86 87 if (table && blobmsg_name(attr)[0]) 88 { 89 lua_pushstring(L, blobmsg_name(attr)); 90 off++; 91 } 92 93 data = blobmsg_data(attr); 94 len = blobmsg_data_len(attr); 95 96 switch (blob_id(attr)) 97 { 98 case BLOBMSG_TYPE_BOOL: 99 lua_pushboolean(L, *(uint8_t *)data); 100 break; 101 102 case BLOBMSG_TYPE_INT16: 103 lua_pushinteger(L, be16_to_cpu(*(uint16_t *)data)); 104 break; 105 106 case BLOBMSG_TYPE_INT32: 107 lua_pushinteger(L, be32_to_cpu(*(uint32_t *)data)); 108 break; 109 110 case BLOBMSG_TYPE_INT64: 111 lua_pushnumber(L, (double) be64_to_cpu(*(uint64_t *)data)); 112 break; 113 114 case BLOBMSG_TYPE_DOUBLE: 115 { 116 union { 117 double d; 118 uint64_t u64; 119 } v; 120 v.u64 = be64_to_cpu(*(uint64_t *)data); 121 lua_pushnumber(L, v.d); 122 } 123 break; 124 125 case BLOBMSG_TYPE_STRING: 126 lua_pushstring(L, data); 127 break; 128 129 case BLOBMSG_TYPE_ARRAY: 130 ubus_lua_parse_blob_array(L, data, len, false); 131 break; 132 133 case BLOBMSG_TYPE_TABLE: 134 ubus_lua_parse_blob_array(L, data, len, true); 135 break; 136 137 default: 138 lua_pushnil(L); 139 break; 140 } 141 142 return off + 1; 143 } 144 145 146 static bool 147 ubus_lua_format_blob_is_array(lua_State *L) 148 { 149 lua_Integer prv = 0; 150 lua_Integer cur = 0; 151 152 /* Find out whether table is array-like */ 153 for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) 154 { 155 #ifdef LUA_TINT 156 if (lua_type(L, -2) != LUA_TNUMBER && lua_type(L, -2) != LUA_TINT) 157 #else 158 if (lua_type(L, -2) != LUA_TNUMBER) 159 #endif 160 { 161 lua_pop(L, 2); 162 return false; 163 } 164 165 cur = lua_tointeger(L, -2); 166 167 if ((cur - 1) != prv) 168 { 169 lua_pop(L, 2); 170 return false; 171 } 172 173 prv = cur; 174 } 175 176 return true; 177 } 178 179 static int 180 ubus_lua_format_blob_array(lua_State *L, struct blob_buf *b, bool table); 181 182 static int 183 ubus_lua_format_blob(lua_State *L, struct blob_buf *b, bool table) 184 { 185 void *c; 186 bool rv = true; 187 const char *key = table ? lua_tostring(L, -2) : NULL; 188 189 switch (lua_type(L, -1)) 190 { 191 case LUA_TBOOLEAN: 192 blobmsg_add_u8(b, key, (uint8_t)lua_toboolean(L, -1)); 193 break; 194 195 #ifdef LUA_TINT 196 case LUA_TINT: 197 #endif 198 case LUA_TNUMBER: 199 if ((uint64_t)lua_tonumber(L, -1) > INT_MAX) 200 blobmsg_add_u64(b, key, (uint64_t)lua_tonumber(L, -1)); 201 else 202 blobmsg_add_u32(b, key, (uint32_t)lua_tointeger(L, -1)); 203 break; 204 205 case LUA_TSTRING: 206 case LUA_TUSERDATA: 207 case LUA_TLIGHTUSERDATA: 208 blobmsg_add_string(b, key, lua_tostring(L, -1)); 209 break; 210 211 case LUA_TTABLE: 212 if (ubus_lua_format_blob_is_array(L)) 213 { 214 c = blobmsg_open_array(b, key); 215 rv = ubus_lua_format_blob_array(L, b, false); 216 blobmsg_close_array(b, c); 217 } 218 else 219 { 220 c = blobmsg_open_table(b, key); 221 rv = ubus_lua_format_blob_array(L, b, true); 222 blobmsg_close_table(b, c); 223 } 224 break; 225 226 default: 227 rv = false; 228 break; 229 } 230 231 return rv; 232 } 233 234 static int 235 ubus_lua_format_blob_array(lua_State *L, struct blob_buf *b, bool table) 236 { 237 for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) 238 { 239 if (!ubus_lua_format_blob(L, b, table)) 240 { 241 lua_pop(L, 1); 242 return false; 243 } 244 } 245 246 return true; 247 } 248 249 250 static int 251 ubus_lua_connect(lua_State *L) 252 { 253 struct ubus_lua_connection *c; 254 const char *sockpath = luaL_optstring(L, 1, NULL); 255 int timeout = luaL_optint(L, 2, 30); 256 257 if ((c = lua_newuserdata(L, sizeof(*c))) != NULL && 258 (c->ctx = ubus_connect(sockpath)) != NULL) 259 { 260 ubus_add_uloop(c->ctx); 261 c->timeout = timeout; 262 memset(&c->buf, 0, sizeof(c->buf)); 263 luaL_getmetatable(L, METANAME); 264 lua_setmetatable(L, -2); 265 return 1; 266 } 267 268 /* NB: no errors from ubus_connect() yet */ 269 lua_pushnil(L); 270 lua_pushinteger(L, UBUS_STATUS_UNKNOWN_ERROR); 271 return 2; 272 } 273 274 275 static void 276 ubus_lua_objects_cb(struct ubus_context *c, struct ubus_object_data *o, void *p) 277 { 278 lua_State *L = (lua_State *)p; 279 280 lua_pushstring(L, o->path); 281 lua_rawseti(L, -2, lua_objlen(L, -2) + 1); 282 } 283 284 static int 285 ubus_lua_objects(lua_State *L) 286 { 287 int rv; 288 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 289 const char *path = (lua_gettop(L) >= 2) ? luaL_checkstring(L, 2) : NULL; 290 291 lua_newtable(L); 292 rv = ubus_lookup(c->ctx, path, ubus_lua_objects_cb, L); 293 294 if (rv != UBUS_STATUS_OK) 295 { 296 lua_pop(L, 1); 297 lua_pushnil(L); 298 lua_pushinteger(L, rv); 299 return 2; 300 } 301 302 return 1; 303 } 304 305 static int 306 ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj, 307 struct ubus_request_data *req, const char *method, 308 struct blob_attr *msg) 309 { 310 struct ubus_lua_object *o = container_of(obj, struct ubus_lua_object, o); 311 int rv = 0; 312 313 lua_getglobal(state, "__ubus_cb"); 314 lua_rawgeti(state, -1, o->r); 315 lua_getfield(state, -1, method); 316 lua_remove(state, -2); 317 lua_remove(state, -2); 318 319 if (lua_isfunction(state, -1)) { 320 lua_pushlightuserdata(state, req); 321 if (!msg) 322 lua_pushnil(state); 323 else 324 ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); 325 lua_call(state, 2, 1); 326 if (lua_isnumber(state, -1)) 327 rv = lua_tonumber(state, -1); 328 } 329 330 lua_pop(state, 1); 331 332 return rv; 333 } 334 335 static int lua_gettablelen(lua_State *L, int index) 336 { 337 int cnt = 0; 338 339 lua_pushnil(L); 340 index -= 1; 341 while (lua_next(L, index) != 0) { 342 cnt++; 343 lua_pop(L, 1); 344 } 345 346 return cnt; 347 } 348 349 static int ubus_lua_reply(lua_State *L) 350 { 351 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 352 struct ubus_request_data *req; 353 354 luaL_checktype(L, 3, LUA_TTABLE); 355 blob_buf_init(&c->buf, 0); 356 357 if (!ubus_lua_format_blob_array(L, &c->buf, true)) 358 { 359 lua_pushnil(L); 360 lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); 361 return 2; 362 } 363 364 req = lua_touserdata(L, 2); 365 ubus_send_reply(c->ctx, req, c->buf.head); 366 367 return 0; 368 } 369 370 static int ubus_lua_defer_request(lua_State *L) 371 { 372 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 373 struct ubus_request_data *req = lua_touserdata(L, 2); 374 struct ubus_request_data *new_req = lua_newuserdata(L, sizeof(struct ubus_request_data)); 375 ubus_defer_request(c->ctx, req, new_req); 376 377 return 1; 378 } 379 380 static int ubus_lua_complete_deferred_request(lua_State *L) 381 { 382 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 383 struct ubus_request_data *req = lua_touserdata(L, 2); 384 int ret = luaL_checkinteger(L, 3); 385 ubus_complete_deferred_request(c->ctx, req, ret); 386 387 return 0; 388 } 389 390 static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) 391 { 392 struct blobmsg_policy *p; 393 int plen; 394 int pidx = 0; 395 396 /* get the function pointer */ 397 lua_pushinteger(L, 1); 398 lua_gettable(L, -2); 399 400 /* get the policy table */ 401 lua_pushinteger(L, 2); 402 lua_gettable(L, -3); 403 404 /* check if the method table is valid */ 405 if ((lua_type(L, -2) != LUA_TFUNCTION) || 406 (lua_type(L, -1) != LUA_TTABLE) || 407 lua_objlen(L, -1)) { 408 lua_pop(L, 2); 409 return 1; 410 } 411 412 /* store function pointer */ 413 lua_pushvalue(L, -2); 414 lua_setfield(L, -6, lua_tostring(L, -5)); 415 416 /* 417 * lua_tostring() returns a pointer into a Lua-managed string; the 418 * method/object/policy structures outlive the caller's argument table, 419 * which may be garbage-collected (its strings then freed) long before 420 * the object is re-registered on reconnect or consulted on an invoke. 421 * Keep an owned copy. 422 */ 423 m->name = strdup(lua_tostring(L, -4)); 424 if (!m->name) { 425 lua_pop(L, 2); 426 return 1; 427 } 428 m->handler = ubus_method_handler; 429 430 plen = lua_gettablelen(L, -1); 431 432 /* exit if policy table is empty */ 433 if (!plen) { 434 lua_pop(L, 2); 435 return 0; 436 } 437 438 /* setup the policy pointers */ 439 p = calloc(plen, sizeof(struct blobmsg_policy)); 440 if (!p) { 441 lua_pop(L, 2); 442 return 1; 443 } 444 445 m->policy = p; 446 lua_pushnil(L); 447 while (lua_next(L, -2) != 0) { 448 int val = lua_tointeger(L, -1); 449 450 /* check if the policy is valid */ 451 if ((lua_type(L, -2) != LUA_TSTRING) || 452 (lua_type(L, -1) != LUA_TNUMBER) || 453 (val < 0) || 454 (val > BLOBMSG_TYPE_LAST)) { 455 lua_pop(L, 1); 456 continue; 457 } 458 p[pidx].name = strdup(lua_tostring(L, -2)); 459 if (!p[pidx].name) { 460 lua_pop(L, 1); 461 continue; 462 } 463 p[pidx].type = val; 464 lua_pop(L, 1); 465 pidx++; 466 } 467 468 m->n_policy = pidx; 469 lua_pop(L, 2); 470 471 return 0; 472 } 473 474 static void 475 ubus_new_sub_cb(struct ubus_context *ctx, struct ubus_object *obj) 476 { 477 struct ubus_lua_object *luobj; 478 479 luobj = container_of(obj, struct ubus_lua_object, o); 480 481 lua_getglobal(state, "__ubus_cb_publisher"); 482 lua_rawgeti(state, -1, luobj->rsubscriber); 483 lua_remove(state, -2); 484 485 if (lua_isfunction(state, -1)) { 486 lua_pushnumber(state, luobj->o.has_subscribers ); 487 lua_call(state, 1, 0); 488 } else { 489 lua_pop(state, 1); 490 } 491 } 492 493 static void 494 ubus_lua_load_newsub_cb( lua_State *L, struct ubus_lua_object *obj ) 495 { 496 /* keep ref to func */ 497 lua_getglobal(L, "__ubus_cb_publisher"); 498 lua_pushvalue(L, -2); 499 obj->rsubscriber = luaL_ref(L, -2); 500 lua_pop(L, 1); 501 502 /* real callback */ 503 obj->o.subscribe_cb = ubus_new_sub_cb; 504 return; 505 } 506 507 static struct ubus_object* ubus_lua_load_object(lua_State *L) 508 { 509 struct ubus_lua_object *obj = NULL; 510 int mlen = lua_gettablelen(L, -1); 511 struct ubus_method *m = NULL; 512 int midx = 0; 513 514 /* setup object pointers */ 515 obj = calloc(1, sizeof(struct ubus_lua_object)); 516 if (!obj) 517 return NULL; 518 519 /* owned copy: the Lua key string may be collected before reconnect */ 520 obj->o.name = strdup(lua_tostring(L, -2)); 521 if (!obj->o.name) { 522 free(obj); 523 return NULL; 524 } 525 526 /* setup method pointers */ 527 if (mlen > 0) { 528 m = calloc(mlen, sizeof(struct ubus_method)); 529 if (!m) { 530 free((void *) obj->o.name); 531 free(obj); 532 return NULL; 533 } 534 } 535 obj->o.methods = m; 536 537 /* setup type pointers */ 538 obj->o.type = calloc(1, sizeof(struct ubus_object_type)); 539 if (!obj->o.type) { 540 free(m); 541 free((void *) obj->o.name); 542 free(obj); 543 return NULL; 544 } 545 546 obj->o.type->name = strdup(lua_tostring(L, -2)); 547 if (!obj->o.type->name) { 548 free(obj->o.type); 549 free(m); 550 free((void *) obj->o.name); 551 free(obj); 552 return NULL; 553 } 554 obj->o.type->id = 0; 555 obj->o.type->methods = obj->o.methods; 556 557 /* create the callback lookup table */ 558 lua_createtable(L, 1, 0); 559 lua_getglobal(L, "__ubus_cb"); 560 lua_pushvalue(L, -2); 561 obj->r = luaL_ref(L, -2); 562 lua_pop(L, 1); 563 564 /* scan each method */ 565 lua_pushnil(L); 566 while (lua_next(L, -3) != 0) { 567 /* check if its the subscriber notification callback */ 568 if( lua_type( L, -2 ) == LUA_TSTRING && 569 lua_type( L, -1 ) == LUA_TFUNCTION ){ 570 if( !strcmp( lua_tostring( L, -2 ), "__subscriber_cb" ) ) 571 ubus_lua_load_newsub_cb( L, obj ); 572 } 573 574 /* check if it looks like a method */ 575 if ((lua_type(L, -2) != LUA_TSTRING) || 576 (lua_type(L, -1) != LUA_TTABLE) || 577 !lua_objlen(L, -1)) { 578 lua_pop(L, 1); 579 continue; 580 } 581 582 if (!ubus_lua_load_methods(L, &m[midx])) 583 midx++; 584 lua_pop(L, 1); 585 } 586 587 obj->o.type->n_methods = obj->o.n_methods = midx; 588 589 /* pop the callback table */ 590 lua_pop(L, 1); 591 592 return &obj->o; 593 } 594 595 static int ubus_lua_add(lua_State *L) 596 { 597 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 598 599 /* verify top level object */ 600 if (!lua_istable(L, 2)) { 601 lua_pushstring(L, "you need to pass a table"); 602 return lua_error(L); 603 } 604 605 /* scan each object */ 606 lua_pushnil(L); 607 while (lua_next(L, -2) != 0) { 608 struct ubus_object *obj = NULL; 609 610 /* check if the object has a table of methods */ 611 if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TTABLE)) { 612 obj = ubus_lua_load_object(L); 613 614 if (obj){ 615 ubus_add_object(c->ctx, obj); 616 617 /* allow future reference of ubus obj */ 618 lua_pushstring(state,"__ubusobj"); 619 lua_pushlightuserdata(state, obj); 620 lua_settable(state,-3); 621 } 622 } 623 lua_pop(L, 1); 624 } 625 626 return 0; 627 } 628 629 static int 630 ubus_lua_notify( lua_State *L ) 631 { 632 struct ubus_lua_connection *c; 633 struct ubus_object *obj; 634 const char* method; 635 636 c = luaL_checkudata(L, 1, METANAME); 637 method = luaL_checkstring(L, 3); 638 luaL_checktype(L, 4, LUA_TTABLE); 639 640 if( !lua_islightuserdata( L, 2 ) ){ 641 lua_pushfstring( L, "Invald 2nd parameter, expected ubus obj ref" ); 642 return lua_error( L ); 643 } 644 obj = lua_touserdata( L, 2 ); 645 646 /* create parameters from table */ 647 blob_buf_init(&c->buf, 0); 648 if( !ubus_lua_format_blob_array( L, &c->buf, true ) ){ 649 lua_pushfstring( L, "Invalid 4th parameter, expected table of arguments" ); 650 return lua_error( L ); 651 } 652 653 ubus_notify( c->ctx, obj, method, c->buf.head, -1 ); 654 return 0; 655 } 656 657 static void 658 ubus_lua_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p) 659 { 660 lua_State *L = (lua_State *)p; 661 662 if (!o->signature) 663 return; 664 665 ubus_lua_parse_blob_array(L, blob_data(o->signature), blob_len(o->signature), true); 666 } 667 668 static int 669 ubus_lua_signatures(lua_State *L) 670 { 671 int rv; 672 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 673 const char *path = luaL_checkstring(L, 2); 674 675 rv = ubus_lookup(c->ctx, path, ubus_lua_signatures_cb, L); 676 677 if (rv != UBUS_STATUS_OK) 678 { 679 lua_pop(L, 1); 680 lua_pushnil(L); 681 lua_pushinteger(L, rv); 682 return 2; 683 } 684 685 return 1; 686 } 687 688 689 static void 690 ubus_lua_call_cb(struct ubus_request *req, int type, struct blob_attr *msg) 691 { 692 lua_State *L = (lua_State *)req->priv; 693 694 if (!msg && L) 695 lua_pushnil(L); 696 697 if (msg && L) 698 ubus_lua_parse_blob_array(L, blob_data(msg), blob_len(msg), true); 699 } 700 701 static int 702 ubus_lua_call(lua_State *L) 703 { 704 int rv, top; 705 uint32_t id; 706 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 707 const char *path = luaL_checkstring(L, 2); 708 const char *func = luaL_checkstring(L, 3); 709 710 luaL_checktype(L, 4, LUA_TTABLE); 711 blob_buf_init(&c->buf, 0); 712 713 if (!ubus_lua_format_blob_array(L, &c->buf, true)) 714 { 715 lua_pushnil(L); 716 lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); 717 return 2; 718 } 719 720 rv = ubus_lookup_id(c->ctx, path, &id); 721 722 if (rv) 723 { 724 lua_pushnil(L); 725 lua_pushinteger(L, rv); 726 return 2; 727 } 728 729 top = lua_gettop(L); 730 rv = ubus_invoke(c->ctx, id, func, c->buf.head, ubus_lua_call_cb, L, c->timeout * 1000); 731 732 if (rv != UBUS_STATUS_OK) 733 { 734 lua_pop(L, 1); 735 lua_pushnil(L); 736 lua_pushinteger(L, rv); 737 return 2; 738 } 739 740 return lua_gettop(L) - top; 741 } 742 743 static void 744 ubus_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, 745 const char *type, struct blob_attr *msg) 746 { 747 struct ubus_lua_event *listener = container_of(ev, struct ubus_lua_event, e); 748 749 lua_getglobal(state, "__ubus_cb_event"); 750 lua_rawgeti(state, -1, listener->r); 751 lua_remove(state, -2); 752 753 if (lua_isfunction(state, -1)) { 754 ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); 755 lua_call(state, 1, 0); 756 } else { 757 lua_pop(state, 1); 758 } 759 } 760 761 static struct ubus_event_handler* 762 ubus_lua_load_event(lua_State *L) 763 { 764 struct ubus_lua_event* event = NULL; 765 766 event = calloc(1, sizeof(struct ubus_lua_event)); 767 if (!event) 768 return NULL; 769 770 event->e.cb = ubus_event_handler; 771 772 /* update the event callback lookup table */ 773 lua_getglobal(L, "__ubus_cb_event"); 774 lua_pushvalue(L, -2); 775 event->r = luaL_ref(L, -2); 776 lua_pop(L, 1); 777 778 return &event->e; 779 } 780 781 static int 782 ubus_lua_listen(lua_State *L) { 783 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 784 785 /* verify top level object */ 786 luaL_checktype(L, 2, LUA_TTABLE); 787 788 /* scan each object */ 789 lua_pushnil(L); 790 while (lua_next(L, -2) != 0) { 791 struct ubus_event_handler *listener; 792 793 /* check if the key is a string and the value is a method */ 794 if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TFUNCTION)) { 795 listener = ubus_lua_load_event(L); 796 if(listener != NULL) { 797 ubus_register_event_handler(c->ctx, listener, lua_tostring(L, -2)); 798 } 799 } 800 lua_pop(L, 1); 801 } 802 return 0; 803 } 804 805 static void 806 ubus_sub_remove_handler(struct ubus_context *ctx, struct ubus_subscriber *s, 807 uint32_t id) 808 { 809 struct ubus_lua_subscriber *sub; 810 811 sub = container_of(s, struct ubus_lua_subscriber, s); 812 813 lua_getglobal(state, "__ubus_cb_subscribe"); 814 lua_rawgeti(state, -1, sub->rremove); 815 lua_remove(state, -2); 816 817 if (lua_isfunction(state, -1)) { 818 lua_call(state, 0, 0); 819 } else { 820 lua_pop(state, 1); 821 } 822 } 823 824 static int 825 ubus_sub_notify_handler(struct ubus_context *ctx, struct ubus_object *obj, 826 struct ubus_request_data *req, const char *method, 827 struct blob_attr *msg) 828 { 829 struct ubus_subscriber *s; 830 struct ubus_lua_subscriber *sub; 831 832 s = container_of(obj, struct ubus_subscriber, obj); 833 sub = container_of(s, struct ubus_lua_subscriber, s); 834 835 lua_getglobal(state, "__ubus_cb_subscribe"); 836 lua_rawgeti(state, -1, sub->rnotify); 837 lua_remove(state, -2); 838 839 if (lua_isfunction(state, -1)) { 840 if( msg ){ 841 ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); 842 } else { 843 lua_pushnil(state); 844 } 845 lua_pushstring(state, method); 846 lua_call(state, 2, 0); 847 } else { 848 lua_pop(state, 1); 849 } 850 851 return 0; 852 } 853 854 855 856 static int 857 ubus_lua_do_subscribe( struct ubus_context *ctx, lua_State *L, const char* target, 858 int idxnotify, int idxremove ) 859 { 860 uint32_t id; 861 int status; 862 struct ubus_lua_subscriber *sub; 863 864 if( ( status = ubus_lookup_id( ctx, target, &id ) ) ){ 865 lua_pushfstring( L, "Unable find target, status=%d", status ); 866 return lua_error( L ); 867 } 868 869 sub = calloc( 1, sizeof( struct ubus_lua_subscriber ) ); 870 if( !sub ){ 871 lua_pushstring( L, "Out of memory" ); 872 return lua_error( L ); 873 } 874 875 if( idxnotify ){ 876 lua_getglobal(L, "__ubus_cb_subscribe"); 877 lua_pushvalue(L, idxnotify); 878 sub->rnotify = luaL_ref(L, -2); 879 lua_pop(L, 1); 880 sub->s.cb = ubus_sub_notify_handler; 881 } 882 883 if( idxremove ){ 884 lua_getglobal(L, "__ubus_cb_subscribe"); 885 lua_pushvalue(L, idxremove); 886 sub->rremove = luaL_ref(L, -2); 887 lua_pop(L, 1); 888 sub->s.remove_cb = ubus_sub_remove_handler; 889 } 890 891 if( ( status = ubus_register_subscriber( ctx, &sub->s ) ) ){ 892 lua_pushfstring( L, "Failed to register subscriber, status=%d", status ); 893 return lua_error( L ); 894 } 895 896 if( ( status = ubus_subscribe( ctx, &sub->s, id) ) ){ 897 lua_pushfstring( L, "Failed to register subscriber, status=%d", status ); 898 return lua_error( L ); 899 } 900 901 return 0; 902 } 903 904 static int 905 ubus_lua_subscribe(lua_State *L) { 906 int idxnotify, idxremove, stackstart; 907 struct ubus_lua_connection *c; 908 const char* target; 909 910 idxnotify = idxremove = 0; 911 stackstart = lua_gettop( L ); 912 913 914 c = luaL_checkudata(L, 1, METANAME); 915 target = luaL_checkstring(L, 2); 916 luaL_checktype(L, 3, LUA_TTABLE); 917 918 919 lua_pushstring( L, "notify"); 920 lua_gettable( L, 3 ); 921 if( lua_type( L, -1 ) == LUA_TFUNCTION ){ 922 idxnotify = lua_gettop( L ); 923 } else { 924 lua_pop( L, 1 ); 925 } 926 927 lua_pushstring( L, "remove"); 928 lua_gettable( L, 3 ); 929 if( lua_type( L, -1 ) == LUA_TFUNCTION ){ 930 idxremove = lua_gettop( L ); 931 } else { 932 lua_pop( L, 1 ); 933 } 934 935 if( idxnotify ) 936 ubus_lua_do_subscribe( c->ctx, L, target, idxnotify, idxremove ); 937 938 if( lua_gettop( L ) > stackstart ) 939 lua_pop( L, lua_gettop( L ) - stackstart ); 940 941 return 0; 942 } 943 944 static int 945 ubus_lua_send(lua_State *L) 946 { 947 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 948 const char *event = luaL_checkstring(L, 2); 949 950 if (*event == 0) 951 return luaL_argerror(L, 2, "no event name"); 952 953 // Event content convert to ubus form 954 luaL_checktype(L, 3, LUA_TTABLE); 955 blob_buf_init(&c->buf, 0); 956 957 if (!ubus_lua_format_blob_array(L, &c->buf, true)) { 958 lua_pushnil(L); 959 lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); 960 return 2; 961 } 962 963 // Send the event 964 ubus_send_event(c->ctx, event, c->buf.head); 965 966 return 0; 967 } 968 969 970 971 static int 972 ubus_lua__gc(lua_State *L) 973 { 974 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 975 976 blob_buf_free(&c->buf); 977 if (c->ctx != NULL) 978 { 979 ubus_free(c->ctx); 980 memset(c, 0, sizeof(*c)); 981 } 982 983 return 0; 984 } 985 986 static const luaL_Reg ubus[] = { 987 { "connect", ubus_lua_connect }, 988 { "objects", ubus_lua_objects }, 989 { "add", ubus_lua_add }, 990 { "notify", ubus_lua_notify }, 991 { "reply", ubus_lua_reply }, 992 { "defer_request", ubus_lua_defer_request }, 993 { "complete_deferred_request", ubus_lua_complete_deferred_request }, 994 { "signatures", ubus_lua_signatures }, 995 { "call", ubus_lua_call }, 996 { "close", ubus_lua__gc }, 997 { "listen", ubus_lua_listen }, 998 { "send", ubus_lua_send }, 999 { "subscribe", ubus_lua_subscribe }, 1000 { "__gc", ubus_lua__gc }, 1001 { NULL, NULL }, 1002 }; 1003 1004 /* avoid missing prototype warning */ 1005 int luaopen_ubus(lua_State *L); 1006 1007 int 1008 luaopen_ubus(lua_State *L) 1009 { 1010 /* create metatable */ 1011 luaL_newmetatable(L, METANAME); 1012 1013 /* metatable.__index = metatable */ 1014 lua_pushvalue(L, -1); 1015 lua_setfield(L, -2, "__index"); 1016 1017 /* fill metatable */ 1018 luaL_register(L, NULL, ubus); 1019 lua_pop(L, 1); 1020 1021 /* create module */ 1022 luaL_register(L, MODNAME, ubus); 1023 1024 /* set some enum defines */ 1025 lua_pushinteger(L, BLOBMSG_TYPE_ARRAY); 1026 lua_setfield(L, -2, "ARRAY"); 1027 lua_pushinteger(L, BLOBMSG_TYPE_TABLE); 1028 lua_setfield(L, -2, "TABLE"); 1029 lua_pushinteger(L, BLOBMSG_TYPE_STRING); 1030 lua_setfield(L, -2, "STRING"); 1031 lua_pushinteger(L, BLOBMSG_TYPE_INT64); 1032 lua_setfield(L, -2, "INT64"); 1033 lua_pushinteger(L, BLOBMSG_TYPE_INT32); 1034 lua_setfield(L, -2, "INT32"); 1035 lua_pushinteger(L, BLOBMSG_TYPE_INT16); 1036 lua_setfield(L, -2, "INT16"); 1037 lua_pushinteger(L, BLOBMSG_TYPE_INT8); 1038 lua_setfield(L, -2, "INT8"); 1039 lua_pushinteger(L, BLOBMSG_TYPE_DOUBLE); 1040 lua_setfield(L, -2, "DOUBLE"); 1041 lua_pushinteger(L, BLOBMSG_TYPE_BOOL); 1042 lua_setfield(L, -2, "BOOLEAN"); 1043 1044 /* used in our callbacks */ 1045 state = L; 1046 1047 /* create the callback table */ 1048 lua_createtable(L, 1, 0); 1049 lua_setglobal(L, "__ubus_cb"); 1050 1051 /* create the event table */ 1052 lua_createtable(L, 1, 0); 1053 lua_setglobal(L, "__ubus_cb_event"); 1054 1055 /* create the subscriber table */ 1056 lua_createtable(L, 1, 0); 1057 lua_setglobal(L, "__ubus_cb_subscribe"); 1058 1059 /* create the publisher table - notifications of new subs */ 1060 lua_createtable(L, 1, 0); 1061 lua_setglobal(L, "__ubus_cb_publisher"); 1062 return 0; 1063 } 1064
This page was automatically generated by LXR 0.3.1. • OpenWrt