moonbridge

changeset 88:fca51922b708

Extended I/O library; Integrated new I/O library into moonbridge.c and moonbridge_http.lua
author jbe
date Tue Apr 07 02:15:17 2015 +0200 (2015-04-07)
parents 1d91c6eedf18
children c4fd976d9537
files moonbridge.c moonbridge_http.lua moonbridge_io.c moonbridge_io.h
line diff
     1.1 --- a/moonbridge.c	Tue Apr 07 01:17:55 2015 +0200
     1.2 +++ b/moonbridge.c	Tue Apr 07 02:15:17 2015 +0200
     1.3 @@ -277,12 +277,6 @@
     1.4  /* Variable set to nonzero value to disallow further calls of 'listen' function */
     1.5  static int moonbr_booted = 0;
     1.6  
     1.7 -/* Global variables to store information on connection socket in child process */
     1.8 -static int moonbr_child_peersocket_type;                   /* type of socket by MOONBR_SOCKETTYPE constant */
     1.9 -static int moonbr_child_peersocket_fd;                     /* Original file descriptor of peer socket */
    1.10 -static luaL_Stream *moonbr_child_peersocket_inputstream;   /* Lua input stream of socket */
    1.11 -static luaL_Stream *moonbr_child_peersocket_outputstream;  /* Lua output stream of socket */
    1.12 -
    1.13  /* Verbosity settings */
    1.14  static int moonbr_debug = 0;
    1.15  static int moonbr_stat = 0;
    1.16 @@ -817,249 +811,10 @@
    1.17    }
    1.18  }
    1.19  
    1.20 -/* Closes the input stream from peer unless it has already been closed */
    1.21 -static int moonbr_child_close_peersocket_inputstream(
    1.22 -  int cleanshut,  /* nonzero = use shutdown() if applicable */
    1.23 -  int mark        /* nonzero = mark the stream as closed for Lua */
    1.24 -) {
    1.25 -  int err = 0;  /* nonzero = error occurred */
    1.26 -  int errno2;   /* stores previous errno values that take precedence */
    1.27 -  if (moonbr_child_peersocket_inputstream->f) {
    1.28 -    /* NOTE: shutdown() with SHUT_RD shows different behavior on different
    1.29 -     * operating systems and particularly causes problems with Linux. Hence it
    1.30 -     * is disabled here. */
    1.31 -    /*
    1.32 -    if (cleanshut && moonbr_child_peersocket_type == MOONBR_SOCKETTYPE_NETWORK) {
    1.33 -      if (shutdown(moonbr_child_peersocket_fd, SHUT_RD)) {
    1.34 -        errno2 = errno;
    1.35 -        err = -1;
    1.36 -      }
    1.37 -    }
    1.38 -    */
    1.39 -    if (fclose(moonbr_child_peersocket_inputstream->f)) {
    1.40 -      if (!err) errno2 = errno;
    1.41 -      err = -1;
    1.42 -    }
    1.43 -    moonbr_child_peersocket_inputstream->f = NULL;
    1.44 -  }
    1.45 -  if (mark) moonbr_child_peersocket_inputstream->closef = NULL;
    1.46 -  if (err) errno = errno2;
    1.47 -  return err;
    1.48 -}
    1.49 -
    1.50 -/* Closes the output stream to peer unless it has already been closed */
    1.51 -static int moonbr_child_close_peersocket_outputstream(
    1.52 -  int cleanshut,  /* nonzero = use fflush() and shutdown() if applicable */
    1.53 -  int mark        /* nonzero = mark the stream as closed for Lua */
    1.54 -) {
    1.55 -  int err = 0;  /* nonzero = error occurred */
    1.56 -  int errno2;   /* stores previous errno values that take precedence */
    1.57 -  if (moonbr_child_peersocket_outputstream->f) {
    1.58 -    if (moonbr_child_peersocket_type == MOONBR_SOCKETTYPE_NETWORK) {
    1.59 -      if (cleanshut) {
    1.60 -        if (fflush(moonbr_child_peersocket_outputstream->f)) {
    1.61 -          errno2 = errno;
    1.62 -          err = -1;
    1.63 -        } else {
    1.64 -          if (shutdown(moonbr_child_peersocket_fd, SHUT_WR)) {
    1.65 -            errno2 = errno;
    1.66 -            err = -1;
    1.67 -          }
    1.68 -        }
    1.69 -      } else {
    1.70 -        fpurge(moonbr_child_peersocket_outputstream->f);
    1.71 -      }
    1.72 -    }
    1.73 -    if (fclose(moonbr_child_peersocket_outputstream->f)) {
    1.74 -      if (!err) errno2 = errno;
    1.75 -      err = -1;
    1.76 -    }
    1.77 -    moonbr_child_peersocket_outputstream->f = NULL;
    1.78 -  }
    1.79 -  if (mark) moonbr_child_peersocket_outputstream->closef = NULL;
    1.80 -  if (err) errno = errno2;
    1.81 -  return err;
    1.82 -}
    1.83 -
    1.84 -/* Perform a clean shutdown of input and output stream (may be called multiple times) */
    1.85 -static int moonbr_child_close_peersocket(int timeout) {
    1.86 -  int errprio = 0;
    1.87 -  int errno2;
    1.88 -  if (moonbr_child_peersocket_fd == -1) return 0;
    1.89 -  if (moonbr_child_close_peersocket_inputstream(1, 1)) {
    1.90 -    errprio = 1;
    1.91 -    errno2 = errno;
    1.92 -  }
    1.93 -  if (moonbr_child_close_peersocket_outputstream(1, 1)) {
    1.94 -    errprio = 4;
    1.95 -    errno2 = errno;
    1.96 -  }
    1.97 -  if (moonbr_child_peersocket_type == MOONBR_SOCKETTYPE_NETWORK) {
    1.98 -    struct linger lingerval = { 0, };
    1.99 -    if (timeout && !errprio) {
   1.100 -      lingerval.l_onoff = 1;
   1.101 -      lingerval.l_linger = timeout;
   1.102 -    }
   1.103 -    if (setsockopt(moonbr_child_peersocket_fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
   1.104 -      if (errprio < 2) {
   1.105 -        errprio = 2;
   1.106 -        errno2 = errno;
   1.107 -      }
   1.108 -    }
   1.109 -  }
   1.110 -  if (close(moonbr_child_peersocket_fd)) {
   1.111 -    if (errprio < 3) {
   1.112 -      errprio = 3;
   1.113 -      errno2 = errno;
   1.114 -    }
   1.115 -  }
   1.116 -  moonbr_child_peersocket_fd = -1;
   1.117 -  if (errprio) {
   1.118 -    errno = errno2;
   1.119 -    return -1;
   1.120 -  }
   1.121 -  return 0;
   1.122 -}
   1.123 -
   1.124 -/* Close socket and cause reset of TCP connection (TCP RST aka "Connection reset by peer") if possible */
   1.125 -static int moonbr_child_cancel_peersocket() {
   1.126 -  int err = 0;
   1.127 -  if (moonbr_child_close_peersocket_inputstream(0, 1)) err = -1;
   1.128 -  if (moonbr_child_close_peersocket_outputstream(0, 1)) err = -1;
   1.129 -  if (close(moonbr_child_peersocket_fd)) err = -1;
   1.130 -  moonbr_child_peersocket_fd = -1;
   1.131 -  return err;
   1.132 -}
   1.133 -
   1.134 -/* Lua method for socket object to read from input stream */
   1.135 -static int moonbr_child_lua_read_stream(lua_State *L) {
   1.136 -  lua_getfield(L, 1, "input");
   1.137 -  lua_getfield(L, -1, "read");
   1.138 -  lua_insert(L, 1);
   1.139 -  lua_replace(L, 2);
   1.140 -  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
   1.141 -  return lua_gettop(L);
   1.142 -}
   1.143 -
   1.144 -/* Lua method for socket object to read from input stream until terminator */
   1.145 -static int moonbr_child_lua_readuntil_stream(lua_State *L) {
   1.146 -  lua_getfield(L, 1, "input");
   1.147 -  lua_getfield(L, -1, "readuntil");
   1.148 -  lua_insert(L, 1);
   1.149 -  lua_replace(L, 2);
   1.150 -  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
   1.151 -  return lua_gettop(L);
   1.152 -}
   1.153 -
   1.154 -/* Lua method for socket object to iterate over input stream */
   1.155 -static int moonbr_child_lua_lines_stream(lua_State *L) {
   1.156 -  lua_getfield(L, 1, "input");
   1.157 -  lua_getfield(L, -1, "lines");
   1.158 -  lua_insert(L, 1);
   1.159 -  lua_replace(L, 2);
   1.160 -  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
   1.161 -  return lua_gettop(L);
   1.162 -}
   1.163 -
   1.164 -/* Lua method for socket object to write to output stream */
   1.165 -static int moonbr_child_lua_write_stream(lua_State *L) {
   1.166 -  lua_getfield(L, 1, "output");
   1.167 -  lua_getfield(L, -1, "write");
   1.168 -  lua_insert(L, 1);
   1.169 -  lua_replace(L, 2);
   1.170 -  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
   1.171 -  return lua_gettop(L);
   1.172 -}
   1.173 -
   1.174 -/* Lua method for socket object to flush the output stream */
   1.175 -static int moonbr_child_lua_flush_stream(lua_State *L) {
   1.176 -  lua_getfield(L, 1, "output");
   1.177 -  lua_getfield(L, -1, "flush");
   1.178 -  lua_insert(L, 1);
   1.179 -  lua_replace(L, 2);
   1.180 -  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
   1.181 -  return lua_gettop(L);
   1.182 -}
   1.183 -
   1.184 -/* Lua function to close a single stream (input or output) from/to peer */
   1.185 -static int moonbr_child_lua_close_stream(lua_State *L) {
   1.186 -  luaL_Stream *stream = lua_touserdata(L, 1);
   1.187 -  if (stream == moonbr_child_peersocket_inputstream) {
   1.188 -    if (moonbr_child_close_peersocket_inputstream(1, 0)) {  /* don't mark as closed as it's done by Lua */
   1.189 -      char errmsg[MOONBR_MAXSTRERRORLEN];
   1.190 -      strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.191 -      lua_pushnil(L);
   1.192 -      lua_pushfstring(L, "Could not close input stream from peer: %s", errmsg);
   1.193 -      return 2;
   1.194 -    }
   1.195 -  } else if (stream == moonbr_child_peersocket_outputstream) {
   1.196 -    if (moonbr_child_close_peersocket_outputstream(1, 0)) {  /* don't mark as closed as it's done by Lua */
   1.197 -      char errmsg[MOONBR_MAXSTRERRORLEN];
   1.198 -      strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.199 -      lua_pushnil(L);
   1.200 -      lua_pushfstring(L, "Could not close output stream to peer: %s", errmsg);
   1.201 -      return 2;
   1.202 -    }
   1.203 -  } else {
   1.204 -    luaL_argerror(L, 1, "Not a connection socket");
   1.205 -  }
   1.206 -  lua_pushboolean(L, 1);
   1.207 -  return 1;
   1.208 -}
   1.209 -
   1.210 -/* Lua function to close both input and output stream from/to peer */
   1.211 -static int moonbr_child_lua_close_both_streams(lua_State *L) {
   1.212 -  int timeout = 0;
   1.213 -  if (!lua_isnoneornil(L, 2)) {
   1.214 -    lua_Integer n = luaL_checkinteger(L, 2);
   1.215 -    luaL_argcheck(L, n >= 0 && n <= INT_MAX, 2, "out of range");
   1.216 -    timeout = n;
   1.217 -  }
   1.218 -  if (moonbr_child_peersocket_fd == -1) {
   1.219 -    luaL_error(L, "Connection with peer has already been explicitly closed");
   1.220 -  }
   1.221 -  if (moonbr_child_close_peersocket(timeout)) {
   1.222 -    char errmsg[MOONBR_MAXSTRERRORLEN];
   1.223 -    strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.224 -    lua_pushnil(L);
   1.225 -    lua_pushfstring(L, "Could not close socket connection with peer: %s", errmsg);
   1.226 -    return 2;
   1.227 -  }
   1.228 -  lua_pushboolean(L, 1);
   1.229 -  return 1;
   1.230 -}
   1.231 -
   1.232 -/* Lua function to close both input and output stream from/to peer */
   1.233 -static int moonbr_child_lua_cancel_both_streams(lua_State *L) {
   1.234 -  if (moonbr_child_peersocket_fd == -1) {
   1.235 -    luaL_error(L, "Connection with peer has already been explicitly closed");
   1.236 -  }
   1.237 -  if (moonbr_child_cancel_peersocket()) {
   1.238 -    char errmsg[MOONBR_MAXSTRERRORLEN];
   1.239 -    strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.240 -    lua_pushnil(L);
   1.241 -    lua_pushfstring(L, "Could not cancel socket connection with peer: %s", errmsg);
   1.242 -    return 2;
   1.243 -  }
   1.244 -  lua_pushboolean(L, 1);
   1.245 -  return 1;
   1.246 -}
   1.247 -
   1.248 -/* Methods of (bidirectional) socket object passed to handler */
   1.249 -static luaL_Reg moonbr_child_lua_socket_functions[] = {
   1.250 -  {"read", moonbr_child_lua_read_stream},
   1.251 -  {"readuntil", moonbr_child_lua_readuntil_stream},
   1.252 -  {"lines", moonbr_child_lua_lines_stream},
   1.253 -  {"write", moonbr_child_lua_write_stream},
   1.254 -  {"flush", moonbr_child_lua_flush_stream},
   1.255 -  {"close", moonbr_child_lua_close_both_streams},
   1.256 -  {"cancel", moonbr_child_lua_cancel_both_streams},
   1.257 -  {NULL, NULL}
   1.258 -};
   1.259 -
   1.260  /* Main function of child process to be called after fork() and file descriptor rearrangement */
   1.261  void moonbr_child_run(struct moonbr_pool *pool, lua_State *L) {
   1.262    char controlmsg;
   1.263 +  int fd;
   1.264    struct itimerval notimer = { { 0, }, { 0, } };
   1.265    lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
   1.266    if (lua_isnil(L, -1)) lua_pop(L, 1);
   1.267 @@ -1076,66 +831,20 @@
   1.268      if (write(MOONBR_FD_CONTROL, &controlmsg, 1) <= 0) {
   1.269        moonbr_child_log_errno_fatal("Error while sending ready message to parent process");
   1.270      }
   1.271 -    moonbr_child_receive_control_message(
   1.272 -      MOONBR_FD_CONTROL,
   1.273 -      &controlmsg,
   1.274 -      &moonbr_child_peersocket_fd
   1.275 -    );
   1.276 +    moonbr_child_receive_control_message(MOONBR_FD_CONTROL, &controlmsg, &fd);
   1.277      if (!(
   1.278 -      (controlmsg == MOONBR_COMMAND_TERMINATE   && moonbr_child_peersocket_fd == -1) ||
   1.279 -      (controlmsg == MOONBR_SOCKETTYPE_INTERVAL && moonbr_child_peersocket_fd == -1) ||
   1.280 -      (controlmsg == MOONBR_SOCKETTYPE_LOCAL    && moonbr_child_peersocket_fd != -1) ||
   1.281 -      (controlmsg == MOONBR_SOCKETTYPE_NETWORK  && moonbr_child_peersocket_fd != -1)
   1.282 +      (controlmsg == MOONBR_COMMAND_TERMINATE   && fd == -1) ||
   1.283 +      (controlmsg == MOONBR_SOCKETTYPE_INTERVAL && fd == -1) ||
   1.284 +      (controlmsg == MOONBR_SOCKETTYPE_LOCAL    && fd != -1) ||
   1.285 +      (controlmsg == MOONBR_SOCKETTYPE_NETWORK  && fd != -1)
   1.286      )) {
   1.287        moonbr_child_log_fatal("Received illegal control message from parent process");
   1.288      }
   1.289      if (controlmsg == MOONBR_COMMAND_TERMINATE) break;
   1.290      listener = moonbr_child_receive_pointer(MOONBR_FD_CONTROL);
   1.291 -    moonbr_child_peersocket_type = controlmsg;
   1.292 -    if (moonbr_child_peersocket_fd != -1) {
   1.293 -      {
   1.294 -        int clonedfd;
   1.295 -        clonedfd = dup(moonbr_child_peersocket_fd);
   1.296 -        if (!clonedfd) {
   1.297 -          moonbr_child_log_errno_fatal("Could not duplicate file descriptor for input stream");
   1.298 -        }
   1.299 -        moonbr_child_peersocket_inputstream = lua_newuserdata(L, sizeof(luaL_Stream));
   1.300 -        if (!moonbr_child_peersocket_inputstream) {
   1.301 -          moonbr_child_log_fatal("Memory allocation error");
   1.302 -        }
   1.303 -        moonbr_child_peersocket_inputstream->f = fdopen(clonedfd, "rb");
   1.304 -        if (!moonbr_child_peersocket_inputstream->f) {
   1.305 -          moonbr_child_log_errno_fatal("Could not open input stream for remote connection");
   1.306 -        }
   1.307 -        moonbr_child_peersocket_inputstream->closef = moonbr_child_lua_close_stream;
   1.308 -        if (luaL_newmetatable(L, LUA_FILEHANDLE)) {
   1.309 -          moonbr_child_log_fatal("Lua metatable LUA_FILEHANDLE does not exist");
   1.310 -        }
   1.311 -        lua_setmetatable(L, -2);
   1.312 -      }
   1.313 -      {
   1.314 -        int clonedfd;
   1.315 -        clonedfd = dup(moonbr_child_peersocket_fd);
   1.316 -        if (!clonedfd) {
   1.317 -          moonbr_child_log_errno_fatal("Could not duplicate file descriptor for output stream");
   1.318 -        }
   1.319 -        moonbr_child_peersocket_outputstream = lua_newuserdata(L, sizeof(luaL_Stream));
   1.320 -        if (!moonbr_child_peersocket_outputstream) {
   1.321 -          moonbr_child_log_fatal("Memory allocation error");
   1.322 -        }
   1.323 -        moonbr_child_peersocket_outputstream->f = fdopen(clonedfd, "wb");
   1.324 -        if (!moonbr_child_peersocket_outputstream->f) {
   1.325 -          moonbr_child_log_errno_fatal("Could not open output stream for remote connection");
   1.326 -        }
   1.327 -        moonbr_child_peersocket_outputstream->closef = moonbr_child_lua_close_stream;
   1.328 -        if (luaL_newmetatable(L, LUA_FILEHANDLE)) {
   1.329 -          moonbr_child_log_fatal("Lua metatable LUA_FILEHANDLE does not exist");
   1.330 -        }
   1.331 -        lua_setmetatable(L, -2);
   1.332 -      }
   1.333 -    }
   1.334 +    if (fd) moonbr_io_pushhandle(L, fd, 1, controlmsg == MOONBR_SOCKETTYPE_NETWORK);
   1.335      lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool));
   1.336 -    if (listener->proto == MOONBR_PROTO_INTERVAL) {
   1.337 +    if (!fd) {
   1.338        lua_newtable(L);
   1.339        lua_pushstring(L,
   1.340          listener->proto_specific.interval.name ?
   1.341 @@ -1143,16 +852,11 @@
   1.342        );
   1.343        lua_setfield(L, -2, "interval");
   1.344      } else {
   1.345 -      lua_newtable(L);
   1.346 -      lua_pushvalue(L, -4);
   1.347 -      lua_setfield(L, -2, "input");
   1.348 -      lua_pushvalue(L, -3);
   1.349 -      lua_setfield(L, -2, "output");
   1.350 -      luaL_setfuncs(L, moonbr_child_lua_socket_functions, 0);
   1.351 +      lua_pushvalue(L, -2);
   1.352        if (listener->proto == MOONBR_PROTO_TCP6) {
   1.353          struct sockaddr_in6 addr;
   1.354          socklen_t addr_len = sizeof(struct sockaddr_in6);
   1.355 -        if (getsockname(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) {
   1.356 +        if (getsockname(fd, (struct sockaddr *)&addr, &addr_len)) {
   1.357            moonbr_child_log_errno("Could not get local IP address/port");
   1.358          } else {
   1.359            lua_pushlstring(L, (char *)addr.sin6_addr.s6_addr, 16);
   1.360 @@ -1160,7 +864,7 @@
   1.361            lua_pushinteger(L, ntohs(addr.sin6_port));
   1.362            lua_setfield(L, -2, "local_tcpport");
   1.363          }
   1.364 -        if (getpeername(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) {
   1.365 +        if (getpeername(fd, (struct sockaddr *)&addr, &addr_len)) {
   1.366            moonbr_child_log_errno("Could not get remote IP address/port");
   1.367          } else {
   1.368            lua_pushlstring(L, (char *)addr.sin6_addr.s6_addr, 16);
   1.369 @@ -1171,7 +875,7 @@
   1.370        } else if (listener->proto == MOONBR_PROTO_TCP4) {
   1.371          struct sockaddr_in addr;
   1.372          socklen_t addr_len = sizeof(struct sockaddr_in);
   1.373 -        if (getsockname(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) {
   1.374 +        if (getsockname(fd, (struct sockaddr *)&addr, &addr_len)) {
   1.375            moonbr_child_log_errno("Could not get local IP address/port");
   1.376          } else {
   1.377            lua_pushlstring(L, (char *)&addr.sin_addr.s_addr, 4);
   1.378 @@ -1179,7 +883,7 @@
   1.379            lua_pushinteger(L, ntohs(addr.sin_port));
   1.380            lua_setfield(L, -2, "local_tcpport");
   1.381          }
   1.382 -        if (getpeername(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) {
   1.383 +        if (getpeername(fd, (struct sockaddr *)&addr, &addr_len)) {
   1.384            moonbr_child_log_errno("Could not get remote IP address/port");
   1.385          } else {
   1.386            lua_pushlstring(L, (char *)&addr.sin_addr.s_addr, 4);
   1.387 @@ -1193,9 +897,7 @@
   1.388        fprintf(stderr, "Error in \"connect\" function: %s\n", lua_tostring(L, -1));
   1.389        exit(1);
   1.390      }
   1.391 -    if (moonbr_child_close_peersocket(0)) {
   1.392 -      moonbr_child_log_errno("Could not close socket connection with peer");
   1.393 -    }
   1.394 +    if (fd) moonbr_io_closehandle(L, -2, -1);  /* attemt clean close */
   1.395      if (lua_type(L, -1) != LUA_TBOOLEAN || !lua_toboolean(L, -1)) break;
   1.396  #ifdef MOONBR_LUA_PANIC_BUG_WORKAROUND
   1.397      lua_settop(L, 2);
     2.1 --- a/moonbridge_http.lua	Tue Apr 07 01:17:55 2015 +0200
     2.2 +++ b/moonbridge_http.lua	Tue Apr 07 02:15:17 2015 +0200
     2.3 @@ -238,7 +238,7 @@
     2.4          io.stderr:write(errmsg, "\n")
     2.5          if not socket_closed then
     2.6            socket_closed = true
     2.7 -          socket:cancel()
     2.8 +          socket:reset()
     2.9          end
    2.10          error("Could not send data to client: " .. errmsg)
    2.11        end
    2.12 @@ -270,7 +270,7 @@
    2.13          else
    2.14            if not socket_closed then
    2.15              socket_closed = true
    2.16 -            socket:cancel()
    2.17 +            socket:reset()
    2.18            end
    2.19          end
    2.20          if throw_error then
    2.21 @@ -309,10 +309,10 @@
    2.22        local function finish_response()
    2.23          if connection_close_responded then
    2.24            -- close output stream:
    2.25 -          assert_output(socket.output:close())
    2.26 +          assert_output(socket:finish())
    2.27            -- wait for EOF of peer to avoid immediate TCP RST condition:
    2.28            timeout(2, function()
    2.29 -            while socket.input:read(input_chunk_size) do end
    2.30 +            socket:drain()
    2.31            end)
    2.32            -- fully close socket:
    2.33            socket_closed = true  -- avoid double close on error
    2.34 @@ -832,7 +832,7 @@
    2.35            end
    2.36            if request.headers_flags["Transfer-Encoding"]["chunked"] then
    2.37              while true do
    2.38 -              local line = socket:readuntil("\n", 32 + remaining_body_size_limit)
    2.39 +              local line = socket:read(32 + remaining_body_size_limit, "\n")
    2.40                if not line then
    2.41                  request_error(true, "400 Bad Request", "Unexpected EOF while reading next chunk of request body")
    2.42                end
    2.43 @@ -853,13 +853,13 @@
    2.44                end
    2.45                if len == 0 then break end
    2.46                read_body_bytes(len, callback)
    2.47 -              local term = socket:readuntil("\n", 2)
    2.48 +              local term = socket:read(2, "\n")
    2.49                if term ~= "\r\n" and term ~= "\n" then
    2.50                  request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body")
    2.51                end
    2.52              end
    2.53              while true do
    2.54 -              local line = socket:readuntil("\n", 2 + remaining_body_size_limit)
    2.55 +              local line = socket:read(2 + remaining_body_size_limit, "\n")
    2.56                if line == "\r\n" or line == "\n" then break end
    2.57                remaining_body_size_limit = remaining_body_size_limit - #line
    2.58                if remaining_body_size_limit < 0 then
    2.59 @@ -894,7 +894,7 @@
    2.60          end
    2.61        })
    2.62        -- read and parse request line:
    2.63 -      local line = socket:readuntil("\n", remaining_header_size_limit)
    2.64 +      local line = socket:read(remaining_header_size_limit, "\n")
    2.65        if not line then return survive end
    2.66        remaining_header_size_limit = remaining_header_size_limit - #line
    2.67        if remaining_header_size_limit == 0 then
    2.68 @@ -910,7 +910,7 @@
    2.69        end
    2.70        -- read and parse headers:
    2.71        while true do
    2.72 -        local line = socket:readuntil("\n", remaining_header_size_limit);
    2.73 +        local line = socket:read(remaining_header_size_limit, "\n");
    2.74          remaining_header_size_limit = remaining_header_size_limit - #line
    2.75          if not line then
    2.76            return request_error(false, "400 Bad Request")
     3.1 --- a/moonbridge_io.c	Tue Apr 07 01:17:55 2015 +0200
     3.2 +++ b/moonbridge_io.c	Tue Apr 07 02:15:17 2015 +0200
     3.3 @@ -26,6 +26,8 @@
     3.4  typedef struct {
     3.5    int fd;
     3.6    int issocket;
     3.7 +  int canshutdown;
     3.8 +  int shutwr;
     3.9    int nonblocking;
    3.10    int readerr;
    3.11    int readbufcnt;
    3.12 @@ -167,6 +169,7 @@
    3.13    ssize_t result;
    3.14    handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
    3.15    if (handle->fd < 0) luaL_error(L, "Attempt to write to a closed I/O handle");
    3.16 +  if (handle->shutwr) luaL_error(L, "Attempt to write to a finished I/O handle");
    3.17    if (handle->writeerr) {
    3.18      lua_pushnil(L);
    3.19      lua_pushliteral(L, "Previous write error");
    3.20 @@ -277,6 +280,30 @@
    3.21    return moonbr_io_write_impl(L, 1, 1);
    3.22  }
    3.23  
    3.24 +static int moonbr_io_finish(lua_State *L) {
    3.25 +  moonbr_io_handle_t *handle;
    3.26 +  handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
    3.27 +  if (handle->fd < 0) luaL_error(L, "Attempt to finish a closed I/O handle");
    3.28 +  if (handle->shutwr) luaL_error(L, "Attempt to finish a finished I/O handle");
    3.29 +  handle->shutwr = 1;
    3.30 +  if (handle->canshutdown) {
    3.31 +    if (handle->writeleft) {
    3.32 +      lua_pushcfunction(L, moonbr_io_flush);
    3.33 +      lua_pushvalue(L, 1);
    3.34 +      lua_call(L, 1, 2);
    3.35 +      if (!lua_toboolean(L, -2)) return 2;
    3.36 +    }
    3.37 +    if (shutdown(handle->fd, SHUT_WR)) {
    3.38 +      moonbr_io_errmsg();
    3.39 +      lua_pushnil(L);
    3.40 +      lua_pushstring(L, errmsg);
    3.41 +      return 2;
    3.42 +    }
    3.43 +  }
    3.44 +  lua_pushboolean(L, 1);
    3.45 +  return 1;
    3.46 +}
    3.47 +
    3.48  static int moonbr_io_close(lua_State *L) {
    3.49    moonbr_io_handle_t *handle;
    3.50    int timeout;
    3.51 @@ -319,11 +346,36 @@
    3.52    return lua_gettop(L);
    3.53  }
    3.54  
    3.55 -void moonbr_io_pushhandle(lua_State *L, int fd, int issocket) {
    3.56 +static int moonbr_io_gc(lua_State *L) {
    3.57 +  moonbr_io_handle_t *handle;
    3.58 +  handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
    3.59 +  if (handle->fd >= 0) {
    3.60 +    lua_pushcfunction(L, moonbr_io_close);
    3.61 +    lua_pushvalue(L, 1);
    3.62 +    lua_pushinteger(L, 0);
    3.63 +    lua_call(L, 2, 0);
    3.64 +  }
    3.65 +  return 0;
    3.66 +}
    3.67 +
    3.68 +void moonbr_io_closehandle(lua_State *L, int idx, int timeout) {
    3.69 +  moonbr_io_handle_t *handle;
    3.70 +  handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
    3.71 +  if (handle->fd >= 0) {
    3.72 +    lua_pushcfunction(L, moonbr_io_close);
    3.73 +    lua_pushvalue(L, idx);
    3.74 +    lua_pushinteger(L, timeout);
    3.75 +    lua_call(L, 2, 0);
    3.76 +  }
    3.77 +}
    3.78 +
    3.79 +void moonbr_io_pushhandle(lua_State *L, int fd, int issocket, int canshutdown) {
    3.80    moonbr_io_handle_t *handle;
    3.81    handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
    3.82    handle->fd = fd;
    3.83    handle->issocket = issocket;
    3.84 +  handle->canshutdown = canshutdown;
    3.85 +  handle->shutwr = 0;
    3.86    handle->nonblocking = -1;
    3.87    handle->readerr = 0;
    3.88    handle->readbufcnt = 0;
    3.89 @@ -374,6 +426,7 @@
    3.90    {"write_nb", moonbr_io_write_nb},
    3.91    {"flush", moonbr_io_flush},
    3.92    {"flush_nb", moonbr_io_flush_nb},
    3.93 +  {"finish", moonbr_io_finish},
    3.94    {"close", moonbr_io_close},
    3.95    {"reset", moonbr_io_reset},
    3.96    {NULL, NULL}
    3.97 @@ -382,7 +435,7 @@
    3.98  static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
    3.99    {"__index", moonbr_io_handleindex},
   3.100    {"__newindex", moonbr_io_handlenewindex},
   3.101 -  {"__gc", moonbr_io_reset},
   3.102 +  {"__gc", moonbr_io_gc},
   3.103    {NULL, NULL}
   3.104  };
   3.105  
     4.1 --- a/moonbridge_io.h	Tue Apr 07 01:17:55 2015 +0200
     4.2 +++ b/moonbridge_io.h	Tue Apr 07 02:15:17 2015 +0200
     4.3 @@ -1,4 +1,5 @@
     4.4  
     4.5 -void moonbr_io_pushhandle(lua_State *L, int fd, int issocket);
     4.6 +void moonbr_io_pushhandle(lua_State *L, int fd, int issocket, int canshutdown);
     4.7 +void moonbr_io_closehandle(lua_State *L, int idx, int timeout);
     4.8  int luaopen_moonbridge_io(lua_State *L);
     4.9  

Impressum / About Us