mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-30 16:36:29 +01:00
Convert to exmpp.
SVN Revision: 1383
This commit is contained in:
parent
1a311a30b5
commit
22e79490ff
@ -13,6 +13,8 @@
|
|||||||
(send_element): For stanzas under the NS_JABBER_SERVER namespace, lie
|
(send_element): For stanzas under the NS_JABBER_SERVER namespace, lie
|
||||||
to exmpp_xml by telling it that this namespace is the default one.
|
to exmpp_xml by telling it that this namespace is the default one.
|
||||||
|
|
||||||
|
* src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl: Convert to exmpp.
|
||||||
|
|
||||||
2008-06-25 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
2008-06-25 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
||||||
|
|
||||||
* src/ejabberd_c2s.erl: Finish ejabberd_c2s conversion with the
|
* src/ejabberd_c2s.erl: Finish ejabberd_c2s conversion with the
|
||||||
|
@ -46,8 +46,9 @@
|
|||||||
handle_info/3,
|
handle_info/3,
|
||||||
terminate/3]).
|
terminate/3]).
|
||||||
|
|
||||||
|
-include("exmpp.hrl").
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("jlib.hrl").
|
|
||||||
-ifdef(SSL39).
|
-ifdef(SSL39).
|
||||||
-include_lib("ssl/include/ssl_pkix.hrl").
|
-include_lib("ssl/include/ssl_pkix.hrl").
|
||||||
-define(PKIXEXPLICIT, 'OTP-PKIX').
|
-define(PKIXEXPLICIT, 'OTP-PKIX').
|
||||||
@ -92,28 +93,10 @@
|
|||||||
[SockData, Opts])).
|
[SockData, Opts])).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-define(STREAM_HEADER(Version),
|
% These are the namespace already declared by the stream opening. This is
|
||||||
("<?xml version='1.0'?>"
|
% used at serialization time.
|
||||||
"<stream:stream "
|
-define(DEFAULT_NS, [?NS_JABBER_SERVER]).
|
||||||
"xmlns:stream='http://etherx.jabber.org/streams' "
|
-define(PREFIXED_NS, [{?NS_XMPP, "stream"}, {?NS_JABBER_DIALBACK, "db"}]).
|
||||||
"xmlns='jabber:server' "
|
|
||||||
"xmlns:db='jabber:server:dialback' "
|
|
||||||
"id='" ++ StateData#state.streamid ++ "'" ++ Version ++ ">")
|
|
||||||
).
|
|
||||||
|
|
||||||
-define(STREAM_TRAILER, "</stream:stream>").
|
|
||||||
|
|
||||||
-define(INVALID_NAMESPACE_ERR,
|
|
||||||
xml:element_to_string(?SERR_INVALID_NAMESPACE)).
|
|
||||||
|
|
||||||
-define(HOST_UNKNOWN_ERR,
|
|
||||||
xml:element_to_string(?SERR_HOST_UNKNOWN)).
|
|
||||||
|
|
||||||
-define(INVALID_FROM_ERR,
|
|
||||||
xml:element_to_string(?SERR_INVALID_FROM)).
|
|
||||||
|
|
||||||
-define(INVALID_XML_ERR,
|
|
||||||
xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)).
|
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% API
|
%%% API
|
||||||
@ -174,13 +157,16 @@ init([{SockMod, Socket}, Opts]) ->
|
|||||||
%% {stop, Reason, NewStateData}
|
%% {stop, Reason, NewStateData}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
|
|
||||||
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
wait_for_stream({xmlstreamstart, Opening}, StateData) ->
|
||||||
case {xml:get_attr_s("xmlns", Attrs),
|
case {exmpp_stream:get_default_ns(Opening),
|
||||||
xml:get_attr_s("xmlns:db", Attrs),
|
exmpp_xml:is_ns_declared_here(Opening, ?NS_JABBER_DIALBACK),
|
||||||
xml:get_attr_s("version", Attrs) == "1.0"} of
|
exmpp_stream:get_version(Opening) == {1, 0}} of
|
||||||
{"jabber:server", _, true} when
|
{?NS_JABBER_SERVER, _, true} when
|
||||||
StateData#state.tls and (not StateData#state.authenticated) ->
|
StateData#state.tls and (not StateData#state.authenticated) ->
|
||||||
send_text(StateData, ?STREAM_HEADER(" version='1.0'")),
|
Opening_Reply = exmpp_stream:opening_reply(Opening,
|
||||||
|
StateData#state.streamid),
|
||||||
|
send_element(StateData,
|
||||||
|
exmpp_stream:set_dialback_support(Opening_Reply)),
|
||||||
SASL =
|
SASL =
|
||||||
if
|
if
|
||||||
StateData#state.tls_enabled ->
|
StateData#state.tls_enabled ->
|
||||||
@ -190,10 +176,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
case (StateData#state.sockmod):get_verify_result(
|
case (StateData#state.sockmod):get_verify_result(
|
||||||
StateData#state.socket) of
|
StateData#state.socket) of
|
||||||
0 ->
|
0 ->
|
||||||
[{xmlelement, "mechanisms",
|
[exmpp_server_sasl:feature(
|
||||||
[{"xmlns", ?NS_SASL}],
|
["EXTERNAL"])];
|
||||||
[{xmlelement, "mechanism", [],
|
|
||||||
[{xmlcdata, "EXTERNAL"}]}]}];
|
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
end;
|
end;
|
||||||
@ -207,30 +191,35 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
StateData#state.tls_enabled ->
|
StateData#state.tls_enabled ->
|
||||||
[];
|
[];
|
||||||
true ->
|
true ->
|
||||||
[{xmlelement, "starttls",
|
[exmpp_server_tls:feature()]
|
||||||
[{"xmlns", ?NS_TLS}], []}]
|
|
||||||
end,
|
end,
|
||||||
send_element(StateData,
|
send_element(StateData, exmpp_stream:features(SASL ++ StartTLS)),
|
||||||
{xmlelement, "stream:features", [],
|
|
||||||
SASL ++ StartTLS}),
|
|
||||||
{next_state, wait_for_feature_request, StateData};
|
{next_state, wait_for_feature_request, StateData};
|
||||||
{"jabber:server", _, true} when
|
{?NS_JABBER_SERVER, _, true} when
|
||||||
StateData#state.authenticated ->
|
StateData#state.authenticated ->
|
||||||
send_text(StateData, ?STREAM_HEADER(" version='1.0'")),
|
Opening_Reply = exmpp_stream:opening_reply(Opening,
|
||||||
|
StateData#state.streamid),
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "stream:features", [], []}),
|
exmpp_stream:set_dialback_support(Opening_Reply)),
|
||||||
|
send_element(StateData, exmpp_stream:features([])),
|
||||||
{next_state, stream_established, StateData};
|
{next_state, stream_established, StateData};
|
||||||
{"jabber:server", "jabber:server:dialback", _} ->
|
{?NS_JABBER_SERVER, true, _} ->
|
||||||
send_text(StateData, ?STREAM_HEADER("")),
|
Opening_Reply = exmpp_stream:opening_reply(Opening,
|
||||||
|
StateData#state.streamid),
|
||||||
|
send_element(StateData,
|
||||||
|
exmpp_stream:set_dialback_support(Opening_Reply)),
|
||||||
{next_state, stream_established, StateData};
|
{next_state, stream_established, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
send_text(StateData, ?INVALID_NAMESPACE_ERR),
|
send_element(StateData, exmpp_stream:error('invalid-namespace')),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData,
|
Opening_Reply = exmpp_stream:opening_reply(undefined, ?NS_JABBER_SERVER,
|
||||||
?STREAM_HEADER("") ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
"", StateData#state.streamid),
|
||||||
|
send_element(StateData, Opening_Reply),
|
||||||
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream(timeout, StateData) ->
|
wait_for_stream(timeout, StateData) ->
|
||||||
@ -241,31 +230,29 @@ wait_for_stream(closed, StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||||
{xmlelement, Name, Attrs, Els} = El,
|
|
||||||
TLS = StateData#state.tls,
|
TLS = StateData#state.tls,
|
||||||
TLSEnabled = StateData#state.tls_enabled,
|
TLSEnabled = StateData#state.tls_enabled,
|
||||||
SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket),
|
SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket),
|
||||||
case {xml:get_attr_s("xmlns", Attrs), Name} of
|
case El of
|
||||||
{?NS_TLS, "starttls"} when TLS == true,
|
#xmlel{ns = ?NS_TLS, name = 'starttls'} when TLS == true,
|
||||||
TLSEnabled == false,
|
TLSEnabled == false,
|
||||||
SockMod == gen_tcp ->
|
SockMod == gen_tcp ->
|
||||||
?DEBUG("starttls", []),
|
?DEBUG("starttls", []),
|
||||||
Socket = StateData#state.socket,
|
Socket = StateData#state.socket,
|
||||||
|
Proceed = exmpp_xml:document_fragment_to_list(
|
||||||
|
exmpp_server_tls:proceed(), ?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
TLSOpts = StateData#state.tls_options,
|
TLSOpts = StateData#state.tls_options,
|
||||||
TLSSocket = (StateData#state.sockmod):starttls(
|
TLSSocket = (StateData#state.sockmod):starttls(
|
||||||
Socket, TLSOpts,
|
Socket, TLSOpts,
|
||||||
xml:element_to_string(
|
Proceed),
|
||||||
{xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})),
|
|
||||||
{next_state, wait_for_stream,
|
{next_state, wait_for_stream,
|
||||||
StateData#state{socket = TLSSocket,
|
StateData#state{socket = TLSSocket,
|
||||||
streamid = new_id(),
|
streamid = new_id(),
|
||||||
tls_enabled = true
|
tls_enabled = true
|
||||||
}};
|
}};
|
||||||
{?NS_SASL, "auth"} when TLSEnabled ->
|
#xmlel{ns = ?NS_SASL, name = 'auth'} when TLSEnabled ->
|
||||||
Mech = xml:get_attr_s("mechanism", Attrs),
|
case exmpp_server_sasl:next_step(El) of
|
||||||
case Mech of
|
{auth, "EXTERNAL", Auth} ->
|
||||||
"EXTERNAL" ->
|
|
||||||
Auth = jlib:decode_base64(xml:get_cdata(Els)),
|
|
||||||
AuthDomain = jlib:nameprep(Auth),
|
AuthDomain = jlib:nameprep(Auth),
|
||||||
AuthRes =
|
AuthRes =
|
||||||
case (StateData#state.sockmod):get_peer_certificate(
|
case (StateData#state.sockmod):get_peer_certificate(
|
||||||
@ -300,8 +287,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
(StateData#state.sockmod):reset_stream(
|
(StateData#state.sockmod):reset_stream(
|
||||||
StateData#state.socket),
|
StateData#state.socket),
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "success",
|
exmpp_server_sasl:success()),
|
||||||
[{"xmlns", ?NS_SASL}], []}),
|
|
||||||
?DEBUG("(~w) Accepted s2s authentication for ~s",
|
?DEBUG("(~w) Accepted s2s authentication for ~s",
|
||||||
[StateData#state.socket, AuthDomain]),
|
[StateData#state.socket, AuthDomain]),
|
||||||
{next_state, wait_for_stream,
|
{next_state, wait_for_stream,
|
||||||
@ -311,16 +297,14 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
}};
|
}};
|
||||||
true ->
|
true ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_sasl:failure()),
|
||||||
[{"xmlns", ?NS_SASL}], []}),
|
send_element(StateData,
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
exmpp_stream:closing()),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_sasl:failure('invalid-mechanism')),
|
||||||
[{"xmlns", ?NS_SASL}],
|
|
||||||
[{xmlelement, "invalid-mechanism", [], []}]}),
|
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
@ -328,11 +312,12 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
wait_for_feature_request({xmlstreamend, _Name}, StateData) ->
|
wait_for_feature_request({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_feature_request({xmlstreamerror, _}, StateData) ->
|
wait_for_feature_request({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_feature_request(closed, StateData) ->
|
wait_for_feature_request(closed, StateData) ->
|
||||||
@ -345,8 +330,8 @@ stream_established({xmlstreamelement, El}, StateData) ->
|
|||||||
case is_key_packet(El) of
|
case is_key_packet(El) of
|
||||||
{key, To, From, Id, Key} ->
|
{key, To, From, Id, Key} ->
|
||||||
?DEBUG("GET KEY: ~p", [{To, From, Id, Key}]),
|
?DEBUG("GET KEY: ~p", [{To, From, Id, Key}]),
|
||||||
LTo = jlib:nameprep(To),
|
LTo = exmpp_stringprep:nameprep(To),
|
||||||
LFrom = jlib:nameprep(From),
|
LFrom = exmpp_stringprep:nameprep(From),
|
||||||
%% Checks if the from domain is allowed and if the to
|
%% Checks if the from domain is allowed and if the to
|
||||||
%% domain is handled by this server:
|
%% domain is handled by this server:
|
||||||
case {ejabberd_s2s:allow_host(To, From),
|
case {ejabberd_s2s:allow_host(To, From),
|
||||||
@ -358,49 +343,56 @@ stream_established({xmlstreamelement, El}, StateData) ->
|
|||||||
Key, StateData#state.streamid}),
|
Key, StateData#state.streamid}),
|
||||||
Conns = ?DICT:store({LFrom, LTo}, wait_for_verification,
|
Conns = ?DICT:store({LFrom, LTo}, wait_for_verification,
|
||||||
StateData#state.connections),
|
StateData#state.connections),
|
||||||
change_shaper(StateData, LTo, jlib:make_jid("", LFrom, "")),
|
change_shaper(StateData, LTo,
|
||||||
|
exmpp_jid:make_bare_jid(undefined, LFrom)),
|
||||||
{next_state,
|
{next_state,
|
||||||
stream_established,
|
stream_established,
|
||||||
StateData#state{connections = Conns,
|
StateData#state{connections = Conns,
|
||||||
timer = Timer}};
|
timer = Timer}};
|
||||||
{_, false} ->
|
{_, false} ->
|
||||||
send_text(StateData, ?HOST_UNKNOWN_ERR),
|
send_element(StateData, exmpp_stream:error('host-unknown')),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
{false, _} ->
|
{false, _} ->
|
||||||
send_text(StateData, ?INVALID_FROM_ERR),
|
send_element(StateData, exmpp_stream:error('invalid-from')),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
{verify, To, From, Id, Key} ->
|
{verify, To, From, Id, Key} ->
|
||||||
?DEBUG("VERIFY KEY: ~p", [{To, From, Id, Key}]),
|
?DEBUG("VERIFY KEY: ~p", [{To, From, Id, Key}]),
|
||||||
LTo = jlib:nameprep(To),
|
LTo = exmpp_stringprep:nameprep(To),
|
||||||
LFrom = jlib:nameprep(From),
|
LFrom = exmpp_stringprep:nameprep(From),
|
||||||
Type = case ejabberd_s2s:has_key({LTo, LFrom}, Key) of
|
send_element(StateData, exmpp_dialback:verify_response(
|
||||||
true -> "valid";
|
El, ejabberd_s2s:has_key({LTo, LFrom}, Key))),
|
||||||
_ -> "invalid"
|
|
||||||
end,
|
|
||||||
%Type = if Key == Key1 -> "valid";
|
|
||||||
% true -> "invalid"
|
|
||||||
% end,
|
|
||||||
send_element(StateData,
|
|
||||||
{xmlelement,
|
|
||||||
"db:verify",
|
|
||||||
[{"from", To},
|
|
||||||
{"to", From},
|
|
||||||
{"id", Id},
|
|
||||||
{"type", Type}],
|
|
||||||
[]}),
|
|
||||||
{next_state, stream_established, StateData#state{timer = Timer}};
|
{next_state, stream_established, StateData#state{timer = Timer}};
|
||||||
_ ->
|
_ ->
|
||||||
NewEl = jlib:remove_attr("xmlns", El),
|
From = case exmpp_stanza:get_sender(El) of
|
||||||
{xmlelement, Name, Attrs, _Els} = NewEl,
|
undefined ->
|
||||||
From_s = xml:get_attr_s("from", Attrs),
|
error;
|
||||||
From = jlib:string_to_jid(From_s),
|
F ->
|
||||||
To_s = xml:get_attr_s("to", Attrs),
|
try
|
||||||
To = jlib:string_to_jid(To_s),
|
exmpp_jid:string_to_jid(F)
|
||||||
|
catch
|
||||||
|
_Exception1 -> error
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
To = case exmpp_stanza:get_recipient(El) of
|
||||||
|
undefined ->
|
||||||
|
error;
|
||||||
|
T ->
|
||||||
|
try
|
||||||
|
exmpp_jid:string_to_jid(T)
|
||||||
|
catch
|
||||||
|
_Exception2 -> error
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
% XXX OLD FORMAT: El.
|
||||||
|
% XXX No namespace conversion (:server <-> :client) is done.
|
||||||
|
% This is handled by C2S and S2S send_element functions.
|
||||||
|
ElOld = exmpp_xml:xmlel_to_xmlelement(El,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
if
|
if
|
||||||
(To /= error) and (From /= error) ->
|
(To /= error) and (From /= error) ->
|
||||||
LFrom = From#jid.lserver,
|
LFrom = From#jid.ldomain,
|
||||||
LTo = To#jid.lserver,
|
LTo = To#jid.ldomain,
|
||||||
if
|
if
|
||||||
StateData#state.authenticated ->
|
StateData#state.authenticated ->
|
||||||
case (LFrom == StateData#state.auth_domain)
|
case (LFrom == StateData#state.auth_domain)
|
||||||
@ -409,15 +401,19 @@ stream_established({xmlstreamelement, El}, StateData) ->
|
|||||||
LTo,
|
LTo,
|
||||||
ejabberd_router:dirty_get_all_domains()) of
|
ejabberd_router:dirty_get_all_domains()) of
|
||||||
true ->
|
true ->
|
||||||
if ((Name == "iq") or
|
Name = El#xmlel.name,
|
||||||
(Name == "message") or
|
if ((Name == 'iq') or
|
||||||
(Name == "presence")) ->
|
(Name == 'message') or
|
||||||
|
(Name == 'presence')) ->
|
||||||
|
% XXX OLD FORMAT: From, To.
|
||||||
|
FromOld = exmpp_jid:to_ejabberd_jid(From),
|
||||||
|
ToOld = exmpp_jid:to_ejabberd_jid(To),
|
||||||
ejabberd_hooks:run(
|
ejabberd_hooks:run(
|
||||||
s2s_receive_packet,
|
s2s_receive_packet,
|
||||||
LFrom,
|
LFrom,
|
||||||
[From, To, NewEl]),
|
[FromOld, ToOld, ElOld]),
|
||||||
ejabberd_router:route(
|
ejabberd_router:route(
|
||||||
From, To, NewEl);
|
FromOld, ToOld, ElOld);
|
||||||
true ->
|
true ->
|
||||||
error
|
error
|
||||||
end;
|
end;
|
||||||
@ -428,15 +424,19 @@ stream_established({xmlstreamelement, El}, StateData) ->
|
|||||||
case ?DICT:find({LFrom, LTo},
|
case ?DICT:find({LFrom, LTo},
|
||||||
StateData#state.connections) of
|
StateData#state.connections) of
|
||||||
{ok, established} ->
|
{ok, established} ->
|
||||||
if ((Name == "iq") or
|
Name = El#xmlel.name,
|
||||||
(Name == "message") or
|
if ((Name == 'iq') or
|
||||||
(Name == "presence")) ->
|
(Name == 'message') or
|
||||||
|
(Name == 'presence')) ->
|
||||||
|
% XXX OLD FORMAT: From, To.
|
||||||
|
FromOld = exmpp_jid:to_ejabberd_jid(From),
|
||||||
|
ToOld = exmpp_jid:to_ejabberd_jid(To),
|
||||||
ejabberd_hooks:run(
|
ejabberd_hooks:run(
|
||||||
s2s_receive_packet,
|
s2s_receive_packet,
|
||||||
LFrom,
|
LFrom,
|
||||||
[From, To, NewEl]),
|
[FromOld, ToOld, ElOld]),
|
||||||
ejabberd_router:route(
|
ejabberd_router:route(
|
||||||
From, To, NewEl);
|
FromOld, ToOld, ElOld);
|
||||||
true ->
|
true ->
|
||||||
error
|
error
|
||||||
end;
|
end;
|
||||||
@ -447,35 +447,24 @@ stream_established({xmlstreamelement, El}, StateData) ->
|
|||||||
true ->
|
true ->
|
||||||
error
|
error
|
||||||
end,
|
end,
|
||||||
ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, El}]),
|
ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, ElOld}]),
|
||||||
{next_state, stream_established, StateData#state{timer = Timer}}
|
{next_state, stream_established, StateData#state{timer = Timer}}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
stream_established({valid, From, To}, StateData) ->
|
stream_established({valid, From, To}, StateData) ->
|
||||||
send_element(StateData,
|
send_element(StateData, exmpp_dialback:validate(From, To)),
|
||||||
{xmlelement,
|
LFrom = exmpp_stringprep:nameprep(From),
|
||||||
"db:result",
|
LTo = exmpp_stringprep:nameprep(To),
|
||||||
[{"from", To},
|
|
||||||
{"to", From},
|
|
||||||
{"type", "valid"}],
|
|
||||||
[]}),
|
|
||||||
LFrom = jlib:nameprep(From),
|
|
||||||
LTo = jlib:nameprep(To),
|
|
||||||
NSD = StateData#state{
|
NSD = StateData#state{
|
||||||
connections = ?DICT:store({LFrom, LTo}, established,
|
connections = ?DICT:store({LFrom, LTo}, established,
|
||||||
StateData#state.connections)},
|
StateData#state.connections)},
|
||||||
{next_state, stream_established, NSD};
|
{next_state, stream_established, NSD};
|
||||||
|
|
||||||
stream_established({invalid, From, To}, StateData) ->
|
stream_established({invalid, From, To}, StateData) ->
|
||||||
send_element(StateData,
|
Valid = exmpp_dialback:validate(From, To),
|
||||||
{xmlelement,
|
send_element(StateData, exmpp_stanza:set_type(Valid, "invalid")),
|
||||||
"db:result",
|
LFrom = exmpp_stringprep:nameprep(From),
|
||||||
[{"from", To},
|
LTo = exmpp_stringprep:nameprep(To),
|
||||||
{"to", From},
|
|
||||||
{"type", "invalid"}],
|
|
||||||
[]}),
|
|
||||||
LFrom = jlib:nameprep(From),
|
|
||||||
LTo = jlib:nameprep(To),
|
|
||||||
NSD = StateData#state{
|
NSD = StateData#state{
|
||||||
connections = ?DICT:erase({LFrom, LTo},
|
connections = ?DICT:erase({LFrom, LTo},
|
||||||
StateData#state.connections)},
|
StateData#state.connections)},
|
||||||
@ -485,8 +474,8 @@ stream_established({xmlstreamend, _Name}, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
stream_established({xmlstreamerror, _}, StateData) ->
|
stream_established({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
stream_established(timeout, StateData) ->
|
stream_established(timeout, StateData) ->
|
||||||
@ -570,12 +559,21 @@ terminate(Reason, _StateName, StateData) ->
|
|||||||
send_text(StateData, Text) ->
|
send_text(StateData, Text) ->
|
||||||
(StateData#state.sockmod):send(StateData#state.socket, Text).
|
(StateData#state.sockmod):send(StateData#state.socket, Text).
|
||||||
|
|
||||||
|
|
||||||
|
send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) ->
|
||||||
|
send_text(StateData, exmpp_xml:document_to_list(El));
|
||||||
|
send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) ->
|
||||||
|
send_text(StateData, exmpp_xml:document_fragment_to_list(El,
|
||||||
|
[?NS_JABBER_CLIENT], ?PREFIXED_NS));
|
||||||
send_element(StateData, El) ->
|
send_element(StateData, El) ->
|
||||||
send_text(StateData, xml:element_to_string(El)).
|
send_text(StateData, exmpp_xml:document_fragment_to_list(El,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS)).
|
||||||
|
|
||||||
|
|
||||||
change_shaper(StateData, Host, JID) ->
|
change_shaper(StateData, Host, JID) ->
|
||||||
Shaper = acl:match_rule(Host, StateData#state.shaper, JID),
|
% XXX OLD FORMAT: JIDOld is an old #jid.
|
||||||
|
JIDOld = exmpp_jid:to_ejabberd_jid(JID),
|
||||||
|
Shaper = acl:match_rule(Host, StateData#state.shaper, JIDOld),
|
||||||
(StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper).
|
(StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper).
|
||||||
|
|
||||||
|
|
||||||
@ -592,18 +590,20 @@ cancel_timer(Timer) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:result" ->
|
is_key_packet(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'result',
|
||||||
|
attrs = Attrs} = El) ->
|
||||||
{key,
|
{key,
|
||||||
xml:get_attr_s("to", Attrs),
|
exmpp_stanza:get_recipient_from_attrs(Attrs),
|
||||||
xml:get_attr_s("from", Attrs),
|
exmpp_stanza:get_sender_from_attrs(Attrs),
|
||||||
xml:get_attr_s("id", Attrs),
|
exmpp_stanza:get_id_from_attrs(Attrs),
|
||||||
xml:get_cdata(Els)};
|
exmpp_xml:get_cdata_as_list(El)};
|
||||||
is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:verify" ->
|
is_key_packet(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'verify',
|
||||||
|
attrs = Attrs} = El) ->
|
||||||
{verify,
|
{verify,
|
||||||
xml:get_attr_s("to", Attrs),
|
exmpp_stanza:get_recipient_from_attrs(Attrs),
|
||||||
xml:get_attr_s("from", Attrs),
|
exmpp_stanza:get_sender_from_attrs(Attrs),
|
||||||
xml:get_attr_s("id", Attrs),
|
exmpp_stanza:get_id_from_attrs(Attrs),
|
||||||
xml:get_cdata(Els)};
|
exmpp_xml:get_cdata_as_list(El)};
|
||||||
is_key_packet(_) ->
|
is_key_packet(_) ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
@ -625,10 +625,10 @@ get_cert_domains(Cert) ->
|
|||||||
end,
|
end,
|
||||||
if
|
if
|
||||||
D /= error ->
|
D /= error ->
|
||||||
case jlib:string_to_jid(D) of
|
case exmpp_jid:string_to_jid(D) of
|
||||||
#jid{luser = "",
|
#jid{lnode = undefined,
|
||||||
lserver = LD,
|
ldomain = LD,
|
||||||
lresource = ""} ->
|
lresource = undefined} ->
|
||||||
[LD];
|
[LD];
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
@ -662,8 +662,8 @@ get_cert_domains(Cert) ->
|
|||||||
{ok, D} when is_binary(D) ->
|
{ok, D} when is_binary(D) ->
|
||||||
case jlib:string_to_jid(
|
case jlib:string_to_jid(
|
||||||
binary_to_list(D)) of
|
binary_to_list(D)) of
|
||||||
#jid{luser = "",
|
#jid{lnode = "",
|
||||||
lserver = LD,
|
ldomain = LD,
|
||||||
lresource = ""} ->
|
lresource = ""} ->
|
||||||
case idna:domain_utf8_to_ascii(LD) of
|
case idna:domain_utf8_to_ascii(LD) of
|
||||||
false ->
|
false ->
|
||||||
@ -678,10 +678,10 @@ get_cert_domains(Cert) ->
|
|||||||
[]
|
[]
|
||||||
end;
|
end;
|
||||||
({dNSName, D}) when is_list(D) ->
|
({dNSName, D}) when is_list(D) ->
|
||||||
case jlib:string_to_jid(D) of
|
case exmpp_jid:string_to_jid(D) of
|
||||||
#jid{luser = "",
|
#jid{lnode = undefined,
|
||||||
lserver = LD,
|
ldomain = LD,
|
||||||
lresource = ""} ->
|
lresource = undefined} ->
|
||||||
[LD];
|
[LD];
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
|
@ -54,8 +54,9 @@
|
|||||||
code_change/4,
|
code_change/4,
|
||||||
test_get_addr_port/1]).
|
test_get_addr_port/1]).
|
||||||
|
|
||||||
|
-include("exmpp.hrl").
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("jlib.hrl").
|
|
||||||
|
|
||||||
-record(state, {socket,
|
-record(state, {socket,
|
||||||
streamid,
|
streamid,
|
||||||
@ -72,7 +73,7 @@
|
|||||||
new = false, verify = false,
|
new = false, verify = false,
|
||||||
timer}).
|
timer}).
|
||||||
|
|
||||||
%%-define(DBGFSM, true).
|
%-define(DBGFSM, true).
|
||||||
|
|
||||||
-ifdef(DBGFSM).
|
-ifdef(DBGFSM).
|
||||||
-define(FSMOPTS, [{debug, [trace]}]).
|
-define(FSMOPTS, [{debug, [trace]}]).
|
||||||
@ -98,25 +99,10 @@
|
|||||||
%% Specified in miliseconds. Default value is 5 minutes.
|
%% Specified in miliseconds. Default value is 5 minutes.
|
||||||
-define(MAX_RETRY_DELAY, 300000).
|
-define(MAX_RETRY_DELAY, 300000).
|
||||||
|
|
||||||
-define(STREAM_HEADER,
|
% These are the namespace already declared by the stream opening. This is
|
||||||
"<?xml version='1.0'?>"
|
% used at serialization time.
|
||||||
"<stream:stream "
|
-define(DEFAULT_NS, [?NS_JABBER_SERVER]).
|
||||||
"xmlns:stream='http://etherx.jabber.org/streams' "
|
-define(PREFIXED_NS, [{?NS_XMPP, "stream"}, {?NS_JABBER_DIALBACK, "db"}]).
|
||||||
"xmlns='jabber:server' "
|
|
||||||
"xmlns:db='jabber:server:dialback' "
|
|
||||||
"to='~s'~s>"
|
|
||||||
).
|
|
||||||
|
|
||||||
-define(STREAM_TRAILER, "</stream:stream>").
|
|
||||||
|
|
||||||
-define(INVALID_NAMESPACE_ERR,
|
|
||||||
xml:element_to_string(?SERR_INVALID_NAMESPACE)).
|
|
||||||
|
|
||||||
-define(HOST_UNKNOWN_ERR,
|
|
||||||
xml:element_to_string(?SERR_HOST_UNKNOWN)).
|
|
||||||
|
|
||||||
-define(INVALID_XML_ERR,
|
|
||||||
xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)).
|
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% API
|
%%% API
|
||||||
@ -209,16 +195,19 @@ open_socket(init, StateData) ->
|
|||||||
{ok, Socket} ->
|
{ok, Socket} ->
|
||||||
Version = if
|
Version = if
|
||||||
StateData#state.use_v10 ->
|
StateData#state.use_v10 ->
|
||||||
" version='1.0'";
|
"1.0";
|
||||||
true ->
|
true ->
|
||||||
""
|
""
|
||||||
end,
|
end,
|
||||||
NewStateData = StateData#state{socket = Socket,
|
NewStateData = StateData#state{socket = Socket,
|
||||||
tls_enabled = false,
|
tls_enabled = false,
|
||||||
streamid = new_id()},
|
streamid = new_id()},
|
||||||
send_text(NewStateData, io_lib:format(?STREAM_HEADER,
|
Opening = exmpp_stream:opening(
|
||||||
[StateData#state.server,
|
StateData#state.server,
|
||||||
Version])),
|
?NS_JABBER_SERVER,
|
||||||
|
Version),
|
||||||
|
send_element(NewStateData,
|
||||||
|
exmpp_stream:set_dialback_support(Opening)),
|
||||||
{next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT};
|
{next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT};
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
?INFO_MSG("s2s connection: ~s -> ~s (remote server not found)",
|
?INFO_MSG("s2s connection: ~s -> ~s (remote server not found)",
|
||||||
@ -272,27 +261,27 @@ open_socket1(Addr, Port) ->
|
|||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
wait_for_stream({xmlstreamstart, Opening}, StateData) ->
|
||||||
case {xml:get_attr_s("xmlns", Attrs),
|
case {exmpp_stream:get_default_ns(Opening),
|
||||||
xml:get_attr_s("xmlns:db", Attrs),
|
exmpp_xml:is_ns_declared_here(Opening, ?NS_JABBER_DIALBACK),
|
||||||
xml:get_attr_s("version", Attrs) == "1.0"} of
|
exmpp_stream:get_version(Opening) == {1, 0}} of
|
||||||
{"jabber:server", "jabber:server:dialback", false} ->
|
{?NS_JABBER_SERVER, true, false} ->
|
||||||
send_db_request(StateData);
|
send_db_request(StateData);
|
||||||
{"jabber:server", "jabber:server:dialback", true} when
|
{?NS_JABBER_SERVER, true, true} when
|
||||||
StateData#state.use_v10 ->
|
StateData#state.use_v10 ->
|
||||||
{next_state, wait_for_features, StateData, ?FSMTIMEOUT};
|
{next_state, wait_for_features, StateData, ?FSMTIMEOUT};
|
||||||
{"jabber:server", "", true} when StateData#state.use_v10 ->
|
{?NS_JABBER_SERVER, false, true} when StateData#state.use_v10 ->
|
||||||
{next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT};
|
{next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT};
|
||||||
_ ->
|
_ ->
|
||||||
send_text(StateData, ?INVALID_NAMESPACE_ERR),
|
send_element(StateData, exmpp_stream:error('invalid-namespace')),
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace)",
|
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace)",
|
||||||
[StateData#state.myname, StateData#state.server]),
|
[StateData#state.myname, StateData#state.server]),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid xml)",
|
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid xml)",
|
||||||
[StateData#state.myname, StateData#state.server]),
|
[StateData#state.myname, StateData#state.server]),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -376,8 +365,8 @@ wait_for_validation({xmlstreamend, _Name}, StateData) ->
|
|||||||
wait_for_validation({xmlstreamerror, _}, StateData) ->
|
wait_for_validation({xmlstreamerror, _}, StateData) ->
|
||||||
?INFO_MSG("wait for validation: ~s -> ~s (xmlstreamerror)",
|
?INFO_MSG("wait for validation: ~s -> ~s (xmlstreamerror)",
|
||||||
[StateData#state.myname, StateData#state.server]),
|
[StateData#state.myname, StateData#state.server]),
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_validation(timeout, #state{verify = {VPid, VKey, SID}} = StateData)
|
wait_for_validation(timeout, #state{verify = {VPid, VKey, SID}} = StateData)
|
||||||
@ -401,41 +390,37 @@ wait_for_validation(closed, StateData) ->
|
|||||||
|
|
||||||
wait_for_features({xmlstreamelement, El}, StateData) ->
|
wait_for_features({xmlstreamelement, El}, StateData) ->
|
||||||
case El of
|
case El of
|
||||||
{xmlelement, "stream:features", _Attrs, Els} ->
|
#xmlel{ns = ?NS_XMPP, name = 'features'} = Features ->
|
||||||
{SASLEXT, StartTLS, StartTLSRequired} =
|
{SASLEXT, StartTLS, StartTLSRequired} =
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun({xmlelement, "mechanisms", Attrs1, Els1} = _El1,
|
fun(#xmlel{ns = ?NS_SASL, name = 'mechanisms'},
|
||||||
{_SEXT, STLS, STLSReq} = Acc) ->
|
{_SEXT, STLS, STLSReq} = Acc) ->
|
||||||
case xml:get_attr_s("xmlns", Attrs1) of
|
try
|
||||||
?NS_SASL ->
|
Mechs = exmpp_client_sasl:announced_mechanisms(
|
||||||
NewSEXT =
|
El),
|
||||||
lists:any(
|
NewSEXT = lists:member("EXTERNAL", Mechs),
|
||||||
fun({xmlelement, "mechanism", _, Els2}) ->
|
{NewSEXT, STLS, STLSReq}
|
||||||
case xml:get_cdata(Els2) of
|
catch
|
||||||
"EXTERNAL" -> true;
|
_Exception ->
|
||||||
_ -> false
|
|
||||||
end;
|
|
||||||
(_) -> false
|
|
||||||
end, Els1),
|
|
||||||
{NewSEXT, STLS, STLSReq};
|
|
||||||
_ ->
|
|
||||||
Acc
|
Acc
|
||||||
end;
|
end;
|
||||||
({xmlelement, "starttls", Attrs1, _Els1} = El1,
|
(#xmlel{ns = ?NS_TLS, name ='starttls'},
|
||||||
{SEXT, _STLS, _STLSReq} = Acc) ->
|
{SEXT, _STLS, _STLSReq} = Acc) ->
|
||||||
case xml:get_attr_s("xmlns", Attrs1) of
|
try
|
||||||
?NS_TLS ->
|
Support = exmpp_client_tls:announced_support(
|
||||||
Req = case xml:get_subtag(El1, "required") of
|
El),
|
||||||
{xmlelement, _, _, _} -> true;
|
case Support of
|
||||||
false -> false
|
none -> Acc;
|
||||||
end,
|
optional -> {SEXT, true, false};
|
||||||
{SEXT, true, Req};
|
required -> {SEXT, true, true}
|
||||||
_ ->
|
end
|
||||||
|
catch
|
||||||
|
_Exception ->
|
||||||
Acc
|
Acc
|
||||||
end;
|
end;
|
||||||
(_, Acc) ->
|
(_, Acc) ->
|
||||||
Acc
|
Acc
|
||||||
end, {false, false, false}, Els),
|
end, {false, false, false}, Features#xmlel.children),
|
||||||
if
|
if
|
||||||
(not SASLEXT) and (not StartTLS) and
|
(not SASLEXT) and (not StartTLS) and
|
||||||
StateData#state.authenticated ->
|
StateData#state.authenticated ->
|
||||||
@ -450,19 +435,14 @@ wait_for_features({xmlstreamelement, El}, StateData) ->
|
|||||||
SASLEXT and StateData#state.try_auth and
|
SASLEXT and StateData#state.try_auth and
|
||||||
(StateData#state.new /= false) ->
|
(StateData#state.new /= false) ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "auth",
|
exmpp_client_sasl:selected_mechanism("EXTERNAL",
|
||||||
[{"xmlns", ?NS_SASL},
|
StateData#state.myname)),
|
||||||
{"mechanism", "EXTERNAL"}],
|
|
||||||
[{xmlcdata,
|
|
||||||
jlib:encode_base64(
|
|
||||||
StateData#state.myname)}]}),
|
|
||||||
{next_state, wait_for_auth_result,
|
{next_state, wait_for_auth_result,
|
||||||
StateData#state{try_auth = false}, ?FSMTIMEOUT};
|
StateData#state{try_auth = false}, ?FSMTIMEOUT};
|
||||||
StartTLS and StateData#state.tls and
|
StartTLS and StateData#state.tls and
|
||||||
(not StateData#state.tls_enabled) ->
|
(not StateData#state.tls_enabled) ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "starttls",
|
exmpp_client_tls:starttls()),
|
||||||
[{"xmlns", ?NS_TLS}], []}),
|
|
||||||
{next_state, wait_for_starttls_proceed, StateData,
|
{next_state, wait_for_starttls_proceed, StateData,
|
||||||
?FSMTIMEOUT};
|
?FSMTIMEOUT};
|
||||||
StartTLSRequired and (not StateData#state.tls) ->
|
StartTLSRequired and (not StateData#state.tls) ->
|
||||||
@ -483,9 +463,8 @@ wait_for_features({xmlstreamelement, El}, StateData) ->
|
|||||||
use_v10 = false}, ?FSMTIMEOUT}
|
use_v10 = false}, ?FSMTIMEOUT}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('bad-format')),
|
||||||
xml:element_to_string(?SERR_BAD_FORMAT) ++
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?STREAM_TRAILER),
|
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
||||||
[StateData#state.myname, StateData#state.server]),
|
[StateData#state.myname, StateData#state.server]),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
@ -496,8 +475,8 @@ wait_for_features({xmlstreamend, _Name}, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_features({xmlstreamerror, _}, StateData) ->
|
wait_for_features({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?INFO_MSG("wait for features: xmlstreamerror", []),
|
?INFO_MSG("wait for features: xmlstreamerror", []),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
@ -512,48 +491,29 @@ wait_for_features(closed, StateData) ->
|
|||||||
|
|
||||||
wait_for_auth_result({xmlstreamelement, El}, StateData) ->
|
wait_for_auth_result({xmlstreamelement, El}, StateData) ->
|
||||||
case El of
|
case El of
|
||||||
{xmlelement, "success", Attrs, _Els} ->
|
#xmlel{ns = ?NS_SASL, name = 'success'} ->
|
||||||
case xml:get_attr_s("xmlns", Attrs) of
|
?DEBUG("auth: ~p", [{StateData#state.myname,
|
||||||
?NS_SASL ->
|
StateData#state.server}]),
|
||||||
?DEBUG("auth: ~p", [{StateData#state.myname,
|
ejabberd_socket:reset_stream(StateData#state.socket),
|
||||||
StateData#state.server}]),
|
Opening = exmpp_stream:opening(
|
||||||
ejabberd_socket:reset_stream(StateData#state.socket),
|
StateData#state.server,
|
||||||
send_text(StateData,
|
?NS_JABBER_SERVER,
|
||||||
io_lib:format(?STREAM_HEADER,
|
"1.0"),
|
||||||
[StateData#state.server,
|
send_element(StateData,
|
||||||
" version='1.0'"])),
|
exmpp_stream:set_dialback_support(Opening)),
|
||||||
{next_state, wait_for_stream,
|
{next_state, wait_for_stream,
|
||||||
StateData#state{streamid = new_id(),
|
StateData#state{streamid = new_id(),
|
||||||
authenticated = true
|
authenticated = true
|
||||||
}, ?FSMTIMEOUT};
|
}, ?FSMTIMEOUT};
|
||||||
_ ->
|
#xmlel{ns = ?NS_SASL, name = 'failure'} ->
|
||||||
send_text(StateData,
|
?DEBUG("restarted: ~p", [{StateData#state.myname,
|
||||||
xml:element_to_string(?SERR_BAD_FORMAT) ++
|
StateData#state.server}]),
|
||||||
?STREAM_TRAILER),
|
ejabberd_socket:close(StateData#state.socket),
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
{next_state, reopen_socket,
|
||||||
[StateData#state.myname, StateData#state.server]),
|
StateData#state{socket = undefined}, ?FSMTIMEOUT};
|
||||||
{stop, normal, StateData}
|
|
||||||
end;
|
|
||||||
{xmlelement, "failure", Attrs, _Els} ->
|
|
||||||
case xml:get_attr_s("xmlns", Attrs) of
|
|
||||||
?NS_SASL ->
|
|
||||||
?DEBUG("restarted: ~p", [{StateData#state.myname,
|
|
||||||
StateData#state.server}]),
|
|
||||||
ejabberd_socket:close(StateData#state.socket),
|
|
||||||
{next_state, reopen_socket,
|
|
||||||
StateData#state{socket = undefined}, ?FSMTIMEOUT};
|
|
||||||
_ ->
|
|
||||||
send_text(StateData,
|
|
||||||
xml:element_to_string(?SERR_BAD_FORMAT) ++
|
|
||||||
?STREAM_TRAILER),
|
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
|
||||||
[StateData#state.myname, StateData#state.server]),
|
|
||||||
{stop, normal, StateData}
|
|
||||||
end;
|
|
||||||
_ ->
|
_ ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('bad-format')),
|
||||||
xml:element_to_string(?SERR_BAD_FORMAT) ++
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?STREAM_TRAILER),
|
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
||||||
[StateData#state.myname, StateData#state.server]),
|
[StateData#state.myname, StateData#state.server]),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
@ -564,8 +524,8 @@ wait_for_auth_result({xmlstreamend, _Name}, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_auth_result({xmlstreamerror, _}, StateData) ->
|
wait_for_auth_result({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?INFO_MSG("wait for auth result: xmlstreamerror", []),
|
?INFO_MSG("wait for auth result: xmlstreamerror", []),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
@ -580,42 +540,36 @@ wait_for_auth_result(closed, StateData) ->
|
|||||||
|
|
||||||
wait_for_starttls_proceed({xmlstreamelement, El}, StateData) ->
|
wait_for_starttls_proceed({xmlstreamelement, El}, StateData) ->
|
||||||
case El of
|
case El of
|
||||||
{xmlelement, "proceed", Attrs, _Els} ->
|
#xmlel{ns = ?NS_TLS, name = 'proceed'} ->
|
||||||
case xml:get_attr_s("xmlns", Attrs) of
|
?DEBUG("starttls: ~p", [{StateData#state.myname,
|
||||||
?NS_TLS ->
|
StateData#state.server}]),
|
||||||
?DEBUG("starttls: ~p", [{StateData#state.myname,
|
Socket = StateData#state.socket,
|
||||||
StateData#state.server}]),
|
TLSOpts = case ejabberd_config:get_local_option(
|
||||||
Socket = StateData#state.socket,
|
{domain_certfile,
|
||||||
TLSOpts = case ejabberd_config:get_local_option(
|
StateData#state.server}) of
|
||||||
{domain_certfile,
|
undefined ->
|
||||||
StateData#state.server}) of
|
StateData#state.tls_options;
|
||||||
undefined ->
|
CertFile ->
|
||||||
StateData#state.tls_options;
|
[{certfile, CertFile} |
|
||||||
CertFile ->
|
lists:keydelete(
|
||||||
[{certfile, CertFile} |
|
certfile, 1,
|
||||||
lists:keydelete(
|
StateData#state.tls_options)]
|
||||||
certfile, 1,
|
end,
|
||||||
StateData#state.tls_options)]
|
TLSSocket = ejabberd_socket:starttls(Socket, TLSOpts),
|
||||||
end,
|
NewStateData = StateData#state{socket = TLSSocket,
|
||||||
TLSSocket = ejabberd_socket:starttls(Socket, TLSOpts),
|
streamid = new_id(),
|
||||||
NewStateData = StateData#state{socket = TLSSocket,
|
tls_enabled = true
|
||||||
streamid = new_id(),
|
},
|
||||||
tls_enabled = true
|
Opening = exmpp_stream:opening(
|
||||||
},
|
StateData#state.server,
|
||||||
send_text(NewStateData,
|
?NS_JABBER_SERVER,
|
||||||
io_lib:format(?STREAM_HEADER,
|
"1.0"),
|
||||||
[StateData#state.server,
|
send_element(NewStateData,
|
||||||
" version='1.0'"])),
|
exmpp_stream:set_dialback_support(Opening)),
|
||||||
{next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT};
|
{next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT};
|
||||||
_ ->
|
|
||||||
send_text(StateData,
|
|
||||||
xml:element_to_string(?SERR_BAD_FORMAT) ++
|
|
||||||
?STREAM_TRAILER),
|
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
|
||||||
[StateData#state.myname, StateData#state.server]),
|
|
||||||
{stop, normal, StateData}
|
|
||||||
end;
|
|
||||||
_ ->
|
_ ->
|
||||||
|
send_element(StateData, exmpp_stream:error('bad-format')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)",
|
||||||
[StateData#state.myname, StateData#state.server]),
|
[StateData#state.myname, StateData#state.server]),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
@ -626,8 +580,8 @@ wait_for_starttls_proceed({xmlstreamend, _Name}, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_starttls_proceed({xmlstreamerror, _}, StateData) ->
|
wait_for_starttls_proceed({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?INFO_MSG("wait for starttls proceed: xmlstreamerror", []),
|
?INFO_MSG("wait for starttls proceed: xmlstreamerror", []),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
@ -690,8 +644,8 @@ stream_established({xmlstreamend, _Name}, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
stream_established({xmlstreamerror, _}, StateData) ->
|
stream_established({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData,
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?INFO_MSG("stream established: ~s -> ~s (xmlstreamerror)",
|
?INFO_MSG("stream established: ~s -> ~s (xmlstreamerror)",
|
||||||
[StateData#state.myname, StateData#state.server]),
|
[StateData#state.myname, StateData#state.server]),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -759,7 +713,10 @@ handle_info({send_text, Text}, StateName, StateData) ->
|
|||||||
{next_state, StateName, StateData#state{timer = Timer},
|
{next_state, StateName, StateData#state{timer = Timer},
|
||||||
get_timeout_interval(StateName)};
|
get_timeout_interval(StateName)};
|
||||||
|
|
||||||
handle_info({send_element, El}, StateName, StateData) ->
|
handle_info({send_element, ElOld}, StateName, StateData) ->
|
||||||
|
% XXX OLD FORMAT: El.
|
||||||
|
El = exmpp_xml:xmlelement_to_xmlel(ElOld,
|
||||||
|
[?NS_JABBER_CLIENT], ?PREFIXED_NS),
|
||||||
case StateName of
|
case StateName of
|
||||||
stream_established ->
|
stream_established ->
|
||||||
cancel_timer(StateData#state.timer),
|
cancel_timer(StateData#state.timer),
|
||||||
@ -769,7 +726,7 @@ handle_info({send_element, El}, StateName, StateData) ->
|
|||||||
%% In this state we bounce all message: We are waiting before
|
%% In this state we bounce all message: We are waiting before
|
||||||
%% trying to reconnect
|
%% trying to reconnect
|
||||||
wait_before_retry ->
|
wait_before_retry ->
|
||||||
bounce_element(El, ?ERR_REMOTE_SERVER_NOT_FOUND),
|
bounce_element(El, 'remote-server-not-found'),
|
||||||
{next_state, StateName, StateData};
|
{next_state, StateName, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
Q = queue:in(El, StateData#state.queue),
|
Q = queue:in(El, StateData#state.queue),
|
||||||
@ -811,8 +768,8 @@ terminate(Reason, StateName, StateData) ->
|
|||||||
{StateData#state.myname, StateData#state.server}, self(), Key)
|
{StateData#state.myname, StateData#state.server}, self(), Key)
|
||||||
end,
|
end,
|
||||||
%% bounce queue manage by process and Erlang message queue
|
%% bounce queue manage by process and Erlang message queue
|
||||||
bounce_queue(StateData#state.queue, ?ERR_REMOTE_SERVER_NOT_FOUND),
|
bounce_queue(StateData#state.queue, 'remote-server-not-found'),
|
||||||
bounce_messages(?ERR_REMOTE_SERVER_NOT_FOUND),
|
bounce_messages('remote-server-not-found'),
|
||||||
case StateData#state.socket of
|
case StateData#state.socket of
|
||||||
undefined ->
|
undefined ->
|
||||||
ok;
|
ok;
|
||||||
@ -828,8 +785,14 @@ terminate(Reason, StateName, StateData) ->
|
|||||||
send_text(StateData, Text) ->
|
send_text(StateData, Text) ->
|
||||||
ejabberd_socket:send(StateData#state.socket, Text).
|
ejabberd_socket:send(StateData#state.socket, Text).
|
||||||
|
|
||||||
|
send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) ->
|
||||||
|
send_text(StateData, exmpp_xml:document_to_list(El));
|
||||||
|
send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) ->
|
||||||
|
send_text(StateData, exmpp_xml:document_fragment_to_list(El,
|
||||||
|
[?NS_JABBER_CLIENT], ?PREFIXED_NS));
|
||||||
send_element(StateData, El) ->
|
send_element(StateData, El) ->
|
||||||
send_text(StateData, xml:element_to_string(El)).
|
send_text(StateData, exmpp_xml:document_fragment_to_list(El,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS)).
|
||||||
|
|
||||||
send_queue(StateData, Q) ->
|
send_queue(StateData, Q) ->
|
||||||
case queue:out(Q) of
|
case queue:out(Q) of
|
||||||
@ -840,24 +803,31 @@ send_queue(StateData, Q) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Bounce a single message (xmlelement)
|
%% Bounce a single message (xmlel)
|
||||||
bounce_element(El, Error) ->
|
bounce_element(El, Condition) ->
|
||||||
{xmlelement, _Name, Attrs, _SubTags} = El,
|
case exmpp_stanza:get_type(El) of
|
||||||
case xml:get_attr_s("type", Attrs) of
|
|
||||||
"error" -> ok;
|
"error" -> ok;
|
||||||
"result" -> ok;
|
"result" -> ok;
|
||||||
_ ->
|
_ ->
|
||||||
Err = jlib:make_error_reply(El, Error),
|
Error = exmpp_stanza:error(El#xmlel.ns, Condition),
|
||||||
From = jlib:string_to_jid(xml:get_tag_attr_s("from", El)),
|
Err = exmpp_stanza:reply_with_error(El, Error),
|
||||||
To = jlib:string_to_jid(xml:get_tag_attr_s("to", El)),
|
From = exmpp_jid:string_to_jid(exmpp_stanza:get_sender(El)),
|
||||||
ejabberd_router:route(To, From, Err)
|
To = exmpp_jid:string_to_jid(exmpp_stanza:get_recipient(El)),
|
||||||
|
% XXX OLD FORMAT: From, To, Err.
|
||||||
|
% XXX No namespace conversion (:server <-> :client) is done.
|
||||||
|
% This is handled by C2S and S2S send_element functions.
|
||||||
|
ErrOld = exmpp_xml:xmlel_to_xmlelement(Err,
|
||||||
|
[?NS_JABBER_CLIENT], ?PREFIXED_NS),
|
||||||
|
FromOld = exmpp_jid:to_ejabberd_jid(From),
|
||||||
|
ToOld = exmpp_jid:to_ejabberd_jid(To),
|
||||||
|
ejabberd_router:route(ToOld, FromOld, ErrOld)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
bounce_queue(Q, Error) ->
|
bounce_queue(Q, Condition) ->
|
||||||
case queue:out(Q) of
|
case queue:out(Q) of
|
||||||
{{value, El}, Q1} ->
|
{{value, El}, Q1} ->
|
||||||
bounce_element(El, Error),
|
bounce_element(El, Condition),
|
||||||
bounce_queue(Q1, Error);
|
bounce_queue(Q1, Condition);
|
||||||
{empty, _} ->
|
{empty, _} ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
@ -874,11 +844,14 @@ cancel_timer(Timer) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
bounce_messages(Error) ->
|
bounce_messages(Condition) ->
|
||||||
receive
|
receive
|
||||||
{send_element, El} ->
|
{send_element, ElOld} ->
|
||||||
bounce_element(El, Error),
|
% XXX OLD FORMAT: El.
|
||||||
bounce_messages(Error)
|
El = exmpp_xml:xmlelement_to_xmlel(ElOld,
|
||||||
|
[?NS_JABBER_CLIENT], ?PREFIXED_NS),
|
||||||
|
bounce_element(El, Condition),
|
||||||
|
bounce_messages(Condition)
|
||||||
after 0 ->
|
after 0 ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
@ -902,40 +875,33 @@ send_db_request(StateData) ->
|
|||||||
false ->
|
false ->
|
||||||
ok;
|
ok;
|
||||||
Key1 ->
|
Key1 ->
|
||||||
send_element(StateData,
|
send_element(StateData, exmpp_dialback:key(
|
||||||
{xmlelement,
|
StateData#state.myname, Server, Key1))
|
||||||
"db:result",
|
|
||||||
[{"from", StateData#state.myname},
|
|
||||||
{"to", Server}],
|
|
||||||
[{xmlcdata, Key1}]})
|
|
||||||
end,
|
end,
|
||||||
case StateData#state.verify of
|
case StateData#state.verify of
|
||||||
false ->
|
false ->
|
||||||
ok;
|
ok;
|
||||||
{_Pid, Key2, SID} ->
|
{_Pid, Key2, SID} ->
|
||||||
send_element(StateData,
|
send_element(StateData, exmpp_dialback:verify_request(
|
||||||
{xmlelement,
|
StateData#state.myname, StateData#state.server, SID, Key2))
|
||||||
"db:verify",
|
|
||||||
[{"from", StateData#state.myname},
|
|
||||||
{"to", StateData#state.server},
|
|
||||||
{"id", SID}],
|
|
||||||
[{xmlcdata, Key2}]})
|
|
||||||
end,
|
end,
|
||||||
{next_state, wait_for_validation, StateData#state{new = New}, ?FSMTIMEOUT*6}.
|
{next_state, wait_for_validation, StateData#state{new = New}, ?FSMTIMEOUT*6}.
|
||||||
|
|
||||||
|
|
||||||
is_verify_res({xmlelement, Name, Attrs, _Els}) when Name == "db:result" ->
|
is_verify_res(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'result',
|
||||||
|
attrs = Attrs}) ->
|
||||||
{result,
|
{result,
|
||||||
xml:get_attr_s("to", Attrs),
|
exmpp_stanza:get_recipient_from_attrs(Attrs),
|
||||||
xml:get_attr_s("from", Attrs),
|
exmpp_stanza:get_sender_from_attrs(Attrs),
|
||||||
xml:get_attr_s("id", Attrs),
|
exmpp_stanza:get_id_from_attrs(Attrs),
|
||||||
xml:get_attr_s("type", Attrs)};
|
exmpp_stanza:get_type_from_attrs(Attrs)};
|
||||||
is_verify_res({xmlelement, Name, Attrs, _Els}) when Name == "db:verify" ->
|
is_verify_res(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'verify',
|
||||||
|
attrs = Attrs}) ->
|
||||||
{verify,
|
{verify,
|
||||||
xml:get_attr_s("to", Attrs),
|
exmpp_stanza:get_recipient_from_attrs(Attrs),
|
||||||
xml:get_attr_s("from", Attrs),
|
exmpp_stanza:get_sender_from_attrs(Attrs),
|
||||||
xml:get_attr_s("id", Attrs),
|
exmpp_stanza:get_id_from_attrs(Attrs),
|
||||||
xml:get_attr_s("type", Attrs)};
|
exmpp_stanza:get_type_from_attrs(Attrs)};
|
||||||
is_verify_res(_) ->
|
is_verify_res(_) ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
@ -1032,8 +998,8 @@ get_timeout_interval(StateName) ->
|
|||||||
%% function that want to wait for a reconnect delay before stopping.
|
%% function that want to wait for a reconnect delay before stopping.
|
||||||
wait_before_reconnect(StateData) ->
|
wait_before_reconnect(StateData) ->
|
||||||
%% bounce queue manage by process and Erlang message queue
|
%% bounce queue manage by process and Erlang message queue
|
||||||
bounce_queue(StateData#state.queue, ?ERR_REMOTE_SERVER_NOT_FOUND),
|
bounce_queue(StateData#state.queue, 'remote-server-not-found'),
|
||||||
bounce_messages(?ERR_REMOTE_SERVER_NOT_FOUND),
|
bounce_messages('remote-server-not-found'),
|
||||||
cancel_timer(StateData#state.timer),
|
cancel_timer(StateData#state.timer),
|
||||||
Delay = case StateData#state.delay_to_retry of
|
Delay = case StateData#state.delay_to_retry of
|
||||||
undefined_delay ->
|
undefined_delay ->
|
||||||
|
Loading…
Reference in New Issue
Block a user