Adding support for bind before connect.

This commit is contained in:
ztaylor 2015-05-27 14:17:58 -07:00
parent 321c0c9b1f
commit da30ec9c2e

View File

@ -106,17 +106,43 @@ end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local metat = { __index = {} } local metat = { __index = {} }
function _M.open(host, port, create) local function _bindBeforeConnect(host, port, timeout)
-- create socket with user connect function, or with default -- Keep trying to get an ephemeral port, degrade gracefully.
local c = socket.try((create or socket.tcp)()) -- Ports will free up as sockets move out of TIME_WAIT and
local h = base.setmetatable({ c = c }, metat) -- are released by the kernel (60 seconds or so).
-- create finalized try local t = socket.gettime() + timeout
h.try = socket.newtry(function() h:close() end) while socket.gettime() < t do
-- set timeout before connecting local c = socket.tcp()
h.try(c:settimeout(_M.TIMEOUT)) c:settimeout(timeout)
h.try(c:connect(host, port or _M.PORT)) c:setoption("reuseaddr", true)
-- here everything worked c:bind("*", 0)
return h if c:connect(host, port) == 1 then
return c
end
c:close()
end
end
function _M.open(host, opt)
local port = opt.port or _M.port
local timeout = opt.timeout or _M.TIMEOUT
if opt.bindBeforeConnect == true then
local c = socket.try(_bindBeforeConnect(host, port, timeout))
local h = base.setmetatable({ c = c }, metat)
h.try = socket.newtry(function() h:close() end)
return h
else
-- create socket with user connect function, or with default
local c = socket.try((create or socket.tcp)())
local h = base.setmetatable({ c = c }, metat)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(timeout))
h.try(c:connect(host, port))
-- here everything worked
return h
end
end end
function metat.__index:sendrequestline(method, uri) function metat.__index:sendrequestline(method, uri)
@ -294,7 +320,7 @@ end
-- we loop until we get what we want, or -- we loop until we get what we want, or
-- until we are sure there is no way to get it -- until we are sure there is no way to get it
local nreqt = adjustrequest(reqt) local nreqt = adjustrequest(reqt)
local h = _M.open(nreqt.host, nreqt.port, nreqt.create) local h = _M.open(nreqt.host, nreqt)
-- send request line and headers -- send request line and headers
h:sendrequestline(nreqt.method, nreqt.uri) h:sendrequestline(nreqt.method, nreqt.uri)
h:sendheaders(nreqt.headers) h:sendheaders(nreqt.headers)
@ -329,12 +355,21 @@ end
return 1, code, headers, status return 1, code, headers, status
end end
local function srequest(u, b) local function srequest(u, b, o)
local t = {} local t = {}
local reqt = { local reqt = {
url = u, url = u,
sink = ltn12.sink.table(t) sink = ltn12.sink.table(t)
} }
if base.type(b) == "table" then
o = b
b = nil
end
if o ~= nil then
for k,v in pairs(o) do
reqt[k] = v
end
end
if b then if b then
reqt.source = ltn12.source.string(b) reqt.source = ltn12.source.string(b)
reqt.headers = { reqt.headers = {
@ -347,8 +382,8 @@ local function srequest(u, b)
return table.concat(t), code, headers, status return table.concat(t), code, headers, status
end end
_M.request = socket.protect(function(reqt, body) _M.request = socket.protect(function(reqt, body, opt)
if base.type(reqt) == "string" then return srequest(reqt, body) if base.type(reqt) == "string" then return srequest(reqt, body, opt)
else return trequest(reqt) end else return trequest(reqt) end
end) end)