./ct_report/coverage/mongoose_listener_config.COVER.html

1 %% @doc Utilities related to listener configuration options
2
3 -module(mongoose_listener_config).
4
5 -export([ensure_ip_options/1,
6 verify_unique_listeners/1,
7 prepare_opts/1,
8 filter_socket_opts/1,
9 listener_id/1]).
10
11 -type listener() :: #{port := inet:port_number(),
12 ip_tuple := inet:ip_address(),
13 ip_address := string(),
14 ip_version := 4 | 6,
15 proto := proto(),
16 any() => any()}.
17 -type listener_id() :: {inet:port_number(), inet:ip_address(), proto()}.
18 -type proto() :: tcp | udp.
19
20 -export_type([listener/0, listener_id/0, proto/0]).
21
22 %% @doc Fill in IP-related options that can be calculated automatically.
23 %% Apart from these options, the input should be a complete listener configuration.
24 -spec ensure_ip_options(map()) -> listener().
25 ensure_ip_options(Opts = #{ip_address := IPAddr, ip_version := 4}) ->
26
:-(
{ok, IPTuple} = inet:parse_ipv4_address(IPAddr),
27
:-(
Opts#{ip_tuple => IPTuple};
28 ensure_ip_options(Opts = #{ip_address := IPAddr, ip_version := 6}) ->
29
:-(
{ok, IPTuple} = inet:parse_ipv6_address(IPAddr),
30
:-(
Opts#{ip_tuple => IPTuple};
31 ensure_ip_options(Opts = #{ip_address := IPAddr}) ->
32 957 {ok, IPTuple} = inet:parse_address(IPAddr),
33 957 Opts#{ip_tuple => IPTuple,
34 ip_version => ip_version(IPTuple)};
35 ensure_ip_options(Opts = #{ip_version := 6}) ->
36
:-(
ensure_ip_options(Opts#{ip_address => "::"});
37 ensure_ip_options(Opts) ->
38 490 ensure_ip_options(Opts#{ip_address => "0"}).
39
40 957 ip_version(T) when tuple_size(T) =:= 4 -> 4;
41
:-(
ip_version(T) when tuple_size(T) =:= 8 -> 6.
42
43 %% @doc Verify that all listeners have unique socket addresses
44 -spec verify_unique_listeners([listener()]) -> [listener()].
45 verify_unique_listeners(Listeners) ->
46 82 Counts = lists:foldl(fun(L, Cts) ->
47 957 maps:update_with(listener_id(L), fun(Ct) -> Ct + 1 end, 1, Cts)
48 end, #{}, Listeners),
49 82 case [K || {K, V} <- maps:to_list(Counts), V > 1] of
50 82 [] -> Listeners;
51
:-(
Dups -> error(#{what => duplicate_listeners, duplicates => Dups,
52 text => <<"Some listeners have duplicate listening socket addresses">>})
53 end.
54
55 %% @doc Convert listener configuration to options that can be passed to listener modules
56 -spec prepare_opts(listener()) -> ejabberd_listener:opts().
57 prepare_opts(Listener) ->
58 1006 lists:flatmap(fun prepare_opt/1, maps:to_list(Listener)).
59
60 257 prepare_opt({tls, Opts}) -> Opts;
61 1006 prepare_opt({ip_version, 4}) -> [inet];
62
:-(
prepare_opt({ip_version, 6}) -> [inet6];
63 1006 prepare_opt({ip_tuple, Val}) -> [{ip, Val}];
64 6783 prepare_opt(Opt) -> [Opt].
65
66 %% @doc Filter listener options, leaving only socket-related ones
67 -spec filter_socket_opts(proplists:proplist()) -> proplists:proplist().
68 filter_socket_opts(Opts) ->
69 428 lists:filter(fun filter_socket_opt/1, Opts).
70
71 428 filter_socket_opt(inet) -> true;
72
:-(
filter_socket_opt(inet6) -> true;
73 428 filter_socket_opt({ip, _}) -> true;
74
:-(
filter_socket_opt({backlog, _}) -> true;
75 3692 filter_socket_opt(_) -> false.
76
77 %% @doc Create a unique ID based on the listening socket address
78 -spec listener_id(listener()) -> listener_id().
79 listener_id(#{port := Port, ip_tuple := IPTuple, proto := Proto}) ->
80 2969 {Port, IPTuple, Proto}.
Line Hits Source