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