./ct_report/coverage/mongoose_c2s_listener.COVER.html

1 -module(mongoose_c2s_listener).
2
3 -include("mongoose.hrl").
4
5 -behaviour(mongoose_listener).
6 -export([start_listener/1]).
7
8 -behaviour(ranch_protocol).
9 -export([start_link/3]).
10
11 -behaviour(supervisor).
12 -export([start_link/1, init/1]).
13 -ignore_xref([start_link/1]).
14
15 %% Hook handlers
16 -export([handle_user_open_session/3]).
17
18 -type options() :: #{module := module(),
19 atom() => any()}.
20
21 %% mongoose_listener
22 -spec start_listener(options()) -> ok.
23 start_listener(Opts) ->
24 205 ListenerId = mongoose_listener_config:listener_id(Opts),
25 205 ChildSpec = listener_child_spec(ListenerId, Opts),
26 205 mongoose_listener_sup:start_child(ChildSpec),
27 205 ok.
28
29 %% Hooks and handlers
30 -spec handle_user_open_session(mongoose_acc:t(), mongoose_c2s_hooks:params(), gen_hook:extra()) ->
31 mongoose_c2s_hooks:result().
32 handle_user_open_session(Acc, #{c2s_data := StateData},
33 #{host_type := HostType, listener_id := ListenerId}) ->
34 15606 ListenerOpts = mongoose_c2s:get_listener_opts(StateData),
35 15606 case mongoose_listener_config:listener_id(ListenerOpts) of
36 ListenerId ->
37 7644 Jid = mongoose_c2s:get_jid(StateData),
38 7644 LServer = mongoose_c2s:get_lserver(StateData),
39 7644 #{access := Access} = ListenerOpts,
40 7644 case acl:match_rule(HostType, LServer, Access, Jid) of
41 allow ->
42 7642 case mongoose_hooks:session_opening_allowed_for_user(HostType, Jid) of
43 7642 allow -> {ok, Acc};
44
:-(
_ -> {stop, Acc}
45 end;
46 deny ->
47 2 {stop, Acc}
48 end;
49 _Other ->
50 7962 {ok, Acc}
51 end.
52
53 %% ranch_protocol
54 start_link(Ref, Transport, Opts = #{hibernate_after := HibernateAfterTimeout}) ->
55 8594 mongoose_c2s:start_link({mongoose_c2s_ranch, {Transport, Ref}, Opts}, [{hibernate_after, HibernateAfterTimeout}]).
56
57 %% supervisor
58 -spec start_link(options()) -> any().
59 start_link(Opts) ->
60 205 supervisor:start_link(?MODULE, Opts).
61
62 -spec init(options()) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
63 init(#{module := Module} = Opts) ->
64 205 HostTypes = ?ALL_HOST_TYPES,
65 205 TransportOpts = prepare_socket_opts(Opts),
66 205 ListenerId = mongoose_listener_config:listener_id(Opts),
67 205 maybe_add_access_check(HostTypes, Opts, ListenerId),
68 205 Child = ranch:child_spec(ListenerId, ranch_tcp, TransportOpts, Module, Opts),
69 205 {ok, {#{strategy => one_for_one, intensity => 100, period => 1}, [Child]}}.
70
71 maybe_add_access_check(_, #{access := all}, _) ->
72
:-(
ok;
73 maybe_add_access_check(HostTypes, _, ListenerId) ->
74 205 AclHooks = [ {user_open_session, HostType, fun ?MODULE:handle_user_open_session/3,
75 #{listener_id => ListenerId}, 10}
76 205 || HostType <- HostTypes ],
77 205 gen_hook:add_handlers(AclHooks).
78
79 listener_child_spec(ListenerId, Opts) ->
80 205 #{id => ListenerId,
81 start => {?MODULE, start_link, [Opts]},
82 restart => permanent,
83 shutdown => infinity,
84 type => supervisor,
85 modules => [?MODULE]}.
86
87 prepare_socket_opts(#{port := Port,
88 ip_version := IPVersion,
89 ip_tuple := IPTuple,
90 backlog := Backlog,
91 num_acceptors := NumAcceptors,
92 max_connections := MaxConnections,
93 reuse_port := ReusePort}) ->
94 205 SocketOpts = [{nodelay, true},
95 {keepalive, true},
96 {ip, IPTuple},
97 {port, Port},
98 {backlog, Backlog},
99 mongoose_listener_config:address_family(IPVersion)
100 | maybe_reuseport(ReusePort)],
101 205 #{max_connections => MaxConnections,
102 num_acceptors => NumAcceptors,
103 num_listen_sockets => num_listen_sockets(ReusePort),
104 socket_opts => SocketOpts}.
105
106 205 maybe_reuseport(false) -> [];
107
:-(
maybe_reuseport(true) -> [{raw, 1, 15, <<1:32/native>>}].
108
109 205 num_listen_sockets(false) -> 1;
110
:-(
num_listen_sockets(true) -> erlang:system_info(schedulers_online).
Line Hits Source