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 + -
显示快捷键?