moonbridge

view moonbridge_io.c @ 82:069ee3f5ab17

Non-blocking write methods shall return io handle
author jbe
date Mon Apr 06 03:41:30 2015 +0200 (2015-04-06)
parents e1aec772a6ab
children 697cdf8e2000
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 nonblocking;
32 int writeerr;
33 int writeleft;
34 int writeqoff;
35 int writebufcnt;
36 char writebuf[MOONBR_IO_WRITEBUFLEN];
37 } moonbr_io_handle_t;
39 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
40 if (handle->nonblocking != nonblocking) {
41 int flags;
42 flags = fcntl(handle->fd, F_GETFL, 0);
43 if (flags == -1) {
44 moonbr_io_errmsg();
45 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
46 }
47 if (nonblocking) flags |= O_NONBLOCK;
48 else flags &= ~O_NONBLOCK;
49 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
50 moonbr_io_errmsg();
51 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
52 }
53 }
54 }
56 static int moonbr_io_close(lua_State *L) {
57 moonbr_io_handle_t *handle;
58 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
59 if (handle->fd < 0) luaL_error(L, "Attempt to close a closed I/O handle");
60 if (close(handle->fd)) {
61 handle->fd = -1;
62 moonbr_io_errmsg();
63 lua_pushnil(L);
64 lua_pushstring(L, errmsg);
65 return 2;
66 }
67 handle->fd = -1;
68 lua_pushboolean(L, 1);
69 return 1;
70 }
72 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
73 moonbr_io_handle_t *handle;
74 int i, top;
75 lua_Integer qlen, qpos, qpos2;
76 const char *str;
77 size_t strlen, strpos;
78 size_t written;
79 ssize_t result;
80 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
81 if (handle->writeerr) {
82 lua_pushnil(L);
83 lua_pushliteral(L, "Previous write error");
84 return 2;
85 }
86 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
87 if (!flush) top = lua_gettop(L);
88 lua_getuservalue(L, 1);
89 lua_getfield(L, -1, "writebuf");
90 qlen = lua_rawlen(L, -1);
91 if (!flush) {
92 for (i=2; i<=top; i++) {
93 luaL_checklstring(L, i, &strlen);
94 lua_pushvalue(L, i);
95 lua_rawseti(L, -2, ++qlen);
96 handle->writeleft += strlen;
97 }
98 }
99 for (qpos=1; qpos<=qlen; qpos++) {
100 lua_rawgeti(L, -1, qpos);
101 str = lua_tolstring(L, -1, &strlen);
102 strpos = handle->writeqoff;
103 while (strpos < strlen) {
104 if (strlen - strpos < MOONBR_IO_WRITEBUFLEN - handle->writebufcnt) {
105 memcpy(handle->writebuf + handle->writebufcnt, str + strpos, strlen - strpos);
106 handle->writebufcnt += strlen - strpos;
107 break;
108 } else {
109 written = 0;
110 memcpy(handle->writebuf + handle->writebufcnt, str + strpos, MOONBR_IO_WRITEBUFLEN - handle->writebufcnt);
111 strpos += MOONBR_IO_WRITEBUFLEN - handle->writebufcnt;
112 while (written < MOONBR_IO_WRITEBUFLEN) {
113 result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written);
114 if (result < 0) {
115 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
116 if (written) {
117 handle->writebufcnt -= written;
118 memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt);
119 }
120 if (i > 1) {
121 for (qpos2=1; qpos2<=qlen; qpos2++) {
122 if (qpos2+qpos-1 <= qlen) lua_rawgeti(L, -1, qpos2+qpos-1);
123 else lua_pushnil(L);
124 lua_rawseti(L, -2, qpos2);
125 }
126 }
127 handle->writeqoff = strpos;
128 goto moonbr_io_write_impl_block;
129 } else if (errno != EINTR) {
130 moonbr_io_errmsg();
131 handle->writeerr = 1;
132 lua_pushnil(L);
133 lua_pushstring(L, errmsg);
134 return 2;
135 }
136 } else {
137 written += result;
138 handle->writeleft -= result;
139 }
140 }
141 handle->writebufcnt = 0;
142 }
143 }
144 handle->writeqoff = 0;
145 lua_pop(L, 1);
146 lua_pushnil(L);
147 lua_rawseti(L, -2, qpos);
148 }
149 if (flush) {
150 written = 0;
151 while (written < handle->writebufcnt) {
152 result = write(handle->fd, handle->writebuf + written, handle->writebufcnt - written);
153 if (result < 0) {
154 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
155 if (written) {
156 handle->writebufcnt -= written;
157 memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt);
158 }
159 goto moonbr_io_write_impl_block;
160 } else if (errno != EINTR) {
161 moonbr_io_errmsg();
162 handle->writeerr = -1;
163 lua_pushnil(L);
164 lua_pushstring(L, errmsg);
165 return 2;
166 }
167 } else {
168 written += result;
169 handle->writeleft -= result;
170 }
171 }
172 handle->writebufcnt = 0;
173 if (nonblocking) lua_pushinteger(L, 0);
174 } else {
175 if (nonblocking) lua_pushinteger(L, handle->writeleft - handle->writebufcnt);
176 }
177 if (!nonblocking) lua_pushvalue(L, 1);
178 return 1;
179 moonbr_io_write_impl_block:
180 if (flush) lua_pushinteger(L, handle->writeleft);
181 else lua_pushinteger(L, handle->writeleft - handle->writebufcnt);
182 return 1;
183 }
185 static int moonbr_io_write(lua_State *L) {
186 return moonbr_io_write_impl(L, 0, 0);
187 }
189 static int moonbr_io_write_nb(lua_State *L) {
190 return moonbr_io_write_impl(L, 1, 0);
191 }
193 static int moonbr_io_flush(lua_State *L) {
194 return moonbr_io_write_impl(L, 0, 1);
195 }
197 static int moonbr_io_flush_nb(lua_State *L) {
198 return moonbr_io_write_impl(L, 1, 1);
199 }
201 void moonbr_io_pushhandle(lua_State *L, int fd, int gc_idx) {
202 moonbr_io_handle_t *handle;
203 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
204 handle->fd = fd;
205 handle->nonblocking = -1;
206 handle->writeerr = 0;
207 handle->writeleft = 0;
208 handle->writeqoff = 0;
209 handle->writebufcnt = 0;
210 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
211 lua_setmetatable(L, -2);
212 lua_newtable(L); // uservalue
213 lua_newtable(L);
214 lua_setfield(L, -2, "writebuf");
215 if (gc_idx) lua_pushvalue(L, gc_idx);
216 else lua_pushcfunction(L, moonbr_io_close);
217 lua_setfield(L, -2, "gc");
218 lua_newtable(L); // public
219 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
220 lua_setmetatable(L, -2);
221 lua_setfield(L, -2, "public");
222 lua_setuservalue(L, -2);
223 }
225 static int moonbr_io_handleindex(lua_State *L) {
226 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
227 lua_getuservalue(L, 1);
228 lua_getfield(L, -1, "public");
229 lua_pushvalue(L, 2);
230 lua_gettable(L, -2);
231 return 1;
232 }
234 static int moonbr_io_handlenewindex(lua_State *L) {
235 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
236 lua_getuservalue(L, 1);
237 lua_getfield(L, -1, "public");
238 lua_pushvalue(L, 2);
239 lua_pushvalue(L, 3);
240 lua_settable(L, -3);
241 return 0;
242 }
244 static int moonbr_io_handlegc(lua_State *L) {
245 moonbr_io_handle_t *handle;
246 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
247 if (handle->fd >= 0) {
248 lua_getuservalue(L, 1);
249 lua_getfield(L, -1, "gc");
250 lua_pushvalue(L, 1);
251 lua_call(L, 1, 0);
252 }
253 return 0;
254 }
256 static int moonbr_io_getdummy(lua_State *L) {
257 moonbr_io_pushhandle(L, 2, 0);
258 return 1;
259 }
261 static const struct luaL_Reg moonbr_io_handle_methods[] = {
262 {"close", moonbr_io_close},
263 {"write", moonbr_io_write},
264 {"write_nb", moonbr_io_write_nb},
265 {"flush", moonbr_io_flush},
266 {"flush_nb", moonbr_io_flush_nb},
267 {NULL, NULL}
268 };
270 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
271 {"__index", moonbr_io_handleindex},
272 {"__newindex", moonbr_io_handlenewindex},
273 {"__gc", moonbr_io_handlegc},
274 {NULL, NULL}
275 };
277 static const struct luaL_Reg moonbr_io_module_funcs[] = {
278 {"getdummy", moonbr_io_getdummy},
279 {NULL, NULL}
280 };
282 int luaopen_moonbridge_io(lua_State *L) {
284 lua_newtable(L); // module
286 lua_newtable(L); // public metatable
287 lua_newtable(L); // handle methods
288 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
289 lua_pushvalue(L, -1);
290 lua_setfield(L, -4, "handle");
291 lua_setfield(L, -2, "__index");
292 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
294 lua_newtable(L); // handle metatable
295 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
296 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
298 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
299 return 1;
301 }

Impressum / About Us