moonbridge
diff moonbridge_io.c @ 108:110493d29f90
Fixes in moonbridge_io.tcpconnect(...); Added moonbridge_io.tcplisten(...)
author | jbe |
---|---|
date | Thu Apr 09 16:38:16 2015 +0200 (2015-04-09) |
parents | 06d965df8a0c |
children | a14e0eb8598b |
line diff
1.1 --- a/moonbridge_io.c Wed Apr 08 23:13:09 2015 +0200 1.2 +++ b/moonbridge_io.c Thu Apr 09 16:38:16 2015 +0200 1.3 @@ -21,12 +21,15 @@ 1.4 #define MOONBR_IO_READBUFLEN 4096 1.5 #define MOONBR_IO_WRITEBUFLEN 4096 1.6 1.7 +#define MOONBR_IO_LISTEN_BACKLOG 1024 1.8 + 1.9 #define moonbr_io_errmsg() \ 1.10 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \ 1.11 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN) 1.12 1.13 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle" 1.14 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public" 1.15 +#define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener" 1.16 1.17 typedef struct { 1.18 int fd; 1.19 @@ -55,6 +58,11 @@ 1.20 char writebuf[MOONBR_IO_WRITEBUFLEN]; 1.21 } moonbr_io_handle_t; 1.22 1.23 +typedef struct { 1.24 + int fd; 1.25 + int nonblocking; 1.26 +} moonbr_io_listener_t; 1.27 + 1.28 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) { 1.29 int flags; 1.30 if (handle->nonblocking == nonblocking) return; 1.31 @@ -453,7 +461,7 @@ 1.32 return moonbr_io_close_impl(L, 1); 1.33 } 1.34 1.35 -static int moonbr_io_gc(lua_State *L) { 1.36 +static int moonbr_io_handlegc(lua_State *L) { 1.37 moonbr_io_handle_t *handle; 1.38 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); 1.39 if (handle->fd >= 0) { 1.40 @@ -655,13 +663,15 @@ 1.41 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0), 1.42 addrinfo->ai_protocol 1.43 ); 1.44 - freeaddrinfo(res); 1.45 if (sock < 0) { 1.46 moonbr_io_errmsg(); 1.47 + freeaddrinfo(res); 1.48 lua_pushnil(L); 1.49 lua_pushstring(L, errmsg); 1.50 + return 2; 1.51 } 1.52 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) { 1.53 + freeaddrinfo(res); 1.54 if (!nonblocking && errno == EINTR) { 1.55 moonbr_io_errmsg(); 1.56 close(sock); 1.57 @@ -674,6 +684,8 @@ 1.58 lua_pushstring(L, errmsg); 1.59 return 2; 1.60 } 1.61 + } else { 1.62 + freeaddrinfo(res); 1.63 } 1.64 moonbr_io_pushhandle(L, sock); 1.65 return 1; 1.66 @@ -687,8 +699,154 @@ 1.67 return moonbr_io_tcpconnect_impl(L, 1); 1.68 } 1.69 1.70 +static int moonbr_io_tcplisten(lua_State *L) { 1.71 + moonbr_io_listener_t *listener; 1.72 + const char *host, *port; 1.73 + struct addrinfo hints = { 0, }; 1.74 + struct addrinfo *res, *addrinfo; 1.75 + int errcode; 1.76 + int sock; 1.77 + host = luaL_optstring(L, 1, NULL); 1.78 + port = luaL_checkstring(L, 2); 1.79 + listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t)); 1.80 + luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY); 1.81 + hints.ai_family = AF_UNSPEC; 1.82 + hints.ai_socktype = SOCK_STREAM; 1.83 + hints.ai_protocol = IPPROTO_TCP; 1.84 + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; 1.85 + errcode = getaddrinfo(host, port, &hints, &res); 1.86 + if (errcode) { 1.87 + freeaddrinfo(res); 1.88 + if (errcode == EAI_SYSTEM) { 1.89 + moonbr_io_errmsg(); 1.90 + lua_pushnil(L); 1.91 + lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg); 1.92 + } else { 1.93 + lua_pushnil(L); 1.94 + lua_pushstring(L, gai_strerror(errcode)); 1.95 + } 1.96 + return 2; 1.97 + } 1.98 + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { 1.99 + if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found; 1.100 + } 1.101 + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { 1.102 + if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found; 1.103 + } 1.104 + addrinfo = res; 1.105 + moonbr_io_tcpconnect_found: 1.106 + sock = socket( 1.107 + addrinfo->ai_family, 1.108 + addrinfo->ai_socktype | SOCK_CLOEXEC, 1.109 + addrinfo->ai_protocol 1.110 + ); 1.111 + if (sock < 0) { 1.112 + moonbr_io_errmsg(); 1.113 + freeaddrinfo(res); 1.114 + lua_pushnil(L); 1.115 + lua_pushstring(L, errmsg); 1.116 + return 2; 1.117 + } 1.118 + if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) { 1.119 + moonbr_io_errmsg(); 1.120 + freeaddrinfo(res); 1.121 + close(sock); 1.122 + lua_pushnil(L); 1.123 + lua_pushstring(L, errmsg); 1.124 + return 2; 1.125 + } 1.126 + freeaddrinfo(res); 1.127 + if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) { 1.128 + moonbr_io_errmsg(); 1.129 + close(sock); 1.130 + lua_pushnil(L); 1.131 + lua_pushstring(L, errmsg); 1.132 + return 2; 1.133 + } 1.134 + listener->fd = sock; 1.135 + listener->nonblocking = -1; 1.136 + return 1; 1.137 +} 1.138 + 1.139 +static int moonbr_io_accept_impl(lua_State *L, int nonblocking) { 1.140 + moonbr_io_listener_t *listener; 1.141 + int fd; 1.142 + listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY); 1.143 + if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener"); 1.144 + if (listener->nonblocking != nonblocking) { 1.145 + int flags; 1.146 + flags = fcntl(listener->fd, F_GETFL, 0); 1.147 + if (flags == -1) { 1.148 + moonbr_io_errmsg(); 1.149 + close(listener->fd); 1.150 + listener->fd = -1; 1.151 + luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); 1.152 + } 1.153 + if (nonblocking) flags |= O_NONBLOCK; 1.154 + else flags &= ~O_NONBLOCK; 1.155 + if (fcntl(listener->fd, F_SETFL, flags) == -1) { 1.156 + moonbr_io_errmsg(); 1.157 + close(listener->fd); 1.158 + listener->fd = -1; 1.159 + luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); 1.160 + } 1.161 + listener->nonblocking = nonblocking; 1.162 + } 1.163 + while (1) { 1.164 + fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC); 1.165 + if (fd < 0) { 1.166 + if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { 1.167 + lua_pushboolean(L, 0); 1.168 + lua_pushliteral(L, "No incoming connection pending"); 1.169 + return 2; 1.170 + } else if (errno != EINTR) { 1.171 + moonbr_io_errmsg(); 1.172 + lua_pushnil(L); 1.173 + lua_pushstring(L, errmsg); 1.174 + return 2; 1.175 + } 1.176 + } else { 1.177 + moonbr_io_pushhandle(L, fd); 1.178 + return 1; 1.179 + } 1.180 + } 1.181 +} 1.182 + 1.183 +static int moonbr_io_accept(lua_State *L) { 1.184 + return moonbr_io_accept_impl(L, 0); 1.185 +} 1.186 + 1.187 +static int moonbr_io_accept_nb(lua_State *L) { 1.188 + return moonbr_io_accept_impl(L, 1); 1.189 +} 1.190 + 1.191 +static int moonbr_io_unlisten(lua_State *L) { 1.192 + moonbr_io_listener_t *listener; 1.193 + listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY); 1.194 + if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener"); 1.195 + if (close(listener->fd)) { 1.196 + moonbr_io_errmsg(); 1.197 + listener->fd = -1; 1.198 + lua_pushnil(L); 1.199 + lua_pushstring(L, errmsg); 1.200 + return 2; 1.201 + } 1.202 + listener->fd = -1; 1.203 + lua_pushboolean(L, 1); 1.204 + return 1; 1.205 +} 1.206 + 1.207 +static int moonbr_io_listenergc(lua_State *L) { 1.208 + moonbr_io_listener_t *listener; 1.209 + listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY); 1.210 + if (listener->fd) close(listener->fd); 1.211 + listener->fd = -1; 1.212 + return 0; 1.213 +} 1.214 + 1.215 static int moonbr_io_poll(lua_State *L) { 1.216 moonbr_io_handle_t *handle; 1.217 + moonbr_io_listener_t *listener; 1.218 int fd, isnum; 1.219 int nfds = 0; 1.220 fd_set readfds, writefds, exceptfds; 1.221 @@ -704,10 +862,16 @@ 1.222 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY); 1.223 if (handle) { 1.224 fd = handle->fd; 1.225 - if (fd < 0) luaL_error(L, "Handle in illegal state"); 1.226 + if (fd < 0) luaL_error(L, "Handle in illegal state"); /* TODO: EOF simulation with finishing local sockets */ 1.227 } else { 1.228 - fd = lua_tointegerx(L, -2, &isnum); 1.229 - if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.230 + listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY); 1.231 + if (listener) { 1.232 + fd = listener->fd; 1.233 + if (fd < 0) luaL_error(L, "Attempt to poll a closed listener"); 1.234 + } else { 1.235 + fd = lua_tointegerx(L, -2, &isnum); 1.236 + if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key"); 1.237 + } 1.238 } 1.239 FD_SET(fd, &readfds); 1.240 if (fd+1 > nfds) nfds = fd+1; 1.241 @@ -723,8 +887,14 @@ 1.242 fd = handle->fd; 1.243 if (fd < 0) luaL_error(L, "Handle in illegal state"); 1.244 } else { 1.245 - fd = lua_tointegerx(L, -2, &isnum); 1.246 - if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.247 + listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY); 1.248 + if (listener) { 1.249 + fd = listener->fd; 1.250 + if (fd < 0) luaL_error(L, "Attempt to poll a closed listener"); 1.251 + } else { 1.252 + fd = lua_tointegerx(L, -2, &isnum); 1.253 + if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key"); 1.254 + } 1.255 } 1.256 FD_SET(fd, &writefds); 1.257 if (fd+1 > nfds) nfds = fd+1; 1.258 @@ -781,13 +951,26 @@ 1.259 static const struct luaL_Reg moonbr_io_handle_metamethods[] = { 1.260 {"__index", moonbr_io_handleindex}, 1.261 {"__newindex", moonbr_io_handlenewindex}, 1.262 - {"__gc", moonbr_io_gc}, 1.263 + {"__gc", moonbr_io_handlegc}, 1.264 + {NULL, NULL} 1.265 +}; 1.266 + 1.267 +static const struct luaL_Reg moonbr_io_listener_methods[] = { 1.268 + {"accept", moonbr_io_accept}, 1.269 + {"accept_nb", moonbr_io_accept_nb}, 1.270 + {"close", moonbr_io_unlisten}, 1.271 + {NULL, NULL} 1.272 +}; 1.273 + 1.274 +static const struct luaL_Reg moonbr_io_listener_metamethods[] = { 1.275 + {"__gc", moonbr_io_listenergc}, 1.276 {NULL, NULL} 1.277 }; 1.278 1.279 static const struct luaL_Reg moonbr_io_module_funcs[] = { 1.280 {"tcpconnect", moonbr_io_tcpconnect}, 1.281 {"tcpconnect_nb", moonbr_io_tcpconnect_nb}, 1.282 + {"tcplisten", moonbr_io_tcplisten}, 1.283 {"poll", moonbr_io_poll}, 1.284 {NULL, NULL} 1.285 }; 1.286 @@ -800,7 +983,7 @@ 1.287 lua_newtable(L); // handle methods 1.288 luaL_setfuncs(L, moonbr_io_handle_methods, 0); 1.289 lua_pushvalue(L, -1); 1.290 - lua_setfield(L, -4, "handle"); 1.291 + lua_setfield(L, -4, "prototype_handle"); 1.292 lua_setfield(L, -2, "__index"); 1.293 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); 1.294 1.295 @@ -808,6 +991,15 @@ 1.296 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0); 1.297 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY); 1.298 1.299 + lua_newtable(L); // listener metatable 1.300 + luaL_setfuncs(L, moonbr_io_listener_metamethods, 0); 1.301 + lua_newtable(L); // listener methods 1.302 + luaL_setfuncs(L, moonbr_io_listener_methods, 0); 1.303 + lua_pushvalue(L, -1); 1.304 + lua_setfield(L, -4, "prototype_listener"); 1.305 + lua_setfield(L, -2, "__index"); 1.306 + lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY); 1.307 + 1.308 luaL_setfuncs(L, moonbr_io_module_funcs, 0); 1.309 return 1; 1.310