Initial commit
This commit is contained in:
149
QUIK/lua/socket.lua
Normal file
149
QUIK/lua/socket.lua
Normal file
@@ -0,0 +1,149 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- 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.tcp4()
|
||||
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
|
||||
Reference in New Issue
Block a user