diff options
author | Micael Karlberg <bmk@erlang.org> | 2019-11-19 17:06:50 +0100 |
---|---|---|
committer | Micael Karlberg <bmk@erlang.org> | 2019-11-25 18:28:27 +0100 |
commit | e83a4a1c6ab164c39e3d8aa353119725924ca08c (patch) | |
tree | d44aed8b7e6ef2f7a1eed964d5d2aead4844b05f | |
parent | d1c6ba0ab9e9379cf5e3aa058e6b9893d0d06307 (diff) | |
download | erlang-e83a4a1c6ab164c39e3d8aa353119725924ca08c.tar.gz |
[enet] Add first version of filter arg to getifaddrs
Added the function getifaddrs/1,2 that takes a filter
argument, which makes it possible to filter out only
those interfaces that "belong" to that specific
(socket) address family.
OTP-16212
-rw-r--r-- | lib/kernel/src/net.erl | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl index e2ccbdc9c5..331582c47a 100644 --- a/lib/kernel/src/net.erl +++ b/lib/kernel/src/net.erl @@ -37,7 +37,7 @@ gethostname/0, getnameinfo/1, getnameinfo/2, getaddrinfo/1, getaddrinfo/2, - getifaddrs/0, getifaddrs/1, + getifaddrs/0, getifaddrs/1, getifaddrs/2, if_name2index/1, if_index2name/1, @@ -94,6 +94,9 @@ broadaddr := socket:sockaddr(), dstaddr := socket:sockaddr()}. +-type ifaddrs_filter_map() :: #{family := default | inet | inet6 | all, + flags := any | ifaddrs_flags()}. + -type name_info_flags() :: [name_info_flag()|name_info_flag_ext()]. -type name_info_flag() :: namereqd | dgram | @@ -287,7 +290,7 @@ getaddrinfo(Host, Service) -ifdef(USE_ESOCK). getifaddrs() -> - prim_net:getifaddrs(#{}). + getifaddrs(getifaddrs_filter_map_default()). -else. getifaddrs() -> erlang:error(notsup). @@ -297,18 +300,71 @@ getifaddrs() -> -spec getifaddrs(Namespace) -> {ok, IfAddrs} | {error, Reason} when Namespace :: file:filename_all(), IfAddrs :: [ifaddrs()], + Reason :: term(); + (FilterMap) -> {ok, IfAddrs} | {error, Reason} when + FilterMap :: ifaddrs_filter_map(), + IfAddrs :: [ifaddrs()], Reason :: term(). -ifdef(USE_ESOCK). getifaddrs(Namespace) when is_list(Namespace) -> - prim_net:getifaddrs(#{netns => Namespace}). + prim_net:getifaddrs(#{netns => Namespace}); +getifaddrs(FilterMap) when is_map(FilterMap) -> + do_getifaddrs(getifaddrs_filter_map(FilterMap), + fun() -> prim_net:getifaddrs(#{}) end). -else. -dialyzer({nowarn_function, getifaddrs/1}). getifaddrs(Namespace) when is_list(Namespace) -> + erlang:error(notsup); +getifaddrs(FilterMap) when is_map(FilterMap) -> erlang:error(notsup). -endif. +-spec getifaddrs(FilterMap, Namespace) -> {ok, IfAddrs} | {error, Reason} when + FilterMap :: ifaddrs_filter_map(), + Namespace :: file:filename_all(), + IfAddrs :: [ifaddrs()], + Reason :: term(). + +getifaddrs(FilterMap, Namespace) + when is_map(FilterMap) andalso is_list(Namespace) -> + do_getifaddrs(getifaddrs_filter_map(FilterMap), + fun() -> getifaddrs(Namespace) end). + +do_getifaddrs(FilterMap, GetIfAddrs) -> + case GetIfAddrs() of + {ok, IfAddrs0} -> + Filter = fun(Elem) -> getifaddrs_filter(FilterMap, Elem) end, + {ok, lists:filtermap(Filter, IfAddrs0)}; + {error, _} = ERROR -> + ERROR + end. + +getifaddrs_filter_map(FilterMap) -> + maps:merge(getifaddrs_filter_map_default(), FilterMap). + +getifaddrs_filter_map_default() -> + #{family => default, flags => any}. + +getifaddrs_filter(#{family := FFamily}, + #{addr := #{family := Family}} = _Entry) + when (FFamily =:= default) andalso + ((Family =:= inet) orelse (Family =:= inet6)) -> + true; +getifaddrs_filter(#{family := FFamily}, + #{addr := #{family := Family}} = _Entry) + when (FFamily =:= inet) andalso (Family =:= inet) -> + true; +getifaddrs_filter(#{family := FFamily}, + #{addr := #{family := Family}} = _Entry) + when (FFamily =:= inet6) andalso (Family =:= inet6) -> + true; +getifaddrs_filter(#{family := FFamily}, _Entry) + when (FFamily =:= all) -> + true; +getifaddrs_filter(_Filter, _Entry) -> + false. %% =========================================================================== |