src/buffer_event.c

1
/* LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com>
2
 * Licensed as LGPL - See doc/COPYING for details */
3
#include <stdlib.h>
4
#include "buffer_event.h"
5
#include "utility.h"
6
#include <lauxlib.h>
7
#include "event_buffer.h"
8
 
9
#define BUFFER_EVENT_MT "BUFFER_EVENT_MT"
10
 
11
/* Locations of READ/WRITE buffers in the fenv */
12
#define READ_BUFFER_LOCATION 4
13
#define WRITE_BUFFER_LOCATION 5
14
 
15
/* Obtains an le_bufferevent structure from a given index */
16
static le_bufferevent* buffer_event_get(lua_State* L, int idx) {
17
	return (le_bufferevent*)luaL_checkudata(L, idx, BUFFER_EVENT_MT);
18
}
19
 
20
/* Obtains an le_bufferevent structure from a given index
21
	AND checks that it hadn't been prematurely freed
22
*/
23
le_bufferevent* buffer_event_check(lua_State* L, int idx) {
24
	le_bufferevent* buf = (le_bufferevent*)luaL_checkudata(L, idx, BUFFER_EVENT_MT);
25
	if(!buf->ev)
26
		luaL_argerror(L, idx, "Attempt to use closed buffer_event object");
27
	return buf;
28
}
29
 
30
/* Checks if the given index contains an le_buffer object */
31
int is_buffer_event(lua_State* L, int idx) {
32
	int ret;
33
	lua_getmetatable(L, idx);
34
	luaL_getmetatable(L, BUFFER_EVENT_MT);
35
	ret = lua_rawequal(L, -2, -1);
36
	lua_pop(L, 2);
37
	return ret;
38
}
39
 
40
static void handle_callback(le_bufferevent* le_ev, short what, int callbackIndex) {
41
	lua_State* L = le_ev->base->loop_L;
42
	le_weak_get(L, le_ev);
43
	lua_getfenv(L, -1);
44
	lua_rawgeti(L, -1, callbackIndex);
45
	lua_remove(L, -2);
46
	lua_pushvalue(L, -2);
47
	lua_remove(L, -3);
48
	/* func, bufferevent */
49
	lua_pushinteger(L, what);
50
	/* What to do w/ errors...? */
51
	if(!lua_pcall(L, 2, 0, 0))
52
	{
53
		/* FIXME: Perhaps luaevent users should be
54
		 * able to set an error handler? */
55
		lua_pop(L, 1); /* Pop error message */
56
	}
57
}
58
 
59
static void buffer_event_readcb(struct bufferevent *ev, void *ptr) {
60
	handle_callback((le_bufferevent*)ptr, EVBUFFER_READ, 1);
61
}
62
 
63
static void buffer_event_writecb(struct bufferevent *ev, void *ptr) {
64
	handle_callback((le_bufferevent*)ptr, EVBUFFER_WRITE, 2);
65
}
66
 
67
static void buffer_event_errorcb(struct bufferevent *ev, short what, void *ptr) {
68
	handle_callback((le_bufferevent*)ptr, what, 3);
69
}
70
 
71
/* LUA: new(fd, read, write, error)
72
	Pushes a new bufferevent instance on the stack
73
	Accepts: base, fd, read, write, error cb
74
	Requires base, fd and error cb
75
*/
76
static int buffer_event_push(lua_State* L) {
77
	le_bufferevent *ev;
78
	le_base* base = event_base_get(L, 1);
79
	/* NOTE: Should probably reference the socket as well... */
80
	int fd = getSocketFd(L, 2);
81
	luaL_checktype(L, 5, LUA_TFUNCTION);
82
	if(!lua_isnil(L, 3)) luaL_checktype(L, 3, LUA_TFUNCTION);
83
	if(!lua_isnil(L, 4)) luaL_checktype(L, 4, LUA_TFUNCTION);
84
	ev= (le_bufferevent*)lua_newuserdata(L, sizeof(le_bufferevent));
85
	luaL_getmetatable(L, BUFFER_EVENT_MT);
86
	lua_setmetatable(L, -2);
87
	ev->ev = bufferevent_new(fd, buffer_event_readcb, buffer_event_writecb, buffer_event_errorcb, ev);
88
	lua_createtable(L, 5, 0);
89
	lua_pushvalue(L, 3);
90
	lua_rawseti(L, -2, 1); // Read
91
	lua_pushvalue(L, 4);
92
	lua_rawseti(L, -2, 2); // Write
93
	lua_pushvalue(L, 5);
94
	lua_rawseti(L, -2, 3); // Err
95
 
96
	event_buffer_push(L, ev->ev->input);
97
	lua_rawseti(L, -2, READ_BUFFER_LOCATION);
98
	event_buffer_push(L, ev->ev->output);
99
	lua_rawseti(L, -2, WRITE_BUFFER_LOCATION);
100
	lua_setfenv(L, -2);
101
	ev->base = base;
102
	return 1;
103
}
104
 
105
/* LUA: __gc and buffer:close()
106
	Releases the buffer resources
107
*/
108
static int buffer_event_gc(lua_State* L) {
109
	le_bufferevent* ev = buffer_event_get(L, 1);
110
	if(ev->ev) {
111
		le_buffer *read, *write;
112
		bufferevent_free(ev->ev);
113
		ev->ev = NULL;
114
		/* Also clear out the associated input/output event_buffers
115
		 * since they would have already been freed.. */
116
		lua_getfenv(L, 1);
117
		lua_rawgeti(L, -1, READ_BUFFER_LOCATION);
118
		lua_rawgeti(L, -2, WRITE_BUFFER_LOCATION);
119
		read = event_buffer_check(L, -2);
120
		write = event_buffer_check(L, -1);
121
		/* Erase Lua's link to the buffers */
122
		lua_pushnil(L);
123
		/* LS: ..., fenv, readBuf, writeBuf, nil */
124
		lua_rawseti(L, -4, READ_BUFFER_LOCATION);
125
		lua_pushnil(L);
126
		lua_rawseti(L, -4, WRITE_BUFFER_LOCATION);
127
		/* Erase their knowledge of the buffer so that the GC won't try to double-free */
128
		read->buffer = NULL;
129
		write->buffer = NULL;
130
	}
131
	return 0;
132
}
133
 
134
static int buffer_event_get_read(lua_State* L) {
135
	(void)buffer_event_get(L, 1);
136
	lua_getfenv(L, 1);
137
	lua_rawgeti(L, -1, READ_BUFFER_LOCATION);
138
	return 1;
139
}
140
 
141
static int buffer_event_get_write(lua_State* L) {
142
	(void)buffer_event_get(L, 1);
143
	lua_getfenv(L, 1);
144
	lua_rawgeti(L, -1, WRITE_BUFFER_LOCATION);
145
	return 1;
146
}
147
 
148
static int buffer_event_set_read_watermarks(lua_State* L) {
149
	int low, high;
150
	le_bufferevent* ev = buffer_event_get(L, 1);
151
	if(!ev->ev) return 0;
152
 
153
	low = lua_tonumber(L, 2);
154
	high = lua_tonumber(L, 3);
155
 
156
	bufferevent_setwatermark(ev->ev, EV_READ, low, high);
157
	return 0;
158
}
159
 
160
static int buffer_event_set_write_watermarks(lua_State* L) {
161
	int low, high;
162
	le_bufferevent* ev = buffer_event_get(L, 1);
163
	if(!ev->ev) return 0;
164
 
165
	low = lua_tonumber(L, 2);
166
	high = lua_tonumber(L, 3);
167
 
168
	bufferevent_setwatermark(ev->ev, EV_WRITE, low, high);
169
	return 0;
170
}
171
 
172
static int buffer_event_set_timeouts(lua_State* L) {
173
	int timeout_read, timeout_write;
174
	le_bufferevent* ev = buffer_event_get(L, 1);
175
	if(!ev->ev) return 0;
176
 
177
	timeout_read = lua_tointeger(L, 2);
178
	timeout_write = lua_tointeger(L, 3);
179
 
180
	bufferevent_settimeout(ev->ev, timeout_read, timeout_write);
181
	return 0;
182
}
183
 
184
static int buffer_event_enable(lua_State* L) {
185
	le_bufferevent* ev = buffer_event_get(L, 1);
186
	if(!ev->ev) return 0;
187
 
188
	lua_pushinteger(L, bufferevent_enable(ev->ev, luaL_checkinteger(L, 2)));
189
	return 1;
190
}
191
 
192
static int buffer_event_disable(lua_State* L) {
193
	le_bufferevent* ev = buffer_event_get(L, 1);
194
	if(!ev->ev) return 0;
195
 
196
	lua_pushinteger(L, bufferevent_disable(ev->ev, luaL_checkinteger(L, 2)));
197
	return 1;
198
}
199
 
200
static luaL_Reg buffer_event_funcs[] = {
201
	{"get_read", buffer_event_get_read},
202
	{"get_write", buffer_event_get_write},
203
	{"set_read_watermarks", buffer_event_set_read_watermarks},
204
	{"set_write_watermarks", buffer_event_set_write_watermarks},
205
	{"set_timeouts", buffer_event_set_timeouts},
206
	{"enable", buffer_event_enable},
207
	{"disable", buffer_event_disable},
208
	{NULL, NULL}
209
};
210
 
211
static luaL_Reg funcs[] = {
212
	{"new", buffer_event_push},
213
	{NULL, NULL}
214
};
215
 
216
int buffer_event_register(lua_State* L) {
217
	luaL_newmetatable(L, BUFFER_EVENT_MT);
218
	lua_pushcfunction(L, buffer_event_gc);
219
	lua_setfield(L, -2, "__gc");
220
	lua_newtable(L);
221
	luaL_register(L, NULL, buffer_event_funcs);
222
	lua_setfield(L, -2, "__index");
223
	lua_pop(L, 1);
224
 
225
	luaL_register(L, "luaevent.core.bufferevent", funcs);
226
	return 1;
227
}