24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-06-26 22:35:31 +02:00

Refactor ejabberd_listener

This commit is contained in:
Evgeny Khramtsov 2018-09-18 12:53:36 +03:00
parent fb367469d4
commit 03de853e4f
11 changed files with 717 additions and 665 deletions

View File

@ -27,7 +27,7 @@
-protocol({rfc, 6121}).
%% ejabberd_listener callbacks
-export([start/2, start_link/2, accept/1, listen_opt_type/1]).
-export([start/2, start_link/2, accept/1, listen_opt_type/1, listen_options/0]).
%% ejabberd_config callbacks
-export([opt_type/1, transform_listen_option/2]).
%% xmpp_stream_in callbacks
@ -979,53 +979,54 @@ opt_type(_) ->
disable_sasl_mechanisms].
-spec listen_opt_type(atom()) -> fun((any()) -> any()) | [atom()].
listen_opt_type(access) -> fun acl:access_rules_validator/1;
listen_opt_type(shaper) -> fun acl:shaper_rules_validator/1;
listen_opt_type(certfile = Opt) ->
fun(S) ->
?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
"'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
ok = ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(ciphers) -> opt_type(c2s_ciphers);
listen_opt_type(dhfile) -> opt_type(c2s_dhfile);
listen_opt_type(cafile) -> opt_type(c2s_cafile);
listen_opt_type(protocol_options) -> opt_type(c2s_protocol_options);
listen_opt_type(tls_compression) -> opt_type(c2s_tls_compression);
listen_opt_type(tls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(starttls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(starttls_required) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(tls_verify) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(zlib) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(supervisor) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(max_stanza_size) ->
fun(I) when is_integer(I), I>0 -> I;
(unlimited) -> infinity;
(infinity) -> infinity
listen_opt_type(zlib) ->
fun(true) ->
ejabberd:start_app(ezlib),
true;
(false) ->
false
end;
listen_opt_type(max_fsm_queue) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(stream_management) ->
?ERROR_MSG("listening option 'stream_management' is ignored: "
"use mod_stream_mgmt module", []),
fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(accept_interval) ->
fun(I) when is_integer(I), I>=0 -> I end;
fun(B) when is_boolean(B) ->
?ERROR_MSG("Listening option 'stream_management' is ignored: "
"use mod_stream_mgmt module", []),
B
end;
listen_opt_type(O) ->
StreamOpts = mod_stream_mgmt:mod_options(ejabberd_config:get_myname()),
case lists:keyfind(O, 1, StreamOpts) of
false ->
[access, shaper, certfile, ciphers, dhfile, cafile,
protocol_options, tls, tls_compression, starttls,
starttls_required, tls_verify, zlib, max_fsm_queue,
backlog, inet, inet6, accept_interval];
_ ->
?ERROR_MSG("Listening option '~s' is ignored: use '~s' "
"option from mod_stream_mgmt module", [O, O]),
mod_stream_mgmt:mod_opt_type(O)
MgmtOpts = mod_stream_mgmt:mod_options(ejabberd_config:get_myname()),
case lists:keymember(O, 1, MgmtOpts) of
true ->
fun(V) ->
?ERROR_MSG("Listening option '~s' is ignored: use '~s' "
"option from mod_stream_mgmt module", [O, O]),
(mod_stream_mgmt:mod_opt_type(O))(V)
end
end.
listen_options() ->
[{access, all},
{shaper, none},
{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{starttls, false},
{starttls_required, false},
{tls_verify, false},
{zlib, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000}|
mod_stream_mgmt:mod_options(ejabberd_config:get_myname())].

View File

@ -32,7 +32,8 @@
%% External exports
-export([start/2, start_link/2,
accept/1, receive_headers/1, recv_file/2,
transform_listen_option/2, listen_opt_type/1]).
transform_listen_option/2, listen_opt_type/1,
listen_options/0]).
-export([init/2, opt_type/1]).
@ -101,6 +102,7 @@ init({SockMod, Socket}, Opts) ->
TLSEnabled = proplists:get_bool(tls, Opts),
TLSOpts1 = lists:filter(fun ({ciphers, _}) -> true;
({dhfile, _}) -> true;
({cafile, _}) -> true;
({protocol_options, _}) -> true;
(_) -> false
end,
@ -959,24 +961,13 @@ opt_type(trusted_proxies) ->
end;
opt_type(_) -> [trusted_proxies].
-spec listen_opt_type(atom()) -> fun((any()) -> any()) | [atom()].
listen_opt_type(tls) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(certfile = Opt) ->
fun(S) ->
?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
"'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
ok = ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(ciphers) ->
fun iolist_to_binary/1;
listen_opt_type(dhfile) ->
fun misc:try_read_file/1;
listen_opt_type(protocol_options) ->
fun(Options) -> str:join(Options, <<"|">>) end;
listen_opt_type(tls_compression) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(captcha) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(register) ->
@ -1003,15 +994,23 @@ listen_opt_type(request_handlers) ->
end} || {Path, Mod} <- Hs2]
end;
listen_opt_type(default_host) ->
fun(A) -> A end;
fun iolist_to_binary/1;
listen_opt_type(custom_headers) ->
fun expand_custom_headers/1;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(accept_interval) ->
fun(I) when is_integer(I), I>=0 -> I end;
listen_opt_type(_) ->
%% TODO
fun(A) -> A end.
fun expand_custom_headers/1.
listen_options() ->
[{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{captcha, false},
{register, false},
{web_admin, false},
{http_bind, false},
{xmlrpc, false},
{request_handlers, []},
{default_host, undefined},
{custom_headers, []}].

File diff suppressed because it is too large Load Diff

View File

@ -63,7 +63,12 @@
-spec add_certfile(file:filename())
-> ok | {error, cert_error() | file:posix()}.
add_certfile(Path) ->
gen_server:call(?MODULE, {add_certfile, prep_path(Path)}).
try gen_server:call(?MODULE, {add_certfile, prep_path(Path)})
catch exit:{noproc, {gen_server, call, _}} ->
%% This hack will be removed after moving
%% the code into a separate repo
ok
end.
-spec try_certfile(file:filename()) -> binary().
try_certfile(Path0) ->

View File

@ -738,7 +738,12 @@ opt_type(s2s_use_starttls) ->
required_trusted
end;
opt_type(s2s_zlib) ->
fun(B) when is_boolean(B) -> B end;
fun(true) ->
ejabberd:start_app(ezlib),
true;
(false) ->
false
end;
opt_type(s2s_timeout) ->
fun(I) when is_integer(I), I >= 0 -> timer:seconds(I);
(infinity) -> infinity;

View File

@ -24,7 +24,7 @@
-behaviour(ejabberd_listener).
%% ejabberd_listener callbacks
-export([start/2, start_link/2, accept/1, listen_opt_type/1]).
-export([start/2, start_link/2, accept/1, listen_opt_type/1, listen_options/0]).
%% xmpp_stream_in callbacks
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
@ -341,35 +341,22 @@ change_shaper(#{shaper := ShaperName, server_host := ServerHost} = State,
xmpp_stream_in:change_shaper(State, ejabberd_shaper:new(Shaper)).
-spec listen_opt_type(atom()) -> fun((any()) -> any()) | [atom()].
listen_opt_type(shaper) -> fun acl:shaper_rules_validator/1;
listen_opt_type(certfile = Opt) ->
fun(S) ->
?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
"'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
ok = ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(ciphers) -> ejabberd_s2s:opt_type(s2s_ciphers);
listen_opt_type(dhfile) -> ejabberd_s2s:opt_type(s2s_dhfile);
listen_opt_type(cafile) -> ejabberd_s2s:opt_type(s2s_cafile);
listen_opt_type(protocol_options) -> ejabberd_s2s:opt_type(s2s_protocol_options);
listen_opt_type(tls_compression) -> ejabberd_s2s:opt_type(s2s_tls_compression);
listen_opt_type(tls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(supervisor) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(max_stanza_size) ->
fun(I) when is_integer(I), I>0 -> I;
(unlimited) -> infinity;
(infinity) -> infinity
end;
listen_opt_type(max_fsm_queue) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(accept_interval) ->
fun(I) when is_integer(I), I>=0 -> I end;
listen_opt_type(_) ->
[shaper, certfile, ciphers, dhfile, cafile, protocol_options,
tls_compression, tls, max_fsm_queue, backlog, inet, inet6,
accept_interval].
end.
listen_options() ->
[{shaper, none},
{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000}].

View File

@ -27,7 +27,7 @@
%% ejabberd_listener callbacks
-export([start/2, start_link/2, accept/1]).
-export([listen_opt_type/1, transform_listen_option/2]).
-export([listen_opt_type/1, listen_options/0, transform_listen_option/2]).
%% xmpp_stream_in callbacks
-export([init/1, handle_info/2, terminate/2, code_change/3]).
-export([handle_stream_start/2, handle_auth_success/4, handle_auth_failure/4,
@ -78,7 +78,8 @@ tls_options(#{tls_options := TLSOptions}) ->
init([State, Opts]) ->
Access = proplists:get_value(access, Opts, all),
Shaper = proplists:get_value(shaper_rule, Opts, none),
Shaper = proplists:get_value(shaper, Opts,
proplists:get_value(shaper_rule, Opts, none)),
GlobalPassword = proplists:get_value(password, Opts, random_password()),
HostOpts = proplists:get_value(hosts, Opts, [{global, GlobalPassword}]),
HostOpts1 = lists:map(
@ -281,20 +282,12 @@ transform_listen_option(Opt, Opts) ->
[Opt|Opts].
-spec listen_opt_type(atom()) -> fun((any()) -> any()) | [atom()].
listen_opt_type(access) -> fun acl:access_rules_validator/1;
listen_opt_type(shaper_rule) -> fun acl:shaper_rules_validator/1;
listen_opt_type(certfile) ->
fun(S) ->
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
listen_opt_type(shaper_rule) ->
fun(V) ->
?WARNING_MSG("Listening option 'shaper_rule' of module ~s "
"is renamed to 'shaper'", [?MODULE]),
acl:shaper_rules_validator(V)
end;
listen_opt_type(ciphers) -> fun iolist_to_binary/1;
listen_opt_type(dhfile) -> fun misc:try_read_file/1;
listen_opt_type(cafile) -> fun misc:try_read_file/1;
listen_opt_type(protocol_options) ->
fun(Options) -> str:join(Options, <<"|">>) end;
listen_opt_type(tls_compression) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(tls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(check_from) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(password) -> fun iolist_to_binary/1;
listen_opt_type(hosts) ->
@ -309,21 +302,22 @@ listen_opt_type(hosts) ->
end, HostOpts)
end;
listen_opt_type(global_routes) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(max_stanza_size) ->
fun(I) when is_integer(I) -> I;
(unlimited) -> infinity;
(infinity) -> infinity
end;
listen_opt_type(max_fsm_queue) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(accept_interval) ->
fun(I) when is_integer(I), I>=0 -> I end;
listen_opt_type(_) ->
[access, shaper_rule, certfile, ciphers, dhfile, cafile, tls,
protocol_options, tls_compression, password, hosts, check_from,
max_fsm_queue, global_routes, backlog, inet, inet6, accept_interval].
fun(B) when is_boolean(B) -> B end.
listen_options() ->
[{access, all},
{shaper, none},
{shaper_rule, none},
{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000},
{password, undefined},
{hosts, []},
{check_from, true},
{global_routes, true}].

View File

@ -28,13 +28,13 @@
-ifndef(SIP).
-include("logger.hrl").
-export([accept/1, start/2, start_link/2, listen_opt_type/1]).
-export([accept/1, start/2, start_link/2, listen_options/0]).
log_error() ->
?CRITICAL_MSG("ejabberd is not compiled with SIP support", []).
accept(_) ->
log_error(),
ok.
listen_opt_type(_) ->
listen_options() ->
log_error(),
[].
start(_, _) ->
@ -46,7 +46,7 @@ start_link(_, _) ->
-else.
%% API
-export([tcp_init/2, udp_init/2, udp_recv/5, start/2,
start_link/2, accept/1, listen_opt_type/1]).
start_link/2, accept/1, listen_options/0]).
%%%===================================================================
@ -90,19 +90,9 @@ set_certfile(Opts) ->
end
end.
listen_opt_type(certfile) ->
fun(S) ->
%% We cannot deprecate the option for now:
%% I think SIP clients are too stupid to set SNI
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(tls) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(accept_interval) ->
fun(I) when is_integer(I), I>=0 -> I end;
listen_opt_type(_) ->
[tls, certfile, accept_interval].
listen_options() ->
[{tls, false},
{certfile, undefined}].
%%%===================================================================
%%% Internal functions

View File

@ -30,15 +30,15 @@
-ifndef(STUN).
-include("logger.hrl").
-export([accept/1, start/2, start_link/2, listen_opt_type/1]).
-export([accept/1, start/2, start_link/2, listen_options/0]).
log_error() ->
?CRITICAL_MSG("ejabberd is not compiled with STUN/TURN support", []).
accept(_) ->
log_error(),
ok.
listen_opt_type(_) ->
listen_options() ->
log_error(),
[].
[];
start(_, _) ->
log_error(),
{error, sip_not_compiled}.
@ -47,7 +47,7 @@ start_link(_, _) ->
{error, sip_not_compiled}.
-else.
-export([tcp_init/2, udp_init/2, udp_recv/5, start/2,
start_link/2, accept/1, listen_opt_type/1]).
start_link/2, accept/1, listen_opt_type/1, listen_options/0]).
-include("logger.hrl").
@ -144,27 +144,16 @@ listen_opt_type(turn_ip) ->
{ok, Addr} = inet_parse:ipv4_address(binary_to_list(S)),
Addr
end;
listen_opt_type(shaper) ->
fun acl:shaper_rules_validator/1;
listen_opt_type(auth_type) ->
fun(anonymous) -> anonymous;
(user) -> user
end;
listen_opt_type(auth_realm) ->
fun iolist_to_binary/1;
listen_opt_type(tls) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(certfile) ->
fun(S) ->
%% We cannot deprecate the option for now:
%% I think STUN/TURN clients are too stupid to set SNI
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(turn_min_port) ->
fun(P) when is_integer(P), P > 0, P =< 65535 -> P end;
fun(P) when is_integer(P), P > 1024, P < 65536 -> P end;
listen_opt_type(turn_max_port) ->
fun(P) when is_integer(P), P > 0, P =< 65535 -> P end;
fun(P) when is_integer(P), P > 1024, P < 65536 -> P end;
listen_opt_type(turn_max_allocations) ->
fun(I) when is_integer(I), I>0 -> I;
(unlimited) -> infinity;
@ -176,13 +165,17 @@ listen_opt_type(turn_max_permissions) ->
(infinity) -> infinity
end;
listen_opt_type(server_name) ->
fun iolist_to_binary/1;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(accept_interval) ->
fun(I) when is_integer(I), I>=0 -> I end;
listen_opt_type(_) ->
[shaper, auth_type, auth_realm, tls, certfile, turn_min_port,
turn_max_port, turn_max_allocations, turn_max_permissions,
server_name, backlog, accept_interval].
fun iolist_to_binary/1.
listen_options() ->
[{shaper, none},
{auth_type, user},
{auth_realm, undefined},
{tls, false},
{certfile, undefined},
{turn_min_port, 49152},
{turn_max_port, 65535},
{turn_max_allocations, 10},
{turn_max_permissions, 10},
{server_name, <<"ejabberd">>}].
-endif.

View File

@ -36,7 +36,7 @@
-author('badlop@process-one.net').
-export([start/2, start_link/2, handler/2, process/2, accept/1,
transform_listen_option/2, listen_opt_type/1]).
transform_listen_option/2, listen_opt_type/1, listen_options/0]).
-include("logger.hrl").
-include("ejabberd_http.hrl").
@ -580,17 +580,7 @@ listen_opt_type(access_commands) ->
{<<"ejabberd_xmlrpc compatibility shim">>,
{[?MODULE], [{access, Ac}], Commands}}
end, lists:flatten(Opts))
end;
listen_opt_type(maxsessions) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(timeout) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(accept_interval) ->
fun(I) when is_integer(I), I>=0 -> I end;
listen_opt_type(_) ->
[access_commands, maxsessions, timeout, backlog, inet, inet6,
accept_interval].
end.
listen_options() ->
[{access_commands, []}].

View File

@ -116,12 +116,10 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
add_listener(Host, Opts) ->
NewOpts = [{server_host, Host} | Opts],
ejabberd_listener:add_listener(get_port_ip(Host),
mod_proxy65_stream, NewOpts).
ejabberd_listener:add_listener(get_endpoint(Host), mod_proxy65_stream, NewOpts).
delete_listener(Host) ->
catch ejabberd_listener:delete_listener(get_port_ip(Host),
mod_proxy65_stream).
ejabberd_listener:delete_listener(get_endpoint(Host), mod_proxy65_stream).
%%%------------------------
%%% IQ Processing
@ -238,7 +236,7 @@ transform_module_options(Opts) ->
-spec get_streamhost(binary(), binary()) -> streamhost().
get_streamhost(Host, ServerHost) ->
{Port, IP} = get_port_ip(ServerHost),
{Port, IP, _} = get_endpoint(ServerHost),
HostName0 = case gen_mod:get_module_opt(ServerHost, mod_proxy65, hostname) of
undefined -> misc:ip_to_list(IP);
Val -> Val
@ -249,14 +247,14 @@ get_streamhost(Host, ServerHost) ->
host = HostName,
port = Port}.
-spec get_port_ip(binary()) -> {pos_integer(), inet:ip_address()}.
get_port_ip(Host) ->
-spec get_endpoint(binary()) -> {inet:port_number(), inet:ip_address(), tcp}.
get_endpoint(Host) ->
Port = gen_mod:get_module_opt(Host, mod_proxy65, port),
IP = case gen_mod:get_module_opt(Host, mod_proxy65, ip) of
undefined -> get_my_ip();
Addr -> Addr
end,
{Port, IP}.
{Port, IP, tcp}.
-spec get_my_ip() -> inet:ip_address().
get_my_ip() ->