mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
Compare commits
47 Commits
v1.0.0-alp
...
v1.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35a5b99bed | ||
|
|
98af25d109 | ||
|
|
cd3391461c | ||
|
|
e3b7f86075 | ||
|
|
86d5865457 | ||
|
|
7b783076e5 | ||
|
|
57c0ad694c | ||
|
|
f55a31c24f | ||
|
|
843095afc6 | ||
|
|
a6bad52181 | ||
|
|
012d98380d | ||
|
|
0298997d23 | ||
|
|
678a94bf71 | ||
|
|
03399e86a9 | ||
|
|
22364bac89 | ||
|
|
9188b5451c | ||
|
|
c7ed527911 | ||
|
|
5a1132101b | ||
|
|
ca33bf8b3e | ||
|
|
7d8c80c9a0 | ||
|
|
c6f993428e | ||
|
|
f6118b858d | ||
|
|
ec1bca238e | ||
|
|
6b87f159b4 | ||
|
|
41b447d41a | ||
|
|
c512b5f59a | ||
|
|
fc9b32b4bd | ||
|
|
36ed8679b8 | ||
|
|
a9b1993686 | ||
|
|
05b458ddb2 | ||
|
|
8d8add3710 | ||
|
|
65e7da9793 | ||
|
|
7e5d9b7399 | ||
|
|
92b7b7beff | ||
|
|
c287f050c1 | ||
|
|
f71beb4018 | ||
|
|
75bbdeb6d2 | ||
|
|
72c43b6614 | ||
|
|
a0eddbdeca | ||
|
|
03f7661a4a | ||
|
|
f95d8db4da | ||
|
|
a0ffff8ad6 | ||
|
|
7ced874d7c | ||
|
|
a630eb796d | ||
|
|
f15eaee060 | ||
|
|
13cb2b79e2 | ||
|
|
4d6d090ff2 |
@@ -94,6 +94,7 @@ typedef struct CallInfo {
|
|||||||
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
|
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
|
||||||
#define CIST_TAIL (1<<5) /* call was tail called */
|
#define CIST_TAIL (1<<5) /* call was tail called */
|
||||||
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
|
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
|
||||||
|
#define CIST_LEQ (1<<7) /* using __lt for __le */
|
||||||
|
|
||||||
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
|
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
|
||||||
|
|
||||||
|
|||||||
@@ -798,7 +798,8 @@ static int str_gsub (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
|
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
|
||||||
#define MAX_ITEM 512
|
#define MAX_ITEM \
|
||||||
|
(sizeof(lua_Number) <= 4 ? 150 : sizeof(lua_Number) <= 8 ? 450 : 5050)
|
||||||
|
|
||||||
/* valid flags in a format specification */
|
/* valid flags in a format specification */
|
||||||
#define FLAGS "-+ #0"
|
#define FLAGS "-+ #0"
|
||||||
|
|||||||
@@ -458,6 +458,11 @@ struct lua_Debug {
|
|||||||
|
|
||||||
/* }====================================================================== */
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
/* Add by skynet */
|
||||||
|
|
||||||
|
extern lua_State * skynet_sig_L;
|
||||||
|
LUA_API void (lua_checksig_)(lua_State *L);
|
||||||
|
#define lua_checksig(L) if (skynet_sig_L) { lua_checksig_(L); }
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
|
* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ LUAMOD_API int (luaopen_debug) (lua_State *L);
|
|||||||
#define LUA_LOADLIBNAME "package"
|
#define LUA_LOADLIBNAME "package"
|
||||||
LUAMOD_API int (luaopen_package) (lua_State *L);
|
LUAMOD_API int (luaopen_package) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_CACHELIB
|
||||||
|
LUAMOD_API int (luaopen_cache) (lua_State *L);
|
||||||
|
|
||||||
/* open all previous libraries */
|
/* open all previous libraries */
|
||||||
LUALIB_API void (luaL_openlibs) (lua_State *L);
|
LUALIB_API void (luaL_openlibs) (lua_State *L);
|
||||||
|
|||||||
@@ -43,6 +43,17 @@
|
|||||||
/* limit for table tag-method chains (to avoid loops) */
|
/* limit for table tag-method chains (to avoid loops) */
|
||||||
#define MAXTAGLOOP 2000
|
#define MAXTAGLOOP 2000
|
||||||
|
|
||||||
|
/* Add by skynet */
|
||||||
|
lua_State * skynet_sig_L = NULL;
|
||||||
|
|
||||||
|
LUA_API void
|
||||||
|
lua_checksig_(lua_State *L) {
|
||||||
|
if (skynet_sig_L == G(L)->mainthread) {
|
||||||
|
skynet_sig_L = NULL;
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_error(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Similar to 'tonumber', but does not attempt to convert strings and
|
** Similar to 'tonumber', but does not attempt to convert strings and
|
||||||
@@ -292,12 +303,18 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
|
|||||||
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
|
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
|
||||||
else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */
|
else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */
|
||||||
return res;
|
return res;
|
||||||
else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */
|
else { /* try 'lt': */
|
||||||
luaG_ordererror(L, l, r);
|
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
|
||||||
return !res;
|
res = luaT_callorderTM(L, r, l, TM_LT);
|
||||||
|
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
|
||||||
|
if (res < 0)
|
||||||
|
luaG_ordererror(L, l, r);
|
||||||
|
return !res; /* result is negated */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Main operation for equality of Lua values; return 't1 == t2'.
|
** Main operation for equality of Lua values; return 't1 == t2'.
|
||||||
** L == NULL means raw equality (no metamethods)
|
** L == NULL means raw equality (no metamethods)
|
||||||
@@ -553,11 +570,11 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
case OP_LE: case OP_LT: case OP_EQ: {
|
case OP_LE: case OP_LT: case OP_EQ: {
|
||||||
int res = !l_isfalse(L->top - 1);
|
int res = !l_isfalse(L->top - 1);
|
||||||
L->top--;
|
L->top--;
|
||||||
/* metamethod should not be called when operand is K */
|
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
|
||||||
lua_assert(!ISK(GETARG_B(inst)));
|
lua_assert(op == OP_LE);
|
||||||
if (op == OP_LE && /* "<=" using "<" instead? */
|
ci->callstatus ^= CIST_LEQ; /* clear mark */
|
||||||
ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE)))
|
res = !res; /* negate result */
|
||||||
res = !res; /* invert result */
|
}
|
||||||
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
|
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
|
||||||
if (res != GETARG_A(inst)) /* condition failed? */
|
if (res != GETARG_A(inst)) /* condition failed? */
|
||||||
ci->u.l.savedpc++; /* skip jump instruction */
|
ci->u.l.savedpc++; /* skip jump instruction */
|
||||||
@@ -935,6 +952,7 @@ void luaV_execute (lua_State *L) {
|
|||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_JMP) {
|
vmcase(OP_JMP) {
|
||||||
|
lua_checksig(L);
|
||||||
dojump(ci, i, 0);
|
dojump(ci, i, 0);
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
@@ -987,6 +1005,7 @@ void luaV_execute (lua_State *L) {
|
|||||||
vmcase(OP_CALL) {
|
vmcase(OP_CALL) {
|
||||||
int b = GETARG_B(i);
|
int b = GETARG_B(i);
|
||||||
int nresults = GETARG_C(i) - 1;
|
int nresults = GETARG_C(i) - 1;
|
||||||
|
lua_checksig(L);
|
||||||
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
||||||
if (luaD_precall(L, ra, nresults)) { /* C function? */
|
if (luaD_precall(L, ra, nresults)) { /* C function? */
|
||||||
if (nresults >= 0) L->top = ci->top; /* adjust results */
|
if (nresults >= 0) L->top = ci->top; /* adjust results */
|
||||||
@@ -1001,6 +1020,7 @@ void luaV_execute (lua_State *L) {
|
|||||||
}
|
}
|
||||||
vmcase(OP_TAILCALL) {
|
vmcase(OP_TAILCALL) {
|
||||||
int b = GETARG_B(i);
|
int b = GETARG_B(i);
|
||||||
|
lua_checksig(L);
|
||||||
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
if (b != 0) L->top = ra+b; /* else previous instruction set top */
|
||||||
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
|
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
|
||||||
if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
|
if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
|
||||||
@@ -1111,6 +1131,7 @@ void luaV_execute (lua_State *L) {
|
|||||||
}
|
}
|
||||||
vmcase(OP_TFORLOOP) {
|
vmcase(OP_TFORLOOP) {
|
||||||
l_tforloop:
|
l_tforloop:
|
||||||
|
lua_checksig(L);
|
||||||
if (!ttisnil(ra + 1)) { /* continue loop? */
|
if (!ttisnil(ra + 1)) { /* continue loop? */
|
||||||
setobjs2s(L, ra, ra + 1); /* save control variable */
|
setobjs2s(L, ra, ra + 1); /* save control variable */
|
||||||
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
|
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
|
||||||
|
|||||||
27
HISTORY.md
27
HISTORY.md
@@ -1,3 +1,30 @@
|
|||||||
|
v1.0.0-alpha5 (2015-4-27)
|
||||||
|
-----------
|
||||||
|
* merge lua 5.3 offical bugfix
|
||||||
|
* improve sproto rpc api
|
||||||
|
* fix a deadlock bug when service retire
|
||||||
|
* improve cluster config reload
|
||||||
|
* add skynet.pcall for calling a function with `require`
|
||||||
|
* better error log in loginserver
|
||||||
|
|
||||||
|
v1.0.0-alpha4 (2015-4-13)
|
||||||
|
-----------
|
||||||
|
* sproto can share c struct between states
|
||||||
|
* udp api changed (use lua string now)
|
||||||
|
* fix memory leak in dns module
|
||||||
|
|
||||||
|
v1.0.0-alpha3 (2015-3-30)
|
||||||
|
-----------
|
||||||
|
* Update sproto (bugfix)
|
||||||
|
* Add async dns query
|
||||||
|
* improve httpc
|
||||||
|
|
||||||
|
v1.0.0-alpha2 (2015-3-16)
|
||||||
|
-----------
|
||||||
|
* Update examples client to lua 5.3
|
||||||
|
* Patch lua 5.3 to interrupt the dead loop (for debug)
|
||||||
|
* Update sproto (fix some bugs and support unordered map)
|
||||||
|
|
||||||
v1.0.0-alpha (2015-3-9)
|
v1.0.0-alpha (2015-3-9)
|
||||||
-----------
|
-----------
|
||||||
* Update lua from 5.2 to 5.3
|
* Update lua from 5.2 to 5.3
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2012-2014 codingnow.com
|
Copyright (c) 2012-2015 codingnow.com
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ skynet.start(function()
|
|||||||
local sdb = skynet.newservice("simpledb")
|
local sdb = skynet.newservice("simpledb")
|
||||||
skynet.name(".simpledb", sdb)
|
skynet.name(".simpledb", sdb)
|
||||||
print(skynet.call(".simpledb", "lua", "SET", "a", "foobar"))
|
print(skynet.call(".simpledb", "lua", "SET", "a", "foobar"))
|
||||||
|
print(skynet.call(".simpledb", "lua", "SET", "b", "foobar2"))
|
||||||
print(skynet.call(".simpledb", "lua", "GET", "a"))
|
print(skynet.call(".simpledb", "lua", "GET", "a"))
|
||||||
|
print(skynet.call(".simpledb", "lua", "GET", "b"))
|
||||||
cluster.open "db"
|
cluster.open "db"
|
||||||
|
cluster.open "db2"
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ skynet.start(function()
|
|||||||
local proxy = cluster.proxy("db", ".simpledb")
|
local proxy = cluster.proxy("db", ".simpledb")
|
||||||
print(skynet.call(proxy, "lua", "GET", "a"))
|
print(skynet.call(proxy, "lua", "GET", "a"))
|
||||||
print(cluster.call("db", ".simpledb", "GET", "a"))
|
print(cluster.call("db", ".simpledb", "GET", "a"))
|
||||||
|
print(cluster.call("db2", ".simpledb", "GET", "b"))
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
db = "127.0.0.1:2528"
|
db = "127.0.0.1:2528"
|
||||||
|
db2 = "127.0.0.1:2529"
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package.cpath = "luaclib/?.so"
|
|||||||
|
|
||||||
local socket = require "clientsocket"
|
local socket = require "clientsocket"
|
||||||
local crypt = require "crypt"
|
local crypt = require "crypt"
|
||||||
local bit32 = require "bit32"
|
|
||||||
|
if _VERSION ~= "Lua 5.3" then
|
||||||
|
error "Use lua 5.3"
|
||||||
|
end
|
||||||
|
|
||||||
local fd = assert(socket.connect("127.0.0.1", 8001))
|
local fd = assert(socket.connect("127.0.0.1", 8001))
|
||||||
|
|
||||||
@@ -93,26 +96,14 @@ print("login ok, subid=", subid)
|
|||||||
|
|
||||||
local function send_request(v, session)
|
local function send_request(v, session)
|
||||||
local size = #v + 4
|
local size = #v + 4
|
||||||
local package = string.char(bit32.extract(size,8,8))..
|
local package = string.pack(">I2", size)..v..string.pack(">I4", session)
|
||||||
string.char(bit32.extract(size,0,8))..
|
|
||||||
v..
|
|
||||||
string.char(bit32.extract(session,24,8))..
|
|
||||||
string.char(bit32.extract(session,16,8))..
|
|
||||||
string.char(bit32.extract(session,8,8))..
|
|
||||||
string.char(bit32.extract(session,0,8))
|
|
||||||
|
|
||||||
socket.send(fd, package)
|
socket.send(fd, package)
|
||||||
return v, session
|
return v, session
|
||||||
end
|
end
|
||||||
|
|
||||||
local function recv_response(v)
|
local function recv_response(v)
|
||||||
local content = v:sub(1,-6)
|
local size = #v - 5
|
||||||
local ok = v:sub(-5,-5):byte()
|
local content, ok, session = string.unpack("c"..tostring(size).."B>I4", v)
|
||||||
local session = 0
|
|
||||||
for i=-4,-1 do
|
|
||||||
local c = v:byte(i)
|
|
||||||
session = session + bit32.lshift(c,(-1-i) * 8)
|
|
||||||
end
|
|
||||||
return ok ~=0 , content, session
|
return ok ~=0 , content, session
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -132,11 +123,7 @@ end
|
|||||||
local readpackage = unpack_f(unpack_package)
|
local readpackage = unpack_f(unpack_package)
|
||||||
|
|
||||||
local function send_package(fd, pack)
|
local function send_package(fd, pack)
|
||||||
local size = #pack
|
local package = string.pack(">s2", pack)
|
||||||
local package = string.char(bit32.extract(size,8,8))..
|
|
||||||
string.char(bit32.extract(size,0,8))..
|
|
||||||
pack
|
|
||||||
|
|
||||||
socket.send(fd, package)
|
socket.send(fd, package)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ function CMD.logout(uid, subid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function server.command_handler(command, source, ...)
|
function server.command_handler(command, ...)
|
||||||
local f = assert(CMD[command])
|
local f = assert(CMD[command])
|
||||||
return f(source, ...)
|
return f(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
login(server)
|
login(server)
|
||||||
|
|||||||
@@ -602,11 +602,7 @@ read64(lua_State *L, uint32_t xx[2], uint32_t yy[2]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lhmac64(lua_State *L) {
|
pushqword(lua_State *L, uint32_t result[2]) {
|
||||||
uint32_t x[2], y[2];
|
|
||||||
read64(L, x, y);
|
|
||||||
uint32_t result[2];
|
|
||||||
hmac(x,y,result);
|
|
||||||
uint8_t tmp[8];
|
uint8_t tmp[8];
|
||||||
tmp[0] = result[0] & 0xff;
|
tmp[0] = result[0] & 0xff;
|
||||||
tmp[1] = (result[0] >> 8 )& 0xff;
|
tmp[1] = (result[0] >> 8 )& 0xff;
|
||||||
@@ -621,6 +617,40 @@ lhmac64(lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lhmac64(lua_State *L) {
|
||||||
|
uint32_t x[2], y[2];
|
||||||
|
read64(L, x, y);
|
||||||
|
uint32_t result[2];
|
||||||
|
hmac(x,y,result);
|
||||||
|
return pushqword(L, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
8bytes key
|
||||||
|
string text
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lhmac_hash(lua_State *L) {
|
||||||
|
uint32_t key[2];
|
||||||
|
size_t sz = 0;
|
||||||
|
const uint8_t *x = (const uint8_t *)luaL_checklstring(L, 1, &sz);
|
||||||
|
if (sz != 8) {
|
||||||
|
luaL_error(L, "Invalid uint64 key");
|
||||||
|
}
|
||||||
|
key[0] = x[0] | x[1]<<8 | x[2]<<16 | x[3]<<24;
|
||||||
|
key[1] = x[4] | x[5]<<8 | x[6]<<16 | x[7]<<24;
|
||||||
|
const char * text = luaL_checklstring(L, 2, &sz);
|
||||||
|
uint8_t h[8];
|
||||||
|
Hash(text,(int)sz,h);
|
||||||
|
uint32_t htext[2];
|
||||||
|
htext[0] = h[0] | h[1]<<8 | h[2]<<16 | h[3]<<24;
|
||||||
|
htext[1] = h[4] | h[5]<<8 | h[6]<<16 | h[7]<<24;
|
||||||
|
uint32_t result[2];
|
||||||
|
hmac(htext,key,result);
|
||||||
|
return pushqword(L, result);
|
||||||
|
}
|
||||||
|
|
||||||
// powmodp64 for DH-key exchange
|
// powmodp64 for DH-key exchange
|
||||||
|
|
||||||
// The biggest 64bit prime
|
// The biggest 64bit prime
|
||||||
@@ -858,6 +888,7 @@ luaopen_crypt(lua_State *L) {
|
|||||||
{ "base64decode", lb64decode },
|
{ "base64decode", lb64decode },
|
||||||
{ "sha1", lsha1 },
|
{ "sha1", lsha1 },
|
||||||
{ "hmac_sha1", lhmac_sha1 },
|
{ "hmac_sha1", lhmac_sha1 },
|
||||||
|
{ "hmac_hash", lhmac_hash },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
luaL_newlib(L,l);
|
luaL_newlib(L,l);
|
||||||
|
|||||||
@@ -140,11 +140,11 @@ The schema text is like this:
|
|||||||
}
|
}
|
||||||
|
|
||||||
.AddressBook {
|
.AddressBook {
|
||||||
person 0 : *Person
|
person 0 : *Person(id) # (id) is optional, means Person.id is main index.
|
||||||
}
|
}
|
||||||
|
|
||||||
foobar 1 { # define a new protocol (for RPC used) with tag 1
|
foobar 1 { # define a new protocol (for RPC used) with tag 1
|
||||||
request person # Associate the type person with foobar.request
|
request Person # Associate the type Person with foobar.request
|
||||||
response { # define the foobar.response type
|
response { # define the foobar.response type
|
||||||
ok 0 : boolean
|
ok 0 : boolean
|
||||||
}
|
}
|
||||||
@@ -161,6 +161,7 @@ A schema text can be self-described by the sproto schema language.
|
|||||||
type 1 : string
|
type 1 : string
|
||||||
id 2 : integer
|
id 2 : integer
|
||||||
array 3 : boolean
|
array 3 : boolean
|
||||||
|
key 4 : integer # optional tag for map
|
||||||
}
|
}
|
||||||
name 0 : string
|
name 0 : string
|
||||||
fields 1 : *field
|
fields 1 : *field
|
||||||
@@ -183,10 +184,12 @@ Types
|
|||||||
=======
|
=======
|
||||||
|
|
||||||
* **string** : binary string
|
* **string** : binary string
|
||||||
* **integer** : integer, the max length of a integer is signed 64bit.
|
* **integer** : integer, the max length of an integer is signed 64bit.
|
||||||
* **boolean** : true or false
|
* **boolean** : true or false
|
||||||
|
|
||||||
You can add * before the typename to declare an array.
|
You can add * before the typename to declare an array.
|
||||||
|
|
||||||
|
You can also specify a main index, the array whould be encode as an unordered map.
|
||||||
|
|
||||||
User defined type can be any name in alphanumeric characters except the build-in typenames, and nested types are supported.
|
User defined type can be any name in alphanumeric characters except the build-in typenames, and nested types are supported.
|
||||||
|
|
||||||
@@ -319,7 +322,19 @@ struct sproto_type * sproto_type(struct sproto *, const char * typename);
|
|||||||
Query the type object from a sproto object:
|
Query the type object from a sproto object:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
typedef int (*sproto_callback)(void *ud, const char *tagname, int type, int index, struct sproto_type *, void *value, int length);
|
struct sproto_arg {
|
||||||
|
void *ud;
|
||||||
|
const char *tagname;
|
||||||
|
int tagid;
|
||||||
|
int type;
|
||||||
|
struct sproto_type *subtype;
|
||||||
|
void *value;
|
||||||
|
int length;
|
||||||
|
int index; // array base 1
|
||||||
|
int mainindex; // for map
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (*sproto_callback)(const struct sproto_arg *args);
|
||||||
|
|
||||||
int sproto_decode(struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud);
|
int sproto_decode(struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud);
|
||||||
int sproto_encode(struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud);
|
int sproto_encode(struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud);
|
||||||
@@ -334,13 +349,9 @@ int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz);
|
|||||||
|
|
||||||
pack and unpack the message with the 0 packing algorithm.
|
pack and unpack the message with the 0 packing algorithm.
|
||||||
|
|
||||||
JIT
|
Other Implementions and bindings
|
||||||
=====
|
=====
|
||||||
You may also interest in https://github.com/lvzixun/sproto-JIT
|
See Wiki https://github.com/cloudwu/sproto/wiki
|
||||||
|
|
||||||
C# version
|
|
||||||
=====
|
|
||||||
https://github.com/lvzixun/sproto-Csharp
|
|
||||||
|
|
||||||
Question?
|
Question?
|
||||||
==========
|
==========
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#define MAX_GLOBALSPROTO 16
|
#define MAX_GLOBALSPROTO 16
|
||||||
#define ENCODE_BUFFERSIZE 2050
|
#define ENCODE_BUFFERSIZE 2050
|
||||||
|
|
||||||
//#define ENCODE_BUFFERSIZE 2050
|
|
||||||
#define ENCODE_MAXSIZE 0x1000000
|
#define ENCODE_MAXSIZE 0x1000000
|
||||||
#define ENCODE_DEEPLEVEL 64
|
#define ENCODE_DEEPLEVEL 64
|
||||||
|
|
||||||
@@ -40,17 +39,18 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
|||||||
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LUA_VERSION_NUM < 503
|
||||||
|
|
||||||
|
// lua_isinteger is lua 5.3 api
|
||||||
|
#define lua_isinteger lua_isnumber
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lnewproto(lua_State *L) {
|
lnewproto(lua_State *L) {
|
||||||
size_t sz = 0;
|
|
||||||
void * buffer;
|
|
||||||
struct sproto * sp;
|
struct sproto * sp;
|
||||||
if (lua_isuserdata(L,1)) {
|
size_t sz;
|
||||||
buffer = lua_touserdata(L,1);
|
void * buffer = (void *)luaL_checklstring(L,1,&sz);
|
||||||
sz = luaL_checkinteger(L,2);
|
|
||||||
} else {
|
|
||||||
buffer = (void *)luaL_checklstring(L,1,&sz);
|
|
||||||
}
|
|
||||||
sp = sproto_create(buffer, sz);
|
sp = sproto_create(buffer, sz);
|
||||||
if (sp) {
|
if (sp) {
|
||||||
lua_pushlightuserdata(L, sp);
|
lua_pushlightuserdata(L, sp);
|
||||||
@@ -94,18 +94,20 @@ struct encode_ud {
|
|||||||
const char * array_tag;
|
const char * array_tag;
|
||||||
int array_index;
|
int array_index;
|
||||||
int deep;
|
int deep;
|
||||||
|
int iter_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
encode(void *ud, const char *tagname, int type, int index, struct sproto_type *st, void *value, int length) {
|
encode(const struct sproto_arg *args) {
|
||||||
struct encode_ud *self = ud;
|
struct encode_ud *self = args->ud;
|
||||||
lua_State *L = self->L;
|
lua_State *L = self->L;
|
||||||
if (self->deep >= ENCODE_DEEPLEVEL)
|
if (self->deep >= ENCODE_DEEPLEVEL)
|
||||||
return luaL_error(L, "The table is too deep");
|
return luaL_error(L, "The table is too deep");
|
||||||
if (index > 0) {
|
if (args->index > 0) {
|
||||||
if (tagname != self->array_tag) {
|
if (args->tagname != self->array_tag) {
|
||||||
self->array_tag = tagname;
|
// a new array
|
||||||
lua_getfield(L, self->tbl_index, tagname);
|
self->array_tag = args->tagname;
|
||||||
|
lua_getfield(L, self->tbl_index, args->tagname);
|
||||||
if (lua_isnil(L, -1)) {
|
if (lua_isnil(L, -1)) {
|
||||||
if (self->array_index) {
|
if (self->array_index) {
|
||||||
lua_replace(L, self->array_index);
|
lua_replace(L, self->array_index);
|
||||||
@@ -113,66 +115,108 @@ encode(void *ud, const char *tagname, int type, int index, struct sproto_type *s
|
|||||||
self->array_index = 0;
|
self->array_index = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
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) {
|
if (self->array_index) {
|
||||||
lua_replace(L, self->array_index);
|
lua_replace(L, self->array_index);
|
||||||
} else {
|
} else {
|
||||||
self->array_index = lua_gettop(L);
|
self->array_index = lua_gettop(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_rawgeti(L, self->array_index, index);
|
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)) {
|
||||||
|
// iterate end
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_replace(L, self->iter_index);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lua_insert(L, -2);
|
||||||
|
lua_replace(L, self->iter_index);
|
||||||
|
} else {
|
||||||
|
lua_rawgeti(L, self->array_index, args->index);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
lua_getfield(L, self->tbl_index, tagname);
|
lua_getfield(L, self->tbl_index, args->tagname);
|
||||||
}
|
}
|
||||||
if (lua_isnil(L, -1)) {
|
if (lua_isnil(L, -1)) {
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (args->type) {
|
||||||
case SPROTO_TINTEGER: {
|
case SPROTO_TINTEGER: {
|
||||||
lua_Integer v = luaL_checkinteger(L, -1);
|
lua_Integer v;
|
||||||
lua_Integer vh;
|
lua_Integer vh;
|
||||||
|
if (!lua_isinteger(L, -1)) {
|
||||||
|
return luaL_error(L, ".%s[%d] is not an integer (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
} else {
|
||||||
|
v = lua_tointeger(L, -1);
|
||||||
|
}
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
// notice: in lua 5.2, lua_Integer maybe 52bit
|
// notice: in lua 5.2, lua_Integer maybe 52bit
|
||||||
vh = v >> 31;
|
vh = v >> 31;
|
||||||
if (vh == 0 || vh == -1) {
|
if (vh == 0 || vh == -1) {
|
||||||
*(uint32_t *)value = (uint32_t)v;
|
*(uint32_t *)args->value = (uint32_t)v;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*(uint64_t *)value = (uint64_t)v;
|
*(uint64_t *)args->value = (uint64_t)v;
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case SPROTO_TBOOLEAN: {
|
case SPROTO_TBOOLEAN: {
|
||||||
int v = lua_toboolean(L, -1);
|
int v = lua_toboolean(L, -1);
|
||||||
*(int *)value = v;
|
if (!lua_isboolean(L,-1)) {
|
||||||
|
return luaL_error(L, ".%s[%d] is not a boolean (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
}
|
||||||
|
*(int *)args->value = v;
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRING: {
|
case SPROTO_TSTRING: {
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
const char * str = luaL_checklstring(L, -1, &sz);
|
const char * str;
|
||||||
if (sz > length)
|
if (!lua_isstring(L, -1)) {
|
||||||
|
return luaL_error(L, ".%s[%d] is not a string (Is a %s)",
|
||||||
|
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
|
||||||
|
} else {
|
||||||
|
str = lua_tolstring(L, -1, &sz);
|
||||||
|
}
|
||||||
|
if (sz > args->length)
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(value, str, sz);
|
memcpy(args->value, str, sz);
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
return sz;
|
return sz + 1; // The length of empty string is 1.
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRUCT: {
|
case SPROTO_TSTRUCT: {
|
||||||
struct encode_ud sub;
|
struct encode_ud sub;
|
||||||
int r;
|
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.L = L;
|
||||||
sub.st = st;
|
sub.st = args->subtype;
|
||||||
sub.tbl_index = lua_gettop(L);
|
sub.tbl_index = top;
|
||||||
sub.array_tag = NULL;
|
sub.array_tag = NULL;
|
||||||
sub.array_index = 0;
|
sub.array_index = 0;
|
||||||
sub.deep = self->deep + 1;
|
sub.deep = self->deep + 1;
|
||||||
r = sproto_encode(st, value, length, encode, &sub);
|
lua_pushnil(L); // prepare an iterator slot
|
||||||
lua_pop(L,1);
|
sub.iter_index = sub.tbl_index + 1;
|
||||||
|
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
|
||||||
|
lua_settop(L, top-1); // pop the value
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return luaL_error(L, "Invalid field type %d", type);
|
return luaL_error(L, "Invalid field type %d", args->type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,21 +249,27 @@ lencode(lua_State *L) {
|
|||||||
struct encode_ud self;
|
struct encode_ud self;
|
||||||
void * buffer = lua_touserdata(L, lua_upvalueindex(1));
|
void * buffer = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
int sz = lua_tointeger(L, lua_upvalueindex(2));
|
int sz = lua_tointeger(L, lua_upvalueindex(2));
|
||||||
|
int tbl_index = 2;
|
||||||
struct sproto_type * st = lua_touserdata(L, 1);
|
struct sproto_type * st = lua_touserdata(L, 1);
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
return luaL_argerror(L, 1, "Need a sproto_type object");
|
return luaL_argerror(L, 1, "Need a sproto_type object");
|
||||||
}
|
}
|
||||||
luaL_checktype(L, 2, LUA_TTABLE);
|
luaL_checktype(L, tbl_index, LUA_TTABLE);
|
||||||
luaL_checkstack(L, ENCODE_DEEPLEVEL + 8, NULL);
|
luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL);
|
||||||
self.L = L;
|
self.L = L;
|
||||||
self.st = st;
|
self.st = st;
|
||||||
self.tbl_index = 2;
|
self.tbl_index = tbl_index;
|
||||||
self.array_tag = NULL;
|
|
||||||
self.array_index = 0;
|
|
||||||
self.deep = 0;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int r = sproto_encode(st, buffer, sz, encode, &self);
|
int r;
|
||||||
|
self.array_tag = NULL;
|
||||||
|
self.array_index = 0;
|
||||||
|
self.deep = 0;
|
||||||
|
|
||||||
|
lua_settop(L, tbl_index);
|
||||||
|
lua_pushnil(L); // for iterator (stack slot 3)
|
||||||
|
self.iter_index = tbl_index+1;
|
||||||
|
|
||||||
|
r = sproto_encode(st, buffer, sz, encode, &self);
|
||||||
if (r<0) {
|
if (r<0) {
|
||||||
buffer = expand_buffer(L, sz, sz*2);
|
buffer = expand_buffer(L, sz, sz*2);
|
||||||
sz *= 2;
|
sz *= 2;
|
||||||
@@ -236,21 +286,23 @@ struct decode_ud {
|
|||||||
int array_index;
|
int array_index;
|
||||||
int result_index;
|
int result_index;
|
||||||
int deep;
|
int deep;
|
||||||
|
int mainindex_tag;
|
||||||
|
int key_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
decode(void *ud, const char *tagname, int type, int index, struct sproto_type *st, void *value, int length) {
|
decode(const struct sproto_arg *args) {
|
||||||
struct decode_ud * self = ud;
|
struct decode_ud * self = args->ud;
|
||||||
lua_State *L = self->L;
|
lua_State *L = self->L;
|
||||||
if (self->deep >= ENCODE_DEEPLEVEL)
|
if (self->deep >= ENCODE_DEEPLEVEL)
|
||||||
return luaL_error(L, "The table is too deep");
|
return luaL_error(L, "The table is too deep");
|
||||||
if (index > 0) {
|
if (args->index > 0) {
|
||||||
// It's array
|
// It's array
|
||||||
if (tagname != self->array_tag) {
|
if (args->tagname != self->array_tag) {
|
||||||
self->array_tag = tagname;
|
self->array_tag = args->tagname;
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
lua_pushvalue(L, -1);
|
lua_pushvalue(L, -1);
|
||||||
lua_setfield(L, self->result_index, tagname);
|
lua_setfield(L, self->result_index, args->tagname);
|
||||||
if (self->array_index) {
|
if (self->array_index) {
|
||||||
lua_replace(L, self->array_index);
|
lua_replace(L, self->array_index);
|
||||||
} else {
|
} else {
|
||||||
@@ -258,20 +310,20 @@ decode(void *ud, const char *tagname, int type, int index, struct sproto_type *s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (args->type) {
|
||||||
case SPROTO_TINTEGER: {
|
case SPROTO_TINTEGER: {
|
||||||
// notice: in lua 5.2, 52bit integer support (not 64)
|
// notice: in lua 5.2, 52bit integer support (not 64)
|
||||||
lua_Integer v = *(uint64_t*)value;
|
lua_Integer v = *(uint64_t*)args->value;
|
||||||
lua_pushinteger(L, v);
|
lua_pushinteger(L, v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPROTO_TBOOLEAN: {
|
case SPROTO_TBOOLEAN: {
|
||||||
int v = *(uint64_t*)value;
|
int v = *(uint64_t*)args->value;
|
||||||
lua_pushboolean(L,v);
|
lua_pushboolean(L,v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRING: {
|
case SPROTO_TSTRING: {
|
||||||
lua_pushlstring(L, value, length);
|
lua_pushlstring(L, args->value, args->length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRUCT: {
|
case SPROTO_TSTRUCT: {
|
||||||
@@ -283,20 +335,47 @@ decode(void *ud, const char *tagname, int type, int index, struct sproto_type *s
|
|||||||
sub.deep = self->deep + 1;
|
sub.deep = self->deep + 1;
|
||||||
sub.array_index = 0;
|
sub.array_index = 0;
|
||||||
sub.array_tag = NULL;
|
sub.array_tag = NULL;
|
||||||
|
if (args->mainindex >= 0) {
|
||||||
|
// This struct will set into a map, so mark the main index tag.
|
||||||
|
sub.mainindex_tag = args->mainindex;
|
||||||
|
lua_pushnil(L);
|
||||||
|
sub.key_index = lua_gettop(L);
|
||||||
|
|
||||||
r = sproto_decode(st, value, length, decode, &sub);
|
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
|
||||||
if (r < 0 || r != length)
|
if (r < 0 || r != args->length)
|
||||||
return r;
|
return r;
|
||||||
lua_settop(L, sub.result_index);
|
// assert(args->index > 0);
|
||||||
break;
|
lua_pushvalue(L, sub.key_index);
|
||||||
|
if (lua_isnil(L, -1)) {
|
||||||
|
luaL_error(L, "Can't find main index (tag=%d) in [%s]", args->mainindex, args->tagname);
|
||||||
|
}
|
||||||
|
lua_pushvalue(L, sub.result_index);
|
||||||
|
lua_rawset(L, self->array_index);
|
||||||
|
lua_settop(L, sub.result_index-1);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
sub.mainindex_tag = -1;
|
||||||
|
sub.key_index = 0;
|
||||||
|
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
|
||||||
|
if (r < 0 || r != args->length)
|
||||||
|
return r;
|
||||||
|
lua_settop(L, sub.result_index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
luaL_error(L, "Invalid type");
|
luaL_error(L, "Invalid type");
|
||||||
}
|
}
|
||||||
if (index > 0) {
|
if (args->index > 0) {
|
||||||
lua_rawseti(L, self->array_index, index);
|
lua_rawseti(L, self->array_index, args->index);
|
||||||
} else {
|
} else {
|
||||||
lua_setfield(L, self->result_index, tagname);
|
if (self->mainindex_tag == args->tagid) {
|
||||||
|
// This tag is marked, save the value to key_index
|
||||||
|
// assert(self->key_index > 0);
|
||||||
|
lua_pushvalue(L,-1);
|
||||||
|
lua_replace(L, self->key_index);
|
||||||
|
}
|
||||||
|
lua_setfield(L, self->result_index, args->tagname);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -339,12 +418,14 @@ ldecode(lua_State *L) {
|
|||||||
if (!lua_istable(L, -1)) {
|
if (!lua_istable(L, -1)) {
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
}
|
}
|
||||||
luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL);
|
luaL_checkstack(L, ENCODE_DEEPLEVEL*3 + 8, NULL);
|
||||||
self.L = L;
|
self.L = L;
|
||||||
self.result_index = lua_gettop(L);
|
self.result_index = lua_gettop(L);
|
||||||
self.array_index = 0;
|
self.array_index = 0;
|
||||||
self.array_tag = NULL;
|
self.array_tag = NULL;
|
||||||
self.deep = 0;
|
self.deep = 0;
|
||||||
|
self.mainindex_tag = -1;
|
||||||
|
self.key_index = 0;
|
||||||
r = sproto_decode(st, buffer, (int)sz, decode, &self);
|
r = sproto_decode(st, buffer, (int)sz, decode, &self);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return luaL_error(L, "decode error");
|
return luaL_error(L, "decode error");
|
||||||
@@ -458,48 +539,38 @@ lprotocol(lua_State *L) {
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* global sproto pointer for multi states */
|
/* global sproto pointer for multi states
|
||||||
struct sproto_bin {
|
NOTICE : It is not thread safe
|
||||||
void *ptr;
|
*/
|
||||||
size_t sz;
|
static struct sproto * G_sproto[MAX_GLOBALSPROTO];
|
||||||
};
|
|
||||||
|
|
||||||
static struct sproto_bin G_sproto[MAX_GLOBALSPROTO];
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lsaveproto(lua_State *L) {
|
lsaveproto(lua_State *L) {
|
||||||
size_t sz;
|
struct sproto * sp = lua_touserdata(L, 1);
|
||||||
void * buffer = (void *)luaL_checklstring(L,1,&sz);
|
|
||||||
int index = luaL_optinteger(L, 2, 0);
|
int index = luaL_optinteger(L, 2, 0);
|
||||||
void * tmp;
|
|
||||||
struct sproto_bin * sbin = &G_sproto[index];
|
|
||||||
if (index < 0 || index >= MAX_GLOBALSPROTO) {
|
if (index < 0 || index >= MAX_GLOBALSPROTO) {
|
||||||
return luaL_error(L, "Invalid global slot index %d", index);
|
return luaL_error(L, "Invalid global slot index %d", index);
|
||||||
}
|
}
|
||||||
tmp = malloc(sz);
|
/* TODO : release old object (memory leak now, but thread safe)*/
|
||||||
memcpy(tmp, buffer, sz);
|
G_sproto[index] = sp;
|
||||||
if (sbin->ptr) {
|
|
||||||
free(sbin->ptr);
|
|
||||||
}
|
|
||||||
sbin->ptr = tmp;
|
|
||||||
sbin->sz = sz;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lloadproto(lua_State *L) {
|
lloadproto(lua_State *L) {
|
||||||
int index = luaL_optinteger(L, 1, 0);
|
int index = luaL_optinteger(L, 1, 0);
|
||||||
struct sproto_bin * sbin = &G_sproto[index];
|
struct sproto * sp;
|
||||||
if (index < 0 || index >= MAX_GLOBALSPROTO) {
|
if (index < 0 || index >= MAX_GLOBALSPROTO) {
|
||||||
return luaL_error(L, "Invalid global slot index %d", index);
|
return luaL_error(L, "Invalid global slot index %d", index);
|
||||||
}
|
}
|
||||||
if (sbin->ptr == NULL) {
|
sp = G_sproto[index];
|
||||||
|
if (sp == NULL) {
|
||||||
return luaL_error(L, "nil sproto at index %d", index);
|
return luaL_error(L, "nil sproto at index %d", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pushlightuserdata(L, sbin->ptr);
|
lua_pushlightuserdata(L, sp);
|
||||||
lua_pushinteger(L, sbin->sz);
|
|
||||||
return 2;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ struct field {
|
|||||||
int type;
|
int type;
|
||||||
const char * name;
|
const char * name;
|
||||||
struct sproto_type * st;
|
struct sproto_type * st;
|
||||||
|
int key;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sproto_type {
|
struct sproto_type {
|
||||||
@@ -188,6 +189,7 @@ import_field(struct sproto *s, struct field *f, const uint8_t * stream) {
|
|||||||
f->type = -1;
|
f->type = -1;
|
||||||
f->name = NULL;
|
f->name = NULL;
|
||||||
f->st = NULL;
|
f->st = NULL;
|
||||||
|
f->key = -1;
|
||||||
|
|
||||||
sz = todword(stream);
|
sz = todword(stream);
|
||||||
stream += SIZEOF_LENGTH;
|
stream += SIZEOF_LENGTH;
|
||||||
@@ -234,6 +236,9 @@ import_field(struct sproto *s, struct field *f, const uint8_t * stream) {
|
|||||||
if (value)
|
if (value)
|
||||||
array = SPROTO_TARRAY;
|
array = SPROTO_TARRAY;
|
||||||
break;
|
break;
|
||||||
|
case 5: // key
|
||||||
|
f->key = value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -485,7 +490,11 @@ sproto_dump(struct sproto *s) {
|
|||||||
type_name = buildin[t];
|
type_name = buildin[t];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\t%s (%d) %s%s\n", f->name, f->tag, array, type_name);
|
if (f->key >= 0) {
|
||||||
|
printf("\t%s (%d) %s%s(%d)\n", f->name, f->tag, array, type_name, f->key);
|
||||||
|
} else {
|
||||||
|
printf("\t%s (%d) %s%s\n", f->name, f->tag, array, type_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("=== %d protocol ===\n", s->protocol_n);
|
printf("=== %d protocol ===\n", s->protocol_n);
|
||||||
@@ -501,7 +510,7 @@ sproto_dump(struct sproto *s) {
|
|||||||
|
|
||||||
// query
|
// query
|
||||||
int
|
int
|
||||||
sproto_prototag(struct sproto *sp, const char * name) {
|
sproto_prototag(const struct sproto *sp, const char * name) {
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<sp->protocol_n;i++) {
|
for (i=0;i<sp->protocol_n;i++) {
|
||||||
if (strcmp(name, sp->proto[i].name) == 0) {
|
if (strcmp(name, sp->proto[i].name) == 0) {
|
||||||
@@ -512,7 +521,7 @@ sproto_prototag(struct sproto *sp, const char * name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct protocol *
|
static struct protocol *
|
||||||
query_proto(struct sproto *sp, int tag) {
|
query_proto(const struct sproto *sp, int tag) {
|
||||||
int begin = 0, end = sp->protocol_n;
|
int begin = 0, end = sp->protocol_n;
|
||||||
while(begin<end) {
|
while(begin<end) {
|
||||||
int mid = (begin+end)/2;
|
int mid = (begin+end)/2;
|
||||||
@@ -530,7 +539,7 @@ query_proto(struct sproto *sp, int tag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sproto_type *
|
struct sproto_type *
|
||||||
sproto_protoquery(struct sproto *sp, int proto, int what) {
|
sproto_protoquery(const struct sproto *sp, int proto, int what) {
|
||||||
struct protocol * p;
|
struct protocol * p;
|
||||||
if (what <0 || what >1) {
|
if (what <0 || what >1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -543,7 +552,7 @@ sproto_protoquery(struct sproto *sp, int proto, int what) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
sproto_protoname(struct sproto *sp, int proto) {
|
sproto_protoname(const struct sproto *sp, int proto) {
|
||||||
struct protocol * p = query_proto(sp, proto);
|
struct protocol * p = query_proto(sp, proto);
|
||||||
if (p) {
|
if (p) {
|
||||||
return p->name;
|
return p->name;
|
||||||
@@ -552,7 +561,7 @@ sproto_protoname(struct sproto *sp, int proto) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sproto_type *
|
struct sproto_type *
|
||||||
sproto_type(struct sproto *sp, const char * type_name) {
|
sproto_type(const struct sproto *sp, const char * type_name) {
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<sp->type_n;i++) {
|
for (i=0;i<sp->type_n;i++) {
|
||||||
if (strcmp(type_name, sp->type[i].name) == 0) {
|
if (strcmp(type_name, sp->type[i].name) == 0) {
|
||||||
@@ -568,7 +577,7 @@ sproto_name(struct sproto_type * st) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct field *
|
static struct field *
|
||||||
findtag(struct sproto_type *st, int tag) {
|
findtag(const struct sproto_type *st, int tag) {
|
||||||
int begin, end;
|
int begin, end;
|
||||||
if (st->base >=0 ) {
|
if (st->base >=0 ) {
|
||||||
tag -= st->base;
|
tag -= st->base;
|
||||||
@@ -600,10 +609,6 @@ findtag(struct sproto_type *st, int tag) {
|
|||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
fill_size(uint8_t * data, int sz) {
|
fill_size(uint8_t * data, int sz) {
|
||||||
if (sz < 0)
|
|
||||||
return -1;
|
|
||||||
if (sz == 0)
|
|
||||||
return 0;
|
|
||||||
data[0] = sz & 0xff;
|
data[0] = sz & 0xff;
|
||||||
data[1] = (sz >> 8) & 0xff;
|
data[1] = (sz >> 8) & 0xff;
|
||||||
data[2] = (sz >> 16) & 0xff;
|
data[2] = (sz >> 16) & 0xff;
|
||||||
@@ -637,22 +642,42 @@ encode_uint64(uint64_t v, uint8_t * data, int size) {
|
|||||||
return fill_size(data, sizeof(v));
|
return fill_size(data, sizeof(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//#define CB(tagname,type,index,subtype,value,length) cb(ud, tagname,type,index,subtype,value,length)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
encode_string(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int size) {
|
do_cb(sproto_callback cb, void *ud, const char *tagname, int type, int index, struct sproto_type *subtype, void *value, int length) {
|
||||||
|
if (subtype) {
|
||||||
|
if (type >= 0) {
|
||||||
|
printf("callback: tag=%s[%d], subtype[%s]:%d\n",tagname,index, subtype->name, type);
|
||||||
|
} else {
|
||||||
|
printf("callback: tag=%s[%d], subtype[%s]\n",tagname,index, subtype->name);
|
||||||
|
}
|
||||||
|
} else if (index > 0) {
|
||||||
|
printf("callback: tag=%s[%d]\n",tagname,index);
|
||||||
|
} else if (index == 0) {
|
||||||
|
printf("callback: tag=%s\n",tagname);
|
||||||
|
} else {
|
||||||
|
printf("callback: tag=%s [mainkey]\n",tagname);
|
||||||
|
}
|
||||||
|
return cb(ud, tagname,type,index,subtype,value,length);
|
||||||
|
}
|
||||||
|
#define CB(tagname,type,index,subtype,value,length) do_cb(cb,ud, tagname,type,index,subtype,value,length)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) {
|
||||||
int sz;
|
int sz;
|
||||||
if (size < SIZEOF_LENGTH)
|
if (size < SIZEOF_LENGTH)
|
||||||
return -1;
|
return -1;
|
||||||
sz = cb(ud, f->name, SPROTO_TSTRING, 0, NULL, data+SIZEOF_LENGTH, size-SIZEOF_LENGTH);
|
args->value = data+SIZEOF_LENGTH;
|
||||||
return fill_size(data, sz);
|
args->length = size-SIZEOF_LENGTH;
|
||||||
}
|
sz = cb(args);
|
||||||
|
if (sz <= 0)
|
||||||
static int
|
return sz;
|
||||||
encode_struct(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int size) {
|
if (args->type == SPROTO_TSTRING) {
|
||||||
int sz;
|
--sz; // the length of null string is 1
|
||||||
if (size < SIZEOF_LENGTH) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
sz = cb(ud, f->name, SPROTO_TSTRUCT, 0, f->st, data+SIZEOF_LENGTH, size-SIZEOF_LENGTH);
|
|
||||||
return fill_size(data, sz);
|
return fill_size(data, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +697,7 @@ uint32_to_uint64(int negative, uint8_t *buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *
|
static uint8_t *
|
||||||
encode_integer_array(sproto_callback cb, void *ud, struct field *f, uint8_t *buffer, int size) {
|
encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size) {
|
||||||
uint8_t * header = buffer;
|
uint8_t * header = buffer;
|
||||||
int intlen;
|
int intlen;
|
||||||
int index;
|
int index;
|
||||||
@@ -688,10 +713,13 @@ encode_integer_array(sproto_callback cb, void *ud, struct field *f, uint8_t *buf
|
|||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
} u;
|
} u;
|
||||||
sz = cb(ud, f->name, SPROTO_TINTEGER, index, f->st, &u, sizeof(u));
|
args->value = &u;
|
||||||
|
args->length = sizeof(u);
|
||||||
|
args->index = index;
|
||||||
|
sz = cb(args);
|
||||||
if (sz < 0)
|
if (sz < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (sz == 0)
|
if (sz == 0) // nil object, end of array
|
||||||
break;
|
break;
|
||||||
if (size < sizeof(uint64_t))
|
if (size < sizeof(uint64_t))
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -749,65 +777,70 @@ encode_integer_array(sproto_callback cb, void *ud, struct field *f, uint8_t *buf
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
encode_array(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int size) {
|
encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) {
|
||||||
uint8_t * buffer;
|
uint8_t * buffer;
|
||||||
int index;
|
|
||||||
int type;
|
|
||||||
int sz;
|
int sz;
|
||||||
if (size < SIZEOF_LENGTH)
|
if (size < SIZEOF_LENGTH)
|
||||||
return -1;
|
return -1;
|
||||||
size -= SIZEOF_LENGTH;
|
size -= SIZEOF_LENGTH;
|
||||||
index = 1;
|
|
||||||
buffer = data + SIZEOF_LENGTH;
|
buffer = data + SIZEOF_LENGTH;
|
||||||
type = f->type & ~SPROTO_TARRAY;
|
switch (args->type) {
|
||||||
switch (type) {
|
|
||||||
case SPROTO_TINTEGER:
|
case SPROTO_TINTEGER:
|
||||||
buffer = encode_integer_array(cb,ud,f,buffer,size);
|
buffer = encode_integer_array(cb,args,buffer,size);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case SPROTO_TBOOLEAN:
|
case SPROTO_TBOOLEAN:
|
||||||
|
args->index = 1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
int sz = cb(ud, f->name, type, index, f->st, &v, sizeof(v));
|
args->value = &v;
|
||||||
|
args->length = sizeof(v);
|
||||||
|
sz = cb(args);
|
||||||
if (sz < 0)
|
if (sz < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (sz == 0)
|
if (sz == 0) // nil object , end of array
|
||||||
break;
|
break;
|
||||||
if (size < 1)
|
if (size < 1)
|
||||||
return -1;
|
return -1;
|
||||||
buffer[0] = v ? 1: 0;
|
buffer[0] = v ? 1: 0;
|
||||||
size -= 1;
|
size -= 1;
|
||||||
buffer += 1;
|
buffer += 1;
|
||||||
index++;
|
++args->index;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
args->index = 1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int sz;
|
|
||||||
if (size < SIZEOF_LENGTH)
|
if (size < SIZEOF_LENGTH)
|
||||||
return -1;
|
return -1;
|
||||||
size -= SIZEOF_LENGTH;
|
size -= SIZEOF_LENGTH;
|
||||||
sz = cb(ud, f->name, type, index, f->st, buffer+SIZEOF_LENGTH, size);
|
args->value = buffer+SIZEOF_LENGTH;
|
||||||
if (sz < 0)
|
args->length = size;
|
||||||
return -1;
|
sz = cb(args);
|
||||||
if (sz == 0)
|
if (sz == 0)
|
||||||
break;
|
break;
|
||||||
|
if (sz < 0)
|
||||||
|
return -1;
|
||||||
|
if (args->type == SPROTO_TSTRING) {
|
||||||
|
--sz;
|
||||||
|
}
|
||||||
fill_size(buffer, sz);
|
fill_size(buffer, sz);
|
||||||
buffer += SIZEOF_LENGTH+sz;
|
buffer += SIZEOF_LENGTH+sz;
|
||||||
size -=sz;
|
size -=sz;
|
||||||
index ++;
|
++args->index;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sz = buffer - (data + SIZEOF_LENGTH);
|
sz = buffer - (data + SIZEOF_LENGTH);
|
||||||
if (sz == 0)
|
if (sz == 0) // empty array
|
||||||
return 0;
|
return 0;
|
||||||
return fill_size(data, sz);
|
return fill_size(data, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) {
|
sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) {
|
||||||
|
struct sproto_arg args;
|
||||||
uint8_t * header = buffer;
|
uint8_t * header = buffer;
|
||||||
uint8_t * data;
|
uint8_t * data;
|
||||||
int header_sz = SIZEOF_HEADER + st->maxn * SIZEOF_FIELD;
|
int header_sz = SIZEOF_HEADER + st->maxn * SIZEOF_FIELD;
|
||||||
@@ -817,6 +850,7 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c
|
|||||||
int datasz;
|
int datasz;
|
||||||
if (size < header_sz)
|
if (size < header_sz)
|
||||||
return -1;
|
return -1;
|
||||||
|
args.ud = ud;
|
||||||
data = header + header_sz;
|
data = header + header_sz;
|
||||||
size -= header_sz;
|
size -= header_sz;
|
||||||
index = 0;
|
index = 0;
|
||||||
@@ -826,9 +860,16 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c
|
|||||||
int type = f->type;
|
int type = f->type;
|
||||||
int value = 0;
|
int value = 0;
|
||||||
int sz = -1;
|
int sz = -1;
|
||||||
|
args.tagname = f->name;
|
||||||
|
args.tagid = f->tag;
|
||||||
|
args.subtype = f->st;
|
||||||
|
args.mainindex = f->key;
|
||||||
if (type & SPROTO_TARRAY) {
|
if (type & SPROTO_TARRAY) {
|
||||||
sz = encode_array(cb,ud, f, data, size);
|
args.type = type & ~SPROTO_TARRAY;
|
||||||
|
sz = encode_array(cb, &args, data, size);
|
||||||
} else {
|
} else {
|
||||||
|
args.type = type;
|
||||||
|
args.index = 0;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SPROTO_TINTEGER:
|
case SPROTO_TINTEGER:
|
||||||
case SPROTO_TBOOLEAN: {
|
case SPROTO_TBOOLEAN: {
|
||||||
@@ -836,10 +877,12 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c
|
|||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
} u;
|
} u;
|
||||||
sz = cb(ud, f->name, type, 0, NULL, &u, sizeof(u));
|
args.value = &u;
|
||||||
|
args.length = sizeof(u);
|
||||||
|
sz = cb(&args);
|
||||||
if (sz < 0)
|
if (sz < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (sz == 0)
|
if (sz == 0) // nil object
|
||||||
continue;
|
continue;
|
||||||
if (sz == sizeof(uint32_t)) {
|
if (sz == sizeof(uint32_t)) {
|
||||||
if (u.u32 < 0x7fff) {
|
if (u.u32 < 0x7fff) {
|
||||||
@@ -855,15 +898,11 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRING: {
|
case SPROTO_TSTRUCT:
|
||||||
sz = encode_string(cb, ud, f, data, size);
|
case SPROTO_TSTRING:
|
||||||
|
sz = encode_object(cb, &args, data, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRUCT: {
|
|
||||||
sz = encode_struct(cb, ud, f, data, size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sz < 0)
|
if (sz < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -904,9 +943,8 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
decode_array_object(sproto_callback cb, void *ud, struct field *f, uint8_t * stream, int sz) {
|
decode_array_object(sproto_callback cb, struct sproto_arg *args, uint8_t * stream, int sz) {
|
||||||
uint32_t hsz;
|
uint32_t hsz;
|
||||||
int type = f->type & ~SPROTO_TARRAY;
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
while (sz > 0) {
|
while (sz > 0) {
|
||||||
if (sz < SIZEOF_LENGTH)
|
if (sz < SIZEOF_LENGTH)
|
||||||
@@ -916,7 +954,10 @@ decode_array_object(sproto_callback cb, void *ud, struct field *f, uint8_t * str
|
|||||||
sz -= SIZEOF_LENGTH;
|
sz -= SIZEOF_LENGTH;
|
||||||
if (hsz > sz)
|
if (hsz > sz)
|
||||||
return -1;
|
return -1;
|
||||||
if (cb(ud, f->name, type, index, f->st, stream, hsz))
|
args->index = index;
|
||||||
|
args->value = stream;
|
||||||
|
args->length = hsz;
|
||||||
|
if (cb(args))
|
||||||
return -1;
|
return -1;
|
||||||
sz -= hsz;
|
sz -= hsz;
|
||||||
stream += hsz;
|
stream += hsz;
|
||||||
@@ -935,9 +976,9 @@ expand64(uint32_t v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) {
|
decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
|
||||||
uint32_t sz = todword(stream);
|
uint32_t sz = todword(stream);
|
||||||
int type = f->type & ~SPROTO_TARRAY;
|
int type = args->type;
|
||||||
int i;
|
int i;
|
||||||
stream += SIZEOF_LENGTH;
|
stream += SIZEOF_LENGTH;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -953,7 +994,10 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) {
|
|||||||
return -1;
|
return -1;
|
||||||
for (i=0;i<sz/sizeof(uint32_t);i++) {
|
for (i=0;i<sz/sizeof(uint32_t);i++) {
|
||||||
uint64_t value = expand64(todword(stream + i*sizeof(uint32_t)));
|
uint64_t value = expand64(todword(stream + i*sizeof(uint32_t)));
|
||||||
cb(ud, f->name, SPROTO_TINTEGER, i+1, NULL, &value, sizeof(value));
|
args->index = i+1;
|
||||||
|
args->value = &value;
|
||||||
|
args->length = sizeof(value);
|
||||||
|
cb(args);
|
||||||
}
|
}
|
||||||
} else if (len == sizeof(uint64_t)) {
|
} else if (len == sizeof(uint64_t)) {
|
||||||
if (sz % sizeof(uint64_t) != 0)
|
if (sz % sizeof(uint64_t) != 0)
|
||||||
@@ -962,7 +1006,10 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) {
|
|||||||
uint64_t low = todword(stream + i*sizeof(uint64_t));
|
uint64_t low = todword(stream + i*sizeof(uint64_t));
|
||||||
uint64_t hi = todword(stream + i*sizeof(uint64_t) + sizeof(uint32_t));
|
uint64_t hi = todword(stream + i*sizeof(uint64_t) + sizeof(uint32_t));
|
||||||
uint64_t value = low | hi << 32;
|
uint64_t value = low | hi << 32;
|
||||||
cb(ud, f->name, SPROTO_TINTEGER, i+1, NULL, &value, sizeof(value));
|
args->index = i+1;
|
||||||
|
args->value = &value;
|
||||||
|
args->length = sizeof(value);
|
||||||
|
cb(args);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -972,12 +1019,15 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) {
|
|||||||
case SPROTO_TBOOLEAN:
|
case SPROTO_TBOOLEAN:
|
||||||
for (i=0;i<sz;i++) {
|
for (i=0;i<sz;i++) {
|
||||||
uint64_t value = stream[i];
|
uint64_t value = stream[i];
|
||||||
cb(ud, f->name, SPROTO_TBOOLEAN, i+1, NULL, &value, sizeof(value));
|
args->index = i+1;
|
||||||
|
args->value = &value;
|
||||||
|
args->length = sizeof(value);
|
||||||
|
cb(args);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPROTO_TSTRING:
|
case SPROTO_TSTRING:
|
||||||
case SPROTO_TSTRUCT:
|
case SPROTO_TSTRUCT:
|
||||||
return decode_array_object(cb, ud, f, stream, sz);
|
return decode_array_object(cb, args, stream, sz);
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -985,7 +1035,8 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callback cb, void *ud) {
|
sproto_decode(const struct sproto_type *st, const void * data, int size, sproto_callback cb, void *ud) {
|
||||||
|
struct sproto_arg args;
|
||||||
int total = size;
|
int total = size;
|
||||||
uint8_t * stream;
|
uint8_t * stream;
|
||||||
uint8_t * datastream;
|
uint8_t * datastream;
|
||||||
@@ -994,6 +1045,8 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba
|
|||||||
int tag;
|
int tag;
|
||||||
if (size < SIZEOF_HEADER)
|
if (size < SIZEOF_HEADER)
|
||||||
return -1;
|
return -1;
|
||||||
|
// debug print
|
||||||
|
// printf("sproto_decode[%p] (%s)\n", ud, st->name);
|
||||||
stream = (void *)data;
|
stream = (void *)data;
|
||||||
fn = toword(stream);
|
fn = toword(stream);
|
||||||
stream += SIZEOF_HEADER;
|
stream += SIZEOF_HEADER;
|
||||||
@@ -1001,7 +1054,8 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba
|
|||||||
if (size < fn * SIZEOF_FIELD)
|
if (size < fn * SIZEOF_FIELD)
|
||||||
return -1;
|
return -1;
|
||||||
datastream = stream + fn * SIZEOF_FIELD;
|
datastream = stream + fn * SIZEOF_FIELD;
|
||||||
size -= fn * SIZEOF_FIELD ;
|
size -= fn * SIZEOF_FIELD;
|
||||||
|
args.ud = ud;
|
||||||
|
|
||||||
tag = -1;
|
tag = -1;
|
||||||
for (i=0;i<fn;i++) {
|
for (i=0;i<fn;i++) {
|
||||||
@@ -1028,9 +1082,15 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba
|
|||||||
f = findtag(st, tag);
|
f = findtag(st, tag);
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
args.tagname = f->name;
|
||||||
|
args.tagid = f->tag;
|
||||||
|
args.type = f->type & ~SPROTO_TARRAY;
|
||||||
|
args.subtype = f->st;
|
||||||
|
args.index = 0;
|
||||||
|
args.mainindex = f->key;
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
if (f->type & SPROTO_TARRAY) {
|
if (f->type & SPROTO_TARRAY) {
|
||||||
if (decode_array(cb, ud, f, currentdata)) {
|
if (decode_array(cb, &args, currentdata)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1039,21 +1099,27 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba
|
|||||||
uint32_t sz = todword(currentdata);
|
uint32_t sz = todword(currentdata);
|
||||||
if (sz == sizeof(uint32_t)) {
|
if (sz == sizeof(uint32_t)) {
|
||||||
uint64_t v = expand64(todword(currentdata + SIZEOF_LENGTH));
|
uint64_t v = expand64(todword(currentdata + SIZEOF_LENGTH));
|
||||||
cb(ud, f->name, SPROTO_TINTEGER, 0, NULL, &v, sizeof(v));
|
args.value = &v;
|
||||||
|
args.length = sizeof(v);
|
||||||
|
cb(&args);
|
||||||
} else if (sz != sizeof(uint64_t)) {
|
} else if (sz != sizeof(uint64_t)) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
uint32_t low = todword(currentdata + SIZEOF_LENGTH);
|
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(uint32_t));
|
||||||
uint64_t v = (uint64_t)low | (uint64_t) hi << 32;
|
uint64_t v = (uint64_t)low | (uint64_t) hi << 32;
|
||||||
cb(ud, f->name, SPROTO_TINTEGER, 0, NULL, &v, sizeof(v));
|
args.value = &v;
|
||||||
|
args.length = sizeof(v);
|
||||||
|
cb(&args);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPROTO_TSTRING:
|
case SPROTO_TSTRING:
|
||||||
case SPROTO_TSTRUCT: {
|
case SPROTO_TSTRUCT: {
|
||||||
uint32_t sz = todword(currentdata);
|
uint32_t sz = todword(currentdata);
|
||||||
if (cb(ud, f->name, f->type, 0, f->st, currentdata+SIZEOF_LENGTH, sz))
|
args.value = currentdata+SIZEOF_LENGTH;
|
||||||
|
args.length = sz;
|
||||||
|
if (cb(&args))
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1065,7 +1131,9 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba
|
|||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
uint64_t v = value;
|
uint64_t v = value;
|
||||||
cb(ud, f->name, f->type, 0, NULL, &v, sizeof(v));
|
args.value = &v;
|
||||||
|
args.length = sizeof(v);
|
||||||
|
cb(&args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return total - size;
|
return total - size;
|
||||||
|
|||||||
@@ -17,20 +17,32 @@ struct sproto_type;
|
|||||||
struct sproto * sproto_create(const void * proto, size_t sz);
|
struct sproto * sproto_create(const void * proto, size_t sz);
|
||||||
void sproto_release(struct sproto *);
|
void sproto_release(struct sproto *);
|
||||||
|
|
||||||
int sproto_prototag(struct sproto *, const char * name);
|
int sproto_prototag(const struct sproto *, const char * name);
|
||||||
const char * sproto_protoname(struct sproto *, int proto);
|
const char * sproto_protoname(const struct sproto *, int proto);
|
||||||
// SPROTO_REQUEST(0) : request, SPROTO_RESPONSE(1): response
|
// SPROTO_REQUEST(0) : request, SPROTO_RESPONSE(1): response
|
||||||
struct sproto_type * sproto_protoquery(struct sproto *, int proto, int what);
|
struct sproto_type * sproto_protoquery(const struct sproto *, int proto, int what);
|
||||||
|
|
||||||
struct sproto_type * sproto_type(struct sproto *, const char * type_name);
|
struct sproto_type * sproto_type(const struct sproto *, const char * type_name);
|
||||||
|
|
||||||
int sproto_pack(const void * src, int srcsz, void * buffer, int bufsz);
|
int sproto_pack(const void * src, int srcsz, void * buffer, int bufsz);
|
||||||
int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz);
|
int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz);
|
||||||
|
|
||||||
typedef int (*sproto_callback)(void *ud, const char *tagname, int type, int index, struct sproto_type *, void *value, int length);
|
struct sproto_arg {
|
||||||
|
void *ud;
|
||||||
|
const char *tagname;
|
||||||
|
int tagid;
|
||||||
|
int type;
|
||||||
|
struct sproto_type *subtype;
|
||||||
|
void *value;
|
||||||
|
int length;
|
||||||
|
int index; // array base 1
|
||||||
|
int mainindex; // for map
|
||||||
|
};
|
||||||
|
|
||||||
int sproto_decode(struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud);
|
typedef int (*sproto_callback)(const struct sproto_arg *args);
|
||||||
int sproto_encode(struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud);
|
|
||||||
|
int sproto_decode(const struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud);
|
||||||
|
int sproto_encode(const struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud);
|
||||||
|
|
||||||
// for debug use
|
// for debug use
|
||||||
void sproto_dump(struct sproto *);
|
void sproto_dump(struct sproto *);
|
||||||
|
|||||||
290
lualib/dns.lua
Normal file
290
lualib/dns.lua
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
--[[
|
||||||
|
lua dns resolver library
|
||||||
|
See https://github.com/xjdrew/levent/blob/master/levent/dns.lua for more detail
|
||||||
|
|
||||||
|
-- resource record type:
|
||||||
|
-- TYPE value and meaning
|
||||||
|
-- A 1 a host address
|
||||||
|
-- NS 2 an authoritative name server
|
||||||
|
-- MD 3 a mail destination (Obsolete - use MX)
|
||||||
|
-- MF 4 a mail forwarder (Obsolete - use MX)
|
||||||
|
-- CNAME 5 the canonical name for an alias
|
||||||
|
-- SOA 6 marks the start of a zone of authority
|
||||||
|
-- MB 7 a mailbox domain name (EXPERIMENTAL)
|
||||||
|
-- MG 8 a mail group member (EXPERIMENTAL)
|
||||||
|
-- MR 9 a mail rename domain name (EXPERIMENTAL)
|
||||||
|
-- NULL 10 a null RR (EXPERIMENTAL)
|
||||||
|
-- WKS 11 a well known service description
|
||||||
|
-- PTR 12 a domain name pointer
|
||||||
|
-- HINFO 13 host information
|
||||||
|
-- MINFO 14 mailbox or mail list information
|
||||||
|
-- MX 15 mail exchange
|
||||||
|
-- TXT 16 text strings
|
||||||
|
-- AAAA 28 a ipv6 host address
|
||||||
|
-- only appear in the question section:
|
||||||
|
-- AXFR 252 A request for a transfer of an entire zone
|
||||||
|
-- MAILB 253 A request for mailbox-related records (MB, MG or MR)
|
||||||
|
-- MAILA 254 A request for mail agent RRs (Obsolete - see MX)
|
||||||
|
-- * 255 A request for all records
|
||||||
|
--
|
||||||
|
-- resource recode class:
|
||||||
|
-- IN 1 the Internet
|
||||||
|
-- CS 2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs)
|
||||||
|
-- CH 3 the CHAOS class
|
||||||
|
-- HS 4 Hesiod [Dyer 87]
|
||||||
|
-- only appear in the question section:
|
||||||
|
-- * 255 any class
|
||||||
|
-- ]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
-- struct header {
|
||||||
|
-- uint16_t tid # identifier assigned by the program that generates any kind of query.
|
||||||
|
-- uint16_t flags # flags
|
||||||
|
-- uint16_t qdcount # the number of entries in the question section.
|
||||||
|
-- uint16_t ancount # the number of resource records in the answer section.
|
||||||
|
-- uint16_t nscount # the number of name server resource records in the authority records section.
|
||||||
|
-- uint16_t arcount # the number of resource records in the additional records section.
|
||||||
|
-- }
|
||||||
|
--
|
||||||
|
-- request body:
|
||||||
|
-- struct request {
|
||||||
|
-- string name
|
||||||
|
-- uint16_t atype
|
||||||
|
-- uint16_t class
|
||||||
|
-- }
|
||||||
|
--
|
||||||
|
-- response body:
|
||||||
|
-- struct response {
|
||||||
|
-- string name
|
||||||
|
-- uint16_t atype
|
||||||
|
-- uint16_t class
|
||||||
|
-- uint16_t ttl
|
||||||
|
-- uint16_t rdlength
|
||||||
|
-- string rdata
|
||||||
|
-- }
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local skynet = require "skynet"
|
||||||
|
local socket = require "socket"
|
||||||
|
|
||||||
|
local MAX_DOMAIN_LEN = 1024
|
||||||
|
local MAX_LABEL_LEN = 63
|
||||||
|
local MAX_PACKET_LEN = 2048
|
||||||
|
local DNS_HEADER_LEN = 12
|
||||||
|
|
||||||
|
local QTYPE = {
|
||||||
|
A = 1,
|
||||||
|
CNAME = 5,
|
||||||
|
AAAA = 28,
|
||||||
|
}
|
||||||
|
|
||||||
|
local QCLASS = {
|
||||||
|
IN = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
local dns = {}
|
||||||
|
|
||||||
|
local function verify_domain_name(name)
|
||||||
|
if #name > MAX_DOMAIN_LEN then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not name:match("^[%l%d-%.]+$") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for w in name:gmatch("([%w-]+)%.?") do
|
||||||
|
if #w > MAX_LABEL_LEN then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local next_tid = 1
|
||||||
|
local function gen_tid()
|
||||||
|
local tid = next_tid
|
||||||
|
next_tid = next_tid + 1
|
||||||
|
return tid
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pack_header(t)
|
||||||
|
return string.pack(">HHHHHH",
|
||||||
|
t.tid, t.flags, t.qdcount, t.ancount or 0, t.nscount or 0, t.arcount or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pack_question(name, qtype, qclass)
|
||||||
|
local labels = {}
|
||||||
|
for w in name:gmatch("([%w-]+)%.?") do
|
||||||
|
table.insert(labels, string.pack("s1",w))
|
||||||
|
end
|
||||||
|
table.insert(labels, '\0')
|
||||||
|
table.insert(labels, string.pack(">HH", qtype, qclass))
|
||||||
|
return table.concat(labels)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_header(chunk)
|
||||||
|
local tid, flags, qdcount, ancount, nscount, arcount, left = string.unpack(">HHHHHH", chunk)
|
||||||
|
return {
|
||||||
|
tid = tid,
|
||||||
|
flags = flags,
|
||||||
|
qdcount = qdcount,
|
||||||
|
ancount = ancount,
|
||||||
|
nscount = nscount,
|
||||||
|
arcount = arcount
|
||||||
|
}, left
|
||||||
|
end
|
||||||
|
|
||||||
|
-- unpack a resource name
|
||||||
|
local function unpack_name(chunk, left)
|
||||||
|
local t = {}
|
||||||
|
local jump_pointer
|
||||||
|
local tag, offset, label
|
||||||
|
while true do
|
||||||
|
tag, left = string.unpack("B", chunk, left)
|
||||||
|
if tag & 0xc0 == 0xc0 then
|
||||||
|
-- pointer
|
||||||
|
offset,left = string.unpack(">H", chunk, left - 1)
|
||||||
|
offset = offset & 0x3fff
|
||||||
|
if not jump_pointer then
|
||||||
|
jump_pointer = left
|
||||||
|
end
|
||||||
|
-- offset is base 0, need to plus 1
|
||||||
|
left = offset + 1
|
||||||
|
elseif tag == 0 then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
label, left = string.unpack("s1", chunk, left - 1)
|
||||||
|
t[#t+1] = label
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(t, "."), jump_pointer or left
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_question(chunk, left)
|
||||||
|
local name, left = unpack_name(chunk, left)
|
||||||
|
local atype, class, left = string.unpack(">HH", chunk, left)
|
||||||
|
return {
|
||||||
|
name = name,
|
||||||
|
atype = atype,
|
||||||
|
class = class
|
||||||
|
}, left
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_answer(chunk, left)
|
||||||
|
local name, left = unpack_name(chunk, left)
|
||||||
|
local atype, class, ttl, rdata, left = string.unpack(">HHI4s2", chunk, left)
|
||||||
|
return {
|
||||||
|
name = name,
|
||||||
|
atype = atype,
|
||||||
|
class = class,
|
||||||
|
ttl = ttl,
|
||||||
|
rdata = rdata
|
||||||
|
},left
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpack_rdata(qtype, chunk)
|
||||||
|
if qtype == QTYPE.A then
|
||||||
|
local a,b,c,d = string.unpack("BBBB", chunk)
|
||||||
|
return string.format("%d.%d.%d.%d", a,b,c,d)
|
||||||
|
elseif qtype == QTYPE.AAAA then
|
||||||
|
local a,b,c,d,e,f,g,h = string.unpack(">HHHHHHHH", chunk)
|
||||||
|
return string.format("%x:%x:%x:%x:%x:%x:%x:%x", a, b, c, d, e, f, g, h)
|
||||||
|
else
|
||||||
|
error("Error qtype " .. qtype)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local dns_server
|
||||||
|
local request_pool = {}
|
||||||
|
|
||||||
|
local function resolve(content)
|
||||||
|
if #content < DNS_HEADER_LEN then
|
||||||
|
-- drop
|
||||||
|
skynet.error("Recv an invalid package when dns query")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local answer_header,left = unpack_header(content)
|
||||||
|
-- verify answer
|
||||||
|
assert(answer_header.qdcount == 1, "malformed packet")
|
||||||
|
|
||||||
|
local resp = request_pool[answer_header.tid]
|
||||||
|
if not resp then
|
||||||
|
skynet.error("Recv an invalid tid when dns query")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local question,left = unpack_question(content, left)
|
||||||
|
if question.name ~= resp.name then
|
||||||
|
skynet.error("Recv an invalid name when dns query")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ttl
|
||||||
|
local answer
|
||||||
|
local answers = {}
|
||||||
|
for i=1, answer_header.ancount do
|
||||||
|
answer, left = unpack_answer(content, left)
|
||||||
|
-- only extract qtype address
|
||||||
|
if answer.atype == resp.qtype then
|
||||||
|
local ip = unpack_rdata(resp.qtype, answer.rdata)
|
||||||
|
ttl = ttl and math.min(ttl, answer.ttl) or answer.ttl
|
||||||
|
answers[#answers+1] = ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #answers > 0 then
|
||||||
|
resp.answers = answers
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
assert(server, "Can't get nameserver")
|
||||||
|
end
|
||||||
|
dns_server = socket.udp(function(str, from)
|
||||||
|
resolve(str)
|
||||||
|
end)
|
||||||
|
socket.udp_connect(dns_server, server, port or 53)
|
||||||
|
return server
|
||||||
|
end
|
||||||
|
|
||||||
|
local function suspend(tid, name, qtype)
|
||||||
|
local req = {
|
||||||
|
name = name,
|
||||||
|
tid = tid,
|
||||||
|
qtype = qtype,
|
||||||
|
time = skynet.now(), -- for timeout
|
||||||
|
co = coroutine.running(),
|
||||||
|
}
|
||||||
|
request_pool[tid] = req
|
||||||
|
skynet.wait()
|
||||||
|
local answers = request_pool[tid].answers
|
||||||
|
request_pool[tid] = nil
|
||||||
|
assert(answers, "no ip")
|
||||||
|
return answers[1], answers
|
||||||
|
end
|
||||||
|
|
||||||
|
function dns.resolve(name, ipv6)
|
||||||
|
local qtype = ipv6 and QTYPE.AAAA or QTYPE.A
|
||||||
|
local name = name:lower()
|
||||||
|
assert(verify_domain_name(name) , "illegal name")
|
||||||
|
local question_header = {
|
||||||
|
tid = gen_tid(),
|
||||||
|
flags = 0x100, -- flags: 00000001 00000000, set RD
|
||||||
|
qdcount = 1,
|
||||||
|
}
|
||||||
|
local req = pack_header(question_header) .. pack_question(name, qtype, QCLASS.IN)
|
||||||
|
assert(dns_server, "Call dns.server fist")
|
||||||
|
socket.write(dns_server, req)
|
||||||
|
return suspend(question_header.tid, name, qtype)
|
||||||
|
end
|
||||||
|
|
||||||
|
return dns
|
||||||
@@ -14,10 +14,17 @@ local function request(fd, method, host, url, recvheader, header, content)
|
|||||||
for k,v in pairs(header) do
|
for k,v in pairs(header) do
|
||||||
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
|
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
|
||||||
end
|
end
|
||||||
|
if header.host then
|
||||||
|
host = ""
|
||||||
|
else
|
||||||
|
host = string.format("host:%s\r\n", host)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
host = string.format("host:%s\r\n",host)
|
||||||
end
|
end
|
||||||
|
|
||||||
if content then
|
if content then
|
||||||
local data = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:%d\r\n%s\r\n%s", method, url, host, #content, header_content, content)
|
local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n%s\r\n%s", method, url, host, #content, header_content, content)
|
||||||
write(data)
|
write(data)
|
||||||
else
|
else
|
||||||
local request_header = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:0\r\n%s\r\n", method, url, host, header_content)
|
local request_header = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:0\r\n%s\r\n", method, url, host, header_content)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
local internal = require "http.internal"
|
local internal = require "http.internal"
|
||||||
|
|
||||||
local table = table
|
local table = table
|
||||||
|
local string = string
|
||||||
|
local type = type
|
||||||
|
|
||||||
local httpd = {}
|
local httpd = {}
|
||||||
|
|
||||||
@@ -112,7 +114,13 @@ local function writeall(writefunc, statuscode, bodyfunc, header)
|
|||||||
writefunc(statusline)
|
writefunc(statusline)
|
||||||
if header then
|
if header then
|
||||||
for k,v in pairs(header) do
|
for k,v in pairs(header) do
|
||||||
writefunc(string.format("%s: %s\r\n", k,v))
|
if type(v) == "table" then
|
||||||
|
for _,v in ipairs(v) do
|
||||||
|
writefunc(string.format("%s: %s\r\n", k,v))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
writefunc(string.format("%s: %s\r\n", k,v))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local t = type(bodyfunc)
|
local t = type(bodyfunc)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
local table = table
|
||||||
|
local type = type
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
local LIMIT = 8192
|
local LIMIT = 8192
|
||||||
@@ -83,7 +86,12 @@ function M.parseheader(lines, from, header)
|
|||||||
end
|
end
|
||||||
name = name:lower()
|
name = name:lower()
|
||||||
if header[name] then
|
if header[name] then
|
||||||
header[name] = header[name] .. ", " .. value
|
local v = header[name]
|
||||||
|
if type(v) == "table" then
|
||||||
|
table.insert(v, value)
|
||||||
|
else
|
||||||
|
header[name] = { v , value }
|
||||||
|
end
|
||||||
else
|
else
|
||||||
header[name] = value
|
header[name] = value
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,12 +30,14 @@ function sharemap.writer(typename, obj)
|
|||||||
local sp = loadsp()
|
local sp = loadsp()
|
||||||
obj = obj or {}
|
obj = obj or {}
|
||||||
local stmobj = stm.new(sp:encode(typename,obj))
|
local stmobj = stm.new(sp:encode(typename,obj))
|
||||||
obj.__typename = typename
|
local ret = {
|
||||||
obj.__obj = stmobj
|
__typename = typename,
|
||||||
obj.__data = obj
|
__obj = stmobj,
|
||||||
obj.commit = sharemap.commit
|
__data = obj,
|
||||||
obj.copy = sharemap.copy
|
commit = sharemap.commit,
|
||||||
return setmetatable(obj, { __index = obj.__data, __newindex = obj.__data })
|
copy = sharemap.copy,
|
||||||
|
}
|
||||||
|
return setmetatable(ret, { __index = obj, __newindex = obj })
|
||||||
end
|
end
|
||||||
|
|
||||||
local function decode(msg, sz, self)
|
local function decode(msg, sz, self)
|
||||||
@@ -63,7 +65,7 @@ function sharemap.reader(typename, stmcpy)
|
|||||||
__data = data,
|
__data = data,
|
||||||
update = sharemap.update,
|
update = sharemap.update,
|
||||||
}
|
}
|
||||||
return setmetatable(obj, { __index = obj.__data, __newindex = error })
|
return setmetatable(obj, { __index = data, __newindex = error })
|
||||||
end
|
end
|
||||||
|
|
||||||
return sharemap
|
return sharemap
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ skynet.pack = assert(c.pack)
|
|||||||
skynet.packstring = assert(c.packstring)
|
skynet.packstring = assert(c.packstring)
|
||||||
skynet.unpack = assert(c.unpack)
|
skynet.unpack = assert(c.unpack)
|
||||||
skynet.tostring = assert(c.tostring)
|
skynet.tostring = assert(c.tostring)
|
||||||
|
skynet.trash = assert(c.trash)
|
||||||
|
|
||||||
local function yield_call(service, session)
|
local function yield_call(service, session)
|
||||||
watching_session[session] = service
|
watching_session[session] = service
|
||||||
@@ -619,8 +620,10 @@ end
|
|||||||
local function init_all()
|
local function init_all()
|
||||||
local funcs = init_func
|
local funcs = init_func
|
||||||
init_func = nil
|
init_func = nil
|
||||||
for k,v in pairs(funcs) do
|
if funcs then
|
||||||
v()
|
for k,v in pairs(funcs) do
|
||||||
|
v()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -631,8 +634,12 @@ local function init_template(start)
|
|||||||
init_all()
|
init_all()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function skynet.pcall(start)
|
||||||
|
return xpcall(init_template, debug.traceback, start)
|
||||||
|
end
|
||||||
|
|
||||||
local function init_service(start)
|
local function init_service(start)
|
||||||
local ok, err = xpcall(init_template, debug.traceback, start)
|
local ok, err = skynet.pcall(start)
|
||||||
if not ok then
|
if not ok then
|
||||||
skynet.error("init service failed: " .. tostring(err))
|
skynet.error("init service failed: " .. tostring(err))
|
||||||
skynet.send(".launcher","lua", "ERROR")
|
skynet.send(".launcher","lua", "ERROR")
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ end
|
|||||||
|
|
||||||
function dbgcmd.RUN(source, filename)
|
function dbgcmd.RUN(source, filename)
|
||||||
local inject = require "skynet.inject"
|
local inject = require "skynet.inject"
|
||||||
local output = inject(source, filename , export.dispatch, skynet.register_protocol)
|
local output = inject(skynet, source, filename , export.dispatch, skynet.register_protocol)
|
||||||
collectgarbage "collect"
|
collectgarbage "collect"
|
||||||
skynet.ret(skynet.pack(table.concat(output, "\n")))
|
skynet.ret(skynet.pack(table.concat(output, "\n")))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ local function getupvaluetable(u, func, unique)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return function(source, filename , ...)
|
return function(skynet, source, filename , ...)
|
||||||
if filename then
|
if filename then
|
||||||
filename = "@" .. filename
|
filename = "@" .. filename
|
||||||
else
|
else
|
||||||
@@ -56,7 +56,7 @@ return function(source, filename , ...)
|
|||||||
if not func then
|
if not func then
|
||||||
return { err }
|
return { err }
|
||||||
end
|
end
|
||||||
local ok, err = xpcall(func, debug.traceback)
|
local ok, err = skynet.pcall(func)
|
||||||
if not ok then
|
if not ok then
|
||||||
table.insert(output, err)
|
table.insert(output, err)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -162,4 +162,8 @@ function snax.hotfix(obj, source, ...)
|
|||||||
return test_result(skynet_call(obj.handle, "snax", t.system.hotfix, source, ...))
|
return test_result(skynet_call(obj.handle, "snax", t.system.hotfix, source, ...))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function snax.printf(fmt, ...)
|
||||||
|
skynet.error(string.format(fmt, ...))
|
||||||
|
end
|
||||||
|
|
||||||
return snax
|
return snax
|
||||||
|
|||||||
@@ -33,17 +33,17 @@ Success:
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local socket_error = {}
|
local socket_error = {}
|
||||||
local function assert_socket(v, fd)
|
local function assert_socket(service, v, fd)
|
||||||
if v then
|
if v then
|
||||||
return v
|
return v
|
||||||
else
|
else
|
||||||
skynet.error(string.format("auth failed: socket (fd = %d) closed", fd))
|
skynet.error(string.format("%s failed: socket (fd = %d) closed", service, fd))
|
||||||
error(socket_error)
|
error(socket_error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function write(fd, text)
|
local function write(service, fd, text)
|
||||||
assert_socket(socket.write(fd, text), fd)
|
assert_socket(service, socket.write(fd, text), fd)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function launch_slave(auth_handler)
|
local function launch_slave(auth_handler)
|
||||||
@@ -57,27 +57,27 @@ local function launch_slave(auth_handler)
|
|||||||
socket.limit(fd, 8192)
|
socket.limit(fd, 8192)
|
||||||
|
|
||||||
local challenge = crypt.randomkey()
|
local challenge = crypt.randomkey()
|
||||||
write(fd, crypt.base64encode(challenge).."\n")
|
write("auth", fd, crypt.base64encode(challenge).."\n")
|
||||||
|
|
||||||
local handshake = assert_socket(socket.readline(fd), fd)
|
local handshake = assert_socket("auth", socket.readline(fd), fd)
|
||||||
local clientkey = crypt.base64decode(handshake)
|
local clientkey = crypt.base64decode(handshake)
|
||||||
if #clientkey ~= 8 then
|
if #clientkey ~= 8 then
|
||||||
error "Invalid client key"
|
error "Invalid client key"
|
||||||
end
|
end
|
||||||
local serverkey = crypt.randomkey()
|
local serverkey = crypt.randomkey()
|
||||||
write(fd, crypt.base64encode(crypt.dhexchange(serverkey)).."\n")
|
write("auth", fd, crypt.base64encode(crypt.dhexchange(serverkey)).."\n")
|
||||||
|
|
||||||
local secret = crypt.dhsecret(clientkey, serverkey)
|
local secret = crypt.dhsecret(clientkey, serverkey)
|
||||||
|
|
||||||
local response = assert_socket(socket.readline(fd), fd)
|
local response = assert_socket("auth", socket.readline(fd), fd)
|
||||||
local hmac = crypt.hmac64(challenge, secret)
|
local hmac = crypt.hmac64(challenge, secret)
|
||||||
|
|
||||||
if hmac ~= crypt.base64decode(response) then
|
if hmac ~= crypt.base64decode(response) then
|
||||||
write(fd, "400 Bad Request\n")
|
write("auth", fd, "400 Bad Request\n")
|
||||||
error "challenge failed"
|
error "challenge failed"
|
||||||
end
|
end
|
||||||
|
|
||||||
local etoken = assert_socket(socket.readline(fd),fd)
|
local etoken = assert_socket("auth", socket.readline(fd),fd)
|
||||||
|
|
||||||
local token = crypt.desdecode(secret, crypt.base64decode(etoken))
|
local token = crypt.desdecode(secret, crypt.base64decode(etoken))
|
||||||
|
|
||||||
@@ -91,7 +91,11 @@ local function launch_slave(auth_handler)
|
|||||||
if ok then
|
if ok then
|
||||||
skynet.ret(skynet.pack(err, ...))
|
skynet.ret(skynet.pack(err, ...))
|
||||||
else
|
else
|
||||||
error(err)
|
if err == socket_error then
|
||||||
|
skynet.ret(skynet.pack(nil, "socket error"))
|
||||||
|
else
|
||||||
|
skynet.ret(skynet.pack(false, err))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -108,13 +112,15 @@ local function accept(conf, s, fd, addr)
|
|||||||
socket.start(fd)
|
socket.start(fd)
|
||||||
|
|
||||||
if not ok then
|
if not ok then
|
||||||
write(fd, "401 Unauthorized\n")
|
if ok ~= nil then
|
||||||
|
write("response 401", fd, "401 Unauthorized\n")
|
||||||
|
end
|
||||||
error(server)
|
error(server)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not conf.multilogin then
|
if not conf.multilogin then
|
||||||
if user_login[uid] then
|
if user_login[uid] then
|
||||||
write(fd, "406 Not Acceptable\n")
|
write("response 406", fd, "406 Not Acceptable\n")
|
||||||
error(string.format("User %s is already login", uid))
|
error(string.format("User %s is already login", uid))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -127,9 +133,9 @@ local function accept(conf, s, fd, addr)
|
|||||||
|
|
||||||
if ok then
|
if ok then
|
||||||
err = err or ""
|
err = err or ""
|
||||||
write(fd, "200 "..crypt.base64encode(err).."\n")
|
write("response 200",fd, "200 "..crypt.base64encode(err).."\n")
|
||||||
else
|
else
|
||||||
write(fd, "403 Forbidden\n")
|
write("response 403",fd, "403 Forbidden\n")
|
||||||
error(err)
|
error(err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ function server.start(conf)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local text = string.format("%s:%s", username, index)
|
local text = string.format("%s:%s", username, index)
|
||||||
local v = crypt.hmac64(crypt.hashkey(text), u.secret)
|
local v = crypt.hmac_hash(u.secret, text) -- equivalent to crypt.hmac64(crypt.hashkey(text), u.secret)
|
||||||
if v ~= hmac then
|
if v ~= hmac then
|
||||||
return "401 Unauthorized"
|
return "401 Unauthorized"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
local driver = require "socketdriver"
|
local driver = require "socketdriver"
|
||||||
local skynet = require "skynet"
|
local skynet = require "skynet"
|
||||||
|
local skynet_core = require "skynet.core"
|
||||||
local assert = assert
|
local assert = assert
|
||||||
|
|
||||||
local socket = {} -- api
|
local socket = {} -- api
|
||||||
@@ -127,7 +128,9 @@ socket_message[6] = function(id, size, data, address)
|
|||||||
driver.drop(data, size)
|
driver.drop(data, size)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
s.callback(data, size, address)
|
local str = skynet.tostring(data, size)
|
||||||
|
skynet_core.trash(data, size)
|
||||||
|
s.callback(str, address)
|
||||||
end
|
end
|
||||||
|
|
||||||
skynet.register_protocol {
|
skynet.register_protocol {
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ local host = {}
|
|||||||
|
|
||||||
local weak_mt = { __mode = "kv" }
|
local weak_mt = { __mode = "kv" }
|
||||||
local sproto_mt = { __index = sproto }
|
local sproto_mt = { __index = sproto }
|
||||||
|
local sproto_nogc = { __index = sproto }
|
||||||
local host_mt = { __index = host }
|
local host_mt = { __index = host }
|
||||||
|
|
||||||
function sproto_mt:__gc()
|
function sproto_mt:__gc()
|
||||||
core.deleteproto(self.__cobj)
|
core.deleteproto(self.__cobj)
|
||||||
end
|
end
|
||||||
|
|
||||||
function sproto.new(...)
|
function sproto.new(bin)
|
||||||
local cobj = assert(core.newproto(...))
|
local cobj = assert(core.newproto(bin))
|
||||||
local self = {
|
local self = {
|
||||||
__cobj = cobj,
|
__cobj = cobj,
|
||||||
__tcache = setmetatable( {} , weak_mt ),
|
__tcache = setmetatable( {} , weak_mt ),
|
||||||
@@ -22,6 +23,15 @@ function sproto.new(...)
|
|||||||
return setmetatable(self, sproto_mt)
|
return setmetatable(self, sproto_mt)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function sproto.sharenew(cobj)
|
||||||
|
local self = {
|
||||||
|
__cobj = cobj,
|
||||||
|
__tcache = setmetatable( {} , weak_mt ),
|
||||||
|
__pcache = setmetatable( {} , weak_mt ),
|
||||||
|
}
|
||||||
|
return setmetatable(self, sproto_nogc)
|
||||||
|
end
|
||||||
|
|
||||||
function sproto.parse(ptext)
|
function sproto.parse(ptext)
|
||||||
local parser = require "sprotoparser"
|
local parser = require "sprotoparser"
|
||||||
local pbin = parser.parse(ptext)
|
local pbin = parser.parse(ptext)
|
||||||
@@ -63,9 +73,9 @@ function sproto:pencode(typename, tbl)
|
|||||||
return core.pack(core.encode(st, tbl))
|
return core.pack(core.encode(st, tbl))
|
||||||
end
|
end
|
||||||
|
|
||||||
function sproto:pdecode(typename, bin)
|
function sproto:pdecode(typename, ...)
|
||||||
local st = querytype(self, typename)
|
local st = querytype(self, typename)
|
||||||
return core.decode(st, core.unpack(bin))
|
return core.decode(st, core.unpack(...))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function queryproto(self, pname)
|
local function queryproto(self, pname)
|
||||||
@@ -89,6 +99,29 @@ local function queryproto(self, pname)
|
|||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function sproto:request_encode(protoname, tbl)
|
||||||
|
local p = queryproto(self, protoname)
|
||||||
|
return core.encode(p.request,tbl) , p.tag
|
||||||
|
end
|
||||||
|
|
||||||
|
function sproto:response_encode(protoname, tbl)
|
||||||
|
local p = queryproto(self, protoname)
|
||||||
|
return core.encode(p.response,tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
function sproto:request_decode(protoname, ...)
|
||||||
|
local p = queryproto(self, protoname)
|
||||||
|
return core.decode(p.request,...) , p.name
|
||||||
|
end
|
||||||
|
|
||||||
|
function sproto:response_decode(protoname, ...)
|
||||||
|
local p = queryproto(self, protoname)
|
||||||
|
return core.decode(p.response,...)
|
||||||
|
end
|
||||||
|
|
||||||
|
sproto.pack = core.pack
|
||||||
|
sproto.unpack = core.unpack
|
||||||
|
|
||||||
local header_tmp = {}
|
local header_tmp = {}
|
||||||
|
|
||||||
local function gen_response(self, response, session)
|
local function gen_response(self, response, session)
|
||||||
|
|||||||
@@ -8,15 +8,19 @@ function loader.register(filename, index)
|
|||||||
local f = assert(io.open(filename), "Can't open sproto file")
|
local f = assert(io.open(filename), "Can't open sproto file")
|
||||||
local data = f:read "a"
|
local data = f:read "a"
|
||||||
f:close()
|
f:close()
|
||||||
local bin = parser.parse(data)
|
local sp = core.newproto(parser.parse(data))
|
||||||
core.saveproto(bin, index)
|
core.saveproto(sp, index)
|
||||||
end
|
end
|
||||||
|
|
||||||
loader.save = core.saveproto
|
function loader.save(bin, index)
|
||||||
|
local sp = core.newproto(bin)
|
||||||
|
core.saveproto(sp, index)
|
||||||
|
end
|
||||||
|
|
||||||
function loader.load(index)
|
function loader.load(index)
|
||||||
local bin, sz = core.loadproto(index)
|
local sp = core.loadproto(index)
|
||||||
return sproto.new(bin,sz)
|
-- no __gc in metatable
|
||||||
|
return sproto.sharenew(sp)
|
||||||
end
|
end
|
||||||
|
|
||||||
return loader
|
return loader
|
||||||
|
|||||||
@@ -1,6 +1,40 @@
|
|||||||
local lpeg = require "lpeg"
|
local lpeg = require "lpeg"
|
||||||
local table = require "table"
|
local table = require "table"
|
||||||
|
|
||||||
|
local packbytes
|
||||||
|
local packvalue
|
||||||
|
|
||||||
|
if _VERSION == "Lua 5.3" then
|
||||||
|
function packbytes(str)
|
||||||
|
return string.pack("<s4",str)
|
||||||
|
end
|
||||||
|
|
||||||
|
function packvalue(id)
|
||||||
|
id = (id + 1) * 2
|
||||||
|
return string.pack("<I2",id)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
function packbytes(str)
|
||||||
|
local size = #str
|
||||||
|
local a = size % 256
|
||||||
|
size = math.floor(size / 256)
|
||||||
|
local b = size % 256
|
||||||
|
size = math.floor(size / 256)
|
||||||
|
local c = size % 256
|
||||||
|
size = math.floor(size / 256)
|
||||||
|
local d = size
|
||||||
|
return string.char(a)..string.char(b)..string.char(c)..string.char(d) .. str
|
||||||
|
end
|
||||||
|
|
||||||
|
function packvalue(id)
|
||||||
|
id = (id + 1) * 2
|
||||||
|
assert(id >=0 and id < 65536)
|
||||||
|
local a = id % 256
|
||||||
|
local b = math.floor(id / 256)
|
||||||
|
return string.char(a) .. string.char(b)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local P = lpeg.P
|
local P = lpeg.P
|
||||||
local S = lpeg.S
|
local S = lpeg.S
|
||||||
local R = lpeg.R
|
local R = lpeg.R
|
||||||
@@ -35,6 +69,7 @@ local word = alpha * alnum ^ 0
|
|||||||
local name = C(word)
|
local name = C(word)
|
||||||
local typename = C(word * ("." * word) ^ 0)
|
local typename = C(word * ("." * word) ^ 0)
|
||||||
local tag = R"09" ^ 1 / tonumber
|
local tag = R"09" ^ 1 / tonumber
|
||||||
|
local mainkey = "(" * blank0 * name * blank0 * ")"
|
||||||
|
|
||||||
local function multipat(pat)
|
local function multipat(pat)
|
||||||
return Ct(blank0 * (pat * blanks) ^ 0 * pat^0 * blank0)
|
return Ct(blank0 * (pat * blanks) ^ 0 * pat^0 * blank0)
|
||||||
@@ -46,10 +81,10 @@ end
|
|||||||
|
|
||||||
local typedef = P {
|
local typedef = P {
|
||||||
"ALL",
|
"ALL",
|
||||||
FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename)),
|
FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename * mainkey^0)),
|
||||||
STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}",
|
STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}",
|
||||||
TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ),
|
TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ),
|
||||||
SUBPROTO = Ct((C"request" + C"response") * blanks * (name + V"STRUCT")),
|
SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")),
|
||||||
PROTOCOL = namedpat("protocol", name * blanks * tag * blank0 * P"{" * multipat(V"SUBPROTO") * P"}"),
|
PROTOCOL = namedpat("protocol", name * blanks * tag * blank0 * P"{" * multipat(V"SUBPROTO") * P"}"),
|
||||||
ALL = multipat(V"TYPE" + V"PROTOCOL"),
|
ALL = multipat(V"TYPE" + V"PROTOCOL"),
|
||||||
}
|
}
|
||||||
@@ -97,6 +132,11 @@ function convert.type(all, obj)
|
|||||||
field.array = true
|
field.array = true
|
||||||
fieldtype = f[4]
|
fieldtype = f[4]
|
||||||
end
|
end
|
||||||
|
local mainkey = f[5]
|
||||||
|
if mainkey then
|
||||||
|
assert(field.array)
|
||||||
|
field.key = mainkey
|
||||||
|
end
|
||||||
field.typename = fieldtype
|
field.typename = fieldtype
|
||||||
else
|
else
|
||||||
assert(f.type == "type") -- nest type
|
assert(f.type == "type") -- nest type
|
||||||
@@ -146,6 +186,32 @@ local function checktype(types, ptype, t)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function check_protocol(r)
|
||||||
|
local map = {}
|
||||||
|
local type = r.type
|
||||||
|
for name, v in pairs(r.protocol) do
|
||||||
|
local tag = v.tag
|
||||||
|
local request = v.request
|
||||||
|
local response = v.response
|
||||||
|
local p = map[tag]
|
||||||
|
|
||||||
|
if p then
|
||||||
|
error(string.format("redefined protocol tag %d at %s", tag, name))
|
||||||
|
end
|
||||||
|
|
||||||
|
if request and not type[request] then
|
||||||
|
error(string.format("Undefined request type %s in protocol %s", request, name))
|
||||||
|
end
|
||||||
|
|
||||||
|
if response and not type[response] then
|
||||||
|
error(string.format("Undefined response type %s in protocol %s", response, name))
|
||||||
|
end
|
||||||
|
|
||||||
|
map[tag] = v
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
local function flattypename(r)
|
local function flattypename(r)
|
||||||
for typename, t in pairs(r.type) do
|
for typename, t in pairs(r.type) do
|
||||||
for _, f in pairs(t) do
|
for _, f in pairs(t) do
|
||||||
@@ -164,7 +230,7 @@ end
|
|||||||
local function parser(text,filename)
|
local function parser(text,filename)
|
||||||
local state = { file = filename, pos = 0, line = 1 }
|
local state = { file = filename, pos = 0, line = 1 }
|
||||||
local r = lpeg.match(proto * -1 + exception , text , 1, state )
|
local r = lpeg.match(proto * -1 + exception , text , 1, state )
|
||||||
return flattypename(adjust(r))
|
return flattypename(check_protocol(adjust(r)))
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -176,6 +242,7 @@ end
|
|||||||
type 2 : integer
|
type 2 : integer
|
||||||
tag 3 : integer
|
tag 3 : integer
|
||||||
array 4 : boolean
|
array 4 : boolean
|
||||||
|
key 5 : integer # If key exists, array must be true, and it's a map.
|
||||||
}
|
}
|
||||||
name 0 : string
|
name 0 : string
|
||||||
fields 1 : *field
|
fields 1 : *field
|
||||||
@@ -194,25 +261,18 @@ end
|
|||||||
}
|
}
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local function packbytes(str)
|
|
||||||
str = string.pack("<s4",str)
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
local function packvalue(id)
|
|
||||||
id = (id + 1) * 2
|
|
||||||
local str = string.pack("<I2", id)
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
local function packfield(f)
|
local function packfield(f)
|
||||||
local strtbl = {}
|
local strtbl = {}
|
||||||
if f.array then
|
if f.array then
|
||||||
table.insert(strtbl, "\5\0") -- 5 fields
|
if f.key then
|
||||||
|
table.insert(strtbl, "\6\0") -- 6 fields
|
||||||
|
else
|
||||||
|
table.insert(strtbl, "\5\0") -- 5 fields
|
||||||
|
end
|
||||||
else
|
else
|
||||||
table.insert(strtbl, "\4\0") -- 4 fields
|
table.insert(strtbl, "\4\0") -- 4 fields
|
||||||
end
|
end
|
||||||
table.insert(strtbl, "\0\0") -- name (tag = 0, ref =0)
|
table.insert(strtbl, "\0\0") -- name (tag = 0, ref an object)
|
||||||
if f.buildin then
|
if f.buildin then
|
||||||
table.insert(strtbl, packvalue(f.buildin)) -- buildin (tag = 1)
|
table.insert(strtbl, packvalue(f.buildin)) -- buildin (tag = 1)
|
||||||
table.insert(strtbl, "\1\0") -- skip (tag = 2)
|
table.insert(strtbl, "\1\0") -- skip (tag = 2)
|
||||||
@@ -225,7 +285,10 @@ local function packfield(f)
|
|||||||
if f.array then
|
if f.array then
|
||||||
table.insert(strtbl, packvalue(1)) -- array = true (tag = 4)
|
table.insert(strtbl, packvalue(1)) -- array = true (tag = 4)
|
||||||
end
|
end
|
||||||
table.insert(strtbl, packbytes(f.name))
|
if f.key then
|
||||||
|
table.insert(strtbl, packvalue(f.key)) -- key tag (tag = 5)
|
||||||
|
end
|
||||||
|
table.insert(strtbl, packbytes(f.name)) -- external object (name)
|
||||||
return packbytes(table.concat(strtbl))
|
return packbytes(table.concat(strtbl))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -238,11 +301,22 @@ local function packtype(name, t, alltypes)
|
|||||||
tmp.tag = f.tag
|
tmp.tag = f.tag
|
||||||
|
|
||||||
tmp.buildin = buildin_types[f.typename]
|
tmp.buildin = buildin_types[f.typename]
|
||||||
|
local subtype
|
||||||
if not tmp.buildin then
|
if not tmp.buildin then
|
||||||
tmp.type = assert(alltypes[f.typename])
|
subtype = assert(alltypes[f.typename])
|
||||||
|
tmp.type = subtype.id
|
||||||
else
|
else
|
||||||
tmp.type = nil
|
tmp.type = nil
|
||||||
end
|
end
|
||||||
|
if f.key then
|
||||||
|
tmp.key = subtype.fields[f.key]
|
||||||
|
if not tmp.key then
|
||||||
|
error("Invalid map index :" .. f.key)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tmp.key = nil
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(fields, packfield(tmp))
|
table.insert(fields, packfield(tmp))
|
||||||
end
|
end
|
||||||
local data
|
local data
|
||||||
@@ -274,6 +348,7 @@ local function packproto(name, p, alltypes)
|
|||||||
if request == nil then
|
if request == nil then
|
||||||
error(string.format("Protocol %s request type %s not found", name, p.request))
|
error(string.format("Protocol %s request type %s not found", name, p.request))
|
||||||
end
|
end
|
||||||
|
request = request.id
|
||||||
end
|
end
|
||||||
local tmp = {
|
local tmp = {
|
||||||
"\4\0", -- 4 fields
|
"\4\0", -- 4 fields
|
||||||
@@ -284,12 +359,12 @@ local function packproto(name, p, alltypes)
|
|||||||
tmp[1] = "\2\0"
|
tmp[1] = "\2\0"
|
||||||
else
|
else
|
||||||
if p.request then
|
if p.request then
|
||||||
table.insert(tmp, packvalue(alltypes[p.request])) -- request typename (tag=2)
|
table.insert(tmp, packvalue(alltypes[p.request].id)) -- request typename (tag=2)
|
||||||
else
|
else
|
||||||
table.insert(tmp, "\1\0")
|
table.insert(tmp, "\1\0")
|
||||||
end
|
end
|
||||||
if p.response then
|
if p.response then
|
||||||
table.insert(tmp, packvalue(alltypes[p.response])) -- request typename (tag=3)
|
table.insert(tmp, packvalue(alltypes[p.response].id)) -- request typename (tag=3)
|
||||||
else
|
else
|
||||||
tmp[1] = "\3\0"
|
tmp[1] = "\3\0"
|
||||||
end
|
end
|
||||||
@@ -312,7 +387,13 @@ local function packgroup(t,p)
|
|||||||
end
|
end
|
||||||
table.sort(alltypes) -- make result stable
|
table.sort(alltypes) -- make result stable
|
||||||
for idx, name in ipairs(alltypes) do
|
for idx, name in ipairs(alltypes) do
|
||||||
alltypes[name] = idx - 1
|
local fields = {}
|
||||||
|
for _, type_fields in ipairs(t[name]) do
|
||||||
|
if buildin_types[type_fields.typename] then
|
||||||
|
fields[type_fields.name] = type_fields.tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
alltypes[name] = { id = idx - 1, fields = fields }
|
||||||
end
|
end
|
||||||
tt = {}
|
tt = {}
|
||||||
for _,name in ipairs(alltypes) do
|
for _,name in ipairs(alltypes) do
|
||||||
|
|||||||
@@ -156,3 +156,12 @@ snlua_release(struct snlua *l) {
|
|||||||
lua_close(l->L);
|
lua_close(l->L);
|
||||||
skynet_free(l);
|
skynet_free(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
snlua_signal(struct snlua *l, int signal) {
|
||||||
|
skynet_error(l->ctx, "recv a signal %d", signal);
|
||||||
|
#ifdef lua_checksig
|
||||||
|
// If our lua support signal (modified lua version by skynet), trigger it.
|
||||||
|
skynet_sig_L = l->L;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,14 +5,6 @@ local cluster = require "cluster.core"
|
|||||||
|
|
||||||
local config_name = skynet.getenv "cluster"
|
local config_name = skynet.getenv "cluster"
|
||||||
local node_address = {}
|
local node_address = {}
|
||||||
|
|
||||||
local function loadconfig()
|
|
||||||
local f = assert(io.open(config_name))
|
|
||||||
local source = f:read "*a"
|
|
||||||
f:close()
|
|
||||||
assert(load(source, "@"..config_name, "t", node_address))()
|
|
||||||
end
|
|
||||||
|
|
||||||
local node_session = {}
|
local node_session = {}
|
||||||
local command = {}
|
local command = {}
|
||||||
|
|
||||||
@@ -37,6 +29,24 @@ end
|
|||||||
|
|
||||||
local node_channel = setmetatable({}, { __index = open_channel })
|
local node_channel = setmetatable({}, { __index = open_channel })
|
||||||
|
|
||||||
|
local function loadconfig()
|
||||||
|
local f = assert(io.open(config_name))
|
||||||
|
local source = f:read "*a"
|
||||||
|
f:close()
|
||||||
|
local tmp = {}
|
||||||
|
assert(load(source, "@"..config_name, "t", tmp))()
|
||||||
|
for name,address in pairs(tmp) do
|
||||||
|
assert(type(address) == "string")
|
||||||
|
if node_address[name] ~= address then
|
||||||
|
-- address changed
|
||||||
|
if rawget(node_channel, name) then
|
||||||
|
node_channel[name] = nil -- reset connection
|
||||||
|
end
|
||||||
|
node_address[name] = address
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function command.reload()
|
function command.reload()
|
||||||
loadconfig()
|
loadconfig()
|
||||||
skynet.ret(skynet.pack(nil))
|
skynet.ret(skynet.pack(nil))
|
||||||
|
|||||||
@@ -50,8 +50,11 @@ end
|
|||||||
|
|
||||||
local function docmd(cmdline, print, fd)
|
local function docmd(cmdline, print, fd)
|
||||||
local split = split_cmdline(cmdline)
|
local split = split_cmdline(cmdline)
|
||||||
table.insert(split, fd)
|
local command = split[1]
|
||||||
local cmd = COMMAND[split[1]]
|
if command == "debug" then
|
||||||
|
table.insert(split, fd)
|
||||||
|
end
|
||||||
|
local cmd = COMMAND[command]
|
||||||
local ok, list
|
local ok, list
|
||||||
if cmd then
|
if cmd then
|
||||||
ok, list = pcall(cmd, select(2,table.unpack(split)))
|
ok, list = pcall(cmd, select(2,table.unpack(split)))
|
||||||
@@ -126,6 +129,7 @@ function COMMAND.help()
|
|||||||
logoff = "logoff address",
|
logoff = "logoff address",
|
||||||
log = "launch a new lua service with log",
|
log = "launch a new lua service with log",
|
||||||
debug = "debug address : debug a lua service",
|
debug = "debug address : debug a lua service",
|
||||||
|
signal = "signal address sig",
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -244,3 +248,12 @@ function COMMAND.logoff(address)
|
|||||||
address = adjust_address(address)
|
address = adjust_address(address)
|
||||||
core.command("LOGOFF", skynet.address(address))
|
core.command("LOGOFF", skynet.address(address))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function COMMAND.signal(address, sig)
|
||||||
|
address = skynet.address(adjust_address(address))
|
||||||
|
if sig then
|
||||||
|
core.command("SIGNAL", string.format("%s %d",address,sig))
|
||||||
|
else
|
||||||
|
core.command("SIGNAL", address)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ function CMD.new(name, t)
|
|||||||
elseif dt == "string" then
|
elseif dt == "string" then
|
||||||
value = setmetatable({}, env_mt)
|
value = setmetatable({}, env_mt)
|
||||||
local f = load(t, "=" .. name, "t", value)
|
local f = load(t, "=" .. name, "t", value)
|
||||||
f()
|
assert(skynet.pcall(f))
|
||||||
setmetatable(value, nil)
|
setmetatable(value, nil)
|
||||||
elseif dt == "nil" then
|
elseif dt == "nil" then
|
||||||
value = {}
|
value = {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef __MALLOC_HOOK_H
|
#ifndef SKYNET_MALLOC_HOOK_H
|
||||||
#define __MALLOC_HOOK_H
|
#define SKYNET_MALLOC_HOOK_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -10,5 +10,5 @@ extern size_t mallctl_int64(const char* name, size_t* newval);
|
|||||||
extern int mallctl_opt(const char* name, int* newval);
|
extern int mallctl_opt(const char* name, int* newval);
|
||||||
extern void dump_c_mem(void);
|
extern void dump_c_mem(void);
|
||||||
|
|
||||||
#endif /* __MALLOC_HOOK_H */
|
#endif /* SKYNET_MALLOC_HOOK_H */
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef _RWLOCK_H_
|
#ifndef SKYNET_RWLOCK_H
|
||||||
#define _RWLOCK_H_
|
#define SKYNET_RWLOCK_H
|
||||||
|
|
||||||
struct rwlock {
|
struct rwlock {
|
||||||
int write;
|
int write;
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ skynet_handle_retire(uint32_t handle) {
|
|||||||
struct skynet_context * ctx = s->slot[hash];
|
struct skynet_context * ctx = s->slot[hash];
|
||||||
|
|
||||||
if (ctx != NULL && skynet_context_handle(ctx) == handle) {
|
if (ctx != NULL && skynet_context_handle(ctx) == handle) {
|
||||||
skynet_context_release(ctx);
|
|
||||||
s->slot[hash] = NULL;
|
s->slot[hash] = NULL;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
int i;
|
int i;
|
||||||
@@ -92,10 +91,17 @@ skynet_handle_retire(uint32_t handle) {
|
|||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
s->name_count = j;
|
s->name_count = j;
|
||||||
|
} else {
|
||||||
|
ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rwlock_wunlock(&s->lock);
|
rwlock_wunlock(&s->lock);
|
||||||
|
|
||||||
|
if (ctx) {
|
||||||
|
// release ctx may call skynet_handle_* , so wunlock first.
|
||||||
|
skynet_context_release(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ _query(const char * name) {
|
|||||||
static int
|
static int
|
||||||
_open_sym(struct skynet_module *mod) {
|
_open_sym(struct skynet_module *mod) {
|
||||||
size_t name_size = strlen(mod->name);
|
size_t name_size = strlen(mod->name);
|
||||||
char tmp[name_size + 9]; // create/init/release , longest name is release (7)
|
char tmp[name_size + 9]; // create/init/release/signal , longest name is release (7)
|
||||||
memcpy(tmp, mod->name, name_size);
|
memcpy(tmp, mod->name, name_size);
|
||||||
strcpy(tmp+name_size, "_create");
|
strcpy(tmp+name_size, "_create");
|
||||||
mod->create = dlsym(mod->module, tmp);
|
mod->create = dlsym(mod->module, tmp);
|
||||||
@@ -83,6 +83,8 @@ _open_sym(struct skynet_module *mod) {
|
|||||||
mod->init = dlsym(mod->module, tmp);
|
mod->init = dlsym(mod->module, tmp);
|
||||||
strcpy(tmp+name_size, "_release");
|
strcpy(tmp+name_size, "_release");
|
||||||
mod->release = dlsym(mod->module, tmp);
|
mod->release = dlsym(mod->module, tmp);
|
||||||
|
strcpy(tmp+name_size, "_signal");
|
||||||
|
mod->signal = dlsym(mod->module, tmp);
|
||||||
|
|
||||||
return mod->init == NULL;
|
return mod->init == NULL;
|
||||||
}
|
}
|
||||||
@@ -150,6 +152,13 @@ skynet_module_instance_release(struct skynet_module *m, void *inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
skynet_module_instance_signal(struct skynet_module *m, void *inst, int signal) {
|
||||||
|
if (m->signal) {
|
||||||
|
m->signal(inst, signal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
skynet_module_init(const char *path) {
|
skynet_module_init(const char *path) {
|
||||||
struct modules *m = skynet_malloc(sizeof(*m));
|
struct modules *m = skynet_malloc(sizeof(*m));
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ struct skynet_context;
|
|||||||
typedef void * (*skynet_dl_create)(void);
|
typedef void * (*skynet_dl_create)(void);
|
||||||
typedef int (*skynet_dl_init)(void * inst, struct skynet_context *, const char * parm);
|
typedef int (*skynet_dl_init)(void * inst, struct skynet_context *, const char * parm);
|
||||||
typedef void (*skynet_dl_release)(void * inst);
|
typedef void (*skynet_dl_release)(void * inst);
|
||||||
|
typedef void (*skynet_dl_signal)(void * inst, int signal);
|
||||||
|
|
||||||
struct skynet_module {
|
struct skynet_module {
|
||||||
const char * name;
|
const char * name;
|
||||||
@@ -13,6 +14,7 @@ struct skynet_module {
|
|||||||
skynet_dl_create create;
|
skynet_dl_create create;
|
||||||
skynet_dl_init init;
|
skynet_dl_init init;
|
||||||
skynet_dl_release release;
|
skynet_dl_release release;
|
||||||
|
skynet_dl_signal signal;
|
||||||
};
|
};
|
||||||
|
|
||||||
void skynet_module_insert(struct skynet_module *mod);
|
void skynet_module_insert(struct skynet_module *mod);
|
||||||
@@ -20,6 +22,7 @@ struct skynet_module * skynet_module_query(const char * name);
|
|||||||
void * skynet_module_instance_create(struct skynet_module *);
|
void * skynet_module_instance_create(struct skynet_module *);
|
||||||
int skynet_module_instance_init(struct skynet_module *, void * inst, struct skynet_context *ctx, const char * parm);
|
int skynet_module_instance_init(struct skynet_module *, void * inst, struct skynet_context *ctx, const char * parm);
|
||||||
void skynet_module_instance_release(struct skynet_module *, void *inst);
|
void skynet_module_instance_release(struct skynet_module *, void *inst);
|
||||||
|
void skynet_module_instance_signal(struct skynet_module *, void *inst, int signal);
|
||||||
|
|
||||||
void skynet_module_init(const char *path);
|
void skynet_module_init(const char *path);
|
||||||
|
|
||||||
|
|||||||
@@ -589,6 +589,26 @@ cmd_logoff(struct skynet_context * context, const char * param) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
cmd_signal(struct skynet_context * context, const char * param) {
|
||||||
|
uint32_t handle = tohandle(context, param);
|
||||||
|
if (handle == 0)
|
||||||
|
return NULL;
|
||||||
|
struct skynet_context * ctx = skynet_handle_grab(handle);
|
||||||
|
if (ctx == NULL)
|
||||||
|
return NULL;
|
||||||
|
param = strchr(param, ' ');
|
||||||
|
int sig = 0;
|
||||||
|
if (param) {
|
||||||
|
sig = strtol(param, NULL, 0);
|
||||||
|
}
|
||||||
|
// NOTICE: the signal function should be thread safe.
|
||||||
|
skynet_module_instance_signal(ctx->mod, ctx->instance, sig);
|
||||||
|
|
||||||
|
skynet_context_release(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct command_func cmd_funcs[] = {
|
static struct command_func cmd_funcs[] = {
|
||||||
{ "TIMEOUT", cmd_timeout },
|
{ "TIMEOUT", cmd_timeout },
|
||||||
{ "REG", cmd_reg },
|
{ "REG", cmd_reg },
|
||||||
@@ -607,6 +627,7 @@ static struct command_func cmd_funcs[] = {
|
|||||||
{ "MQLEN", cmd_mqlen },
|
{ "MQLEN", cmd_mqlen },
|
||||||
{ "LOGON", cmd_logon },
|
{ "LOGON", cmd_logon },
|
||||||
{ "LOGOFF", cmd_logoff },
|
{ "LOGOFF", cmd_logoff },
|
||||||
|
{ "SIGNAL", cmd_signal },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
11
test/testdns.lua
Normal file
11
test/testdns.lua
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
local skynet = require "skynet"
|
||||||
|
local dns = require "dns"
|
||||||
|
|
||||||
|
skynet.start(function()
|
||||||
|
print("nameserver:", dns.server()) -- set nameserver
|
||||||
|
-- you can specify the server like dns.server("8.8.4.4", 53)
|
||||||
|
local ip, ips = dns.resolve "github.com"
|
||||||
|
for k,v in ipairs(ips) do
|
||||||
|
print("github.com",v)
|
||||||
|
end
|
||||||
|
end)
|
||||||
@@ -1,16 +1,24 @@
|
|||||||
local skynet = require "skynet"
|
local skynet = require "skynet"
|
||||||
local httpc = require "http.httpc"
|
local httpc = require "http.httpc"
|
||||||
|
local dns = require "dns"
|
||||||
|
|
||||||
skynet.start(function()
|
skynet.start(function()
|
||||||
print("GET baidu.com")
|
print("GET baidu.com")
|
||||||
local header = {}
|
local respheader = {}
|
||||||
local status, body = httpc.get("baidu.com", "/", header)
|
local status, body = httpc.get("baidu.com", "/", respheader)
|
||||||
print("[header] =====>")
|
print("[header] =====>")
|
||||||
for k,v in pairs(header) do
|
for k,v in pairs(respheader) do
|
||||||
print(k,v)
|
print(k,v)
|
||||||
end
|
end
|
||||||
print("[body] =====>", status)
|
print("[body] =====>", status)
|
||||||
print(body)
|
print(body)
|
||||||
|
|
||||||
|
local respheader = {}
|
||||||
|
dns.server()
|
||||||
|
local ip = dns.resolve "baidu.com"
|
||||||
|
print(string.format("GET %s (baidu.com)", ip))
|
||||||
|
local status, body = httpc.get("baidu.com", "/", respheader, { host = "baidu.com" })
|
||||||
|
print(status)
|
||||||
|
|
||||||
skynet.exit()
|
skynet.exit()
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -3,16 +3,15 @@ local socket = require "socket"
|
|||||||
|
|
||||||
local function server()
|
local function server()
|
||||||
local host
|
local host
|
||||||
host = socket.udp(function(data, sz, from)
|
host = socket.udp(function(str, from)
|
||||||
local str = skynet.tostring(data,sz) -- skynet.tostring should call only once, because it will free the pointer data
|
|
||||||
print("server recv", str, socket.udp_address(from))
|
print("server recv", str, socket.udp_address(from))
|
||||||
socket.sendto(host, from, "OK " .. str)
|
socket.sendto(host, from, "OK " .. str)
|
||||||
end , "127.0.0.1", 8765) -- bind an address
|
end , "127.0.0.1", 8765) -- bind an address
|
||||||
end
|
end
|
||||||
|
|
||||||
local function client()
|
local function client()
|
||||||
local c = socket.udp(function(data, sz, from)
|
local c = socket.udp(function(str, from)
|
||||||
print("client recv", skynet.tostring(data,sz), socket.udp_address(from))
|
print("client recv", str, socket.udp_address(from))
|
||||||
end)
|
end)
|
||||||
socket.udp_connect(c, "127.0.0.1", 8765)
|
socket.udp_connect(c, "127.0.0.1", 8765)
|
||||||
for i=1,20 do
|
for i=1,20 do
|
||||||
|
|||||||
Reference in New Issue
Block a user