-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. handle_call({call, Command, Timeout}, _From, #state{socket=Socket, master=Master, ip=IP, port=Port}=State) -> case gen_tcp:send(Socket, term_to_binary(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}.