-- original file : socket.lua -- for more into : see util-soc.lua local type, tostring, setmetatable = type, tostring, setmetatable local min = math.min local format = string.format local socket = socket or package.loaded.socket or require("socket.core") local connect = socket.connect local tcp4 = socket.tcp4 local tcp6 = socket.tcp6 local getaddrinfo = socket.dns.getaddrinfo local defaulthost = "0.0.0.0" local function report(fmt,first,...) if logs then report = logs and logs.reporter("socket") report(fmt,first,...) elseif fmt then fmt = "socket: " .. fmt if first then print(format(fmt,first,...)) else print(fmt) end end end socket.report = report function socket.connect4(address, port, laddress, lport) return connect(address, port, laddress, lport, "inet") end function socket.connect6(address, port, laddress, lport) return connect(address, port, laddress, lport, "inet6") end function socket.bind(host, port, backlog) if host == "*" or host == "" then host = defaulthost end local addrinfo, err = getaddrinfo(host) if not addrinfo then return nil, err end for i=1,#addrinfo do local alt = addrinfo[i] local sock, err = (alt.family == "inet" and tcp4 or tcp6)() if not sock then return nil, err or "unknown error" end sock:setoption("reuseaddr", true) local res, err = sock:bind(alt.addr, port) if res then res, err = sock:listen(backlog) if res then return sock else sock:close() end else sock:close() end end return nil, "invalid address" end socket.try = socket.newtry() function socket.choose(list) return function(name, opt1, opt2) if type(name) ~= "string" then name, opt1, opt2 = "default", name, opt1 end local f = list[name or "nil"] if f then return f(opt1, opt2) else report("error: unknown key '%s'",tostring(name)) end end end local sourcet = { } local sinkt = { } socket.sourcet = sourcet socket.sinkt = sinkt socket.BLOCKSIZE = 2048 sinkt["close-when-done"] = function(sock) return 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 sock:close() return 1 -- why 1 end end } ) end sinkt["keep-open"] = function(sock) return 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 -- why 1 end end } ) end sinkt["default"] = sinkt["keep-open"] socket.sink = socket.choose(sinkt) sourcet["by-length"] = function(sock, length) local blocksize = socket.BLOCKSIZE return setmetatable ( { getfd = function() return sock:getfd() end, dirty = function() return sock:dirty() end, }, { __call = function() if length <= 0 then return nil end local chunk, err = sock:receive(min(blocksize,length)) if err then return nil, err end length = length - #chunk return chunk end } ) end sourcet["until-closed"] = function(sock) local blocksize = socket.BLOCKSIZE local done = false return setmetatable ( { getfd = function() return sock:getfd() end, dirty = function() return sock:dirty() end, }, { __call = function() if done then return nil end local chunk, status, partial = sock:receive(blocksize) if not status then return chunk elseif status == "closed" then sock:close() done = true return partial else return nil, status end end } ) end sourcet["default"] = sourcet["until-closed"] socket.source = socket.choose(sourcet) _G.socket = socket -- for now global package.loaded["socket"] = socket return socket