Compare commits

..

11 Commits

Author SHA1 Message Date
Cloud Wu
35a5b99bed release alpha5 2015-04-27 10:45:31 +08:00
Cloud Wu
98af25d109 better error log, see pr #260 2015-04-24 14:31:18 +08:00
Cloud Wu
cd3391461c add skynet.pcall for hotfix use (call a function with require) 2015-04-22 17:01:03 +08:00
Cloud Wu
e3b7f86075 cluster reload should reset old connection to update address:port 2015-04-21 15:35:29 +08:00
Cloud Wu
86d5865457 bugfix: wunlock first, and then release context. (may dead lock) 2015-04-18 21:11:57 +08:00
Cloud Wu
7b783076e5 use hmac_hash 2015-04-16 10:41:23 +08:00
Cloud Wu
57c0ad694c add hmac_hash to simplify hmac64(hashkey(d), key) 2015-04-16 10:35:47 +08:00
Cloud Wu
f55a31c24f sproto.request_decode returns name 2015-04-15 22:01:01 +08:00
Cloud Wu
843095afc6 add snax.printf 2015-04-15 16:52:55 +08:00
Cloud Wu
a6bad52181 add sproto new api 2015-04-14 23:38:49 +08:00
Cloud Wu
012d98380d merge lua bugfix from lua offical bugs page 2015-04-13 17:14:08 +08:00
17 changed files with 152 additions and 45 deletions

View File

@@ -94,6 +94,7 @@ typedef struct CallInfo {
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#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)

View File

@@ -303,12 +303,18 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */
return res;
else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */
luaG_ordererror(L, l, r);
return !res;
else { /* try 'lt': */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
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'.
** L == NULL means raw equality (no metamethods)
@@ -564,11 +570,11 @@ void luaV_finishOp (lua_State *L) {
case OP_LE: case OP_LT: case OP_EQ: {
int res = !l_isfalse(L->top - 1);
L->top--;
/* metamethod should not be called when operand is K */
lua_assert(!ISK(GETARG_B(inst)));
if (op == OP_LE && /* "<=" using "<" instead? */
ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE)))
res = !res; /* invert result */
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
lua_assert(op == OP_LE);
ci->callstatus ^= CIST_LEQ; /* clear mark */
res = !res; /* negate result */
}
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
if (res != GETARG_A(inst)) /* condition failed? */
ci->u.l.savedpc++; /* skip jump instruction */

View File

@@ -1,3 +1,12 @@
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

View File

@@ -5,6 +5,9 @@ skynet.start(function()
local sdb = skynet.newservice("simpledb")
skynet.name(".simpledb", sdb)
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", "b"))
cluster.open "db"
cluster.open "db2"
end)

View File

@@ -5,4 +5,5 @@ skynet.start(function()
local proxy = cluster.proxy("db", ".simpledb")
print(skynet.call(proxy, "lua", "GET", "a"))
print(cluster.call("db", ".simpledb", "GET", "a"))
print(cluster.call("db2", ".simpledb", "GET", "b"))
end)

View File

@@ -1 +1,2 @@
db = "127.0.0.1:2528"
db2 = "127.0.0.1:2529"

View File

@@ -602,11 +602,7 @@ read64(lua_State *L, uint32_t xx[2], uint32_t yy[2]) {
}
static int
lhmac64(lua_State *L) {
uint32_t x[2], y[2];
read64(L, x, y);
uint32_t result[2];
hmac(x,y,result);
pushqword(lua_State *L, uint32_t result[2]) {
uint8_t tmp[8];
tmp[0] = result[0] & 0xff;
tmp[1] = (result[0] >> 8 )& 0xff;
@@ -621,6 +617,40 @@ lhmac64(lua_State *L) {
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
// The biggest 64bit prime
@@ -858,6 +888,7 @@ luaopen_crypt(lua_State *L) {
{ "base64decode", lb64decode },
{ "sha1", lsha1 },
{ "hmac_sha1", lhmac_sha1 },
{ "hmac_hash", lhmac_hash },
{ NULL, NULL },
};
luaL_newlib(L,l);

View File

@@ -620,8 +620,10 @@ end
local function init_all()
local funcs = init_func
init_func = nil
for k,v in pairs(funcs) do
v()
if funcs then
for k,v in pairs(funcs) do
v()
end
end
end
@@ -632,8 +634,12 @@ local function init_template(start)
init_all()
end
function skynet.pcall(start)
return xpcall(init_template, debug.traceback, start)
end
local function init_service(start)
local ok, err = xpcall(init_template, debug.traceback, start)
local ok, err = skynet.pcall(start)
if not ok then
skynet.error("init service failed: " .. tostring(err))
skynet.send(".launcher","lua", "ERROR")

View File

@@ -49,7 +49,7 @@ end
function dbgcmd.RUN(source, filename)
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"
skynet.ret(skynet.pack(table.concat(output, "\n")))
end

View File

@@ -18,7 +18,7 @@ local function getupvaluetable(u, func, unique)
end
end
return function(source, filename , ...)
return function(skynet, source, filename , ...)
if filename then
filename = "@" .. filename
else
@@ -56,7 +56,7 @@ return function(source, filename , ...)
if not func then
return { err }
end
local ok, err = xpcall(func, debug.traceback)
local ok, err = skynet.pcall(func)
if not ok then
table.insert(output, err)
end

View File

@@ -162,4 +162,8 @@ function snax.hotfix(obj, source, ...)
return test_result(skynet_call(obj.handle, "snax", t.system.hotfix, source, ...))
end
function snax.printf(fmt, ...)
skynet.error(string.format(fmt, ...))
end
return snax

View File

@@ -33,17 +33,17 @@ Success:
]]
local socket_error = {}
local function assert_socket(v, fd)
local function assert_socket(service, v, fd)
if v then
return v
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)
end
end
local function write(fd, text)
assert_socket(socket.write(fd, text), fd)
local function write(service, fd, text)
assert_socket(service, socket.write(fd, text), fd)
end
local function launch_slave(auth_handler)
@@ -57,27 +57,27 @@ local function launch_slave(auth_handler)
socket.limit(fd, 8192)
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)
if #clientkey ~= 8 then
error "Invalid client key"
end
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 response = assert_socket(socket.readline(fd), fd)
local response = assert_socket("auth", socket.readline(fd), fd)
local hmac = crypt.hmac64(challenge, secret)
if hmac ~= crypt.base64decode(response) then
write(fd, "400 Bad Request\n")
write("auth", fd, "400 Bad Request\n")
error "challenge failed"
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))
@@ -91,7 +91,11 @@ local function launch_slave(auth_handler)
if ok then
skynet.ret(skynet.pack(err, ...))
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
@@ -108,13 +112,15 @@ local function accept(conf, s, fd, addr)
socket.start(fd)
if not ok then
write(fd, "401 Unauthorized\n")
if ok ~= nil then
write("response 401", fd, "401 Unauthorized\n")
end
error(server)
end
if not conf.multilogin 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))
end
@@ -127,9 +133,9 @@ local function accept(conf, s, fd, addr)
if ok then
err = err or ""
write(fd, "200 "..crypt.base64encode(err).."\n")
write("response 200",fd, "200 "..crypt.base64encode(err).."\n")
else
write(fd, "403 Forbidden\n")
write("response 403",fd, "403 Forbidden\n")
error(err)
end
end

View File

@@ -178,7 +178,7 @@ function server.start(conf)
end
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
return "401 Unauthorized"
end

View File

@@ -99,6 +99,29 @@ local function queryproto(self, pname)
return v
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 function gen_response(self, response, session)

View File

@@ -5,14 +5,6 @@ local cluster = require "cluster.core"
local config_name = skynet.getenv "cluster"
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 command = {}
@@ -37,6 +29,24 @@ end
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()
loadconfig()
skynet.ret(skynet.pack(nil))

View File

@@ -44,7 +44,7 @@ function CMD.new(name, t)
elseif dt == "string" then
value = setmetatable({}, env_mt)
local f = load(t, "=" .. name, "t", value)
f()
assert(skynet.pcall(f))
setmetatable(value, nil)
elseif dt == "nil" then
value = {}

View File

@@ -77,7 +77,6 @@ skynet_handle_retire(uint32_t handle) {
struct skynet_context * ctx = s->slot[hash];
if (ctx != NULL && skynet_context_handle(ctx) == handle) {
skynet_context_release(ctx);
s->slot[hash] = NULL;
ret = 1;
int i;
@@ -92,10 +91,17 @@ skynet_handle_retire(uint32_t handle) {
++j;
}
s->name_count = j;
} else {
ctx = NULL;
}
rwlock_wunlock(&s->lock);
if (ctx) {
// release ctx may call skynet_handle_* , so wunlock first.
skynet_context_release(ctx);
}
return ret;
}