mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-20 17:27:00 +01:00
* src/ejabberd_c2s.erl: Hibernate inactive c2s processes (EJAB-356).
SVN Revision: 934
This commit is contained in:
parent
f787a3ed71
commit
8d3d59535d
@ -87,6 +87,7 @@
|
||||
%% This is the timeout to apply between event when starting a new
|
||||
%% session:
|
||||
-define(C2S_OPEN_TIMEOUT, 5000).
|
||||
-define(C2S_HIBERNATE_TIMEOUT, 90000).
|
||||
|
||||
-define(STREAM_HEADER,
|
||||
"<?xml version='1.0'?>"
|
||||
@ -266,11 +267,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
c2s_stream_features,
|
||||
Server,
|
||||
[], [])}),
|
||||
{next_state, wait_for_feature_request,
|
||||
StateData#state{server = Server,
|
||||
sasl_state = SASLState,
|
||||
lang = Lang},
|
||||
?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_feature_request,
|
||||
StateData#state{
|
||||
server = Server,
|
||||
sasl_state = SASLState,
|
||||
lang = Lang});
|
||||
_ ->
|
||||
case StateData#state.resource of
|
||||
"" ->
|
||||
@ -281,17 +282,18 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
[{"xmlns", ?NS_BIND}], []},
|
||||
{xmlelement, "session",
|
||||
[{"xmlns", ?NS_SESSION}], []}]}),
|
||||
{next_state, wait_for_bind,
|
||||
StateData#state{server = Server,
|
||||
lang = Lang},
|
||||
?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_bind,
|
||||
StateData#state{
|
||||
server = Server,
|
||||
lang = Lang});
|
||||
_ ->
|
||||
send_element(
|
||||
StateData,
|
||||
{xmlelement, "stream:features", [], []}),
|
||||
{next_state, wait_for_session,
|
||||
StateData#state{server = Server,
|
||||
lang = Lang}}
|
||||
fsm_next_state(wait_for_session,
|
||||
StateData#state{
|
||||
server = Server,
|
||||
lang = Lang})
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
@ -311,9 +313,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
{stop, normal, StateData};
|
||||
true ->
|
||||
send_text(StateData, Header),
|
||||
{next_state, wait_for_auth,
|
||||
StateData#state{server = Server,
|
||||
lang = Lang}}
|
||||
fsm_next_state(wait_for_auth,
|
||||
StateData#state{
|
||||
server = Server,
|
||||
lang = Lang})
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
@ -385,13 +388,13 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
]}]}
|
||||
end,
|
||||
send_element(StateData, Res),
|
||||
{next_state, wait_for_auth, StateData, ?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_auth, StateData);
|
||||
{auth, _ID, set, {_U, _P, _D, ""}} ->
|
||||
Err = jlib:make_error_reply(
|
||||
El,
|
||||
?ERR_AUTH_NO_RESOURCE_PROVIDED(StateData#state.lang)),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_auth, StateData, ?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_auth, StateData);
|
||||
{auth, _ID, set, {U, P, D, R}} ->
|
||||
JID = jlib:make_jid(U, StateData#state.server, R),
|
||||
case (JID /= error) andalso
|
||||
@ -428,14 +431,15 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
privacy_get_user_list, StateData#state.server,
|
||||
none,
|
||||
[U, StateData#state.server]),
|
||||
{next_state, session_established,
|
||||
StateData#state{user = U,
|
||||
fsm_next_state(session_established,
|
||||
StateData#state{
|
||||
user = U,
|
||||
resource = R,
|
||||
jid = JID,
|
||||
sid = SID,
|
||||
pres_f = ?SETS:from_list(Fs1),
|
||||
pres_t = ?SETS:from_list(Ts1),
|
||||
privacy_list = PrivList}};
|
||||
privacy_list = PrivList});
|
||||
_ ->
|
||||
?INFO_MSG(
|
||||
"(~w) Failed legacy authentication for ~s",
|
||||
@ -444,8 +448,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
Err = jlib:make_error_reply(
|
||||
El, ?ERR_NOT_AUTHORIZED),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_auth, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_auth, StateData)
|
||||
end;
|
||||
_ ->
|
||||
if
|
||||
@ -456,8 +459,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
[StateData#state.socket, U, R]),
|
||||
Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_auth, StateData,
|
||||
?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_auth, StateData);
|
||||
true ->
|
||||
?INFO_MSG(
|
||||
"(~w) Forbidden legacy authentication for ~s",
|
||||
@ -465,13 +467,12 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
jlib:jid_to_string(JID)]),
|
||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_auth, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_auth, StateData)
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
process_unauthenticated_stanza(StateData, El),
|
||||
{next_state, wait_for_auth, StateData, ?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_auth, StateData)
|
||||
end;
|
||||
|
||||
wait_for_auth(timeout, StateData) ->
|
||||
@ -512,20 +513,20 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
U = xml:get_attr_s(username, Props),
|
||||
?INFO_MSG("(~w) Accepted authentication for ~s",
|
||||
[StateData#state.socket, U]),
|
||||
{next_state, wait_for_stream,
|
||||
StateData#state{streamid = new_id(),
|
||||
fsm_next_state(wait_for_stream,
|
||||
StateData#state{
|
||||
streamid = new_id(),
|
||||
authenticated = true,
|
||||
user = U
|
||||
}, ?C2S_OPEN_TIMEOUT};
|
||||
user = U });
|
||||
{continue, ServerOut, NewSASLState} ->
|
||||
send_element(StateData,
|
||||
{xmlelement, "challenge",
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
[{xmlcdata,
|
||||
jlib:encode_base64(ServerOut)}]}),
|
||||
{next_state, wait_for_sasl_response,
|
||||
StateData#state{sasl_state = NewSASLState},
|
||||
?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_sasl_response,
|
||||
StateData#state{
|
||||
sasl_state = NewSASLState});
|
||||
{error, Error, Username} ->
|
||||
?INFO_MSG(
|
||||
"(~w) Failed authentication for ~s@~s",
|
||||
@ -542,8 +543,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
{xmlelement, "failure",
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
[{xmlelement, Error, [], []}]}),
|
||||
{next_state, wait_for_feature_request, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_feature_request, StateData)
|
||||
end;
|
||||
{?NS_TLS, "starttls"} when TLS == true,
|
||||
TLSEnabled == false,
|
||||
@ -562,11 +562,11 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
Socket, TLSOpts,
|
||||
xml:element_to_string(
|
||||
{xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})),
|
||||
{next_state, wait_for_stream,
|
||||
StateData#state{socket = TLSSocket,
|
||||
streamid = new_id(),
|
||||
tls_enabled = true
|
||||
}, ?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_stream,
|
||||
StateData#state{socket = TLSSocket,
|
||||
streamid = new_id(),
|
||||
tls_enabled = true
|
||||
});
|
||||
{?NS_COMPRESS, "compress"} when Zlib == true,
|
||||
SockMod == gen_tcp ->
|
||||
case xml:get_subtag(El, "method") of
|
||||
@ -575,8 +575,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
{xmlelement, "failure",
|
||||
[{"xmlns", ?NS_COMPRESS}],
|
||||
[{xmlelement, "setup-failed", [], []}]}),
|
||||
{next_state, wait_for_feature_request, StateData,
|
||||
?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_feature_request, StateData);
|
||||
Method ->
|
||||
case xml:get_tag_cdata(Method) of
|
||||
"zlib" ->
|
||||
@ -586,18 +585,18 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
xml:element_to_string(
|
||||
{xmlelement, "compressed",
|
||||
[{"xmlns", ?NS_COMPRESS}], []})),
|
||||
{next_state, wait_for_stream,
|
||||
fsm_next_state(wait_for_stream,
|
||||
StateData#state{socket = ZlibSocket,
|
||||
streamid = new_id()
|
||||
}, ?C2S_OPEN_TIMEOUT};
|
||||
});
|
||||
_ ->
|
||||
send_element(StateData,
|
||||
{xmlelement, "failure",
|
||||
[{"xmlns", ?NS_COMPRESS}],
|
||||
[{xmlelement, "unsupported-method",
|
||||
[], []}]}),
|
||||
{next_state, wait_for_feature_request, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_feature_request,
|
||||
StateData)
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
@ -611,8 +610,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
{stop, normal, StateData};
|
||||
true ->
|
||||
process_unauthenticated_stanza(StateData, El),
|
||||
{next_state, wait_for_feature_request, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_feature_request, StateData)
|
||||
end
|
||||
end;
|
||||
|
||||
@ -647,19 +645,19 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
|
||||
U = xml:get_attr_s(username, Props),
|
||||
?INFO_MSG("(~w) Accepted authentication for ~s",
|
||||
[StateData#state.socket, U]),
|
||||
{next_state, wait_for_stream,
|
||||
StateData#state{streamid = new_id(),
|
||||
fsm_next_state(wait_for_stream,
|
||||
StateData#state{
|
||||
streamid = new_id(),
|
||||
authenticated = true,
|
||||
user = U
|
||||
}, ?C2S_OPEN_TIMEOUT};
|
||||
user = U});
|
||||
{continue, ServerOut, NewSASLState} ->
|
||||
send_element(StateData,
|
||||
{xmlelement, "challenge",
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
[{xmlcdata,
|
||||
jlib:encode_base64(ServerOut)}]}),
|
||||
{next_state, wait_for_sasl_response,
|
||||
StateData#state{sasl_state = NewSASLState}};
|
||||
fsm_next_state(wait_for_sasl_response,
|
||||
StateData#state{sasl_state = NewSASLState});
|
||||
{error, Error, Username} ->
|
||||
?INFO_MSG(
|
||||
"(~w) Failed authentication for ~s@~s",
|
||||
@ -669,20 +667,17 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
|
||||
{xmlelement, "failure",
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
[{xmlelement, Error, [], []}]}),
|
||||
{next_state, wait_for_feature_request, StateData,
|
||||
?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_feature_request, StateData);
|
||||
{error, Error} ->
|
||||
send_element(StateData,
|
||||
{xmlelement, "failure",
|
||||
[{"xmlns", ?NS_SASL}],
|
||||
[{xmlelement, Error, [], []}]}),
|
||||
{next_state, wait_for_feature_request, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_feature_request, StateData)
|
||||
end;
|
||||
_ ->
|
||||
process_unauthenticated_stanza(StateData, El),
|
||||
{next_state, wait_for_feature_request, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_feature_request, StateData)
|
||||
end;
|
||||
|
||||
wait_for_sasl_response(timeout, StateData) ->
|
||||
@ -717,7 +712,7 @@ wait_for_bind({xmlstreamelement, El}, StateData) ->
|
||||
error ->
|
||||
Err = jlib:make_error_reply(El, ?ERR_BAD_REQUEST),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_bind, StateData, ?C2S_OPEN_TIMEOUT};
|
||||
fsm_next_state(wait_for_bind, StateData);
|
||||
_ ->
|
||||
JID = jlib:make_jid(U, StateData#state.server, R),
|
||||
Res = IQ#iq{type = result,
|
||||
@ -727,12 +722,11 @@ wait_for_bind({xmlstreamelement, El}, StateData) ->
|
||||
[{xmlcdata,
|
||||
jlib:jid_to_string(JID)}]}]}]},
|
||||
send_element(StateData, jlib:iq_to_xml(Res)),
|
||||
{next_state, wait_for_session,
|
||||
StateData#state{resource = R, jid = JID},
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_session,
|
||||
StateData#state{resource = R, jid = JID})
|
||||
end;
|
||||
_ ->
|
||||
{next_state, wait_for_bind, StateData, ?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_bind, StateData)
|
||||
end;
|
||||
|
||||
wait_for_bind(timeout, StateData) ->
|
||||
@ -783,22 +777,22 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
||||
privacy_get_user_list, StateData#state.server,
|
||||
none,
|
||||
[U, StateData#state.server]),
|
||||
{next_state, session_established,
|
||||
StateData#state{sid = SID,
|
||||
fsm_next_state(session_established,
|
||||
StateData#state{
|
||||
sid = SID,
|
||||
pres_f = ?SETS:from_list(Fs1),
|
||||
pres_t = ?SETS:from_list(Ts1),
|
||||
privacy_list = PrivList}};
|
||||
privacy_list = PrivList});
|
||||
_ ->
|
||||
?INFO_MSG("(~w) Forbidden session for ~s",
|
||||
[StateData#state.socket,
|
||||
jlib:jid_to_string(JID)]),
|
||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_session, StateData,
|
||||
?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_session, StateData)
|
||||
end;
|
||||
_ ->
|
||||
{next_state, wait_for_session, StateData, ?C2S_OPEN_TIMEOUT}
|
||||
fsm_next_state(wait_for_session, StateData)
|
||||
end;
|
||||
|
||||
wait_for_session(timeout, StateData) ->
|
||||
@ -903,7 +897,16 @@ session_established({xmlstreamelement, El}, StateData) ->
|
||||
StateData
|
||||
end
|
||||
end,
|
||||
{next_state, session_established, NewState};
|
||||
fsm_next_state(session_established, NewState);
|
||||
|
||||
%% We hibernate the process to reduce memory consumption after a
|
||||
%% configurable activity timeout
|
||||
session_established(timeout, StateData) ->
|
||||
%% TODO: Options must be stored in state:
|
||||
Options = [],
|
||||
proc_lib:hibernate(gen_fsm, enter_loop,
|
||||
[?MODULE, Options, session_established, StateData]),
|
||||
fsm_next_state(session_established, StateData);
|
||||
|
||||
session_established({xmlstreamend, _Name}, StateData) ->
|
||||
send_text(StateData, ?STREAM_TRAILER),
|
||||
@ -938,7 +941,7 @@ session_established(closed, StateData) ->
|
||||
%% {stop, Reason, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
handle_event(_Event, StateName, StateData) ->
|
||||
{next_state, StateName, StateData}.
|
||||
fsm_next_state(StateName, StateData).
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_sync_event/4
|
||||
@ -958,12 +961,11 @@ handle_sync_event({get_presence}, _From, StateName, StateData) ->
|
||||
Resource = StateData#state.resource,
|
||||
|
||||
Reply = {User, Resource, Show, Status},
|
||||
{reply, Reply, StateName, StateData};
|
||||
fsm_reply(Reply, StateName, StateData);
|
||||
|
||||
handle_sync_event(_Event, _From, StateName, StateData) ->
|
||||
Reply = ok,
|
||||
{reply, Reply, StateName, StateData}.
|
||||
|
||||
fsm_reply(Reply, StateName, StateData).
|
||||
|
||||
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||
{ok, StateName, StateData}.
|
||||
@ -976,7 +978,7 @@ code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||
%%----------------------------------------------------------------------
|
||||
handle_info({send_text, Text}, StateName, StateData) ->
|
||||
send_text(StateData, Text),
|
||||
{next_state, StateName, StateData};
|
||||
fsm_next_state(StateName, StateData);
|
||||
handle_info(replaced, _StateName, StateData) ->
|
||||
Lang = StateData#state.lang,
|
||||
send_text(StateData,
|
||||
@ -1187,16 +1189,16 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||
ejabberd_hooks:run(user_receive_packet,
|
||||
StateData#state.server,
|
||||
[StateData#state.jid, From, To, FixedPacket]),
|
||||
{next_state, StateName, NewState};
|
||||
fsm_next_state(StateName, NewState);
|
||||
true ->
|
||||
{next_state, StateName, NewState}
|
||||
fsm_next_state(StateName, NewState)
|
||||
end;
|
||||
handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData)
|
||||
when Monitor == StateData#state.socket_monitor ->
|
||||
{stop, normal, StateData};
|
||||
handle_info(Info, StateName, StateData) ->
|
||||
?ERROR_MSG("Unexpected info: ~p", [Info]),
|
||||
{next_state, StateName, StateData}.
|
||||
fsm_next_state(StateName, StateData).
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: terminate/3
|
||||
@ -1858,3 +1860,17 @@ peerip(SockMod, Socket) ->
|
||||
{ok, IPOK} -> IPOK;
|
||||
_ -> undefined
|
||||
end.
|
||||
|
||||
%% fsm_next_state: Generate the next_state FSM tuple with different
|
||||
%% timeout, depending on the future state
|
||||
fsm_next_state(session_established, StateData) ->
|
||||
{next_state, session_established, StateData, ?C2S_HIBERNATE_TIMEOUT};
|
||||
fsm_next_state(StateName, StateData) ->
|
||||
{next_state, StateName, StateData, ?C2S_OPEN_TIMEOUT}.
|
||||
|
||||
%% fsm_reply: Generate the reply FSM tuple with different timeout,
|
||||
%% depending on the future state
|
||||
fsm_reply(Reply, session_established, StateData) ->
|
||||
{reply, Reply, session_established, StateData, ?C2S_HIBERNATE_TIMEOUT};
|
||||
fsm_reply(Reply, StateName, StateData) ->
|
||||
{reply, Reply, StateName, StateData, ?C2S_OPEN_TIMEOUT}.
|
||||
|
Loading…
Reference in New Issue
Block a user