diff --git a/src/acl.erl b/src/acl.erl index 0feabfb32..99c8e17eb 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -86,6 +86,7 @@ start() -> {attributes, record_info(fields, access)}]), mnesia:add_table_copy(acl, node(), ram_copies), mnesia:add_table_copy(access, node(), ram_copies), + ejabberd_hooks:add(config_reloaded, ?MODULE, load_from_config, 20), load_from_config(), ok. diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 493600afc..1340607cd 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -57,10 +57,10 @@ start(normal, _Args) -> setup_if_elixir_conf_used(), ejabberd_config:start(), set_settings_from_config(), - acl:start(), - shaper:start(), connect_nodes(), Sup = ejabberd_sup:start_link(), + acl:start(), + shaper:start(), ejabberd_rdbms:start(), ejabberd_riak_sup:start(), ejabberd_redis:start(), @@ -88,7 +88,7 @@ start(_, _) -> prep_stop(State) -> ejabberd_listener:stop_listeners(), ejabberd_admin:stop(), - broadcast_c2s_shutdown(), + ejabberd_sm:stop(), gen_mod:stop_modules(), timer:sleep(5000), State. @@ -164,16 +164,6 @@ add_windows_nameservers() -> ?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]), lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs). - -broadcast_c2s_shutdown() -> - Children = ejabberd_sm:get_all_pids(), - lists:foreach( - fun(C2SPid) when node(C2SPid) == node() -> - ejabberd_c2s:send(C2SPid, xmpp:serr_system_shutdown()); - (_) -> - ok - end, Children). - %%% %%% PID file %%% diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 59b5c32a9..daf9c85a1 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -48,7 +48,8 @@ %% API -export([get_presence/1, get_subscription/2, get_subscribed/1, open_session/1, call/3, send/2, close/1, close/2, stop/1, - reply/2, copy_state/2, set_timeout/2, route/2, add_hooks/1]). + reply/2, copy_state/2, set_timeout/2, route/2, + host_up/1, host_down/1]). -include("ejabberd.hrl"). -include("xmpp.hrl"). @@ -145,8 +146,8 @@ route(Pid, Term) -> set_timeout(State, Timeout) -> xmpp_stream_in:set_timeout(State, Timeout). --spec add_hooks(binary()) -> ok. -add_hooks(Host) -> +-spec host_up(binary()) -> ok. +host_up(Host) -> ejabberd_hooks:add(c2s_closed, Host, ?MODULE, process_closed, 100), ejabberd_hooks:add(c2s_terminated, Host, ?MODULE, process_terminated, 100), @@ -157,6 +158,18 @@ add_hooks(Host) -> ejabberd_hooks:add(c2s_handle_cast, Host, ?MODULE, handle_unexpected_cast, 100). +-spec host_down(binary()) -> ok. +host_down(Host) -> + ejabberd_hooks:delete(c2s_closed, Host, ?MODULE, process_closed, 100), + ejabberd_hooks:delete(c2s_terminated, Host, ?MODULE, + process_terminated, 100), + ejabberd_hooks:delete(c2s_unauthenticated_packet, Host, ?MODULE, + reject_unauthenticated_packet, 100), + ejabberd_hooks:delete(c2s_handle_info, Host, ?MODULE, + process_info, 100), + ejabberd_hooks:delete(c2s_handle_cast, Host, ?MODULE, + handle_unexpected_cast, 100). + %% Copies content of one c2s state to another. %% This is needed for session migration from one pid to another. -spec copy_state(state(), state()) -> state(). diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index ff0f7b3e8..c79c0cd27 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -194,7 +194,17 @@ load_file(File) -> reload_file() -> Config = get_ejabberd_config_path(), + OldHosts = get_myhosts(), load_file(Config), + NewHosts = get_myhosts(), + lists:foreach( + fun(Host) -> + ejabberd_hooks:run(host_up, [Host]) + end, NewHosts -- OldHosts), + lists:foreach( + fun(Host) -> + ejabberd_hooks:run(host_down, [Host]) + end, OldHosts -- NewHosts), ejabberd_hooks:run(config_reloaded, []). -spec convert_to_yaml(file:filename()) -> ok | {error, any()}. diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 2095dfc78..7a9034563 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -36,7 +36,8 @@ process_iq_reply/1, get_features/1, register_iq_handler/5, register_iq_response_handler/4, register_iq_response_handler/5, unregister_iq_handler/2, - unregister_iq_response_handler/2, bounce_resource_packet/1]). + unregister_iq_response_handler/2, bounce_resource_packet/1, + host_up/1, host_down/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, @@ -196,16 +197,9 @@ get_features(_, _, XMLNSs) -> %%==================================================================== init([]) -> - lists:foreach(fun (Host) -> - ejabberd_router:register_route(Host, - Host, - {apply, ?MODULE, - route}), - ejabberd_hooks:add(local_send_to_resource_hook, Host, - ?MODULE, bounce_resource_packet, - 100) - end, - ?MYHOSTS), + lists:foreach(fun host_up/1, ?MYHOSTS), + ejabberd_hooks:add(host_up, ?MODULE, host_up, 10), + ejabberd_hooks:add(host_down, ?MODULE, host_down, 100), catch ets:new(?IQTABLE, [named_table, public, ordered_set]), update_table(), ejabberd_mnesia:create(?MODULE, iq_response, @@ -245,6 +239,9 @@ handle_info(Info, State) -> {noreply, State}. terminate(_Reason, _State) -> + lists:foreach(fun host_down/1, ?MYHOSTS), + ejabberd_hooks:delete(host_up, ?MODULE, host_up, 10), + ejabberd_hooks:delete(host_down, ?MODULE, host_down, 100), ok. code_change(_OldVsn, State, _Extra) -> @@ -281,6 +278,16 @@ update_table() -> ok end. +host_up(Host) -> + ejabberd_router:register_route(Host, Host, {apply, ?MODULE, route}), + ejabberd_hooks:add(local_send_to_resource_hook, Host, + ?MODULE, bounce_resource_packet, 100). + +host_down(Host) -> + ejabberd_router:unregister_route(Host), + ejabberd_hooks:delete(local_send_to_resource_hook, Host, + ?MODULE, bounce_resource_packet, 100). + -spec get_iq_callback(binary()) -> {ok, module(), atom() | function()} | error. get_iq_callback(ID) -> case mnesia:dirty_read(iq_response, ID) of diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl index e3a211f8e..5fc73c624 100644 --- a/src/ejabberd_rdbms.erl +++ b/src/ejabberd_rdbms.erl @@ -29,7 +29,7 @@ -author('alexey@process-one.net'). --export([start/0, opt_type/1]). +-export([start/0, opt_type/1, start_hosts/0, start_host/1, stop_host/1]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -38,6 +38,9 @@ start() -> file:delete(ejabberd_sql:freetds_config()), file:delete(ejabberd_sql:odbc_config()), file:delete(ejabberd_sql:odbcinst_config()), + ejabberd_hooks:add(host_up, ?MODULE, start_host, 20), + ejabberd_hooks:add(host_down, ?MODULE, stop_host, 90), + ejabberd_hooks:add(config_reloaded, ?MODULE, start_hosts, 20), case lists:any(fun(H) -> needs_sql(H) /= false end, ?MYHOSTS) of true -> @@ -48,13 +51,21 @@ start() -> %% Start relationnal DB module on the nodes where it is needed start_hosts() -> - lists:foreach(fun (Host) -> - case needs_sql(Host) of - {true, App} -> start_sql(Host, App); - false -> ok - end - end, - ?MYHOSTS). + lists:foreach(fun start_host/1, ?MYHOSTS). + +-spec start_host(binary()) -> ok. +start_host(Host) -> + case needs_sql(Host) of + {true, App} -> start_sql(Host, App); + false -> ok + end. + +-spec stop_host(binary()) -> ok. +stop_host(Host) -> + SupName = gen_mod:get_module_proc(Host, ejabberd_sql_sup), + supervisor:terminate_child(ejabberd_sup, SupName), + supervisor:delete_child(ejabberd_sup, SupName), + ok. %% Start the SQL module on the given host start_sql(Host, App) -> @@ -66,10 +77,12 @@ start_sql(Host, App) -> infinity, supervisor, [ejabberd_sql_sup]}, case supervisor:start_child(ejabberd_sup, ChildSpec) of {ok, _PID} -> ok; + {error, {already_started, _}} -> ok; _Error -> ?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying." "..~n", [Supervisor_name, _Error]), + timer:sleep(5000), start_sql(Host, App) end. diff --git a/src/ejabberd_redis.erl b/src/ejabberd_redis.erl index 9d4264df3..6a853737d 100644 --- a/src/ejabberd_redis.erl +++ b/src/ejabberd_redis.erl @@ -28,7 +28,7 @@ -behaviour(ejabberd_config). %% API --export([start/0, start_link/0, q/1, qp/1, opt_type/1]). +-export([start/0, stop/0, start_link/0, q/1, qp/1, host_up/1, opt_type/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, @@ -49,16 +49,16 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). start() -> + ejabberd_hooks:add(config_reloaded, ?MODULE, start, 20), + ejabberd_hooks:add(host_up, ?MODULE, host_up, 20), case lists:any( fun(Host) -> is_redis_configured(Host) end, ?MYHOSTS) of true -> - Spec = {?MODULE, {?MODULE, start_link, []}, - permanent, 2000, worker, [?MODULE]}, - supervisor:start_child(ejabberd_sup, Spec); + do_start(); false -> - ok + stop() end. q(Command) -> @@ -71,6 +71,16 @@ qp(Pipeline) -> catch _:Reason -> {error, Reason} end. +stop() -> + supervisor:terminate_child(ejabberd_sup, ?MODULE), + supervisor:delete_child(ejabberd_sup, ?MODULE). + +host_up(Host) -> + case is_redis_configured(Host) of + true -> do_start(); + false -> ok + end. + %%%=================================================================== %%% gen_server callbacks %%%=================================================================== @@ -108,6 +118,11 @@ code_change(_OldVsn, State, _Extra) -> %%%=================================================================== %%% Internal functions %%%=================================================================== +do_start() -> + Spec = {?MODULE, {?MODULE, start_link, []}, + permanent, 5000, worker, [?MODULE]}, + supervisor:start_child(ejabberd_sup, Spec). + is_redis_configured(Host) -> ServerConfigured = ejabberd_config:has_option({redis_server, Host}), PortConfigured = ejabberd_config:has_option({redis_port, Host}), diff --git a/src/ejabberd_riak_sup.erl b/src/ejabberd_riak_sup.erl index 840de29b5..d1ab126f8 100644 --- a/src/ejabberd_riak_sup.erl +++ b/src/ejabberd_riak_sup.erl @@ -28,9 +28,9 @@ -behaviour(ejabberd_config). -author('alexey@process-one.net'). --export([start/0, start_link/0, init/1, get_pids/0, +-export([start/0, stop/0, start_link/0, init/1, get_pids/0, transform_options/1, get_random_pid/0, get_random_pid/1, - opt_type/1]). + host_up/1, opt_type/1]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -45,10 +45,26 @@ -define(CONNECT_TIMEOUT, 500). % milliseconds start() -> + ejabberd_hooks:add(config_reloaded, ?MODULE, start, 20), + ejabberd_hooks:add(host_up, ?MODULE, host_up, 20), case lists:any( fun(Host) -> is_riak_configured(Host) end, ?MYHOSTS) of + true -> + ejabberd:start_app(riakc), + do_start(); + false -> + stop() + end. + +stop() -> + supervisor:terminate_child(ejabberd_sup, ?MODULE), + supervisor:delete_child(ejabberd_sup, ?MODULE), + ok. + +host_up(Host) -> + case is_riak_configured(Host) of true -> ejabberd:start_app(riakc), do_start(); @@ -77,9 +93,8 @@ is_riak_configured(Host) -> or AuthConfigured or ModuleWithRiakDBConfigured. do_start() -> - SupervisorName = ?MODULE, ChildSpec = - {SupervisorName, + {?MODULE, {?MODULE, start_link, []}, transient, infinity, @@ -88,9 +103,11 @@ do_start() -> case supervisor:start_child(ejabberd_sup, ChildSpec) of {ok, _PID} -> ok; + {error, {already_started, _}} -> + ok; _Error -> ?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying...~n", - [SupervisorName, _Error]), + [?MODULE, _Error]), timer:sleep(5000), start() end. diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 73004a06b..76fb522f0 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -44,7 +44,8 @@ list_temporarily_blocked_hosts/0, external_host_overloaded/1, is_temporarly_blocked/1, get_commands_spec/0, zlib_enabled/1, get_idle_timeout/1, - tls_required/1, tls_verify/1, tls_enabled/1, tls_options/2]). + tls_required/1, tls_verify/1, tls_enabled/1, tls_options/2, + host_up/1, host_down/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, @@ -300,8 +301,9 @@ init([]) -> ejabberd_mnesia:create(?MODULE, temporarily_blocked, [{ram_copies, [node()]}, {attributes, record_info(fields, temporarily_blocked)}]), - ejabberd_s2s_in:add_hooks(), - ejabberd_s2s_out:add_hooks(), + ejabberd_hooks:add(host_up, ?MODULE, host_up, 50), + ejabberd_hooks:add(host_down, ?MODULE, host_down, 60), + lists:foreach(fun host_up/1, ?MYHOSTS), {ok, #state{}}. handle_call(_Request, _From, State) -> @@ -320,6 +322,9 @@ handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ejabberd_commands:unregister_commands(get_commands_spec()), + lists:foreach(fun host_down/1, ?MYHOSTS), + ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50), + ejabberd_hooks:delete(host_down, ?MODULE, host_down, 60), ok. code_change(_OldVsn, State, _Extra) -> @@ -328,6 +333,26 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +host_up(Host) -> + ejabberd_s2s_in:host_up(Host), + ejabberd_s2s_out:host_up(Host). + +host_down(Host) -> + lists:foreach( + fun(#s2s{fromto = {From, _}, pid = Pid}) when node(Pid) == node() -> + case ejabberd_router:host_of_route(From) of + Host -> + ejabberd_s2s_out:send(Pid, xmpp:serr_system_shutdown()), + ejabberd_s2s_out:stop(Pid); + _ -> + ok + end; + (_) -> + ok + end, ets:tab2list(s2s)), + ejabberd_s2s_in:host_down(Host), + ejabberd_s2s_out:host_down(Host). + -spec clean_table_from_bad_node(node()) -> any(). clean_table_from_bad_node(Node) -> F = fun() -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index f9d9e6f85..4289a8b34 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -42,7 +42,8 @@ -export([handle_unexpected_info/2, handle_unexpected_cast/2, reject_unauthenticated_packet/2, process_closed/2]). %% API --export([stop/1, close/1, send/2, update_state/2, establish/1, add_hooks/0]). +-export([stop/1, close/1, send/2, update_state/2, establish/1, + host_up/1, host_down/1]). -include("ejabberd.hrl"). -include("xmpp.hrl"). @@ -90,19 +91,27 @@ establish(State) -> update_state(Ref, Callback) -> xmpp_stream_in:cast(Ref, {update_state, Callback}). --spec add_hooks() -> ok. -add_hooks() -> - lists:foreach( - fun(Host) -> - ejabberd_hooks:add(s2s_in_closed, Host, ?MODULE, - process_closed, 100), - ejabberd_hooks:add(s2s_in_unauthenticated_packet, Host, ?MODULE, - reject_unauthenticated_packet, 100), - ejabberd_hooks:add(s2s_in_handle_info, Host, ?MODULE, - handle_unexpected_info, 100), - ejabberd_hooks:add(s2s_in_handle_cast, Host, ?MODULE, - handle_unexpected_cast, 100) - end, ?MYHOSTS). +-spec host_up(binary()) -> ok. +host_up(Host) -> + ejabberd_hooks:add(s2s_in_closed, Host, ?MODULE, + process_closed, 100), + ejabberd_hooks:add(s2s_in_unauthenticated_packet, Host, ?MODULE, + reject_unauthenticated_packet, 100), + ejabberd_hooks:add(s2s_in_handle_info, Host, ?MODULE, + handle_unexpected_info, 100), + ejabberd_hooks:add(s2s_in_handle_cast, Host, ?MODULE, + handle_unexpected_cast, 100). + +-spec host_down(binary()) -> ok. +host_down(Host) -> + ejabberd_hooks:delete(s2s_in_closed, Host, ?MODULE, + process_closed, 100), + ejabberd_hooks:delete(s2s_in_unauthenticated_packet, Host, ?MODULE, + reject_unauthenticated_packet, 100), + ejabberd_hooks:delete(s2s_in_handle_info, Host, ?MODULE, + handle_unexpected_info, 100), + ejabberd_hooks:delete(s2s_in_handle_cast, Host, ?MODULE, + handle_unexpected_cast, 100). %%%=================================================================== %%% Hooks diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 32dda56ad..77f555475 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -40,7 +40,7 @@ handle_unexpected_cast/2, process_downgraded/2]). %% API -export([start/3, start_link/3, connect/1, close/1, stop/1, send/2, - route/2, establish/1, update_state/2, add_hooks/0]). + route/2, establish/1, update_state/2, host_up/1, host_down/1]). -include("ejabberd.hrl"). -include("xmpp.hrl"). @@ -99,21 +99,31 @@ establish(State) -> update_state(Ref, Callback) -> xmpp_stream_out:cast(Ref, {update_state, Callback}). --spec add_hooks() -> ok. -add_hooks() -> - lists:foreach( - fun(Host) -> - ejabberd_hooks:add(s2s_out_auth_result, Host, ?MODULE, - process_auth_result, 100), - ejabberd_hooks:add(s2s_out_closed, Host, ?MODULE, - process_closed, 100), - ejabberd_hooks:add(s2s_out_handle_info, Host, ?MODULE, - handle_unexpected_info, 100), - ejabberd_hooks:add(s2s_out_handle_cast, Host, ?MODULE, - handle_unexpected_cast, 100), - ejabberd_hooks:add(s2s_out_downgraded, Host, ?MODULE, - process_downgraded, 100) - end, ?MYHOSTS). +-spec host_up(binary()) -> ok. +host_up(Host) -> + ejabberd_hooks:add(s2s_out_auth_result, Host, ?MODULE, + process_auth_result, 100), + ejabberd_hooks:add(s2s_out_closed, Host, ?MODULE, + process_closed, 100), + ejabberd_hooks:add(s2s_out_handle_info, Host, ?MODULE, + handle_unexpected_info, 100), + ejabberd_hooks:add(s2s_out_handle_cast, Host, ?MODULE, + handle_unexpected_cast, 100), + ejabberd_hooks:add(s2s_out_downgraded, Host, ?MODULE, + process_downgraded, 100). + +-spec host_down(binary()) -> ok. +host_down(Host) -> + ejabberd_hooks:delete(s2s_out_auth_result, Host, ?MODULE, + process_auth_result, 100), + ejabberd_hooks:delete(s2s_out_closed, Host, ?MODULE, + process_closed, 100), + ejabberd_hooks:delete(s2s_out_handle_info, Host, ?MODULE, + handle_unexpected_info, 100), + ejabberd_hooks:delete(s2s_out_handle_cast, Host, ?MODULE, + handle_unexpected_cast, 100), + ejabberd_hooks:delete(s2s_out_downgraded, Host, ?MODULE, + process_downgraded, 100). %%%=================================================================== %%% Hooks diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index eaa1ab4ae..ab6f59639 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -36,6 +36,7 @@ %% API -export([start/0, + stop/0, start_link/0, route/1, route/2, @@ -74,6 +75,8 @@ is_existing_resource/3, get_commands_spec/0, c2s_handle_info/2, + host_up/1, + host_down/1, make_sid/0 ]). @@ -109,9 +112,15 @@ start() -> ChildSpec = {?MODULE, {?MODULE, start_link, []}, - transient, 1000, worker, [?MODULE]}, + transient, 5000, worker, [?MODULE]}, supervisor:start_child(ejabberd_sup, ChildSpec). +-spec stop() -> ok. +stop() -> + supervisor:terminate_child(ejabberd_sup, ?MODULE), + supervisor:delete_child(ejabberd_sup, ?MODULE), + ok. + start_link() -> ?GEN_SERVER:start_link({local, ?MODULE}, ?MODULE, [], []). @@ -388,20 +397,12 @@ c2s_handle_info(State, _) -> %%==================================================================== init([]) -> + process_flag(trap_exit, true), lists:foreach(fun(Mod) -> Mod:init() end, get_sm_backends()), ets:new(sm_iqtable, [named_table, public]), - lists:foreach( - fun(Host) -> - ejabberd_hooks:add(c2s_handle_info, Host, - ejabberd_sm, c2s_handle_info, 50), - ejabberd_hooks:add(roster_in_subscription, Host, - ejabberd_sm, check_in_subscription, 20), - ejabberd_hooks:add(offline_message_hook, Host, - ejabberd_sm, bounce_offline_message, 100), - ejabberd_hooks:add(remove_user, Host, - ejabberd_sm, disconnect_removed_user, 100), - ejabberd_c2s:add_hooks(Host) - end, ?MYHOSTS), + ejabberd_hooks:add(host_up, ?MODULE, host_up, 50), + ejabberd_hooks:add(host_down, ?MODULE, host_down, 60), + lists:foreach(fun host_up/1, ?MYHOSTS), ejabberd_commands:register_commands(get_commands_spec()), {ok, #state{}}. @@ -433,17 +434,9 @@ handle_info(Info, State) -> {noreply, State}. terminate(_Reason, _State) -> - lists:foreach( - fun(Host) -> - ejabberd_hooks:delete(c2s_handle_info, Host, - ejabberd_sm, c2s_handle_info, 50), - ejabberd_hooks:delete(roster_in_subscription, Host, - ejabberd_sm, check_in_subscription, 20), - ejabberd_hooks:delete(offline_message_hook, Host, - ejabberd_sm, bounce_offline_message, 100), - ejabberd_hooks:delete(remove_user, Host, - ejabberd_sm, disconnect_removed_user, 100) - end, ?MYHOSTS), + lists:foreach(fun host_down/1, ?MYHOSTS), + ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50), + ejabberd_hooks:delete(host_down, ?MODULE, host_down, 60), ejabberd_commands:unregister_commands(get_commands_spec()), ok. @@ -452,6 +445,36 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +-spec host_up(binary()) -> ok. +host_up(Host) -> + ejabberd_hooks:add(c2s_handle_info, Host, + ejabberd_sm, c2s_handle_info, 50), + ejabberd_hooks:add(roster_in_subscription, Host, + ejabberd_sm, check_in_subscription, 20), + ejabberd_hooks:add(offline_message_hook, Host, + ejabberd_sm, bounce_offline_message, 100), + ejabberd_hooks:add(remove_user, Host, + ejabberd_sm, disconnect_removed_user, 100), + ejabberd_c2s:host_up(Host). + +-spec host_down(binary()) -> ok. +host_down(Host) -> + Mod = get_sm_backend(Host), + lists:foreach( + fun(#session{sid = {_, Pid}}) when node(Pid) == node() -> + ejabberd_c2s:send(Pid, xmpp:serr_system_shutdown()); + (_) -> + ok + end, Mod:get_sessions(Host)), + ejabberd_hooks:delete(c2s_handle_info, Host, + ejabberd_sm, c2s_handle_info, 50), + ejabberd_hooks:delete(roster_in_subscription, Host, + ejabberd_sm, check_in_subscription, 20), + ejabberd_hooks:delete(offline_message_hook, Host, + ejabberd_sm, bounce_offline_message, 100), + ejabberd_hooks:delete(remove_user, Host, + ejabberd_sm, disconnect_removed_user, 100), + ejabberd_c2s:host_down(Host). -spec set_session(sid(), binary(), binary(), binary(), prio(), info()) -> ok. diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index d160afd72..e4c8f4ef7 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -33,7 +33,7 @@ %% API -export([start_link/0, process_command/1, register_hook/1, - process_remote_command/1]). + unregister_hook/1, process_remote_command/1]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, opt_type/1]). @@ -86,6 +86,10 @@ register_hook(Host) -> ejabberd_hooks:add(local_send_to_resource_hook, Host, ?MODULE, process_command, 50). +unregister_hook(Host) -> + ejabberd_hooks:delete(local_send_to_resource_hook, Host, + ?MODULE, process_command, 50). + %%==================================================================== %% gen_server callbacks %%==================================================================== @@ -101,6 +105,8 @@ init(Opts) -> LH = proplists:get_value(large_heap, Opts), process_flag(priority, high), erlang:system_monitor(self(), [{large_heap, LH}]), + ejabberd_hooks:add(host_up, ?MODULE, register_hook, 50), + ejabberd_hooks:add(host_down, ?MODULE, unregister_hook, 60), lists:foreach(fun register_hook/1, ?MYHOSTS), {ok, #state{}}. diff --git a/src/gen_mod.erl b/src/gen_mod.erl index b74d1555d..178fccb1f 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -80,6 +80,8 @@ start_link() -> init([]) -> ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50), + ejabberd_hooks:add(host_up, ?MODULE, start_modules, 40), + ejabberd_hooks:add(host_down, ?MODULE, stop_modules, 80), ets:new(ejabberd_modules, [named_table, public, {keypos, #ejabberd_module.module_host}]), @@ -162,7 +164,7 @@ sort_modules(Host, ModOpts) -> end, ModOpts), [digraph:vertex(G, V) || V <- digraph_utils:topsort(G)]. --spec start_modules(binary()) -> any(). +-spec start_modules(binary()) -> ok. start_modules(Host) -> Modules = sort_modules(Host, get_modules_options(Host)), @@ -171,7 +173,7 @@ start_modules(Host) -> start_module(Host, Module, Opts) end, Modules). --spec start_module(binary(), atom()) -> any(). +-spec start_module(binary(), atom()) -> ok | {ok, pid()} | {error, not_found_in_config}. start_module(Host, Module) -> Modules = get_modules_options(Host), @@ -293,7 +295,7 @@ is_app_running(AppName) -> lists:keymember(AppName, 1, application:which_applications(Timeout)). --spec stop_modules() -> any(). +-spec stop_modules() -> ok. stop_modules() -> lists:foreach( @@ -301,7 +303,7 @@ stop_modules() -> stop_modules(Host) end, ?MYHOSTS). --spec stop_modules(binary()) -> any(). +-spec stop_modules(binary()) -> ok. stop_modules(Host) -> Modules = get_modules_options(Host),