add new map utility functiosn and a skeleton AS server

This commit is contained in:
Harald Welte 2012-02-02 23:52:08 +01:00
parent aa3b39ea6c
commit f188fca9b9
2 changed files with 241 additions and 0 deletions

121
src/map_as_server.erl Normal file
View File

@ -0,0 +1,121 @@
-module(map_as_server).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-export([bind_ac/1, unbind_ac/1, dump/0]).
-record(ass_state, {sap_sup_pid, as_tbl}).
-record(ass_record, {ac, user_pid}).
% client side
bind_ac(Srv, AcName) when is_list(AcName) ->
bind_ac(Srv, list_to_tuple(AcName);
bind_ac(Srv, AcName) when is_tuple(AcName) ->
gen_server:call(Srv, {bind_ac, AcName}).
unbind_ac(Srv, AcName) when is_list(AcName) ->
unbind_ac(Srv, list_to_tuple(AcName);
unbind_ac(Srv, AcName) when is_tuple(AcName) ->
gen_server:call(Srv, {unbind_ac, AcName}).
dump() ->
fixme.
% gen_fsm callbacks
start_link(Ssn, {M, A, O}) when is_integer(Ssn) ->
ProcName = list_to_atom(?MODULE ++ "_" ++ integer_to_list(Ssn)),
gen_server:start_link({local, ProcName}, ?MODULE, [Ssn, {M, A, O}], []).
init([Ssn, {M, A, O}]) ->
{ok, SapSupPid} = tcap_sap_sup:start_link(M, A, O),
AssTbl = ets:new(list_to_atom(?MODULE ++ "_" ++ integer_to_list(Ssn)),
[ordered_set, named_table, {keypos, #ass_record.ac}]),
{ok, #ass_state{sap_sup_pid = SapSupPid, as_tbl = AssTbl}}.
handle_call({bind_ac, Ac}, {FromPid, _FromRef}, LoopDat) ->
NewRec = #actbl_record{ac = Ac, user_pid = FromPid},
case ets:insert_new(LoopDat#ass_state.as_tbl, NewRec) of
false ->
{reply, {error, ets_insert}, LoopDat};
_ ->
link(FromPid),
{reply, ok, LoopDat}
end;
handle_call({unbind_ac, Ac}, {FromPid, _FromRef}, LoopDat) ->
DelRec = #actbl_record{ac = Ac, user_pid = FromPid},
ets:delete_object(LoopDat#ass_state.as_tbl, DelRec),
{reply, ok, LoopDat}.
handle_cast(Info, LoopDat) ->
error_logger:error_report(["unknown handle_cast",
{module, ?MODULE}, {info, Info},
{state, LoopDat}]),
{noreply, LoopDat}.
handle_info({'EXIT', Pid, Reason}, LoopDat) ->
io:format("EXIT from process ~p (~p), cleaning up tables~n",
[Pid, Reason]),
ets:match_delete(LoopDat#ass_state.as_tbl, #actbl_record{user_pid = Pid}),
{noreply, LoopDat};
handle_info(Info, LoopDat) ->
error:logger:error_report(["unknown handle_info",
{module, ?MODULE}, {info, Info},
{state, LoopDat}]),
{noreply, LoopDat}.
terminate(Reason, _LoopDat) ->
io:format("terminating ~p with reason ~p~n", [self(), Reason]),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
% server side
as_for_ac(Ac, LoopDat) ->
case ets:lookup(LoopDat#ass_state.as_tbl, Ac) of
[#ass_record{user_pid = UserPid}] ->
{ok, UserPid};
_ ->
{error, no_such_ac}
end.
handle_tcap({'TC','BEGIN',indication,
I='TC-BEGIN'{appContextName = Ac, dialogueID = DlgId}}, LoopDat) ->
case as_for_ac(Ac, LoopDat) of
{ok, UserPid} ->
gen_fsm:send_event(UserPid, I);
{error, Reason} ->
error_logger:error_report(["TC-BEGIN for non-existing AC",
{application_context, Ac}]),
ok
end;
handle_tcap({'TC', What, indication, P}) when
What == 'CONTINUE'; What == 'END';
What == 'U-ABORT'; What == 'P-ABORT';
What == 'NOTICE' ->
% look up the Pid for the specific Dialogue Handler
case as_for_ac(Ac, LoopDat) of
FIXME FIXME
ok;
handle_tcap({'TC', 'INVOKE', indication, P}) when
% look up AS for AC, start new invoke in dialogue
handle_tcap({'TC', What, indication, P}) when
What == 'RESULT-L'; What == 'RESULT-NL';
What == 'U-ERROR'; What == 'L-CANCEL';
What == 'L-REJECT'; What == 'U-REJECT';
What == 'TIMER-RESET' ->
% look up the gen_fsm for the specific Invoke
ok.

120
src/map_helper.erl Normal file
View File

@ -0,0 +1,120 @@
% GSM MAP codec wrapper functions
% (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
%
% 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(map_helper).
-author('Harald Welte <laforge@gnumonks.org>').
-include_lib("osmo_ss7/include/isup.hrl").
-include_lib("osmo_map/include/map.hrl").
-export([postproc/2, postproc_gt/2, postproc_imsi/2, postproc_msisdn/2]).
postproc(M=#'UpdateLocationArg'{imsi = Imsi, 'msc-Number' = Msc, 'vlr-Number' = Vlr,
'v-gmlc-Address' = Gmlc}, Mode) ->
M#'UpdateLocationArg'{imsi = postproc_imsi(Imsi, Mode),
'msc-Number' = postproc_gt(Msc, Mode),
'vlr-Number' = postproc_gt(Vlr, Mode),
'v-gmlc-Address' = postproc_gt(Gmlc, Mode)};
postproc(M=#'UpdateLocationRes'{'hlr-Number' = Hlr}, Mode) ->
M#'UpdateLocationRes'{'hlr-Number' = postproc_gt(Hlr, Mode)};
postproc(M=#'UpdateGprsLocationArg'{imsi = Imsi, 'sgsn-Address' = Sgsn}, Mode) ->
M#'UpdateGprsLocationArg'{imsi = postproc_imsi(Imsi, Mode),
'sgsn-Address' = postproc_gt(Sgsn, Mode)};
postproc(M=#'UpdateGprsLocationRes'{'hlr-Number' = Hlr}, Mode) ->
M#'UpdateGprsLocationRes'{'hlr-Number' = postproc_gt(Hlr, Mode)};
postproc(M=#'SendAuthenticationInfoArg'{imsi = Imsi}, Mode) ->
M#'SendAuthenticationInfoArg'{imsi = postproc_imsi(Imsi, Mode)};
postproc(M=#'ReadyForSM-Arg'{imsi = Imsi}, Mode) ->
M#'ReadyForSM-Arg'{imsi = postproc_imsi(Imsi, Mode)};
postproc(M=#'MO-ForwardSM-Arg'{imsi = Imsi}, Mode) ->
M#'MO-ForwardSM-Arg'{imsi = postproc_imsi(Imsi, Mode)};
postproc(M=#'RoutingInfoForSM-Res'{imsi = Imsi}, Mode) ->
M#'RoutingInfoForSM-Res'{imsi = postproc_imsi(Imsi, Mode)};
postproc(M=#'DeactivateTraceModeArg'{imsi = Imsi}, Mode) ->
M#'DeactivateTraceModeArg'{imsi = postproc_imsi(Imsi, Mode)};
postproc(M=#'ActivateTraceModeArg'{imsi = Imsi}, Mode) ->
M#'ActivateTraceModeArg'{imsi = postproc_imsi(Imsi, Mode)};
postproc(M=#'InsertSubscriberDataArg'{imsi = Imsi, msisdn = Msisdn}, Mode) ->
M#'InsertSubscriberDataArg'{imsi = postproc_imsi(Imsi, Mode),
msisdn = postproc_msisdn(Msisdn, Mode)};
postproc(M=#'AuthenticationFailureReportArg'{imsi = Imsi}, Mode) ->
M#'AuthenticationFailureReportArg'{imsi = postproc_imsi(Imsi, Mode)};
postproc(M=#'AlertServiceCentreArg'{msisdn = Msisdn, serviceCentreAddress = Smsc}, Mode) ->
M#'AlertServiceCentreArg'{msisdn = postproc_msisdn(Msisdn, Mode),
serviceCentreAddress = postproc_gt(Smsc, Mode)};
postproc(M=#'RoutingInfoForSM-Arg'{msisdn = Msisdn, serviceCentreAddress = Smsc}, Mode) ->
M#'RoutingInfoForSM-Arg'{msisdn = postproc_msisdn(Msisdn, Mode),
serviceCentreAddress = postproc_gt(Smsc, Mode)};
postproc(M=#'ProvideRoamingNumberArg'{imsi = Imsi, msisdn = Msisdn,
'gmsc-Address' = Gmsc}, Mode) ->
M#'ProvideRoamingNumberArg'{imsi = postproc_imsi(Imsi, Mode),
msisdn = postproc_msisdn(Msisdn, Mode),
'gmsc-Address' = postproc_gt(Gmsc, Mode)};
postproc(M=#'SendRoutingInfoRes'{msisdn = Msisdn}, Mode) ->
M#'SendRoutingInfoRes'{msisdn = postproc_msisdn(Msisdn, Mode)};
postproc(M=#'SendRoutingInfoArg'{msisdn = Msisdn, 'gmsc-OrGsmSCF-Address' = Gmsc}, Mode) ->
M#'SendRoutingInfoArg'{msisdn = postproc_msisdn(Msisdn, Mode),
'gmsc-OrGsmSCF-Address' = postproc_gt(Gmsc, Mode)};
postproc(M=#'USSD-Arg'{msisdn = Msisdn}, Mode) ->
M#'USSD-Arg'{msisdn = postproc_msisdn(Msisdn, Mode)};
postproc(M=#'ReportSM-DeliveryStatusArg'{msisdn = Msisdn,
serviceCentreAddress = Smsc}, Mode) ->
M#'ReportSM-DeliveryStatusArg'{msisdn = postproc_msisdn(Msisdn, Mode),
serviceCentreAddress = postproc_gt(Smsc, Mode)};
postproc(M=#'AnyTimeInterrogationArg'{'gsmSCF-Address' = Scf}, Mode) ->
M#'AnyTimeInterrogationArg'{'gsmSCF-Address' = postproc_gt(Scf, Mode)};
postproc(M, _Mode) ->
M.
postproc_gt(In, post) when is_binary(In) ->
postproc_gt(binary_to_list(In), post);
postproc_gt(asn1_NOVALUE, post) ->
undefined;
postproc_gt(In, post) ->
map_codec:parse_addr_string(In);
postproc_gt(undefined, pre) ->
asn1_NOVALUE;
postproc_gt(In, pre) when is_record(In, party_number) ->
map_codec:encode_addr_string(In);
postproc_gt(In, pre) ->
In.
postproc_imsi(asn1_NOVALUE, post) ->
undefined;
postproc_imsi(In, post) ->
map_codec:parse_map_addr(In);
postproc_imsi(undefined, pre) ->
asn1_NOVALUE;
postproc_imsi([], pre) ->
asn1_NOVALUE;
postproc_imsi(In, pre) ->
map_codec:encode_map_tbcd(In).
postproc_msisdn(asn1_NOVALUE, post) ->
undefined;
postproc_msisdn(In, post) ->
map_codec:parse_map_addr(In);
postproc_msisdn(undefined, pre) ->
asn1_NOVALUE;
postproc_msisdn([], pre) ->
asn1_NOVALUE;
postproc_msisdn(In, pre) ->
map_codec:encode_map_tbcd(In).