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 +%%% +%%% +%%% 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 - true -> - ejabberd:start_app(riakc), - do_start(); - false -> - stop() - end. - -stop() -> - supervisor:terminate_child(ejabberd_sup, ?MODULE), - supervisor:delete_child(ejabberd_sup, ?MODULE), - ok. - 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 -> ok end. +config_reloaded() -> + case is_riak_configured() of + true -> + ejabberd:start_app(riakc), + lists:foreach( + fun(Spec) -> + supervisor:start_child(?MODULE, Spec) + end, get_specs()); + false -> + 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() ->