% (C) 2019 by Harald Welte % % 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 . % % Additional Permission under GNU AGPL version 3 section 7: % % If you modify this Program, or any covered work, by linking or % combining it with runtime libraries of Erlang/OTP as released by % Ericsson on https://www.erlang.org (or a modified version of these % libraries), containing parts covered by the terms of the Erlang Public % License (https://www.erlang.org/EPLICENSE), the licensors of this % Program grant you additional permission to convey the resulting work % without the need to license the runtime libraries of Erlang/OTP under % the GNU Affero General Public License. Corresponding Source for a % non-source form of such a combination shall include the source code % for the parts of the runtime libraries of Erlang/OTP used as well as % that of the covered work. -module(osmo_dia2gsup). -behavior(gen_server). -include_lib("diameter/include/diameter.hrl"). -include_lib("diameter/include/diameter_gen_base_rfc6733.hrl"). %-include_lib("diameter_settings.hrl"). -export([get_env/2, main/1]). % API -export([start_link/0]). -export([stop/0]). % gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2]). -export([code_change/3, terminate/2]). -define(SERVER, ?MODULE). -define(ENV_DEFAULT_NODELAY, true). -define(ENV_DEFAULT_SCTP_BUFSZ, 65536). % Diameter application definitions -define(SVC_NAME, ?MODULE). -define(APP_ALIAS, ?MODULE). -define(CALLBACK_MOD, server_cb). -define(DIAMETER_DICT_HSS, diameter_3gpp_ts29_272). -define(APPID_S6, #'diameter_base_Vendor-Specific-Application-Id'{'Vendor-Id'=10415, 'Auth-Application-Id'=[16777251]}). -define(SERVICE(Name), [{'Origin-Host', get_env(origin_host, "hss.localdomain")}, {'Origin-Realm', get_env(origin_realm, "localdomain")}, {'Vendor-Id', get_env(vendor_id, 0)}, {'Origin-State-Id', diameter:origin_state_id()}, {'Product-Name', Name}, {'Auth-Application-Id', []}, {'Vendor-Specific-Application-Id', [?APPID_S6]}, {application, [{alias, ?APP_ALIAS}, {dictionary, ?DIAMETER_DICT_HSS}, {module, ?CALLBACK_MOD}] }]). %% ------------------------------------------------------------------ %% API %% ------------------------------------------------------------------ start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). stop() -> gen_server:cast(?SERVER, stop). get_env(Param, Default) -> application:get_env(?MODULE, Param, Default). main(_Args) -> application:ensure_all_started(?MODULE), timer:sleep(infinity). %% ------------------------------------------------------------------ %% gen_server Function Definitions %% ------------------------------------------------------------------ %% @callback gen_server init(State) -> % DIAMETER side ProdName = atom_to_list(?MODULE), ok = diameter:start_service(?SVC_NAME, ?SERVICE(ProdName)), listen(?SVC_NAME), {ok, State}. %% @callback gen_server handle_call(_Req, _From, State) -> {noreply, State}. %% @callback gen_server handle_cast(stop, State) -> {stop, normal, State}; handle_cast(_req, State) -> {noreply, State}. %% @callback gen_server handle_info(_Info, State) -> {noreply, State}. %% @callback gen_server code_change(_OldVsn, State, _Extra) -> {ok, State}. %% @callback gen_server terminate(normal, _State) -> diameter:stop_service(?SVC_NAME), lager:info("Diameter HSS Application stopped.~n"), ok; terminate(shutdown, _State) -> ok; terminate({shutdown, _Reason}, _State) -> ok; terminate(_Reason, _State) -> ok. %% ------------------------------------------------------------------ %% Internal Function Definitions %% ------------------------------------------------------------------ listen(Name) -> LAddr = get_env(diameter_ip, "127.0.0.8"), LPort = get_env(diameter_port, 3868), Proto = get_env(diameter_proto, sctp), ConnectTimer = get_env(diameter_connect_timer, 30000), TransOpts = [{transport_module, tmod(Proto)}, {transport_config, tcfg(Proto, LAddr, LPort)}, {connect_timer, ConnectTimer}], {ok, _} = diameter:add_transport(Name, {listen, TransOpts}), lager:info("Diameter HSS Application started on IP ~s, ~p port ~p~n", [LAddr, Proto, LPort]). tmod(tcp) -> diameter_tcp; tmod(sctp) -> diameter_sctp. tcfg(tcp, LAddr, LPort) -> Cfg = #{nodelay => get_env(diameter_nodelay, ?ENV_DEFAULT_NODELAY)}, tcfg(Cfg, LAddr, LPort); tcfg(sctp, LAddr, LPort) -> Cfg = #{sctp_nodelay => get_env(diameter_nodelay, ?ENV_DEFAULT_NODELAY), recbuf => get_env(diameter_sctp_recbuf, ?ENV_DEFAULT_SCTP_BUFSZ), sndbuf => get_env(diameter_sctp_sndbuf, ?ENV_DEFAULT_SCTP_BUFSZ)}, tcfg(Cfg, LAddr, LPort); tcfg(Cfg, LAddr, LPort) when is_map(Cfg) -> maps:to_list(Cfg#{ip => parse_addr(LAddr), port => LPort, reuseaddr => true}). parse_addr(any) -> any; parse_addr(localhost) -> localhost; parse_addr(AddrStr) when is_list(AddrStr) -> {ok, Addr} = inet:parse_address(AddrStr), Addr; parse_addr(Addr) -> true = inet:is_ip_address(Addr), Addr.