first attempt at implementing the TCO and ISM parts

This commit is contained in:
Harald Welte 2011-10-18 20:22:36 +02:00
parent f564ef7227
commit 6b363e580e
2 changed files with 163 additions and 22 deletions

View File

@ -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}]).

View File

@ -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) ->