24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-07-14 23:44:18 +02:00

HTTP prebinding support (TECH-1327)

Example configuration:
{modules,
 [
  ...
  {mod_http_bind, [{prebind, true}]},
  ...
]}
This commit is contained in:
Evgeniy Khramtsov 2011-07-06 18:04:00 +10:00
parent b6a637c121
commit 302294faec
2 changed files with 82 additions and 16 deletions

View File

@ -273,7 +273,18 @@ init([{SockMod, Socket}, Opts, FSMLimitOpts]) ->
ip = IP,
redirect = Redirect,
fsm_limit_opts = FSMLimitOpts},
{ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}
case get_jid_from_opts(Opts) of
{ok, #jid{user = U, server = Server, resource = R} = JID} ->
?GEN_FSM:send_event(self(), open_session),
{ok, wait_for_session, StateData#state{
user = U,
server = Server,
resource = R,
jid = JID,
lang = ""}};
_ ->
{ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}
end
end;
init([StateName, StateData, _FSMLimitOpts]) ->
MRef = (StateData#state.sockmod):monitor(StateData#state.socket),
@ -1084,6 +1095,11 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
fsm_next_state(wait_for_session, StateData)
end;
wait_for_session(open_session, StateData) ->
El = {xmlelement, "iq", [{"type", "set"}, {"id", "session"}],
[{xmlelement, "session", [{"xmlns", ?NS_SESSION}], []}]},
wait_for_session({xmlstreamelement, El}, StateData);
wait_for_session(timeout, StateData) ->
{stop, normal, StateData};
@ -3497,3 +3513,21 @@ need_redirect(#state{redirect = true, user = User, server = Server}) ->
end;
need_redirect(_) ->
false.
get_jid_from_opts(Opts) ->
case lists:keysearch(jid, 1, Opts) of
{value, {_, JIDValue}} ->
JID = case JIDValue of
{_U, _S, _R} ->
jlib:make_jid(JIDValue);
_ when is_binary(JIDValue) ->
jlib:string_to_jid(binary_to_list(JIDValue));
_ when is_list(JIDValue) ->
jlib:string_to_jid(JIDValue);
_ ->
JIDValue
end,
{ok, JID};
_ ->
error
end.

View File

@ -13,7 +13,7 @@
-behaviour(gen_fsm).
%% External exports
-export([start_link/3,
-export([start_link/4,
init/1,
handle_event/3,
handle_sync_event/4,
@ -70,6 +70,7 @@
wait_timer,
ctime = 0,
timer,
jid,
pause=0,
unprocessed_req_list = [], % list of request that have been delayed for proper reordering: {Request, PID}
req_list = [], % list of requests (cache)
@ -124,7 +125,7 @@
start(XMPPDomain, Sid, Key, IP) ->
?DEBUG("Starting session", []),
SupervisorProc = gen_mod:get_module_proc(XMPPDomain, ?PROCNAME_MHB),
case catch supervisor:start_child(SupervisorProc, [Sid, Key, IP]) of
case catch supervisor:start_child(SupervisorProc, [XMPPDomain, Sid, Key, IP]) of
{ok, Pid} ->
{ok, Pid};
{error, _} = Err ->
@ -140,8 +141,8 @@ start(XMPPDomain, Sid, Key, IP) ->
{error, Exit}
end.
start_link(Sid, Key, IP) ->
gen_fsm:start_link(?MODULE, [Sid, Key, IP], ?FSMOPTS).
start_link(ServerHost, Sid, Key, IP) ->
gen_fsm:start_link(?MODULE, [ServerHost, Sid, Key, IP], ?FSMOPTS).
send({http_bind, FsmRef, _IP}, Packet) ->
gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
@ -333,7 +334,7 @@ handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs,
%% ignore |
%% {stop, StopReason}
%%----------------------------------------------------------------------
init([Sid, Key, IP]) ->
init([ServerHost, Sid, Key, IP]) ->
?DEBUG("started: ~p", [{Sid, Key, IP}]),
%% Read c2s options from the first ejabberd_c2s configuration in
@ -348,15 +349,25 @@ init([Sid, Key, IP]) ->
Shaper = none,
ShaperState = shaper:new(Shaper),
Socket = {http_bind, self(), IP},
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts),
Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []),
{ok, loop, #state{id = Sid,
key = Key,
socket = Socket,
shaper_state = ShaperState,
max_inactivity = ?MAX_INACTIVITY,
max_pause = ?MAX_PAUSE,
timer = Timer}}.
State = #state{id = Sid,
key = Key,
socket = Socket,
shaper_state = ShaperState,
max_inactivity = ?MAX_INACTIVITY,
max_pause = ?MAX_PAUSE,
timer = Timer},
case gen_mod:get_module_opt(ServerHost, mod_http_bind,
prebind, false) of
true ->
JID = make_random_jid(ServerHost),
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket,
[{jid, JID} | Opts]),
{ok, loop, State#state{jid = JID}};
false ->
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts),
{ok, loop, State}
end.
%%----------------------------------------------------------------------
%% Func: handle_event/3
@ -469,6 +480,11 @@ handle_sync_event(#http_put{payload_size = PayloadSize} = Request,
shaper_timer = NewShaperTimer});
%% HTTP GET: send packets to the client
handle_sync_event({http_get, _Rid, _Wait, _Hold}, _From,
StateName, #state{jid = JID} = StateData)
when JID /= undefined ->
%% This is a pre-bind state
{reply, {ok, {prebind, JID}}, StateName, StateData#state{jid = undefined}};
handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
%% setup timer
send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
@ -745,15 +761,16 @@ process_http_put(#http_put{rid = Rid, attrs = Attrs, payload = Payload,
ip = IP
});
C2SPid ->
JID = StateData#state.jid,
case StreamTo of
{To, ""} ->
{To, ""} when JID == undefined ->
gen_fsm:send_event(
C2SPid,
{xmlstreamstart, "stream:stream",
[{"to", To},
{"xmlns", ?NS_CLIENT},
{"xmlns:stream", ?NS_STREAM}]});
{To, Version} ->
{To, Version} when JID == undefined ->
gen_fsm:send_event(
C2SPid,
{xmlstreamstart, "stream:stream",
@ -950,6 +967,16 @@ prepare_response(Sess, Rid, OutputEls, StreamStart) ->
{200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"};
{ok, terminate} ->
{200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"};
{ok, {prebind, JID}} ->
{200, ?HEADER,
xml:element_to_string(
{xmlelement, "body",
[{"xmlns", ?NS_HTTP_BIND}, {"sid", Sess#http_bind.id},
{"rid", integer_to_list(Rid + 1)}],
[{xmlelement, "iq", [{"id", "pre_bind"}, {"type", "result"}],
[{xmlelement, "bind", [{"xmlns", ?NS_BIND}],
[{xmlelement, "jid", [],
[{xmlcdata, jlib:jid_to_string(JID)}]}]}]}]})};
{ok, ROutPacket} ->
OutPacket = lists:reverse(ROutPacket),
?DEBUG("OutPacket: ~p", [OutputEls++OutPacket]),
@ -1308,3 +1335,8 @@ get_session(SID) ->
_ ->
{error, enoent}
end.
make_random_jid(Host) ->
%% Copied from cyrsasl_anonymous.erl
User = lists:concat([randoms:get_string() | tuple_to_list(now())]),
jlib:make_jid(User, Host, randoms:get_string()).