]> granicus.if.org Git - ejabberd/commitdiff
Start/stop virtual hosts when reloading configuration file
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Thu, 23 Feb 2017 07:12:19 +0000 (10:12 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Thu, 23 Feb 2017 07:12:19 +0000 (10:12 +0300)
14 files changed:
src/acl.erl
src/ejabberd_app.erl
src/ejabberd_c2s.erl
src/ejabberd_config.erl
src/ejabberd_local.erl
src/ejabberd_rdbms.erl
src/ejabberd_redis.erl
src/ejabberd_riak_sup.erl
src/ejabberd_s2s.erl
src/ejabberd_s2s_in.erl
src/ejabberd_s2s_out.erl
src/ejabberd_sm.erl
src/ejabberd_system_monitor.erl
src/gen_mod.erl

index 0feabfb3283fd4a1b94fa56e72debd0e0ee4e69b..99c8e17eb7c74c8b2824f6e6300dde0dd1be5705 100644 (file)
@@ -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.
 
index 493600afc46c52c3893f2ddc234a18b06de69555..1340607cd34453a620b1aaa91013e8ef5b952442 100644 (file)
@@ -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
 %%%
index 59b5c32a98d9db9c75fe6681887450f9860f5f5c..daf9c85a1ccaf9c79df6c6ce5f5ced5b2570d727 100644 (file)
@@ -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().
index ff0f7b3e8bfb4d6cae8d304a757aec87ec065bdc..c79c0cd2758211eb3895e071aa21383b472afe1d 100644 (file)
@@ -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()}.
index 2095dfc78ae972115df145e5c6cf1df05b94a271..7a9034563b59feaa46a2a8642ffaba2f74b53d8e 100644 (file)
@@ -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
index e3a211f8e40bf0482811e68f82d87d5f9aa3e4da..5fc73c624f31322823d1cfd6fe9f463702727e50 100644 (file)
@@ -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.
 
index 9d4264df33489cf12bf9a093c4a7b4aef6824e51..6a853737d1eb3c520f1b9d3ce02d8edadcc00767 100644 (file)
@@ -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}),
index 840de29b5c754d63cff98537da693cd8eca6e13d..d1ab126f8b2e066434251679195dfdc2afc19dfe 100644 (file)
@@ -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").
 -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.
index 73004a06b79fc3e713a222a92e9147fdedc386e8..76fb522f0a78b0dd173767958a4a6ba6c3ce9c9f 100644 (file)
@@ -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() ->
index f9d9e6f858842c86d54c75db1d1169a298230176..4289a8b34411104a6dd53bcf7d20cbdae75164e3 100644 (file)
@@ -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
index 32dda56ad554453aa3f073b55b968ed1c11ba540..77f5554755ad56892623ffd8ae8643854fea2585 100644 (file)
@@ -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
index eaa1ab4ae54f49bb77be09c59b556a78482884fd..ab6f59639d90bc00a9420a83f5123882c95688ab 100644 (file)
@@ -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
        ]).
 
 
 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.
index d160afd7250b30f20a842de7ec570c7df8411b4f..e4c8f4ef72a27ab14c6044ae73a2538d98ffa190 100644 (file)
@@ -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{}}.
 
index b74d1555d4ae82d443f4852e7f9da0efcea1c281..178fccb1fca5476e503b24fbc62d2b420d53ab64 100644 (file)
@@ -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),