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, }