moonbridge

view moonbridge_io.c @ 80:1a0346580e6d

Blocking :write(...) and :flush(...) methods in I/O library
author jbe
date Mon Apr 06 01:35:23 2015 +0200 (2015-04-06)
parents 22dbb9d09f02
children e1aec772a6ab
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>
13 #include <lua.h>
14 #include <lauxlib.h>
15 #include <lualib.h>
17 #define MOONBR_IO_MAXSTRERRORLEN 80
18 #define MOONBR_IO_WRITEBUFLEN 4096
20 #define moonbr_io_errmsg() \
21 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
22 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
25 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
26 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
28 typedef struct {
29 int fd;
30 int writecnt;
31 char writebuf[MOONBR_IO_WRITEBUFLEN];
32 } moonbr_io_handle_t;
34 static int moonbr_io_close(lua_State *L) {
35 moonbr_io_handle_t *handle;
36 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
37 if (handle->fd < 0) luaL_error(L, "Attempt to close a closed I/O handle");
38 if (close(handle->fd)) {
39 handle->fd = -1;
40 moonbr_io_errmsg();
41 lua_pushnil(L);
42 lua_pushstring(L, errmsg);
43 return 2;
44 }
45 handle->fd = -1;
46 lua_pushboolean(L, 1);
47 return 1;
48 }
50 static int moonbr_io_write(lua_State *L) {
51 moonbr_io_handle_t *handle;
52 int i, top;
53 const char *str;
54 size_t strlen;
55 size_t written;
56 ssize_t result;
57 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
58 if (handle->writecnt < 0) {
59 lua_pushnil(L);
60 lua_pushliteral(L, "Previous write error");
61 return 2;
62 }
63 top = lua_gettop(L);
64 for (i=2; i<=top; i++) {
65 str = luaL_checklstring(L, i, &strlen);
66 while (strlen) {
67 if (strlen < MOONBR_IO_WRITEBUFLEN - handle->writecnt) {
68 memcpy(handle->writebuf + handle->writecnt, str, strlen);
69 handle->writecnt += strlen;
70 break;
71 } else {
72 written = 0;
73 memcpy(handle->writebuf + handle->writecnt, str, MOONBR_IO_WRITEBUFLEN - handle->writecnt);
74 while (written < MOONBR_IO_WRITEBUFLEN) {
75 result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written);
76 if (result < 0) {
77 if (errno != EINTR) {
78 moonbr_io_errmsg();
79 handle->writecnt = -1;
80 lua_pushnil(L);
81 lua_pushstring(L, errmsg);
82 return 2;
83 }
84 } else {
85 written += result;
86 }
87 }
88 str += MOONBR_IO_WRITEBUFLEN - handle->writecnt;
89 strlen -= MOONBR_IO_WRITEBUFLEN - handle->writecnt;
90 handle->writecnt = 0;
91 }
92 }
93 }
94 lua_settop(L, 1);
95 return 1;
96 }
98 static int moonbr_io_flush(lua_State *L) {
99 moonbr_io_handle_t *handle;
100 size_t written;
101 ssize_t result;
102 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
103 if (handle->writecnt < 0) {
104 lua_pushnil(L);
105 lua_pushliteral(L, "Previous write error");
106 return 2;
107 }
108 written = 0;
109 while (written < handle->writecnt) {
110 result = write(handle->fd, handle->writebuf + written, handle->writecnt - written);
111 if (result < 0) {
112 if (errno != EINTR) {
113 moonbr_io_errmsg();
114 handle->writecnt = -1;
115 lua_pushnil(L);
116 lua_pushstring(L, errmsg);
117 return 2;
118 }
119 } else {
120 written += result;
121 }
122 }
123 handle->writecnt = 0;
124 lua_settop(L, 1);
125 return 1;
126 }
128 void moonbr_io_pushhandle(lua_State *L, int fd, int gc_idx) {
129 moonbr_io_handle_t *handle;
130 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
131 handle->fd = fd;
132 handle->writecnt = 0;
133 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
134 lua_setmetatable(L, -2);
135 lua_newtable(L); // uservalue
136 if (gc_idx) lua_pushvalue(L, gc_idx);
137 else lua_pushcfunction(L, moonbr_io_close);
138 lua_setfield(L, -2, "gc");
139 lua_newtable(L); // public
140 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
141 lua_setmetatable(L, -2);
142 lua_setfield(L, -2, "public");
143 lua_setuservalue(L, -2);
144 }
146 static int moonbr_io_handleindex(lua_State *L) {
147 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
148 lua_getuservalue(L, 1);
149 lua_getfield(L, -1, "public");
150 lua_pushvalue(L, 2);
151 lua_gettable(L, -2);
152 return 1;
153 }
155 static int moonbr_io_handlenewindex(lua_State *L) {
156 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
157 lua_getuservalue(L, 1);
158 lua_getfield(L, -1, "public");
159 lua_pushvalue(L, 2);
160 lua_pushvalue(L, 3);
161 lua_settable(L, -3);
162 return 0;
163 }
165 static int moonbr_io_handlegc(lua_State *L) {
166 moonbr_io_handle_t *handle;
167 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
168 if (handle->fd >= 0) {
169 lua_getuservalue(L, 1);
170 lua_getfield(L, -1, "gc");
171 lua_pushvalue(L, 1);
172 lua_call(L, 1, 0);
173 }
174 return 0;
175 }
177 static int moonbr_io_getdummy(lua_State *L) {
178 moonbr_io_pushhandle(L, 2, 0);
179 return 1;
180 }
182 static const struct luaL_Reg moonbr_io_handle_methods[] = {
183 {"close", moonbr_io_close},
184 {"write", moonbr_io_write},
185 {"flush", moonbr_io_flush},
186 {NULL, NULL}
187 };
189 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
190 {"__index", moonbr_io_handleindex},
191 {"__newindex", moonbr_io_handlenewindex},
192 {"__gc", moonbr_io_handlegc},
193 {NULL, NULL}
194 };
196 static const struct luaL_Reg moonbr_io_module_funcs[] = {
197 {"getdummy", moonbr_io_getdummy},
198 {NULL, NULL}
199 };
201 int luaopen_moonbridge_io(lua_State *L) {
203 lua_newtable(L); // module
205 lua_newtable(L); // public metatable
206 lua_newtable(L); // handle methods
207 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
208 lua_pushvalue(L, -1);
209 lua_setfield(L, -4, "handle");
210 lua_setfield(L, -2, "__index");
211 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
213 lua_newtable(L); // handle metatable
214 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
215 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
217 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
218 return 1;
220 }

Impressum / About Us