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 290 lua_newtable(L); 291 rv = ubus_lookup(c->ctx, NULL, ubus_lua_objects_cb, L); 292 293 if (rv != UBUS_STATUS_OK) 294 { 295 lua_pop(L, 1); 296 lua_pushnil(L); 297 lua_pushinteger(L, rv); 298 return 2; 299 } 300 301 return 1; 302 } 303 304 static int 305 ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj, 306 struct ubus_request_data *req, const char *method, 307 struct blob_attr *msg) 308 { 309 struct ubus_lua_object *o = container_of(obj, struct ubus_lua_object, o); 310 int rv = 0; 311 312 lua_getglobal(state, "__ubus_cb"); 313 lua_rawgeti(state, -1, o->r); 314 lua_getfield(state, -1, method); 315 lua_remove(state, -2); 316 lua_remove(state, -2); 317 318 if (lua_isfunction(state, -1)) { 319 lua_pushlightuserdata(state, req); 320 if (!msg) 321 lua_pushnil(state); 322 else 323 ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); 324 lua_call(state, 2, 1); 325 if (lua_isnumber(state, -1)) 326 rv = lua_tonumber(state, -1); 327 } 328 329 lua_pop(state, 1); 330 331 return rv; 332 } 333 334 static int lua_gettablelen(lua_State *L, int index) 335 { 336 int cnt = 0; 337 338 lua_pushnil(L); 339 index -= 1; 340 while (lua_next(L, index) != 0) { 341 cnt++; 342 lua_pop(L, 1); 343 } 344 345 return cnt; 346 } 347 348 static int ubus_lua_reply(lua_State *L) 349 { 350 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 351 struct ubus_request_data *req; 352 353 luaL_checktype(L, 3, LUA_TTABLE); 354 blob_buf_init(&c->buf, 0); 355 356 if (!ubus_lua_format_blob_array(L, &c->buf, true)) 357 { 358 lua_pushnil(L); 359 lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); 360 return 2; 361 } 362 363 req = lua_touserdata(L, 2); 364 ubus_send_reply(c->ctx, req, c->buf.head); 365 366 return 0; 367 } 368 369 static int ubus_lua_defer_request(lua_State *L) 370 { 371 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 372 struct ubus_request_data *req = lua_touserdata(L, 2); 373 struct ubus_request_data *new_req = lua_newuserdata(L, sizeof(struct ubus_request_data)); 374 ubus_defer_request(c->ctx, req, new_req); 375 376 return 1; 377 } 378 379 static int ubus_lua_complete_deferred_request(lua_State *L) 380 { 381 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 382 struct ubus_request_data *req = lua_touserdata(L, 2); 383 int ret = luaL_checkinteger(L, 3); 384 ubus_complete_deferred_request(c->ctx, req, ret); 385 386 return 0; 387 } 388 389 static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) 390 { 391 struct blobmsg_policy *p; 392 int plen; 393 int pidx = 0; 394 395 /* get the function pointer */ 396 lua_pushinteger(L, 1); 397 lua_gettable(L, -2); 398 399 /* get the policy table */ 400 lua_pushinteger(L, 2); 401 lua_gettable(L, -3); 402 403 /* check if the method table is valid */ 404 if ((lua_type(L, -2) != LUA_TFUNCTION) || 405 (lua_type(L, -1) != LUA_TTABLE) || 406 lua_objlen(L, -1)) { 407 lua_pop(L, 2); 408 return 1; 409 } 410 411 /* store function pointer */ 412 lua_pushvalue(L, -2); 413 lua_setfield(L, -6, lua_tostring(L, -5)); 414 415 m->name = lua_tostring(L, -4); 416 m->handler = ubus_method_handler; 417 418 plen = lua_gettablelen(L, -1); 419 420 /* exit if policy table is empty */ 421 if (!plen) { 422 lua_pop(L, 2); 423 return 0; 424 } 425 426 /* setup the policy pointers */ 427 p = calloc(plen, sizeof(struct blobmsg_policy)); 428 if (!p) 429 return 1; 430 431 m->policy = p; 432 lua_pushnil(L); 433 while (lua_next(L, -2) != 0) { 434 int val = lua_tointeger(L, -1); 435 436 /* check if the policy is valid */ 437 if ((lua_type(L, -2) != LUA_TSTRING) || 438 (lua_type(L, -1) != LUA_TNUMBER) || 439 (val < 0) || 440 (val > BLOBMSG_TYPE_LAST)) { 441 lua_pop(L, 1); 442 continue; 443 } 444 p[pidx].name = lua_tostring(L, -2); 445 p[pidx].type = val; 446 lua_pop(L, 1); 447 pidx++; 448 } 449 450 m->n_policy = pidx; 451 lua_pop(L, 2); 452 453 return 0; 454 } 455 456 static void 457 ubus_new_sub_cb(struct ubus_context *ctx, struct ubus_object *obj) 458 { 459 struct ubus_lua_object *luobj; 460 461 luobj = container_of(obj, struct ubus_lua_object, o); 462 463 lua_getglobal(state, "__ubus_cb_publisher"); 464 lua_rawgeti(state, -1, luobj->rsubscriber); 465 lua_remove(state, -2); 466 467 if (lua_isfunction(state, -1)) { 468 lua_pushnumber(state, luobj->o.has_subscribers ); 469 lua_call(state, 1, 0); 470 } else { 471 lua_pop(state, 1); 472 } 473 } 474 475 static void 476 ubus_lua_load_newsub_cb( lua_State *L, struct ubus_lua_object *obj ) 477 { 478 /* keep ref to func */ 479 lua_getglobal(L, "__ubus_cb_publisher"); 480 lua_pushvalue(L, -2); 481 obj->rsubscriber = luaL_ref(L, -2); 482 lua_pop(L, 1); 483 484 /* real callback */ 485 obj->o.subscribe_cb = ubus_new_sub_cb; 486 return; 487 } 488 489 static struct ubus_object* ubus_lua_load_object(lua_State *L) 490 { 491 struct ubus_lua_object *obj = NULL; 492 int mlen = lua_gettablelen(L, -1); 493 struct ubus_method *m; 494 int midx = 0; 495 496 /* setup object pointers */ 497 obj = calloc(1, sizeof(struct ubus_lua_object)); 498 if (!obj) 499 return NULL; 500 501 obj->o.name = lua_tostring(L, -2); 502 503 /* setup method pointers */ 504 m = calloc(mlen, sizeof(struct ubus_method)); 505 obj->o.methods = m; 506 507 /* setup type pointers */ 508 obj->o.type = calloc(1, sizeof(struct ubus_object_type)); 509 if (!obj->o.type) { 510 free(obj); 511 return NULL; 512 } 513 514 obj->o.type->name = lua_tostring(L, -2); 515 obj->o.type->id = 0; 516 obj->o.type->methods = obj->o.methods; 517 518 /* create the callback lookup table */ 519 lua_createtable(L, 1, 0); 520 lua_getglobal(L, "__ubus_cb"); 521 lua_pushvalue(L, -2); 522 obj->r = luaL_ref(L, -2); 523 lua_pop(L, 1); 524 525 /* scan each method */ 526 lua_pushnil(L); 527 while (lua_next(L, -3) != 0) { 528 /* check if its the subscriber notification callback */ 529 if( lua_type( L, -2 ) == LUA_TSTRING && 530 lua_type( L, -1 ) == LUA_TFUNCTION ){ 531 if( !strcmp( lua_tostring( L, -2 ), "__subscriber_cb" ) ) 532 ubus_lua_load_newsub_cb( L, obj ); 533 } 534 535 /* check if it looks like a method */ 536 if ((lua_type(L, -2) != LUA_TSTRING) || 537 (lua_type(L, -1) != LUA_TTABLE) || 538 !lua_objlen(L, -1)) { 539 lua_pop(L, 1); 540 continue; 541 } 542 543 if (!ubus_lua_load_methods(L, &m[midx])) 544 midx++; 545 lua_pop(L, 1); 546 } 547 548 obj->o.type->n_methods = obj->o.n_methods = midx; 549 550 /* pop the callback table */ 551 lua_pop(L, 1); 552 553 return &obj->o; 554 } 555 556 static int ubus_lua_add(lua_State *L) 557 { 558 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 559 560 /* verify top level object */ 561 if (lua_istable(L, 1)) { 562 lua_pushstring(L, "you need to pass a table"); 563 return lua_error(L); 564 } 565 566 /* scan each object */ 567 lua_pushnil(L); 568 while (lua_next(L, -2) != 0) { 569 struct ubus_object *obj = NULL; 570 571 /* check if the object has a table of methods */ 572 if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TTABLE)) { 573 obj = ubus_lua_load_object(L); 574 575 if (obj){ 576 ubus_add_object(c->ctx, obj); 577 578 /* allow future reference of ubus obj */ 579 lua_pushstring(state,"__ubusobj"); 580 lua_pushlightuserdata(state, obj); 581 lua_settable(state,-3); 582 } 583 } 584 lua_pop(L, 1); 585 } 586 587 return 0; 588 } 589 590 static int 591 ubus_lua_notify( lua_State *L ) 592 { 593 struct ubus_lua_connection *c; 594 struct ubus_object *obj; 595 const char* method; 596 597 c = luaL_checkudata(L, 1, METANAME); 598 method = luaL_checkstring(L, 3); 599 luaL_checktype(L, 4, LUA_TTABLE); 600 601 if( !lua_islightuserdata( L, 2 ) ){ 602 lua_pushfstring( L, "Invald 2nd parameter, expected ubus obj ref" ); 603 return lua_error( L ); 604 } 605 obj = lua_touserdata( L, 2 ); 606 607 /* create parameters from table */ 608 blob_buf_init(&c->buf, 0); 609 if( !ubus_lua_format_blob_array( L, &c->buf, true ) ){ 610 lua_pushfstring( L, "Invalid 4th parameter, expected table of arguments" ); 611 return lua_error( L ); 612 } 613 614 ubus_notify( c->ctx, obj, method, c->buf.head, -1 ); 615 return 0; 616 } 617 618 static void 619 ubus_lua_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p) 620 { 621 lua_State *L = (lua_State *)p; 622 623 if (!o->signature) 624 return; 625 626 ubus_lua_parse_blob_array(L, blob_data(o->signature), blob_len(o->signature), true); 627 } 628 629 static int 630 ubus_lua_signatures(lua_State *L) 631 { 632 int rv; 633 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 634 const char *path = luaL_checkstring(L, 2); 635 636 rv = ubus_lookup(c->ctx, path, ubus_lua_signatures_cb, L); 637 638 if (rv != UBUS_STATUS_OK) 639 { 640 lua_pop(L, 1); 641 lua_pushnil(L); 642 lua_pushinteger(L, rv); 643 return 2; 644 } 645 646 return 1; 647 } 648 649 650 static void 651 ubus_lua_call_cb(struct ubus_request *req, int type, struct blob_attr *msg) 652 { 653 lua_State *L = (lua_State *)req->priv; 654 655 if (!msg && L) 656 lua_pushnil(L); 657 658 if (msg && L) 659 ubus_lua_parse_blob_array(L, blob_data(msg), blob_len(msg), true); 660 } 661 662 static int 663 ubus_lua_call(lua_State *L) 664 { 665 int rv, top; 666 uint32_t id; 667 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 668 const char *path = luaL_checkstring(L, 2); 669 const char *func = luaL_checkstring(L, 3); 670 671 luaL_checktype(L, 4, LUA_TTABLE); 672 blob_buf_init(&c->buf, 0); 673 674 if (!ubus_lua_format_blob_array(L, &c->buf, true)) 675 { 676 lua_pushnil(L); 677 lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); 678 return 2; 679 } 680 681 rv = ubus_lookup_id(c->ctx, path, &id); 682 683 if (rv) 684 { 685 lua_pushnil(L); 686 lua_pushinteger(L, rv); 687 return 2; 688 } 689 690 top = lua_gettop(L); 691 rv = ubus_invoke(c->ctx, id, func, c->buf.head, ubus_lua_call_cb, L, c->timeout * 1000); 692 693 if (rv != UBUS_STATUS_OK) 694 { 695 lua_pop(L, 1); 696 lua_pushnil(L); 697 lua_pushinteger(L, rv); 698 return 2; 699 } 700 701 return lua_gettop(L) - top; 702 } 703 704 static void 705 ubus_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, 706 const char *type, struct blob_attr *msg) 707 { 708 struct ubus_lua_event *listener = container_of(ev, struct ubus_lua_event, e); 709 710 lua_getglobal(state, "__ubus_cb_event"); 711 lua_rawgeti(state, -1, listener->r); 712 lua_remove(state, -2); 713 714 if (lua_isfunction(state, -1)) { 715 ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); 716 lua_call(state, 1, 0); 717 } else { 718 lua_pop(state, 1); 719 } 720 } 721 722 static struct ubus_event_handler* 723 ubus_lua_load_event(lua_State *L) 724 { 725 struct ubus_lua_event* event = NULL; 726 727 event = calloc(1, sizeof(struct ubus_lua_event)); 728 if (!event) 729 return NULL; 730 731 event->e.cb = ubus_event_handler; 732 733 /* update the he callback lookup table */ 734 lua_getglobal(L, "__ubus_cb_event"); 735 lua_pushvalue(L, -2); 736 event->r = luaL_ref(L, -2); 737 lua_setfield(L, -1, lua_tostring(L, -3)); 738 739 return &event->e; 740 } 741 742 static int 743 ubus_lua_listen(lua_State *L) { 744 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 745 746 /* verify top level object */ 747 luaL_checktype(L, 2, LUA_TTABLE); 748 749 /* scan each object */ 750 lua_pushnil(L); 751 while (lua_next(L, -2) != 0) { 752 struct ubus_event_handler *listener; 753 754 /* check if the key is a string and the value is a method */ 755 if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TFUNCTION)) { 756 listener = ubus_lua_load_event(L); 757 if(listener != NULL) { 758 ubus_register_event_handler(c->ctx, listener, lua_tostring(L, -2)); 759 } 760 } 761 lua_pop(L, 1); 762 } 763 return 0; 764 } 765 766 static void 767 ubus_sub_remove_handler(struct ubus_context *ctx, struct ubus_subscriber *s, 768 uint32_t id) 769 { 770 struct ubus_lua_subscriber *sub; 771 772 sub = container_of(s, struct ubus_lua_subscriber, s); 773 774 lua_getglobal(state, "__ubus_cb_subscribe"); 775 lua_rawgeti(state, -1, sub->rremove); 776 lua_remove(state, -2); 777 778 if (lua_isfunction(state, -1)) { 779 lua_call(state, 0, 0); 780 } else { 781 lua_pop(state, 1); 782 } 783 } 784 785 static int 786 ubus_sub_notify_handler(struct ubus_context *ctx, struct ubus_object *obj, 787 struct ubus_request_data *req, const char *method, 788 struct blob_attr *msg) 789 { 790 struct ubus_subscriber *s; 791 struct ubus_lua_subscriber *sub; 792 793 s = container_of(obj, struct ubus_subscriber, obj); 794 sub = container_of(s, struct ubus_lua_subscriber, s); 795 796 lua_getglobal(state, "__ubus_cb_subscribe"); 797 lua_rawgeti(state, -1, sub->rnotify); 798 lua_remove(state, -2); 799 800 if (lua_isfunction(state, -1)) { 801 if( msg ){ 802 ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); 803 } else { 804 lua_pushnil(state); 805 } 806 lua_pushstring(state, method); 807 lua_call(state, 2, 0); 808 } else { 809 lua_pop(state, 1); 810 } 811 812 return 0; 813 } 814 815 816 817 static int 818 ubus_lua_do_subscribe( struct ubus_context *ctx, lua_State *L, const char* target, 819 int idxnotify, int idxremove ) 820 { 821 uint32_t id; 822 int status; 823 struct ubus_lua_subscriber *sub; 824 825 if( ( status = ubus_lookup_id( ctx, target, &id ) ) ){ 826 lua_pushfstring( L, "Unable find target, status=%d", status ); 827 return lua_error( L ); 828 } 829 830 sub = calloc( 1, sizeof( struct ubus_lua_subscriber ) ); 831 if( !sub ){ 832 lua_pushstring( L, "Out of memory" ); 833 return lua_error( L ); 834 } 835 836 if( idxnotify ){ 837 lua_getglobal(L, "__ubus_cb_subscribe"); 838 lua_pushvalue(L, idxnotify); 839 sub->rnotify = luaL_ref(L, -2); 840 lua_pop(L, 1); 841 sub->s.cb = ubus_sub_notify_handler; 842 } 843 844 if( idxremove ){ 845 lua_getglobal(L, "__ubus_cb_subscribe"); 846 lua_pushvalue(L, idxremove); 847 sub->rremove = luaL_ref(L, -2); 848 lua_pop(L, 1); 849 sub->s.remove_cb = ubus_sub_remove_handler; 850 } 851 852 if( ( status = ubus_register_subscriber( ctx, &sub->s ) ) ){ 853 lua_pushfstring( L, "Failed to register subscriber, status=%d", status ); 854 return lua_error( L ); 855 } 856 857 if( ( status = ubus_subscribe( ctx, &sub->s, id) ) ){ 858 lua_pushfstring( L, "Failed to register subscriber, status=%d", status ); 859 return lua_error( L ); 860 } 861 862 return 0; 863 } 864 865 static int 866 ubus_lua_subscribe(lua_State *L) { 867 int idxnotify, idxremove, stackstart; 868 struct ubus_lua_connection *c; 869 const char* target; 870 871 idxnotify = idxremove = 0; 872 stackstart = lua_gettop( L ); 873 874 875 c = luaL_checkudata(L, 1, METANAME); 876 target = luaL_checkstring(L, 2); 877 luaL_checktype(L, 3, LUA_TTABLE); 878 879 880 lua_pushstring( L, "notify"); 881 lua_gettable( L, 3 ); 882 if( lua_type( L, -1 ) == LUA_TFUNCTION ){ 883 idxnotify = lua_gettop( L ); 884 } else { 885 lua_pop( L, 1 ); 886 } 887 888 lua_pushstring( L, "remove"); 889 lua_gettable( L, 3 ); 890 if( lua_type( L, -1 ) == LUA_TFUNCTION ){ 891 idxremove = lua_gettop( L ); 892 } else { 893 lua_pop( L, 1 ); 894 } 895 896 if( idxnotify ) 897 ubus_lua_do_subscribe( c->ctx, L, target, idxnotify, idxremove ); 898 899 if( lua_gettop( L ) > stackstart ) 900 lua_pop( L, lua_gettop( L ) - stackstart ); 901 902 return 0; 903 } 904 905 static int 906 ubus_lua_send(lua_State *L) 907 { 908 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 909 const char *event = luaL_checkstring(L, 2); 910 911 if (*event == 0) 912 return luaL_argerror(L, 2, "no event name"); 913 914 // Event content convert to ubus form 915 luaL_checktype(L, 3, LUA_TTABLE); 916 blob_buf_init(&c->buf, 0); 917 918 if (!ubus_lua_format_blob_array(L, &c->buf, true)) { 919 lua_pushnil(L); 920 lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); 921 return 2; 922 } 923 924 // Send the event 925 ubus_send_event(c->ctx, event, c->buf.head); 926 927 return 0; 928 } 929 930 931 932 static int 933 ubus_lua__gc(lua_State *L) 934 { 935 struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); 936 937 blob_buf_free(&c->buf); 938 if (c->ctx != NULL) 939 { 940 ubus_free(c->ctx); 941 memset(c, 0, sizeof(*c)); 942 } 943 944 return 0; 945 } 946 947 static const luaL_Reg ubus[] = { 948 { "connect", ubus_lua_connect }, 949 { "objects", ubus_lua_objects }, 950 { "add", ubus_lua_add }, 951 { "notify", ubus_lua_notify }, 952 { "reply", ubus_lua_reply }, 953 { "defer_request", ubus_lua_defer_request }, 954 { "complete_deferred_request", ubus_lua_complete_deferred_request }, 955 { "signatures", ubus_lua_signatures }, 956 { "call", ubus_lua_call }, 957 { "close", ubus_lua__gc }, 958 { "listen", ubus_lua_listen }, 959 { "send", ubus_lua_send }, 960 { "subscribe", ubus_lua_subscribe }, 961 { "__gc", ubus_lua__gc }, 962 { NULL, NULL }, 963 }; 964 965 /* avoid missing prototype warning */ 966 int luaopen_ubus(lua_State *L); 967 968 int 969 luaopen_ubus(lua_State *L) 970 { 971 /* create metatable */ 972 luaL_newmetatable(L, METANAME); 973 974 /* metatable.__index = metatable */ 975 lua_pushvalue(L, -1); 976 lua_setfield(L, -2, "__index"); 977 978 /* fill metatable */ 979 luaL_register(L, NULL, ubus); 980 lua_pop(L, 1); 981 982 /* create module */ 983 luaL_register(L, MODNAME, ubus); 984 985 /* set some enum defines */ 986 lua_pushinteger(L, BLOBMSG_TYPE_ARRAY); 987 lua_setfield(L, -2, "ARRAY"); 988 lua_pushinteger(L, BLOBMSG_TYPE_TABLE); 989 lua_setfield(L, -2, "TABLE"); 990 lua_pushinteger(L, BLOBMSG_TYPE_STRING); 991 lua_setfield(L, -2, "STRING"); 992 lua_pushinteger(L, BLOBMSG_TYPE_INT64); 993 lua_setfield(L, -2, "INT64"); 994 lua_pushinteger(L, BLOBMSG_TYPE_INT32); 995 lua_setfield(L, -2, "INT32"); 996 lua_pushinteger(L, BLOBMSG_TYPE_INT16); 997 lua_setfield(L, -2, "INT16"); 998 lua_pushinteger(L, BLOBMSG_TYPE_INT8); 999 lua_setfield(L, -2, "INT8"); 1000 lua_pushinteger(L, BLOBMSG_TYPE_DOUBLE); 1001 lua_setfield(L, -2, "DOUBLE"); 1002 lua_pushinteger(L, BLOBMSG_TYPE_BOOL); 1003 lua_setfield(L, -2, "BOOLEAN"); 1004 1005 /* used in our callbacks */ 1006 state = L; 1007 1008 /* create the callback table */ 1009 lua_createtable(L, 1, 0); 1010 lua_setglobal(L, "__ubus_cb"); 1011 1012 /* create the event table */ 1013 lua_createtable(L, 1, 0); 1014 lua_setglobal(L, "__ubus_cb_event"); 1015 1016 /* create the subscriber table */ 1017 lua_createtable(L, 1, 0); 1018 lua_setglobal(L, "__ubus_cb_subscribe"); 1019 1020 /* create the publisher table - notifications of new subs */ 1021 lua_createtable(L, 1, 0); 1022 lua_setglobal(L, "__ubus_cb_publisher"); 1023 return 0; 1024 } 1025
This page was automatically generated by LXR 0.3.1. • OpenWrt