tevent: use an immediate event fot tevent_req_post()
[Samba/gbeck.git] / source3 / utils / net_lua.c
blobe4af9b55777bc2e6be2a2d7e2d8a08a96fca2fce
1 /*
2 * Unix SMB/CIFS implementation.
3 * Lua experiments
4 * Copyright (C) Volker Lendecke 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "utils/net.h"
24 #include "lua-5.1.4/src/lualib.h"
25 #include "lua-5.1.4/src/lauxlib.h"
27 #define SOCK_METATABLE "cade1208-9029-4d76-8748-426dfc1436f7"
29 struct sock_userdata {
30 int fd;
33 static int sock_userdata_gc(lua_State *L)
35 struct sock_userdata *p = (struct sock_userdata *)
36 luaL_checkudata(L, 1, SOCK_METATABLE);
37 close(p->fd);
38 return 0;
41 static int sock_userdata_tostring(lua_State *L)
43 struct sock_userdata *p = (struct sock_userdata *)
44 luaL_checkudata(L, 1, SOCK_METATABLE);
46 lua_pushfstring(L, "socket: %d", p->fd);
47 return 1;
50 static int sock_userdata_connect(lua_State *L)
52 struct sock_userdata *p = (struct sock_userdata *)
53 luaL_checkudata(L, 1, SOCK_METATABLE);
54 const char *hostname;
55 int port;
56 struct sockaddr_in addr;
57 int res;
59 if (!lua_isstring(L, 2)) {
60 luaL_error(L, "connect: Expected IP-Address");
62 hostname = lua_tostring(L, 2);
64 if (!lua_isnumber(L, 3)) {
65 luaL_error(L, "connect: Expected port");
67 port = lua_tointeger(L, 3);
69 if (lua_gettop(L) == 4) {
71 * Here we expect an event context in the last argument to
72 * make connect() asynchronous.
76 addr.sin_family = AF_INET;
77 inet_aton(hostname, &addr.sin_addr);
78 addr.sin_port = htons(port);
80 res = connect(p->fd, (struct sockaddr *)&addr, sizeof(addr));
81 if (res == -1) {
82 int err = errno;
83 lua_pushnil(L);
84 lua_pushfstring(L, "connect failed: %s", strerror(err));
85 return 2;
88 lua_pushboolean(L, 1);
89 return 1;
92 static const struct luaL_Reg sock_methods[] = {
93 {"__gc", sock_userdata_gc},
94 {"__tostring", sock_userdata_tostring},
95 {"connect", sock_userdata_connect},
96 {NULL, NULL}
99 static const struct {
100 const char *name;
101 int domain;
102 } socket_domains[] = {
103 {"PF_UNIX", PF_UNIX},
104 {"PF_INET", PF_INET},
105 {NULL, 0},
108 static const struct {
109 const char *name;
110 int type;
111 } socket_types[] = {
112 {"SOCK_STREAM", SOCK_STREAM},
113 {"SOCK_DGRAM", SOCK_DGRAM},
114 {NULL, 0},
117 static int sock_userdata_new(lua_State *L)
119 struct sock_userdata *result;
120 const char *domain_str = luaL_checkstring(L, 1);
121 const char *type_str = luaL_checkstring(L, 2);
122 int i, domain, type;
124 i = 0;
125 while (socket_domains[i].name != NULL) {
126 if (strcmp(domain_str, socket_domains[i].name) == 0) {
127 break;
129 i += 1;
131 if (socket_domains[i].name == NULL) {
132 return luaL_error(L, "socket domain %s unknown", domain_str);
134 domain = socket_domains[i].domain;
136 i = 0;
137 while (socket_types[i].name != NULL) {
138 if (strcmp(type_str, socket_types[i].name) == 0) {
139 break;
141 i += 1;
143 if (socket_types[i].name == NULL) {
144 return luaL_error(L, "socket type %s unknown", type_str);
146 type = socket_types[i].type;
148 result = (struct sock_userdata *)lua_newuserdata(L, sizeof(*result));
149 ZERO_STRUCTP(result);
151 result->fd = socket(domain, type, 0);
152 if (result->fd == -1) {
153 int err = errno;
154 lua_pushnil(L);
155 lua_pushfstring(L, "socket() failed: %s", strerror(errno));
156 lua_pushinteger(L, err);
157 return 3;
160 luaL_getmetatable(L, SOCK_METATABLE);
161 lua_setmetatable(L, -2);
162 return 1;
165 static const struct luaL_Reg sock_funcs[] = {
166 {"new", sock_userdata_new},
167 {NULL, NULL}
170 static int sock_lua_init(lua_State *L, const char *libname) {
171 luaL_newmetatable(L, SOCK_METATABLE);
173 lua_pushvalue(L, -1);
174 lua_setfield(L, -2, "__index");
176 luaL_register(L, NULL, sock_methods);
177 luaL_register(L, libname, sock_funcs);
178 return 1;
181 #define EVT_METATABLE "c42e0642-b24a-40f0-8483-d8eb4aee9ea3"
184 * The userdata we allocate from lua when a new event context is created
186 struct evt_userdata {
187 struct event_context *ev;
190 static bool evt_is_main_thread(lua_State *L) {
191 int ret;
193 ret = lua_pushthread(L);
194 lua_pop(L, 1);
195 return (ret != 0);
199 * Per event we allocate a struct thread_reference to keep the coroutine from
200 * being garbage-collected. This is also the hook to find the right thread to
201 * be resumed.
204 struct thread_reference {
205 struct lua_State *L;
207 * Reference to the Thread (i.e. lua_State) this event is hanging on
209 int thread_ref;
212 static int thread_reference_destructor(struct thread_reference *ref)
214 luaL_unref(ref->L, LUA_REGISTRYINDEX, ref->thread_ref);
215 return 0;
218 static struct thread_reference *evt_reference_thread(TALLOC_CTX *mem_ctx,
219 lua_State *L)
221 struct thread_reference *result;
223 result = talloc(mem_ctx, struct thread_reference);
224 if (result == NULL) {
225 return NULL;
228 lua_pushthread(L);
229 result->thread_ref = luaL_ref(L, LUA_REGISTRYINDEX);
230 result->L = L;
231 talloc_set_destructor(result, thread_reference_destructor);
233 return result;
236 static int evt_userdata_gc(lua_State *L)
238 struct evt_userdata *p = (struct evt_userdata *)
239 luaL_checkudata(L, 1, EVT_METATABLE);
240 TALLOC_FREE(p->ev);
241 return 0;
244 static int evt_userdata_tostring(lua_State *L) {
245 lua_pushstring(L, "event context");
246 return 1;
249 static void evt_userdata_sleep_done(struct event_context *event_ctx,
250 struct timed_event *te,
251 struct timeval now,
252 void *priv)
254 struct thread_reference *ref = talloc_get_type_abort(
255 priv, struct thread_reference);
256 lua_resume(ref->L, 0);
257 TALLOC_FREE(ref);
260 static int evt_userdata_sleep(lua_State *L)
262 struct evt_userdata *p = (struct evt_userdata *)
263 luaL_checkudata(L, 1, EVT_METATABLE);
264 lua_Integer usecs = luaL_checkint(L, 2);
265 struct thread_reference *ref;
266 struct timed_event *te;
268 if (evt_is_main_thread(L)) {
270 * Block in the main thread
272 smb_msleep(usecs/1000);
273 return 0;
276 ref = evt_reference_thread(p->ev, L);
277 if (ref == NULL) {
278 return luaL_error(L, "evt_reference_thread failed\n");
281 te = event_add_timed(p->ev, ref, timeval_current_ofs(0, usecs),
282 evt_userdata_sleep_done,
283 ref);
285 if (te == NULL) {
286 TALLOC_FREE(ref);
287 return luaL_error(L, "event_add_timed failed");
290 return lua_yield(L, 0);
293 static int evt_userdata_once(lua_State *L)
295 struct evt_userdata *p = (struct evt_userdata *)
296 luaL_checkudata(L, 1, EVT_METATABLE);
298 if (!evt_is_main_thread(L)) {
299 return luaL_error(L, "event_once called from non-base thread");
302 lua_pushinteger(L, event_loop_once(p->ev));
303 return 1;
306 static const struct luaL_Reg evt_methods[] = {
307 {"__gc", evt_userdata_gc},
308 {"__tostring", evt_userdata_tostring},
309 {"sleep", evt_userdata_sleep},
310 {"once", evt_userdata_once},
311 {NULL, NULL}
314 static int evt_userdata_new(lua_State *L) {
315 struct evt_userdata *result;
317 result = (struct evt_userdata *)lua_newuserdata(L, sizeof(*result));
318 ZERO_STRUCTP(result);
320 result->ev = event_context_init(NULL);
321 if (result->ev == NULL) {
322 return luaL_error(L, "event_context_init failed");
325 luaL_getmetatable(L, EVT_METATABLE);
326 lua_setmetatable(L, -2);
327 return 1;
330 static const struct luaL_Reg evt_funcs[] = {
331 {"new", evt_userdata_new},
332 {NULL, NULL}
335 static int evt_lua_init(lua_State *L, const char *libname) {
336 luaL_newmetatable(L, EVT_METATABLE);
338 lua_pushvalue(L, -1);
339 lua_setfield(L, -2, "__index");
341 luaL_register(L, NULL, evt_methods);
342 luaL_register(L, libname, evt_funcs);
343 return 1;
346 int net_lua(struct net_context *c, int argc, const char **argv)
348 lua_State *state;
350 state = lua_open();
351 if (state == NULL) {
352 d_fprintf(stderr, "lua_newstate failed\n");
353 return -1;
356 luaL_openlibs(state);
357 evt_lua_init(state, "event");
358 sock_lua_init(state, "socket");
360 while (1) {
361 char *line = NULL;
363 line = smb_readline("lua> ", NULL, NULL);
364 if (line == NULL) {
365 break;
368 if (line[0] == ':') {
369 if (luaL_dofile(state, &line[1])) {
370 d_printf("luaL_dofile returned an error\n");
371 continue;
373 } else if (line[0] != '\n') {
374 if (luaL_dostring(state, line) != 0) {
375 d_printf("luaL_dostring returned an error\n");
379 SAFE_FREE(line);
382 lua_close(state);
383 return -1;