mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-26 17:38:45 +01:00
[TECH-1511] preliminary XMPP support via websockets
This commit is contained in:
parent
c8567f1de2
commit
b0a81778af
@ -75,7 +75,7 @@ update_reg_users_counter_table(Server) ->
|
|||||||
mnesia:sync_dirty(F).
|
mnesia:sync_dirty(F).
|
||||||
|
|
||||||
plain_password_required() ->
|
plain_password_required() ->
|
||||||
false.
|
true.
|
||||||
|
|
||||||
check_password(User, Server, Password) ->
|
check_password(User, Server, Password) ->
|
||||||
LUser = jlib:nodeprep(User),
|
LUser = jlib:nodeprep(User),
|
||||||
|
@ -1851,6 +1851,7 @@ get_conn_type(StateData) ->
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
ejabberd_http_poll -> http_poll;
|
ejabberd_http_poll -> http_poll;
|
||||||
|
ejabberd_http_ws -> http_ws;
|
||||||
ejabberd_http_bind -> http_bind;
|
ejabberd_http_bind -> http_bind;
|
||||||
_ -> unknown
|
_ -> unknown
|
||||||
end.
|
end.
|
||||||
|
@ -146,6 +146,14 @@ init([]) ->
|
|||||||
infinity,
|
infinity,
|
||||||
supervisor,
|
supervisor,
|
||||||
[ejabberd_tmp_sup]},
|
[ejabberd_tmp_sup]},
|
||||||
|
WSLoopSupervisor =
|
||||||
|
{ejabberd_wsloop_sup,
|
||||||
|
{ejabberd_tmp_sup, start_link,
|
||||||
|
[ejabberd_wsloop_sup, ejabberd_wsloop]},
|
||||||
|
permanent,
|
||||||
|
infinity,
|
||||||
|
supervisor,
|
||||||
|
[ejabberd_tmp_sup]},
|
||||||
FrontendSocketSupervisor =
|
FrontendSocketSupervisor =
|
||||||
{ejabberd_frontend_socket_sup,
|
{ejabberd_frontend_socket_sup,
|
||||||
{ejabberd_tmp_sup, start_link,
|
{ejabberd_tmp_sup, start_link,
|
||||||
|
@ -409,8 +409,6 @@ process_request(#state{request_method = Method,
|
|||||||
origin = Origin,
|
origin = Origin,
|
||||||
headers = RequestHeaders
|
headers = RequestHeaders
|
||||||
},
|
},
|
||||||
?DEBUG("WS: ~p/~p~n", [WebSocketHandlers, Path]),
|
|
||||||
?DEBUG("It is a websocket version : ~p",[VSN]),
|
|
||||||
process(WebSocketHandlers, Ws),
|
process(WebSocketHandlers, Ws),
|
||||||
none;
|
none;
|
||||||
false ->
|
false ->
|
||||||
|
206
src/web/ejabberd_http_ws.erl
Normal file
206
src/web/ejabberd_http_ws.erl
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd_websocket.erl
|
||||||
|
%%% Author : Eric Cestari <ecestari@process-one.net>
|
||||||
|
%%% Purpose : XMPP Websocket support
|
||||||
|
%%% Created : 09-10-2010 by Eric Cestari <ecestari@process-one.net>
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
||||||
|
%%%
|
||||||
|
%%% 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.
|
||||||
|
%%%
|
||||||
|
%%% 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
|
||||||
|
%%%
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
-module (ejabberd_http_ws).
|
||||||
|
|
||||||
|
-author('ecestari@process-one.net').
|
||||||
|
|
||||||
|
-behaviour(gen_fsm).
|
||||||
|
|
||||||
|
% External exports
|
||||||
|
-export([
|
||||||
|
start/1,
|
||||||
|
start_link/1,
|
||||||
|
init/1,
|
||||||
|
handle_event/3,
|
||||||
|
handle_sync_event/4,
|
||||||
|
code_change/4,
|
||||||
|
handle_info/3,
|
||||||
|
terminate/3,
|
||||||
|
send/2,
|
||||||
|
setopts/2,
|
||||||
|
sockname/1, peername/1,
|
||||||
|
controlling_process/2,
|
||||||
|
close/1]).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
-include("jlib.hrl").
|
||||||
|
-include("ejabberd_http.hrl").
|
||||||
|
|
||||||
|
-record(state, {
|
||||||
|
socket,
|
||||||
|
timeout,
|
||||||
|
timer,
|
||||||
|
input = "",
|
||||||
|
waiting_input = false, %% {ReceiverPid, Tag}
|
||||||
|
last_receiver,
|
||||||
|
ws}).
|
||||||
|
|
||||||
|
%-define(DBGFSM, true).
|
||||||
|
|
||||||
|
-ifdef(DBGFSM).
|
||||||
|
-define(FSMOPTS, [{debug, [trace]}]).
|
||||||
|
-else.
|
||||||
|
-define(FSMOPTS, []).
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
-define(WEBSOCKET_TIMEOUT, 300000).
|
||||||
|
%
|
||||||
|
%
|
||||||
|
%%%%----------------------------------------------------------------------
|
||||||
|
%%%% API
|
||||||
|
%%%%----------------------------------------------------------------------
|
||||||
|
start(WS) ->
|
||||||
|
supervisor:start_child(ejabberd_wsloop_sup, [WS]).
|
||||||
|
|
||||||
|
start_link(WS) ->
|
||||||
|
gen_fsm:start_link(?MODULE, [WS],[{debug, [trace]}]).
|
||||||
|
|
||||||
|
send({http_ws, FsmRef, _IP}, Packet) ->
|
||||||
|
gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
|
||||||
|
|
||||||
|
setopts({http_ws, FsmRef, _IP}, Opts) ->
|
||||||
|
case lists:member({active, once}, Opts) of
|
||||||
|
true ->
|
||||||
|
gen_fsm:send_all_state_event(FsmRef, {activate, self()});
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
sockname(_Socket) ->
|
||||||
|
{ok, {{0, 0, 0, 0}, 0}}.
|
||||||
|
|
||||||
|
peername({http_ws, _FsmRef, IP}) ->
|
||||||
|
{ok, IP}.
|
||||||
|
|
||||||
|
controlling_process(_Socket, _Pid) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
become_controller(FsmRef, C2SPid) ->
|
||||||
|
gen_fsm:send_all_state_event(FsmRef, {become_controller, C2SPid}).
|
||||||
|
|
||||||
|
close({http_ws, FsmRef, _IP}) ->
|
||||||
|
catch gen_fsm:sync_send_all_state_event(FsmRef, close).
|
||||||
|
|
||||||
|
%%% Internal
|
||||||
|
|
||||||
|
|
||||||
|
init([WS]) ->
|
||||||
|
?INFO_MSG("started: ~p", [WS]),
|
||||||
|
|
||||||
|
%% 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.
|
||||||
|
Opts = ejabberd_c2s_config:get_c2s_limits(),
|
||||||
|
|
||||||
|
WSTimeout = case ejabberd_config:get_local_option({websocket_timeout,
|
||||||
|
?MYNAME}) of
|
||||||
|
%% convert seconds of option into milliseconds
|
||||||
|
Int when is_integer(Int) -> Int*1000;
|
||||||
|
undefined -> ?WEBSOCKET_TIMEOUT
|
||||||
|
end,
|
||||||
|
|
||||||
|
Socket = {http_ws, self(), {{127,0,0,1}, 5280}}, %FIXME
|
||||||
|
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts),
|
||||||
|
Timer = erlang:start_timer(WSTimeout, self(), []),
|
||||||
|
{ok, loop, #state{
|
||||||
|
socket = Socket,
|
||||||
|
timeout = WSTimeout,
|
||||||
|
timer = Timer,
|
||||||
|
ws = WS}}.
|
||||||
|
|
||||||
|
handle_event({activate, From}, StateName, StateData) ->
|
||||||
|
case StateData#state.input of
|
||||||
|
"" ->
|
||||||
|
{next_state, StateName,
|
||||||
|
StateData#state{waiting_input = {From, ok}}};
|
||||||
|
Input ->
|
||||||
|
Receiver = From,
|
||||||
|
Receiver ! {tcp, StateData#state.socket, list_to_binary(Input)},
|
||||||
|
{next_state, StateName, StateData#state{input = "",
|
||||||
|
waiting_input = false,
|
||||||
|
last_receiver = Receiver
|
||||||
|
}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
handle_sync_event({send, Packet}, _From, StateName, #state{ws = WS} = StateData) ->
|
||||||
|
Packet2 = if
|
||||||
|
is_binary(Packet) ->
|
||||||
|
binary_to_list(Packet);
|
||||||
|
true ->
|
||||||
|
Packet
|
||||||
|
end,
|
||||||
|
?DEBUG("sending on websocket : ~p ", [Packet2]),
|
||||||
|
WS:send(lists:flatten(Packet2)),
|
||||||
|
{reply, ok, StateName, StateData};
|
||||||
|
|
||||||
|
handle_sync_event(close, _From, _StateName, StateData) ->
|
||||||
|
Reply = ok,
|
||||||
|
{stop, normal, Reply, StateData}.
|
||||||
|
|
||||||
|
handle_info({browser, Packet}, StateName, StateData)->
|
||||||
|
case StateData#state.waiting_input of
|
||||||
|
false ->
|
||||||
|
Input = [StateData#state.input|Packet],
|
||||||
|
Reply = ok,
|
||||||
|
{reply, Reply, StateName, StateData#state{input = Input}};
|
||||||
|
{Receiver, _Tag} ->
|
||||||
|
Receiver ! {tcp, StateData#state.socket,
|
||||||
|
list_to_binary(Packet)},
|
||||||
|
cancel_timer(StateData#state.timer),
|
||||||
|
Timer = erlang:start_timer(StateData#state.timeout, self(), []),
|
||||||
|
Reply = ok,
|
||||||
|
{reply, Reply, StateName,
|
||||||
|
StateData#state{waiting_input = false,
|
||||||
|
last_receiver = Receiver,
|
||||||
|
timer = Timer}}
|
||||||
|
end,
|
||||||
|
{next_state, StateName, StateData};
|
||||||
|
|
||||||
|
|
||||||
|
handle_info({timeout, Timer, _}, _StateName,
|
||||||
|
#state{timer = Timer} = StateData) ->
|
||||||
|
{stop, normal, StateData};
|
||||||
|
|
||||||
|
handle_info(_, StateName, StateData) ->
|
||||||
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
|
|
||||||
|
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||||
|
{ok, StateName, StateData}.
|
||||||
|
|
||||||
|
terminate(_Reason, _StateName, _StateData) -> ok.
|
||||||
|
|
||||||
|
cancel_timer(Timer) ->
|
||||||
|
erlang:cancel_timer(Timer),
|
||||||
|
receive
|
||||||
|
{timeout, Timer, _} ->
|
||||||
|
ok
|
||||||
|
after 0 ->
|
||||||
|
ok
|
||||||
|
end.
|
@ -44,7 +44,7 @@
|
|||||||
-include("ejabberd_http.hrl").
|
-include("ejabberd_http.hrl").
|
||||||
|
|
||||||
check(_Path, Headers)->
|
check(_Path, Headers)->
|
||||||
?DEBUG("testing for a websocket request path: ~p headers: ~p", [_Path, Headers]),
|
%?DEBUG("testing for a websocket request path: ~p headers: ~p", [_Path, Headers]),
|
||||||
% set supported websocket protocols, order does matter
|
% set supported websocket protocols, order does matter
|
||||||
VsnSupported = [{'draft-hixie', 76}, {'draft-hixie', 68}],
|
VsnSupported = [{'draft-hixie', 76}, {'draft-hixie', 68}],
|
||||||
% checks
|
% checks
|
||||||
@ -55,12 +55,12 @@ connect(#ws{vsn = Vsn, socket = Socket, origin=Origin, host=Host, port=Port, soc
|
|||||||
% build handshake
|
% build handshake
|
||||||
HandshakeServer = handshake(Vsn, Socket,SockMod, Headers, {Path, Origin, Host, Port}),
|
HandshakeServer = handshake(Vsn, Socket,SockMod, Headers, {Path, Origin, Host, Port}),
|
||||||
% send handshake back
|
% send handshake back
|
||||||
?DEBUG("building handshake response : ~p", [HandshakeServer]),
|
%?DEBUG("building handshake response : ~p", [HandshakeServer]),
|
||||||
SockMod:send(Socket, HandshakeServer),
|
SockMod:send(Socket, HandshakeServer),
|
||||||
Ws0 = ejabberd_ws:new(Ws#ws{origin = Origin, host = Host}, self()),
|
Ws0 = ejabberd_ws:new(Ws#ws{origin = Origin, host = Host}, self()),
|
||||||
?DEBUG("Ws0 : ~p",[Ws0]),
|
%?DEBUG("Ws0 : ~p",[Ws0]),
|
||||||
% add data to ws record and spawn controlling process
|
% add data to ws record and spawn controlling process
|
||||||
WsHandleLoopPid = WsLoop:start(Ws0),
|
{ok, WsHandleLoopPid} = WsLoop:start_link(Ws0),
|
||||||
erlang:monitor(process, WsHandleLoopPid),
|
erlang:monitor(process, WsHandleLoopPid),
|
||||||
% set opts
|
% set opts
|
||||||
case SockMod of
|
case SockMod of
|
||||||
@ -83,7 +83,7 @@ check_websockets([Vsn|T], Headers) ->
|
|||||||
% Function: {true, Vsn} | false
|
% Function: {true, Vsn} | false
|
||||||
% Description: Check if the incoming request is a websocket request.
|
% Description: Check if the incoming request is a websocket request.
|
||||||
check_websocket({'draft-hixie', 76} = Vsn, Headers) ->
|
check_websocket({'draft-hixie', 76} = Vsn, Headers) ->
|
||||||
?DEBUG("testing for websocket protocol ~p", [Vsn]),
|
%?DEBUG("testing for websocket protocol ~p", [Vsn]),
|
||||||
% set required headers
|
% set required headers
|
||||||
RequiredHeaders = [
|
RequiredHeaders = [
|
||||||
{'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {"Origin", ignore},
|
{'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {"Origin", ignore},
|
||||||
@ -95,11 +95,11 @@ check_websocket({'draft-hixie', 76} = Vsn, Headers) ->
|
|||||||
% return
|
% return
|
||||||
{true, Vsn};
|
{true, Vsn};
|
||||||
_RemainingHeaders ->
|
_RemainingHeaders ->
|
||||||
?DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]),
|
%?DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]),
|
||||||
false
|
false
|
||||||
end;
|
end;
|
||||||
check_websocket({'draft-hixie', 68} = Vsn, Headers) ->
|
check_websocket({'draft-hixie', 68} = Vsn, Headers) ->
|
||||||
?DEBUG("testing for websocket protocol ~p", [Vsn]),
|
%?DEBUG("testing for websocket protocol ~p", [Vsn]),
|
||||||
% set required headers
|
% set required headers
|
||||||
RequiredHeaders = [
|
RequiredHeaders = [
|
||||||
{'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {"Origin", ignore}
|
{'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {"Origin", ignore}
|
||||||
@ -108,7 +108,7 @@ check_websocket({'draft-hixie', 68} = Vsn, Headers) ->
|
|||||||
case check_headers(Headers, RequiredHeaders) of
|
case check_headers(Headers, RequiredHeaders) of
|
||||||
true -> {true, Vsn};
|
true -> {true, Vsn};
|
||||||
_RemainingHeaders ->
|
_RemainingHeaders ->
|
||||||
?DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]),
|
%?DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]),
|
||||||
false
|
false
|
||||||
end;
|
end;
|
||||||
check_websocket(_Vsn, _Headers) -> false. % not implemented
|
check_websocket(_Vsn, _Headers) -> false. % not implemented
|
||||||
@ -121,7 +121,7 @@ check_headers(Headers, RequiredHeaders) ->
|
|||||||
case lists:keyfind(Tag, 1, Headers) of
|
case lists:keyfind(Tag, 1, Headers) of
|
||||||
false -> true; % header not found, keep in list
|
false -> true; % header not found, keep in list
|
||||||
{Tag, HVal} ->
|
{Tag, HVal} ->
|
||||||
?DEBUG("check: ~p", [{Tag, HVal,Val }]),
|
%?DEBUG("check: ~p", [{Tag, HVal,Val }]),
|
||||||
case Val of
|
case Val of
|
||||||
ignore -> false; % ignore value -> ok, remove from list
|
ignore -> false; % ignore value -> ok, remove from list
|
||||||
HVal -> false; % expected val -> ok, remove from list
|
HVal -> false; % expected val -> ok, remove from list
|
||||||
@ -156,7 +156,7 @@ handshake({'draft-hixie', 76}, Sock,SocketMod, Headers, {Path, Origin, Host, Por
|
|||||||
?ERROR_MSG("tcp error treating data: ~p", [_Other]),
|
?ERROR_MSG("tcp error treating data: ~p", [_Other]),
|
||||||
<<>>
|
<<>>
|
||||||
end,
|
end,
|
||||||
?DEBUG("got content in body of websocket request: ~p, ~p", [Body,string:join([Host, Path],"/")]),
|
%?DEBUG("got content in body of websocket request: ~p, ~p", [Body,string:join([Host, Path],"/")]),
|
||||||
% prepare handhsake response
|
% prepare handhsake response
|
||||||
["HTTP/1.1 101 WebSocket Protocol Handshake\r\n",
|
["HTTP/1.1 101 WebSocket Protocol Handshake\r\n",
|
||||||
"Upgrade: WebSocket\r\n",
|
"Upgrade: WebSocket\r\n",
|
||||||
@ -193,18 +193,19 @@ build_challenge({'draft-hixie', 76}, {Key1, Key2, Key3}) ->
|
|||||||
|
|
||||||
|
|
||||||
ws_loop(Socket, Buffer, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
ws_loop(Socket, Buffer, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
||||||
?DEBUG("websocket loop", []),
|
%?DEBUG("websocket loop", []),
|
||||||
receive
|
receive
|
||||||
{tcp, Socket, Data} ->
|
{tcp, Socket, Data} ->
|
||||||
handle_data(Buffer, binary_to_list(Data), Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
handle_data(Buffer, binary_to_list(Data), Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
{tcp_closed, Socket} ->
|
{tcp_closed, Socket} ->
|
||||||
?DEBUG("tcp connection was closed, exit", []),
|
%?DEBUG("tcp connection was closed, exit", []),
|
||||||
% close websocket and custom controlling loop
|
% close websocket and custom controlling loop
|
||||||
websocket_close(Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
websocket_close(Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
{'DOWN', Ref, process, WsHandleLoopPid, Reason} ->
|
{'DOWN', Ref, process, WsHandleLoopPid, Reason} ->
|
||||||
case Reason of
|
case Reason of
|
||||||
normal ->
|
normal ->
|
||||||
?DEBUG("linked websocket controlling loop stopped.", []);
|
%?DEBUG("linked websocket controlling loop stopped.", []);
|
||||||
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
?ERROR_MSG("linked websocket controlling loop crashed with reason: ~p", [Reason])
|
?ERROR_MSG("linked websocket controlling loop crashed with reason: ~p", [Reason])
|
||||||
end,
|
end,
|
||||||
@ -213,11 +214,11 @@ ws_loop(Socket, Buffer, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
|||||||
% close websocket and custom controlling loop
|
% close websocket and custom controlling loop
|
||||||
websocket_close(Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
websocket_close(Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
{send, Data} ->
|
{send, Data} ->
|
||||||
?DEBUG("sending data to websocket: ~p", [Data]),
|
%?DEBUG("sending data to websocket: ~p", [Data]),
|
||||||
SocketMode:send(Socket, [0, Data, 255]),
|
SocketMode:send(Socket, [0, Data, 255]),
|
||||||
ws_loop(Socket, Buffer, WsHandleLoopPid, SocketMode, WsAutoExit);
|
ws_loop(Socket, Buffer, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
shutdown ->
|
shutdown ->
|
||||||
?DEBUG("shutdown request received, closing websocket with pid ~p", [self()]),
|
%?DEBUG("shutdown request received, closing websocket with pid ~p", [self()]),
|
||||||
% close websocket and custom controlling loop
|
% close websocket and custom controlling loop
|
||||||
websocket_close(Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
websocket_close(Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
_Ignored ->
|
_Ignored ->
|
||||||
@ -227,24 +228,24 @@ ws_loop(Socket, Buffer, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
|||||||
|
|
||||||
% Buffering and data handling
|
% Buffering and data handling
|
||||||
handle_data(none, [0|T], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
handle_data(none, [0|T], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
||||||
?DEBUG("handle_data 1", []),
|
%?DEBUG("handle_data 1", []),
|
||||||
handle_data([], T, Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
handle_data([], T, Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
|
|
||||||
handle_data(none, [], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
handle_data(none, [], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
||||||
?DEBUG("handle_data 2", []),
|
%?DEBUG("handle_data 2", []),
|
||||||
ws_loop(Socket, none, WsHandleLoopPid, SocketMode, WsAutoExit);
|
ws_loop(Socket, none, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
|
|
||||||
handle_data(L, [255|T], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
handle_data(L, [255|T], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
||||||
?DEBUG("handle_data 3", []),
|
%?DEBUG("handle_data 3", []),
|
||||||
WsHandleLoopPid ! {browser, lists:reverse(L)},
|
WsHandleLoopPid ! {browser, lists:reverse(L)},
|
||||||
handle_data(none, T, Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
handle_data(none, T, Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
|
|
||||||
handle_data(L, [H|T], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
handle_data(L, [H|T], Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
||||||
?DEBUG("handle_data 4, Buffer = ~p", [L]),
|
%?DEBUG("handle_data 4, Buffer = ~p", [L]),
|
||||||
handle_data([H|L], T, Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
handle_data([H|L], T, Socket, WsHandleLoopPid, SocketMode, WsAutoExit);
|
||||||
|
|
||||||
handle_data([], L, Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
handle_data([], L, Socket, WsHandleLoopPid, SocketMode, WsAutoExit) ->
|
||||||
?DEBUG("handle_data 5", []),
|
%?DEBUG("handle_data 5", []),
|
||||||
ws_loop(Socket, L, WsHandleLoopPid, SocketMode, WsAutoExit).
|
ws_loop(Socket, L, WsHandleLoopPid, SocketMode, WsAutoExit).
|
||||||
|
|
||||||
% Close socket and custom handling loop dependency
|
% Close socket and custom handling loop dependency
|
||||||
|
Loading…
Reference in New Issue
Block a user