From c6b5bb3abb1e2c7ff67e9b4e36f65970f4fab75a Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 2 May 2024 16:08:30 +0200 Subject: [PATCH] wip --- src/eradius.erl | 10 ++-- src/eradius_server.erl | 93 +++++++++++++++++++++++------------ src/eradius_server_sup.erl | 10 +--- test/eradius_test_handler.erl | 8 +-- 4 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/eradius.erl b/src/eradius.erl index c3ccc9a..af7d1a4 100644 --- a/src/eradius.erl +++ b/src/eradius.erl @@ -31,12 +31,14 @@ load_tables(Dir, Tables) -> eradius_dict:load_tables(Dir, Tables). start_server(IP, Port, #{handler := {_, _}, clients := #{}} = Opts) - when is_tuple(IP), is_integer(Port), Port >= 0, Port < 65536 -> - eradius_server:start_instance(eradius_server:config(IP, Port, Opts)). + when (IP =:= any orelse is_tuple(IP)) andalso + is_integer(Port) andalso Port >= 0 andalso Port < 65536 -> + eradius_server:start_instance(IP, Port, Opts). start_server(ServerName, IP, Port, #{handler := {_, _}, clients := #{}} = Opts) - when is_tuple(IP), is_integer(Port), Port >= 0, Port < 65536 -> - eradius_server:start_instance(ServerName, eradius_server:config(IP, Port, Opts)). + when (IP =:= any orelse is_tuple(IP)) andalso + is_integer(Port) andalso Port >= 0 andalso Port < 65536 -> + eradius_server:start_instance(ServerName, IP, Port, Opts). %%%=================================================================== %%% application callbacks diff --git a/src/eradius_server.erl b/src/eradius_server.erl index 8dcc2d7..6ba799d 100644 --- a/src/eradius_server.erl +++ b/src/eradius_server.erl @@ -4,12 +4,13 @@ %% SPDX-License-Identifier: MIT %% -module(eradius_server). +-feature(maybe_expr, enable). -behaviour(gen_server). %% API --export([start_instance/1, start_instance/2, stop_instance/1]). --export([config/3, start_link/1, start_link/2]). +-export([start_instance/3, start_instance/4, stop_instance/1]). +-export([start_link/3, start_link/4]). -export_type([req_id/0]). %% internal API @@ -19,8 +20,8 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --ignore_xref([start_link/1, start_link/2]). --ignore_xref([start_instance/1, start_instance/2, stop_instance/1]). +-ignore_xref([start_link/3, start_link/4]). +-ignore_xref([start_instance/3, start_instance/4, stop_instance/1]). -include_lib("stdlib/include/ms_transform.hrl"). -include_lib("kernel/include/logger.hrl"). @@ -92,41 +93,46 @@ %%% API %%%========================================================================= -start_instance(Opts) -> - eradius_server_sup:start_instance(Opts). +-spec start_instance(IP :: 'any' | inet:ip_address(), Port :: inet:port_number(), + Opts :: server_opts()) -> gen_server:start_ret(). +start_instance(IP, Port, Opts) + when (IP =:= any orelse is_tuple(IP)) andalso + is_integer(Port) andalso Port >= 0 andalso Port < 65536 -> + eradius_server_sup:start_instance([IP, Port, Opts]). -start_instance(ServerName, Opts) -> - eradius_server_sup:start_instance(ServerName, Opts). +-spec start_instance(ServerName :: gen_server:server_name(), + IP :: 'any' | inet:ip_address(), Port :: inet:port_number(), + Opts :: server_opts()) -> gen_server:start_ret(). +start_instance(ServerName, IP, Port, Opts) + when (IP =:= any orelse is_tuple(IP)) andalso + is_integer(Port) andalso Port >= 0 andalso Port < 65536 -> + eradius_server_sup:start_instance([ServerName, IP, Port, Opts]). +-spec stop_instance(Pid :: pid()) -> ok. stop_instance(Pid) -> - eradius_server_sup:stop_instance(Pid). + try gen_server:call(Pid, stop) + catch exit:_ -> ok end. --spec config(IP :: inet:ip_address() | any, inet:port_number(), - server_opts()) -> server_config(). -config(IP, Port, #{handler := {_, _}, clients := Clients} = Opts) +-spec start_link(IP :: 'any' | inet:ip_address(), Port :: inet:port_number(), + Opts :: server_opts()) -> gen_server:start_ret(). +start_link(IP, Port, #{handler := {_, _}, clients := #{}} = Opts) when (IP =:= any orelse is_tuple(IP)) andalso - is_map(Clients) andalso is_integer(Port) andalso Port >= 0 andalso Port < 65536 -> - SocketOpts0 = maps:get(socket_opts, Opts, #{}), - SocketOpts = #{family := Family, ifaddr := IfAddr} = - maps:merge(default_socket_opts(IP, Port), to_map(SocketOpts0)), - - Opts#{server_name => server_name(IP, Port, Opts), - socket_opts => SocketOpts#{ifaddr := socket_ip(Family, IfAddr)}, - metrics_callback => maps:get(metrics_callback, Opts, undefined), - clients => - maps:fold(fun(K, V, M) -> M#{socket_ip(Family, K) => V} end, #{}, Clients) - }. - --spec start_link(server_config()) -> gen_server:start_ret(). -start_link(#{socket_opts := #{ifaddr := IP, port := Port}} = Config) -> - ServerName = list_to_atom(lists:flatten(["eradius_server_", server_name(IP, Port)])), - start_link({local, ServerName}, Config). + maybe + {ok, Config} ?= config(IP, Port, Opts), + gen_server:start_link(?MODULE, [Config], []) + end. --spec start_link(gen_server:server_name(), - server_config()) -> gen_server:start_ret(). -start_link(ServerName, Config) -> - gen_server:start_link(ServerName, ?MODULE, [Config], []). +-spec start_link(ServerName :: gen_server:server_name(), + IP :: 'any' | inet:ip_address(), Port :: inet:port_number(), + Opts :: server_opts()) -> gen_server:start_ret(). +start_link(ServerName, IP, Port, #{handler := {_, _}, clients := #{}} = Opts) + when (IP =:= any orelse is_tuple(IP)) andalso + is_integer(Port) andalso Port >= 0 andalso Port < 65536 -> + maybe + {ok, Config} ?= config(IP, Port, Opts), + gen_server:start_link(ServerName, ?MODULE, [Config], []) + end. %%%=================================================================== %%% gen_server callbacks @@ -167,6 +173,8 @@ init([#{server_name := ServerName, end. %% @private +handle_call(stop, _From, State) -> + {stop, normal, ok, State}; handle_call(_Call, _From, State) -> {reply, ok, State}. @@ -328,6 +336,25 @@ apply_handler_mod(HandlerMod, HandlerArg, %%% internal functions %%%========================================================================= +-spec config(IP :: inet:ip_address() | any, inet:port_number(), + server_opts()) -> {ok, server_config()}. +config(IP, Port, #{handler := {_, _}, clients := Clients} = Opts0) + when (IP =:= any orelse is_tuple(IP)) andalso + is_map(Clients) andalso + is_integer(Port) andalso Port >= 0 andalso Port < 65536 -> + SocketOpts0 = maps:get(socket_opts, Opts0, #{}), + SocketOpts = #{family := Family, ifaddr := IfAddr} = + maps:merge(default_socket_opts(IP, Port), to_map(SocketOpts0)), + + Opts = + Opts0#{server_name => server_name(IP, Port, Opts0), + socket_opts => SocketOpts#{ifaddr := socket_ip(Family, IfAddr)}, + metrics_callback => maps:get(metrics_callback, Opts0, undefined), + clients => + maps:fold(fun(K, V, M) -> M#{socket_ip(Family, K) => V} end, #{}, Clients) + }, + {ok, Opts}. + flow_control(#state{socket = Socket, active_n = once}) -> inet:setopts(Socket, [{active, once}]); flow_control(_) -> @@ -347,6 +374,8 @@ to_map(Opts) when is_map(Opts) -> Opts. %% @private +socket_ip(_, any) -> + any; socket_ip(inet, {_, _, _, _} = IP) -> IP; socket_ip(inet6, {_, _, _, _} = IP) -> diff --git a/src/eradius_server_sup.erl b/src/eradius_server_sup.erl index 09f298a..624e1f7 100644 --- a/src/eradius_server_sup.erl +++ b/src/eradius_server_sup.erl @@ -3,7 +3,7 @@ -module(eradius_server_sup). -behaviour(supervisor). --export([start_link/0, start_instance/1, start_instance/2, stop_instance/1, all/0]). +-export([start_link/0, start_instance/1, all/0]). -export([init/1]). -import(eradius_lib, [printable_peer/2]). @@ -20,13 +20,7 @@ start_link() -> supervisor:start_link({local, ?SERVER}, ?MODULE, []). start_instance(Opts) -> - supervisor:start_child(?SERVER, [Opts]). - -start_instance(ServerName, Opts) -> - supervisor:start_child(?SERVER, [ServerName, Opts]). - -stop_instance(Pid) -> - supervisor:terminate_child(?SERVER, Pid). + supervisor:start_child(?SERVER, Opts). all() -> lists:map(fun({_, Child, _, _}) -> Child end, supervisor:which_children(?SERVER)). diff --git a/test/eradius_test_handler.erl b/test/eradius_test_handler.erl index a49c584..33b2c9d 100644 --- a/test/eradius_test_handler.erl +++ b/test/eradius_test_handler.erl @@ -22,10 +22,10 @@ start(Backend, Family) -> SrvOpts = #{handler => {?MODULE, []}, clients => #{eradius_test_lib:localhost(Family, tuple) => #{secret => "secret", client => <<"ONE">>}}}, - eradius:start_server( - eradius_test_lib:localhost(Family, tuple), 1812, SrvOpts#{server_name => one}), - eradius:start_server( - eradius_test_lib:localhost(Family, tuple), 1813, SrvOpts#{server_name => two}), + {ok, _} = eradius:start_server( + eradius_test_lib:localhost(Family, tuple), 1812, SrvOpts#{server_name => one}), + {ok, _} = eradius:start_server( + eradius_test_lib:localhost(Family, tuple), 1813, SrvOpts#{server_name => two}), ok. stop() ->