simplify clientsocket lib

This commit is contained in:
Cloud Wu
2014-07-19 14:22:24 +08:00
parent d41c9db019
commit a8b80cd73e
6 changed files with 171 additions and 207 deletions

View File

@@ -2,6 +2,7 @@ Dev version
-----------
* skynet.exit will quit service immediately.
* Add snax.gateserver, snax.loginserver, snax.msgserver
* Simplify clientsocket lib
v0.4.2 (2014-7-14)
-----------

View File

@@ -2,30 +2,47 @@ package.cpath = "luaclib/?.so"
local socket = require "clientsocket"
local cjson = require "cjson"
local bit32 = require "bit32"
local fd = socket.connect("127.0.0.1", 8888)
local fd = assert(socket.connect("127.0.0.1", 8888))
local last
local result = {}
local function send_package(fd, pack)
local size = #pack
local package = string.format("%c%c%s",
bit32.extract(size,8,8),
bit32.extract(size,0,8),
pack)
local function dispatch()
while true do
local status
status, last = socket.recv(fd, last, result)
if status == nil then
error "Server closed"
end
if not status then
break
end
for _, v in ipairs(result) do
local session,t,str = string.match(v, "(%d+)(.)(.*)")
assert(t == '-' or t == '+')
session = tonumber(session)
local result = cjson.decode(str)
print("Response:",session, result[1], result[2])
end
socket.send(fd, package)
end
local function unpack_package(text)
local size = #text
if size < 2 then
return nil, text
end
local s = text:byte(1) * 256 + text:byte(2)
if size < s+2 then
return nil, text
end
return text:sub(3,2+s), text:sub(3+s)
end
local function recv_package(last)
local result
result, last = unpack_package(last)
if result then
return result, last
end
local r = socket.recv(fd)
if not r then
return nil, last
end
if r == "" then
error "Server closed"
end
return unpack_package(last .. r)
end
local session = 0
@@ -33,12 +50,25 @@ local session = 0
local function send_request(v)
session = session + 1
local str = string.format("%d+%s",session, cjson.encode(v))
socket.send(fd, str)
send_package(fd, str)
print("Request:", session)
end
local last = ""
while true do
dispatch()
while true do
local v
v, last = recv_package(last)
if not v then
break
end
local session,t,str = string.match(v, "(%d+)(.)(.*)")
assert(t == '-' or t == '+')
session = tonumber(session)
local result = cjson.decode(str)
print("Response:",session, result[1], result[2])
end
local cmd = socket.readstdin()
if cmd then
local args = {}

View File

@@ -2,44 +2,65 @@ package.cpath = "luaclib/?.so"
local socket = require "clientsocket"
local crypt = require "crypt"
local bit32 = require "bit32"
local last
local fd = assert(socket.connect("127.0.0.1", 8001))
local input = {}
local function readline()
local line = table.remove(input, 1)
if line then
return line
local function writeline(fd, text)
socket.send(fd, text .. "\n")
end
local function unpack_line(text)
local from = text:find("\n", 1, true)
if from then
return text:sub(1, from-1), text:sub(from+1)
end
return nil, text
end
while true do
local status
status, last = socket.readline(fd, last, input)
if status == nil then
local last = ""
local function unpack_f(f)
local function try_recv(fd, last)
local result
result, last = f(last)
if result then
return result, last
end
local r = socket.recv(fd)
if not r then
return nil, last
end
if r == "" then
error "Server closed"
end
if not status then
socket.usleep(100)
else
local line = table.remove(input, 1)
if line then
return line
return f(last .. r)
end
return function()
while true do
local result
result, last = try_recv(fd, last)
if result then
return result
end
socket.usleep(100)
end
end
end
local readline = unpack_f(unpack_line)
local challenge = crypt.base64decode(readline())
local clientkey = crypt.randomkey()
socket.writeline(fd, crypt.base64encode(crypt.dhexchange(clientkey)))
writeline(fd, crypt.base64encode(crypt.dhexchange(clientkey)))
local secret = crypt.dhsecret(crypt.base64decode(readline()), clientkey)
print("sceret is ", crypt.hexencode(secret))
local hmac = crypt.hmac64(challenge, secret)
socket.writeline(fd, crypt.base64encode(hmac))
writeline(fd, crypt.base64encode(hmac))
local token = {
server = "sample",
@@ -56,7 +77,7 @@ end
local etoken = crypt.desencode(secret, encode_token(token))
local b = crypt.base64encode(etoken)
socket.writeline(fd, crypt.base64encode(etoken))
writeline(fd, crypt.base64encode(etoken))
local result = readline()
print(result)
@@ -71,8 +92,18 @@ print("login ok, subid=", subid)
----- connect to game server
local function send_request(v, session)
local s = string.char(bit32.extract(session,24,8), bit32.extract(session,16,8), bit32.extract(session,8,8), bit32.extract(session,0,8))
socket.send(fd , v..s)
local size = #v + 4
local package = string.format("%c%c%s%c%c%c%c",
bit32.extract(size,8,8),
bit32.extract(size,0,8),
v,
bit32.extract(session,24,8),
bit32.extract(session,16,8),
bit32.extract(session,8,8),
bit32.extract(session,0,8)
)
socket.send(fd, package)
return v, session
end
@@ -87,29 +118,29 @@ local function recv_response(v)
return ok ~=0 , content, session
end
local input = {}
local function readpackage()
local line = table.remove(input, 1)
if line then
return line
local function unpack_package(text)
local size = #text
if size < 2 then
return nil, text
end
local s = text:byte(1) * 256 + text:byte(2)
if size < s+2 then
return nil, text
end
while true do
local status
status, last = socket.recv(fd, last, input)
if status == nil then
error "Server closed"
end
if not status then
socket.usleep(100)
else
local line = table.remove(input, 1)
if line then
return line
end
end
end
return text:sub(3,2+s), text:sub(3+s)
end
local readpackage = unpack_f(unpack_package)
local function send_package(fd, pack)
local size = #pack
local package = string.format("%c%c%s",
bit32.extract(size,8,8),
bit32.extract(size,0,8),
pack)
socket.send(fd, package)
end
local text = "echo"
@@ -117,12 +148,13 @@ local index = 1
print("connect")
local fd = assert(socket.connect("127.0.0.1", 8888))
input = {}
last = ""
local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index)
local hmac = crypt.hmac64(crypt.hashkey(handshake), secret)
socket.send(fd, handshake .. ":" .. crypt.base64encode(hmac))
send_package(fd, handshake .. ":" .. crypt.base64encode(hmac))
print(readpackage())
print("===>",send_request(text,0))
@@ -136,12 +168,12 @@ index = index + 1
print("connect again")
local fd = assert(socket.connect("127.0.0.1", 8888))
input = {}
last = ""
local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index)
local hmac = crypt.hmac64(crypt.hashkey(handshake), secret)
socket.send(fd, handshake .. ":" .. crypt.base64encode(hmac))
send_package(fd, handshake .. ":" .. crypt.base64encode(hmac))
print(readpackage())
print("===>",send_request("fake",0)) -- request again (use last session 0, so the request message is fake)

View File

@@ -16,7 +16,11 @@ end
skynet.start(function()
skynet.dispatch("lua", function(session, address, cmd, ...)
local f = command[string.upper(cmd)]
skynet.ret(skynet.pack(f(...)))
if f then
skynet.ret(skynet.pack(f(...)))
else
error(string.format("Unknown command %s", tostring(cmd)))
end
end)
skynet.register "SIMPLEDB"
end)

View File

@@ -75,47 +75,12 @@ lsend(lua_State *L) {
size_t sz = 0;
int fd = luaL_checkinteger(L,1);
const char * msg = luaL_checklstring(L, 2, &sz);
uint8_t tmp[sz + 2];
if (sz >= 0x10000) {
return luaL_error(L, "package too long %d (16bit limited)", (int)sz);
}
tmp[0] = (sz >> 8) & 0xff;
tmp[1] = sz & 0xff;
memcpy(tmp+2, msg, sz);
block_send(L, fd, (const char *)tmp, (int)sz+2);
block_send(L, fd, msg, (int)sz);
return 0;
}
static int
unpack(lua_State *L, uint8_t *buffer, int sz, int n) {
int size = 0;
if (sz >= 2) {
size = buffer[0] << 8 | buffer[1];
if (size > sz - 2) {
goto _block;
}
} else {
goto _block;
}
++n;
lua_pushlstring(L, (const char *)buffer+2, size);
lua_rawseti(L, 3, n);
buffer += size + 2;
sz -= size + 2;
return unpack(L, buffer, sz, n);
_block:
lua_pushboolean(L, n==0 ? 0:1);
if (sz == 0) {
lua_pushnil(L);
} else {
lua_pushlstring(L, (const char *)buffer, sz);
}
return 2;
}
/*
intger fd
string last
@@ -132,100 +97,26 @@ struct socket_buffer {
};
static int
recv_socket(lua_State *L, char *tmp, struct socket_buffer *result) {
lrecv(lua_State *L) {
int fd = luaL_checkinteger(L,1);
size_t sz = 0;
const char * last = lua_tolstring(L,2,&sz);
luaL_checktype(L, 3, LUA_TTABLE);
char * buffer;
int r = recv(fd, tmp, CACHE_SIZE, 0);
char buffer[CACHE_SIZE];
int r = recv(fd, buffer, CACHE_SIZE, 0);
if (r == 0) {
lua_pushliteral(L, "");
// close
return 0;
return 1;
}
if (r < 0) {
if (errno == EAGAIN || errno == EINTR) {
lua_pushboolean(L, 0);
lua_pushvalue(L, 2);
return 2;
return 0;
}
luaL_error(L, "socket error: %s", strerror(errno));
}
if (sz + r <= CACHE_SIZE) {
buffer = tmp;
memmove(buffer + sz, buffer, r);
memcpy(buffer, last, sz);
} else {
buffer = lua_newuserdata(L, r + sz);
memcpy(buffer, last, sz);
memcpy(buffer + sz, tmp, r);
}
int i;
int n = lua_rawlen(L, 3);
for (i=1;i<=n;i++) {
lua_pushnil(L);
lua_rawseti(L, 3, i);
}
result->buffer = buffer;
result->sz = r + sz;
return -1;
lua_pushlstring(L, buffer, r);
return 1;
}
static int
lrecv(lua_State *L) {
struct socket_buffer sb;
char tmp[CACHE_SIZE];
int ret = recv_socket(L, tmp, &sb);
if (ret < 0) {
return unpack(L, sb.buffer, sb.sz, 0);
} else {
return ret;
}
}
static int
unpack_line(lua_State *L, uint8_t *buffer, int sz, int n) {
if (sz == 0)
goto _block;
if (buffer[0] == '\n') {
return unpack_line(L, buffer+1, sz-1, n);
}
int i;
for (i=1;i<sz;i++) {
if (buffer[i] == '\n') {
++n;
lua_pushlstring(L, (const char *)buffer, i);
lua_rawseti(L, 3, n);
buffer += i + 1;
sz -= i + 1;
return unpack_line(L, buffer, sz, n);
}
}
_block:
lua_pushboolean(L, n==0 ? 0:1);
if (sz == 0) {
lua_pushnil(L);
} else {
lua_pushlstring(L, (const char *)buffer, sz);
}
return 2;
}
static int
lreadline(lua_State *L) {
struct socket_buffer sb;
char tmp[CACHE_SIZE];
int ret = recv_socket(L, tmp, &sb);
if (ret < 0) {
return unpack_line(L, sb.buffer, sb.sz, 0);
} else {
return ret;
}
}
static int
lusleep(lua_State *L) {
int n = luaL_checknumber(L, 1);
@@ -295,18 +186,6 @@ lreadstdin(lua_State *L) {
return 1;
}
static int
lwriteline(lua_State *L) {
size_t sz = 0;
int fd = luaL_checkinteger(L,1);
const char * msg = luaL_checklstring(L, 2, &sz);
block_send(L, fd, msg, sz);
char nl[1] = { '\n' };
block_send(L, fd, nl, 1);
return 0;
}
int
luaopen_clientsocket(lua_State *L) {
luaL_checkversion(L);
@@ -316,8 +195,6 @@ luaopen_clientsocket(lua_State *L) {
{ "send", lsend },
{ "close", lclose },
{ "usleep", lusleep },
{ "readline", lreadline },
{ "writeline", lwriteline },
{ NULL, NULL },
};
luaL_newlib(L, l);

View File

@@ -32,8 +32,18 @@ Success:
200 base64(subid)
]]
local socket_error = {}
local function assert_socket(v, fd)
if v then
return v
else
skynet.error(string.format("auth failed: socket (fd = %d) closed", fd))
error(socket_error)
end
end
local function write(fd, text)
assert(socket.write(fd, text), "socket error")
assert_socket(socket.write(fd, text), fd)
end
local function launch_slave(auth_handler)
@@ -48,7 +58,7 @@ local function launch_slave(auth_handler)
local challenge = crypt.randomkey()
write(fd, crypt.base64encode(challenge).."\n")
local handshake = assert(socket.readline(fd), "socket closed")
local handshake = assert_socket(socket.readline(fd), fd)
local clientkey = crypt.base64decode(handshake)
if #clientkey ~= 8 then
error "Invalid client key"
@@ -58,7 +68,7 @@ local function launch_slave(auth_handler)
local secret = crypt.dhsecret(clientkey, serverkey)
local response = assert(socket.readline(fd), "socket closed")
local response = assert_socket(socket.readline(fd), fd)
local hmac = crypt.hmac64(challenge, secret)
if hmac ~= crypt.base64decode(response) then
@@ -66,7 +76,7 @@ local function launch_slave(auth_handler)
error "challenge failed"
end
local etoken = assert(socket.readline(fd), "socket closed")
local etoken = assert_socket(socket.readline(fd),fd)
local token = crypt.desdecode(secret, crypt.base64decode(etoken))
@@ -76,8 +86,16 @@ local function launch_slave(auth_handler)
return ok, server, uid, secret
end
local function ret_pack(ok, err, ...)
if ok then
skynet.ret(skynet.pack(err, ...))
elseif err ~= socket_error then
error(err)
end
end
skynet.dispatch("lua", function(_,_,...)
skynet.ret(skynet.pack(auth(...)))
ret_pack(pcall(auth, ...))
end)
end
@@ -146,7 +164,9 @@ local function launch_master(conf)
end
local ok, err = pcall(accept, conf, s, fd, addr)
if not ok then
skynet.error(string.format("invalid client (fd = %d) error = %s", fd, err))
if err ~= socket_error then
skynet.error(string.format("invalid client (fd = %d) error = %s", fd, err))
end
end
socket.close(fd)
end)