diff options
Diffstat (limited to 'ThirdParty/tolua_runtime/luasocket')
37 files changed, 8059 insertions, 0 deletions
diff --git a/ThirdParty/tolua_runtime/luasocket/auxiliar.c b/ThirdParty/tolua_runtime/luasocket/auxiliar.c new file mode 100644 index 0000000..18fa8e4 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/auxiliar.c @@ -0,0 +1,158 @@ +/*=========================================================================*\ +* Auxiliar routines for class hierarchy manipulation +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> +#include <stdio.h> + +#include "auxiliar.h" + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes the module +\*-------------------------------------------------------------------------*/ +int auxiliar_open(lua_State *L) { + (void) L; + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Creates a new class with given methods +* Methods whose names start with __ are passed directly to the metatable. +\*-------------------------------------------------------------------------*/ +void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) { + luaL_newmetatable(L, classname); /* mt */ + /* create __index table to place methods */ + lua_pushstring(L, "__index"); /* mt,"__index" */ + lua_newtable(L); /* mt,"__index",it */ + /* put class name into class metatable */ + lua_pushstring(L, "class"); /* mt,"__index",it,"class" */ + lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */ + lua_rawset(L, -3); /* mt,"__index",it */ + /* pass all methods that start with _ to the metatable, and all others + * to the index table */ + for (; func->name; func++) { /* mt,"__index",it */ + lua_pushstring(L, func->name); + lua_pushcfunction(L, func->func); + lua_rawset(L, func->name[0] == '_' ? -5: -3); + } + lua_rawset(L, -3); /* mt */ + lua_pop(L, 1); +} + +/*-------------------------------------------------------------------------*\ +* Prints the value of a class in a nice way +\*-------------------------------------------------------------------------*/ +int auxiliar_tostring(lua_State *L) { + char buf[32]; + if (!lua_getmetatable(L, 1)) goto error; + lua_pushstring(L, "__index"); + lua_gettable(L, -2); + if (!lua_istable(L, -1)) goto error; + lua_pushstring(L, "class"); + lua_gettable(L, -2); + if (!lua_isstring(L, -1)) goto error; + sprintf(buf, "%p", lua_touserdata(L, 1)); + lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf); + return 1; +error: + lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'"); + lua_error(L); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Insert class into group +\*-------------------------------------------------------------------------*/ +void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) { + luaL_getmetatable(L, classname); + lua_pushstring(L, groupname); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + lua_pop(L, 1); +} + +/*-------------------------------------------------------------------------*\ +* Make sure argument is a boolean +\*-------------------------------------------------------------------------*/ +int auxiliar_checkboolean(lua_State *L, int objidx) { + if (!lua_isboolean(L, objidx)) + auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); + return lua_toboolean(L, objidx); +} + +/*-------------------------------------------------------------------------*\ +* Return userdata pointer if object belongs to a given class, abort with +* error otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { + void *data = auxiliar_getclassudata(L, classname, objidx); + if (!data) { + char msg[45]; + sprintf(msg, "%.35s expected", classname); + luaL_argerror(L, objidx, msg); + } + return data; +} + +/*-------------------------------------------------------------------------*\ +* Return userdata pointer if object belongs to a given group, abort with +* error otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) { + void *data = auxiliar_getgroupudata(L, groupname, objidx); + if (!data) { + char msg[45]; + sprintf(msg, "%.35s expected", groupname); + luaL_argerror(L, objidx, msg); + } + return data; +} + +/*-------------------------------------------------------------------------*\ +* Set object class +\*-------------------------------------------------------------------------*/ +void auxiliar_setclass(lua_State *L, const char *classname, int objidx) { + luaL_getmetatable(L, classname); + if (objidx < 0) objidx--; + lua_setmetatable(L, objidx); +} + +/*-------------------------------------------------------------------------*\ +* Get a userdata pointer if object belongs to a given group. Return NULL +* otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) { + if (!lua_getmetatable(L, objidx)) + return NULL; + lua_pushstring(L, groupname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); + return NULL; + } else { + lua_pop(L, 2); + return lua_touserdata(L, objidx); + } +} + +/*-------------------------------------------------------------------------*\ +* Get a userdata pointer if object belongs to a given class. Return NULL +* otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { + return luaL_checkudata(L, objidx, classname); +} + +/*-------------------------------------------------------------------------*\ +* Throws error when argument does not have correct type. +* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2. +\*-------------------------------------------------------------------------*/ +int auxiliar_typeerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, + luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} + diff --git a/ThirdParty/tolua_runtime/luasocket/auxiliar.h b/ThirdParty/tolua_runtime/luasocket/auxiliar.h new file mode 100644 index 0000000..65511d4 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/auxiliar.h @@ -0,0 +1,48 @@ +#ifndef AUXILIAR_H +#define AUXILIAR_H +/*=========================================================================*\ +* Auxiliar routines for class hierarchy manipulation +* LuaSocket toolkit (but completely independent of other LuaSocket modules) +* +* A LuaSocket class is a name associated with Lua metatables. A LuaSocket +* group is a name associated with a class. A class can belong to any number +* of groups. This module provides the functionality to: +* +* - create new classes +* - add classes to groups +* - set the class of objects +* - check if an object belongs to a given class or group +* - get the userdata associated to objects +* - print objects in a pretty way +* +* LuaSocket class names follow the convention <module>{<class>}. Modules +* can define any number of classes and groups. The module tcp.c, for +* example, defines the classes tcp{master}, tcp{client} and tcp{server} and +* the groups tcp{client,server} and tcp{any}. Module functions can then +* perform type-checking on their arguments by either class or group. +* +* LuaSocket metatables define the __index metamethod as being a table. This +* table has one field for each method supported by the class, and a field +* "class" with the class name. +* +* The mapping from class name to the corresponding metatable and the +* reverse mapping are done using lauxlib. +\*=========================================================================*/ + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +int auxiliar_open(lua_State *L); +void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func); +void auxiliar_add2group(lua_State *L, const char *classname, const char *group); +void auxiliar_setclass(lua_State *L, const char *classname, int objidx); +void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); +void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); +void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); +void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); +int auxiliar_checkboolean(lua_State *L, int objidx); +int auxiliar_tostring(lua_State *L); +int auxiliar_typeerror(lua_State *L, int narg, const char *tname); + +#endif /* AUXILIAR_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/buffer.c b/ThirdParty/tolua_runtime/luasocket/buffer.c new file mode 100644 index 0000000..fff1634 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/buffer.c @@ -0,0 +1,273 @@ +/*=========================================================================*\ +* Input/Output interface for Lua programs +* LuaSocket toolkit +\*=========================================================================*/ +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "buffer.h" + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); +static int recvline(p_buffer buf, luaL_Buffer *b); +static int recvall(p_buffer buf, luaL_Buffer *b); +static int buffer_get(p_buffer buf, const char **data, size_t *count); +static void buffer_skip(p_buffer buf, size_t count); +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int buffer_open(lua_State *L) { + (void) L; + return 0; +} + +/*-------------------------------------------------------------------------*\ +* 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: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; +} + +/*-------------------------------------------------------------------------*\ +* 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; +} + +/*-------------------------------------------------------------------------*\ +* 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); + timeout_markstart(buf->tm); + 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(buf->tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* 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); + timeout_markstart(buf->tm); + /* 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(buf->tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* Determines if there is any data in the read buffer +\*-------------------------------------------------------------------------*/ +int buffer_isempty(p_buffer buf) { + return buf->first >= buf->last; +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Sends a block of data (unbuffered) +\*-------------------------------------------------------------------------*/ +#define STEPSIZE 8192 +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { + p_io io = buf->io; + p_timeout tm = buf->tm; + size_t total = 0; + int err = IO_DONE; + while (total < count && err == IO_DONE) { + size_t done = 0; + size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; + err = io->send(io->ctx, data+total, step, &done, tm); + total += done; + } + *sent = total; + buf->sent += total; + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a fixed number of bytes (buffered) +\*-------------------------------------------------------------------------*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + size_t count; const char *data; + err = buffer_get(buf, &data, &count); + count = MIN(count, wanted - total); + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + total += count; + if (total >= wanted) break; + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads everything until the connection is closed (buffered) +\*-------------------------------------------------------------------------*/ +static int recvall(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + const char *data; size_t count; + err = buffer_get(buf, &data, &count); + total += count; + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + } + if (err == IO_CLOSED) { + if (total > 0) return IO_DONE; + else return IO_CLOSED; + } else return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF +* are not returned by the function and are discarded from the buffer +\*-------------------------------------------------------------------------*/ +static int recvline(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + while (err == IO_DONE) { + size_t count, pos; const char *data; + err = buffer_get(buf, &data, &count); + pos = 0; + while (pos < count && data[pos] != '\n') { + /* we ignore all \r's */ + if (data[pos] != '\r') luaL_addchar(b, data[pos]); + pos++; + } + if (pos < count) { /* found '\n' */ + buffer_skip(buf, pos+1); /* skip '\n' too */ + break; /* we are done */ + } else /* reached the end of the buffer */ + buffer_skip(buf, pos); + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Skips a given number of bytes from read buffer. No data is read from the +* transport layer +\*-------------------------------------------------------------------------*/ +static void buffer_skip(p_buffer buf, size_t count) { + buf->received += count; + buf->first += count; + if (buffer_isempty(buf)) + buf->first = buf->last = 0; +} + +/*-------------------------------------------------------------------------*\ +* Return any data available in buffer, or get more data from transport layer +* if buffer is empty +\*-------------------------------------------------------------------------*/ +static int buffer_get(p_buffer buf, const char **data, size_t *count) { + int err = IO_DONE; + p_io io = buf->io; + p_timeout tm = buf->tm; + if (buffer_isempty(buf)) { + size_t got; + err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); + buf->first = 0; + buf->last = got; + } + *count = buf->last - buf->first; + *data = buf->data + buf->first; + return err; +} diff --git a/ThirdParty/tolua_runtime/luasocket/buffer.h b/ThirdParty/tolua_runtime/luasocket/buffer.h new file mode 100644 index 0000000..1281bb3 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/buffer.h @@ -0,0 +1,45 @@ +#ifndef BUF_H +#define BUF_H +/*=========================================================================*\ +* Input/Output interface for Lua programs +* LuaSocket toolkit +* +* Line patterns require buffering. Reading one character at a time involves +* too many system calls and is very slow. This module implements the +* LuaSocket interface for input/output on connected objects, as seen by +* Lua programs. +* +* Input is buffered. Output is *not* buffered because there was no simple +* way of making sure the buffered output data would ever be sent. +* +* The module is built on top of the I/O abstraction defined in io.h and the +* timeout management is done with the timeout.h interface. +\*=========================================================================*/ +#include "lua.h" + +#include "io.h" +#include "timeout.h" + +/* buffer size in bytes */ +#define BUF_SIZE 8192 + +/* buffer control structure */ +typedef struct t_buffer_ { + double birthday; /* throttle support info: creation time, */ + size_t sent, received; /* bytes sent, and bytes received */ + p_io io; /* IO driver used for this buffer */ + p_timeout tm; /* timeout management for this buffer */ + size_t first, last; /* index of first and last bytes of stored data */ + char data[BUF_SIZE]; /* storage space for buffer data */ +} t_buffer; +typedef t_buffer *p_buffer; + +int buffer_open(lua_State *L); +void buffer_init(p_buffer buf, p_io io, p_timeout tm); +int buffer_meth_send(lua_State *L, p_buffer buf); +int buffer_meth_receive(lua_State *L, p_buffer buf); +int buffer_meth_getstats(lua_State *L, p_buffer buf); +int buffer_meth_setstats(lua_State *L, p_buffer buf); +int buffer_isempty(p_buffer buf); + +#endif /* BUF_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/compat.c b/ThirdParty/tolua_runtime/luasocket/compat.c new file mode 100644 index 0000000..c2d99cb --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/compat.c @@ -0,0 +1,19 @@ +#include "compat.h" + +#if LUA_VERSION_NUM==501 +/* +** Adapted from Lua 5.2 +*/ +void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup+1, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + lua_pushstring(L, l->name); + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -(nup+1)); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_settable(L, -(nup + 3)); + } + lua_pop(L, nup); /* remove upvalues */ +} +#endif diff --git a/ThirdParty/tolua_runtime/luasocket/compat.h b/ThirdParty/tolua_runtime/luasocket/compat.h new file mode 100644 index 0000000..7bf8010 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/compat.h @@ -0,0 +1,11 @@ +#ifndef COMPAT_H +#define COMPAT_H + +#include "lua.h" +#include "lauxlib.h" + +#if LUA_VERSION_NUM==501 +void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); +#endif + +#endif diff --git a/ThirdParty/tolua_runtime/luasocket/except.c b/ThirdParty/tolua_runtime/luasocket/except.c new file mode 100644 index 0000000..60b5005 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/except.c @@ -0,0 +1,133 @@ +/*=========================================================================*\ +* Simple exception support +* LuaSocket toolkit +\*=========================================================================*/ +#include <stdio.h> + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "except.h" + +#if LUA_VERSION_NUM < 502 +#define lua_pcallk(L, na, nr, err, ctx, cont) \ + (((void)ctx),((void)cont),lua_pcall(L, na, nr, err)) +#endif + +#if LUA_VERSION_NUM < 503 +typedef int lua_KContext; +#endif + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int global_protect(lua_State *L); +static int global_newtry(lua_State *L); +static int protected_(lua_State *L); +static int finalize(lua_State *L); +static int do_nothing(lua_State *L); + +/* except functions */ +static luaL_Reg func[] = { + {"newtry", global_newtry}, + {"protect", global_protect}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Try factory +\*-------------------------------------------------------------------------*/ +static void wrap(lua_State *L) { + lua_createtable(L, 1, 0); + lua_pushvalue(L, -2); + lua_rawseti(L, -2, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_setmetatable(L, -2); +} + +static int finalize(lua_State *L) { + if (!lua_toboolean(L, 1)) { + lua_pushvalue(L, lua_upvalueindex(2)); + lua_call(L, 0, 0); + lua_settop(L, 2); + wrap(L); + lua_error(L); + return 0; + } else return lua_gettop(L); +} + +static int do_nothing(lua_State *L) { + (void) L; + return 0; +} + +static int global_newtry(lua_State *L) { + lua_settop(L, 1); + if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, -2); + lua_pushcclosure(L, finalize, 2); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Protect factory +\*-------------------------------------------------------------------------*/ +static int unwrap(lua_State *L) { + if (lua_istable(L, -1) && lua_getmetatable(L, -1)) { + int r = lua_rawequal(L, -1, lua_upvalueindex(1)); + lua_pop(L, 1); + if (r) { + lua_pushnil(L); + lua_rawgeti(L, -2, 1); + return 1; + } + } + return 0; +} + +static int protected_finish(lua_State *L, int status, lua_KContext ctx) { + (void)ctx; + if (status != 0 && status != LUA_YIELD) { + if (unwrap(L)) return 2; + else return lua_error(L); + } else return lua_gettop(L); +} + +#if LUA_VERSION_NUM == 502 +static int protected_cont(lua_State *L) { + int ctx = 0; + int status = lua_getctx(L, &ctx); + return protected_finish(L, status, ctx); +} +#else +#define protected_cont protected_finish +#endif + +static int protected_(lua_State *L) { + int status; + lua_pushvalue(L, lua_upvalueindex(2)); + lua_insert(L, 1); + status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); + return protected_finish(L, status, 0); +} + +static int global_protect(lua_State *L) { + lua_settop(L, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, 1); + lua_pushcclosure(L, protected_, 2); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Init module +\*-------------------------------------------------------------------------*/ +int except_open(lua_State *L) { + lua_newtable(L); /* metatable for wrapped exceptions */ + lua_pushboolean(L, 0); + lua_setfield(L, -2, "__metatable"); + luaL_setfuncs(L, func, 1); + return 0; +} diff --git a/ThirdParty/tolua_runtime/luasocket/except.h b/ThirdParty/tolua_runtime/luasocket/except.h new file mode 100644 index 0000000..2497c05 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/except.h @@ -0,0 +1,38 @@ +#ifndef EXCEPT_H +#define EXCEPT_H +/*=========================================================================*\ +* Exception control +* LuaSocket toolkit (but completely independent from other modules) +* +* This provides support for simple exceptions in Lua. During the +* development of the HTTP/FTP/SMTP support, it became aparent that +* error checking was taking a substantial amount of the coding. These +* function greatly simplify the task of checking errors. +* +* The main idea is that functions should return nil as their first return +* values when they find an error, and return an error message (or value) +* following nil. In case of success, as long as the first value is not nil, +* the other values don't matter. +* +* The idea is to nest function calls with the "try" function. This function +* checks the first value, and, if it's falsy, wraps the second value in a +* table with metatable and calls "error" on it. Otherwise, it returns all +* values it received. Basically, it works like the Lua "assert" function, +* but it creates errors targeted specifically at "protect". +* +* The "newtry" function is a factory for "try" functions that call a +* finalizer in protected mode before calling "error". +* +* The "protect" function returns a new function that behaves exactly like +* the function it receives, but the new function catches exceptions thrown +* by "try" functions and returns nil followed by the error message instead. +* +* With these three functions, it's easy to write functions that throw +* exceptions on error, but that don't interrupt the user script. +\*=========================================================================*/ + +#include "lua.h" + +int except_open(lua_State *L); + +#endif diff --git a/ThirdParty/tolua_runtime/luasocket/inet.c b/ThirdParty/tolua_runtime/luasocket/inet.c new file mode 100644 index 0000000..f4c8404 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/inet.c @@ -0,0 +1,543 @@ +/*=========================================================================*\ +* Internet domain functions +* LuaSocket toolkit +\*=========================================================================*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "inet.h" + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int inet_global_toip(lua_State *L); +static int inet_global_getaddrinfo(lua_State *L); +static int inet_global_tohostname(lua_State *L); +static int inet_global_getnameinfo(lua_State *L); +static void inet_pushresolved(lua_State *L, struct hostent *hp); +static int inet_global_gethostname(lua_State *L); + +/* DNS functions */ +static luaL_Reg func[] = { + { "toip", inet_global_toip}, + { "getaddrinfo", inet_global_getaddrinfo}, + { "tohostname", inet_global_tohostname}, + { "getnameinfo", inet_global_getnameinfo}, + { "gethostname", inet_global_gethostname}, + { NULL, NULL} +}; + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int inet_open(lua_State *L) +{ + lua_pushstring(L, "dns"); + lua_newtable(L); + luaL_setfuncs(L, func, 0); + lua_settable(L, -3); + return 0; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_gethost(const char *address, struct hostent **hp) { + struct in_addr addr; + if (inet_aton(address, &addr)) + return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); + else + return socket_gethostbyname(address, hp); +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_tohostname(lua_State *L) { + const char *address = luaL_checkstring(L, 1); + struct hostent *hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, hp->h_name); + inet_pushresolved(L, hp); + return 2; +} + +static int inet_global_getnameinfo(lua_State *L) { + char hbuf[NI_MAXHOST]; + char sbuf[NI_MAXSERV]; + int i, ret; + struct addrinfo hints; + struct addrinfo *resolved, *iter; + const char *host = luaL_optstring(L, 1, NULL); + const char *serv = luaL_optstring(L, 2, NULL); + + if (!(host || serv)) + luaL_error(L, "host and serv cannot be both nil"); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + + ret = getaddrinfo(host, serv, &hints, &resolved); + if (ret != 0) { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + + lua_newtable(L); + for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { + getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, + hbuf, host? (socklen_t) sizeof(hbuf): 0, + sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); + if (host) { + lua_pushnumber(L, i); + lua_pushstring(L, hbuf); + lua_settable(L, -3); + } + } + freeaddrinfo(resolved); + + if (serv) { + lua_pushstring(L, sbuf); + return 2; + } else { + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_toip(lua_State *L) +{ + const char *address = luaL_checkstring(L, 1); + struct hostent *hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); + inet_pushresolved(L, hp); + return 2; +} + +int inet_optfamily(lua_State* L, int narg, const char* def) +{ + static const char* optname[] = { "unspec", "inet", "inet6", NULL }; + static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 }; + + return optvalue[luaL_checkoption(L, narg, def, optname)]; +} + +int inet_optsocktype(lua_State* L, int narg, const char* def) +{ + static const char* optname[] = { "stream", "dgram", NULL }; + static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 }; + + return optvalue[luaL_checkoption(L, narg, def, optname)]; +} + +static int inet_global_getaddrinfo(lua_State *L) +{ + const char *hostname = luaL_checkstring(L, 1); + struct addrinfo *iterator = NULL, *resolved = NULL; + struct addrinfo hints; + int i = 1, ret = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + ret = getaddrinfo(hostname, NULL, &hints, &resolved); + if (ret != 0) { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + lua_newtable(L); + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + char hbuf[NI_MAXHOST]; + ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, + hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); + if (ret){ + freeaddrinfo(resolved); + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + lua_pushnumber(L, i); + lua_newtable(L); + switch (iterator->ai_family) { + case AF_INET: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet"); + lua_settable(L, -3); + break; + case AF_INET6: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet6"); + lua_settable(L, -3); + break; + case AF_UNSPEC: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unspec"); + lua_settable(L, -3); + break; + default: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unknown"); + lua_settable(L, -3); + break; + } + lua_pushliteral(L, "addr"); + lua_pushstring(L, hbuf); + lua_settable(L, -3); + lua_settable(L, -3); + i++; + } + freeaddrinfo(resolved); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Gets the host name +\*-------------------------------------------------------------------------*/ +static int inet_global_gethostname(lua_State *L) +{ + char name[257]; + name[256] = '\0'; + if (gethostname(name, 256) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } else { + lua_pushstring(L, name); + return 1; + } +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Retrieves socket peer name +\*-------------------------------------------------------------------------*/ +int inet_meth_getpeername(lua_State *L, p_socket ps, int family) +{ + int err; + struct sockaddr_storage peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ + if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + err = getnameinfo((struct sockaddr *) &peer, peer_len, + name, INET6_ADDRSTRLEN, + port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); + if (err) { + lua_pushnil(L); + lua_pushstring(L, gai_strerror(err)); + return 2; + } + lua_pushstring(L, name); + lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); + switch (family) { + case AF_INET: lua_pushliteral(L, "inet"); break; + case AF_INET6: lua_pushliteral(L, "inet6"); break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; + default: lua_pushliteral(L, "unknown"); break; + } + return 3; +} + +/*-------------------------------------------------------------------------*\ +* Retrieves socket local name +\*-------------------------------------------------------------------------*/ +int inet_meth_getsockname(lua_State *L, p_socket ps, int family) +{ + int err; + struct sockaddr_storage peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ + if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + err=getnameinfo((struct sockaddr *)&peer, peer_len, + name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); + if (err) { + lua_pushnil(L); + lua_pushstring(L, gai_strerror(err)); + return 2; + } + lua_pushstring(L, name); + lua_pushstring(L, port); + switch (family) { + case AF_INET: lua_pushliteral(L, "inet"); break; + case AF_INET6: lua_pushliteral(L, "inet6"); break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; + default: lua_pushliteral(L, "unknown"); break; + } + return 3; +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Passes all resolver information to Lua as a table +\*-------------------------------------------------------------------------*/ +static void inet_pushresolved(lua_State *L, struct hostent *hp) +{ + char **alias; + struct in_addr **addr; + int i, resolved; + lua_newtable(L); resolved = lua_gettop(L); + lua_pushstring(L, "name"); + lua_pushstring(L, hp->h_name); + lua_settable(L, resolved); + lua_pushstring(L, "ip"); + lua_pushstring(L, "alias"); + i = 1; + alias = hp->h_aliases; + lua_newtable(L); + if (alias) { + while (*alias) { + lua_pushnumber(L, i); + lua_pushstring(L, *alias); + lua_settable(L, -3); + i++; alias++; + } + } + lua_settable(L, resolved); + i = 1; + lua_newtable(L); + addr = (struct in_addr **) hp->h_addr_list; + if (addr) { + while (*addr) { + lua_pushnumber(L, i); + lua_pushstring(L, inet_ntoa(**addr)); + lua_settable(L, -3); + i++; addr++; + } + } + lua_settable(L, resolved); +} + +/*-------------------------------------------------------------------------*\ +* Tries to create a new inet socket +\*-------------------------------------------------------------------------*/ +const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { + const char *err = socket_strerror(socket_create(ps, family, type, protocol)); + if (err == NULL && family == AF_INET6) { + int yes = 1; + setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* "Disconnects" a DGRAM socket +\*-------------------------------------------------------------------------*/ +const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) +{ + switch (family) { + case AF_INET: { + struct sockaddr_in sin; + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_UNSPEC; + sin.sin_addr.s_addr = INADDR_ANY; + return socket_strerror(socket_connect(ps, (SA *) &sin, + sizeof(sin), tm)); + } + case AF_INET6: { + struct sockaddr_in6 sin6; + struct in6_addr addrany = IN6ADDR_ANY_INIT; + memset((char *) &sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_UNSPEC; + sin6.sin6_addr = addrany; + return socket_strerror(socket_connect(ps, (SA *) &sin6, + sizeof(sin6), tm)); + } + } + return NULL; +} + +/*-------------------------------------------------------------------------*\ +* Tries to connect to remote address (address, port) +\*-------------------------------------------------------------------------*/ +const char *inet_tryconnect(p_socket ps, int *family, const char *address, + const char *serv, p_timeout tm, struct addrinfo *connecthints) +{ + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + int current_family = *family; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, + connecthints, &resolved)); + if (err != NULL) { + if (resolved) freeaddrinfo(resolved); + return err; + } + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + timeout_markstart(tm); + /* create new socket if necessary. if there was no + * bind, we need to create one for every new family + * that shows up while iterating. if there was a + * bind, all families will be the same and we will + * not enter this branch. */ + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { + socket_destroy(ps); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); + if (err) continue; + current_family = iterator->ai_family; + /* set non-blocking before connect */ + socket_setnonblocking(ps); + } + /* try connecting to remote address */ + err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, + (socklen_t) iterator->ai_addrlen, tm)); + /* if success or timeout is zero, break out of loop */ + if (err == NULL || timeout_iszero(tm)) { + *family = current_family; + break; + } + } + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; +} + +/*-------------------------------------------------------------------------*\ +* Tries to accept a socket +\*-------------------------------------------------------------------------*/ +const char *inet_tryaccept(p_socket server, int family, p_socket client, + p_timeout tm) { + socklen_t len; + t_sockaddr_storage addr; + switch (family) { + case AF_INET6: len = sizeof(struct sockaddr_in6); break; + case AF_INET: len = sizeof(struct sockaddr_in); break; + default: len = sizeof(addr); break; + } + return socket_strerror(socket_accept(server, client, (SA *) &addr, + &len, tm)); +} + +/*-------------------------------------------------------------------------*\ +* Tries to bind socket to (address, port) +\*-------------------------------------------------------------------------*/ +const char *inet_trybind(p_socket ps, int *family, const char *address, + const char *serv, struct addrinfo *bindhints) { + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + int current_family = *family; + /* translate luasocket special values to C */ + if (strcmp(address, "*") == 0) address = NULL; + if (!serv) serv = "0"; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); + if (err) { + if (resolved) freeaddrinfo(resolved); + return err; + } + /* iterate over resolved addresses until one is good */ + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { + socket_destroy(ps); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); + if (err) continue; + current_family = iterator->ai_family; + } + /* try binding to local address */ + err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, + (socklen_t) iterator->ai_addrlen)); + /* keep trying unless bind succeeded */ + if (err == NULL) { + *family = current_family; + /* set to non-blocking after bind */ + socket_setnonblocking(ps); + break; + } + } + /* cleanup and return error */ + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; +} + +/*-------------------------------------------------------------------------*\ +* Some systems do not provide these so that we provide our own. +\*-------------------------------------------------------------------------*/ +#ifdef LUASOCKET_INET_ATON +int inet_aton(const char *cp, struct in_addr *inp) +{ + unsigned int a = 0, b = 0, c = 0, d = 0; + int n = 0, r; + unsigned long int addr = 0; + r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); + if (r == 0 || n == 0) return 0; + cp += n; + if (*cp) return 0; + if (a > 255 || b > 255 || c > 255 || d > 255) return 0; + if (inp) { + addr += a; addr <<= 8; + addr += b; addr <<= 8; + addr += c; addr <<= 8; + addr += d; + inp->s_addr = htonl(addr); + } + return 1; +} +#endif + +#ifdef LUASOCKET_INET_PTON +int inet_pton(int af, const char *src, void *dst) +{ + struct addrinfo hints, *res; + int ret = 1; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = af; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1; + if (af == AF_INET) { + struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr; + memcpy(dst, &in->sin_addr, sizeof(in->sin_addr)); + } else if (af == AF_INET6) { + struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr; + memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr)); + } else { + ret = -1; + } + freeaddrinfo(res); + return ret; +} + +#endif diff --git a/ThirdParty/tolua_runtime/luasocket/inet.h b/ThirdParty/tolua_runtime/luasocket/inet.h new file mode 100644 index 0000000..d060175 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/inet.h @@ -0,0 +1,54 @@ +#ifndef INET_H +#define INET_H +/*=========================================================================*\ +* Internet domain functions +* LuaSocket toolkit +* +* This module implements the creation and connection of internet domain +* sockets, on top of the socket.h interface, and the interface of with the +* resolver. +* +* The function inet_aton is provided for the platforms where it is not +* available. The module also implements the interface of the internet +* getpeername and getsockname functions as seen by Lua programs. +* +* The Lua functions toip and tohostname are also implemented here. +\*=========================================================================*/ +#include "lua.h" +#include "socket.h" +#include "timeout.h" + +#ifdef _WIN32 +#define LUASOCKET_INET_ATON +#endif + +#ifdef __MINGW32__ +#define LUASOCKET_INET_PTON +#endif + +int inet_open(lua_State *L); + +const char *inet_trycreate(p_socket ps, int family, int type, int protocol); +const char *inet_tryconnect(p_socket ps, int *family, const char *address, + const char *serv, p_timeout tm, struct addrinfo *connecthints); +const char *inet_trybind(p_socket ps, int *family, const char *address, + const char *serv, struct addrinfo *bindhints); +const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm); +const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); + +int inet_meth_getpeername(lua_State *L, p_socket ps, int family); +int inet_meth_getsockname(lua_State *L, p_socket ps, int family); + +int inet_optfamily(lua_State* L, int narg, const char* def); +int inet_optsocktype(lua_State* L, int narg, const char* def); + +#ifdef LUASOCKET_INET_ATON +int inet_aton(const char *cp, struct in_addr *inp); +#endif + +#ifdef LUASOCKET_INET_PTON +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); +int inet_pton(int af, const char *src, void *dst); +#endif + +#endif /* INET_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/io.c b/ThirdParty/tolua_runtime/luasocket/io.c new file mode 100644 index 0000000..a4230ce --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/io.c @@ -0,0 +1,30 @@ +/*=========================================================================*\ +* Input/Output abstraction +* LuaSocket toolkit +\*=========================================================================*/ +#include "io.h" + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes C structure +\*-------------------------------------------------------------------------*/ +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { + io->send = send; + io->recv = recv; + io->error = error; + io->ctx = ctx; +} + +/*-------------------------------------------------------------------------*\ +* I/O error strings +\*-------------------------------------------------------------------------*/ +const char *io_strerror(int err) { + switch (err) { + case IO_DONE: return NULL; + case IO_CLOSED: return "closed"; + case IO_TIMEOUT: return "timeout"; + default: return "unknown error"; + } +} diff --git a/ThirdParty/tolua_runtime/luasocket/io.h b/ThirdParty/tolua_runtime/luasocket/io.h new file mode 100644 index 0000000..8cca08a --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/io.h @@ -0,0 +1,65 @@ +#ifndef IO_H +#define IO_H +/*=========================================================================*\ +* Input/Output abstraction +* LuaSocket toolkit +* +* This module defines the interface that LuaSocket expects from the +* transport layer for streamed input/output. The idea is that if any +* transport implements this interface, then the buffer.c functions +* automatically work on it. +* +* The module socket.h implements this interface, and thus the module tcp.h +* is very simple. +\*=========================================================================*/ +#include <stdio.h> +#include "lua.h" + +#include "timeout.h" + +/* IO error codes */ +enum { + IO_DONE = 0, /* operation completed successfully */ + IO_TIMEOUT = -1, /* operation timed out */ + IO_CLOSED = -2, /* the connection has been closed */ + IO_UNKNOWN = -3 +}; + +/* interface to error message function */ +typedef const char *(*p_error) ( + void *ctx, /* context needed by send */ + int err /* error code */ +); + +/* interface to send function */ +typedef int (*p_send) ( + void *ctx, /* context needed by send */ + const char *data, /* pointer to buffer with data to send */ + size_t count, /* number of bytes to send from buffer */ + size_t *sent, /* number of bytes sent uppon return */ + p_timeout tm /* timeout control */ +); + +/* interface to recv function */ +typedef int (*p_recv) ( + void *ctx, /* context needed by recv */ + char *data, /* pointer to buffer where data will be writen */ + size_t count, /* number of bytes to receive into buffer */ + size_t *got, /* number of bytes received uppon return */ + p_timeout tm /* timeout control */ +); + +/* IO driver definition */ +typedef struct t_io_ { + void *ctx; /* context needed by send/recv */ + p_send send; /* send function pointer */ + p_recv recv; /* receive function pointer */ + p_error error; /* strerror function */ +} t_io; +typedef t_io *p_io; + +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); +const char *io_strerror(int err); + +#endif /* IO_H */ + diff --git a/ThirdParty/tolua_runtime/luasocket/luasocket.c b/ThirdParty/tolua_runtime/luasocket/luasocket.c new file mode 100644 index 0000000..7d9c802 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/luasocket.c @@ -0,0 +1,114 @@ +/*=========================================================================*\ +* LuaSocket toolkit +* Networking support for the Lua language +* Diego Nehab +* 26/11/1999 +* +* This library is part of an effort to progressively increase the network +* connectivity of the Lua language. The Lua interface to networking +* functions follows the Sockets API closely, trying to simplify all tasks +* involved in setting up both client and server connections. The provided +* IO routines, however, follow the Lua style, being very similar to the +* standard Lua read and write functions. +\*=========================================================================*/ + +/*=========================================================================*\ +* Standard include files +\*=========================================================================*/ +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +/*=========================================================================*\ +* LuaSocket includes +\*=========================================================================*/ +#include "luasocket.h" +#include "auxiliar.h" +#include "except.h" +#include "timeout.h" +#include "buffer.h" +#include "inet.h" +#include "tcp.h" +#include "udp.h" +#include "select.h" + +/*-------------------------------------------------------------------------*\ +* Internal function prototypes +\*-------------------------------------------------------------------------*/ +static int global_skip(lua_State *L); +static int global_unload(lua_State *L); +static int base_open(lua_State *L); + +/*-------------------------------------------------------------------------*\ +* Modules and functions +\*-------------------------------------------------------------------------*/ +static const luaL_Reg mod[] = { + {"auxiliar", auxiliar_open}, + {"except", except_open}, + {"timeout", timeout_open}, + {"buffer", buffer_open}, + {"inet", inet_open}, + {"tcp", tcp_open}, + {"udp", udp_open}, + {"select", select_open}, + {NULL, NULL} +}; + +static luaL_Reg func[] = { + {"skip", global_skip}, + {"__unload", global_unload}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Skip a few arguments +\*-------------------------------------------------------------------------*/ +static int global_skip(lua_State *L) { + int amount = luaL_checkinteger(L, 1); + int ret = lua_gettop(L) - amount - 1; + return ret >= 0 ? ret : 0; +} + +/*-------------------------------------------------------------------------*\ +* Unloads the library +\*-------------------------------------------------------------------------*/ +static int global_unload(lua_State *L) { + (void) L; + socket_close(); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Setup basic stuff. +\*-------------------------------------------------------------------------*/ +static int base_open(lua_State *L) { + if (socket_open()) { + /* export functions (and leave namespace table on top of stack) */ + lua_newtable(L); + luaL_setfuncs(L, func, 0); +#ifdef LUASOCKET_DEBUG + lua_pushstring(L, "_DEBUG"); + lua_pushboolean(L, 1); + lua_rawset(L, -3); +#endif + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, LUASOCKET_VERSION); + lua_rawset(L, -3); + return 1; + } else { + lua_pushstring(L, "unable to initialize library"); + lua_error(L); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Initializes all library modules. +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_core(lua_State *L) { + int i; + base_open(L); + for (i = 0; mod[i].name; i++) mod[i].func(L); + return 1; +} diff --git a/ThirdParty/tolua_runtime/luasocket/luasocket.h b/ThirdParty/tolua_runtime/luasocket/luasocket.h new file mode 100644 index 0000000..f75d21f --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/luasocket.h @@ -0,0 +1,29 @@ +#ifndef LUASOCKET_H +#define LUASOCKET_H +/*=========================================================================*\ +* LuaSocket toolkit +* Networking support for the Lua language +* Diego Nehab +* 9/11/1999 +\*=========================================================================*/ +#include "lua.h" + +/*-------------------------------------------------------------------------*\ +* Current socket library version +\*-------------------------------------------------------------------------*/ +#define LUASOCKET_VERSION "LuaSocket 3.0-rc1" +#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab" + +/*-------------------------------------------------------------------------*\ +* This macro prefixes all exported API functions +\*-------------------------------------------------------------------------*/ +#ifndef LUASOCKET_API +#define LUASOCKET_API extern +#endif + +/*-------------------------------------------------------------------------*\ +* Initializes the library. +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_core(lua_State *L); + +#endif /* LUASOCKET_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/luasocket_scripts.c b/ThirdParty/tolua_runtime/luasocket/luasocket_scripts.c new file mode 100644 index 0000000..f5aabb7 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/luasocket_scripts.c @@ -0,0 +1,2195 @@ + +/* luasocket_scripts.c */ + +#include "lua.h" +#include "lauxlib.h" +#include "luasocket_scripts.h" + +/* ltn12 */ +static const char *lua_m_ltn12 = +"-----------------------------------------------------------------------------\n" +"-- LTN12 - Filters, sources, sinks and pumps.\n" +"-- LuaSocket toolkit.\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module\n" +"-----------------------------------------------------------------------------\n" +"local string = require(\"string\")\n" +"local table = require(\"table\")\n" +"local base = _G\n" +"local _M = {}\n" +"if module then -- heuristic for exporting a global package table\n" +" ltn12 = _M\n" +"end\n" +"local filter,source,sink,pump = {},{},{},{}\n" +"\n" +"_M.filter = filter\n" +"_M.source = source\n" +"_M.sink = sink\n" +"_M.pump = pump\n" +"\n" +"-- 2048 seems to be better in windows...\n" +"_M.BLOCKSIZE = 2048\n" +"_M._VERSION = \"LTN12 1.0.3\"\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Filter stuff\n" +"-----------------------------------------------------------------------------\n" +"-- returns a high level filter that cycles a low-level filter\n" +"function filter.cycle(low, ctx, extra)\n" +" base.assert(low)\n" +" return function(chunk)\n" +" local ret\n" +" ret, ctx = low(ctx, chunk, extra)\n" +" return ret\n" +" end\n" +"end\n" +"\n" +"-- chains a bunch of filters together\n" +"-- (thanks to Wim Couwenberg)\n" +"function filter.chain(...)\n" +" local arg = {...}\n" +" local n = select('#',...)\n" +" local top, index = 1, 1\n" +" local retry = \"\"\n" +" return function(chunk)\n" +" retry = chunk and retry\n" +" while true do\n" +" if index == top then\n" +" chunk = arg[index](chunk)\n" +" if chunk == \"\" or top == n then return chunk\n" +" elseif chunk then index = index + 1\n" +" else\n" +" top = top+1\n" +" index = top\n" +" end\n" +" else\n" +" chunk = arg[index](chunk or \"\")\n" +" if chunk == \"\" then\n" +" index = index - 1\n" +" chunk = retry\n" +" elseif chunk then\n" +" if index == n then return chunk\n" +" else index = index + 1 end\n" +" else base.error(\"filter returned inappropriate nil\") end\n" +" end\n" +" end\n" +" end\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Source stuff\n" +"-----------------------------------------------------------------------------\n" +"-- create an empty source\n" +"local function empty()\n" +" return nil\n" +"end\n" +"\n" +"function source.empty()\n" +" return empty\n" +"end\n" +"\n" +"-- returns a source that just outputs an error\n" +"function source.error(err)\n" +" return function()\n" +" return nil, err\n" +" end\n" +"end\n" +"\n" +"-- creates a file source\n" +"function source.file(handle, io_err)\n" +" if handle then\n" +" return function()\n" +" local chunk = handle:read(_M.BLOCKSIZE)\n" +" if not chunk then handle:close() end\n" +" return chunk\n" +" end\n" +" else return source.error(io_err or \"unable to open file\") end\n" +"end\n" +"\n" +"-- turns a fancy source into a simple source\n" +"function source.simplify(src)\n" +" base.assert(src)\n" +" return function()\n" +" local chunk, err_or_new = src()\n" +" src = err_or_new or src\n" +" if not chunk then return nil, err_or_new\n" +" else return chunk end\n" +" end\n" +"end\n" +"\n" +"-- creates string source\n" +"function source.string(s)\n" +" if s then\n" +" local i = 1\n" +" return function()\n" +" local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)\n" +" i = i + _M.BLOCKSIZE\n" +" if chunk ~= \"\" then return chunk\n" +" else return nil end\n" +" end\n" +" else return source.empty() end\n" +"end\n" +"\n" +"-- creates rewindable source\n" +"function source.rewind(src)\n" +" base.assert(src)\n" +" local t = {}\n" +" return function(chunk)\n" +" if not chunk then\n" +" chunk = table.remove(t)\n" +" if not chunk then return src()\n" +" else return chunk end\n" +" else\n" +" table.insert(t, chunk)\n" +" end\n" +" end\n" +"end\n" +"\n" +"function source.chain(src, f)\n" +" base.assert(src and f)\n" +" local last_in, last_out = \"\", \"\"\n" +" local state = \"feeding\"\n" +" local err\n" +" return function()\n" +" if not last_out then\n" +" base.error('source is empty!', 2)\n" +" end\n" +" while true do\n" +" if state == \"feeding\" then\n" +" last_in, err = src()\n" +" if err then return nil, err end\n" +" last_out = f(last_in)\n" +" if not last_out then\n" +" if last_in then\n" +" base.error('filter returned inappropriate nil')\n" +" else\n" +" return nil\n" +" end\n" +" elseif last_out ~= \"\" then\n" +" state = \"eating\"\n" +" if last_in then last_in = \"\" end\n" +" return last_out\n" +" end\n" +" else\n" +" last_out = f(last_in)\n" +" if last_out == \"\" then\n" +" if last_in == \"\" then\n" +" state = \"feeding\"\n" +" else\n" +" base.error('filter returned \"\"')\n" +" end\n" +" elseif not last_out then\n" +" if last_in then\n" +" base.error('filter returned inappropriate nil')\n" +" else\n" +" return nil\n" +" end\n" +" else\n" +" return last_out\n" +" end\n" +" end\n" +" end\n" +" end\n" +"end\n" +"\n" +"-- creates a source that produces contents of several sources, one after the\n" +"-- other, as if they were concatenated\n" +"-- (thanks to Wim Couwenberg)\n" +"function source.cat(...)\n" +" local arg = {...}\n" +" local src = table.remove(arg, 1)\n" +" return function()\n" +" while src do\n" +" local chunk, err = src()\n" +" if chunk then return chunk end\n" +" if err then return nil, err end\n" +" src = table.remove(arg, 1)\n" +" end\n" +" end\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Sink stuff\n" +"-----------------------------------------------------------------------------\n" +"-- creates a sink that stores into a table\n" +"function sink.table(t)\n" +" t = t or {}\n" +" local f = function(chunk, err)\n" +" if chunk then table.insert(t, chunk) end\n" +" return 1\n" +" end\n" +" return f, t\n" +"end\n" +"\n" +"-- turns a fancy sink into a simple sink\n" +"function sink.simplify(snk)\n" +" base.assert(snk)\n" +" return function(chunk, err)\n" +" local ret, err_or_new = snk(chunk, err)\n" +" if not ret then return nil, err_or_new end\n" +" snk = err_or_new or snk\n" +" return 1\n" +" end\n" +"end\n" +"\n" +"-- creates a file sink\n" +"function sink.file(handle, io_err)\n" +" if handle then\n" +" return function(chunk, err)\n" +" if not chunk then\n" +" handle:close()\n" +" return 1\n" +" else return handle:write(chunk) end\n" +" end\n" +" else return sink.error(io_err or \"unable to open file\") end\n" +"end\n" +"\n" +"-- creates a sink that discards data\n" +"local function null()\n" +" return 1\n" +"end\n" +"\n" +"function sink.null()\n" +" return null\n" +"end\n" +"\n" +"-- creates a sink that just returns an error\n" +"function sink.error(err)\n" +" return function()\n" +" return nil, err\n" +" end\n" +"end\n" +"\n" +"-- chains a sink with a filter\n" +"function sink.chain(f, snk)\n" +" base.assert(f and snk)\n" +" return function(chunk, err)\n" +" if chunk ~= \"\" then\n" +" local filtered = f(chunk)\n" +" local done = chunk and \"\"\n" +" while true do\n" +" local ret, snkerr = snk(filtered, err)\n" +" if not ret then return nil, snkerr end\n" +" if filtered == done then return 1 end\n" +" filtered = f(done)\n" +" end\n" +" else return 1 end\n" +" end\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Pump stuff\n" +"-----------------------------------------------------------------------------\n" +"-- pumps one chunk from the source to the sink\n" +"function pump.step(src, snk)\n" +" local chunk, src_err = src()\n" +" local ret, snk_err = snk(chunk, src_err)\n" +" if chunk and ret then return 1\n" +" else return nil, src_err or snk_err end\n" +"end\n" +"\n" +"-- pumps all data from a source to a sink, using a step function\n" +"function pump.all(src, snk, step)\n" +" base.assert(src and snk)\n" +" step = step or pump.step\n" +" while true do\n" +" local ret, err = step(src, snk)\n" +" if not ret then\n" +" if err then return nil, err\n" +" else return 1 end\n" +" end\n" +" end\n" +"end\n" +"\n" +"return _M\n" +"\n"; + +/* mime */ +static const char *lua_m_mime = +"-----------------------------------------------------------------------------\n" +"-- MIME support for the Lua language.\n" +"-- Author: Diego Nehab\n" +"-- Conforming to RFCs 2045-2049\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module and import dependencies\n" +"-----------------------------------------------------------------------------\n" +"local base = _G\n" +"local ltn12 = require(\"ltn12\")\n" +"local mime = require(\"mime.core\")\n" +"local io = require(\"io\")\n" +"local string = require(\"string\")\n" +"local _M = mime\n" +"\n" +"-- encode, decode and wrap algorithm tables\n" +"local encodet, decodet, wrapt = {},{},{}\n" +"\n" +"_M.encodet = encodet\n" +"_M.decodet = decodet\n" +"_M.wrapt = wrapt \n" +"\n" +"-- creates a function that chooses a filter by name from a given table\n" +"local function choose(table)\n" +" return function(name, opt1, opt2)\n" +" if base.type(name) ~= \"string\" then\n" +" name, opt1, opt2 = \"default\", name, opt1\n" +" end\n" +" local f = table[name or \"nil\"]\n" +" if not f then \n" +" base.error(\"unknown key (\" .. base.tostring(name) .. \")\", 3)\n" +" else return f(opt1, opt2) end\n" +" end\n" +"end\n" +"\n" +"-- define the encoding filters\n" +"encodet['base64'] = function()\n" +" return ltn12.filter.cycle(_M.b64, \"\")\n" +"end\n" +"\n" +"encodet['quoted-printable'] = function(mode)\n" +" return ltn12.filter.cycle(_M.qp, \"\",\n" +" (mode == \"binary\") and \"=0D=0A\" or \"\\r\\n\")\n" +"end\n" +"\n" +"-- define the decoding filters\n" +"decodet['base64'] = function()\n" +" return ltn12.filter.cycle(_M.unb64, \"\")\n" +"end\n" +"\n" +"decodet['quoted-printable'] = function()\n" +" return ltn12.filter.cycle(_M.unqp, \"\")\n" +"end\n" +"\n" +"local function format(chunk)\n" +" if chunk then\n" +" if chunk == \"\" then return \"''\"\n" +" else return string.len(chunk) end\n" +" else return \"nil\" end\n" +"end\n" +"\n" +"-- define the line-wrap filters\n" +"wrapt['text'] = function(length)\n" +" length = length or 76\n" +" return ltn12.filter.cycle(_M.wrp, length, length)\n" +"end\n" +"wrapt['base64'] = wrapt['text']\n" +"wrapt['default'] = wrapt['text']\n" +"\n" +"wrapt['quoted-printable'] = function()\n" +" return ltn12.filter.cycle(_M.qpwrp, 76, 76)\n" +"end\n" +"\n" +"-- function that choose the encoding, decoding or wrap algorithm\n" +"_M.encode = choose(encodet)\n" +"_M.decode = choose(decodet)\n" +"_M.wrap = choose(wrapt)\n" +"\n" +"-- define the end-of-line normalization filter\n" +"function _M.normalize(marker)\n" +" return ltn12.filter.cycle(_M.eol, 0, marker)\n" +"end\n" +"\n" +"-- high level stuffing filter\n" +"function _M.stuff()\n" +" return ltn12.filter.cycle(_M.dot, 2)\n" +"end\n" +"\n" +"return _M\n"; + +/* socket.ftp */ +static const char *lua_m_socket_ftp = +"-----------------------------------------------------------------------------\n" +"-- FTP support for the Lua language\n" +"-- LuaSocket toolkit.\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module and import dependencies\n" +"-----------------------------------------------------------------------------\n" +"local base = _G\n" +"local table = require(\"table\")\n" +"local string = require(\"string\")\n" +"local math = require(\"math\")\n" +"local socket = require(\"socket.socket\")\n" +"local url = require(\"socket.url\")\n" +"local tp = require(\"socket.tp\")\n" +"local ltn12 = require(\"ltn12\")\n" +"socket.ftp = {}\n" +"local _M = socket.ftp\n" +"-----------------------------------------------------------------------------\n" +"-- Program constants\n" +"-----------------------------------------------------------------------------\n" +"-- timeout in seconds before the program gives up on a connection\n" +"_M.TIMEOUT = 60\n" +"-- default port for ftp service\n" +"_M.PORT = 21\n" +"-- this is the default anonymous password. used when no password is\n" +"-- provided in url. should be changed to your e-mail.\n" +"_M.USER = \"ftp\"\n" +"_M.PASSWORD = \"anonymous@anonymous.org\"\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Low level FTP API\n" +"-----------------------------------------------------------------------------\n" +"local metat = { __index = {} }\n" +"\n" +"function _M.open(server, port, create)\n" +" local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, create))\n" +" local f = base.setmetatable({ tp = tp }, metat)\n" +" -- make sure everything gets closed in an exception\n" +" f.try = socket.newtry(function() f:close() end)\n" +" return f\n" +"end\n" +"\n" +"function metat.__index:portconnect()\n" +" self.try(self.server:settimeout(_M.TIMEOUT))\n" +" self.data = self.try(self.server:accept())\n" +" self.try(self.data:settimeout(_M.TIMEOUT))\n" +"end\n" +"\n" +"function metat.__index:pasvconnect()\n" +" self.data = self.try(socket.tcp())\n" +" self.try(self.data:settimeout(_M.TIMEOUT))\n" +" self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))\n" +"end\n" +"\n" +"function metat.__index:login(user, password)\n" +" self.try(self.tp:command(\"user\", user or _M.USER))\n" +" local code, reply = self.try(self.tp:check{\"2..\", 331})\n" +" if code == 331 then\n" +" self.try(self.tp:command(\"pass\", password or _M.PASSWORD))\n" +" self.try(self.tp:check(\"2..\"))\n" +" end\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:pasv()\n" +" self.try(self.tp:command(\"pasv\"))\n" +" local code, reply = self.try(self.tp:check(\"2..\"))\n" +" local pattern = \"(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)\"\n" +" local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))\n" +" self.try(a and b and c and d and p1 and p2, reply)\n" +" self.pasvt = {\n" +" ip = string.format(\"%d.%d.%d.%d\", a, b, c, d),\n" +" port = p1*256 + p2\n" +" }\n" +" if self.server then\n" +" self.server:close()\n" +" self.server = nil\n" +" end\n" +" return self.pasvt.ip, self.pasvt.port\n" +"end\n" +"\n" +"function metat.__index:port(ip, port)\n" +" self.pasvt = nil\n" +" if not ip then\n" +" ip, port = self.try(self.tp:getcontrol():getsockname())\n" +" self.server = self.try(socket.bind(ip, 0))\n" +" ip, port = self.try(self.server:getsockname())\n" +" self.try(self.server:settimeout(_M.TIMEOUT))\n" +" end\n" +" local pl = math.mod(port, 256)\n" +" local ph = (port - pl)/256\n" +" local arg = string.gsub(string.format(\"%s,%d,%d\", ip, ph, pl), \"%.\", \",\")\n" +" self.try(self.tp:command(\"port\", arg))\n" +" self.try(self.tp:check(\"2..\"))\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:send(sendt)\n" +" self.try(self.pasvt or self.server, \"need port or pasv first\")\n" +" -- if there is a pasvt table, we already sent a PASV command\n" +" -- we just get the data connection into self.data\n" +" if self.pasvt then self:pasvconnect() end\n" +" -- get the transfer argument and command\n" +" local argument = sendt.argument or\n" +" url.unescape(string.gsub(sendt.path or \"\", \"^[/\\\\]\", \"\"))\n" +" if argument == \"\" then argument = nil end\n" +" local command = sendt.command or \"stor\"\n" +" -- send the transfer command and check the reply\n" +" self.try(self.tp:command(command, argument))\n" +" local code, reply = self.try(self.tp:check{\"2..\", \"1..\"})\n" +" -- if there is not a a pasvt table, then there is a server\n" +" -- and we already sent a PORT command\n" +" if not self.pasvt then self:portconnect() end\n" +" -- get the sink, source and step for the transfer\n" +" local step = sendt.step or ltn12.pump.step\n" +" local readt = {self.tp.c}\n" +" local checkstep = function(src, snk)\n" +" -- check status in control connection while downloading\n" +" local readyt = socket.select(readt, nil, 0)\n" +" if readyt[tp] then code = self.try(self.tp:check(\"2..\")) end\n" +" return step(src, snk)\n" +" end\n" +" local sink = socket.sink(\"close-when-done\", self.data)\n" +" -- transfer all data and check error\n" +" self.try(ltn12.pump.all(sendt.source, sink, checkstep))\n" +" if string.find(code, \"1..\") then self.try(self.tp:check(\"2..\")) end\n" +" -- done with data connection\n" +" self.data:close()\n" +" -- find out how many bytes were sent\n" +" local sent = socket.skip(1, self.data:getstats())\n" +" self.data = nil\n" +" return sent\n" +"end\n" +"\n" +"function metat.__index:receive(recvt)\n" +" self.try(self.pasvt or self.server, \"need port or pasv first\")\n" +" if self.pasvt then self:pasvconnect() end\n" +" local argument = recvt.argument or\n" +" url.unescape(string.gsub(recvt.path or \"\", \"^[/\\\\]\", \"\"))\n" +" if argument == \"\" then argument = nil end\n" +" local command = recvt.command or \"retr\"\n" +" self.try(self.tp:command(command, argument))\n" +" local code,reply = self.try(self.tp:check{\"1..\", \"2..\"})\n" +" if (code >= 200) and (code <= 299) then\n" +" recvt.sink(reply)\n" +" return 1\n" +" end\n" +" if not self.pasvt then self:portconnect() end\n" +" local source = socket.source(\"until-closed\", self.data)\n" +" local step = recvt.step or ltn12.pump.step\n" +" self.try(ltn12.pump.all(source, recvt.sink, step))\n" +" if string.find(code, \"1..\") then self.try(self.tp:check(\"2..\")) end\n" +" self.data:close()\n" +" self.data = nil\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:cwd(dir)\n" +" self.try(self.tp:command(\"cwd\", dir))\n" +" self.try(self.tp:check(250))\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:type(type)\n" +" self.try(self.tp:command(\"type\", type))\n" +" self.try(self.tp:check(200))\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:greet()\n" +" local code = self.try(self.tp:check{\"1..\", \"2..\"})\n" +" if string.find(code, \"1..\") then self.try(self.tp:check(\"2..\")) end\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:quit()\n" +" self.try(self.tp:command(\"quit\"))\n" +" self.try(self.tp:check(\"2..\"))\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:close()\n" +" if self.data then self.data:close() end\n" +" if self.server then self.server:close() end\n" +" return self.tp:close()\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- High level FTP API\n" +"-----------------------------------------------------------------------------\n" +"local function override(t)\n" +" if t.url then\n" +" local u = url.parse(t.url)\n" +" for i,v in base.pairs(t) do\n" +" u[i] = v\n" +" end\n" +" return u\n" +" else return t end\n" +"end\n" +"\n" +"local function tput(putt)\n" +" putt = override(putt)\n" +" socket.try(putt.host, \"missing hostname\")\n" +" local f = _M.open(putt.host, putt.port, putt.create)\n" +" f:greet()\n" +" f:login(putt.user, putt.password)\n" +" if putt.type then f:type(putt.type) end\n" +" f:pasv()\n" +" local sent = f:send(putt)\n" +" f:quit()\n" +" f:close()\n" +" return sent\n" +"end\n" +"\n" +"local default = {\n" +" path = \"/\",\n" +" scheme = \"ftp\"\n" +"}\n" +"\n" +"local function parse(u)\n" +" local t = socket.try(url.parse(u, default))\n" +" socket.try(t.scheme == \"ftp\", \"wrong scheme '\" .. t.scheme .. \"'\")\n" +" socket.try(t.host, \"missing hostname\")\n" +" local pat = \"^type=(.)$\"\n" +" if t.params then\n" +" t.type = socket.skip(2, string.find(t.params, pat))\n" +" socket.try(t.type == \"a\" or t.type == \"i\",\n" +" \"invalid type '\" .. t.type .. \"'\")\n" +" end\n" +" return t\n" +"end\n" +"\n" +"local function sput(u, body)\n" +" local putt = parse(u)\n" +" putt.source = ltn12.source.string(body)\n" +" return tput(putt)\n" +"end\n" +"\n" +"_M.put = socket.protect(function(putt, body)\n" +" if base.type(putt) == \"string\" then return sput(putt, body)\n" +" else return tput(putt) end\n" +"end)\n" +"\n" +"local function tget(gett)\n" +" gett = override(gett)\n" +" socket.try(gett.host, \"missing hostname\")\n" +" local f = _M.open(gett.host, gett.port, gett.create)\n" +" f:greet()\n" +" f:login(gett.user, gett.password)\n" +" if gett.type then f:type(gett.type) end\n" +" f:pasv()\n" +" f:receive(gett)\n" +" f:quit()\n" +" return f:close()\n" +"end\n" +"\n" +"local function sget(u)\n" +" local gett = parse(u)\n" +" local t = {}\n" +" gett.sink = ltn12.sink.table(t)\n" +" tget(gett)\n" +" return table.concat(t)\n" +"end\n" +"\n" +"_M.command = socket.protect(function(cmdt)\n" +" cmdt = override(cmdt)\n" +" socket.try(cmdt.host, \"missing hostname\")\n" +" socket.try(cmdt.command, \"missing command\")\n" +" local f = open(cmdt.host, cmdt.port, cmdt.create)\n" +" f:greet()\n" +" f:login(cmdt.user, cmdt.password)\n" +" f.try(f.tp:command(cmdt.command, cmdt.argument))\n" +" if cmdt.check then f.try(f.tp:check(cmdt.check)) end\n" +" f:quit()\n" +" return f:close()\n" +"end)\n" +"\n" +"_M.get = socket.protect(function(gett)\n" +" if base.type(gett) == \"string\" then return sget(gett)\n" +" else return tget(gett) end\n" +"end)\n" +"\n" +"return _M\n" +"\n"; + +/* socket.headers */ +static const char *lua_m_socket_headers = +"-----------------------------------------------------------------------------\n" +"-- Canonic header field capitalization\n" +"-- LuaSocket toolkit.\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"local socket = require(\"socket.socket\")\n" +"socket.headers = {}\n" +"local _M = socket.headers\n" +"\n" +"_M.canonic = {\n" +" [\"accept\"] = \"Accept\",\n" +" [\"accept-charset\"] = \"Accept-Charset\",\n" +" [\"accept-encoding\"] = \"Accept-Encoding\",\n" +" [\"accept-language\"] = \"Accept-Language\",\n" +" [\"accept-ranges\"] = \"Accept-Ranges\",\n" +" [\"action\"] = \"Action\",\n" +" [\"alternate-recipient\"] = \"Alternate-Recipient\",\n" +" [\"age\"] = \"Age\",\n" +" [\"allow\"] = \"Allow\",\n" +" [\"arrival-date\"] = \"Arrival-Date\",\n" +" [\"authorization\"] = \"Authorization\",\n" +" [\"bcc\"] = \"Bcc\",\n" +" [\"cache-control\"] = \"Cache-Control\",\n" +" [\"cc\"] = \"Cc\",\n" +" [\"comments\"] = \"Comments\",\n" +" [\"connection\"] = \"Connection\",\n" +" [\"content-description\"] = \"Content-Description\",\n" +" [\"content-disposition\"] = \"Content-Disposition\",\n" +" [\"content-encoding\"] = \"Content-Encoding\",\n" +" [\"content-id\"] = \"Content-ID\",\n" +" [\"content-language\"] = \"Content-Language\",\n" +" [\"content-length\"] = \"Content-Length\",\n" +" [\"content-location\"] = \"Content-Location\",\n" +" [\"content-md5\"] = \"Content-MD5\",\n" +" [\"content-range\"] = \"Content-Range\",\n" +" [\"content-transfer-encoding\"] = \"Content-Transfer-Encoding\",\n" +" [\"content-type\"] = \"Content-Type\",\n" +" [\"cookie\"] = \"Cookie\",\n" +" [\"date\"] = \"Date\",\n" +" [\"diagnostic-code\"] = \"Diagnostic-Code\",\n" +" [\"dsn-gateway\"] = \"DSN-Gateway\",\n" +" [\"etag\"] = \"ETag\",\n" +" [\"expect\"] = \"Expect\",\n" +" [\"expires\"] = \"Expires\",\n" +" [\"final-log-id\"] = \"Final-Log-ID\",\n" +" [\"final-recipient\"] = \"Final-Recipient\",\n" +" [\"from\"] = \"From\",\n" +" [\"host\"] = \"Host\",\n" +" [\"if-match\"] = \"If-Match\",\n" +" [\"if-modified-since\"] = \"If-Modified-Since\",\n" +" [\"if-none-match\"] = \"If-None-Match\",\n" +" [\"if-range\"] = \"If-Range\",\n" +" [\"if-unmodified-since\"] = \"If-Unmodified-Since\",\n" +" [\"in-reply-to\"] = \"In-Reply-To\",\n" +" [\"keywords\"] = \"Keywords\",\n" +" [\"last-attempt-date\"] = \"Last-Attempt-Date\",\n" +" [\"last-modified\"] = \"Last-Modified\",\n" +" [\"location\"] = \"Location\",\n" +" [\"max-forwards\"] = \"Max-Forwards\",\n" +" [\"message-id\"] = \"Message-ID\",\n" +" [\"mime-version\"] = \"MIME-Version\",\n" +" [\"original-envelope-id\"] = \"Original-Envelope-ID\",\n" +" [\"original-recipient\"] = \"Original-Recipient\",\n" +" [\"pragma\"] = \"Pragma\",\n" +" [\"proxy-authenticate\"] = \"Proxy-Authenticate\",\n" +" [\"proxy-authorization\"] = \"Proxy-Authorization\",\n" +" [\"range\"] = \"Range\",\n" +" [\"received\"] = \"Received\",\n" +" [\"received-from-mta\"] = \"Received-From-MTA\",\n" +" [\"references\"] = \"References\",\n" +" [\"referer\"] = \"Referer\",\n" +" [\"remote-mta\"] = \"Remote-MTA\",\n" +" [\"reply-to\"] = \"Reply-To\",\n" +" [\"reporting-mta\"] = \"Reporting-MTA\",\n" +" [\"resent-bcc\"] = \"Resent-Bcc\",\n" +" [\"resent-cc\"] = \"Resent-Cc\",\n" +" [\"resent-date\"] = \"Resent-Date\",\n" +" [\"resent-from\"] = \"Resent-From\",\n" +" [\"resent-message-id\"] = \"Resent-Message-ID\",\n" +" [\"resent-reply-to\"] = \"Resent-Reply-To\",\n" +" [\"resent-sender\"] = \"Resent-Sender\",\n" +" [\"resent-to\"] = \"Resent-To\",\n" +" [\"retry-after\"] = \"Retry-After\",\n" +" [\"return-path\"] = \"Return-Path\",\n" +" [\"sender\"] = \"Sender\",\n" +" [\"server\"] = \"Server\",\n" +" [\"smtp-remote-recipient\"] = \"SMTP-Remote-Recipient\",\n" +" [\"status\"] = \"Status\",\n" +" [\"subject\"] = \"Subject\",\n" +" [\"te\"] = \"TE\",\n" +" [\"to\"] = \"To\",\n" +" [\"trailer\"] = \"Trailer\",\n" +" [\"transfer-encoding\"] = \"Transfer-Encoding\",\n" +" [\"upgrade\"] = \"Upgrade\",\n" +" [\"user-agent\"] = \"User-Agent\",\n" +" [\"vary\"] = \"Vary\",\n" +" [\"via\"] = \"Via\",\n" +" [\"warning\"] = \"Warning\",\n" +" [\"will-retry-until\"] = \"Will-Retry-Until\",\n" +" [\"www-authenticate\"] = \"WWW-Authenticate\",\n" +" [\"x-mailer\"] = \"X-Mailer\",\n" +"}\n" +"\n" +"return _M\n" +"\n"; + +/* socket.http */ +static const char *lua_m_socket_http = +"-----------------------------------------------------------------------------\n" +"-- HTTP/1.1 client support for the Lua language.\n" +"-- LuaSocket toolkit.\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module and import dependencies\n" +"-------------------------------------------------------------------------------\n" +"local socket = require(\"socket.socket\")\n" +"local url = require(\"socket.url\")\n" +"local ltn12 = require(\"socket.ltn12\")\n" +"local mime = require(\"socket.mime\")\n" +"local string = require(\"string\")\n" +"local headers = require(\"socket.headers\")\n" +"local base = _G\n" +"local table = require(\"table\")\n" +"socket.http = {}\n" +"local _M = socket.http\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Program constants\n" +"-----------------------------------------------------------------------------\n" +"-- connection timeout in seconds\n" +"TIMEOUT = 60\n" +"-- default port for document retrieval\n" +"_M.PORT = 80\n" +"-- user agent field sent in request\n" +"_M.USERAGENT = socket._VERSION\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Reads MIME headers from a connection, unfolding where needed\n" +"-----------------------------------------------------------------------------\n" +"local function receiveheaders(sock, headers)\n" +" local line, name, value, err\n" +" headers = headers or {}\n" +" -- get first line\n" +" line, err = sock:receive()\n" +" if err then return nil, err end\n" +" -- headers go until a blank line is found\n" +" while line ~= \"\" do\n" +" -- get field-name and value\n" +" name, value = socket.skip(2, string.find(line, \"^(.-):%s*(.*)\"))\n" +" if not (name and value) then return nil, \"malformed reponse headers\" end\n" +" name = string.lower(name)\n" +" -- get next line (value might be folded)\n" +" line, err = sock:receive()\n" +" if err then return nil, err end\n" +" -- unfold any folded values\n" +" while string.find(line, \"^%s\") do\n" +" value = value .. line\n" +" line = sock:receive()\n" +" if err then return nil, err end\n" +" end\n" +" -- save pair in table\n" +" if headers[name] then headers[name] = headers[name] .. \", \" .. value\n" +" else headers[name] = value end\n" +" end\n" +" return headers\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Extra sources and sinks\n" +"-----------------------------------------------------------------------------\n" +"socket.sourcet[\"http-chunked\"] = function(sock, headers)\n" +" return base.setmetatable({\n" +" getfd = function() return sock:getfd() end,\n" +" dirty = function() return sock:dirty() end\n" +" }, {\n" +" __call = function()\n" +" -- get chunk size, skip extention\n" +" local line, err = sock:receive()\n" +" if err then return nil, err end\n" +" local size = base.tonumber(string.gsub(line, \";.*\", \"\"), 16)\n" +" if not size then return nil, \"invalid chunk size\" end\n" +" -- was it the last chunk?\n" +" if size > 0 then\n" +" -- if not, get chunk and skip terminating CRLF\n" +" local chunk, err, part = sock:receive(size)\n" +" if chunk then sock:receive() end\n" +" return chunk, err\n" +" else\n" +" -- if it was, read trailers into headers table\n" +" headers, err = receiveheaders(sock, headers)\n" +" if not headers then return nil, err end\n" +" end\n" +" end\n" +" })\n" +"end\n" +"\n" +"socket.sinkt[\"http-chunked\"] = function(sock)\n" +" return base.setmetatable({\n" +" getfd = function() return sock:getfd() end,\n" +" dirty = function() return sock:dirty() end\n" +" }, {\n" +" __call = function(self, chunk, err)\n" +" if not chunk then return sock:send(\"0\\r\\n\\r\\n\") end\n" +" local size = string.format(\"%X\\r\\n\", string.len(chunk))\n" +" return sock:send(size .. chunk .. \"\\r\\n\")\n" +" end\n" +" })\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Low level HTTP API\n" +"-----------------------------------------------------------------------------\n" +"local metat = { __index = {} }\n" +"\n" +"function _M.open(host, port, create)\n" +" -- create socket with user connect function, or with default\n" +" local c = socket.try((create or socket.tcp)())\n" +" local h = base.setmetatable({ c = c }, metat)\n" +" -- create finalized try\n" +" h.try = socket.newtry(function() h:close() end)\n" +" -- set timeout before connecting\n" +" h.try(c:settimeout(_M.TIMEOUT))\n" +" h.try(c:connect(host, port or _M.PORT))\n" +" -- here everything worked\n" +" return h\n" +"end\n" +"\n" +"function metat.__index:sendrequestline(method, uri)\n" +" local reqline = string.format(\"%s %s HTTP/1.1\\r\\n\", method or \"GET\", uri)\n" +" return self.try(self.c:send(reqline))\n" +"end\n" +"\n" +"function metat.__index:sendheaders(tosend)\n" +" local canonic = headers.canonic\n" +" local h = \"\\r\\n\"\n" +" for f, v in base.pairs(tosend) do\n" +" h = (canonic[f] or f) .. \": \" .. v .. \"\\r\\n\" .. h\n" +" end\n" +" self.try(self.c:send(h))\n" +" return 1\n" +"end\n" +"\n" +"function metat.__index:sendbody(headers, source, step)\n" +" source = source or ltn12.source.empty()\n" +" step = step or ltn12.pump.step\n" +" -- if we don't know the size in advance, send chunked and hope for the best\n" +" local mode = \"http-chunked\"\n" +" if headers[\"content-length\"] then mode = \"keep-open\" end\n" +" return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))\n" +"end\n" +"\n" +"function metat.__index:receivestatusline()\n" +" local status = self.try(self.c:receive(5))\n" +" -- identify HTTP/0.9 responses, which do not contain a status line\n" +" -- this is just a heuristic, but is what the RFC recommends\n" +" if status ~= \"HTTP/\" then return nil, status end\n" +" -- otherwise proceed reading a status line\n" +" status = self.try(self.c:receive(\"*l\", status))\n" +" local code = socket.skip(2, string.find(status, \"HTTP/%d*%.%d* (%d%d%d)\"))\n" +" return self.try(base.tonumber(code), status)\n" +"end\n" +"\n" +"function metat.__index:receiveheaders()\n" +" return self.try(receiveheaders(self.c))\n" +"end\n" +"\n" +"function metat.__index:receivebody(headers, sink, step)\n" +" sink = sink or ltn12.sink.null()\n" +" step = step or ltn12.pump.step\n" +" local length = base.tonumber(headers[\"content-length\"])\n" +" local t = headers[\"transfer-encoding\"] -- shortcut\n" +" local mode = \"default\" -- connection close\n" +" if t and t ~= \"identity\" then mode = \"http-chunked\"\n" +" elseif base.tonumber(headers[\"content-length\"]) then mode = \"by-length\" end\n" +" return self.try(ltn12.pump.all(socket.source(mode, self.c, length),\n" +" sink, step))\n" +"end\n" +"\n" +"function metat.__index:receive09body(status, sink, step)\n" +" local source = ltn12.source.rewind(socket.source(\"until-closed\", self.c))\n" +" source(status)\n" +" return self.try(ltn12.pump.all(source, sink, step))\n" +"end\n" +"\n" +"function metat.__index:close()\n" +" return self.c:close()\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- High level HTTP API\n" +"-----------------------------------------------------------------------------\n" +"local function adjusturi(reqt)\n" +" local u = reqt\n" +" -- if there is a proxy, we need the full url. otherwise, just a part.\n" +" if not reqt.proxy and not PROXY then\n" +" u = {\n" +" path = socket.try(reqt.path, \"invalid path 'nil'\"),\n" +" params = reqt.params,\n" +" query = reqt.query,\n" +" fragment = reqt.fragment\n" +" }\n" +" end\n" +" return url.build(u)\n" +"end\n" +"\n" +"local function adjustproxy(reqt)\n" +" local proxy = reqt.proxy or PROXY\n" +" if proxy then\n" +" proxy = url.parse(proxy)\n" +" return proxy.host, proxy.port or 3128\n" +" else\n" +" return reqt.host, reqt.port\n" +" end\n" +"end\n" +"\n" +"local function adjustheaders(reqt)\n" +" -- default headers\n" +" local lower = {\n" +" [\"user-agent\"] = _M.USERAGENT,\n" +" [\"host\"] = reqt.host,\n" +" [\"connection\"] = \"close, TE\",\n" +" [\"te\"] = \"trailers\"\n" +" }\n" +" -- if we have authentication information, pass it along\n" +" if reqt.user and reqt.password then\n" +" lower[\"authorization\"] =\n" +" \"Basic \" .. (mime.b64(reqt.user .. \":\" .. reqt.password))\n" +" end\n" +" -- override with user headers\n" +" for i,v in base.pairs(reqt.headers or lower) do\n" +" lower[string.lower(i)] = v\n" +" end\n" +" return lower\n" +"end\n" +"\n" +"-- default url parts\n" +"local default = {\n" +" host = \"\",\n" +" port = _M.PORT,\n" +" path =\"/\",\n" +" scheme = \"http\"\n" +"}\n" +"\n" +"local function adjustrequest(reqt)\n" +" -- parse url if provided\n" +" local nreqt = reqt.url and url.parse(reqt.url, default) or {}\n" +" -- explicit components override url\n" +" for i,v in base.pairs(reqt) do nreqt[i] = v end\n" +" if nreqt.port == \"\" then nreqt.port = 80 end\n" +" socket.try(nreqt.host and nreqt.host ~= \"\",\n" +" \"invalid host '\" .. base.tostring(nreqt.host) .. \"'\")\n" +" -- compute uri if user hasn't overriden\n" +" nreqt.uri = reqt.uri or adjusturi(nreqt)\n" +" -- ajust host and port if there is a proxy\n" +" nreqt.host, nreqt.port = adjustproxy(nreqt)\n" +" -- adjust headers in request\n" +" nreqt.headers = adjustheaders(nreqt)\n" +" return nreqt\n" +"end\n" +"\n" +"local function shouldredirect(reqt, code, headers)\n" +" return headers.location and\n" +" string.gsub(headers.location, \"%s\", \"\") ~= \"\" and\n" +" (reqt.redirect ~= false) and\n" +" (code == 301 or code == 302 or code == 303 or code == 307) and\n" +" (not reqt.method or reqt.method == \"GET\" or reqt.method == \"HEAD\")\n" +" and (not reqt.nredirects or reqt.nredirects < 5)\n" +"end\n" +"\n" +"local function shouldreceivebody(reqt, code)\n" +" if reqt.method == \"HEAD\" then return nil end\n" +" if code == 204 or code == 304 then return nil end\n" +" if code >= 100 and code < 200 then return nil end\n" +" return 1\n" +"end\n" +"\n" +"-- forward declarations\n" +"local trequest, tredirect\n" +"\n" +"--[[local]] function tredirect(reqt, location)\n" +" local result, code, headers, status = trequest {\n" +" -- the RFC says the redirect URL has to be absolute, but some\n" +" -- servers do not respect that\n" +" url = url.absolute(reqt.url, location),\n" +" source = reqt.source,\n" +" sink = reqt.sink,\n" +" headers = reqt.headers,\n" +" proxy = reqt.proxy,\n" +" nredirects = (reqt.nredirects or 0) + 1,\n" +" create = reqt.create\n" +" }\n" +" -- pass location header back as a hint we redirected\n" +" headers = headers or {}\n" +" headers.location = headers.location or location\n" +" return result, code, headers, status\n" +"end\n" +"\n" +"--[[local]] function trequest(reqt)\n" +" -- we loop until we get what we want, or\n" +" -- until we are sure there is no way to get it\n" +" local nreqt = adjustrequest(reqt)\n" +" local h = _M.open(nreqt.host, nreqt.port, nreqt.create)\n" +" -- send request line and headers\n" +" h:sendrequestline(nreqt.method, nreqt.uri)\n" +" h:sendheaders(nreqt.headers)\n" +" -- if there is a body, send it\n" +" if nreqt.source then\n" +" h:sendbody(nreqt.headers, nreqt.source, nreqt.step)\n" +" end\n" +" local code, status = h:receivestatusline()\n" +" -- if it is an HTTP/0.9 server, simply get the body and we are done\n" +" if not code then\n" +" h:receive09body(status, nreqt.sink, nreqt.step)\n" +" return 1, 200\n" +" end\n" +" local headers\n" +" -- ignore any 100-continue messages\n" +" while code == 100 do\n" +" headers = h:receiveheaders()\n" +" code, status = h:receivestatusline()\n" +" end\n" +" headers = h:receiveheaders()\n" +" -- at this point we should have a honest reply from the server\n" +" -- we can't redirect if we already used the source, so we report the error\n" +" if shouldredirect(nreqt, code, headers) and not nreqt.source then\n" +" h:close()\n" +" return tredirect(reqt, headers.location)\n" +" end\n" +" -- here we are finally done\n" +" if shouldreceivebody(nreqt, code) then\n" +" h:receivebody(headers, nreqt.sink, nreqt.step)\n" +" end\n" +" h:close()\n" +" return 1, code, headers, status\n" +"end\n" +"\n" +"local function srequest(u, b)\n" +" local t = {}\n" +" local reqt = {\n" +" url = u,\n" +" sink = ltn12.sink.table(t)\n" +" }\n" +" if b then\n" +" reqt.source = ltn12.source.string(b)\n" +" reqt.headers = {\n" +" [\"content-length\"] = string.len(b),\n" +" [\"content-type\"] = \"application/x-www-form-urlencoded\"\n" +" }\n" +" reqt.method = \"POST\"\n" +" end\n" +" local code, headers, status = socket.skip(1, trequest(reqt))\n" +" return table.concat(t), code, headers, status\n" +"end\n" +"\n" +"_M.request = socket.protect(function(reqt, body)\n" +" if base.type(reqt) == \"string\" then return srequest(reqt, body)\n" +" else return trequest(reqt) end\n" +"end)\n" +"\n" +"return _M\n" +"\n"; + +/* socket.mbox */ +static const char *lua_m_socket_mbox = +"local _M = {}\n" +"\n" +"if module then\n" +" mbox = _M\n" +"end \n" +"\n" +"function _M.split_message(message_s)\n" +" local message = {}\n" +" message_s = string.gsub(message_s, \"\\r\\n\", \"\\n\")\n" +" string.gsub(message_s, \"^(.-\\n)\\n\", function (h) message.headers = h end)\n" +" string.gsub(message_s, \"^.-\\n\\n(.*)\", function (b) message.body = b end)\n" +" if not message.body then\n" +" string.gsub(message_s, \"^\\n(.*)\", function (b) message.body = b end)\n" +" end\n" +" if not message.headers and not message.body then\n" +" message.headers = message_s\n" +" end\n" +" return message.headers or \"\", message.body or \"\"\n" +"end\n" +"\n" +"function _M.split_headers(headers_s)\n" +" local headers = {}\n" +" headers_s = string.gsub(headers_s, \"\\r\\n\", \"\\n\")\n" +" headers_s = string.gsub(headers_s, \"\\n[ ]+\", \" \")\n" +" string.gsub(\"\\n\" .. headers_s, \"\\n([^\\n]+)\", function (h) table.insert(headers, h) end)\n" +" return headers\n" +"end\n" +"\n" +"function _M.parse_header(header_s)\n" +" header_s = string.gsub(header_s, \"\\n[ ]+\", \" \")\n" +" header_s = string.gsub(header_s, \"\\n+\", \"\")\n" +" local _, __, name, value = string.find(header_s, \"([^%s:]-):%s*(.*)\")\n" +" return name, value\n" +"end\n" +"\n" +"function _M.parse_headers(headers_s)\n" +" local headers_t = _M.split_headers(headers_s)\n" +" local headers = {}\n" +" for i = 1, #headers_t do\n" +" local name, value = _M.parse_header(headers_t[i])\n" +" if name then\n" +" name = string.lower(name)\n" +" if headers[name] then\n" +" headers[name] = headers[name] .. \", \" .. value\n" +" else headers[name] = value end\n" +" end\n" +" end\n" +" return headers\n" +"end\n" +"\n" +"function _M.parse_from(from)\n" +" local _, __, name, address = string.find(from, \"^%s*(.-)%s*%<(.-)%>\")\n" +" if not address then\n" +" _, __, address = string.find(from, \"%s*(.+)%s*\")\n" +" end\n" +" name = name or \"\"\n" +" address = address or \"\"\n" +" if name == \"\" then name = address end\n" +" name = string.gsub(name, '\"', \"\")\n" +" return name, address\n" +"end\n" +"\n" +"function _M.split_mbox(mbox_s)\n" +" mbox = {}\n" +" mbox_s = string.gsub(mbox_s, \"\\r\\n\", \"\\n\") ..\"\\n\\nFrom \\n\"\n" +" local nj, i, j = 1, 1, 1\n" +" while 1 do\n" +" i, nj = string.find(mbox_s, \"\\n\\nFrom .-\\n\", j)\n" +" if not i then break end\n" +" local message = string.sub(mbox_s, j, i-1)\n" +" table.insert(mbox, message)\n" +" j = nj+1\n" +" end\n" +" return mbox\n" +"end\n" +"\n" +"function _M.parse(mbox_s)\n" +" local mbox = _M.split_mbox(mbox_s)\n" +" for i = 1, #mbox do\n" +" mbox[i] = _M.parse_message(mbox[i])\n" +" end\n" +" return mbox\n" +"end\n" +"\n" +"function _M.parse_message(message_s)\n" +" local message = {}\n" +" message.headers, message.body = _M.split_message(message_s)\n" +" message.headers = _M.parse_headers(message.headers)\n" +" return message\n" +"end\n" +"\n" +"return _M\n" +"\n"; + +/* socket.smtp */ +static const char *lua_m_socket_smtp = +"-----------------------------------------------------------------------------\n" +"-- SMTP client support for the Lua language.\n" +"-- LuaSocket toolkit.\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module and import dependencies\n" +"-----------------------------------------------------------------------------\n" +"local base = _G\n" +"local coroutine = require(\"coroutine\")\n" +"local string = require(\"string\")\n" +"local math = require(\"math\")\n" +"local os = require(\"os\")\n" +"local socket = require(\"socket.socket\")\n" +"local tp = require(\"socket.tp\")\n" +"local ltn12 = require(\"socket.ltn12\")\n" +"local headers = require(\"socket.headers\")\n" +"local mime = require(\"socket.mime\")\n" +"\n" +"socket.smtp = {}\n" +"local _M = socket.smtp\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Program constants\n" +"-----------------------------------------------------------------------------\n" +"-- timeout for connection\n" +"_M.TIMEOUT = 60\n" +"-- default server used to send e-mails\n" +"_M.SERVER = \"localhost\"\n" +"-- default port\n" +"_M.PORT = 25\n" +"-- domain used in HELO command and default sendmail\n" +"-- If we are under a CGI, try to get from environment\n" +"_M.DOMAIN = os.getenv(\"SERVER_NAME\") or \"localhost\"\n" +"-- default time zone (means we don't know)\n" +"_M.ZONE = \"-0000\"\n" +"\n" +"---------------------------------------------------------------------------\n" +"-- Low level SMTP API\n" +"-----------------------------------------------------------------------------\n" +"local metat = { __index = {} }\n" +"\n" +"function metat.__index:greet(domain)\n" +" self.try(self.tp:check(\"2..\"))\n" +" self.try(self.tp:command(\"EHLO\", domain or _M.DOMAIN))\n" +" return socket.skip(1, self.try(self.tp:check(\"2..\")))\n" +"end\n" +"\n" +"function metat.__index:mail(from)\n" +" self.try(self.tp:command(\"MAIL\", \"FROM:\" .. from))\n" +" return self.try(self.tp:check(\"2..\"))\n" +"end\n" +"\n" +"function metat.__index:rcpt(to)\n" +" self.try(self.tp:command(\"RCPT\", \"TO:\" .. to))\n" +" return self.try(self.tp:check(\"2..\"))\n" +"end\n" +"\n" +"function metat.__index:data(src, step)\n" +" self.try(self.tp:command(\"DATA\"))\n" +" self.try(self.tp:check(\"3..\"))\n" +" self.try(self.tp:source(src, step))\n" +" self.try(self.tp:send(\"\\r\\n.\\r\\n\"))\n" +" return self.try(self.tp:check(\"2..\"))\n" +"end\n" +"\n" +"function metat.__index:quit()\n" +" self.try(self.tp:command(\"QUIT\"))\n" +" return self.try(self.tp:check(\"2..\"))\n" +"end\n" +"\n" +"function metat.__index:close()\n" +" return self.tp:close()\n" +"end\n" +"\n" +"function metat.__index:login(user, password)\n" +" self.try(self.tp:command(\"AUTH\", \"LOGIN\"))\n" +" self.try(self.tp:check(\"3..\"))\n" +" self.try(self.tp:send(mime.b64(user) .. \"\\r\\n\"))\n" +" self.try(self.tp:check(\"3..\"))\n" +" self.try(self.tp:send(mime.b64(password) .. \"\\r\\n\"))\n" +" return self.try(self.tp:check(\"2..\"))\n" +"end\n" +"\n" +"function metat.__index:plain(user, password)\n" +" local auth = \"PLAIN \" .. mime.b64(\"\\0\" .. user .. \"\\0\" .. password)\n" +" self.try(self.tp:command(\"AUTH\", auth))\n" +" return self.try(self.tp:check(\"2..\"))\n" +"end\n" +"\n" +"function metat.__index:auth(user, password, ext)\n" +" if not user or not password then return 1 end\n" +" if string.find(ext, \"AUTH[^\\n]+LOGIN\") then\n" +" return self:login(user, password)\n" +" elseif string.find(ext, \"AUTH[^\\n]+PLAIN\") then\n" +" return self:plain(user, password)\n" +" else\n" +" self.try(nil, \"authentication not supported\")\n" +" end\n" +"end\n" +"\n" +"-- send message or throw an exception\n" +"function metat.__index:send(mailt)\n" +" self:mail(mailt.from)\n" +" if base.type(mailt.rcpt) == \"table\" then\n" +" for i,v in base.ipairs(mailt.rcpt) do\n" +" self:rcpt(v)\n" +" end\n" +" else\n" +" self:rcpt(mailt.rcpt)\n" +" end\n" +" self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)\n" +"end\n" +"\n" +"function _M.open(server, port, create)\n" +" local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT,\n" +" _M.TIMEOUT, create))\n" +" local s = base.setmetatable({tp = tp}, metat)\n" +" -- make sure tp is closed if we get an exception\n" +" s.try = socket.newtry(function()\n" +" s:close()\n" +" end)\n" +" return s\n" +"end\n" +"\n" +"-- convert headers to lowercase\n" +"local function lower_headers(headers)\n" +" local lower = {}\n" +" for i,v in base.pairs(headers or lower) do\n" +" lower[string.lower(i)] = v\n" +" end\n" +" return lower\n" +"end\n" +"\n" +"---------------------------------------------------------------------------\n" +"-- Multipart message source\n" +"-----------------------------------------------------------------------------\n" +"-- returns a hopefully unique mime boundary\n" +"local seqno = 0\n" +"local function newboundary()\n" +" seqno = seqno + 1\n" +" return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),\n" +" math.random(0, 99999), seqno)\n" +"end\n" +"\n" +"-- send_message forward declaration\n" +"local send_message\n" +"\n" +"-- yield the headers all at once, it's faster\n" +"local function send_headers(tosend)\n" +" local canonic = headers.canonic\n" +" local h = \"\\r\\n\"\n" +" for f,v in base.pairs(tosend) do\n" +" h = (canonic[f] or f) .. ': ' .. v .. \"\\r\\n\" .. h\n" +" end\n" +" coroutine.yield(h)\n" +"end\n" +"\n" +"-- yield multipart message body from a multipart message table\n" +"local function send_multipart(mesgt)\n" +" -- make sure we have our boundary and send headers\n" +" local bd = newboundary()\n" +" local headers = lower_headers(mesgt.headers or {})\n" +" headers['content-type'] = headers['content-type'] or 'multipart/mixed'\n" +" headers['content-type'] = headers['content-type'] ..\n" +" '; boundary=\"' .. bd .. '\"'\n" +" send_headers(headers)\n" +" -- send preamble\n" +" if mesgt.body.preamble then\n" +" coroutine.yield(mesgt.body.preamble)\n" +" coroutine.yield(\"\\r\\n\")\n" +" end\n" +" -- send each part separated by a boundary\n" +" for i, m in base.ipairs(mesgt.body) do\n" +" coroutine.yield(\"\\r\\n--\" .. bd .. \"\\r\\n\")\n" +" send_message(m)\n" +" end\n" +" -- send last boundary\n" +" coroutine.yield(\"\\r\\n--\" .. bd .. \"--\\r\\n\\r\\n\")\n" +" -- send epilogue\n" +" if mesgt.body.epilogue then\n" +" coroutine.yield(mesgt.body.epilogue)\n" +" coroutine.yield(\"\\r\\n\")\n" +" end\n" +"end\n" +"\n" +"-- yield message body from a source\n" +"local function send_source(mesgt)\n" +" -- make sure we have a content-type\n" +" local headers = lower_headers(mesgt.headers or {})\n" +" headers['content-type'] = headers['content-type'] or\n" +" 'text/plain; charset=\"iso-8859-1\"'\n" +" send_headers(headers)\n" +" -- send body from source\n" +" while true do\n" +" local chunk, err = mesgt.body()\n" +" if err then coroutine.yield(nil, err)\n" +" elseif chunk then coroutine.yield(chunk)\n" +" else break end\n" +" end\n" +"end\n" +"\n" +"-- yield message body from a string\n" +"local function send_string(mesgt)\n" +" -- make sure we have a content-type\n" +" local headers = lower_headers(mesgt.headers or {})\n" +" headers['content-type'] = headers['content-type'] or\n" +" 'text/plain; charset=\"iso-8859-1\"'\n" +" send_headers(headers)\n" +" -- send body from string\n" +" coroutine.yield(mesgt.body)\n" +"end\n" +"\n" +"-- message source\n" +"function send_message(mesgt)\n" +" if base.type(mesgt.body) == \"table\" then send_multipart(mesgt)\n" +" elseif base.type(mesgt.body) == \"function\" then send_source(mesgt)\n" +" else send_string(mesgt) end\n" +"end\n" +"\n" +"-- set defaul headers\n" +"local function adjust_headers(mesgt)\n" +" local lower = lower_headers(mesgt.headers)\n" +" lower[\"date\"] = lower[\"date\"] or\n" +" os.date(\"!%a, %d %b %Y %H:%M:%S \") .. (mesgt.zone or _M.ZONE)\n" +" lower[\"x-mailer\"] = lower[\"x-mailer\"] or socket._VERSION\n" +" -- this can't be overriden\n" +" lower[\"mime-version\"] = \"1.0\"\n" +" return lower\n" +"end\n" +"\n" +"function _M.message(mesgt)\n" +" mesgt.headers = adjust_headers(mesgt)\n" +" -- create and return message source\n" +" local co = coroutine.create(function() send_message(mesgt) end)\n" +" return function()\n" +" local ret, a, b = coroutine.resume(co)\n" +" if ret then return a, b\n" +" else return nil, a end\n" +" end\n" +"end\n" +"\n" +"---------------------------------------------------------------------------\n" +"-- High level SMTP API\n" +"-----------------------------------------------------------------------------\n" +"_M.send = socket.protect(function(mailt)\n" +" local s = _M.open(mailt.server, mailt.port, mailt.create)\n" +" local ext = s:greet(mailt.domain)\n" +" s:auth(mailt.user, mailt.password, ext)\n" +" s:send(mailt)\n" +" s:quit()\n" +" return s:close()\n" +"end)\n" +"\n" +"return _M\n" +"\n"; + +/* socket.tp */ +static const char *lua_m_socket_tp = +"-----------------------------------------------------------------------------\n" +"-- Unified SMTP/FTP subsystem\n" +"-- LuaSocket toolkit.\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module and import dependencies\n" +"-----------------------------------------------------------------------------\n" +"local base = _G\n" +"local string = require(\"string\")\n" +"local socket = require(\"socket.socket\")\n" +"local ltn12 = require(\"socket.ltn12\")\n" +"\n" +"socket.tp = {}\n" +"local _M = socket.tp\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Program constants\n" +"-----------------------------------------------------------------------------\n" +"_M.TIMEOUT = 60\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Implementation\n" +"-----------------------------------------------------------------------------\n" +"-- gets server reply (works for SMTP and FTP)\n" +"local function get_reply(c)\n" +" local code, current, sep\n" +" local line, err = c:receive()\n" +" local reply = line\n" +" if err then return nil, err end\n" +" code, sep = socket.skip(2, string.find(line, \"^(%d%d%d)(.?)\"))\n" +" if not code then return nil, \"invalid server reply\" end\n" +" if sep == \"-\" then -- reply is multiline\n" +" repeat\n" +" line, err = c:receive()\n" +" if err then return nil, err end\n" +" current, sep = socket.skip(2, string.find(line, \"^(%d%d%d)(.?)\"))\n" +" reply = reply .. \"\\n\" .. line\n" +" -- reply ends with same code\n" +" until code == current and sep == \" \"\n" +" end\n" +" return code, reply\n" +"end\n" +"\n" +"-- metatable for sock object\n" +"local metat = { __index = {} }\n" +"\n" +"function metat.__index:check(ok)\n" +" local code, reply = get_reply(self.c)\n" +" if not code then return nil, reply end\n" +" if base.type(ok) ~= \"function\" then\n" +" if base.type(ok) == \"table\" then\n" +" for i, v in base.ipairs(ok) do\n" +" if string.find(code, v) then\n" +" return base.tonumber(code), reply\n" +" end\n" +" end\n" +" return nil, reply\n" +" else\n" +" if string.find(code, ok) then return base.tonumber(code), reply\n" +" else return nil, reply end\n" +" end\n" +" else return ok(base.tonumber(code), reply) end\n" +"end\n" +"\n" +"function metat.__index:command(cmd, arg)\n" +" cmd = string.upper(cmd)\n" +" if arg then\n" +" return self.c:send(cmd .. \" \" .. arg.. \"\\r\\n\")\n" +" else\n" +" return self.c:send(cmd .. \"\\r\\n\")\n" +" end\n" +"end\n" +"\n" +"function metat.__index:sink(snk, pat)\n" +" local chunk, err = c:receive(pat)\n" +" return snk(chunk, err)\n" +"end\n" +"\n" +"function metat.__index:send(data)\n" +" return self.c:send(data)\n" +"end\n" +"\n" +"function metat.__index:receive(pat)\n" +" return self.c:receive(pat)\n" +"end\n" +"\n" +"function metat.__index:getfd()\n" +" return self.c:getfd()\n" +"end\n" +"\n" +"function metat.__index:dirty()\n" +" return self.c:dirty()\n" +"end\n" +"\n" +"function metat.__index:getcontrol()\n" +" return self.c\n" +"end\n" +"\n" +"function metat.__index:source(source, step)\n" +" local sink = socket.sink(\"keep-open\", self.c)\n" +" local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)\n" +" return ret, err\n" +"end\n" +"\n" +"-- closes the underlying c\n" +"function metat.__index:close()\n" +" self.c:close()\n" +" return 1\n" +"end\n" +"\n" +"-- connect with server and return c object\n" +"function _M.connect(host, port, timeout, create)\n" +" local c, e = (create or socket.tcp)()\n" +" if not c then return nil, e end\n" +" c:settimeout(timeout or _M.TIMEOUT)\n" +" local r, e = c:connect(host, port)\n" +" if not r then\n" +" c:close()\n" +" return nil, e\n" +" end\n" +" return base.setmetatable({c = c}, metat)\n" +"end\n" +"\n" +"return _M\n" +"\n"; + +/* socket.url */ +static const char *lua_m_socket_url = +"-----------------------------------------------------------------------------\n" +"-- URI parsing, composition and relative URL resolution\n" +"-- LuaSocket toolkit.\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module\n" +"-----------------------------------------------------------------------------\n" +"local string = require(\"string\")\n" +"local base = _G\n" +"local table = require(\"table\")\n" +"local socket = require(\"socket.socket\")\n" +"\n" +"socket.url = {}\n" +"local _M = socket.url\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Module version\n" +"-----------------------------------------------------------------------------\n" +"_M._VERSION = \"URL 1.0.3\"\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Encodes a string into its escaped hexadecimal representation\n" +"-- Input\n" +"-- s: binary string to be encoded\n" +"-- Returns\n" +"-- escaped representation of string binary\n" +"-----------------------------------------------------------------------------\n" +"function _M.escape(s)\n" +" return (string.gsub(s, \"([^A-Za-z0-9_])\", function(c)\n" +" return string.format(\"%%%02x\", string.byte(c))\n" +" end))\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Protects a path segment, to prevent it from interfering with the\n" +"-- url parsing.\n" +"-- Input\n" +"-- s: binary string to be encoded\n" +"-- Returns\n" +"-- escaped representation of string binary\n" +"-----------------------------------------------------------------------------\n" +"local function make_set(t)\n" +" local s = {}\n" +" for i,v in base.ipairs(t) do\n" +" s[t[i]] = 1\n" +" end\n" +" return s\n" +"end\n" +"\n" +"-- these are allowed withing a path segment, along with alphanum\n" +"-- other characters must be escaped\n" +"local segment_set = make_set {\n" +" \"-\", \"_\", \".\", \"!\", \"~\", \"*\", \"'\", \"(\",\n" +" \")\", \":\", \"@\", \"&\", \"=\", \"+\", \"$\", \",\",\n" +"}\n" +"\n" +"local function protect_segment(s)\n" +" return string.gsub(s, \"([^A-Za-z0-9_])\", function (c)\n" +" if segment_set[c] then return c\n" +" else return string.format(\"%%%02x\", string.byte(c)) end\n" +" end)\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Encodes a string into its escaped hexadecimal representation\n" +"-- Input\n" +"-- s: binary string to be encoded\n" +"-- Returns\n" +"-- escaped representation of string binary\n" +"-----------------------------------------------------------------------------\n" +"function _M.unescape(s)\n" +" return (string.gsub(s, \"%%(%x%x)\", function(hex)\n" +" return string.char(base.tonumber(hex, 16))\n" +" end))\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Builds a path from a base path and a relative path\n" +"-- Input\n" +"-- base_path\n" +"-- relative_path\n" +"-- Returns\n" +"-- corresponding absolute path\n" +"-----------------------------------------------------------------------------\n" +"local function absolute_path(base_path, relative_path)\n" +" if string.sub(relative_path, 1, 1) == \"/\" then return relative_path end\n" +" local path = string.gsub(base_path, \"[^/]*$\", \"\")\n" +" path = path .. relative_path\n" +" path = string.gsub(path, \"([^/]*%./)\", function (s)\n" +" if s ~= \"./\" then return s else return \"\" end\n" +" end)\n" +" path = string.gsub(path, \"/%.$\", \"/\")\n" +" local reduced\n" +" while reduced ~= path do\n" +" reduced = path\n" +" path = string.gsub(reduced, \"([^/]*/%.%./)\", function (s)\n" +" if s ~= \"../../\" then return \"\" else return s end\n" +" end)\n" +" end\n" +" path = string.gsub(reduced, \"([^/]*/%.%.)$\", function (s)\n" +" if s ~= \"../..\" then return \"\" else return s end\n" +" end)\n" +" return path\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Parses a url and returns a table with all its parts according to RFC 2396\n" +"-- The following grammar describes the names given to the URL parts\n" +"-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>\n" +"-- <authority> ::= <userinfo>@<host>:<port>\n" +"-- <userinfo> ::= <user>[:<password>]\n" +"-- <path> :: = {<segment>/}<segment>\n" +"-- Input\n" +"-- url: uniform resource locator of request\n" +"-- default: table with default values for each field\n" +"-- Returns\n" +"-- table with the following fields, where RFC naming conventions have\n" +"-- been preserved:\n" +"-- scheme, authority, userinfo, user, password, host, port,\n" +"-- path, params, query, fragment\n" +"-- Obs:\n" +"-- the leading '/' in {/<path>} is considered part of <path>\n" +"-----------------------------------------------------------------------------\n" +"function _M.parse(url, default)\n" +" -- initialize default parameters\n" +" local parsed = {}\n" +" for i,v in base.pairs(default or parsed) do parsed[i] = v end\n" +" -- empty url is parsed to nil\n" +" if not url or url == \"\" then return nil, \"invalid url\" end\n" +" -- remove whitespace\n" +" -- url = string.gsub(url, \"%s\", \"\")\n" +" -- get fragment\n" +" url = string.gsub(url, \"#(.*)$\", function(f)\n" +" parsed.fragment = f\n" +" return \"\"\n" +" end)\n" +" -- get scheme\n" +" url = string.gsub(url, \"^([%w][%w%+%-%.]*)%:\",\n" +" function(s) parsed.scheme = s; return \"\" end)\n" +" -- get authority\n" +" url = string.gsub(url, \"^//([^/]*)\", function(n)\n" +" parsed.authority = n\n" +" return \"\"\n" +" end)\n" +" -- get query string\n" +" url = string.gsub(url, \"%?(.*)\", function(q)\n" +" parsed.query = q\n" +" return \"\"\n" +" end)\n" +" -- get params\n" +" url = string.gsub(url, \"%;(.*)\", function(p)\n" +" parsed.params = p\n" +" return \"\"\n" +" end)\n" +" -- path is whatever was left\n" +" if url ~= \"\" then parsed.path = url end\n" +" local authority = parsed.authority\n" +" if not authority then return parsed end\n" +" authority = string.gsub(authority,\"^([^@]*)@\",\n" +" function(u) parsed.userinfo = u; return \"\" end)\n" +" authority = string.gsub(authority, \":([^:%]]*)$\",\n" +" function(p) parsed.port = p; return \"\" end)\n" +" if authority ~= \"\" then\n" +" -- IPv6?\n" +" parsed.host = string.match(authority, \"^%[(.+)%]$\") or authority\n" +" end\n" +" local userinfo = parsed.userinfo\n" +" if not userinfo then return parsed end\n" +" userinfo = string.gsub(userinfo, \":([^:]*)$\",\n" +" function(p) parsed.password = p; return \"\" end)\n" +" parsed.user = userinfo\n" +" return parsed\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Rebuilds a parsed URL from its components.\n" +"-- Components are protected if any reserved or unallowed characters are found\n" +"-- Input\n" +"-- parsed: parsed URL, as returned by parse\n" +"-- Returns\n" +"-- a stringing with the corresponding URL\n" +"-----------------------------------------------------------------------------\n" +"function _M.build(parsed)\n" +" local ppath = _M.parse_path(parsed.path or \"\")\n" +" local url = _M.build_path(ppath)\n" +" if parsed.params then url = url .. \";\" .. parsed.params end\n" +" if parsed.query then url = url .. \"?\" .. parsed.query end\n" +" local authority = parsed.authority\n" +" if parsed.host then\n" +" authority = parsed.host\n" +" if string.find(authority, \":\") then -- IPv6?\n" +" authority = \"[\" .. authority .. \"]\"\n" +" end\n" +" if parsed.port then authority = authority .. \":\" .. parsed.port end\n" +" local userinfo = parsed.userinfo\n" +" if parsed.user then\n" +" userinfo = parsed.user\n" +" if parsed.password then\n" +" userinfo = userinfo .. \":\" .. parsed.password\n" +" end\n" +" end\n" +" if userinfo then authority = userinfo .. \"@\" .. authority end\n" +" end\n" +" if authority then url = \"//\" .. authority .. url end\n" +" if parsed.scheme then url = parsed.scheme .. \":\" .. url end\n" +" if parsed.fragment then url = url .. \"#\" .. parsed.fragment end\n" +" -- url = string.gsub(url, \"%s\", \"\")\n" +" return url\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Builds a absolute URL from a base and a relative URL according to RFC 2396\n" +"-- Input\n" +"-- base_url\n" +"-- relative_url\n" +"-- Returns\n" +"-- corresponding absolute url\n" +"-----------------------------------------------------------------------------\n" +"function _M.absolute(base_url, relative_url)\n" +" if base.type(base_url) == \"table\" then\n" +" base_parsed = base_url\n" +" base_url = _M.build(base_parsed)\n" +" else\n" +" base_parsed = _M.parse(base_url)\n" +" end\n" +" local relative_parsed = _M.parse(relative_url)\n" +" if not base_parsed then return relative_url\n" +" elseif not relative_parsed then return base_url\n" +" elseif relative_parsed.scheme then return relative_url\n" +" else\n" +" relative_parsed.scheme = base_parsed.scheme\n" +" if not relative_parsed.authority then\n" +" relative_parsed.authority = base_parsed.authority\n" +" if not relative_parsed.path then\n" +" relative_parsed.path = base_parsed.path\n" +" if not relative_parsed.params then\n" +" relative_parsed.params = base_parsed.params\n" +" if not relative_parsed.query then\n" +" relative_parsed.query = base_parsed.query\n" +" end\n" +" end\n" +" else\n" +" relative_parsed.path = absolute_path(base_parsed.path or \"\",\n" +" relative_parsed.path)\n" +" end\n" +" end\n" +" return _M.build(relative_parsed)\n" +" end\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Breaks a path into its segments, unescaping the segments\n" +"-- Input\n" +"-- path\n" +"-- Returns\n" +"-- segment: a table with one entry per segment\n" +"-----------------------------------------------------------------------------\n" +"function _M.parse_path(path)\n" +" local parsed = {}\n" +" path = path or \"\"\n" +" --path = string.gsub(path, \"%s\", \"\")\n" +" string.gsub(path, \"([^/]+)\", function (s) table.insert(parsed, s) end)\n" +" for i = 1, #parsed do\n" +" parsed[i] = _M.unescape(parsed[i])\n" +" end\n" +" if string.sub(path, 1, 1) == \"/\" then parsed.is_absolute = 1 end\n" +" if string.sub(path, -1, -1) == \"/\" then parsed.is_directory = 1 end\n" +" return parsed\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Builds a path component from its segments, escaping protected characters.\n" +"-- Input\n" +"-- parsed: path segments\n" +"-- unsafe: if true, segments are not protected before path is built\n" +"-- Returns\n" +"-- path: corresponding path stringing\n" +"-----------------------------------------------------------------------------\n" +"function _M.build_path(parsed, unsafe)\n" +" local path = \"\"\n" +" local n = #parsed\n" +" if unsafe then\n" +" for i = 1, n-1 do\n" +" path = path .. parsed[i]\n" +" path = path .. \"/\"\n" +" end\n" +" if n > 0 then\n" +" path = path .. parsed[n]\n" +" if parsed.is_directory then path = path .. \"/\" end\n" +" end\n" +" else\n" +" for i = 1, n-1 do\n" +" path = path .. protect_segment(parsed[i])\n" +" path = path .. \"/\"\n" +" end\n" +" if n > 0 then\n" +" path = path .. protect_segment(parsed[n])\n" +" if parsed.is_directory then path = path .. \"/\" end\n" +" end\n" +" end\n" +" if parsed.is_absolute then path = \"/\" .. path end\n" +" return path\n" +"end\n" +"\n" +"return _M\n" +"\n"; + +/* socket */ +static const char *lua_m_socket = +"-----------------------------------------------------------------------------\n" +"-- LuaSocket helper module\n" +"-- Author: Diego Nehab\n" +"-----------------------------------------------------------------------------\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Declare module and import dependencies\n" +"-----------------------------------------------------------------------------\n" +"local base = _G\n" +"local string = require(\"string\")\n" +"local math = require(\"math\")\n" +"local socket = require(\"socket.core\")\n" +"\n" +"local _M = socket\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Exported auxiliar functions\n" +"-----------------------------------------------------------------------------\n" +"function _M.connect4(address, port, laddress, lport)\n" +" return socket.connect(address, port, laddress, lport, \"inet\")\n" +"end\n" +"\n" +"function _M.connect6(address, port, laddress, lport)\n" +" return socket.connect(address, port, laddress, lport, \"inet6\")\n" +"end\n" +"\n" +"function _M.bind(host, port, backlog)\n" +" if host == \"*\" then host = \"0.0.0.0\" end\n" +" local addrinfo, err = socket.dns.getaddrinfo(host);\n" +" if not addrinfo then return nil, err end\n" +" local sock, res\n" +" err = \"no info on address\"\n" +" for i, alt in base.ipairs(addrinfo) do\n" +" if alt.family == \"inet\" then\n" +" sock, err = socket.tcp()\n" +" else\n" +" sock, err = socket.tcp6()\n" +" end\n" +" if not sock then return nil, err end\n" +" sock:setoption(\"reuseaddr\", true)\n" +" res, err = sock:bind(alt.addr, port)\n" +" if not res then \n" +" sock:close()\n" +" else \n" +" res, err = sock:listen(backlog)\n" +" if not res then \n" +" sock:close()\n" +" else\n" +" return sock\n" +" end\n" +" end \n" +" end\n" +" return nil, err\n" +"end\n" +"\n" +"_M.try = _M.newtry()\n" +"\n" +"function _M.choose(table)\n" +" return function(name, opt1, opt2)\n" +" if base.type(name) ~= \"string\" then\n" +" name, opt1, opt2 = \"default\", name, opt1\n" +" end\n" +" local f = table[name or \"nil\"]\n" +" if not f then base.error(\"unknown key (\".. base.tostring(name) ..\")\", 3)\n" +" else return f(opt1, opt2) end\n" +" end\n" +"end\n" +"\n" +"-----------------------------------------------------------------------------\n" +"-- Socket sources and sinks, conforming to LTN12\n" +"-----------------------------------------------------------------------------\n" +"-- create namespaces inside LuaSocket namespace\n" +"local sourcet, sinkt = {}, {}\n" +"_M.sourcet = sourcet\n" +"_M.sinkt = sinkt\n" +"\n" +"_M.BLOCKSIZE = 2048\n" +"\n" +"sinkt[\"close-when-done\"] = function(sock)\n" +" return base.setmetatable({\n" +" getfd = function() return sock:getfd() end,\n" +" dirty = function() return sock:dirty() end\n" +" }, {\n" +" __call = function(self, chunk, err)\n" +" if not chunk then\n" +" sock:close()\n" +" return 1\n" +" else return sock:send(chunk) end\n" +" end\n" +" })\n" +"end\n" +"\n" +"sinkt[\"keep-open\"] = function(sock)\n" +" return base.setmetatable({\n" +" getfd = function() return sock:getfd() end,\n" +" dirty = function() return sock:dirty() end\n" +" }, {\n" +" __call = function(self, chunk, err)\n" +" if chunk then return sock:send(chunk)\n" +" else return 1 end\n" +" end\n" +" })\n" +"end\n" +"\n" +"sinkt[\"default\"] = sinkt[\"keep-open\"]\n" +"\n" +"_M.sink = _M.choose(sinkt)\n" +"\n" +"sourcet[\"by-length\"] = function(sock, length)\n" +" return base.setmetatable({\n" +" getfd = function() return sock:getfd() end,\n" +" dirty = function() return sock:dirty() end\n" +" }, {\n" +" __call = function()\n" +" if length <= 0 then return nil end\n" +" local size = math.min(socket.BLOCKSIZE, length)\n" +" local chunk, err = sock:receive(size)\n" +" if err then return nil, err end\n" +" length = length - string.len(chunk)\n" +" return chunk\n" +" end\n" +" })\n" +"end\n" +"\n" +"sourcet[\"until-closed\"] = function(sock)\n" +" local done\n" +" return base.setmetatable({\n" +" getfd = function() return sock:getfd() end,\n" +" dirty = function() return sock:dirty() end\n" +" }, {\n" +" __call = function()\n" +" if done then return nil end\n" +" local chunk, err, partial = sock:receive(socket.BLOCKSIZE)\n" +" if not err then return chunk\n" +" elseif err == \"closed\" then\n" +" sock:close()\n" +" done = 1\n" +" return partial\n" +" else return nil, err end\n" +" end\n" +" })\n" +"end\n" +"\n" +"\n" +"sourcet[\"default\"] = sourcet[\"until-closed\"]\n" +"\n" +"_M.source = _M.choose(sourcet)\n" +"\n" +"return _M\n" +"\n"; + + + +int luaopen_lua_m_ltn12(lua_State *L) { + luaL_loadstring(L, lua_m_ltn12); + return 1; +} + + +int luaopen_lua_m_mime(lua_State *L) { + luaL_loadstring(L, lua_m_mime); + return 1; +} + + +int luaopen_lua_m_socket_ftp(lua_State *L) { + luaL_loadstring(L, lua_m_socket_ftp); + return 1; +} + + +int luaopen_lua_m_socket_headers(lua_State *L) { + luaL_loadstring(L, lua_m_socket_headers); + return 1; +} + + +int luaopen_lua_m_socket_http(lua_State *L) { + luaL_loadstring(L, lua_m_socket_http); + return 1; +} + + +int luaopen_lua_m_socket_mbox(lua_State *L) { + luaL_loadstring(L, lua_m_socket_mbox); + return 1; +} + + +int luaopen_lua_m_socket_smtp(lua_State *L) { + luaL_loadstring(L, lua_m_socket_smtp); + return 1; +} + + +int luaopen_lua_m_socket_tp(lua_State *L) { + luaL_loadstring(L, lua_m_socket_tp); + return 1; +} + + +int luaopen_lua_m_socket_url(lua_State *L) { + luaL_loadstring(L, lua_m_socket_url); + return 1; +} + + +int luaopen_lua_m_socket(lua_State *L) { + luaL_loadstring(L, lua_m_socket); + return 1; +} + + +static luaL_Reg luasocket_scripts_modules[] = { + {"ltn12", luaopen_lua_m_ltn12}, + {"mime", luaopen_lua_m_mime}, + {"socket.ftp", luaopen_lua_m_socket_ftp}, + {"socket.headers", luaopen_lua_m_socket_headers}, + {"socket.http", luaopen_lua_m_socket_http}, + {"socket.mbox", luaopen_lua_m_socket_mbox}, + {"socket.smtp", luaopen_lua_m_socket_smtp}, + {"socket.tp", luaopen_lua_m_socket_tp}, + {"socket.url", luaopen_lua_m_socket_url}, + {"socket", luaopen_lua_m_socket}, + {NULL, NULL} +}; + +void luaopen_luasocket_scripts(lua_State* L) +{ + luaL_Reg* lib = luasocket_scripts_modules; + lua_getglobal(L, "package"); + lua_getfield(L, -1, "preload"); + for (; lib->func; lib++) + { + lib->func(L); + lua_setfield(L, -2, lib->name); + } + lua_pop(L, 2); +} diff --git a/ThirdParty/tolua_runtime/luasocket/luasocket_scripts.h b/ThirdParty/tolua_runtime/luasocket/luasocket_scripts.h new file mode 100644 index 0000000..dfc47eb --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/luasocket_scripts.h @@ -0,0 +1,32 @@ + +/* luasocket_scripts.h.h */ + +#ifndef __LUA_MODULES_606BA1C00D116CA81B695C141D124DB7_H_ +#define __LUA_MODULES_606BA1C00D116CA81B695C141D124DB7_H_ + +#if __cplusplus +extern "C" { +#endif + +#include "lua.h" + +void luaopen_luasocket_scripts(lua_State* L); + +/* +int luaopen_lua_m_ltn12(lua_State* L); +int luaopen_lua_m_mime(lua_State* L); +int luaopen_lua_m_socket_ftp(lua_State* L); +int luaopen_lua_m_socket_headers(lua_State* L); +int luaopen_lua_m_socket_http(lua_State* L); +int luaopen_lua_m_socket_mbox(lua_State* L); +int luaopen_lua_m_socket_smtp(lua_State* L); +int luaopen_lua_m_socket_tp(lua_State* L); +int luaopen_lua_m_socket_url(lua_State* L); +int luaopen_lua_m_socket(lua_State* L); +*/ + +#if __cplusplus +} +#endif + +#endif /* __LUA_MODULES_606BA1C00D116CA81B695C141D124DB7_H_ */ diff --git a/ThirdParty/tolua_runtime/luasocket/mime.c b/ThirdParty/tolua_runtime/luasocket/mime.c new file mode 100644 index 0000000..ed44104 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/mime.c @@ -0,0 +1,721 @@ +/*=========================================================================*\ +* MIME support functions +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "mime.h" + +/*=========================================================================*\ +* Don't want to trust escape character constants +\*=========================================================================*/ +typedef unsigned char UC; +static const char CRLF[] = "\r\n"; +static const char EQCRLF[] = "=\r\n"; + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int mime_global_wrp(lua_State *L); +static int mime_global_b64(lua_State *L); +static int mime_global_unb64(lua_State *L); +static int mime_global_qp(lua_State *L); +static int mime_global_unqp(lua_State *L); +static int mime_global_qpwrp(lua_State *L); +static int mime_global_eol(lua_State *L); +static int mime_global_dot(lua_State *L); + +static size_t dot(int c, size_t state, luaL_Buffer *buffer); +static void b64setup(UC *base); +static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); + +static void qpsetup(UC *class, UC *unbase); +static void qpquote(UC c, luaL_Buffer *buffer); +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer); +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); + +/* code support functions */ +static luaL_Reg func[] = { + { "dot", mime_global_dot }, + { "b64", mime_global_b64 }, + { "eol", mime_global_eol }, + { "qp", mime_global_qp }, + { "qpwrp", mime_global_qpwrp }, + { "unb64", mime_global_unb64 }, + { "unqp", mime_global_unqp }, + { "wrp", mime_global_wrp }, + { NULL, NULL } +}; + +/*-------------------------------------------------------------------------*\ +* Quoted-printable globals +\*-------------------------------------------------------------------------*/ +static UC qpclass[256]; +static UC qpbase[] = "0123456789ABCDEF"; +static UC qpunbase[256]; +enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; + +/*-------------------------------------------------------------------------*\ +* Base64 globals +\*-------------------------------------------------------------------------*/ +static const UC b64base[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static UC b64unbase[256]; + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +MIME_API int luaopen_mime_core(lua_State *L) +{ + lua_newtable(L); + luaL_setfuncs(L, func, 0); + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, MIME_VERSION); + lua_rawset(L, -3); + /* initialize lookup tables */ + qpsetup(qpclass, qpunbase); + b64setup(b64unbase); + return 1; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Incrementaly breaks a string into lines. The string can have CRLF breaks. +* A, n = wrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +\*-------------------------------------------------------------------------*/ +static int mime_global_wrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end of input black-hole */ + if (!input) { + /* if last line has not been terminated, add a line break */ + if (left < length) lua_pushstring(L, CRLF); + /* otherwise, we are done */ + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + luaL_addstring(&buffer, CRLF); + left = length; + break; + default: + if (left <= 0) { + left = length; + luaL_addstring(&buffer, CRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Fill base64 decode map. +\*-------------------------------------------------------------------------*/ +static void b64setup(UC *unbase) +{ + int i; + for (i = 0; i <= 255; i++) unbase[i] = (UC) 255; + for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i; + unbase['='] = 0; +} + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 3 bytes are available. +* Translate the 3 bytes into Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64encode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + input[size++] = c; + if (size == 3) { + UC code[4]; + unsigned long value = 0; + value += input[0]; value <<= 8; + value += input[1]; value <<= 8; + value += input[2]; + code[3] = b64base[value & 0x3f]; value >>= 6; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + size = 0; + } + return size; +} + +/*-------------------------------------------------------------------------*\ +* Encodes the Base64 last 1 or 2 bytes and adds padding '=' +* Result, if any, is appended to buffer. +* Returns 0. +\*-------------------------------------------------------------------------*/ +static size_t b64pad(const UC *input, size_t size, + luaL_Buffer *buffer) +{ + unsigned long value = 0; + UC code[4] = {'=', '=', '=', '='}; + switch (size) { + case 1: + value = input[0] << 4; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + case 2: + value = input[0]; value <<= 8; + value |= input[1]; value <<= 2; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + default: + break; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 4 bytes are available. +* Translate the 4 bytes from Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64decode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + /* ignore invalid characters */ + if (b64unbase[c] > 64) return size; + input[size++] = c; + /* decode atom */ + if (size == 4) { + UC decoded[3]; + int valid, value = 0; + value = b64unbase[input[0]]; value <<= 6; + value |= b64unbase[input[1]]; value <<= 6; + value |= b64unbase[input[2]]; value <<= 6; + value |= b64unbase[input[3]]; + decoded[2] = (UC) (value & 0xff); value >>= 8; + decoded[1] = (UC) (value & 0xff); value >>= 8; + decoded[0] = (UC) value; + /* take care of paddding */ + valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; + luaL_addlstring(buffer, (char *) decoded, valid); + return 0; + /* need more data */ + } else return size; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies the Base64 transfer content encoding to a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 3. B has the remaining bytes of C .. D, *without* encoding. +* The easiest thing would be to concatenate the two strings and +* encode the result, but we can't afford that or Lua would dupplicate +* every chunk we received. +\*-------------------------------------------------------------------------*/ +static int mime_global_b64(lua_State *L) +{ + UC atom[3]; + size_t isize = 0, asize = 0; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + size_t osize = 0; + asize = b64pad(atom, asize, &buffer); + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process the second part */ + last = input + isize; + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally removes the Base64 transfer content encoding from a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 4. B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unb64(lua_State *L) +{ + UC atom[4]; + size_t isize = 0, asize = 0; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second is nil, we are done */ + if (!input) { + size_t osize = 0; + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise, process the rest of the input */ + last = input + isize; + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Quoted-printable encoding scheme +* all (except CRLF in text) can be =XX +* CLRL in not text must be =XX=XX +* 33 through 60 inclusive can be plain +* 62 through 126 inclusive can be plain +* 9 and 32 can be plain, unless in the end of a line, where must be =XX +* encoded lines must be no longer than 76 not counting CRLF +* soft line-break are =CRLF +* To encode one byte, we need to see the next two. +* Worst case is when we see a space, and wonder if a CRLF is comming +\*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*\ +* Split quoted-printable characters into classes +* Precompute reverse map for encoding +\*-------------------------------------------------------------------------*/ +static void qpsetup(UC *cl, UC *unbase) +{ + int i; + for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; + for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; + for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN; + cl['\t'] = QP_IF_LAST; + cl[' '] = QP_IF_LAST; + cl['\r'] = QP_CR; + for (i = 0; i < 256; i++) unbase[i] = 255; + unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2; + unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5; + unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8; + unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10; + unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12; + unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13; + unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15; + unbase['f'] = 15; +} + +/*-------------------------------------------------------------------------*\ +* Output one character in form =XX +\*-------------------------------------------------------------------------*/ +static void qpquote(UC c, luaL_Buffer *buffer) +{ + luaL_addchar(buffer, '='); + luaL_addchar(buffer, qpbase[c >> 4]); + luaL_addchar(buffer, qpbase[c & 0x0F]); +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer) +{ + input[size++] = c; + /* deal with all characters we can have */ + while (size > 0) { + switch (qpclass[input[0]]) { + /* might be the CR of a CRLF sequence */ + case QP_CR: + if (size < 2) return size; + if (input[1] == '\n') { + luaL_addstring(buffer, marker); + return 0; + } else qpquote(input[0], buffer); + break; + /* might be a space and that has to be quoted if last in line */ + case QP_IF_LAST: + if (size < 3) return size; + /* if it is the last, quote it and we are done */ + if (input[1] == '\r' && input[2] == '\n') { + qpquote(input[0], buffer); + luaL_addstring(buffer, marker); + return 0; + } else luaL_addchar(buffer, input[0]); + break; + /* might have to be quoted always */ + case QP_QUOTED: + qpquote(input[0], buffer); + break; + /* might never have to be quoted */ + default: + luaL_addchar(buffer, input[0]); + break; + } + input[0] = input[1]; input[1] = input[2]; + size--; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Deal with the final characters +\*-------------------------------------------------------------------------*/ +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) +{ + size_t i; + for (i = 0; i < size; i++) { + if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]); + else qpquote(input[i], buffer); + } + if (size > 0) luaL_addstring(buffer, EQCRLF); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally converts a string to quoted-printable +* A, B = qp(C, D, marker) +* Marker is the text to be used to replace CRLF sequences found in A. +* A is the encoded version of the largest prefix of C .. D that +* can be encoded without doubts. +* B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_qp(lua_State *L) +{ + + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 3); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + asize = qppad(atom, asize, &buffer); + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output the to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { + int d; + input[size++] = c; + /* deal with all characters we can deal */ + switch (input[0]) { + /* if we have an escape character */ + case '=': + if (size < 3) return size; + /* eliminate soft line break */ + if (input[1] == '\r' && input[2] == '\n') return 0; + /* decode quoted representation */ + c = qpunbase[input[1]]; d = qpunbase[input[2]]; + /* if it is an invalid, do not decode */ + if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); + else luaL_addchar(buffer, (char) ((c << 4) + d)); + return 0; + case '\r': + if (size < 2) return size; + if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); + return 0; + default: + if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) + luaL_addchar(buffer, input[0]); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally decodes a string in quoted-printable +* A, B = qp(C, D) +* A is the decoded version of the largest prefix of C .. D that +* can be decoded without doubts. +* B has the remaining bytes of C .. D, *without* decoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unqp(lua_State *L) +{ + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally breaks a quoted-printed string into lines +* A, n = qpwrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +* There are two complications: lines can't be broken in the middle +* of an encoded =XX, and there might be line breaks already +\*-------------------------------------------------------------------------*/ +static int mime_global_qpwrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + if (left < length) lua_pushstring(L, EQCRLF); + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + left = length; + luaL_addstring(&buffer, CRLF); + break; + case '=': + if (left <= 3) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + default: + if (left <= 1) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Here is what we do: \n, and \r are considered candidates for line +* break. We issue *one* new line marker if any of them is seen alone, or +* followed by a different one. That is, \n\n and \r\r will issue two +* end of line markers each, but \r\n, \n\r etc will only issue *one* +* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as +* probably other more obscure conventions. +* +* c is the current character being processed +* last is the previous character +\*-------------------------------------------------------------------------*/ +#define eolcandidate(c) (c == '\r' || c == '\n') +static int eolprocess(int c, int last, const char *marker, + luaL_Buffer *buffer) +{ + if (eolcandidate(c)) { + if (eolcandidate(last)) { + if (c == last) luaL_addstring(buffer, marker); + return 0; + } else { + luaL_addstring(buffer, marker); + return c; + } + } else { + luaL_addchar(buffer, (char) c); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Converts a string to uniform EOL convention. +* A, n = eol(o, B, marker) +* A is the converted version of the largest prefix of B that can be +* converted unambiguously. 'o' is the context returned by the previous +* call. 'n' is the new context. +\*-------------------------------------------------------------------------*/ +static int mime_global_eol(lua_State *L) +{ + int ctx = luaL_checkinteger(L, 1); + size_t isize = 0; + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + luaL_buffinit(L, &buffer); + /* end of input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 0); + return 2; + } + /* process all input */ + while (input < last) + ctx = eolprocess(*input++, ctx, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, ctx); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Takes one byte and stuff it if needed. +\*-------------------------------------------------------------------------*/ +static size_t dot(int c, size_t state, luaL_Buffer *buffer) +{ + luaL_addchar(buffer, (char) c); + switch (c) { + case '\r': + return 1; + case '\n': + return (state == 1)? 2: 0; + case '.': + if (state == 2) + luaL_addchar(buffer, '.'); + default: + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies smtp stuffing to a string +* A, n = dot(l, D) +\*-------------------------------------------------------------------------*/ +static int mime_global_dot(lua_State *L) +{ + size_t isize = 0, state = (size_t) luaL_checknumber(L, 1); + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 2); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) + state = dot(*input++, state, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, (lua_Number) state); + return 2; +} + diff --git a/ThirdParty/tolua_runtime/luasocket/mime.h b/ThirdParty/tolua_runtime/luasocket/mime.h new file mode 100644 index 0000000..99968a5 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/mime.h @@ -0,0 +1,29 @@ +#ifndef MIME_H +#define MIME_H +/*=========================================================================*\ +* Core MIME support +* LuaSocket toolkit +* +* This module provides functions to implement transfer content encodings +* and formatting conforming to RFC 2045. It is used by mime.lua, which +* provide a higher level interface to this functionality. +\*=========================================================================*/ +#include "lua.h" + +/*-------------------------------------------------------------------------*\ +* Current MIME library version +\*-------------------------------------------------------------------------*/ +#define MIME_VERSION "MIME 1.0.3" +#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab" +#define MIME_AUTHORS "Diego Nehab" + +/*-------------------------------------------------------------------------*\ +* This macro prefixes all exported API functions +\*-------------------------------------------------------------------------*/ +#ifndef MIME_API +#define MIME_API extern +#endif + +MIME_API int luaopen_mime_core(lua_State *L); + +#endif /* MIME_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/options.c b/ThirdParty/tolua_runtime/luasocket/options.c new file mode 100644 index 0000000..20f4c28 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/options.c @@ -0,0 +1,374 @@ +/*=========================================================================*\ +* Common option interface +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> + +#include "lauxlib.h" + +#include "auxiliar.h" +#include "options.h" +#include "inet.h" + + +/*=========================================================================*\ +* Internal functions prototypes +\*=========================================================================*/ +static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); +static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name); +static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); +static int opt_setint(lua_State *L, p_socket ps, int level, int name); +static int opt_getint(lua_State *L, p_socket ps, int level, int name); +static int opt_set(lua_State *L, p_socket ps, int level, int name, + void *val, int len); +static int opt_get(lua_State *L, p_socket ps, int level, int name, + void *val, int* len); + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Calls appropriate option handler +\*-------------------------------------------------------------------------*/ +int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps) +{ + const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) { + char msg[45]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); +} + +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) +{ + const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) { + char msg[45]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); +} + +/* enables reuse of local address */ +int opt_set_reuseaddr(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); +} + +int opt_get_reuseaddr(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); +} + +/* enables reuse of local port */ +int opt_set_reuseport(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); +} + +int opt_get_reuseport(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); +} + +/* disables the Naggle algorithm */ +int opt_set_tcp_nodelay(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); +} + +int opt_get_tcp_nodelay(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); +} + +int opt_set_keepalive(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); +} + +int opt_get_keepalive(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); +} + +int opt_set_dontroute(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); +} + +int opt_get_dontroute(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); +} + +int opt_set_broadcast(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); +} + +int opt_get_broadcast(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); +} + +int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); +} + +int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); +} + +int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); +} + +int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); +} + +int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +int opt_get_ip_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); +} + +int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); +} + +int opt_set_linger(lua_State *L, p_socket ps) +{ + struct linger li; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "on"); + lua_gettable(L, 3); + if (!lua_isboolean(L, -1)) + luaL_argerror(L, 3, "boolean 'on' field expected"); + li.l_onoff = (u_short) lua_toboolean(L, -1); + lua_pushstring(L, "timeout"); + lua_gettable(L, 3); + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 3, "number 'timeout' field expected"); + li.l_linger = (u_short) lua_tonumber(L, -1); + return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); +} + +int opt_get_linger(lua_State *L, p_socket ps) +{ + struct linger li; /* obj, name */ + int len = sizeof(li); + int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len); + if (err) + return err; + lua_newtable(L); + lua_pushboolean(L, li.l_onoff); + lua_setfield(L, -2, "on"); + lua_pushinteger(L, li.l_linger); + lua_setfield(L, -2, "timeout"); + return 1; +} + +int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); +} + +int opt_set_ip_multicast_if(lua_State *L, p_socket ps) +{ + const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ + struct in_addr val; + val.s_addr = htonl(INADDR_ANY); + if (strcmp(address, "*") && !inet_aton(address, &val)) + luaL_argerror(L, 3, "ip expected"); + return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF, + (char *) &val, sizeof(val)); +} + +int opt_get_ip_multicast_if(lua_State *L, p_socket ps) +{ + struct in_addr val; + socklen_t len = sizeof(val); + if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + lua_pushstring(L, inet_ntoa(val)); + return 1; +} + +int opt_set_ip_add_membership(lua_State *L, p_socket ps) +{ + return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); +} + +int opt_set_ip_drop_membersip(lua_State *L, p_socket ps) +{ + return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); +} + +int opt_set_ip6_add_membership(lua_State *L, p_socket ps) +{ + return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); +} + +int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps) +{ + return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); +} + +int opt_get_ip6_v6only(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); +} + +int opt_set_ip6_v6only(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); +} + +/*=========================================================================*\ +* Auxiliar functions +\*=========================================================================*/ +static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) +{ + struct ip_mreq val; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'multiaddr' field expected"); + if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'interface' field expected"); + val.imr_interface.s_addr = htonl(INADDR_ANY); + if (strcmp(lua_tostring(L, -1), "*") && + !inet_aton(lua_tostring(L, -1), &val.imr_interface)) + luaL_argerror(L, 3, "invalid 'interface' ip address"); + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + +static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name) +{ + struct ipv6_mreq val; /* obj, opt-name, table */ + memset(&val, 0, sizeof(val)); + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'multiaddr' field expected"); + if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 3); + /* By default we listen to interface on default route + * (sigh). However, interface= can override it. We should + * support either number, or name for it. Waiting for + * windows port of if_nametoindex */ + if (!lua_isnil(L, -1)) { + if (lua_isnumber(L, -1)) { + val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1); + } else + luaL_argerror(L, -1, "number 'interface' field expected"); + } + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + +static +int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) +{ + socklen_t socklen = *len; + if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + *len = socklen; + return 0; +} + +static +int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) +{ + if (setsockopt(*ps, level, name, (char *) val, len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) +{ + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char *) &val, &len); + if (err) + return err; + lua_pushboolean(L, val); + return 1; +} + +int opt_get_error(lua_State *L, p_socket ps) +{ + int val = 0; + socklen_t len = sizeof(val); + if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + lua_pushstring(L, socket_strerror(val)); + return 1; +} + +static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) +{ + int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + +static int opt_getint(lua_State *L, p_socket ps, int level, int name) +{ + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char *) &val, &len); + if (err) + return err; + lua_pushnumber(L, val); + return 1; +} + +static int opt_setint(lua_State *L, p_socket ps, int level, int name) +{ + int val = (int) lua_tonumber(L, 3); /* obj, name, int */ + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} diff --git a/ThirdParty/tolua_runtime/luasocket/options.h b/ThirdParty/tolua_runtime/luasocket/options.h new file mode 100644 index 0000000..19ba0df --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/options.h @@ -0,0 +1,62 @@ +#ifndef OPTIONS_H +#define OPTIONS_H +/*=========================================================================*\ +* Common option interface +* LuaSocket toolkit +* +* This module provides a common interface to socket options, used mainly by +* modules UDP and TCP. +\*=========================================================================*/ + +#include "lua.h" +#include "socket.h" + +/* option registry */ +typedef struct t_opt { + const char *name; + int (*func)(lua_State *L, p_socket ps); +} t_opt; +typedef t_opt *p_opt; + +/* supported options for setoption */ +int opt_set_dontroute(lua_State *L, p_socket ps); +int opt_set_broadcast(lua_State *L, p_socket ps); +int opt_set_tcp_nodelay(lua_State *L, p_socket ps); +int opt_set_keepalive(lua_State *L, p_socket ps); +int opt_set_linger(lua_State *L, p_socket ps); +int opt_set_reuseaddr(lua_State *L, p_socket ps); +int opt_set_reuseport(lua_State *L, p_socket ps); +int opt_set_ip_multicast_if(lua_State *L, p_socket ps); +int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps); +int opt_set_ip_multicast_loop(lua_State *L, p_socket ps); +int opt_set_ip_add_membership(lua_State *L, p_socket ps); +int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); +int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps); +int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps); +int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps); +int opt_set_ip6_add_membership(lua_State *L, p_socket ps); +int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps); +int opt_set_ip6_v6only(lua_State *L, p_socket ps); + +/* supported options for getoption */ +int opt_get_dontroute(lua_State *L, p_socket ps); +int opt_get_broadcast(lua_State *L, p_socket ps); +int opt_get_reuseaddr(lua_State *L, p_socket ps); +int opt_get_reuseport(lua_State *L, p_socket ps); +int opt_get_tcp_nodelay(lua_State *L, p_socket ps); +int opt_get_keepalive(lua_State *L, p_socket ps); +int opt_get_linger(lua_State *L, p_socket ps); +int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); +int opt_get_ip_multicast_if(lua_State *L, p_socket ps); +int opt_get_error(lua_State *L, p_socket ps); +int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps); +int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps); +int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps); +int opt_get_ip6_v6only(lua_State *L, p_socket ps); +int opt_get_reuseport(lua_State *L, p_socket ps); + +/* invokes the appropriate option handler */ +int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); + +#endif diff --git a/ThirdParty/tolua_runtime/luasocket/pierror.h b/ThirdParty/tolua_runtime/luasocket/pierror.h new file mode 100644 index 0000000..cb773ab --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/pierror.h @@ -0,0 +1,28 @@ +#ifndef PIERROR_H +#define PIERROR_H +/*=========================================================================*\ +* Error messages +* Defines platform independent error messages +\*=========================================================================*/ + +#define PIE_HOST_NOT_FOUND "host not found" +#define PIE_ADDRINUSE "address already in use" +#define PIE_ISCONN "already connected" +#define PIE_ACCESS "permission denied" +#define PIE_CONNREFUSED "connection refused" +#define PIE_CONNABORTED "closed" +#define PIE_CONNRESET "closed" +#define PIE_TIMEDOUT "timeout" +#define PIE_AGAIN "temporary failure in name resolution" +#define PIE_BADFLAGS "invalid value for ai_flags" +#define PIE_BADHINTS "invalid value for hints" +#define PIE_FAIL "non-recoverable failure in name resolution" +#define PIE_FAMILY "ai_family not supported" +#define PIE_MEMORY "memory allocation failure" +#define PIE_NONAME "host or service not provided, or not known" +#define PIE_OVERFLOW "argument buffer overflow" +#define PIE_PROTOCOL "resolved protocol is unknown" +#define PIE_SERVICE "service not supported for socket type" +#define PIE_SOCKTYPE "ai_socktype not supported" + +#endif diff --git a/ThirdParty/tolua_runtime/luasocket/select.c b/ThirdParty/tolua_runtime/luasocket/select.c new file mode 100644 index 0000000..9d133b7 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/select.c @@ -0,0 +1,220 @@ +/*=========================================================================*\ +* Select implementation +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "socket.h" +#include "timeout.h" +#include "select.h" + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static t_socket getfd(lua_State *L); +static int dirty(lua_State *L); +static void collect_fd(lua_State *L, int tab, int itab, + fd_set *set, t_socket *max_fd); +static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); +static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, + int itab, int tab, int start); +static void make_assoc(lua_State *L, int tab); +static int global_select(lua_State *L); + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"select", global_select}, + {NULL, NULL} +}; + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int select_open(lua_State *L) { + lua_pushstring(L, "_SETSIZE"); + lua_pushinteger(L, FD_SETSIZE); + lua_rawset(L, -3); + lua_pushstring(L, "_SOCKETINVALID"); + lua_pushinteger(L, SOCKET_INVALID); + lua_rawset(L, -3); + luaL_setfuncs(L, func, 0); + return 0; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Waits for a set of sockets until a condition is met or timeout. +\*-------------------------------------------------------------------------*/ +static int global_select(lua_State *L) { + int rtab, wtab, itab, ret, ndirty; + t_socket max_fd = SOCKET_INVALID; + fd_set rset, wset; + t_timeout tm; + double t = luaL_optnumber(L, 3, -1); + FD_ZERO(&rset); FD_ZERO(&wset); + lua_settop(L, 3); + lua_newtable(L); itab = lua_gettop(L); + lua_newtable(L); rtab = lua_gettop(L); + lua_newtable(L); wtab = lua_gettop(L); + collect_fd(L, 1, itab, &rset, &max_fd); + collect_fd(L, 2, itab, &wset, &max_fd); + ndirty = check_dirty(L, 1, rtab, &rset); + t = ndirty > 0? 0.0: t; + timeout_init(&tm, t, -1); + timeout_markstart(&tm); + ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); + if (ret > 0 || ndirty > 0) { + return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); + return_fd(L, &wset, max_fd+1, itab, wtab, 0); + make_assoc(L, rtab); + make_assoc(L, wtab); + return 2; + } else if (ret == 0) { + lua_pushstring(L, "timeout"); + return 3; + } else { + luaL_error(L, "select failed"); + return 3; + } +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +static t_socket getfd(lua_State *L) { + t_socket fd = SOCKET_INVALID; + lua_pushstring(L, "getfd"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + if (lua_isnumber(L, -1)) { + double numfd = lua_tonumber(L, -1); + fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID; + } + } + lua_pop(L, 1); + return fd; +} + +static int dirty(lua_State *L) { + int is = 0; + lua_pushstring(L, "dirty"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + is = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return is; +} + +static void collect_fd(lua_State *L, int tab, int itab, + fd_set *set, t_socket *max_fd) { + int i = 1, n = 0; + /* nil is the same as an empty table */ + if (lua_isnil(L, tab)) return; + /* otherwise we need it to be a table */ + luaL_checktype(L, tab, LUA_TTABLE); + for ( ;; ) { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + break; + } + /* getfd figures out if this is a socket */ + fd = getfd(L); + if (fd != SOCKET_INVALID) { + /* make sure we don't overflow the fd_set */ +#ifdef _WIN32 + if (n >= FD_SETSIZE) + luaL_argerror(L, tab, "too many sockets"); +#else + if (fd >= FD_SETSIZE) + luaL_argerror(L, tab, "descriptor too large for set size"); +#endif + FD_SET(fd, set); + n++; + /* keep track of the largest descriptor so far */ + if (*max_fd == SOCKET_INVALID || *max_fd < fd) + *max_fd = fd; + /* make sure we can map back from descriptor to the object */ + lua_pushnumber(L, (lua_Number) fd); + lua_pushvalue(L, -2); + lua_settable(L, itab); + } + lua_pop(L, 1); + i = i + 1; + } +} + +static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) { + int ndirty = 0, i = 1; + if (lua_isnil(L, tab)) + return 0; + for ( ;; ) { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + break; + } + fd = getfd(L); + if (fd != SOCKET_INVALID && dirty(L)) { + lua_pushnumber(L, ++ndirty); + lua_pushvalue(L, -2); + lua_settable(L, dtab); + FD_CLR(fd, set); + } + lua_pop(L, 1); + i = i + 1; + } + return ndirty; +} + +static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, + int itab, int tab, int start) { + t_socket fd; + for (fd = 0; fd < max_fd; fd++) { + if (FD_ISSET(fd, set)) { + lua_pushnumber(L, ++start); + lua_pushnumber(L, (lua_Number) fd); + lua_gettable(L, itab); + lua_settable(L, tab); + } + } +} + +static void make_assoc(lua_State *L, int tab) { + int i = 1, atab; + lua_newtable(L); atab = lua_gettop(L); + for ( ;; ) { + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (!lua_isnil(L, -1)) { + lua_pushnumber(L, i); + lua_pushvalue(L, -2); + lua_settable(L, atab); + lua_pushnumber(L, i); + lua_settable(L, atab); + } else { + lua_pop(L, 1); + break; + } + i = i+1; + } +} + diff --git a/ThirdParty/tolua_runtime/luasocket/select.h b/ThirdParty/tolua_runtime/luasocket/select.h new file mode 100644 index 0000000..8750200 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/select.h @@ -0,0 +1,15 @@ +#ifndef SELECT_H +#define SELECT_H +/*=========================================================================*\ +* Select implementation +* LuaSocket toolkit +* +* Each object that can be passed to the select function has to export +* method getfd() which returns the descriptor to be passed to the +* underlying select function. Another method, dirty(), should return +* true if there is data ready for reading (required for buffered input). +\*=========================================================================*/ + +int select_open(lua_State *L); + +#endif /* SELECT_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/serial.c b/ThirdParty/tolua_runtime/luasocket/serial.c new file mode 100644 index 0000000..a119d18 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/serial.c @@ -0,0 +1,173 @@ +/*=========================================================================*\ +* Serial stream +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" + +#include "auxiliar.h" +#include "socket.h" +#include "options.h" +#include "unix.h" +#include "luasocket.h" +#include <sys/un.h> + +/* +Reuses userdata definition from unix.h, since it is useful for all +stream-like objects. + +If we stored the serial path for use in error messages or userdata +printing, we might need our own userdata definition. + +Group usage is semi-inherited from unix.c, but unnecessary since we +have only one object type. +*/ + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int meth_send(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_close(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); + +/* serial object methods */ +static luaL_Reg serial_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"close", meth_close}, + {"dirty", meth_dirty}, + {"getfd", meth_getfd}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"settimeout", meth_settimeout}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_serial(lua_State *L) { + /* create classes */ + auxiliar_newclass(L, "serial{client}", serial_methods); + /* create class groups */ + auxiliar_add2group(L, "serial{client}", "serial{any}"); + lua_pushcfunction(L, global_create); + return 1; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_send(L, &un->buf); +} + +static int meth_receive(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_receive(L, &un->buf); +} + +static int meth_getstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_getstats(L, &un->buf); +} + +static int meth_setstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_setstats(L, &un->buf); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + lua_pushnumber(L, (int) un->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + un->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + lua_pushboolean(L, !buffer_isempty(&un->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + socket_destroy(&un->sock); + lua_pushnumber(L, 1); + return 1; +} + + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + return timeout_meth_settimeout(L, &un->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ + + +/*-------------------------------------------------------------------------*\ +* Creates a serial object +\*-------------------------------------------------------------------------*/ +static int global_create(lua_State *L) { + const char* path = luaL_checkstring(L, 1); + + /* allocate unix object */ + p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + + /* open serial device */ + t_socket sock = open(path, O_NOCTTY|O_RDWR); + + /*printf("open %s on %d\n", path, sock);*/ + + if (sock < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + lua_pushnumber(L, errno); + return 3; + } + /* set its type as client object */ + auxiliar_setclass(L, "serial{client}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + un->sock = sock; + io_init(&un->io, (p_send) socket_write, (p_recv) socket_read, + (p_error) socket_ioerror, &un->sock); + timeout_init(&un->tm, -1, -1); + buffer_init(&un->buf, &un->io, &un->tm); + return 1; +} diff --git a/ThirdParty/tolua_runtime/luasocket/socket.h b/ThirdParty/tolua_runtime/luasocket/socket.h new file mode 100644 index 0000000..63573de --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/socket.h @@ -0,0 +1,78 @@ +#ifndef SOCKET_H +#define SOCKET_H +/*=========================================================================*\ +* Socket compatibilization module +* LuaSocket toolkit +* +* BSD Sockets and WinSock are similar, but there are a few irritating +* differences. Also, not all *nix platforms behave the same. This module +* (and the associated usocket.h and wsocket.h) factor these differences and +* creates a interface compatible with the io.h module. +\*=========================================================================*/ +#include "io.h" + +/*=========================================================================*\ +* Platform specific compatibilization +\*=========================================================================*/ +#ifdef _WIN32 +#include "wsocket.h" +#else +#include "usocket.h" +#endif + +/*=========================================================================*\ +* The connect and accept functions accept a timeout and their +* implementations are somewhat complicated. We chose to move +* the timeout control into this module for these functions in +* order to simplify the modules that use them. +\*=========================================================================*/ +#include "timeout.h" + +/* we are lazy... */ +typedef struct sockaddr SA; + +/*=========================================================================*\ +* Functions bellow implement a comfortable platform independent +* interface to sockets +\*=========================================================================*/ +int socket_open(void); +int socket_close(void); +void socket_destroy(p_socket ps); +void socket_shutdown(p_socket ps, int how); +int socket_sendto(p_socket ps, const char *data, size_t count, + size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm); +int socket_recvfrom(p_socket ps, char *data, size_t count, + size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm); + +void socket_setnonblocking(p_socket ps); +void socket_setblocking(p_socket ps); + +int socket_waitfd(p_socket ps, int sw, p_timeout tm); +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm); + +int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm); +int socket_create(p_socket ps, int domain, int type, int protocol); +int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); +int socket_listen(p_socket ps, int backlog); +int socket_accept(p_socket ps, p_socket pa, SA *addr, + socklen_t *addr_len, p_timeout tm); + +const char *socket_hoststrerror(int err); +const char *socket_gaistrerror(int err); +const char *socket_strerror(int err); + +/* these are perfect to use with the io abstraction module + and the buffered input module */ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm); +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); +int socket_write(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm); +int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); +const char *socket_ioerror(p_socket ps, int err); + +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); +int socket_gethostbyname(const char *addr, struct hostent **hp); + +#endif /* SOCKET_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/tcp.c b/ThirdParty/tolua_runtime/luasocket/tcp.c new file mode 100644 index 0000000..ef9ee6f --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/tcp.c @@ -0,0 +1,451 @@ +/*=========================================================================*\ +* TCP object +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "auxiliar.h" +#include "socket.h" +#include "inet.h" +#include "options.h" +#include "tcp.h" + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int global_create4(lua_State *L); +static int global_create6(lua_State *L); +static int global_connect(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_listen(lua_State *L); +static int meth_getfamily(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_shutdown(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_accept(lua_State *L); +static int meth_close(lua_State *L); +static int meth_getoption(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_gettimeout(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); + +/* tcp object methods */ +static luaL_Reg tcp_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"accept", meth_accept}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getoption", meth_getoption}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"listen", meth_listen}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"settimeout", meth_settimeout}, + {"gettimeout", meth_gettimeout}, + {"shutdown", meth_shutdown}, + {NULL, NULL} +}; + +/* socket option handlers */ +static t_opt optget[] = { + {"keepalive", opt_get_keepalive}, + {"reuseaddr", opt_get_reuseaddr}, + {"reuseport", opt_get_reuseport}, + {"tcp-nodelay", opt_get_tcp_nodelay}, + {"linger", opt_get_linger}, + {"error", opt_get_error}, + {NULL, NULL} +}; + +static t_opt optset[] = { + {"keepalive", opt_set_keepalive}, + {"reuseaddr", opt_set_reuseaddr}, + {"reuseport", opt_set_reuseport}, + {"tcp-nodelay", opt_set_tcp_nodelay}, + {"ipv6-v6only", opt_set_ip6_v6only}, + {"linger", opt_set_linger}, + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"tcp", global_create}, + {"tcp4", global_create4}, + {"tcp6", global_create6}, + {"connect", global_connect}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int tcp_open(lua_State *L) +{ + /* create classes */ + auxiliar_newclass(L, "tcp{master}", tcp_methods); + auxiliar_newclass(L, "tcp{client}", tcp_methods); + auxiliar_newclass(L, "tcp{server}", tcp_methods); + /* create class groups */ + auxiliar_add2group(L, "tcp{master}", "tcp{any}"); + auxiliar_add2group(L, "tcp{client}", "tcp{any}"); + auxiliar_add2group(L, "tcp{server}", "tcp{any}"); + /* define library functions */ + luaL_setfuncs(L, func, 0); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_send(L, &tcp->buf); +} + +static int meth_receive(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_receive(L, &tcp->buf); +} + +static int meth_getstats(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_getstats(L, &tcp->buf); +} + +static int meth_setstats(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_setstats(L, &tcp->buf); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_getoption(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_getoption(L, optget, &tcp->sock); +} + +static int meth_setoption(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_setoption(L, optset, &tcp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushnumber(L, (int) tcp->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + tcp->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushboolean(L, !buffer_isempty(&tcp->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Waits for and returns a client object attempting connection to the +* server object +\*-------------------------------------------------------------------------*/ +static int meth_accept(lua_State *L) +{ + p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); + p_timeout tm = timeout_markstart(&server->tm); + t_socket sock; + const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm); + /* if successful, push client socket */ + if (err == NULL) { + p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + auxiliar_setclass(L, "tcp{client}", -1); + /* initialize structure fields */ + memset(clnt, 0, sizeof(t_tcp)); + socket_setnonblocking(&sock); + clnt->sock = sock; + io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &clnt->sock); + timeout_init(&clnt->tm, -1, -1); + buffer_init(&clnt->buf, &clnt->io, &clnt->tm); + clnt->family = server->family; + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } +} + +/*-------------------------------------------------------------------------*\ +* Binds an object to an address +\*-------------------------------------------------------------------------*/ +static int meth_bind(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = tcp->family; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master tcp object into a client object. +\*-------------------------------------------------------------------------*/ +static int meth_connect(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->family; + timeout_markstart(&tcp->tm); + err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, + &tcp->tm, &connecthints); + /* have to set the class even if it failed due to non-blocking connects */ + auxiliar_setclass(L, "tcp{client}", 1); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + socket_destroy(&tcp->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Returns family as string +\*-------------------------------------------------------------------------*/ +static int meth_getfamily(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + if (tcp->family == AF_INET6) { + lua_pushliteral(L, "inet6"); + return 1; + } else if (tcp->family == AF_INET) { + lua_pushliteral(L, "inet4"); + return 1; + } else { + lua_pushliteral(L, "inet4"); + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Puts the sockt in listen mode +\*-------------------------------------------------------------------------*/ +static int meth_listen(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); + int backlog = (int) luaL_optnumber(L, 2, 32); + int err = socket_listen(&tcp->sock, backlog); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } + /* turn master object into a server object */ + auxiliar_setclass(L, "tcp{server}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Shuts the connection down partially +\*-------------------------------------------------------------------------*/ +static int meth_shutdown(lua_State *L) +{ + /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ + static const char* methods[] = { "receive", "send", "both", NULL }; + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + int how = luaL_checkoption(L, 2, "both", methods); + socket_shutdown(&tcp->sock, how); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call inet methods +\*-------------------------------------------------------------------------*/ +static int meth_getpeername(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getpeername(L, &tcp->sock, tcp->family); +} + +static int meth_getsockname(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getsockname(L, &tcp->sock, tcp->family); +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return timeout_meth_settimeout(L, &tcp->tm); +} + +static int meth_gettimeout(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return timeout_meth_gettimeout(L, &tcp->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master tcp object +\*-------------------------------------------------------------------------*/ +static int tcp_create(lua_State *L, int family) { + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + memset(tcp, 0, sizeof(t_tcp)); + /* set its type as master object */ + auxiliar_setclass(L, "tcp{master}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + tcp->sock = SOCKET_INVALID; + tcp->family = family; + io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + if (family != AF_UNSPEC) { + const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0); + if (err != NULL) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + socket_setnonblocking(&tcp->sock); + } + return 1; +} + +static int global_create(lua_State *L) { + return tcp_create(L, AF_UNSPEC); +} + +static int global_create4(lua_State *L) { + return tcp_create(L, AF_INET); +} + +static int global_create6(lua_State *L) { + return tcp_create(L, AF_INET6); +} + +static int global_connect(lua_State *L) { + const char *remoteaddr = luaL_checkstring(L, 1); + const char *remoteserv = luaL_checkstring(L, 2); + const char *localaddr = luaL_optstring(L, 3, NULL); + const char *localserv = luaL_optstring(L, 4, "0"); + int family = inet_optfamily(L, 5, "unspec"); + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + struct addrinfo bindhints, connecthints; + const char *err = NULL; + /* initialize tcp structure */ + memset(tcp, 0, sizeof(t_tcp)); + io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + tcp->sock = SOCKET_INVALID; + tcp->family = AF_UNSPEC; + /* allow user to pick local address and port */ + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = family; + bindhints.ai_flags = AI_PASSIVE; + if (localaddr) { + err = inet_trybind(&tcp->sock, &tcp->family, localaddr, + localserv, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + } + /* try to connect to remote address and port */ + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->family; + err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, + &tcp->tm, &connecthints); + if (err) { + socket_destroy(&tcp->sock); + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "tcp{client}", -1); + return 1; +} diff --git a/ThirdParty/tolua_runtime/luasocket/tcp.h b/ThirdParty/tolua_runtime/luasocket/tcp.h new file mode 100644 index 0000000..eded620 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/tcp.h @@ -0,0 +1,35 @@ +#ifndef TCP_H +#define TCP_H +/*=========================================================================*\ +* TCP object +* LuaSocket toolkit +* +* The tcp.h module is basicly a glue that puts together modules buffer.h, +* timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET, +* SOCK_STREAM) support. +* +* Three classes are defined: master, client and server. The master class is +* a newly created tcp object, that has not been bound or connected. Server +* objects are tcp objects bound to some local address. Client objects are +* tcp objects either connected to some address or returned by the accept +* method of a server object. +\*=========================================================================*/ +#include "lua.h" + +#include "buffer.h" +#include "timeout.h" +#include "socket.h" + +typedef struct t_tcp_ { + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; + int family; +} t_tcp; + +typedef t_tcp *p_tcp; + +int tcp_open(lua_State *L); + +#endif /* TCP_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/timeout.c b/ThirdParty/tolua_runtime/luasocket/timeout.c new file mode 100644 index 0000000..5a601d5 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/timeout.c @@ -0,0 +1,228 @@ +/*=========================================================================*\ +* Timeout management functions +* LuaSocket toolkit +\*=========================================================================*/ +#include <stdio.h> +#include <limits.h> +#include <float.h> + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "auxiliar.h" +#include "timeout.h" + +#ifdef _WIN32 +#include <windows.h> +#else +#include <time.h> +#include <sys/time.h> +#endif + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int timeout_lua_gettime(lua_State *L); +static int timeout_lua_sleep(lua_State *L); + +static luaL_Reg func[] = { + { "gettime", timeout_lua_gettime }, + { "sleep", timeout_lua_sleep }, + { NULL, NULL } +}; + +/*=========================================================================*\ +* Exported functions. +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initialize structure +\*-------------------------------------------------------------------------*/ +void timeout_init(p_timeout tm, double block, double total) { + tm->block = block; + tm->total = total; +} + +/*-------------------------------------------------------------------------*\ +* 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)); + } +} + +/*-------------------------------------------------------------------------*\ +* Returns time since start of operation +* Input +* tm: timeout control structure +* Returns +* start field of structure +\*-------------------------------------------------------------------------*/ +double timeout_getstart(p_timeout tm) { + return tm->start; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was a failure +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +double timeout_getretry(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) { + double t = tm->block - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } +} + +/*-------------------------------------------------------------------------*\ +* 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; +} + +/*-------------------------------------------------------------------------*\ +* Gets time in s, relative to January 1, 1970 (UTC) +* Returns +* time in s. +\*-------------------------------------------------------------------------*/ +#ifdef _WIN32 +double timeout_gettime(void) { + FILETIME ft; + double t; + GetSystemTimeAsFileTime(&ft); + /* Windows file time (time since January 1, 1601 (UTC)) */ + t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7); + /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ + return (t - 11644473600.0); +} +#else +double timeout_gettime(void) { + struct timeval v; + gettimeofday(&v, (struct timezone *) NULL); + /* Unix Epoch time (time since January 1, 1970 (UTC)) */ + return v.tv_sec + v.tv_usec/1.0e6; +} +#endif + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int timeout_open(lua_State *L) { + luaL_setfuncs(L, func, 0); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Sets timeout values for IO operations +* Lua Input: base, time [, mode] +* time: time out value in seconds +* mode: "b" for block timeout, "t" for total timeout. (default: b) +\*-------------------------------------------------------------------------*/ +int timeout_meth_settimeout(lua_State *L, p_timeout tm) { + double t = luaL_optnumber(L, 2, -1); + const char *mode = luaL_optstring(L, 3, "b"); + switch (*mode) { + case 'b': + tm->block = t; + break; + case 'r': case 't': + tm->total = t; + break; + default: + luaL_argcheck(L, 0, 3, "invalid timeout mode"); + break; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Gets timeout values for IO operations +* Lua Output: block, total +\*-------------------------------------------------------------------------*/ +int timeout_meth_gettimeout(lua_State *L, p_timeout tm) { + lua_pushnumber(L, tm->block); + lua_pushnumber(L, tm->total); + return 2; +} + +/*=========================================================================*\ +* Test support functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* 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; +} + +/*-------------------------------------------------------------------------*\ +* Sleep for n seconds. +\*-------------------------------------------------------------------------*/ +#ifdef _WIN32 +int timeout_lua_sleep(lua_State *L) +{ + double n = luaL_checknumber(L, 1); + if (n < 0.0) n = 0.0; + if (n < DBL_MAX/1000.0) n *= 1000.0; + if (n > INT_MAX) n = INT_MAX; + Sleep((int)n); + return 0; +} +#else +int timeout_lua_sleep(lua_State *L) +{ + double n = luaL_checknumber(L, 1); + struct timespec t, r; + if (n < 0.0) n = 0.0; + if (n > INT_MAX) n = INT_MAX; + t.tv_sec = (int) n; + n -= t.tv_sec; + t.tv_nsec = (int) (n * 1000000000); + if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999; + while (nanosleep(&t, &r) != 0) { + t.tv_sec = r.tv_sec; + t.tv_nsec = r.tv_nsec; + } + return 0; +} +#endif diff --git a/ThirdParty/tolua_runtime/luasocket/timeout.h b/ThirdParty/tolua_runtime/luasocket/timeout.h new file mode 100644 index 0000000..af90231 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/timeout.h @@ -0,0 +1,29 @@ +#ifndef TIMEOUT_H +#define TIMEOUT_H +/*=========================================================================*\ +* Timeout management functions +* LuaSocket toolkit +\*=========================================================================*/ +#include "lua.h" + +/* timeout control structure */ +typedef struct t_timeout_ { + double block; /* maximum time for blocking calls */ + double total; /* total number of miliseconds for operation */ + double start; /* time of start of operation */ +} t_timeout; +typedef t_timeout *p_timeout; + +int timeout_open(lua_State *L); +void timeout_init(p_timeout tm, double block, double total); +double timeout_get(p_timeout tm); +double timeout_getretry(p_timeout tm); +p_timeout timeout_markstart(p_timeout tm); +double timeout_getstart(p_timeout tm); +double timeout_gettime(void); +int timeout_meth_settimeout(lua_State *L, p_timeout tm); +int timeout_meth_gettimeout(lua_State *L, p_timeout tm); + +#define timeout_iszero(tm) ((tm)->block == 0.0) + +#endif /* TIMEOUT_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/udp.c b/ThirdParty/tolua_runtime/luasocket/udp.c new file mode 100644 index 0000000..ec97252 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/udp.c @@ -0,0 +1,462 @@ +/*=========================================================================*\ +* UDP object +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> +#include <stdlib.h> + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +#include "auxiliar.h" +#include "socket.h" +#include "inet.h" +#include "options.h" +#include "udp.h" + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int global_create4(lua_State *L); +static int global_create6(lua_State *L); +static int meth_send(lua_State *L); +static int meth_sendto(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_receivefrom(lua_State *L); +static int meth_getfamily(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_gettimeout(lua_State *L); +static int meth_setsockname(lua_State *L); +static int meth_setpeername(lua_State *L); +static int meth_close(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_getoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); + +/* udp object methods */ +static luaL_Reg udp_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"close", meth_close}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"receive", meth_receive}, + {"receivefrom", meth_receivefrom}, + {"send", meth_send}, + {"sendto", meth_sendto}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"getoption", meth_getoption}, + {"setpeername", meth_setpeername}, + {"setsockname", meth_setsockname}, + {"settimeout", meth_settimeout}, + {"gettimeout", meth_gettimeout}, + {NULL, NULL} +}; + +/* socket options for setoption */ +static t_opt optset[] = { + {"dontroute", opt_set_dontroute}, + {"broadcast", opt_set_broadcast}, + {"reuseaddr", opt_set_reuseaddr}, + {"reuseport", opt_set_reuseport}, + {"ip-multicast-if", opt_set_ip_multicast_if}, + {"ip-multicast-ttl", opt_set_ip_multicast_ttl}, + {"ip-multicast-loop", opt_set_ip_multicast_loop}, + {"ip-add-membership", opt_set_ip_add_membership}, + {"ip-drop-membership", opt_set_ip_drop_membersip}, + {"ipv6-unicast-hops", opt_set_ip6_unicast_hops}, + {"ipv6-multicast-hops", opt_set_ip6_unicast_hops}, + {"ipv6-multicast-loop", opt_set_ip6_multicast_loop}, + {"ipv6-add-membership", opt_set_ip6_add_membership}, + {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, + {"ipv6-v6only", opt_set_ip6_v6only}, + {NULL, NULL} +}; + +/* socket options for getoption */ +static t_opt optget[] = { + {"dontroute", opt_get_dontroute}, + {"broadcast", opt_get_broadcast}, + {"reuseaddr", opt_get_reuseaddr}, + {"reuseport", opt_get_reuseport}, + {"ip-multicast-if", opt_get_ip_multicast_if}, + {"ip-multicast-loop", opt_get_ip_multicast_loop}, + {"error", opt_get_error}, + {"ipv6-unicast-hops", opt_get_ip6_unicast_hops}, + {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, + {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, + {"ipv6-v6only", opt_get_ip6_v6only}, + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"udp", global_create}, + {"udp4", global_create4}, + {"udp6", global_create6}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int udp_open(lua_State *L) { + /* create classes */ + auxiliar_newclass(L, "udp{connected}", udp_methods); + auxiliar_newclass(L, "udp{unconnected}", udp_methods); + /* create class groups */ + auxiliar_add2group(L, "udp{connected}", "udp{any}"); + auxiliar_add2group(L, "udp{unconnected}", "udp{any}"); + auxiliar_add2group(L, "udp{connected}", "select{able}"); + auxiliar_add2group(L, "udp{unconnected}", "select{able}"); + /* define library functions */ + luaL_setfuncs(L, func, 0); + /* export default UDP size */ + lua_pushliteral(L, "_DATAGRAMSIZE"); + lua_pushinteger(L, UDP_DATAGRAMSIZE); + lua_rawset(L, -3); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +static const char *udp_strerror(int err) { + /* a 'closed' error on an unconnected means the target address was not + * accepted by the transport layer */ + if (err == IO_CLOSED) return "refused"; + else return socket_strerror(err); +} + +/*-------------------------------------------------------------------------*\ +* Send data through connected udp socket +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); + p_timeout tm = &udp->tm; + size_t count, sent = 0; + int err; + const char *data = luaL_checklstring(L, 2, &count); + timeout_markstart(tm); + err = socket_send(&udp->sock, data, count, &sent, tm); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Send data through unconnected udp socket +\*-------------------------------------------------------------------------*/ +static int meth_sendto(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + size_t count, sent = 0; + const char *data = luaL_checklstring(L, 2, &count); + const char *ip = luaL_checkstring(L, 3); + const char *port = luaL_checkstring(L, 4); + p_timeout tm = &udp->tm; + int err; + struct addrinfo aihint; + struct addrinfo *ai; + memset(&aihint, 0, sizeof(aihint)); + aihint.ai_family = udp->family; + aihint.ai_socktype = SOCK_DGRAM; + aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + err = getaddrinfo(ip, port, &aihint, &ai); + if (err) { + lua_pushnil(L); + lua_pushstring(L, gai_strerror(err)); + return 2; + } + timeout_markstart(tm); + err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, + (socklen_t) ai->ai_addrlen, tm); + freeaddrinfo(ai); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Receives data from a UDP socket +\*-------------------------------------------------------------------------*/ +static int meth_receive(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + char buf[UDP_DATAGRAMSIZE]; + size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); + char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; + int err; + p_timeout tm = &udp->tm; + timeout_markstart(tm); + if (!dgram) { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + err = socket_recv(&udp->sock, dgram, wanted, &got, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + lua_pushlstring(L, dgram, got); + if (wanted > sizeof(buf)) free(dgram); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Receives data and sender from a UDP socket +\*-------------------------------------------------------------------------*/ +static int meth_receivefrom(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + char buf[UDP_DATAGRAMSIZE]; + size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); + char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + char addrstr[INET6_ADDRSTRLEN]; + char portstr[6]; + int err; + p_timeout tm = &udp->tm; + timeout_markstart(tm); + if (!dgram) { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr, + &addr_len, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, + INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); + if (err) { + lua_pushnil(L); + lua_pushstring(L, gai_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + lua_pushlstring(L, dgram, got); + lua_pushstring(L, addrstr); + lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); + if (wanted > sizeof(buf)) free(dgram); + return 3; +} + +/*-------------------------------------------------------------------------*\ +* Returns family as string +\*-------------------------------------------------------------------------*/ +static int meth_getfamily(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + if (udp->family == AF_INET6) { + lua_pushliteral(L, "inet6"); + return 1; + } else { + lua_pushliteral(L, "inet4"); + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + lua_pushnumber(L, (int) udp->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + udp->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + (void) udp; + lua_pushboolean(L, 0); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call inet methods +\*-------------------------------------------------------------------------*/ +static int meth_getpeername(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); + return inet_meth_getpeername(L, &udp->sock, udp->family); +} + +static int meth_getsockname(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return inet_meth_getsockname(L, &udp->sock, udp->family); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_setoption(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_setoption(L, optset, &udp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_getoption(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_getoption(L, optget, &udp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return timeout_meth_settimeout(L, &udp->tm); +} + +static int meth_gettimeout(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return timeout_meth_gettimeout(L, &udp->tm); +} + +/*-------------------------------------------------------------------------*\ +* Turns a master udp object into a client object. +\*-------------------------------------------------------------------------*/ +static int meth_setpeername(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + p_timeout tm = &udp->tm; + const char *address = luaL_checkstring(L, 2); + int connecting = strcmp(address, "*"); + const char *port = connecting? luaL_checkstring(L, 3): "0"; + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_DGRAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = udp->family; + if (connecting) { + err = inet_tryconnect(&udp->sock, &udp->family, address, + port, tm, &connecthints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "udp{connected}", 1); + } else { + /* we ignore possible errors because Mac OS X always + * returns EAFNOSUPPORT */ + inet_trydisconnect(&udp->sock, udp->family, tm); + auxiliar_setclass(L, "udp{unconnected}", 1); + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + socket_destroy(&udp->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master object into a server object +\*-------------------------------------------------------------------------*/ +static int meth_setsockname(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_DGRAM; + bindhints.ai_family = udp->family; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master udp object +\*-------------------------------------------------------------------------*/ +static int udp_create(lua_State *L, int family) { + /* allocate udp object */ + p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); + auxiliar_setclass(L, "udp{unconnected}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + udp->sock = SOCKET_INVALID; + timeout_init(&udp->tm, -1, -1); + udp->family = family; + if (family != AF_UNSPEC) { + const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0); + if (err != NULL) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + socket_setnonblocking(&udp->sock); + } + return 1; +} + +static int global_create(lua_State *L) { + return udp_create(L, AF_UNSPEC); +} + +static int global_create4(lua_State *L) { + return udp_create(L, AF_INET); +} + +static int global_create6(lua_State *L) { + return udp_create(L, AF_INET6); +} diff --git a/ThirdParty/tolua_runtime/luasocket/udp.h b/ThirdParty/tolua_runtime/luasocket/udp.h new file mode 100644 index 0000000..be9b6a5 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/udp.h @@ -0,0 +1,31 @@ +#ifndef UDP_H +#define UDP_H +/*=========================================================================*\ +* UDP object +* LuaSocket toolkit +* +* The udp.h module provides LuaSocket with support for UDP protocol +* (AF_INET, SOCK_DGRAM). +* +* Two classes are defined: connected and unconnected. UDP objects are +* originally unconnected. They can be "connected" to a given address +* with a call to the setpeername function. The same function can be used to +* break the connection. +\*=========================================================================*/ +#include "lua.h" + +#include "timeout.h" +#include "socket.h" + +#define UDP_DATAGRAMSIZE 8192 + +typedef struct t_udp_ { + t_socket sock; + t_timeout tm; + int family; +} t_udp; +typedef t_udp *p_udp; + +int udp_open(lua_State *L); + +#endif /* UDP_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/unix.c b/ThirdParty/tolua_runtime/luasocket/unix.c new file mode 100644 index 0000000..5bc3148 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/unix.c @@ -0,0 +1,330 @@ +/*=========================================================================*\ +* Unix domain socket +* LuaSocket toolkit +\*=========================================================================*/ +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" + +#include "auxiliar.h" +#include "socket.h" +#include "options.h" +#include "unix.h" +#include <sys/un.h> + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_listen(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_shutdown(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_accept(lua_State *L); +static int meth_close(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); + +static const char *unix_tryconnect(p_unix un, const char *path); +static const char *unix_trybind(p_unix un, const char *path); + +/* unix object methods */ +static luaL_Reg unix_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"accept", meth_accept}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfd", meth_getfd}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"listen", meth_listen}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"settimeout", meth_settimeout}, + {"shutdown", meth_shutdown}, + {NULL, NULL} +}; + +/* socket option handlers */ +static t_opt optset[] = { + {"keepalive", opt_set_keepalive}, + {"reuseaddr", opt_set_reuseaddr}, + {"linger", opt_set_linger}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int luaopen_socket_unix(lua_State *L) { + /* create classes */ + auxiliar_newclass(L, "unix{master}", unix_methods); + auxiliar_newclass(L, "unix{client}", unix_methods); + auxiliar_newclass(L, "unix{server}", unix_methods); + /* create class groups */ + auxiliar_add2group(L, "unix{master}", "unix{any}"); + auxiliar_add2group(L, "unix{client}", "unix{any}"); + auxiliar_add2group(L, "unix{server}", "unix{any}"); + /* return the function instead of the 'socket' table */ + lua_pushcfunction(L, global_create); + return 1; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_send(L, &un->buf); +} + +static int meth_receive(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_receive(L, &un->buf); +} + +static int meth_getstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_getstats(L, &un->buf); +} + +static int meth_setstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_setstats(L, &un->buf); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_setoption(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + return opt_meth_setoption(L, optset, &un->sock); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + lua_pushnumber(L, (int) un->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + un->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + lua_pushboolean(L, !buffer_isempty(&un->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Waits for and returns a client object attempting connection to the +* server object +\*-------------------------------------------------------------------------*/ +static int meth_accept(lua_State *L) { + p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1); + p_timeout tm = timeout_markstart(&server->tm); + t_socket sock; + int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); + /* if successful, push client socket */ + if (err == IO_DONE) { + p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + auxiliar_setclass(L, "unix{client}", -1); + /* initialize structure fields */ + socket_setnonblocking(&sock); + clnt->sock = sock; + io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv, + (p_error) socket_ioerror, &clnt->sock); + timeout_init(&clnt->tm, -1, -1); + buffer_init(&clnt->buf, &clnt->io, &clnt->tm); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } +} + +/*-------------------------------------------------------------------------*\ +* Binds an object to an address +\*-------------------------------------------------------------------------*/ +static const char *unix_trybind(p_unix un, const char *path) { + struct sockaddr_un local; + size_t len = strlen(path); + int err; + if (len >= sizeof(local.sun_path)) return "path too long"; + memset(&local, 0, sizeof(local)); + strcpy(local.sun_path, path); + local.sun_family = AF_UNIX; +#ifdef UNIX_HAS_SUN_LEN + local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len) + + len + 1; + err = socket_bind(&un->sock, (SA *) &local, local.sun_len); + +#else + err = socket_bind(&un->sock, (SA *) &local, + sizeof(local.sun_family) + len); +#endif + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_bind(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unix_trybind(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master unix object into a client object. +\*-------------------------------------------------------------------------*/ +static const char *unix_tryconnect(p_unix un, const char *path) +{ + struct sockaddr_un remote; + int err; + size_t len = strlen(path); + if (len >= sizeof(remote.sun_path)) return "path too long"; + memset(&remote, 0, sizeof(remote)); + strcpy(remote.sun_path, path); + remote.sun_family = AF_UNIX; + timeout_markstart(&un->tm); +#ifdef UNIX_HAS_SUN_LEN + remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len) + + len + 1; + err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm); +#else + err = socket_connect(&un->sock, (SA *) &remote, + sizeof(remote.sun_family) + len, &un->tm); +#endif + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_connect(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unix_tryconnect(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + /* turn master object into a client object */ + auxiliar_setclass(L, "unix{client}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + socket_destroy(&un->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Puts the sockt in listen mode +\*-------------------------------------------------------------------------*/ +static int meth_listen(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); + int backlog = (int) luaL_optnumber(L, 2, 32); + int err = socket_listen(&un->sock, backlog); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } + /* turn master object into a server object */ + auxiliar_setclass(L, "unix{server}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Shuts the connection down partially +\*-------------------------------------------------------------------------*/ +static int meth_shutdown(lua_State *L) +{ + /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ + static const char* methods[] = { "receive", "send", "both", NULL }; + p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + int how = luaL_checkoption(L, 2, "both", methods); + socket_shutdown(&tcp->sock, how); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + return timeout_meth_settimeout(L, &un->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master unix object +\*-------------------------------------------------------------------------*/ +static int global_create(lua_State *L) { + t_socket sock; + int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0); + /* try to allocate a system socket */ + if (err == IO_DONE) { + /* allocate unix object */ + p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + /* set its type as master object */ + auxiliar_setclass(L, "unix{master}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + un->sock = sock; + io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &un->sock); + timeout_init(&un->tm, -1, -1); + buffer_init(&un->buf, &un->io, &un->tm); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } +} diff --git a/ThirdParty/tolua_runtime/luasocket/unix.h b/ThirdParty/tolua_runtime/luasocket/unix.h new file mode 100644 index 0000000..8cc7a79 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/unix.h @@ -0,0 +1,30 @@ +#ifndef UNIX_H +#define UNIX_H +/*=========================================================================*\ +* Unix domain object +* LuaSocket toolkit +* +* This module is just an example of how to extend LuaSocket with a new +* domain. +\*=========================================================================*/ +#include "lua.h" + +#include "buffer.h" +#include "timeout.h" +#include "socket.h" + +#ifndef UNIX_API +#define UNIX_API extern +#endif + +typedef struct t_unix_ { + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; +} t_unix; +typedef t_unix *p_unix; + +UNIX_API int luaopen_socket_unix(lua_State *L); + +#endif /* UNIX_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/usocket.c b/ThirdParty/tolua_runtime/luasocket/usocket.c new file mode 100644 index 0000000..8adc573 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/usocket.c @@ -0,0 +1,451 @@ +/*=========================================================================*\ +* Socket compatibilization module for Unix +* LuaSocket toolkit +* +* The code is now interrupt-safe. +* The penalty of calling select to avoid busy-wait is only paid when +* the I/O call fail in the first place. +\*=========================================================================*/ +#include <string.h> +#include <signal.h> + +#include "socket.h" +#include "pierror.h" + +/*-------------------------------------------------------------------------*\ +* Wait for readable/writable/connected socket with timeout +\*-------------------------------------------------------------------------*/ +#ifndef SOCKET_SELECT +#include <sys/poll.h> + +#define WAITFD_R POLLIN +#define WAITFD_W POLLOUT +#define WAITFD_C (POLLIN|POLLOUT) +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + struct pollfd pfd; + pfd.fd = *ps; + pfd.events = sw; + pfd.revents = 0; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + do { + int t = (int)(timeout_getretry(tm)*1e3); + ret = poll(&pfd, 1, t >= 0? t: -1); + } while (ret == -1 && errno == EINTR); + if (ret == -1) return errno; + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED; + return IO_DONE; +} +#else + +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_C (WAITFD_R|WAITFD_W) + +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + fd_set rfds, wfds, *rp, *wp; + struct timeval tv, *tp; + double t; + if (*ps >= FD_SETSIZE) return EINVAL; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + do { + /* must set bits within loop, because select may have modifed them */ + rp = wp = NULL; + if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; } + if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } + t = timeout_getretry(tm); + tp = NULL; + if (t >= 0.0) { + tv.tv_sec = (int)t; + tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); + tp = &tv; + } + ret = select(*ps+1, rp, wp, NULL, tp); + } while (ret == -1 && errno == EINTR); + if (ret == -1) return errno; + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED; + return IO_DONE; +} +#endif + + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int socket_open(void) { + /* instals a handler to ignore sigpipe or it will crash us */ + signal(SIGPIPE, SIG_IGN); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close module +\*-------------------------------------------------------------------------*/ +int socket_close(void) { + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close and inutilize socket +\*-------------------------------------------------------------------------*/ +void socket_destroy(p_socket ps) { + if (*ps != SOCKET_INVALID) { + close(*ps); + *ps = SOCKET_INVALID; + } +} + +/*-------------------------------------------------------------------------*\ +* Select with timeout control +\*-------------------------------------------------------------------------*/ +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm) { + int ret; + do { + struct timeval tv; + double t = timeout_getretry(tm); + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); + /* timeout = 0 means no wait */ + ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL); + } while (ret < 0 && errno == EINTR); + return ret; +} + +/*-------------------------------------------------------------------------*\ +* Creates and sets up a socket +\*-------------------------------------------------------------------------*/ +int socket_create(p_socket ps, int domain, int type, int protocol) { + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) return IO_DONE; + else return errno; +} + +/*-------------------------------------------------------------------------*\ +* Binds or returns error message +\*-------------------------------------------------------------------------*/ +int socket_bind(p_socket ps, SA *addr, socklen_t len) { + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) err = errno; + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +int socket_listen(p_socket ps, int backlog) { + int err = IO_DONE; + if (listen(*ps, backlog)) err = errno; + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +void socket_shutdown(p_socket ps, int how) { + shutdown(*ps, how); +} + +/*-------------------------------------------------------------------------*\ +* Connects or returns error message +\*-------------------------------------------------------------------------*/ +int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { + int err; + /* avoid calling on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* call connect until done or failed without being interrupted */ + do if (connect(*ps, addr, len) == 0) return IO_DONE; + while ((err = errno) == EINTR); + /* if connection failed immediately, return error code */ + if (err != EINPROGRESS && err != EAGAIN) return err; + /* zero timeout case optimization */ + if (timeout_iszero(tm)) return IO_TIMEOUT; + /* wait until we have the result of the connection attempt or timeout */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) { + if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; + else return errno; + } else return err; +} + +/*-------------------------------------------------------------------------*\ +* Accept with timeout +\*-------------------------------------------------------------------------*/ +int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) { + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int err; + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; + err = errno; + if (err == EINTR) continue; + if (err != EAGAIN && err != ECONNABORTED) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Send with timeout +\*-------------------------------------------------------------------------*/ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + long put = (long) send(*ps, data, count, 0); + /* if we sent anything, we are done */ + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + /* EPIPE means the connection was closed */ + if (err == EPIPE) return IO_CLOSED; + /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/ + if (err == EPROTOTYPE) continue; + /* we call was interrupted, just try again */ + if (err == EINTR) continue; + /* if failed fatal reason, report error */ + if (err != EAGAIN) return err; + /* wait until we can send something or we timeout */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Sendto with timeout +\*-------------------------------------------------------------------------*/ +int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, + SA *addr, socklen_t len, p_timeout tm) +{ + int err; + *sent = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long put = (long) sendto(*ps, data, count, 0, addr, len); + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + if (err == EPIPE) return IO_CLOSED; + if (err == EPROTOTYPE) continue; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Receive with timeout +\*-------------------------------------------------------------------------*/ +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) recv(*ps, data, count, 0); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Recvfrom with timeout +\*-------------------------------------------------------------------------*/ +int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, + SA *addr, socklen_t *len, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) recvfrom(*ps, data, count, 0, addr, len); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + + +/*-------------------------------------------------------------------------*\ +* Write with timeout +* +* socket_read and socket_write are cut-n-paste of socket_send and socket_recv, +* with send/recv replaced with write/read. We can't just use write/read +* in the socket version, because behaviour when size is zero is different. +\*-------------------------------------------------------------------------*/ +int socket_write(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + long put = (long) write(*ps, data, count); + /* if we sent anything, we are done */ + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + /* EPIPE means the connection was closed */ + if (err == EPIPE) return IO_CLOSED; + /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/ + if (err == EPROTOTYPE) continue; + /* we call was interrupted, just try again */ + if (err == EINTR) continue; + /* if failed fatal reason, report error */ + if (err != EAGAIN) return err; + /* wait until we can send something or we timeout */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Read with timeout +* See note for socket_write +\*-------------------------------------------------------------------------*/ +int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) read(*ps, data, count); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Put socket into blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setblocking(p_socket ps) { + int flags = fcntl(*ps, F_GETFL, 0); + flags &= (~(O_NONBLOCK)); + fcntl(*ps, F_SETFL, flags); +} + +/*-------------------------------------------------------------------------*\ +* Put socket into non-blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setnonblocking(p_socket ps) { + int flags = fcntl(*ps, F_GETFL, 0); + flags |= O_NONBLOCK; + fcntl(*ps, F_SETFL, flags); +} + +/*-------------------------------------------------------------------------*\ +* DNS helpers +\*-------------------------------------------------------------------------*/ +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) return IO_DONE; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; +} + +int socket_gethostbyname(const char *addr, struct hostent **hp) { + *hp = gethostbyname(addr); + if (*hp) return IO_DONE; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Error translation functions +* Make sure important error messages are standard +\*-------------------------------------------------------------------------*/ +const char *socket_hoststrerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case HOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; + default: return hstrerror(err); + } +} + +const char *socket_strerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case EADDRINUSE: return PIE_ADDRINUSE; + case EISCONN: return PIE_ISCONN; + case EACCES: return PIE_ACCESS; + case ECONNREFUSED: return PIE_CONNREFUSED; + case ECONNABORTED: return PIE_CONNABORTED; + case ECONNRESET: return PIE_CONNRESET; + case ETIMEDOUT: return PIE_TIMEDOUT; + default: { + return strerror(err); + } + } +} + +const char *socket_ioerror(p_socket ps, int err) { + (void) ps; + return socket_strerror(err); +} + +const char *socket_gaistrerror(int err) { + if (err == 0) return NULL; + switch (err) { + case EAI_AGAIN: return PIE_AGAIN; + case EAI_BADFLAGS: return PIE_BADFLAGS; +#ifdef EAI_BADHINTS + case EAI_BADHINTS: return PIE_BADHINTS; +#endif + case EAI_FAIL: return PIE_FAIL; + case EAI_FAMILY: return PIE_FAMILY; + case EAI_MEMORY: return PIE_MEMORY; + case EAI_NONAME: return PIE_NONAME; + case EAI_OVERFLOW: return PIE_OVERFLOW; +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: return PIE_PROTOCOL; +#endif + case EAI_SERVICE: return PIE_SERVICE; + case EAI_SOCKTYPE: return PIE_SOCKTYPE; + case EAI_SYSTEM: return strerror(errno); + default: return gai_strerror(err); + } +} + diff --git a/ThirdParty/tolua_runtime/luasocket/usocket.h b/ThirdParty/tolua_runtime/luasocket/usocket.h new file mode 100644 index 0000000..45f2f99 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/usocket.h @@ -0,0 +1,59 @@ +#ifndef USOCKET_H +#define USOCKET_H +/*=========================================================================*\ +* Socket compatibilization module for Unix +* LuaSocket toolkit +\*=========================================================================*/ + +/*=========================================================================*\ +* BSD include files +\*=========================================================================*/ +/* error codes */ +#include <errno.h> +/* close function */ +#include <unistd.h> +/* fnctnl function and associated constants */ +#include <fcntl.h> +/* struct sockaddr */ +#include <sys/types.h> +/* socket function */ +#include <sys/socket.h> +/* struct timeval */ +#include <sys/time.h> +/* gethostbyname and gethostbyaddr functions */ +#include <netdb.h> +/* sigpipe handling */ +#include <signal.h> +/* IP stuff*/ +#include <netinet/in.h> +#include <arpa/inet.h> +/* TCP options (nagle algorithm disable) */ +#include <netinet/tcp.h> +#include <net/if.h> + +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +/* Some platforms use IPV6_JOIN_GROUP instead if + * IPV6_ADD_MEMBERSHIP. The semantics are same, though. */ +#ifndef IPV6_ADD_MEMBERSHIP +#ifdef IPV6_JOIN_GROUP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif /* IPV6_JOIN_GROUP */ +#endif /* !IPV6_ADD_MEMBERSHIP */ + +/* Same with IPV6_DROP_MEMBERSHIP / IPV6_LEAVE_GROUP. */ +#ifndef IPV6_DROP_MEMBERSHIP +#ifdef IPV6_LEAVE_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif /* IPV6_LEAVE_GROUP */ +#endif /* !IPV6_DROP_MEMBERSHIP */ + +typedef int t_socket; +typedef t_socket *p_socket; +typedef struct sockaddr_storage t_sockaddr_storage; + +#define SOCKET_INVALID (-1) + +#endif /* USOCKET_H */ diff --git a/ThirdParty/tolua_runtime/luasocket/wsocket.c b/ThirdParty/tolua_runtime/luasocket/wsocket.c new file mode 100644 index 0000000..8ecb0fc --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/wsocket.c @@ -0,0 +1,433 @@ +/*=========================================================================*\ +* Socket compatibilization module for Win32 +* LuaSocket toolkit +* +* The penalty of calling select to avoid busy-wait is only paid when +* the I/O call fail in the first place. +\*=========================================================================*/ +#include <string.h> + +#include "socket.h" +#include "pierror.h" + +/* WinSock doesn't have a strerror... */ +static const char *wstrerror(int err); + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int socket_open(void) { + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + int err = WSAStartup(wVersionRequested, &wsaData ); + if (err != 0) return 0; + if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) && + (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) { + WSACleanup(); + return 0; + } + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close module +\*-------------------------------------------------------------------------*/ +int socket_close(void) { + WSACleanup(); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Wait for readable/writable/connected socket with timeout +\*-------------------------------------------------------------------------*/ +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_E 4 +#define WAITFD_C (WAITFD_E|WAITFD_W) + +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; + struct timeval tv, *tp = NULL; + double t; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + if (sw & WAITFD_R) { + FD_ZERO(&rfds); + FD_SET(*ps, &rfds); + rp = &rfds; + } + if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } + if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; } + if ((t = timeout_get(tm)) >= 0.0) { + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6); + tp = &tv; + } + ret = select(0, rp, wp, ep, tp); + if (ret == -1) return WSAGetLastError(); + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED; + return IO_DONE; +} + +/*-------------------------------------------------------------------------*\ +* Select with int timeout in ms +\*-------------------------------------------------------------------------*/ +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm) { + struct timeval tv; + double t = timeout_get(tm); + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); + if (n <= 0) { + Sleep((DWORD) (1000*t)); + return 0; + } else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL); +} + +/*-------------------------------------------------------------------------*\ +* Close and inutilize socket +\*-------------------------------------------------------------------------*/ +void socket_destroy(p_socket ps) { + if (*ps != SOCKET_INVALID) { + socket_setblocking(ps); /* close can take a long time on WIN32 */ + closesocket(*ps); + *ps = SOCKET_INVALID; + } +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +void socket_shutdown(p_socket ps, int how) { + socket_setblocking(ps); + shutdown(*ps, how); + socket_setnonblocking(ps); +} + +/*-------------------------------------------------------------------------*\ +* Creates and sets up a socket +\*-------------------------------------------------------------------------*/ +int socket_create(p_socket ps, int domain, int type, int protocol) { + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) return IO_DONE; + else return WSAGetLastError(); +} + +/*-------------------------------------------------------------------------*\ +* Connects or returns error message +\*-------------------------------------------------------------------------*/ +int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { + int err; + /* don't call on closed socket */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* ask system to connect */ + if (connect(*ps, addr, len) == 0) return IO_DONE; + /* make sure the system is trying to connect */ + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err; + /* zero timeout case optimization */ + if (timeout_iszero(tm)) return IO_TIMEOUT; + /* we wait until something happens */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) { + int len = sizeof(err); + /* give windows time to set the error (yes, disgusting) */ + Sleep(10); + /* find out why we failed */ + getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); + /* we KNOW there was an error. if 'why' is 0, we will return + * "unknown error", but it's not really our fault */ + return err > 0? err: IO_UNKNOWN; + } else return err; + +} + +/*-------------------------------------------------------------------------*\ +* Binds or returns error message +\*-------------------------------------------------------------------------*/ +int socket_bind(p_socket ps, SA *addr, socklen_t len) { + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +int socket_listen(p_socket ps, int backlog) { + int err = IO_DONE; + socket_setblocking(ps); + if (listen(*ps, backlog) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* Accept with timeout +\*-------------------------------------------------------------------------*/ +int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, + p_timeout tm) { + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int err; + /* try to get client socket */ + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; + /* find out why we failed */ + err = WSAGetLastError(); + /* if we failed because there was no connectoin, keep trying */ + if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; + /* call select to avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Send with timeout +* On windows, if you try to send 10MB, the OS will buffer EVERYTHING +* this can take an awful lot of time and we will end up blocked. +* Therefore, whoever calls this function should not pass a huge buffer. +\*-------------------------------------------------------------------------*/ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + /* try to send something */ + int put = send(*ps, data, (int) count, 0); + /* if we sent something, we are done */ + if (put > 0) { + *sent = put; + return IO_DONE; + } + /* deal with failure */ + err = WSAGetLastError(); + /* we can only proceed if there was no serious error */ + if (err != WSAEWOULDBLOCK) return err; + /* avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Sendto with timeout +\*-------------------------------------------------------------------------*/ +int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, + SA *addr, socklen_t len, p_timeout tm) +{ + int err; + *sent = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int put = sendto(*ps, data, (int) count, 0, addr, len); + if (put > 0) { + *sent = put; + return IO_DONE; + } + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK) return err; + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Receive with timeout +\*-------------------------------------------------------------------------*/ +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, + p_timeout tm) +{ + int err, prev = IO_DONE; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int taken = recv(*ps, data, (int) count, 0); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + /* On UDP, a connreset simply means the previous send failed. + * So we try again. + * On TCP, it means our socket is now useless, so the error passes. + * (We will loop again, exiting because the same error will happen) */ + if (err != WSAEWOULDBLOCK) { + if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; + prev = err; + } + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Recvfrom with timeout +\*-------------------------------------------------------------------------*/ +int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, + SA *addr, socklen_t *len, p_timeout tm) +{ + int err, prev = IO_DONE; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int taken = recvfrom(*ps, data, (int) count, 0, addr, len); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + /* On UDP, a connreset simply means the previous send failed. + * So we try again. + * On TCP, it means our socket is now useless, so the error passes. + * (We will loop again, exiting because the same error will happen) */ + if (err != WSAEWOULDBLOCK) { + if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; + prev = err; + } + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Put socket into blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setblocking(p_socket ps) { + u_long argp = 0; + ioctlsocket(*ps, FIONBIO, &argp); +} + +/*-------------------------------------------------------------------------*\ +* Put socket into non-blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setnonblocking(p_socket ps) { + u_long argp = 1; + ioctlsocket(*ps, FIONBIO, &argp); +} + +/*-------------------------------------------------------------------------*\ +* DNS helpers +\*-------------------------------------------------------------------------*/ +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) return IO_DONE; + else return WSAGetLastError(); +} + +int socket_gethostbyname(const char *addr, struct hostent **hp) { + *hp = gethostbyname(addr); + if (*hp) return IO_DONE; + else return WSAGetLastError(); +} + +/*-------------------------------------------------------------------------*\ +* Error translation functions +\*-------------------------------------------------------------------------*/ +const char *socket_hoststrerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; + default: return wstrerror(err); + } +} + +const char *socket_strerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case WSAEADDRINUSE: return PIE_ADDRINUSE; + case WSAECONNREFUSED : return PIE_CONNREFUSED; + case WSAEISCONN: return PIE_ISCONN; + case WSAEACCES: return PIE_ACCESS; + case WSAECONNABORTED: return PIE_CONNABORTED; + case WSAECONNRESET: return PIE_CONNRESET; + case WSAETIMEDOUT: return PIE_TIMEDOUT; + default: return wstrerror(err); + } +} + +const char *socket_ioerror(p_socket ps, int err) { + (void) ps; + return socket_strerror(err); +} + +static const char *wstrerror(int err) { + switch (err) { + case WSAEINTR: return "Interrupted function call"; + case WSAEACCES: return PIE_ACCESS; // "Permission denied"; + case WSAEFAULT: return "Bad address"; + case WSAEINVAL: return "Invalid argument"; + case WSAEMFILE: return "Too many open files"; + case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; + case WSAEINPROGRESS: return "Operation now in progress"; + case WSAEALREADY: return "Operation already in progress"; + case WSAENOTSOCK: return "Socket operation on nonsocket"; + case WSAEDESTADDRREQ: return "Destination address required"; + case WSAEMSGSIZE: return "Message too long"; + case WSAEPROTOTYPE: return "Protocol wrong type for socket"; + case WSAENOPROTOOPT: return "Bad protocol option"; + case WSAEPROTONOSUPPORT: return "Protocol not supported"; + case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; // "Socket type not supported"; + case WSAEOPNOTSUPP: return "Operation not supported"; + case WSAEPFNOSUPPORT: return "Protocol family not supported"; + case WSAEAFNOSUPPORT: return PIE_FAMILY; // "Address family not supported by protocol family"; + case WSAEADDRINUSE: return PIE_ADDRINUSE; // "Address already in use"; + case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; + case WSAENETDOWN: return "Network is down"; + case WSAENETUNREACH: return "Network is unreachable"; + case WSAENETRESET: return "Network dropped connection on reset"; + case WSAECONNABORTED: return "Software caused connection abort"; + case WSAECONNRESET: return PIE_CONNRESET; // "Connection reset by peer"; + case WSAENOBUFS: return "No buffer space available"; + case WSAEISCONN: return PIE_ISCONN; // "Socket is already connected"; + case WSAENOTCONN: return "Socket is not connected"; + case WSAESHUTDOWN: return "Cannot send after socket shutdown"; + case WSAETIMEDOUT: return PIE_TIMEDOUT; // "Connection timed out"; + case WSAECONNREFUSED: return PIE_CONNREFUSED; // "Connection refused"; + case WSAEHOSTDOWN: return "Host is down"; + case WSAEHOSTUNREACH: return "No route to host"; + case WSAEPROCLIM: return "Too many processes"; + case WSASYSNOTREADY: return "Network subsystem is unavailable"; + case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range"; + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performed"; + case WSAEDISCON: return "Graceful shutdown in progress"; + case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; // "Host not found"; + case WSATRY_AGAIN: return "Nonauthoritative host not found"; + case WSANO_RECOVERY: return PIE_FAIL; // "Nonrecoverable name lookup error"; + case WSANO_DATA: return "Valid name, no data record of requested type"; + default: return "Unknown error"; + } +} + +const char *socket_gaistrerror(int err) { + if (err == 0) return NULL; + switch (err) { + case EAI_AGAIN: return PIE_AGAIN; + case EAI_BADFLAGS: return PIE_BADFLAGS; +#ifdef EAI_BADHINTS + case EAI_BADHINTS: return PIE_BADHINTS; +#endif + case EAI_FAIL: return PIE_FAIL; + case EAI_FAMILY: return PIE_FAMILY; + case EAI_MEMORY: return PIE_MEMORY; + case EAI_NONAME: return PIE_NONAME; +#ifdef EAI_OVERFLOW + case EAI_OVERFLOW: return PIE_OVERFLOW; +#endif +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: return PIE_PROTOCOL; +#endif + case EAI_SERVICE: return PIE_SERVICE; + case EAI_SOCKTYPE: return PIE_SOCKTYPE; +#ifdef EAI_SYSTEM + case EAI_SYSTEM: return strerror(errno); +#endif + default: return gai_strerror(err); + } +} + diff --git a/ThirdParty/tolua_runtime/luasocket/wsocket.h b/ThirdParty/tolua_runtime/luasocket/wsocket.h new file mode 100644 index 0000000..3986640 --- /dev/null +++ b/ThirdParty/tolua_runtime/luasocket/wsocket.h @@ -0,0 +1,33 @@ +#ifndef WSOCKET_H +#define WSOCKET_H +/*=========================================================================*\ +* Socket compatibilization module for Win32 +* LuaSocket toolkit +\*=========================================================================*/ + +/*=========================================================================*\ +* WinSock include files +\*=========================================================================*/ +#include <winsock2.h> +#include <ws2tcpip.h> + +typedef int socklen_t; +typedef SOCKADDR_STORAGE t_sockaddr_storage; +typedef SOCKET t_socket; +typedef t_socket *p_socket; + +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +#define SOCKET_INVALID (INVALID_SOCKET) + +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +#ifndef AI_NUMERICSERV +#define AI_NUMERICSERV (0) +#endif + +#endif /* WSOCKET_H */ |