-behaviour(gen_mod).
%% API
--export([start/2, stop/1]).
+-export([start/2, stop/1, reload/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2,
-export([get_user_roster/2, c2s_session_opened/1,
get_jid_info/4, process_item/2, in_subscription/6,
- out_subscription/4, mod_opt_type/1, opt_type/1, depends/2]).
+ out_subscription/4, mod_opt_type/1, opt_type/1, depends/2,
+ transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("eldap.hrl").
-define(SETS, gb_sets).
--define(CACHE_SIZE, 1000).
--define(USER_CACHE_VALIDITY, 300). %% in seconds
--define(GROUP_CACHE_VALIDITY, 300).
+-define(USER_CACHE, shared_roster_ldap_user_cache).
+-define(GROUP_CACHE, shared_roster_ldap_group_cache).
-define(LDAP_SEARCH_TIMEOUT, 5). %% Timeout for LDAP search queries in seconds
-define(INVALID_SETTING_MSG, "~s is not properly set! ~s will not function.").
ufilter = <<"">> :: binary(),
rfilter = <<"">> :: binary(),
gfilter = <<"">> :: binary(),
- auth_check = true :: boolean(),
- user_cache_size = ?CACHE_SIZE :: non_neg_integer(),
- group_cache_size = ?CACHE_SIZE :: non_neg_integer(),
- user_cache_validity = ?USER_CACHE_VALIDITY :: non_neg_integer(),
- group_cache_validity = ?GROUP_CACHE_VALIDITY :: non_neg_integer()}).
+ auth_check = true :: boolean()}).
-record(group_info, {desc, members}).
stop(Host) ->
gen_mod:stop_child(?MODULE, Host).
+reload(Host, NewOpts, _OldOpts) ->
+ case init_cache(Host, NewOpts) of
+ true ->
+ ets_cache:setopts(?USER_CACHE, cache_opts(Host, NewOpts)),
+ ets_cache:setopts(?GROUP_CACHE, cache_opts(Host, NewOpts));
+ false ->
+ ok
+ end,
+ Proc = gen_mod:get_module_proc(Host, ?MODULE),
+ gen_server:cast(Proc, {set_state, parse_options(Host, NewOpts)}).
+
depends(_Host, _Opts) ->
[{mod_roster, hard}].
init([Host, Opts]) ->
process_flag(trap_exit, true),
State = parse_options(Host, Opts),
- cache_tab:new(shared_roster_ldap_user,
- [{max_size, State#state.user_cache_size}, {lru, false},
- {life_time, State#state.user_cache_validity}]),
- cache_tab:new(shared_roster_ldap_group,
- [{max_size, State#state.group_cache_size}, {lru, false},
- {life_time, State#state.group_cache_validity}]),
+ init_cache(Host, Opts),
ejabberd_hooks:add(roster_get, Host, ?MODULE,
get_user_roster, 70),
ejabberd_hooks:add(roster_in_subscription, Host,
handle_call(_Request, _From, State) ->
{reply, {error, badarg}, State}.
+handle_cast({set_state, NewState}, _State) ->
+ {noreply, NewState};
handle_cast(_Msg, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
get_group_users(Host, Group) ->
{ok, State} = eldap_utils:get_state(Host, ?MODULE),
- case cache_tab:dirty_lookup(shared_roster_ldap_group,
- {Group, Host},
- fun () -> search_group_info(State, Group) end) of
+ case ets_cache:lookup(?GROUP_CACHE,
+ {Group, Host},
+ fun () -> search_group_info(State, Group) end) of
{ok, #group_info{members = Members}}
when Members /= undefined ->
Members;
get_group_name(Host, Group) ->
{ok, State} = eldap_utils:get_state(Host, ?MODULE),
- case cache_tab:dirty_lookup(shared_roster_ldap_group,
- {Group, Host},
- fun () -> search_group_info(State, Group) end)
+ case ets_cache:lookup(?GROUP_CACHE,
+ {Group, Host},
+ fun () -> search_group_info(State, Group) end)
of
{ok, #group_info{desc = GroupName}}
when GroupName /= undefined ->
get_user_name(User, Host) ->
{ok, State} = eldap_utils:get_state(Host, ?MODULE),
- case cache_tab:dirty_lookup(shared_roster_ldap_user,
- {User, Host},
- fun () -> search_user_name(State, User) end)
+ case ets_cache:lookup(?USER_CACHE,
+ {User, Host},
+ fun () -> search_user_name(State, User) end)
of
{ok, UserName} -> UserName;
error -> User
(false) -> false;
(true) -> true
end, true),
- UserCacheValidity = gen_mod:get_opt(
- {ldap_user_cache_validity, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?USER_CACHE_VALIDITY),
- GroupCacheValidity = gen_mod:get_opt(
- {ldap_group_cache_validity, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?GROUP_CACHE_VALIDITY),
- UserCacheSize = gen_mod:get_opt(
- {ldap_user_cache_size, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?CACHE_SIZE),
- GroupCacheSize = gen_mod:get_opt(
- {ldap_group_cache_size, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?CACHE_SIZE),
ConfigFilter = gen_mod:get_opt({ldap_filter, Host}, Opts,
fun check_filter/1, <<"">>),
ConfigUserFilter = gen_mod:get_opt({ldap_ufilter, Host}, Opts,
uid_format = UIDAttrFormat,
uid_format_re = UIDAttrFormatRe, filter = Filter,
ufilter = UserFilter, rfilter = RosterFilter,
- gfilter = GroupFilter, auth_check = AuthCheck,
- user_cache_size = UserCacheSize,
- user_cache_validity = UserCacheValidity,
- group_cache_size = GroupCacheSize,
- group_cache_validity = GroupCacheValidity}.
+ gfilter = GroupFilter, auth_check = AuthCheck}.
check_filter(F) ->
NewF = iolist_to_binary(F),
{ok, _} = eldap_filter:parse(NewF),
NewF.
+init_cache(Host, Opts) ->
+ UseCache = use_cache(Host, Opts),
+ case UseCache of
+ true ->
+ CacheOpts = cache_opts(Host, Opts),
+ ets_cache:new(?USER_CACHE, CacheOpts),
+ ets_cache:new(?GROUP_CACHE, CacheOpts);
+ false ->
+ ets_cache:delete(?USER_CACHE),
+ ets_cache:delete(?GROUP_CACHE)
+ end,
+ UseCache.
+
+use_cache(Host, Opts) ->
+ gen_mod:get_opt(use_cache, Opts, mod_opt_type(use_cache),
+ ejabberd_config:use_cache(Host)).
+
+cache_opts(Host, Opts) ->
+ MaxSize = gen_mod:get_opt(cache_size, Opts,
+ mod_opt_type(cache_size),
+ ejabberd_config:cache_size(Host)),
+ CacheMissed = gen_mod:get_opt(cache_missed, Opts,
+ mod_opt_type(cache_missed),
+ ejabberd_config:cache_missed(Host)),
+ LifeTime = case gen_mod:get_opt(cache_life_time, Opts,
+ mod_opt_type(cache_life_time),
+ ejabberd_config:cache_life_time(Host)) of
+ infinity -> infinity;
+ I -> timer:seconds(I)
+ end,
+ [{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
+
+transform_module_options(Opts) ->
+ lists:map(
+ fun({ldap_group_cache_size, I}) ->
+ ?WARNING_MSG("Option 'ldap_group_cache_size' is deprecated, "
+ "use 'cache_size' instead", []),
+ {cache_size, I};
+ ({ldap_user_cache_size, I}) ->
+ ?WARNING_MSG("Option 'ldap_user_cache_size' is deprecated, "
+ "use 'cache_size' instead", []),
+ {cache_size, I};
+ ({ldap_group_cache_validity, Secs}) ->
+ ?WARNING_MSG("Option 'ldap_group_cache_validity' is deprecated, "
+ "use 'cache_life_time' instead", []),
+ {cache_life_time, Secs};
+ ({ldap_user_cache_validity, Secs}) ->
+ ?WARNING_MSG("Option 'ldap_user_cache_validity' is deprecated, "
+ "use 'cache_life_time' instead", []),
+ {cache_life_time, Secs};
+ (Opt) ->
+ Opt
+ end, Opts).
+
mod_opt_type(deref_aliases) ->
fun (never) -> never;
(searching) -> searching;
end;
mod_opt_type(ldap_filter) -> fun check_filter/1;
mod_opt_type(ldap_gfilter) -> fun check_filter/1;
-mod_opt_type(ldap_group_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(ldap_group_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
+mod_opt_type(O) when O == cache_size;
+ O == cache_life_time ->
+ fun (I) when is_integer(I), I > 0 -> I;
+ (infinity) -> infinity
+ end;
+mod_opt_type(O) when O == use_cache; O == cache_missed ->
+ fun (B) when is_boolean(B) -> B end;
mod_opt_type(ldap_groupattr) -> fun iolist_to_binary/1;
mod_opt_type(ldap_groupdesc) -> fun iolist_to_binary/1;
mod_opt_type(ldap_memberattr) -> fun iolist_to_binary/1;
end;
mod_opt_type(ldap_rfilter) -> fun check_filter/1;
mod_opt_type(ldap_ufilter) -> fun check_filter/1;
-mod_opt_type(ldap_user_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(ldap_user_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
mod_opt_type(ldap_userdesc) -> fun iolist_to_binary/1;
mod_opt_type(ldap_useruid) -> fun iolist_to_binary/1;
mod_opt_type(_) ->
[ldap_auth_check, ldap_filter, ldap_gfilter,
- ldap_group_cache_size, ldap_group_cache_validity,
ldap_groupattr, ldap_groupdesc, ldap_memberattr,
ldap_memberattr_format, ldap_memberattr_format_re,
- ldap_rfilter, ldap_ufilter, ldap_user_cache_size,
- ldap_user_cache_validity, ldap_userdesc, ldap_useruid,
+ ldap_rfilter, ldap_ufilter, ldap_userdesc, ldap_useruid,
deref_aliases, ldap_backups, ldap_base,
ldap_deref_aliases, ldap_encrypt, ldap_password,
ldap_port, ldap_rootdn, ldap_servers,
ldap_tls_cacertfile, ldap_tls_certfile, ldap_tls_depth,
- ldap_tls_verify].
+ ldap_tls_verify, use_cache, cache_missed, cache_size, cache_life_time].
opt_type(ldap_filter) -> fun check_filter/1;
opt_type(ldap_gfilter) -> fun check_filter/1;
-opt_type(ldap_group_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-opt_type(ldap_group_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
opt_type(ldap_rfilter) -> fun check_filter/1;
opt_type(ldap_ufilter) -> fun check_filter/1;
-opt_type(ldap_user_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-opt_type(ldap_user_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
opt_type(_) ->
- [ldap_filter, ldap_gfilter, ldap_group_cache_size,
- ldap_group_cache_validity, ldap_rfilter, ldap_ufilter,
- ldap_user_cache_size, ldap_user_cache_validity].
+ [ldap_filter, ldap_gfilter, ldap_rfilter, ldap_ufilter].