-module(cabal_accept_worker).
-behaviour(gen_server).
-export([start_link/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-record(state, {
listener_pid,
keypair,
transport_pid
}).
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
init(Args) ->
TransportPid = proplists:get_value(transport_pid, Args),
{ok, {ListenerPid, KeyPair}} = cabal_transport:get_listener_info(TransportPid),
io:format("[AcceptWorker] Starting with listener ~p, transport ~p~n", [
ListenerPid, TransportPid
]),
self() ! accept,
{ok, #state{
listener_pid = ListenerPid,
keypair = KeyPair,
transport_pid = TransportPid
}}.
handle_call(Request, _From, State) ->
io:format("[AcceptWorker] Unhandled call: ~p~n", [Request]),
{reply, {error, unknown_call}, State}.
handle_cast(Msg, State) ->
io:format("[AcceptWorker] Unhandled cast: ~p~n", [Msg]),
{noreply, State}.
handle_info(
accept,
State = #state{listener_pid = ListenerPid, keypair = KeyPair, transport_pid = TransportPid}
) ->
io:format("[AcceptWorker] Waiting for encrypted connections (listener: ~p, transport: ~p)~n", [
ListenerPid, TransportPid
]),
Opts = [{keypair, KeyPair}],
case enoise_cable:accept(ListenerPid, Opts) of
{ok, ConnPid} ->
io:format("[AcceptWorker] Accepted new encrypted connection: ~p~n", [ConnPid]),
Result =
try
ok = enoise_cable:controlling_process(ConnPid, TransportPid),
{ok, {PeerIP, PeerPort}} = enoise_cable:peername(ConnPid),
PeerAddr = {PeerIP, PeerPort},
io:format("[AcceptWorker] Peer address: ~p~n", [PeerAddr]),
TransportPid ! {new_connection, ConnPid, PeerAddr},
ok
catch
Error:ErrorReason:Stacktrace ->
io:format(
"[AcceptWorker] Error setting up connection ~p: ~p:~p~n Stacktrace: ~p~n",
[ConnPid, Error, ErrorReason, Stacktrace]
),
catch enoise_cable:close(ConnPid),
error
end,
case Result of
ok -> ok;
error -> io:format("[AcceptWorker] Connection setup failed, continuing to accept~n")
end,
self() ! accept,
{noreply, State};
{error, AcceptReason} ->
io:format("[AcceptWorker] Accept error: ~p~n", [AcceptReason]),
erlang:send_after(1000, self(), accept),
{noreply, State}
end;
handle_info(Info, State) ->
io:format("[AcceptWorker] Unhandled info: ~p~n", [Info]),
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.