2004-03-06 22:13:16 +01:00
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
%%% File : ejabberd_http_poll.erl
|
2007-11-01 14:59:29 +01:00
|
|
|
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
2004-03-06 22:13:16 +01:00
|
|
|
%%% Purpose : HTTP Polling support (JEP-0025)
|
2007-11-01 14:59:29 +01:00
|
|
|
%%% Created : 4 Mar 2004 by Alexey Shchepin <alexey@process-one.net>
|
2007-12-24 14:57:53 +01:00
|
|
|
%%%
|
|
|
|
%%%
|
2010-01-12 17:15:16 +01:00
|
|
|
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
2007-12-24 14:57:53 +01:00
|
|
|
%%%
|
|
|
|
%%% This program is free software; you can redistribute it and/or
|
|
|
|
%%% modify it under the terms of the GNU General Public License as
|
|
|
|
%%% published by the Free Software Foundation; either version 2 of the
|
|
|
|
%%% License, or (at your option) any later version.
|
|
|
|
%%%
|
|
|
|
%%% This program is distributed in the hope that it will be useful,
|
|
|
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
%%% General Public License for more details.
|
2009-01-19 15:47:33 +01:00
|
|
|
%%%
|
2007-12-24 14:57:53 +01:00
|
|
|
%%% You should have received a copy of the GNU General Public License
|
|
|
|
%%% along with this program; if not, write to the Free Software
|
|
|
|
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
|
|
%%% 02111-1307 USA
|
|
|
|
%%%
|
2004-03-06 22:13:16 +01:00
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
|
|
|
|
-module(ejabberd_http_poll).
|
2007-11-01 14:59:29 +01:00
|
|
|
-author('alexey@process-one.net').
|
2004-03-06 22:13:16 +01:00
|
|
|
|
2004-03-13 21:01:37 +01:00
|
|
|
-behaviour(gen_fsm).
|
|
|
|
|
2004-03-06 22:13:16 +01:00
|
|
|
%% External exports
|
2008-07-17 17:33:50 +02:00
|
|
|
-export([start_link/3,
|
2004-03-06 22:13:16 +01:00
|
|
|
init/1,
|
|
|
|
handle_event/3,
|
|
|
|
handle_sync_event/4,
|
|
|
|
code_change/4,
|
|
|
|
handle_info/3,
|
|
|
|
terminate/3,
|
|
|
|
send/2,
|
2006-02-03 04:28:15 +01:00
|
|
|
setopts/2,
|
2007-05-07 19:52:35 +02:00
|
|
|
sockname/1, peername/1,
|
2006-02-03 04:28:15 +01:00
|
|
|
controlling_process/2,
|
2004-03-06 22:13:16 +01:00
|
|
|
close/1,
|
2007-01-25 06:53:58 +01:00
|
|
|
process/2]).
|
2004-03-06 22:13:16 +01:00
|
|
|
|
2008-10-13 17:36:43 +02:00
|
|
|
-include_lib("exmpp/include/exmpp.hrl").
|
|
|
|
|
2004-03-06 22:13:16 +01:00
|
|
|
-include("ejabberd.hrl").
|
|
|
|
-include("ejabberd_http.hrl").
|
|
|
|
|
|
|
|
-record(http_poll, {id, pid}).
|
|
|
|
|
|
|
|
-record(state, {id,
|
|
|
|
key,
|
2008-07-17 17:33:50 +02:00
|
|
|
socket,
|
2004-03-06 22:13:16 +01:00
|
|
|
output = "",
|
|
|
|
input = "",
|
2006-06-02 15:16:21 +02:00
|
|
|
waiting_input = false, %% {ReceiverPid, Tag}
|
2006-05-15 17:45:52 +02:00
|
|
|
last_receiver,
|
2009-03-03 19:49:02 +01:00
|
|
|
http_poll_timeout,
|
2008-07-17 17:33:50 +02:00
|
|
|
timer}).
|
2004-03-06 22:13:16 +01:00
|
|
|
|
|
|
|
%-define(DBGFSM, true).
|
|
|
|
|
|
|
|
-ifdef(DBGFSM).
|
|
|
|
-define(FSMOPTS, [{debug, [trace]}]).
|
|
|
|
-else.
|
|
|
|
-define(FSMOPTS, []).
|
|
|
|
-endif.
|
|
|
|
|
2004-03-07 22:15:12 +01:00
|
|
|
-define(HTTP_POLL_TIMEOUT, 300000).
|
2004-03-13 21:01:37 +01:00
|
|
|
-define(CT, {"Content-Type", "text/xml; charset=utf-8"}).
|
|
|
|
-define(BAD_REQUEST, [?CT, {"Set-Cookie", "ID=-3:0; expires=-1"}]).
|
|
|
|
|
2008-10-13 17:36:43 +02:00
|
|
|
-define(PARSER_OPTIONS, [
|
|
|
|
{namespace, true},
|
|
|
|
{name_as_atom, true},
|
|
|
|
{autoload_known, true}
|
|
|
|
]).
|
2004-03-06 22:13:16 +01:00
|
|
|
|
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
%%% API
|
|
|
|
%%%----------------------------------------------------------------------
|
2008-07-17 17:33:50 +02:00
|
|
|
start(ID, Key, IP) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
mnesia:create_table(http_poll,
|
|
|
|
[{ram_copies, [node()]},
|
|
|
|
{attributes, record_info(fields, http_poll)}]),
|
2008-07-17 17:33:50 +02:00
|
|
|
supervisor:start_child(ejabberd_http_poll_sup, [ID, Key, IP]).
|
2004-03-06 22:13:16 +01:00
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
start_link(ID, Key, IP) ->
|
|
|
|
gen_fsm:start_link(?MODULE, [ID, Key, IP], ?FSMOPTS).
|
2004-03-06 22:13:16 +01:00
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
send({http_poll, FsmRef, _IP}, Packet) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
|
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
setopts({http_poll, FsmRef, _IP}, Opts) ->
|
2006-02-03 04:28:15 +01:00
|
|
|
case lists:member({active, once}, Opts) of
|
|
|
|
true ->
|
2006-10-01 03:53:37 +02:00
|
|
|
gen_fsm:send_all_state_event(FsmRef, {activate, self()});
|
2006-02-03 04:28:15 +01:00
|
|
|
_ ->
|
|
|
|
ok
|
|
|
|
end.
|
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
sockname(_Socket) ->
|
|
|
|
{ok, {{0, 0, 0, 0}, 0}}.
|
2007-05-07 19:52:35 +02:00
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
peername({http_poll, _FsmRef, IP}) ->
|
|
|
|
{ok, IP}.
|
2007-05-07 19:52:35 +02:00
|
|
|
|
2006-02-03 04:28:15 +01:00
|
|
|
controlling_process(_Socket, _Pid) ->
|
|
|
|
ok.
|
2004-03-06 22:13:16 +01:00
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
close({http_poll, FsmRef, _IP}) ->
|
2004-03-07 22:15:12 +01:00
|
|
|
catch gen_fsm:sync_send_all_state_event(FsmRef, close).
|
2004-03-06 22:13:16 +01:00
|
|
|
|
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
process([], #request{data = Data,
|
|
|
|
ip = IP} = _Request) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
case catch parse_request(Data) of
|
|
|
|
{ok, ID1, Key, NewKey, Packet} ->
|
2004-04-17 21:00:10 +02:00
|
|
|
ID = if
|
|
|
|
(ID1 == "0") or (ID1 == "mobile") ->
|
|
|
|
NewID = sha:sha(term_to_binary({now(), make_ref()})),
|
2008-07-17 17:33:50 +02:00
|
|
|
{ok, Pid} = start(NewID, "", IP),
|
2004-04-17 21:00:10 +02:00
|
|
|
mnesia:transaction(
|
|
|
|
fun() ->
|
|
|
|
mnesia:write(#http_poll{id = NewID,
|
|
|
|
pid = Pid})
|
|
|
|
end),
|
|
|
|
NewID;
|
|
|
|
true ->
|
|
|
|
ID1
|
|
|
|
end,
|
2008-07-17 17:33:50 +02:00
|
|
|
case http_put(ID, Key, NewKey, Packet) of
|
2004-03-06 22:13:16 +01:00
|
|
|
{error, not_exists} ->
|
2004-03-13 21:01:37 +01:00
|
|
|
{200, ?BAD_REQUEST, ""};
|
2004-03-06 22:13:16 +01:00
|
|
|
{error, bad_key} ->
|
2004-03-13 21:01:37 +01:00
|
|
|
{200, ?BAD_REQUEST, ""};
|
2004-03-06 22:13:16 +01:00
|
|
|
ok ->
|
|
|
|
receive
|
|
|
|
after 100 -> ok
|
|
|
|
end,
|
|
|
|
case http_get(ID) of
|
|
|
|
{error, not_exists} ->
|
2008-03-09 22:28:42 +01:00
|
|
|
{200, ?BAD_REQUEST, ""};
|
2004-03-06 22:13:16 +01:00
|
|
|
{ok, OutPacket} ->
|
2004-03-13 21:01:37 +01:00
|
|
|
if
|
|
|
|
ID == ID1 ->
|
2004-08-15 23:18:53 +02:00
|
|
|
Cookie = "ID=" ++ ID ++ "; expires=-1",
|
|
|
|
{200, [?CT, {"Set-Cookie", Cookie}],
|
|
|
|
OutPacket};
|
2004-04-17 21:00:10 +02:00
|
|
|
ID1 == "mobile" ->
|
|
|
|
{200, [?CT], [ID, $\n, OutPacket]};
|
2004-03-13 21:01:37 +01:00
|
|
|
true ->
|
|
|
|
Cookie = "ID=" ++ ID ++ "; expires=-1",
|
|
|
|
{200, [?CT, {"Set-Cookie", Cookie}],
|
|
|
|
OutPacket}
|
|
|
|
end
|
2004-03-06 22:13:16 +01:00
|
|
|
end
|
|
|
|
end;
|
|
|
|
_ ->
|
2009-11-23 16:22:45 +01:00
|
|
|
HumanHTMLxmlel = get_human_html_xmlel(),
|
|
|
|
{200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], HumanHTMLxmlel}
|
2004-10-05 21:31:17 +02:00
|
|
|
end;
|
2007-01-25 06:53:58 +01:00
|
|
|
process(_, _Request) ->
|
2008-10-13 17:36:43 +02:00
|
|
|
{400, [], #xmlel{ns = ?NS_XHTML, name = 'h1', children =
|
|
|
|
[#xmlcdata{cdata = <<"400 Bad Request">>}]}}.
|
2004-03-06 22:13:16 +01:00
|
|
|
|
2009-11-23 16:22:45 +01:00
|
|
|
%% Code copied from mod_http_bind.erl and customized
|
|
|
|
get_human_html_xmlel() ->
|
|
|
|
Heading = "ejabberd " ++ atom_to_list(?MODULE),
|
|
|
|
H = #xmlel{name = h1, children = [#xmlcdata{cdata = Heading}]},
|
|
|
|
Par1 = #xmlel{name = p, children =
|
|
|
|
[#xmlcdata{cdata = <<"An implementation of ">>},
|
|
|
|
#xmlel{name = a,
|
|
|
|
attrs = [#xmlattr{name=href, value = <<"http://xmpp.org/extensions/xep-0025.html">>}],
|
|
|
|
children = [#xmlcdata{cdata = <<"Jabber HTTP Polling (XEP-0025)">>}]
|
|
|
|
}
|
|
|
|
]},
|
|
|
|
Par2 = #xmlel{name = p, children =
|
|
|
|
[#xmlcdata{cdata = <<"This web page is only informative. "
|
|
|
|
"To use HTTP-Poll you need a Jabber/XMPP client that supports it.">>}
|
|
|
|
]},
|
|
|
|
#xmlel{name = html,
|
|
|
|
attrs = [#xmlattr{name = xmlns, value= <<"http://www.w3.org/1999/xhtml">>}],
|
|
|
|
children =
|
|
|
|
[#xmlel{name = head, children = [#xmlel{name = title, children = [#xmlcdata{cdata = Heading}]}]},
|
|
|
|
#xmlel{name = body, children = [H, Par1, Par2]}]}.
|
|
|
|
|
2004-03-06 22:13:16 +01:00
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
%%% Callback functions from gen_fsm
|
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%% Func: init/1
|
|
|
|
%% Returns: {ok, StateName, StateData} |
|
|
|
|
%% {ok, StateName, StateData, Timeout} |
|
|
|
|
%% ignore |
|
|
|
|
%% {stop, StopReason}
|
|
|
|
%%----------------------------------------------------------------------
|
2008-07-17 17:33:50 +02:00
|
|
|
init([ID, Key, IP]) ->
|
|
|
|
?INFO_MSG("started: ~p", [{ID, Key, IP}]),
|
2007-11-01 14:59:29 +01:00
|
|
|
|
|
|
|
%% Read c2s options from the first ejabberd_c2s configuration in
|
|
|
|
%% the config file listen section
|
|
|
|
%% TODO: We should have different access and shaper values for
|
|
|
|
%% each connector. The default behaviour should be however to use
|
|
|
|
%% the default c2s restrictions if not defined for the current
|
|
|
|
%% connector.
|
2007-11-02 15:45:06 +01:00
|
|
|
Opts = ejabberd_c2s_config:get_c2s_limits(),
|
2007-11-01 14:59:29 +01:00
|
|
|
|
2009-03-03 19:49:02 +01:00
|
|
|
HTTPPollTimeout = case ejabberd_config:get_local_option({http_poll_timeout,
|
|
|
|
?MYNAME}) of
|
|
|
|
%% convert seconds of option into milliseconds
|
|
|
|
Int when is_integer(Int) -> Int*1000;
|
|
|
|
undefined -> ?HTTP_POLL_TIMEOUT
|
|
|
|
end,
|
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
Socket = {http_poll, self(), IP},
|
|
|
|
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts),
|
2009-03-03 19:49:02 +01:00
|
|
|
Timer = erlang:start_timer(HTTPPollTimeout, self(), []),
|
2004-03-07 22:15:12 +01:00
|
|
|
{ok, loop, #state{id = ID,
|
|
|
|
key = Key,
|
2008-07-17 17:33:50 +02:00
|
|
|
socket = Socket,
|
2009-03-03 19:49:02 +01:00
|
|
|
http_poll_timeout = HTTPPollTimeout,
|
2004-03-07 22:15:12 +01:00
|
|
|
timer = Timer}}.
|
2004-03-06 22:13:16 +01:00
|
|
|
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%% Func: StateName/2
|
|
|
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
|
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
|
|
%% {stop, Reason, NewStateData}
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%% Func: StateName/3
|
|
|
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
|
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
|
|
%% {reply, Reply, NextStateName, NextStateData} |
|
|
|
|
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
|
|
%% {stop, Reason, NewStateData} |
|
|
|
|
%% {stop, Reason, Reply, NewStateData}
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%state_name(Event, From, StateData) ->
|
|
|
|
% Reply = ok,
|
|
|
|
% {reply, Reply, state_name, StateData}.
|
|
|
|
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%% Func: handle_event/3
|
|
|
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
|
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
|
|
%% {stop, Reason, NewStateData}
|
|
|
|
%%----------------------------------------------------------------------
|
2006-10-01 03:53:37 +02:00
|
|
|
handle_event({activate, From}, StateName, StateData) ->
|
|
|
|
case StateData#state.input of
|
|
|
|
"" ->
|
|
|
|
{next_state, StateName,
|
|
|
|
StateData#state{waiting_input = {From, ok}}};
|
|
|
|
Input ->
|
2006-10-09 22:32:41 +02:00
|
|
|
Receiver = From,
|
2008-07-17 17:33:50 +02:00
|
|
|
Receiver ! {tcp, StateData#state.socket, list_to_binary(Input)},
|
2006-10-01 03:53:37 +02:00
|
|
|
{next_state, StateName, StateData#state{input = "",
|
|
|
|
waiting_input = false,
|
2006-10-09 22:32:41 +02:00
|
|
|
last_receiver = Receiver
|
2006-10-01 03:53:37 +02:00
|
|
|
}}
|
|
|
|
end;
|
|
|
|
|
2007-12-07 01:48:11 +01:00
|
|
|
handle_event(_Event, StateName, StateData) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
{next_state, StateName, StateData}.
|
|
|
|
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%% Func: handle_sync_event/4
|
|
|
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
|
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
|
|
%% {reply, Reply, NextStateName, NextStateData} |
|
|
|
|
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
|
|
|
%% {stop, Reason, NewStateData} |
|
|
|
|
%% {stop, Reason, Reply, NewStateData}
|
|
|
|
%%----------------------------------------------------------------------
|
2007-12-07 01:48:11 +01:00
|
|
|
handle_sync_event({send, Packet}, _From, StateName, StateData) ->
|
2006-06-02 15:16:21 +02:00
|
|
|
Output = StateData#state.output ++ [lists:flatten(Packet)],
|
2004-03-06 22:13:16 +01:00
|
|
|
Reply = ok,
|
|
|
|
{reply, Reply, StateName, StateData#state{output = Output}};
|
|
|
|
|
2007-12-07 01:48:11 +01:00
|
|
|
handle_sync_event(stop, _From, _StateName, StateData) ->
|
2004-03-07 22:15:12 +01:00
|
|
|
Reply = ok,
|
|
|
|
{stop, normal, Reply, StateData};
|
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
handle_sync_event({http_put, Key, NewKey, Packet},
|
2007-12-07 01:48:11 +01:00
|
|
|
_From, StateName, StateData) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
Allow = case StateData#state.key of
|
|
|
|
"" ->
|
|
|
|
true;
|
|
|
|
OldKey ->
|
|
|
|
NextKey = jlib:encode_base64(
|
|
|
|
binary_to_list(crypto:sha(Key))),
|
|
|
|
if
|
|
|
|
OldKey == NextKey ->
|
|
|
|
true;
|
|
|
|
true ->
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
if
|
|
|
|
Allow ->
|
|
|
|
case StateData#state.waiting_input of
|
|
|
|
false ->
|
2006-06-02 15:16:21 +02:00
|
|
|
Input = [StateData#state.input|Packet],
|
2004-03-06 22:13:16 +01:00
|
|
|
Reply = ok,
|
|
|
|
{reply, Reply, StateName, StateData#state{input = Input,
|
2008-07-17 17:33:50 +02:00
|
|
|
key = NewKey}};
|
2006-02-03 04:28:15 +01:00
|
|
|
{Receiver, _Tag} ->
|
2008-07-17 17:33:50 +02:00
|
|
|
Receiver ! {tcp, StateData#state.socket,
|
2006-02-03 04:28:15 +01:00
|
|
|
list_to_binary(Packet)},
|
2004-03-07 22:15:12 +01:00
|
|
|
cancel_timer(StateData#state.timer),
|
2009-03-03 19:49:02 +01:00
|
|
|
Timer = erlang:start_timer(StateData#state.http_poll_timeout, self(), []),
|
2004-03-06 22:13:16 +01:00
|
|
|
Reply = ok,
|
|
|
|
{reply, Reply, StateName,
|
|
|
|
StateData#state{waiting_input = false,
|
2006-05-15 17:45:52 +02:00
|
|
|
last_receiver = Receiver,
|
2004-03-07 22:15:12 +01:00
|
|
|
key = NewKey,
|
2008-07-17 17:33:50 +02:00
|
|
|
timer = Timer}}
|
2004-03-06 22:13:16 +01:00
|
|
|
end;
|
|
|
|
true ->
|
|
|
|
Reply = {error, bad_key},
|
|
|
|
{reply, Reply, StateName, StateData}
|
|
|
|
end;
|
|
|
|
|
2007-12-07 01:48:11 +01:00
|
|
|
handle_sync_event(http_get, _From, StateName, StateData) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
Reply = {ok, StateData#state.output},
|
|
|
|
{reply, Reply, StateName, StateData#state{output = ""}};
|
|
|
|
|
2007-12-07 01:48:11 +01:00
|
|
|
handle_sync_event(_Event, _From, StateName, StateData) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
Reply = ok,
|
|
|
|
{reply, Reply, StateName, StateData}.
|
|
|
|
|
2007-12-07 01:48:11 +01:00
|
|
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
{ok, StateName, StateData}.
|
|
|
|
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%% Func: handle_info/3
|
|
|
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
|
|
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
|
|
|
%% {stop, Reason, NewStateData}
|
|
|
|
%%----------------------------------------------------------------------
|
2007-12-07 01:48:11 +01:00
|
|
|
handle_info({timeout, Timer, _}, _StateName,
|
2004-03-07 22:15:12 +01:00
|
|
|
#state{timer = Timer} = StateData) ->
|
|
|
|
{stop, normal, StateData};
|
|
|
|
|
2004-03-06 22:13:16 +01:00
|
|
|
handle_info(_, StateName, StateData) ->
|
|
|
|
{next_state, StateName, StateData}.
|
|
|
|
|
|
|
|
%%----------------------------------------------------------------------
|
|
|
|
%% Func: terminate/3
|
|
|
|
%% Purpose: Shutdown the fsm
|
|
|
|
%% Returns: any
|
|
|
|
%%----------------------------------------------------------------------
|
2007-12-07 01:48:11 +01:00
|
|
|
terminate(_Reason, _StateName, StateData) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
mnesia:transaction(
|
|
|
|
fun() ->
|
|
|
|
mnesia:delete({http_poll, StateData#state.id})
|
|
|
|
end),
|
|
|
|
case StateData#state.waiting_input of
|
|
|
|
false ->
|
2006-06-02 15:16:21 +02:00
|
|
|
%% We are testing this case due to "socket activation": If we pass
|
|
|
|
%% here and the "socket" is not ready to receive, the tcp_closed
|
|
|
|
%% will be lost.
|
2006-05-15 17:45:52 +02:00
|
|
|
case StateData#state.last_receiver of
|
|
|
|
undefined -> ok;
|
2006-06-02 15:16:21 +02:00
|
|
|
Receiver ->
|
2008-07-17 17:33:50 +02:00
|
|
|
Receiver ! {tcp_closed, StateData#state.socket}
|
2006-05-15 17:45:52 +02:00
|
|
|
end;
|
|
|
|
{Receiver, _Tag} ->
|
2008-07-17 17:33:50 +02:00
|
|
|
Receiver ! {tcp_closed, StateData#state.socket}
|
2004-03-06 22:13:16 +01:00
|
|
|
end,
|
2006-12-07 03:56:14 +01:00
|
|
|
catch resend_messages(StateData#state.output),
|
2004-03-06 22:13:16 +01:00
|
|
|
ok.
|
|
|
|
|
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
%%% Internal functions
|
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
|
2008-07-17 17:33:50 +02:00
|
|
|
http_put(ID, Key, NewKey, Packet) ->
|
2004-03-06 22:13:16 +01:00
|
|
|
case mnesia:dirty_read({http_poll, ID}) of
|
|
|
|
[] ->
|
|
|
|
{error, not_exists};
|
|
|
|
[#http_poll{pid = FsmRef}] ->
|
|
|
|
gen_fsm:sync_send_all_state_event(
|
2008-07-17 17:33:50 +02:00
|
|
|
FsmRef, {http_put, Key, NewKey, Packet})
|
2004-03-06 22:13:16 +01:00
|
|
|
end.
|
|
|
|
|
|
|
|
http_get(ID) ->
|
|
|
|
case mnesia:dirty_read({http_poll, ID}) of
|
|
|
|
[] ->
|
|
|
|
{error, not_exists};
|
|
|
|
[#http_poll{pid = FsmRef}] ->
|
|
|
|
gen_fsm:sync_send_all_state_event(FsmRef, http_get)
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
parse_request(Data) ->
|
|
|
|
Comma = string:chr(Data, $,),
|
|
|
|
Header = lists:sublist(Data, Comma - 1),
|
|
|
|
Packet = lists:nthtail(Comma, Data),
|
|
|
|
{ID, Key, NewKey} =
|
|
|
|
case string:tokens(Header, ";") of
|
|
|
|
[ID1] ->
|
|
|
|
{ID1, "", ""};
|
|
|
|
[ID1, Key1] ->
|
|
|
|
{ID1, Key1, Key1};
|
|
|
|
[ID1, Key1, NewKey1] ->
|
|
|
|
{ID1, Key1, NewKey1}
|
|
|
|
end,
|
|
|
|
{ok, ID, Key, NewKey, Packet}.
|
|
|
|
|
|
|
|
|
2004-03-07 22:15:12 +01:00
|
|
|
cancel_timer(Timer) ->
|
|
|
|
erlang:cancel_timer(Timer),
|
|
|
|
receive
|
|
|
|
{timeout, Timer, _} ->
|
|
|
|
ok
|
|
|
|
after 0 ->
|
|
|
|
ok
|
|
|
|
end.
|
|
|
|
|
2006-06-02 15:16:21 +02:00
|
|
|
%% Resend the polled messages
|
|
|
|
resend_messages(Messages) ->
|
|
|
|
lists:foreach(fun(Packet) ->
|
|
|
|
resend_message(Packet)
|
|
|
|
end, Messages).
|
|
|
|
|
|
|
|
%% This function is used to resend messages that have been polled but not
|
|
|
|
%% delivered.
|
|
|
|
resend_message(Packet) ->
|
2008-10-13 17:36:43 +02:00
|
|
|
[ParsedPacket] = exmpp_xml:parse_document(Packet, ?PARSER_OPTIONS),
|
2006-06-02 15:16:21 +02:00
|
|
|
From = get_jid("from", ParsedPacket),
|
|
|
|
To = get_jid("to", ParsedPacket),
|
2008-03-21 15:44:16 +01:00
|
|
|
?DEBUG("Resend ~p ~p ~p~n",[From,To, ParsedPacket]),
|
2006-06-02 15:16:21 +02:00
|
|
|
ejabberd_router:route(From, To, ParsedPacket).
|
|
|
|
|
|
|
|
%% Type can be "from" or "to"
|
|
|
|
%% Parsed packet is a parsed Jabber packet.
|
2008-10-13 17:36:43 +02:00
|
|
|
get_jid("from", ParsedPacket) ->
|
|
|
|
case exmpp_stanza:get_sender(ParsedPacket) of
|
|
|
|
undefined ->
|
2009-06-01 18:26:00 +02:00
|
|
|
exmpp_jid:make();
|
2008-10-13 17:36:43 +02:00
|
|
|
From ->
|
2009-06-01 18:35:55 +02:00
|
|
|
exmpp_jid:parse(From)
|
2008-10-13 17:36:43 +02:00
|
|
|
end;
|
|
|
|
get_jid("to", ParsedPacket) ->
|
|
|
|
case exmpp_stanza:get_recipient(ParsedPacket) of
|
|
|
|
undefined ->
|
2009-06-01 18:26:00 +02:00
|
|
|
exmpp_jid:make();
|
2008-10-13 17:36:43 +02:00
|
|
|
From ->
|
2009-06-01 18:35:55 +02:00
|
|
|
exmpp_jid:parse(From)
|
2006-06-02 15:16:21 +02:00
|
|
|
end.
|