orber_iiop_outproxy.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 530 行 · 第 1/2 页
ERL
530 行
%%--------------------------------------------------------------------%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%%%-----------------------------------------------------------------%% File: orber_iiop_outproxy.erl%% %% Description:%% This file contains the IIOP "proxy" for outgoing connections%%%% Creation date: 990425%%%%------------------------------------------------------------------module(orber_iiop_outproxy).-behaviour(gen_server).-include_lib("orber/src/orber_iiop.hrl").-include_lib("orber/include/corba.hrl").%%-----------------------------------------------------------------%% External exports%%------------------------------------------------------------------export([start/0, start/1, request/5, cancel/2, cancel/3]).%%-----------------------------------------------------------------%% Internal exports%%------------------------------------------------------------------export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2, stop/2, stop/1, checkheaders/1]).%%-----------------------------------------------------------------%% Macros/Defines%%------------------------------------------------------------------define(DEBUG_LEVEL, 7).-record(state, {stype, socket, db, timeout, client_timeout, host, port, parent, error_reason = {'EXCEPTION', #'COMM_FAILURE' {completion_status=?COMPLETED_MAYBE}}}).%%-----------------------------------------------------------------%% External interface functions%%-----------------------------------------------------------------start() -> ignore.start(Opts) -> gen_server:start_link(orber_iiop_outproxy, Opts, []).request(Pid, true, Timeout, Msg, RequestId) -> %% Why not simply use gen_server:call? We must be able to receive %% more than one reply (i.e. fragmented messages). MRef = erlang:monitor(process, Pid), gen_server:cast(Pid, {request, Timeout, Msg, RequestId, self(), MRef}), receive {MRef, Reply} -> erlang:demonitor(MRef), receive {'DOWN', MRef, _, _, _} -> Reply after 0 -> Reply end; {'DOWN', MRef, _, Pid, _Reason} when pid(Pid) -> receive %% Clear EXIT message from queue {'EXIT', _Pid, _What} -> corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE}) after 0 -> corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE}) end; {fragmented, GIOPHdr, Bytes, RequestId, MRef} -> collect_fragments(GIOPHdr, [], Bytes, Pid, RequestId, MRef) end;request(Pid, _, _, Msg, _RequestId) -> %% No response expected gen_server:cast(Pid, {oneway_request, Msg}).cancel(Pid, RequestId) -> gen_server:cast(Pid, {cancel, RequestId}).cancel(Pid, RequestId, MRef) -> gen_server:cast(Pid, {cancel, RequestId, MRef, self()}).%%-----------------------------------------------------------------%% Internal interface functions%%-----------------------------------------------------------------%%-----------------------------------------------------------------%% Func: stop/2%%-----------------------------------------------------------------stop(Pid, Timeout) -> gen_server:call(Pid, stop, Timeout).stop(Pid) -> gen_server:cast(Pid, stop).%%-----------------------------------------------------------------%% Server functions%%-----------------------------------------------------------------%%-----------------------------------------------------------------%% Func: init/1%%-----------------------------------------------------------------init({connect, Host, Port, SocketType, SocketOptions, Parent, Key, NewKey}) -> process_flag(trap_exit, true), case catch orber_socket:connect(SocketType, Host, Port, SocketOptions) of {'EXCEPTION', _E} -> ignore; %% We used to reply the below but since this would generate a CRASH REPORT %% if '-boot start_sasl' used. Due to a request to change this behaviour %% we did. %% {stop, {'EXCEPTION', E}}; Socket -> SockData = orber_socket:sockdata(SocketType, Socket), orber_iiop_pm:add_connection(Key, NewKey, SockData), Timeout = orber:iiop_connection_timeout(), {ok, #state{stype = SocketType, socket = Socket, db = ets:new(orber_outgoing_requests, [set]), timeout = Timeout, client_timeout = orber:iiop_timeout(), host = Host, port = Port, parent = Parent}, Timeout} end.%%-----------------------------------------------------------------%% Func: terminate/2%%-----------------------------------------------------------------terminate(_Reason, #state{db = OutRequests, error_reason = ER}) -> %% Kill all proxies and delete table before terminating notify_clients(OutRequests, ets:first(OutRequests), ER), ets:delete(OutRequests), ok.notify_clients(_, '$end_of_table', _ER) -> ok;notify_clients(OutRequests, Key, ER) -> case ets:lookup(OutRequests, Key) of [{_, Pid, TRef, MRef}] -> cancel_timer(TRef), Pid ! {MRef, ER}, notify_clients(OutRequests, ets:next(OutRequests, Key), ER) end.%%-----------------------------------------------------------------%% Func: handle_call/3%%-----------------------------------------------------------------handle_call(stop, _From, State) -> {stop, normal, ok, State};handle_call(X, From, State) -> orber:dbg("[~p] orber_iiop_outproxy:handle_call(~p);~n" "Un-recognized call from ~p", [?LINE, X, From], ?DEBUG_LEVEL), {noreply, State, State#state.timeout}.%%-----------------------------------------------------------------%% Func: handle_cast/2%%-----------------------------------------------------------------handle_cast({request, Timeout, Msg, RequestId, From, MRef}, #state{client_timeout = DefaultTimeout} = State) -> orber_socket:write(State#state.stype, State#state.socket, Msg), true = ets:insert(State#state.db, {RequestId, From, start_timer(Timeout, DefaultTimeout, RequestId), MRef}), {noreply, State, State#state.timeout};handle_cast({oneway_request, Msg}, State) -> orber_socket:write(State#state.stype, State#state.socket, Msg), {noreply, State, State#state.timeout};handle_cast({cancel, ReqId}, State) -> case ets:lookup(State#state.db, ReqId) of [{ReqId, _From, TRef, _MRef}] -> cancel_timer(TRef), ets:delete(State#state.db, ReqId), orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p);~n" "Request cancelled", [?LINE, State], ?DEBUG_LEVEL), {noreply, State, State#state.timeout}; _ -> {noreply, State, State#state.timeout} end;handle_cast({cancel, ReqId, MRef, From}, State) -> case ets:lookup(State#state.db, ReqId) of [{ReqId, From, TRef, MRef}] -> cancel_timer(TRef), ets:delete(State#state.db, ReqId), From ! {MRef, ReqId, cancelled}, orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p); Request cancelled", [?LINE, State], ?DEBUG_LEVEL), {noreply, State, State#state.timeout}; _ -> From ! {MRef, ReqId, cancelled}, {noreply, State, State#state.timeout} end;handle_cast(stop, State) -> {stop, normal, State};handle_cast(X, State) -> orber:dbg("[~p] orber_iiop_outproxy:handle_cast(~p); Un-recognized cast.", [?LINE, X], ?DEBUG_LEVEL), {noreply, State, State#state.timeout}.%%-----------------------------------------------------------------%% Func: handle_info/2%%-----------------------------------------------------------------handle_info({tcp, _Socket, Bytes}, State) -> handle_reply(Bytes, State);handle_info({ssl, _Socket, Bytes}, State) -> handle_reply(Bytes, State);handle_info({tcp_closed, _Socket}, State) -> {stop, normal, State}; handle_info({ssl_closed, _Socket}, State) -> {stop, normal, State};handle_info({tcp_error, Socket, Reason}, #state{socket = Socket, host = Host, port = Port} = State) -> orber:error("[~p] IIOP proxy received the TCP error message: ~p~n" "The server-side ORB is located at '~p:~p'~n" "See the gen_tcp/inet documentation for more information.", [?LINE, Reason, Host, Port], ?DEBUG_LEVEL), {stop, normal, State};handle_info({ssl_error, Socket, Reason}, #state{socket = Socket, host = Host, port = Port} = State) -> orber:error("[~p] IIOP proxy received the SSL error message: ~p~n" "The server-side ORB is located at '~p:~p'~n" "See the SSL-application documentation for more information.", [?LINE, Reason, Host, Port], ?DEBUG_LEVEL), {stop, normal, State};handle_info({timeout, _TRef, ReqId}, State) -> case ets:lookup(State#state.db, ReqId) of [{ReqId, Pid, _, MRef}] -> ets:delete(State#state.db, ReqId), Pid ! {MRef, {'EXCEPTION', #'TIMEOUT'{completion_status=?COMPLETED_MAYBE}}}, orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p, ~p);~n" "Request timed out", [?LINE, State#state.host, State#state.port], ?DEBUG_LEVEL), {noreply, State, State#state.timeout}; _ -> {noreply, State, State#state.timeout} end;handle_info(stop, State) -> {stop, normal, State};handle_info(timeout, State) -> case ets:info(State#state.db, size) of 0 -> orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p, ~p);~n" "Outgoing connection timed out after ~p msec", [?LINE, State#state.host, State#state.port, State#state.timeout], ?DEBUG_LEVEL), {stop, normal, State}; _Amount -> %% Still pending request, cannot close the connection. {noreply, State, State#state.timeout} end;handle_info({'EXIT', Parent, Reason}, #state{parent = Parent} = State) -> orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p);~nParent terminated.", [?LINE, Reason], ?DEBUG_LEVEL), {stop, normal, State};handle_info({reconfigure, _Options}, State) -> %% Currently there are no parameters that can be changed.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?