|
|
local buffer_queue = require "buffer_queue"
|
|
|
local conn = require "conn"
|
|
|
local crypt = require "crypt"
|
|
|
local rc4 = require "rc4.c"
|
|
|
|
|
|
local pack_data = buffer_queue.pack_data
|
|
|
|
|
|
local DEF_MSG_HEADER_LEN = 2
|
|
|
local DEF_MSG_ENDIAN = "big"
|
|
|
local CACHE_MAX_COUNT = 100
|
|
|
|
|
|
local mt = {}
|
|
|
local cache_mt = {}
|
|
|
|
|
|
-------------- cache ------------------
|
|
|
local function cache_create()
|
|
|
local raw = {
|
|
|
size = 0,
|
|
|
|
|
|
top = 0,
|
|
|
cache = {},
|
|
|
}
|
|
|
return setmetatable(raw, {
|
|
|
__index = cache_mt,
|
|
|
})
|
|
|
end
|
|
|
|
|
|
function cache_mt:insert(data)
|
|
|
local cache = self.cache
|
|
|
self.top = self.top + 1
|
|
|
cache[self.top] = data
|
|
|
self.size = self.size + #data
|
|
|
local remove_cache_value = cache[self.top - CACHE_MAX_COUNT]
|
|
|
cache[self.top - CACHE_MAX_COUNT] = nil -- 只缓存最近CACHE_MAX_COUNT个包
|
|
|
if remove_cache_value then
|
|
|
self.size = self.size - #remove_cache_value
|
|
|
end
|
|
|
end
|
|
|
|
|
|
function cache_mt:get(nbytes)
|
|
|
if self.size < nbytes then
|
|
|
return false
|
|
|
end
|
|
|
|
|
|
local cache = self.cache
|
|
|
local i = self.top
|
|
|
local count = 0
|
|
|
local ret = {}
|
|
|
while count < nbytes do
|
|
|
local v = cache[i]
|
|
|
local len = #v
|
|
|
local n = len
|
|
|
local vv = v
|
|
|
if count + len > nbytes then
|
|
|
local sub_n = nbytes - count
|
|
|
local pos = len - sub_n
|
|
|
local sub_v = string.sub(v, pos + 1)
|
|
|
n = sub_n
|
|
|
vv = sub_v
|
|
|
end
|
|
|
table.insert(ret, 1, vv)
|
|
|
count = count + n
|
|
|
i = i - 1
|
|
|
end
|
|
|
|
|
|
return table.concat(ret)
|
|
|
end
|
|
|
|
|
|
function cache_mt:clear()
|
|
|
self.size = 0
|
|
|
self.top = 0
|
|
|
end
|
|
|
|
|
|
local function dummy(...)
|
|
|
print("send dummy", ...)
|
|
|
end
|
|
|
|
|
|
local function dispose_error(state_self, _success, _err, _status)
|
|
|
local success = false
|
|
|
local err = state_self.name
|
|
|
local status = "reconnect_error"
|
|
|
return success, err, status
|
|
|
end
|
|
|
|
|
|
-------------- state ------------------
|
|
|
|
|
|
local state = {
|
|
|
newconnect = {
|
|
|
name = "newconnect",
|
|
|
request = false,
|
|
|
dispatch = false,
|
|
|
send = false,
|
|
|
dispose = false,
|
|
|
},
|
|
|
|
|
|
reconnect = {
|
|
|
name = "reconnect",
|
|
|
request = false,
|
|
|
dispatch = false,
|
|
|
send = false,
|
|
|
dispose = false,
|
|
|
},
|
|
|
|
|
|
forward = {
|
|
|
name = "forward",
|
|
|
request = false,
|
|
|
dispatch = false,
|
|
|
send = false,
|
|
|
dispose = false,
|
|
|
},
|
|
|
|
|
|
reconnect_error = {
|
|
|
name = "reconnect_error",
|
|
|
send = dummy,
|
|
|
dispose = dispose_error,
|
|
|
},
|
|
|
|
|
|
reconnect_match_error = {
|
|
|
name = "reconnect_match_error",
|
|
|
send = dummy,
|
|
|
dispose = dispose_error,
|
|
|
},
|
|
|
|
|
|
reconnect_cache_error = {
|
|
|
name = "reconnect_cache_error",
|
|
|
send = dummy,
|
|
|
dispose = dispose_error,
|
|
|
},
|
|
|
|
|
|
close = {
|
|
|
name = "close",
|
|
|
send = dummy,
|
|
|
dispose = false,
|
|
|
},
|
|
|
}
|
|
|
|
|
|
local function switch_state(self, s, ...)
|
|
|
local v = state[s]
|
|
|
assert(v)
|
|
|
print(">>>>>>>>>>>>>switch_state:", s, ...)
|
|
|
self.v_state = v
|
|
|
if v.request then
|
|
|
v.request(self, ...)
|
|
|
end
|
|
|
end
|
|
|
|
|
|
local out = {}
|
|
|
|
|
|
-------------- new connect state ------------------
|
|
|
function state.newconnect.request(self, target_server, flag)
|
|
|
-- 0\n
|
|
|
-- base64(DH_key)\n
|
|
|
-- targetServer\n
|
|
|
-- flag
|
|
|
|
|
|
target_server = target_server or ""
|
|
|
flag = flag or 0
|
|
|
local clientkey = crypt.randomkey()
|
|
|
local data = string.format("0\n%s\n%s\n%d", crypt.base64encode(crypt.dhexchange(clientkey)), target_server, flag)
|
|
|
|
|
|
data = pack_data(data, 2, "big")
|
|
|
self.v_sock:send(data)
|
|
|
self.v_clientkey = clientkey
|
|
|
print("request:", data)
|
|
|
self.v_send_buf_top = 0
|
|
|
end
|
|
|
|
|
|
function state.newconnect.send(self, data)
|
|
|
self.v_send_buf_top = self.v_send_buf_top + 1
|
|
|
self.v_send_buf[self.v_send_buf_top] = data
|
|
|
end
|
|
|
|
|
|
local function send(self, data)
|
|
|
local _send = self.v_state.send
|
|
|
_send(self, data)
|
|
|
return true
|
|
|
end
|
|
|
|
|
|
function state.newconnect.dispatch(self)
|
|
|
local data = self.v_sock:pop_msg(2, "big")
|
|
|
|
|
|
if not data then
|
|
|
return
|
|
|
end
|
|
|
|
|
|
print("dispatch:", data)
|
|
|
local id, key = data:match("([^\n]*)\n([^\n]*)")
|
|
|
|
|
|
self.v_id = tonumber(id)
|
|
|
key = crypt.base64decode(key)
|
|
|
|
|
|
local secret = crypt.dhsecret(key, self.v_clientkey)
|
|
|
|
|
|
local rc4_key = crypt.hmac64_md5(secret, "\0\0\0\0\0\0\0\0") .. crypt.hmac64_md5(secret, "\1\0\0\0\0\0\0\0") ..
|
|
|
crypt.hmac64_md5(secret, "\2\0\0\0\0\0\0\0") .. crypt.hmac64_md5(secret, "\3\0\0\0\0\0\0\0")
|
|
|
|
|
|
self.v_secret = secret
|
|
|
self.v_rc4_c2s = rc4.rc4(rc4_key)
|
|
|
self.v_rc4_s2c = rc4.rc4(rc4_key)
|
|
|
|
|
|
switch_state(self, "forward")
|
|
|
|
|
|
-- 发送在新连接建立中间缓存的数据包
|
|
|
for i = 1, self.v_send_buf_top do
|
|
|
send(self, self.v_send_buf[i])
|
|
|
end
|
|
|
self.v_send_buf_top = 0
|
|
|
self.v_send_buf = {}
|
|
|
end
|
|
|
|
|
|
function state.newconnect.dispose(state_self, success, err, status)
|
|
|
if success then
|
|
|
return true, nil, "connect"
|
|
|
else
|
|
|
err = string.format("sock_error:%s sock_status:%s sconn_state:newconnect", err, status)
|
|
|
return false, err, "connect"
|
|
|
end
|
|
|
end
|
|
|
|
|
|
-------------- reconnect state ------------------
|
|
|
function state.reconnect.request(self)
|
|
|
-- id\n
|
|
|
-- index\n
|
|
|
-- recvnumber\n
|
|
|
-- base64(HMAC_CODE)\n
|
|
|
|
|
|
self.v_reconnect_index = self.v_reconnect_index + 1
|
|
|
|
|
|
local content = string.format("%d\n%d\n%d\n", self.v_id, self.v_reconnect_index, self.v_recvnumber)
|
|
|
|
|
|
local hmac = crypt.base64encode(crypt.hmac64_md5(crypt.hashkey(content), self.v_secret))
|
|
|
local data = string.format("%s%s\n", content, hmac)
|
|
|
data = pack_data(data, 2, "big")
|
|
|
|
|
|
print("request:", data)
|
|
|
|
|
|
self.v_sock:send(data)
|
|
|
end
|
|
|
|
|
|
-- 在断线重连期间,仅仅是把数据插入到cache中
|
|
|
function state.reconnect.send(self, data)
|
|
|
local rc4_c2s = self.v_rc4_c2s
|
|
|
local cache = self.v_cache
|
|
|
data = rc4_c2s:crypt(data)
|
|
|
|
|
|
self.v_sendnumber = self.v_sendnumber + #data
|
|
|
cache:insert(data)
|
|
|
end
|
|
|
|
|
|
function state.reconnect.dispatch(self)
|
|
|
local data = self.v_sock:pop_msg(2, "big")
|
|
|
|
|
|
if not data then
|
|
|
return
|
|
|
end
|
|
|
|
|
|
print("dispatch:", data)
|
|
|
local recv, msg = data:match "([^\n]*)\n([^\n]*)"
|
|
|
recv = tonumber(recv)
|
|
|
|
|
|
local sendnumber = self.v_sendnumber
|
|
|
|
|
|
local cb = self.v_reconnect_cb
|
|
|
self.v_reconnect_cb = nil
|
|
|
|
|
|
-- 重连失败
|
|
|
if msg ~= "200" then
|
|
|
print("msg:", msg)
|
|
|
if cb then
|
|
|
cb(false)
|
|
|
end
|
|
|
switch_state(self, "reconnect_error")
|
|
|
return
|
|
|
end
|
|
|
|
|
|
-- 服务器接受的数据要比客户端记录的发送的数据还要多
|
|
|
if recv > sendnumber then
|
|
|
if cb then
|
|
|
cb(false)
|
|
|
end
|
|
|
switch_state(self, "reconnect_match_error")
|
|
|
return
|
|
|
end
|
|
|
|
|
|
-- 需要补发的数据
|
|
|
local nbytes = 0
|
|
|
if recv < sendnumber then
|
|
|
nbytes = sendnumber - recv
|
|
|
local more_data = self.v_cache:get(nbytes)
|
|
|
-- 缓存的数据不足
|
|
|
if not more_data then
|
|
|
if cb then
|
|
|
cb(false)
|
|
|
end
|
|
|
switch_state(self, "reconnect_cache_error")
|
|
|
return
|
|
|
end
|
|
|
|
|
|
-- 发送补发数据
|
|
|
assert(#more_data == nbytes)
|
|
|
self.v_sock:send(more_data)
|
|
|
end
|
|
|
|
|
|
-- 重连成功
|
|
|
if cb then
|
|
|
cb(true)
|
|
|
end
|
|
|
switch_state(self, "forward")
|
|
|
end
|
|
|
|
|
|
function state.reconnect.dispose(state_self, success, err, status)
|
|
|
if success then
|
|
|
return true, nil, "reconnect"
|
|
|
else
|
|
|
err = string.format("sock_error:%s sock_status:%s sconn_state:reconnect", err, status)
|
|
|
return false, err, "reconnect"
|
|
|
end
|
|
|
end
|
|
|
|
|
|
-------------- forward ------------------
|
|
|
function state.forward.dispatch(self)
|
|
|
local recv_buf = self.v_recv_buf
|
|
|
local rc4_s2c = self.v_rc4_s2c
|
|
|
local sock = self.v_sock
|
|
|
local count = sock:recv(out)
|
|
|
|
|
|
for i = 1, count do
|
|
|
local v = out[i]
|
|
|
self.v_recvnumber = self.v_recvnumber + #v
|
|
|
v = rc4_s2c:crypt(v)
|
|
|
recv_buf:push(v)
|
|
|
end
|
|
|
end
|
|
|
|
|
|
function state.forward.send(self, data)
|
|
|
local sock = self.v_sock
|
|
|
local rc4_c2s = self.v_rc4_c2s
|
|
|
local cache = self.v_cache
|
|
|
data = rc4_c2s:crypt(data)
|
|
|
|
|
|
sock:send(data)
|
|
|
|
|
|
self.v_sendnumber = self.v_sendnumber + #data
|
|
|
cache:insert(data)
|
|
|
end
|
|
|
|
|
|
function state.forward.dispose(state_self, success, err, status)
|
|
|
if success then
|
|
|
if status ~= "forward" then
|
|
|
error(string.format("invalid sock_status:%s", status))
|
|
|
end
|
|
|
return true, nil, "forward"
|
|
|
else
|
|
|
err = string.format("sock_error:%s sock_status:%s sconn_state:forward", err, status)
|
|
|
return false, err, "forward"
|
|
|
end
|
|
|
end
|
|
|
|
|
|
-------------- close ------------------
|
|
|
function state.close.dispose(state_self, success, err, status)
|
|
|
err = string.format("sock_error:%s sock_status:%s sconn_state:close", err, status)
|
|
|
return false, err, "close"
|
|
|
end
|
|
|
|
|
|
local function connect(host, port, targetserver, flag)
|
|
|
local raw = {
|
|
|
v_state = false,
|
|
|
v_sock = false,
|
|
|
|
|
|
v_clientkey = false,
|
|
|
v_secret = false,
|
|
|
v_id = false,
|
|
|
|
|
|
v_rc4_c2s = false,
|
|
|
v_rc4_s2c = false,
|
|
|
|
|
|
v_sendnumber = 0,
|
|
|
v_recvnumber = 0,
|
|
|
v_reconnect_index = 0,
|
|
|
v_cache = cache_create(),
|
|
|
|
|
|
v_send_buf = {},
|
|
|
v_send_buf_top = 0,
|
|
|
|
|
|
v_recv_buf = buffer_queue.create(),
|
|
|
}
|
|
|
|
|
|
local sock, err = conn.connect_host(host, port)
|
|
|
if not sock then
|
|
|
return nil, err
|
|
|
end
|
|
|
|
|
|
raw.v_sock = sock
|
|
|
local self = setmetatable(raw, {
|
|
|
__index = mt,
|
|
|
})
|
|
|
switch_state(self, "newconnect", targetserver, flag)
|
|
|
return self
|
|
|
end
|
|
|
|
|
|
function mt:reconnect(cb)
|
|
|
local state_name = self.v_state.name
|
|
|
if state_name ~= "forward" and state_name ~= "reconnect" then
|
|
|
return false, string.format("error state switch `%s` to reconnect", state_name)
|
|
|
end
|
|
|
|
|
|
local addr = self.v_sock.o_host_addr
|
|
|
local port = self.v_sock.o_port
|
|
|
|
|
|
local success, err = self.v_sock:new_connect(addr, port)
|
|
|
if not success then
|
|
|
return false, err
|
|
|
end
|
|
|
|
|
|
self.v_reconnect_cb = cb
|
|
|
switch_state(self, "reconnect")
|
|
|
return true
|
|
|
end
|
|
|
|
|
|
--[[
|
|
|
update 接口现在会返回三个参数 success, err, status
|
|
|
|
|
|
success: boolean类型 表示当前status是否正常
|
|
|
true: err返回值为nil
|
|
|
false: err返回值为string,描述错误信息
|
|
|
|
|
|
err: string类型 表示当前status的错误信息,在success 为false才会有效
|
|
|
|
|
|
status: string类型 当前sconn所在的状态,状态只能是:
|
|
|
"connect": 连接状态
|
|
|
"forward": 连接成功状态
|
|
|
"reconnect": 断线重连状态
|
|
|
"connect_break": 断开连接状态
|
|
|
"close": 关闭状态
|
|
|
]]
|
|
|
function mt:update()
|
|
|
local sock = self.v_sock
|
|
|
local cur_state = self.v_state
|
|
|
local success, err, status = sock:update()
|
|
|
local dispatch = cur_state.dispatch
|
|
|
if success and dispatch then
|
|
|
dispatch(self)
|
|
|
end
|
|
|
|
|
|
-- 网络连接主动断开
|
|
|
if status == "connect_break" then
|
|
|
return success, err, status
|
|
|
end
|
|
|
|
|
|
-- 处理返回状态值
|
|
|
success, err, status = cur_state.dispose(cur_state, success, err, status)
|
|
|
return success, err, status
|
|
|
end
|
|
|
|
|
|
function mt:send_msg(data, header_len, endian)
|
|
|
local _send = self.v_state.send
|
|
|
header_len = header_len or DEF_MSG_HEADER_LEN
|
|
|
endian = endian or DEF_MSG_ENDIAN
|
|
|
|
|
|
data = pack_data(data, header_len, endian)
|
|
|
_send(self, data)
|
|
|
return true
|
|
|
end
|
|
|
|
|
|
function mt:recv_msg(out_msg, header_len, endian)
|
|
|
header_len = header_len or DEF_MSG_HEADER_LEN
|
|
|
endian = endian or DEF_MSG_ENDIAN
|
|
|
|
|
|
local recv_buf = self.v_recv_buf
|
|
|
return recv_buf:pop_all_block(out_msg, header_len, endian)
|
|
|
end
|
|
|
|
|
|
function mt:close()
|
|
|
if self.v_sock then
|
|
|
self.v_sock:close()
|
|
|
end
|
|
|
self.v_sock = nil
|
|
|
self.v_recv_buf:clear()
|
|
|
switch_state(self, "close")
|
|
|
end
|
|
|
|
|
|
return {
|
|
|
connect_host = connect,
|
|
|
}
|
|
|
|