core: updates to MIT-style license and properly includes in file heading
[luaevent.git] / src / buffer_event.c
blob783186f36519576869528f2a63d5cd9667428ab4
1 /* LuaEvent
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
20 THE SOFTWARE.
23 #include <stdlib.h>
24 #include "buffer_event.h"
25 #include "utility.h"
26 #include <lauxlib.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);
45 if(!buf->ev)
46 luaL_argerror(L, idx, "Attempt to use closed buffer_event object");
47 return buf;
50 /* Checks if the given index contains an le_buffer object */
51 int is_buffer_event(lua_State* L, int idx) {
52 int ret;
53 lua_getmetatable(L, idx);
54 luaL_getmetatable(L, BUFFER_EVENT_MT);
55 ret = lua_rawequal(L, -2, -1);
56 lua_pop(L, 2);
57 return ret;
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);
63 lua_getfenv(L, -1);
64 lua_rawgeti(L, -1, callbackIndex);
65 lua_remove(L, -2);
66 lua_pushvalue(L, -2);
67 lua_remove(L, -3);
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) {
97 le_bufferevent *ev;
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);
109 lua_pushvalue(L, 3);
110 lua_rawseti(L, -2, 1); // Read
111 lua_pushvalue(L, 4);
112 lua_rawseti(L, -2, 2); // Write
113 lua_pushvalue(L, 5);
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);
120 lua_setfenv(L, -2);
121 ev->base = base;
122 return 1;
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);
130 if(ev->ev) {
131 le_buffer *read, *write;
132 bufferevent_free(ev->ev);
133 ev->ev = NULL;
134 /* Also clear out the associated input/output event_buffers
135 * since they would have already been freed.. */
136 lua_getfenv(L, 1);
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 */
142 lua_pushnil(L);
143 /* LS: ..., fenv, readBuf, writeBuf, nil */
144 lua_rawseti(L, -4, READ_BUFFER_LOCATION);
145 lua_pushnil(L);
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 */
148 read->buffer = NULL;
149 write->buffer = NULL;
151 return 0;
154 static int buffer_event_get_read(lua_State* L) {
155 (void)buffer_event_get(L, 1);
156 lua_getfenv(L, 1);
157 lua_rawgeti(L, -1, READ_BUFFER_LOCATION);
158 return 1;
161 static int buffer_event_get_write(lua_State* L) {
162 (void)buffer_event_get(L, 1);
163 lua_getfenv(L, 1);
164 lua_rawgeti(L, -1, WRITE_BUFFER_LOCATION);
165 return 1;
168 static int buffer_event_set_read_watermarks(lua_State* L) {
169 int low, high;
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);
177 return 0;
180 static int buffer_event_set_write_watermarks(lua_State* L) {
181 int low, high;
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);
189 return 0;
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);
201 return 0;
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)));
209 return 1;
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)));
217 return 1;
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},
228 {NULL, NULL}
231 static luaL_Reg funcs[] = {
232 {"new", buffer_event_push},
233 {NULL, NULL}
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");
240 lua_newtable(L);
241 luaL_register(L, NULL, buffer_event_funcs);
242 lua_setfield(L, -2, "__index");
243 lua_pop(L, 1);
245 lua_newtable(L);
246 luaL_register(L, NULL, funcs);
247 lua_setfield(L, coreIndex, "bufferevent");