]> granicus.if.org Git - ejabberd/commitdiff
Introduce 'hosts' option
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 8 Aug 2017 14:46:26 +0000 (17:46 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 8 Aug 2017 14:46:26 +0000 (17:46 +0300)
The option can be used as a replacement of 'host' option
when several (sub)domains are needed to be registered for the module.
Note that you cannot combine both 'host' and 'hosts' in the config
because 'host' option is of a higher priority. Example:

mod_pubsub:
   ...
   hosts:
     - "pubsub1.@HOST@"
     - "pubsub2.@HOST@"

Fixes #1883

12 files changed:
src/gen_mod.erl
src/mod_echo.erl
src/mod_http_upload.erl
src/mod_irc.erl
src/mod_mix.erl
src/mod_muc.erl
src/mod_muc_mnesia.erl
src/mod_proxy65.erl
src/mod_proxy65_service.erl
src/mod_pubsub.erl
src/mod_vcard.erl
src/mod_vcard_ldap.erl

index 5bfa3b4d46e7cc5e1295a2542233b1908291e8a8..e17197dfb5732fde977cf1600ac5479d9c8b342f 100644 (file)
@@ -34,7 +34,8 @@
         stop_child/1, stop_child/2, config_reloaded/0]).
 -export([start_module/2, start_module/3,
         stop_module/2, stop_module_keep_config/2,
-        get_opt/2, get_opt/3, get_opt_host/3, opt_type/1, is_equal_opt/4,
+        get_opt/2, get_opt/3, get_opt_host/3,
+        get_opt_hosts/3, opt_type/1, is_equal_opt/4,
         get_module_opt/3, get_module_opt/4, get_module_opt_host/3,
         loaded_modules/1, loaded_modules_with_opts/1,
         get_hosts/2, get_module_proc/2, is_loaded/2, is_loaded_elsewhere/2,
@@ -441,6 +442,20 @@ get_opt_host(Host, Opts, Default) ->
     Val = get_opt(host, Opts, Default),
     ejabberd_regexp:greplace(Val, <<"@HOST@">>, Host).
 
+-spec get_opt_hosts(binary(), opts(), binary()) -> [binary()].
+
+get_opt_hosts(Host, Opts, Default) ->
+    Vals = case get_opt(host, Opts, undefined) of
+              undefined ->
+                   case get_opt(hosts, Opts, []) of
+                       [] -> [Default];
+                       L -> L
+                   end;
+              Val ->
+                  [Val]
+          end,
+    [ejabberd_regexp:greplace(V, <<"@HOST@">>, Host) || V <- Vals].
+
 -spec get_validators(binary(), module(), opts()) -> dict:dict() | undef.
 get_validators(Host, Module, Opts) ->
     try Module:mod_opt_type('') of
index 861b1a0eff85126411380f52af5314a7538f29a7..79dd59962f0fc634c87e57a59d16694b7dfc06b5 100644 (file)
@@ -43,7 +43,7 @@
 
 -include("xmpp.hrl").
 
--record(state, {host = <<"">> :: binary()}).
+-record(state, {hosts = [] :: [binary()]}).
 
 %%====================================================================
 %% gen_mod API
@@ -62,7 +62,9 @@ depends(_Host, _Opts) ->
     [].
 
 mod_opt_type(host) -> fun iolist_to_binary/1;
-mod_opt_type(_) -> [host].
+mod_opt_type(hosts) ->
+    fun(L) -> lists:map(fun iolist_to_binary/1, L) end;
+mod_opt_type(_) -> [host, hosts].
 
 %%====================================================================
 %% gen_server callbacks
@@ -77,10 +79,13 @@ mod_opt_type(_) -> [host].
 %%--------------------------------------------------------------------
 init([Host, Opts]) ->
     process_flag(trap_exit, true),
-    MyHost = gen_mod:get_opt_host(Host, Opts,
+    Hosts = gen_mod:get_opt_hosts(Host, Opts,
                                  <<"echo.@HOST@">>),
-    ejabberd_router:register_route(MyHost, Host),
-    {ok, #state{host = MyHost}}.
+    lists:foreach(
+      fun(H) ->
+             ejabberd_router:register_route(H, Host)
+      end, Hosts),
+    {ok, #state{hosts = Hosts}}.
 
 %%--------------------------------------------------------------------
 %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
@@ -101,17 +106,19 @@ handle_call(stop, _From, State) ->
 %% Description: Handling cast messages
 %%--------------------------------------------------------------------
 handle_cast({reload, Host, NewOpts, OldOpts}, State) ->
-    NewMyHost = gen_mod:get_opt_host(Host, NewOpts,
-                                    <<"echo.@HOST@">>),
-    OldMyHost = gen_mod:get_opt_host(Host, OldOpts,
-                                    <<"echo.@HOST@">>),
-    if NewMyHost /= OldMyHost ->
-           ejabberd_router:register_route(NewMyHost, Host),
-           ejabberd_router:unregister_route(OldMyHost);
-       true ->
-           ok
-    end,
-    {noreply, State#state{host = NewMyHost}};
+    NewMyHosts = gen_mod:get_opt_hosts(Host, NewOpts,
+                                      <<"echo.@HOST@">>),
+    OldMyHosts = gen_mod:get_opt_hosts(Host, OldOpts,
+                                      <<"echo.@HOST@">>),
+    lists:foreach(
+      fun(H) ->
+             ejabberd_router:unregister_route(H)
+      end, OldMyHosts -- NewMyHosts),
+    lists:foreach(
+      fun(H) ->
+             ejabberd_router:register_route(H, Host)
+      end, NewMyHosts -- OldMyHosts),
+    {noreply, State#state{hosts = NewMyHosts}};
 handle_cast(Msg, State) ->
     ?WARNING_MSG("unexpected cast: ~p", [Msg]),
     {noreply, State}.
@@ -147,7 +154,7 @@ handle_info(_Info, State) -> {noreply, State}.
 %% The return value is ignored.
 %%--------------------------------------------------------------------
 terminate(_Reason, State) ->
-    ejabberd_router:unregister_route(State#state.host), ok.
+    lists:foreach(fun ejabberd_router:unregister_route/1, State#state.hosts).
 
 %%--------------------------------------------------------------------
 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
index c8cd300f4e02abdaacd8cdeddbaa6b054ea2a7b9..6d981e9eca5d526eeab3e35a255de3e6a10d1c9d 100644 (file)
@@ -94,7 +94,7 @@
 
 -record(state,
        {server_host            :: binary(),
-        host                   :: binary(),
+        hosts                  :: [binary()],
         name                   :: binary(),
         access                 :: atom(),
         max_size               :: pos_integer() | infinity,
@@ -151,6 +151,8 @@ stop(ServerHost) ->
 
 mod_opt_type(host) ->
     fun iolist_to_binary/1;
+mod_opt_type(hosts) ->
+    fun (L) -> lists:map(fun iolist_to_binary/1, L) end;
 mod_opt_type(name) ->
     fun iolist_to_binary/1;
 mod_opt_type(access) ->
@@ -194,7 +196,7 @@ mod_opt_type(rm_on_unregister) ->
 mod_opt_type(thumbnail) ->
     fun(B) when is_boolean(B) -> B end;
 mod_opt_type(_) ->
-    [host, name, access, max_size, secret_length, jid_in_url, file_mode,
+    [host, hosts, name, access, max_size, secret_length, jid_in_url, file_mode,
      dir_mode, docroot, put_url, get_url, service_url, custom_headers,
      rm_on_unregister, thumbnail].
 
@@ -211,7 +213,7 @@ depends(_Host, _Opts) ->
 
 init([ServerHost, Opts]) ->
     process_flag(trap_exit, true),
-    Host = gen_mod:get_opt_host(ServerHost, Opts, <<"upload.@HOST@">>),
+    Hosts = gen_mod:get_opt_hosts(ServerHost, Opts, <<"upload.@HOST@">>),
     Name = gen_mod:get_opt(name, Opts, <<"HTTP File Upload">>),
     Access = gen_mod:get_opt(access, Opts, local),
     MaxSize = gen_mod:get_opt(max_size, Opts, 104857600),
@@ -244,8 +246,11 @@ init([ServerHost, Opts]) ->
        false ->
            ok
     end,
-    ejabberd_router:register_route(Host, ServerHost),
-    {ok, #state{server_host = ServerHost, host = Host, name = Name,
+    lists:foreach(
+      fun(Host) ->
+             ejabberd_router:register_route(Host, ServerHost)
+      end, Hosts),
+    {ok, #state{server_host = ServerHost, hosts = Hosts, name = Name,
                access = Access, max_size = MaxSize,
                secret_length = SecretLength, jid_in_url = JIDinURL,
                file_mode = FileMode, dir_mode = DirMode,
@@ -324,10 +329,9 @@ handle_info(Info, State) ->
 
 -spec terminate(normal | shutdown | {shutdown, _} | _, state()) -> ok.
 
-terminate(Reason, #state{server_host = ServerHost, host = Host}) ->
+terminate(Reason, #state{server_host = ServerHost, hosts = Hosts}) ->
     ?DEBUG("Stopping HTTP upload process for ~s: ~p", [ServerHost, Reason]),
-    ejabberd_router:unregister_route(Host),
-    ok.
+    lists:foreach(fun ejabberd_router:unregister_route/1, Hosts).
 
 -spec code_change({down, _} | _, state(), _) -> {ok, state()}.
 
index fc85668e88a2b947fe7948125b0b551893b134b9..04687ea67b8e1ef97ce8cd8b6289e00eec0d10b0 100644 (file)
@@ -58,7 +58,7 @@
        [<<"koi8-r">>, <<"iso8859-15">>, <<"iso8859-1">>, <<"iso8859-2">>,
         <<"utf-8">>, <<"utf-8+latin-1">>]).
 
--record(state, {host = <<"">>        :: binary(),
+-record(state, {hosts = []           :: [binary()],
                 server_host = <<"">> :: binary(),
                 access = all         :: atom()}).
 
@@ -99,8 +99,7 @@ depends(_Host, _Opts) ->
 init([Host, Opts]) ->
     process_flag(trap_exit, true),
     ejabberd:start_app(iconv),
-    MyHost = gen_mod:get_opt_host(Host, Opts,
-                                 <<"irc.@HOST@">>),
+    MyHosts = gen_mod:get_opt_hosts(Host, Opts, <<"irc.@HOST@">>),
     Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
     Mod:init(Host, Opts),
     Access = gen_mod:get_opt(access, Opts, all),
@@ -108,10 +107,13 @@ init([Host, Opts]) ->
                  [named_table, public,
                   {keypos, #irc_connection.jid_server_host}]),
     IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(Host)),
-    register_hooks(MyHost, IQDisc),
-    ejabberd_router:register_route(MyHost, Host),
+    lists:foreach(
+      fun(MyHost) ->
+             register_hooks(MyHost, IQDisc),
+             ejabberd_router:register_route(MyHost, Host)
+      end, MyHosts),
     {ok,
-     #state{host = MyHost, server_host = Host,
+     #state{hosts = MyHosts, server_host = Host,
            access = Access}}.
 
 %%--------------------------------------------------------------------
@@ -133,8 +135,8 @@ handle_call(stop, _From, State) ->
 %% Description: Handling cast messages
 %%--------------------------------------------------------------------
 handle_cast({reload, ServerHost, NewOpts, OldOpts}, State) ->
-    NewHost = gen_mod:get_opt_host(ServerHost, NewOpts, <<"irc.@HOST@">>),
-    OldHost = gen_mod:get_opt_host(ServerHost, OldOpts, <<"irc.@HOST@">>),
+    NewHosts = gen_mod:get_opt_hosts(ServerHost, NewOpts, <<"irc.@HOST@">>),
+    OldHosts = gen_mod:get_opt_hosts(ServerHost, OldOpts, <<"irc.@HOST@">>),
     NewIQDisc = gen_mod:get_opt(iqdisc, NewOpts, gen_iq_handler:iqdisc(ServerHost)),
     OldIQDisc = gen_mod:get_opt(iqdisc, OldOpts, gen_iq_handler:iqdisc(ServerHost)),
     NewMod = gen_mod:db_mod(ServerHost, NewOpts, ?MODULE),
@@ -145,20 +147,26 @@ handle_cast({reload, ServerHost, NewOpts, OldOpts}, State) ->
        true ->
            ok
     end,
-    if (NewIQDisc /= OldIQDisc) or (NewHost /= OldHost) ->
-           register_hooks(NewHost, NewIQDisc);
-       true ->
-           ok
-    end,
-    if NewHost /= OldHost ->
-           ejabberd_router:register_route(NewHost, ServerHost),
-           ejabberd_router:unregister_route(OldHost),
-           unregister_hooks(OldHost);
+    if (NewIQDisc /= OldIQDisc) ->
+           lists:foreach(
+             fun(NewHost) ->
+                     register_hooks(NewHost, NewIQDisc)
+             end, NewHosts -- (NewHosts -- OldHosts));
        true ->
            ok
     end,
+    lists:foreach(
+      fun(NewHost) ->
+             ejabberd_router:register_route(NewHost, ServerHost),
+             register_hooks(NewHost, NewIQDisc)
+      end, NewHosts -- OldHosts),
+    lists:foreach(
+      fun(OldHost) ->
+             ejabberd_router:unregister_route(OldHost),
+             unregister_hooks(OldHost)
+      end, OldHosts -- NewHosts),
     Access = gen_mod:get_opt(access, NewOpts, all),
-    {noreply, State#state{host = NewHost, access = Access}};
+    {noreply, State#state{hosts = NewHosts, access = Access}};
 handle_cast(Msg, State) ->
     ?WARNING_MSG("unexpected cast: ~p", [Msg]),
     {noreply, State}.
@@ -170,9 +178,10 @@ handle_cast(Msg, State) ->
 %% Description: Handling all non call/cast messages
 %%--------------------------------------------------------------------
 handle_info({route, Packet},
-           #state{host = Host, server_host = ServerHost,
-                  access = Access} =
+           #state{server_host = ServerHost, access = Access} =
                State) ->
+    To = xmpp:get_to(Packet),
+    Host = To#jid.lserver,
     case catch do_route(Host, ServerHost, Access, Packet) of
       {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
       _ -> ok
@@ -187,9 +196,12 @@ handle_info(_Info, State) -> {noreply, State}.
 %% cleaning up. When it returns, the gen_server terminates with Reason.
 %% The return value is ignored.
 %%--------------------------------------------------------------------
-terminate(_Reason, #state{host = MyHost}) ->
-    ejabberd_router:unregister_route(MyHost),
-    unregister_hooks(MyHost).
+terminate(_Reason, #state{hosts = MyHosts}) ->
+    lists:foreach(
+      fun(MyHost) ->
+             ejabberd_router:unregister_route(MyHost),
+             unregister_hooks(MyHost)
+      end, MyHosts).
 
 %%--------------------------------------------------------------------
 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
@@ -975,8 +987,10 @@ mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
 mod_opt_type(default_encoding) ->
     fun iolist_to_binary/1;
 mod_opt_type(host) -> fun iolist_to_binary/1;
+mod_opt_type(hosts) ->
+    fun (L) -> lists:map(fun iolist_to_binary/1, L) end;
 mod_opt_type(_) ->
-    [access, db_type, default_encoding, host].
+    [access, db_type, default_encoding, host, hosts].
 
 -spec extract_ident(stanza()) -> binary().
 extract_ident(Packet) ->
index 4763447f3cb19f8f84c3801a8ceb016a4ced4241..90507665be615eb906366a1294d856d6bd387a5c 100644 (file)
@@ -46,7 +46,7 @@
                ?NS_MIX_NODES_CONFIG]).
 
 -record(state, {server_host :: binary(),
-               host :: binary()}).
+               hosts :: [binary()]}).
 
 %%%===================================================================
 %%% API
@@ -124,36 +124,39 @@ process_iq(#iq{lang = Lang} = IQ) ->
 %%%===================================================================
 init([ServerHost, Opts]) ->
     process_flag(trap_exit, true),
-    Host = gen_mod:get_opt_host(ServerHost, Opts, <<"mix.@HOST@">>),
-    IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(Host)),
-    ConfigTab = gen_mod:get_module_proc(Host, config),
-    ets:new(ConfigTab, [named_table]),
-    ets:insert(ConfigTab, {plugins, [<<"mix">>]}),
-    ejabberd_hooks:add(disco_local_items, Host, ?MODULE, disco_items, 100),
-    ejabberd_hooks:add(disco_local_features, Host, ?MODULE, disco_features, 100),
-    ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, disco_identity, 100),
-    ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, disco_items, 100),
-    ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, disco_features, 100),
-    ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, disco_identity, 100),
-    ejabberd_hooks:add(disco_info, Host, ?MODULE, disco_info, 100),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host,
-                                 ?NS_DISCO_ITEMS, mod_disco,
-                                 process_local_iq_items, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host,
-                                 ?NS_DISCO_INFO, mod_disco,
-                                 process_local_iq_info, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
-                                 ?NS_DISCO_ITEMS, mod_disco,
-                                 process_local_iq_items, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
-                                 ?NS_DISCO_INFO, mod_disco,
-                                 process_local_iq_info, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
-                                 ?NS_PUBSUB, mod_pubsub, iq_sm, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
-                                 ?NS_MIX_0, ?MODULE, process_iq, IQDisc),
-    ejabberd_router:register_route(Host, ServerHost),
-    {ok, #state{server_host = ServerHost, host = Host}}.
+    Hosts = gen_mod:get_opt_hosts(ServerHost, Opts, <<"mix.@HOST@">>),
+    IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(ServerHost)),
+    lists:foreach(
+      fun(Host) ->
+             ConfigTab = gen_mod:get_module_proc(Host, config),
+             ets:new(ConfigTab, [named_table]),
+             ets:insert(ConfigTab, {plugins, [<<"mix">>]}),
+             ejabberd_hooks:add(disco_local_items, Host, ?MODULE, disco_items, 100),
+             ejabberd_hooks:add(disco_local_features, Host, ?MODULE, disco_features, 100),
+             ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, disco_identity, 100),
+             ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, disco_items, 100),
+             ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, disco_features, 100),
+             ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, disco_identity, 100),
+             ejabberd_hooks:add(disco_info, Host, ?MODULE, disco_info, 100),
+             gen_iq_handler:add_iq_handler(ejabberd_local, Host,
+                                           ?NS_DISCO_ITEMS, mod_disco,
+                                           process_local_iq_items, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_local, Host,
+                                           ?NS_DISCO_INFO, mod_disco,
+                                           process_local_iq_info, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
+                                           ?NS_DISCO_ITEMS, mod_disco,
+                                           process_local_iq_items, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
+                                           ?NS_DISCO_INFO, mod_disco,
+                                           process_local_iq_info, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
+                                           ?NS_PUBSUB, mod_pubsub, iq_sm, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
+                                           ?NS_MIX_0, ?MODULE, process_iq, IQDisc),
+             ejabberd_router:register_route(Host, ServerHost)
+      end, Hosts),
+    {ok, #state{server_host = ServerHost, hosts = Hosts}}.
 
 handle_call(_Request, _From, State) ->
     Reply = ok,
@@ -180,22 +183,24 @@ handle_info({route, Packet}, State) ->
 handle_info(_Info, State) ->
     {noreply, State}.
 
-terminate(_Reason, #state{host = Host}) ->
-    ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 100),
-    ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 100),
-    ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 100),
-    ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, disco_items, 100),
-    ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, disco_features, 100),
-    ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, disco_identity, 100),
-    ejabberd_hooks:delete(disco_info, Host, ?MODULE, disco_info, 100),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
-    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS),
-    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO),
-    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PUBSUB),
-    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_MIX_0),
-    ejabberd_router:unregister_route(Host),
-    ok.
+terminate(_Reason, #state{hosts = Hosts}) ->
+    lists:foreach(
+      fun(Host) ->
+             ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 100),
+             ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 100),
+             ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 100),
+             ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, disco_items, 100),
+             ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, disco_features, 100),
+             ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, disco_identity, 100),
+             ejabberd_hooks:delete(disco_info, Host, ?MODULE, disco_info, 100),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
+             gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS),
+             gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO),
+             gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PUBSUB),
+             gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_MIX_0),
+             ejabberd_router:unregister_route(Host)
+      end, Hosts).
 
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
@@ -316,4 +321,6 @@ depends(_Host, _Opts) ->
 
 mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
 mod_opt_type(host) -> fun iolist_to_binary/1;
-mod_opt_type(_) -> [host, iqdisc].
+mod_opt_type(hosts) ->
+    fun (L) -> lists:map(fun iolist_to_binary/1, L) end;
+mod_opt_type(_) -> [host, hosts, iqdisc].
index 2d87dd1d545c4e5080602390452975f5390ca91e..db101e4f68b906315e4b0f29e57d96bbb512f779 100644 (file)
@@ -75,7 +75,7 @@
 -include("mod_muc.hrl").
 
 -record(state,
-       {host = <<"">> :: binary(),
+       {hosts = [] :: [binary()],
          server_host = <<"">> :: binary(),
          access = {none, none, none, none} :: {atom(), atom(), atom(), atom()},
          history_size = 20 :: non_neg_integer(),
@@ -151,8 +151,9 @@ room_destroyed(Host, Room, Pid, ServerHost) ->
 %% If Opts = default, the default room options are used.
 %% Else use the passed options as defined in mod_muc_room.
 create_room(Host, Name, From, Nick, Opts) ->
-    Proc = gen_mod:get_module_proc(Host, ?MODULE),
-    gen_server:call(Proc, {create, Name, From, Nick, Opts}).
+    ServerHost = ejabberd_router:host_of_route(Host),
+    Proc = gen_mod:get_module_proc(ServerHost, ?MODULE),
+    gen_server:call(Proc, {create, Name, Host, From, Nick, Opts}).
 
 store_room(ServerHost, Host, Name, Opts) ->
     LServer = jid:nameprep(ServerHost),
@@ -225,22 +226,26 @@ get_online_rooms_by_user(ServerHost, LUser, LServer) ->
 init([Host, Opts]) ->
     process_flag(trap_exit, true),
     IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(Host)),
-    #state{access = Access, host = MyHost,
+    #state{access = Access, hosts = MyHosts,
           history_size = HistorySize, queue_type = QueueType,
           room_shaper = RoomShaper} = State = init_state(Host, Opts),
     Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
     RMod = gen_mod:ram_db_mod(Host, Opts, ?MODULE),
-    Mod:init(Host, [{host, MyHost}|Opts]),
-    RMod:init(Host, [{host, MyHost}|Opts]),
-    register_iq_handlers(MyHost, IQDisc),
-    ejabberd_router:register_route(MyHost, Host),
-    load_permanent_rooms(MyHost, Host, Access, HistorySize, RoomShaper, QueueType),
+    Mod:init(Host, [{hosts, MyHosts}|Opts]),
+    RMod:init(Host, [{hosts, MyHosts}|Opts]),
+    lists:foreach(
+      fun(MyHost) ->
+             register_iq_handlers(MyHost, IQDisc),
+             ejabberd_router:register_route(MyHost, Host),
+             load_permanent_rooms(MyHost, Host, Access, HistorySize,
+                                  RoomShaper, QueueType)
+      end, MyHosts),
     {ok, State}.
 
 handle_call(stop, _From, State) ->
     {stop, normal, ok, State};
-handle_call({create, Room, From, Nick, Opts}, _From,
-           #state{host = Host, server_host = ServerHost,
+handle_call({create, Room, Host, From, Nick, Opts}, _From,
+           #state{server_host = ServerHost,
                   access = Access, default_room_opts = DefOpts,
                   history_size = HistorySize, queue_type = QueueType,
                   room_shaper = RoomShaper} = State) ->
@@ -259,49 +264,56 @@ handle_call({create, Room, From, Nick, Opts}, _From,
     ejabberd_hooks:run(create_room, ServerHost, [ServerHost, Room, Host]),
     {reply, ok, State}.
 
-handle_cast({reload, ServerHost, NewOpts, OldOpts}, #state{host = OldHost}) ->
+handle_cast({reload, ServerHost, NewOpts, OldOpts}, #state{hosts = OldHosts}) ->
     NewIQDisc = gen_mod:get_opt(iqdisc, NewOpts, gen_iq_handler:iqdisc(ServerHost)),
     OldIQDisc = gen_mod:get_opt(iqdisc, OldOpts, gen_iq_handler:iqdisc(ServerHost)),
     NewMod = gen_mod:db_mod(ServerHost, NewOpts, ?MODULE),
     NewRMod = gen_mod:ram_db_mod(ServerHost, NewOpts, ?MODULE),
     OldMod = gen_mod:db_mod(ServerHost, OldOpts, ?MODULE),
     OldRMod = gen_mod:ram_db_mod(ServerHost, OldOpts, ?MODULE),
-    #state{host = NewHost} = NewState = init_state(ServerHost, NewOpts),
+    #state{hosts = NewHosts} = NewState = init_state(ServerHost, NewOpts),
     if NewMod /= OldMod ->
-           NewMod:init(ServerHost, [{host, NewHost}|NewOpts]);
+           NewMod:init(ServerHost, [{hosts, NewHosts}|NewOpts]);
        true ->
            ok
     end,
     if NewRMod /= OldRMod ->
-           NewRMod:init(ServerHost, [{host, NewHost}|NewOpts]);
-       true ->
-           ok
-    end,
-    if (NewIQDisc /= OldIQDisc) or (NewHost /= OldHost) ->
-           register_iq_handlers(NewHost, NewIQDisc);
+           NewRMod:init(ServerHost, [{hosts, NewHosts}|NewOpts]);
        true ->
            ok
     end,
-    if NewHost /= OldHost ->
-           ejabberd_router:register_route(NewHost, ServerHost),
-           ejabberd_router:unregister_route(OldHost),
-           unregister_iq_handlers(OldHost);
+    if (NewIQDisc /= OldIQDisc) ->
+           lists:foreach(
+             fun(NewHost) ->
+                     register_iq_handlers(NewHost, NewIQDisc)
+             end, NewHosts -- (NewHosts -- OldHosts));
        true ->
            ok
     end,
+    lists:foreach(
+      fun(NewHost) ->
+             ejabberd_router:register_route(NewHost, ServerHost),
+             register_iq_handlers(NewHost, NewIQDisc)
+      end, NewHosts -- OldHosts),
+    lists:foreach(
+      fun(OldHost) ->
+             ejabberd_router:unregister_route(OldHost),
+             unregister_iq_handlers(OldHost)
+      end, OldHosts -- NewHosts),
     {noreply, NewState};
 handle_cast(Msg, State) ->
     ?WARNING_MSG("unexpected cast: ~p", [Msg]),
     {noreply, State}.
 
 handle_info({route, Packet},
-           #state{host = Host, server_host = ServerHost,
+           #state{server_host = ServerHost,
                   access = Access, default_room_opts = DefRoomOpts,
                   history_size = HistorySize, queue_type = QueueType,
                   max_rooms_discoitems = MaxRoomsDiscoItems,
                   room_shaper = RoomShaper} = State) ->
     From = xmpp:get_from(Packet),
     To = xmpp:get_to(Packet),
+    Host = To#jid.lserver,
     case catch do_route(Host, ServerHost, Access, HistorySize, RoomShaper,
                        From, To, Packet, DefRoomOpts, MaxRoomsDiscoItems,
                        QueueType) of
@@ -320,9 +332,12 @@ handle_info(Info, State) ->
     ?ERROR_MSG("unexpected info: ~p", [Info]),
     {noreply, State}.
 
-terminate(_Reason, #state{host = MyHost}) ->
-    ejabberd_router:unregister_route(MyHost),
-    unregister_iq_handlers(MyHost).
+terminate(_Reason, #state{hosts = MyHosts}) ->
+    lists:foreach(
+      fun(MyHost) ->
+             ejabberd_router:unregister_route(MyHost),
+             unregister_iq_handlers(MyHost)
+      end, MyHosts).
 
 code_change(_OldVsn, State, _Extra) -> {ok, State}.
 
@@ -330,8 +345,8 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
 %%% Internal functions
 %%--------------------------------------------------------------------
 init_state(Host, Opts) ->
-    MyHost = gen_mod:get_opt_host(Host, Opts,
-                                 <<"conference.@HOST@">>),
+    MyHosts = gen_mod:get_opt_hosts(Host, Opts,
+                                   <<"conference.@HOST@">>),
     Access = gen_mod:get_opt(access, Opts, all),
     AccessCreate = gen_mod:get_opt(access_create, Opts, all),
     AccessAdmin = gen_mod:get_opt(access_admin, Opts, none),
@@ -342,7 +357,7 @@ init_state(Host, Opts) ->
     QueueType = gen_mod:get_opt(queue_type, Opts,
                                ejabberd_config:default_queue_type(Host)),
     RoomShaper = gen_mod:get_opt(room_shaper, Opts, none),
-    #state{host = MyHost,
+    #state{hosts = MyHosts,
           server_host = Host,
           access = {Access, AccessCreate, AccessAdmin, AccessPersistent},
           default_room_opts = DefRoomOpts,
@@ -851,6 +866,8 @@ mod_opt_type(ram_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
 mod_opt_type(history_size) ->
     fun (I) when is_integer(I), I >= 0 -> I end;
 mod_opt_type(host) -> fun iolist_to_binary/1;
+mod_opt_type(hosts) ->
+    fun (L) -> lists:map(fun iolist_to_binary/1, L) end;
 mod_opt_type(max_room_desc) ->
     fun (infinity) -> infinity;
        (I) when is_integer(I), I > 0 -> I
@@ -944,7 +961,7 @@ mod_opt_type({default_room_options, presence_broadcast}) ->
     end;
 mod_opt_type(_) ->
     [access, access_admin, access_create, access_persistent,
-     db_type, ram_db_type, history_size, host,
+     db_type, ram_db_type, history_size, host, hosts,
      max_room_desc, max_room_id, max_room_name,
      max_rooms_discoitems, max_user_conferences, max_users,
      max_users_admin_threshold, max_users_presence,
index 53f31cb9f9a68ecdc07468ef316cb77fd1d4cae5..015c5ec43d67c3ac9693ef878122e2514b427f0c 100644 (file)
@@ -296,7 +296,7 @@ import(_LServer, <<"muc_registered">>,
 %%% gen_server callbacks
 %%%===================================================================
 init([Host, Opts]) ->
-    MyHost = proplists:get_value(host, Opts),
+    MyHosts = proplists:get_value(hosts, Opts),
     case gen_mod:db_mod(Host, Opts, mod_muc) of
        ?MODULE ->
            ejabberd_mnesia:create(?MODULE, muc_room,
@@ -318,7 +318,10 @@ init([Host, Opts]) ->
                                    {type, ordered_set},
                                    {attributes, record_info(fields, muc_online_room)}]),
            catch ets:new(muc_online_users, [bag, named_table, public, {keypos, 2}]),
-           clean_table_from_bad_node(node(), MyHost),
+           lists:foreach(
+             fun(MyHost) ->
+                     clean_table_from_bad_node(node(), MyHost)
+             end, MyHosts),
            mnesia:subscribe(system);
        _ ->
            ok
index aee324960f6704c801ed08f6fcedcada1da51efe..671baef9a105d172296e7b60d9bc0575562f33da 100644 (file)
@@ -112,6 +112,8 @@ depends(_Host, _Opts) ->
 
 mod_opt_type(access) -> fun acl:access_rules_validator/1;
 mod_opt_type(host) -> fun iolist_to_binary/1;
+mod_opt_type(hosts) ->
+    fun(L) -> lists:map(fun iolist_to_binary/1, L) end;
 mod_opt_type(hostname) -> fun iolist_to_binary/1;
 mod_opt_type(ip) ->
     fun (S) ->
@@ -131,7 +133,7 @@ mod_opt_type(ram_db_type) ->
 mod_opt_type(Opt) ->
     case mod_proxy65_stream:listen_opt_type(Opt) of
        Opts when is_list(Opts) ->
-           [access, host, hostname, ip, name, port,
+           [access, host, hosts, hostname, ip, name, port,
             max_connections, ram_db_type] ++ Opts;
        Fun ->
            Fun
index b27f3bc2062ea91f929e595105a69922a56638c2..aaece980af8204c9e935a9acc4c48f23cbb53bc1 100644 (file)
@@ -43,7 +43,7 @@
 
 -define(PROCNAME, ejabberd_mod_proxy65_service).
 
--record(state, {myhost = <<"">> :: binary()}).
+-record(state, {myhosts = [] :: [binary()]}).
 
 %%%------------------------
 %%% gen_server callbacks
@@ -61,24 +61,27 @@ reload(Host, NewOpts, OldOpts) ->
 init([Host, Opts]) ->
     process_flag(trap_exit, true),
     IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(Host)),
-    MyHost = gen_mod:get_opt_host(Host, Opts, <<"proxy.@HOST@">>),
-    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO,
-                                 ?MODULE, process_disco_info, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS,
-                                 ?MODULE, process_disco_items, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_VCARD,
-                                 ?MODULE, process_vcard, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_BYTESTREAMS,
-                                 ?MODULE, process_bytestreams, IQDisc),
-    ejabberd_router:register_route(MyHost, Host),
-    {ok, #state{myhost = MyHost}}.
+    MyHosts = gen_mod:get_opt_hosts(Host, Opts, <<"proxy.@HOST@">>),
+    lists:foreach(
+      fun(MyHost) ->
+             gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO,
+                                           ?MODULE, process_disco_info, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS,
+                                           ?MODULE, process_disco_items, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_VCARD,
+                                           ?MODULE, process_vcard, IQDisc),
+             gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_BYTESTREAMS,
+                                           ?MODULE, process_bytestreams, IQDisc),
+             ejabberd_router:register_route(MyHost, Host)
+      end, MyHosts),
+    {ok, #state{myhosts = MyHosts}}.
 
-terminate(_Reason, #state{myhost = MyHost}) ->
-    ejabberd_router:unregister_route(MyHost),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_BYTESTREAMS).
+terminate(_Reason, #state{myhosts = MyHosts}) ->
+    lists:foreach(
+      fun(MyHost) ->
+             ejabberd_router:unregister_route(MyHost),
+             unregister_handlers(MyHost)
+      end, MyHosts).
 
 handle_info({route, #iq{} = Packet}, State) ->
     ejabberd_router:process_iq(Packet),
@@ -89,33 +92,29 @@ handle_call(_Request, _From, State) ->
     {reply, ok, State}.
 
 handle_cast({reload, ServerHost, NewOpts, OldOpts}, State) ->
-    NewHost = gen_mod:get_opt_host(ServerHost, NewOpts, <<"proxy.@HOST@">>),
-    OldHost = gen_mod:get_opt_host(ServerHost, OldOpts, <<"proxy.@HOST@">>),
+    NewHosts = gen_mod:get_opt_hosts(ServerHost, NewOpts, <<"proxy.@HOST@">>),
+    OldHosts = gen_mod:get_opt_hosts(ServerHost, OldOpts, <<"proxy.@HOST@">>),
     NewIQDisc = gen_mod:get_opt(iqdisc, NewOpts, gen_iq_handler:iqdisc(ServerHost)),
     OldIQDisc = gen_mod:get_opt(iqdisc, OldOpts, gen_iq_handler:iqdisc(ServerHost)),
-    if (NewIQDisc /= OldIQDisc) or (NewHost /= OldHost) ->
-           gen_iq_handler:add_iq_handler(ejabberd_local, NewHost, ?NS_DISCO_INFO,
-                                         ?MODULE, process_disco_info, NewIQDisc),
-           gen_iq_handler:add_iq_handler(ejabberd_local, NewHost, ?NS_DISCO_ITEMS,
-                                         ?MODULE, process_disco_items, NewIQDisc),
-           gen_iq_handler:add_iq_handler(ejabberd_local, NewHost, ?NS_VCARD,
-                                         ?MODULE, process_vcard, NewIQDisc),
-           gen_iq_handler:add_iq_handler(ejabberd_local, NewHost, ?NS_BYTESTREAMS,
-                                         ?MODULE, process_bytestreams, NewIQDisc);
-       true ->
-           ok
-    end,
-    if NewHost /= OldHost ->
-           ejabberd_router:register_route(NewHost, ServerHost),
-           ejabberd_router:unregister_route(OldHost),
-           gen_iq_handler:remove_iq_handler(ejabberd_local, OldHost, ?NS_DISCO_INFO),
-           gen_iq_handler:remove_iq_handler(ejabberd_local, OldHost, ?NS_DISCO_ITEMS),
-           gen_iq_handler:remove_iq_handler(ejabberd_local, OldHost, ?NS_VCARD),
-           gen_iq_handler:remove_iq_handler(ejabberd_local, OldHost, ?NS_BYTESTREAMS);
+    if (NewIQDisc /= OldIQDisc) ->
+           lists:foreach(
+             fun(NewHost) ->
+                     register_handlers(NewHost, NewIQDisc)
+             end, NewHosts -- (NewHosts -- OldHosts));
        true ->
            ok
     end,
-    {noreply, State#state{myhost = NewHost}};
+    lists:foreach(
+      fun(NewHost) ->
+             ejabberd_router:register_route(NewHost, ServerHost),
+             register_handlers(NewHost, NewIQDisc)
+      end, NewHosts -- OldHosts),
+    lists:foreach(
+      fun(OldHost) ->
+             ejabberd_router:unregister_route(OldHost),
+             unregister_handlers(OldHost)
+      end, OldHosts -- NewHosts),
+    {noreply, State#state{myhosts = NewHosts}};
 handle_cast(Msg, State) ->
     ?WARNING_MSG("unexpected cast: ~p", [Msg]),
     {noreply, State}.
@@ -276,3 +275,19 @@ get_my_ip() ->
 
 max_connections(ServerHost) ->
     gen_mod:get_module_opt(ServerHost, mod_proxy65, max_connections, infinity).
+
+register_handlers(Host, IQDisc) ->
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO,
+                                 ?MODULE, process_disco_info, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS,
+                                 ?MODULE, process_disco_items, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD,
+                                 ?MODULE, process_vcard, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_BYTESTREAMS,
+                                 ?MODULE, process_bytestreams, IQDisc).
+
+unregister_handlers(Host) ->
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_BYTESTREAMS).
index d682eb5f39ba73f507106dcf6dfa62a382c2efee..0ae68b24b830f0cc2622da71c89f3cf310a8949f 100644 (file)
 -record(state,
     {
        server_host,
-       host,
+       hosts,
        access,
        pep_mapping             = [],
        ignore_pep_from_offline = true,
 -type(state() ::
     #state{
        server_host             :: binary(),
-       host                    :: mod_pubsub:hostPubsub(),
+       hosts                   :: [mod_pubsub:hostPubsub()],
        access                  :: atom(),
        pep_mapping             :: [{binary(), binary()}],
        ignore_pep_from_offline :: boolean(),
@@ -243,42 +243,63 @@ stop(Host) ->
 init([ServerHost, Opts]) ->
     process_flag(trap_exit, true),
     ?DEBUG("pubsub init ~p ~p", [ServerHost, Opts]),
-    Host = gen_mod:get_opt_host(ServerHost, Opts, <<"pubsub.@HOST@">>),
-    ejabberd_router:register_route(Host, ServerHost),
+    Hosts = gen_mod:get_opt_hosts(ServerHost, Opts, <<"pubsub.@HOST@">>),
     Access = gen_mod:get_opt(access_createnode, Opts, all),
     PepOffline = gen_mod:get_opt(ignore_pep_from_offline, Opts, true),
-    IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(Host)),
+    IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(ServerHost)),
     LastItemCache = gen_mod:get_opt(last_item_cache, Opts, false),
     MaxItemsNode = gen_mod:get_opt(max_items_node, Opts, ?MAXITEMS),
     MaxSubsNode = gen_mod:get_opt(max_subscriptions_node, Opts),
-    case gen_mod:db_type(ServerHost, ?MODULE) of
-       mnesia -> pubsub_index:init(Host, ServerHost, Opts);
-       _ -> ok
-    end,
-    {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
-    DefaultModule = plugin(Host, hd(Plugins)),
-    BaseOptions = DefaultModule:options(),
-    DefaultNodeCfg = filter_node_options(
-                      gen_mod:get_opt(default_node_config, Opts, []),
-                      BaseOptions),
     ejabberd_mnesia:create(?MODULE, pubsub_last_item,
-       [{ram_copies, [node()]},
-           {attributes, record_info(fields, pubsub_last_item)}]),
-    lists:foreach(
-      fun(H) ->
-             T = gen_mod:get_module_proc(H, config),
-             ets:new(T, [set, named_table]),
-             ets:insert(T, {nodetree, NodeTree}),
-             ets:insert(T, {plugins, Plugins}),
-             ets:insert(T, {last_item_cache, LastItemCache}),
-             ets:insert(T, {max_items_node, MaxItemsNode}),
-             ets:insert(T, {max_subscriptions_node, MaxSubsNode}),
-             ets:insert(T, {default_node_config, DefaultNodeCfg}),
-             ets:insert(T, {pep_mapping, PepMapping}),
-             ets:insert(T, {ignore_pep_from_offline, PepOffline}),
-             ets:insert(T, {host, Host}),
-             ets:insert(T, {access, Access})
-      end, [Host, ServerHost]),
+                          [{ram_copies, [node()]},
+                           {attributes, record_info(fields, pubsub_last_item)}]),
+    AllPlugins =
+       lists:flatmap(
+         fun(Host) ->
+                 ejabberd_router:register_route(Host, ServerHost),
+                 case gen_mod:db_type(ServerHost, ?MODULE) of
+                     mnesia -> pubsub_index:init(Host, ServerHost, Opts);
+                     _ -> ok
+                 end,
+                 {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
+                 DefaultModule = plugin(Host, hd(Plugins)),
+                 BaseOptions = DefaultModule:options(),
+                 DefaultNodeCfg = filter_node_options(
+                                    gen_mod:get_opt(default_node_config, Opts, []),
+                                    BaseOptions),
+                 lists:foreach(
+                   fun(H) ->
+                           T = gen_mod:get_module_proc(H, config),
+                           try
+                               ets:new(T, [set, named_table]),
+                               ets:insert(T, {nodetree, NodeTree}),
+                               ets:insert(T, {plugins, Plugins}),
+                               ets:insert(T, {last_item_cache, LastItemCache}),
+                               ets:insert(T, {max_items_node, MaxItemsNode}),
+                               ets:insert(T, {max_subscriptions_node, MaxSubsNode}),
+                               ets:insert(T, {default_node_config, DefaultNodeCfg}),
+                               ets:insert(T, {pep_mapping, PepMapping}),
+                               ets:insert(T, {ignore_pep_from_offline, PepOffline}),
+                               ets:insert(T, {host, Host}),
+                               ets:insert(T, {access, Access})
+                           catch error:badarg when H == ServerHost ->
+                                   ok
+                           end
+                   end, [Host, ServerHost]),
+                 gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO,
+                                               ?MODULE, process_disco_info, IQDisc),
+                 gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS,
+                                               ?MODULE, process_disco_items, IQDisc),
+                 gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_PUBSUB,
+                                               ?MODULE, process_pubsub, IQDisc),
+                 gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_PUBSUB_OWNER,
+                                               ?MODULE, process_pubsub_owner, IQDisc),
+                 gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD,
+                                               ?MODULE, process_vcard, IQDisc),
+                 gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_COMMANDS,
+                                               ?MODULE, process_commands, IQDisc),
+                 Plugins
+         end, Hosts),
     ejabberd_hooks:add(sm_remove_connection_hook, ServerHost,
        ?MODULE, on_user_offline, 75),
     ejabberd_hooks:add(disco_local_identity, ServerHost,
@@ -297,19 +318,7 @@ init([ServerHost, Opts]) ->
        ?MODULE, remove_user, 50),
     ejabberd_hooks:add(c2s_handle_info, ServerHost,
        ?MODULE, c2s_handle_info, 50),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO,
-                                 ?MODULE, process_disco_info, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS,
-                                 ?MODULE, process_disco_items, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_PUBSUB,
-                                 ?MODULE, process_pubsub, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_PUBSUB_OWNER,
-                                 ?MODULE, process_pubsub_owner, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD,
-                                 ?MODULE, process_vcard, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_COMMANDS,
-                                 ?MODULE, process_commands, IQDisc),
-    case lists:member(?PEPNODE, Plugins) of
+    case lists:member(?PEPNODE, AllPlugins) of
        true ->
            ejabberd_hooks:add(caps_add, ServerHost,
                ?MODULE, caps_add, 80),
@@ -328,20 +337,19 @@ init([ServerHost, Opts]) ->
        false ->
            ok
     end,
-    {_, State} = init_send_loop(ServerHost),
+    {_, State} = init_send_loop(ServerHost, Hosts),
     {ok, State}.
 
-init_send_loop(ServerHost) ->
+init_send_loop(ServerHost, Hosts) ->
     NodeTree = config(ServerHost, nodetree),
     Plugins = config(ServerHost, plugins),
     LastItemCache = config(ServerHost, last_item_cache),
     MaxItemsNode = config(ServerHost, max_items_node),
     PepMapping = config(ServerHost, pep_mapping),
     PepOffline = config(ServerHost, ignore_pep_from_offline),
-    Host = config(ServerHost, host),
     Access = config(ServerHost, access),
     DBType = gen_mod:db_type(ServerHost, ?MODULE),
-    State = #state{host = Host, server_host = ServerHost,
+    State = #state{hosts = Hosts, server_host = ServerHost,
            access = Access, pep_mapping = PepMapping,
            ignore_pep_from_offline = PepOffline,
            last_item_cache = LastItemCache,
@@ -419,7 +427,7 @@ get_subscribed(User, Server) ->
 send_loop(State) ->
     receive
        {presence, JID, _Pid} ->
-           Host = State#state.host,
+           Host = State#state.server_host,
            ServerHost = State#state.server_host,
            DBType = State#state.db_type,
            LJID = jid:tolower(JID),
@@ -461,7 +469,7 @@ send_loop(State) ->
            send_loop(State);
        {presence, User, Server, Resources, JID} ->
            spawn(fun() ->
-                       Host = State#state.host,
+                       Host = State#state.server_host,
                        Owner = jid:remove_resource(jid:tolower(JID)),
                        lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = Nidx, options = Options}) ->
                                    case match_option(Options, send_last_published_item, on_sub_and_presence) of
@@ -689,11 +697,7 @@ presence_probe(_From, _To, _Pid) ->
     ok.
 
 presence(ServerHost, Presence) ->
-    {SendLoop, _} = case whereis(gen_mod:get_module_proc(ServerHost, ?LOOPNAME)) of
-       undefined -> init_send_loop(ServerHost);
-       Pid -> {Pid, undefined}
-    end,
-    SendLoop ! Presence,
+    gen_mod:get_module_proc(ServerHost, ?LOOPNAME) ! Presence,
     ok.
 
 %% -------
@@ -859,7 +863,7 @@ handle_info(_Info, State) ->
 %%--------------------------------------------------------------------
 %% @private
 terminate(_Reason,
-           #state{host = Host, server_host = ServerHost, nodetree = TreePlugin, plugins = Plugins}) ->
+           #state{hosts = Hosts, server_host = ServerHost, nodetree = TreePlugin, plugins = Plugins}) ->
     case lists:member(?PEPNODE, Plugins) of
        true ->
            ejabberd_hooks:delete(caps_add, ServerHost,
@@ -897,20 +901,23 @@ terminate(_Reason,
        ?MODULE, remove_user, 50),
     ejabberd_hooks:delete(c2s_handle_info, ServerHost,
        ?MODULE, c2s_handle_info, 50),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PUBSUB),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PUBSUB_OWNER),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_COMMANDS),
     case whereis(gen_mod:get_module_proc(ServerHost, ?LOOPNAME)) of
        undefined ->
            ?ERROR_MSG("~s process is dead, pubsub was broken", [?LOOPNAME]);
        Pid ->
            Pid ! stop
     end,
-    terminate_plugins(Host, ServerHost, Plugins, TreePlugin),
-    ejabberd_router:unregister_route(Host).
+    lists:foreach(
+      fun(Host) ->
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PUBSUB),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PUBSUB_OWNER),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_COMMANDS),
+             terminate_plugins(Host, ServerHost, Plugins, TreePlugin),
+             ejabberd_router:unregister_route(Host)
+      end, Hosts).
 
 %%--------------------------------------------------------------------
 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
@@ -3877,6 +3884,8 @@ export(Server) ->
 mod_opt_type(access_createnode) -> fun acl:access_rules_validator/1;
 mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
 mod_opt_type(host) -> fun iolist_to_binary/1;
+mod_opt_type(hosts) ->
+    fun (L) -> lists:map(fun iolist_to_binary/1, L) end;
 mod_opt_type(ignore_pep_from_offline) ->
     fun (A) when is_boolean(A) -> A end;
 mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
@@ -3895,7 +3904,7 @@ mod_opt_type(pep_mapping) ->
 mod_opt_type(plugins) ->
     fun (A) when is_list(A) -> A end;
 mod_opt_type(_) ->
-    [access_createnode, db_type, host,
+    [access_createnode, db_type, host, hosts,
      ignore_pep_from_offline, iqdisc, last_item_cache,
      max_items_node, nodetree, pep_mapping, plugins,
      max_subscriptions_node, default_node_config].
index 495393f72910c26790e3955a2af4d71bf0ad60cf..67d01a0854dacbcbffbfd57bc10d68df7dda4a41 100644 (file)
@@ -67,7 +67,7 @@
 
 -optional_callbacks([use_cache/1, cache_nodes/1]).
 
--record(state, {host :: binary(), server_host :: binary()}).
+-record(state, {hosts :: [binary()], server_host :: binary()}).
 
 %%====================================================================
 %% gen_mod callbacks
@@ -95,37 +95,40 @@ init([Host, Opts]) ->
                                  ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc),
     ejabberd_hooks:add(disco_sm_features, Host, ?MODULE,
                       get_sm_features, 50),
-    MyHost = gen_mod:get_opt_host(Host, Opts, <<"vjud.@HOST@">>),
+    MyHosts = gen_mod:get_opt_hosts(Host, Opts, <<"vjud.@HOST@">>),
     Search = gen_mod:get_opt(search, Opts, false),
     if Search ->
-           ejabberd_hooks:add(
-             disco_local_items, MyHost, ?MODULE, disco_items, 100),
-           ejabberd_hooks:add(
-             disco_local_features, MyHost, ?MODULE, disco_features, 100),
-           ejabberd_hooks:add(
-             disco_local_identity, MyHost, ?MODULE, disco_identity, 100),
-           gen_iq_handler:add_iq_handler(
-             ejabberd_local, MyHost, ?NS_SEARCH, ?MODULE, process_search, IQDisc),
-           gen_iq_handler:add_iq_handler(
-             ejabberd_local, MyHost, ?NS_VCARD, ?MODULE, process_vcard, IQDisc),
-           gen_iq_handler:add_iq_handler(
-             ejabberd_local, MyHost, ?NS_DISCO_ITEMS, mod_disco,
-             process_local_iq_items, IQDisc),
-           gen_iq_handler:add_iq_handler(
-             ejabberd_local, MyHost, ?NS_DISCO_INFO, mod_disco,
-             process_local_iq_info, IQDisc),
-           case Mod:is_search_supported(Host) of
-               false ->
-                   ?WARNING_MSG("vcard search functionality is "
-                                "not implemented for ~s backend",
-                                [gen_mod:db_type(Host, Opts, ?MODULE)]);
-               true ->
-                   ejabberd_router:register_route(MyHost, Host)
-           end;
+           lists:foreach(
+             fun(MyHost) ->
+                     ejabberd_hooks:add(
+                       disco_local_items, MyHost, ?MODULE, disco_items, 100),
+                     ejabberd_hooks:add(
+                       disco_local_features, MyHost, ?MODULE, disco_features, 100),
+                     ejabberd_hooks:add(
+                       disco_local_identity, MyHost, ?MODULE, disco_identity, 100),
+                     gen_iq_handler:add_iq_handler(
+                       ejabberd_local, MyHost, ?NS_SEARCH, ?MODULE, process_search, IQDisc),
+                     gen_iq_handler:add_iq_handler(
+                       ejabberd_local, MyHost, ?NS_VCARD, ?MODULE, process_vcard, IQDisc),
+                     gen_iq_handler:add_iq_handler(
+                       ejabberd_local, MyHost, ?NS_DISCO_ITEMS, mod_disco,
+                       process_local_iq_items, IQDisc),
+                     gen_iq_handler:add_iq_handler(
+                       ejabberd_local, MyHost, ?NS_DISCO_INFO, mod_disco,
+                       process_local_iq_info, IQDisc),
+                     case Mod:is_search_supported(Host) of
+                         false ->
+                             ?WARNING_MSG("vcard search functionality is "
+                                          "not implemented for ~s backend",
+                                          [gen_mod:db_type(Host, Opts, ?MODULE)]);
+                         true ->
+                             ejabberd_router:register_route(MyHost, Host)
+                     end
+             end, MyHosts);
        true ->
            ok
     end,
-    {ok, #state{host = MyHost, server_host = Host}}.
+    {ok, #state{hosts = MyHosts, server_host = Host}}.
 
 handle_call(_Call, _From, State) ->
     {noreply, State}.
@@ -144,21 +147,24 @@ handle_info(Info, State) ->
     ?WARNING_MSG("unexpected info: ~p", [Info]),
     {noreply, State}.
 
-terminate(_Reason, #state{host = MyHost, server_host = Host}) ->
+terminate(_Reason, #state{hosts = MyHosts, server_host = Host}) ->
     ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50),
     gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
     gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD),
     ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
     Mod = gen_mod:db_mod(Host, ?MODULE),
     Mod:stop(Host),
-    ejabberd_router:unregister_route(MyHost),
-    ejabberd_hooks:delete(disco_local_items, MyHost, ?MODULE, disco_items, 100),
-    ejabberd_hooks:delete(disco_local_features, MyHost, ?MODULE, disco_features, 100),
-    ejabberd_hooks:delete(disco_local_identity, MyHost, ?MODULE, disco_identity, 100),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_SEARCH),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS),
-    gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO).
+    lists:foreach(
+      fun(MyHost) ->
+             ejabberd_router:unregister_route(MyHost),
+             ejabberd_hooks:delete(disco_local_items, MyHost, ?MODULE, disco_items, 100),
+             ejabberd_hooks:delete(disco_local_features, MyHost, ?MODULE, disco_features, 100),
+             ejabberd_hooks:delete(disco_local_identity, MyHost, ?MODULE, disco_identity, 100),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_SEARCH),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS),
+             gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO)
+      end, MyHosts).
 
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
@@ -527,6 +533,8 @@ mod_opt_type(allow_return_all) ->
     fun (B) when is_boolean(B) -> B end;
 mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
 mod_opt_type(host) -> fun iolist_to_binary/1;
+mod_opt_type(hosts) ->
+    fun (L) -> lists:map(fun iolist_to_binary/1, L) end;
 mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
 mod_opt_type(matches) ->
     fun (infinity) -> infinity;
@@ -543,6 +551,6 @@ mod_opt_type(O) when O == cache_life_time; O == cache_size ->
 mod_opt_type(O) when O == use_cache; O == cache_missed ->
     fun (B) when is_boolean(B) -> B end;
 mod_opt_type(_) ->
-    [allow_return_all, db_type, host, iqdisc, matches,
+    [allow_return_all, db_type, host, hosts, iqdisc, matches,
      search, search_all_hosts, cache_life_time, cache_size,
      use_cache, cache_missed].
index f1f07646848765642461c1fb9888338883bce1df..38c4747e60cc070ed1754b98cee6f9383faf6f47 100644 (file)
@@ -47,7 +47,7 @@
 
 -record(state,
        {serverhost = <<"">>        :: binary(),
-         myhost = <<"">>            :: binary(),
+         myhosts = []               :: [binary()],
          eldap_id = <<"">>          :: binary(),
          search = false             :: boolean(),
          servers = []               :: [binary()],
@@ -351,8 +351,7 @@ default_search_reported() ->
      {<<"Organization Unit">>, <<"ORGUNIT">>}].
 
 parse_options(Host, Opts) ->
-    MyHost = gen_mod:get_opt_host(Host, Opts,
-                                 <<"vjud.@HOST@">>),
+    MyHosts = gen_mod:get_opt_hosts(Host, Opts, <<"vjud.@HOST@">>),
     Search = gen_mod:get_opt(search, Opts, false),
     Matches = gen_mod:get_opt(matches, Opts, 30),
     Eldap_ID = misc:atom_to_binary(gen_mod:get_module_proc(Host, ?PROCNAME)),
@@ -394,7 +393,7 @@ parse_options(Host, Opts) ->
                                                    end,
                                                    SearchReported)
                                        ++ UIDAttrs),
-    #state{serverhost = Host, myhost = MyHost,
+    #state{serverhost = Host, myhosts = MyHosts,
           eldap_id = Eldap_ID, search = Search,
           servers = Cfg#eldap_config.servers,
           backups = Cfg#eldap_config.backups,