mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-23 11:33:09 +00:00
Compare commits
276 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3a6b8d80b | ||
|
|
672bdcf39f | ||
|
|
d232af70f2 | ||
|
|
c075de7425 | ||
|
|
f2d3bc3e5c | ||
|
|
386c709f42 | ||
|
|
64d6baa176 | ||
|
|
ed6dd39670 | ||
|
|
5527e9e32e | ||
|
|
3c7279a6b7 | ||
|
|
b2e50c3bfa | ||
|
|
99a7d745fb | ||
|
|
b295b875c8 | ||
|
|
a15c64a73b | ||
|
|
b7b595e53a | ||
|
|
0e3f37f38b | ||
|
|
a6293f27cd | ||
|
|
8450e7f366 | ||
|
|
4585da9cbd | ||
|
|
38c47b8a5d | ||
|
|
21d680d5b7 | ||
|
|
ec8e518abc | ||
|
|
082fb732e5 | ||
|
|
b5ea18f44b | ||
|
|
8aac2114e3 | ||
|
|
0e96c761f8 | ||
|
|
60f4f26b85 | ||
|
|
7240de08a9 | ||
|
|
4341106364 | ||
|
|
81a7c44a05 | ||
|
|
80d1082b42 | ||
|
|
9d7ea09789 | ||
|
|
58291a2a48 | ||
|
|
49c21916a2 | ||
|
|
6b4050bf2c | ||
|
|
f4d54182e9 | ||
|
|
f6679a778f | ||
|
|
082430147f | ||
|
|
6dd47e6690 | ||
|
|
d3c4bee0c9 | ||
|
|
15ae26b8bc | ||
|
|
29e7256948 | ||
|
|
4f050fa987 | ||
|
|
066c2c3a54 | ||
|
|
41c66d1b20 | ||
|
|
82ed7efb1b | ||
|
|
f17c17b8c7 | ||
|
|
8a1d7006eb | ||
|
|
4ddc1577ef | ||
|
|
9c4e0d5bb7 | ||
|
|
21b1c449de | ||
|
|
e485aae55b | ||
|
|
5025e6887f | ||
|
|
e4224137f1 | ||
|
|
478575436b | ||
|
|
65eb351a3b | ||
|
|
2e8659d5fc | ||
|
|
baf5987b0b | ||
|
|
7e42653f80 | ||
|
|
89f487e0a4 | ||
|
|
9193035767 | ||
|
|
4fa1ba57cb | ||
|
|
10fd5791f7 | ||
|
|
5d26fb3f18 | ||
|
|
7032f21d18 | ||
|
|
c80b462412 | ||
|
|
744fbea7ee | ||
|
|
5750b2d5ee | ||
|
|
e9581adfc4 | ||
|
|
6803f45aa1 | ||
|
|
8e2facbfb8 | ||
|
|
6f0e88dc59 | ||
|
|
5a0f68999e | ||
|
|
24b333a5e9 | ||
|
|
b45384cc9f | ||
|
|
7fed938593 | ||
|
|
ca4f549f0d | ||
|
|
a04e6b5b29 | ||
|
|
82f3e80e06 | ||
|
|
9ffa0c6e30 | ||
|
|
64d99c1bd5 | ||
|
|
da87df6b86 | ||
|
|
fafc4cad34 | ||
|
|
1b60c522b0 | ||
|
|
a8c1828786 | ||
|
|
ff9b0538a4 | ||
|
|
bed5f878dc | ||
|
|
505da68cb6 | ||
|
|
68e94b2792 | ||
|
|
e3c5d63a97 | ||
|
|
3a0981661c | ||
|
|
47d1047004 | ||
|
|
2bcc691c4d | ||
|
|
76b166f04a | ||
|
|
2ceb642b5d | ||
|
|
2d6d2c75a4 | ||
|
|
194940822e | ||
|
|
be590cfa8c | ||
|
|
6addb504e4 | ||
|
|
db61ec376a | ||
|
|
431feb6f16 | ||
|
|
2c8d373236 | ||
|
|
9b69af0a4d | ||
|
|
046fb69f84 | ||
|
|
6231f1c884 | ||
|
|
35aa00fb13 | ||
|
|
4159600fbc | ||
|
|
04e2a36c4a | ||
|
|
95cb848772 | ||
|
|
302fc580a5 | ||
|
|
3048eed2aa | ||
|
|
e0729a483d | ||
|
|
201becd3d1 | ||
|
|
77e2643728 | ||
|
|
9ba0860c70 | ||
|
|
4c17005c03 | ||
|
|
cf18b59d90 | ||
|
|
fbd932e846 | ||
|
|
8e8a92ca2d | ||
|
|
6ab841beec | ||
|
|
6f40120ad8 | ||
|
|
f8d55affba | ||
|
|
56d24f46d6 | ||
|
|
64e0c4daff | ||
|
|
5bf635c75c | ||
|
|
2011596de0 | ||
|
|
3c6c0f7aa4 | ||
|
|
ea0cc1fade | ||
|
|
ee1f5055ea | ||
|
|
305a29d885 | ||
|
|
2651929f5b | ||
|
|
1af78bc585 | ||
|
|
062f767bbf | ||
|
|
0c66252cd1 | ||
|
|
45afa0fdcf | ||
|
|
4c9c2ac41d | ||
|
|
bfbbe91efa | ||
|
|
eda9f771e6 | ||
|
|
7cb4bbb960 | ||
|
|
2c247b511e | ||
|
|
ea1affda4c | ||
|
|
1c3b563ef8 | ||
|
|
9ffdf2dbde | ||
|
|
000fa2be3a | ||
|
|
7746193b5f | ||
|
|
3f38a711ad | ||
|
|
1d4308f33a | ||
|
|
48e5c36b5e | ||
|
|
1422cae7fb | ||
|
|
9e16b04a5b | ||
|
|
0fbbd5f4d5 | ||
|
|
6eb9b64f06 | ||
|
|
d71c8f8b7d | ||
|
|
68c3762abf | ||
|
|
304272249e | ||
|
|
2102d8b9f0 | ||
|
|
2ee85a91f9 | ||
|
|
8a3a0c1b71 | ||
|
|
b4752f2394 | ||
|
|
f110b51290 | ||
|
|
e0f16b8df5 | ||
|
|
08e56f4316 | ||
|
|
7e57e498f6 | ||
|
|
98b5c7c7c6 | ||
|
|
02d5f4fbe9 | ||
|
|
818ff8314d | ||
|
|
d23e6f8d8e | ||
|
|
f217a56f6e | ||
|
|
46b49adf9e | ||
|
|
d9fb4d06ec | ||
|
|
34a9979255 | ||
|
|
89e7a06deb | ||
|
|
43d02ac456 | ||
|
|
c839159470 | ||
|
|
823b773051 | ||
|
|
f8434d34b6 | ||
|
|
61980c8a1f | ||
|
|
35176383b7 | ||
|
|
c96e20e6c3 | ||
|
|
ce0cdc7bd3 | ||
|
|
7e63080c03 | ||
|
|
1c8ed8a46e | ||
|
|
c4334be9c3 | ||
|
|
e6e69ae805 | ||
|
|
8ce816de7f | ||
|
|
2fb52f6fce | ||
|
|
c72d4d2134 | ||
|
|
18a36c171f | ||
|
|
7b3c1631d1 | ||
|
|
4613fde654 | ||
|
|
143baec319 | ||
|
|
168a07d658 | ||
|
|
281acf4c71 | ||
|
|
d2ab6863e3 | ||
|
|
e55ad63d3c | ||
|
|
ec2eaa70a4 | ||
|
|
d402619347 | ||
|
|
c101d9df17 | ||
|
|
b5653a68ea | ||
|
|
c9942deaa9 | ||
|
|
2df1446c37 | ||
|
|
9421815327 | ||
|
|
1a0c9997ec | ||
|
|
16f060f864 | ||
|
|
ea7c6402dd | ||
|
|
07db2580c4 | ||
|
|
1df72c0afe | ||
|
|
0e41231298 | ||
|
|
8224b5a62a | ||
|
|
d8ab9dea1b | ||
|
|
a8e5c31381 | ||
|
|
3a1556e1fd | ||
|
|
4b5fbab129 | ||
|
|
b1ec1f4d18 | ||
|
|
16d8f4c774 | ||
|
|
f8b5ec48e8 | ||
|
|
7a26926965 | ||
|
|
2990fbc7cf | ||
|
|
e8e38f1682 | ||
|
|
35b4a09c3d | ||
|
|
9035fbe96b | ||
|
|
a41a5fadd2 | ||
|
|
d6f265e703 | ||
|
|
596c77afcd | ||
|
|
e53d985c4f | ||
|
|
348e53245b | ||
|
|
2fde0a0ae4 | ||
|
|
85ec428f3f | ||
|
|
a8ab809928 | ||
|
|
6c7cb5313d | ||
|
|
188e38198a | ||
|
|
294f557268 | ||
|
|
4dd622e180 | ||
|
|
5f8e5f9be5 | ||
|
|
e561896966 | ||
|
|
ea25e20c88 | ||
|
|
003b0fdb02 | ||
|
|
8de6500677 | ||
|
|
7df13e922b | ||
|
|
182d7c7dc7 | ||
|
|
f4d5bc7aa4 | ||
|
|
d53d98b625 | ||
|
|
2bfba716ef | ||
|
|
4cbe33d15d | ||
|
|
a9852273cb | ||
|
|
eb8a2b5e65 | ||
|
|
7304a990cb | ||
|
|
311d7c8f6a | ||
|
|
5a3d2fdac7 | ||
|
|
4b88f68ab8 | ||
|
|
70c224c3e7 | ||
|
|
1932d33b41 | ||
|
|
9cf4525a8f | ||
|
|
0846a6533d | ||
|
|
484404295e | ||
|
|
3e54becb95 | ||
|
|
ab13305b64 | ||
|
|
6fdb123df4 | ||
|
|
6cdc1cf95c | ||
|
|
2dd5a06616 | ||
|
|
e7436bfa95 | ||
|
|
084aab4bcd | ||
|
|
cd99557368 | ||
|
|
04f4004934 | ||
|
|
bbf46f935a | ||
|
|
b792c7144d | ||
|
|
5d5112257c | ||
|
|
747e6c7848 | ||
|
|
45d848c910 | ||
|
|
f12fa7e8f9 | ||
|
|
568a435e9e | ||
|
|
c46f2633be | ||
|
|
b51e28a3e0 | ||
|
|
badfab8561 | ||
|
|
d5c0d687b3 | ||
|
|
57f08426ee |
Submodule 3rd/jemalloc updated: 896ed3a8b3...ea6b3e973b
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
|
||||
** $Id: lapi.c,v 2.259.1.2 2017/12/06 18:35:12 roberto Exp $
|
||||
** Lua API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -534,6 +534,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||
lua_lock(L);
|
||||
if (n == 0) {
|
||||
setfvalue(L->top, fn);
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
CClosure *cl;
|
||||
@@ -547,9 +548,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||
/* does not need barrier because closure is white */
|
||||
}
|
||||
setclCvalue(L, L->top, cl);
|
||||
api_incr_top(L);
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
api_incr_top(L);
|
||||
luaC_checkGC(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
@@ -857,6 +858,8 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
|
||||
}
|
||||
switch (ttnov(obj)) {
|
||||
case LUA_TTABLE: {
|
||||
if (isshared(hvalue(obj)))
|
||||
luaG_runerror(L, "can't setmetatable to shared table");
|
||||
hvalue(obj)->metatable = mt;
|
||||
if (mt) {
|
||||
luaC_objbarrier(L, gcvalue(obj), mt);
|
||||
@@ -1012,46 +1015,15 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
|
||||
return status;
|
||||
}
|
||||
|
||||
static void cloneproto (lua_State *L, Proto *f, const Proto *src) {
|
||||
/* copy constants and nested proto */
|
||||
int i,n;
|
||||
n = src->sp->sizek;
|
||||
f->k=luaM_newvector(L,n,TValue);
|
||||
for (i=0; i<n; i++) setnilvalue(&f->k[i]);
|
||||
for (i=0; i<n; i++) {
|
||||
const TValue *s=&src->k[i];
|
||||
TValue *o=&f->k[i];
|
||||
if (ttisstring(s)) {
|
||||
TString * str = luaS_clonestring(L,tsvalue(s));
|
||||
setsvalue2n(L,o,str);
|
||||
} else {
|
||||
setobj(L,o,s);
|
||||
}
|
||||
}
|
||||
n = src->sp->sizep;
|
||||
f->p=luaM_newvector(L,n,struct Proto *);
|
||||
for (i=0; i<n; i++) f->p[i]=NULL;
|
||||
for (i=0; i<n; i++) {
|
||||
f->p[i]= luaF_newproto(L, src->p[i]->sp);
|
||||
cloneproto(L, f->p[i], src->p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
|
||||
LClosure *cl;
|
||||
LClosure *f = cast(LClosure *, fp);
|
||||
api_check(L, isshared(f->p), "Not a shared proto");
|
||||
lua_lock(L);
|
||||
if (f->p->sp->l_G == G(L)) {
|
||||
setclLvalue(L,L->top,f);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
return;
|
||||
}
|
||||
cl = luaF_newLclosure(L,f->nupvalues);
|
||||
setclLvalue(L,L->top,cl);
|
||||
api_incr_top(L);
|
||||
cl->p = luaF_newproto(L, f->p->sp);
|
||||
cloneproto(L, cl->p, f->p);
|
||||
cl->p = f->p;
|
||||
luaF_initupvals(L, cl);
|
||||
|
||||
if (cl->nupvalues >= 1) { /* does it have an upvalue? */
|
||||
@@ -1065,6 +1037,34 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
LUA_API void lua_sharefunction (lua_State *L, int index) {
|
||||
if (!lua_isfunction(L,index) || lua_iscfunction(L,index))
|
||||
luaG_runerror(L, "Only Lua function can share");
|
||||
LClosure *f = cast(LClosure *, lua_topointer(L, index));
|
||||
luaF_shareproto(f->p);
|
||||
}
|
||||
|
||||
LUA_API void lua_sharestring (lua_State *L, int index) {
|
||||
const char *str = lua_tostring(L, index);
|
||||
if (str == NULL)
|
||||
luaG_runerror(L, "need a string to share");
|
||||
|
||||
TString *ts = (TString *)(str - sizeof(UTString));
|
||||
luaS_share(ts);
|
||||
}
|
||||
|
||||
LUA_API void lua_clonetable(lua_State *L, const void * tp) {
|
||||
Table *t = cast(Table *, tp);
|
||||
|
||||
if (!isshared(t))
|
||||
luaG_runerror(L, "Not a shared table");
|
||||
|
||||
lua_lock(L);
|
||||
sethvalue(L, L->top, t);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
|
||||
int status;
|
||||
TValue *o;
|
||||
@@ -1259,7 +1259,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
|
||||
case LUA_TLCL: { /* Lua closure */
|
||||
LClosure *f = clLvalue(fi);
|
||||
TString *name;
|
||||
SharedProto *p = f->p->sp;
|
||||
Proto *p = f->p;
|
||||
if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
|
||||
*val = f->upvals[n-1]->v;
|
||||
if (uv) *uv = f->upvals[n - 1];
|
||||
@@ -1311,7 +1311,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
|
||||
StkId fi = index2addr(L, fidx);
|
||||
api_check(L, ttisLclosure(fi), "Lua function expected");
|
||||
f = clLvalue(fi);
|
||||
api_check(L, (1 <= n && n <= f->p->sp->sizeupvalues), "invalid upvalue index");
|
||||
api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
|
||||
if (pf) *pf = f;
|
||||
return &f->upvals[n - 1]; /* get its upvalue pointer */
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $
|
||||
** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Auxiliary functions from Lua API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $
|
||||
** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -699,8 +699,7 @@ static int skipcomment (LoadF *lf, int *cp) {
|
||||
else return 0; /* no comment */
|
||||
}
|
||||
|
||||
|
||||
static int luaL_loadfilex_ (lua_State *L, const char *filename,
|
||||
LUALIB_API int luaL_loadfilex_ (lua_State *L, const char *filename,
|
||||
const char *mode) {
|
||||
LoadF lf;
|
||||
int status, readstatus;
|
||||
@@ -1064,10 +1063,14 @@ clearcache() {
|
||||
|
||||
static void
|
||||
init() {
|
||||
SPIN_INIT(&CC);
|
||||
CC.L = luaL_newstate();
|
||||
}
|
||||
|
||||
LUALIB_API void
|
||||
luaL_initcodecache(void) {
|
||||
SPIN_INIT(&CC);
|
||||
}
|
||||
|
||||
static const void *
|
||||
load(const char *key) {
|
||||
if (CC.L == NULL)
|
||||
@@ -1091,21 +1094,20 @@ save(const char *key, const void * proto) {
|
||||
SPIN_LOCK(&CC)
|
||||
if (CC.L == NULL) {
|
||||
init();
|
||||
L = CC.L;
|
||||
} else {
|
||||
L = CC.L;
|
||||
lua_pushstring(L, key);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
result = lua_touserdata(L, -1); /* stack: key oldvalue */
|
||||
if (result == NULL) {
|
||||
lua_pop(L,1);
|
||||
lua_pushlightuserdata(L, (void *)proto);
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
} else {
|
||||
lua_pop(L,2);
|
||||
}
|
||||
}
|
||||
L = CC.L;
|
||||
lua_pushstring(L, key);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
result = lua_touserdata(L, -1); /* stack: key oldvalue */
|
||||
if (result == NULL) {
|
||||
lua_pop(L,1);
|
||||
lua_pushlightuserdata(L, (void *)proto);
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
} else {
|
||||
lua_pop(L,2);
|
||||
}
|
||||
|
||||
SPIN_UNLOCK(&CC)
|
||||
return result;
|
||||
}
|
||||
@@ -1179,6 +1181,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
||||
lua_close(eL);
|
||||
return err;
|
||||
}
|
||||
lua_sharefunction(eL, -1);
|
||||
proto = lua_topointer(eL, -1);
|
||||
const void * oldv = save(filename, proto);
|
||||
if (oldv) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lauxlib.h,v 1.131 2016/12/06 14:54:31 roberto Exp $
|
||||
** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -82,6 +82,8 @@ LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
|
||||
|
||||
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
|
||||
const char *mode);
|
||||
LUALIB_API int (luaL_loadfilex_) (lua_State *L, const char *filename,
|
||||
const char *mode);
|
||||
|
||||
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp $
|
||||
** $Id: lbaselib.c,v 1.314.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Basic library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $
|
||||
** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Standard library for bitwise operations
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lcode.c,v 2.112 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -65,7 +65,7 @@ void luaK_nil (FuncState *fs, int from, int n) {
|
||||
Instruction *previous;
|
||||
int l = from + n - 1; /* last register to set nil */
|
||||
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
|
||||
previous = &fs->f->sp->code[fs->pc-1];
|
||||
previous = &fs->f->code[fs->pc-1];
|
||||
if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
|
||||
int pfrom = GETARG_A(*previous); /* get previous range */
|
||||
int pl = pfrom + GETARG_B(*previous);
|
||||
@@ -88,7 +88,7 @@ void luaK_nil (FuncState *fs, int from, int n) {
|
||||
** a list of jumps.
|
||||
*/
|
||||
static int getjump (FuncState *fs, int pc) {
|
||||
int offset = GETARG_sBx(fs->f->sp->code[pc]);
|
||||
int offset = GETARG_sBx(fs->f->code[pc]);
|
||||
if (offset == NO_JUMP) /* point to itself represents end of list */
|
||||
return NO_JUMP; /* end of list */
|
||||
else
|
||||
@@ -101,7 +101,7 @@ static int getjump (FuncState *fs, int pc) {
|
||||
** (Jump addresses are relative in Lua)
|
||||
*/
|
||||
static void fixjump (FuncState *fs, int pc, int dest) {
|
||||
Instruction *jmp = &fs->f->sp->code[pc];
|
||||
Instruction *jmp = &fs->f->code[pc];
|
||||
int offset = dest - (pc + 1);
|
||||
lua_assert(dest != NO_JUMP);
|
||||
if (abs(offset) > MAXARG_sBx)
|
||||
@@ -177,7 +177,7 @@ int luaK_getlabel (FuncState *fs) {
|
||||
** unconditional.
|
||||
*/
|
||||
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
|
||||
Instruction *pi = &fs->f->sp->code[pc];
|
||||
Instruction *pi = &fs->f->code[pc];
|
||||
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
|
||||
return pi-1;
|
||||
else
|
||||
@@ -278,10 +278,10 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
|
||||
void luaK_patchclose (FuncState *fs, int list, int level) {
|
||||
level++; /* argument is +1 to reserve 0 as non-op */
|
||||
for (; list != NO_JUMP; list = getjump(fs, list)) {
|
||||
lua_assert(GET_OPCODE(fs->f->sp->code[list]) == OP_JMP &&
|
||||
(GETARG_A(fs->f->sp->code[list]) == 0 ||
|
||||
GETARG_A(fs->f->sp->code[list]) >= level));
|
||||
SETARG_A(fs->f->sp->code[list], level);
|
||||
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
|
||||
(GETARG_A(fs->f->code[list]) == 0 ||
|
||||
GETARG_A(fs->f->code[list]) >= level));
|
||||
SETARG_A(fs->f->code[list], level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,13 +294,13 @@ static int luaK_code (FuncState *fs, Instruction i) {
|
||||
Proto *f = fs->f;
|
||||
dischargejpc(fs); /* 'pc' will change */
|
||||
/* put new instruction in code array */
|
||||
luaM_growvector(fs->ls->L, f->sp->code, fs->pc, f->sp->sizecode, Instruction,
|
||||
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
|
||||
MAX_INT, "opcodes");
|
||||
f->sp->code[fs->pc] = i;
|
||||
f->code[fs->pc] = i;
|
||||
/* save corresponding line information */
|
||||
luaM_growvector(fs->ls->L, f->sp->lineinfo, fs->pc, f->sp->sizelineinfo, int,
|
||||
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
|
||||
MAX_INT, "opcodes");
|
||||
f->sp->lineinfo[fs->pc] = fs->ls->lastline;
|
||||
f->lineinfo[fs->pc] = fs->ls->lastline;
|
||||
return fs->pc++;
|
||||
}
|
||||
|
||||
@@ -360,11 +360,11 @@ int luaK_codek (FuncState *fs, int reg, int k) {
|
||||
*/
|
||||
void luaK_checkstack (FuncState *fs, int n) {
|
||||
int newstack = fs->freereg + n;
|
||||
if (newstack > fs->f->sp->maxstacksize) {
|
||||
if (newstack > fs->f->maxstacksize) {
|
||||
if (newstack >= MAXREGS)
|
||||
luaX_syntaxerror(fs->ls,
|
||||
"function or expression needs too many registers");
|
||||
fs->f->sp->maxstacksize = cast_byte(newstack);
|
||||
fs->f->maxstacksize = cast_byte(newstack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,13 +438,13 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
|
||||
return k; /* reuse index */
|
||||
}
|
||||
/* constant not found; create a new entry */
|
||||
oldsize = f->sp->sizek;
|
||||
oldsize = f->sizek;
|
||||
k = fs->nk;
|
||||
/* numerical value does not need GC barrier;
|
||||
table has no metatable, so it does not need to invalidate cache */
|
||||
setivalue(idx, k);
|
||||
luaM_growvector(L, f->k, k, f->sp->sizek, TValue, MAXARG_Ax, "constants");
|
||||
while (oldsize < f->sp->sizek) setnilvalue(&f->k[oldsize++]);
|
||||
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
|
||||
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
|
||||
setobj(L, &f->k[k], v);
|
||||
fs->nk++;
|
||||
luaC_barrier(L, f, v);
|
||||
@@ -1175,7 +1175,7 @@ void luaK_posfix (FuncState *fs, BinOpr op,
|
||||
** Change line information associated with current position.
|
||||
*/
|
||||
void luaK_fixline (FuncState *fs, int line) {
|
||||
fs->f->sp->lineinfo[fs->pc - 1] = line;
|
||||
fs->f->lineinfo[fs->pc - 1] = line;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
|
||||
** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -41,7 +41,7 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
|
||||
|
||||
|
||||
/* get (pointer to) instruction of given 'expdesc' */
|
||||
#define getinstruction(fs,e) ((fs)->f->sp->code[(e)->u.info])
|
||||
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
|
||||
|
||||
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
|
||||
** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Coroutine Library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $
|
||||
** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** 'ctype' functions for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $
|
||||
** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $
|
||||
** 'ctype' functions for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $
|
||||
** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Interface from Lua to its debug API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp $
|
||||
** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $
|
||||
** Debug Interface
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -125,14 +125,14 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
|
||||
|
||||
|
||||
static const char *upvalname (Proto *p, int uv) {
|
||||
TString *s = check_exp(uv < p->sp->sizeupvalues, p->sp->upvalues[uv].name);
|
||||
TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
|
||||
if (s == NULL) return "?";
|
||||
else return getstr(s);
|
||||
}
|
||||
|
||||
|
||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||
int nparams = clLvalue(ci->func)->p->sp->numparams;
|
||||
int nparams = clLvalue(ci->func)->p->numparams;
|
||||
if (n >= cast_int(ci->u.l.base - ci->func) - nparams)
|
||||
return NULL; /* no such vararg */
|
||||
else {
|
||||
@@ -216,7 +216,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||
ar->what = "C";
|
||||
}
|
||||
else {
|
||||
SharedProto *p = cl->l.p->sp;
|
||||
Proto *p = cl->l.p;
|
||||
ar->source = p->source ? getstr(p->source) : "=?";
|
||||
ar->linedefined = p->linedefined;
|
||||
ar->lastlinedefined = p->lastlinedefined;
|
||||
@@ -234,12 +234,12 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
else {
|
||||
int i;
|
||||
TValue v;
|
||||
int *lineinfo = f->l.p->sp->lineinfo;
|
||||
int *lineinfo = f->l.p->lineinfo;
|
||||
Table *t = luaH_new(L); /* new table to store active lines */
|
||||
sethvalue(L, L->top, t); /* push it on stack */
|
||||
api_incr_top(L);
|
||||
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
|
||||
for (i = 0; i < f->l.p->sp->sizelineinfo; i++) /* for all lines with code */
|
||||
for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
|
||||
luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
|
||||
}
|
||||
}
|
||||
@@ -279,8 +279,8 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
ar->nparams = 0;
|
||||
}
|
||||
else {
|
||||
ar->isvararg = f->l.p->sp->is_vararg;
|
||||
ar->nparams = f->l.p->sp->numparams;
|
||||
ar->isvararg = f->l.p->is_vararg;
|
||||
ar->nparams = f->l.p->numparams;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -387,7 +387,7 @@ static int findsetreg (Proto *p, int lastpc, int reg) {
|
||||
int setreg = -1; /* keep last instruction that changed 'reg' */
|
||||
int jmptarget = 0; /* any code before this address is conditional */
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
Instruction i = p->sp->code[pc];
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
int a = GETARG_A(i);
|
||||
switch (op) {
|
||||
@@ -437,7 +437,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
|
||||
/* else try symbolic execution */
|
||||
pc = findsetreg(p, lastpc, reg);
|
||||
if (pc != -1) { /* could find instruction? */
|
||||
Instruction i = p->sp->code[pc];
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
switch (op) {
|
||||
case OP_MOVE: {
|
||||
@@ -463,7 +463,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
|
||||
case OP_LOADK:
|
||||
case OP_LOADKX: {
|
||||
int b = (op == OP_LOADK) ? GETARG_Bx(i)
|
||||
: GETARG_Ax(p->sp->code[pc + 1]);
|
||||
: GETARG_Ax(p->code[pc + 1]);
|
||||
if (ttisstring(&p->k[b])) {
|
||||
*name = svalue(&p->k[b]);
|
||||
return "constant";
|
||||
@@ -493,7 +493,7 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
||||
TMS tm = (TMS)0; /* (initial value avoids warnings) */
|
||||
Proto *p = ci_func(ci)->p; /* calling function */
|
||||
int pc = currentpc(ci); /* calling instruction index */
|
||||
Instruction i = p->sp->code[pc]; /* calling instruction */
|
||||
Instruction i = p->code[pc]; /* calling instruction */
|
||||
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
|
||||
*name = "?";
|
||||
return "hook";
|
||||
@@ -658,7 +658,7 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
|
||||
va_end(argp);
|
||||
if (isLua(ci)) /* if Lua function, add source:line information */
|
||||
luaG_addinfo(L, msg, ci_func(ci)->p->sp->source, currentline(ci));
|
||||
luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
|
||||
luaG_errormsg(L);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $
|
||||
** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Auxiliary functions from Debug Interface module
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -11,9 +11,9 @@
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
#define pcRel(pc, p) (cast(int, (pc) - (p)->sp->code) - 1)
|
||||
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
|
||||
|
||||
#define getfuncline(f,pc) (((f)->sp->lineinfo) ? (f)->sp->lineinfo[pc] : -1)
|
||||
#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1)
|
||||
|
||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldo.c,v 2.157 2016/12/13 15:52:21 roberto Exp $
|
||||
** $Id: ldo.c,v 2.157.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -290,7 +290,7 @@ static void callhook (lua_State *L, CallInfo *ci) {
|
||||
}
|
||||
|
||||
|
||||
static StkId adjust_varargs (lua_State *L, SharedProto *p, int actual) {
|
||||
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
||||
int i;
|
||||
int nfixargs = p->numparams;
|
||||
StkId base, fixed;
|
||||
@@ -439,7 +439,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
}
|
||||
case LUA_TLCL: { /* Lua function: prepare its call */
|
||||
StkId base;
|
||||
SharedProto *p = clLvalue(func)->p->sp;
|
||||
Proto *p = clLvalue(func)->p;
|
||||
int n = cast_int(L->top - func) - 1; /* number of real arguments */
|
||||
int fsize = p->maxstacksize; /* frame size */
|
||||
checkstackp(L, fsize, func);
|
||||
@@ -775,7 +775,7 @@ static void f_parser (lua_State *L, void *ud) {
|
||||
checkmode(L, p->mode, "text");
|
||||
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
|
||||
}
|
||||
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
|
||||
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
||||
luaF_initupvals(L, cl);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
|
||||
** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $
|
||||
** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** save precompiled Lua chunks
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -87,7 +87,7 @@ static void DumpString (const TString *s, DumpState *D) {
|
||||
}
|
||||
|
||||
|
||||
static void DumpCode (const SharedProto *f, DumpState *D) {
|
||||
static void DumpCode (const Proto *f, DumpState *D) {
|
||||
DumpInt(f->sizecode, D);
|
||||
DumpVector(f->code, f->sizecode, D);
|
||||
}
|
||||
@@ -97,7 +97,7 @@ static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
|
||||
|
||||
static void DumpConstants (const Proto *f, DumpState *D) {
|
||||
int i;
|
||||
int n = f->sp->sizek;
|
||||
int n = f->sizek;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++) {
|
||||
const TValue *o = &f->k[i];
|
||||
@@ -127,14 +127,14 @@ static void DumpConstants (const Proto *f, DumpState *D) {
|
||||
|
||||
static void DumpProtos (const Proto *f, DumpState *D) {
|
||||
int i;
|
||||
int n = f->sp->sizep;
|
||||
int n = f->sizep;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++)
|
||||
DumpFunction(f->p[i], f->sp->source, D);
|
||||
DumpFunction(f->p[i], f->source, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpUpvalues (const SharedProto *f, DumpState *D) {
|
||||
static void DumpUpvalues (const Proto *f, DumpState *D) {
|
||||
int i, n = f->sizeupvalues;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++) {
|
||||
@@ -144,7 +144,7 @@ static void DumpUpvalues (const SharedProto *f, DumpState *D) {
|
||||
}
|
||||
|
||||
|
||||
static void DumpDebug (const SharedProto *f, DumpState *D) {
|
||||
static void DumpDebug (const Proto *f, DumpState *D) {
|
||||
int i, n;
|
||||
n = (D->strip) ? 0 : f->sizelineinfo;
|
||||
DumpInt(n, D);
|
||||
@@ -163,8 +163,7 @@ static void DumpDebug (const SharedProto *f, DumpState *D) {
|
||||
}
|
||||
|
||||
|
||||
static void DumpFunction (const Proto *fp, TString *psource, DumpState *D) {
|
||||
const SharedProto *f = fp->sp;
|
||||
static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
|
||||
if (D->strip || f->source == psource)
|
||||
DumpString(NULL, D); /* no debug info or same source as its parent */
|
||||
else
|
||||
@@ -175,9 +174,9 @@ static void DumpFunction (const Proto *fp, TString *psource, DumpState *D) {
|
||||
DumpByte(f->is_vararg, D);
|
||||
DumpByte(f->maxstacksize, D);
|
||||
DumpCode(f, D);
|
||||
DumpConstants(fp, D);
|
||||
DumpConstants(f, D);
|
||||
DumpUpvalues(f, D);
|
||||
DumpProtos(fp, D);
|
||||
DumpProtos(f, D);
|
||||
DumpDebug(f, D);
|
||||
}
|
||||
|
||||
@@ -209,7 +208,7 @@ int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
|
||||
D.strip = strip;
|
||||
D.status = 0;
|
||||
DumpHeader(&D);
|
||||
DumpByte(f->sp->sizeupvalues, &D);
|
||||
DumpByte(f->sizeupvalues, &D);
|
||||
DumpFunction(f, NULL, &D);
|
||||
return D.status;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $
|
||||
** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
|
||||
|
||||
|
||||
@@ -96,63 +97,48 @@ void luaF_close (lua_State *L, StkId level) {
|
||||
}
|
||||
|
||||
|
||||
Proto *luaF_newproto (lua_State *L, SharedProto *sp) {
|
||||
Proto *luaF_newproto (lua_State *L) {
|
||||
GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));
|
||||
Proto *f = gco2p(o);
|
||||
f->sp = NULL;
|
||||
f->k = NULL;
|
||||
f->sizek = 0;
|
||||
f->p = NULL;
|
||||
f->cache = NULL;
|
||||
if (sp == NULL) {
|
||||
sp = luaM_new(L, SharedProto);
|
||||
sp->l_G = G(L);
|
||||
sp->sizek = 0;
|
||||
sp->sizep = 0;
|
||||
sp->code = NULL;
|
||||
sp->sizecode = 0;
|
||||
sp->lineinfo = NULL;
|
||||
sp->sizelineinfo = 0;
|
||||
sp->upvalues = NULL;
|
||||
sp->sizeupvalues = 0;
|
||||
sp->numparams = 0;
|
||||
sp->is_vararg = 0;
|
||||
sp->maxstacksize = 0;
|
||||
sp->locvars = NULL;
|
||||
sp->sizelocvars = 0;
|
||||
sp->linedefined = 0;
|
||||
sp->lastlinedefined = 0;
|
||||
sp->source = NULL;
|
||||
}
|
||||
f->sp = sp;
|
||||
f->sizep = 0;
|
||||
f->code = NULL;
|
||||
f->sizecode = 0;
|
||||
f->lineinfo = NULL;
|
||||
f->sizelineinfo = 0;
|
||||
f->upvalues = NULL;
|
||||
f->sizeupvalues = 0;
|
||||
f->numparams = 0;
|
||||
f->is_vararg = 0;
|
||||
f->maxstacksize = 0;
|
||||
f->locvars = NULL;
|
||||
f->sizelocvars = 0;
|
||||
f->linedefined = 0;
|
||||
f->lastlinedefined = 0;
|
||||
f->source = NULL;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
static void freesharedproto (lua_State *L, SharedProto *f) {
|
||||
if (f == NULL || G(L) != f->l_G)
|
||||
return;
|
||||
void luaF_freeproto (lua_State *L, Proto *f) {
|
||||
luaM_freearray(L, f->code, f->sizecode);
|
||||
luaM_freearray(L, f->p, f->sizep);
|
||||
luaM_freearray(L, f->k, f->sizek);
|
||||
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
|
||||
luaM_freearray(L, f->locvars, f->sizelocvars);
|
||||
luaM_freearray(L, f->upvalues, f->sizeupvalues);
|
||||
luaM_free(L, f);
|
||||
}
|
||||
|
||||
void luaF_freeproto (lua_State *L, Proto *f) {
|
||||
luaM_freearray(L, f->p, f->sp->sizep);
|
||||
luaM_freearray(L, f->k, f->sp->sizek);
|
||||
freesharedproto(L, f->sp);
|
||||
luaM_free(L, f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Look for n-th local variable at line 'line' in function 'func'.
|
||||
** Returns NULL if not found.
|
||||
*/
|
||||
const char *luaF_getlocalname (const Proto *fp, int local_number, int pc) {
|
||||
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
|
||||
int i;
|
||||
const SharedProto *f = fp->sp;
|
||||
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
|
||||
if (pc < f->locvars[i].endpc) { /* is variable active? */
|
||||
local_number--;
|
||||
@@ -163,3 +149,20 @@ const char *luaF_getlocalname (const Proto *fp, int local_number, int pc) {
|
||||
return NULL; /* not found */
|
||||
}
|
||||
|
||||
void luaF_shareproto (Proto *f) {
|
||||
int i;
|
||||
if (f == NULL)
|
||||
return;
|
||||
makeshared(f);
|
||||
luaS_share(f->source);
|
||||
for (i = 0; i < f->sizek; i++) {
|
||||
if (ttnov(&f->k[i]) == LUA_TSTRING)
|
||||
luaS_share(tsvalue(&f->k[i]));
|
||||
}
|
||||
for (i = 0; i < f->sizeupvalues; i++)
|
||||
luaS_share(f->upvalues[i].name);
|
||||
for (i = 0; i < f->sizelocvars; i++)
|
||||
luaS_share(f->locvars[i].varname);
|
||||
for (i = 0; i < f->sizep; i++)
|
||||
luaF_shareproto(f->p[i]);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $
|
||||
** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -47,7 +47,7 @@ struct UpVal {
|
||||
#define upisopen(up) ((up)->v != &(up)->u.value)
|
||||
|
||||
|
||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L, SharedProto *sp);
|
||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||
LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
|
||||
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
|
||||
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
|
||||
@@ -56,6 +56,7 @@ LUAI_FUNC void luaF_close (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||
int pc);
|
||||
LUAI_FUNC void luaF_shareproto (Proto *func);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lgc.c,v 2.215.1.2 2017/08/31 16:15:27 roberto Exp $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -65,7 +65,7 @@
|
||||
*/
|
||||
#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS))
|
||||
#define makewhite(g,x) \
|
||||
(x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g)))
|
||||
(x->marked = cast_byte((x->marked & maskcolors) | (x->marked & bitmask(SHAREBIT)) | luaC_white(g)))
|
||||
|
||||
#define white2gray(x) resetbits(x->marked, WHITEBITS)
|
||||
#define black2gray(x) resetbit(x->marked, BLACKBIT)
|
||||
@@ -193,8 +193,7 @@ void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
|
||||
|
||||
void luaC_fix (lua_State *L, GCObject *o) {
|
||||
global_State *g = G(L);
|
||||
if (g->allgc != o)
|
||||
return; /* if object is not 1st in 'allgc' list, it is in global short string table */
|
||||
lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
|
||||
white2gray(o); /* they will be gray forever */
|
||||
g->allgc = o->next; /* remove object from 'allgc' list */
|
||||
o->next = g->fixedgc; /* link it to 'fixedgc' list */
|
||||
@@ -235,6 +234,8 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
|
||||
*/
|
||||
static void reallymarkobject (global_State *g, GCObject *o) {
|
||||
reentry:
|
||||
if (isshared(o))
|
||||
return;
|
||||
white2gray(o);
|
||||
switch (o->tt) {
|
||||
case LUA_TSHRSTR: {
|
||||
@@ -471,20 +472,6 @@ static lu_mem traversetable (global_State *g, Table *h) {
|
||||
sizeof(Node) * cast(size_t, allocsizenode(h));
|
||||
}
|
||||
|
||||
static int marksharedproto (global_State *g, SharedProto *f) {
|
||||
int i;
|
||||
if (g != f->l_G)
|
||||
return 0;
|
||||
markobjectN(g, f->source);
|
||||
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
|
||||
markobjectN(g, f->upvalues[i].name);
|
||||
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
|
||||
markobjectN(g, f->locvars[i].varname);
|
||||
return sizeof(Instruction) * f->sizecode +
|
||||
sizeof(int) * f->sizelineinfo +
|
||||
sizeof(LocVar) * f->sizelocvars +
|
||||
sizeof(Upvaldesc) * f->sizeupvalues;
|
||||
}
|
||||
|
||||
/*
|
||||
** Traverse a prototype. (While a prototype is being build, its
|
||||
@@ -492,20 +479,22 @@ static int marksharedproto (global_State *g, SharedProto *f) {
|
||||
** NULL, so the use of 'markobjectN')
|
||||
*/
|
||||
static int traverseproto (global_State *g, Proto *f) {
|
||||
int i,nk,np;
|
||||
if (f->cache && iswhite(f->cache))
|
||||
f->cache = NULL; /* allow cache to be collected */
|
||||
if (f->sp == NULL)
|
||||
return sizeof(Proto);
|
||||
nk = (f->k == NULL) ? 0 : f->sp->sizek;
|
||||
np = (f->p == NULL) ? 0 : f->sp->sizep;
|
||||
for (i = 0; i < nk; i++) /* mark literals */
|
||||
int i;
|
||||
markobjectN(g, f->source);
|
||||
for (i = 0; i < f->sizek; i++) /* mark literals */
|
||||
markvalue(g, &f->k[i]);
|
||||
for (i = 0; i < np; i++) /* mark nested protos */
|
||||
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
|
||||
markobjectN(g, f->upvalues[i].name);
|
||||
for (i = 0; i < f->sizep; i++) /* mark nested protos */
|
||||
markobjectN(g, f->p[i]);
|
||||
return sizeof(Proto) + sizeof(Proto *) * np +
|
||||
sizeof(TValue) * nk +
|
||||
marksharedproto(g, f->sp);
|
||||
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
|
||||
markobjectN(g, f->locvars[i].varname);
|
||||
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
|
||||
sizeof(Proto *) * f->sizep +
|
||||
sizeof(TValue) * f->sizek +
|
||||
sizeof(int) * f->sizelineinfo +
|
||||
sizeof(LocVar) * f->sizelocvars +
|
||||
sizeof(Upvaldesc) * f->sizeupvalues;
|
||||
}
|
||||
|
||||
|
||||
@@ -732,8 +721,13 @@ static void freeobj (lua_State *L, GCObject *o) {
|
||||
}
|
||||
|
||||
|
||||
#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
|
||||
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
|
||||
static void sweepwholelist (lua_State *L, GCObject **p) {
|
||||
while (*p != NULL) {
|
||||
GCObject *curr = *p;
|
||||
*p = curr->next; /* remove 'curr' from list */
|
||||
freeobj(L, curr); /* erase 'curr' */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -745,7 +739,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
|
||||
*/
|
||||
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
|
||||
global_State *g = G(L);
|
||||
int ow = otherwhite(g);
|
||||
int ow = otherwhite(g) | bitmask(SHAREBIT); /* shared object never dead */
|
||||
int white = luaC_white(g); /* current white */
|
||||
while (*p != NULL && count-- > 0) {
|
||||
GCObject *curr = *p;
|
||||
@@ -755,7 +749,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
|
||||
freeobj(L, curr); /* erase 'curr' */
|
||||
}
|
||||
else { /* change mark to 'white' */
|
||||
curr->marked = cast_byte((marked & maskcolors) | white);
|
||||
curr->marked = cast_byte((marked & maskcolors) | (marked & bitmask(SHAREBIT)) |white);
|
||||
p = &curr->next; /* go to next element */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
|
||||
** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -79,6 +79,7 @@
|
||||
#define WHITE1BIT 1 /* object is white (type 1) */
|
||||
#define BLACKBIT 2 /* object is black */
|
||||
#define FINALIZEDBIT 3 /* object has been marked for finalization */
|
||||
#define SHAREBIT 4 /* object shared from other state */
|
||||
/* bit 7 is currently used by tests (luaL_checkmemory) */
|
||||
|
||||
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
|
||||
@@ -91,9 +92,11 @@
|
||||
|
||||
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
|
||||
|
||||
#define isshared(x) testbit((x)->marked, SHAREBIT)
|
||||
#define makeshared(x) l_setbit((x)->marked, SHAREBIT)
|
||||
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
|
||||
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
|
||||
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
|
||||
#define isdead(g,v) isdeadm(otherwhite(g) | bitmask(SHAREBIT), (v)->marked)
|
||||
|
||||
#define changewhite(x) ((x)->marked ^= WHITEBITS)
|
||||
#define gray2black(x) l_setbit((x)->marked, BLACKBIT)
|
||||
@@ -116,15 +119,15 @@
|
||||
|
||||
|
||||
#define luaC_barrier(L,p,v) ( \
|
||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v)) && !isshared(gcvalue(v))) ? \
|
||||
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
|
||||
|
||||
#define luaC_barrierback(L,p,v) ( \
|
||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v)) && !isshared(gcvalue(v))) ? \
|
||||
luaC_barrierback_(L,p) : cast_void(0))
|
||||
|
||||
#define luaC_objbarrier(L,p,o) ( \
|
||||
(isblack(p) && iswhite(o)) ? \
|
||||
(isblack(p) && iswhite(o) && !isshared(o)) ? \
|
||||
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
||||
|
||||
#define luaC_upvalbarrier(L,uv) ( \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: linit.c,v 1.39 2016/12/04 20:17:24 roberto Exp $
|
||||
** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Initialization of libraries for lua.c and other clients
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: liolib.c,v 2.151 2016/12/20 18:37:00 roberto Exp $
|
||||
** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $
|
||||
** Standard I/O (and system) library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -206,11 +206,16 @@ static int aux_close (lua_State *L) {
|
||||
}
|
||||
|
||||
|
||||
static int f_close (lua_State *L) {
|
||||
tofile(L); /* make sure argument is an open stream */
|
||||
return aux_close(L);
|
||||
}
|
||||
|
||||
|
||||
static int io_close (lua_State *L) {
|
||||
if (lua_isnone(L, 1)) /* no argument? */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
|
||||
tofile(L); /* make sure argument is an open stream */
|
||||
return aux_close(L);
|
||||
return f_close(L);
|
||||
}
|
||||
|
||||
|
||||
@@ -712,7 +717,7 @@ static const luaL_Reg iolib[] = {
|
||||
** methods for file handles
|
||||
*/
|
||||
static const luaL_Reg flib[] = {
|
||||
{"close", io_close},
|
||||
{"close", f_close},
|
||||
{"flush", f_flush},
|
||||
{"lines", f_lines},
|
||||
{"read", f_read},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
|
||||
** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Lexical Analyzer
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
|
||||
** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Lexical Analyzer
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $
|
||||
** $Id: llimits.h,v 1.141.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Limits, basic types, and some other 'installation-dependent' definitions
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lmathlib.c,v 1.119 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lmathlib.c,v 1.119.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Standard mathematical library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $
|
||||
** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Interface to Memory Manager
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $
|
||||
** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Interface to Memory Manager
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp $
|
||||
** $Id: loadlib.c,v 1.130.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Dynamic library loader for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lobject.c,v 2.113 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lobject.c,v 2.113.1.1 2017/04/19 17:29:57 roberto Exp $
|
||||
** Some generic functions over Lua objects
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -435,7 +435,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
||||
}
|
||||
case 'p': { /* a pointer */
|
||||
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
|
||||
int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
|
||||
void *p = va_arg(argp, void *);
|
||||
int l = lua_pointer2str(buff, sizeof(buff), p);
|
||||
pushstr(L, buff, l);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lobject.h,v 2.117 2016/08/01 19:51:24 roberto Exp $
|
||||
** $Id: lobject.h,v 2.117.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Type definitions for Lua objects
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -189,7 +189,7 @@ typedef struct lua_TValue {
|
||||
|
||||
#define checkliveness(L,obj) \
|
||||
lua_longassert(!iscollectable(obj) || \
|
||||
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
|
||||
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)) || isshared(gcvalue(obj)))))
|
||||
|
||||
|
||||
/* Macros to set values */
|
||||
@@ -305,6 +305,7 @@ typedef struct TString {
|
||||
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
||||
lu_byte shrlen; /* length for short strings */
|
||||
unsigned int hash;
|
||||
size_t id; /* id for short strings */
|
||||
union {
|
||||
size_t lnglen; /* length for long strings */
|
||||
struct TString *hnext; /* linked list for hash table */
|
||||
@@ -400,7 +401,12 @@ typedef struct LocVar {
|
||||
int endpc; /* first point where variable is dead */
|
||||
} LocVar;
|
||||
|
||||
typedef struct SharedProto {
|
||||
|
||||
/*
|
||||
** Function Prototypes
|
||||
*/
|
||||
typedef struct Proto {
|
||||
CommonHeader;
|
||||
lu_byte numparams; /* number of fixed parameters */
|
||||
lu_byte is_vararg;
|
||||
lu_byte maxstacksize; /* number of registers needed by this function */
|
||||
@@ -412,23 +418,13 @@ typedef struct SharedProto {
|
||||
int sizelocvars;
|
||||
int linedefined; /* debug information */
|
||||
int lastlinedefined; /* debug information */
|
||||
void *l_G; /* global state belongs to */
|
||||
TValue *k; /* constants used by the function */
|
||||
Instruction *code; /* opcodes */
|
||||
struct Proto **p; /* functions defined inside the function */
|
||||
int *lineinfo; /* map from opcodes to source lines (debug information) */
|
||||
LocVar *locvars; /* information about local variables (debug information) */
|
||||
Upvaldesc *upvalues; /* upvalue information */
|
||||
TString *source; /* used for debug information */
|
||||
} SharedProto;
|
||||
|
||||
/*
|
||||
** Function Prototypes
|
||||
*/
|
||||
typedef struct Proto {
|
||||
CommonHeader;
|
||||
struct SharedProto *sp;
|
||||
TValue *k; /* constants used by the function */
|
||||
struct Proto **p; /* functions defined inside the function */
|
||||
struct LClosure *cache; /* last-created closure with this prototype */
|
||||
GCObject *gclist;
|
||||
} Proto;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $
|
||||
** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Opcodes for Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $
|
||||
** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Opcodes for Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp $
|
||||
** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $
|
||||
** Standard Operating System library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -293,7 +293,8 @@ static int os_date (lua_State *L) {
|
||||
else
|
||||
stm = l_localtime(&t, &tmr);
|
||||
if (stm == NULL) /* invalid date? */
|
||||
luaL_error(L, "time result cannot be represented in this installation");
|
||||
return luaL_error(L,
|
||||
"time result cannot be represented in this installation");
|
||||
if (strcmp(s, "*t") == 0) {
|
||||
lua_createtable(L, 0, 9); /* 9 = number of fields */
|
||||
setallfields(L, stm);
|
||||
@@ -340,7 +341,8 @@ static int os_time (lua_State *L) {
|
||||
setallfields(L, &ts); /* update fields with normalized values */
|
||||
}
|
||||
if (t != (time_t)(l_timet)t || t == (time_t)(-1))
|
||||
luaL_error(L, "time result cannot be represented in this installation");
|
||||
return luaL_error(L,
|
||||
"time result cannot be represented in this installation");
|
||||
l_pushtime(L, t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lparser.c,v 2.155 2016/08/01 19:51:24 roberto Exp $
|
||||
** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $
|
||||
** Lua Parser
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -79,7 +79,7 @@ static l_noret error_expected (LexState *ls, int token) {
|
||||
static l_noret errorlimit (FuncState *fs, int limit, const char *what) {
|
||||
lua_State *L = fs->ls->L;
|
||||
const char *msg;
|
||||
int line = fs->f->sp->linedefined;
|
||||
int line = fs->f->linedefined;
|
||||
const char *where = (line == 0)
|
||||
? "main function"
|
||||
: luaO_pushfstring(L, "function at line %d", line);
|
||||
@@ -160,15 +160,14 @@ static void checkname (LexState *ls, expdesc *e) {
|
||||
|
||||
static int registerlocalvar (LexState *ls, TString *varname) {
|
||||
FuncState *fs = ls->fs;
|
||||
Proto *fp = fs->f;
|
||||
SharedProto *f = fp->sp;
|
||||
Proto *f = fs->f;
|
||||
int oldsize = f->sizelocvars;
|
||||
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
|
||||
LocVar, SHRT_MAX, "local variables");
|
||||
while (oldsize < f->sizelocvars)
|
||||
f->locvars[oldsize++].varname = NULL;
|
||||
f->locvars[fs->nlocvars].varname = varname;
|
||||
luaC_objbarrier(ls->L, fp, varname);
|
||||
luaC_objbarrier(ls->L, f, varname);
|
||||
return fs->nlocvars++;
|
||||
}
|
||||
|
||||
@@ -196,7 +195,7 @@ static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
|
||||
static LocVar *getlocvar (FuncState *fs, int i) {
|
||||
int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
|
||||
lua_assert(idx < fs->nlocvars);
|
||||
return &fs->f->sp->locvars[idx];
|
||||
return &fs->f->locvars[idx];
|
||||
}
|
||||
|
||||
|
||||
@@ -218,7 +217,7 @@ static void removevars (FuncState *fs, int tolevel) {
|
||||
|
||||
static int searchupvalue (FuncState *fs, TString *name) {
|
||||
int i;
|
||||
Upvaldesc *up = fs->f->sp->upvalues;
|
||||
Upvaldesc *up = fs->f->upvalues;
|
||||
for (i = 0; i < fs->nups; i++) {
|
||||
if (eqstr(up[i].name, name)) return i;
|
||||
}
|
||||
@@ -227,8 +226,7 @@ static int searchupvalue (FuncState *fs, TString *name) {
|
||||
|
||||
|
||||
static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
||||
Proto *fp = fs->f;
|
||||
SharedProto *f = fp->sp;
|
||||
Proto *f = fs->f;
|
||||
int oldsize = f->sizeupvalues;
|
||||
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
|
||||
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
|
||||
@@ -238,7 +236,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
||||
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
|
||||
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
|
||||
f->upvalues[fs->nups].name = name;
|
||||
luaC_objbarrier(fs->ls->L, fp, name);
|
||||
luaC_objbarrier(fs->ls->L, f, name);
|
||||
return fs->nups++;
|
||||
}
|
||||
|
||||
@@ -503,13 +501,13 @@ static Proto *addprototype (LexState *ls) {
|
||||
lua_State *L = ls->L;
|
||||
FuncState *fs = ls->fs;
|
||||
Proto *f = fs->f; /* prototype of current function */
|
||||
if (fs->np >= f->sp->sizep) {
|
||||
int oldsize = f->sp->sizep;
|
||||
luaM_growvector(L, f->p, fs->np, f->sp->sizep, Proto *, MAXARG_Bx, "functions");
|
||||
while (oldsize < f->sp->sizep)
|
||||
if (fs->np >= f->sizep) {
|
||||
int oldsize = f->sizep;
|
||||
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
|
||||
while (oldsize < f->sizep)
|
||||
f->p[oldsize++] = NULL;
|
||||
}
|
||||
f->p[fs->np++] = clp = luaF_newproto(L, NULL);
|
||||
f->p[fs->np++] = clp = luaF_newproto(L);
|
||||
luaC_objbarrier(L, f, clp);
|
||||
return clp;
|
||||
}
|
||||
@@ -529,7 +527,7 @@ static void codeclosure (LexState *ls, expdesc *v) {
|
||||
|
||||
|
||||
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
||||
SharedProto *f;
|
||||
Proto *f;
|
||||
fs->prev = ls->fs; /* linked list of funcstates */
|
||||
fs->ls = ls;
|
||||
ls->fs = fs;
|
||||
@@ -544,7 +542,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
||||
fs->nactvar = 0;
|
||||
fs->firstlocal = ls->dyd->actvar.n;
|
||||
fs->bl = NULL;
|
||||
f = fs->f->sp;
|
||||
f = fs->f;
|
||||
f->source = ls->source;
|
||||
f->maxstacksize = 2; /* registers 0/1 are always valid */
|
||||
enterblock(fs, bl, 0);
|
||||
@@ -555,21 +553,20 @@ static void close_func (LexState *ls) {
|
||||
lua_State *L = ls->L;
|
||||
FuncState *fs = ls->fs;
|
||||
Proto *f = fs->f;
|
||||
SharedProto *sp = f->sp;
|
||||
luaK_ret(fs, 0, 0); /* final return */
|
||||
leaveblock(fs);
|
||||
luaM_reallocvector(L, sp->code, sp->sizecode, fs->pc, Instruction);
|
||||
sp->sizecode = fs->pc;
|
||||
luaM_reallocvector(L, sp->lineinfo, sp->sizelineinfo, fs->pc, int);
|
||||
sp->sizelineinfo = fs->pc;
|
||||
luaM_reallocvector(L, f->k, sp->sizek, fs->nk, TValue);
|
||||
sp->sizek = fs->nk;
|
||||
luaM_reallocvector(L, f->p, sp->sizep, fs->np, Proto *);
|
||||
sp->sizep = fs->np;
|
||||
luaM_reallocvector(L, sp->locvars, sp->sizelocvars, fs->nlocvars, LocVar);
|
||||
sp->sizelocvars = fs->nlocvars;
|
||||
luaM_reallocvector(L, sp->upvalues, sp->sizeupvalues, fs->nups, Upvaldesc);
|
||||
sp->sizeupvalues = fs->nups;
|
||||
luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
|
||||
f->sizecode = fs->pc;
|
||||
luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
|
||||
f->sizelineinfo = fs->pc;
|
||||
luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
|
||||
f->sizek = fs->nk;
|
||||
luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
|
||||
f->sizep = fs->np;
|
||||
luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
|
||||
f->sizelocvars = fs->nlocvars;
|
||||
luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
|
||||
f->sizeupvalues = fs->nups;
|
||||
lua_assert(fs->bl == NULL);
|
||||
ls->fs = fs->prev;
|
||||
luaC_checkGC(L);
|
||||
@@ -745,8 +742,8 @@ static void constructor (LexState *ls, expdesc *t) {
|
||||
} while (testnext(ls, ',') || testnext(ls, ';'));
|
||||
check_match(ls, '}', '{', line);
|
||||
lastlistfield(fs, &cc);
|
||||
SETARG_B(fs->f->sp->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
|
||||
SETARG_C(fs->f->sp->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
|
||||
SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
|
||||
SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
|
||||
}
|
||||
|
||||
/* }====================================================================== */
|
||||
@@ -756,7 +753,7 @@ static void constructor (LexState *ls, expdesc *t) {
|
||||
static void parlist (LexState *ls) {
|
||||
/* parlist -> [ param { ',' param } ] */
|
||||
FuncState *fs = ls->fs;
|
||||
SharedProto *f = fs->f->sp;
|
||||
Proto *f = fs->f;
|
||||
int nparams = 0;
|
||||
f->is_vararg = 0;
|
||||
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
||||
@@ -787,7 +784,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
|
||||
FuncState new_fs;
|
||||
BlockCnt bl;
|
||||
new_fs.f = addprototype(ls);
|
||||
new_fs.f->sp->linedefined = line;
|
||||
new_fs.f->linedefined = line;
|
||||
open_func(ls, &new_fs, &bl);
|
||||
checknext(ls, '(');
|
||||
if (ismethod) {
|
||||
@@ -797,7 +794,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
|
||||
parlist(ls);
|
||||
checknext(ls, ')');
|
||||
statlist(ls);
|
||||
new_fs.f->sp->lastlinedefined = ls->linenumber;
|
||||
new_fs.f->lastlinedefined = ls->linenumber;
|
||||
check_match(ls, TK_END, TK_FUNCTION, line);
|
||||
codeclosure(ls, e);
|
||||
close_func(ls);
|
||||
@@ -963,7 +960,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
|
||||
}
|
||||
case TK_DOTS: { /* vararg */
|
||||
FuncState *fs = ls->fs;
|
||||
check_condition(ls, fs->f->sp->is_vararg,
|
||||
check_condition(ls, fs->f->is_vararg,
|
||||
"cannot use '...' outside a vararg function");
|
||||
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
|
||||
break;
|
||||
@@ -1395,7 +1392,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
|
||||
luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */
|
||||
enterblock(fs, &bl, 0); /* must enter block before 'goto' */
|
||||
gotostat(ls, v.t); /* handle goto/break */
|
||||
while (testnext(ls, ';')) {} /* skip semicolons */
|
||||
while (testnext(ls, ';')) {} /* skip colons */
|
||||
if (block_follow(ls, 0)) { /* 'goto' is the entire block? */
|
||||
leaveblock(fs);
|
||||
return; /* and that is it */
|
||||
@@ -1599,7 +1596,7 @@ static void statement (LexState *ls) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_assert(ls->fs->f->sp->maxstacksize >= ls->fs->freereg &&
|
||||
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
|
||||
ls->fs->freereg >= ls->fs->nactvar);
|
||||
ls->fs->freereg = ls->fs->nactvar; /* free registers */
|
||||
leavelevel(ls);
|
||||
@@ -1616,7 +1613,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
||||
BlockCnt bl;
|
||||
expdesc v;
|
||||
open_func(ls, fs, &bl);
|
||||
fs->f->sp->is_vararg = 1; /* main function is always declared vararg */
|
||||
fs->f->is_vararg = 1; /* main function is always declared vararg */
|
||||
init_exp(&v, VLOCAL, 0); /* create and... */
|
||||
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
|
||||
luaX_next(ls); /* read first token */
|
||||
@@ -1636,13 +1633,13 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
lexstate.h = luaH_new(L); /* create table for scanner */
|
||||
sethvalue(L, L->top, lexstate.h); /* anchor it */
|
||||
luaD_inctop(L);
|
||||
funcstate.f = cl->p = luaF_newproto(L, NULL);
|
||||
funcstate.f->sp->source = luaS_new(L, name); /* create and anchor TString */
|
||||
funcstate.f = cl->p = luaF_newproto(L);
|
||||
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
||||
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
|
||||
lexstate.buff = buff;
|
||||
lexstate.dyd = dyd;
|
||||
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
|
||||
luaX_setinput(L, &lexstate, z, funcstate.f->sp->source, firstchar);
|
||||
luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
|
||||
mainfunc(&lexstate, &funcstate);
|
||||
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
||||
/* all scopes should be correctly finished */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
|
||||
** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Lua Parser
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $
|
||||
** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Definitions for Lua code that must come before any other header file
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $
|
||||
** $Id: lstate.c,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -70,27 +70,6 @@ typedef struct LG {
|
||||
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
|
||||
|
||||
|
||||
/*
|
||||
** Compute an initial seed as random as possible. Rely on Address Space
|
||||
** Layout Randomization (if present) to increase randomness..
|
||||
*/
|
||||
#define addbuff(b,p,e) \
|
||||
{ size_t t = cast(size_t, e); \
|
||||
memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
|
||||
|
||||
static unsigned int makeseed (lua_State *L) {
|
||||
char buff[4 * sizeof(size_t)];
|
||||
unsigned int h = luai_makeseed();
|
||||
int p = 0;
|
||||
addbuff(buff, p, L); /* heap variable */
|
||||
addbuff(buff, p, &h); /* local variable */
|
||||
addbuff(buff, p, luaO_nilobject); /* global variable */
|
||||
addbuff(buff, p, &lua_newstate); /* public function */
|
||||
lua_assert(p == sizeof(buff));
|
||||
return luaS_hash(buff, p, h);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
|
||||
** invariant (and avoiding underflows in 'totalbytes')
|
||||
@@ -308,7 +287,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
||||
g->frealloc = f;
|
||||
g->ud = ud;
|
||||
g->mainthread = L;
|
||||
g->seed = makeseed(L);
|
||||
g->gcrunning = 0; /* no GC while building state */
|
||||
g->GCestimate = 0;
|
||||
g->strt.size = g->strt.nuse = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstate.h,v 2.133 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lstate.h,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -26,6 +26,24 @@
|
||||
** 'tobefnz': all objects ready to be finalized;
|
||||
** 'fixedgc': all objects that are not to be collected (currently
|
||||
** only small strings, such as reserved words).
|
||||
**
|
||||
** Moreover, there is another set of lists that control gray objects.
|
||||
** These lists are linked by fields 'gclist'. (All objects that
|
||||
** can become gray have such a field. The field is not the same
|
||||
** in all objects, but it always has this name.) Any gray object
|
||||
** must belong to one of these lists, and all objects in these lists
|
||||
** must be gray:
|
||||
**
|
||||
** 'gray': regular gray objects, still waiting to be visited.
|
||||
** 'grayagain': objects that must be revisited at the atomic phase.
|
||||
** That includes
|
||||
** - black objects got in a write barrier;
|
||||
** - all kinds of weak tables during propagation phase;
|
||||
** - all threads.
|
||||
** 'weak': tables with weak values to be cleared;
|
||||
** 'ephemeron': ephemeron tables with white->white entries;
|
||||
** 'allweak': tables with weak keys and/or weak values to be cleared.
|
||||
** The last three lists are used only during the atomic phase.
|
||||
|
||||
*/
|
||||
|
||||
@@ -125,7 +143,6 @@ typedef struct global_State {
|
||||
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
|
||||
stringtable strt; /* hash table for strings */
|
||||
TValue l_registry;
|
||||
unsigned int seed; /* randomized seed for hashes */
|
||||
lu_byte currentwhite;
|
||||
lu_byte gcstate; /* state of garbage collector */
|
||||
lu_byte gckind; /* kind of GC running */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $
|
||||
** $Id: lstring.c,v 2.56.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** String table (keeps all strings handled by Lua)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
@@ -20,7 +21,10 @@
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "atomic.h"
|
||||
|
||||
static unsigned int STRSEED;
|
||||
static size_t STRID = 0;
|
||||
|
||||
#define MEMERRMSG "not enough memory"
|
||||
|
||||
@@ -45,6 +49,26 @@ int luaS_eqlngstr (TString *a, TString *b) {
|
||||
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
|
||||
}
|
||||
|
||||
int luaS_eqshrstr (TString *a, TString *b) {
|
||||
lu_byte len = a->shrlen;
|
||||
lua_assert(b->tt == LUA_TSHRSTR);
|
||||
int r = len == b->shrlen && (memcmp(getstr(a), getstr(b), len) == 0);
|
||||
if (r) {
|
||||
if (a->id < b->id) {
|
||||
a->id = b->id;
|
||||
} else {
|
||||
b->id = a->id;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void luaS_share (TString *ts) {
|
||||
if (ts == NULL)
|
||||
return;
|
||||
makeshared(ts);
|
||||
ts->id = ATOM_DEC(&STRID);
|
||||
}
|
||||
|
||||
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
||||
unsigned int h = seed ^ cast(unsigned int, l);
|
||||
@@ -109,6 +133,15 @@ void luaS_clearcache (global_State *g) {
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int make_str_seed(lua_State *L) {
|
||||
size_t buff[4];
|
||||
unsigned int h = time(NULL);
|
||||
buff[0] = cast(size_t, h);
|
||||
buff[1] = cast(size_t, &STRSEED);
|
||||
buff[2] = cast(size_t, &make_str_seed);
|
||||
buff[3] = cast(size_t, L);
|
||||
return luaS_hash((const char*)buff, sizeof(buff), h);
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the string table and the string cache
|
||||
@@ -116,6 +149,9 @@ void luaS_clearcache (global_State *g) {
|
||||
void luaS_init (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
int i, j;
|
||||
if (STRSEED == 0) {
|
||||
STRSEED = make_str_seed(L);
|
||||
}
|
||||
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
|
||||
/* pre-create memory-error message */
|
||||
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
|
||||
@@ -139,13 +175,14 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
|
||||
ts = gco2ts(o);
|
||||
ts->hash = h;
|
||||
ts->extra = 0;
|
||||
ts->id = 0;
|
||||
getstr(ts)[l] = '\0'; /* ending 0 */
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
|
||||
TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
|
||||
TString *ts = createstrobj(L, l, LUA_TLNGSTR, STRSEED);
|
||||
ts->u.lnglen = l;
|
||||
return ts;
|
||||
}
|
||||
@@ -164,9 +201,10 @@ void luaS_remove (lua_State *L, TString *ts) {
|
||||
/*
|
||||
** checks whether short string exists and reuses it or creates a new one
|
||||
*/
|
||||
static TString *queryshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
|
||||
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
||||
TString *ts;
|
||||
global_State *g = G(L);
|
||||
unsigned int h = luaS_hash(str, l, STRSEED);
|
||||
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
|
||||
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
||||
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
||||
@@ -178,13 +216,6 @@ static TString *queryshrstr (lua_State *L, const char *str, size_t l, unsigned i
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TString *addshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
|
||||
TString *ts;
|
||||
global_State *g = G(L);
|
||||
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
|
||||
if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) {
|
||||
luaS_resize(L, g->strt.size * 2);
|
||||
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
|
||||
@@ -198,7 +229,6 @@ static TString *addshrstr (lua_State *L, const char *str, size_t l, unsigned int
|
||||
return ts;
|
||||
}
|
||||
|
||||
static TString *internshrstr (lua_State *L, const char *str, size_t l);
|
||||
|
||||
/*
|
||||
** new string (with explicit length)
|
||||
@@ -253,217 +283,3 @@ Udata *luaS_newudata (lua_State *L, size_t s) {
|
||||
return u;
|
||||
}
|
||||
|
||||
/*
|
||||
* global shared table
|
||||
*/
|
||||
|
||||
#include "rwlock.h"
|
||||
#include "atomic.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SHRSTR_SLOT 0x10000
|
||||
#define HASH_NODE(h) ((h) % SHRSTR_SLOT)
|
||||
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
|
||||
|
||||
struct shrmap_slot {
|
||||
struct rwlock lock;
|
||||
TString *str;
|
||||
};
|
||||
|
||||
struct shrmap {
|
||||
struct shrmap_slot h[SHRSTR_SLOT];
|
||||
int n;
|
||||
};
|
||||
|
||||
static struct shrmap SSM;
|
||||
|
||||
LUA_API void
|
||||
luaS_initshr() {
|
||||
struct shrmap * s = &SSM;
|
||||
int i;
|
||||
for (i=0;i<SHRSTR_SLOT;i++) {
|
||||
rwlock_init(&s->h[i].lock);
|
||||
}
|
||||
}
|
||||
|
||||
LUA_API void
|
||||
luaS_exitshr() {
|
||||
int i;
|
||||
for (i=0;i<SHRSTR_SLOT;i++) {
|
||||
TString *str = SSM.h[i].str;
|
||||
while (str) {
|
||||
TString * next = str->u.hnext;
|
||||
free(str);
|
||||
str = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TString *
|
||||
query_string(unsigned int h, const char *str, lu_byte l) {
|
||||
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
|
||||
rwlock_rlock(&s->lock);
|
||||
TString *ts = s->str;
|
||||
while (ts) {
|
||||
if (ts->hash == h &&
|
||||
ts->shrlen == l &&
|
||||
memcmp(str, ts+1, l) == 0) {
|
||||
break;
|
||||
}
|
||||
ts = ts->u.hnext;
|
||||
}
|
||||
rwlock_runlock(&s->lock);
|
||||
return ts;
|
||||
}
|
||||
|
||||
static TString *
|
||||
query_ptr(TString *t) {
|
||||
unsigned int h = t->hash;
|
||||
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
|
||||
rwlock_rlock(&s->lock);
|
||||
TString *ts = s->str;
|
||||
while (ts) {
|
||||
if (ts == t)
|
||||
break;
|
||||
ts = ts->u.hnext;
|
||||
}
|
||||
rwlock_runlock(&s->lock);
|
||||
return ts;
|
||||
}
|
||||
|
||||
static TString *
|
||||
new_string(unsigned int h, const char *str, lu_byte l) {
|
||||
size_t sz = sizelstring(l);
|
||||
TString *ts = malloc(sz);
|
||||
memset(ts, 0, sz);
|
||||
ts->tt = LUA_TSHRSTR;
|
||||
ts->hash = h;
|
||||
ts->shrlen = l;
|
||||
memcpy(ts+1, str, l);
|
||||
return ts;
|
||||
}
|
||||
|
||||
static TString *
|
||||
add_string(unsigned int h, const char *str, lu_byte l) {
|
||||
TString * tmp = new_string(h, str, l);
|
||||
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
|
||||
rwlock_wlock(&s->lock);
|
||||
TString *ts = s->str;
|
||||
while (ts) {
|
||||
if (ts->hash == h &&
|
||||
ts->shrlen == l &&
|
||||
memcmp(str, ts+1, l) == 0) {
|
||||
break;
|
||||
}
|
||||
ts = ts->u.hnext;
|
||||
}
|
||||
if (ts == NULL) {
|
||||
ts = tmp;
|
||||
ts->u.hnext = s->str;
|
||||
s->str = ts;
|
||||
tmp = NULL;
|
||||
}
|
||||
rwlock_wunlock(&s->lock);
|
||||
if (tmp) {
|
||||
// string is create by other thread, so free tmp
|
||||
free(tmp);
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
static TString *
|
||||
internshrstr (lua_State *L, const char *str, size_t l) {
|
||||
TString *ts;
|
||||
global_State *g = G(L);
|
||||
unsigned int h = luaS_hash(str, l, g->seed);
|
||||
unsigned int h0;
|
||||
// lookup global state of this L first
|
||||
ts = queryshrstr (L, str, l, h);
|
||||
if (ts)
|
||||
return ts;
|
||||
// lookup SSM again
|
||||
h0 = luaS_hash(str, l, 0);
|
||||
ts = query_string(h0, str, l);
|
||||
if (ts)
|
||||
return ts;
|
||||
// If SSM.n greate than 0, add it to SSM
|
||||
if (SSM.n > 0) {
|
||||
ATOM_DEC(&SSM.n);
|
||||
return add_string(h0, str, l);
|
||||
}
|
||||
// Else add it to global state (local)
|
||||
return addshrstr (L, str, l, h);
|
||||
}
|
||||
|
||||
LUA_API void
|
||||
luaS_expandshr(int n) {
|
||||
ATOM_ADD(&SSM.n, n);
|
||||
}
|
||||
|
||||
LUAI_FUNC TString *
|
||||
luaS_clonestring(lua_State *L, TString *ts) {
|
||||
unsigned int h;
|
||||
int l;
|
||||
const char * str = getaddrstr(ts);
|
||||
global_State *g = G(L);
|
||||
TString *result;
|
||||
if (ts->tt == LUA_TLNGSTR)
|
||||
return luaS_newlstr(L, str, ts->u.lnglen);
|
||||
// look up global state of this L first
|
||||
l = ts->shrlen;
|
||||
h = luaS_hash(str, l, g->seed);
|
||||
result = queryshrstr (L, str, l, h);
|
||||
if (result)
|
||||
return result;
|
||||
// look up SSM by ptr
|
||||
result = query_ptr(ts);
|
||||
if (result)
|
||||
return result;
|
||||
h = luaS_hash(str, l, 0);
|
||||
result = query_string(h, str, l);
|
||||
if (result)
|
||||
return result;
|
||||
// ts is not in SSM, so recalc hash, and add it to SSM
|
||||
return add_string(h, str, l);
|
||||
}
|
||||
|
||||
struct slotinfo {
|
||||
int len;
|
||||
int size;
|
||||
};
|
||||
|
||||
static void
|
||||
getslot(struct shrmap_slot *s, struct slotinfo *info) {
|
||||
memset(info, 0, sizeof(*info));
|
||||
rwlock_rlock(&s->lock);
|
||||
TString *ts = s->str;
|
||||
while (ts) {
|
||||
++info->len;
|
||||
info->size += sizelstring(ts->shrlen);
|
||||
ts = ts->u.hnext;
|
||||
}
|
||||
rwlock_runlock(&s->lock);
|
||||
}
|
||||
|
||||
LUA_API int
|
||||
luaS_shrinfo(lua_State *L) {
|
||||
struct slotinfo total;
|
||||
struct slotinfo tmp;
|
||||
memset(&total, 0, sizeof(total));
|
||||
int i;
|
||||
int len = 0;
|
||||
for (i=0;i<SHRSTR_SLOT;i++) {
|
||||
struct shrmap_slot *s = &SSM.h[i];
|
||||
getslot(s, &tmp);
|
||||
len += tmp.len;
|
||||
if (tmp.len > total.len) {
|
||||
total.len = tmp.len;
|
||||
}
|
||||
total.size += tmp.size;
|
||||
}
|
||||
lua_pushinteger(L, len);
|
||||
lua_pushinteger(L, total.size);
|
||||
lua_pushinteger(L, total.len);
|
||||
lua_pushinteger(L, SSM.n);
|
||||
return 4;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $
|
||||
** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** String table (keep all strings handled by Lua)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -28,14 +28,15 @@
|
||||
|
||||
|
||||
/*
|
||||
** equality for short strings, which are always internalized
|
||||
** equality for short strings, compare id first
|
||||
*/
|
||||
#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b))
|
||||
|
||||
#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b) || \
|
||||
( ((a)->id == (b)->id) ? ((a)->id != 0) : ((a)->hash == (b)->hash && luaS_eqshrstr(a,b)) ) )
|
||||
|
||||
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
|
||||
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
|
||||
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
|
||||
LUAI_FUNC int luaS_eqshrstr (TString *a, TString *b);
|
||||
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
||||
LUAI_FUNC void luaS_clearcache (global_State *g);
|
||||
LUAI_FUNC void luaS_init (lua_State *L);
|
||||
@@ -44,13 +45,7 @@ LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
|
||||
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
||||
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
|
||||
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
|
||||
LUAI_FUNC void luaS_share(TString *ts);
|
||||
|
||||
#define ENABLE_SHORT_STRING_TABLE
|
||||
|
||||
LUA_API void luaS_initshr();
|
||||
LUA_API void luaS_exitshr();
|
||||
LUA_API void luaS_expandshr(int n);
|
||||
LUAI_FUNC TString *luaS_clonestring(lua_State *L, TString *);
|
||||
LUA_API int luaS_shrinfo(lua_State *L);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $
|
||||
** Standard library for string operations and pattern-matching
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -879,7 +879,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
|
||||
buff[i] = toupper(uchar(buff[i]));
|
||||
}
|
||||
else if (fmt[SIZELENMOD] != 'a')
|
||||
luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
|
||||
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -1199,8 +1199,8 @@ static int getnum (const char **fmt, int df) {
|
||||
static int getnumlimit (Header *h, const char **fmt, int df) {
|
||||
int sz = getnum(fmt, df);
|
||||
if (sz > MAXINTSIZE || sz <= 0)
|
||||
luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
||||
sz, MAXINTSIZE);
|
||||
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
||||
sz, MAXINTSIZE);
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ltable.c,v 2.118 2016/11/07 12:38:35 roberto Exp $
|
||||
** $Id: ltable.c,v 2.118.1.4 2018/06/08 16:22:51 roberto Exp $
|
||||
** Lua tables (hash)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -223,7 +223,9 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
|
||||
unsigned int na = 0; /* number of elements to go to array part */
|
||||
unsigned int optimal = 0; /* optimal size for array part */
|
||||
/* loop while keys can fill more than half of total size */
|
||||
for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) {
|
||||
for (i = 0, twotoi = 1;
|
||||
twotoi > 0 && *pna > twotoi / 2;
|
||||
i++, twotoi *= 2) {
|
||||
if (nums[i] > 0) {
|
||||
a += nums[i];
|
||||
if (a > twotoi/2) { /* more than half elements present? */
|
||||
@@ -330,17 +332,34 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
Table *t;
|
||||
unsigned int nhsize;
|
||||
} AuxsetnodeT;
|
||||
|
||||
|
||||
static void auxsetnode (lua_State *L, void *ud) {
|
||||
AuxsetnodeT *asn = cast(AuxsetnodeT *, ud);
|
||||
setnodevector(L, asn->t, asn->nhsize);
|
||||
}
|
||||
|
||||
|
||||
void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
|
||||
unsigned int nhsize) {
|
||||
unsigned int i;
|
||||
int j;
|
||||
AuxsetnodeT asn;
|
||||
unsigned int oldasize = t->sizearray;
|
||||
int oldhsize = allocsizenode(t);
|
||||
Node *nold = t->node; /* save old hash ... */
|
||||
if (nasize > oldasize) /* array part must grow? */
|
||||
setarrayvector(L, t, nasize);
|
||||
/* create new hash part with appropriate size */
|
||||
setnodevector(L, t, nhsize);
|
||||
asn.t = t; asn.nhsize = nhsize;
|
||||
if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */
|
||||
setarrayvector(L, t, oldasize); /* array back to its original size */
|
||||
luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */
|
||||
}
|
||||
if (nasize < oldasize) { /* array part must shrink? */
|
||||
t->sizearray = nasize;
|
||||
/* re-insert elements from vanishing slice */
|
||||
@@ -589,7 +608,10 @@ const TValue *luaH_get (Table *t, const TValue *key) {
|
||||
** barrier and invalidate the TM cache.
|
||||
*/
|
||||
TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
|
||||
const TValue *p = luaH_get(t, key);
|
||||
const TValue *p;
|
||||
if(isshared(t))
|
||||
luaG_runerror(L,"attempt to change a shared table");
|
||||
p = luaH_get(t, key);
|
||||
if (p != luaO_nilobject)
|
||||
return cast(TValue *, p);
|
||||
else return luaH_newkey(L, t, key);
|
||||
@@ -610,13 +632,13 @@ void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
|
||||
}
|
||||
|
||||
|
||||
static int unbound_search (Table *t, unsigned int j) {
|
||||
unsigned int i = j; /* i is zero or a present index */
|
||||
static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) {
|
||||
lua_Unsigned i = j; /* i is zero or a present index */
|
||||
j++;
|
||||
/* find 'i' and 'j' such that i is present and j is not */
|
||||
while (!ttisnil(luaH_getint(t, j))) {
|
||||
i = j;
|
||||
if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */
|
||||
if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */
|
||||
/* table was built with bad purposes: resort to linear search */
|
||||
i = 1;
|
||||
while (!ttisnil(luaH_getint(t, i))) i++;
|
||||
@@ -626,7 +648,7 @@ static int unbound_search (Table *t, unsigned int j) {
|
||||
}
|
||||
/* now do a binary search between them */
|
||||
while (j - i > 1) {
|
||||
unsigned int m = (i+j)/2;
|
||||
lua_Unsigned m = (i+j)/2;
|
||||
if (ttisnil(luaH_getint(t, m))) j = m;
|
||||
else i = m;
|
||||
}
|
||||
@@ -638,7 +660,7 @@ static int unbound_search (Table *t, unsigned int j) {
|
||||
** Try to find a boundary in table 't'. A 'boundary' is an integer index
|
||||
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
|
||||
*/
|
||||
int luaH_getn (Table *t) {
|
||||
lua_Unsigned luaH_getn (Table *t) {
|
||||
unsigned int j = t->sizearray;
|
||||
if (j > 0 && ttisnil(&t->array[j - 1])) {
|
||||
/* there is a boundary in the array part: (binary) search for it */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $
|
||||
** Lua tables (hash)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -54,7 +54,7 @@ LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
|
||||
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
|
||||
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
|
||||
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
|
||||
LUAI_FUNC int luaH_getn (Table *t);
|
||||
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
|
||||
|
||||
|
||||
#if defined(LUA_DEBUG)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
|
||||
** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Library for Table Manipulation
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Tag methods
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
|
||||
** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Tag methods
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lua.c,v 1.230 2017/01/12 17:14:26 roberto Exp $
|
||||
** $Id: lua.c,v 1.230.1.1 2017/04/19 17:29:57 roberto Exp $
|
||||
** Lua stand-alone interpreter
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
#include "lstring.h"
|
||||
|
||||
|
||||
|
||||
@@ -139,7 +138,7 @@ static void print_usage (const char *badoption) {
|
||||
"Available options are:\n"
|
||||
" -e stat execute string 'stat'\n"
|
||||
" -i enter interactive mode after executing 'script'\n"
|
||||
" -l name require library 'name'\n"
|
||||
" -l name require library 'name' into global 'name'\n"
|
||||
" -v show version information\n"
|
||||
" -E ignore environment variables\n"
|
||||
" -- stop handling options\n"
|
||||
@@ -596,9 +595,7 @@ static int pmain (lua_State *L) {
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
int status, result;
|
||||
lua_State *L;
|
||||
luaS_initshr(); /* init global short string table */
|
||||
L = luaL_newstate(); /* create state */
|
||||
lua_State *L = luaL_newstate(); /* create state */
|
||||
if (L == NULL) {
|
||||
l_message(argv[0], "cannot create state: not enough memory");
|
||||
return EXIT_FAILURE;
|
||||
@@ -610,7 +607,6 @@ int main (int argc, char **argv) {
|
||||
result = lua_toboolean(L, -1); /* get result */
|
||||
report(L, status);
|
||||
lua_close(L);
|
||||
luaS_exitshr();
|
||||
return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lua.h,v 1.332 2016/12/22 15:51:20 roberto Exp $
|
||||
** $Id: lua.h,v 1.332.1.2 2018/06/13 16:58:17 roberto Exp $
|
||||
** Lua - A Scripting Language
|
||||
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
||||
** See Copyright Notice at the end of this file
|
||||
@@ -19,11 +19,11 @@
|
||||
#define LUA_VERSION_MAJOR "5"
|
||||
#define LUA_VERSION_MINOR "3"
|
||||
#define LUA_VERSION_NUM 503
|
||||
#define LUA_VERSION_RELEASE "4"
|
||||
#define LUA_VERSION_RELEASE "5"
|
||||
|
||||
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2017 Lua.org, PUC-Rio"
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2018 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||
|
||||
|
||||
@@ -234,6 +234,10 @@ LUA_API void (lua_pushboolean) (lua_State *L, int b);
|
||||
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
|
||||
LUA_API int (lua_pushthread) (lua_State *L);
|
||||
|
||||
LUA_API void (lua_clonefunction) (lua_State *L, const void * fp);
|
||||
LUA_API void (lua_sharefunction) (lua_State *L, int index);
|
||||
LUA_API void (lua_sharestring) (lua_State *L, int index);
|
||||
LUA_API void (lua_clonetable) (lua_State *L, const void * t);
|
||||
|
||||
/*
|
||||
** get functions (Lua -> stack)
|
||||
@@ -282,8 +286,6 @@ LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
|
||||
|
||||
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
|
||||
|
||||
LUA_API void (lua_clonefunction) (lua_State *L, const void *eL);
|
||||
|
||||
|
||||
/*
|
||||
** coroutine functions
|
||||
@@ -467,7 +469,7 @@ LUA_API void (lua_checksig_)(lua_State *L);
|
||||
#define lua_checksig(L) if (skynet_sig_L) { lua_checksig_(L); }
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
|
||||
* Copyright (C) 1994-2018 Lua.org, PUC-Rio.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
|
||||
** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $
|
||||
** Lua compiler (saves bytecodes to files; also lists bytecodes)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lundump.h"
|
||||
#include "lstring.h"
|
||||
|
||||
static void PrintFunction(const Proto* f, int full);
|
||||
#define luaU_print PrintFunction
|
||||
@@ -150,9 +149,9 @@ static const Proto* combine(lua_State* L, int n)
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
f->p[i]=toproto(L,i-n-1);
|
||||
if (f->p[i]->sp->sizeupvalues>0) f->p[i]->sp->upvalues[0].instack=0;
|
||||
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
|
||||
}
|
||||
f->sp->sizelineinfo=0;
|
||||
f->sizelineinfo=0;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
@@ -196,7 +195,6 @@ int main(int argc, char* argv[])
|
||||
int i=doargs(argc,argv);
|
||||
argc-=i; argv+=i;
|
||||
if (argc<=0) usage("no input files given");
|
||||
luaS_initshr();
|
||||
L=luaL_newstate();
|
||||
if (L==NULL) fatal("cannot create state: not enough memory");
|
||||
lua_pushcfunction(L,&pmain);
|
||||
@@ -208,7 +206,7 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
/*
|
||||
** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
|
||||
** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $
|
||||
** print bytecodes
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -284,13 +282,13 @@ static void PrintConstant(const Proto* f, int i)
|
||||
}
|
||||
}
|
||||
|
||||
#define UPVALNAME(x) ((f->sp->upvalues[x].name) ? getstr(f->sp->upvalues[x].name) : "-")
|
||||
#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
|
||||
#define MYK(x) (-1-(x))
|
||||
|
||||
static void PrintCode(const Proto* f)
|
||||
{
|
||||
const Instruction* code=f->sp->code;
|
||||
int pc,n=f->sp->sizecode;
|
||||
const Instruction* code=f->code;
|
||||
int pc,n=f->sizecode;
|
||||
for (pc=0; pc<n; pc++)
|
||||
{
|
||||
Instruction i=code[pc];
|
||||
@@ -350,6 +348,7 @@ static void PrintCode(const Proto* f)
|
||||
case OP_ADD:
|
||||
case OP_SUB:
|
||||
case OP_MUL:
|
||||
case OP_MOD:
|
||||
case OP_POW:
|
||||
case OP_DIV:
|
||||
case OP_IDIV:
|
||||
@@ -394,7 +393,7 @@ static void PrintCode(const Proto* f)
|
||||
#define SS(x) ((x==1)?"":"s")
|
||||
#define S(x) (int)(x),SS(x)
|
||||
|
||||
static void PrintHeader(const SharedProto* f)
|
||||
static void PrintHeader(const Proto* f)
|
||||
{
|
||||
const char* s=f->source ? getstr(f->source) : "=?";
|
||||
if (*s=='@' || *s=='=')
|
||||
@@ -416,9 +415,8 @@ static void PrintHeader(const SharedProto* f)
|
||||
|
||||
static void PrintDebug(const Proto* f)
|
||||
{
|
||||
const SharedProto *sp = f->sp;
|
||||
int i,n;
|
||||
n=sp->sizek;
|
||||
n=f->sizek;
|
||||
printf("constants (%d) for %p:\n",n,VOID(f));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
@@ -426,26 +424,26 @@ static void PrintDebug(const Proto* f)
|
||||
PrintConstant(f,i);
|
||||
printf("\n");
|
||||
}
|
||||
n=sp->sizelocvars;
|
||||
n=f->sizelocvars;
|
||||
printf("locals (%d) for %p:\n",n,VOID(f));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
printf("\t%d\t%s\t%d\t%d\n",
|
||||
i,getstr(sp->locvars[i].varname),sp->locvars[i].startpc+1,sp->locvars[i].endpc+1);
|
||||
i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
|
||||
}
|
||||
n=f->sp->sizeupvalues;
|
||||
n=f->sizeupvalues;
|
||||
printf("upvalues (%d) for %p:\n",n,VOID(f));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
printf("\t%d\t%s\t%d\t%d\n",
|
||||
i,UPVALNAME(i),sp->upvalues[i].instack,sp->upvalues[i].idx);
|
||||
i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintFunction(const Proto* f, int full)
|
||||
{
|
||||
int i,n=f->sp->sizep;
|
||||
PrintHeader(f->sp);
|
||||
int i,n=f->sizep;
|
||||
PrintHeader(f);
|
||||
PrintCode(f);
|
||||
if (full) PrintDebug(f);
|
||||
for (i=0; i<n; i++) PrintFunction(f->p[i],full);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: luaconf.h,v 1.259 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $
|
||||
** Configuration file for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -620,6 +620,13 @@
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ lua_pointer2str converts a pointer to a readable string in a
|
||||
** non-specified way.
|
||||
*/
|
||||
#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p)
|
||||
|
||||
|
||||
/*
|
||||
@@ lua_number2strx converts a float to an hexadecimal numeric string.
|
||||
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lualib.h,v 1.45 2017/01/12 17:14:26 roberto Exp $
|
||||
** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Lua standard libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -49,6 +49,7 @@ LUAMOD_API int (luaopen_package) (lua_State *L);
|
||||
|
||||
#define LUA_CACHELIB
|
||||
LUAMOD_API int (luaopen_cache) (lua_State *L);
|
||||
LUALIB_API void (luaL_initcodecache) (void);
|
||||
|
||||
/* open all previous libraries */
|
||||
LUALIB_API void (luaL_openlibs) (lua_State *L);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $
|
||||
** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** load precompiled Lua chunks
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -104,7 +104,7 @@ static TString *LoadString (LoadState *S) {
|
||||
}
|
||||
|
||||
|
||||
static void LoadCode (LoadState *S, SharedProto *f) {
|
||||
static void LoadCode (LoadState *S, Proto *f) {
|
||||
int n = LoadInt(S);
|
||||
f->code = luaM_newvector(S->L, n, Instruction);
|
||||
f->sizecode = n;
|
||||
@@ -119,7 +119,7 @@ static void LoadConstants (LoadState *S, Proto *f) {
|
||||
int i;
|
||||
int n = LoadInt(S);
|
||||
f->k = luaM_newvector(S->L, n, TValue);
|
||||
f->sp->sizek = n;
|
||||
f->sizek = n;
|
||||
for (i = 0; i < n; i++)
|
||||
setnilvalue(&f->k[i]);
|
||||
for (i = 0; i < n; i++) {
|
||||
@@ -153,17 +153,17 @@ static void LoadProtos (LoadState *S, Proto *f) {
|
||||
int i;
|
||||
int n = LoadInt(S);
|
||||
f->p = luaM_newvector(S->L, n, Proto *);
|
||||
f->sp->sizep = n;
|
||||
f->sizep = n;
|
||||
for (i = 0; i < n; i++)
|
||||
f->p[i] = NULL;
|
||||
for (i = 0; i < n; i++) {
|
||||
f->p[i] = luaF_newproto(S->L, NULL);
|
||||
LoadFunction(S, f->p[i], f->sp->source);
|
||||
f->p[i] = luaF_newproto(S->L);
|
||||
LoadFunction(S, f->p[i], f->source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void LoadUpvalues (LoadState *S, SharedProto *f) {
|
||||
static void LoadUpvalues (LoadState *S, Proto *f) {
|
||||
int i, n;
|
||||
n = LoadInt(S);
|
||||
f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
|
||||
@@ -177,7 +177,7 @@ static void LoadUpvalues (LoadState *S, SharedProto *f) {
|
||||
}
|
||||
|
||||
|
||||
static void LoadDebug (LoadState *S, SharedProto *f) {
|
||||
static void LoadDebug (LoadState *S, Proto *f) {
|
||||
int i, n;
|
||||
n = LoadInt(S);
|
||||
f->lineinfo = luaM_newvector(S->L, n, int);
|
||||
@@ -199,8 +199,7 @@ static void LoadDebug (LoadState *S, SharedProto *f) {
|
||||
}
|
||||
|
||||
|
||||
static void LoadFunction (LoadState *S, Proto *fp, TString *psource) {
|
||||
SharedProto *f = fp->sp;
|
||||
static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
|
||||
f->source = LoadString(S);
|
||||
if (f->source == NULL) /* no source in dump? */
|
||||
f->source = psource; /* reuse parent's source */
|
||||
@@ -210,9 +209,9 @@ static void LoadFunction (LoadState *S, Proto *fp, TString *psource) {
|
||||
f->is_vararg = LoadByte(S);
|
||||
f->maxstacksize = LoadByte(S);
|
||||
LoadCode(S, f);
|
||||
LoadConstants(S, fp);
|
||||
LoadConstants(S, f);
|
||||
LoadUpvalues(S, f);
|
||||
LoadProtos(S, fp);
|
||||
LoadProtos(S, f);
|
||||
LoadDebug(S, f);
|
||||
}
|
||||
|
||||
@@ -271,9 +270,9 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
|
||||
cl = luaF_newLclosure(L, LoadByte(&S));
|
||||
setclLvalue(L, L->top, cl);
|
||||
luaD_inctop(L);
|
||||
cl->p = luaF_newproto(L, NULL);
|
||||
cl->p = luaF_newproto(L);
|
||||
LoadFunction(&S, cl->p, NULL);
|
||||
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
|
||||
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
||||
luai_verifycode(L, buff, cl->p);
|
||||
return cl;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $
|
||||
** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** load precompiled Lua chunks
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $
|
||||
** Standard library for UTF-8 manipulation
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -171,7 +171,7 @@ static int byteoffset (lua_State *L) {
|
||||
}
|
||||
else {
|
||||
if (iscont(s + posi))
|
||||
luaL_error(L, "initial position is a continuation byte");
|
||||
return luaL_error(L, "initial position is a continuation byte");
|
||||
if (n < 0) {
|
||||
while (n < 0 && posi > 0) { /* move back */
|
||||
do { /* find beginning of previous character */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
|
||||
** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $
|
||||
** Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -217,6 +217,8 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||||
const TValue *tm; /* '__newindex' metamethod */
|
||||
if (slot != NULL) { /* is 't' a table? */
|
||||
Table *h = hvalue(t); /* save 't' table */
|
||||
if (isshared(h))
|
||||
luaG_typeerror(L, t, "change");
|
||||
lua_assert(ttisnil(slot)); /* old value must be nil */
|
||||
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
|
||||
if (tm == NULL) { /* no metamethod? */
|
||||
@@ -612,27 +614,6 @@ lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** check whether cached closure in prototype 'p' may be reused, that is,
|
||||
** whether there is a cached closure with the same upvalues needed by
|
||||
** new closure to be created.
|
||||
*/
|
||||
static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
|
||||
LClosure *c = p->cache;
|
||||
if (c != NULL) { /* is there a cached closure? */
|
||||
int nup = p->sp->sizeupvalues;
|
||||
Upvaldesc *uv = p->sp->upvalues;
|
||||
int i;
|
||||
for (i = 0; i < nup; i++) { /* check whether it has right upvalues */
|
||||
TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v;
|
||||
if (c->upvals[i]->v != v)
|
||||
return NULL; /* wrong upvalue; cannot reuse closure */
|
||||
}
|
||||
}
|
||||
return c; /* return cached closure (or NULL if no cached closure) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** create a new Lua closure, push it in the stack, and initialize
|
||||
** its upvalues. Note that the closure is not cached if prototype is
|
||||
@@ -641,8 +622,8 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
|
||||
*/
|
||||
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
|
||||
StkId ra) {
|
||||
int nup = p->sp->sizeupvalues;
|
||||
Upvaldesc *uv = p->sp->upvalues;
|
||||
int nup = p->sizeupvalues;
|
||||
Upvaldesc *uv = p->upvalues;
|
||||
int i;
|
||||
LClosure *ncl = luaF_newLclosure(L, nup);
|
||||
ncl->p = p;
|
||||
@@ -655,8 +636,6 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
|
||||
ncl->upvals[i]->refcount++;
|
||||
/* new closure is white, so we do not need a barrier here */
|
||||
}
|
||||
if (!isblack(p)) /* cache will not break GC invariant? */
|
||||
p->cache = ncl; /* save it on cache for reuse */
|
||||
}
|
||||
|
||||
|
||||
@@ -1169,10 +1148,10 @@ void luaV_execute (lua_State *L) {
|
||||
StkId nfunc = nci->func; /* called function */
|
||||
StkId ofunc = oci->func; /* caller function */
|
||||
/* last stack slot filled by 'precall' */
|
||||
StkId lim = nci->u.l.base + getproto(nfunc)->sp->numparams;
|
||||
StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
|
||||
int aux;
|
||||
/* close all upvalues from previous call */
|
||||
if (cl->p->sp->sizep > 0) luaF_close(L, oci->u.l.base);
|
||||
if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
|
||||
/* move new frame into old one */
|
||||
for (aux = 0; nfunc + aux < lim; aux++)
|
||||
setobjs2s(L, ofunc + aux, nfunc + aux);
|
||||
@@ -1181,14 +1160,14 @@ void luaV_execute (lua_State *L) {
|
||||
oci->u.l.savedpc = nci->u.l.savedpc;
|
||||
oci->callstatus |= CIST_TAIL; /* function was tail called */
|
||||
ci = L->ci = oci; /* remove new frame */
|
||||
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->sp->maxstacksize);
|
||||
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
|
||||
goto newframe; /* restart luaV_execute over new Lua function */
|
||||
}
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_RETURN) {
|
||||
int b = GETARG_B(i);
|
||||
if (cl->p->sp->sizep > 0) luaF_close(L, base);
|
||||
if (cl->p->sizep > 0) luaF_close(L, base);
|
||||
b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
|
||||
if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
|
||||
return; /* external invocation: return */
|
||||
@@ -1299,18 +1278,14 @@ void luaV_execute (lua_State *L) {
|
||||
}
|
||||
vmcase(OP_CLOSURE) {
|
||||
Proto *p = cl->p->p[GETARG_Bx(i)];
|
||||
LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */
|
||||
if (ncl == NULL) /* no match? */
|
||||
pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
|
||||
else
|
||||
setclLvalue(L, ra, ncl); /* push cashed closure */
|
||||
pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
|
||||
checkGC(L, ra + 1);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_VARARG) {
|
||||
int b = GETARG_B(i) - 1; /* required results */
|
||||
int j;
|
||||
int n = cast_int(base - ci->func) - cl->p->sp->numparams - 1;
|
||||
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
|
||||
if (n < 0) /* less arguments than parameters? */
|
||||
n = 0; /* no vararg arguments */
|
||||
if (b < 0) { /* B == 0? */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp $
|
||||
** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -81,7 +81,7 @@
|
||||
(!ttistable(t) \
|
||||
? (slot = NULL, 0) \
|
||||
: (slot = f(hvalue(t), k), \
|
||||
ttisnil(slot) ? 0 \
|
||||
(ttisnil(slot) || isshared(hvalue(t))) ? 0 \
|
||||
: (luaC_barrierback(L, hvalue(t), v), \
|
||||
setobj2t(L, cast(TValue *,slot), v), \
|
||||
1)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $
|
||||
** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Buffered streams
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $
|
||||
** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $
|
||||
** Buffered streams
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
32
HISTORY.md
32
HISTORY.md
@@ -1,3 +1,35 @@
|
||||
v1.3.0 (2019-11-19)
|
||||
-----------
|
||||
* Improve mysql driver (@yxt945)
|
||||
* Improve cluster
|
||||
* Improve lua shared proto (@hongling0)
|
||||
* Improve socket.write
|
||||
* Add lua sharetable
|
||||
* Add https support (@lvzixun)
|
||||
* Add websocket support (@lvzixun)
|
||||
* Fix bug in dns
|
||||
* Fix some memory leaks
|
||||
* jemalloc update to 5.2.1
|
||||
|
||||
v1.2.0 (2018-11-6)
|
||||
-----------
|
||||
* Improve cluster support
|
||||
* Improve mongodb driver
|
||||
* Improve redis driver
|
||||
* Improve socket concurrent write
|
||||
* Improve socket channel
|
||||
* Improve service gate
|
||||
* Improve udp support
|
||||
* Add skynet.ignoreret
|
||||
* Add skynet.trace
|
||||
* Add skynet.context
|
||||
* Improve skynet.wait/wakeup
|
||||
* Add socket.netstat
|
||||
* Add socketchannel.overload
|
||||
* Fix memory leak for dead service
|
||||
* lua update to 5.3.5
|
||||
* jemalloc update to 5.1.0
|
||||
|
||||
v1.1.0 (2017-10-31)
|
||||
-----------
|
||||
* add socket.disconnected()
|
||||
|
||||
17
Makefile
17
Makefile
@@ -17,7 +17,13 @@ LUA_INC ?= 3rd/lua
|
||||
$(LUA_STATICLIB) :
|
||||
cd 3rd/lua && $(MAKE) CC='$(CC) -std=gnu99' $(PLAT)
|
||||
|
||||
# jemalloc
|
||||
# https : turn on TLS_MODULE to add https support
|
||||
|
||||
# TLS_MODULE=ltls
|
||||
TLS_LIB=
|
||||
TLS_INC=
|
||||
|
||||
# jemalloc
|
||||
|
||||
JEMALLOC_STATICLIB := 3rd/jemalloc/lib/libjemalloc_pic.a
|
||||
JEMALLOC_INC := 3rd/jemalloc/include/jemalloc
|
||||
@@ -35,7 +41,7 @@ $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
|
||||
git submodule update --init
|
||||
|
||||
3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh
|
||||
cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --disable-valgrind
|
||||
cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --enable-prof
|
||||
|
||||
jemalloc : $(MALLOC_STATICLIB)
|
||||
|
||||
@@ -47,7 +53,7 @@ update3rd :
|
||||
CSERVICE = snlua logger gate harbor
|
||||
LUA_CLIB = skynet \
|
||||
client \
|
||||
bson md5 sproto lpeg
|
||||
bson md5 sproto lpeg $(TLS_MODULE)
|
||||
|
||||
LUA_CLIB_SKYNET = \
|
||||
lua-skynet.c lua-seri.c \
|
||||
@@ -61,9 +67,9 @@ LUA_CLIB_SKYNET = \
|
||||
lua-crypt.c lsha1.c \
|
||||
lua-sharedata.c \
|
||||
lua-stm.c \
|
||||
lua-mysqlaux.c \
|
||||
lua-debugchannel.c \
|
||||
lua-datasheet.c \
|
||||
lua-sharetable.c \
|
||||
\
|
||||
|
||||
SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \
|
||||
@@ -107,6 +113,9 @@ $(LUA_CLIB_PATH)/client.so : lualib-src/lua-clientsocket.c lualib-src/lua-crypt.
|
||||
$(LUA_CLIB_PATH)/sproto.so : lualib-src/sproto/sproto.c lualib-src/sproto/lsproto.c | $(LUA_CLIB_PATH)
|
||||
$(CC) $(CFLAGS) $(SHARED) -Ilualib-src/sproto $^ -o $@
|
||||
|
||||
$(LUA_CLIB_PATH)/ltls.so : lualib-src/ltls.c | $(LUA_CLIB_PATH)
|
||||
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src -L$(TLS_LIB) -I$(TLS_INC) $^ -o $@ -lssl
|
||||
|
||||
$(LUA_CLIB_PATH)/lpeg.so : 3rd/lpeg/lpcap.c 3rd/lpeg/lpcode.c 3rd/lpeg/lpprint.c 3rd/lpeg/lptree.c 3rd/lpeg/lpvm.c | $(LUA_CLIB_PATH)
|
||||
$(CC) $(CFLAGS) $(SHARED) -I3rd/lpeg $^ -o $@
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -1,6 +1,6 @@
|
||||
## Skynet
|
||||
## 
|
||||
|
||||
Skynet is a lightweight online game framework, and it can be used in many other fields.
|
||||
Skynet is a lightweight online game framework which can be used in many other fields.
|
||||
|
||||
## Build
|
||||
|
||||
@@ -12,7 +12,7 @@ cd skynet
|
||||
make 'PLATFORM' # PLATFORM can be linux, macosx, freebsd now
|
||||
```
|
||||
|
||||
Or you can:
|
||||
Or:
|
||||
|
||||
```
|
||||
export PLAT=linux
|
||||
@@ -32,11 +32,11 @@ Run these in different consoles:
|
||||
|
||||
## About Lua version
|
||||
|
||||
Skynet now uses a modified version of lua 5.3.4 ( https://github.com/ejoy/lua/tree/skynet ) for multiple lua states.
|
||||
Skynet now uses a modified version of lua 5.3.5 ( https://github.com/ejoy/lua/tree/skynet ) for multiple lua states.
|
||||
|
||||
You can also use official Lua versions, just edit the Makefile by yourself.
|
||||
Official Lua versions can also be used as long as the Makefile is edited.
|
||||
|
||||
## How To Use (Sorry, Only in Chinese now)
|
||||
## How To Use (Sorry, currently only available in Chinese)
|
||||
|
||||
* Read Wiki for documents https://github.com/cloudwu/skynet/wiki
|
||||
* The FAQ in wiki https://github.com/cloudwu/skynet/wiki/FAQ
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
local skynet = require "skynet"
|
||||
local netpack = require "skynet.netpack"
|
||||
local socket = require "skynet.socket"
|
||||
local sproto = require "sproto"
|
||||
local sprotoloader = require "sprotoloader"
|
||||
@@ -50,7 +49,10 @@ skynet.register_protocol {
|
||||
unpack = function (msg, sz)
|
||||
return host:dispatch(msg, sz)
|
||||
end,
|
||||
dispatch = function (_, _, type, ...)
|
||||
dispatch = function (fd, _, type, ...)
|
||||
assert(fd == client_fd) -- You can use fd to reply message
|
||||
skynet.ignoreret() -- session is fd, don't call skynet.ret
|
||||
skynet.trace()
|
||||
if type == "REQUEST" then
|
||||
local ok, result = pcall(request, ...)
|
||||
if ok then
|
||||
@@ -92,6 +94,7 @@ end
|
||||
|
||||
skynet.start(function()
|
||||
skynet.dispatch("lua", function(_,_, command, ...)
|
||||
skynet.trace()
|
||||
local f = CMD[command]
|
||||
skynet.ret(skynet.pack(f(...)))
|
||||
end)
|
||||
|
||||
@@ -2,22 +2,30 @@ local skynet = require "skynet"
|
||||
local cluster = require "skynet.cluster"
|
||||
|
||||
skynet.start(function()
|
||||
-- query name "sdb" of cluster db.
|
||||
local sdb = cluster.query("db", "sdb")
|
||||
print("db.sbd=",sdb)
|
||||
local proxy = cluster.proxy("db", sdb)
|
||||
local proxy = cluster.proxy "db@sdb" -- cluster.proxy("db", "@sdb")
|
||||
local largekey = string.rep("X", 128*1024)
|
||||
local largevalue = string.rep("R", 100 * 1024)
|
||||
print(skynet.call(proxy, "lua", "SET", largekey, largevalue))
|
||||
skynet.call(proxy, "lua", "SET", largekey, largevalue)
|
||||
local v = skynet.call(proxy, "lua", "GET", largekey)
|
||||
assert(largevalue == v)
|
||||
skynet.send(proxy, "lua", "PING", "proxy")
|
||||
|
||||
print(cluster.call("db", sdb, "GET", "a"))
|
||||
print(cluster.call("db2", sdb, "GET", "b"))
|
||||
cluster.send("db2", sdb, "PING", "db2:longstring" .. largevalue)
|
||||
skynet.fork(function()
|
||||
skynet.trace("cluster")
|
||||
print(cluster.call("db", "@sdb", "GET", "a"))
|
||||
print(cluster.call("db2", "@sdb", "GET", "b"))
|
||||
cluster.send("db2", "@sdb", "PING", "db2:longstring" .. largevalue)
|
||||
end)
|
||||
|
||||
-- test snax service
|
||||
local pingserver = cluster.snax("db", "pingserver")
|
||||
skynet.timeout(300,function()
|
||||
cluster.reload {
|
||||
db = false, -- db is down
|
||||
db3 = "127.0.0.1:2529"
|
||||
}
|
||||
print(pcall(cluster.call, "db", "@sdb", "GET", "a")) -- db is down
|
||||
end)
|
||||
cluster.reload { __nowaiting = false }
|
||||
local pingserver = cluster.snax("db3", "pingserver")
|
||||
print(pingserver.req.ping "hello")
|
||||
end)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
__nowaiting = true -- If you turn this flag off, cluster.call would block when node name is absent
|
||||
|
||||
db = "127.0.0.1:2528"
|
||||
db2 = "127.0.0.1:2529"
|
||||
|
||||
11
examples/config.mongodb
Normal file
11
examples/config.mongodb
Normal file
@@ -0,0 +1,11 @@
|
||||
root = "./"
|
||||
thread = 8
|
||||
logger = nil
|
||||
harbor = 0
|
||||
start = "main_mongodb" -- main script
|
||||
bootstrap = "snlua bootstrap" -- The service for bootstrap
|
||||
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
|
||||
lualoader = "lualib/loader.lua"
|
||||
snax = root.."examples/?.lua;"..root.."test/?.lua"
|
||||
cpath = root.."cservice/?.so"
|
||||
-- daemon = "./skynet.pid"
|
||||
12
examples/main_mongodb.lua
Normal file
12
examples/main_mongodb.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
local skynet = require "skynet"
|
||||
|
||||
|
||||
skynet.start(function()
|
||||
print("Main Server start")
|
||||
local console = skynet.newservice(
|
||||
"testmongodb", "127.0.0.1", 27017, "testdb", "test", "test"
|
||||
)
|
||||
|
||||
print("Main Server exit")
|
||||
skynet.exit()
|
||||
end)
|
||||
@@ -33,5 +33,6 @@ skynet.start(function()
|
||||
error(string.format("Unknown command %s", tostring(cmd)))
|
||||
end
|
||||
end)
|
||||
-- skynet.traceproto("lua", false) -- true off tracelog
|
||||
skynet.register "SIMPLEDB"
|
||||
end)
|
||||
|
||||
@@ -6,26 +6,64 @@ local urllib = require "http.url"
|
||||
local table = table
|
||||
local string = string
|
||||
|
||||
local mode = ...
|
||||
local mode, protocol = ...
|
||||
protocol = protocol or "http"
|
||||
|
||||
if mode == "agent" then
|
||||
|
||||
local function response(id, ...)
|
||||
local ok, err = httpd.write_response(sockethelper.writefunc(id), ...)
|
||||
local function response(id, write, ...)
|
||||
local ok, err = httpd.write_response(write, ...)
|
||||
if not ok then
|
||||
-- if err == sockethelper.socket_error , that means socket closed.
|
||||
skynet.error(string.format("fd = %d, %s", id, err))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local SSLCTX_SERVER = nil
|
||||
local function gen_interface(protocol, fd)
|
||||
if protocol == "http" then
|
||||
return {
|
||||
init = nil,
|
||||
close = nil,
|
||||
read = sockethelper.readfunc(fd),
|
||||
write = sockethelper.writefunc(fd),
|
||||
}
|
||||
elseif protocol == "https" then
|
||||
local tls = require "http.tlshelper"
|
||||
if not SSLCTX_SERVER then
|
||||
SSLCTX_SERVER = tls.newctx()
|
||||
-- gen cert and key
|
||||
-- openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-cert.pem
|
||||
local certfile = skynet.getenv("certfile") or "./server-cert.pem"
|
||||
local keyfile = skynet.getenv("keyfile") or "./server-key.pem"
|
||||
print(certfile, keyfile)
|
||||
SSLCTX_SERVER:set_cert(certfile, keyfile)
|
||||
end
|
||||
local tls_ctx = tls.newtls("server", SSLCTX_SERVER)
|
||||
return {
|
||||
init = tls.init_responsefunc(fd, tls_ctx),
|
||||
close = tls.closefunc(tls_ctx),
|
||||
read = tls.readfunc(fd, tls_ctx),
|
||||
write = tls.writefunc(fd, tls_ctx),
|
||||
}
|
||||
else
|
||||
error(string.format("Invalid protocol: %s", protocol))
|
||||
end
|
||||
end
|
||||
|
||||
skynet.start(function()
|
||||
skynet.dispatch("lua", function (_,_,id)
|
||||
socket.start(id)
|
||||
local interface = gen_interface(protocol, id)
|
||||
if interface.init then
|
||||
interface.init()
|
||||
end
|
||||
-- limit request body size to 8192 (you can pass nil to unlimit)
|
||||
local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id), 8192)
|
||||
local code, url, method, header, body = httpd.read_request(interface.read, 8192)
|
||||
if code then
|
||||
if code ~= 200 then
|
||||
response(id, code)
|
||||
response(id, interface.write, code)
|
||||
else
|
||||
local tmp = {}
|
||||
if header.host then
|
||||
@@ -44,7 +82,7 @@ skynet.start(function()
|
||||
table.insert(tmp, string.format("%s = %s",k,v))
|
||||
end
|
||||
table.insert(tmp, "-----body----\n" .. body)
|
||||
response(id, code, table.concat(tmp,"\n"))
|
||||
response(id, interface.write, code, table.concat(tmp,"\n"))
|
||||
end
|
||||
else
|
||||
if url == sockethelper.socket_error then
|
||||
@@ -54,6 +92,9 @@ skynet.start(function()
|
||||
end
|
||||
end
|
||||
socket.close(id)
|
||||
if interface.close then
|
||||
interface.close()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -61,12 +102,13 @@ else
|
||||
|
||||
skynet.start(function()
|
||||
local agent = {}
|
||||
local protocol = "http"
|
||||
for i= 1, 20 do
|
||||
agent[i] = skynet.newservice(SERVICE_NAME, "agent")
|
||||
agent[i] = skynet.newservice(SERVICE_NAME, "agent", protocol)
|
||||
end
|
||||
local balance = 1
|
||||
local id = socket.listen("0.0.0.0", 8001)
|
||||
skynet.error("Listen web port 8001")
|
||||
skynet.error(string.format("Listen web port 8001 protocol:%s", protocol))
|
||||
socket.start(id , function(id, addr)
|
||||
skynet.error(string.format("%s connected, pass it to agent :%08x", addr, agent[balance]))
|
||||
skynet.send(agent[balance], "lua", id)
|
||||
|
||||
94
examples/simplewebsocket.lua
Executable file
94
examples/simplewebsocket.lua
Executable file
@@ -0,0 +1,94 @@
|
||||
local skynet = require "skynet"
|
||||
local socket = require "skynet.socket"
|
||||
local service = require "skynet.service"
|
||||
local websocket = require "http.websocket"
|
||||
|
||||
local handle = {}
|
||||
local MODE = ...
|
||||
|
||||
if MODE == "agent" then
|
||||
function handle.connect(id)
|
||||
print("ws connect from: " .. tostring(id))
|
||||
end
|
||||
|
||||
function handle.handshake(id, header, url)
|
||||
local addr = websocket.addrinfo(id)
|
||||
print("ws handshake from: " .. tostring(id), "url", url, "addr:", addr)
|
||||
print("----header-----")
|
||||
for k,v in pairs(header) do
|
||||
print(k,v)
|
||||
end
|
||||
print("--------------")
|
||||
end
|
||||
|
||||
function handle.message(id, msg)
|
||||
websocket.write(id, msg)
|
||||
end
|
||||
|
||||
function handle.ping(id)
|
||||
print("ws ping from: " .. tostring(id) .. "\n")
|
||||
end
|
||||
|
||||
function handle.pong(id)
|
||||
print("ws pong from: " .. tostring(id))
|
||||
end
|
||||
|
||||
function handle.close(id, code, reason)
|
||||
print("ws close from: " .. tostring(id), code, reason)
|
||||
end
|
||||
|
||||
function handle.error(id)
|
||||
print("ws error from: " .. tostring(id))
|
||||
end
|
||||
|
||||
skynet.start(function ()
|
||||
skynet.dispatch("lua", function (_,_, id, protocol, addr)
|
||||
local ok, err = websocket.accept(id, handle, protocol, addr)
|
||||
if not ok then
|
||||
print(err)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
else
|
||||
local function simple_echo_client_service(protocol)
|
||||
local skynet = require "skynet"
|
||||
local websocket = require "http.websocket"
|
||||
local url = string.format("%s://127.0.0.1:9948/test_websocket", protocol)
|
||||
local ws_id = websocket.connect(url)
|
||||
while true do
|
||||
local msg = "hello world!"
|
||||
websocket.write(ws_id, msg)
|
||||
print(">: " .. msg)
|
||||
local resp, close_reason = websocket.read(ws_id)
|
||||
print("<: " .. (resp and resp or "[Close] " .. close_reason))
|
||||
if not resp then
|
||||
print("echo server close.")
|
||||
break
|
||||
end
|
||||
websocket.ping(ws_id)
|
||||
skynet.sleep(100)
|
||||
end
|
||||
end
|
||||
|
||||
skynet.start(function ()
|
||||
local agent = {}
|
||||
for i= 1, 20 do
|
||||
agent[i] = skynet.newservice(SERVICE_NAME, "agent")
|
||||
end
|
||||
local balance = 1
|
||||
local protocol = "ws"
|
||||
local id = socket.listen("0.0.0.0", 9948)
|
||||
skynet.error(string.format("Listen websocket port 9948 protocol:%s", protocol))
|
||||
socket.start(id, function(id, addr)
|
||||
print(string.format("accept client socket_id: %s addr:%s", id, addr))
|
||||
skynet.send(agent[balance], "lua", id, protocol, addr)
|
||||
balance = balance + 1
|
||||
if balance > #agent then
|
||||
balance = 1
|
||||
end
|
||||
end)
|
||||
-- test echo client
|
||||
service.new("websocket_echo_client", simple_echo_client_service, protocol)
|
||||
end)
|
||||
end
|
||||
@@ -1,6 +1,7 @@
|
||||
local skynet = require "skynet"
|
||||
require "skynet.manager"
|
||||
|
||||
-- register protocol text before skynet.start would be better.
|
||||
skynet.register_protocol {
|
||||
name = "text",
|
||||
id = skynet.PTYPE_TEXT,
|
||||
@@ -21,5 +22,4 @@ skynet.register_protocol {
|
||||
}
|
||||
|
||||
skynet.start(function()
|
||||
skynet.register ".logger"
|
||||
end)
|
||||
414
lualib-src/ltls.c
Normal file
414
lualib-src/ltls.c
Normal file
@@ -0,0 +1,414 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/engine.h>
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
|
||||
static bool TLS_IS_INIT = false;
|
||||
|
||||
struct tls_context {
|
||||
SSL* ssl;
|
||||
BIO* in_bio;
|
||||
BIO* out_bio;
|
||||
bool is_server;
|
||||
bool is_close;
|
||||
};
|
||||
|
||||
struct ssl_ctx {
|
||||
SSL_CTX* ctx;
|
||||
};
|
||||
|
||||
// static int
|
||||
// _ssl_verify_peer(int ok, X509_STORE_CTX* ctx) {
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
|
||||
static void
|
||||
_init_bio(lua_State* L, struct tls_context* tls_p, struct ssl_ctx* ctx_p) {
|
||||
tls_p->ssl = SSL_new(ctx_p->ctx);
|
||||
if(!tls_p->ssl) {
|
||||
luaL_error(L, "SSL_new faild");
|
||||
}
|
||||
|
||||
tls_p->in_bio = BIO_new(BIO_s_mem());
|
||||
if(!tls_p->in_bio) {
|
||||
luaL_error(L, "new in bio faild");
|
||||
}
|
||||
BIO_set_mem_eof_return(tls_p->in_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
|
||||
|
||||
tls_p->out_bio = BIO_new(BIO_s_mem());
|
||||
if(!tls_p->out_bio) {
|
||||
luaL_error(L, "new out bio faild");
|
||||
}
|
||||
BIO_set_mem_eof_return(tls_p->out_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
|
||||
|
||||
SSL_set_bio(tls_p->ssl, tls_p->in_bio, tls_p->out_bio);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_init_client_context(lua_State* L, struct tls_context* tls_p, struct ssl_ctx* ctx_p) {
|
||||
tls_p->is_server = false;
|
||||
_init_bio(L, tls_p, ctx_p);
|
||||
SSL_set_connect_state(tls_p->ssl);
|
||||
}
|
||||
|
||||
static void
|
||||
_init_server_context(lua_State* L, struct tls_context* tls_p, struct ssl_ctx* ctx_p) {
|
||||
tls_p->is_server = true;
|
||||
_init_bio(L, tls_p, ctx_p);
|
||||
SSL_set_accept_state(tls_p->ssl);
|
||||
}
|
||||
|
||||
static struct tls_context *
|
||||
_check_context(lua_State* L, int idx) {
|
||||
struct tls_context* tls_p = (struct tls_context*)lua_touserdata(L, idx);
|
||||
if(!tls_p) {
|
||||
luaL_error(L, "need tls context");
|
||||
}
|
||||
if(tls_p->is_close) {
|
||||
luaL_error(L, "context is closed");
|
||||
}
|
||||
return tls_p;
|
||||
}
|
||||
|
||||
static struct ssl_ctx *
|
||||
_check_sslctx(lua_State* L, int idx) {
|
||||
struct ssl_ctx* ctx_p = (struct ssl_ctx*)lua_touserdata(L, idx);
|
||||
if(!ctx_p) {
|
||||
luaL_error(L, "need sslctx");
|
||||
}
|
||||
return ctx_p;
|
||||
}
|
||||
|
||||
static int
|
||||
_ltls_context_finished(lua_State* L) {
|
||||
struct tls_context* tls_p = _check_context(L, 1);
|
||||
int b = SSL_is_init_finished(tls_p->ssl);
|
||||
lua_pushboolean(L, b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_ltls_context_close(lua_State* L) {
|
||||
struct tls_context* tls_p = lua_touserdata(L, 1);
|
||||
if(!tls_p->is_close) {
|
||||
SSL_free(tls_p->ssl);
|
||||
tls_p->ssl = NULL;
|
||||
tls_p->in_bio = NULL; //in_bio and out_bio will be free when SSL_free is called
|
||||
tls_p->out_bio = NULL;
|
||||
tls_p->is_close = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_bio_read(lua_State* L, struct tls_context* tls_p) {
|
||||
char outbuff[4096];
|
||||
int all_read = 0;
|
||||
int read = 0;
|
||||
int pending = BIO_ctrl_pending(tls_p->out_bio);
|
||||
if(pending >0) {
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
while(pending > 0) {
|
||||
read = BIO_read(tls_p->out_bio, outbuff, sizeof(outbuff));
|
||||
// printf("BIO_read read:%d pending:%d\n", read, pending);
|
||||
if(read <= 0) {
|
||||
luaL_error(L, "BIO_read error:%d", read);
|
||||
}else if(read <= sizeof(outbuff)) {
|
||||
all_read += read;
|
||||
luaL_addlstring(&b, (const char*)outbuff, read);
|
||||
}else {
|
||||
luaL_error(L, "invalid BIO_read:%d", read);
|
||||
}
|
||||
pending = BIO_ctrl_pending(tls_p->out_bio);
|
||||
}
|
||||
if(all_read>0) {
|
||||
luaL_pushresult(&b);
|
||||
}
|
||||
}
|
||||
return all_read;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_bio_write(lua_State* L, struct tls_context* tls_p, const char* s, size_t len) {
|
||||
char* p = (char*)s;
|
||||
size_t sz = len;
|
||||
while(sz > 0) {
|
||||
int written = BIO_write(tls_p->in_bio, p, sz);
|
||||
// printf("BIO_write written:%d sz:%zu\n", written, sz);
|
||||
if(written <= 0) {
|
||||
luaL_error(L, "BIO_write error:%d", written);
|
||||
}else if (written <= sz) {
|
||||
p += written;
|
||||
sz -= written;
|
||||
}else {
|
||||
luaL_error(L, "invalid BIO_write:%d", written);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_ltls_context_handshake(lua_State* L) {
|
||||
struct tls_context* tls_p = _check_context(L, 1);
|
||||
size_t slen = 0;
|
||||
const char* exchange = lua_tolstring(L, 2, &slen);
|
||||
|
||||
// check handshake is finished
|
||||
if(SSL_is_init_finished(tls_p->ssl)) {
|
||||
luaL_error(L, "handshake is finished");
|
||||
}
|
||||
|
||||
// handshake exchange
|
||||
if(slen > 0 && exchange != NULL) {
|
||||
_bio_write(L, tls_p, exchange, slen);
|
||||
}
|
||||
|
||||
// first handshake; initiated by client
|
||||
if(!SSL_is_init_finished(tls_p->ssl)) {
|
||||
int ret = SSL_do_handshake(tls_p->ssl);
|
||||
if(ret == 1) {
|
||||
return 0;
|
||||
} else if (ret < 0) {
|
||||
int err = SSL_get_error(tls_p->ssl, ret);
|
||||
if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
|
||||
int all_read = _bio_read(L, tls_p);
|
||||
if(all_read>0) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
luaL_error(L, "SSL_do_handshake error:%d ret:%d", err, ret);
|
||||
}
|
||||
} else {
|
||||
int err = SSL_get_error(tls_p->ssl, ret);
|
||||
luaL_error(L, "SSL_do_handshake error:%d ret:%d", err, ret);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_ltls_context_read(lua_State* L) {
|
||||
struct tls_context* tls_p = _check_context(L, 1);
|
||||
size_t slen = 0;
|
||||
const char* encrypted_data = lua_tolstring(L, 2, &slen);
|
||||
|
||||
// write encrypted data
|
||||
if(slen>0 && encrypted_data) {
|
||||
_bio_write(L, tls_p, encrypted_data, slen);
|
||||
}
|
||||
|
||||
char outbuff[4096];
|
||||
int read = 0;
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
|
||||
do {
|
||||
read = SSL_read(tls_p->ssl, outbuff, sizeof(outbuff));
|
||||
if(read <= 0) {
|
||||
int err = SSL_get_error(tls_p->ssl, read);
|
||||
if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
|
||||
break;
|
||||
}
|
||||
luaL_error(L, "SSL_read error:%d", err);
|
||||
}else if(read <= sizeof(outbuff)) {
|
||||
luaL_addlstring(&b, outbuff, read);
|
||||
}else {
|
||||
luaL_error(L, "invalid SSL_read:%d", read);
|
||||
}
|
||||
}while(true);
|
||||
luaL_pushresult(&b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_ltls_context_write(lua_State* L) {
|
||||
struct tls_context* tls_p = _check_context(L, 1);
|
||||
size_t slen = 0;
|
||||
char* unencrypted_data = (char*)lua_tolstring(L, 2, &slen);
|
||||
|
||||
while(slen > 0) {
|
||||
int written = SSL_write(tls_p->ssl, unencrypted_data, slen);
|
||||
if(written <= 0) {
|
||||
int err = SSL_get_error(tls_p->ssl, written);
|
||||
luaL_error(L, "SSL_write error:%d", err);
|
||||
}else if(written <= slen) {
|
||||
unencrypted_data += written;
|
||||
slen -= written;
|
||||
}else {
|
||||
luaL_error(L, "invalid SSL_write:%d", written);
|
||||
}
|
||||
}
|
||||
|
||||
int all_read = _bio_read(L, tls_p);
|
||||
if(all_read <= 0) {
|
||||
lua_pushstring(L, "");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_lctx_gc(lua_State* L) {
|
||||
struct ssl_ctx* ctx_p = _check_sslctx(L, 1);
|
||||
if(ctx_p->ctx) {
|
||||
SSL_CTX_free(ctx_p->ctx);
|
||||
ctx_p->ctx = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lctx_cert(lua_State* L) {
|
||||
struct ssl_ctx* ctx_p = _check_sslctx(L, 1);
|
||||
const char* certfile = lua_tostring(L, 2);
|
||||
const char* key = lua_tostring(L, 3);
|
||||
if(!certfile) {
|
||||
luaL_error(L, "need certfile");
|
||||
}
|
||||
|
||||
if(!key) {
|
||||
luaL_error(L, "need private key");
|
||||
}
|
||||
|
||||
int ret = SSL_CTX_use_certificate_chain_file(ctx_p->ctx, certfile);
|
||||
if(ret != 1) {
|
||||
luaL_error(L, "SSL_CTX_use_certificate_chain_file error:%d", ret);
|
||||
}
|
||||
|
||||
ret = SSL_CTX_use_PrivateKey_file(ctx_p->ctx, key, SSL_FILETYPE_PEM);
|
||||
if(ret != 1) {
|
||||
luaL_error(L, "SSL_CTX_use_PrivateKey_file error:%d", ret);
|
||||
}
|
||||
ret = SSL_CTX_check_private_key(ctx_p->ctx);
|
||||
if(ret != 1) {
|
||||
luaL_error(L, "SSL_CTX_check_private_key error:%d", ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lctx_ciphers(lua_State* L) {
|
||||
struct ssl_ctx* ctx_p = _check_sslctx(L, 1);
|
||||
const char* s = lua_tostring(L, 2);
|
||||
if(!s) {
|
||||
luaL_error(L, "need cipher list");
|
||||
}
|
||||
int ret = SSL_CTX_set_tlsext_use_srtp(ctx_p->ctx, s);
|
||||
if(ret != 0) {
|
||||
luaL_error(L, "SSL_CTX_set_tlsext_use_srtp error:%d", ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lnew_ctx(lua_State* L) {
|
||||
struct ssl_ctx* ctx_p = (struct ssl_ctx*)lua_newuserdata(L, sizeof(*ctx_p));
|
||||
ctx_p->ctx = SSL_CTX_new(SSLv23_method());
|
||||
if(!ctx_p->ctx) {
|
||||
unsigned int err = ERR_get_error();
|
||||
char buf[256];
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
luaL_error(L, "SSL_CTX_new client faild. %s\n", buf);
|
||||
}
|
||||
|
||||
if(luaL_newmetatable(L, "_TLS_SSLCTX_METATABLE_")) {
|
||||
luaL_Reg l[] = {
|
||||
{"set_ciphers", _lctx_ciphers},
|
||||
{"set_cert", _lctx_cert},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
luaL_newlib(L, l);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, _lctx_gc);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lnew_tls(lua_State* L) {
|
||||
struct tls_context* tls_p = (struct tls_context*)lua_newuserdata(L, sizeof(*tls_p));
|
||||
tls_p->is_close = false;
|
||||
const char* method = luaL_optstring(L, 1, "nil");
|
||||
struct ssl_ctx* ctx_p = _check_sslctx(L, 2);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_setuservalue(L, -2); // set ssl_ctx associated to tls_context
|
||||
|
||||
if(strcmp(method, "client") == 0) {
|
||||
_init_client_context(L, tls_p, ctx_p);
|
||||
}else if(strcmp(method, "server") == 0) {
|
||||
_init_server_context(L, tls_p, ctx_p);
|
||||
} else {
|
||||
luaL_error(L, "invalid method:%s e.g[server, client]", method);
|
||||
}
|
||||
|
||||
if(luaL_newmetatable(L, "_TLS_CONTEXT_METATABLE_")) {
|
||||
luaL_Reg l[] = {
|
||||
{"close", _ltls_context_close},
|
||||
{"finished", _ltls_context_finished},
|
||||
{"handshake", _ltls_context_handshake},
|
||||
{"read", _ltls_context_read},
|
||||
{"write", _ltls_context_write},
|
||||
{NULL, NULL},
|
||||
};
|
||||
luaL_newlib(L, l);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, _ltls_context_close);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
luaopen_ltls_c(lua_State* L) {
|
||||
luaL_Reg l[] = {
|
||||
{"newctx", lnew_ctx},
|
||||
{"newtls", lnew_tls},
|
||||
{NULL, NULL},
|
||||
};
|
||||
luaL_checkversion(L);
|
||||
luaL_newlib(L, l);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) ltls_init(void) {
|
||||
#ifndef OPENSSL_EXTERNAL_INITIALIZATION
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
ERR_load_BIO_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
TLS_IS_INIT = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void __attribute__((destructor)) ltls_destory(void) {
|
||||
if(TLS_IS_INIT) {
|
||||
ENGINE_cleanup();
|
||||
CONF_modules_unload(1);
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <lauxlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "skynet.h"
|
||||
|
||||
@@ -73,6 +74,11 @@ fill_header(lua_State *L, uint8_t *buf, int sz) {
|
||||
BYTE 2/3 ; 2:multipart, 3:multipart end
|
||||
DWORD SESSION
|
||||
PADDING msgpart(sz)
|
||||
|
||||
trace
|
||||
WORD stringsz + 1
|
||||
BYTE 4
|
||||
STRING tag
|
||||
*/
|
||||
static int
|
||||
packreq_number(lua_State *L, int session, void * msg, uint32_t sz, int is_push) {
|
||||
@@ -105,7 +111,11 @@ packreq_string(lua_State *L, int session, void * msg, uint32_t sz, int is_push)
|
||||
const char *name = lua_tolstring(L, 1, &namelen);
|
||||
if (name == NULL || namelen < 1 || namelen > 255) {
|
||||
skynet_free(msg);
|
||||
luaL_error(L, "name is too long %s", name);
|
||||
if (name == NULL) {
|
||||
luaL_error(L, "name is not a string, it's a %s", lua_typename(L, lua_type(L, 1)));
|
||||
} else {
|
||||
luaL_error(L, "name is too long %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t buf[TEMP_LENGTH];
|
||||
@@ -177,14 +187,14 @@ packrequest(lua_State *L, int is_push) {
|
||||
} else {
|
||||
multipak = packreq_string(L, session, msg, sz, is_push);
|
||||
}
|
||||
int current_session = session;
|
||||
if (++session < 0) {
|
||||
session = 1;
|
||||
uint32_t new_session = (uint32_t)session + 1;
|
||||
if (new_session > INT32_MAX) {
|
||||
new_session = 1;
|
||||
}
|
||||
lua_pushinteger(L, session);
|
||||
lua_pushinteger(L, new_session);
|
||||
if (multipak) {
|
||||
lua_createtable(L, multipak, 0);
|
||||
packreq_multi(L, current_session, msg, sz);
|
||||
packreq_multi(L, session, msg, sz);
|
||||
skynet_free(msg);
|
||||
return 3;
|
||||
} else {
|
||||
@@ -203,13 +213,30 @@ lpackpush(lua_State *L) {
|
||||
return packrequest(L, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
lpacktrace(lua_State *L) {
|
||||
size_t sz;
|
||||
const char * tag = luaL_checklstring(L, 1, &sz);
|
||||
if (sz > 0x8000) {
|
||||
return luaL_error(L, "trace tag is too long : %d", (int) sz);
|
||||
}
|
||||
uint8_t buf[TEMP_LENGTH];
|
||||
buf[2] = 4;
|
||||
fill_header(L, buf, sz+1);
|
||||
memcpy(buf+3, tag, sz);
|
||||
lua_pushlstring(L, (const char *)buf, sz+3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
string packed message
|
||||
return
|
||||
uint32_t or string addr
|
||||
int session
|
||||
string msg
|
||||
lightuserdata msg
|
||||
int sz
|
||||
boolean padding
|
||||
boolean is_push
|
||||
*/
|
||||
|
||||
static inline uint32_t
|
||||
@@ -217,6 +244,14 @@ unpack_uint32(const uint8_t * buf) {
|
||||
return buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24;
|
||||
}
|
||||
|
||||
static void
|
||||
return_buffer(lua_State *L, const char * buffer, int sz) {
|
||||
void * ptr = skynet_malloc(sz);
|
||||
memcpy(ptr, buffer, sz);
|
||||
lua_pushlightuserdata(L, ptr);
|
||||
lua_pushinteger(L, sz);
|
||||
}
|
||||
|
||||
static int
|
||||
unpackreq_number(lua_State *L, const uint8_t * buf, int sz) {
|
||||
if (sz < 9) {
|
||||
@@ -226,14 +261,15 @@ unpackreq_number(lua_State *L, const uint8_t * buf, int sz) {
|
||||
uint32_t session = unpack_uint32(buf+5);
|
||||
lua_pushinteger(L, address);
|
||||
lua_pushinteger(L, session);
|
||||
lua_pushlstring(L, (const char *)buf+9, sz-9);
|
||||
|
||||
return_buffer(L, (const char *)buf+9, sz-9);
|
||||
if (session == 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushboolean(L,1); // is_push, no reponse
|
||||
return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -246,11 +282,12 @@ unpackmreq_number(lua_State *L, const uint8_t * buf, int sz, int is_push) {
|
||||
uint32_t size = unpack_uint32(buf+9);
|
||||
lua_pushinteger(L, address);
|
||||
lua_pushinteger(L, session);
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, size);
|
||||
lua_pushboolean(L, 1); // padding multi part
|
||||
lua_pushboolean(L, is_push);
|
||||
|
||||
return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -262,10 +299,16 @@ unpackmreq_part(lua_State *L, const uint8_t * buf, int sz) {
|
||||
uint32_t session = unpack_uint32(buf+1);
|
||||
lua_pushboolean(L, 0); // no address
|
||||
lua_pushinteger(L, session);
|
||||
lua_pushlstring(L, (const char *)buf+5, sz-5);
|
||||
return_buffer(L, (const char *)buf+5, sz-5);
|
||||
lua_pushboolean(L, padding);
|
||||
|
||||
return 4;
|
||||
return 5;
|
||||
}
|
||||
|
||||
static int
|
||||
unpacktrace(lua_State *L, const char * buf, int sz) {
|
||||
lua_pushlstring(L, buf + 1, sz - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -280,14 +323,14 @@ unpackreq_string(lua_State *L, const uint8_t * buf, int sz) {
|
||||
lua_pushlstring(L, (const char *)buf+2, namesz);
|
||||
uint32_t session = unpack_uint32(buf + namesz + 2);
|
||||
lua_pushinteger(L, (uint32_t)session);
|
||||
lua_pushlstring(L, (const char *)buf+2+namesz+4, sz - namesz - 6);
|
||||
return_buffer(L, (const char *)buf+2+namesz+4, sz - namesz - 6);
|
||||
if (session == 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushboolean(L,1); // is_push, no reponse
|
||||
return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -303,18 +346,26 @@ unpackmreq_string(lua_State *L, const uint8_t * buf, int sz, int is_push) {
|
||||
uint32_t session = unpack_uint32(buf + namesz + 2);
|
||||
uint32_t size = unpack_uint32(buf + namesz + 6);
|
||||
lua_pushinteger(L, session);
|
||||
lua_pushnil(L);
|
||||
lua_pushinteger(L, size);
|
||||
lua_pushboolean(L, 1); // padding multipart
|
||||
lua_pushboolean(L, is_push);
|
||||
|
||||
return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
static int
|
||||
lunpackrequest(lua_State *L) {
|
||||
size_t ssz;
|
||||
const char *msg = luaL_checklstring(L,1,&ssz);
|
||||
int sz = (int)ssz;
|
||||
int sz;
|
||||
const char *msg;
|
||||
if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) {
|
||||
msg = (const char *)lua_touserdata(L, 1);
|
||||
sz = luaL_checkinteger(L, 2);
|
||||
} else {
|
||||
size_t ssz;
|
||||
msg = luaL_checklstring(L,1,&ssz);
|
||||
sz = (int)ssz;
|
||||
}
|
||||
switch (msg[0]) {
|
||||
case 0:
|
||||
return unpackreq_number(L, (const uint8_t *)msg, sz);
|
||||
@@ -325,6 +376,8 @@ lunpackrequest(lua_State *L) {
|
||||
case 2:
|
||||
case 3:
|
||||
return unpackmreq_part(L, (const uint8_t *)msg, sz);
|
||||
case 4:
|
||||
return unpacktrace(L, msg, sz);
|
||||
case '\x80':
|
||||
return unpackreq_string(L, (const uint8_t *)msg, sz);
|
||||
case '\x81':
|
||||
@@ -474,6 +527,32 @@ lunpackresponse(lua_State *L) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
table
|
||||
pointer
|
||||
sz
|
||||
|
||||
push (pointer/sz) as string into table, and free pointer
|
||||
*/
|
||||
static int
|
||||
lappend(lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
int n = lua_rawlen(L, 1);
|
||||
if (lua_isnil(L, 2)) {
|
||||
lua_settop(L, 3);
|
||||
lua_seti(L, 1, n + 1);
|
||||
return 0;
|
||||
}
|
||||
void * buffer = lua_touserdata(L, 2);
|
||||
if (buffer == NULL)
|
||||
return luaL_error(L, "Need lightuserdata");
|
||||
int sz = luaL_checkinteger(L, 3);
|
||||
lua_pushlstring(L, (const char *)buffer, sz);
|
||||
skynet_free((void *)buffer);
|
||||
lua_seti(L, 1, n+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lconcat(lua_State *L) {
|
||||
if (!lua_istable(L,1))
|
||||
@@ -507,15 +586,41 @@ lconcat(lua_State *L) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int
|
||||
lisname(lua_State *L) {
|
||||
const char * name = lua_tostring(L, 1);
|
||||
if (name && name[0] == '@') {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lnodename(lua_State *L) {
|
||||
pid_t pid = getpid();
|
||||
char hostname[256];
|
||||
if (gethostname(hostname, sizeof(hostname))==0) {
|
||||
lua_pushfstring(L, "%s%d", hostname, (int)pid);
|
||||
} else {
|
||||
lua_pushfstring(L, "noname%d", (int)pid);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
LUAMOD_API int
|
||||
luaopen_skynet_cluster_core(lua_State *L) {
|
||||
luaL_Reg l[] = {
|
||||
{ "packrequest", lpackrequest },
|
||||
{ "packpush", lpackpush },
|
||||
{ "packtrace", lpacktrace },
|
||||
{ "unpackrequest", lunpackrequest },
|
||||
{ "packresponse", lpackresponse },
|
||||
{ "unpackresponse", lunpackresponse },
|
||||
{ "append", lappend },
|
||||
{ "concat", lconcat },
|
||||
{ "isname", lisname },
|
||||
{ "nodename", lnodename },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
luaL_checkversion(L);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SMALL_CHUNK 256
|
||||
|
||||
@@ -960,7 +961,7 @@ luaopen_skynet_crypt(lua_State *L) {
|
||||
if (!init) {
|
||||
// Don't need call srandom more than once.
|
||||
init = 1 ;
|
||||
srandom(time(NULL));
|
||||
srandom((random() << 8) ^ (time(NULL) << 16) ^ getpid());
|
||||
}
|
||||
luaL_Reg l[] = {
|
||||
{ "hashkey", lhashkey },
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "malloc_hook.h"
|
||||
#include "luashrtbl.h"
|
||||
|
||||
static int
|
||||
ltotal(lua_State *L) {
|
||||
@@ -37,15 +36,28 @@ ldump(lua_State *L) {
|
||||
}
|
||||
|
||||
static int
|
||||
lexpandshrtbl(lua_State *L) {
|
||||
int n = luaL_checkinteger(L, 1);
|
||||
luaS_expandshr(n);
|
||||
lcurrent(lua_State *L) {
|
||||
lua_pushinteger(L, malloc_current_memory());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ldumpheap(lua_State *L) {
|
||||
mallctl_cmd("prof.dump");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lcurrent(lua_State *L) {
|
||||
lua_pushinteger(L, malloc_current_memory());
|
||||
lprofactive(lua_State *L) {
|
||||
bool *pval, active;
|
||||
if (lua_isnone(L, 1)) {
|
||||
pval = NULL;
|
||||
} else {
|
||||
active = lua_toboolean(L, 1) ? true : false;
|
||||
pval = &active;
|
||||
}
|
||||
bool ret = mallctl_bool("prof.active", pval);
|
||||
lua_pushboolean(L, ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -59,9 +71,9 @@ luaopen_skynet_memory(lua_State *L) {
|
||||
{ "dumpinfo", ldumpinfo },
|
||||
{ "dump", ldump },
|
||||
{ "info", dump_mem_lua },
|
||||
{ "ssinfo", luaS_shrinfo },
|
||||
{ "ssexpand", lexpandshrtbl },
|
||||
{ "current", lcurrent },
|
||||
{ "dumpheap", ldumpheap },
|
||||
{ "profactive", lprofactive },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ mc_remote(lua_State *L) {
|
||||
lua_pushlightuserdata(L, pack->data);
|
||||
lua_pushinteger(L, (lua_Integer)(pack->size));
|
||||
skynet_free(pack);
|
||||
skynet_free(ptr);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -140,7 +141,8 @@ static int
|
||||
mc_nextid(lua_State *L) {
|
||||
uint32_t id = (uint32_t)luaL_checkinteger(L, 1);
|
||||
id += 256;
|
||||
lua_pushinteger(L, (uint32_t)id);
|
||||
// remove the highest bit, see #1139
|
||||
lua_pushinteger(L, id & 0x7fffffffu);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
#define LUA_LIB
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static unsigned int num_escape_sql_str(unsigned char *dst, unsigned char *src, size_t size)
|
||||
{
|
||||
unsigned int n =0;
|
||||
while (size) {
|
||||
/* the highest bit of all the UTF-8 chars
|
||||
* is always 1 */
|
||||
if ((*src & 0x80) == 0) {
|
||||
switch (*src) {
|
||||
case '\0':
|
||||
case '\b':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case 26: /* \Z */
|
||||
case '\\':
|
||||
case '\'':
|
||||
case '"':
|
||||
n++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
src++;
|
||||
size--;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
static unsigned char*
|
||||
escape_sql_str(unsigned char *dst, unsigned char *src, size_t size)
|
||||
{
|
||||
|
||||
while (size) {
|
||||
if ((*src & 0x80) == 0) {
|
||||
switch (*src) {
|
||||
case '\0':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '0';
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'b';
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'n';
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'r';
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 't';
|
||||
break;
|
||||
|
||||
case 26:
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'Z';
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '\\';
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '\'';
|
||||
break;
|
||||
|
||||
case '"':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '"';
|
||||
break;
|
||||
|
||||
default:
|
||||
*dst++ = *src;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*dst++ = *src;
|
||||
}
|
||||
src++;
|
||||
size--;
|
||||
} /* while (size) */
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
quote_sql_str(lua_State *L)
|
||||
{
|
||||
size_t len, dlen, escape;
|
||||
unsigned char *p;
|
||||
unsigned char *src, *dst;
|
||||
|
||||
if (lua_gettop(L) != 1) {
|
||||
return luaL_error(L, "expecting one argument");
|
||||
}
|
||||
|
||||
src = (unsigned char *) luaL_checklstring(L, 1, &len);
|
||||
|
||||
if (len == 0) {
|
||||
dst = (unsigned char *) "''";
|
||||
dlen = sizeof("''") - 1;
|
||||
lua_pushlstring(L, (char *) dst, dlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
escape = num_escape_sql_str(NULL, src, len);
|
||||
|
||||
dlen = sizeof("''") - 1 + len + escape;
|
||||
p = lua_newuserdata(L, dlen);
|
||||
|
||||
dst = p;
|
||||
|
||||
*p++ = '\'';
|
||||
|
||||
if (escape == 0) {
|
||||
memcpy(p, src, len);
|
||||
p+=len;
|
||||
} else {
|
||||
p = (unsigned char *) escape_sql_str(p, src, len);
|
||||
}
|
||||
|
||||
*p++ = '\'';
|
||||
|
||||
if (p != dst + dlen) {
|
||||
return luaL_error(L, "quote sql string error");
|
||||
}
|
||||
|
||||
lua_pushlstring(L, (char *) dst, p - dst);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct luaL_Reg mysqlauxlib[] = {
|
||||
{"quote_sql_str",quote_sql_str},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_skynet_mysqlaux_c (lua_State *L) {
|
||||
lua_newtable(L);
|
||||
luaL_setfuncs(L, mysqlauxlib, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -253,6 +253,7 @@ fillcolliding(lua_State *L, struct context *ctx) {
|
||||
for (i=emptyslot;i<sizehash;i++) {
|
||||
if (tbl->hash[i].valuetype == VALUETYPE_NIL) {
|
||||
n = &tbl->hash[i];
|
||||
emptyslot = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
263
lualib-src/lua-sharetable.c
Normal file
263
lualib-src/lua-sharetable.c
Normal file
@@ -0,0 +1,263 @@
|
||||
#define LUA_LIB
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
#include "lgc.h"
|
||||
|
||||
#ifdef makeshared
|
||||
|
||||
static void
|
||||
mark_shared(lua_State *L) {
|
||||
if (lua_type(L, -1) != LUA_TTABLE) {
|
||||
luaL_error(L, "Not a table, it's a %s.", lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
Table * t = (Table *)lua_topointer(L, -1);
|
||||
if (isshared(t))
|
||||
return;
|
||||
makeshared(t);
|
||||
luaL_checkstack(L, 4, NULL);
|
||||
if (lua_getmetatable(L, -1)) {
|
||||
luaL_error(L, "Can't share metatable");
|
||||
}
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
int i;
|
||||
for (i=0;i<2;i++) {
|
||||
int idx = -i-1;
|
||||
int t = lua_type(L, idx);
|
||||
switch (t) {
|
||||
case LUA_TTABLE:
|
||||
mark_shared(L);
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TBOOLEAN:
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
break;
|
||||
case LUA_TFUNCTION:
|
||||
if (lua_getupvalue(L, idx, 1) != NULL) {
|
||||
luaL_error(L, "Invalid function with upvalue");
|
||||
} else if (!lua_iscfunction(L, idx)) {
|
||||
LClosure *f = (LClosure *)lua_topointer(L, idx);
|
||||
makeshared(f);
|
||||
}
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
lua_sharestring(L, idx);
|
||||
break;
|
||||
default:
|
||||
luaL_error(L, "Invalid type [%s]", lua_typename(L, t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
lis_sharedtable(lua_State* L) {
|
||||
int b = 0;
|
||||
if(lua_type(L, 1) == LUA_TTABLE) {
|
||||
Table * t = (Table *)lua_topointer(L, 1);
|
||||
b = isshared(t);
|
||||
}
|
||||
lua_pushboolean(L, b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
make_matrix(lua_State *L) {
|
||||
// turn off gc , because marking shared will prevent gc mark.
|
||||
lua_gc(L, LUA_GCSTOP, 0);
|
||||
mark_shared(L);
|
||||
Table * t = (Table *)lua_topointer(L, -1);
|
||||
lua_pushlightuserdata(L, t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
clone_table(lua_State *L) {
|
||||
lua_clonetable(L, lua_touserdata(L, 1));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lco_stackvalues(lua_State* L) {
|
||||
lua_State *cL = lua_tothread(L, 1);
|
||||
luaL_argcheck(L, cL, 1, "thread expected");
|
||||
int n = 0;
|
||||
if(cL != L) {
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
n = lua_gettop(cL);
|
||||
if(n > 0) {
|
||||
luaL_checkstack(L, n+1, NULL);
|
||||
int top = lua_gettop(L);
|
||||
lua_xmove(cL, L, n);
|
||||
int i=0;
|
||||
for(i=1; i<=n; i++) {
|
||||
lua_pushvalue(L, top+i);
|
||||
lua_seti(L, 2, i);
|
||||
}
|
||||
lua_xmove(L, cL, n);
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushinteger(L, n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
struct state_ud {
|
||||
lua_State *L;
|
||||
};
|
||||
|
||||
static int
|
||||
close_state(lua_State *L) {
|
||||
struct state_ud *ud = (struct state_ud *)luaL_checkudata(L, 1, "BOXMATRIXSTATE");
|
||||
if (ud->L) {
|
||||
lua_close(ud->L);
|
||||
ud->L = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_matrix(lua_State *L) {
|
||||
struct state_ud *ud = (struct state_ud *)luaL_checkudata(L, 1, "BOXMATRIXSTATE");
|
||||
if (ud->L) {
|
||||
const void * v = lua_topointer(ud->L, 1);
|
||||
lua_pushlightuserdata(L, (void *)v);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_size(lua_State *L) {
|
||||
struct state_ud *ud = (struct state_ud *)luaL_checkudata(L, 1, "BOXMATRIXSTATE");
|
||||
if (ud->L) {
|
||||
lua_Integer sz = lua_gc(ud->L, LUA_GCCOUNT, 0);
|
||||
sz *= 1024;
|
||||
sz += lua_gc(ud->L, LUA_GCCOUNTB, 0);
|
||||
lua_pushinteger(L, sz);
|
||||
} else {
|
||||
lua_pushinteger(L, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
box_state(lua_State *L, lua_State *mL) {
|
||||
struct state_ud *ud = (struct state_ud *)lua_newuserdata(L, sizeof(*ud));
|
||||
ud->L = mL;
|
||||
if (luaL_newmetatable(L, "BOXMATRIXSTATE")) {
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, close_state);
|
||||
lua_setfield(L, -2, "close");
|
||||
lua_pushcfunction(L, get_matrix);
|
||||
lua_setfield(L, -2, "getptr");
|
||||
lua_pushcfunction(L, get_size);
|
||||
lua_setfield(L, -2, "size");
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
load_matrixfile(lua_State *L) {
|
||||
luaL_openlibs(L);
|
||||
const char * source = (const char *)lua_touserdata(L, 1);
|
||||
if (source[0] == '@') {
|
||||
if (luaL_loadfilex_(L, source+1, NULL) != LUA_OK)
|
||||
lua_error(L);
|
||||
} else {
|
||||
if (luaL_loadstring(L, source) != LUA_OK)
|
||||
lua_error(L);
|
||||
}
|
||||
lua_replace(L, 1);
|
||||
if (lua_pcall(L, lua_gettop(L) - 1, 1, 0) != LUA_OK)
|
||||
lua_error(L);
|
||||
lua_gc(L, LUA_GCCOLLECT, 0);
|
||||
lua_pushcfunction(L, make_matrix);
|
||||
lua_insert(L, -2);
|
||||
lua_call(L, 1, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
matrix_from_file(lua_State *L) {
|
||||
lua_State *mL = luaL_newstate();
|
||||
if (mL == NULL) {
|
||||
return luaL_error(L, "luaL_newstate failed");
|
||||
}
|
||||
const char * source = luaL_checkstring(L, 1);
|
||||
int top = lua_gettop(L);
|
||||
lua_pushcfunction(mL, load_matrixfile);
|
||||
lua_pushlightuserdata(mL, (void *)source);
|
||||
if (top > 1) {
|
||||
if (!lua_checkstack(mL, top + 1)) {
|
||||
return luaL_error(L, "Too many argument %d", top);
|
||||
}
|
||||
int i;
|
||||
for (i=2;i<=top;i++) {
|
||||
switch(lua_type(L, i)) {
|
||||
case LUA_TBOOLEAN:
|
||||
lua_pushboolean(mL, lua_toboolean(L, i));
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
if (lua_isinteger(L, i)) {
|
||||
lua_pushinteger(mL, lua_tointeger(L, i));
|
||||
} else {
|
||||
lua_pushnumber(mL, lua_tonumber(L, i));
|
||||
}
|
||||
break;
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
lua_pushlightuserdata(mL, lua_touserdata(L, i));
|
||||
break;
|
||||
case LUA_TFUNCTION:
|
||||
if (lua_iscfunction(L, i) && lua_getupvalue(L, i, 1) == NULL) {
|
||||
lua_pushcfunction(mL, lua_tocfunction(L, i));
|
||||
break;
|
||||
}
|
||||
return luaL_argerror(L, i, "Only support light C function");
|
||||
default:
|
||||
return luaL_argerror(L, i, "Type invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
int ok = lua_pcall(mL, top, 1, 0);
|
||||
if (ok != LUA_OK) {
|
||||
lua_pushstring(L, lua_tostring(mL, -1));
|
||||
lua_close(mL);
|
||||
lua_error(L);
|
||||
}
|
||||
return box_state(L, mL);
|
||||
}
|
||||
|
||||
LUAMOD_API int
|
||||
luaopen_skynet_sharetable_core(lua_State *L) {
|
||||
luaL_checkversion(L);
|
||||
luaL_Reg l[] = {
|
||||
{ "clone", clone_table },
|
||||
{ "stackvalues", lco_stackvalues },
|
||||
{ "matrix", matrix_from_file },
|
||||
{ "is_sharedtable", lis_sharedtable },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
luaL_newlib(L, l);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
LUAMOD_API int
|
||||
luaopen_skynet_sharetable_core(lua_State *L) {
|
||||
return luaL_error(L, "No share string table support");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -11,6 +11,29 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "skynet.h"
|
||||
|
||||
// return nsec
|
||||
static int64_t
|
||||
get_time() {
|
||||
#if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
|
||||
struct timespec ti;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ti);
|
||||
return (int64_t)1000000000 * ti.tv_sec + ti.tv_nsec;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (int64_t)1000000000 * tv.tv_sec + tv.tv_usec * 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct snlua {
|
||||
lua_State * L;
|
||||
@@ -120,6 +143,38 @@ lcommand(lua_State *L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
laddresscommand(lua_State *L) {
|
||||
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
|
||||
const char * cmd = luaL_checkstring(L,1);
|
||||
const char * result;
|
||||
const char * parm = NULL;
|
||||
if (lua_gettop(L) == 2) {
|
||||
parm = luaL_checkstring(L,2);
|
||||
}
|
||||
result = skynet_command(context, cmd, parm);
|
||||
if (result && result[0] == ':') {
|
||||
int i;
|
||||
uint32_t addr = 0;
|
||||
for (i=1;result[i];i++) {
|
||||
int c = result[i];
|
||||
if (c>='0' && c<='9') {
|
||||
c = c - '0';
|
||||
} else if (c>='a' && c<='f') {
|
||||
c = c - 'a' + 10;
|
||||
} else if (c>='A' && c<='F') {
|
||||
c = c - 'A' + 10;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
addr = addr * 16 + c;
|
||||
}
|
||||
lua_pushinteger(L, addr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lintcommand(lua_State *L) {
|
||||
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
|
||||
@@ -223,6 +278,11 @@ send_message(lua_State *L, int source, int idx_type) {
|
||||
luaL_error(L, "invalid param %s", lua_typename(L, lua_type(L,idx_type+2)));
|
||||
}
|
||||
if (session < 0) {
|
||||
if (session == -2) {
|
||||
// package is too large
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
// send to invalid address
|
||||
// todo: maybe throw an error would be better
|
||||
return 0;
|
||||
@@ -346,6 +406,79 @@ lnow(lua_State *L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lhpc(lua_State *L) {
|
||||
lua_pushinteger(L, get_time());
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAX_LEVEL 3
|
||||
|
||||
struct source_info {
|
||||
const char * source;
|
||||
int line;
|
||||
};
|
||||
|
||||
/*
|
||||
string tag
|
||||
string userstring
|
||||
thread co (default nil/current L)
|
||||
integer level (default nil)
|
||||
*/
|
||||
static int
|
||||
ltrace(lua_State *L) {
|
||||
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
|
||||
const char * tag = luaL_checkstring(L, 1);
|
||||
const char * user = luaL_checkstring(L, 2);
|
||||
if (!lua_isnoneornil(L, 3)) {
|
||||
lua_State * co = L;
|
||||
int level;
|
||||
if (lua_isthread(L, 3)) {
|
||||
co = lua_tothread (L, 3);
|
||||
level = luaL_optinteger(L, 4, 1);
|
||||
} else {
|
||||
level = luaL_optinteger(L, 3, 1);
|
||||
}
|
||||
struct source_info si[MAX_LEVEL];
|
||||
lua_Debug d;
|
||||
int index = 0;
|
||||
do {
|
||||
if (!lua_getstack(co, level, &d))
|
||||
break;
|
||||
lua_getinfo(co, "Sl", &d);
|
||||
level++;
|
||||
si[index].source = d.source;
|
||||
si[index].line = d.currentline;
|
||||
if (d.currentline >= 0)
|
||||
++index;
|
||||
} while (index < MAX_LEVEL);
|
||||
switch (index) {
|
||||
case 1:
|
||||
skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d", tag, get_time(), user, si[0].source, si[0].line);
|
||||
break;
|
||||
case 2:
|
||||
skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d %s:%d", tag, get_time(), user,
|
||||
si[0].source, si[0].line,
|
||||
si[1].source, si[1].line
|
||||
);
|
||||
break;
|
||||
case 3:
|
||||
skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d %s:%d %s:%d", tag, get_time(), user,
|
||||
si[0].source, si[0].line,
|
||||
si[1].source, si[1].line,
|
||||
si[2].source, si[2].line
|
||||
);
|
||||
break;
|
||||
default:
|
||||
skynet_error(context, "<TRACE %s> %" PRId64 " %s", tag, get_time(), user);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
skynet_error(context, "<TRACE %s> %" PRId64 " %s", tag, get_time(), user);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LUAMOD_API int
|
||||
luaopen_skynet_core(lua_State *L) {
|
||||
luaL_checkversion(L);
|
||||
@@ -356,19 +489,27 @@ luaopen_skynet_core(lua_State *L) {
|
||||
{ "redirect", lredirect },
|
||||
{ "command" , lcommand },
|
||||
{ "intcommand", lintcommand },
|
||||
{ "addresscommand", laddresscommand },
|
||||
{ "error", lerror },
|
||||
{ "tostring", ltostring },
|
||||
{ "harbor", lharbor },
|
||||
{ "callback", lcallback },
|
||||
{ "trace", ltrace },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
// functions without skynet_context
|
||||
luaL_Reg l2[] = {
|
||||
{ "tostring", ltostring },
|
||||
{ "pack", luaseri_pack },
|
||||
{ "unpack", luaseri_unpack },
|
||||
{ "packstring", lpackstring },
|
||||
{ "trash" , ltrash },
|
||||
{ "callback", lcallback },
|
||||
{ "now", lnow },
|
||||
{ "hpc", lhpc }, // getHPCounter
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
luaL_newlibtable(L, l);
|
||||
lua_createtable(L, 0, sizeof(l)/sizeof(l[0]) + sizeof(l2)/sizeof(l2[0]) -2);
|
||||
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context");
|
||||
struct skynet_context *ctx = lua_touserdata(L,-1);
|
||||
@@ -376,7 +517,10 @@ luaopen_skynet_core(lua_State *L) {
|
||||
return luaL_error(L, "Init skynet context first");
|
||||
}
|
||||
|
||||
|
||||
luaL_setfuncs(L,l,1);
|
||||
|
||||
luaL_setfuncs(L,l2,0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -525,41 +525,59 @@ concat_table(lua_State *L, int index, void *buffer, size_t tlen) {
|
||||
lua_pop(L,1);
|
||||
}
|
||||
|
||||
static void *
|
||||
get_buffer(lua_State *L, int index, int *sz) {
|
||||
static void
|
||||
get_buffer(lua_State *L, int index, struct socket_sendbuffer *buf) {
|
||||
void *buffer;
|
||||
switch(lua_type(L, index)) {
|
||||
const char * str;
|
||||
size_t len;
|
||||
case LUA_TUSERDATA:
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
buffer = lua_touserdata(L,index);
|
||||
*sz = luaL_checkinteger(L,index+1);
|
||||
// lua full useobject must be a raw pointer, it can't be a socket object or a memory object.
|
||||
buf->type = SOCKET_BUFFER_RAWPOINTER;
|
||||
buf->buffer = lua_touserdata(L, index);
|
||||
if (lua_isinteger(L, index+1)) {
|
||||
buf->sz = lua_tointeger(L, index+1);
|
||||
} else {
|
||||
buf->sz = lua_rawlen(L, index);
|
||||
}
|
||||
break;
|
||||
case LUA_TLIGHTUSERDATA: {
|
||||
int sz = -1;
|
||||
if (lua_isinteger(L, index+1)) {
|
||||
sz = lua_tointeger(L,index+1);
|
||||
}
|
||||
if (sz < 0) {
|
||||
buf->type = SOCKET_BUFFER_OBJECT;
|
||||
} else {
|
||||
buf->type = SOCKET_BUFFER_MEMORY;
|
||||
}
|
||||
buf->buffer = lua_touserdata(L,index);
|
||||
buf->sz = (size_t)sz;
|
||||
break;
|
||||
}
|
||||
case LUA_TTABLE:
|
||||
// concat the table as a string
|
||||
len = count_size(L, index);
|
||||
buffer = skynet_malloc(len);
|
||||
concat_table(L, index, buffer, len);
|
||||
*sz = (int)len;
|
||||
buf->type = SOCKET_BUFFER_MEMORY;
|
||||
buf->buffer = buffer;
|
||||
buf->sz = len;
|
||||
break;
|
||||
default:
|
||||
str = luaL_checklstring(L, index, &len);
|
||||
buffer = skynet_malloc(len);
|
||||
memcpy(buffer, str, len);
|
||||
*sz = (int)len;
|
||||
buf->type = SOCKET_BUFFER_RAWPOINTER;
|
||||
buf->buffer = luaL_checklstring(L, index, &buf->sz);
|
||||
break;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int
|
||||
lsend(lua_State *L) {
|
||||
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
|
||||
int id = luaL_checkinteger(L, 1);
|
||||
int sz = 0;
|
||||
void *buffer = get_buffer(L, 2, &sz);
|
||||
int err = skynet_socket_send(ctx, id, buffer, sz);
|
||||
struct socket_sendbuffer buf;
|
||||
buf.id = id;
|
||||
get_buffer(L, 2, &buf);
|
||||
int err = skynet_socket_sendbuffer(ctx, &buf);
|
||||
lua_pushboolean(L, !err);
|
||||
return 1;
|
||||
}
|
||||
@@ -568,9 +586,10 @@ static int
|
||||
lsendlow(lua_State *L) {
|
||||
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
|
||||
int id = luaL_checkinteger(L, 1);
|
||||
int sz = 0;
|
||||
void *buffer = get_buffer(L, 2, &sz);
|
||||
int err = skynet_socket_send_lowpriority(ctx, id, buffer, sz);
|
||||
struct socket_sendbuffer buf;
|
||||
buf.id = id;
|
||||
get_buffer(L, 2, &buf);
|
||||
int err = skynet_socket_sendbuffer_lowpriority(ctx, &buf);
|
||||
lua_pushboolean(L, !err);
|
||||
return 1;
|
||||
}
|
||||
@@ -645,9 +664,10 @@ ludp_send(lua_State *L) {
|
||||
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
|
||||
int id = luaL_checkinteger(L, 1);
|
||||
const char * address = luaL_checkstring(L, 2);
|
||||
int sz = 0;
|
||||
void *buffer = get_buffer(L, 3, &sz);
|
||||
int err = skynet_socket_udp_send(ctx, id, address, buffer, sz);
|
||||
struct socket_sendbuffer buf;
|
||||
buf.id = id;
|
||||
get_buffer(L, 3, &buf);
|
||||
int err = skynet_socket_udp_sendbuffer(ctx, address, &buf);
|
||||
|
||||
lua_pushboolean(L, !err);
|
||||
|
||||
@@ -680,6 +700,72 @@ ludp_address(lua_State *L) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void
|
||||
getinfo(lua_State *L, struct socket_info *si) {
|
||||
lua_newtable(L);
|
||||
lua_pushinteger(L, si->id);
|
||||
lua_setfield(L, -2, "id");
|
||||
lua_pushinteger(L, si->opaque);
|
||||
lua_setfield(L, -2, "address");
|
||||
switch(si->type) {
|
||||
case SOCKET_INFO_LISTEN:
|
||||
lua_pushstring(L, "LISTEN");
|
||||
lua_setfield(L, -2, "type");
|
||||
lua_pushinteger(L, si->read);
|
||||
lua_setfield(L, -2, "accept");
|
||||
lua_pushinteger(L, si->rtime);
|
||||
lua_setfield(L, -2, "rtime");
|
||||
if (si->name[0]) {
|
||||
lua_pushstring(L, si->name);
|
||||
lua_setfield(L, -2, "sock");
|
||||
}
|
||||
return;
|
||||
case SOCKET_INFO_TCP:
|
||||
lua_pushstring(L, "TCP");
|
||||
break;
|
||||
case SOCKET_INFO_UDP:
|
||||
lua_pushstring(L, "UDP");
|
||||
break;
|
||||
case SOCKET_INFO_BIND:
|
||||
lua_pushstring(L, "BIND");
|
||||
break;
|
||||
default:
|
||||
lua_pushstring(L, "UNKNOWN");
|
||||
lua_setfield(L, -2, "type");
|
||||
return;
|
||||
}
|
||||
lua_setfield(L, -2, "type");
|
||||
lua_pushinteger(L, si->read);
|
||||
lua_setfield(L, -2, "read");
|
||||
lua_pushinteger(L, si->write);
|
||||
lua_setfield(L, -2, "write");
|
||||
lua_pushinteger(L, si->wbuffer);
|
||||
lua_setfield(L, -2, "wbuffer");
|
||||
lua_pushinteger(L, si->rtime);
|
||||
lua_setfield(L, -2, "rtime");
|
||||
lua_pushinteger(L, si->wtime);
|
||||
lua_setfield(L, -2, "wtime");
|
||||
if (si->name[0]) {
|
||||
lua_pushstring(L, si->name);
|
||||
lua_setfield(L, -2, "peer");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
linfo(lua_State *L) {
|
||||
lua_newtable(L);
|
||||
struct socket_info * si = skynet_socket_info();
|
||||
struct socket_info * temp = si;
|
||||
int n = 0;
|
||||
while (temp) {
|
||||
getinfo(L, temp);
|
||||
lua_seti(L, -2, ++n);
|
||||
temp = temp->next;
|
||||
}
|
||||
socket_info_release(si);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LUAMOD_API int
|
||||
luaopen_skynet_socketdriver(lua_State *L) {
|
||||
luaL_checkversion(L);
|
||||
@@ -693,6 +779,7 @@ luaopen_skynet_socketdriver(lua_State *L) {
|
||||
{ "readline", lreadline },
|
||||
{ "str2p", lstr2p },
|
||||
{ "header", lheader },
|
||||
{ "info", linfo },
|
||||
|
||||
{ "unpack", lunpack },
|
||||
{ NULL, NULL },
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "msvcint.h"
|
||||
|
||||
#include "lua.h"
|
||||
@@ -56,9 +57,20 @@ static int64_t lua_tointegerx(lua_State *L, int idx, int *isnum) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// work around , use push & lua_gettable may be better
|
||||
#define lua_geti lua_rawgeti
|
||||
#define lua_seti lua_rawseti
|
||||
static void
|
||||
lua_geti(lua_State *L, int index, lua_Integer i) {
|
||||
index = lua_absindex(L, index);
|
||||
lua_pushinteger(L, i);
|
||||
lua_gettable(L, index);
|
||||
}
|
||||
|
||||
static void
|
||||
lua_seti(lua_State *L, int index, lua_Integer n) {
|
||||
index = lua_absindex(L, index);
|
||||
lua_pushinteger(L, n);
|
||||
lua_insert(L, -2);
|
||||
lua_settable(L, index);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -109,13 +121,35 @@ struct encode_ud {
|
||||
const char * array_tag;
|
||||
int array_index;
|
||||
int deep;
|
||||
int iter_index;
|
||||
int iter_func;
|
||||
int iter_table;
|
||||
int iter_key;
|
||||
};
|
||||
|
||||
static int
|
||||
next_list(lua_State *L, struct encode_ud * self) {
|
||||
// todo: check the key is equal to mainindex value
|
||||
if (self->iter_func) {
|
||||
lua_pushvalue(L, self->iter_func);
|
||||
lua_pushvalue(L, self->iter_table);
|
||||
lua_pushvalue(L, self->iter_key);
|
||||
lua_call(L, 2, 2);
|
||||
if (lua_isnil(L, -2)) {
|
||||
lua_pop(L, 2);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushvalue(L,self->iter_key);
|
||||
return lua_next(L, self->array_index);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
encode(const struct sproto_arg *args) {
|
||||
struct encode_ud *self = args->ud;
|
||||
lua_State *L = self->L;
|
||||
luaL_checkstack(L, 12, NULL);
|
||||
if (self->deep >= ENCODE_DEEPLEVEL)
|
||||
return luaL_error(L, "The table is too deep");
|
||||
if (args->index > 0) {
|
||||
@@ -130,29 +164,38 @@ encode(const struct sproto_arg *args) {
|
||||
self->array_index = 0;
|
||||
return SPROTO_CB_NOARRAY;
|
||||
}
|
||||
if (!lua_istable(L, -1)) {
|
||||
return luaL_error(L, ".*%s(%d) should be a table (Is a %s)",
|
||||
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
if (self->array_index) {
|
||||
lua_replace(L, self->array_index);
|
||||
} else {
|
||||
self->array_index = lua_gettop(L);
|
||||
}
|
||||
|
||||
if (luaL_getmetafield(L, self->array_index, "__pairs")) {
|
||||
lua_pushvalue(L, self->array_index);
|
||||
lua_call(L, 1, 3);
|
||||
int top = lua_gettop(L);
|
||||
self->iter_func = top - 2;
|
||||
self->iter_table = top - 1;
|
||||
self->iter_key = top;
|
||||
} else if (!lua_istable(L,self->array_index)) {
|
||||
return luaL_error(L, ".*%s(%d) should be a table or an userdata with metamethods (Is a %s)",
|
||||
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
self->iter_func = 0;
|
||||
self->iter_table = 0;
|
||||
self->iter_key = lua_gettop(L);
|
||||
}
|
||||
}
|
||||
if (args->mainindex >= 0) {
|
||||
// use lua_next to iterate the table
|
||||
// todo: check the key is equal to mainindex value
|
||||
|
||||
lua_pushvalue(L,self->iter_index);
|
||||
if (!lua_next(L, self->array_index)) {
|
||||
if (!next_list(L, self)) {
|
||||
// iterate end
|
||||
lua_pushnil(L);
|
||||
lua_replace(L, self->iter_index);
|
||||
lua_replace(L, self->iter_key);
|
||||
return SPROTO_CB_NIL;
|
||||
}
|
||||
lua_insert(L, -2);
|
||||
lua_replace(L, self->iter_index);
|
||||
lua_replace(L, self->iter_key);
|
||||
} else {
|
||||
lua_geti(L, self->array_index, args->index);
|
||||
}
|
||||
@@ -172,7 +215,7 @@ encode(const struct sproto_arg *args) {
|
||||
// It's decimal.
|
||||
lua_Number vn = lua_tonumber(L, -1);
|
||||
// use 64bit integer for 32bit architecture.
|
||||
v = (int64_t)(vn * args->extra + 0.5);
|
||||
v = (int64_t)(round(vn * args->extra));
|
||||
} else {
|
||||
v = lua_tointegerx(L, -1, &isnum);
|
||||
if(!isnum) {
|
||||
@@ -221,18 +264,15 @@ encode(const struct sproto_arg *args) {
|
||||
struct encode_ud sub;
|
||||
int r;
|
||||
int top = lua_gettop(L);
|
||||
if (!lua_istable(L, top)) {
|
||||
return luaL_error(L, ".%s[%d] is not a table (Is a %s)",
|
||||
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||
}
|
||||
sub.L = L;
|
||||
sub.st = args->subtype;
|
||||
sub.tbl_index = top;
|
||||
sub.array_tag = NULL;
|
||||
sub.array_index = 0;
|
||||
sub.deep = self->deep + 1;
|
||||
lua_pushnil(L); // prepare an iterator slot
|
||||
sub.iter_index = sub.tbl_index + 1;
|
||||
sub.iter_func = 0;
|
||||
sub.iter_table = 0;
|
||||
sub.iter_key = 0;
|
||||
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
|
||||
lua_settop(L, top-1); // pop the value
|
||||
if (r < 0)
|
||||
@@ -280,8 +320,6 @@ lencode(lua_State *L) {
|
||||
lua_pushstring(L, "");
|
||||
return 1; // response nil
|
||||
}
|
||||
luaL_checktype(L, tbl_index, LUA_TTABLE);
|
||||
luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL);
|
||||
self.L = L;
|
||||
self.st = st;
|
||||
self.tbl_index = tbl_index;
|
||||
@@ -292,8 +330,9 @@ lencode(lua_State *L) {
|
||||
self.deep = 0;
|
||||
|
||||
lua_settop(L, tbl_index);
|
||||
lua_pushnil(L); // for iterator (stack slot 3)
|
||||
self.iter_index = tbl_index+1;
|
||||
self.iter_func = 0;
|
||||
self.iter_table = 0;
|
||||
self.iter_key = 0;
|
||||
|
||||
r = sproto_encode(st, buffer, sz, encode, &self);
|
||||
if (r<0) {
|
||||
@@ -322,6 +361,7 @@ decode(const struct sproto_arg *args) {
|
||||
lua_State *L = self->L;
|
||||
if (self->deep >= ENCODE_DEEPLEVEL)
|
||||
return luaL_error(L, "The table is too deep");
|
||||
luaL_checkstack(L, 12, NULL);
|
||||
if (args->index != 0) {
|
||||
// It's array
|
||||
if (args->tagname != self->array_tag) {
|
||||
@@ -460,7 +500,6 @@ ldecode(lua_State *L) {
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_newtable(L);
|
||||
}
|
||||
luaL_checkstack(L, ENCODE_DEEPLEVEL*3 + 8, NULL);
|
||||
self.L = L;
|
||||
self.result_index = lua_gettop(L);
|
||||
self.array_index = 0;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#define SIZEOF_LENGTH 4
|
||||
#define SIZEOF_HEADER 2
|
||||
#define SIZEOF_FIELD 2
|
||||
#define SIZEOF_INT64 ((int)sizeof(uint64_t))
|
||||
#define SIZEOF_INT32 ((int)sizeof(uint32_t))
|
||||
|
||||
struct field {
|
||||
int tag;
|
||||
@@ -758,7 +760,7 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
|
||||
return NULL;
|
||||
buffer++;
|
||||
size--;
|
||||
intlen = sizeof(uint32_t);
|
||||
intlen = SIZEOF_INT32;
|
||||
index = 1;
|
||||
*noarray = 0;
|
||||
|
||||
@@ -781,36 +783,38 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
|
||||
}
|
||||
return NULL; // sz == SPROTO_CB_ERROR
|
||||
}
|
||||
if (size < sizeof(uint64_t))
|
||||
// notice: sizeof(uint64_t) is size_t (unsigned) , size may be negative. See issue #75
|
||||
// so use MACRO SIZOF_INT64 instead
|
||||
if (size < SIZEOF_INT64)
|
||||
return NULL;
|
||||
if (sz == sizeof(uint32_t)) {
|
||||
if (sz == SIZEOF_INT32) {
|
||||
uint32_t v = u.u32;
|
||||
buffer[0] = v & 0xff;
|
||||
buffer[1] = (v >> 8) & 0xff;
|
||||
buffer[2] = (v >> 16) & 0xff;
|
||||
buffer[3] = (v >> 24) & 0xff;
|
||||
|
||||
if (intlen == sizeof(uint64_t)) {
|
||||
if (intlen == SIZEOF_INT64) {
|
||||
uint32_to_uint64(v & 0x80000000, buffer);
|
||||
}
|
||||
} else {
|
||||
uint64_t v;
|
||||
if (sz != sizeof(uint64_t))
|
||||
if (sz != SIZEOF_INT64)
|
||||
return NULL;
|
||||
if (intlen == sizeof(uint32_t)) {
|
||||
if (intlen == SIZEOF_INT32) {
|
||||
int i;
|
||||
// rearrange
|
||||
size -= (index-1) * sizeof(uint32_t);
|
||||
if (size < sizeof(uint64_t))
|
||||
size -= (index-1) * SIZEOF_INT32;
|
||||
if (size < SIZEOF_INT64)
|
||||
return NULL;
|
||||
buffer += (index-1) * sizeof(uint32_t);
|
||||
buffer += (index-1) * SIZEOF_INT32;
|
||||
for (i=index-2;i>=0;i--) {
|
||||
int negative;
|
||||
memcpy(header+1+i*sizeof(uint64_t), header+1+i*sizeof(uint32_t), sizeof(uint32_t));
|
||||
negative = header[1+i*sizeof(uint64_t)+3] & 0x80;
|
||||
uint32_to_uint64(negative, header+1+i*sizeof(uint64_t));
|
||||
memcpy(header+1+i*SIZEOF_INT64, header+1+i*SIZEOF_INT32, SIZEOF_INT32);
|
||||
negative = header[1+i*SIZEOF_INT64+3] & 0x80;
|
||||
uint32_to_uint64(negative, header+1+i*SIZEOF_INT64);
|
||||
}
|
||||
intlen = sizeof(uint64_t);
|
||||
intlen = SIZEOF_INT64;
|
||||
}
|
||||
|
||||
v = u.u64;
|
||||
@@ -956,14 +960,14 @@ sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_call
|
||||
return 0;
|
||||
return -1; // sz == SPROTO_CB_ERROR
|
||||
}
|
||||
if (sz == sizeof(uint32_t)) {
|
||||
if (sz == SIZEOF_INT32) {
|
||||
if (u.u32 < 0x7fff) {
|
||||
value = (u.u32+1) * 2;
|
||||
sz = 2; // sz can be any number > 0
|
||||
} else {
|
||||
sz = encode_integer(u.u32, data, size);
|
||||
}
|
||||
} else if (sz == sizeof(uint64_t)) {
|
||||
} else if (sz == SIZEOF_INT64) {
|
||||
sz= encode_uint64(u.u64, data, size);
|
||||
} else {
|
||||
return -1;
|
||||
@@ -1066,22 +1070,22 @@ decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
|
||||
int len = *stream;
|
||||
++stream;
|
||||
--sz;
|
||||
if (len == sizeof(uint32_t)) {
|
||||
if (sz % sizeof(uint32_t) != 0)
|
||||
if (len == SIZEOF_INT32) {
|
||||
if (sz % SIZEOF_INT32 != 0)
|
||||
return -1;
|
||||
for (i=0;i<sz/sizeof(uint32_t);i++) {
|
||||
uint64_t value = expand64(todword(stream + i*sizeof(uint32_t)));
|
||||
for (i=0;i<sz/SIZEOF_INT32;i++) {
|
||||
uint64_t value = expand64(todword(stream + i*SIZEOF_INT32));
|
||||
args->index = i+1;
|
||||
args->value = &value;
|
||||
args->length = sizeof(value);
|
||||
cb(args);
|
||||
}
|
||||
} else if (len == sizeof(uint64_t)) {
|
||||
if (sz % sizeof(uint64_t) != 0)
|
||||
} else if (len == SIZEOF_INT64) {
|
||||
if (sz % SIZEOF_INT64 != 0)
|
||||
return -1;
|
||||
for (i=0;i<sz/sizeof(uint64_t);i++) {
|
||||
uint64_t low = todword(stream + i*sizeof(uint64_t));
|
||||
uint64_t hi = todword(stream + i*sizeof(uint64_t) + sizeof(uint32_t));
|
||||
for (i=0;i<sz/SIZEOF_INT64;i++) {
|
||||
uint64_t low = todword(stream + i*SIZEOF_INT64);
|
||||
uint64_t hi = todword(stream + i*SIZEOF_INT64 + SIZEOF_INT32);
|
||||
uint64_t value = low | hi << 32;
|
||||
args->index = i+1;
|
||||
args->value = &value;
|
||||
@@ -1175,16 +1179,16 @@ sproto_decode(const struct sproto_type *st, const void * data, int size, sproto_
|
||||
switch (f->type) {
|
||||
case SPROTO_TINTEGER: {
|
||||
uint32_t sz = todword(currentdata);
|
||||
if (sz == sizeof(uint32_t)) {
|
||||
if (sz == SIZEOF_INT32) {
|
||||
uint64_t v = expand64(todword(currentdata + SIZEOF_LENGTH));
|
||||
args.value = &v;
|
||||
args.length = sizeof(v);
|
||||
cb(&args);
|
||||
} else if (sz != sizeof(uint64_t)) {
|
||||
} else if (sz != SIZEOF_INT64) {
|
||||
return -1;
|
||||
} else {
|
||||
uint32_t low = todword(currentdata + SIZEOF_LENGTH);
|
||||
uint32_t hi = todword(currentdata + SIZEOF_LENGTH + sizeof(uint32_t));
|
||||
uint32_t hi = todword(currentdata + SIZEOF_LENGTH + SIZEOF_INT32);
|
||||
uint64_t v = (uint64_t)low | (uint64_t) hi << 32;
|
||||
args.value = &v;
|
||||
args.length = sizeof(v);
|
||||
|
||||
@@ -8,78 +8,6 @@ local table = table
|
||||
|
||||
local httpc = {}
|
||||
|
||||
local function request(fd, method, host, url, recvheader, header, content)
|
||||
local read = socket.readfunc(fd)
|
||||
local write = socket.writefunc(fd)
|
||||
local header_content = ""
|
||||
if header then
|
||||
if not header.host then
|
||||
header.host = host
|
||||
end
|
||||
for k,v in pairs(header) do
|
||||
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
|
||||
end
|
||||
else
|
||||
header_content = string.format("host:%s\r\n",host)
|
||||
end
|
||||
|
||||
if content then
|
||||
local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n\r\n", method, url, header_content, #content)
|
||||
write(data)
|
||||
write(content)
|
||||
else
|
||||
local request_header = string.format("%s %s HTTP/1.1\r\n%scontent-length:0\r\n\r\n", method, url, header_content)
|
||||
write(request_header)
|
||||
end
|
||||
|
||||
local tmpline = {}
|
||||
local body = internal.recvheader(read, tmpline, "")
|
||||
if not body then
|
||||
error(socket.socket_error)
|
||||
end
|
||||
|
||||
local statusline = tmpline[1]
|
||||
local code, info = statusline:match "HTTP/[%d%.]+%s+([%d]+)%s+(.*)$"
|
||||
code = assert(tonumber(code))
|
||||
|
||||
local header = internal.parseheader(tmpline,2,recvheader or {})
|
||||
if not header then
|
||||
error("Invalid HTTP response header")
|
||||
end
|
||||
|
||||
local length = header["content-length"]
|
||||
if length then
|
||||
length = tonumber(length)
|
||||
end
|
||||
local mode = header["transfer-encoding"]
|
||||
if mode then
|
||||
if mode ~= "identity" and mode ~= "chunked" then
|
||||
error ("Unsupport transfer-encoding")
|
||||
end
|
||||
end
|
||||
|
||||
if mode == "chunked" then
|
||||
body, header = internal.recvchunkedbody(read, nil, header, body)
|
||||
if not body then
|
||||
error("Invalid response body")
|
||||
end
|
||||
else
|
||||
-- identity mode
|
||||
if length then
|
||||
if #body >= length then
|
||||
body = body:sub(1,length)
|
||||
else
|
||||
local padding = read(length - #body)
|
||||
body = body .. padding
|
||||
end
|
||||
else
|
||||
-- no content-length, read all
|
||||
body = body .. socket.readall(fd)
|
||||
end
|
||||
end
|
||||
|
||||
return code, body
|
||||
end
|
||||
|
||||
local async_dns
|
||||
|
||||
@@ -88,11 +16,60 @@ function httpc.dns(server,port)
|
||||
dns.server(server,port)
|
||||
end
|
||||
|
||||
|
||||
local function check_protocol(host)
|
||||
local protocol = host:match("^[Hh][Tt][Tt][Pp][Ss]?://")
|
||||
if protocol then
|
||||
host = string.gsub(host, "^"..protocol, "")
|
||||
protocol = string.lower(protocol)
|
||||
if protocol == "https://" then
|
||||
return "https", host
|
||||
elseif protocol == "http://" then
|
||||
return "http", host
|
||||
else
|
||||
error(string.format("Invalid protocol: %s", protocol))
|
||||
end
|
||||
else
|
||||
return "http", host
|
||||
end
|
||||
end
|
||||
|
||||
local SSLCTX_CLIENT = nil
|
||||
local function gen_interface(protocol, fd)
|
||||
if protocol == "http" then
|
||||
return {
|
||||
init = nil,
|
||||
close = nil,
|
||||
read = socket.readfunc(fd),
|
||||
write = socket.writefunc(fd),
|
||||
readall = function ()
|
||||
return socket.readall(fd)
|
||||
end,
|
||||
}
|
||||
elseif protocol == "https" then
|
||||
local tls = require "http.tlshelper"
|
||||
SSLCTX_CLIENT = SSLCTX_CLIENT or tls.newctx()
|
||||
local tls_ctx = tls.newtls("client", SSLCTX_CLIENT)
|
||||
return {
|
||||
init = tls.init_requestfunc(fd, tls_ctx),
|
||||
close = tls.closefunc(tls_ctx),
|
||||
read = tls.readfunc(fd, tls_ctx),
|
||||
write = tls.writefunc(fd, tls_ctx),
|
||||
readall = tls.readallfunc(fd, tls_ctx),
|
||||
}
|
||||
else
|
||||
error(string.format("Invalid protocol: %s", protocol))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function httpc.request(method, host, url, recvheader, header, content)
|
||||
local protocol
|
||||
local timeout = httpc.timeout -- get httpc.timeout before any blocked api
|
||||
protocol, host = check_protocol(host)
|
||||
local hostname, port = host:match"([^:]+):?(%d*)$"
|
||||
if port == "" then
|
||||
port = 80
|
||||
port = protocol=="http" and 80 or protocol=="https" and 443
|
||||
else
|
||||
port = tonumber(port)
|
||||
end
|
||||
@@ -101,20 +78,31 @@ function httpc.request(method, host, url, recvheader, header, content)
|
||||
end
|
||||
local fd = socket.connect(hostname, port, timeout)
|
||||
if not fd then
|
||||
error(string.format("http connect error host:%s, port:%s, timeout:%s", hostname, port, timeout))
|
||||
error(string.format("%s connect error host:%s, port:%s, timeout:%s", protocol, hostname, port, timeout))
|
||||
return
|
||||
end
|
||||
-- print("protocol hostname port", protocol, hostname, port)
|
||||
local interface = gen_interface(protocol, fd)
|
||||
local finish
|
||||
if timeout then
|
||||
skynet.timeout(timeout, function()
|
||||
if not finish then
|
||||
socket.shutdown(fd) -- shutdown the socket fd, need close later.
|
||||
if interface.close then
|
||||
interface.close()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
local ok , statuscode, body = pcall(request, fd,method, host, url, recvheader, header, content)
|
||||
if interface.init then
|
||||
interface.init()
|
||||
end
|
||||
local ok , statuscode, body = pcall(internal.request, interface, method, host, url, recvheader, header, content)
|
||||
finish = true
|
||||
socket.close(fd)
|
||||
if interface.close then
|
||||
interface.close()
|
||||
end
|
||||
if ok then
|
||||
return statuscode, body
|
||||
else
|
||||
|
||||
@@ -48,9 +48,6 @@ function M.recvheader(readbytes, lines, header)
|
||||
while true do
|
||||
local bytes = readbytes()
|
||||
header = header .. bytes
|
||||
if #header > LIMIT then
|
||||
return
|
||||
end
|
||||
e = header:find("\r\n\r\n", -#bytes-3, true)
|
||||
if e then
|
||||
result = header:sub(e+4)
|
||||
@@ -59,6 +56,9 @@ function M.recvheader(readbytes, lines, header)
|
||||
if header:find "^\r\n" then
|
||||
return header:sub(3)
|
||||
end
|
||||
if #header > LIMIT then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
for v in header:gmatch("(.-)\r\n") do
|
||||
@@ -141,4 +141,85 @@ function M.recvchunkedbody(readbytes, bodylimit, header, body)
|
||||
return result, header
|
||||
end
|
||||
|
||||
|
||||
function M.request(interface, method, host, url, recvheader, header, content)
|
||||
local is_ws = interface.websocket
|
||||
local read = interface.read
|
||||
local write = interface.write
|
||||
local header_content = ""
|
||||
if header then
|
||||
if not header.host then
|
||||
header.host = host
|
||||
end
|
||||
for k,v in pairs(header) do
|
||||
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
|
||||
end
|
||||
else
|
||||
header_content = string.format("host:%s\r\n",host)
|
||||
end
|
||||
|
||||
if content then
|
||||
local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n\r\n", method, url, header_content, #content)
|
||||
write(data)
|
||||
write(content)
|
||||
else
|
||||
local request_header = string.format("%s %s HTTP/1.1\r\n%scontent-length:0\r\n\r\n", method, url, header_content)
|
||||
write(request_header)
|
||||
end
|
||||
|
||||
local tmpline = {}
|
||||
local body = M.recvheader(read, tmpline, "")
|
||||
if not body then
|
||||
error(socket.socket_error)
|
||||
end
|
||||
|
||||
local statusline = tmpline[1]
|
||||
local code, info = statusline:match "HTTP/[%d%.]+%s+([%d]+)%s+(.*)$"
|
||||
code = assert(tonumber(code))
|
||||
|
||||
local header = M.parseheader(tmpline,2,recvheader or {})
|
||||
if not header then
|
||||
error("Invalid HTTP response header")
|
||||
end
|
||||
|
||||
local length = header["content-length"]
|
||||
if length then
|
||||
length = tonumber(length)
|
||||
end
|
||||
local mode = header["transfer-encoding"]
|
||||
if mode then
|
||||
if mode ~= "identity" and mode ~= "chunked" then
|
||||
error ("Unsupport transfer-encoding")
|
||||
end
|
||||
end
|
||||
|
||||
if mode == "chunked" then
|
||||
body, header = M.recvchunkedbody(read, nil, header, body)
|
||||
if not body then
|
||||
error("Invalid response body")
|
||||
end
|
||||
else
|
||||
-- identity mode
|
||||
if length then
|
||||
if #body >= length then
|
||||
body = body:sub(1,length)
|
||||
else
|
||||
local padding = read(length - #body)
|
||||
body = body .. padding
|
||||
end
|
||||
elseif code == 204 or code == 304 or code < 200 then
|
||||
body = ""
|
||||
-- See https://stackoverflow.com/questions/15991173/is-the-content-length-header-required-for-a-http-1-0-response
|
||||
elseif is_ws and code == 101 then
|
||||
-- if websocket handshake success
|
||||
return code, body
|
||||
else
|
||||
-- no content-length, read all
|
||||
body = body .. interface.readall()
|
||||
end
|
||||
end
|
||||
|
||||
return code, body
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
96
lualib/http/tlshelper.lua
Normal file
96
lualib/http/tlshelper.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
local socket = require "http.sockethelper"
|
||||
local c = require "ltls.c"
|
||||
|
||||
local tlshelper = {}
|
||||
|
||||
function tlshelper.init_requestfunc(fd, tls_ctx)
|
||||
local readfunc = socket.readfunc(fd)
|
||||
local writefunc = socket.writefunc(fd)
|
||||
return function ()
|
||||
local ds1 = tls_ctx:handshake()
|
||||
writefunc(ds1)
|
||||
while not tls_ctx:finished() do
|
||||
local ds2 = readfunc()
|
||||
local ds3 = tls_ctx:handshake(ds2)
|
||||
if ds3 then
|
||||
writefunc(ds3)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function tlshelper.init_responsefunc(fd, tls_ctx)
|
||||
local readfunc = socket.readfunc(fd)
|
||||
local writefunc = socket.writefunc(fd)
|
||||
return function ()
|
||||
while not tls_ctx:finished() do
|
||||
local ds1 = readfunc()
|
||||
local ds2 = tls_ctx:handshake(ds1)
|
||||
if ds2 then
|
||||
writefunc(ds2)
|
||||
end
|
||||
end
|
||||
local ds3 = tls_ctx:write()
|
||||
writefunc(ds3)
|
||||
end
|
||||
end
|
||||
|
||||
function tlshelper.closefunc(tls_ctx)
|
||||
return function ()
|
||||
tls_ctx:close()
|
||||
end
|
||||
end
|
||||
|
||||
function tlshelper.readfunc(fd, tls_ctx)
|
||||
local readfunc = socket.readfunc(fd)
|
||||
local read_buff = ""
|
||||
return function (sz)
|
||||
if not sz then
|
||||
local s = ""
|
||||
if #read_buff == 0 then
|
||||
local ds = readfunc(sz)
|
||||
s = tls_ctx:read(ds)
|
||||
end
|
||||
s = read_buff .. s
|
||||
read_buff = ""
|
||||
return s
|
||||
else
|
||||
while #read_buff < sz do
|
||||
local ds = readfunc()
|
||||
local s = tls_ctx:read(ds)
|
||||
read_buff = read_buff .. s
|
||||
end
|
||||
local s = string.sub(read_buff, 1, sz)
|
||||
read_buff = string.sub(read_buff, sz+1, #read_buff)
|
||||
return s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function tlshelper.writefunc(fd, tls_ctx)
|
||||
local writefunc = socket.writefunc(fd)
|
||||
return function (s)
|
||||
local ds = tls_ctx:write(s)
|
||||
return writefunc(ds)
|
||||
end
|
||||
end
|
||||
|
||||
function tlshelper.readallfunc(fd, tls_ctx)
|
||||
local readfunc = socket.readfunc(fd)
|
||||
return function ()
|
||||
local ds = socket.readall(fd)
|
||||
local s = tls_ctx:read(ds)
|
||||
return s
|
||||
end
|
||||
end
|
||||
|
||||
function tlshelper.newctx()
|
||||
return c.newctx()
|
||||
end
|
||||
|
||||
function tlshelper.newtls(method, ssl_ctx)
|
||||
return c.newtls(method, ssl_ctx)
|
||||
end
|
||||
|
||||
return tlshelper
|
||||
507
lualib/http/websocket.lua
Executable file
507
lualib/http/websocket.lua
Executable file
@@ -0,0 +1,507 @@
|
||||
local internal = require "http.internal"
|
||||
local socket = require "skynet.socket"
|
||||
local crypt = require "skynet.crypt"
|
||||
local httpd = require "http.httpd"
|
||||
local skynet = require "skynet"
|
||||
local sockethelper = require "http.sockethelper"
|
||||
local socket_error = sockethelper.socket_error
|
||||
|
||||
local GLOBAL_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
local MAX_FRAME_SIZE = 256 * 1024 -- max frame is 256K
|
||||
|
||||
local M = {}
|
||||
|
||||
|
||||
local ws_pool = {}
|
||||
local function _close_websocket(ws_obj)
|
||||
local id = ws_obj.id
|
||||
assert(ws_pool[id] == ws_obj)
|
||||
ws_pool[id] = nil
|
||||
ws_obj.close()
|
||||
end
|
||||
|
||||
local function _isws_closed(id)
|
||||
return not ws_pool[id]
|
||||
end
|
||||
|
||||
|
||||
local function write_handshake(self, host, url, header)
|
||||
local key = crypt.base64encode(crypt.randomkey()..crypt.randomkey())
|
||||
local request_header = {
|
||||
["Upgrade"] = "websocket",
|
||||
["Connection"] = "Upgrade",
|
||||
["Sec-WebSocket-Version"] = "13",
|
||||
["Sec-WebSocket-Key"] = key
|
||||
}
|
||||
if header then
|
||||
for k,v in pairs(header) do
|
||||
assert(request_header[k] == nil, k)
|
||||
request_header[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
local recvheader = {}
|
||||
local code, body = internal.request(self, "GET", host, url, recvheader, request_header)
|
||||
if code ~= 101 then
|
||||
error(string.format("websocket handshake error: code[%s] info:%s", code, body))
|
||||
end
|
||||
|
||||
if not recvheader["upgrade"] or recvheader["upgrade"]:lower() ~= "websocket" then
|
||||
error("websocket handshake upgrade must websocket")
|
||||
end
|
||||
|
||||
if not recvheader["connection"] or recvheader["connection"]:lower() ~= "upgrade" then
|
||||
error("websocket handshake connection must upgrade")
|
||||
end
|
||||
|
||||
local sw_key = recvheader["sec-websocket-accept"]
|
||||
if not sw_key then
|
||||
error("websocket handshake need Sec-WebSocket-Accept")
|
||||
end
|
||||
|
||||
local guid = self.guid
|
||||
sw_key = crypt.base64decode(sw_key)
|
||||
if sw_key ~= crypt.sha1(key .. guid) then
|
||||
error("websocket handshake invalid Sec-WebSocket-Accept")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function read_handshake(self)
|
||||
local tmpline = {}
|
||||
local header_body = internal.recvheader(self.read, tmpline, "")
|
||||
if not header_body then
|
||||
return 413
|
||||
end
|
||||
|
||||
local request = assert(tmpline[1])
|
||||
local method, url, httpver = request:match "^(%a+)%s+(.-)%s+HTTP/([%d%.]+)$"
|
||||
assert(method and url and httpver)
|
||||
if method ~= "GET" then
|
||||
return 400, "need GET method"
|
||||
end
|
||||
|
||||
httpver = assert(tonumber(httpver))
|
||||
if httpver < 1.1 then
|
||||
return 505 -- HTTP Version not supported
|
||||
end
|
||||
|
||||
local header = internal.parseheader(tmpline, 2, {})
|
||||
if not header then
|
||||
return 400 -- Bad request
|
||||
end
|
||||
if not header["upgrade"] or header["upgrade"]:lower() ~= "websocket" then
|
||||
return 426, "Upgrade Required"
|
||||
end
|
||||
|
||||
if not header["host"] then
|
||||
return 400, "host Required"
|
||||
end
|
||||
|
||||
if not header["connection"] or header["connection"]:lower() ~= "upgrade" then
|
||||
return 400, "Connection must Upgrade"
|
||||
end
|
||||
|
||||
local sw_key = header["sec-websocket-key"]
|
||||
if not sw_key then
|
||||
return 400, "Sec-WebSocket-Key Required"
|
||||
else
|
||||
local raw_key = crypt.base64decode(sw_key)
|
||||
if #raw_key ~= 16 then
|
||||
return 400, "Sec-WebSocket-Key invalid"
|
||||
end
|
||||
end
|
||||
|
||||
if not header["sec-websocket-version"] or header["sec-websocket-version"] ~= "13" then
|
||||
return 400, "Sec-WebSocket-Version must 13"
|
||||
end
|
||||
|
||||
local sw_protocol = header["sec-websocket-protocol"]
|
||||
local sub_pro = ""
|
||||
if sw_protocol then
|
||||
local has_chat = false
|
||||
for sub_protocol in string.gmatch(sw_protocol, "[^%s,]+") do
|
||||
if sub_protocol == "chat" then
|
||||
sub_pro = "Sec-WebSocket-Protocol: chat\r\n"
|
||||
has_chat = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not has_chat then
|
||||
return 400, "Sec-WebSocket-Protocol need include chat"
|
||||
end
|
||||
end
|
||||
|
||||
-- response handshake
|
||||
local accept = crypt.base64encode(crypt.sha1(sw_key .. self.guid))
|
||||
local resp = "HTTP/1.1 101 Switching Protocols\r\n"..
|
||||
"Upgrade: websocket\r\n"..
|
||||
"Connection: Upgrade\r\n"..
|
||||
string.format("Sec-WebSocket-Accept: %s\r\n", accept)..
|
||||
sub_pro ..
|
||||
"\r\n"
|
||||
self.write(resp)
|
||||
return nil, header, url
|
||||
end
|
||||
|
||||
local function try_handle(self, method, ...)
|
||||
local handle = self.handle
|
||||
local f = handle and handle[method]
|
||||
if f then
|
||||
f(self.id, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local op_code = {
|
||||
["frame"] = 0x00,
|
||||
["text"] = 0x01,
|
||||
["binary"] = 0x02,
|
||||
["close"] = 0x08,
|
||||
["ping"] = 0x09,
|
||||
["pong"] = 0x0A,
|
||||
[0x00] = "frame",
|
||||
[0x01] = "text",
|
||||
[0x02] = "binary",
|
||||
[0x08] = "close",
|
||||
[0x09] = "ping",
|
||||
[0x0A] = "pong",
|
||||
}
|
||||
|
||||
local function write_frame(self, op, payload_data, masking_key)
|
||||
payload_data = payload_data or ""
|
||||
local payload_len = #payload_data
|
||||
local op_v = assert(op_code[op])
|
||||
local v1 = 0x80 | op_v -- fin is 1 with opcode
|
||||
local s
|
||||
local mask = masking_key and 0x80 or 0x00
|
||||
-- mask set to 0
|
||||
if payload_len < 126 then
|
||||
s = string.pack("I1I1", v1, mask | payload_len)
|
||||
elseif payload_len < 0xffff then
|
||||
s = string.pack("I1I1>I2", v1, mask | 126, payload_len)
|
||||
else
|
||||
s = string.pack("I1I1>I8", v1, mask | 127, payload_len)
|
||||
end
|
||||
self.write(s)
|
||||
|
||||
-- write masking_key
|
||||
if masking_key then
|
||||
s = string.pack(">I4", masking_key)
|
||||
self.write(s)
|
||||
payload_data = crypt.xor_str(payload_data, s)
|
||||
end
|
||||
|
||||
if payload_len > 0 then
|
||||
self.write(payload_data)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function read_close(payload_data)
|
||||
local code, reason
|
||||
local payload_len = #payload_data
|
||||
if payload_len > 2 then
|
||||
local fmt = string.format(">I2c%d", payload_len - 2)
|
||||
code, reason = string.unpack(fmt, payload_data)
|
||||
end
|
||||
return code, reason
|
||||
end
|
||||
|
||||
|
||||
local function read_frame(self)
|
||||
local s = self.read(2)
|
||||
local v1, v2 = string.unpack("I1I1", s)
|
||||
local fin = (v1 & 0x80) ~= 0
|
||||
-- unused flag
|
||||
-- local rsv1 = (v1 & 0x40) ~= 0
|
||||
-- local rsv2 = (v1 & 0x20) ~= 0
|
||||
-- local rsv3 = (v1 & 0x10) ~= 0
|
||||
local op = v1 & 0x0f
|
||||
local mask = (v2 & 0x80) ~= 0
|
||||
local payload_len = (v2 & 0x7f)
|
||||
if payload_len == 126 then
|
||||
s = self.read(2)
|
||||
payload_len = string.unpack(">I2", s)
|
||||
elseif payload_len == 127 then
|
||||
s = self.read(8)
|
||||
payload_len = string.unpack(">I8", s)
|
||||
end
|
||||
|
||||
if self.mode == "server" and payload_len > MAX_FRAME_SIZE then
|
||||
error("payload_len is too large")
|
||||
end
|
||||
|
||||
-- print(string.format("fin:%s, op:%s, mask:%s, payload_len:%s", fin, op_code[op], mask, payload_len))
|
||||
local masking_key = mask and self.read(4) or false
|
||||
local payload_data = payload_len>0 and self.read(payload_len) or ""
|
||||
payload_data = masking_key and crypt.xor_str(payload_data, masking_key) or payload_data
|
||||
return fin, assert(op_code[op]), payload_data
|
||||
end
|
||||
|
||||
|
||||
local function resolve_accept(self)
|
||||
try_handle(self, "connect")
|
||||
local code, err, url = read_handshake(self)
|
||||
if code then
|
||||
local ok, s = httpd.write_response(self.write, code, err)
|
||||
if not ok then
|
||||
error(s)
|
||||
end
|
||||
end
|
||||
|
||||
local header = err
|
||||
try_handle(self, "handshake", header, url)
|
||||
local recv_count = 0
|
||||
local recv_buf = {}
|
||||
while true do
|
||||
if _isws_closed(self.id) then
|
||||
try_handle(self, "close")
|
||||
return
|
||||
end
|
||||
local fin, op, payload_data = read_frame(self)
|
||||
if op == "close" then
|
||||
local code, reason = read_close(payload_data)
|
||||
write_frame(self, "close")
|
||||
try_handle(self, "close", code, reason)
|
||||
break
|
||||
elseif op == "ping" then
|
||||
write_frame(self, "pong")
|
||||
try_handle(self, "ping")
|
||||
elseif op == "pong" then
|
||||
try_handle(self, "pong")
|
||||
else
|
||||
if fin and #recv_buf == 0 then
|
||||
try_handle(self, "message", payload_data)
|
||||
else
|
||||
recv_buf[#recv_buf+1] = payload_data
|
||||
recv_count = recv_count + #payload_data
|
||||
if recv_count > MAX_FRAME_SIZE then
|
||||
error("payload_len is too large")
|
||||
end
|
||||
if fin then
|
||||
local s = table.concat(recv_buf)
|
||||
try_handle(self, "message", s)
|
||||
recv_buf = {} -- clear recv_buf
|
||||
recv_count = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local SSLCTX_CLIENT = nil
|
||||
local function _new_client_ws(socket_id, protocol)
|
||||
local obj
|
||||
if protocol == "ws" then
|
||||
obj = {
|
||||
websocket = true,
|
||||
close = function ()
|
||||
socket.close(socket_id)
|
||||
end,
|
||||
read = sockethelper.readfunc(socket_id),
|
||||
write = sockethelper.writefunc(socket_id),
|
||||
readall = function ()
|
||||
return socket.readall(socket_id)
|
||||
end,
|
||||
}
|
||||
elseif protocol == "wss" then
|
||||
local tls = require "http.tlshelper"
|
||||
SSLCTX_CLIENT = SSLCTX_CLIENT or tls.newctx()
|
||||
local tls_ctx = tls.newtls("client", SSLCTX_CLIENT)
|
||||
local init = tls.init_requestfunc(socket_id, tls_ctx)
|
||||
init()
|
||||
obj = {
|
||||
websocket = true,
|
||||
close = function ()
|
||||
socket.close(socket_id)
|
||||
tls.closefunc(tls_ctx)()
|
||||
end,
|
||||
read = tls.readfunc(socket_id, tls_ctx),
|
||||
write = tls.writefunc(socket_id, tls_ctx),
|
||||
readall = tls.readallfunc(socket_id, tls_ctx),
|
||||
}
|
||||
else
|
||||
error(string.format("invalid websocket protocol:%s", tostring(protocol)))
|
||||
end
|
||||
|
||||
obj.mode = "client"
|
||||
obj.id = assert(socket_id)
|
||||
obj.guid = GLOBAL_GUID
|
||||
ws_pool[socket_id] = obj
|
||||
return obj
|
||||
end
|
||||
|
||||
|
||||
local SSLCTX_SERVER = nil
|
||||
local function _new_server_ws(socket_id, handle, protocol)
|
||||
local obj
|
||||
if protocol == "ws" then
|
||||
obj = {
|
||||
close = function ()
|
||||
socket.close(socket_id)
|
||||
end,
|
||||
read = sockethelper.readfunc(socket_id),
|
||||
write = sockethelper.writefunc(socket_id),
|
||||
}
|
||||
|
||||
elseif protocol == "wss" then
|
||||
local tls = require "http.tlshelper"
|
||||
if not SSLCTX_SERVER then
|
||||
SSLCTX_SERVER = tls.newctx()
|
||||
-- gen cert and key
|
||||
-- openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-cert.pem
|
||||
local certfile = skynet.getenv("certfile") or "./server-cert.pem"
|
||||
local keyfile = skynet.getenv("keyfile") or "./server-key.pem"
|
||||
SSLCTX_SERVER:set_cert(certfile, keyfile)
|
||||
end
|
||||
local tls_ctx = tls.newtls("server", SSLCTX_SERVER)
|
||||
local init = tls.init_responsefunc(socket_id, tls_ctx)
|
||||
init()
|
||||
obj = {
|
||||
close = function ()
|
||||
socket.close(socket_id)
|
||||
tls.closefunc(tls_ctx)()
|
||||
end,
|
||||
read = tls.readfunc(socket_id, tls_ctx),
|
||||
write = tls.writefunc(socket_id, tls_ctx),
|
||||
}
|
||||
|
||||
else
|
||||
error(string.format("invalid websocket protocol:%s", tostring(protocol)))
|
||||
end
|
||||
|
||||
obj.mode = "server"
|
||||
obj.id = assert(socket_id)
|
||||
obj.handle = handle
|
||||
obj.guid = GLOBAL_GUID
|
||||
ws_pool[socket_id] = obj
|
||||
return obj
|
||||
end
|
||||
|
||||
|
||||
-- handle interface
|
||||
-- connect / handshake / message / ping / pong / close / error
|
||||
function M.accept(socket_id, handle, protocol, addr)
|
||||
socket.start(socket_id)
|
||||
protocol = protocol or "ws"
|
||||
local ws_obj = _new_server_ws(socket_id, handle, protocol)
|
||||
ws_obj.addr = addr
|
||||
local on_warning = handle and handle["warning"]
|
||||
if on_warning then
|
||||
socket.warning(socket_id, function (id, sz)
|
||||
on_warning(ws_obj, sz)
|
||||
end)
|
||||
end
|
||||
|
||||
local ok, err = xpcall(resolve_accept, debug.traceback, ws_obj)
|
||||
local closed = _isws_closed(socket_id)
|
||||
if not closed then
|
||||
_close_websocket(ws_obj)
|
||||
end
|
||||
if not ok then
|
||||
if err == socket_error then
|
||||
if closed then
|
||||
try_handle(ws_obj, "close")
|
||||
else
|
||||
try_handle(ws_obj, "error")
|
||||
end
|
||||
else
|
||||
-- error(err)
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function M.connect(url, header, timeout)
|
||||
local protocol, host, uri = string.match(url, "^(wss?)://([^/]+)(.*)$")
|
||||
if protocol ~= "wss" and protocol ~= "ws" then
|
||||
error(string.format("invalid protocol: %s", protocol))
|
||||
end
|
||||
|
||||
assert(host)
|
||||
local host_name, host_port = string.match(host, "^([^:]+):?(%d*)$")
|
||||
assert(host_name and host_port)
|
||||
if host_port == "" then
|
||||
host_port = protocol == "ws" and 80 or 443
|
||||
end
|
||||
|
||||
uri = uri == "" and "/" or uri
|
||||
local socket_id = sockethelper.connect(host_name, host_port, timeout)
|
||||
local ws_obj = _new_client_ws(socket_id, protocol)
|
||||
ws_obj.addr = host
|
||||
write_handshake(ws_obj, host_name, uri, header)
|
||||
return socket_id
|
||||
end
|
||||
|
||||
|
||||
function M.read(id)
|
||||
local ws_obj = assert(ws_pool[id])
|
||||
local recv_buf
|
||||
while true do
|
||||
local fin, op, payload_data = read_frame(ws_obj)
|
||||
if op == "close" then
|
||||
_close_websocket(ws_obj)
|
||||
return false, payload_data
|
||||
elseif op == "ping" then
|
||||
write_frame(ws_obj, "pong")
|
||||
elseif op ~= "pong" then -- op is frame, text binary
|
||||
if fin and not recv_buf then
|
||||
return payload_data
|
||||
else
|
||||
recv_buf = recv_buf or {}
|
||||
recv_buf[#recv_buf+1] = payload_data
|
||||
if fin then
|
||||
local s = table.concat(recv_buf)
|
||||
return s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
assert(false)
|
||||
end
|
||||
|
||||
|
||||
function M.write(id, data, fmt, masking_key)
|
||||
local ws_obj = assert(ws_pool[id])
|
||||
fmt = fmt or "text"
|
||||
assert(fmt == "text" or fmt == "binary")
|
||||
write_frame(ws_obj, fmt, data, masking_key)
|
||||
end
|
||||
|
||||
|
||||
function M.ping(id)
|
||||
local ws_obj = assert(ws_pool[id])
|
||||
write_frame(ws_obj, "ping")
|
||||
end
|
||||
|
||||
function M.addrinfo(id)
|
||||
local ws_obj = assert(ws_pool[id])
|
||||
return ws_obj.addr
|
||||
end
|
||||
|
||||
function M.close(id, code ,reason)
|
||||
local ws_obj = ws_pool[id]
|
||||
if not ws_obj then
|
||||
return
|
||||
end
|
||||
|
||||
local ok, err = xpcall(function ()
|
||||
reason = reason or ""
|
||||
local payload_data
|
||||
if code then
|
||||
local fmt =string.format(">I2c%d", #reason)
|
||||
payload_data = string.pack(fmt, code, reason)
|
||||
end
|
||||
write_frame(ws_obj, "close", payload_data)
|
||||
end, debug.traceback)
|
||||
_close_websocket(ws_obj)
|
||||
if not ok then
|
||||
skynet.error(err)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
@@ -1,17 +1,27 @@
|
||||
-- read https://github.com/cloudwu/skynet/wiki/FAQ for the module "skynet.core"
|
||||
local c = require "skynet.core"
|
||||
local tostring = tostring
|
||||
local tonumber = tonumber
|
||||
local coroutine = coroutine
|
||||
local assert = assert
|
||||
local pairs = pairs
|
||||
local pcall = pcall
|
||||
local table = table
|
||||
local tremove = table.remove
|
||||
local tinsert = table.insert
|
||||
local traceback = debug.traceback
|
||||
|
||||
local profile = require "skynet.profile"
|
||||
|
||||
local coroutine_resume = profile.resume
|
||||
local cresume = profile.resume
|
||||
local running_thread = nil
|
||||
local init_thread = nil
|
||||
|
||||
local function coroutine_resume(co, ...)
|
||||
running_thread = co
|
||||
return cresume(co, ...)
|
||||
end
|
||||
local coroutine_yield = profile.yield
|
||||
local coroutine_create = coroutine.create
|
||||
|
||||
local proto = {}
|
||||
local skynet = {
|
||||
@@ -28,6 +38,7 @@ local skynet = {
|
||||
PTYPE_DEBUG = 9,
|
||||
PTYPE_LUA = 10,
|
||||
PTYPE_SNAX = 11,
|
||||
PTYPE_TRACE = 12, -- use for debug trace
|
||||
}
|
||||
|
||||
-- code cache
|
||||
@@ -45,29 +56,24 @@ end
|
||||
local session_id_coroutine = {}
|
||||
local session_coroutine_id = {}
|
||||
local session_coroutine_address = {}
|
||||
local session_response = {}
|
||||
local session_coroutine_tracetag = {}
|
||||
local unresponse = {}
|
||||
|
||||
local wakeup_queue = {}
|
||||
local sleep_session = {}
|
||||
|
||||
local watching_service = {}
|
||||
local watching_session = {}
|
||||
local dead_service = {}
|
||||
local error_queue = {}
|
||||
local fork_queue = {}
|
||||
|
||||
-- suspend is function
|
||||
local suspend
|
||||
|
||||
local function string_to_handle(str)
|
||||
return tonumber("0x" .. string.sub(str , 2))
|
||||
end
|
||||
|
||||
----- monitor exit
|
||||
|
||||
local function dispatch_error_queue()
|
||||
local session = table.remove(error_queue,1)
|
||||
local session = tremove(error_queue,1)
|
||||
if session then
|
||||
local co = session_id_coroutine[session]
|
||||
session_id_coroutine[session] = nil
|
||||
@@ -76,21 +82,23 @@ local function dispatch_error_queue()
|
||||
end
|
||||
|
||||
local function _error_dispatch(error_session, error_source)
|
||||
skynet.ignoreret() -- don't return for error
|
||||
if error_session == 0 then
|
||||
-- service is down
|
||||
-- Don't remove from watching_service , because user may call dead service
|
||||
if watching_service[error_source] then
|
||||
dead_service[error_source] = true
|
||||
-- error_source is down, clear unreponse set
|
||||
for resp, address in pairs(unresponse) do
|
||||
if error_source == address then
|
||||
unresponse[resp] = nil
|
||||
end
|
||||
end
|
||||
for session, srv in pairs(watching_session) do
|
||||
if srv == error_source then
|
||||
table.insert(error_queue, session)
|
||||
tinsert(error_queue, session)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- capture an error for error_session
|
||||
if watching_session[error_session] then
|
||||
table.insert(error_queue, error_session)
|
||||
tinsert(error_queue, error_session)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -100,179 +108,148 @@ end
|
||||
local coroutine_pool = setmetatable({}, { __mode = "kv" })
|
||||
|
||||
local function co_create(f)
|
||||
local co = table.remove(coroutine_pool)
|
||||
local co = tremove(coroutine_pool)
|
||||
if co == nil then
|
||||
co = coroutine.create(function(...)
|
||||
co = coroutine_create(function(...)
|
||||
f(...)
|
||||
while true do
|
||||
local session = session_coroutine_id[co]
|
||||
if session and session ~= 0 then
|
||||
local source = debug.getinfo(f,"S")
|
||||
skynet.error(string.format("Maybe forgot response session %s from %s : %s:%d",
|
||||
session,
|
||||
skynet.address(session_coroutine_address[co]),
|
||||
source.source, source.linedefined))
|
||||
end
|
||||
-- coroutine exit
|
||||
local tag = session_coroutine_tracetag[co]
|
||||
if tag ~= nil then
|
||||
if tag then c.trace(tag, "end") end
|
||||
session_coroutine_tracetag[co] = nil
|
||||
end
|
||||
local address = session_coroutine_address[co]
|
||||
if address then
|
||||
session_coroutine_id[co] = nil
|
||||
session_coroutine_address[co] = nil
|
||||
end
|
||||
|
||||
-- recycle co into pool
|
||||
f = nil
|
||||
coroutine_pool[#coroutine_pool+1] = co
|
||||
f = coroutine_yield "EXIT"
|
||||
-- recv new main function f
|
||||
f = coroutine_yield "SUSPEND"
|
||||
f(coroutine_yield())
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- pass the main function f to coroutine, and restore running thread
|
||||
local running = running_thread
|
||||
coroutine_resume(co, f)
|
||||
running_thread = running
|
||||
end
|
||||
return co
|
||||
end
|
||||
|
||||
local function dispatch_wakeup()
|
||||
local co = table.remove(wakeup_queue,1)
|
||||
if co then
|
||||
local session = sleep_session[co]
|
||||
local token = tremove(wakeup_queue,1)
|
||||
if token then
|
||||
local session = sleep_session[token]
|
||||
if session then
|
||||
local co = session_id_coroutine[session]
|
||||
local tag = session_coroutine_tracetag[co]
|
||||
if tag then c.trace(tag, "resume") end
|
||||
session_id_coroutine[session] = "BREAK"
|
||||
return suspend(co, coroutine_resume(co, false, "BREAK"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function release_watching(address)
|
||||
local ref = watching_service[address]
|
||||
if ref then
|
||||
ref = ref - 1
|
||||
if ref > 0 then
|
||||
watching_service[address] = ref
|
||||
else
|
||||
watching_service[address] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- suspend is local function
|
||||
function suspend(co, result, command, param, size)
|
||||
function suspend(co, result, command)
|
||||
if not result then
|
||||
local session = session_coroutine_id[co]
|
||||
if session then -- coroutine may fork by others (session is nil)
|
||||
local addr = session_coroutine_address[co]
|
||||
if session ~= 0 then
|
||||
-- only call response error
|
||||
local tag = session_coroutine_tracetag[co]
|
||||
if tag then c.trace(tag, "error") end
|
||||
c.send(addr, skynet.PTYPE_ERROR, session, "")
|
||||
end
|
||||
session_coroutine_id[co] = nil
|
||||
session_coroutine_address[co] = nil
|
||||
end
|
||||
error(debug.traceback(co,tostring(command)))
|
||||
session_coroutine_address[co] = nil
|
||||
session_coroutine_tracetag[co] = nil
|
||||
skynet.fork(function() end) -- trigger command "SUSPEND"
|
||||
error(traceback(co,tostring(command)))
|
||||
end
|
||||
if command == "CALL" then
|
||||
session_id_coroutine[param] = co
|
||||
elseif command == "SLEEP" then
|
||||
session_id_coroutine[param] = co
|
||||
sleep_session[co] = param
|
||||
elseif command == "RETURN" then
|
||||
local co_session = session_coroutine_id[co]
|
||||
if co_session == 0 then
|
||||
if size ~= nil then
|
||||
c.trash(param, size)
|
||||
end
|
||||
return suspend(co, coroutine_resume(co, false)) -- send don't need ret
|
||||
end
|
||||
local co_address = session_coroutine_address[co]
|
||||
if param == nil or session_response[co] then
|
||||
error(debug.traceback(co))
|
||||
end
|
||||
session_response[co] = true
|
||||
local ret
|
||||
if not dead_service[co_address] then
|
||||
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, param, size) ~= nil
|
||||
if not ret then
|
||||
-- If the package is too large, returns nil. so we should report error back
|
||||
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
|
||||
end
|
||||
elseif size ~= nil then
|
||||
c.trash(param, size)
|
||||
ret = false
|
||||
end
|
||||
return suspend(co, coroutine_resume(co, ret))
|
||||
elseif command == "RESPONSE" then
|
||||
local co_session = session_coroutine_id[co]
|
||||
local co_address = session_coroutine_address[co]
|
||||
if session_response[co] then
|
||||
error(debug.traceback(co))
|
||||
end
|
||||
local f = param
|
||||
local function response(ok, ...)
|
||||
if ok == "TEST" then
|
||||
if dead_service[co_address] then
|
||||
release_watching(co_address)
|
||||
unresponse[response] = nil
|
||||
f = false
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
if not f then
|
||||
if f == false then
|
||||
f = nil
|
||||
return false
|
||||
end
|
||||
error "Can't response more than once"
|
||||
end
|
||||
|
||||
local ret
|
||||
-- do not response when session == 0 (send)
|
||||
if co_session ~= 0 and not dead_service[co_address] then
|
||||
if ok then
|
||||
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, f(...)) ~= nil
|
||||
if not ret then
|
||||
-- If the package is too large, returns false. so we should report error back
|
||||
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
|
||||
end
|
||||
else
|
||||
ret = c.send(co_address, skynet.PTYPE_ERROR, co_session, "") ~= nil
|
||||
end
|
||||
else
|
||||
ret = false
|
||||
end
|
||||
release_watching(co_address)
|
||||
unresponse[response] = nil
|
||||
f = nil
|
||||
return ret
|
||||
end
|
||||
watching_service[co_address] = watching_service[co_address] + 1
|
||||
session_response[co] = true
|
||||
unresponse[response] = true
|
||||
return suspend(co, coroutine_resume(co, response))
|
||||
elseif command == "EXIT" then
|
||||
-- coroutine exit
|
||||
local address = session_coroutine_address[co]
|
||||
if address then
|
||||
release_watching(address)
|
||||
session_coroutine_id[co] = nil
|
||||
session_coroutine_address[co] = nil
|
||||
session_response[co] = nil
|
||||
end
|
||||
if command == "SUSPEND" then
|
||||
dispatch_wakeup()
|
||||
dispatch_error_queue()
|
||||
elseif command == "QUIT" then
|
||||
-- service exit
|
||||
return
|
||||
elseif command == "USER" then
|
||||
-- See skynet.coutine for detail
|
||||
error("Call skynet.coroutine.yield out of skynet.coroutine.resume\n" .. debug.traceback(co))
|
||||
error("Call skynet.coroutine.yield out of skynet.coroutine.resume\n" .. traceback(co))
|
||||
elseif command == nil then
|
||||
-- debug trace
|
||||
return
|
||||
else
|
||||
error("Unknown command : " .. command .. "\n" .. debug.traceback(co))
|
||||
error("Unknown command : " .. command .. "\n" .. traceback(co))
|
||||
end
|
||||
dispatch_wakeup()
|
||||
dispatch_error_queue()
|
||||
end
|
||||
|
||||
local co_create_for_timeout
|
||||
local timeout_traceback
|
||||
|
||||
function skynet.trace_timeout(on)
|
||||
local function trace_coroutine(func, ti)
|
||||
local co
|
||||
co = co_create(function()
|
||||
timeout_traceback[co] = nil
|
||||
func()
|
||||
end)
|
||||
local info = string.format("TIMER %d+%d : ", skynet.now(), ti)
|
||||
timeout_traceback[co] = traceback(info, 3)
|
||||
return co
|
||||
end
|
||||
if on then
|
||||
timeout_traceback = timeout_traceback or {}
|
||||
co_create_for_timeout = trace_coroutine
|
||||
else
|
||||
timeout_traceback = nil
|
||||
co_create_for_timeout = co_create
|
||||
end
|
||||
end
|
||||
|
||||
skynet.trace_timeout(false) -- turn off by default
|
||||
|
||||
function skynet.timeout(ti, func)
|
||||
local session = c.intcommand("TIMEOUT",ti)
|
||||
assert(session)
|
||||
local co = co_create(func)
|
||||
local co = co_create_for_timeout(func, ti)
|
||||
assert(session_id_coroutine[session] == nil)
|
||||
session_id_coroutine[session] = co
|
||||
return co -- for debug
|
||||
end
|
||||
|
||||
function skynet.sleep(ti)
|
||||
local function suspend_sleep(session, token)
|
||||
local tag = session_coroutine_tracetag[running_thread]
|
||||
if tag then c.trace(tag, "sleep", 2) end
|
||||
session_id_coroutine[session] = running_thread
|
||||
assert(sleep_session[token] == nil, "token duplicative")
|
||||
sleep_session[token] = session
|
||||
|
||||
return coroutine_yield "SUSPEND"
|
||||
end
|
||||
|
||||
function skynet.sleep(ti, token)
|
||||
local session = c.intcommand("TIMEOUT",ti)
|
||||
assert(session)
|
||||
local succ, ret = coroutine_yield("SLEEP", session)
|
||||
sleep_session[coroutine.running()] = nil
|
||||
token = token or coroutine.running()
|
||||
local succ, ret = suspend_sleep(session, token)
|
||||
sleep_session[token] = nil
|
||||
if succ then
|
||||
return
|
||||
end
|
||||
@@ -287,31 +264,46 @@ function skynet.yield()
|
||||
return skynet.sleep(0)
|
||||
end
|
||||
|
||||
function skynet.wait(co)
|
||||
function skynet.wait(token)
|
||||
local session = c.genid()
|
||||
local ret, msg = coroutine_yield("SLEEP", session)
|
||||
co = co or coroutine.running()
|
||||
sleep_session[co] = nil
|
||||
token = token or coroutine.running()
|
||||
local ret, msg = suspend_sleep(session, token)
|
||||
sleep_session[token] = nil
|
||||
session_id_coroutine[session] = nil
|
||||
end
|
||||
|
||||
local self_handle
|
||||
function skynet.self()
|
||||
if self_handle then
|
||||
return self_handle
|
||||
end
|
||||
self_handle = string_to_handle(c.command("REG"))
|
||||
return self_handle
|
||||
return c.addresscommand "REG"
|
||||
end
|
||||
|
||||
function skynet.localname(name)
|
||||
local addr = c.command("QUERY", name)
|
||||
if addr then
|
||||
return string_to_handle(addr)
|
||||
end
|
||||
return c.addresscommand("QUERY", name)
|
||||
end
|
||||
|
||||
skynet.now = c.now
|
||||
skynet.hpc = c.hpc -- high performance counter
|
||||
|
||||
local traceid = 0
|
||||
function skynet.trace(info)
|
||||
skynet.error("TRACE", session_coroutine_tracetag[running_thread])
|
||||
if session_coroutine_tracetag[running_thread] == false then
|
||||
-- force off trace log
|
||||
return
|
||||
end
|
||||
traceid = traceid + 1
|
||||
|
||||
local tag = string.format(":%08x-%d",skynet.self(), traceid)
|
||||
session_coroutine_tracetag[running_thread] = tag
|
||||
if info then
|
||||
c.trace(tag, "trace " .. info)
|
||||
else
|
||||
c.trace(tag, "trace")
|
||||
end
|
||||
end
|
||||
|
||||
function skynet.tracetag()
|
||||
return session_coroutine_tracetag[running_thread]
|
||||
end
|
||||
|
||||
local starttime
|
||||
|
||||
@@ -385,7 +377,8 @@ skynet.trash = assert(c.trash)
|
||||
|
||||
local function yield_call(service, session)
|
||||
watching_session[session] = service
|
||||
local succ, msg, sz = coroutine_yield("CALL", session)
|
||||
session_id_coroutine[session] = running_thread
|
||||
local succ, msg, sz = coroutine_yield "SUSPEND"
|
||||
watching_session[session] = nil
|
||||
if not succ then
|
||||
error "call failed"
|
||||
@@ -394,6 +387,12 @@ local function yield_call(service, session)
|
||||
end
|
||||
|
||||
function skynet.call(addr, typename, ...)
|
||||
local tag = session_coroutine_tracetag[running_thread]
|
||||
if tag then
|
||||
c.trace(tag, "call", 2)
|
||||
c.send(addr, skynet.PTYPE_TRACE, 0, tag)
|
||||
end
|
||||
|
||||
local p = proto[typename]
|
||||
local session = c.send(addr, p.id , nil , p.pack(...))
|
||||
if session == nil then
|
||||
@@ -403,28 +402,112 @@ function skynet.call(addr, typename, ...)
|
||||
end
|
||||
|
||||
function skynet.rawcall(addr, typename, msg, sz)
|
||||
local tag = session_coroutine_tracetag[running_thread]
|
||||
if tag then
|
||||
c.trace(tag, "call", 2)
|
||||
c.send(addr, skynet.PTYPE_TRACE, 0, tag)
|
||||
end
|
||||
local p = proto[typename]
|
||||
local session = assert(c.send(addr, p.id , nil , msg, sz), "call to invalid address")
|
||||
return yield_call(addr, session)
|
||||
end
|
||||
|
||||
function skynet.tracecall(tag, addr, typename, msg, sz)
|
||||
c.trace(tag, "tracecall begin")
|
||||
c.send(addr, skynet.PTYPE_TRACE, 0, tag)
|
||||
local p = proto[typename]
|
||||
local session = assert(c.send(addr, p.id , nil , msg, sz), "call to invalid address")
|
||||
local msg, sz = yield_call(addr, session)
|
||||
c.trace(tag, "tracecall end")
|
||||
return msg, sz
|
||||
end
|
||||
|
||||
function skynet.ret(msg, sz)
|
||||
msg = msg or ""
|
||||
return coroutine_yield("RETURN", msg, sz)
|
||||
local tag = session_coroutine_tracetag[running_thread]
|
||||
if tag then c.trace(tag, "response") end
|
||||
local co_session = session_coroutine_id[running_thread]
|
||||
session_coroutine_id[running_thread] = nil
|
||||
if co_session == 0 then
|
||||
if sz ~= nil then
|
||||
c.trash(msg, sz)
|
||||
end
|
||||
return false -- send don't need ret
|
||||
end
|
||||
local co_address = session_coroutine_address[running_thread]
|
||||
if not co_session then
|
||||
error "No session"
|
||||
end
|
||||
local ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, msg, sz)
|
||||
if ret then
|
||||
return true
|
||||
elseif ret == false then
|
||||
-- If the package is too large, returns false. so we should report error back
|
||||
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function skynet.context()
|
||||
local co_session = session_coroutine_id[running_thread]
|
||||
local co_address = session_coroutine_address[running_thread]
|
||||
return co_session, co_address
|
||||
end
|
||||
|
||||
function skynet.ignoreret()
|
||||
-- We use session for other uses
|
||||
session_coroutine_id[running_thread] = nil
|
||||
end
|
||||
|
||||
function skynet.response(pack)
|
||||
pack = pack or skynet.pack
|
||||
return coroutine_yield("RESPONSE", pack)
|
||||
|
||||
local co_session = assert(session_coroutine_id[running_thread], "no session")
|
||||
session_coroutine_id[running_thread] = nil
|
||||
local co_address = session_coroutine_address[running_thread]
|
||||
if co_session == 0 then
|
||||
-- do not response when session == 0 (send)
|
||||
return function() end
|
||||
end
|
||||
local function response(ok, ...)
|
||||
if ok == "TEST" then
|
||||
return unresponse[response] ~= nil
|
||||
end
|
||||
if not pack then
|
||||
error "Can't response more than once"
|
||||
end
|
||||
|
||||
local ret
|
||||
if unresponse[response] then
|
||||
if ok then
|
||||
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, pack(...))
|
||||
if ret == false then
|
||||
-- If the package is too large, returns false. so we should report error back
|
||||
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
|
||||
end
|
||||
else
|
||||
ret = c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
|
||||
end
|
||||
unresponse[response] = nil
|
||||
ret = ret ~= nil
|
||||
else
|
||||
ret = false
|
||||
end
|
||||
pack = nil
|
||||
return ret
|
||||
end
|
||||
unresponse[response] = co_address
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
function skynet.retpack(...)
|
||||
return skynet.ret(skynet.pack(...))
|
||||
end
|
||||
|
||||
function skynet.wakeup(co)
|
||||
if sleep_session[co] then
|
||||
table.insert(wakeup_queue, co)
|
||||
function skynet.wakeup(token)
|
||||
if sleep_session[token] then
|
||||
tinsert(wakeup_queue, token)
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -463,14 +546,20 @@ function skynet.dispatch_unknown_response(unknown)
|
||||
end
|
||||
|
||||
function skynet.fork(func,...)
|
||||
local args = table.pack(...)
|
||||
local co = co_create(function()
|
||||
func(table.unpack(args,1,args.n))
|
||||
end)
|
||||
table.insert(fork_queue, co)
|
||||
local n = select("#", ...)
|
||||
local co
|
||||
if n == 0 then
|
||||
co = co_create(func)
|
||||
else
|
||||
local args = { ... }
|
||||
co = co_create(function() func(table.unpack(args,1,n)) end)
|
||||
end
|
||||
tinsert(fork_queue, co)
|
||||
return co
|
||||
end
|
||||
|
||||
local trace_source = {}
|
||||
|
||||
local function raw_dispatch_message(prototype, msg, sz, session, source)
|
||||
-- skynet.PTYPE_RESPONSE = 1, read skynet.h
|
||||
if prototype == 1 then
|
||||
@@ -480,35 +569,55 @@ local function raw_dispatch_message(prototype, msg, sz, session, source)
|
||||
elseif co == nil then
|
||||
unknown_response(session, source, msg, sz)
|
||||
else
|
||||
local tag = session_coroutine_tracetag[co]
|
||||
if tag then c.trace(tag, "resume") end
|
||||
session_id_coroutine[session] = nil
|
||||
suspend(co, coroutine_resume(co, true, msg, sz))
|
||||
end
|
||||
else
|
||||
local p = proto[prototype]
|
||||
if p == nil then
|
||||
if session ~= 0 then
|
||||
if prototype == skynet.PTYPE_TRACE then
|
||||
-- trace next request
|
||||
trace_source[source] = c.tostring(msg,sz)
|
||||
elseif session ~= 0 then
|
||||
c.send(source, skynet.PTYPE_ERROR, session, "")
|
||||
else
|
||||
unknown_request(session, source, msg, sz, prototype)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local f = p.dispatch
|
||||
if f then
|
||||
local ref = watching_service[source]
|
||||
if ref then
|
||||
watching_service[source] = ref + 1
|
||||
else
|
||||
watching_service[source] = 1
|
||||
end
|
||||
local co = co_create(f)
|
||||
session_coroutine_id[co] = session
|
||||
session_coroutine_address[co] = source
|
||||
local traceflag = p.trace
|
||||
if traceflag == false then
|
||||
-- force off
|
||||
trace_source[source] = nil
|
||||
session_coroutine_tracetag[co] = false
|
||||
else
|
||||
local tag = trace_source[source]
|
||||
if tag then
|
||||
trace_source[source] = nil
|
||||
c.trace(tag, "request")
|
||||
session_coroutine_tracetag[co] = tag
|
||||
elseif traceflag then
|
||||
-- set running_thread for trace
|
||||
running_thread = co
|
||||
skynet.trace()
|
||||
end
|
||||
end
|
||||
suspend(co, coroutine_resume(co, session,source, p.unpack(msg,sz)))
|
||||
elseif session ~= 0 then
|
||||
c.send(source, skynet.PTYPE_ERROR, session, "")
|
||||
else
|
||||
unknown_request(session, source, msg, sz, proto[prototype].name)
|
||||
trace_source[source] = nil
|
||||
if session ~= 0 then
|
||||
c.send(source, skynet.PTYPE_ERROR, session, "")
|
||||
else
|
||||
unknown_request(session, source, msg, sz, proto[prototype].name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -516,11 +625,10 @@ end
|
||||
function skynet.dispatch_message(...)
|
||||
local succ, err = pcall(raw_dispatch_message,...)
|
||||
while true do
|
||||
local key,co = next(fork_queue)
|
||||
local co = tremove(fork_queue,1)
|
||||
if co == nil then
|
||||
break
|
||||
end
|
||||
fork_queue[key] = nil
|
||||
local fork_succ, fork_err = pcall(suspend,co,coroutine_resume(co))
|
||||
if not fork_succ then
|
||||
if succ then
|
||||
@@ -567,6 +675,15 @@ function skynet.harbor(addr)
|
||||
end
|
||||
|
||||
skynet.error = c.error
|
||||
skynet.tracelog = c.trace
|
||||
|
||||
-- true: force on
|
||||
-- false: force off
|
||||
-- nil: optional (use skynet.trace() to trace one message)
|
||||
function skynet.traceproto(prototype, flag)
|
||||
local p = assert(proto[prototype])
|
||||
p.trace = flag
|
||||
end
|
||||
|
||||
----- register protocol
|
||||
do
|
||||
@@ -599,7 +716,7 @@ function skynet.init(f, name)
|
||||
if init_func == nil then
|
||||
f()
|
||||
else
|
||||
table.insert(init_func, f)
|
||||
tinsert(init_func, f)
|
||||
if name then
|
||||
assert(type(name) == "string")
|
||||
assert(init_func[name] == nil)
|
||||
@@ -630,7 +747,7 @@ local function init_template(start, ...)
|
||||
end
|
||||
|
||||
function skynet.pcall(start, ...)
|
||||
return xpcall(init_template, debug.traceback, start, ...)
|
||||
return xpcall(init_template, traceback, start, ...)
|
||||
end
|
||||
|
||||
function skynet.init_service(start)
|
||||
@@ -646,8 +763,9 @@ end
|
||||
|
||||
function skynet.start(start_func)
|
||||
c.callback(skynet.dispatch_message)
|
||||
skynet.timeout(0, function()
|
||||
init_thread = skynet.timeout(0, function()
|
||||
skynet.init_service(start_func)
|
||||
init_thread = nil
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -664,14 +782,69 @@ function skynet.stat(what)
|
||||
end
|
||||
|
||||
function skynet.task(ret)
|
||||
local t = 0
|
||||
for session,co in pairs(session_id_coroutine) do
|
||||
if ret then
|
||||
ret[session] = debug.traceback(co)
|
||||
if ret == nil then
|
||||
local t = 0
|
||||
for session,co in pairs(session_id_coroutine) do
|
||||
t = t + 1
|
||||
end
|
||||
t = t + 1
|
||||
return t
|
||||
end
|
||||
return t
|
||||
if ret == "init" then
|
||||
if init_thread then
|
||||
return traceback(init_thread)
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
local tt = type(ret)
|
||||
if tt == "table" then
|
||||
for session,co in pairs(session_id_coroutine) do
|
||||
if timeout_traceback and timeout_traceback[co] then
|
||||
ret[session] = timeout_traceback[co]
|
||||
else
|
||||
ret[session] = traceback(co)
|
||||
end
|
||||
end
|
||||
return
|
||||
elseif tt == "number" then
|
||||
local co = session_id_coroutine[ret]
|
||||
if co then
|
||||
return traceback(co)
|
||||
else
|
||||
return "No session"
|
||||
end
|
||||
elseif tt == "thread" then
|
||||
for session, co in pairs(session_id_coroutine) do
|
||||
if co == ret then
|
||||
return session
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
function skynet.uniqtask()
|
||||
local stacks = {}
|
||||
for session, co in pairs(session_id_coroutine) do
|
||||
local stack = traceback(co)
|
||||
local info = stacks[stack] or {count = 0, sessions = {}}
|
||||
info.count = info.count + 1
|
||||
if info.count < 10 then
|
||||
info.sessions[#info.sessions+1] = session
|
||||
end
|
||||
stacks[stack] = info
|
||||
end
|
||||
local ret = {}
|
||||
for stack, info in pairs(stacks) do
|
||||
local count = info.count
|
||||
local sessions = table.concat(info.sessions, ",")
|
||||
if count > 10 then
|
||||
sessions = sessions .. "..."
|
||||
end
|
||||
local head_line = string.format("%d\tsessions:[%s]\n", count, sessions)
|
||||
ret[head_line] = stack
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function skynet.term(service)
|
||||
|
||||
@@ -2,15 +2,68 @@ local skynet = require "skynet"
|
||||
|
||||
local clusterd
|
||||
local cluster = {}
|
||||
local sender = {}
|
||||
local task_queue = {}
|
||||
|
||||
local function request_sender(q, node)
|
||||
local ok, c = pcall(skynet.call, clusterd, "lua", "sender", node)
|
||||
if not ok then
|
||||
skynet.error(c)
|
||||
c = nil
|
||||
end
|
||||
-- run tasks in queue
|
||||
local confirm = coroutine.running()
|
||||
q.confirm = confirm
|
||||
q.sender = c
|
||||
for _, task in ipairs(q) do
|
||||
if type(task) == "table" then
|
||||
if c then
|
||||
skynet.send(c, "lua", "push", task[1], skynet.pack(table.unpack(task,2,task.n)))
|
||||
end
|
||||
else
|
||||
skynet.wakeup(task)
|
||||
skynet.wait(confirm)
|
||||
end
|
||||
end
|
||||
task_queue[node] = nil
|
||||
sender[node] = c
|
||||
end
|
||||
|
||||
local function get_queue(t, node)
|
||||
local q = {}
|
||||
t[node] = q
|
||||
skynet.fork(request_sender, q, node)
|
||||
return q
|
||||
end
|
||||
|
||||
setmetatable(task_queue, { __index = get_queue } )
|
||||
|
||||
local function get_sender(node)
|
||||
local s = sender[node]
|
||||
if not s then
|
||||
local q = task_queue[node]
|
||||
local task = coroutine.running()
|
||||
table.insert(q, task)
|
||||
skynet.wait(task)
|
||||
skynet.wakeup(q.confirm)
|
||||
return q.sender
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function cluster.call(node, address, ...)
|
||||
-- skynet.pack(...) will free by cluster.core.packrequest
|
||||
return skynet.call(clusterd, "lua", "req", node, address, skynet.pack(...))
|
||||
return skynet.call(get_sender(node), "lua", "req", address, skynet.pack(...))
|
||||
end
|
||||
|
||||
function cluster.send(node, address, ...)
|
||||
-- push is the same with req, but no response
|
||||
skynet.send(clusterd, "lua", "push", node, address, skynet.pack(...))
|
||||
local s = sender[node]
|
||||
if not s then
|
||||
table.insert(task_queue[node], table.pack(address, ...))
|
||||
else
|
||||
skynet.send(sender[node], "lua", "push", address, skynet.pack(...))
|
||||
end
|
||||
end
|
||||
|
||||
function cluster.open(port)
|
||||
@@ -45,7 +98,7 @@ function cluster.register(name, addr)
|
||||
end
|
||||
|
||||
function cluster.query(node, name)
|
||||
return skynet.call(clusterd, "lua", "req", node, 0, skynet.pack(name))
|
||||
return skynet.call(get_sender(node), "lua", "req", 0, skynet.pack(name))
|
||||
end
|
||||
|
||||
skynet.init(function()
|
||||
|
||||
@@ -69,8 +69,15 @@ local skynet = require "skynet"
|
||||
local datasheet = {}
|
||||
local handles = {} -- handle:{ ref:count , name:name , collect:resp }
|
||||
local dataset = {} -- name:{ handle:handle, monitor:{monitors queue} }
|
||||
local customers = {} -- source: { handle:true }
|
||||
|
||||
local function releasehandle(handle)
|
||||
setmetatable(customers, { __index = function(c, source)
|
||||
local v = {}
|
||||
c[source] = v
|
||||
return v
|
||||
end } )
|
||||
|
||||
local function releasehandle(source, handle)
|
||||
local h = handles[handle]
|
||||
h.ref = h.ref - 1
|
||||
if h.ref == 0 and h.collect then
|
||||
@@ -78,10 +85,12 @@ local function releasehandle(handle)
|
||||
h.collect = nil
|
||||
handles[handle] = nil
|
||||
end
|
||||
local t=dataset[h.name]
|
||||
t.monitor[source]=nil
|
||||
end
|
||||
|
||||
-- from builder, create or update handle
|
||||
function datasheet.update(name, handle)
|
||||
function datasheet.update(source, name, handle)
|
||||
local t = dataset[name]
|
||||
if not t then
|
||||
-- new datasheet
|
||||
@@ -89,11 +98,11 @@ function datasheet.update(name, handle)
|
||||
dataset[name] = t
|
||||
handles[handle] = { ref = 1, name = name }
|
||||
else
|
||||
t.handle = handle
|
||||
-- report update to customers
|
||||
handles[handle] = { ref = 1 + #t.monitor, name = name }
|
||||
handles[handle] = { ref = handles[t.handle].ref, name = name }
|
||||
t.handle = handle
|
||||
|
||||
for k,v in ipairs(t.monitor) do
|
||||
for k,v in pairs(t.monitor) do
|
||||
v(true, handle)
|
||||
t.monitor[k] = nil
|
||||
end
|
||||
@@ -102,34 +111,51 @@ function datasheet.update(name, handle)
|
||||
end
|
||||
|
||||
-- from customers
|
||||
function datasheet.query(name)
|
||||
function datasheet.query(source, name)
|
||||
local t = assert(dataset[name], "create data first")
|
||||
local handle = t.handle
|
||||
local h = handles[handle]
|
||||
h.ref = h.ref + 1
|
||||
customers[source][handle] = true
|
||||
skynet.ret(skynet.pack(handle))
|
||||
end
|
||||
|
||||
-- from customers, monitor handle change
|
||||
function datasheet.monitor(handle)
|
||||
function datasheet.monitor(source, handle)
|
||||
local h = assert(handles[handle], "Invalid data handle")
|
||||
local t = dataset[h.name]
|
||||
if t.handle ~= handle then -- already changes
|
||||
customers[source][t.handle] = true
|
||||
skynet.ret(skynet.pack(t.handle))
|
||||
else
|
||||
h.ref = h.ref + 1
|
||||
table.insert(t.monitor, skynet.response())
|
||||
assert(not t.monitor[source])
|
||||
local resp = skynet.response()
|
||||
t.monitor[source]= function(ok, handle)
|
||||
if ok then
|
||||
customers[source][handle] = true
|
||||
end
|
||||
resp(ok, handle)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- from customers, release handle , ref count - 1
|
||||
function datasheet.release(handle)
|
||||
function datasheet.release(source, handle)
|
||||
-- send message, don't ret
|
||||
releasehandle(handle)
|
||||
customers[source][handle] = nil
|
||||
releasehandle(source, handle)
|
||||
end
|
||||
|
||||
-- customer closed, clear all handles it queried
|
||||
function datasheet.close(source)
|
||||
for handle in pairs(customers[source]) do
|
||||
releasehandle(source, handle)
|
||||
end
|
||||
customers[source] = nil
|
||||
end
|
||||
|
||||
-- from builder, monitor handle release
|
||||
function datasheet.collect(handle)
|
||||
function datasheet.collect(source, handle)
|
||||
local h = assert(handles[handle], "Invalid data handle")
|
||||
if h.ref == 0 then
|
||||
handles[handle] = nil
|
||||
@@ -140,8 +166,8 @@ function datasheet.collect(handle)
|
||||
end
|
||||
end
|
||||
|
||||
skynet.dispatch("lua", function(_,_,cmd,...)
|
||||
datasheet[cmd](...)
|
||||
skynet.dispatch("lua", function(_,source,cmd,...)
|
||||
datasheet[cmd](source,...)
|
||||
end)
|
||||
|
||||
skynet.info_func(function()
|
||||
@@ -155,7 +181,7 @@ skynet.info_func(function()
|
||||
tmp[v.handle] = nil
|
||||
info[k] = {
|
||||
handle = v.handle,
|
||||
monitors = #v.monitor,
|
||||
monitors = h.ref,
|
||||
}
|
||||
end
|
||||
for k,v in pairs(tmp) do
|
||||
|
||||
@@ -59,7 +59,7 @@ function ctd.dump(root)
|
||||
local index = dump_table(v)
|
||||
return '\4', string.pack("<i4", index-1)
|
||||
elseif t == "number" then
|
||||
if math.tointeger(v) then
|
||||
if math.tointeger(v) and v <= 0x7FFFFFFF and v >= -(0x7FFFFFFF+1) then
|
||||
return '\1', string.pack("<i4", v)
|
||||
else
|
||||
return '\2', string.pack("<f",v)
|
||||
|
||||
@@ -11,9 +11,7 @@ end)
|
||||
local datasheet = {}
|
||||
local sheets = setmetatable({}, {
|
||||
__gc = function(t)
|
||||
for _,v in pairs(t) do
|
||||
skynet.send(datasheet_svr, "lua", "release", v.handle)
|
||||
end
|
||||
skynet.send(datasheet_svr, "lua", "close")
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -32,7 +30,7 @@ local function updateobject(name)
|
||||
core.update(t.object, newhandle)
|
||||
t.handle = newhandle
|
||||
skynet.send(datasheet_svr, "lua", "release", handle)
|
||||
skynet.fork(monitor)
|
||||
return monitor()
|
||||
end
|
||||
skynet.fork(monitor)
|
||||
end
|
||||
|
||||
@@ -82,18 +82,24 @@ local function __parse_addr(addr)
|
||||
return host, tonumber(port)
|
||||
end
|
||||
|
||||
local auth_method = {}
|
||||
|
||||
local function mongo_auth(mongoc)
|
||||
local user = rawget(mongoc, "username")
|
||||
local pass = rawget(mongoc, "password")
|
||||
local authmod = rawget(mongoc, "authmod") or "scram_sha1"
|
||||
authmod = "auth_" .. authmod
|
||||
local authdb = rawget(mongoc, "authdb")
|
||||
if authdb then
|
||||
authdb = mongo_client.getDB(mongoc, authdb) -- mongoc has not set metatable yet
|
||||
end
|
||||
|
||||
return function()
|
||||
if user ~= nil and pass ~= nil then
|
||||
-- autmod can be "mongodb_cr" or "scram_sha1"
|
||||
local auth_func = mongoc[authmod]
|
||||
local auth_func = auth_method[authmod]
|
||||
assert(auth_func , "Invalid authmod")
|
||||
assert(auth_func(mongoc,user, pass))
|
||||
assert(auth_func(authdb or mongoc, user, pass))
|
||||
end
|
||||
local rs_data = mongoc:runCommand("ismaster")
|
||||
if rs_data.ok == 1 then
|
||||
@@ -156,6 +162,7 @@ function mongo.client( conf )
|
||||
username = first.username,
|
||||
password = first.password,
|
||||
authmod = first.authmod,
|
||||
authdb = first.authdb,
|
||||
}
|
||||
|
||||
obj.__id = 0
|
||||
@@ -166,6 +173,7 @@ function mongo.client( conf )
|
||||
auth = mongo_auth(obj),
|
||||
backup = backup,
|
||||
nodelay = true,
|
||||
overload = conf.overload,
|
||||
}
|
||||
setmetatable(obj, client_meta)
|
||||
obj.__sock:connect(true) -- try connect only once
|
||||
@@ -206,7 +214,7 @@ function mongo_client:runCommand(...)
|
||||
return self.admin:runCommand(...)
|
||||
end
|
||||
|
||||
function mongo_client:auth_mongodb_cr(user,password)
|
||||
function auth_method:auth_mongodb_cr(user,password)
|
||||
local password = md5.sumhexa(string.format("%s:mongo:%s",user,password))
|
||||
local result= self:runCommand "getnonce"
|
||||
if result.ok ~=1 then
|
||||
@@ -229,7 +237,7 @@ local function salt_password(password, salt, iter)
|
||||
return output
|
||||
end
|
||||
|
||||
function mongo_client:auth_scram_sha1(username,password)
|
||||
function auth_method:auth_scram_sha1(username,password)
|
||||
local user = string.gsub(string.gsub(username, '=', '=3D'), ',' , '=2C')
|
||||
local nonce = crypt.base64encode(crypt.randomkey())
|
||||
local first_bare = "n=" .. user .. ",r=" .. nonce
|
||||
@@ -300,6 +308,13 @@ function mongo_client:logout()
|
||||
return result.ok == 1
|
||||
end
|
||||
|
||||
function mongo_db:auth(user, pass)
|
||||
local authmod = rawget(self.connection, "authmod") or "scram_sha1"
|
||||
local auth_func = auth_method["auth_" .. authmod]
|
||||
assert(auth_func , "Invalid authmod")
|
||||
return auth_func(self, user, pass)
|
||||
end
|
||||
|
||||
function mongo_db:runCommand(cmd,cmd_v,...)
|
||||
local conn = self.connection
|
||||
local request_id = conn:genId()
|
||||
@@ -340,8 +355,23 @@ function mongo_collection:insert(doc)
|
||||
sock:request(pack)
|
||||
end
|
||||
|
||||
local function werror(r)
|
||||
local ok = (r.ok == 1 and not r.writeErrors and not r.writeConcernError)
|
||||
|
||||
local err
|
||||
if not ok then
|
||||
if r.writeErrors then
|
||||
err = r.writeErrors[1].errmsg
|
||||
else
|
||||
err = r.writeConcernError.errmsg
|
||||
end
|
||||
end
|
||||
return ok, err, r
|
||||
end
|
||||
|
||||
function mongo_collection:safe_insert(doc)
|
||||
return self.database:runCommand("insert", self.name, "documents", {bson_encode(doc)})
|
||||
local r = self.database:runCommand("insert", self.name, "documents", {bson_encode(doc)})
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:batch_insert(docs)
|
||||
@@ -363,12 +393,30 @@ function mongo_collection:update(selector,update,upsert,multi)
|
||||
sock:request(pack)
|
||||
end
|
||||
|
||||
function mongo_collection:safe_update(selector, update, upsert, multi)
|
||||
local r = self.database:runCommand("update", self.name, "updates", {bson_encode({
|
||||
q = selector,
|
||||
u = update,
|
||||
upsert = upsert,
|
||||
multi = multi,
|
||||
})})
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:delete(selector, single)
|
||||
local sock = self.connection.__sock
|
||||
local pack = driver.delete(self.full_name, single, bson_encode(selector))
|
||||
sock:request(pack)
|
||||
end
|
||||
|
||||
function mongo_collection:safe_delete(selector, single)
|
||||
local r = self.database:runCommand("delete", self.name, "deletes", {bson_encode({
|
||||
q = selector,
|
||||
limit = single and 1 or 0,
|
||||
})})
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:findOne(query, selector)
|
||||
local conn = self.connection
|
||||
local request_id = conn:genId()
|
||||
@@ -574,10 +622,20 @@ function mongo_cursor:hasNext()
|
||||
|
||||
if ok then
|
||||
if doc then
|
||||
self.__document = result.result
|
||||
local doc = result.result
|
||||
self.__document = doc
|
||||
self.__data = result.data
|
||||
self.__ptr = 1
|
||||
self.__cursor = cursor
|
||||
local limit = self.__limit
|
||||
if cursor and limit > 0 then
|
||||
limit = limit - #doc
|
||||
if limit <= 0 then
|
||||
-- reach limit
|
||||
self:close()
|
||||
end
|
||||
self.__limit = limit
|
||||
end
|
||||
return true
|
||||
else
|
||||
self.__document = nil
|
||||
@@ -615,11 +673,11 @@ function mongo_cursor:next()
|
||||
end
|
||||
|
||||
function mongo_cursor:close()
|
||||
-- todo: warning hasNext after close
|
||||
if self.__cursor then
|
||||
local sock = self.__collection.connection.__sock
|
||||
local pack = driver.kill(self.__cursor)
|
||||
sock:request(pack)
|
||||
self.__cursor = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -143,6 +143,7 @@ function redis.connect(db_conf)
|
||||
port = db_conf.port or 6379,
|
||||
auth = redis_login(db_conf.auth, db_conf.db),
|
||||
nodelay = true,
|
||||
overload = db_conf.overload,
|
||||
}
|
||||
-- try connect first only once
|
||||
channel:connect(true)
|
||||
|
||||
@@ -8,24 +8,60 @@ local crc16 = require "skynet.db.redis.crc16"
|
||||
local RedisClusterHashSlots = 16384
|
||||
local RedisClusterRequestTTL = 16
|
||||
|
||||
local sync = {
|
||||
once = {
|
||||
tasks = {},
|
||||
}
|
||||
}
|
||||
|
||||
function sync.once.Do(id,func,...)
|
||||
local tasks = sync.once.tasks
|
||||
local task = tasks[id]
|
||||
if not task then
|
||||
task = {
|
||||
waiting = {},
|
||||
result = nil,
|
||||
}
|
||||
tasks[id] = task
|
||||
local rettbl = table.pack(xpcall(func,debug.traceback,...))
|
||||
task.result = rettbl
|
||||
local waiting = task.waiting
|
||||
tasks[id] = nil
|
||||
if next(waiting) then
|
||||
for i,co in ipairs(waiting) do
|
||||
skynet.wakeup(co)
|
||||
end
|
||||
end
|
||||
return table.unpack(task.result,1,task.result.n)
|
||||
else
|
||||
local co = coroutine.running()
|
||||
table.insert(task.waiting,co)
|
||||
skynet.wait(co)
|
||||
return table.unpack(task.result,1,task.result.n)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local _M = {}
|
||||
|
||||
local rediscluster = {}
|
||||
rediscluster.__index = rediscluster
|
||||
_M.rediscluster = rediscluster
|
||||
|
||||
function _M.new(startup_nodes,opt)
|
||||
function _M.new(startup_nodes,opt,onmessage)
|
||||
if #startup_nodes == 0 then
|
||||
startup_nodes = {startup_nodes,}
|
||||
end
|
||||
opt = opt or {}
|
||||
local self = {
|
||||
startup_nodes = startup_nodes,
|
||||
max_connections = opt.max_connections or 16,
|
||||
connections = setmetatable({},{__mode = "kv"}),
|
||||
max_connections = opt.max_connections or 256,
|
||||
connections = {},
|
||||
opt = opt,
|
||||
refresh_table_asap = false,
|
||||
|
||||
-- for subscribe/publish
|
||||
__onmessage = onmessage,
|
||||
__watching = {},
|
||||
}
|
||||
setmetatable(self,rediscluster)
|
||||
self:initialize_slots_cache()
|
||||
@@ -53,13 +89,6 @@ function rediscluster:set_node_name(node)
|
||||
if not node.name then
|
||||
node.name = nodename(node)
|
||||
end
|
||||
if not node.slaves then
|
||||
local oldnode = self.name_node[node.name]
|
||||
if oldnode then
|
||||
node.slaves = oldnode.slaves
|
||||
end
|
||||
end
|
||||
self.name_node[node.name] = node
|
||||
end
|
||||
|
||||
-- Contact the startup nodes and try to fetch the hash slots -> instances
|
||||
@@ -67,11 +96,9 @@ end
|
||||
function rediscluster:initialize_slots_cache()
|
||||
self.slots = {}
|
||||
self.nodes = {}
|
||||
self.name_node = {}
|
||||
for _,startup_node in ipairs(self.startup_nodes) do
|
||||
local ok = pcall(function ()
|
||||
local name = nodename(startup_node)
|
||||
local conn = self.connections[name] or self:get_redis_link(startup_node)
|
||||
local conn = self:get_connection(startup_node)
|
||||
local list = conn:cluster("slots")
|
||||
for _,result in ipairs(list) do
|
||||
local ip,port = table.unpack(result[3])
|
||||
@@ -100,9 +127,6 @@ function rediscluster:initialize_slots_cache()
|
||||
end
|
||||
end
|
||||
self.refresh_table_asap = false
|
||||
if not self.connections[name] then
|
||||
self.connections[name] = conn
|
||||
end
|
||||
end)
|
||||
-- Exit the loop as long as the first node replies
|
||||
if ok then
|
||||
@@ -154,6 +178,21 @@ function rediscluster:get_key_from_command(argv)
|
||||
cmd == "shutdown" then
|
||||
return nil
|
||||
end
|
||||
if cmd == "eval" or cmd == "evalsha" then
|
||||
-- eval script numkeys key [key...] arg [arg...]
|
||||
local numkeys = argv[3]
|
||||
local firstkey_slot = nil
|
||||
for i=4,4+numkeys-1 do
|
||||
local slot = self:keyslot(argv[i])
|
||||
if not firstkey_slot then
|
||||
firstkey_slot = slot
|
||||
elseif firstkey_slot ~= slot then
|
||||
error(string.format("%s - all keys must map to the same key slot",cmd))
|
||||
end
|
||||
end
|
||||
-- numkeys <=0 will return nil
|
||||
return argv[4]
|
||||
end
|
||||
-- Unknown commands, and all the commands having the key
|
||||
-- as first argument are handled here:
|
||||
-- set, get, ...
|
||||
@@ -179,21 +218,28 @@ end
|
||||
|
||||
function rediscluster:close_all_connection()
|
||||
local connections = self.connections
|
||||
self.connections = setmetatable({},{__mode = "kv"})
|
||||
self.connections = {}
|
||||
for name,conn in pairs(connections) do
|
||||
pcall(conn.disconnect,conn)
|
||||
end
|
||||
end
|
||||
|
||||
function rediscluster:get_connection(node)
|
||||
node.port = assert(tonumber(node.port))
|
||||
local name = node.name or nodename(node)
|
||||
local conn = self.connections[name]
|
||||
if not conn then
|
||||
conn = self:get_redis_link(node)
|
||||
self.connections[name] = conn
|
||||
if not node.name then
|
||||
node.name = nodename(node)
|
||||
end
|
||||
return self.connections[name]
|
||||
local name = node.name
|
||||
local ok,conn = sync.once.Do(name,function ()
|
||||
local conn = self.connections[name]
|
||||
if not conn then
|
||||
self:close_existing_connection()
|
||||
conn = self:get_redis_link(node)
|
||||
self.connections[name] = conn
|
||||
end
|
||||
return conn
|
||||
end)
|
||||
assert(ok,conn)
|
||||
return conn
|
||||
end
|
||||
|
||||
-- Return a link to a random node, or raise an error if no node can be
|
||||
@@ -219,25 +265,15 @@ function rediscluster:get_random_connection()
|
||||
for i,idx in ipairs(shuffle_idx) do
|
||||
local ok,conn = pcall(function ()
|
||||
local node = self.nodes[idx]
|
||||
local conn = self.connections[node.name]
|
||||
if not conn then
|
||||
-- Connect the node if it is not connected
|
||||
conn = self:get_redis_link(node)
|
||||
if conn:ping() == "PONG" then
|
||||
self:close_existing_connection()
|
||||
self.connections[node.name] = conn
|
||||
return conn
|
||||
else
|
||||
-- If the connection is not good close it ASAP in order
|
||||
-- to avoid waiting for the GC finalizer. File
|
||||
-- descriptors are a rare resource.
|
||||
conn:disconnect()
|
||||
end
|
||||
local conn = self:get_connection(node)
|
||||
if conn:ping() == "PONG" then
|
||||
return conn
|
||||
else
|
||||
-- The node was already connected, test the connection.
|
||||
if conn:ping() == "PONG" then
|
||||
return conn
|
||||
end
|
||||
-- If the connection is not good close it ASAP in order
|
||||
-- to avoid waiting for the GC finalizer. File
|
||||
-- descriptors are a rare resource.
|
||||
self.connetions[node.name] = nil
|
||||
conn:disconnect()
|
||||
end
|
||||
end)
|
||||
if ok and conn then
|
||||
@@ -256,33 +292,40 @@ function rediscluster:get_connection_by_slot(slot)
|
||||
if not node then
|
||||
return self:get_random_connection()
|
||||
end
|
||||
if not self.connections[node.name] then
|
||||
local ok = pcall(function ()
|
||||
self:close_existing_connection()
|
||||
self.connections[node.name] = self:get_redis_link(node)
|
||||
end)
|
||||
if not ok then
|
||||
if self.opt.read_slave and node.slaves and #node.slaves > 0 then
|
||||
local slave_node = node.slaves[math.random(1,#node.slaves)]
|
||||
local ok2,conn = pcall(self.get_connection,self,slave_node)
|
||||
if ok2 then
|
||||
conn:readonly() -- allow this connection read-slave
|
||||
return conn
|
||||
end
|
||||
local ok,conn = pcall(self.get_connection,self,node)
|
||||
if not ok then
|
||||
if self.opt.read_slave and node.slaves and #node.slaves > 0 then
|
||||
local slave_node = node.slaves[math.random(1,#node.slaves)]
|
||||
local ok2,conn = pcall(self.get_connection,self,slave_node)
|
||||
if ok2 then
|
||||
conn:readonly() -- allow this connection read-slave
|
||||
return conn
|
||||
end
|
||||
-- This will probably never happen with recent redis-rb
|
||||
-- versions because the connection is enstablished in a lazy
|
||||
-- way only when a command is called. However it is wise to
|
||||
-- handle an instance creation error of some kind.
|
||||
return self:get_random_connection()
|
||||
end
|
||||
-- This will probably never happen with recent redis-rb
|
||||
-- versions because the connection is enstablished in a lazy
|
||||
-- way only when a command is called. However it is wise to
|
||||
-- handle an instance creation error of some kind.
|
||||
return self:get_random_connection()
|
||||
end
|
||||
return self.connections[node.name]
|
||||
return conn
|
||||
end
|
||||
|
||||
-- Dispatch commands.
|
||||
function rediscluster:call(...)
|
||||
local argv = table.pack(...)
|
||||
local cmd = argv[1]
|
||||
local key = self:get_key_from_command(argv)
|
||||
if not key then
|
||||
error("No way to dispatch this command to Redis Cluster: " .. tostring(argv[1]))
|
||||
end
|
||||
if cmd == "subscribe" or cmd == "unsubscribe" or cmd == "psubscribe" or cmd == "punsubscribe" then
|
||||
local slot = self:keyslot(key)
|
||||
local conn = self:get_watch_connection_by_slot(slot)
|
||||
local func = conn[cmd]
|
||||
return func(conn,table.unpack(argv,2))
|
||||
end
|
||||
|
||||
if self.refresh_table_asap then
|
||||
self:initialize_slots_cache()
|
||||
end
|
||||
@@ -292,10 +335,6 @@ function rediscluster:call(...)
|
||||
local try_random_node = false
|
||||
while ttl > 0 do
|
||||
ttl = ttl - 1
|
||||
local key = self:get_key_from_command(argv)
|
||||
if not key then
|
||||
error("No way to dispatch this command to Redis Cluster: " .. tostring(argv[1]))
|
||||
end
|
||||
local conn
|
||||
local slot = self:keyslot(key)
|
||||
if asking then
|
||||
@@ -312,7 +351,6 @@ function rediscluster:call(...)
|
||||
conn:asking()
|
||||
end
|
||||
asking = false
|
||||
local cmd = argv[1]
|
||||
local func = conn[cmd]
|
||||
return func(conn,table.unpack(argv,2))
|
||||
end)}
|
||||
@@ -321,7 +359,7 @@ function rediscluster:call(...)
|
||||
err = table.unpack(result,2)
|
||||
err = tostring(err)
|
||||
if err == "[Error: socket]" then
|
||||
-- may be nerver come here?
|
||||
-- may be never come here?
|
||||
try_random_node = true
|
||||
if ttl < RedisClusterRequestTTL/2 then
|
||||
skynet.sleep(10)
|
||||
@@ -351,6 +389,10 @@ function rediscluster:call(...)
|
||||
port = node_port,
|
||||
}
|
||||
if not asking then
|
||||
local oldnode = self.slots[newslot]
|
||||
if oldnode then
|
||||
node.slaves = oldnode.slaves
|
||||
end
|
||||
self:set_node_name(node)
|
||||
self.slots[newslot] = node
|
||||
else
|
||||
@@ -365,6 +407,44 @@ function rediscluster:call(...)
|
||||
error(string.format("Too many Cluster redirections?,maybe node is disconnected (last error: %q)",err))
|
||||
end
|
||||
|
||||
function rediscluster:get_watch_connection_by_slot(slot)
|
||||
if not self.slots[slot] then
|
||||
self:initialize_slots_cache()
|
||||
end
|
||||
local node = assert(self.slots[slot])
|
||||
return self:get_watch_connection(node)
|
||||
end
|
||||
|
||||
function rediscluster:get_watch_connection(node)
|
||||
local name = node.name
|
||||
local ok,conn = sync.once.Do(name,function ()
|
||||
if not self.__watching[name] then
|
||||
local conf = {
|
||||
host = node.host,
|
||||
port = node.port,
|
||||
auth = self.opt.auth,
|
||||
db = self.opt.db or 0,
|
||||
}
|
||||
local db = redis.watch(conf)
|
||||
self.__watching[name] = db
|
||||
local onmessage = rawget(self,"__onmessage")
|
||||
skynet.fork(function ()
|
||||
while true do
|
||||
local ok,data,channel,pchannel = pcall(db.message,db)
|
||||
if ok then
|
||||
if data and onmessage then
|
||||
pcall(onmessage,data,channel,pchannel)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
return self.__watching[name]
|
||||
end)
|
||||
assert(ok,conn)
|
||||
return conn
|
||||
end
|
||||
|
||||
-- Currently we handle all the commands using method_missing for
|
||||
-- simplicity. For a Cluster client actually it will be better to have
|
||||
-- every single command as a method with the right arity and possibly
|
||||
@@ -379,5 +459,4 @@ setmetatable(rediscluster,{
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
return _M
|
||||
|
||||
@@ -14,8 +14,8 @@ local function init(skynet, export)
|
||||
dbgcmd = {}
|
||||
|
||||
function dbgcmd.MEM()
|
||||
local kb, bytes = collectgarbage "count"
|
||||
skynet.ret(skynet.pack(kb,bytes))
|
||||
local kb = collectgarbage "count"
|
||||
skynet.ret(skynet.pack(kb))
|
||||
end
|
||||
|
||||
function dbgcmd.GC()
|
||||
@@ -32,10 +32,18 @@ local function init(skynet, export)
|
||||
skynet.ret(skynet.pack(stat))
|
||||
end
|
||||
|
||||
function dbgcmd.TASK()
|
||||
local task = {}
|
||||
skynet.task(task)
|
||||
skynet.ret(skynet.pack(task))
|
||||
function dbgcmd.TASK(session)
|
||||
if session then
|
||||
skynet.ret(skynet.pack(skynet.task(session)))
|
||||
else
|
||||
local task = {}
|
||||
skynet.task(task)
|
||||
skynet.ret(skynet.pack(task))
|
||||
end
|
||||
end
|
||||
|
||||
function dbgcmd.UNIQTASK()
|
||||
skynet.ret(skynet.pack(skynet.uniqtask()))
|
||||
end
|
||||
|
||||
function dbgcmd.INFO(...)
|
||||
@@ -50,9 +58,10 @@ local function init(skynet, export)
|
||||
skynet.exit()
|
||||
end
|
||||
|
||||
function dbgcmd.RUN(source, filename)
|
||||
function dbgcmd.RUN(source, filename, ...)
|
||||
local inject = require "skynet.inject"
|
||||
local ok, output = inject(skynet, source, filename , export.dispatch, skynet.register_protocol)
|
||||
local args = table.pack(...)
|
||||
local ok, output = inject(skynet, source, filename, args, export.dispatch, skynet.register_protocol)
|
||||
collectgarbage "collect"
|
||||
skynet.ret(skynet.pack(ok, table.concat(output, "\n")))
|
||||
end
|
||||
@@ -78,6 +87,16 @@ local function init(skynet, export)
|
||||
skynet.response() -- get response , but not return. raise error when exit
|
||||
end
|
||||
|
||||
function dbgcmd.TRACELOG(proto, flag)
|
||||
if type(proto) ~= "string" then
|
||||
flag = proto
|
||||
proto = "lua"
|
||||
end
|
||||
skynet.error(string.format("Turn trace log %s for %s", flag, proto))
|
||||
skynet.traceproto(proto, flag)
|
||||
skynet.ret()
|
||||
end
|
||||
|
||||
return dbgcmd
|
||||
end -- function init_dbgcmd
|
||||
|
||||
|
||||
@@ -88,6 +88,87 @@ local CACHE = {}
|
||||
|
||||
local dns = {}
|
||||
local request_pool = {}
|
||||
local local_hosts -- local static table lookup for hostnames
|
||||
|
||||
dns.DEFAULT_HOSTS = "/etc/hosts"
|
||||
dns.DEFAULT_RESOLV_CONF = "/etc/resolv.conf"
|
||||
|
||||
-- return name type: 'ipv4', 'ipv6', or 'hostname'
|
||||
local function guess_name_type(name)
|
||||
if name:match("^[%d%.]+$") then
|
||||
return "ipv4"
|
||||
end
|
||||
|
||||
if name:find(":") then
|
||||
return "ipv6"
|
||||
end
|
||||
|
||||
return "hostname"
|
||||
end
|
||||
|
||||
-- http://man7.org/linux/man-pages/man5/hosts.5.html
|
||||
local function parse_hosts()
|
||||
if not dns.DEFAULT_HOSTS then
|
||||
return
|
||||
end
|
||||
|
||||
local f = io.open(dns.DEFAULT_HOSTS)
|
||||
if not f then
|
||||
return
|
||||
end
|
||||
|
||||
local rts = {}
|
||||
for line in f:lines() do
|
||||
local ip, hosts = string.match(line, "^%s*([%[%]%x%.%:]+)%s+([^#;]+)")
|
||||
if not ip or not hosts then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local family = guess_name_type(ip)
|
||||
if family == "hostname" then
|
||||
goto continue
|
||||
end
|
||||
|
||||
for host in hosts:gmatch("%S+") do
|
||||
host = host:lower()
|
||||
local rt = rts[host]
|
||||
if not rt then
|
||||
rt = {}
|
||||
rts[host] = rt
|
||||
end
|
||||
|
||||
if not rt[family] then
|
||||
rt[family] = {}
|
||||
end
|
||||
table.insert(rt[family], ip)
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
return rts
|
||||
end
|
||||
|
||||
-- http://man7.org/linux/man-pages/man5/resolv.conf.5.html
|
||||
local function parse_resolv_conf()
|
||||
if not dns.DEFAULT_RESOLV_CONF then
|
||||
return
|
||||
end
|
||||
|
||||
local f = io.open(dns.DEFAULT_RESOLV_CONF)
|
||||
if not f then
|
||||
return
|
||||
end
|
||||
|
||||
local server
|
||||
for line in f:lines() do
|
||||
server = line:match("%s*nameserver%s+([^#;%s]+)")
|
||||
if server then
|
||||
break
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
return server
|
||||
end
|
||||
|
||||
function dns.flush()
|
||||
CACHE[QTYPE.A] = setmetatable({},weak)
|
||||
@@ -219,7 +300,12 @@ local function unpack_rdata(qtype, chunk)
|
||||
end
|
||||
end
|
||||
|
||||
local dns_server
|
||||
local dns_server = {
|
||||
fd = nil,
|
||||
address = nil,
|
||||
port = nil,
|
||||
retire = nil,
|
||||
}
|
||||
|
||||
local function resolve(content)
|
||||
if #content < DNS_HEADER_LEN then
|
||||
@@ -281,23 +367,56 @@ local function resolve(content)
|
||||
skynet.wakeup(resp.co)
|
||||
end
|
||||
|
||||
function dns.server(server, port)
|
||||
if not server then
|
||||
local f = assert(io.open "/etc/resolv.conf")
|
||||
for line in f:lines() do
|
||||
server = line:match("%s*nameserver%s+([^%s]+)")
|
||||
if server then
|
||||
break
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
assert(server, "Can't get nameserver")
|
||||
end
|
||||
dns_server = socket.udp(function(str, from)
|
||||
local function connect_server()
|
||||
local fd = socket.udp(function(str, from)
|
||||
resolve(str)
|
||||
end)
|
||||
socket.udp_connect(dns_server, server, port or 53)
|
||||
return server
|
||||
|
||||
if not dns_server.address then
|
||||
dns_server.address = parse_resolv_conf()
|
||||
dns_server.port = 53
|
||||
end
|
||||
|
||||
assert(dns_server.address, "Call dns.server first")
|
||||
|
||||
local ok, err = pcall(socket.udp_connect,fd, dns_server.address, dns_server.port)
|
||||
if not ok then
|
||||
socket.close(fd)
|
||||
error(err)
|
||||
end
|
||||
|
||||
dns_server.fd = fd
|
||||
skynet.error(string.format("Udp server open %s:%s (%d)", dns_server.address, dns_server.port, fd))
|
||||
end
|
||||
|
||||
local DNS_SERVER_RETIRE = 60 * 100
|
||||
local function touch_server()
|
||||
dns_server.retire = skynet.now()
|
||||
if dns_server.fd then
|
||||
return
|
||||
end
|
||||
|
||||
connect_server()
|
||||
|
||||
local function check_alive()
|
||||
if skynet.now() > dns_server.retire + DNS_SERVER_RETIRE then
|
||||
local fd = dns_server.fd
|
||||
if fd then
|
||||
dns_server.fd = nil
|
||||
socket.close(fd)
|
||||
skynet.error(string.format("Udp server close %s:%s (%d)", dns_server.address, dns_server.port, fd))
|
||||
end
|
||||
else
|
||||
skynet.timeout( 2 * DNS_SERVER_RETIRE, check_alive)
|
||||
end
|
||||
end
|
||||
|
||||
skynet.timeout( 2 * DNS_SERVER_RETIRE, check_alive)
|
||||
end
|
||||
|
||||
function dns.server(server, port)
|
||||
dns_server.address = server
|
||||
dns_server.port = port or 53
|
||||
end
|
||||
|
||||
local function lookup_cache(name, qtype, ignorettl)
|
||||
@@ -328,7 +447,6 @@ local function suspend(tid, name, qtype)
|
||||
end
|
||||
end)
|
||||
skynet.wait(req.co)
|
||||
local answers = req.answers
|
||||
request_pool[tid] = nil
|
||||
if not req.answers then
|
||||
local answers = lookup_cache(name, qtype, true)
|
||||
@@ -340,10 +458,30 @@ local function suspend(tid, name, qtype)
|
||||
return req.answers[1], req.answers
|
||||
end
|
||||
|
||||
function dns.resolve(name, ipv6)
|
||||
-- lookup local static table
|
||||
local function local_resolve(name, ipv6)
|
||||
if not local_hosts then
|
||||
local_hosts = parse_hosts()
|
||||
end
|
||||
|
||||
if not local_hosts then
|
||||
return
|
||||
end
|
||||
|
||||
local family = ipv6 and "ipv6" or "ipv4"
|
||||
local t = local_hosts[name]
|
||||
if t then
|
||||
local answers = t[family]
|
||||
if answers then
|
||||
return answers[1], answers
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- lookup dns server
|
||||
local function remote_resolve(name, ipv6)
|
||||
local qtype = ipv6 and QTYPE.AAAA or QTYPE.A
|
||||
local name = name:lower()
|
||||
assert(verify_domain_name(name) , "illegal name")
|
||||
local answers = lookup_cache(name, qtype)
|
||||
if answers then
|
||||
return answers[1], answers
|
||||
@@ -354,9 +492,31 @@ function dns.resolve(name, ipv6)
|
||||
qdcount = 1,
|
||||
}
|
||||
local req = pack_header(question_header) .. pack_question(name, qtype, QCLASS.IN)
|
||||
assert(dns_server, "Call dns.server first")
|
||||
socket.write(dns_server, req)
|
||||
touch_server()
|
||||
socket.write(dns_server.fd, req)
|
||||
return suspend(question_header.tid, name, qtype)
|
||||
end
|
||||
|
||||
function dns.resolve(name, ipv6)
|
||||
local name = name:lower()
|
||||
local ntype = guess_name_type(name)
|
||||
if ntype ~= "hostname" then
|
||||
if (ipv6 and name == "ipv4") or (not ipv6 and name == "ipv6") then
|
||||
return nil, "illegal ip address"
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
if not verify_domain_name(name) then
|
||||
return nil, "illegal name"
|
||||
end
|
||||
|
||||
local answer, answers = local_resolve(name, ipv6)
|
||||
if answer then
|
||||
return answer, answers
|
||||
end
|
||||
|
||||
return remote_resolve(name, ipv6)
|
||||
end
|
||||
|
||||
return dns
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user