diff options
Diffstat (limited to 'src/mod_ping.erl')
-rw-r--r-- | src/mod_ping.erl | 216 |
1 files changed, 106 insertions, 110 deletions
diff --git a/src/mod_ping.erl b/src/mod_ping.erl index fb1ab9c64..4e5cdf0bf 100644 --- a/src/mod_ping.erl +++ b/src/mod_ping.erl @@ -25,18 +25,24 @@ %%%---------------------------------------------------------------------- -module(mod_ping). + -author('bjc@kublai.com'). -behavior(gen_mod). + -behavior(gen_server). -include("ejabberd.hrl"). + -include("jlib.hrl"). -define(SUPERVISOR, ejabberd_sup). --define(NS_PING, "urn:xmpp:ping"). --define(DEFAULT_SEND_PINGS, false). % bool() --define(DEFAULT_PING_INTERVAL, 60). % seconds + +-define(NS_PING, <<"urn:xmpp:ping">>). + +-define(DEFAULT_SEND_PINGS, false). + +-define(DEFAULT_PING_INTERVAL, 60). -define(DICT, dict). @@ -47,24 +53,24 @@ -export([start/2, stop/1]). %% gen_server callbacks --export([init/1, terminate/2, handle_call/3, handle_cast/2, - handle_info/2, code_change/3]). +-export([init/1, terminate/2, handle_call/3, + handle_cast/2, handle_info/2, code_change/3]). %% Hook callbacks --export([iq_ping/3, user_online/3, user_offline/3, user_send/4]). +-export([iq_ping/3, user_online/3, user_offline/3, + user_send/4]). --record(state, {host = "", - send_pings = ?DEFAULT_SEND_PINGS, - ping_interval = ?DEFAULT_PING_INTERVAL, - timeout_action = none, - timers = ?DICT:new()}). +-record(state, + {host = <<"">>, + send_pings = ?DEFAULT_SEND_PINGS :: boolean(), + ping_interval = ?DEFAULT_PING_INTERVAL :: non_neg_integer(), + timeout_action = none :: none | kill, + timers = (?DICT):new() :: dict()}). -%%==================================================================== -%% API -%%==================================================================== start_link(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), - gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). + gen_server:start_link({local, Proc}, ?MODULE, + [Host, Opts], []). start_ping(Host, JID) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), @@ -74,13 +80,10 @@ stop_ping(Host, JID) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:cast(Proc, {stop_ping, JID}). -%%==================================================================== -%% gen_mod callbacks -%%==================================================================== start(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), PingSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, - transient, 2000, worker, [?MODULE]}, + transient, 2000, worker, [?MODULE]}, supervisor:start_child(?SUPERVISOR, PingSpec). stop(Host) -> @@ -88,51 +91,55 @@ stop(Host) -> gen_server:call(Proc, stop), supervisor:delete_child(?SUPERVISOR, Proc). -%%==================================================================== -%% gen_server callbacks -%%==================================================================== init([Host, Opts]) -> - SendPings = gen_mod:get_opt(send_pings, Opts, ?DEFAULT_SEND_PINGS), - PingInterval = gen_mod:get_opt(ping_interval, Opts, ?DEFAULT_PING_INTERVAL), - TimeoutAction = gen_mod:get_opt(timeout_action, Opts, none), - IQDisc = gen_mod:get_opt(iqdisc, Opts, no_queue), + SendPings = gen_mod:get_opt(send_pings, Opts, + fun(B) when is_boolean(B) -> B end, + ?DEFAULT_SEND_PINGS), + PingInterval = gen_mod:get_opt(ping_interval, Opts, + fun(I) when is_integer(I), I>0 -> I end, + ?DEFAULT_PING_INTERVAL), + TimeoutAction = gen_mod:get_opt(timeout_action, Opts, + fun(none) -> none; + (kill) -> kill + end, none), + IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, + no_queue), mod_disco:register_feature(Host, ?NS_PING), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PING, - ?MODULE, iq_ping, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_PING, - ?MODULE, iq_ping, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, + ?NS_PING, ?MODULE, iq_ping, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, + ?NS_PING, ?MODULE, iq_ping, IQDisc), case SendPings of - true -> - %% Ping requests are sent to all entities, whether they - %% announce 'urn:xmpp:ping' in their caps or not - ejabberd_hooks:add(sm_register_connection_hook, Host, - ?MODULE, user_online, 100), - ejabberd_hooks:add(sm_remove_connection_hook, Host, - ?MODULE, user_offline, 100), - ejabberd_hooks:add(sm_remove_migrated_connection_hook, Host, - ?MODULE, user_offline, 100), - ejabberd_hooks:add(user_send_packet, Host, - ?MODULE, user_send, 100); - _ -> - ok + true -> + ejabberd_hooks:add(sm_register_connection_hook, Host, + ?MODULE, user_online, 100), + ejabberd_hooks:add(sm_remove_connection_hook, Host, + ?MODULE, user_offline, 100), + ejabberd_hooks:add(sm_remove_migrated_connection_hook, + Host, ?MODULE, user_offline, 100), + ejabberd_hooks:add(user_send_packet, Host, ?MODULE, + user_send, 100); + _ -> ok end, - {ok, #state{host = Host, - send_pings = SendPings, - ping_interval = PingInterval, - timeout_action = TimeoutAction, - timers = ?DICT:new()}}. + {ok, + #state{host = Host, send_pings = SendPings, + ping_interval = PingInterval, + timeout_action = TimeoutAction, + timers = (?DICT):new()}}. terminate(_Reason, #state{host = Host}) -> ejabberd_hooks:delete(sm_remove_connection_hook, Host, ?MODULE, user_offline, 100), - ejabberd_hooks:delete(sm_remove_migrated_connection_hook, Host, - ?MODULE, user_offline, 100), + ejabberd_hooks:delete(sm_remove_migrated_connection_hook, + Host, ?MODULE, user_offline, 100), ejabberd_hooks:delete(sm_register_connection_hook, Host, ?MODULE, user_online, 100), - ejabberd_hooks:delete(user_send_packet, Host, - ?MODULE, user_send, 100), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PING), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PING), + ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, + user_send, 100), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, + ?NS_PING), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, + ?NS_PING), mod_disco:unregister_feature(Host, ?NS_PING). handle_call(stop, _From, State) -> @@ -141,56 +148,57 @@ handle_call(_Req, _From, State) -> {reply, {error, badarg}, State}. handle_cast({start_ping, JID}, State) -> - Timers = add_timer(JID, State#state.ping_interval, State#state.timers), + Timers = add_timer(JID, State#state.ping_interval, + State#state.timers), {noreply, State#state{timers = Timers}}; handle_cast({stop_ping, JID}, State) -> Timers = del_timer(JID, State#state.timers), {noreply, State#state{timers = Timers}}; handle_cast({iq_pong, JID, timeout}, State) -> Timers = del_timer(JID, State#state.timers), - ejabberd_hooks:run(user_ping_timeout, State#state.host, [JID]), + ejabberd_hooks:run(user_ping_timeout, State#state.host, + [JID]), case State#state.timeout_action of - kill -> - #jid{user = User, server = Server, resource = Resource} = JID, - case ejabberd_sm:get_session_pid(User, Server, Resource) of - Pid when is_pid(Pid) -> - ejabberd_c2s:stop(Pid); - _ -> - ok - end; - _ -> - ok + kill -> + #jid{user = User, server = Server, + resource = Resource} = + JID, + case ejabberd_sm:get_session_pid(User, Server, Resource) + of + Pid when is_pid(Pid) -> ejabberd_c2s:stop(Pid); + _ -> ok + end; + _ -> ok end, {noreply, State#state{timers = Timers}}; -handle_cast(_Msg, State) -> - {noreply, State}. +handle_cast(_Msg, State) -> {noreply, State}. handle_info({timeout, _TRef, {ping, JID}}, State) -> IQ = #iq{type = get, - sub_el = [{xmlelement, "ping", [{"xmlns", ?NS_PING}], []}]}, + sub_el = + [#xmlel{name = <<"ping">>, + attrs = [{<<"xmlns">>, ?NS_PING}], children = []}]}, Pid = self(), - F = fun(Response) -> + F = fun (Response) -> gen_server:cast(Pid, {iq_pong, JID, Response}) end, - From = jlib:make_jid("", State#state.host, ""), + From = jlib:make_jid(<<"">>, State#state.host, <<"">>), ejabberd_local:route_iq(From, JID, IQ, F), - Timers = add_timer(JID, State#state.ping_interval, State#state.timers), + Timers = add_timer(JID, State#state.ping_interval, + State#state.timers), {noreply, State#state{timers = Timers}}; -handle_info(_Info, State) -> - {noreply, State}. +handle_info(_Info, State) -> {noreply, State}. -code_change(_OldVsn, State, _Extra) -> - {ok, State}. +code_change(_OldVsn, State, _Extra) -> {ok, State}. -%%==================================================================== -%% Hook callbacks -%%==================================================================== -iq_ping(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> +iq_ping(_From, _To, + #iq{type = Type, sub_el = SubEl} = IQ) -> case {Type, SubEl} of - {get, {xmlelement, "ping", _, _}} -> - IQ#iq{type = result, sub_el = []}; - _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]} + {get, #xmlel{name = <<"ping">>}} -> + IQ#iq{type = result, sub_el = []}; + _ -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]} end. user_online(_SID, JID, _Info) -> @@ -202,40 +210,28 @@ user_offline(_SID, JID, _Info) -> user_send(_DebugFlag, JID, _From, _Packet) -> start_ping(JID#jid.lserver, JID). -%%==================================================================== -%% Internal functions -%%==================================================================== add_timer(JID, Interval, Timers) -> LJID = jlib:jid_tolower(JID), - NewTimers = case ?DICT:find(LJID, Timers) of - {ok, OldTRef} -> - cancel_timer(OldTRef), - ?DICT:erase(LJID, Timers); - _ -> - Timers + NewTimers = case (?DICT):find(LJID, Timers) of + {ok, OldTRef} -> + cancel_timer(OldTRef), (?DICT):erase(LJID, Timers); + _ -> Timers end, - TRef = erlang:start_timer(Interval * 1000, self(), {ping, JID}), - ?DICT:store(LJID, TRef, NewTimers). + TRef = erlang:start_timer(Interval * 1000, self(), + {ping, JID}), + (?DICT):store(LJID, TRef, NewTimers). del_timer(JID, Timers) -> LJID = jlib:jid_tolower(JID), - case ?DICT:find(LJID, Timers) of - {ok, TRef} -> - cancel_timer(TRef), - ?DICT:erase(LJID, Timers); - _ -> - Timers + case (?DICT):find(LJID, Timers) of + {ok, TRef} -> + cancel_timer(TRef), (?DICT):erase(LJID, Timers); + _ -> Timers end. cancel_timer(TRef) -> case erlang:cancel_timer(TRef) of - false -> - receive - {timeout, TRef, _} -> - ok - after 0 -> - ok - end; - _ -> - ok + false -> + receive {timeout, TRef, _} -> ok after 0 -> ok end; + _ -> ok end. |