diff --git a/src/eradius_client.erl b/src/eradius_client.erl index db621494..ce89567c 100644 --- a/src/eradius_client.erl +++ b/src/eradius_client.erl @@ -62,19 +62,29 @@ send_request(NAS, Request) -> % If no answer is received within the specified timeout, the request will be sent again. -spec send_request(nas_address(), #radius_request{}, options()) -> {ok, binary(), eradius_lib:authenticator()} | {error, 'timeout' | 'socket_down'}. -send_request({Host, Port, Secret}, Request, Options) +send_request({Host, Port, Secret}, Request, Options) when ?GOOD_CMD(Request) andalso is_binary(Host) -> send_request({erlang:binary_to_list(Host), Port, Secret}, Request, Options); -send_request({Host, Port, Secret}, Request, Options) +send_request({Host, Port, Secret}, Request, Options) when ?GOOD_CMD(Request) andalso is_list(Host) -> case inet:gethostbyname(Host) of - {ok, #hostent{h_addrtype = inet, h_addr_list = [IP]}} -> + {ok, #hostent{h_addrtype = inet, h_addr_list = [IP]}} -> send_request({IP, Port, Secret}, Request, Options); - {ok, #hostent{h_addrtype = inet, h_addr_list = [_ | _] = IPs}} -> + {ok, #hostent{h_addrtype = inet, h_addr_list = [_ | _] = IPs}} -> Index = rand:uniform(length(IPs)), IP = lists:nth(Index, IPs), send_request({IP, Port, Secret}, Request, Options); - _ -> error(badarg) + _Err -> + case inet:gethostbyname(Host, inet6) of + {ok, #hostent{h_addrtype = inet6, h_addr_list = [IP]}} -> + send_request({IP, Port, Secret}, Request, Options); + {ok, #hostent{h_addrtype = inet6, h_addr_list = [_ | _] = IPs}} -> + Index = rand:uniform(length(IPs)), + IP = lists:nth(Index, IPs), + send_request({IP, Port, Secret}, Request, Options); + _Err -> + error(badarg) + end end; send_request({IP, Port, Secret}, Request, Options) when ?GOOD_CMD(Request) andalso is_tuple(IP) -> TS1 = eradius_lib:timestamp(milli_seconds), @@ -315,10 +325,19 @@ init([]) -> Else -> Else end. +%% @private +inet_family_based_on_peer(_PeerSocket = {{_, _, _, _}, _port}) -> + [inet]; +inet_family_based_on_peer(_PeerSocket = {{_, _, _, _, _, _, _, _}, _port}) -> + [inet6]; +inet_family_based_on_peer(_PeerSocket) -> + []. + %% @private handle_call({wanna_send, Peer = {_PeerName, PeerSocket}, _MetricsInfo}, _From, State) -> {PortIdx, ReqId, NewIdCounters} = next_port_and_req_id(PeerSocket, State#state.no_ports, State#state.idcounters), - {SocketProcess, NewSockets} = find_socket_process(PortIdx, State#state.sockets, State#state.socket_ip, State#state.sup), + InetFamily = inet_family_based_on_peer(PeerSocket), + {SocketProcess, NewSockets} = find_socket_process(PortIdx, State#state.sockets, State#state.socket_ip, InetFamily, State#state.sup), IsCreated = lists:member(Peer, State#state.clients), NewState = case IsCreated of false -> @@ -464,11 +483,11 @@ next_port_and_req_id(Peer, NumberOfPorts, Counters) -> NewCounters = Counters#{Peer => {NextPortIdx, NextReqId}}, {NextPortIdx, NextReqId, NewCounters}. -find_socket_process(PortIdx, Sockets, SocketIP, Sup) -> +find_socket_process(PortIdx, Sockets, SocketIP, Options, Sup) -> case array:get(PortIdx, Sockets) of undefined -> Res = supervisor:start_child(Sup, {PortIdx, - {eradius_client_socket, start, [SocketIP, self(), PortIdx]}, + {eradius_client_socket, start, [SocketIP, self(), PortIdx, Options]}, transient, brutal_kill, worker, [eradius_client_socket]}), Pid = case Res of {ok, P} -> P; @@ -490,7 +509,7 @@ parse_ip(Address) when is_list(Address) -> inet_parse:address(Address); parse_ip(T = {_, _, _, _}) -> {ok, T}; -parse_ip(T = {_, _, _, _, _, _}) -> +parse_ip(T = {_, _, _, _, _, _, _, _}) -> {ok, T}. make_metrics_info(Options, {ServerIP, ServerPort}) -> diff --git a/src/eradius_client_socket.erl b/src/eradius_client_socket.erl index c90f1b02..efcf1803 100644 --- a/src/eradius_client_socket.erl +++ b/src/eradius_client_socket.erl @@ -2,22 +2,23 @@ -behaviour(gen_server). --export([start/3]). +-export([start/4]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {client, socket, pending, mode, counter}). -start(SocketIP, Client, PortIdx) -> - gen_server:start_link(?MODULE, [SocketIP, Client, PortIdx], []). +start(SocketIP, Client, PortIdx, Options) -> + gen_server:start_link(?MODULE, [SocketIP, Client, PortIdx, Options], []). -init([SocketIP, Client, PortIdx]) -> +init([SocketIP, Client, PortIdx, Options]) -> Client ! {PortIdx, self()}, - case SocketIP of - undefined -> - ExtraOptions = []; - SocketIP when is_tuple(SocketIP) -> - ExtraOptions = [{ip, SocketIP}] - end, + ExtraOptions = + case SocketIP of + undefined -> + Options; + SocketIP when is_tuple(SocketIP) -> + [{ip, SocketIP} | Options] + end, RecBuf = application:get_env(eradius, recbuf, 8192), {ok, Socket} = gen_udp:open(0, [{active, once}, binary , {recbuf, RecBuf} | ExtraOptions]), {ok, #state{client = Client, socket = Socket, pending = maps:new(), mode = active, counter = 0}}. diff --git a/test/eradius_client_SUITE.erl b/test/eradius_client_SUITE.erl index e550df4f..380e926d 100644 --- a/test/eradius_client_SUITE.erl +++ b/test/eradius_client_SUITE.erl @@ -122,7 +122,7 @@ split2(N, List1, [L|List2]) -> split2(N-1, [L|List1], List2). meckStart() -> ok = meck:new(eradius_client_socket), - ok = meck:expect(eradius_client_socket, start, fun(X, Y, Z) -> eradius_client_socket_test:start(X, Y, Z) end), + ok = meck:expect(eradius_client_socket, start, fun(X, Y, Z, O) -> eradius_client_socket_test:start(X, Y, Z, O) end), ok = meck:expect(eradius_client_socket, init, fun(X) -> eradius_client_socket_test:init(X) end), ok = meck:expect(eradius_client_socket, handle_call, fun(X, Y, Z) -> eradius_client_socket_test:handle_call(X, Y, Z) end), ok = meck:expect(eradius_client_socket, handle_cast, fun(X, Y) -> eradius_client_socket_test:handle_cast(X, Y) end), @@ -139,7 +139,7 @@ parse_ip(Address) when is_list(Address) -> inet_parse:address(Address); parse_ip(T = {_, _, _, _}) -> {ok, T}; -parse_ip(T = {_, _, _, _, _, _}) -> +parse_ip(T = {_, _, _, _, _, _, _, _}) -> {ok, T}. %% CHECK diff --git a/test/eradius_client_socket_test.erl b/test/eradius_client_socket_test.erl index ee465c59..538c5d3c 100644 --- a/test/eradius_client_socket_test.erl +++ b/test/eradius_client_socket_test.erl @@ -22,15 +22,15 @@ -behaviour(gen_server). --export([start/3]). +-export([start/4]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {client, socket, pending, mode, counter}). -start(SocketIP, Client, PortIdx) -> - gen_server:start_link(?MODULE, [SocketIP, Client, PortIdx], []). +start(SocketIP, Client, PortIdx, Options) -> + gen_server:start_link(?MODULE, [SocketIP, Client, PortIdx, Options], []). -init([_SocketIP, Client, PortIdx]) -> +init([_SocketIP, Client, PortIdx, Options]) -> Client ! {PortIdx, self()}, eradius_client_SUITE:addSocket(), {ok, #state{pending = maps:new(), mode = active, counter = 0}}.