-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathlevent.c
417 lines (344 loc) · 10.3 KB
/
levent.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
#include <sys/types.h>
#include <event.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
/* ----------- some utility functions ---------*/
/* turns end-relative indexes to [0..top] range */
static int fixindex (lua_State *L, int index) {
int top = lua_gettop (L);
if (index < 0 && -index <= top)
index = top+index+1;
return index;
}
/* missing luaL_optfunction() */
// static int kzL_optfunction (lua_State *L, int narg) {
// if (lua_isnoneornil(L, narg))
// return 0;
// luaL_checktype (L, narg, LUA_TFUNCTION);
// return 1;
// }
/* creates a luaL_ref from an optional argument */
static int ref_optarg (lua_State *L, int narg) {
if (lua_isnoneornil (L, narg))
return LUA_NOREF;
lua_pushvalue (L, narg);
return luaL_ref (L, LUA_REGISTRYINDEX);
}
/* turns a Lua "r"|"w"|"rw" string into EV_READ | EV_WRITE flags */
static short check_evtype (lua_State *L, int index) {
short evt = 0;
index = fixindex (L, index);
size_t len;
const char *evtyp_s = luaL_optlstring (L, index, "r", &len);
while (len--) {
switch (*evtyp_s++) {
case 'r': evt |= EV_READ; break;
case 'w': evt |= EV_WRITE; break;
}
}
return evt;
}
/* ------------- event base object ----------- */
typedef struct lev_base {
struct event_base *base;
lua_State *L;
} lev_base;
#define EVENT_BASE "levent base obj"
#define check_base(L,i) ((lev_base *)luaL_checkudata (L,i,EVENT_BASE))
/* -------------- event object --------------- */
typedef struct lev_event {
struct event event;
lev_base *base;
int cb_ref;
} lev_event;
#define EVENT "levent event obj"
#define check_ev(L,i) ((lev_event *)luaL_checkudata (L,i,EVENT))
/* -------------- bufferevent object ---------- */
typedef struct lev_buffered {
struct bufferevent *buffered;
lev_base *base;
int fd;
int readcb_ref;
int writecb_ref;
int errorcb_ref;
} lev_buffered;
#define BUFFEREVENT "levent buffered event obj"
#define check_buffered(L,i) ((lev_buffered *)luaL_checkudata (L,i,BUFFEREVENT))
/* ------------- module functions ------------- */
/* creates an event base */
static int new_event_base (lua_State *L) {
// TODO: pasar a event_base_new(), depende libevent 1.4 o 2.0
// struct event_base *b = event_base_new();
struct event_base *b = event_init();
if (!b) {
return luaL_error (L, "Can't create event base");
}
lev_base *lb = lua_newuserdata (L, sizeof (lev_base));
lb->base = b;
lb->L = L;
luaL_getmetatable (L, EVENT_BASE);
lua_setmetatable (L, -2);
return 1;
}
static int g_fdacc_ref = LUA_NOREF;
/* setaccessor (mt, f) */
/* sets an fd accessor */
static int set_accessor (lua_State *L) {
if (g_fdacc_ref == LUA_NOREF) {
lua_newtable (L);
g_fdacc_ref = luaL_ref (L, LUA_REGISTRYINDEX);
}
// (mt, f)
lua_rawgeti (L, LUA_REGISTRYINDEX, g_fdacc_ref); // (mf, f, fdacc)
lua_insert (L, -2); // (fdacc, mt, f)
lua_rawset (L, -2);
return 0;
}
/* gets an fd from any value */
static int fd_from_value (lua_State *L) {
int fd = 0;
// (v)
if (lua_getmetatable (L, 1)) { // (v mt)
lua_rawgeti (L, LUA_REGISTRYINDEX, g_fdacc_ref); // (v mt fdacc)
if (lua_isnil (L, -1))
return luaL_error (L, "undefined object type");
lua_pushvalue (L, -2); // (v mt fdacc mt)
lua_rawget (L, -2); // (v mt fdacc f)
lua_pushvalue (L, 1); // (v mt fdacc f v)
lua_pcall (L, 1, 1, 0); // (v mt fdacc r)
return 1;
} else {
fd = lua_tointeger (L, 1);
lua_pushinteger (L, fd);
return 1;
}
}
/* gets an fd from a file object */
static int fd_from_file (lua_State *L) {
FILE **f = luaL_checkudata (L, 1, LUA_FILEHANDLE);
lua_pushinteger (L, fileno (*f));
return 1;
}
static const luaL_Reg module_functs[] = {
{ "newbase", new_event_base },
{ "fdfromfile", fd_from_file },
{ "setfdaccessor", set_accessor },
{ "fdfromvalue", fd_from_value },
{ NULL, NULL },
};
/* ----------- event base methods --------------*/
static void event_cb (int fd, short evtype, void *v) {
lev_event *ev = v;
lua_State *L = ev->base->L;
lua_rawgeti (L, LUA_REGISTRYINDEX, ev->cb_ref);
lua_pushinteger (L, fd);
lua_pcall (L, 1, 0, 0);
}
/* base:addevent (fd, callback, evtype) */
static int base_newevent (lua_State *L) {
lev_base *b = check_base (L, 1);
int fd = luaL_checkint (L, 2);
luaL_checktype (L, 3, LUA_TFUNCTION);
int cb_ref = luaL_ref (L, LUA_REGISTRYINDEX);
short evtype = check_evtype (L, 4);
lev_event *ev = lua_newuserdata (L, sizeof (lev_event));
event_set (&ev->event, fd, evtype, event_cb, ev);
event_base_set (b->base, &ev->event);
ev->base = b;
ev->cb_ref = cb_ref;
// if (event_add (&ev->event, NULL) < 0) {
// return luaL_error (L, "mal event_add");
// }
luaL_getmetatable (L, EVENT);
lua_setmetatable (L, -2);
return 1;
}
/* event buffer callbacks */
static void basic_bfrdcb (struct bufferevent *evbf, void *v) {
lev_buffered *bf = v;
lua_State *L = bf->base->L;
if (bf->readcb_ref != LUA_NOREF) {
lua_rawgeti (L, LUA_REGISTRYINDEX, bf->readcb_ref);
lua_pushinteger (L, bf->fd);
lua_pcall (L, 1, 0, 0);
}
}
static void basic_bfwrcb (struct bufferevent *evbf, void *v) {
lev_buffered *bf = v;
lua_State *L = bf->base->L;
if (bf->writecb_ref != LUA_NOREF) {
lua_rawgeti (L, LUA_REGISTRYINDEX, bf->writecb_ref);
lua_pushinteger (L, bf->fd);
lua_pcall (L, 1, 0, 0);
}
}
static void basic_bferrcb (struct bufferevent *evbf, short what, void *v) {
lev_buffered *bf = v;
lua_State *L = bf->base->L;
if (bf->errorcb_ref != LUA_NOREF) {
lua_rawgeti (L, LUA_REGISTRYINDEX, bf->errorcb_ref);
lua_pushinteger (L, bf->fd);
lua_pushinteger (L, what);
lua_pcall (L, 2, 0, 0);
}
}
/* base:newevbuf (fd, cb_read, cb_write, cb_error) */
static int base_newevbuf (lua_State *L) {
lev_base *b = check_base (L, 1);
int fd = luaL_checkint (L, 2);
lev_buffered *bf = lua_newuserdata (L, sizeof (lev_buffered));
bf->buffered = bufferevent_new (fd, basic_bfrdcb, basic_bfwrcb, basic_bferrcb, bf);
// TODO: check allocation
if (bufferevent_base_set (b->base, bf->buffered) < 0) {
return luaL_error (L, "mal bufferevent_base_set");
}
bf->base = b;
bf->fd = fd;
bf->readcb_ref = ref_optarg (L, 3);
bf->writecb_ref = ref_optarg (L, 4);
bf->errorcb_ref = ref_optarg (L, 5);
luaL_getmetatable (L, BUFFEREVENT);
lua_setmetatable (L, -2);
return 1;
}
/* base:loop ([times]) */
static int base_loop (lua_State *L) {
lev_base *b = check_base (L, 1);
int times = luaL_optinteger (L, 2, -1);
int flags = 0;
if (times > 0) flags |= EVLOOP_ONCE;
if (times ==0) flags |= EVLOOP_NONBLOCK;
int r = event_base_loop (b->base, flags);
if (r < 0)
return luaL_error (L, "mal event_base_loop");
lua_pushboolean (L, 1);
return 1;
}
static const luaL_Reg base_methods[] = {
{ "newevent", base_newevent },
{ "newevbuf", base_newevbuf },
{ "loop", base_loop },
{ NULL, NULL },
};
/* -------- event object methods ------------- */
static int event_start (lua_State *L) {
lev_event *ev = check_ev (L, 1);
if (event_add (&ev->event, NULL) < 0) {
return luaL_error (L, "mal event_add");
}
return 1;
}
static int event_stop (lua_State *L) {
lev_event *ev = check_ev (L, 1);
if (event_del (&ev->event) < 0) {
return luaL_error (L, "mal event_del");
}
return 1;
}
static int event_delete (lua_State *L) {
lev_event *ev = check_ev (L, 1);
luaL_unref (L, LUA_REGISTRYINDEX, ev->cb_ref);
if (event_del (&ev->event) < 0)
return luaL_error (L, "mal event_del");
lua_pushboolean (L, 1);
return 1;
}
static const luaL_Reg event_methods[] = {
{ "start", event_start },
{ "stop", event_stop },
{ "delete", event_delete },
{ "__gc", event_delete },
{ NULL, NULL },
};
/* ----------- buffered event object methods ---------- */
static int evbuf_start (lua_State *L) {
lev_buffered *bf = check_buffered (L, 1);
short typ = ((bf->readcb_ref != LUA_NOREF) ? EV_READ : 0) |
((bf->writecb_ref != LUA_NOREF) ? EV_WRITE : 0);
if (bufferevent_enable (bf->buffered, typ) < 0)
return luaL_error (L, "mal bufferevent_enable");
return 1;
}
static int evbuf_stop (lua_State *L) {
lev_buffered *bf = check_buffered (L, 1);
if (bufferevent_disable (bf->buffered, EV_READ | EV_WRITE) < 0)
return luaL_error (L, "mal bufferevent_disable");
return 1;
}
#define MAXREAD 16384
static int evbuf_read (lua_State *L) {
lev_buffered *bf = check_buffered (L, 1);
size_t len = luaL_optinteger (L, 2, MAXREAD);
struct evbuffer *ibuf = bf->buffered->input;
if (len > ibuf->off)
len = ibuf->off;
lua_pushlstring (L, (const char *)ibuf->buffer, len);
if (len)
evbuffer_drain (ibuf, len);
return 1;
}
static int evbuf_readline (lua_State *L) {
lev_buffered *bf = check_buffered (L, 1);
struct evbuffer *ibuf = bf->buffered->input;
size_t len = ibuf->off;
const unsigned char *p = ibuf->buffer;
const unsigned char *end = ibuf->buffer + len;
while (p < end && *p != '\r' && *p != '\n')
p++;
if (p >= end)
return 0;
lua_pushlstring (L, (const char *)ibuf->buffer, p-ibuf->buffer);
if (p+1 < end) {
char fch = *p, sch = *(p+1);
if ((sch == '\r' || sch == '\n') && sch != fch)
p++;
}
evbuffer_drain (ibuf, p-ibuf->buffer);
return 1;
}
static int evbuf_write (lua_State *L) {
lev_buffered *bf = check_buffered (L, 1);
size_t len = 0;
const char *data = luaL_checklstring (L, 2, &len);
if (!data || !len || bufferevent_write (bf->buffered, data, len) < 0)
return luaL_error (L, "mal bufferevent_write");
lua_pop (L, 1);
return 1;
}
static int evbuf_delete (lua_State *L) {
lev_buffered *bf = check_buffered (L, 1);
bufferevent_free (bf->buffered);
bf->buffered = NULL;
luaL_unref (L, LUA_REGISTRYINDEX, bf->readcb_ref);
luaL_unref (L, LUA_REGISTRYINDEX, bf->writecb_ref);
luaL_unref (L, LUA_REGISTRYINDEX, bf->errorcb_ref);
lua_pushboolean (L, 1);
return 1;
}
static const luaL_Reg evbuf_methods[] = {
{ "start", evbuf_start },
{ "stop", evbuf_stop },
{ "read", evbuf_read },
{ "readline", evbuf_readline },
{ "write", evbuf_write },
{ "delete", evbuf_delete },
{ "__gc", evbuf_delete },
{ NULL, NULL },
};
/* ----------- module setup ---------- */
static void meta_register (lua_State *L, const luaL_Reg *methods, const char *name) {
luaL_newmetatable (L, name);
lua_pushliteral (L, "__index");
lua_pushvalue (L, -2);
lua_rawset (L, -3);
luaL_register (L, NULL, methods);
}
int luaopen_levent (lua_State *L);
int luaopen_levent (lua_State *L) {
meta_register (L, base_methods, EVENT_BASE);
meta_register (L, event_methods, EVENT);
meta_register (L, evbuf_methods, BUFFEREVENT);
luaL_register (L, "levent", module_functs);
return 1;
}