aboutsummaryrefslogtreecommitdiff
path: root/src/mod_pubsub/mod_pubsub.erl
diff options
context:
space:
mode:
authorChristophe Romain <christophe.romain@process-one.net>2009-05-11 17:16:25 +0000
committerChristophe Romain <christophe.romain@process-one.net>2009-05-11 17:16:25 +0000
commit20088d8a9274e07a153c35514c42ba9f5129ad83 (patch)
tree36d077cb9cae29eea9ad93ace62b1d57db40e147 /src/mod_pubsub/mod_pubsub.erl
parent* src/ejabberd_debug.erl: Handled fprof based profiling (EJABS-872). (diff)
Prevent race condition when calling get_caps while note_caps has not been handled yet (EJAB-934)
SVN Revision: 2071
Diffstat (limited to 'src/mod_pubsub/mod_pubsub.erl')
-rw-r--r--src/mod_pubsub/mod_pubsub.erl98
1 files changed, 51 insertions, 47 deletions
diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl
index 9dbd0fead..fa021cc77 100644
--- a/src/mod_pubsub/mod_pubsub.erl
+++ b/src/mod_pubsub/mod_pubsub.erl
@@ -177,7 +177,7 @@ init([ServerHost, Opts]) ->
ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
- ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50),
+ ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80),
ejabberd_hooks:add(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50),
@@ -447,54 +447,58 @@ send_loop(State) ->
send_loop(State);
{presence, User, Server, Resources, JID} ->
%% get resources caps and check if processing is needed
- {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) ->
- case mod_caps:get_caps({User, Server, Resource}) of
- nothing -> {R, L};
- Caps -> {true, [{Resource, Caps} | L]}
- end
- end, {false, []}, Resources),
- case HasCaps of
- true ->
- Host = State#state.host,
- ServerHost = State#state.server_host,
- Owner = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
- lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) ->
- case get_option(Options, send_last_published_item) of
- on_sub_and_presence ->
- lists:foreach(fun({Resource, Caps}) ->
- CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of
- Features when is_list(Features) -> lists:member(Node ++ "+notify", Features);
- _ -> false
- end,
- case CapsNotify of
- true ->
- LJID = {User, Server, Resource},
- Subscribed = case get_option(Options, access_model) of
- open -> true;
- presence -> true;
- whitelist -> false; % subscribers are added manually
- authorize -> false; % likewise
- roster ->
- Grps = get_option(Options, roster_groups_allowed, []),
- {OU, OS, _} = Owner,
- element(2, get_roster_info(OU, OS, LJID, Grps))
+ %% get_caps may be blocked few seconds, get_caps as well
+ %% so we spawn the whole process not to block other queries
+ spawn(fun() ->
+ {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) ->
+ case mod_caps:get_caps({User, Server, Resource}) of
+ nothing -> {R, L};
+ Caps -> {true, [{Resource, Caps} | L]}
+ end
+ end, {false, []}, Resources),
+ case HasCaps of
+ true ->
+ Host = State#state.host,
+ ServerHost = State#state.server_host,
+ Owner = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
+ lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) ->
+ case get_option(Options, send_last_published_item) of
+ on_sub_and_presence ->
+ lists:foreach(fun({Resource, Caps}) ->
+ CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of
+ Features when is_list(Features) -> lists:member(Node ++ "+notify", Features);
+ _ -> false
end,
- if Subscribed ->
- send_items(Owner, Node, NodeId, Type, LJID, last);
+ case CapsNotify of
true ->
+ LJID = {User, Server, Resource},
+ Subscribed = case get_option(Options, access_model) of
+ open -> true;
+ presence -> true;
+ whitelist -> false; % subscribers are added manually
+ authorize -> false; % likewise
+ roster ->
+ Grps = get_option(Options, roster_groups_allowed, []),
+ {OU, OS, _} = Owner,
+ element(2, get_roster_info(OU, OS, LJID, Grps))
+ end,
+ if Subscribed ->
+ send_items(Owner, Node, NodeId, Type, LJID, last);
+ true ->
+ ok
+ end;
+ false ->
ok
- end;
- false ->
- ok
- end
- end, ResourcesCaps);
- _ ->
- ok
- end
- end, tree_action(Host, get_nodes, [Owner, JID]));
- false ->
- ok
- end,
+ end
+ end, ResourcesCaps);
+ _ ->
+ ok
+ end
+ end, tree_action(Host, get_nodes, [Owner, JID]));
+ false ->
+ ok
+ end
+ end),
send_loop(State);
stop ->
ok
@@ -786,7 +790,7 @@ terminate(_Reason, #state{host = Host,
ejabberd_hooks:delete(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
- ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50),
+ ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 80),
ejabberd_hooks:delete(roster_in_subscription, ServerHost, ?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription, ServerHost, ?MODULE, out_subscription, 50),
ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50),