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