Handles c2s connections.\\
Options: \texttt{access}, \texttt{certfile}, \texttt{ciphers},
\texttt{max\_ack\_queue}, \texttt{max\_fsm\_queue},
- \texttt{max\_stanza\_size}, \texttt{resume\_timeout},
- \texttt{shaper}, \texttt{starttls}, \texttt{starttls\_required},
+ \texttt{max\_stanza\_size}, \texttt{resend\_on\_timeout},
+ \texttt{resume\_timeout}, \texttt{shaper},
+ \texttt{starttls}, \texttt{starttls\_required},
\texttt{stream\_management}, \texttt{tls},
\texttt{zlib}, \texttt{tls\_compression}
\titem{\texttt{ejabberd\_s2s\_in}}
/"a"/"b": mod_foo
/"http-bind": mod_http_bind
\end{verbatim}
+ \titem{resend\_on\_timeout: true|false}
+ If \term{stream\_management} is enabled and this option is set to
+ \term{true}, any stanzas that weren't acknowledged by the client
+ will be resent on session timeout. This behavior might often be
+ desired, but could have unexpected results under certain
+ circumstances. For example, a message that was sent to two resources
+ might get resent to one of them if the other one timed out.
+ Therefore, the default value for this option is \term{false}, which
+ tells ejabberd to generate an error message instead. The option can
+ be specified for \term{ejabberd\_c2s} listeners.
\titem{resume\_timeout: Seconds}
This option configures the number of seconds until a session times
out if the connection is lost. During this period of time, a client
max_ack_queue,
pending_since,
resume_timeout,
+ resend_on_timeout,
n_stanzas_in = 0,
n_stanzas_out = 0,
lang}).
Timeout when is_integer(Timeout), Timeout >= 0 -> Timeout;
_ -> 300
end,
+ ResendOnTimeout = proplists:get_bool(resend_on_timeout, Opts),
IP = peerip(SockMod, Socket),
%% Check if IP is blacklisted:
case is_ip_blacklisted(IP) of
access = Access, shaper = Shaper, ip = IP,
sm_state = StreamMgmtState,
max_ack_queue = MaxAckQueue,
- resume_timeout = ResumeTimeout},
+ resume_timeout = ResumeTimeout,
+ resend_on_timeout = ResendOnTimeout},
{ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}
end.
StateData#state.pres_a, Packet),
presence_broadcast(StateData, From,
StateData#state.pres_i, Packet),
- resend_unacked_stanzas(StateData);
+ handle_unacked_stanzas(StateData);
_ ->
?INFO_MSG("(~w) Close session for ~s",
[StateData#state.socket,
presence_broadcast(StateData, From,
StateData#state.pres_i, Packet)
end,
- resend_unacked_stanzas(StateData)
+ handle_unacked_stanzas(StateData)
end,
bounce_messages();
true ->
{<<"previd">>, AttrId}],
children = []}),
SendFun = fun(_F, _T, El) -> send_element(NewState, El) end,
- resend_unacked_stanzas(NewState, SendFun),
+ handle_unacked_stanzas(NewState, SendFun),
send_element(NewState,
#xmlel{name = <<"r">>,
attrs = [{<<"xmlns">>, AttrXmlns}],
StateData
end.
-resend_unacked_stanzas(StateData, F) when StateData#state.sm_state == active;
+handle_unacked_stanzas(StateData, F) when StateData#state.sm_state == active;
StateData#state.sm_state == pending ->
Queue = StateData#state.ack_queue,
case queue:len(Queue) of
0 ->
ok;
N ->
- ?INFO_MSG("Resending ~B unacknowledged stanzas to ~s",
+ ?INFO_MSG("~B stanzas were not acknowledged by ~s",
[N, jlib:jid_to_string(StateData#state.jid)]),
lists:foreach(
- fun({Num, #xmlel{attrs = Attrs} = El}) ->
+ fun({_, #xmlel{attrs = Attrs} = El}) ->
From_s = xml:get_attr_s(<<"from">>, Attrs),
From = jlib:string_to_jid(From_s),
To_s = xml:get_attr_s(<<"to">>, Attrs),
To = jlib:string_to_jid(To_s),
- ?DEBUG("Resending unacknowledged stanza #~B from ~s to ~s",
- [Num, From_s, To_s]),
F(From, To, El)
end, queue:to_list(Queue))
end;
-resend_unacked_stanzas(_StateData, _F) ->
+handle_unacked_stanzas(_StateData, _F) ->
ok.
-resend_unacked_stanzas(StateData) when StateData#state.sm_state == active;
+handle_unacked_stanzas(StateData) when StateData#state.sm_state == active;
StateData#state.sm_state == pending ->
- resend_unacked_stanzas(StateData, fun ejabberd_router:route/3);
-resend_unacked_stanzas(_StateData) ->
+ F = case StateData#state.resend_on_timeout of
+ true ->
+ fun ejabberd_router:route/3;
+ false ->
+ fun(From, To, El) ->
+ Err = jlib:make_error_reply(El, ?ERR_SERVICE_UNAVAILABLE),
+ ejabberd_router:route(To, From, Err)
+ end
+ end,
+ handle_unacked_stanzas(StateData, F);
+handle_unacked_stanzas(_StateData) ->
ok.
inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) ->