./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 mongoose_instrument:persist(),
82 53 gen_hook:reload_hooks(),
83 53 update_status_file(started),
84 53 ?LOG_NOTICE(#{what => mongooseim_node_started, version => ?MONGOOSE_VERSION, node => node()}),
85 53 Sup.
86
87 %% @doc Prepare the application for termination.
88 %% This function is called when an application is about to be stopped,
89 %% before shutting down the processes of the application.
90 prep_stop(State) ->
91 54 mongoose_deprecations:stop(),
92 54 broadcast_c2s_shutdown_listeners(),
93 53 mongoose_listener:stop(),
94 53 mongoose_modules:stop(),
95 53 mongoose_service:stop(),
96 53 broadcast_c2s_shutdown_sup(),
97 53 mongoose_wpool:stop(),
98 53 mongoose_metrics:remove_all_metrics(),
99 53 mongoose_config:stop(),
100 53 mongoose_graphql_commands:stop(),
101 53 State.
102
103 %% All the processes were killed when this function is called
104 stop(_State) ->
105 54 ?LOG_NOTICE(#{what => mongooseim_node_stopped, version => ?MONGOOSE_VERSION, node => node()}),
106 54 delete_pid_file(),
107 54 update_status_file(stopped),
108 %% We cannot stop other applications inside of the stop callback
109 %% (because we would deadlock the application controller process).
110 %% That is why we call mnesia:stop() inside of db_init_mnesia() instead.
111 54 ok.
112
113 %%%
114 %%% Internal functions
115 %%%
116
117 -spec broadcast_c2s_shutdown_listeners() -> ok.
118 broadcast_c2s_shutdown_listeners() ->
119 54 Children = supervisor:which_children(mongoose_listener_sup),
120 53 Listeners = [Ref || {Ref, _, _, [mongoose_c2s_listener]} <- Children],
121 53 lists:foreach(
122 fun(Listener) ->
123 104 ranch:suspend_listener(Listener),
124 104 [mongoose_c2s:exit(Pid, system_shutdown) || Pid <- ranch:procs(Listener, connections)],
125 104 mongoose_lib:wait_until(
126 fun() ->
127 106 length(ranch:procs(Listener, connections))
128 end,
129 0)
130 end,
131 Listeners).
132
133 -spec broadcast_c2s_shutdown_sup() -> ok.
134 broadcast_c2s_shutdown_sup() ->
135 53 Children = supervisor:which_children(mongoose_c2s_sup),
136 53 lists:foreach(
137 fun({_, Pid, _, _}) ->
138
:-(
mongoose_c2s:exit(Pid, system_shutdown)
139 end,
140 Children),
141 53 mongoose_lib:wait_until(
142 fun() ->
143 53 Res = supervisor:count_children(mongoose_c2s_sup),
144 53 proplists:get_value(active, Res)
145 end,
146 0).
147
148 %%%
149 %%% PID file
150 %%%
151
152 -spec write_pid_file() -> 'ok' | {'error', atom()}.
153 write_pid_file() ->
154 53 case ejabberd:get_pid_file() of
155 false ->
156
:-(
ok;
157 PidFilename ->
158 53 write_pid_file(os:getpid(), PidFilename)
159 end.
160
161 -spec write_pid_file(Pid :: string(),
162 PidFilename :: nonempty_string()
163 ) -> 'ok' | {'error', atom()}.
164 write_pid_file(Pid, PidFilename) ->
165 53 case file:open(PidFilename, [write]) of
166 {ok, Fd} ->
167 53 io:format(Fd, "~s~n", [Pid]),
168 53 file:close(Fd);
169 {error, Reason} ->
170
:-(
?LOG_ERROR(#{what => cannot_write_to_pid_file,
171
:-(
pid_file => PidFilename, reason => Reason}),
172
:-(
throw({cannot_write_pid_file, PidFilename, Reason})
173 end.
174
175 update_status_file(Status) ->
176 160 case ejabberd:get_status_file() of
177 false ->
178
:-(
ok;
179 StatusFilename ->
180 160 file:write_file(StatusFilename, atom_to_list(Status))
181 end.
182
183 -spec delete_pid_file() -> 'ok' | {'error', atom()}.
184 delete_pid_file() ->
185 54 case ejabberd:get_pid_file() of
186 false ->
187
:-(
ok;
188 PidFilename ->
189 54 file:delete(PidFilename)
190 end.
Line Hits Source