moonbridge
view moonbridge_io.c @ 84:8a6e2a80fcad
Refined interface of I/O library to directly support (previously opened) sockets
author | jbe |
---|---|
date | Mon Apr 06 15:41:37 2015 +0200 (2015-04-06) |
parents | 697cdf8e2000 |
children | ef552870f1b6 |
line source
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <stdint.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <time.h>
9 #include <sys/time.h>
10 #include <sys/socket.h>
11 #include <sys/select.h>
12 #include <fcntl.h>
14 #include <lua.h>
15 #include <lauxlib.h>
16 #include <lualib.h>
18 #define MOONBR_IO_MAXSTRERRORLEN 80
19 #define MOONBR_IO_WRITEBUFLEN 4096
21 #define moonbr_io_errmsg() \
22 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
23 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
26 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
27 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
29 typedef struct {
30 int fd;
31 int issocket;
32 int nonblocking;
33 int writeerr;
34 size_t writeleft;
35 #if LUA_VERSION_NUM >= 503
36 lua_Integer writeqin;
37 lua_Integer writeqout;
38 #else
39 int writeqin;
40 int writeqout;
41 #endif
42 size_t writeqoff;
43 int writebufcnt;
44 char writebuf[MOONBR_IO_WRITEBUFLEN];
45 } moonbr_io_handle_t;
47 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
48 if (handle->nonblocking != nonblocking) {
49 int flags;
50 flags = fcntl(handle->fd, F_GETFL, 0);
51 if (flags == -1) {
52 moonbr_io_errmsg();
53 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
54 }
55 if (nonblocking) flags |= O_NONBLOCK;
56 else flags &= ~O_NONBLOCK;
57 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
58 moonbr_io_errmsg();
59 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
60 }
61 }
62 }
64 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
65 moonbr_io_handle_t *handle;
66 int i, top;
67 const char *str;
68 size_t strlen, strpos;
69 size_t written;
70 ssize_t result;
71 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
72 if (handle->fd < 0) luaL_error(L, "Attempt to write to a closed I/O handle");
73 if (handle->writeerr) {
74 lua_pushnil(L);
75 lua_pushliteral(L, "Previous write error");
76 return 2;
77 }
78 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
79 top = lua_gettop(L);
80 lua_getuservalue(L, 1);
81 lua_getfield(L, -1, "writebuf");
82 for (i=2; i<=top; i++) {
83 luaL_checklstring(L, i, &strlen);
84 lua_pushvalue(L, i);
85 lua_rawseti(L, -2, handle->writeqin++);
86 handle->writeleft += strlen;
87 }
88 while (handle->writeqout != handle->writeqin) {
89 lua_rawgeti(L, -1, handle->writeqout);
90 str = lua_tolstring(L, -1, &strlen);
91 strpos = handle->writeqoff;
92 while (strpos < strlen) {
93 if (strlen - strpos < MOONBR_IO_WRITEBUFLEN - handle->writebufcnt) {
94 memcpy(handle->writebuf + handle->writebufcnt, str + strpos, strlen - strpos);
95 handle->writebufcnt += strlen - strpos;
96 break;
97 } else {
98 written = 0;
99 memcpy(handle->writebuf + handle->writebufcnt, str + strpos, MOONBR_IO_WRITEBUFLEN - handle->writebufcnt);
100 strpos += MOONBR_IO_WRITEBUFLEN - handle->writebufcnt;
101 while (written < MOONBR_IO_WRITEBUFLEN) {
102 result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written);
103 if (result < 0) {
104 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
105 if (written) {
106 handle->writebufcnt -= written;
107 memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt);
108 }
109 handle->writeqoff = strpos;
110 goto moonbr_io_write_impl_block;
111 } else if (errno != EINTR) {
112 moonbr_io_errmsg();
113 handle->writeerr = 1;
114 lua_pushnil(L);
115 lua_pushstring(L, errmsg);
116 return 2;
117 }
118 } else {
119 written += result;
120 handle->writeleft -= result;
121 }
122 }
123 handle->writebufcnt = 0;
124 }
125 }
126 handle->writeqoff = 0;
127 lua_pop(L, 1);
128 lua_pushnil(L);
129 lua_rawseti(L, -2, handle->writeqout++);
130 }
131 if (flush) {
132 written = 0;
133 while (written < handle->writebufcnt) {
134 result = write(handle->fd, handle->writebuf + written, handle->writebufcnt - written);
135 if (result < 0) {
136 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
137 if (written) {
138 handle->writebufcnt -= written;
139 memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt);
140 }
141 goto moonbr_io_write_impl_block;
142 } else if (errno != EINTR) {
143 moonbr_io_errmsg();
144 handle->writeerr = -1;
145 lua_pushnil(L);
146 lua_pushstring(L, errmsg);
147 return 2;
148 }
149 } else {
150 written += result;
151 handle->writeleft -= result;
152 }
153 }
154 handle->writebufcnt = 0;
155 if (nonblocking) lua_pushinteger(L, 0);
156 } else {
157 if (nonblocking) lua_pushinteger(L, handle->writeleft - handle->writebufcnt);
158 }
159 if (!nonblocking) lua_pushvalue(L, 1);
160 return 1;
161 moonbr_io_write_impl_block:
162 if (flush) lua_pushinteger(L, handle->writeleft);
163 else lua_pushinteger(L, handle->writeleft - handle->writebufcnt);
164 return 1;
165 }
167 static int moonbr_io_write(lua_State *L) {
168 return moonbr_io_write_impl(L, 0, 0);
169 }
171 static int moonbr_io_write_nb(lua_State *L) {
172 return moonbr_io_write_impl(L, 1, 0);
173 }
175 static int moonbr_io_flush(lua_State *L) {
176 return moonbr_io_write_impl(L, 0, 1);
177 }
179 static int moonbr_io_flush_nb(lua_State *L) {
180 return moonbr_io_write_impl(L, 1, 1);
181 }
183 static int moonbr_io_close_impl(lua_State *L, int clean) {
184 moonbr_io_handle_t *handle;
185 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
186 if (handle->fd < 0) luaL_error(L, "Attempt to close a closed I/O handle");
187 if (clean && handle->writeleft) {
188 lua_pushcfunction(L, moonbr_io_flush);
189 lua_pushvalue(L, 1);
190 lua_call(L, 1, 2);
191 if (!lua_toboolean(L, -2)) {
192 close(handle->fd);
193 handle->fd = -1;
194 return 2;
195 }
196 }
197 if (close(handle->fd)) {
198 moonbr_io_errmsg();
199 handle->fd = -1;
200 lua_pushnil(L);
201 lua_pushstring(L, errmsg);
202 return 2;
203 }
204 handle->fd = -1;
205 lua_pushboolean(L, 1);
206 return 1;
208 }
210 static int moonbr_io_reset(lua_State *L) {
211 return moonbr_io_close_impl(L, 0);
212 }
214 static int moonbr_io_close(lua_State *L) {
215 return moonbr_io_close_impl(L, 1);
216 }
218 void moonbr_io_pushhandle(lua_State *L, int fd, int issocket) {
219 moonbr_io_handle_t *handle;
220 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
221 handle->fd = fd;
222 handle->issocket = issocket;
223 handle->nonblocking = -1;
224 handle->writeerr = 0;
225 handle->writeleft = 0;
226 handle->writeqin = 0;
227 handle->writeqout = 0;
228 handle->writeqoff = 0;
229 handle->writebufcnt = 0;
230 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
231 lua_setmetatable(L, -2);
232 lua_newtable(L); // uservalue
233 lua_newtable(L);
234 lua_setfield(L, -2, "writebuf");
235 lua_newtable(L); // public
236 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
237 lua_setmetatable(L, -2);
238 lua_setfield(L, -2, "public");
239 lua_setuservalue(L, -2);
240 }
242 static int moonbr_io_handleindex(lua_State *L) {
243 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
244 lua_getuservalue(L, 1);
245 lua_getfield(L, -1, "public");
246 lua_pushvalue(L, 2);
247 lua_gettable(L, -2);
248 return 1;
249 }
251 static int moonbr_io_handlenewindex(lua_State *L) {
252 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
253 lua_getuservalue(L, 1);
254 lua_getfield(L, -1, "public");
255 lua_pushvalue(L, 2);
256 lua_pushvalue(L, 3);
257 lua_settable(L, -3);
258 return 0;
259 }
261 static int moonbr_io_handlegc(lua_State *L) {
262 moonbr_io_handle_t *handle;
263 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
264 if (handle->fd >= 0) {
265 lua_getuservalue(L, 1);
266 lua_getfield(L, -1, "gc");
267 lua_pushvalue(L, 1);
268 lua_call(L, 1, 0);
269 }
270 return 0;
271 }
273 static int moonbr_io_getdummy(lua_State *L) {
274 moonbr_io_pushhandle(L, 2, 0);
275 return 1;
276 }
278 static const struct luaL_Reg moonbr_io_handle_methods[] = {
279 {"reset", moonbr_io_reset},
280 {"close", moonbr_io_close},
281 {"write", moonbr_io_write},
282 {"write_nb", moonbr_io_write_nb},
283 {"flush", moonbr_io_flush},
284 {"flush_nb", moonbr_io_flush_nb},
285 {NULL, NULL}
286 };
288 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
289 {"__index", moonbr_io_handleindex},
290 {"__newindex", moonbr_io_handlenewindex},
291 {"__gc", moonbr_io_handlegc},
292 {NULL, NULL}
293 };
295 static const struct luaL_Reg moonbr_io_module_funcs[] = {
296 {"getdummy", moonbr_io_getdummy},
297 {NULL, NULL}
298 };
300 int luaopen_moonbridge_io(lua_State *L) {
302 lua_newtable(L); // module
304 lua_newtable(L); // public metatable
305 lua_newtable(L); // handle methods
306 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
307 lua_pushvalue(L, -1);
308 lua_setfield(L, -4, "handle");
309 lua_setfield(L, -2, "__index");
310 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
312 lua_newtable(L); // handle metatable
313 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
314 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
316 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
317 return 1;
319 }