diff options
Diffstat (limited to 'source3/utils')
-rw-r--r-- | source3/utils/net.c | 7 | ||||
-rw-r--r-- | source3/utils/net_lua.c | 384 | ||||
-rw-r--r-- | source3/utils/net_proto.h | 5 |
3 files changed, 396 insertions, 0 deletions
diff --git a/source3/utils/net.c b/source3/utils/net.c index f1a5be1876..c9525ab2eb 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -582,6 +582,13 @@ static struct functable net_func[] = { " Use 'net help registry' to get more information about 'net " "registry' commands." }, + { "lua", + net_lua, + NET_TRANSPORT_LOCAL, + "Open a lua interpreter", + " Use 'net help lua' to get more information about 'net " + "lua' commands." + }, #ifdef WITH_FAKE_KASERVER { "afs", net_afs, diff --git a/source3/utils/net_lua.c b/source3/utils/net_lua.c new file mode 100644 index 0000000000..3a5d1bdeb6 --- /dev/null +++ b/source3/utils/net_lua.c @@ -0,0 +1,384 @@ +/* + * Unix SMB/CIFS implementation. + * Lua experiments + * Copyright (C) Volker Lendecke 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include "includes.h" +#include "utils/net.h" + +#include "lua-5.1.4/src/lualib.h" +#include "lua-5.1.4/src/lauxlib.h" + +#define SOCK_METATABLE "cade1208-9029-4d76-8748-426dfc1436f7" + +struct sock_userdata { + int fd; +}; + +static int sock_userdata_gc(lua_State *L) +{ + struct sock_userdata *p = (struct sock_userdata *) + luaL_checkudata(L, 1, SOCK_METATABLE); + close(p->fd); + return 0; +} + +static int sock_userdata_tostring(lua_State *L) +{ + struct sock_userdata *p = (struct sock_userdata *) + luaL_checkudata(L, 1, SOCK_METATABLE); + + lua_pushfstring(L, "socket: %d", p->fd); + return 1; +} + +static int sock_userdata_connect(lua_State *L) +{ + struct sock_userdata *p = (struct sock_userdata *) + luaL_checkudata(L, 1, SOCK_METATABLE); + const char *hostname; + int port; + struct sockaddr_in addr; + int res; + + if (!lua_isstring(L, 2)) { + luaL_error(L, "connect: Expected IP-Address"); + } + hostname = lua_tostring(L, 2); + + if (!lua_isnumber(L, 3)) { + luaL_error(L, "connect: Expected port"); + } + port = lua_tointeger(L, 3); + + if (lua_gettop(L) == 4) { + /* + * Here we expect an event context in the last argument to + * make connect() asynchronous. + */ + } + + addr.sin_family = AF_INET; + inet_aton(hostname, &addr.sin_addr); + addr.sin_port = htons(port); + + res = connect(p->fd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1) { + int err = errno; + lua_pushnil(L); + lua_pushfstring(L, "connect failed: %s", strerror(err)); + return 2; + } + + lua_pushboolean(L, 1); + return 1; +} + +static const struct luaL_Reg sock_methods[] = { + {"__gc", sock_userdata_gc}, + {"__tostring", sock_userdata_tostring}, + {"connect", sock_userdata_connect}, + {NULL, NULL} +}; + +static const struct { + const char *name; + int domain; +} socket_domains[] = { + {"PF_UNIX", PF_UNIX}, + {"PF_INET", PF_INET}, + {NULL, 0}, +}; + +static const struct { + const char *name; + int type; +} socket_types[] = { + {"SOCK_STREAM", SOCK_STREAM}, + {"SOCK_DGRAM", SOCK_DGRAM}, + {NULL, 0}, +}; + +static int sock_userdata_new(lua_State *L) +{ + struct sock_userdata *result; + const char *domain_str = luaL_checkstring(L, 1); + const char *type_str = luaL_checkstring(L, 2); + int i, domain, type; + + i = 0; + while (socket_domains[i].name != NULL) { + if (strcmp(domain_str, socket_domains[i].name) == 0) { + break; + } + i += 1; + } + if (socket_domains[i].name == NULL) { + return luaL_error(L, "socket domain %s unknown", domain_str); + } + domain = socket_domains[i].domain; + + i = 0; + while (socket_types[i].name != NULL) { + if (strcmp(type_str, socket_types[i].name) == 0) { + break; + } + i += 1; + } + if (socket_types[i].name == NULL) { + return luaL_error(L, "socket type %s unknown", type_str); + } + type = socket_types[i].type; + + result = (struct sock_userdata *)lua_newuserdata(L, sizeof(*result)); + ZERO_STRUCTP(result); + + result->fd = socket(domain, type, 0); + if (result->fd == -1) { + int err = errno; + lua_pushnil(L); + lua_pushfstring(L, "socket() failed: %s", strerror(errno)); + lua_pushinteger(L, err); + return 3; + } + + luaL_getmetatable(L, SOCK_METATABLE); + lua_setmetatable(L, -2); + return 1; +} + +static const struct luaL_Reg sock_funcs[] = { + {"new", sock_userdata_new}, + {NULL, NULL} +}; + +static int sock_lua_init(lua_State *L, const char *libname) { + luaL_newmetatable(L, SOCK_METATABLE); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + luaL_register(L, NULL, sock_methods); + luaL_register(L, libname, sock_funcs); + return 1; +} + +#define EVT_METATABLE "c42e0642-b24a-40f0-8483-d8eb4aee9ea3" + +/* + * The userdata we allocate from lua when a new event context is created + */ +struct evt_userdata { + struct event_context *ev; +}; + +static bool evt_is_main_thread(lua_State *L) { + int ret; + + ret = lua_pushthread(L); + lua_pop(L, 1); + return (ret != 0); +} + +/* + * Per event we allocate a struct thread_reference to keep the coroutine from + * being garbage-collected. This is also the hook to find the right thread to + * be resumed. + */ + +struct thread_reference { + struct lua_State *L; + /* + * Reference to the Thread (i.e. lua_State) this event is hanging on + */ + int thread_ref; +}; + +static int thread_reference_destructor(struct thread_reference *ref) +{ + luaL_unref(ref->L, LUA_REGISTRYINDEX, ref->thread_ref); + return 0; +} + +static struct thread_reference *evt_reference_thread(TALLOC_CTX *mem_ctx, + lua_State *L) +{ + struct thread_reference *result; + + result = talloc(mem_ctx, struct thread_reference); + if (result == NULL) { + return NULL; + } + + lua_pushthread(L); + result->thread_ref = luaL_ref(L, LUA_REGISTRYINDEX); + result->L = L; + talloc_set_destructor(result, thread_reference_destructor); + + return result; +} + +static int evt_userdata_gc(lua_State *L) +{ + struct evt_userdata *p = (struct evt_userdata *) + luaL_checkudata(L, 1, EVT_METATABLE); + TALLOC_FREE(p->ev); + return 0; +} + +static int evt_userdata_tostring(lua_State *L) { + lua_pushstring(L, "event context"); + return 1; +} + +static void evt_userdata_sleep_done(struct event_context *event_ctx, + struct timed_event *te, + const struct timeval *now, + void *priv) +{ + struct thread_reference *ref = talloc_get_type_abort( + priv, struct thread_reference); + lua_resume(ref->L, 0); + TALLOC_FREE(ref); +} + +static int evt_userdata_sleep(lua_State *L) +{ + struct evt_userdata *p = (struct evt_userdata *) + luaL_checkudata(L, 1, EVT_METATABLE); + lua_Integer usecs = luaL_checkint(L, 2); + struct thread_reference *ref; + struct timed_event *te; + + if (evt_is_main_thread(L)) { + /* + * Block in the main thread + */ + smb_msleep(usecs/1000); + return 0; + } + + ref = evt_reference_thread(p->ev, L); + if (ref == NULL) { + return luaL_error(L, "evt_reference_thread failed\n"); + } + + te = event_add_timed(p->ev, ref, timeval_current_ofs(0, usecs), + "evt_userdata_sleep", evt_userdata_sleep_done, + ref); + + if (te == NULL) { + TALLOC_FREE(ref); + return luaL_error(L, "event_add_timed failed"); + } + + return lua_yield(L, 0); +} + +static int evt_userdata_once(lua_State *L) +{ + struct evt_userdata *p = (struct evt_userdata *) + luaL_checkudata(L, 1, EVT_METATABLE); + + if (!evt_is_main_thread(L)) { + return luaL_error(L, "event_once called from non-base thread"); + } + + lua_pushinteger(L, event_loop_once(p->ev)); + return 1; +} + +static const struct luaL_Reg evt_methods[] = { + {"__gc", evt_userdata_gc}, + {"__tostring", evt_userdata_tostring}, + {"sleep", evt_userdata_sleep}, + {"once", evt_userdata_once}, + {NULL, NULL} +}; + +static int evt_userdata_new(lua_State *L) { + struct evt_userdata *result; + + result = (struct evt_userdata *)lua_newuserdata(L, sizeof(*result)); + ZERO_STRUCTP(result); + + result->ev = event_context_init(NULL); + if (result->ev == NULL) { + return luaL_error(L, "event_context_init failed"); + } + + luaL_getmetatable(L, EVT_METATABLE); + lua_setmetatable(L, -2); + return 1; +} + +static const struct luaL_Reg evt_funcs[] = { + {"new", evt_userdata_new}, + {NULL, NULL} +}; + +static int evt_lua_init(lua_State *L, const char *libname) { + luaL_newmetatable(L, EVT_METATABLE); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + luaL_register(L, NULL, evt_methods); + luaL_register(L, libname, evt_funcs); + return 1; +} + +int net_lua(struct net_context *c, int argc, const char **argv) +{ + lua_State *state; + + state = lua_open(); + if (state == NULL) { + d_fprintf(stderr, "lua_newstate failed\n"); + return -1; + } + + luaL_openlibs(state); + evt_lua_init(state, "event"); + sock_lua_init(state, "socket"); + + while (1) { + char *line = NULL; + + line = smb_readline("lua> ", NULL, NULL); + if (line == NULL) { + break; + } + + if (line[0] == ':') { + if (luaL_dofile(state, &line[1])) { + d_printf("luaL_dofile returned an error\n"); + continue; + } + } else if (line[0] != '\n') { + if (luaL_dostring(state, line) != 0) { + d_printf("luaL_dostring returned an error\n"); + } + } + + SAFE_FREE(line); + } + + lua_close(state); + return -1; +} diff --git a/source3/utils/net_proto.h b/source3/utils/net_proto.h index c058a0166f..a65fbbb6eb 100644 --- a/source3/utils/net_proto.h +++ b/source3/utils/net_proto.h @@ -423,6 +423,11 @@ int net_usershare_usage(struct net_context *c, int argc, const char **argv); int net_usershare_help(struct net_context *c, int argc, const char **argv); int net_usershare(struct net_context *c, int argc, const char **argv); +/* The following definitions come from utils/net_lua.c */ + +int net_lua(struct net_context *c, int argc, const char **argv); + + /* The following definitions come from utils/net_util.c */ NTSTATUS net_rpc_lookup_name(struct net_context *c, |