%% API
-export([start/0, start_link/0]).
--export([route/1, process_iq/1,
+-export([route/1,
get_features/1,
- register_iq_handler/4,
- unregister_iq_handler/2,
bounce_resource_packet/1,
host_up/1, host_down/1]).
-record(state, {}).
--define(IQTABLE, local_iqtable).
-
%%====================================================================
%% API
%%====================================================================
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
[]).
--spec process_iq(iq()) -> any().
-process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet)
- when T == get; T == set ->
- XMLNS = xmpp:get_ns(El),
- Host = To#jid.lserver,
- case ets:lookup(?IQTABLE, {Host, XMLNS}) of
- [{_, Module, Function}] ->
- gen_iq_handler:handle(Host, Module, Function, Packet);
- [] ->
- Txt = <<"No module is handling this query">>,
- Err = xmpp:err_service_unavailable(Txt, Lang),
- ejabberd_router:route_error(Packet, Err)
- end;
-process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet)
- when T == get; T == set ->
- Txt = case SubEls of
- [] -> <<"No child elements found">>;
- _ -> <<"Too many child elements">>
- end,
- Err = xmpp:err_bad_request(Txt, Lang),
- ejabberd_router:route_error(Packet, Err);
-process_iq(#iq{type = T}) when T == result; T == error ->
- ok.
-
-spec route(stanza()) -> any().
route(Packet) ->
try do_route(Packet)
route_iq(IQ, Fun, Timeout) ->
ejabberd_router:route_iq(IQ, Fun, undefined, Timeout).
--spec register_iq_handler(binary(), binary(), module(), function()) -> ok.
-register_iq_handler(Host, XMLNS, Module, Fun) ->
- gen_server:cast(?MODULE,
- {register_iq_handler, Host, XMLNS, Module, Fun}).
-
--spec unregister_iq_handler(binary(), binary()) -> ok.
-unregister_iq_handler(Host, XMLNS) ->
- gen_server:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}).
-
-spec bounce_resource_packet(stanza()) -> ok | stop.
bounce_resource_packet(#presence{to = #jid{lresource = <<"">>}}) ->
ok;
-spec get_features(binary()) -> [binary()].
get_features(Host) ->
- get_features(ets:next(?IQTABLE, {Host, <<"">>}), Host, []).
-
-get_features({Host, XMLNS}, Host, XMLNSs) ->
- get_features(ets:next(?IQTABLE, {Host, XMLNS}), Host, [XMLNS|XMLNSs]);
-get_features(_, _, XMLNSs) ->
- XMLNSs.
+ gen_iq_handler:get_features(?MODULE, Host).
%%====================================================================
%% gen_server callbacks
lists:foreach(fun host_up/1, ?MYHOSTS),
ejabberd_hooks:add(host_up, ?MODULE, host_up, 10),
ejabberd_hooks:add(host_down, ?MODULE, host_down, 100),
- catch ets:new(?IQTABLE, [named_table, public, ordered_set,
- {read_concurrency, true}]),
+ gen_iq_handler:start(?MODULE),
update_table(),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
Reply = ok, {reply, Reply, State}.
-handle_cast({register_iq_handler, Host, XMLNS, Module, Function},
- State) ->
- ets:insert(?IQTABLE,
- {{Host, XMLNS}, Module, Function}),
- {noreply, State};
-handle_cast({unregister_iq_handler, Host, XMLNS},
- State) ->
- ets:delete(?IQTABLE, {Host, XMLNS}),
- {noreply, State};
handle_cast(_Msg, State) -> {noreply, State}.
handle_info({route, Packet}, State) ->
if To#jid.luser /= <<"">> ->
ejabberd_sm:route(Packet);
is_record(Packet, iq), To#jid.lresource == <<"">> ->
- process_iq(Packet);
+ gen_iq_handler:handle(?MODULE, Packet);
Type == result; Type == error ->
ok;
true ->
end.
-spec process_iq(iq()) -> any().
-process_iq(#iq{to = To} = IQ) ->
- if To#jid.luser == <<"">> ->
- ejabberd_local:process_iq(IQ);
- true ->
- ejabberd_sm:process_iq(IQ)
- end.
+process_iq(IQ) ->
+ gen_iq_handler:handle(IQ).
-spec config_reloaded() -> ok.
config_reloaded() ->
stop/0,
route/1,
route/2,
- process_iq/1,
open_session/5,
open_session/6,
close_session/4,
get_vh_session_list/1,
get_vh_session_number/1,
get_vh_by_backend/1,
- register_iq_handler/4,
- unregister_iq_handler/2,
force_update_presence/1,
connected_users/0,
connected_users_number/0,
Mod = get_sm_backend(LServer),
length(online(get_sessions(Mod, LServer))).
--spec register_iq_handler(binary(), binary(), atom(), atom()) -> ok.
-
-register_iq_handler(Host, XMLNS, Module, Fun) ->
- ?GEN_SERVER:cast(?MODULE,
- {register_iq_handler, Host, XMLNS, Module, Fun}).
-
--spec unregister_iq_handler(binary(), binary()) -> ok.
-
-unregister_iq_handler(Host, XMLNS) ->
- ?GEN_SERVER:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}).
-
%% Why the hell do we have so many similar kicks?
c2s_handle_info(#{lang := Lang} = State, replaced) ->
State1 = State#{replaced => true},
init_cache(),
lists:foreach(fun(Mod) -> Mod:init() end, get_sm_backends()),
clean_cache(),
- ets:new(sm_iqtable, [named_table, public, {read_concurrency, true}]),
+ gen_iq_handler:start(?MODULE),
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:add(host_down, ?MODULE, host_down, 60),
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
handle_call(_Request, _From, State) ->
Reply = ok, {reply, Reply, State}.
-handle_cast({register_iq_handler, Host, XMLNS, Module, Function},
- State) ->
- ets:insert(sm_iqtable,
- {{Host, XMLNS}, Module, Function}),
- {noreply, State};
-handle_cast({unregister_iq_handler, Host, XMLNS},
- State) ->
- ets:delete(sm_iqtable, {Host, XMLNS}),
- {noreply, State};
handle_cast(_Msg, State) -> {noreply, State}.
handle_info({route, Packet}, State) ->
end;
do_route(#iq{to = #jid{lresource = <<"">>}} = Packet) ->
?DEBUG("processing IQ to bare JID:~n~s", [xmpp:pp(Packet)]),
- process_iq(Packet);
+ gen_iq_handler:handle(?MODULE, Packet);
do_route(Packet) ->
?DEBUG("processing packet to full JID:~n~s", [xmpp:pp(Packet)]),
To = xmpp:get_to(Packet),
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--spec process_iq(iq()) -> any().
-process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet)
- when T == get; T == set ->
- XMLNS = xmpp:get_ns(El),
- Host = To#jid.lserver,
- case ets:lookup(sm_iqtable, {Host, XMLNS}) of
- [{_, Module, Function}] ->
- gen_iq_handler:handle(Host, Module, Function, Packet);
- [] ->
- Txt = <<"No module is handling this query">>,
- Err = xmpp:err_service_unavailable(Txt, Lang),
- ejabberd_router:route_error(Packet, Err)
- end;
-process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet)
- when T == get; T == set ->
- Txt = case SubEls of
- [] -> <<"No child elements found">>;
- _ -> <<"Too many child elements">>
- end,
- Err = xmpp:err_bad_request(Txt, Lang),
- ejabberd_router:route_error(Packet, Err);
-process_iq(#iq{}) ->
- ok.
-
-spec force_update_presence({binary(), binary()}) -> ok.
force_update_presence({LUser, LServer}) ->
-behaviour(ejabberd_config).
%% API
--export([add_iq_handler/5, remove_iq_handler/3, handle/4,
- process_iq/4, check_type/1, transform_module_options/1,
- opt_type/1]).
+-export([add_iq_handler/5, remove_iq_handler/3, handle/1, handle/2,
+ check_type/1, transform_module_options/1,
+ opt_type/1, start/1, get_features/2]).
%% Deprecated functions
-export([add_iq_handler/6, handle/5, iqdisc/1]).
-deprecated([{add_iq_handler, 6}, {handle, 5}, {iqdisc, 1}]).
%%====================================================================
%% API
%%====================================================================
--spec add_iq_handler(module(), binary(), binary(), module(), atom()) -> ok.
+-spec start(component()) -> ok.
+start(Component) ->
+ catch ets:new(Component, [named_table, public, ordered_set,
+ {read_concurrency, true},
+ {heir, erlang:group_leader(), none}]),
+ ok.
+
+-spec add_iq_handler(component(), binary(), binary(), module(), atom()) -> ok.
add_iq_handler(Component, Host, NS, Module, Function) ->
- Component:register_iq_handler(Host, NS, Module, Function).
+ ets:insert(Component, {{Host, NS}, Module, Function}),
+ ok.
-spec remove_iq_handler(component(), binary(), binary()) -> ok.
remove_iq_handler(Component, Host, NS) ->
- Component:unregister_iq_handler(Host, NS).
-
--spec handle(binary(), atom(), atom(), iq()) -> any().
-handle(Host, Module, Function, IQ) ->
- process_iq(Host, Module, Function, IQ).
+ ets:delete(Component, {Host, NS}),
+ ok.
+
+-spec handle(iq()) -> ok.
+handle(#iq{to = To} = IQ) ->
+ Component = case To#jid.luser of
+ <<"">> -> ejabberd_local;
+ _ -> ejabberd_sm
+ end,
+ handle(Component, IQ).
+
+-spec handle(component(), iq()) -> ok.
+handle(Component,
+ #iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet)
+ when T == get; T == set ->
+ XMLNS = xmpp:get_ns(El),
+ Host = To#jid.lserver,
+ case ets:lookup(Component, {Host, XMLNS}) of
+ [{_, Module, Function}] ->
+ process_iq(Host, Module, Function, Packet);
+ [] ->
+ Txt = <<"No module is handling this query">>,
+ Err = xmpp:err_service_unavailable(Txt, Lang),
+ ejabberd_router:route_error(Packet, Err)
+ end;
+handle(_, #iq{type = T, lang = Lang, sub_els = SubEls} = Packet)
+ when T == get; T == set ->
+ Txt = case SubEls of
+ [] -> <<"No child elements found">>;
+ _ -> <<"Too many child elements">>
+ end,
+ Err = xmpp:err_bad_request(Txt, Lang),
+ ejabberd_router:route_error(Packet, Err);
+handle(_, #iq{type = T}) when T == result; T == error ->
+ ok.
+
+-spec get_features(component(), binary()) -> [binary()].
+get_features(Component, Host) ->
+ get_features(Component, ets:next(Component, {Host, <<"">>}), Host, []).
+
+get_features(Component, {Host, XMLNS}, Host, XMLNSs) ->
+ get_features(Component,
+ ets:next(Component, {Host, XMLNS}), Host, [XMLNS|XMLNSs]);
+get_features(_, _, _, XMLNSs) ->
+ XMLNSs.
-spec process_iq(binary(), atom(), atom(), iq()) -> any().
process_iq(_Host, Module, Function, IQ) ->
-spec handle(binary(), atom(), atom(), any(), iq()) -> any().
handle(Host, Module, Function, _Opts, IQ) ->
- handle(Host, Module, Function, IQ).
+ process_iq(Host, Module, Function, IQ).
do_route1(_Host, _ServerHost, _Access, _HistorySize, _RoomShaper,
_From, #jid{luser = <<"">>, lresource = <<"">>} = _To,
#iq{} = IQ, _DefRoomOpts, _QueueType) ->
- ejabberd_local:process_iq(IQ);
+ ejabberd_router:process_iq(IQ);
do_route1(Host, ServerHost, Access, _HistorySize, _RoomShaper,
From, #jid{luser = <<"">>, lresource = <<"">>} = _To,
#message{lang = Lang, body = Body, type = Type} = Packet, _, _) ->