megaco_test_generator.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,523 行 · 第 1/4 页
ERL
1,523 行
%% ``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$%%%%----------------------------------------------------------------------%% Purpose: Message sequence generator for megaco%%-----------------------------------------------------------------------module(megaco_test_generator).-export([start_link/1, start_link/2, stop/1, tcp/2, tcp/3, megaco/2, megaco/3, await_reply/2, await_reply/3, tcp_await_reply/1, tcp_await_reply/2, megaco_await_reply/1, megaco_await_reply/2 ]).%% Internal exports-export([start/2, init/3, tcp_handler_main/3, megaco_handler_main/3]).%% Megaco callback api-export([ handle_connect/3, handle_disconnect/4, handle_syntax_error/4, handle_message_error/4, handle_trans_request/4, handle_trans_long_request/4, handle_trans_reply/5, handle_trans_ack/5, handle_trans_request_abort/5, handle_unexpected_trans/4 ]).-export([megaco_connect/5]).-include_lib("megaco/include/megaco.hrl").%%-----------------------------------------------------------------------define(TIMEOUT, timer:minutes(5)).%%-----------------------------------------------------------------------record(state, {parent, handler, name, timer}).%% A TCP sequence generator data record-record(tcp, { listen, % Listen socket connection, % Connection socket encode, % Encode fun decode, % Decode fun result = [] % Accumulated results from verification }).%% A MEGACO sequence generator data record-record(megaco, { mid, recv_handle, port, send_handle, conn_handle, transport_sup, ctrl_pid, result = [] % Accumulated results from verification }).%%----------------------------------------------------------------------start_link(Name) when is_list(Name) -> start(Name, self()).start_link(Name, Node) when is_list(Name) and (Node /= node()) -> case rpc:call(Node, ?MODULE, start, [Name, self()]) of {ok, Pid} -> link(Pid), {ok, Pid}; Error -> Error end;start_link(Name, Node) when is_list(Name) and (Node == node()) -> case start(Name, self()) of {ok, Pid} -> link(Pid), {ok, Pid}; Error -> Error end. start(Name, Pid) when is_pid(Pid) -> proc_lib:start(?MODULE, init, [Name, self(), Pid]).stop(Pid) -> request(Pid, stop).tcp(Pid, Instructions) -> tcp(Pid, Instructions, ?TIMEOUT).tcp(Pid, Instructions, Timeout) when is_pid(Pid) and is_list(Instructions) and is_integer(Timeout) -> request(Pid, {tcp, Instructions, Timeout}), tcp_reply.tcp_await_reply(Pid) -> await_reply(tcp_reply, Pid).tcp_await_reply(Pid, Timeout) -> await_reply(tcp_reply, Pid, Timeout).megaco(Pid, Instructions) -> megaco(Pid, Instructions, ?TIMEOUT).megaco(Pid, Instructions, Timeout) when is_pid(Pid) and is_list(Instructions) and is_integer(Timeout) -> request(Pid, {megaco, Instructions, Timeout}), megaco_reply.megaco_await_reply(Pid) -> await_reply(megaco_reply, Pid).megaco_await_reply(Pid, Timeout) -> await_reply(megaco_reply, Pid, Timeout).request(Pid, Req) -> Pid ! {Req, self()}. await_reply(Tag, Pid) -> await_reply(Tag, Pid, infinity).await_reply(Tag, Pid, Timeout) -> receive {Tag, Pid, Reply} -> Reply after Timeout -> {error, timeout} end.%%---------------------------------------------------------------------- init(Name, Starter, Parent) -> put(name, Name ++ "-GEN"), process_flag(trap_exit, true), d("init -> entry with" "~n Name: ~s" "~n Starter: ~p" "~n Parent: ~p", [Name, Starter, Parent]), proc_lib:init_ack(Starter, {ok, self()}), loop(#state{parent = Parent, name = Name}).loop(#state{parent = Parent} = State) -> d("loop -> await request"), receive {stop, Parent} -> abort(State), exit(normal); {'EXIT', Parent, Reason} -> exit({parent_exit, Reason}); {abort, Parent} -> abort(State), loop(State); {{tcp, Instructions, Timeout}, Parent} -> d("loop -> received tcp request"), Handler = start_tcp_handler(State#state.name, Instructions), d("loop -> tcp handler: ~p", [Handler]), Timer = erlang:send_after(Timeout, self(), tcp_timeout), loop(State#state{handler = Handler, timer = Timer}); {tcp_result, Pid, Res} when State#state.handler == Pid -> d("loop -> received tcp result: ~n~p", [Res]), Parent ! {tcp_reply, self(), Res}, Timer = State#state.timer, Time = erlang:cancel_timer(Timer), d("loop -> Time: ~w msec", [Time]), loop(State#state{handler = undefined, timer = undefined}); {{megaco, Instructions, Timeout}, Parent} -> d("loop -> received megaco request"), Handler = start_megaco_handler(State#state.name, Instructions), d("loop -> megaco handler: ~p", [Handler]), Timer = erlang:send_after(Timeout, self(), megaco_timeout), loop(State#state{handler = Handler, timer = Timer}); {megaco_result, Pid, Res} when State#state.handler == Pid -> d("loop -> received megaco_reply"), Parent ! {megaco_reply, self(), Res}, Timer = State#state.timer, Time = erlang:cancel_timer(Timer), d("loop -> Time: ~p", [Time]), loop(State#state{handler = undefined, timer = undefined}); {'EXIT', Handler, Reason} when State#state.handler == Handler -> abort(State), exit({handler_exit, Reason}); tcp_timeout -> d("loop -> received tcp-timeout"), Handler = State#state.handler, exit(Handler, kill), Parent ! {tcp_reply, self(), {error, timeout}}, loop(State#state{handler = undefined, timer = undefined}); megaco_timeout -> d("loop -> received megaco-timeout"), Handler = State#state.handler, exit(Handler, kill), Parent ! {megaco_reply, self(), {error, timeout}}, loop(State#state{handler = undefined, timer = undefined}); Any -> p("loop -> received " "~n Any: ~p", [Any]), loop(State) end.%%% ----------------------------------------------------------------abort(#state{handler = Pid}) when is_pid(Pid) -> Pid ! {stop, self()};abort(_) -> ok.%%% ----------------------------------------------------------------start_tcp_handler(Name, Instructions) -> spawn_link(?MODULE, tcp_handler_main, [Name, Instructions, self()]).tcp_handler_main(Name, Instructions, Parent) -> put(name, Name), {Tcp, Reply} = handle_tcp(Instructions), close(Tcp), %% attempt to close just in case Parent ! {tcp_result, self(), Reply}, receive {stop, Parent} -> tcp_cleanup(Tcp), exit(normal) end.%% Instructions: [instruction()]%% instruction() = {debug, Debug} |%% {encode, Encode} |%% {decode, Decode} |%% {send, Msg} |%% {expect_receive, TransactionType} |%% {expect_receive, {TransactionType, To}} |%% {listen, Port} |%% {expect_accept, {{Host, Port}, To}} |%% {accept, Port} |%% {accept, {Addr, Port}} |%% {sleep, To} |%% handle_tcp(Instructions0) when is_list(Instructions0) -> case (catch parse_tcp(Instructions0, [])) of {ok, Instructions} -> (catch handle_tcp1(Instructions)); Error -> {invalid, Error} end.handle_tcp1(Instructions) -> handle_tcp1(Instructions, #tcp{}).handle_tcp1([], #tcp{result = Res} = Tcp) -> Reply = {ok, lists:reverse(Res)}, {Tcp, Reply};handle_tcp1([Instruction|Instructions], Tcp0) -> case (catch do_tcp(Instruction, Tcp0)) of Tcp when is_record(Tcp, tcp) -> handle_tcp1(Instructions, Tcp); Error -> {Tcp0, Error} end.do_tcp({debug, Debug}, Tcp) -> p("debug: ~p", [Debug]), put(debug, Debug), Tcp;do_tcp({encode, Encode}, Tcp) -> p("encode: ~p", [Encode]), Tcp#tcp{encode = Encode};do_tcp({decode, Decode}, Tcp) -> p("decode: ~p", [Decode]), Tcp#tcp{decode = Decode};do_tcp(disconnect, Tcp) -> p("disconnect"), tcp_cleanup(Tcp), Tcp#tcp{listen = undefined, connection = undefined};do_tcp({listen, Port}, Tcp) -> p("listen to ~p", [Port]), Opts = [binary, {packet, tpkt}, {active, false}, {reuseaddr, true}], case (catch gen_tcp:listen(Port, Opts)) of {ok, Listen} -> d("listen -> listen socket created"), Tcp#tcp{listen = Listen}; Error -> e("failed creating listen socket: ~p", [Error]), tcp_error(listen, Error) end;do_tcp({expect_accept, {Addr, To}}, #tcp{listen = Listen} = Tcp) -> p("expect_accept from ~p (~p)", [Addr, To]), case (catch gen_tcp:accept(Listen, To)) of {ok, Sock} -> d("expect_accept -> connection accepted"), case (catch inet:peername(Sock)) of {ok, {Addr, _Port}} -> d("expect_accept -> valid address"), Tcp#tcp{connection = Sock}; {ok, {_Addr, _Port}} when Addr == any -> d("expect_accept -> valid"), Tcp#tcp{connection = Sock}; {ok, AddrPort} -> tcp_error(expect_accept, {unknown_connect, AddrPort}); Else -> e("failed getting peername for socket: ~p", [Else]), tcp_error(expect_accept, {peername, Else}) end; Error -> e("failed accepting connection: ~p", [Error]), close(Listen), tcp_error(expect_accept, {accept_error, Error}) end;do_tcp({connect, {Addr, Port, To}}, Tcp) -> p("connect to ~p, ~p", [Addr, Port]), Opts = [binary, {packet, tpkt}, {active, once}], case (catch gen_tcp:connect(Addr, Port, Opts, To)) of {ok, Sock} -> d("connect -> connected"), Tcp#tcp{connection = Sock}; Error -> e("failed connecting: ~p", [Error]), tcp_error(connect, Error) end;%% Already encodeddo_tcp({send, Desc, Bin}, #tcp{connection = Sock} = Tcp) when is_binary(Bin) -> p("send ~s message", [Desc]), NewBin = add_tpkt_header(Bin), d("send -> tpkt header added [~w], now send", [sz(NewBin)]), case (catch gen_tcp:send(Sock, NewBin)) of ok -> d("send -> message sent"), Tcp;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?