151 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
R"-++**++-(
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
-- LuaSocket helper module
 | 
						|
-- Author: Diego Nehab
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
-- Declare module and import dependencies
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
local base = _G
 | 
						|
local string = require("string")
 | 
						|
local math = require("math")
 | 
						|
local socket = require("socket.core")
 | 
						|
 | 
						|
local _M = socket
 | 
						|
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
-- Exported auxiliar functions
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
function _M.connect4(address, port, laddress, lport)
 | 
						|
    return socket.connect(address, port, laddress, lport, "inet")
 | 
						|
end
 | 
						|
 | 
						|
function _M.connect6(address, port, laddress, lport)
 | 
						|
    return socket.connect(address, port, laddress, lport, "inet6")
 | 
						|
end
 | 
						|
 | 
						|
function _M.bind(host, port, backlog)
 | 
						|
    if host == "*" then host = "0.0.0.0" end
 | 
						|
    local addrinfo, err = socket.dns.getaddrinfo(host);
 | 
						|
    if not addrinfo then return nil, err end
 | 
						|
    local sock, res
 | 
						|
    err = "no info on address"
 | 
						|
    for i, alt in base.ipairs(addrinfo) do
 | 
						|
        if alt.family == "inet" then
 | 
						|
            sock, err = socket.tcp()
 | 
						|
        else
 | 
						|
            sock, err = socket.tcp6()
 | 
						|
        end
 | 
						|
        if not sock then return nil, err end
 | 
						|
        sock:setoption("reuseaddr", true)
 | 
						|
        res, err = sock:bind(alt.addr, port)
 | 
						|
        if not res then 
 | 
						|
            sock:close()
 | 
						|
        else 
 | 
						|
            res, err = sock:listen(backlog)
 | 
						|
            if not res then 
 | 
						|
                sock:close()
 | 
						|
            else
 | 
						|
                return sock
 | 
						|
            end
 | 
						|
        end 
 | 
						|
    end
 | 
						|
    return nil, err
 | 
						|
end
 | 
						|
 | 
						|
_M.try = _M.newtry()
 | 
						|
 | 
						|
function _M.choose(table)
 | 
						|
    return function(name, opt1, opt2)
 | 
						|
        if base.type(name) ~= "string" then
 | 
						|
            name, opt1, opt2 = "default", name, opt1
 | 
						|
        end
 | 
						|
        local f = table[name or "nil"]
 | 
						|
        if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
 | 
						|
        else return f(opt1, opt2) end
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
-- Socket sources and sinks, conforming to LTN12
 | 
						|
-----------------------------------------------------------------------------
 | 
						|
-- create namespaces inside LuaSocket namespace
 | 
						|
local sourcet, sinkt = {}, {}
 | 
						|
_M.sourcet = sourcet
 | 
						|
_M.sinkt = sinkt
 | 
						|
 | 
						|
_M.BLOCKSIZE = 2048
 | 
						|
 | 
						|
sinkt["close-when-done"] = function(sock)
 | 
						|
    return base.setmetatable({
 | 
						|
        getfd = function() return sock:getfd() end,
 | 
						|
        dirty = function() return sock:dirty() end
 | 
						|
    }, {
 | 
						|
        __call = function(self, chunk, err)
 | 
						|
            if not chunk then
 | 
						|
                sock:close()
 | 
						|
                return 1
 | 
						|
            else return sock:send(chunk) end
 | 
						|
        end
 | 
						|
    })
 | 
						|
end
 | 
						|
 | 
						|
sinkt["keep-open"] = function(sock)
 | 
						|
    return base.setmetatable({
 | 
						|
        getfd = function() return sock:getfd() end,
 | 
						|
        dirty = function() return sock:dirty() end
 | 
						|
    }, {
 | 
						|
        __call = function(self, chunk, err)
 | 
						|
            if chunk then return sock:send(chunk)
 | 
						|
            else return 1 end
 | 
						|
        end
 | 
						|
    })
 | 
						|
end
 | 
						|
 | 
						|
sinkt["default"] = sinkt["keep-open"]
 | 
						|
 | 
						|
_M.sink = _M.choose(sinkt)
 | 
						|
 | 
						|
sourcet["by-length"] = function(sock, length)
 | 
						|
    return base.setmetatable({
 | 
						|
        getfd = function() return sock:getfd() end,
 | 
						|
        dirty = function() return sock:dirty() end
 | 
						|
    }, {
 | 
						|
        __call = function()
 | 
						|
            if length <= 0 then return nil end
 | 
						|
            local size = math.min(socket.BLOCKSIZE, length)
 | 
						|
            local chunk, err = sock:receive(size)
 | 
						|
            if err then return nil, err end
 | 
						|
            length = length - string.len(chunk)
 | 
						|
            return chunk
 | 
						|
        end
 | 
						|
    })
 | 
						|
end
 | 
						|
 | 
						|
sourcet["until-closed"] = function(sock)
 | 
						|
    local done
 | 
						|
    return base.setmetatable({
 | 
						|
        getfd = function() return sock:getfd() end,
 | 
						|
        dirty = function() return sock:dirty() end
 | 
						|
    }, {
 | 
						|
        __call = function()
 | 
						|
            if done then return nil end
 | 
						|
            local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
 | 
						|
            if not err then return chunk
 | 
						|
            elseif err == "closed" then
 | 
						|
                sock:close()
 | 
						|
                done = 1
 | 
						|
                return partial
 | 
						|
            else return nil, err end
 | 
						|
        end
 | 
						|
    })
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
sourcet["default"] = sourcet["until-closed"]
 | 
						|
 | 
						|
_M.source = _M.choose(sourcet)
 | 
						|
 | 
						|
return _M
 | 
						|
)-++**++-"; |