mirror of
https://github.com/processone/ejabberd.git
synced 2024-06-12 21:52:07 +02:00
*** empty log message ***
SVN Revision: 66
This commit is contained in:
parent
4f7d0c5030
commit
51e811f8fb
|
@ -1,6 +1,6 @@
|
||||||
% $Id$
|
% $Id$
|
||||||
|
|
||||||
override_acls.
|
%override_acls.
|
||||||
|
|
||||||
{acl, admin, {user, "aleksey"}}.
|
{acl, admin, {user, "aleksey"}}.
|
||||||
{acl, admin, {user, "ermine"}}.
|
{acl, admin, {user, "ermine"}}.
|
||||||
|
@ -14,10 +14,13 @@ override_acls.
|
||||||
{acl, jabberorg, {server, "jabber.org"}}.
|
{acl, jabberorg, {server, "jabber.org"}}.
|
||||||
{acl, aleksey, {user, "aleksey", "jabber.ru"}}.
|
{acl, aleksey, {user, "aleksey", "jabber.ru"}}.
|
||||||
|
|
||||||
{acl, test, {user_glob, "test.*"}}.
|
%{acl, test, {user_regexp, "^test"}}.
|
||||||
%{acl, test2, {user_glob, "test*"}}.
|
%{acl, test2, {user_glob, "test*"}}.
|
||||||
|
|
||||||
|
|
||||||
|
{shaper, normal, {maxrate, 1000}}.
|
||||||
|
|
||||||
|
|
||||||
{access, disco_admin, [{allow, admin},
|
{access, disco_admin, [{allow, admin},
|
||||||
{deny, all}]}.
|
{deny, all}]}.
|
||||||
|
|
||||||
|
@ -26,9 +29,15 @@ override_acls.
|
||||||
{access, c2s, [{deny, blocked},
|
{access, c2s, [{deny, blocked},
|
||||||
{allow, all}]}.
|
{allow, all}]}.
|
||||||
|
|
||||||
|
|
||||||
|
{access, c2s_shaper, [{none, admin},
|
||||||
|
{normal, all}]}.
|
||||||
|
|
||||||
|
|
||||||
{host, "e.localhost"}.
|
{host, "e.localhost"}.
|
||||||
|
|
||||||
{listen, [{5522, ejabberd_c2s, start, [{access, c2s}]},
|
{listen, [{5522, ejabberd_c2s, start, [{access, c2s},
|
||||||
|
{shaper, c2s_shaper}]},
|
||||||
%{5523, ejabberd_c2s, start,
|
%{5523, ejabberd_c2s, start,
|
||||||
% [{access, c2s}, {ssl, [{certfile, "./ssl.pem"}]}]},
|
% [{access, c2s}, {ssl, [{certfile, "./ssl.pem"}]}]},
|
||||||
{5269, ejabberd_s2s_in, start, []},
|
{5269, ejabberd_s2s_in, start, []},
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
-behaviour(gen_fsm).
|
-behaviour(gen_fsm).
|
||||||
|
|
||||||
%% External exports
|
%% External exports
|
||||||
-export([start/2, receiver/3, sender/2, send_text/2, send_element/2]).
|
-export([start/2, receiver/4, send_text/2, send_element/2]).
|
||||||
|
|
||||||
%% gen_fsm callbacks
|
%% gen_fsm callbacks
|
||||||
-export([init/1, wait_for_stream/2, wait_for_auth/2, session_established/2,
|
-export([init/1, wait_for_stream/2, wait_for_auth/2, session_established/2,
|
||||||
|
@ -28,8 +28,9 @@
|
||||||
|
|
||||||
-define(SETS, gb_sets).
|
-define(SETS, gb_sets).
|
||||||
|
|
||||||
-record(state, {socket, sender, receiver, streamid,
|
-record(state, {socket, receiver, streamid,
|
||||||
access,
|
access,
|
||||||
|
shaper,
|
||||||
user = "", server = ?MYNAME, resource = "",
|
user = "", server = ?MYNAME, resource = "",
|
||||||
pres_t = ?SETS:new(),
|
pres_t = ?SETS:new(),
|
||||||
pres_f = ?SETS:new(),
|
pres_f = ?SETS:new(),
|
||||||
|
@ -76,19 +77,20 @@ start(SockData, Opts) ->
|
||||||
%% {stop, StopReason}
|
%% {stop, StopReason}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
init([{SockMod, Socket}, Opts]) ->
|
init([{SockMod, Socket}, Opts]) ->
|
||||||
SenderPid = spawn(?MODULE, sender, [Socket, SockMod]),
|
ReceiverPid = spawn(?MODULE, receiver, [Socket, SockMod, none, self()]),
|
||||||
ReceiverPid = spawn(?MODULE, receiver, [Socket, SockMod, self()]),
|
|
||||||
Access = case lists:keysearch(access, 1, Opts) of
|
Access = case lists:keysearch(access, 1, Opts) of
|
||||||
{value, {_, A}} ->
|
{value, {_, A}} -> A;
|
||||||
A;
|
_ -> all
|
||||||
_ ->
|
end,
|
||||||
all
|
Shaper = case lists:keysearch(shaper, 1, Opts) of
|
||||||
|
{value, {_, S}} -> S;
|
||||||
|
_ -> none
|
||||||
end,
|
end,
|
||||||
{ok, wait_for_stream, #state{socket = Socket,
|
{ok, wait_for_stream, #state{socket = Socket,
|
||||||
receiver = ReceiverPid,
|
receiver = ReceiverPid,
|
||||||
sender = SenderPid,
|
|
||||||
streamid = new_id(),
|
streamid = new_id(),
|
||||||
access = Access}}.
|
access = Access,
|
||||||
|
shaper = Shaper}}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
%% Func: StateName/2
|
%% Func: StateName/2
|
||||||
|
@ -101,13 +103,13 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
|
||||||
% TODO
|
% TODO
|
||||||
Header = io_lib:format(?STREAM_HEADER,
|
Header = io_lib:format(?STREAM_HEADER,
|
||||||
[StateData#state.streamid, ?MYNAME]),
|
[StateData#state.streamid, ?MYNAME]),
|
||||||
send_text(StateData#state.sender, Header),
|
send_text(StateData#state.socket, Header),
|
||||||
case lists:keysearch("xmlns:stream", 1, Attrs) of
|
case lists:keysearch("xmlns:stream", 1, Attrs) of
|
||||||
{value, {"xmlns:stream", "http://etherx.jabber.org/streams"}} ->
|
{value, {"xmlns:stream", "http://etherx.jabber.org/streams"}} ->
|
||||||
% TODO
|
% TODO
|
||||||
{next_state, wait_for_auth, StateData};
|
{next_state, wait_for_auth, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
send_text(StateData#state.sender, ?INVALID_NS_ERR ?STREAM_TRAILER),
|
send_text(StateData#state.socket, ?INVALID_NS_ERR ?STREAM_TRAILER),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -119,18 +121,20 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||||
case is_auth_packet(El) of
|
case is_auth_packet(El) of
|
||||||
{auth, ID, {U, P, D, ""}} ->
|
{auth, ID, {U, P, D, ""}} ->
|
||||||
Err = jlib:make_error_reply(El, "406", "Not Acceptable"),
|
Err = jlib:make_error_reply(El, "406", "Not Acceptable"),
|
||||||
send_element(StateData#state.sender, Err),
|
send_element(StateData#state.socket, Err),
|
||||||
{next_state, wait_for_auth, StateData};
|
{next_state, wait_for_auth, StateData};
|
||||||
{auth, ID, {U, P, D, R}} ->
|
{auth, ID, {U, P, D, R}} ->
|
||||||
io:format("AUTH: ~p~n", [{U, P, D, R}]),
|
io:format("AUTH: ~p~n", [{U, P, D, R}]),
|
||||||
case acl:match_rule(StateData#state.access, {U, ?MYNAME, R}) of
|
JID = {U, ?MYNAME, R},
|
||||||
|
case acl:match_rule(StateData#state.access, JID) of
|
||||||
allow ->
|
allow ->
|
||||||
case ejabberd_auth:check_password(
|
case ejabberd_auth:check_password(
|
||||||
U, P, StateData#state.streamid, D) of
|
U, P, StateData#state.streamid, D) of
|
||||||
true ->
|
true ->
|
||||||
ejabberd_sm:open_session(U, R),
|
ejabberd_sm:open_session(U, R),
|
||||||
Res = jlib:make_result_iq_reply(El),
|
Res = jlib:make_result_iq_reply(El),
|
||||||
send_element(StateData#state.sender, Res),
|
send_element(StateData#state.socket, Res),
|
||||||
|
change_shaper(StateData, JID),
|
||||||
{Fs, Ts} = mod_roster:get_subscription_lists(U),
|
{Fs, Ts} = mod_roster:get_subscription_lists(U),
|
||||||
{next_state, session_established,
|
{next_state, session_established,
|
||||||
StateData#state{user = U,
|
StateData#state{user = U,
|
||||||
|
@ -140,12 +144,12 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||||
_ ->
|
_ ->
|
||||||
Err = jlib:make_error_reply(
|
Err = jlib:make_error_reply(
|
||||||
El, "401", "Unauthorized"),
|
El, "401", "Unauthorized"),
|
||||||
send_element(StateData#state.sender, Err),
|
send_element(StateData#state.socket, Err),
|
||||||
{next_state, wait_for_auth, StateData}
|
{next_state, wait_for_auth, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Err = jlib:make_error_reply(El, "405", "Not Allowed"),
|
Err = jlib:make_error_reply(El, "405", "Not Allowed"),
|
||||||
send_element(StateData#state.sender, Err),
|
send_element(StateData#state.socket, Err),
|
||||||
{next_state, wait_for_auth, StateData}
|
{next_state, wait_for_auth, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -158,7 +162,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||||
{"", "", ""},
|
{"", "", ""},
|
||||||
jlib:iq_to_xml(ResIQ)),
|
jlib:iq_to_xml(ResIQ)),
|
||||||
Res = jlib:remove_attr("to", Res1),
|
Res = jlib:remove_attr("to", Res1),
|
||||||
send_element(StateData#state.sender, Res),
|
send_element(StateData#state.socket, Res),
|
||||||
{next_state, wait_for_auth, StateData};
|
{next_state, wait_for_auth, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
{next_state, wait_for_auth, StateData}
|
{next_state, wait_for_auth, StateData}
|
||||||
|
@ -262,7 +266,7 @@ code_change(OldVsn, StateName, StateData, Extra) ->
|
||||||
%% {stop, Reason, NewStateData}
|
%% {stop, Reason, NewStateData}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
handle_info({send_text, Text}, StateName, StateData) ->
|
handle_info({send_text, Text}, StateName, StateData) ->
|
||||||
send_text(StateData#state.sender, Text),
|
send_text(StateData#state.socket, Text),
|
||||||
{next_state, StateName, StateData};
|
{next_state, StateName, StateData};
|
||||||
handle_info(replaced, StateName, StateData) ->
|
handle_info(replaced, StateName, StateData) ->
|
||||||
% TODO
|
% TODO
|
||||||
|
@ -333,7 +337,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||||
jlib:jid_to_string(To),
|
jlib:jid_to_string(To),
|
||||||
NewAttrs),
|
NewAttrs),
|
||||||
Text = xml:element_to_string({xmlelement, Name, Attrs2, Els}),
|
Text = xml:element_to_string({xmlelement, Name, Attrs2, Els}),
|
||||||
send_text(StateData#state.sender, Text),
|
send_text(StateData#state.socket, Text),
|
||||||
{next_state, StateName, NewState};
|
{next_state, StateName, NewState};
|
||||||
true ->
|
true ->
|
||||||
{next_state, StateName, NewState}
|
{next_state, StateName, NewState}
|
||||||
|
@ -360,43 +364,46 @@ terminate(Reason, StateName, StateData) ->
|
||||||
presence_broadcast(From, StateData#state.pres_a, Packet),
|
presence_broadcast(From, StateData#state.pres_a, Packet),
|
||||||
presence_broadcast(From, StateData#state.pres_i, Packet)
|
presence_broadcast(From, StateData#state.pres_i, Packet)
|
||||||
end,
|
end,
|
||||||
StateData#state.sender ! close,
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
receiver(Socket, SockMod, C2SPid) ->
|
receiver(Socket, SockMod, Shaper, C2SPid) ->
|
||||||
XMLStreamPid = xml_stream:start(C2SPid),
|
XMLStreamPid = xml_stream:start(C2SPid),
|
||||||
receiver(Socket, SockMod, C2SPid, XMLStreamPid).
|
ShaperState = shaper:new(Shaper),
|
||||||
|
receiver(Socket, SockMod, ShaperState, C2SPid, XMLStreamPid).
|
||||||
|
|
||||||
receiver(Socket, SockMod, C2SPid, XMLStreamPid) ->
|
receiver(Socket, SockMod, ShaperState, C2SPid, XMLStreamPid) ->
|
||||||
case SockMod:recv(Socket, 0) of
|
case SockMod:recv(Socket, 0) of
|
||||||
{ok, Text} ->
|
{ok, Text} ->
|
||||||
|
ShaperSt1 = receive
|
||||||
|
{change_shaper, Shaper} ->
|
||||||
|
io:format("RECV: ChShaper to ~p~n", [Shaper]),
|
||||||
|
shaper:new(Shaper)
|
||||||
|
after 0 ->
|
||||||
|
ShaperState
|
||||||
|
end,
|
||||||
|
NewShaperState = shaper:update(ShaperSt1, size(Text)),
|
||||||
xml_stream:send_text(XMLStreamPid, Text),
|
xml_stream:send_text(XMLStreamPid, Text),
|
||||||
receiver(Socket, SockMod, C2SPid, XMLStreamPid);
|
receiver(Socket, SockMod, NewShaperState, C2SPid, XMLStreamPid);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
exit(XMLStreamPid, closed),
|
exit(XMLStreamPid, closed),
|
||||||
gen_fsm:send_event(C2SPid, closed),
|
gen_fsm:send_event(C2SPid, closed),
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
sender(Socket, SockMod) ->
|
change_shaper(StateData, JID) ->
|
||||||
receive
|
Shaper = acl:match_rule(StateData#state.shaper, JID),
|
||||||
{send_text, Text} ->
|
StateData#state.receiver ! {change_shaper, Shaper}.
|
||||||
SockMod:send(Socket,Text),
|
|
||||||
sender(Socket, SockMod);
|
|
||||||
close ->
|
|
||||||
SockMod:close(Socket),
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
send_text(Pid, Text) ->
|
send_text(Socket, Text) ->
|
||||||
Pid ! {send_text, Text}.
|
gen_tcp:send(Socket,Text).
|
||||||
|
|
||||||
|
send_element(Socket, El) ->
|
||||||
|
send_text(Socket, xml:element_to_string(El)).
|
||||||
|
|
||||||
send_element(Pid, El) ->
|
|
||||||
send_text(Pid, xml:element_to_string(El)).
|
|
||||||
|
|
||||||
new_id() ->
|
new_id() ->
|
||||||
randoms:get_string().
|
randoms:get_string().
|
||||||
|
|
|
@ -62,6 +62,10 @@ process_term(Term, State) ->
|
||||||
State#state{opts = [#config{key = {access, RuleName},
|
State#state{opts = [#config{key = {access, RuleName},
|
||||||
value = Rules} |
|
value = Rules} |
|
||||||
State#state.opts]};
|
State#state.opts]};
|
||||||
|
{shaper, Name, Data} ->
|
||||||
|
State#state{opts = [#config{key = {shaper, Name},
|
||||||
|
value = Data} |
|
||||||
|
State#state.opts]};
|
||||||
{Opt, Val} ->
|
{Opt, Val} ->
|
||||||
add_option(Opt, Val, State)
|
add_option(Opt, Val, State)
|
||||||
end.
|
end.
|
||||||
|
|
58
src/shaper.erl
Normal file
58
src/shaper.erl
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : shaper.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose : Functions to control connections traffic
|
||||||
|
%%% Created : 9 Feb 2003 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(shaper).
|
||||||
|
-author('alexey@sevcom.net').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-export([new/1, new1/1, update/2]).
|
||||||
|
|
||||||
|
-record(maxrate, {maxrate, lastrate, lasttime}).
|
||||||
|
|
||||||
|
|
||||||
|
new(Name) ->
|
||||||
|
Data = case ejabberd_config:get_global_option({shaper, Name}) of
|
||||||
|
undefined ->
|
||||||
|
none;
|
||||||
|
D ->
|
||||||
|
D
|
||||||
|
end,
|
||||||
|
new1(Data).
|
||||||
|
|
||||||
|
|
||||||
|
new1(none) ->
|
||||||
|
none;
|
||||||
|
new1({maxrate, MaxRate}) ->
|
||||||
|
#maxrate{maxrate = MaxRate,
|
||||||
|
lastrate = 0,
|
||||||
|
lasttime = now_to_usec(now())}.
|
||||||
|
|
||||||
|
|
||||||
|
update(none, Size) ->
|
||||||
|
none;
|
||||||
|
update(#maxrate{} = State, Size) ->
|
||||||
|
MinInterv = 1000 * Size /
|
||||||
|
(2 * State#maxrate.maxrate - State#maxrate.lastrate),
|
||||||
|
Interv = (now_to_usec(now()) - State#maxrate.lasttime) / 1000,
|
||||||
|
%io:format("State: ~p, Size=~p~nM=~p, I=~p~n",
|
||||||
|
% [State, Size, MinInterv, Interv]),
|
||||||
|
if
|
||||||
|
MinInterv > Interv ->
|
||||||
|
timer:sleep(1 + trunc(MinInterv - Interv));
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
Now = now_to_usec(now()),
|
||||||
|
State#maxrate{
|
||||||
|
lastrate = (State#maxrate.lastrate +
|
||||||
|
1000000 * Size / (Now - State#maxrate.lasttime))/2,
|
||||||
|
lasttime = Now}.
|
||||||
|
|
||||||
|
|
||||||
|
now_to_usec({MSec, Sec, USec}) ->
|
||||||
|
(MSec*1000000 + Sec)*1000000 + USec.
|
Loading…
Reference in New Issue
Block a user