From 42036d8f68beb13f97f8bb06f93eb05ee09d80b3 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 23 Dec 2008 01:34:52 +0000 Subject: [PATCH] * src/mod_last.erl: Implement workaround for uptime statistic in 32 bit machines, so it can show uptime greater than 50 days (EJAB-610) * src/mod_last_odbc.erl: Likewise * src/ejabberd_config.erl: Store start time in local_config table SVN Revision: 1744 --- ChangeLog | 6 ++++++ src/ejabberd_config.erl | 7 +++++-- src/mod_last.erl | 35 ++++++++++++++++++++++++++++------- src/mod_last_odbc.erl | 33 +++++++++++++++++++++++++++------ 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8574d1808..dc97f4d67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2008-12-23 Badlop + * src/mod_last.erl: Implement workaround for uptime statistic in + 32 bit machines, so it can show uptime greater than 50 + days (EJAB-610) + * src/mod_last_odbc.erl: Likewise + * src/ejabberd_config.erl: Store start time in local_config table + * src/cyrsasl_digest.erl: Check digest-uri in SASL digest authentication (thanks to Paul Guyot)(EJAB-569) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 182b4a216..6ee0fa528 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -55,7 +55,10 @@ start() -> {attributes, record_info(fields, local_config)}]), mnesia:add_table_copy(local_config, node(), ram_copies), Config = get_ejabberd_config_path(), - load_file(Config). + load_file(Config), + %% This start time is used by mod_last: + add_local_option(node_start, now()), + ok. %% @doc Get the filename of the ejabberd configuration file. %% The filename can be specified with: erl -config "/path/to/ejabberd.cfg". @@ -76,7 +79,7 @@ get_ejabberd_config_path() -> %% @doc Load the ejabberd configuration file. %% It also includes additional configuration files and replaces macros. -%% @spec (File::string()) -> [term()] +%% @spec (File::string()) -> ok load_file(File) -> Terms = get_plain_terms_file(File), State = lists:foldl(fun search_hosts/2, #state{}, Terms), diff --git a/src/mod_last.erl b/src/mod_last.erl index a6eb9d5ad..aac37ec59 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -68,12 +68,16 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST). +%%% +%%% Uptime of ejabberd node +%%% + process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of set -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; get -> - Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), + Sec = get_node_uptime(), IQ#iq{type = result, sub_el = [{xmlelement, "query", [{"xmlns", ?NS_LAST}, @@ -81,6 +85,24 @@ process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> []}]} end. +%% @spec () -> integer() +%% @doc Get the uptime of the ejabberd node, expressed in seconds. +%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime. +get_node_uptime() -> + case ejabberd_config:get_local_option(node_start) of + {_, _, _} = StartNow -> + now_to_seconds(now()) - now_to_seconds(StartNow); + _undefined -> + trunc(element(1, erlang:statistics(wall_clock))/1000) + end. + +now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> + MegaSecs * 1000000 + Secs. + + +%%% +%%% Serve queries about user last online +%%% process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of @@ -126,8 +148,7 @@ get_last(IQ, SubEl, LUser, LServer) -> [] -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; [#last_activity{timestamp = TimeStamp, status = Status}] -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp2 = MegaSecs * 1000000 + Secs, + TimeStamp2 = now_to_seconds(now()), Sec = TimeStamp2 - TimeStamp, IQ#iq{type = result, sub_el = [{xmlelement, "query", @@ -139,8 +160,7 @@ get_last(IQ, SubEl, LUser, LServer) -> on_presence_update(User, Server, _Resource, Status) -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp = MegaSecs * 1000000 + Secs, + TimeStamp = now_to_seconds(now()), store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) -> @@ -153,8 +173,9 @@ store_last_info(User, Server, TimeStamp, Status) -> status = Status}) end, mnesia:transaction(F). - -%% Returns: {ok, Timestamp, Status} | not_found + +%% @spec (LUser::string(), LServer::string() -> +%% {ok, Timestamp::integer(), Status::string()} | not_found get_last_info(LUser, LServer) -> case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of {'EXIT', _Reason} -> diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 9253c09e1..9fd41da12 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -61,12 +61,16 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST). +%%% +%%% Uptime of ejabberd node +%%% + process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of set -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; get -> - Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), + Sec = get_node_uptime(), IQ#iq{type = result, sub_el = [{xmlelement, "query", [{"xmlns", ?NS_LAST}, @@ -74,6 +78,24 @@ process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> []}]} end. +%% @spec () -> integer() +%% @doc Get the uptime of the ejabberd node, expressed in seconds. +%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime. +get_node_uptime() -> + case ejabberd_config:get_local_option(node_start) of + {_, _, _} = StartNow -> + now_to_seconds(now()) - now_to_seconds(StartNow); + _undefined -> + trunc(element(1, erlang:statistics(wall_clock))/1000) + end. + +now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> + MegaSecs * 1000000 + Secs. + + +%%% +%%% Serve queries about user last online +%%% process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of set -> @@ -119,8 +141,7 @@ get_last(IQ, SubEl, LUser, LServer) -> {selected, ["seconds","state"], [{STimeStamp, Status}]} -> case catch list_to_integer(STimeStamp) of TimeStamp when is_integer(TimeStamp) -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp2 = MegaSecs * 1000000 + Secs, + TimeStamp2 = now_to_seconds(now()), Sec = TimeStamp2 - TimeStamp, IQ#iq{type = result, sub_el = [{xmlelement, "query", @@ -136,8 +157,7 @@ get_last(IQ, SubEl, LUser, LServer) -> end. on_presence_update(User, Server, _Resource, Status) -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp = MegaSecs * 1000000 + Secs, + TimeStamp = now_to_seconds(now()), store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) -> @@ -148,7 +168,8 @@ store_last_info(User, Server, TimeStamp, Status) -> State = ejabberd_odbc:escape(Status), odbc_queries:set_last_t(LServer, Username, Seconds, State). -%% Returns: {ok, Timestamp, Status} | not_found +%% @spec (LUser::string(), LServer::string() -> +%% {ok, Timestamp::integer(), Status::string()} | not_found get_last_info(LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_last(LServer, Username) of