%%%-------------------------------------------------------------------
%% @doc UDP sink worker for local test traffic.
%%%-------------------------------------------------------------------
-module(vpn_udp_sink).
-behaviour(gen_server).
-export([start_link/1, stop/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
start_link(Port) ->
gen_server:start_link(?MODULE, Port, []).
stop(Pid) ->
gen_server:stop(Pid).
init(Port) ->
process_flag(trap_exit, true),
case vpn_udp:start_link(Port, self()) of
{ok, UdpPid} ->
{ok, #{udp_pid => UdpPid, port => Port}};
{error, Reason} ->
{stop, Reason}
end.
handle_call(_Request, _From, State) ->
{reply, {error, not_implemented}, State}.
handle_cast(_Request, State) ->
{noreply, State}.
handle_info({vpn_udp_packet, UdpPid, Ip, Port, Packet},
State = #{udp_pid := UdpPid}) ->
logger:info("vpn_udp_sink received packet from ~p:~p: ~p bytes, first16=~p",
[Ip, Port, byte_size(Packet), first16(Packet)]),
{noreply, State};
handle_info({vpn_udp_packet, _OtherUdpPid, _Ip, _Port, _Packet}, State) ->
{noreply, State};
handle_info({'EXIT', UdpPid, Reason}, State = #{udp_pid := UdpPid}) ->
{stop, {udp_exit, Reason}, State};
handle_info(_Message, State) ->
{noreply, State}.
terminate(_Reason, State) ->
stop_udp(maps:get(udp_pid, State, undefined)),
ok.
first16(Packet) when byte_size(Packet) =< 16 ->
binary:encode_hex(Packet);
first16(Packet) ->
binary:encode_hex(binary:part(Packet, 0, 16)).
stop_udp(undefined) ->
ok;
stop_udp(UdpPid) ->
case is_process_alive(UdpPid) of
true ->
_ = vpn_udp:stop(UdpPid),
ok;
false ->
ok
end.