%% Copyright (C) 2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
%% Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
%%
%% All Rights Reserved
%%
%% SPDX-License-Identifier: AGPL-3.0-or-later
%%
%% 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 <https://www.gnu.org/licenses/>.
%%
%% 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(sctp_common).

-export([parse_addr/1,
         report_error/1,
         gen_sockopts/1,
         send_data/2,
         shutdown/1]).

-include_lib("kernel/include/logger.hrl").
-include_lib("kernel/include/inet_sctp.hrl").

-include("s1gw_metrics.hrl").
-include("s1ap.hrl").


-define(SOCKOPTS_DEFAULT_BUFSZ, 65536).
-define(SOCKOPTS_DEFAULT_NODELAY, true).


-type sock_aid() :: {gen_sctp:sctp_socket(),
                     gen_sctp:assoc_id()}.


%% ------------------------------------------------------------------
%% public API
%% ------------------------------------------------------------------

-spec parse_addr(AddrStr :: string()) -> Addr :: inet:ip_address();
                (Addr) -> Addr when Addr :: any | localhost | inet:ip_address().
parse_addr(AddrStr) when is_list(AddrStr) ->
    {ok, Addr} = inet:parse_address(AddrStr),
    Addr;

parse_addr(Addr) ->
    case Addr of
        any -> any;
        localhost -> localhost;
        _ ->
            true = inet:is_ip_address(Addr),
            Addr
    end.


-spec report_error(term()) -> term().
report_error(Error) ->
    s1gw_metrics:ctr_inc(?S1GW_CTR_SCTP_ERROR_ALL),
    case Error of
        #sctp_send_failed{} ->
            s1gw_metrics:ctr_inc(?S1GW_CTR_SCTP_ERROR_SEND_FAILED);
        #sctp_pdapi_event{} ->
            s1gw_metrics:ctr_inc(?S1GW_CTR_SCTP_ERROR_PDAPI_EVENT);
        #sctp_remote_error{} ->
            s1gw_metrics:ctr_inc(?S1GW_CTR_SCTP_ERROR_REMOTE_ERROR);
        _ -> ok
    end.


-spec gen_sockopts(map()) -> [gen_sctp:option()].
gen_sockopts(SockOptsCfg) ->
    SockOpts = #{recbuf => maps:get(recbuf, SockOptsCfg, ?SOCKOPTS_DEFAULT_BUFSZ),
                 sndbuf => maps:get(sndbuf, SockOptsCfg, ?SOCKOPTS_DEFAULT_BUFSZ),
                 sctp_nodelay => maps:get(nodelay, SockOptsCfg, ?SOCKOPTS_DEFAULT_NODELAY)},
    maps:to_list(SockOpts).


-spec send_data(sock_aid(), binary()) -> ok | {error, term()}.
send_data({Sock, Aid}, Data) ->
    gen_sctp:send(Sock, #sctp_sndrcvinfo{stream = ?S1AP_SCTP_STREAM,
                                         ppid = ?S1AP_SCTP_PPID,
                                         assoc_id = Aid}, Data).


-spec shutdown(sock_aid()) -> ok | {error, term()}.
shutdown({Sock, Aid}) ->
    gen_sctp:eof(Sock, #sctp_assoc_change{assoc_id = Aid}).


%% vim:set ts=4 sw=4 et:
