|
|
@ -1,15 +1,20 @@ |
|
|
|
-module(tpTracerSocket). |
|
|
|
|
|
|
|
-export([start_link/2]). |
|
|
|
-export([init/2]). |
|
|
|
-export([ |
|
|
|
start_link/2 |
|
|
|
, init/2 |
|
|
|
]). |
|
|
|
|
|
|
|
-export([system_continue/3]). |
|
|
|
-export([system_terminate/4]). |
|
|
|
-export([system_code_change/4]). |
|
|
|
%% sys callbacks |
|
|
|
-export([ |
|
|
|
system_continue/3 |
|
|
|
, system_terminate/4 |
|
|
|
, system_code_change/4 |
|
|
|
]). |
|
|
|
|
|
|
|
-record(state, { |
|
|
|
parent :: pid(), |
|
|
|
lsocket :: inet:socket(), |
|
|
|
lSocket :: inet:socket(), |
|
|
|
timeout_ref :: reference() | undefined |
|
|
|
}). |
|
|
|
|
|
|
@ -23,42 +28,27 @@ init(Parent, Port) -> |
|
|
|
%% We need to trap exit signals in order to shutdown properly. |
|
|
|
process_flag(trap_exit, true), |
|
|
|
%% Open the listening socket. |
|
|
|
{ok, LSocket} = gen_tcp:listen(Port, [ |
|
|
|
binary, {reuseaddr, true}, {nodelay, true}, |
|
|
|
%% We encode all events to binary inside a 2-byte length frame. |
|
|
|
{packet, 2}, |
|
|
|
%% We expect the client to send pings every second or so and |
|
|
|
%% nothing else, so using active mode is faster and still safe. |
|
|
|
{active, true}, |
|
|
|
%% We only expect one connection at a time. We don't need |
|
|
|
%% a backlog except for the cases where the connection is |
|
|
|
%% lost and will reconnect immediately before we get a |
|
|
|
%% chance to accept again. |
|
|
|
{backlog, 1} |
|
|
|
%% We are using non-blocking TCP send. We therefore do not |
|
|
|
%% need to configure send timeout options. |
|
|
|
]), |
|
|
|
{ok, LSocket} = gen_tcp:listen(Port, [binary, {reuseaddr, true}, {nodelay, true}, {packet, 2}, {active, true}, {backlog, 1}]), |
|
|
|
%% We reject all messages until we get a connection. |
|
|
|
accept(#state{parent = Parent, lsocket = LSocket}). |
|
|
|
accept(#state{parent = Parent, lSocket = LSocket}). |
|
|
|
|
|
|
|
accept(State = #state{lsocket = LSocket}) -> |
|
|
|
accept(State = #state{lSocket = LSocket}) -> |
|
|
|
{ok, AcceptRef} = prim_inet:async_accept(LSocket, -1), |
|
|
|
accept_loop(State, AcceptRef). |
|
|
|
|
|
|
|
accept_loop(State = #state{parent = Parent, lsocket = LSocket}, AcceptRef) -> |
|
|
|
accept_loop(State = #state{parent = Parent, lSocket = LSocket}, AcceptRef) -> |
|
|
|
receive |
|
|
|
{system, From, Request} -> |
|
|
|
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {accept_loop, State, AcceptRef}); |
|
|
|
{'EXIT', Parent, Reason} -> |
|
|
|
exit(Reason); |
|
|
|
{system, From, Request} -> |
|
|
|
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], |
|
|
|
{accept_loop, State, AcceptRef}); |
|
|
|
{inet_async, LSocket, AcceptRef, {ok, CSocket}} -> |
|
|
|
trace_loop(set_timeout(State), CSocket); |
|
|
|
{inet_async, LSocket, AcceptRef, Error} -> |
|
|
|
exit({accept_error, Error}); |
|
|
|
%% We discard all trace events when no client is connected. |
|
|
|
%% We may also end up discarding old timeouts or TCP messages. |
|
|
|
_ -> |
|
|
|
%% We discard all trace events when no client is connected. |
|
|
|
%% We may also end up discarding old timeouts or TCP messages. |
|
|
|
accept_loop(State, AcceptRef) |
|
|
|
end. |
|
|
|
|
|
|
@ -67,8 +57,7 @@ trace_loop(State = #state{parent = Parent, timeout_ref = TRef}, CSocket) -> |
|
|
|
{'EXIT', Parent, Reason} -> |
|
|
|
exit(Reason); |
|
|
|
{system, From, Request} -> |
|
|
|
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], |
|
|
|
{trace_loop, State, CSocket}); |
|
|
|
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {trace_loop, State, CSocket}); |
|
|
|
%% Reset the timeout when we receive data. |
|
|
|
{tcp, CSocket, _} -> |
|
|
|
trace_loop(reset_timeout(State), CSocket); |
|
|
@ -110,10 +99,13 @@ close(State, CSocket) -> |
|
|
|
_ = gen_tcp:close(CSocket), |
|
|
|
accept(cancel_timeout(State)). |
|
|
|
|
|
|
|
system_continue(_, _, {accept_loop, State, AcceptRef}) -> |
|
|
|
accept_loop(State, AcceptRef); |
|
|
|
system_continue(_, _, {trace_loop, State, CSocket}) -> |
|
|
|
trace_loop(State, CSocket). |
|
|
|
system_continue(_, _, {LoopTag = accept_loop, State, LoopArgs}) -> |
|
|
|
case LoopTag of |
|
|
|
accept_loop -> |
|
|
|
accept_loop(State, LoopArgs); |
|
|
|
trace_loop -> |
|
|
|
trace_loop(State, LoopArgs) |
|
|
|
end. |
|
|
|
|
|
|
|
-spec system_terminate(any(), _, _, _) -> no_return(). |
|
|
|
system_terminate(Reason, _, _, _) -> |
|
|
|