164 lines
5.6 KiB
Lua

--------------------------------------------------------------------------------
------------------------------ ##### ## ------------------------------
------------------------------ ## ## # ## ------------------------------
------------------------------ ## ## ## ## ------------------------------
------------------------------ ## ## # ## ------------------------------
------------------------------ ##### ### ###### ------------------------------
-------------------------------- --------------------------------
----------------------- An Object Request Broker in Lua ------------------------
--------------------------------------------------------------------------------
-- Project: OiL - ORB in Lua --
-- Release: 0.4 --
-- Title : Client-side CORBA GIOP Protocol specific to IIOP --
-- Authors: Renato Maia <maia@inf.puc-rio.br> --
--------------------------------------------------------------------------------
-- Notes: --
-- See section 15.7 of CORBA 3.0 specification. --
-- See section 13.6.10.3 of CORBA 3.0 specification for IIOP corbaloc. --
--------------------------------------------------------------------------------
-- channels:Facet
-- channel:object retieve(configs:table, [probe:boolean])
--
-- sockets:Receptacle
-- socket:object tcp()
-- input:table, output:table select([input:table], [output:table], [timeout:number])
--------------------------------------------------------------------------------
local next = next
local pairs = pairs
local setmetatable = setmetatable
local type = type
local ObjectCache = require "loop.collection.ObjectCache"
local Wrapper = require "loop.object.Wrapper"
local oo = require "oil.oo" --[[VERBOSE]] local verbose = require "oil.verbose"
module("oil.kernel.base.Connector", oo.class)
context = false
--------------------------------------------------------------------------------
-- connection management
local function reset_wrapped_socket(self) --[[VERBOSE]] verbose:channels("resetting channel (attempt to reconnect)")
self.__object:close()
local sockets = self.factory.context.sockets
local result, errmsg = sockets:tcp()
if result then
local socket = result
result, errmsg = socket:connect(self.host, self.port)
if result then
self.__object = socket.__object
end
end
return result, errmsg
end
local function reset_plain_socket(self) --[[VERBOSE]] verbose:channels("resetting channel (attempt to reconnect)")
self.__object:close()
local sockets = self.factory.context.sockets
local result, errmsg = sockets:tcp()
if result then
local socket = result
result, errmsg = socket:connect(self.host, self.port)
if result then
self.__object = socket
end
end
return result, errmsg
end
local function probe_wrapped_socket(self)
local list = { self }
return self.factory.context.sockets:select(list, nil, 0)[1] == list[1]
end
local list = {}
local function probe_plain_socket(self)
list[1] = self.__object
return self.factory.context.sockets:select(list, nil, 0)[1] == list[1]
end
local function close_socket(self)
local ports = self.factory.cache[self.host]
ports[self.port] = nil
if next(ports) == nil then
self.cache[self.host] = nil
end
return self.__object:close()
end
--------------------------------------------------------------------------------
-- setup of TCP socket options
function setupsocket(self, socket)
local options = self.options
if options then
for name, value in pairs(options) do
socket:setoption(name, value)
end
end
return socket
end
--------------------------------------------------------------------------------
-- channel cache for reuse
SocketCache = oo.class{ __index = ObjectCache.__index, __mode = "v" }
function __init(self, object)
self = oo.rawnew(self, object)
--
-- cache of active channels
-- self.cache[host][port] == <channel to host:port>
--
self.cache = ObjectCache()
function self.cache.retrieve(_, host)
local cache = SocketCache()
function cache.retrieve(_, port)
local socket, errmsg = self.context.sockets:tcp()
if socket then --[[VERBOSE]] verbose:channels("new socket to ",host,":",port)
local success
success, errmsg = socket:connect(host, port)
if success then
if type(socket) ~= "table" then
socket = Wrapper{
__object = socket,
probe = probe_plain_socket,
reset = reset_plain_socket,
}
else
socket.probe = probe_wrapped_socket
socket.reset = reset_wrapped_socket
end
socket.factory = self
socket.host = host
socket.port = port
socket.close = close_socket
return self:setupsocket(socket)
else
self.except = "connection refused"
end
else
self.except = "too many open connections"
end
end
cache[cache.retrieve] = true -- avoid being collected as unused sockets
return cache
end
return self
end
--------------------------------------------------------------------------------
-- channel factory
function retrieve(self, profile) --[[VERBOSE]] verbose:channels("retrieve channel connected to ",profile.host,":",profile.port)
local channel = self.cache[profile.host][profile.port]
if channel then
return channel
else
return nil, self.except
end
end