Current section

Files

Jump to
mdns_client_lib src mdns_client_lib_worker.erl
Raw

src/mdns_client_lib_worker.erl

-module(mdns_client_lib_worker).
-behaviour(gen_server).
-export([start_link/4]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).
-record(state, {name, socket, master, ip, port}).
reconnect(Pid) ->
gen_server:cast(Pid, reconnect).
start_link(Name, IP, Port, Master) ->
gen_server:start_link(?MODULE, [Name, IP, Port, Master], []).
init([Name, IP, Port, Master]) ->
process_flag(trap_exit, true),
%%timer:send_interval(1000, do_ping),
lager:debug("[MDNS Client:~p] Initialization started.",
[Name]),
case gen_tcp:connect(IP, Port,
[binary, {active,false}, {packet,4}],
250) of
{ok, Socket} ->
lager:debug("[MDNS Client:~p] Initialization successful.",
[Name]),
{ok, #state{name=Name, socket=Socket, master=Master, ip=IP,
port=Port}};
E ->
lager:error("[MDNS Client:~p] Initialization failed: ~p.",
[Name, E]),
reconnect(self()),
{ok, #state{name=Name, master=Master, ip=IP, port=Port}}
end.
cmd_bin(Command) ->
case seq_trace:get_token() of
[] ->
term_to_binary(Command);
_Tkn ->
{serial, {Previous, Current}} = seq_trace:get_token(serial),
%% Since we got thos over TCP we need to 'update' the serial ourselfs
seq_trace:get_token(serial, {Previous, Current + 1}),
Tkn = seq_trace:get_token(),
term_to_binary({trace, Tkn, Command})
end.
handle_call({call, Command, Timeout}, _From,
#state{socket=Socket, master=Master, ip=IP, port=Port}=State) ->
case gen_tcp:send(Socket, cmd_bin(Command)) of
ok ->
case gen_tcp:recv(Socket, 0, Timeout) of
{error, E} ->
lager:error("[MDNS Client:~p] recv error on ~p:~p: ~p for ~p",
[Master, IP, Port, E, Command]),
reconnect(self()),
{reply, {error, E}, State};
Res ->
{reply, Res, State}
end;
E ->
lager:error("[MDNS Client:~p] send error on ~p:~p: ~p",
[Master, IP, Port, E]),
reconnect(self()),
{reply, E, State}
end.
handle_cast(reconnect, State = #state{socket = S0, name = Name, master=Master,
ip = IP, port = Port}) ->
mdns_client_lib_server:downvote_endpoint(Master, Name),
gen_tcp:close(S0),
case gen_tcp:connect(IP, Port, [binary, {active,false}, {packet,4}], 250) of
{ok, Socket} ->
{noreply, State#state{socket = Socket}};
E ->
lager:error("[MDNS Client:~p] reconnect failed: ~p.",
[Name, E]),
mdns_client_lib_server:downvote_endpoint(Master, Name, 3),
reconnect(self()),
{noreply, State}
end.
handle_info(do_ping,
#state{socket=Socket, master=Master, ip=IP, port=Port}=State) ->
Pong = term_to_binary(pong),
case gen_tcp:send(Socket, term_to_binary(ping)) of
ok ->
case gen_tcp:recv(Socket, 0, 500) of
{error, E} ->
lager:error("[MDNS Client:~p] recv error on ~p:~p: ~p",
[Master, IP, Port, E]),
reconnect(self()),
{noreply, State};
{ok, Res} when Res =:= Pong ->
{noreply, State}
end;
E ->
lager:error("[MDNS Client:~p] send error on ~p:~p: ~p",
[Master, IP, Port, E]),
reconnect(self()),
{noreply, State}
end;
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, #state{socket=undefined}) ->
ok;
terminate(Reason, #state{name = Name, socket=Socket}) ->
gen_tcp:close(Socket),
lager:error("[MDNS Client:~p] Terminted with reason: ~p.",
[Name, Reason]),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.