aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/test/megaco_test_generic_transport.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/megaco/test/megaco_test_generic_transport.erl')
-rw-r--r--lib/megaco/test/megaco_test_generic_transport.erl354
1 files changed, 354 insertions, 0 deletions
diff --git a/lib/megaco/test/megaco_test_generic_transport.erl b/lib/megaco/test/megaco_test_generic_transport.erl
new file mode 100644
index 0000000000..10afa45baa
--- /dev/null
+++ b/lib/megaco/test/megaco_test_generic_transport.erl
@@ -0,0 +1,354 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% 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 online 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.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Generic megaco transport simulator module
+%%----------------------------------------------------------------------
+
+-module(megaco_test_generic_transport).
+
+-behaviour(gen_server).
+-behaviour(megaco_transport).
+
+-export([
+ start_transport/0,
+ listen/2,
+ connect/2,
+ start/1,
+ stop/0,
+ incomming_message/2
+ ]).
+
+%% gen_server callbacks
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3
+ ]).
+
+%% megaco_transport callbacks
+-export([
+ send_message/2,
+ send_message/3,
+ resend_message/2
+ ]).
+
+-record(state, {parent,
+ controller,
+ receive_handle}).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include("megaco_test_lib.hrl").
+-define(SERVER, ?MODULE).
+
+
+%%-------------------------------------------------------------------
+%% API
+%%-------------------------------------------------------------------
+
+start(RH) ->
+ {ok, Pid} = start_transport(),
+ {ok, SendHandle, _} = connect(Pid, [{receive_handle, RH}]),
+ {ok, SendHandle}.
+
+start_transport() ->
+ %% GS_ARGS = [{debug,[trace]}],
+ GS_ARGS = [],
+ {ok, Pid} = gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], GS_ARGS),
+ unlink(Pid),
+ {ok, Pid}.
+
+connect(Sup, Opts) ->
+ call({connect, Sup, Opts}).
+
+listen(Sup, Opts) ->
+ call({listen, Sup, Opts}).
+
+stop() ->
+ call(stop).
+
+
+%%----------------------------------------------------------------------
+%% Megaco transport callback
+%%----------------------------------------------------------------------
+
+send_message(SendHandle, Bin) ->
+ call({transport, {send_message, SendHandle, Bin}}).
+
+send_message(SendHandle, Bin, Resend) ->
+ call({transport, {send_message, SendHandle, Bin, Resend}}).
+
+resend_message(SendHandle, Bin) ->
+ call({transport, {resend_message, SendHandle, Bin}}).
+
+incomming_message(Pid, Msg) ->
+ cast(Pid, {incomming_message, Msg}).
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+init([Parent]) ->
+ {ok, #state{parent = Parent}}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_call({connect, _Sup, Opts}, _From, State) ->
+ d("handle_call(connect) -> entry with"
+ "~n Opts: ~p", [Opts]),
+ {value, {_, ReceiveHandle}} = lists:keysearch(receive_handle, 1, Opts),
+ {value, {_, Controller}} = lists:keysearch(port, 1, Opts),
+ SendHandle = self(),
+ ControlPid = self(),
+ Reply = {ok, SendHandle, ControlPid},
+ {reply, Reply, State#state{controller = Controller,
+ receive_handle = ReceiveHandle}};
+
+handle_call({listen, _Sup, Opts}, _From, State) ->
+ d("handle_call(listen) -> entry with"
+ "~n Opts: ~p", [Opts]),
+ {value, {_, ReceiveHandle}} = lists:keysearch(receive_handle, 1, Opts),
+ {value, {_, Controller}} = lists:keysearch(port, 1, Opts),
+ SendHandle = self(),
+ ControlPid = self(),
+ Reply = {ok, SendHandle, ControlPid},
+ Controller ! {listen, ReceiveHandle, SendHandle, ControlPid},
+ {reply, Reply, State#state{controller = Controller,
+ receive_handle = ReceiveHandle}};
+
+handle_call(stop, _From, State) ->
+ d("handle_call(stop) -> entry"),
+ Reply = ok,
+ Reason = normal,
+ {stop, Reason, Reply, State};
+
+handle_call({transport, Event}, _From,
+ #state{controller = Pid, receive_handle = RH} = State) ->
+ d("handle_call(transport) -> entry with"
+ "~n Event: ~p", [Event]),
+ Reply = handle_transport(Pid, RH, Event),
+ {reply, Reply, State};
+
+handle_call(Req, From, State) ->
+ d("handle_call -> entry with"
+ "~n Req: ~p", [Req]),
+ Reply = {error, {unknown_request, Req}},
+ Reason = {received_unexpected_request, Req, From},
+ {stop, Reason, Reply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast({incomming_message, Msg},
+ #state{receive_handle = RH} = State) ->
+ d("handle_cast(incomming_message) -> entry with"
+ "~n Msg: ~p", [Msg]),
+ handle_incomming_message(Msg, RH),
+ {noreply, State};
+
+handle_cast(Msg, State) ->
+ d("handle_cast -> entry with"
+ "~n Msg: ~p", [Msg]),
+ Reason = {received_unexpected_message, Msg},
+ {stop, Reason, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info(Info, State) ->
+ d("handle_info -> entry with"
+ "~n Info: ~p", [Info]),
+ Reason = {received_unexpected_info, Info},
+ {stop, Reason, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+handle_transport(Pid,
+ #megaco_receive_handle{encoding_mod = EM,
+ encoding_config = EC},
+ {Event, SendHandle, Bin, Resend}) ->
+ Info =
+ case (catch EM:decode_message(EC, Bin)) of
+ {ok, MegMsg} ->
+ {message, MegMsg, Resend};
+ Error ->
+ d("handle_transport -> decode failed"
+ "~n Error: ~p", [Error]),
+ {bad_message, Error, Bin}
+ end,
+ handle_transport(Pid, Event, SendHandle, Info);
+handle_transport(Pid,
+ #megaco_receive_handle{encoding_mod = EM,
+ encoding_config = EC},
+ {Event, SendHandle, Bin}) ->
+ Info =
+ case (catch EM:decode_message(EC, Bin)) of
+ {ok, MegMsg} ->
+ {message, MegMsg};
+ Error ->
+ d("handle_transport -> decode failed"
+ "~n Error: ~p", [Error]),
+ {bad_message, Error, Bin}
+ end,
+ handle_transport(Pid, Event, SendHandle, Info).
+
+handle_transport(Pid, Event, SendHandle, Info) ->
+ Pid ! {transport_event, {Event, SendHandle, Info}, self()},
+ receive
+ {transport_reply, Reply, Pid} ->
+ d("handle_transport -> received reply"
+ "~n Reply: ~p", [Reply]),
+ Reply
+ after 10000 ->
+ receive
+ Any ->
+ d("handle_transport -> received crap after timeout"
+ "~n Any: ~p", [Any]),
+ exit({timeout, Any})
+ after 0 ->
+ d("handle_transport -> timeout"),
+ exit(timeout)
+ end
+ end.
+
+
+%% This function is used to simulate incomming messages
+handle_incomming_message(Msg,
+ #megaco_receive_handle{encoding_mod = EM,
+ encoding_config = EC} = RH) ->
+ Self = self(),
+ case EM:encode_message(EC, Msg) of
+ {ok, Bin} ->
+ ProcessMessage =
+ fun() ->
+ megaco:process_received_message(RH, Self, Self, Bin)
+ end,
+ spawn(ProcessMessage),
+ ok;
+ Error ->
+ d("handle_incomming_message -> encode failed"
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end.
+
+
+%%-------------------------------------------------------------------
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, Timeout) ->
+ case (catch gen_server:call(?SERVER, Req, Timeout)) of
+ {'EXIT', _} ->
+ {error, not_started};
+ Res ->
+ Res
+ end.
+
+%% cast(Msg) ->
+%% cast(whereis(?SERVER), Msg).
+
+cast(Pid, Msg) ->
+ d("cast -> entry with"
+ "~n Pid: ~p"
+ "~n Msg: ~p", [Pid, Msg]),
+ case (catch gen_server:cast(Pid, Msg)) of
+ {'EXIT', Reason} ->
+ d("cast -> failed casting"
+ "~n Reason: ~p", [Reason]),
+ {error, not_started};
+ Res ->
+ Res
+ end.
+
+
+%%-------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(now(), F, A).
+
+
+print(Ts, F, A) ->
+ io:format("*** [~s] GENERIC TRANSPORT [~p] ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), self() | A]).
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+