/*-------------------------------------------------------------------------*\ * Determines how much time we have left for the next system call, * if the previous call was successful * Input * tm: timeout control structure * Returns * the number of ms left or -1 if there is no time limit \*-------------------------------------------------------------------------*/ double timeout_get(p_timeout tm) { if (tm->block < 0.0 && tm->total < 0.0) { return -1; } else if (tm->block < 0.0) { double t = tm->total - timeout_gettime() + tm->start; return MAX(t, 0.0); } else if (tm->total < 0.0) { return tm->block; } else { double t = tm->total - timeout_gettime() + tm->start; return MIN(tm->block, MAX(t, 0.0)); } }
/*-------------------------------------------------------------------------*\ * object:send() interface \*-------------------------------------------------------------------------*/ int buffer_meth_send(lua_State *L, p_buffer buf) { int top = lua_gettop(L); int err = IO_DONE; size_t size = 0, sent = 0; const char *data = luaL_checklstring(L, 2, &size); long start = (long) luaL_optnumber(L, 3, 1); long end = (long) luaL_optnumber(L, 4, -1); #ifdef LUASOCKET_DEBUG p_timeout tm = timeout_markstart(buf->tm); #endif if (start < 0) start = (long) (size+start+1); if (end < 0) end = (long) (size+end+1); if (start < 1) start = (long) 1; if (end > (long) size) end = (long) size; if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); /* check if there was an error */ if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, buf->io->error(buf->io->ctx, err)); lua_pushnumber(L, (lua_Number) (sent+start-1)); } else { lua_pushnumber(L, (lua_Number) (sent+start-1)); lua_pushnil(L); lua_pushnil(L); } #ifdef LUASOCKET_DEBUG /* push time elapsed during operation as the last return value */ lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); #endif return lua_gettop(L) - top; }
/*-------------------------------------------------------------------------*\ * object:setstats() interface \*-------------------------------------------------------------------------*/ int buffer_meth_setstats(lua_State *L, p_buffer buf) { buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); lua_pushnumber(L, 1); return 1; }
/*-------------------------------------------------------------------------*\ * Initializes C structure \*-------------------------------------------------------------------------*/ void buffer_init(p_buffer buf, p_io io, p_timeout tm) { buf->first = buf->last = 0; buf->io = io; buf->tm = tm; buf->received = buf->sent = 0; buf->birthday = timeout_gettime(); }
/*-------------------------------------------------------------------------*\ * object:receive() interface \*-------------------------------------------------------------------------*/ int buffer_meth_receive(lua_State *L, p_buffer buf) { int err = IO_DONE, top = lua_gettop(L); luaL_Buffer b; size_t size; const char *part = luaL_optlstring(L, 3, "", &size); #ifdef LUASOCKET_DEBUG p_timeout tm = timeout_markstart(buf->tm); #endif /* initialize buffer with optional extra prefix * (useful for concatenating previous partial results) */ luaL_buffinit(L, &b); luaL_addlstring(&b, part, size); /* receive new patterns */ if (!lua_isnumber(L, 2)) { const char *p= luaL_optstring(L, 2, "*l"); if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); else luaL_argcheck(L, 0, 2, "invalid receive pattern"); /* get a fixed number of bytes (minus what was already partially * received) */ } else { double n = lua_tonumber(L, 2); size_t wanted = (size_t) n; luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); if (size == 0 || wanted > size) err = recvraw(buf, wanted-size, &b); } /* check if there was an error */ if (err != IO_DONE) { /* we can't push anyting in the stack before pushing the * contents of the buffer. this is the reason for the complication */ luaL_pushresult(&b); lua_pushstring(L, buf->io->error(buf->io->ctx, err)); lua_pushvalue(L, -2); lua_pushnil(L); lua_replace(L, -4); } else { luaL_pushresult(&b); lua_pushnil(L); lua_pushnil(L); } #ifdef LUASOCKET_DEBUG /* push time elapsed during operation as the last return value */ lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); #endif return lua_gettop(L) - top; }
/*-------------------------------------------------------------------------*\ * Returns the time the system has been up, in secconds. \*-------------------------------------------------------------------------*/ static int timeout_lua_gettime(lua_State *L) { lua_pushnumber(L, timeout_gettime()); return 1; }
/*-------------------------------------------------------------------------*\ * Marks the operation start time in structure * Input * tm: timeout control structure \*-------------------------------------------------------------------------*/ p_timeout timeout_markstart(p_timeout tm) { tm->start = timeout_gettime(); return tm; }
/*-------------------------------------------------------------------------*\ * object:getstats() interface \*-------------------------------------------------------------------------*/ int buffer_meth_getstats(lua_State *L, p_buffer buf) { lua_pushnumber(L, (lua_Number) buf->received); lua_pushnumber(L, (lua_Number) buf->sent); lua_pushnumber(L, timeout_gettime() - buf->birthday); return 3; }
/*-------------------------------------------------------------------------*\ * Marks the operation start time in structure * Input * tm: timeout control structure \*-------------------------------------------------------------------------*/ LUASOCKET_API p_timeout timeout_markstart(p_timeout tm) { tm->start = timeout_gettime(); return tm; }