aboutsummaryrefslogtreecommitdiff
path: root/src/gen_iq_handler.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/gen_iq_handler.erl')
-rw-r--r--src/gen_iq_handler.erl240
1 files changed, 104 insertions, 136 deletions
diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl
index c2b4252c9..c18ae1918 100644
--- a/src/gen_iq_handler.erl
+++ b/src/gen_iq_handler.erl
@@ -5,7 +5,7 @@
%%% Created : 22 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
-%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2019 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,156 +27,124 @@
-author('alexey@process-one.net').
--behaviour(gen_server).
-
%% API
--export([start_link/3, add_iq_handler/6,
- remove_iq_handler/3, stop_iq_handler/3, handle/7,
- process_iq/6, check_type/1, transform_module_options/1]).
-
-%% gen_server callbacks
--export([init/1, handle_call/3, handle_cast/2,
- handle_info/2, terminate/2, code_change/3]).
+-export([add_iq_handler/5, remove_iq_handler/3, handle/1, handle/2,
+ 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}]).
--include("ejabberd.hrl").
-include("logger.hrl").
--include("jlib.hrl").
-
--record(state, {host, module, function}).
+-include("xmpp.hrl").
+-include("translate.hrl").
+-include("ejabberd_stacktrace.hrl").
-type component() :: ejabberd_sm | ejabberd_local.
--type type() :: no_queue | one_queue | pos_integer() | parallel.
--type opts() :: no_queue | {one_queue, pid()} | {queues, [pid()]} | parallel.
%%====================================================================
%% API
%%====================================================================
-%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
-%% Description: Starts the server
-%%--------------------------------------------------------------------
-start_link(Host, Module, Function) ->
- gen_server:start_link(?MODULE, [Host, Module, Function],
- []).
-
-add_iq_handler(Component, Host, NS, Module, Function,
- Type) ->
- case Type of
- no_queue ->
- Component:register_iq_handler(Host, NS, Module,
- Function, no_queue);
- one_queue ->
- {ok, Pid} = supervisor:start_child(ejabberd_iq_sup,
- [Host, Module, Function]),
- Component:register_iq_handler(Host, NS, Module,
- Function, {one_queue, Pid});
- N when is_integer(N) ->
- Pids = lists:map(fun (_) ->
- {ok, Pid} =
- supervisor:start_child(ejabberd_iq_sup,
- [Host, Module,
- Function]),
- Pid
- end,
- lists:seq(1, N)),
- Component:register_iq_handler(Host, NS, Module,
- Function, {queues, Pids});
- parallel ->
- Component:register_iq_handler(Host, NS, Module,
- Function, parallel)
- end.
-
--spec remove_iq_handler(component(), binary(), binary()) -> any().
-
+-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) ->
+ 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 stop_iq_handler(atom(), atom(), [pid()]) -> any().
-
-stop_iq_handler(_Module, _Function, Opts) ->
- case Opts of
- {one_queue, Pid} -> gen_server:call(Pid, stop);
- {queues, Pids} ->
- lists:foreach(fun (Pid) ->
- catch gen_server:call(Pid, stop)
- end,
- Pids);
- _ -> ok
- end.
-
--spec handle(binary(), atom(), atom(), opts(), jid(), jid(), iq()) -> any().
-
-handle(Host, Module, Function, Opts, From, To, IQ) ->
- case Opts of
- no_queue ->
- process_iq(Host, Module, Function, From, To, IQ);
- {one_queue, Pid} ->
- Pid ! {process_iq, From, To, IQ};
- {queues, Pids} ->
- Pid = lists:nth(erlang:phash(p1_time_compat:unique_integer(),
- length(Pids)), Pids),
- Pid ! {process_iq, From, To, IQ};
- parallel ->
- spawn(?MODULE, process_iq,
- [Host, Module, Function, From, To, IQ]);
- _ -> todo
+ 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 = ?T("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
+ [] -> ?T("No child elements found");
+ _ -> ?T("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()) -> ok.
+process_iq(_Host, Module, Function, IQ) ->
+ try process_iq(Module, Function, IQ) of
+ #iq{} = ResIQ ->
+ ejabberd_router:route(ResIQ);
+ ignore ->
+ ok
+ catch ?EX_RULE(Class, Reason, St) ->
+ StackTrace = ?EX_STACK(St),
+ ?ERROR_MSG("Failed to process iq:~n~ts~n** ~ts",
+ [xmpp:pp(IQ),
+ misc:format_exception(2, Class, Reason, StackTrace)]),
+ Txt = ?T("Module failed to handle the query"),
+ Err = xmpp:err_internal_server_error(Txt, IQ#iq.lang),
+ ejabberd_router:route_error(IQ, Err)
end.
--spec process_iq(binary(), atom(), atom(), jid(), jid(), iq()) -> any().
-
-process_iq(_Host, Module, Function, From, To, IQ) ->
- case catch Module:Function(From, To, IQ) of
- {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
- ResIQ ->
- if ResIQ /= ignore ->
- ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ));
- true -> ok
- end
+-spec process_iq(module(), atom(), iq()) -> ignore | iq().
+process_iq(Module, Function, #iq{lang = Lang, sub_els = [El]} = IQ) ->
+ try
+ Pkt = case erlang:function_exported(Module, decode_iq_subel, 1) of
+ true -> Module:decode_iq_subel(El);
+ false -> xmpp:decode(El)
+ end,
+ Module:Function(IQ#iq{sub_els = [Pkt]})
+ catch error:{xmpp_codec, Why} ->
+ Txt = xmpp:io_format_error(Why),
+ xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang))
end.
--spec check_type(type()) -> type().
-
-check_type(no_queue) -> no_queue;
-check_type(one_queue) -> one_queue;
-check_type(N) when is_integer(N), N>0 -> N;
-check_type(parallel) -> parallel.
-
--spec transform_module_options([{atom(), any()}]) -> [{atom(), any()}].
-
-transform_module_options(Opts) ->
- lists:map(
- fun({iqdisc, {queues, N}}) ->
- {iqdisc, N};
- (Opt) ->
- Opt
- end, Opts).
+-spec iqdisc(binary() | global) -> no_queue.
+iqdisc(_Host) ->
+ no_queue.
%%====================================================================
-%% gen_server callbacks
+%% Deprecated API
%%====================================================================
+-spec add_iq_handler(module(), binary(), binary(), module(), atom(), any()) -> ok.
+add_iq_handler(Component, Host, NS, Module, Function, _Type) ->
+ add_iq_handler(Component, Host, NS, Module, Function).
-init([Host, Module, Function]) ->
- {ok,
- #state{host = Host, module = Module,
- function = Function}}.
-
-handle_call(stop, _From, State) ->
- Reply = ok, {stop, normal, Reply, State}.
-
-handle_cast(_Msg, State) -> {noreply, State}.
-
-handle_info({process_iq, From, To, IQ},
- #state{host = Host, module = Module,
- function = Function} =
- State) ->
- process_iq(Host, Module, Function, From, To, IQ),
- {noreply, State};
-handle_info(_Info, State) -> {noreply, State}.
-
-terminate(_Reason, _State) -> ok.
-
-code_change(_OldVsn, State, _Extra) -> {ok, State}.
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
+-spec handle(binary(), atom(), atom(), any(), iq()) -> any().
+handle(Host, Module, Function, _Opts, IQ) ->
+ process_iq(Host, Module, Function, IQ).