<commit_before>% SCCP routing control procedures (SCRC)

% (C) 2010 by <NAME> <<EMAIL>>
%
% All Rights Reserved
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU Affero General Public License as
% published by the Free Software Foundation; either version 3 of the
% License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU Affero General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

-module(sccp_scrc).
-behaviour(gen_fsm).
-export([start_link/1, init/1, idle/2]).

-include("sccp.hrl").



-record(scrc_state, {
		scoc_conn_ets,
		next_local_ref,
		user_pid,	% pid() of the user process
		mtp_tx_action	% action to be performed for MTP-TRANSFER.req
	}).
% TODO: 

% is the supplied message type a connectionless message?
is_connectionless(MsgType) ->
	case MsgType of
		?SCCP_MSGT_UDT -> true;
		?SCCP_MSGT_UDTS -> true;
		?SCCP_MSGT_XUDT -> true;
		?SCCP_MSGT_XUDTS -> true;
		?SCCP_MSGT_LUDT -> true;
		?SCCP_MSGT_LUDTS -> true;
		_ -> false
	end.

tx_prim_to_local_ref(Prim, LocalRef) ->
	% determine the Pid to which the primitive must be sent
	ConnTable = get(scoc_by_ref),
	case ets:lookup(ConnTable, LocalRef) of
		{ok, ScocPid} ->	
			gen_fsm:send_event(ScocPid, Prim);
		_ ->
			io:format("Primitive ~p for unknown local reference ~p~n",
				  [Prim, LocalRef])
	end.


start_link(InitData) ->
	% make sure to store the Pid of the caller in the scrc_state
	gen_fsm:start_link(sccp_scrc, [{user_pid,self()}|InitData], [{debug, [trace]}]).

init(InitPropList) ->
	io:format("SCRC Init PropList~p ~n", [InitPropList]),
	UserPid = proplists:get_value(user_pid, InitPropList),
	MtpTxAct = proplists:get_value(mtp_tx_action, InitPropList),
	LoopData = #scrc_state{user_pid = UserPid, mtp_tx_action = MtpTxAct, next_local_ref = 0},
	TableRef = ets:new(scoc_by_ref, [set]),
	put(scoc_by_ref, TableRef),
	{ok, idle, LoopData}.


idle(Prim = #primitive{subsystem = 'MTP', gen_name = 'TRANSFER',
		       spec_name = indication, parameters = Params}, LoopDat) ->
	{ok, Msg} = sccp_codec:parse_sccp_msg(Params),
	io:format("Parsed Msg: ~p LoopDat ~p ~n", [Msg, LoopDat]),
	case Msg of
		% special handling for CR message here in SCRC
		#sccp_msg{msg_type = ?SCCP_MSGT_CR} ->
			% create new SCOC instance
			UserPid = LoopDat#scrc_state.user_pid,
			% Compute the new local reference
			LocalRef = LoopDat#scrc_state.next_local_ref + 1,
			LoopDat1 = LoopDat#scrc_state{next_local_ref = LocalRef},
			% generate proplist for SCRC initialization
			ScocPropList = [{scrc_pid, self()}, {user_pid, UserPid}, {local_reference, LocalRef}],
			{ok, ScocPid} = sccp_scoc:start_link(ScocPropList),
			% insert SCOC instance in connection table
			ConnTable = get(scoc_by_ref),
			ets:insert_new(ConnTable, LocalRef, ScocPid),
			% send a RCOC-CONNECTING.ind primitive to the new SCOC fsm
			UserPrim = sccp_scoc:make_prim('RCOC','CONNECTION', indication, Msg#sccp_msg.parameters),
			io:format("Sending ~p to ~p~n", [UserPrim, ScocPid]),
			gen_fsm:send_event(ScocPid, UserPrim);
		_ ->
			IsConnLess = is_connectionless(Msg#sccp_msg.msg_type),
			case IsConnLess of
				true ->
					% it would be more proper to send them via SCLC ??
					%gen_fsm:send(sccp_sclc, ??
					UserPid = LoopDat#scrc_state.user_pid,
					% FIXME: N-NOTICE.ind for NOTICE 
					UserPrim = sccp_scoc:make_prim('N','UNITDATA', indication, Msg),
					UserPid ! {sccp, UserPrim};
				false ->
					% connection oriented messages need to go via SCOC instance
					#sccp_msg{parameters = Opts} = Msg,
					LocalRef = proplists:get_value(dst_local_ref, Opts),
					case LocalRef of
						undefined ->
							% FIXME: send SCCP_MSGT_ERR
							io:format("Conn-Msg to undefined ref ~p~n", [Msg]);
						_ ->
							tx_prim_to_local_ref(Prim, LocalRef)
					end
			end,
			LoopDat1 = LoopDat
	end,
	{next_state, idle, LoopDat1};
idle(sclc_scrc_connless_msg, LoopDat) ->
	% FIXME: get to MTP-TRANSFER.req
	{next_state, idle, LoopDat};
idle(sclc_scrc_conn_msg, LoopDat) ->
	{next_state, idle, LoopDat};
% SCOC has received confirmation about new incoming connection from user
idle(Prim = #primitive{subsystem = 'OCRC', gen_name = 'CONNECTION',
		       spec_name = confirm, parameters = Params}, LoopDat) ->
	% encode the actual SCCP message
	EncMsg = sccp_codec:encode_sccp_msgt(?SCCP_MSGT_CC, Params),<commit_msg>SCRC: Forward incoming connection oriented msgs via RCOC-CONNECTION.ind to SCOC<commit_after>% SCCP routing control procedures (SCRC)

% (C) 2010 by <NAME> <<EMAIL>>
%
% All Rights Reserved
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU Affero General Public License as
% published by the Free Software Foundation; either version 3 of the
% License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU Affero General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

-module(sccp_scrc).
-behaviour(gen_fsm).
-export([start_link/1, init/1, idle/2]).

-include("sccp.hrl").



-record(scrc_state, {
		scoc_conn_ets,
		next_local_ref,
		user_pid,	% pid() of the user process
		mtp_tx_action	% action to be performed for MTP-TRANSFER.req
	}).
% TODO: 

% is the supplied message type a connectionless message?
is_connectionless(MsgType) ->
	case MsgType of
		?SCCP_MSGT_UDT -> true;
		?SCCP_MSGT_UDTS -> true;
		?SCCP_MSGT_XUDT -> true;
		?SCCP_MSGT_XUDTS -> true;
		?SCCP_MSGT_LUDT -> true;
		?SCCP_MSGT_LUDTS -> true;
		_ -> false
	end.

tx_prim_to_local_ref(Prim, LocalRef) ->
	% determine the Pid to which the primitive must be sent
	ConnTable = get(scoc_by_ref),
	case ets:lookup(ConnTable, LocalRef) of
		{ok, ScocPid} ->	
			gen_fsm:send_event(ScocPid, Prim);
		_ ->
			io:format("Primitive ~p for unknown local reference ~p~n",
				  [Prim, LocalRef])
	end.


start_link(InitData) ->
	% make sure to store the Pid of the caller in the scrc_state
	gen_fsm:start_link(sccp_scrc, [{user_pid,self()}|InitData], [{debug, [trace]}]).

init(InitPropList) ->
	io:format("SCRC Init PropList~p ~n", [InitPropList]),
	UserPid = proplists:get_value(user_pid, InitPropList),
	MtpTxAct = proplists:get_value(mtp_tx_action, InitPropList),
	LoopData = #scrc_state{user_pid = UserPid, mtp_tx_action = MtpTxAct, next_local_ref = 0},
	TableRef = ets:new(scoc_by_ref, [set]),
	put(scoc_by_ref, TableRef),
	{ok, idle, LoopData}.


idle(Prim = #primitive{subsystem = 'MTP', gen_name = 'TRANSFER',
		       spec_name = indication, parameters = Params}, LoopDat) ->
	{ok, Msg} = sccp_codec:parse_sccp_msg(Params),
	io:format("Parsed Msg: ~p LoopDat ~p ~n", [Msg, LoopDat]),
	case Msg of
		% special handling for CR message here in SCRC
		#sccp_msg{msg_type = ?SCCP_MSGT_CR} ->
			% create new SCOC instance
			UserPid = LoopDat#scrc_state.user_pid,
			% Compute the new local reference
			LocalRef = LoopDat#scrc_state.next_local_ref + 1,
			LoopDat1 = LoopDat#scrc_state{next_local_ref = LocalRef},
			% generate proplist for SCRC initialization
			ScocPropList = [{scrc_pid, self()}, {user_pid, UserPid}, {local_reference, LocalRef}],
			{ok, ScocPid} = sccp_scoc:start_link(ScocPropList),
			% insert SCOC instance in connection table
			ConnTable = get(scoc_by_ref),
			ets:insert_new(ConnTable, LocalRef, ScocPid),
			% send a RCOC-CONNECTING.ind primitive to the new SCOC fsm
			UserPrim = sccp_scoc:make_prim('RCOC','CONNECTION', indication, Msg#sccp_msg.parameters),
			io:format("Sending ~p to ~p~n", [UserPrim, ScocPid]),
			gen_fsm:send_event(ScocPid, UserPrim);
		_ ->
			IsConnLess = is_connectionless(Msg#sccp_msg.msg_type),
			case IsConnLess of
				true ->
					% it would be more proper to send them via SCLC ??
					%gen_fsm:send(sccp_sclc, ??
					UserPid = LoopDat#scrc_state.user_pid,
					% FIXME: N-NOTICE.ind for NOTICE 
					UserPrim = sccp_scoc:make_prim('N','UNITDATA', indication, Msg),
					UserPid ! {sccp, UserPrim};
				false ->
					% connection oriented messages need to go via SCOC instance
					#sccp_msg{parameters = Opts} = Msg,
					LocalRef = proplists:get_value(dst_local_ref, Opts),
					UserPrim = sccp_scoc:make_prim('RCOC', 'CONNECTION-MSG', indication, Msg),
					case LocalRef of
						undefined ->
							% FIXME: send SCCP_MSGT_ERR
							io:format("Conn-Msg to undefined ref ~p~n", [Msg]);
						_ ->
							tx_prim_to_local_ref(UserPrim, LocalRef)
					end
			end,
			LoopDat1 = LoopDat
	end,
	{next_state, idle, LoopDat1};
idle(sclc_scrc_connless_msg, LoopDat) ->
	% FIXME: get to MTP-TRANSFER.req
	{next_state, idle, LoopDat};
idle(sclc_scrc_conn_msg, LoopDat) ->
	{next_state, idle, LoopDat};
% SCOC has received confirmation about new incoming connection from user
idle(Prim = #primitive{subsystem = 'OCRC', gen_name = 'CONNECTION',
		       spec_name = confirm, parameters = Params}, LoopDat) ->
	% encode the actual SCCP message
	EncMsg = sccp_codec:encode_sccp_msgt(?SCCP_MSGT_CC, Params),
{'fraction_non_alphanumeric': 0.1136267456622937, 'fraction_numerical': 0.0027507405840033854, 'mean_word_length': 4.310674157303371, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1155098', 'n_tokens_mistral': 3816, 'n_tokens_neox': 3462, 'n_words': 911}