From 3fec782494042ab1e1a015524e01cd63e6757c7e Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 8 Aug 2017 17:46:26 +0300 Subject: [PATCH] Introduce 'hosts' option 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 --- src/gen_mod.erl | 17 ++++- src/mod_echo.erl | 41 ++++++----- src/mod_http_upload.erl | 20 +++-- src/mod_irc.erl | 62 ++++++++++------ src/mod_mix.erl | 103 ++++++++++++++------------ src/mod_muc.erl | 81 +++++++++++++-------- src/mod_muc_mnesia.erl | 7 +- src/mod_proxy65.erl | 4 +- src/mod_proxy65_service.erl | 95 ++++++++++++++---------- src/mod_pubsub.erl | 141 +++++++++++++++++++----------------- src/mod_vcard.erl | 82 +++++++++++---------- src/mod_vcard_ldap.erl | 7 +- 12 files changed, 380 insertions(+), 280 deletions(-) diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 5bfa3b4d4..e17197dfb 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -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 diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 861b1a0ef..79dd59962 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -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} diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index c8cd300f4..6d981e9ec 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -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()}. diff --git a/src/mod_irc.erl b/src/mod_irc.erl index fc85668e8..04687ea67 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -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) -> diff --git a/src/mod_mix.erl b/src/mod_mix.erl index 4763447f3..90507665b 100644 --- a/src/mod_mix.erl +++ b/src/mod_mix.erl @@ -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]. diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 2d87dd1d5..db101e4f6 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -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]); + NewRMod:init(ServerHost, [{hosts, NewHosts}|NewOpts]); true -> ok end, - if (NewIQDisc /= OldIQDisc) or (NewHost /= OldHost) -> - register_iq_handlers(NewHost, NewIQDisc); - 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, diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl index 53f31cb9f..015c5ec43 100644 --- a/src/mod_muc_mnesia.erl +++ b/src/mod_muc_mnesia.erl @@ -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 diff --git a/src/mod_proxy65.erl b/src/mod_proxy65.erl index aee324960..671baef9a 100644 --- a/src/mod_proxy65.erl +++ b/src/mod_proxy65.erl @@ -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 diff --git a/src/mod_proxy65_service.erl b/src/mod_proxy65_service.erl index b27f3bc20..aaece980a 100644 --- a/src/mod_proxy65_service.erl +++ b/src/mod_proxy65_service.erl @@ -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); + if (NewIQDisc /= OldIQDisc) -> + lists:foreach( + fun(NewHost) -> + register_handlers(NewHost, NewIQDisc) + end, NewHosts -- (NewHosts -- OldHosts)); 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); - 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). diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index d682eb5f3..0ae68b24b 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -189,7 +189,7 @@ -record(state, { server_host, - host, + hosts, access, pep_mapping = [], ignore_pep_from_offline = true, @@ -205,7 +205,7 @@ -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]. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 495393f72..67d01a085 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -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]. diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index f1f076468..38c4747e6 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -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,