jbe@79: jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@81: #include jbe@95: #include jbe@95: #include jbe@98: #include jbe@98: #include jbe@79: jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: jbe@80: #define MOONBR_IO_MAXSTRERRORLEN 80 jbe@85: #define MOONBR_IO_READBUFLEN 4096 jbe@80: #define MOONBR_IO_WRITEBUFLEN 4096 jbe@80: jbe@80: #define moonbr_io_errmsg() \ jbe@80: char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \ jbe@80: strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN) jbe@80: jbe@79: #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle" jbe@79: #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public" jbe@79: jbe@79: typedef struct { jbe@79: int fd; jbe@95: int isnetwork; jbe@94: int finished; jbe@94: int closed; jbe@81: int nonblocking; jbe@95: int nopush; jbe@85: int readerr; jbe@85: int readbufcnt; jbe@81: int writeerr; jbe@83: size_t writeleft; jbe@83: #if LUA_VERSION_NUM >= 503 jbe@83: lua_Integer writeqin; jbe@83: lua_Integer writeqout; jbe@83: #else jbe@83: int writeqin; jbe@83: int writeqout; jbe@83: #endif jbe@83: size_t writeqoff; jbe@81: int writebufcnt; jbe@85: char readbuf[MOONBR_IO_READBUFLEN]; jbe@80: char writebuf[MOONBR_IO_WRITEBUFLEN]; jbe@79: } moonbr_io_handle_t; jbe@79: jbe@81: static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) { jbe@95: int flags; jbe@95: if (handle->nonblocking == nonblocking) return; jbe@95: flags = fcntl(handle->fd, F_GETFL, 0); jbe@95: if (flags == -1) { jbe@95: moonbr_io_errmsg(); jbe@96: close(handle->fd); jbe@96: handle->fd = -1; jbe@96: handle->closed = 1; jbe@95: luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); jbe@81: } jbe@95: if (nonblocking) flags |= O_NONBLOCK; jbe@95: else flags &= ~O_NONBLOCK; jbe@95: if (fcntl(handle->fd, F_SETFL, flags) == -1) { jbe@95: moonbr_io_errmsg(); jbe@96: close(handle->fd); jbe@96: handle->fd = -1; jbe@96: handle->closed = 1; jbe@95: luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); jbe@95: } jbe@95: handle->nonblocking = nonblocking; jbe@81: } jbe@81: jbe@87: static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) { jbe@87: struct linger lingerval = { 0, }; jbe@95: if (!handle->isnetwork) return; jbe@87: if (timeout >= 0) { jbe@87: lingerval.l_onoff = 1; jbe@87: lingerval.l_linger = timeout; jbe@87: } jbe@87: if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) { jbe@87: moonbr_io_errmsg(); jbe@96: close(handle->fd); jbe@96: handle->fd = -1; jbe@96: handle->closed = 1; jbe@95: luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg); jbe@87: } jbe@87: } jbe@87: jbe@95: static void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) { jbe@96: #if defined(TCP_NOPUSH) || defined(TCP_CORK) jbe@95: if (!handle->isnetwork || handle->nopush == nopush) return; jbe@96: #if defined(TCP_NOPUSH) jbe@96: if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) { jbe@96: moonbr_io_errmsg(); jbe@96: close(handle->fd); jbe@96: handle->fd = -1; jbe@96: handle->closed = 1; jbe@96: luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg); jbe@96: } jbe@96: #elif defined(TCP_CORK) jbe@95: if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) { jbe@95: moonbr_io_errmsg(); jbe@96: close(handle->fd); jbe@96: handle->fd = -1; jbe@96: handle->closed = 1; jbe@95: luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg); jbe@95: } jbe@95: #endif jbe@95: handle->nopush = nopush; jbe@96: #else jbe@96: #warning Neither TCP_NOPUSH nor TCP_CORK is available jbe@96: #endif jbe@95: } jbe@95: jbe@86: static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) { jbe@85: moonbr_io_handle_t *handle; jbe@85: lua_Integer maxread; jbe@85: const char *terminatorstr; jbe@85: size_t terminatorlen; jbe@85: char terminator; jbe@85: luaL_Buffer luabuf; jbe@85: size_t luabufcnt = 0; jbe@86: int endcnt; jbe@85: char *terminatorpos; jbe@85: ssize_t result; jbe@85: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@85: maxread = luaL_optinteger(L, 2, 0); jbe@85: terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen); jbe@85: if (terminatorlen) { jbe@85: luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected"); jbe@85: terminator = terminatorstr[0]; jbe@85: } jbe@86: lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */ jbe@94: if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle"); jbe@94: if (handle->fd < 0) goto moonbr_io_read_impl_eof; /* fake EOF to simulate shutdown */ jbe@85: if (handle->readerr) { jbe@85: lua_pushnil(L); jbe@85: lua_pushliteral(L, "Previous read error"); jbe@85: return 2; jbe@85: } jbe@85: moonbr_io_handle_set_nonblocking(L, handle, nonblocking); jbe@86: if (!drain) luaL_buffinit(L, &luabuf); jbe@85: while (1) { jbe@86: endcnt = -1; jbe@85: if (maxread > 0 && handle->readbufcnt >= maxread - luabufcnt) { jbe@86: endcnt = maxread - luabufcnt; jbe@85: } else if (terminatorlen) { jbe@85: terminatorpos = memchr(handle->readbuf, terminator, handle->readbufcnt); jbe@86: if (terminatorpos) endcnt = 1 + (terminatorpos - handle->readbuf); jbe@85: } jbe@86: if (endcnt >= 0) { jbe@86: if (!drain) { jbe@86: luaL_addlstring(&luabuf, handle->readbuf, endcnt); jbe@86: luaL_pushresult(&luabuf); jbe@90: } else { jbe@90: luabufcnt += handle->readbufcnt; jbe@90: lua_pushinteger(L, luabufcnt); jbe@86: } jbe@86: handle->readbufcnt -= endcnt; jbe@86: memmove(handle->readbuf, handle->readbuf + endcnt, handle->readbufcnt); jbe@85: return 1; jbe@85: } jbe@86: if (!drain) luaL_addlstring(&luabuf, handle->readbuf, handle->readbufcnt); jbe@85: luabufcnt += handle->readbufcnt; jbe@85: handle->readbufcnt = 0; jbe@85: do { jbe@85: result = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN); jbe@85: } while (result < 0 && (errno == EINTR)); jbe@85: if (result == 0 || (nonblocking && result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))) break; jbe@85: if (result < 0) { jbe@85: moonbr_io_errmsg(); jbe@85: handle->readerr = 1; jbe@85: lua_pushnil(L); jbe@85: lua_pushstring(L, errmsg); jbe@85: return 2; jbe@85: } jbe@85: handle->readbufcnt += result; jbe@85: } jbe@86: if (!drain) { jbe@86: luaL_addlstring(&luabuf, handle->readbuf, handle->readbufcnt); jbe@86: luaL_pushresult(&luabuf); jbe@86: } jbe@90: luabufcnt += handle->readbufcnt; jbe@85: handle->readbufcnt = 0; jbe@90: if (!drain) { jbe@90: if (!luabufcnt && result == 0) { jbe@94: moonbr_io_read_impl_eof: jbe@90: lua_pushboolean(L, 0); jbe@90: lua_pushliteral(L, "End of file"); jbe@90: return 2; jbe@90: } jbe@90: } else { jbe@90: if (!luabufcnt && result == 0) lua_pushboolean(L, 1); jbe@90: else lua_pushboolean(L, luabufcnt); jbe@90: } jbe@85: return 1; jbe@85: } jbe@85: jbe@85: static int moonbr_io_read(lua_State *L) { jbe@86: return moonbr_io_read_impl(L, 0, 0); jbe@85: } jbe@85: jbe@85: static int moonbr_io_read_nb(lua_State *L) { jbe@86: return moonbr_io_read_impl(L, 1, 0); jbe@86: } jbe@86: jbe@86: static int moonbr_io_drain(lua_State *L) { jbe@86: return moonbr_io_read_impl(L, 0, 1); jbe@86: } jbe@86: jbe@86: static int moonbr_io_drain_nb(lua_State *L) { jbe@86: return moonbr_io_read_impl(L, 1, 1); jbe@85: } jbe@85: jbe@81: static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) { jbe@80: moonbr_io_handle_t *handle; jbe@80: int i, top; jbe@80: const char *str; jbe@92: size_t strlen; jbe@80: size_t written; jbe@80: ssize_t result; jbe@80: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@94: if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle"); jbe@94: if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle"); jbe@81: if (handle->writeerr) { jbe@80: lua_pushnil(L); jbe@80: lua_pushliteral(L, "Previous write error"); jbe@80: return 2; jbe@80: } jbe@81: moonbr_io_handle_set_nonblocking(L, handle, nonblocking); jbe@84: top = lua_gettop(L); jbe@81: lua_getuservalue(L, 1); jbe@81: lua_getfield(L, -1, "writebuf"); jbe@84: for (i=2; i<=top; i++) { jbe@84: luaL_checklstring(L, i, &strlen); jbe@84: lua_pushvalue(L, i); jbe@84: lua_rawseti(L, -2, handle->writeqin++); jbe@84: handle->writeleft += strlen; jbe@81: } jbe@83: while (handle->writeqout != handle->writeqin) { jbe@83: lua_rawgeti(L, -1, handle->writeqout); jbe@81: str = lua_tolstring(L, -1, &strlen); jbe@92: while (handle->writeqoff < strlen) { jbe@96: if (strlen - handle->writeqoff <= MOONBR_IO_WRITEBUFLEN - handle->writebufcnt) { jbe@92: memcpy(handle->writebuf + handle->writebufcnt, str + handle->writeqoff, strlen - handle->writeqoff); jbe@92: handle->writebufcnt += strlen - handle->writeqoff; jbe@80: break; jbe@80: } else { jbe@97: moonbr_io_handle_set_nopush(L, handle, 1); jbe@80: written = 0; jbe@92: memcpy(handle->writebuf + handle->writebufcnt, str + handle->writeqoff, MOONBR_IO_WRITEBUFLEN - handle->writebufcnt); jbe@92: handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufcnt; jbe@80: while (written < MOONBR_IO_WRITEBUFLEN) { jbe@80: result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written); jbe@80: if (result < 0) { jbe@81: if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { jbe@81: if (written) { jbe@81: handle->writebufcnt -= written; jbe@81: memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt); jbe@92: goto moonbr_io_write_impl_continue; jbe@81: } jbe@81: goto moonbr_io_write_impl_block; jbe@81: } else if (errno != EINTR) { jbe@80: moonbr_io_errmsg(); jbe@81: handle->writeerr = 1; jbe@80: lua_pushnil(L); jbe@80: lua_pushstring(L, errmsg); jbe@80: return 2; jbe@80: } jbe@80: } jbe@92: written += result; jbe@92: handle->writeleft -= result; jbe@80: } jbe@81: handle->writebufcnt = 0; jbe@80: } jbe@92: moonbr_io_write_impl_continue:; jbe@80: } jbe@81: handle->writeqoff = 0; jbe@81: lua_pop(L, 1); jbe@81: lua_pushnil(L); jbe@83: lua_rawseti(L, -2, handle->writeqout++); jbe@80: } jbe@81: if (flush) { jbe@97: moonbr_io_handle_set_nopush(L, handle, 0); jbe@81: written = 0; jbe@81: while (written < handle->writebufcnt) { jbe@81: result = write(handle->fd, handle->writebuf + written, handle->writebufcnt - written); jbe@81: if (result < 0) { jbe@81: if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { jbe@81: if (written) { jbe@81: handle->writebufcnt -= written; jbe@81: memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt); jbe@81: } jbe@81: goto moonbr_io_write_impl_block; jbe@81: } else if (errno != EINTR) { jbe@81: moonbr_io_errmsg(); jbe@81: handle->writeerr = -1; jbe@81: lua_pushnil(L); jbe@81: lua_pushstring(L, errmsg); jbe@81: return 2; jbe@81: } jbe@81: } else { jbe@81: written += result; jbe@81: handle->writeleft -= result; jbe@81: } jbe@81: } jbe@81: handle->writebufcnt = 0; jbe@82: if (nonblocking) lua_pushinteger(L, 0); jbe@81: } else { jbe@91: if (nonblocking) lua_pushinteger(L, handle->writeleft); jbe@81: } jbe@82: if (!nonblocking) lua_pushvalue(L, 1); jbe@80: return 1; jbe@81: moonbr_io_write_impl_block: jbe@91: lua_pushinteger(L, handle->writeleft); jbe@81: return 1; jbe@81: } jbe@81: jbe@81: static int moonbr_io_write(lua_State *L) { jbe@81: return moonbr_io_write_impl(L, 0, 0); jbe@81: } jbe@81: jbe@81: static int moonbr_io_write_nb(lua_State *L) { jbe@81: return moonbr_io_write_impl(L, 1, 0); jbe@80: } jbe@80: jbe@80: static int moonbr_io_flush(lua_State *L) { jbe@81: return moonbr_io_write_impl(L, 0, 1); jbe@81: } jbe@81: jbe@81: static int moonbr_io_flush_nb(lua_State *L) { jbe@81: return moonbr_io_write_impl(L, 1, 1); jbe@80: } jbe@80: jbe@88: static int moonbr_io_finish(lua_State *L) { jbe@88: moonbr_io_handle_t *handle; jbe@88: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@94: if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle"); jbe@94: if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle"); jbe@94: if (handle->writeleft) { jbe@94: lua_pushcfunction(L, moonbr_io_flush); jbe@94: lua_pushvalue(L, 1); jbe@94: lua_call(L, 1, 2); jbe@94: if (!lua_toboolean(L, -2)) { jbe@94: handle->finished = 1; jbe@94: return 2; jbe@88: } jbe@94: } jbe@94: handle->finished = 1; jbe@95: if (handle->isnetwork) { jbe@88: if (shutdown(handle->fd, SHUT_WR)) { jbe@88: moonbr_io_errmsg(); jbe@88: lua_pushnil(L); jbe@88: lua_pushstring(L, errmsg); jbe@88: return 2; jbe@88: } jbe@94: } else { jbe@94: if (close(handle->fd)) { jbe@94: moonbr_io_errmsg(); jbe@94: handle->fd = -1; jbe@94: lua_pushnil(L); jbe@94: lua_pushstring(L, errmsg); jbe@94: return 2; jbe@94: } jbe@94: handle->fd = -1; /* fake EOF on read */ jbe@88: } jbe@88: lua_pushboolean(L, 1); jbe@88: return 1; jbe@88: } jbe@88: jbe@94: static int moonbr_io_close_impl(lua_State *L, int reset) { jbe@83: moonbr_io_handle_t *handle; jbe@83: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@94: if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle"); jbe@94: if (!reset) { jbe@87: if (handle->writeleft) { jbe@87: lua_pushcfunction(L, moonbr_io_flush); jbe@87: lua_pushvalue(L, 1); jbe@87: lua_call(L, 1, 2); jbe@87: if (!lua_toboolean(L, -2)) { jbe@87: close(handle->fd); jbe@87: handle->fd = -1; jbe@87: return 2; jbe@87: } jbe@83: } jbe@94: moonbr_io_handle_set_linger(L, handle, -1); jbe@83: } jbe@94: if (handle->fd >= 0) { jbe@94: if (close(handle->fd)) { jbe@94: moonbr_io_errmsg(); jbe@94: handle->fd = -1; jbe@94: lua_pushnil(L); jbe@94: lua_pushstring(L, errmsg); jbe@94: return 2; jbe@94: } jbe@83: } jbe@83: handle->fd = -1; jbe@83: lua_pushboolean(L, 1); jbe@83: return 1; jbe@84: jbe@83: } jbe@83: jbe@94: static int moonbr_io_close(lua_State *L) { jbe@94: return moonbr_io_close_impl(L, 0); jbe@94: } jbe@94: jbe@84: static int moonbr_io_reset(lua_State *L) { jbe@94: return moonbr_io_close_impl(L, 1); jbe@84: } jbe@84: jbe@88: static int moonbr_io_gc(lua_State *L) { jbe@88: moonbr_io_handle_t *handle; jbe@88: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@88: if (handle->fd >= 0) { jbe@88: lua_pushcfunction(L, moonbr_io_close); jbe@88: lua_pushvalue(L, 1); jbe@88: lua_pushinteger(L, 0); jbe@88: lua_call(L, 2, 0); jbe@88: } jbe@88: return 0; jbe@88: } jbe@88: jbe@100: void moonbr_io_closehandle(lua_State *L, int idx, int reset) { jbe@88: moonbr_io_handle_t *handle; jbe@88: handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY); jbe@100: if (!handle->closed) { jbe@100: lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close); jbe@100: lua_pushvalue(L, idx < 0 ? idx-1 : idx); jbe@100: lua_call(L, 1, 0); jbe@88: } jbe@88: } jbe@88: jbe@95: void moonbr_io_pushhandle(lua_State *L, int fd, int isnetwork) { jbe@79: moonbr_io_handle_t *handle; jbe@79: handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t)); jbe@79: handle->fd = fd; jbe@95: handle->isnetwork = isnetwork; jbe@94: handle->finished = 0; jbe@94: handle->closed = 0; jbe@81: handle->nonblocking = -1; jbe@95: handle->nopush = -1; jbe@85: handle->readerr = 0; jbe@85: handle->readbufcnt = 0; jbe@81: handle->writeerr = 0; jbe@81: handle->writeleft = 0; jbe@83: handle->writeqin = 0; jbe@83: handle->writeqout = 0; jbe@81: handle->writeqoff = 0; jbe@81: handle->writebufcnt = 0; jbe@87: moonbr_io_handle_set_linger(L, handle, 0); jbe@79: luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: lua_setmetatable(L, -2); jbe@79: lua_newtable(L); // uservalue jbe@81: lua_newtable(L); jbe@81: lua_setfield(L, -2, "writebuf"); jbe@79: lua_newtable(L); // public jbe@79: luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); jbe@79: lua_setmetatable(L, -2); jbe@79: lua_setfield(L, -2, "public"); jbe@79: lua_setuservalue(L, -2); jbe@79: } jbe@79: jbe@79: static int moonbr_io_handleindex(lua_State *L) { jbe@80: luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: lua_getuservalue(L, 1); jbe@79: lua_getfield(L, -1, "public"); jbe@79: lua_pushvalue(L, 2); jbe@79: lua_gettable(L, -2); jbe@79: return 1; jbe@79: } jbe@79: jbe@79: static int moonbr_io_handlenewindex(lua_State *L) { jbe@80: luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: lua_getuservalue(L, 1); jbe@79: lua_getfield(L, -1, "public"); jbe@79: lua_pushvalue(L, 2); jbe@79: lua_pushvalue(L, 3); jbe@79: lua_settable(L, -3); jbe@79: return 0; jbe@79: } jbe@79: jbe@99: static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) { jbe@98: const char *host, *port; jbe@98: struct addrinfo hints = { 0, }; jbe@98: struct addrinfo *res, *addrinfo; jbe@98: int errcode; jbe@98: int sock; jbe@98: host = luaL_checkstring(L, 1); jbe@98: port = luaL_checkstring(L, 2); jbe@98: hints.ai_family = AF_UNSPEC; jbe@98: hints.ai_socktype = SOCK_STREAM; jbe@98: hints.ai_protocol = IPPROTO_TCP; jbe@98: hints.ai_flags = AI_ADDRCONFIG; jbe@98: errcode = getaddrinfo(host, port, &hints, &res); jbe@98: if (errcode) { jbe@102: freeaddrinfo(res); jbe@98: if (errcode == EAI_SYSTEM) { jbe@98: moonbr_io_errmsg(); jbe@98: lua_pushnil(L); jbe@98: lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg); jbe@98: } else { jbe@98: lua_pushnil(L); jbe@98: lua_pushstring(L, gai_strerror(errcode)); jbe@98: } jbe@98: return 2; jbe@98: } jbe@98: for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { jbe@98: if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found; jbe@98: } jbe@98: for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { jbe@98: if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found; jbe@98: } jbe@98: addrinfo = res; jbe@98: moonbr_io_tcpconnect_found: jbe@99: sock = socket( jbe@99: addrinfo->ai_family, jbe@99: addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0), jbe@99: addrinfo->ai_protocol jbe@99: ); jbe@102: freeaddrinfo(res); jbe@98: if (sock < 0) { jbe@98: moonbr_io_errmsg(); jbe@98: lua_pushnil(L); jbe@98: lua_pushstring(L, errmsg); jbe@98: } jbe@98: if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) { jbe@99: if (!nonblocking && errno == EINTR) { jbe@99: moonbr_io_errmsg(); jbe@99: close(sock); jbe@99: lua_pushnil(L); jbe@99: lua_pushstring(L, errmsg); jbe@99: return 2; jbe@99: } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) { jbe@99: moonbr_io_errmsg(); jbe@99: lua_pushnil(L); jbe@99: lua_pushstring(L, errmsg); jbe@99: return 2; jbe@99: } jbe@98: } jbe@98: moonbr_io_pushhandle(L, sock, 1); jbe@98: return 1; jbe@98: } jbe@98: jbe@99: static int moonbr_io_tcpconnect(lua_State *L) { jbe@99: return moonbr_io_tcpconnect_impl(L, 0); jbe@99: } jbe@99: jbe@99: static int moonbr_io_tcpconnect_nb(lua_State *L) { jbe@99: return moonbr_io_tcpconnect_impl(L, 1); jbe@99: } jbe@99: jbe@79: static const struct luaL_Reg moonbr_io_handle_methods[] = { jbe@85: {"read", moonbr_io_read}, jbe@85: {"read_nb", moonbr_io_read_nb}, jbe@86: {"drain", moonbr_io_drain}, jbe@86: {"drain_nb", moonbr_io_drain_nb}, jbe@80: {"write", moonbr_io_write}, jbe@81: {"write_nb", moonbr_io_write_nb}, jbe@80: {"flush", moonbr_io_flush}, jbe@81: {"flush_nb", moonbr_io_flush_nb}, jbe@88: {"finish", moonbr_io_finish}, jbe@87: {"close", moonbr_io_close}, jbe@85: {"reset", moonbr_io_reset}, jbe@79: {NULL, NULL} jbe@79: }; jbe@79: jbe@79: static const struct luaL_Reg moonbr_io_handle_metamethods[] = { jbe@79: {"__index", moonbr_io_handleindex}, jbe@79: {"__newindex", moonbr_io_handlenewindex}, jbe@88: {"__gc", moonbr_io_gc}, jbe@79: {NULL, NULL} jbe@79: }; jbe@79: jbe@79: static const struct luaL_Reg moonbr_io_module_funcs[] = { jbe@98: {"tcpconnect", moonbr_io_tcpconnect}, jbe@99: {"tcpconnect_nb", moonbr_io_tcpconnect_nb}, jbe@79: {NULL, NULL} jbe@79: }; jbe@79: jbe@79: int luaopen_moonbridge_io(lua_State *L) { jbe@79: jbe@80: lua_newtable(L); // module jbe@80: jbe@79: lua_newtable(L); // public metatable jbe@79: lua_newtable(L); // handle methods jbe@79: luaL_setfuncs(L, moonbr_io_handle_methods, 0); jbe@80: lua_pushvalue(L, -1); jbe@80: lua_setfield(L, -4, "handle"); jbe@79: lua_setfield(L, -2, "__index"); jbe@79: lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); jbe@79: jbe@79: lua_newtable(L); // handle metatable jbe@79: luaL_setfuncs(L, moonbr_io_handle_metamethods, 0); jbe@79: lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: jbe@79: luaL_setfuncs(L, moonbr_io_module_funcs, 0); jbe@79: return 1; jbe@79: jbe@79: } jbe@79: