%% Copyright (C) 2024 by sysmocom - s.f.m.c. GmbH %% Author: Vadim Yanitskiy %% %% 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 . %% %% 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_client). -export([connect/0, connect/1, connect/2, send_data/2, disconnect/1]). -include_lib("kernel/include/logger.hrl"). -include_lib("kernel/include/inet.hrl"). -include_lib("kernel/include/inet_sctp.hrl"). -include("s1ap.hrl"). -type loc_addr() :: any | list() | inet:ip_address(). -type rem_addr() :: localhost | list() | inet:ip_address(). -type loc_rem_addr() :: {loc_addr(), rem_addr()}. -type connect_result() :: {ok, gen_sctp:sctp_socket()}. -type sock_aid() :: {gen_sctp:sctp_socket(), gen_sctp:assoc_id()}. -export_type([loc_addr/0, rem_addr/0, loc_rem_addr/0, connect_result/0, sock_aid/0]). %% ------------------------------------------------------------------ %% behavior callbacks %% ------------------------------------------------------------------ -callback start_link(AID, Priv) -> Result when AID :: gen_sctp:assoc_id(), Priv :: term(), Result :: {ok, pid()} | term(). -callback send_data(Pid, Data) -> Result when Pid :: pid(), Data :: binary(), Result :: term(). -callback shutdown(Pid) -> Result when Pid :: pid(), Result :: term(). %% ------------------------------------------------------------------ %% public API %% ------------------------------------------------------------------ -spec connect() -> connect_result(). connect() -> connect({any, localhost}). -spec connect(loc_rem_addr()) -> connect_result(). connect(LocRemAddr) -> connect(LocRemAddr, ?S1AP_PORT). -spec connect(loc_rem_addr(), inet:port_number()) -> connect_result(). connect({LocAddrStr, RemAddr}, Port) when is_list(LocAddrStr) -> {ok, LocAddr} = inet:parse_address(LocAddrStr), connect({LocAddr, RemAddr}, Port); connect({LocAddr, RemAddrStr}, Port) when is_list(RemAddrStr) -> {ok, RemAddr} = inet:parse_address(RemAddrStr), connect({LocAddr, RemAddr}, Port); connect({LocAddr, RemAddr}, Port) -> {ok, Sock} = gen_sctp:open([{ip, LocAddr}, {type, seqpacket}, {active, true}]), gen_sctp:connect_init(Sock, RemAddr, Port, []), {ok, Sock}. -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 disconnect(sock_aid()) -> ok | {error, term()}. disconnect({Sock, Aid}) -> gen_sctp:eof(Sock, #sctp_assoc_change{assoc_id = Aid}). %% vim:set ts=4 sw=4 et: