|
|
local buffer_queue = require "buffer_queue"
|
|
|
local socket = require "socket"
|
|
|
|
|
|
local DEF_MSG_HEADER_LEN = 2
|
|
|
local DEF_MSG_ENDIAN = "big"
|
|
|
|
|
|
local mt = {}
|
|
|
|
|
|
local function resolve(host)
|
|
|
local addr_tbl, err = socket.dns.getaddrinfo(host)
|
|
|
if not addr_tbl then
|
|
|
return false, err .. "[" .. tostring(host) .. "]"
|
|
|
end
|
|
|
return assert(addr_tbl[1])
|
|
|
end
|
|
|
|
|
|
local function connect(addr, port)
|
|
|
-- just support tcp now
|
|
|
if not (addr.family == "inet" or addr.family == "inet6") then
|
|
|
return nil, "just support tcp now"
|
|
|
end
|
|
|
local c, e = socket.tcp()
|
|
|
if not c then
|
|
|
return nil, e
|
|
|
end
|
|
|
local fd, e = c:connect(addr.addr, port)
|
|
|
if not fd then
|
|
|
c:close()
|
|
|
return nil, e
|
|
|
else
|
|
|
c:settimeout(0) -- non blocking
|
|
|
local raw = {
|
|
|
v_send_buf = buffer_queue.create(),
|
|
|
v_recv_buf = buffer_queue.create(),
|
|
|
v_fd = c,
|
|
|
|
|
|
o_host_addr = addr,
|
|
|
o_port = port,
|
|
|
v_check_connect = true,
|
|
|
}
|
|
|
return setmetatable(raw, {
|
|
|
__index = mt,
|
|
|
})
|
|
|
end
|
|
|
end
|
|
|
|
|
|
local function connect_host(host, port)
|
|
|
local addr, err = resolve(host)
|
|
|
if not addr then
|
|
|
return false, err
|
|
|
end
|
|
|
return connect(addr, port)
|
|
|
end
|
|
|
|
|
|
local function _flush_send(self)
|
|
|
local send_buf = self.v_send_buf
|
|
|
local v = send_buf:get_head_data()
|
|
|
local fd = self.v_fd
|
|
|
local count = 0
|
|
|
|
|
|
while v do
|
|
|
local len = #v
|
|
|
local n, err, last_sent = fd:send(v)
|
|
|
if not n then
|
|
|
if last_sent and last_sent > 0 then
|
|
|
send_buf:pop(last_sent)
|
|
|
end
|
|
|
return false, err
|
|
|
else
|
|
|
count = count + n
|
|
|
send_buf:pop(n)
|
|
|
if n < len then
|
|
|
break
|
|
|
end
|
|
|
end
|
|
|
v = send_buf:get_head_data()
|
|
|
end
|
|
|
return count
|
|
|
end
|
|
|
|
|
|
local function _flush_recv(self)
|
|
|
local recv_buf = self.v_recv_buf
|
|
|
local fd = self.v_fd
|
|
|
local data, err, piece_data = fd:receive("*a")
|
|
|
if not data then
|
|
|
if piece_data and #piece_data > 0 then
|
|
|
recv_buf:push(piece_data)
|
|
|
end
|
|
|
if err == "timeout" then
|
|
|
return true
|
|
|
end
|
|
|
return false, err
|
|
|
else
|
|
|
local count = 0
|
|
|
local len = #data
|
|
|
count = count + len
|
|
|
recv_buf:push(data)
|
|
|
return count
|
|
|
end
|
|
|
end
|
|
|
|
|
|
local function _check_connect(self)
|
|
|
local fd = self.v_fd
|
|
|
if not fd then
|
|
|
return false, 'fd is nil'
|
|
|
end
|
|
|
|
|
|
if self.v_check_connect then
|
|
|
local _, wfd, err = socket.select(nil, {fd}, 0)
|
|
|
if wfd and wfd[fd] then
|
|
|
self.v_check_connect = false
|
|
|
return true
|
|
|
else
|
|
|
if err == "timeout" then
|
|
|
return false, "connecting"
|
|
|
end
|
|
|
return false, err
|
|
|
end
|
|
|
else
|
|
|
return true
|
|
|
end
|
|
|
end
|
|
|
|
|
|
-- ====================== 供sconn 调用 ======================
|
|
|
function mt:new_connect(addr, port)
|
|
|
-- just support tcp now
|
|
|
if not (addr.family == "inet" or addr.family == "inet6") then
|
|
|
return nil, "just support tcp now"
|
|
|
end
|
|
|
local c, e = socket.tcp()
|
|
|
if not c then
|
|
|
return nil, e
|
|
|
end
|
|
|
local fd, e = c:connect(addr.addr, port)
|
|
|
if not fd then
|
|
|
c:close()
|
|
|
return false, e
|
|
|
else
|
|
|
c:settimeout(0) -- non blocking
|
|
|
self.v_fd:close()
|
|
|
self.v_send_buf:clear()
|
|
|
self.v_recv_buf:clear()
|
|
|
self.v_fd = c
|
|
|
self.o_host_addr = addr
|
|
|
self.o_port = port
|
|
|
self.v_check_connect = true
|
|
|
return true
|
|
|
end
|
|
|
end
|
|
|
|
|
|
function mt:pop_msg(header_len, endian)
|
|
|
local recv_buf = self.v_recv_buf
|
|
|
header_len = header_len or DEF_MSG_HEADER_LEN
|
|
|
endian = endian or DEF_MSG_ENDIAN
|
|
|
|
|
|
return recv_buf:pop_block(header_len, endian)
|
|
|
end
|
|
|
|
|
|
function mt:send(data)
|
|
|
self.v_send_buf:push(data)
|
|
|
end
|
|
|
|
|
|
function mt:recv(out)
|
|
|
local recv_buf = self.v_recv_buf
|
|
|
return recv_buf:pop_all(out)
|
|
|
end
|
|
|
-- ====================== 供sconn 调用 ======================
|
|
|
|
|
|
function mt:send_msg(data, header_len, endian)
|
|
|
local send_buf = self.v_send_buf
|
|
|
header_len = header_len or DEF_MSG_HEADER_LEN
|
|
|
endian = endian or DEF_MSG_ENDIAN
|
|
|
|
|
|
send_buf:push_block(data, header_len, endian)
|
|
|
end
|
|
|
|
|
|
function mt:recv_msg(out_msg, header_len, endian)
|
|
|
local recv_buf = self.v_recv_buf
|
|
|
header_len = header_len or DEF_MSG_HEADER_LEN
|
|
|
endian = endian or DEF_MSG_ENDIAN
|
|
|
|
|
|
return recv_buf:pop_all_block(out_msg, header_len, endian)
|
|
|
end
|
|
|
|
|
|
--[[
|
|
|
update 接口现在会返回三个参数 success, err, status
|
|
|
|
|
|
success: boolean类型 表示当前status是否正常
|
|
|
true: err返回值为nil
|
|
|
false: err返回值为string,描述错误信息
|
|
|
|
|
|
err: string类型 表示当前status的错误信息,在success 为false才会有效
|
|
|
|
|
|
status: string类型 当前conn所在的状态,状态只能是:
|
|
|
"connect": 连接状态
|
|
|
"forward": 连接成功状态
|
|
|
"recv": 接受状态数据状态
|
|
|
"send": 发送数据状态
|
|
|
"close": 关闭状态
|
|
|
]]
|
|
|
|
|
|
function mt:update()
|
|
|
local fd = self.v_fd
|
|
|
if not fd then
|
|
|
return false, "fd is nil", "close"
|
|
|
end
|
|
|
|
|
|
local success, err = _check_connect(self)
|
|
|
if not success then
|
|
|
if err == "connecting" then
|
|
|
return true, nil, "connect"
|
|
|
else
|
|
|
return false, err, "connect"
|
|
|
end
|
|
|
end
|
|
|
|
|
|
success, err = _flush_send(self)
|
|
|
if not success then
|
|
|
return false, err, "send"
|
|
|
end
|
|
|
|
|
|
success, err = _flush_recv(self)
|
|
|
if not success then
|
|
|
if err == "connect_break" then
|
|
|
return false, "connect break", "connect_break"
|
|
|
else
|
|
|
return false, err, "recv"
|
|
|
end
|
|
|
end
|
|
|
|
|
|
return true, nil, "forward"
|
|
|
end
|
|
|
|
|
|
local function flush_send(self)
|
|
|
local count = false
|
|
|
repeat
|
|
|
count = _flush_send(self)
|
|
|
until not count or count == 0
|
|
|
end
|
|
|
|
|
|
-- function mt:getsockname()
|
|
|
-- return self.v_fd:getsockname()
|
|
|
-- end
|
|
|
|
|
|
function mt:close()
|
|
|
if self.v_fd then
|
|
|
flush_send(self)
|
|
|
self.v_fd:close()
|
|
|
end
|
|
|
self.v_fd = nil
|
|
|
self.v_check_connect = true
|
|
|
end
|
|
|
|
|
|
return {
|
|
|
connect_host = connect_host,
|
|
|
}
|