mirror of
https://github.com/processone/ejabberd.git
synced 2024-10-27 15:02:14 +01:00
BOSH module optimization and clean-up (thanks to Aleksey Shchepin and Mickaël Rémond)(EJAB-936)
SVN Revision: 2574
This commit is contained in:
parent
4d3708b637
commit
a033b06150
@ -67,6 +67,7 @@
|
|||||||
-record(state, {socket,
|
-record(state, {socket,
|
||||||
sockmod,
|
sockmod,
|
||||||
socket_monitor,
|
socket_monitor,
|
||||||
|
xml_socket,
|
||||||
streamid,
|
streamid,
|
||||||
sasl_state,
|
sasl_state,
|
||||||
access,
|
access,
|
||||||
@ -124,16 +125,12 @@
|
|||||||
|
|
||||||
-define(STREAM_TRAILER, "</stream:stream>").
|
-define(STREAM_TRAILER, "</stream:stream>").
|
||||||
|
|
||||||
-define(INVALID_NS_ERR,
|
-define(INVALID_NS_ERR, ?SERR_INVALID_NAMESPACE).
|
||||||
xml:element_to_string(?SERR_INVALID_NAMESPACE)).
|
-define(INVALID_XML_ERR, ?SERR_XML_NOT_WELL_FORMED).
|
||||||
-define(INVALID_XML_ERR,
|
-define(HOST_UNKNOWN_ERR, ?SERR_HOST_UNKNOWN).
|
||||||
xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)).
|
|
||||||
-define(HOST_UNKNOWN_ERR,
|
|
||||||
xml:element_to_string(?SERR_HOST_UNKNOWN)).
|
|
||||||
-define(POLICY_VIOLATION_ERR(Lang, Text),
|
-define(POLICY_VIOLATION_ERR(Lang, Text),
|
||||||
xml:element_to_string(?SERRT_POLICY_VIOLATION(Lang, Text))).
|
?SERRT_POLICY_VIOLATION(Lang, Text)).
|
||||||
-define(INVALID_FROM,
|
-define(INVALID_FROM, ?SERR_INVALID_FROM).
|
||||||
xml:element_to_string(?SERR_INVALID_FROM)).
|
|
||||||
|
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -175,6 +172,11 @@ init([{SockMod, Socket}, Opts]) ->
|
|||||||
{value, {_, S}} -> S;
|
{value, {_, S}} -> S;
|
||||||
_ -> none
|
_ -> none
|
||||||
end,
|
end,
|
||||||
|
XMLSocket =
|
||||||
|
case lists:keysearch(xml_socket, 1, Opts) of
|
||||||
|
{value, {_, XS}} -> XS;
|
||||||
|
_ -> false
|
||||||
|
end,
|
||||||
Zlib = lists:member(zlib, Opts),
|
Zlib = lists:member(zlib, Opts),
|
||||||
StartTLS = lists:member(starttls, Opts),
|
StartTLS = lists:member(starttls, Opts),
|
||||||
StartTLSRequired = lists:member(starttls_required, Opts),
|
StartTLSRequired = lists:member(starttls_required, Opts),
|
||||||
@ -205,6 +207,7 @@ init([{SockMod, Socket}, Opts]) ->
|
|||||||
{ok, wait_for_stream, #state{socket = Socket1,
|
{ok, wait_for_stream, #state{socket = Socket1,
|
||||||
sockmod = SockMod,
|
sockmod = SockMod,
|
||||||
socket_monitor = SocketMonitor,
|
socket_monitor = SocketMonitor,
|
||||||
|
xml_socket = XMLSocket,
|
||||||
zlib = Zlib,
|
zlib = Zlib,
|
||||||
tls = TLS,
|
tls = TLS,
|
||||||
tls_required = StartTLSRequired,
|
tls_required = StartTLSRequired,
|
||||||
@ -231,9 +234,9 @@ get_subscribed(FsmRef) ->
|
|||||||
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||||
DefaultLang = case ?MYLANG of
|
DefaultLang = case ?MYLANG of
|
||||||
undefined ->
|
undefined ->
|
||||||
" xml:lang='en'";
|
"en";
|
||||||
DL ->
|
DL ->
|
||||||
" xml:lang='" ++ DL ++ "'"
|
DL
|
||||||
end,
|
end,
|
||||||
case xml:get_attr_s("xmlns:stream", Attrs) of
|
case xml:get_attr_s("xmlns:stream", Attrs) of
|
||||||
?NS_STREAM ->
|
?NS_STREAM ->
|
||||||
@ -244,12 +247,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
change_shaper(StateData, jlib:make_jid("", Server, "")),
|
change_shaper(StateData, jlib:make_jid("", Server, "")),
|
||||||
case xml:get_attr_s("version", Attrs) of
|
case xml:get_attr_s("version", Attrs) of
|
||||||
"1.0" ->
|
"1.0" ->
|
||||||
Header = io_lib:format(?STREAM_HEADER,
|
send_header(StateData, Server, "1.0", DefaultLang),
|
||||||
[StateData#state.streamid,
|
|
||||||
Server,
|
|
||||||
" version='1.0'",
|
|
||||||
DefaultLang]),
|
|
||||||
send_text(StateData, Header),
|
|
||||||
case StateData#state.authenticated of
|
case StateData#state.authenticated of
|
||||||
false ->
|
false ->
|
||||||
SASLState =
|
SASLState =
|
||||||
@ -351,22 +349,18 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Header = io_lib:format(
|
send_header(StateData, Server, "", DefaultLang),
|
||||||
?STREAM_HEADER,
|
|
||||||
[StateData#state.streamid, Server, "",
|
|
||||||
DefaultLang]),
|
|
||||||
if
|
if
|
||||||
(not StateData#state.tls_enabled) and
|
(not StateData#state.tls_enabled) and
|
||||||
StateData#state.tls_required ->
|
StateData#state.tls_required ->
|
||||||
send_text(StateData,
|
send_element(
|
||||||
Header ++
|
StateData,
|
||||||
?POLICY_VIOLATION_ERR(
|
?POLICY_VIOLATION_ERR(
|
||||||
Lang,
|
Lang,
|
||||||
"Use of STARTTLS required") ++
|
"Use of STARTTLS required")),
|
||||||
?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
true ->
|
true ->
|
||||||
send_text(StateData, Header),
|
|
||||||
fsm_next_state(wait_for_auth,
|
fsm_next_state(wait_for_auth,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
server = Server,
|
server = Server,
|
||||||
@ -374,20 +368,15 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Header = io_lib:format(
|
send_header(StateData, ?MYNAME, "", DefaultLang),
|
||||||
?STREAM_HEADER,
|
send_element(StateData, ?HOST_UNKNOWN_ERR),
|
||||||
[StateData#state.streamid, ?MYNAME, "",
|
send_trailer(StateData),
|
||||||
DefaultLang]),
|
|
||||||
send_text(StateData,
|
|
||||||
Header ++ ?HOST_UNKNOWN_ERR ++ ?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Header = io_lib:format(
|
send_header(StateData, ?MYNAME, "", DefaultLang),
|
||||||
?STREAM_HEADER,
|
send_element(StateData, ?INVALID_NS_ERR),
|
||||||
[StateData#state.streamid, ?MYNAME, "", DefaultLang]),
|
send_trailer(StateData),
|
||||||
send_text(StateData,
|
|
||||||
Header ++ ?INVALID_NS_ERR ++ ?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -395,18 +384,19 @@ wait_for_stream(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream({xmlstreamelement, _}, StateData) ->
|
wait_for_stream({xmlstreamelement, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream({xmlstreamend, _}, StateData) ->
|
wait_for_stream({xmlstreamend, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
||||||
Header = io_lib:format(?STREAM_HEADER,
|
send_header(StateData, ?MYNAME, "1.0", ""),
|
||||||
["none", ?MYNAME, " version='1.0'", ""]),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_text(StateData,
|
send_trailer(StateData),
|
||||||
Header ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream(closed, StateData) ->
|
wait_for_stream(closed, StateData) ->
|
||||||
@ -538,11 +528,12 @@ wait_for_auth(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_auth({xmlstreamend, _Name}, StateData) ->
|
wait_for_auth({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_auth({xmlstreamerror, _}, StateData) ->
|
wait_for_auth({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_auth(closed, StateData) ->
|
wait_for_auth(closed, StateData) ->
|
||||||
@ -665,10 +656,10 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
if
|
if
|
||||||
(SockMod == gen_tcp) and TLSRequired ->
|
(SockMod == gen_tcp) and TLSRequired ->
|
||||||
Lang = StateData#state.lang,
|
Lang = StateData#state.lang,
|
||||||
send_text(StateData, ?POLICY_VIOLATION_ERR(
|
send_element(StateData, ?POLICY_VIOLATION_ERR(
|
||||||
Lang,
|
Lang,
|
||||||
"Use of STARTTLS required") ++
|
"Use of STARTTLS required")),
|
||||||
?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
true ->
|
true ->
|
||||||
process_unauthenticated_stanza(StateData, El),
|
process_unauthenticated_stanza(StateData, El),
|
||||||
@ -680,11 +671,12 @@ wait_for_feature_request(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_feature_request({xmlstreamend, _Name}, StateData) ->
|
wait_for_feature_request({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{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, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_feature_request(closed, StateData) ->
|
wait_for_feature_request(closed, StateData) ->
|
||||||
@ -748,11 +740,12 @@ wait_for_sasl_response(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_sasl_response({xmlstreamend, _Name}, StateData) ->
|
wait_for_sasl_response({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_sasl_response({xmlstreamerror, _}, StateData) ->
|
wait_for_sasl_response({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_sasl_response(closed, StateData) ->
|
wait_for_sasl_response(closed, StateData) ->
|
||||||
@ -797,11 +790,12 @@ wait_for_bind(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_bind({xmlstreamend, _Name}, StateData) ->
|
wait_for_bind({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_bind({xmlstreamerror, _}, StateData) ->
|
wait_for_bind({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_bind(closed, StateData) ->
|
wait_for_bind(closed, StateData) ->
|
||||||
@ -868,11 +862,12 @@ wait_for_session(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_session({xmlstreamend, _Name}, StateData) ->
|
wait_for_session({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_session({xmlstreamerror, _}, StateData) ->
|
wait_for_session({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_session(closed, StateData) ->
|
wait_for_session(closed, StateData) ->
|
||||||
@ -884,7 +879,8 @@ session_established({xmlstreamelement, El}, StateData) ->
|
|||||||
% Check 'from' attribute in stanza RFC 3920 Section 9.1.2
|
% Check 'from' attribute in stanza RFC 3920 Section 9.1.2
|
||||||
case check_from(El, FromJID) of
|
case check_from(El, FromJID) of
|
||||||
'invalid-from' ->
|
'invalid-from' ->
|
||||||
send_text(StateData, ?INVALID_FROM ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_FROM),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
_NewEl ->
|
_NewEl ->
|
||||||
session_established2(El, StateData)
|
session_established2(El, StateData)
|
||||||
@ -900,16 +896,17 @@ session_established(timeout, StateData) ->
|
|||||||
fsm_next_state(session_established, StateData);
|
fsm_next_state(session_established, StateData);
|
||||||
|
|
||||||
session_established({xmlstreamend, _Name}, StateData) ->
|
session_established({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
session_established({xmlstreamerror, "XML stanza is too big" = E}, StateData) ->
|
session_established({xmlstreamerror, "XML stanza is too big" = E}, StateData) ->
|
||||||
Text = ?POLICY_VIOLATION_ERR(StateData#state.lang, E) ++ ?STREAM_TRAILER,
|
send_element(StateData, ?POLICY_VIOLATION_ERR(StateData#state.lang, E)),
|
||||||
send_text(StateData, Text),
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
session_established({xmlstreamerror, _}, StateData) ->
|
session_established({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
|
send_trailer(StateData),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
session_established(closed, StateData) ->
|
session_established(closed, StateData) ->
|
||||||
@ -1070,10 +1067,9 @@ handle_info({send_text, Text}, StateName, StateData) ->
|
|||||||
fsm_next_state(StateName, StateData);
|
fsm_next_state(StateName, StateData);
|
||||||
handle_info(replaced, _StateName, StateData) ->
|
handle_info(replaced, _StateName, StateData) ->
|
||||||
Lang = StateData#state.lang,
|
Lang = StateData#state.lang,
|
||||||
send_text(StateData,
|
send_element(StateData,
|
||||||
xml:element_to_string(
|
?SERRT_CONFLICT(Lang, "Replaced by new connection")),
|
||||||
?SERRT_CONFLICT(Lang, "Replaced by new connection"))
|
send_trailer(StateData),
|
||||||
++ ?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData#state{authenticated = replaced}};
|
{stop, normal, StateData#state{authenticated = replaced}};
|
||||||
%% Process Packets that are to be send to the user
|
%% Process Packets that are to be send to the user
|
||||||
handle_info({route, From, To, Packet}, StateName, StateData) ->
|
handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||||
@ -1273,18 +1269,15 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
|||||||
Pass == exit ->
|
Pass == exit ->
|
||||||
%% When Pass==exit, NewState contains a string instead of a #state{}
|
%% When Pass==exit, NewState contains a string instead of a #state{}
|
||||||
Lang = StateData#state.lang,
|
Lang = StateData#state.lang,
|
||||||
catch send_text(StateData,
|
send_element(StateData, ?SERRT_CONFLICT(Lang, NewState)),
|
||||||
xml:element_to_string(
|
send_trailer(StateData),
|
||||||
?SERRT_CONFLICT(Lang, NewState))
|
|
||||||
++ ?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
Pass ->
|
Pass ->
|
||||||
Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From),
|
Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From),
|
||||||
jlib:jid_to_string(To),
|
jlib:jid_to_string(To),
|
||||||
NewAttrs),
|
NewAttrs),
|
||||||
FixedPacket = {xmlelement, Name, Attrs2, Els},
|
FixedPacket = {xmlelement, Name, Attrs2, Els},
|
||||||
Text = xml:element_to_string(FixedPacket),
|
send_element(StateData, FixedPacket),
|
||||||
send_text(StateData, Text),
|
|
||||||
ejabberd_hooks:run(user_receive_packet,
|
ejabberd_hooks:run(user_receive_packet,
|
||||||
StateData#state.server,
|
StateData#state.server,
|
||||||
[StateData#state.jid, From, To, FixedPacket]),
|
[StateData#state.jid, From, To, FixedPacket]),
|
||||||
@ -1379,9 +1372,60 @@ send_text(StateData, Text) ->
|
|||||||
?DEBUG("Send XML on stream = ~p", [lists:flatten(Text)]),
|
?DEBUG("Send XML on stream = ~p", [lists:flatten(Text)]),
|
||||||
(StateData#state.sockmod):send(StateData#state.socket, Text).
|
(StateData#state.sockmod):send(StateData#state.socket, Text).
|
||||||
|
|
||||||
|
send_element(StateData, El) when StateData#state.xml_socket ->
|
||||||
|
(StateData#state.sockmod):send_xml(StateData#state.socket,
|
||||||
|
{xmlstreamelement, El});
|
||||||
send_element(StateData, El) ->
|
send_element(StateData, El) ->
|
||||||
send_text(StateData, xml:element_to_string(El)).
|
send_text(StateData, xml:element_to_string(El)).
|
||||||
|
|
||||||
|
send_header(StateData, Server, Version, Lang)
|
||||||
|
when StateData#state.xml_socket ->
|
||||||
|
VersionAttr =
|
||||||
|
case Version of
|
||||||
|
"" -> [];
|
||||||
|
_ -> [{"version", Version}]
|
||||||
|
end,
|
||||||
|
LangAttr =
|
||||||
|
case Lang of
|
||||||
|
"" -> [];
|
||||||
|
_ -> [{"xml:lang", Lang}]
|
||||||
|
end,
|
||||||
|
Header =
|
||||||
|
{xmlstreamstart,
|
||||||
|
"stream:stream",
|
||||||
|
VersionAttr ++
|
||||||
|
LangAttr ++
|
||||||
|
[{"xmlns", "jabber:client"},
|
||||||
|
{"xmlns:stream", "http://etherx.jabber.org/streams"},
|
||||||
|
{"id", StateData#state.streamid},
|
||||||
|
{"from", Server}]},
|
||||||
|
(StateData#state.sockmod):send_xml(
|
||||||
|
StateData#state.socket, Header);
|
||||||
|
send_header(StateData, Server, Version, Lang) ->
|
||||||
|
VersionStr =
|
||||||
|
case Version of
|
||||||
|
"" -> "";
|
||||||
|
_ -> [" version='", Version, "'"]
|
||||||
|
end,
|
||||||
|
LangStr =
|
||||||
|
case Lang of
|
||||||
|
"" -> "";
|
||||||
|
_ -> [" xml:lang='", Lang, "'"]
|
||||||
|
end,
|
||||||
|
Header = io_lib:format(?STREAM_HEADER,
|
||||||
|
[StateData#state.streamid,
|
||||||
|
Server,
|
||||||
|
VersionStr,
|
||||||
|
LangStr]),
|
||||||
|
send_text(StateData, Header).
|
||||||
|
|
||||||
|
send_trailer(StateData) when StateData#state.xml_socket ->
|
||||||
|
(StateData#state.sockmod):send_xml(
|
||||||
|
StateData#state.socket,
|
||||||
|
{xmlstreamend, "stream:stream"});
|
||||||
|
send_trailer(StateData) ->
|
||||||
|
send_text(StateData, ?STREAM_TRAILER).
|
||||||
|
|
||||||
|
|
||||||
new_id() ->
|
new_id() ->
|
||||||
randoms:get_string().
|
randoms:get_string().
|
||||||
|
@ -205,7 +205,7 @@ handle_cast(_Msg, State) ->
|
|||||||
handle_info({Tag, _TCPSocket, Data},
|
handle_info({Tag, _TCPSocket, Data},
|
||||||
#state{socket = Socket,
|
#state{socket = Socket,
|
||||||
sock_mod = SockMod} = State)
|
sock_mod = SockMod} = State)
|
||||||
when (Tag == tcp) or (Tag == ssl) ->
|
when (Tag == tcp) or (Tag == ssl) or (Tag == ejabberd_xml) ->
|
||||||
case SockMod of
|
case SockMod of
|
||||||
tls ->
|
tls ->
|
||||||
case tls:recv_data(Socket, Data) of
|
case tls:recv_data(Socket, Data) of
|
||||||
@ -294,6 +294,25 @@ activate_socket(#state{socket = Socket,
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% Data processing for connectors directly generating xmlelement in
|
||||||
|
%% Erlang data structure.
|
||||||
|
%% WARNING: Shaper does not work with Erlang data structure.
|
||||||
|
process_data([], State) ->
|
||||||
|
activate_socket(State),
|
||||||
|
State;
|
||||||
|
process_data([Element|Els], #state{c2s_pid = C2SPid} = State)
|
||||||
|
when element(1, Element) == xmlelement;
|
||||||
|
element(1, Element) == xmlstreamstart;
|
||||||
|
element(1, Element) == xmlstreamelement;
|
||||||
|
element(1, Element) == xmlstreamend ->
|
||||||
|
if
|
||||||
|
C2SPid == undefined ->
|
||||||
|
State;
|
||||||
|
true ->
|
||||||
|
catch gen_fsm:send_event(C2SPid, element_wrapper(Element)),
|
||||||
|
process_data(Els, State)
|
||||||
|
end;
|
||||||
|
%% Data processing for connectors receivind data as string.
|
||||||
process_data(Data,
|
process_data(Data,
|
||||||
#state{xml_stream_state = XMLStreamState,
|
#state{xml_stream_state = XMLStreamState,
|
||||||
shaper_state = ShaperState,
|
shaper_state = ShaperState,
|
||||||
@ -312,6 +331,16 @@ process_data(Data,
|
|||||||
State#state{xml_stream_state = XMLStreamState1,
|
State#state{xml_stream_state = XMLStreamState1,
|
||||||
shaper_state = NewShaperState}.
|
shaper_state = NewShaperState}.
|
||||||
|
|
||||||
|
%% Element coming from XML parser are wrapped inside xmlstreamelement
|
||||||
|
%% When we receive directly xmlelement tuple (from a socket module
|
||||||
|
%% speaking directly Erlang XML), we wrap it inside the same
|
||||||
|
%% xmlstreamelement coming from the XML parser.
|
||||||
|
element_wrapper(XMLElement)
|
||||||
|
when element(1, XMLElement) == xmlelement ->
|
||||||
|
{xmlstreamelement, XMLElement};
|
||||||
|
element_wrapper(Element) ->
|
||||||
|
Element.
|
||||||
|
|
||||||
close_stream(undefined) ->
|
close_stream(undefined) ->
|
||||||
ok;
|
ok;
|
||||||
close_stream(XMLStreamState) ->
|
close_stream(XMLStreamState) ->
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
compress/2,
|
compress/2,
|
||||||
reset_stream/1,
|
reset_stream/1,
|
||||||
send/2,
|
send/2,
|
||||||
|
send_xml/2,
|
||||||
change_shaper/2,
|
change_shaper/2,
|
||||||
monitor/1,
|
monitor/1,
|
||||||
get_sockmod/1,
|
get_sockmod/1,
|
||||||
@ -62,10 +63,18 @@ start(Module, SockMod, Socket, Opts) ->
|
|||||||
{value, {_, Size}} -> Size;
|
{value, {_, Size}} -> Size;
|
||||||
_ -> infinity
|
_ -> infinity
|
||||||
end,
|
end,
|
||||||
Receiver = ejabberd_receiver:start(Socket, SockMod, none, MaxStanzaSize),
|
{ReceiverMod, Receiver, RecRef} =
|
||||||
|
case catch SockMod:custom_receiver(Socket) of
|
||||||
|
{receiver, RecMod, RecPid} ->
|
||||||
|
{RecMod, RecPid, RecMod};
|
||||||
|
_ ->
|
||||||
|
RecPid = ejabberd_receiver:start(
|
||||||
|
Socket, SockMod, none, MaxStanzaSize),
|
||||||
|
{ejabberd_receiver, RecPid, RecPid}
|
||||||
|
end,
|
||||||
SocketData = #socket_state{sockmod = SockMod,
|
SocketData = #socket_state{sockmod = SockMod,
|
||||||
socket = Socket,
|
socket = Socket,
|
||||||
receiver = Receiver},
|
receiver = RecRef},
|
||||||
case Module:start({?MODULE, SocketData}, Opts) of
|
case Module:start({?MODULE, SocketData}, Opts) of
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
case SockMod:controlling_process(Socket, Receiver) of
|
case SockMod:controlling_process(Socket, Receiver) of
|
||||||
@ -74,7 +83,7 @@ start(Module, SockMod, Socket, Opts) ->
|
|||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
SockMod:close(Socket)
|
SockMod:close(Socket)
|
||||||
end,
|
end,
|
||||||
ejabberd_receiver:become_controller(Receiver, Pid);
|
ReceiverMod:become_controller(Receiver, Pid);
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
SockMod:close(Socket)
|
SockMod:close(Socket)
|
||||||
end;
|
end;
|
||||||
@ -143,18 +152,33 @@ compress(SocketData, Data) ->
|
|||||||
send(SocketData, Data),
|
send(SocketData, Data),
|
||||||
SocketData#socket_state{socket = ZlibSocket, sockmod = ejabberd_zlib}.
|
SocketData#socket_state{socket = ZlibSocket, sockmod = ejabberd_zlib}.
|
||||||
|
|
||||||
reset_stream(SocketData) ->
|
reset_stream(SocketData) when is_pid(SocketData#socket_state.receiver) ->
|
||||||
ejabberd_receiver:reset_stream(SocketData#socket_state.receiver).
|
ejabberd_receiver:reset_stream(SocketData#socket_state.receiver);
|
||||||
|
reset_stream(SocketData) when is_atom(SocketData#socket_state.receiver) ->
|
||||||
|
(SocketData#socket_state.receiver):reset_stream(
|
||||||
|
SocketData#socket_state.socket).
|
||||||
|
|
||||||
send(SocketData, Data) ->
|
send(SocketData, Data) ->
|
||||||
catch (SocketData#socket_state.sockmod):send(
|
catch (SocketData#socket_state.sockmod):send(
|
||||||
SocketData#socket_state.socket, Data).
|
SocketData#socket_state.socket, Data).
|
||||||
|
|
||||||
change_shaper(SocketData, Shaper) ->
|
send_xml(SocketData, Data) ->
|
||||||
ejabberd_receiver:change_shaper(SocketData#socket_state.receiver, Shaper).
|
catch (SocketData#socket_state.sockmod):send_xml(
|
||||||
|
SocketData#socket_state.socket, Data).
|
||||||
|
|
||||||
monitor(SocketData) ->
|
change_shaper(SocketData, Shaper)
|
||||||
erlang:monitor(process, SocketData#socket_state.receiver).
|
when is_pid(SocketData#socket_state.receiver) ->
|
||||||
|
ejabberd_receiver:change_shaper(SocketData#socket_state.receiver, Shaper);
|
||||||
|
change_shaper(SocketData, Shaper)
|
||||||
|
when is_atom(SocketData#socket_state.receiver) ->
|
||||||
|
(SocketData#socket_state.receiver):change_shaper(
|
||||||
|
SocketData#socket_state.socket, Shaper).
|
||||||
|
|
||||||
|
monitor(SocketData) when is_pid(SocketData#socket_state.receiver) ->
|
||||||
|
erlang:monitor(process, SocketData#socket_state.receiver);
|
||||||
|
monitor(SocketData) when is_atom(SocketData#socket_state.receiver) ->
|
||||||
|
(SocketData#socket_state.receiver):monitor(
|
||||||
|
SocketData#socket_state.socket).
|
||||||
|
|
||||||
get_sockmod(SocketData) ->
|
get_sockmod(SocketData) ->
|
||||||
SocketData#socket_state.sockmod.
|
SocketData#socket_state.sockmod.
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user