./ct_report/coverage/ejabberd_app.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : ejabberd_app.erl
3 %%% Author : Alexey Shchepin <alexey@process-one.net>
4 %%% Purpose : ejabberd's application callback module
5 %%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2011 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%----------------------------------------------------------------------
25
26 -module(ejabberd_app).
27 -author('alexey@process-one.net').
28
29 -behaviour(application).
30
31 -export([start/2, prep_stop/1, stop/1]).
32
33 -ignore_xref([prep_stop/1]).
34
35 -include("mongoose.hrl").
36
37
38 %%%
39 %%% Application API
40 %%%
41
42 start(normal, _Args) ->
43 53 try
44 53 do_start()
45 catch Class:Reason:StackTrace ->
46 %% Log a stacktrace because while proc_lib:crash_report/4 would report a crash reason,
47 %% it would not report the stacktrace
48
:-(
?LOG_CRITICAL(#{what => app_failed_to_start,
49
:-(
class => Class, reason => Reason, stacktrace => StackTrace}),
50
:-(
erlang:raise(Class, Reason, StackTrace)
51 end;
52 start(_, _) ->
53
:-(
{error, badarg}.
54
55 do_start() ->
56 53 mongoose_fips:notify(),
57 53 write_pid_file(),
58 53 update_status_file(starting),
59 53 mongoose_config:start(),
60 53 mongoose_metrics:init(),
61 53 mongoose_internal_databases:init(),
62 53 mongoose_graphql:init(),
63 53 translate:start(),
64 53 mongoose_graphql_commands:start(),
65 53 mongoose_router:start(),
66 53 mongoose_logs:set_global_loglevel(mongoose_config:get_opt(loglevel)),
67 53 mongoose_deprecations:start(),
68 53 {ok, _} = Sup = ejabberd_sup:start_link(),
69 53 mongoose_wpool:ensure_started(),
70 53 mongoose_wpool:start_configured_pools(),
71 %% ejabberd_sm is started separately because it may use one of the outgoing_pools
72 %% but some outgoing_pools should be started only with ejabberd_sup already running
73 53 ejabberd_sm:start(),
74 53 ejabberd_auth:start(),
75 53 mongoose_cluster_id:start(),
76 53 mongoose_service:start(),
77 53 mongoose_modules:start(),
78 53 service_mongoose_system_metrics:verify_if_configured(),
79 53 mongoose_listener:start(),
80 53 mongoose_metrics:init_mongooseim_metrics(),
81 53 gen_hook:reload_hooks(),
82 53 update_status_file(started),
83 53 ?LOG_NOTICE(#{what => mongooseim_node_started, version => ?MONGOOSE_VERSION, node => node()}),
84 53 Sup.
85
86 %% @doc Prepare the application for termination.
87 %% This function is called when an application is about to be stopped,
88 %% before shutting down the processes of the application.
89 prep_stop(State) ->
90 54 mongoose_deprecations:stop(),
91 54 broadcast_c2s_shutdown_listeners(),
92 53 mongoose_listener:stop(),
93 53 mongoose_modules:stop(),
94 53 mongoose_service:stop(),
95 53 broadcast_c2s_shutdown_sup(),
96 53 mongoose_wpool:stop(),
97 53 mongoose_metrics:remove_all_metrics(),
98 53 mongoose_config:stop(),
99 53 mongoose_graphql_commands:stop(),
100 53 State.
101
102 %% All the processes were killed when this function is called
103 stop(_State) ->
104 54 ?LOG_NOTICE(#{what => mongooseim_node_stopped, version => ?MONGOOSE_VERSION, node => node()}),
105 54 delete_pid_file(),
106 54 update_status_file(stopped),
107 %% We cannot stop other applications inside of the stop callback
108 %% (because we would deadlock the application controller process).
109 %% That is why we call mnesia:stop() inside of db_init_mnesia() instead.
110 54 ok.
111
112 %%%
113 %%% Internal functions
114 %%%
115
116 -spec broadcast_c2s_shutdown_listeners() -> ok.
117 broadcast_c2s_shutdown_listeners() ->
118 54 Children = supervisor:which_children(mongoose_listener_sup),
119 53 Listeners = [Ref || {Ref, _, _, [mongoose_c2s_listener]} <- Children],
120 53 lists:foreach(
121 fun(Listener) ->
122 104 ranch:suspend_listener(Listener),
123 104 [mongoose_c2s:exit(Pid, system_shutdown) || Pid <- ranch:procs(Listener, connections)],
124 104 mongoose_lib:wait_until(
125 fun() ->
126 106 length(ranch:procs(Listener, connections))
127 end,
128 0)
129 end,
130 Listeners).
131
132 -spec broadcast_c2s_shutdown_sup() -> ok.
133 broadcast_c2s_shutdown_sup() ->
134 53 Children = supervisor:which_children(mongoose_c2s_sup),
135 53 lists:foreach(
136 fun({_, Pid, _, _}) ->
137
:-(
mongoose_c2s:exit(Pid, system_shutdown)
138 end,
139 Children),
140 53 mongoose_lib:wait_until(
141 fun() ->
142 53 Res = supervisor:count_children(mongoose_c2s_sup),
143 53 proplists:get_value(active, Res)
144 end,
145 0).
146
147 %%%
148 %%% PID file
149 %%%
150
151 -spec write_pid_file() -> 'ok' | {'error', atom()}.
152 write_pid_file() ->
153 53 case ejabberd:get_pid_file() of
154 false ->
155
:-(
ok;
156 PidFilename ->
157 53 write_pid_file(os:getpid(), PidFilename)
158 end.
159
160 -spec write_pid_file(Pid :: string(),
161 PidFilename :: nonempty_string()
162 ) -> 'ok' | {'error', atom()}.
163 write_pid_file(Pid, PidFilename) ->
164 53 case file:open(PidFilename, [write]) of
165 {ok, Fd} ->
166 53 io:format(Fd, "~s~n", [Pid]),
167 53 file:close(Fd);
168 {error, Reason} ->
169
:-(
?LOG_ERROR(#{what => cannot_write_to_pid_file,
170
:-(
pid_file => PidFilename, reason => Reason}),
171
:-(
throw({cannot_write_pid_file, PidFilename, Reason})
172 end.
173
174 update_status_file(Status) ->
175 160 case ejabberd:get_status_file() of
176 false ->
177
:-(
ok;
178 StatusFilename ->
179 160 file:write_file(StatusFilename, atom_to_list(Status))
180 end.
181
182 -spec delete_pid_file() -> 'ok' | {'error', atom()}.
183 delete_pid_file() ->
184 54 case ejabberd:get_pid_file() of
185 false ->
186
:-(
ok;
187 PidFilename ->
188 54 file:delete(PidFilename)
189 end.
Line Hits Source