moonbridge

changeset 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
files moonbridge_io.c
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  

Impressum / About Us