diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/megaco/examples/simple | |
download | otp-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/Makefile | 153 | ||||
-rw-r--r-- | lib/megaco/examples/simple/megaco_simple_mg.erl | 437 | ||||
-rw-r--r-- | lib/megaco/examples/simple/megaco_simple_mgc.erl | 455 | ||||
-rw-r--r-- | lib/megaco/examples/simple/modules.mk | 27 |
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 = + |