./ct_report/coverage/ejabberd_router.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : ejabberd_router.erl
3 %%% Author : Alexey Shchepin <alexey@process-one.net>
4 %%% Purpose : Main router
5 %%% Created : 27 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2011 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%----------------------------------------------------------------------
25
26 -module(ejabberd_router).
27 -author('alexey@process-one.net').
28
29 -behaviour(gen_server).
30 %% API
31 -export([route/3,
32 route/4,
33 route_error/4,
34 route_error_reply/4]).
35
36 -export([start_link/0]).
37
38 %% gen_server callbacks
39 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
40
41 -ignore_xref([route_error/4, start_link/0]).
42
43 -include("mongoose.hrl").
44 -include("jlib.hrl").
45
46 -record(state, {}).
47
48 %%====================================================================
49 %% API
50 %%====================================================================
51
52 -spec start_link() -> 'ignore' | {'error', _} | {'ok', pid()}.
53 start_link() ->
54 101 gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
55
56 %% @doc The main routing function. It puts the message through a chain
57 %% of filtering/routing modules, as defined in config 'routing_modules'
58 %% setting (default is hardcoded in default_routing_modules function
59 %% of this module). Each of those modules should use xmpp_router behaviour
60 %% and implement two functions:
61 %% filter/3 - should return either 'drop' atom or its args
62 %% route/3, which should either:
63 %% - deliver the message locally by calling mongoose_local_delivery:do_route/5
64 %% and return 'done'
65 %% - deliver the message it its own way and return 'done'
66 %% - return its args
67 %% - return a tuple of {From, To, Packet} which might be modified
68 %% For both functions, returning a 'drop' or 'done' atom terminates the procedure,
69 %% while returning a tuple means 'proceed' and the tuple is passed to
70 %% the next module in sequence.
71 -spec route(From :: jid:jid(),
72 To :: jid:jid(),
73 Packet :: mongoose_acc:t()|exml:element()) -> mongoose_acc:t().
74 route(From, To, #xmlel{} = Packet) ->
75 % ?LOG_ERROR("Deprecated - it should be Acc: ~p", [Packet]),
76 2793 Acc = mongoose_acc:new(#{ location => ?LOCATION,
77 lserver => From#jid.lserver,
78 element => Packet,
79 from_jid => From,
80 to_jid => To }),
81 % (called by broadcasting)
82 2793 route(From, To, Acc);
83 route(From, To, Acc) ->
84 6151 ?LOG_DEBUG(#{what => route, acc => Acc}),
85 6151 El = mongoose_acc:element(Acc),
86 6151 RoutingModules = mongoose_router:routing_modules_list(),
87 6151 NewAcc = route(From, To, Acc, El, RoutingModules),
88 6151 ?LOG_DEBUG(#{what => routing_result,
89 routing_result => mongoose_acc:get(router, result, {drop, undefined}, NewAcc),
90 6151 routing_modules => RoutingModules, acc => Acc}),
91 6151 NewAcc.
92
93 -spec route(From :: jid:jid(),
94 To :: jid:jid(),
95 Acc :: mongoose_acc:t(),
96 El :: exml:element() | {error, term()}) -> mongoose_acc:t().
97 route(_From, _To, Acc, {error, Reason} = Err) ->
98
:-(
?LOG_INFO(#{what => cannot_route_stanza, acc => Acc, reason => Reason}),
99
:-(
mongoose_acc:append(router, result, Err, Acc);
100 route(From, To, Acc, El) ->
101 17330 Acc1 = mongoose_acc:update_stanza(#{ from_jid => From,
102 to_jid => To,
103 element => El }, Acc),
104 17330 ?LOG_DEBUG(#{what => route, acc => Acc1}),
105 17330 RoutingModules = mongoose_router:routing_modules_list(),
106 17330 NewAcc = route(From, To, Acc1, El, RoutingModules),
107 17330 ?LOG_DEBUG(#{what => routing_result,
108 routing_result => mongoose_acc:get(router, result, {drop, undefined}, NewAcc),
109 17330 routing_modules => RoutingModules, acc => Acc}),
110 17330 NewAcc.
111
112 %% Route the error packet only if the originating packet is not an error itself.
113 %% RFC3920 9.3.1
114 -spec route_error(From :: jid:jid(),
115 To :: jid:jid(),
116 Acc :: mongoose_acc:t(),
117 ErrPacket :: exml:element()) -> mongoose_acc:t().
118 route_error(From, To, Acc, ErrPacket) ->
119
:-(
case mongoose_acc:stanza_type(Acc) of
120 <<"error">> ->
121
:-(
Acc;
122 _ ->
123
:-(
route(From, To, Acc, ErrPacket)
124 end.
125
126 -spec route_error_reply(jid:jid(), jid:jid(), mongoose_acc:t(), exml:element()) ->
127 mongoose_acc:t().
128 route_error_reply(From, To, Acc, Error) ->
129
:-(
{Acc1, ErrorReply} = jlib:make_error_reply(Acc, Error),
130
:-(
route_error(From, To, Acc1, ErrorReply).
131
132 %%====================================================================
133 %% gen_server callbacks
134 %%====================================================================
135
136 init([]) ->
137 101 mongoose_metrics:ensure_metric(global, routingErrors, spiral),
138 101 mongoose_component:start(),
139 101 {ok, #state{}}.
140
141 handle_call(_Request, _From, State) ->
142
:-(
Reply = ok,
143
:-(
{reply, Reply, State}.
144
145 handle_cast(_Msg, State) ->
146
:-(
{noreply, State}.
147
148 handle_info(_Info, State) ->
149
:-(
{noreply, State}.
150
151 terminate(_Reason, _State) ->
152
:-(
mongoose_component:stop(),
153
:-(
ok.
154
155 code_change(_OldVsn, State, _Extra) ->
156
:-(
{ok, State}.
157
158 %%--------------------------------------------------------------------
159 %%% Internal functions
160 %%--------------------------------------------------------------------
161
162 -spec route(From :: jid:jid(),
163 To :: jid:jid(),
164 Acc :: mongoose_acc:t(),
165 Packet :: exml:element(),
166 [xmpp_router:t()]) -> mongoose_acc:t().
167 route(_From, _To, Acc, _Packet, []) ->
168
:-(
?LOG_ERROR(#{what => no_more_routing_modules, acc => Acc}),
169
:-(
mongoose_metrics:update(global, routingErrors, 1),
170
:-(
mongoose_acc:append(router, result, {error, out_of_modules}, Acc);
171 route(OrigFrom, OrigTo, Acc0, OrigPacket, [M|Tail]) ->
172 47457 try xmpp_router:call_filter(M, OrigFrom, OrigTo, Acc0, OrigPacket) of
173 drop ->
174 388 mongoose_acc:append(router, result, {drop, M}, Acc0);
175 {OrigFrom, OrigTo, Acc1, OrigPacketFiltered} ->
176 47069 try xmpp_router:call_route(M, OrigFrom, OrigTo, Acc1, OrigPacketFiltered) of
177 {done, Acc2} ->
178 23090 mongoose_acc:append(router, result, {done, M}, Acc2);
179 {From, To, NAcc1, Packet} ->
180 23976 route(From, To, NAcc1, Packet, Tail)
181 catch Class:Reason:Stacktrace ->
182 3 ?LOG_WARNING(#{what => routing_failed,
183 router_module => M, acc => Acc1,
184
:-(
class => Class, reason => Reason, stacktrace => Stacktrace}),
185 3 mongoose_acc:append(router, result, {error, {M, Reason}}, Acc1)
186 end
187 catch Class:Reason:Stacktrace ->
188
:-(
?LOG_WARNING(#{what => route_filter_failed,
189 text => <<"Error when filtering packet in router">>,
190 router_module => M, acc => Acc0,
191
:-(
class => Class, reason => Reason, stacktrace => Stacktrace}),
192
:-(
mongoose_acc:append(router, result, {error, {M, Reason}}, Acc0)
193 end.
Line Hits Source