forked from erlang/signerl
first attempt at implementing the TCO and ISM parts
This commit is contained in:
parent
f564ef7227
commit
6b363e580e
|
@ -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 <vances@motivity.ca> [http://www.motivity.ca]
|
||||
%%% @copyright 2010-2011 Harald Welte
|
||||
%%% @author Harald Welte <laforge@gnumonks.org>
|
||||
%%% @end
|
||||
%%%
|
||||
%%% Copyright (c) 2004-2005, Motivity Telecom
|
||||
%%% Copyright (c) 2010-2011, Harald Welte <laforge@gnumonks.org>
|
||||
%%%
|
||||
%%% 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}]).
|
||||
|
|
|
@ -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) ->
|
||||
|
|
Loading…
Reference in New Issue