aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/acl.erl28
-rw-r--r--src/ejabberd_app.erl36
-rw-r--r--src/ejabberd_auth.erl35
-rw-r--r--src/ejabberd_auth_ldap.erl6
-rw-r--r--src/ejabberd_backend_sup.erl46
-rw-r--r--src/ejabberd_listener.erl110
-rw-r--r--src/ejabberd_oauth.erl48
-rw-r--r--src/ejabberd_rdbms.erl81
-rw-r--r--src/ejabberd_redis.erl77
-rw-r--r--src/ejabberd_riak_sup.erl95
-rw-r--r--src/ejabberd_router.erl7
-rw-r--r--src/ejabberd_router_multicast.erl7
-rw-r--r--src/ejabberd_sm.erl15
-rw-r--r--src/ejabberd_sup.erl46
-rw-r--r--src/gen_mod.erl15
-rw-r--r--src/mod_bosh.erl6
-rw-r--r--src/mod_irc.erl6
-rw-r--r--src/mod_proxy65.erl6
-rw-r--r--src/mod_proxy65_mnesia.erl2
-rw-r--r--src/mod_sip.erl4
-rw-r--r--src/mod_vcard_ldap.erl6
-rw-r--r--src/randoms.erl5
-rw-r--r--src/shaper.erl30
23 files changed, 403 insertions, 314 deletions
diff --git a/src/acl.erl b/src/acl.erl
index 99c8e17eb..40ab682e5 100644
--- a/src/acl.erl
+++ b/src/acl.erl
@@ -25,12 +25,13 @@
-module(acl).
+-behaviour(gen_server).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
-export([add_access/3, clear/0]).
--export([start/0, add/3, add_list/3, add_local/3, add_list_local/3,
+-export([start_link/0, add/3, add_list/3, add_local/3, add_list_local/3,
load_from_config/0, match_rule/3, any_rules_allowed/3,
transform_options/1, opt_type/1, acl_rule_matches/3,
acl_rule_verify/1, access_matches/3,
@@ -38,6 +39,9 @@
parse_ip_netmask/1,
access_rules_validator/1, shaper_rules_validator/1,
normalize_spec/1, resolve_access/2]).
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -46,6 +50,7 @@
-record(acl, {aclname, aclspec}).
-record(access, {name :: aclname(),
rules = [] :: [access_rule()]}).
+-record(state, {}).
-type regexp() :: binary().
-type iprange() :: {inet:ip_address(), integer()} | binary().
@@ -75,7 +80,10 @@
-export_type([acl/0]).
-start() ->
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+init([]) ->
ejabberd_mnesia:create(?MODULE, acl,
[{ram_copies, [node()]}, {type, bag},
{local_content, true},
@@ -88,8 +96,24 @@ start() ->
mnesia:add_table_copy(access, node(), ram_copies),
ejabberd_hooks:add(config_reloaded, ?MODULE, load_from_config, 20),
load_from_config(),
+ {ok, #state{}}.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
ok.
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
add(Host, ACLName, ACLSpec) ->
diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl
index 1340607cd..e51c31cd0 100644
--- a/src/ejabberd_app.erl
+++ b/src/ejabberd_app.erl
@@ -30,8 +30,7 @@
-behaviour(application).
--export([start/2, prep_stop/1, stop/1,
- init/0, opt_type/1]).
+-export([start/2, prep_stop/1, stop/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -46,9 +45,7 @@ start(normal, _Args) ->
start_apps(),
start_elixir_application(),
ejabberd:check_app(ejabberd),
- randoms:start(),
db_init(),
- start(),
translate:start(),
ejabberd_access_permissions:start_link(),
ejabberd_ctl:init(),
@@ -57,25 +54,11 @@ start(normal, _Args) ->
setup_if_elixir_conf_used(),
ejabberd_config:start(),
set_settings_from_config(),
+ maybe_add_nameservers(),
+ cyrsasl:start(),
connect_nodes(),
Sup = ejabberd_sup:start_link(),
- acl:start(),
- shaper:start(),
- ejabberd_rdbms:start(),
- ejabberd_riak_sup:start(),
- ejabberd_redis:start(),
- ejabberd_router:start(),
- ejabberd_router_multicast:start(),
- ejabberd_local:start(),
- ejabberd_sm:start(),
- cyrsasl:start(),
- gen_mod:start(),
ext_mod:start(),
- maybe_add_nameservers(),
- ejabberd_auth:start(),
- ejabberd_oauth:start(),
- gen_mod:start_modules(),
- ejabberd_listener:start_listeners(),
register_elixir_config_hooks(),
?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
Sup;
@@ -105,19 +88,6 @@ stop(_State) ->
%%% Internal functions
%%%
-start() ->
- spawn_link(?MODULE, init, []).
-
-init() ->
- register(ejabberd, self()),
- loop().
-
-loop() ->
- receive
- _ ->
- loop()
- end.
-
db_init() ->
ejabberd_config:env_binary_to_list(mnesia, dir),
MyNode = node(),
diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl
index fd5b6b244..1639a3a54 100644
--- a/src/ejabberd_auth.erl
+++ b/src/ejabberd_auth.erl
@@ -27,12 +27,13 @@
-module(ejabberd_auth).
+-behaviour(gen_server).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
%% External exports
--export([start/0, start/1, stop/1, set_password/3, check_password/4,
+-export([start_link/0, start/1, stop/1, set_password/3, check_password/4,
check_password/6, check_password_with_authmodule/4,
check_password_with_authmodule/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
@@ -43,12 +44,17 @@
is_user_exists/2, is_user_exists_in_other_modules/3,
remove_user/2, remove_user/3, plain_password_required/1,
store_type/1, entropy/1, backend_type/1]).
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
-export([auth_modules/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
+-record(state, {}).
+
-type scrammed_password() :: {binary(), binary(), binary(), non_neg_integer()}.
-type password() :: binary() | scrammed_password().
-export_type([password/0]).
@@ -81,11 +87,34 @@
-callback get_password(binary(), binary()) -> false | password().
-callback get_password_s(binary(), binary()) -> password().
-start() ->
+-spec start_link() -> {ok, pid()} | {error, any()}.
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+init([]) ->
ets:new(ejabberd_auth_modules, [named_table, public]),
ejabberd_hooks:add(host_up, ?MODULE, start, 30),
ejabberd_hooks:add(host_down, ?MODULE, stop, 80),
- lists:foreach(fun start/1, ?MYHOSTS).
+ lists:foreach(fun start/1, ?MYHOSTS),
+ {ok, #state{}}.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ejabberd_hooks:delete(host_up, ?MODULE, start, 30),
+ ejabberd_hooks:delete(host_down, ?MODULE, stop, 80),
+ lists:foreach(fun stop/1, ?MYHOSTS).
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
start(Host) ->
Modules = auth_modules_from_config(Host),
diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl
index 18770a512..059a66e7b 100644
--- a/src/ejabberd_auth_ldap.erl
+++ b/src/ejabberd_auth_ldap.erl
@@ -86,12 +86,12 @@ start(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
ChildSpec = {Proc, {?MODULE, start_link, [Host]},
transient, 1000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, ChildSpec).
+ supervisor:start_child(ejabberd_backend_sup, ChildSpec).
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
- supervisor:terminate_child(ejabberd_sup, Proc),
- supervisor:delete_child(ejabberd_sup, Proc).
+ supervisor:terminate_child(ejabberd_backend_sup, Proc),
+ supervisor:delete_child(ejabberd_backend_sup, Proc).
start_link(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
diff --git a/src/ejabberd_backend_sup.erl b/src/ejabberd_backend_sup.erl
new file mode 100644
index 000000000..c9492be63
--- /dev/null
+++ b/src/ejabberd_backend_sup.erl
@@ -0,0 +1,46 @@
+%%%-------------------------------------------------------------------
+%%% Created : 24 Feb 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%-------------------------------------------------------------------
+-module(ejabberd_backend_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+%%%===================================================================
+%%% API functions
+%%%===================================================================
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%%%===================================================================
+%%% Supervisor callbacks
+%%%===================================================================
+init([]) ->
+ {ok, {{one_for_one, 10, 1}, []}}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl
index bad1da134..97dd88582 100644
--- a/src/ejabberd_listener.erl
+++ b/src/ejabberd_listener.erl
@@ -45,58 +45,29 @@ start_link() ->
init(_) ->
- ets:new(listen_sockets, [named_table, public]),
- bind_tcp_ports(),
- {ok, {{one_for_one, 10, 1}, []}}.
+ {ok, {{one_for_one, 10, 1}, listeners_childspec()}}.
-bind_tcp_ports() ->
+listeners_childspec() ->
case ejabberd_config:get_option(listen, fun validate_cfg/1) of
undefined ->
- ignore;
+ [];
Ls ->
- lists:foreach(
- fun({Port, Module, Opts}) ->
- case Module:socket_type() of
- independent -> ok;
- _ ->
- bind_tcp_port(Port, Module, Opts)
- end
- end, Ls)
- end.
-
-bind_tcp_port(PortIP, Module, RawOpts) ->
- try check_listener_options(RawOpts) of
- ok ->
- {Port, IPT, IPS, IPV, Proto, OptsClean} = parse_listener_portip(PortIP, RawOpts),
- {_Opts, SockOpts} = prepare_opts(IPT, IPV, OptsClean),
- case Proto of
- udp -> ok;
- _ ->
- ListenSocket = listen_tcp(PortIP, Module, SockOpts, Port, IPS),
- ets:insert(listen_sockets, {PortIP, ListenSocket}),
- ok
- end
- catch
- throw:{error, Error} ->
- ?ERROR_MSG(Error, [])
+ Specs = lists:map(
+ fun({Port, Module, Opts}) ->
+ maybe_start_sip(Module),
+ {Port,
+ {?MODULE, start, [Port, Module, Opts]},
+ transient,
+ brutal_kill,
+ worker,
+ [?MODULE]}
+ end, Ls),
+ report_duplicated_portips(Ls),
+ Specs
end.
start_listeners() ->
- case ejabberd_config:get_option(listen, fun validate_cfg/1) of
- undefined ->
- ignore;
- Ls ->
- Ls2 = lists:map(
- fun({Port, Module, Opts}) ->
- case start_listener(Port, Module, Opts) of
- {ok, _Pid} = R -> R;
- {error, Error} ->
- throw(Error)
- end
- end, Ls),
- report_duplicated_portips(Ls),
- {ok, {{one_for_one, 10, 1}, Ls2}}
- end.
+ ok.
report_duplicated_portips(L) ->
LKeys = [Port || {Port, _, _} <- L],
@@ -144,6 +115,9 @@ init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
{ok, Socket} ->
%% Inform my parent that this port was opened succesfully
proc_lib:init_ack({ok, self()}),
+ start_module_sup(Port, Module),
+ ?INFO_MSG("Start accepting UDP connections at ~s for ~p",
+ [format_portip(PortIP), Module]),
case erlang:function_exported(Module, udp_init, 2) of
false ->
udp_recv(Socket, Module, Opts);
@@ -166,6 +140,9 @@ init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
ListenSocket = listen_tcp(PortIP, Module, SockOpts, Port, IPS),
%% Inform my parent that this port was opened succesfully
proc_lib:init_ack({ok, self()}),
+ start_module_sup(Port, Module),
+ ?INFO_MSG("Start accepting TCP connections at ~s for ~p",
+ [format_portip(PortIP), Module]),
case erlang:function_exported(Module, tcp_init, 2) of
false ->
accept(ListenSocket, Module, Opts);
@@ -182,29 +159,20 @@ init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
end.
listen_tcp(PortIP, Module, SockOpts, Port, IPS) ->
- case ets:lookup(listen_sockets, PortIP) of
- [{PortIP, ListenSocket}] ->
- {_, _, Transport} = PortIP,
- ?INFO_MSG("Reusing listening ~s port ~p at ~s",
- [Transport, Port, IPS]),
- ets:delete(listen_sockets, PortIP),
+ Res = gen_tcp:listen(Port, [binary,
+ {packet, 0},
+ {active, false},
+ {reuseaddr, true},
+ {nodelay, true},
+ {send_timeout, ?TCP_SEND_TIMEOUT},
+ {send_timeout_close, true},
+ {keepalive, true} |
+ SockOpts]),
+ case Res of
+ {ok, ListenSocket} ->
ListenSocket;
- _ ->
- Res = gen_tcp:listen(Port, [binary,
- {packet, 0},
- {active, false},
- {reuseaddr, true},
- {nodelay, true},
- {send_timeout, ?TCP_SEND_TIMEOUT},
- {send_timeout_close, true},
- {keepalive, true} |
- SockOpts]),
- case Res of
- {ok, ListenSocket} ->
- ListenSocket;
- {error, Reason} ->
- socket_error(Reason, PortIP, Module, SockOpts, Port, IPS)
- end
+ {error, Reason} ->
+ socket_error(Reason, PortIP, Module, SockOpts, Port, IPS)
end.
%% @spec (PortIP, Opts) -> {Port, IPT, IPS, IPV, OptsClean}
@@ -388,7 +356,6 @@ start_listener2(Port, Module, Opts) ->
%% But it doesn't hurt to attempt to start it for any listener.
%% So, it's normal (and harmless) that in most cases this call returns: {error, {already_started, pid()}}
maybe_start_sip(Module),
- start_module_sup(Port, Module),
start_listener_sup(Port, Module, Opts).
start_module_sup(_Port, Module) ->
@@ -578,6 +545,13 @@ format_error(Reason) ->
ReasonStr
end.
+format_portip({Port, IP, _Transport}) ->
+ IPStr = case tuple_size(IP) of
+ 4 -> inet:ntoa(IP);
+ 8 -> "[" ++ inet:ntoa(IP) ++ "]"
+ end,
+ IPStr ++ ":" ++ integer_to_list(Port).
+
check_rate_limit(Interval) ->
NewInterval = receive
{rate_limit, AcceptInterval} ->
diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl
index 61944a79d..a4e8bb6ca 100644
--- a/src/ejabberd_oauth.erl
+++ b/src/ejabberd_oauth.erl
@@ -32,8 +32,7 @@
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
--export([start/0,
- start_link/0,
+-export([start_link/0,
get_client_identity/2,
verify_redirection_uri/3,
authenticate_user/2,
@@ -70,32 +69,6 @@
-define(EXPIRE, 4294967).
-start() ->
- DBMod = get_db_backend(),
- DBMod:init(),
- MaxSize =
- ejabberd_config:get_option(
- oauth_cache_size,
- fun(I) when is_integer(I), I>0 -> I end,
- 1000),
- LifeTime =
- ejabberd_config:get_option(
- oauth_cache_life_time,
- fun(I) when is_integer(I), I>0 -> I end,
- timer:hours(1) div 1000),
- cache_tab:new(oauth_token,
- [{max_size, MaxSize}, {life_time, LifeTime}]),
- Expire = expire(),
- application:set_env(oauth2, backend, ejabberd_oauth),
- application:set_env(oauth2, expiry_time, Expire),
- application:start(oauth2),
- ChildSpec = {?MODULE, {?MODULE, start_link, []},
- transient, 1000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, ChildSpec),
- ejabberd_commands:register_commands(get_commands_spec()),
- ok.
-
-
get_commands_spec() ->
[
#ejabberd_commands{name = oauth_issue_token, tags = [oauth],
@@ -173,6 +146,25 @@ start_link() ->
init([]) ->
+ DBMod = get_db_backend(),
+ DBMod:init(),
+ MaxSize =
+ ejabberd_config:get_option(
+ oauth_cache_size,
+ fun(I) when is_integer(I), I>0 -> I end,
+ 1000),
+ LifeTime =
+ ejabberd_config:get_option(
+ oauth_cache_life_time,
+ fun(I) when is_integer(I), I>0 -> I end,
+ timer:hours(1) div 1000),
+ cache_tab:new(oauth_token,
+ [{max_size, MaxSize}, {life_time, LifeTime}]),
+ Expire = expire(),
+ application:set_env(oauth2, backend, ejabberd_oauth),
+ application:set_env(oauth2, expiry_time, Expire),
+ application:start(oauth2),
+ ejabberd_commands:register_commands(get_commands_spec()),
erlang:send_after(expire() * 1000, self(), clean),
{ok, ok}.
diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl
index 5fc73c624..0f89e333e 100644
--- a/src/ejabberd_rdbms.erl
+++ b/src/ejabberd_rdbms.erl
@@ -25,67 +25,78 @@
-module(ejabberd_rdbms).
+-behaviour(supervisor).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
--export([start/0, opt_type/1, start_hosts/0, start_host/1, stop_host/1]).
+-export([start_link/0, init/1, opt_type/1,
+ config_reloaded/0, start_host/1, stop_host/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-start() ->
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
file:delete(ejabberd_sql:freetds_config()),
file:delete(ejabberd_sql:odbc_config()),
file:delete(ejabberd_sql:odbcinst_config()),
ejabberd_hooks:add(host_up, ?MODULE, start_host, 20),
ejabberd_hooks:add(host_down, ?MODULE, stop_host, 90),
- ejabberd_hooks:add(config_reloaded, ?MODULE, start_hosts, 20),
- case lists:any(fun(H) -> needs_sql(H) /= false end,
- ?MYHOSTS) of
- true ->
- start_hosts();
- false ->
- ok
+ ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 20),
+ {ok, {{one_for_one, 10, 1}, get_specs()}}.
+
+-spec get_specs() -> [supervisor:child_spec()].
+get_specs() ->
+ lists:flatmap(
+ fun(Host) ->
+ case get_spec(Host) of
+ {ok, Spec} -> [Spec];
+ undefined -> []
+ end
+ end, ?MYHOSTS).
+
+-spec get_spec(binary()) -> {ok, supervisor:child_spec()} | undefined.
+get_spec(Host) ->
+ case needs_sql(Host) of
+ {true, App} ->
+ ejabberd:start_app(App),
+ SupName = gen_mod:get_module_proc(Host, ejabberd_sql_sup),
+ {ok, {SupName, {ejabberd_sql_sup, start_link, [Host]},
+ transient, infinity, supervisor, [ejabberd_sql_sup]}};
+ false ->
+ undefined
end.
-%% Start relationnal DB module on the nodes where it is needed
-start_hosts() ->
+-spec config_reloaded() -> ok.
+config_reloaded() ->
lists:foreach(fun start_host/1, ?MYHOSTS).
-spec start_host(binary()) -> ok.
start_host(Host) ->
- case needs_sql(Host) of
- {true, App} -> start_sql(Host, App);
- false -> ok
+ case get_spec(Host) of
+ {ok, Spec} ->
+ case supervisor:start_child(?MODULE, Spec) of
+ {ok, _PID} ->
+ ok;
+ {error, {already_started, _}} ->
+ ok;
+ {error, _} = Err ->
+ erlang:error(Err)
+ end;
+ undefined ->
+ ok
end.
-spec stop_host(binary()) -> ok.
stop_host(Host) ->
SupName = gen_mod:get_module_proc(Host, ejabberd_sql_sup),
- supervisor:terminate_child(ejabberd_sup, SupName),
- supervisor:delete_child(ejabberd_sup, SupName),
+ supervisor:terminate_child(?MODULE, SupName),
+ supervisor:delete_child(?MODULE, SupName),
ok.
-%% Start the SQL module on the given host
-start_sql(Host, App) ->
- ejabberd:start_app(App),
- Supervisor_name = gen_mod:get_module_proc(Host,
- ejabberd_sql_sup),
- ChildSpec = {Supervisor_name,
- {ejabberd_sql_sup, start_link, [Host]}, transient,
- infinity, supervisor, [ejabberd_sql_sup]},
- case supervisor:start_child(ejabberd_sup, ChildSpec) of
- {ok, _PID} -> ok;
- {error, {already_started, _}} -> ok;
- _Error ->
- ?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying."
- "..~n",
- [Supervisor_name, _Error]),
- timer:sleep(5000),
- start_sql(Host, App)
- end.
-
%% Returns {true, App} if we have configured sql for the given host
needs_sql(Host) ->
LHost = jid:nameprep(Host),
diff --git a/src/ejabberd_redis.erl b/src/ejabberd_redis.erl
index 6a853737d..f349baac5 100644
--- a/src/ejabberd_redis.erl
+++ b/src/ejabberd_redis.erl
@@ -28,7 +28,7 @@
-behaviour(ejabberd_config).
%% API
--export([start/0, stop/0, start_link/0, q/1, qp/1, host_up/1, opt_type/1]).
+-export([start_link/0, q/1, qp/1, config_reloaded/0, opt_type/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -40,7 +40,7 @@
-include("logger.hrl").
-include("ejabberd.hrl").
--record(state, {}).
+-record(state, {connection :: {pid(), reference()} | undefined}).
%%%===================================================================
%%% API
@@ -48,19 +48,6 @@
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-start() ->
- ejabberd_hooks:add(config_reloaded, ?MODULE, start, 20),
- ejabberd_hooks:add(host_up, ?MODULE, host_up, 20),
- case lists:any(
- fun(Host) ->
- is_redis_configured(Host)
- end, ?MYHOSTS) of
- true ->
- do_start();
- false ->
- stop()
- end.
-
q(Command) ->
try eredis:q(?PROCNAME, Command)
catch _:Reason -> {error, Reason}
@@ -71,22 +58,21 @@ qp(Pipeline) ->
catch _:Reason -> {error, Reason}
end.
-stop() ->
- supervisor:terminate_child(ejabberd_sup, ?MODULE),
- supervisor:delete_child(ejabberd_sup, ?MODULE).
-
-host_up(Host) ->
- case is_redis_configured(Host) of
- true -> do_start();
- false -> ok
+config_reloaded() ->
+ case is_redis_configured() of
+ true ->
+ ?MODULE ! connect;
+ false ->
+ ?MODULE ! disconnect
end.
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
init([]) ->
+ ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 20),
process_flag(trap_exit, true),
- connect(),
+ self() ! connect,
{ok, #state{}}.
handle_call(_Request, _From, State) ->
@@ -96,13 +82,35 @@ handle_call(_Request, _From, State) ->
handle_cast(_Msg, State) ->
{noreply, State}.
+handle_info(connect, #state{connection = undefined} = State) ->
+ NewState = case is_redis_configured() of
+ true ->
+ case connect() of
+ {ok, Connection} ->
+ State#state{connection = Connection};
+ {error, _} ->
+ State
+ end;
+ false ->
+ State
+ end,
+ {noreply, NewState};
handle_info(connect, State) ->
- connect(),
+ %% Already connected
{noreply, State};
-handle_info({'DOWN', _MRef, _Type, _Pid, Reason}, State) ->
+handle_info(disconnect, #state{connection = {Pid, MRef}} = State) ->
+ ?INFO_MSG("Disconnecting from Redis server", []),
+ erlang:demonitor(MRef, [flush]),
+ eredis:stop(Pid),
+ {noreply, State#state{connection = undefined}};
+handle_info(disconnect, State) ->
+ %% Not connected
+ {noreply, State};
+handle_info({'DOWN', MRef, _Type, Pid, Reason},
+ #state{connection = {Pid, MRef}} = State) ->
?INFO_MSG("Redis connection has failed: ~p", [Reason]),
connect(),
- {noreply, State};
+ {noreply, State#state{connection = undefined}};
handle_info({'EXIT', _, _}, State) ->
{noreply, State};
handle_info(Info, State) ->
@@ -110,7 +118,7 @@ handle_info(Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
- ok.
+ ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 20).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -118,10 +126,8 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
-do_start() ->
- Spec = {?MODULE, {?MODULE, start_link, []},
- permanent, 5000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, Spec).
+is_redis_configured() ->
+ lists:any(fun is_redis_configured/1, ?MYHOSTS).
is_redis_configured(Host) ->
ServerConfigured = ejabberd_config:has_option({redis_server, Host}),
@@ -181,9 +187,9 @@ connect() ->
{ok, Client} ->
?INFO_MSG("Connected to Redis at ~s:~p", [Server, Port]),
unlink(Client),
- erlang:monitor(process, Client),
+ MRef = erlang:monitor(process, Client),
register(?PROCNAME, Client),
- {ok, Client};
+ {ok, {Client, MRef}};
{error, Why} ->
erlang:error(Why)
end
@@ -192,7 +198,8 @@ connect() ->
?ERROR_MSG("Redis connection at ~s:~p has failed: ~p; "
"reconnecting in ~p seconds",
[Server, Port, Reason, Timeout]),
- erlang:send_after(timer:seconds(Timeout), self(), connect)
+ erlang:send_after(timer:seconds(Timeout), self(), connect),
+ {error, Reason}
end.
opt_type(redis_connect_timeout) ->
diff --git a/src/ejabberd_riak_sup.erl b/src/ejabberd_riak_sup.erl
index d1ab126f8..12b701b47 100644
--- a/src/ejabberd_riak_sup.erl
+++ b/src/ejabberd_riak_sup.erl
@@ -25,12 +25,13 @@
-module(ejabberd_riak_sup).
+-behaviour(supervisor).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
--export([start/0, stop/0, start_link/0, init/1, get_pids/0,
+-export([start_link/0, init/1, get_pids/0,
transform_options/1, get_random_pid/0, get_random_pid/1,
- host_up/1, opt_type/1]).
+ host_up/1, config_reloaded/0, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -44,34 +45,37 @@
% a timeout error to the request
-define(CONNECT_TIMEOUT, 500). % milliseconds
-start() ->
- ejabberd_hooks:add(config_reloaded, ?MODULE, start, 20),
- ejabberd_hooks:add(host_up, ?MODULE, host_up, 20),
- case lists:any(
- fun(Host) ->
- is_riak_configured(Host)
- end, ?MYHOSTS) of
+host_up(Host) ->
+ case is_riak_configured(Host) of
true ->
ejabberd:start_app(riakc),
- do_start();
+ lists:foreach(
+ fun(Spec) ->
+ supervisor:start_child(?MODULE, Spec)
+ end, get_specs());
false ->
- stop()
+ ok
end.
-stop() ->
- supervisor:terminate_child(ejabberd_sup, ?MODULE),
- supervisor:delete_child(ejabberd_sup, ?MODULE),
- ok.
-
-host_up(Host) ->
- case is_riak_configured(Host) of
+config_reloaded() ->
+ case is_riak_configured() of
true ->
ejabberd:start_app(riakc),
- do_start();
+ lists:foreach(
+ fun(Spec) ->
+ supervisor:start_child(?MODULE, Spec)
+ end, get_specs());
false ->
- ok
+ lists:foreach(
+ fun({Id, _, _, _}) ->
+ supervisor:terminate_child(?MODULE, Id),
+ supervisor:delete_child(?MODULE, Id)
+ end, supervisor:which_children(?MODULE))
end.
+is_riak_configured() ->
+ lists:any(fun is_riak_configured/1, ?MYHOSTS).
+
is_riak_configured(Host) ->
ServerConfigured = ejabberd_config:get_option(
{riak_server, Host},
@@ -92,30 +96,23 @@ is_riak_configured(Host) ->
ServerConfigured or PortConfigured
or AuthConfigured or ModuleWithRiakDBConfigured.
-do_start() ->
- ChildSpec =
- {?MODULE,
- {?MODULE, start_link, []},
- transient,
- infinity,
- supervisor,
- [?MODULE]},
- case supervisor:start_child(ejabberd_sup, ChildSpec) of
- {ok, _PID} ->
- ok;
- {error, {already_started, _}} ->
- ok;
- _Error ->
- ?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying...~n",
- [?MODULE, _Error]),
- timer:sleep(5000),
- start()
- end.
-
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
+ ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 20),
+ ejabberd_hooks:add(host_up, ?MODULE, host_up, 20),
+ Specs = case is_riak_configured() of
+ true ->
+ ejabberd:start_app(riakc),
+ get_specs();
+ false ->
+ []
+ end,
+ {ok, {{one_for_one, 500, 1}, Specs}}.
+
+-spec get_specs() -> [supervisor:child_spec()].
+get_specs() ->
PoolSize = get_pool_size(),
StartInterval = get_start_interval(),
Server = get_riak_server(),
@@ -133,16 +130,14 @@ init([]) ->
if (Username /= nil) and (Password /= nil) ->
{credentials, Username, Password};
true -> nil
- end
- ]),
- {ok, {{one_for_one, PoolSize*10, 1},
- lists:map(
- fun(I) ->
- {ejabberd_riak:get_proc(I),
- {ejabberd_riak, start_link,
- [I, Server, Port, StartInterval*1000, Options]},
- transient, 2000, worker, [?MODULE]}
- end, lists:seq(1, PoolSize))}}.
+ end]),
+ lists:map(
+ fun(I) ->
+ {ejabberd_riak:get_proc(I),
+ {ejabberd_riak, start_link,
+ [I, Server, Port, StartInterval*1000, Options]},
+ transient, 2000, worker, [?MODULE]}
+ end, lists:seq(1, PoolSize)).
get_start_interval() ->
ejabberd_config:get_option(
diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl
index 075becad0..17b43c15d 100644
--- a/src/ejabberd_router.erl
+++ b/src/ejabberd_router.erl
@@ -49,7 +49,7 @@
is_my_host/1,
get_backend/0]).
--export([start/0, start_link/0]).
+-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3, opt_type/1]).
@@ -78,11 +78,6 @@
%%====================================================================
%% API
%%====================================================================
-start() ->
- ChildSpec = {?MODULE, {?MODULE, start_link, []},
- transient, 1000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, ChildSpec).
-
start_link() ->
?GEN_SERVER:start_link({local, ?MODULE}, ?MODULE, [], []).
diff --git a/src/ejabberd_router_multicast.erl b/src/ejabberd_router_multicast.erl
index bb2442b4f..ff2862a72 100644
--- a/src/ejabberd_router_multicast.erl
+++ b/src/ejabberd_router_multicast.erl
@@ -35,7 +35,7 @@
unregister_route/1
]).
--export([start/0, start_link/0]).
+-export([start_link/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -56,11 +56,6 @@
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
-start() ->
- ChildSpec = {?MODULE, {?MODULE, start_link, []},
- transient, 1000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, ChildSpec).
-
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index aa7c1d080..173b9a2ad 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -35,9 +35,7 @@
-behaviour(?GEN_SERVER).
%% API
--export([start/0,
- stop/0,
- start_link/0,
+-export([start_link/0,
route/1,
route/2,
process_iq/1,
@@ -110,17 +108,6 @@
%%====================================================================
-export_type([sid/0, info/0]).
-start() ->
- ChildSpec = {?MODULE, {?MODULE, start_link, []},
- transient, 5000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, ChildSpec).
-
--spec stop() -> ok.
-stop() ->
- supervisor:terminate_child(ejabberd_sup, ?MODULE),
- supervisor:delete_child(ejabberd_sup, ?MODULE),
- ok.
-
start_link() ->
?GEN_SERVER:start_link({local, ?MODULE}, ?MODULE, [], []).
diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl
index f9a48be4d..d8f93ce02 100644
--- a/src/ejabberd_sup.erl
+++ b/src/ejabberd_sup.erl
@@ -101,8 +101,40 @@ init([]) ->
infinity,
supervisor,
[ejabberd_tmp_sup]},
+ BackendSupervisor = {ejabberd_backend_sup,
+ {ejabberd_backend_sup, start_link, []},
+ permanent, infinity, supervisor,
+ [ejabberd_backend_sup]},
+ ACL = {acl, {acl, start_link, []},
+ permanent, 5000, worker, [acl]},
+ Shaper = {shaper, {shaper, start_link, []},
+ permanent, 5000, worker, [shaper]},
+ SQLSupervisor = {ejabberd_rdbms,
+ {ejabberd_rdbms, start_link, []},
+ permanent, infinity, supervisor, [ejabberd_rdbms]},
+ RiakSupervisor = {ejabberd_riak_sup,
+ {ejabberd_riak_sup, start_link, []},
+ permanent, infinity, supervisor, [ejabberd_riak_sup]},
+ Redis = {ejabberd_redis, {ejabberd_redis, start_link, []},
+ permanent, 5000, worker, [ejabberd_redis]},
+ Router = {ejabberd_router, {ejabberd_router, start_link, []},
+ permanent, 5000, worker, [ejabberd_router]},
+ RouterMulticast = {ejabberd_router_multicast,
+ {ejabberd_router_multicast, start_link, []},
+ permanent, 5000, worker, [ejabberd_router_multicast]},
+ Local = {ejabberd_local, {ejabberd_local, start_link, []},
+ permanent, 5000, worker, [ejabberd_local]},
+ SM = {ejabberd_sm, {ejabberd_sm, start_link, []},
+ permanent, 5000, worker, [ejabberd_sm]},
+ GenModSupervisor = {ejabberd_gen_mod_sup, {gen_mod, start_link, []},
+ permanent, infinity, supervisor, [gen_mod]},
+ Auth = {ejabberd_auth, {ejabberd_auth, start_link, []},
+ permanent, 5000, worker, [ejabberd_auth]},
+ OAuth = {ejabberd_oauth, {ejabberd_oauth, start_link, []},
+ permanent, 5000, worker, [ejabberd_oauth]},
{ok, {{one_for_one, 10, 1},
[Hooks,
+ Listener,
SystemMonitor,
S2S,
Captcha,
@@ -110,4 +142,16 @@ init([]) ->
S2SOutSupervisor,
ServiceSupervisor,
IQSupervisor,
- Listener]}}.
+ ACL,
+ Shaper,
+ BackendSupervisor,
+ SQLSupervisor,
+ RiakSupervisor,
+ Redis,
+ Router,
+ RouterMulticast,
+ Local,
+ SM,
+ GenModSupervisor,
+ Auth,
+ OAuth]}}.
diff --git a/src/gen_mod.erl b/src/gen_mod.erl
index 77edb0e90..63bfa314b 100644
--- a/src/gen_mod.erl
+++ b/src/gen_mod.erl
@@ -32,7 +32,7 @@
-export([init/1, start_link/0, start_child/3, start_child/4,
stop_child/1, stop_child/2, config_reloaded/0]).
--export([start/0, start_module/2, start_module/3,
+-export([start_module/2, start_module/3,
stop_module/2, stop_module_keep_config/2, get_opt/3,
get_opt/4, get_opt_host/3, opt_type/1, is_equal_opt/5,
get_module_opt/4, get_module_opt/5, get_module_opt_host/3,
@@ -70,13 +70,14 @@
-define(GEN_SERVER, gen_server).
-endif.
-start() ->
- Spec = {ejabberd_gen_mod_sup, {?MODULE, start_link, []},
- permanent, infinity, supervisor, [?MODULE]},
- supervisor:start_child(ejabberd_sup, Spec).
-
start_link() ->
- supervisor:start_link({local, ejabberd_gen_mod_sup}, ?MODULE, []).
+ case supervisor:start_link({local, ejabberd_gen_mod_sup}, ?MODULE, []) of
+ {ok, Pid} ->
+ gen_mod:start_modules(),
+ {ok, Pid};
+ Err ->
+ Err
+ end.
init([]) ->
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
diff --git a/src/mod_bosh.erl b/src/mod_bosh.erl
index 049504ee4..abe3c2f16 100644
--- a/src/mod_bosh.erl
+++ b/src/mod_bosh.erl
@@ -96,12 +96,12 @@ start(Host, Opts) ->
TmpSupSpec = {TmpSup,
{ejabberd_tmp_sup, start_link, [TmpSup, ejabberd_bosh]},
permanent, infinity, supervisor, [ejabberd_tmp_sup]},
- supervisor:start_child(ejabberd_sup, TmpSupSpec).
+ supervisor:start_child(ejabberd_gen_mod_sup, TmpSupSpec).
stop(Host) ->
TmpSup = gen_mod:get_module_proc(Host, ?MODULE),
- supervisor:terminate_child(ejabberd_sup, TmpSup),
- supervisor:delete_child(ejabberd_sup, TmpSup).
+ supervisor:terminate_child(ejabberd_gen_mod_sup, TmpSup),
+ supervisor:delete_child(ejabberd_gen_mod_sup, TmpSup).
reload(_Host, NewOpts, _OldOpts) ->
start_jiffy(NewOpts),
diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index 37d54954b..c7af2834b 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -237,13 +237,13 @@ start_supervisor(Host) ->
{ejabberd_tmp_sup, start_link,
[Proc, mod_irc_connection]},
permanent, infinity, supervisor, [ejabberd_tmp_sup]},
- supervisor:start_child(ejabberd_sup, ChildSpec).
+ supervisor:start_child(ejabberd_gen_mod_sup, ChildSpec).
stop_supervisor(Host) ->
Proc = gen_mod:get_module_proc(Host,
ejabberd_mod_irc_sup),
- supervisor:terminate_child(ejabberd_sup, Proc),
- supervisor:delete_child(ejabberd_sup, Proc).
+ supervisor:terminate_child(ejabberd_gen_mod_sup, Proc),
+ supervisor:delete_child(ejabberd_gen_mod_sup, Proc).
do_route(Host, ServerHost, Access, Packet) ->
#jid{luser = LUser, lresource = LResource} = xmpp:get_to(Packet),
diff --git a/src/mod_proxy65.erl b/src/mod_proxy65.erl
index e8183b21f..d7793115e 100644
--- a/src/mod_proxy65.erl
+++ b/src/mod_proxy65.erl
@@ -59,14 +59,14 @@ start(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]},
transient, infinity, supervisor, [?MODULE]},
- supervisor:start_child(ejabberd_sup, ChildSpec)
+ supervisor:start_child(ejabberd_gen_mod_sup, ChildSpec)
end.
stop(Host) ->
mod_proxy65_service:delete_listener(Host),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- supervisor:terminate_child(ejabberd_sup, Proc),
- supervisor:delete_child(ejabberd_sup, Proc).
+ supervisor:terminate_child(ejabberd_gen_mod_sup, Proc),
+ supervisor:delete_child(ejabberd_gen_mod_sup, Proc).
reload(Host, NewOpts, OldOpts) ->
Mod = gen_mod:ram_db_mod(global, ?MODULE),
diff --git a/src/mod_proxy65_mnesia.erl b/src/mod_proxy65_mnesia.erl
index 6e3643606..2763fab6a 100644
--- a/src/mod_proxy65_mnesia.erl
+++ b/src/mod_proxy65_mnesia.erl
@@ -50,7 +50,7 @@ start_link() ->
init() ->
Spec = {?MODULE, {?MODULE, start_link, []}, transient,
5000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, Spec).
+ supervisor:start_child(ejabberd_backend_sup, Spec).
register_stream(SHA1, StreamPid) ->
F = fun () ->
diff --git a/src/mod_sip.erl b/src/mod_sip.erl
index c34a90795..eb5cbe545 100644
--- a/src/mod_sip.erl
+++ b/src/mod_sip.erl
@@ -55,8 +55,8 @@ start(_Host, _Opts) ->
{ejabberd_tmp_sup, start_link,
[mod_sip_proxy_sup, mod_sip_proxy]},
permanent, infinity, supervisor, [ejabberd_tmp_sup]},
- supervisor:start_child(ejabberd_sup, Spec),
- supervisor:start_child(ejabberd_sup, TmpSupSpec),
+ supervisor:start_child(ejabberd_gen_mod_sup, Spec),
+ supervisor:start_child(ejabberd_gen_mod_sup, TmpSupSpec),
ok.
stop(_Host) ->
diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl
index aa669897e..eb9f584ef 100644
--- a/src/mod_vcard_ldap.erl
+++ b/src/mod_vcard_ldap.erl
@@ -81,12 +81,12 @@ init(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]},
transient, 1000, worker, [?MODULE]},
- supervisor:start_child(ejabberd_sup, ChildSpec).
+ supervisor:start_child(ejabberd_backend_sup, ChildSpec).
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- supervisor:terminate_child(ejabberd_sup, Proc),
- supervisor:delete_child(ejabberd_sup, Proc),
+ supervisor:terminate_child(ejabberd_backend_sup, Proc),
+ supervisor:delete_child(ejabberd_backend_sup, Proc),
ok.
is_search_supported(_LServer) ->
diff --git a/src/randoms.erl b/src/randoms.erl
index 90cc34f10..a5e33becd 100644
--- a/src/randoms.erl
+++ b/src/randoms.erl
@@ -29,13 +29,8 @@
-export([get_string/0, uniform/0, uniform/1, bytes/1]).
--export([start/0]).
-
-define(THRESHOLD, 16#10000000000000000).
-start() ->
- ok.
-
get_string() ->
R = crypto:rand_uniform(0, ?THRESHOLD),
integer_to_binary(R).
diff --git a/src/shaper.erl b/src/shaper.erl
index a2f76b1c4..cc1923f86 100644
--- a/src/shaper.erl
+++ b/src/shaper.erl
@@ -25,13 +25,17 @@
-module(shaper).
+-behaviour(gen_server).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
--export([start/0, new/1, new1/1, update/2,
+-export([start_link/0, new/1, new1/1, update/2,
get_max_rate/1, transform_options/1, load_from_config/0,
opt_type/1]).
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -43,13 +47,17 @@
-record(shaper, {name :: {atom(), global},
maxrate :: integer()}).
+-record(state, {}).
+
-type shaper() :: none | #maxrate{}.
-export_type([shaper/0]).
--spec start() -> ok.
+-spec start_link() -> {ok, pid()} | {error, any()}.
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-start() ->
+init([]) ->
ejabberd_mnesia:create(?MODULE, shaper,
[{ram_copies, [node()]},
{local_content, true},
@@ -57,8 +65,24 @@ start() ->
mnesia:add_table_copy(shaper, node(), ram_copies),
ejabberd_hooks:add(config_reloaded, ?MODULE, load_from_config, 20),
load_from_config(),
+ {ok, #state{}}.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
ok.
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
-spec load_from_config() -> ok | {error, any()}.
load_from_config() ->