aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/examples/simple
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/megaco/examples/simple
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/megaco/examples/simple')
-rw-r--r--lib/megaco/examples/simple/Makefile153
-rw-r--r--lib/megaco/examples/simple/megaco_simple_mg.erl437
-rw-r--r--lib/megaco/examples/simple/megaco_simple_mgc.erl455
-rw-r--r--lib/megaco/examples/simple/modules.mk27
4 files changed, 1072 insertions, 0 deletions
diff --git a/lib/megaco/examples/simple/Makefile b/lib/megaco/examples/simple/Makefile
new file mode 100644
index 0000000000..f91d1d886f
--- /dev/null
+++ b/lib/megaco/examples/simple/Makefile
@@ -0,0 +1,153 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-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%
+
+include $(ERL_TOP)/make/target.mk
+
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug -W
+endif
+
+EBIN = .
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+MODULES = $(MG_MODULES) $(MGC_MODULES) $(COMMON_MODULES)
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR))
+
+MEGACO_ROOT_DIR = $(shell (cd .. ; dirname `pwd`))
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(WARN_UNUSED_WARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ERL_COMPILE_FLAGS += \
+ -pa $(ERL_TOP)/lib/megaco/ebin \
+ -I../../include
+
+ifneq ($(MGC_HOST),)
+MG_START_ARGS = "{mgc_host, $(MGC_HOST)}"
+endif
+
+ifneq ($(MG_INLINE_TRACE),true)
+MG_MEGACO_FILTER = -s megaco_filter
+MG_START_ARGS += "{trace,false}"
+else
+MG_START_ARGS += "{trace,true}"
+endif
+
+ifneq ($(MG_DEBUG),)
+MG_START_ARGS += "{debug,true}"
+else
+MG_START_ARGS += "{debug,false}"
+endif
+
+
+ifneq ($(MGC_INLINE_TRACE),true)
+MGC_MEGACO_FILTER = -s megaco_filter
+MGC_START_ARGS += "{trace,false}"
+else
+MGC_START_ARGS += "{trace,true}"
+endif
+
+ifneq ($(MGC_DEBUG),)
+MGC_START_ARGS += "{debug,true}"
+else
+MGC_START_ARGS += "{debug,false}"
+endif
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+opt: $(TARGET_FILES)
+
+debug:
+ @${MAKE} TYPE=debug opt
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "MEGACO_ROOT_DIR = $(MEGACO_ROOT_DIR)"
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+mg: opt
+ erl -noshell -pa $(MEGACO_ROOT_DIR)/ebin \
+ $(MG_MEGACO_FILTER) \
+ -s megaco \
+ -s megaco_simple_mg start_batch $(MG_START_ARGS)
+
+mgc: opt
+ erl -noshell -pa $(MEGACO_ROOT_DIR)/ebin \
+ $(MGC_MEGACO_FILTER) \
+ -s megaco \
+ -s megaco_simple_mgc start_batch $(MGC_START_ARGS)
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) $(RELSYSDIR)/examples/simple
+ $(INSTALL_DATA) $(ERL_FILES) $(TARGET_FILES) $(RELSYSDIR)/examples/simple
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
diff --git a/lib/megaco/examples/simple/megaco_simple_mg.erl b/lib/megaco/examples/simple/megaco_simple_mg.erl
new file mode 100644
index 0000000000..95efaf5df3
--- /dev/null
+++ b/lib/megaco/examples/simple/megaco_simple_mg.erl
@@ -0,0 +1,437 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-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: Simple example of an MG
+%%
+%% Example usage:
+%%
+%% cd megaco/examples/simple
+%% erl -pa ../../../megaco/ebin -s megaco_filter -s megaco
+%% megaco_simple_mg:start().
+%%----------------------------------------------------------------------
+
+-module(megaco_simple_mg).
+
+-behaviour(megaco_user).
+
+-export([
+ start_batch/0, start_batch/1, init_batch/4,
+ start/0, start/3,
+ start/4, %% ????????????????????????
+ stop/0, stop/1,
+ start_tcp_text/2, start_tcp_binary/2,
+ start_udp_text/2, start_udp_binary/2
+ ]).
+
+-export([
+ handle_connect/2,
+ handle_disconnect/3,
+ handle_syntax_error/3,
+ handle_message_error/3,
+ handle_trans_request/3,
+ handle_trans_long_request/3,
+ handle_trans_reply/4,
+ handle_trans_ack/4,
+ handle_unexpected_trans/3,
+ handle_trans_request_abort/4
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+
+
+%%----------------------------------------------------------------------
+%% To be used at command line: erl -s ?MODULE start_batch
+%%----------------------------------------------------------------------
+
+start_batch() ->
+ start_batch([]).
+
+start_batch(Args0) when is_list(Args0) ->
+ {ok, LocalHost} = inet:gethostname(),
+ Defs = [{mgc_host, LocalHost}, {trace,false}, {debug, false}],
+ Args = parse_args(Args0, Defs),
+ MgcHost = get_arg(mgc_host, Args),
+ Trace = get_arg(trace, Args),
+ Debug = get_arg(debug, Args),
+ Pid = spawn(?MODULE, init_batch, [self(), MgcHost, Trace, Debug]),
+ receive
+ {init_batch, Pid, Res} ->
+ io:format("~p(~p): ~p~n", [?MODULE, ?LINE, Res]),
+ Res
+ end.
+
+parse_args([], Acc) ->
+ Acc;
+parse_args([Arg|Args], Acc) when is_atom(Arg) ->
+ case string:tokens(atom_to_list(Arg),"{},") of
+ ["mgc_host", Host] when is_list(Host) ->
+ parse_args(Args, parse_args(mgc_host, Host, Acc));
+ ["trace",Trace] ->
+ parse_args(Args, parse_args(trace, list_to_atom(Trace), Acc));
+ ["debug",Debug] ->
+ parse_args(Args, parse_args(debug, list_to_atom(Debug), Acc));
+ _Invalid ->
+ parse_args(Args, Acc)
+ end.
+
+parse_args(Key, Val, Args) ->
+ Entry = {Key, Val},
+ case lists:keyreplace(Key, 1, Args, {Key, Val}) of
+ Args ->
+ [Entry|Args];
+ Args2 ->
+ Args2
+ end.
+
+get_arg(Key, Args) ->
+ {value, {Key, Val}} = lists:keysearch(Key, 1, Args),
+ Val.
+
+init_batch(ReplyTo, MgcHost, Trace, Debug) ->
+ register(?MODULE, self()),
+ Res = start(MgcHost, Trace, Debug),
+ ReplyTo ! {init_batch, self(), Res},
+ receive
+ after infinity -> Res
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Starting the MG
+%%----------------------------------------------------------------------
+
+%% -----------------------------------------------------------------------
+
+init_inline_trace(true) ->
+ megaco:enable_trace(max, io);
+init_inline_trace(_) ->
+ ok.
+
+%% -----------------------------------------------------------------------
+
+
+start() ->
+ {ok, LocalHost} = inet:gethostname(),
+ start(LocalHost, false, false).
+
+%% Used when calling from the erlang shell:
+start(MgcHost, Trace, Debug)
+ when is_atom(MgcHost) andalso is_atom(Trace) andalso is_atom(Debug) ->
+ start(atom_to_list(MgcHost), Trace, Debug);
+
+start(MgcHost, Trace, Debug)
+ when is_list(MgcHost) andalso is_atom(Trace) andalso is_atom(Debug) ->
+ put(debug, Debug),
+ d("start -> entry with"
+ "~n MgcHost: ~s"
+ "~n Trace: ~p", [MgcHost, Trace]),
+ init_inline_trace(Trace),
+ Starters = [fun start_tcp_text/2,
+ fun start_tcp_binary/2,
+ fun start_udp_text/2,
+ fun start_udp_binary/2],
+ [Fun(MgcHost, []) || Fun <- Starters].
+
+start_tcp_text(MgcHost, Default) ->
+ d("start_tcp_text -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_tcp} | Default],
+ Mid = {deviceName, "gateway_tt"},
+ {Mid, start(MgcHost, ?megaco_ip_port_text, Mid, Config)}.
+
+start_tcp_binary(MgcHost, Default) ->
+ d("start_tcp_binary -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_binary_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_tcp} | Default],
+ Mid = {deviceName, "gateway_tb"},
+ {Mid, start(MgcHost, ?megaco_ip_port_binary, Mid, Config)}.
+
+start_udp_text(MgcHost, Default) ->
+ d("start_udp_text -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_udp} | Default],
+ Mid = {deviceName, "gateway_ut"},
+ {Mid, start(MgcHost, ?megaco_ip_port_text, Mid, Config)}.
+
+start_udp_binary(MgcHost, Default) ->
+ d("start_udp_binary -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_binary_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_udp} | Default],
+ Mid = {deviceName, "gateway_ub"},
+ {Mid, start(MgcHost, ?megaco_ip_port_binary, Mid, Config)}.
+
+start(MgcHost, MgcPort, Mid, Config) ->
+ case megaco:start_user(Mid, [{user_mod, ?MODULE} | Config]) of
+ ok ->
+ case start_transport(MgcHost, MgcPort, Mid) of
+ {ok, ConnHandle} ->
+ service_change(ConnHandle);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ {error, {start_user, Reason}}
+ end.
+
+start_transport(MgcHost, MgcPort, Mid) ->
+ RecHandle = megaco:user_info(Mid, receive_handle),
+ case RecHandle#megaco_receive_handle.send_mod of
+ megaco_tcp -> start_tcp(MgcHost, MgcPort, RecHandle);
+ megaco_udp -> start_udp(MgcHost, MgcPort, RecHandle);
+ SendMod -> {error, {bad_send_mod, SendMod}}
+ end.
+
+start_tcp(MgcHost, MgcPort, RecHandle) ->
+ d("start_tcp -> start transport"),
+ case megaco_tcp:start_transport() of
+ {ok, Pid} ->
+ d("start_tcp -> transport started: ~p", [Pid]),
+ Options = [{host, MgcHost},
+ {port, MgcPort},
+ {receive_handle, RecHandle}],
+ case megaco_tcp:connect(Pid, Options) of
+ {ok, SendHandle, ControlPid} ->
+ d("start_tcp -> connected: ~p", [ControlPid]),
+ MgcMid = preliminary_mid,
+ megaco:connect(RecHandle, MgcMid, SendHandle, ControlPid);
+ {error, Reason} ->
+ d("start_tcp -> connection failed: ~p", [Reason]),
+ {error, {megaco_tcp_connect, Reason}}
+ end;
+ {error, Reason} ->
+ d("start_tcp -> failed starting transport: ~p", [Reason]),
+ {error, {megaco_tcp_start_transport, Reason}}
+ end.
+
+start_udp(MgcHost, MgcPort, RecHandle) ->
+ d("start_udp -> start transport"),
+ case megaco_udp:start_transport() of
+ {ok, SupPid} ->
+ d("start_udp -> transport started: ~p", [SupPid]),
+ Options = [{port, 0}, {receive_handle, RecHandle}],
+ case megaco_udp:open(SupPid, Options) of
+ {ok, Handle, ControlPid} ->
+ d("start_udp -> port opened: ~p", [ControlPid]),
+ %% Socket = megaco_udp:socket(Handle),
+ %% MgPort = inet:port(Socket), BUGBUG BUGBUG
+ MgcMid = preliminary_mid,
+ SendHandle = megaco_udp:create_send_handle(Handle,
+ MgcHost, % BUGBUG BUGBUG
+ MgcPort),
+ megaco:connect(RecHandle, MgcMid, SendHandle, ControlPid);
+ {error, Reason} ->
+ d("start_udp -> failed open port: ~p", [Reason]),
+ {error, {megaco_udp_open, Reason}}
+ end;
+ {error, Reason} ->
+ d("start_udp -> failed starting transport: ~p", [Reason]),
+ {error, {megaco_udp_start_transport, Reason}}
+ end.
+
+service_change(ConnHandle) ->
+ service_change(ConnHandle, restart, ?megaco_cold_boot).
+
+service_change(ConnHandle, Method, Reason) ->
+ SCP = #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeReason = [Reason]},
+ TermId = [?megaco_root_termination_id],
+ SCR = #'ServiceChangeRequest'{terminationID = TermId,
+ serviceChangeParms = SCP},
+ CR = #'CommandRequest'{command = {serviceChangeReq, SCR}},
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ megaco:call(ConnHandle, [AR], []).
+
+%%----------------------------------------------------------------------
+%% Stopping the MG
+%%----------------------------------------------------------------------
+
+stop() ->
+ [{Mid, stop(Mid)} || Mid <- megaco:system_info(users)].
+
+stop(Mid) ->
+ Reason = stopped_by_user,
+ Disco = fun(CH) ->
+ Pid = megaco:conn_info(CH, control_pid),
+ megaco:disconnect(CH, Reason),
+ megaco:cancel(CH, Reason),
+ exit(Pid, Reason)
+ end,
+ lists:map(Disco, megaco:user_info(Mid, connections)),
+ megaco:stop_user(Mid).
+
+%%----------------------------------------------------------------------
+%% Invoked when a new connection is established
+%%----------------------------------------------------------------------
+
+handle_connect(ConnHandle, ProtocolVersion) ->
+ d("handle_connect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p", [ConnHandle, ProtocolVersion]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a connection is teared down
+%%----------------------------------------------------------------------
+
+handle_disconnect(ConnHandle, ProtocolVersion, Reason) ->
+ d("handle_disconnect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n Reason: ~p", [ConnHandle, ProtocolVersion, Reason]),
+ megaco:cancel(ConnHandle, Reason), % Cancel the outstanding messages
+ d("handle_disconnect -> done", []),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message had syntax errors
+%%----------------------------------------------------------------------
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_syntax_error -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p",
+ [ReceiveHandle, ProtocolVersion, ErrorDescriptor]),
+ reply.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message contained no transactions
+%%----------------------------------------------------------------------
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_message_error -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p",
+ [ConnHandle, ProtocolVersion, ErrorDescriptor]),
+ no_reply.
+
+%%----------------------------------------------------------------------
+%% Invoked for each transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) ->
+ d("handle_trans_request -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActionRequests: ~p",
+ [ConnHandle, ProtocolVersion, ActionRequests]),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Transaction requests not handled"},
+ {discard_ack, ED}.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a time consuming transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) ->
+ d("handle_trans_long_request -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ReqData: ~p", [ConnHandle, ProtocolVersion, ReqData]),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long transaction requests not handled"},
+ {discard_ack, ED}.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction reply
+%%----------------------------------------------------------------------
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData) ->
+ d("handle_trans_reply -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActualReply: ~p"
+ "~n ReplyData: ~p",
+ [ConnHandle, ProtocolVersion, ActualReply, ReplyData]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction acknowledgement
+%%----------------------------------------------------------------------
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) ->
+ d("handle_trans_ack -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n AckStatus: ~p"
+ "~n AckData: ~p",
+ [ConnHandle, ProtocolVersion, AckStatus, AckData]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) ->
+ d("handle_unexpected_trans -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n AckStatus: ~p"
+ "~n AckData: ~p",
+ [ConnHandle, ProtocolVersion, Trans]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_trans_request_abort(ConnHandle, ProtocolVersion, TransId, Pid) ->
+ d("handle_trans_request_abort -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n TransId: ~p"
+ "~n Pid: ~p",
+ [ConnHandle, ProtocolVersion, TransId, Pid]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% DEBUGGING
+%%----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F,A) ->
+ d(get(debug),F,A).
+
+d(true,F,A) ->
+ io:format("SIMPLE_MG: " ++ F ++ "~n", A);
+d(_, _F, _A) ->
+ ok.
+
+
+
+
diff --git a/lib/megaco/examples/simple/megaco_simple_mgc.erl b/lib/megaco/examples/simple/megaco_simple_mgc.erl
new file mode 100644
index 0000000000..04493b983f
--- /dev/null
+++ b/lib/megaco/examples/simple/megaco_simple_mgc.erl
@@ -0,0 +1,455 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-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: Simple example of an MGC
+%%
+%% Example usage:
+%%
+%% cd megaco/examples/simple
+%% erl -pa ../../../megaco/ebin -s megaco_filter -s megaco
+%% megaco_simple_mgc:start().
+%%----------------------------------------------------------------------
+
+-module(megaco_simple_mgc).
+
+-behaviour(megaco_user).
+
+-export([
+ start_batch/0, start_batch/1, init_batch/3,
+ start/0, start/2,
+ start/4,
+ stop/0, stop/1
+ ]).
+
+-export([
+ handle_connect/2,
+ handle_disconnect/3,
+ handle_syntax_error/3,
+ handle_message_error/3,
+ handle_trans_request/3,
+ handle_trans_long_request/3,
+ handle_trans_reply/4,
+ handle_trans_ack/4,
+ handle_unexpected_trans/3,
+ handle_trans_request_abort/4
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Starting the MGC
+%%----------------------------------------------------------------------
+
+start() ->
+ start(false, false).
+
+start(Trace, Debug) ->
+ start({deviceName, "controller"}, [], Trace, Debug).
+
+start(Mid, Config, Trace, Debug) ->
+ put(debug, Debug),
+ d("start -> entry with"
+ "~n Mid: ~p"
+ "~n Config: ~p"
+ "~n Trace: ~p", [Mid, Config, Trace]),
+ init_inline_trace(Trace),
+ case megaco:start_user(Mid, [{user_mod, ?MODULE} | Config]) of
+ ok ->
+ d("start -> user started"),
+ case catch do_start(Mid) of
+ {'EXIT', Reason} ->
+ d("start -> exited: ~n~p",[Reason]),
+ {error, Reason};
+ Other ->
+ d("start -> Other: ~n~p",[Other]),
+ Other
+ end;
+ {error, Reason} ->
+ d("start -> user start failed: ~n~p", [Reason]),
+ {error, {start_user, Reason}}
+ end.
+
+
+%% -----------------------------------------------------------------------
+
+init_inline_trace(true) ->
+ megaco:enable_trace(max, io);
+init_inline_trace(_) ->
+ ok.
+
+%% -----------------------------------------------------------------------
+
+do_start(Mid) ->
+ d("do_start -> entry"),
+ RecHandle = megaco:user_info(Mid, receive_handle),
+ d("do_start -> RecHandle: ~n~p",[RecHandle]),
+
+ TextMod = megaco_pretty_text_encoder,
+ TextTcp = RecHandle#megaco_receive_handle{encoding_mod = TextMod,
+ encoding_config = [],
+ send_mod = megaco_tcp},
+ d("do_start -> TextTcp: ~n~p",[TextTcp]),
+ TextUdp = TextTcp#megaco_receive_handle{send_mod = megaco_udp},
+ d("do_start -> TextUdp: ~n~p",[TextUdp]),
+
+ BinMod = megaco_binary_encoder,
+ BinTcp = RecHandle#megaco_receive_handle{encoding_mod = BinMod,
+ encoding_config = [],
+ send_mod = megaco_tcp},
+ d("do_start -> BinTcp: ~n~p",[BinTcp]),
+ BinUdp = BinTcp#megaco_receive_handle{send_mod = megaco_udp},
+ d("do_start -> BinUdp: ~n~p",[BinUdp]),
+
+ ListenTo = [{?megaco_ip_port_text, TextTcp},
+ {?megaco_ip_port_text, TextUdp},
+ {?megaco_ip_port_binary, BinTcp},
+ {?megaco_ip_port_binary, BinUdp}
+ ],
+
+ d("do_start -> start transports"),
+ Transports =
+ [{start_transport(Port, RH), Port, RH} || {Port, RH} <- ListenTo],
+ d("do_start -> Transports: ~n~p",[Transports]),
+
+ {ok, Transports}.
+
+start_transport(MgcPort, RecHandle) ->
+ case RecHandle#megaco_receive_handle.send_mod of
+ megaco_tcp -> start_tcp(MgcPort, RecHandle);
+ megaco_udp -> start_udp(MgcPort, RecHandle);
+ SendMod -> {error, {bad_send_mod, SendMod}}
+ end.
+
+start_udp(MgcPort, RecHandle) ->
+ d("start_udp -> entry with"
+ "~n MgcPort: ~p"
+ "~n RecHandle: ~p", [MgcPort, RecHandle]),
+ case megaco_udp:start_transport() of
+ {ok, SupPid} ->
+ Options = [{port, MgcPort}, {receive_handle, RecHandle}],
+ case megaco_udp:open(SupPid, Options) of
+ {ok, _SendHandle, _ControlPid} ->
+ ok;
+ {error, Reason} ->
+ {error, {megaco_udp_open, Reason}}
+ end;
+ {error, Reason} ->
+ {error, {megaco_udp_start_transport, Reason}}
+ end.
+
+start_tcp(MgcPort, RecHandle) ->
+ d("start_tcp -> entry with"
+ "~n MgcPort: ~p"
+ "~n RecHandle: ~p", [MgcPort, RecHandle]),
+ case megaco_tcp:start_transport() of
+ {ok, SupPid} ->
+ d("start_tcp -> transport started: "
+ "~n SupPid: ~p", [SupPid]),
+ Options = [{port, MgcPort}, {receive_handle, RecHandle}],
+ case megaco_tcp:listen(SupPid, Options) of
+ ok ->
+ d("start_tcp -> listen ok"),
+ ok;
+ {error, Reason} ->
+ d("start_tcp -> listen failed: "
+ "~n Reason: ~p", [Reason]),
+ {error, {megaco_tcp_listen, Reason}}
+ end;
+ {error, Reason} ->
+ d("start_tcp -> transport start failed: "
+ "~n Reason: ~p", [Reason]),
+ {error, {megaco_tcp_start_transport, Reason}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Stopping the MGC
+%%----------------------------------------------------------------------
+
+stop() ->
+ [{Mid, stop(Mid)} || Mid <- megaco:system_info(users)].
+
+stop(Mid) ->
+ d("stop -> entry with~n Mid: ~p", [Mid]),
+ Disco = fun(CH) ->
+ d("stop -> CH: ~p", [CH]),
+ Reason = stopped_by_user,
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+
+ d("stop -> disconnect", []),
+ megaco:disconnect(CH, Reason),
+ d("stop -> cancel", []),
+ megaco:cancel(CH, Reason),
+ d("stop -> close transport"
+ "~n SendMod: ~p"
+ "~n SendHandle: ~p", [SendMod, SendHandle]),
+ case SendMod of
+ megaco_tcp -> megaco_tcp:close(SendHandle);
+ megaco_udp -> megaco_udp:close(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end
+ end,
+ Conns = megaco:user_info(Mid, connections),
+ d("stop -> Conns: ~p", [Conns]),
+ Disconns = lists:map(Disco, Conns),
+ d("stop -> Disconns: ~p", [Disconns]),
+ megaco:stop_user(Mid),
+ case whereis(?MODULE) of
+ undefined ->
+ ignore;
+ Pid ->
+ d("stop -> Pid: ~p", [Pid]),
+ unlink(Pid),
+ exit(Pid, shutdown)
+ end,
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a new connection is established
+%%----------------------------------------------------------------------
+
+handle_connect(ConnHandle, ProtocolVersion) ->
+ d("handle_connect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "", [ConnHandle, ProtocolVersion]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a connection is teared down
+%%----------------------------------------------------------------------
+
+handle_disconnect(ConnHandle, ProtocolVersion, Reason) ->
+ d("handle_disconnect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n Reason: ~p"
+ "", [ConnHandle, ProtocolVersion, Reason]),
+ megaco:cancel(ConnHandle, Reason), % Cancel the outstanding messages
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message had syntax errors
+%%----------------------------------------------------------------------
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_syntax_error -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p"
+ "", [ReceiveHandle, ProtocolVersion, ErrorDescriptor]),
+ reply.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message contained no transactions
+%%----------------------------------------------------------------------
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_message_error -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p"
+ "", [ConnHandle, ProtocolVersion, ErrorDescriptor]),
+ no_reply.
+
+%%----------------------------------------------------------------------
+%% Invoked for each transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) ->
+ d("handle_trans_request -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActionRequests: ~p"
+ "", [ConnHandle, ProtocolVersion, ActionRequests]),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Only single service change on null context handled"},
+ case ActionRequests of
+ [AR] ->
+ ContextId = AR#'ActionRequest'.contextId,
+ case AR#'ActionRequest'.commandRequests of
+ [CR] when ContextId =:= ?megaco_null_context_id ->
+ case CR#'CommandRequest'.command of
+ {serviceChangeReq, Req} ->
+ Rep = service_change(ConnHandle, ProtocolVersion, Req),
+ {discard_ack,
+ [#'ActionReply'{contextId = ContextId,
+ commandReply = [{serviceChangeReply, Rep}]}]};
+ _ ->
+ {discard_ack, ED}
+ end;
+ _ ->
+ {discard_ack, ED}
+ end;
+ _ ->
+ {discard_ack, ED}
+ end.
+
+service_change(ConnHandle, _ProtocolVersion, SCR) ->
+ SCP = SCR#'ServiceChangeRequest'.serviceChangeParms,
+ #'ServiceChangeParm'{serviceChangeAddress = Address,
+ serviceChangeProfile = Profile} = SCP,
+ TermId = SCR#'ServiceChangeRequest'.terminationID,
+ if
+ TermId == [?megaco_root_termination_id] ->
+ MyMid = ConnHandle#megaco_conn_handle.local_mid,
+ Res = {serviceChangeResParms,
+ #'ServiceChangeResParm'{serviceChangeMgcId = MyMid,
+ serviceChangeAddress = Address,
+ serviceChangeProfile = Profile}},
+ #'ServiceChangeReply'{terminationID = TermId,
+ serviceChangeResult = Res};
+ true ->
+ Res = {errorDescriptor,
+ #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Only handled for root"}},
+
+ #'ServiceChangeReply'{terminationID = TermId,
+ serviceChangeResult = Res}
+ end.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a time consuming transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_long_request(_ConnHandle, _ProtocolVersion, _ReqData) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long transaction requests not handled"},
+ {discard_ack, ED}.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction reply
+%%----------------------------------------------------------------------
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData) ->
+ d("handle_trans_eply -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActualReply: ~p"
+ "~n ReplyData: ~p"
+ "", [ConnHandle, ProtocolVersion, ActualReply, ReplyData]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction acknowledgement
+%%----------------------------------------------------------------------
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) ->
+ d("handle_trans_ack -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ckStatus: ~p"
+ "~n AckData: ~p"
+ "", [ConnHandle, ProtocolVersion, AckStatus, AckData]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) ->
+ d("handle_unexpected_trans -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n Trans: ~p"
+ "", [ConnHandle, ProtocolVersion, Trans]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_trans_request_abort(_ConnHandle, _ProtocolVersion, _TransId, _Pid) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% To be used at command line: erl -s ?MODULE start_batch
+%%----------------------------------------------------------------------
+
+start_batch() ->
+ start_batch([false]).
+
+start_batch(Args0) ->
+ Defs = [{trace,false}, {debug, false}],
+ Args = parse_args(Args0, Defs),
+ Trace = get_arg(trace, Args),
+ Debug = get_arg(debug, Args),
+ Pid = spawn(?MODULE, init_batch, [self(), Trace, Debug]),
+ receive
+ {init_batch, Pid, Res} ->
+ io:format("~p(~p): ~p~n", [?MODULE, ?LINE, Res]),
+ Res
+ end.
+
+init_batch(ReplyTo, Trace, Debug) ->
+ register(?MODULE, self()),
+ Res = start(Trace, Debug),
+ ReplyTo ! {init_batch, self(), Res},
+ receive
+ after infinity -> Res
+ end.
+
+
+parse_args([], Acc) ->
+ Acc;
+parse_args([Arg|Args], Acc) when is_atom(Arg) ->
+ case string:tokens(atom_to_list(Arg),"{},") of
+ ["trace",Trace] ->
+ parse_args(Args, parse_args(trace, list_to_atom(Trace), Acc));
+ ["debug",Debug] ->
+ parse_args(Args, parse_args(debug, list_to_atom(Debug), Acc));
+ _Invalid ->
+ parse_args(Args, Acc)
+ end.
+
+parse_args(Key, Val, Args) ->
+ Entry = {Key, Val},
+ case lists:keyreplace(Key, 1, Args, {Key, Val}) of
+ Args ->
+ [Entry|Args];
+ Args2 ->
+ Args2
+ end.
+
+get_arg(Key, Args) ->
+ {value, {Key, Val}} = lists:keysearch(Key, 1, Args),
+ Val.
+
+
+%%----------------------------------------------------------------------
+%% DEBUGGING
+%%----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F,A) ->
+ d(get(debug),F,A).
+
+d(true,F,A) ->
+ io:format("SIMPLE_MGC: " ++ F ++ "~n", A);
+d(_, _F, _A) ->
+ ok.
+
diff --git a/lib/megaco/examples/simple/modules.mk b/lib/megaco/examples/simple/modules.mk
new file mode 100644
index 0000000000..bcba5666a1
--- /dev/null
+++ b/lib/megaco/examples/simple/modules.mk
@@ -0,0 +1,27 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-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%
+
+MG_MODULES = \
+ megaco_simple_mg
+
+MGC_MODULES = \
+ megaco_simple_mgc
+
+COMMON_MODULES =
+