25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-08 15:42:29 +01:00

Implement MUC rooms load distribution (TECH-1351).

Configuration example:
{domain_balancing, "conference.domain.com", broadcast}.
NOTE: both ejabberd_router and mod_muc use the option.
This commit is contained in:
Evgeniy Khramtsov 2011-09-14 17:43:07 +10:00
parent d6e81ac06b
commit c9a712a16a
2 changed files with 163 additions and 77 deletions

View File

@ -115,7 +115,7 @@ room_destroyed(Host, Room, Pid, ServerHost) ->
create_room(Host, Name, From, Nick, Opts) -> create_room(Host, Name, From, Nick, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
RoomHost = gen_mod:get_module_opt_host(Host, ?MODULE, "conference.@HOST@"), RoomHost = gen_mod:get_module_opt_host(Host, ?MODULE, "conference.@HOST@"),
Node = ejabberd_cluster:get_node({Name, RoomHost}), Node = get_node({Name, RoomHost}),
gen_server:call({Proc, Node}, {create, Name, From, Nick, Opts}). gen_server:call({Proc, Node}, {create, Name, From, Nick, Opts}).
store_room(Host, Name, Opts) -> store_room(Host, Name, Opts) ->
@ -177,7 +177,7 @@ migrate(_Node, _UpOrDown, After) ->
['$$']}]), ['$$']}]),
lists:foreach( lists:foreach(
fun([NameHost, Pid]) -> fun([NameHost, Pid]) ->
case ejabberd_cluster:get_node(NameHost) of case get_node(NameHost) of
Node when Node /= node() -> Node when Node /= node() ->
mod_muc_room:migrate(Pid, Node, random:uniform(After)); mod_muc_room:migrate(Pid, Node, random:uniform(After));
_ -> _ ->
@ -198,7 +198,7 @@ copy_rooms('$end_of_table') ->
copy_rooms(Key) -> copy_rooms(Key) ->
case mnesia:dirty_read(muc_online_room, Key) of case mnesia:dirty_read(muc_online_room, Key) of
[#muc_online_room{name_host = NameHost} = Room] -> [#muc_online_room{name_host = NameHost} = Room] ->
case ejabberd_cluster:get_node_new(NameHost) of case get_node_new(NameHost) of
Node when node() /= Node -> Node when node() /= Node ->
rpc:cast(Node, mnesia, dirty_write, [Room]); rpc:cast(Node, mnesia, dirty_write, [Room]);
_ -> _ ->
@ -315,7 +315,7 @@ handle_info({route, From, To, Packet},
history_size = HistorySize, history_size = HistorySize,
room_shaper = RoomShaper} = State) -> room_shaper = RoomShaper} = State) ->
{U, S, _} = jlib:jid_tolower(To), {U, S, _} = jlib:jid_tolower(To),
case ejabberd_cluster:get_node({U, S}) of case get_node({U, S}) of
Node when Node == node() -> Node when Node == node() ->
case catch do_route(Host, ServerHost, Access, HistorySize, case catch do_route(Host, ServerHost, Access, HistorySize,
RoomShaper, From, To, Packet, DefRoomOpts) of RoomShaper, From, To, Packet, DefRoomOpts) of
@ -335,7 +335,7 @@ handle_info({room_destroyed, RoomHost, Pid}, State) ->
pid = Pid}) pid = Pid})
end, end,
mnesia:async_dirty(F), mnesia:async_dirty(F),
case ejabberd_cluster:get_node_new(RoomHost) of case get_node_new(RoomHost) of
Node when Node /= node() -> Node when Node /= node() ->
rpc:cast(Node, mnesia, dirty_delete_object, rpc:cast(Node, mnesia, dirty_delete_object,
[#muc_online_room{name_host = RoomHost, [#muc_online_room{name_host = RoomHost,
@ -603,19 +603,26 @@ load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) ->
lists:foreach( lists:foreach(
fun(R) -> fun(R) ->
{Room, Host} = R#muc_room.name_host, {Room, Host} = R#muc_room.name_host,
case ejabberd_cluster:get_node({Room, Host}) of case get_node({Room, Host}) of
Node when Node == node() -> Node when Node == node() ->
case mnesia:dirty_read(muc_online_room, {Room, Host}) of case mnesia:dirty_read(muc_online_room, {Room, Host}) of
[] -> [] ->
{ok, Pid} = mod_muc_room:start( case get_room_state_if_broadcasted(
Host, {Room, Host}) of
ServerHost, {ok, RoomState} ->
Access, mod_muc_room:start(
Room, normal_state, RoomState);
HistorySize, error ->
RoomShaper, {ok, Pid} = mod_muc_room:start(
R#muc_room.opts), Host,
register_room(Host, Room, Pid); ServerHost,
Access,
Room,
HistorySize,
RoomShaper,
R#muc_room.opts),
register_room(Host, Room, Pid)
end;
_ -> _ ->
ok ok
end; end;
@ -628,18 +635,24 @@ load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) ->
start_new_room(Host, ServerHost, Access, Room, start_new_room(Host, ServerHost, Access, Room,
HistorySize, RoomShaper, From, HistorySize, RoomShaper, From,
Nick, DefRoomOpts) -> Nick, DefRoomOpts) ->
case mnesia:dirty_read(muc_room, {Room, Host}) of case get_room_state_if_broadcasted({Room, Host}) of
[] -> {ok, RoomState} ->
?DEBUG("MUC: open new room '~s'~n", [Room]), ?DEBUG("MUC: restore room '~s' from other node~n", [Room]),
mod_muc_room:start(Host, ServerHost, Access, mod_muc_room:start(normal_state, RoomState);
Room, HistorySize, error ->
RoomShaper, From, case mnesia:dirty_read(muc_room, {Room, Host}) of
Nick, DefRoomOpts); [] ->
[#muc_room{opts = Opts}|_] -> ?DEBUG("MUC: open new room '~s'~n", [Room]),
?DEBUG("MUC: restore room '~s'~n", [Room]), mod_muc_room:start(Host, ServerHost, Access,
mod_muc_room:start(Host, ServerHost, Access, Room, HistorySize,
Room, HistorySize, RoomShaper, From,
RoomShaper, Opts) Nick, DefRoomOpts);
[#muc_room{opts = Opts}|_] ->
?DEBUG("MUC: restore room '~s'~n", [Room]),
mod_muc_room:start(Host, ServerHost, Access,
Room, HistorySize,
RoomShaper, Opts)
end
end. end.
register_room(Host, Room, Pid) -> register_room(Host, Room, Pid) ->
@ -648,7 +661,7 @@ register_room(Host, Room, Pid) ->
pid = Pid}) pid = Pid})
end, end,
mnesia:async_dirty(F), mnesia:async_dirty(F),
case ejabberd_cluster:get_node_new({Room, Host}) of case get_node_new({Room, Host}) of
Node when Node /= node() -> Node when Node /= node() ->
%% New node has just been added. But we may miss MUC records %% New node has just been added. But we may miss MUC records
%% copy procedure, so we copy the MUC record manually just %% copy procedure, so we copy the MUC record manually just
@ -656,7 +669,7 @@ register_room(Host, Room, Pid) ->
rpc:cast(Node, mnesia, dirty_write, rpc:cast(Node, mnesia, dirty_write,
[#muc_online_room{name_host = {Room, Host}, [#muc_online_room{name_host = {Room, Host},
pid = Pid}]), pid = Pid}]),
case ejabberd_cluster:get_node({Room, Host}) of case get_node({Room, Host}) of
Node when node() /= Node -> Node when node() /= Node ->
%% Migration to new node has completed, and seems like %% Migration to new node has completed, and seems like
%% we missed it, so we migrate the MUC room pid manually. %% we missed it, so we migrate the MUC room pid manually.
@ -934,7 +947,7 @@ get_vh_rooms_all_nodes(Host) ->
_ -> _ ->
Acc Acc
end end
end, [], ejabberd_cluster:get_nodes()), end, [], get_nodes(Host)),
lists:ukeysort(#muc_online_room.name_host, Rooms). lists:ukeysort(#muc_online_room.name_host, Rooms).
get_vh_rooms(Host) -> get_vh_rooms(Host) ->
@ -1038,3 +1051,67 @@ update_muc_registered_table(Host) ->
?INFO_MSG("Recreating muc_registered table", []), ?INFO_MSG("Recreating muc_registered table", []),
mnesia:transform_table(muc_registered, ignore, Fields) mnesia:transform_table(muc_registered, ignore, Fields)
end. end.
is_broadcasted(RoomHost) ->
case ejabberd_config:get_local_option({domain_balancing, RoomHost}) of
broadcast ->
true;
_ ->
false
end.
get_node({_, RoomHost} = Key) ->
case is_broadcasted(RoomHost) of
true ->
node();
false ->
ejabberd_cluster:get_node(Key)
end;
get_node(RoomHost) ->
get_node({"", RoomHost}).
get_node_new({_, RoomHost} = Key) ->
case is_broadcasted(RoomHost) of
true ->
node();
false ->
ejabberd_cluster:get_node_new(Key)
end;
get_node_new(RoomHost) ->
get_node_new({"", RoomHost}).
get_nodes(RoomHost) ->
case is_broadcasted(RoomHost) of
true ->
[node()];
false ->
ejabberd_cluster:get_nodes()
end.
get_room_state_if_broadcasted({Room, Host}) ->
case is_broadcasted(Host) of
true ->
lists:foldl(
fun(_, {ok, StateData}) ->
{ok, StateData};
(Node, _) when Node /= node() ->
case catch rpc:call(
Node, mnesia, dirty_read,
[muc_online_room, {Room, Host}], 5000) of
[#muc_online_room{pid = Pid}] ->
case catch gen_fsm:sync_send_all_state_event(
Pid, get_state, 5000) of
{ok, StateData} ->
{ok, StateData};
_ ->
error
end;
_ ->
error
end;
(_, Acc) ->
Acc
end, error, ejabberd_cluster:get_nodes());
false ->
error
end.

View File

@ -187,7 +187,7 @@ normal_state({route, From, "",
ErrText = "Traffic rate limit is exceeded", ErrText = "Traffic rate limit is exceeded",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)), Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)),
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
From, Err), From, Err),
{next_state, normal_state, StateData}; {next_state, normal_state, StateData};
@ -268,7 +268,7 @@ normal_state({route, From, "",
ErrText = "It is not allowed to send private messages to the conference", ErrText = "It is not allowed to send private messages to the conference",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)),
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
From, Err), From, Err),
{next_state, normal_state, StateData}; {next_state, normal_state, StateData};
@ -277,7 +277,7 @@ normal_state({route, From, "",
{error, Error} -> {error, Error} ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, Error), Packet, Error),
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
From, Err), From, Err),
{next_state, normal_state, StateData}; {next_state, normal_state, StateData};
@ -313,7 +313,7 @@ normal_state({route, From, "",
ErrText = "Improper message type", ErrText = "Improper message type",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)),
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
From, Err), From, Err),
{next_state, normal_state, StateData} {next_state, normal_state, StateData}
@ -364,7 +364,7 @@ normal_state({route, From, "",
sub_el = [SubEl, Error]}, sub_el = [SubEl, Error]},
StateData} StateData}
end, end,
ejabberd_router:route(StateData#state.jid, route_stanza(StateData#state.jid,
From, From,
jlib:iq_to_xml(IQRes)), jlib:iq_to_xml(IQRes)),
case NewStateData of case NewStateData of
@ -378,7 +378,7 @@ normal_state({route, From, "",
_ -> _ ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), Packet, ?ERR_FEATURE_NOT_IMPLEMENTED),
ejabberd_router:route(StateData#state.jid, From, Err), route_stanza(StateData#state.jid, From, Err),
{next_state, normal_state, StateData} {next_state, normal_state, StateData}
end; end;
@ -437,7 +437,7 @@ normal_state({route, From, ToNick,
"messages of type \"groupchat\"", "messages of type \"groupchat\"",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_BAD_REQUEST(Lang, ErrText)), Packet, ?ERRT_BAD_REQUEST(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
ToNick), ToNick),
@ -455,7 +455,7 @@ normal_state({route, From, ToNick,
ErrText = "Recipient is not in the conference room", ErrText = "Recipient is not in the conference room",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)), Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
ToNick), ToNick),
@ -465,13 +465,13 @@ normal_state({route, From, ToNick,
?DICT:find(jlib:jid_tolower(From), ?DICT:find(jlib:jid_tolower(From),
StateData#state.users), StateData#state.users),
FromNickJID = jlib:jid_replace_resource(StateData#state.jid, FromNick), FromNickJID = jlib:jid_replace_resource(StateData#state.jid, FromNick),
[ejabberd_router:route(FromNickJID, ToJID, Packet) || ToJID <- ToJIDs] [route_stanza(FromNickJID, ToJID, Packet) || ToJID <- ToJIDs]
end; end;
true -> true ->
ErrText = "It is not allowed to send private messages", ErrText = "It is not allowed to send private messages",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), Packet, ?ERRT_FORBIDDEN(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
ToNick), ToNick),
@ -482,7 +482,7 @@ normal_state({route, From, ToNick,
ErrText = "Only occupants are allowed to send messages to the conference", ErrText = "Only occupants are allowed to send messages to the conference",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
ToNick), ToNick),
@ -491,7 +491,7 @@ normal_state({route, From, ToNick,
ErrText = "It is not allowed to send private messages", ErrText = "It is not allowed to send private messages",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), Packet, ?ERRT_FORBIDDEN(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
ToNick), ToNick),
@ -517,7 +517,7 @@ normal_state({route, From, ToNick,
ErrText = "Recipient is not in the conference room", ErrText = "Recipient is not in the conference room",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)), Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, ToNick), StateData#state.jid, ToNick),
From, Err) From, Err)
@ -528,7 +528,7 @@ normal_state({route, From, ToNick,
StateData#state.users), StateData#state.users),
{ToJID2, Packet2} = handle_iq_vcard(FromFull, ToJID, {ToJID2, Packet2} = handle_iq_vcard(FromFull, ToJID,
StanzaId, NewId,Packet), StanzaId, NewId,Packet),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, FromNick), jlib:jid_replace_resource(StateData#state.jid, FromNick),
ToJID2, Packet2) ToJID2, Packet2)
end; end;
@ -540,7 +540,7 @@ normal_state({route, From, ToNick,
ErrText = "Only occupants are allowed to send queries to the conference", ErrText = "Only occupants are allowed to send queries to the conference",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, ToNick), jlib:jid_replace_resource(StateData#state.jid, ToNick),
From, Err) From, Err)
end; end;
@ -552,7 +552,7 @@ normal_state({route, From, ToNick,
ErrText = "Queries to the conference members are not allowed in this room", ErrText = "Queries to the conference members are not allowed in this room",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_ALLOWED(Lang, ErrText)), Packet, ?ERRT_NOT_ALLOWED(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, ToNick), jlib:jid_replace_resource(StateData#state.jid, ToNick),
From, Err) From, Err)
end end
@ -576,7 +576,7 @@ handle_event({service_message, Msg}, _StateName, StateData) ->
[{xmlelement, "body", [], [{xmlcdata, Msg}]}]}, [{xmlelement, "body", [], [{xmlcdata, Msg}]}]},
lists:foreach( lists:foreach(
fun({_LJID, Info}) -> fun({_LJID, Info}) ->
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
Info#user.jid, Info#user.jid,
MessagePkt) MessagePkt)
@ -718,7 +718,7 @@ handle_info({captcha_failed, From}, normal_state, StateData) ->
Robots = ?DICT:erase(From, StateData#state.robots), Robots = ?DICT:erase(From, StateData#state.robots),
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERR_NOT_AUTHORIZED), Packet, ?ERR_NOT_AUTHORIZED),
ejabberd_router:route( % TODO: s/Nick/""/ route_stanza( % TODO: s/Nick/""/
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, Nick), StateData#state.jid, Nick),
From, Err), From, Err),
@ -769,7 +769,7 @@ terminate(Reason, _StateName, StateData) ->
Nick = Info#user.nick, Nick = Info#user.nick,
case Reason of case Reason of
shutdown -> shutdown ->
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
Info#user.jid, Info#user.jid,
Packet); Packet);
@ -830,7 +830,7 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
true -> true ->
lists:foreach( lists:foreach(
fun({_LJID, Info}) -> fun({_LJID, Info}) ->
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
FromNick), FromNick),
@ -858,7 +858,7 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
"Only moderators " "Only moderators "
"are allowed to change the subject in this room") "are allowed to change the subject in this room")
end, end,
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
From, From,
jlib:make_error_reply(Packet, Err)), jlib:make_error_reply(Packet, Err)),
@ -868,7 +868,7 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
ErrText = "Visitors are not allowed to send messages to all occupants", ErrText = "Visitors are not allowed to send messages to all occupants",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), Packet, ?ERRT_FORBIDDEN(Lang, ErrText)),
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
From, Err), From, Err),
{next_state, normal_state, StateData} {next_state, normal_state, StateData}
@ -877,7 +877,7 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
ErrText = "Only occupants are allowed to send messages to the conference", ErrText = "Only occupants are allowed to send messages to the conference",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)),
ejabberd_router:route(StateData#state.jid, From, Err), route_stanza(StateData#state.jid, From, Err),
{next_state, normal_state, StateData} {next_state, normal_state, StateData}
end. end.
@ -961,7 +961,7 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet,
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, Packet,
?ERRT_NOT_ALLOWED(Lang, ErrText)), ?ERRT_NOT_ALLOWED(Lang, ErrText)),
ejabberd_router:route( route_stanza(
% TODO: s/Nick/""/ % TODO: s/Nick/""/
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
@ -974,7 +974,7 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet,
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, Packet,
?ERRT_CONFLICT(Lang, ErrText)), ?ERRT_CONFLICT(Lang, ErrText)),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
Nick), % TODO: s/Nick/""/ Nick), % TODO: s/Nick/""/
@ -985,7 +985,7 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet,
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, Packet,
?ERRT_CONFLICT(Lang, ErrText)), ?ERRT_CONFLICT(Lang, ErrText)),
ejabberd_router:route( route_stanza(
% TODO: s/Nick/""/ % TODO: s/Nick/""/
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, StateData#state.jid,
@ -1680,7 +1680,7 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, Packet,
?ERR_SERVICE_UNAVAILABLE), ?ERR_SERVICE_UNAVAILABLE),
ejabberd_router:route( % TODO: s/Nick/""/ route_stanza( % TODO: s/Nick/""/
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
From, Err), From, Err),
StateData; StateData;
@ -1695,14 +1695,14 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
ErrText = "Membership is required to enter this room", ErrText = "Membership is required to enter this room",
?ERRT_REGISTRATION_REQUIRED(Lang, ErrText) ?ERRT_REGISTRATION_REQUIRED(Lang, ErrText)
end), end),
ejabberd_router:route( % TODO: s/Nick/""/ route_stanza( % TODO: s/Nick/""/
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
From, Err), From, Err),
StateData; StateData;
{_, true, _, _} -> {_, true, _, _} ->
ErrText = "That nickname is already in use by another occupant", ErrText = "That nickname is already in use by another occupant",
Err = jlib:make_error_reply(Packet, ?ERRT_CONFLICT(Lang, ErrText)), Err = jlib:make_error_reply(Packet, ?ERRT_CONFLICT(Lang, ErrText)),
ejabberd_router:route( route_stanza(
% TODO: s/Nick/""/ % TODO: s/Nick/""/
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
From, Err), From, Err),
@ -1710,7 +1710,7 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
{_, _, false, _} -> {_, _, false, _} ->
ErrText = "That nickname is registered by another person", ErrText = "That nickname is registered by another person",
Err = jlib:make_error_reply(Packet, ?ERRT_CONFLICT(Lang, ErrText)), Err = jlib:make_error_reply(Packet, ?ERRT_CONFLICT(Lang, ErrText)),
ejabberd_router:route( route_stanza(
% TODO: s/Nick/""/ % TODO: s/Nick/""/
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
From, Err), From, Err),
@ -1731,7 +1731,7 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
"This room is not anonymous")}]}, "This room is not anonymous")}]},
{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], {xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
[{xmlelement, "status", [{"code", "100"}], []}]}]}, [{xmlelement, "status", [{"code", "100"}], []}]}]},
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
From, WPacket); From, WPacket);
true -> true ->
@ -1757,7 +1757,7 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
ErrText = "A password is required to enter this room", ErrText = "A password is required to enter this room",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_AUTHORIZED(Lang, ErrText)), Packet, ?ERRT_NOT_AUTHORIZED(Lang, ErrText)),
ejabberd_router:route( % TODO: s/Nick/""/ route_stanza( % TODO: s/Nick/""/
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, Nick), StateData#state.jid, Nick),
From, Err), From, Err),
@ -1773,13 +1773,13 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls}, MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls},
Robots = ?DICT:store(From, Robots = ?DICT:store(From,
{Nick, Packet}, StateData#state.robots), {Nick, Packet}, StateData#state.robots),
ejabberd_router:route(RoomJID, From, MsgPkt), route_stanza(RoomJID, From, MsgPkt),
StateData#state{robots = Robots}; StateData#state{robots = Robots};
{error, limit} -> {error, limit} ->
ErrText = "Too many CAPTCHA requests", ErrText = "Too many CAPTCHA requests",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)), Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)),
ejabberd_router:route( % TODO: s/Nick/""/ route_stanza( % TODO: s/Nick/""/
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, Nick), StateData#state.jid, Nick),
From, Err), From, Err),
@ -1788,7 +1788,7 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
ErrText = "Unable to generate a captcha", ErrText = "Unable to generate a captcha",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)), Packet, ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)),
ejabberd_router:route( % TODO: s/Nick/""/ route_stanza( % TODO: s/Nick/""/
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, Nick), StateData#state.jid, Nick),
From, Err), From, Err),
@ -1798,7 +1798,7 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
ErrText = "Incorrect password", ErrText = "Incorrect password",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_AUTHORIZED(Lang, ErrText)), Packet, ?ERRT_NOT_AUTHORIZED(Lang, ErrText)),
ejabberd_router:route( % TODO: s/Nick/""/ route_stanza( % TODO: s/Nick/""/
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, Nick), StateData#state.jid, Nick),
From, Err), From, Err),
@ -2074,7 +2074,7 @@ send_new_presence(NJID, Reason, StateData) ->
Presence, Presence,
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
[{xmlelement, "item", ItemAttrs, ItemEls} | Status3]}]), [{xmlelement, "item", ItemAttrs, ItemEls} | Status3]}]),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
Info#user.jid, Info#user.jid,
Packet) Packet)
@ -2116,7 +2116,7 @@ send_existing_presences(ToJID, StateData) ->
Presence, Presence,
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
[{xmlelement, "item", ItemAttrs, []}]}]), [{xmlelement, "item", ItemAttrs, []}]}]),
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource( jlib:jid_replace_resource(
StateData#state.jid, FromNick), StateData#state.jid, FromNick),
RealToJID, RealToJID,
@ -2214,7 +2214,7 @@ send_nick_changing(JID, OldNick, StateData,
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
[{xmlelement, "item", ItemAttrs2, []}]}]), [{xmlelement, "item", ItemAttrs2, []}]}]),
if SendOldUnavailable -> if SendOldUnavailable ->
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, OldNick), jlib:jid_replace_resource(StateData#state.jid, OldNick),
Info#user.jid, Info#user.jid,
Packet1); Packet1);
@ -2222,7 +2222,7 @@ send_nick_changing(JID, OldNick, StateData,
ok ok
end, end,
if SendNewAvailable -> if SendNewAvailable ->
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
Info#user.jid, Info#user.jid,
Packet2); Packet2);
@ -2294,7 +2294,7 @@ add_message_to_history(FromNick, FromJID, Packet, StateData) ->
send_history(JID, Shift, StateData) -> send_history(JID, Shift, StateData) ->
lists:foldl( lists:foldl(
fun({Nick, Packet, HaveSubject, _TimeStamp, _Size}, B) -> fun({Nick, Packet, HaveSubject, _TimeStamp, _Size}, B) ->
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
JID, JID,
Packet), Packet),
@ -2316,7 +2316,7 @@ send_subject(JID, Lang, StateData) ->
translate:translate(Lang, translate:translate(Lang,
" has set the subject to: ") ++ " has set the subject to: ") ++
Subject}]}]}, Subject}]}]},
ejabberd_router:route( route_stanza(
StateData#state.jid, StateData#state.jid,
JID, JID,
Packet) Packet)
@ -2903,7 +2903,7 @@ send_kickban_presence1(UJID, Reason, Code, Affiliation, StateData) ->
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
[{xmlelement, "item", ItemAttrs, ItemEls}, [{xmlelement, "item", ItemAttrs, ItemEls},
{xmlelement, "status", [{"code", Code}], []}]}]}, {xmlelement, "status", [{"code", Code}], []}]}]},
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
Info#user.jid, Info#user.jid,
Packet) Packet)
@ -3527,7 +3527,7 @@ destroy_room(DEl, StateData) ->
Packet = {xmlelement, "presence", [{"type", "unavailable"}], Packet = {xmlelement, "presence", [{"type", "unavailable"}],
[{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}],
[{xmlelement, "item", ItemAttrs, []}, DEl]}]}, [{xmlelement, "item", ItemAttrs, []}, DEl]}]},
ejabberd_router:route( route_stanza(
jlib:jid_replace_resource(StateData#state.jid, Nick), jlib:jid_replace_resource(StateData#state.jid, Nick),
Info#user.jid, Info#user.jid,
Packet) Packet)
@ -3769,7 +3769,7 @@ check_invitation(From, Els, Lang, StateData) ->
""})}], ""})}],
[{xmlcdata, Reason}]}, [{xmlcdata, Reason}]},
Body]}, Body]},
ejabberd_router:route(StateData#state.jid, JID, Msg), route_stanza(StateData#state.jid, JID, Msg),
JID JID
end. end.
@ -3807,7 +3807,7 @@ send_decline_invitation({Packet, XEl, DEl, ToJID}, RoomJID, FromJID) ->
DEl2 = {xmlelement, "decline", DAttrs3, DEls}, DEl2 = {xmlelement, "decline", DAttrs3, DEls},
XEl2 = replace_subelement(XEl, DEl2), XEl2 = replace_subelement(XEl, DEl2),
Packet2 = replace_subelement(Packet, XEl2), Packet2 = replace_subelement(Packet, XEl2),
ejabberd_router:route(RoomJID, ToJID, Packet2). route_stanza(RoomJID, ToJID, Packet2).
%% Given an element and a new subelement, %% Given an element and a new subelement,
%% replace the instance of the subelement in element with the new subelement. %% replace the instance of the subelement in element with the new subelement.
@ -3819,7 +3819,7 @@ replace_subelement({xmlelement, Name, Attrs, SubEls}, NewSubEl) ->
send_error_only_occupants(Packet, Lang, RoomJID, From) -> send_error_only_occupants(Packet, Lang, RoomJID, From) ->
ErrText = "Only occupants are allowed to send messages to the conference", ErrText = "Only occupants are allowed to send messages to the conference",
Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)),
ejabberd_router:route(RoomJID, From, Err). route_stanza(RoomJID, From, Err).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -3877,3 +3877,12 @@ tab_count_user(JID) ->
element_size(El) -> element_size(El) ->
size(xml:element_to_binary(El)). size(xml:element_to_binary(El)).
route_stanza(From, To, El) ->
#jid{luser = LUser, lserver = LServer} = To,
case ejabberd_cluster:get_node({LUser, LServer}) of
Node when Node == node() ->
ejabberd_router:route(From, To, El);
_ ->
ok
end.