diff --git a/TCAP/src/ITU/tcap_ism_fsm.erl b/TCAP/src/ITU/tcap_ism_fsm.erl index 264fc66..f6bbf28 100644 --- a/TCAP/src/ITU/tcap_ism_fsm.erl +++ b/TCAP/src/ITU/tcap_ism_fsm.erl @@ -1,10 +1,10 @@ %%% $Id: tcap_ism_fsm.erl,v 1.3 2005/08/04 09:33:17 vances Exp $ %%%--------------------------------------------------------------------- -%%% @copyright 2004-2005 Motivity Telecom -%%% @author Vance Shipley [http://www.motivity.ca] +%%% @copyright 2010-2011 Harald Welte +%%% @author Harald Welte %%% @end %%% -%%% Copyright (c) 2004-2005, Motivity Telecom +%%% Copyright (c) 2010-2011, Harald Welte %%% %%% All rights reserved. %%% @@ -46,18 +46,20 @@ %%% -module(tcap_ism_fsm). --copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.'). --author('vances@motivity.ca'). +-copyright('Copyright (c) 2010-2011 Harald Welte'). +-author('laforge@gnumonks.org'). -vsn('$Revision: 1.3 $'). -behaviour(gen_fsm). %% call backs needed for gen_fsm behaviour -%-export([init/1, handle_event/3, handle_info/3, terminate/3, code_change/4]). --export([handle_info/3, terminate/3, code_change/4]). +-export([init/1, handle_event/3, handle_info/3, terminate/3, code_change/4]). %% invocation_fsm state callbacks --export([]). +-export([start_link/5]). + +-export([idle/2, op_sent_cl1/2, op_sent_cl2/2, op_sent_cl3/2, + op_sent_cl4/2, wait_for_reject/2]). %% record definitions for TC-User primitives -include("tcap.hrl"). @@ -65,7 +67,30 @@ %-include("TCAPMessages.hrl"). %% the invocation_fsm state data --record(state, {usap, dialogueID, cco}). +-record(state, { + usap, % Pid of the TC-User + dialogueId, + invokeId, + cco, % Pid of the CCO + op_class, % operation class (1..4) + inv_timeout, % milliseconds + inv_timer, % timer() + rej_timer % timer() +}). + +% value in milliseconds, spec doesn't say how long... +-define(REJECT_TIMER, 1 * 1000). + +start_link(Usap, DialogueId, InvokeId, OpClass, InvTimeout) -> + ArgL = [Usap, DialogueId, InvokeId, self(), OpClass, InvTimeout], + gen_fsm:start_link(ArgL, [{debug, [trace]}]). + +% DHA needs to tell us: USAP, DialogueID, InvokeID, CCO-PID, OpClass, InvTimer +init([Usap, DialogueId, InvokeId, CcoPid, OpClass, InvTimeout]) -> + State = #state{usap = Usap, dialogueId = DialogueId, + invokeId = InvokeId, cco = CcoPid, + op_class = OpClass, inv_timeout = InvTimeout}, + {ok, idle, State}. %%---------------------------------------------------------------------- %% The gen_fsm call backs @@ -74,6 +99,117 @@ %% Start the Invocation State Machine (ISM) process %% reference: Figure A.7/Q.774 (sheet 1 of 6) +% CCO -> ISM: Operation sent +idle('operation-sent', State) -> + % start invocation timer + Tinv = timer:apply_after(State#state.inv_timeout, gen_fsm, + send_all_state_event, + [self(), {timer_expired, invoke}]), + case State#state.op_class of + 1 -> + StateName = op_sent_cl1; + 2 -> + StateName = op_sent_cl2; + 3 -> + StateName = op_sent_cl3; + 4 -> + StateName = op_sent_cl4 + end, + {next_state, StateName, State#state{inv_timer = Tinv}}. + +op_sent_cl1(P=#'TC-RESULT-L'{}, State) -> + % Figure A.7/Q.774 (2 of 6) + % TC-RESULT-L.ind to user + gen_server:cast(P, State#state.usap), + % stop invocation timer + timer:cancel(State#state.inv_timer), + % start reject timer + Trej = start_reject_timer(), + {next_state, wait_for_reject, State#state{rej_timer = Trej}}; +op_sent_cl1(P=#'TC-U-REJECT'{}, State) -> + % Figure A.7/Q.774 (2 of 6) + % TC-U-ERROR.ind to user + gen_server:cast(P, State#state.usap), + % stop invocation timer + timer:cancel(State#state.inv_timer), + % start reject timer + Trej = start_reject_timer(), + {next_state, wait_for_reject, State#state{rej_timer = Trej}}; +op_sent_cl1(P=#'TC-RESULT-NL'{}, State) -> + % Figure A.7/Q.774 (2 of 6) + % TC-RESULT-NL.ind to user + gen_server:cast(P, State#state.usap), + {next_state, op_sent_cl1, State}; +op_sent_cl1('terminate', State) -> + % stop invocation timer + timer:cancel(State#state.inv_timer), + {stop, terminate_req, State}. + +wait_for_reject('terminate', State) -> + % stop reject timer + timer:cancel(State#state.rej_timer), + {stop, terminate_req, State}; +wait_for_reject({timer_expired, reject}, State) -> + % reject timer expiry + % terminate + {stop, rej_timer_exp, State}. + +op_sent_cl2(#'TC-U-REJECT'{}, State) -> + % FIXME: TC-U-ERROR.ind to user + % stop invocation timer + timer:cancel(State#state.inv_timer), + % start reject timer + Trej = start_reject_timer(), + {next_state, wait_for_reject, State#state{rej_timer = Trej}}; +op_sent_cl2(Op, State) when + is_record(Op, 'TC-RESULT-L'); + is_record(Op, 'TC-RESULT-NL') -> + % Generate RJ component to CCO + % stop invocation timer + timer:cancel(State#state.inv_timer), + % terminate + {stop, class2_result, State}; +op_sent_cl2('terminate', State) -> + % terminate + {stop, terminate_req, State}. + +op_sent_cl3(P=#'TC-RESULT-L'{}, State) -> + % Figure A.7/Q.774 (5 of 6) + % TC-RESULT-L.ind to user + gen_server:cast(State#state.usap, P), + % stop invocation timer + timer:cancel(State#state.inv_timer), + % start reject timer + Trej = start_reject_timer(), + {next_state, wait_for_reject, State#state{rej_timer = Trej}}; +op_sent_cl3(P=#'TC-RESULT-NL'{}, State) -> + % TC-RESULT-NL.ind to user + gen_server:cast(State#state.usap, P), + {next_state, op_sent_cl3, State}; +op_sent_cl3('terminate', State) -> + % stop invocation timter + timer:cancel(State#state.inv_timer), + % terminate + {stop, terminate_req, State}. + +op_sent_cl4('terminate', State) -> + % terminate + {stop, terminate_req, State}; +op_sent_cl4(Op, State) -> + % Figure A.7/Q.774 (6 of 6) + % FIXME: generate RJ component to CCO + % stop invocation timer + timer:cancel(State#state.inv_timer), + % terminate + {stop, cl4_op_received, State}. + +handle_event({timer_expired, invoke}, _StateName, State) -> + % invocation timer expiry + #state{dialogueId = DlgId, invokeId = InvId} = State, + % TC-L-CANCEL.ind to user + P = #'TC-L-CANCEL'{dialogueID = DlgId, invokeID = InvId}, + gen_fsm:send_event(State#state.usap, P), + {stop, inv_timer_expired, State}. %% handle any other message handle_info(Info, StateName, State) -> @@ -81,9 +217,14 @@ handle_info(Info, StateName, State) -> {next_state, StateName, State}. %% handle a shutdown request -terminate(_Reason, _StateName, State) -> ok. +terminate(_Reason, _StateName, _State) -> ok. %% handle updating state data due to a code replacement -code_change(OldVsn, StateName, State, _Extra) -> +code_change(_OldVsn, StateName, State, _Extra) -> {ok, StateName, State}. + +start_reject_timer() -> + timer:apply_after(?REJECT_TIMER, gen_fsm, + send_event, + [self(), {timer_expired, reject}]). diff --git a/TCAP/src/ITU/tcap_tco_server.erl b/TCAP/src/ITU/tcap_tco_server.erl index f57491c..d4d7454 100644 --- a/TCAP/src/ITU/tcap_tco_server.erl +++ b/TCAP/src/ITU/tcap_tco_server.erl @@ -153,7 +153,7 @@ -behaviour(gen_server). % export the gen_server interface --export([start/3, start/4, start_link/3, start_link/4, +-export([start/4, start/5, start_link/3, start_link/4, call/2, call/3, multi_call/2, multi_call/3, multi_call/4, cast/2, abcast/2, abcast/3, reply/2, enter_loop/4, enter_loop/5]). @@ -288,7 +288,7 @@ handle_cast({'N', 'UNITDATA', indication, UdataParams}, State) {ok, Begin} -> % Assign local transaction ID TransactionID = new_tid(), - StartFunc = get_start(transaction, TransactionID, State), + StartFunc = get_start(in_transaction, TransactionID, State), ChildSpec = {TransactionID, StartFunc, temporary, infinity, supervisor, [tcap_tsm_fsm]}, % Is TID = no TID? % Note: The assignment of the ID above just gets the next available @@ -509,11 +509,11 @@ handle_cast({'TR', 'BEGIN', request, BeginParams}, State) % Create a Transaction State Machine (TSM) OTID = BeginParams#'TR-BEGIN'.transactionID, ChildName = list_to_atom("tsm_" ++ integer_to_list(OTID)), - {ok, {M, F, A, Mods}} = application:get_env(start_tsm), - % TDODO: fixme!!! StartFunc = get_start(transaction, OTID, State), - % ChildSpec = {ChildName, StartFunc, temporary, infinity, worker, [tcap_tsm_fsm]}, - % {ok, TSM} = supervisor:start_child(State#state.supervisor, ChildSpec), - % gen_fsm:send_event(TSM, {'BEGIN', transaction, BeginParams}), + %%%% FIXME {ok, {M, F, A, Mods}} = application:get_env(start_tsm), + StartFunc = get_start(out_transaction, OTID, State), + ChildSpec = {ChildName, StartFunc, temporary, 1000, worker, [tcap_tsm_fsm]}, + {ok, TSM} = supervisor:start_child(State#state.supervisor, ChildSpec), + gen_fsm:send_event(TSM, {'BEGIN', transaction, BeginParams}), {noreply, State}; handle_cast({'TR', 'CONTINUE', request, ContParams}, State) when is_record(ContParams, 'TR-CONTINUE') -> @@ -664,12 +664,12 @@ get_start(out_transaction, TransactionID, State) -> %%---------------------------------------------------------------------- %% @hidden -start(Module, Args, Options) -> - gen_server:start(?MODULE, [Module, Args], Options). +start(Module, SupRef, Args, Options) -> + gen_server:start(?MODULE, [SupRef, Module, Args], Options). %% @hidden -start(ServerRef, Module, Args, Options) -> - gen_fsm:start(ServerRef, ?MODULE, [Module, Args], Options). +start(ServerRef, SupRef, Module, Args, Options) -> + gen_server:start(ServerRef, ?MODULE, [SupRef, Module, Args], Options). %% @hidden start_link(Module, Args, Options) ->