2 Copyright (C) 2007,2012,2013 Thomas Harning <harningt@gmail.com>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "buffer_event.h"
27 #include "event_buffer.h"
29 #define BUFFER_EVENT_MT "BUFFER_EVENT_MT"
31 /* Locations of READ/WRITE buffers in the fenv */
32 #define READ_BUFFER_LOCATION 4
33 #define WRITE_BUFFER_LOCATION 5
35 /* Obtains an le_bufferevent structure from a given index */
36 static le_bufferevent
* buffer_event_get(lua_State
* L
, int idx
) {
37 return (le_bufferevent
*)luaL_checkudata(L
, idx
, BUFFER_EVENT_MT
);
40 /* Obtains an le_bufferevent structure from a given index
41 AND checks that it hadn't been prematurely freed
43 le_bufferevent
* buffer_event_check(lua_State
* L
, int idx
) {
44 le_bufferevent
* buf
= (le_bufferevent
*)luaL_checkudata(L
, idx
, BUFFER_EVENT_MT
);
46 luaL_argerror(L
, idx
, "Attempt to use closed buffer_event object");
50 /* Checks if the given index contains an le_buffer object */
51 int is_buffer_event(lua_State
* L
, int idx
) {
53 lua_getmetatable(L
, idx
);
54 luaL_getmetatable(L
, BUFFER_EVENT_MT
);
55 ret
= lua_rawequal(L
, -2, -1);
60 static void handle_callback(le_bufferevent
* le_ev
, short what
, int callbackIndex
) {
61 lua_State
* L
= le_ev
->base
->loop_L
;
62 le_weak_get(L
, le_ev
);
64 lua_rawgeti(L
, -1, callbackIndex
);
68 /* func, bufferevent */
69 lua_pushinteger(L
, what
);
70 /* What to do w/ errors...? */
71 if(!lua_pcall(L
, 2, 0, 0))
73 /* FIXME: Perhaps luaevent users should be
74 * able to set an error handler? */
75 lua_pop(L
, 1); /* Pop error message */
79 static void buffer_event_readcb(struct bufferevent
*ev
, void *ptr
) {
80 handle_callback((le_bufferevent
*)ptr
, EVBUFFER_READ
, 1);
83 static void buffer_event_writecb(struct bufferevent
*ev
, void *ptr
) {
84 handle_callback((le_bufferevent
*)ptr
, EVBUFFER_WRITE
, 2);
87 static void buffer_event_errorcb(struct bufferevent
*ev
, short what
, void *ptr
) {
88 handle_callback((le_bufferevent
*)ptr
, what
, 3);
91 /* LUA: new(fd, read, write, error)
92 Pushes a new bufferevent instance on the stack
93 Accepts: base, fd, read, write, error cb
94 Requires base, fd and error cb
96 static int buffer_event_push(lua_State
* L
) {
98 le_base
* base
= event_base_get(L
, 1);
99 /* NOTE: Should probably reference the socket as well... */
100 int fd
= getSocketFd(L
, 2);
101 luaL_checktype(L
, 5, LUA_TFUNCTION
);
102 if(!lua_isnil(L
, 3)) luaL_checktype(L
, 3, LUA_TFUNCTION
);
103 if(!lua_isnil(L
, 4)) luaL_checktype(L
, 4, LUA_TFUNCTION
);
104 ev
= (le_bufferevent
*)lua_newuserdata(L
, sizeof(le_bufferevent
));
105 luaL_getmetatable(L
, BUFFER_EVENT_MT
);
106 lua_setmetatable(L
, -2);
107 ev
->ev
= bufferevent_new(fd
, buffer_event_readcb
, buffer_event_writecb
, buffer_event_errorcb
, ev
);
108 lua_createtable(L
, 5, 0);
110 lua_rawseti(L
, -2, 1); // Read
112 lua_rawseti(L
, -2, 2); // Write
114 lua_rawseti(L
, -2, 3); // Err
116 event_buffer_push(L
, ev
->ev
->input
);
117 lua_rawseti(L
, -2, READ_BUFFER_LOCATION
);
118 event_buffer_push(L
, ev
->ev
->output
);
119 lua_rawseti(L
, -2, WRITE_BUFFER_LOCATION
);
125 /* LUA: __gc and buffer:close()
126 Releases the buffer resources
128 static int buffer_event_gc(lua_State
* L
) {
129 le_bufferevent
* ev
= buffer_event_get(L
, 1);
131 le_buffer
*read
, *write
;
132 bufferevent_free(ev
->ev
);
134 /* Also clear out the associated input/output event_buffers
135 * since they would have already been freed.. */
137 lua_rawgeti(L
, -1, READ_BUFFER_LOCATION
);
138 lua_rawgeti(L
, -2, WRITE_BUFFER_LOCATION
);
139 read
= event_buffer_check(L
, -2);
140 write
= event_buffer_check(L
, -1);
141 /* Erase Lua's link to the buffers */
143 /* LS: ..., fenv, readBuf, writeBuf, nil */
144 lua_rawseti(L
, -4, READ_BUFFER_LOCATION
);
146 lua_rawseti(L
, -4, WRITE_BUFFER_LOCATION
);
147 /* Erase their knowledge of the buffer so that the GC won't try to double-free */
149 write
->buffer
= NULL
;
154 static int buffer_event_get_read(lua_State
* L
) {
155 (void)buffer_event_get(L
, 1);
157 lua_rawgeti(L
, -1, READ_BUFFER_LOCATION
);
161 static int buffer_event_get_write(lua_State
* L
) {
162 (void)buffer_event_get(L
, 1);
164 lua_rawgeti(L
, -1, WRITE_BUFFER_LOCATION
);
168 static int buffer_event_set_read_watermarks(lua_State
* L
) {
170 le_bufferevent
* ev
= buffer_event_get(L
, 1);
171 if(!ev
->ev
) return 0;
173 low
= lua_tonumber(L
, 2);
174 high
= lua_tonumber(L
, 3);
176 bufferevent_setwatermark(ev
->ev
, EV_READ
, low
, high
);
180 static int buffer_event_set_write_watermarks(lua_State
* L
) {
182 le_bufferevent
* ev
= buffer_event_get(L
, 1);
183 if(!ev
->ev
) return 0;
185 low
= lua_tonumber(L
, 2);
186 high
= lua_tonumber(L
, 3);
188 bufferevent_setwatermark(ev
->ev
, EV_WRITE
, low
, high
);
192 static int buffer_event_set_timeouts(lua_State
* L
) {
193 int timeout_read
, timeout_write
;
194 le_bufferevent
* ev
= buffer_event_get(L
, 1);
195 if(!ev
->ev
) return 0;
197 timeout_read
= lua_tointeger(L
, 2);
198 timeout_write
= lua_tointeger(L
, 3);
200 bufferevent_settimeout(ev
->ev
, timeout_read
, timeout_write
);
204 static int buffer_event_enable(lua_State
* L
) {
205 le_bufferevent
* ev
= buffer_event_get(L
, 1);
206 if(!ev
->ev
) return 0;
208 lua_pushinteger(L
, bufferevent_enable(ev
->ev
, luaL_checkinteger(L
, 2)));
212 static int buffer_event_disable(lua_State
* L
) {
213 le_bufferevent
* ev
= buffer_event_get(L
, 1);
214 if(!ev
->ev
) return 0;
216 lua_pushinteger(L
, bufferevent_disable(ev
->ev
, luaL_checkinteger(L
, 2)));
220 static luaL_Reg buffer_event_funcs
[] = {
221 {"get_read", buffer_event_get_read
},
222 {"get_write", buffer_event_get_write
},
223 {"set_read_watermarks", buffer_event_set_read_watermarks
},
224 {"set_write_watermarks", buffer_event_set_write_watermarks
},
225 {"set_timeouts", buffer_event_set_timeouts
},
226 {"enable", buffer_event_enable
},
227 {"disable", buffer_event_disable
},
231 static luaL_Reg funcs
[] = {
232 {"new", buffer_event_push
},
236 void buffer_event_register(lua_State
* L
, int coreIndex
) {
237 luaL_newmetatable(L
, BUFFER_EVENT_MT
);
238 lua_pushcfunction(L
, buffer_event_gc
);
239 lua_setfield(L
, -2, "__gc");
241 luaL_register(L
, NULL
, buffer_event_funcs
);
242 lua_setfield(L
, -2, "__index");
246 luaL_register(L
, NULL
, funcs
);
247 lua_setfield(L
, coreIndex
, "bufferevent");