11.Orber拦截器 | 11. Orber Interceptors
11 Orber拦截器
11.1使用拦截器
对于Inter-ORB通信,例如通过IIOP
,可以拦截请求和回复。为了能够使用Interceptors
Orber,interceptors
必须定义配置参数。
配置Orber使用拦截器
interceptors
必须定义配置参数,例如,作为命令行选项:
erl -orber interceptors "{native, ['myInterceptor']}"
有可能使用多个拦截器; 只需将它们添加到列表中,它们将按照它们出现在列表中的顺序调用。
也可以在运行时激活和停用拦截器,但这只会影响当前现有的连接。有关更多信息,请参阅Orber的参考手册,了解有关操作orber:activate_audit_trail/0/1
和orber:activate_audit_trail/0/1.
创建拦截器
每个提供的拦截器都必须
输出以下功能:
new_out_connection / 3/5
- 当客户端应用程序调用驻留在远程ORB上的对象时,将调用其中一个操作。如果一个拦截器导出了两个版本,arity 3和5,那么将调用哪个操作是Orber内部的。
new_in_connection / 3/5
- 当客户端ORB尝试建立与目标ORB的连接时,将调用其中一个操作。如果一个拦截器导出了两个版本,arity 3和5,那么将调用哪个操作是Orber内部的。
out_request / 6
- 提供客户端ORB上的所有请求数据。
out_request_encoded / 6
- 类似于out_request
请求主体是编码。
in_request_encoded / 6
- 在新的请求到达目标ORB后,请求数据以编码格式传递给拦截器。
in_request / 6
- 在调用目标对象的操作之前,调用拦截器in_request
。
out_reply / 6
- 在目标对象回复之后,out_reply
操作被调用的结果是对象调用。
out_reply_encoded / 6
- 在将响应发送回客户端ORB之前,将以编码格式调用结果调用此操作。
in_reply_encoded / 6
- 在客户端ORB收到回复后,以编码格式回复此函数。
in_reply / 6
- 在将响应传递给客户端之前,调用该操作。
closed_in_connection / 1
- 当连接在客户端终止时,调用该函数。
closed_out_connection / 1
- 如果传出连接终止,将调用此操作。
操作new_out_connection
,new_in_connection
,closed_in_connection
和closed_out_connection
操作仅调用一次,
每个连接。对于每个远程CORBA对象的请求/响应,剩下的操作被调用,如下所示。
图11.1:Interceptor函数的调用顺序。
11.2 拦截器示例
假设我们希望创建一个简单的访问服务,其目的是:
- 只允许ORB驻留在特定节点上的传入请求。
- 限制任何客户端可以调用操作的对象。
- 只允许传出请求调用有限的外部ORB%27。
- 向每个二进制请求/回复正文添加校验和。
为了限制访问,我们使用一个保护所有信息的受保护和命名的ets表。 如何启动和维护ets-table是特定于实现的,但它包含{Node,ObjectTable,ChecksumModule},其中Node用作ets-key,ObjectTable是另一个ets-table的引用,我们在其中存储客户端是哪些对象 允许调用操作,并且ChecksumModule确定我们应该使用哪个模块来处理校验和。
new_in_connection(Arg, Host, Port) ->
%% Since we only use one interceptor we do not care about the
%% input Arg since it is set do undefined by Orber.
case ets:lookup(in_access_table, Host) of
[] ->
%% We may want to log the Host/Port to see if someone tried
%% to hack in to our system.
exit("Access not granted"
[{Host, ObjTable, ChecksumModule}] ->
{ObjTable, ChecksumModule}
end.
每当调用其中一个拦截器函数时,返回的元组(即{ObjTable,ChecksumModule})将作为第一个参数传递。除非连接尝试没有失败,否则我们现在准备好接收来自客户端ORB的请求。
当一个新的请求进入时,第一个被调用的拦截器函数是in_request_encoded。 我们将通过以下方式从编码请求主体中移除校验和:
in_request_encoded{ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
NewBin = ChecksumModule:remove_checksum(Bin),
{NewBin, Extra}.
如果校验和检查失败,ChecksumModule应该调用exit / 1。 但是,如果检查成功,我们现在准备检查是否允许客户端ORB对象调用目标对象上的操作。 请注意,可以在in_request_encoded中运行这两项检查。 请注意,校验和计算必须相对较快以确保良好的吞吐量。
如果我们愿意,可以限制任何客户端只使用服务器导出的操作的子集:
in_request{ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Params, Extra) ->
case ets:lookup(ObjTable, {ObjKey, Op}) of
[] ->
exit("Client tried to invoke illegal operation"
[SomeData] ->
{Params, Extra}
end.
此时,Orber现在准备调用目标对象的操作。由于我们不关心答复是out_reply
,函数什么也不做,即:
out_reply(_, _, _, _, Reply, Extra) ->
{Reply, Extra}.
如果客户端ORB希望将校验和添加到回复中,我们使用以下命令添加它:
out_reply_encoded{ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
NewBin = ChecksumModule:add_checksum(Bin),
{NewBin, Extra}.
警告
如果我们像上面的行为那样操作二进制文件必
成Bin == remove_checksum(add_checksum(Bin))
...
对于传出请求,原则是相同的。因此,这里不再对此作进一步的描述。完整的拦截器模块如下所示:
-module(myInterceptor).
%% Interceptor functions.
-export([new_out_connection/3,
new_in_connection/3,
closed_in_connection/1,
closed_out_connection/1,
in_request_encoded/6,
in_reply_encoded/6,
out_reply_encoded/6,
out_request_encoded/6,
in_request/6,
in_reply/6,
out_reply/6,
out_request/6]).
new_in_connection(Arg, Host, Port) ->
%% Since we only use one interceptor we do not care about the
%% input Arg since it is set do undefined by Orber.
case ets:lookup(in_access_table, Host) of
[] ->
%% We may want to log the Host/Port to see if someone tried
%% to hack in to our system.
exit("Access not granted"
[{Host, ObjTable, ChecksumModule}] ->
{ObjTable, ChecksumModule}
end.
new_out_connection(Arg, Host, Port) ->
case ets:lookup(out_access_table, Host) of
[] ->
exit("Access not granted"
[{Host, ObjTable, ChecksumModule}] ->
{ObjTable, ChecksumModule}
end.
in_request_encoded{_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
NewBin = ChecksumModule:remove_checksum(Bin),
{NewBin, Extra}.
in_request{ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
case ets:lookup(ObjTable, {ObjKey, Op}) of
[] ->
exit("Client tried to invoke illegal operation"
[SomeData] ->
{Params, Extra}
end.
out_reply(_, _, _, _, Reply, Extra) ->
{Reply, Extra}.
out_reply_encoded{_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
NewBin = ChecksumModule:add_checksum(Bin),
{NewBin, Extra}.
out_request{ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
case ets:lookup(ObjTable, {ObjKey, Op}) of
[] ->
exit("Client tried to invoke illegal operation"
[SomeData] ->
{Params, Extra}
end.
out_request_encoded{_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
NewBin = ChecksumModule:add_checksum(Bin),
{NewBin, Extra}.
in_reply_encoded{_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
NewBin = ChecksumModule:remove_checksum(Bin),
{NewBin, Extra}.
in_reply(_, _, _, _, Reply, Extra) ->
{Reply, Extra}.
closed_in_connection(Arg) ->
%% Nothing to clean up.
Arg.
closed_out_connection(Arg) ->
%% Nothing to clean up.
Arg.
注
还可以使用拦截器进行调试,例如,打印调用哪些对象和操作,使用哪些参数和操作的结果。结合配置参数orber_debug_level
找出什么问题或仅仅记录流量是相当容易的。