From 18de1d9ede51604f65586f7026ff10ba1d3e181b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 5 Jun 2024 08:53:57 +0200 Subject: [PATCH 01/37] [kernel] Implement use of inet_backend for getservby[name|port] Make the functions inet:getservby[name|port]/2 take inet_backend into account. This will have the effect of using the net-module instead of the inet-driver in inet_backend is set to 'socket'. --- lib/kernel/src/inet.erl | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 5f815e9a5932..08a06186b180 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -293,6 +293,7 @@ Function `parse_address/1` can be useful: -export([getaddrs/2, getaddrs/3, getaddrs_tm/3, getaddr/2, getaddr/3, getaddr_tm/3]). -export([translate_ip/2]). +-export([inet_backend/0]). -export([get_rc/0]). @@ -2208,29 +2209,58 @@ getaddrs(Address, Family, Timeout) -> -spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) -> {'ok', string()} | {'error', posix()}. -getservbyport(Port, Proto) -> +getservbyport(Port, Protocol) -> + case inet_backend() of + 'inet' -> + inet_getservbyport(Port, Protocol); + 'socket' -> + net_getservbyport(Port, Protocol) + end. + +inet_getservbyport(Port, Protocol) -> case inet_udp:open(0, []) of {ok,U} -> - Res = prim_inet:getservbyport(U, Port, Proto), + Res = prim_inet:getservbyport(U, Port, Protocol), inet_udp:close(U), Res; Error -> Error end. +net_getservbyport(Port, Protocol) when is_list(Protocol) -> + net_getservbyport(Port, list_to_atom(Protocol)); +net_getservbyport(Port, Protocol) when is_atom(Protocol) -> + net:getservbyport(Port, Protocol). + -doc false. -spec getservbyname(Name :: atom() | string(), Protocol :: atom() | string()) -> {'ok', port_number()} | {'error', posix()}. getservbyname(Name, Protocol) when is_atom(Name) -> + getservbyname(atom_to_list(Name), Protocol); +getservbyname(Name, Protocol) when is_list(Name) -> + case inet_backend() of + 'inet' -> + inet_getservbyname(Name, Protocol); + 'socket' -> + net_getservbyname(Name, Protocol) + end. + +inet_getservbyname(Name, Protocol) -> case inet_udp:open(0, []) of - {ok,U} -> + {ok, U} -> Res = prim_inet:getservbyname(U, Name, Protocol), inet_udp:close(U), Res; Error -> Error end. +net_getservbyname(Name, Protocol) when is_list(Protocol) -> + net_getservbyname(Name, list_to_atom(Protocol)); +net_getservbyname(Name, Protocol) when is_atom(Protocol) -> + net:getservbyname(Name, Protocol). + + -doc "Parse an `t:ip_address/0` to an IPv4 or IPv6 address string.". -doc(#{since => <<"OTP R16B02">>}). -spec ntoa(IpAddress) -> Address | {error, einval} when @@ -3962,3 +3992,8 @@ ensure_sockaddr(SockAddr) -> throw : {invalid, _} = Invalid : Stacktrace -> erlang:raise(error, Invalid, Stacktrace) end. + + +-doc false. +inet_backend() -> + persistent_term:get({kernel, inet_backend}, ?DEFAULT_KERNEL_INET_BACKEND). From 56d4986bae65abf8eaa164f37b872a0fcd3ee488 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 5 Jun 2024 10:24:05 +0200 Subject: [PATCH 02/37] [enet] Fixed prim_net command and debug --- erts/preloaded/ebin/prim_net.beam | Bin 2800 -> 2828 bytes erts/preloaded/src/prim_net.erl | 8 +++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/erts/preloaded/ebin/prim_net.beam b/erts/preloaded/ebin/prim_net.beam index 3c78ee94c56ea4163fab5ebaa88296b45207c997..7e59c25f2e6eb531503f79b42aac9e3146cb88bb 100644 GIT binary patch delta 1354 zcmZ9M-D@0G7{<@pnN8kKd+20mvy<;kGP_A8n@u*EeAO5`ZA{}y+oX+wws(o92x4s% z1w~;&5WMiBaj%XRjX@Mk#n@F*ET;7XOSMJ8KcEx@Z-gQQ@6_i^=R#a~c%ONG=Y98_ z!_MAod_6};7MF$@+iPx6P2#+>zJiH}X6Az5GGmkT>Oz@|L_Uf0n-l zw}YR8n~W{LxPF!~WBbeN{8aU~-vyVOhME&FE&z)O+dd*y0 zeQx!WKXy`k*v$Dgbeor|pBgJYZ>Hy%VY|^Q&%R;Q*&^f@)JiI|#rS5ej)^h8t=3bS zE7d`>P`Mj9M#gjaou_<<-%}S-nLj;Fc5Om57}FxdsiC-QST?83gm9c`k>%tRcOAmJ9rXs7sP}}vk7a2}u8n4+*T{AuL zs9m<-tKKqmqYkFHwTmLBH#^0tN!>|htSr*z+LR$W-A$`ebXYmjZn>h(Y7(thbJa~B ztF&NA7aBd?c!*QCA{(8ph<(J}IzGrLuc!fW8{z`uypCr$^(e|9ZpV3hao!#Sa_T%W z%c)P11JnT&)Jmccs86FgPW_6qK%E#?y_q2K3aUoCX!;z`GcyA${A&Ih7T; zh`JFC*CNX|6g4f_WlkfCngI$J5hkD|2BV5v0ea9emVmYxj4Nsf=*7k+Vo*`k5tB(p zogjS}dmw4?V(@^XE`R`EGL?Yt7(A%R2j~ZwPCz~e4=E}D6afwGLw-07(A?~2r!5Z&n93X21gW?0EPhO5-=EpM-&YKlrc&spd5pFMZ*BY z07nxrvaqP{@tC3zWCYiBJRzfT%YtIaL*$FKC}S+x5vLRPGfX*I)4xc>-U&`i>Kc}g zRj=23{&;v%oOa$8%cq>O>xJQ@SPr+sP|?_1Y2S}r&l<0q6y_!{afQ=qMdR}hr!$Hs z=6$2OK!wUays-k}koK9x>sLGfA3yp(pTe_VGpY007uJ_ie}^0>)ERU#@hEH&>e2?E zA;^QUrou`vo%bJD5w!!-!vm;2@x7>RkRDoqS`+W1wj^E;&nCVZRc}PEccJ}|o~i${ P_9k8*)?&41_Eh-4GGOkp delta 1216 zcmZ9MO>7%g6oudO*vakC5%x@MCywKc<2cF0cI?FYp_GuJC4rl^NgGuH#3mJm1!`%Q zumB4rb|5v(>PbjMf(3|*whRc=@{{r_ssg1*ED>ZwmlY@ytjd|`TOceQ-{bSWd*^zj znOAbRvb40iHYtR8bCbNz3tr&8>AmG$@xJ!1dcSyoc>i#oM|g%8nE7!&#n1EG{0_g% z=lDH7&lmZ9{(wK^kN9K0#FzO~{*1Tz3V+F8@i+V}f5%t(8h_6}@^!w!KYQ1`AG~Wq z9Di=(Ng+fUGN9z$w}lih3xD%Mcj_+$vzwoI)cwSn)2B~7bMoTfpC{N%oxOIP+GIB&W9P?9_K3F^EXSPM2#fN*Yt-;6O3>Jyqxopu2_x<54$D zsw>I@mJm0>hEO{U_O!;0DfE!?gn8cfGvMG54S z$X7$(HdfNUq@#B-3^^A1h7-l^QAulR8%Nv0uidVk4sLgs@m;2Neg<9Zk{(qwyX;7M zOwrtO#Sp>MRPC5}PVRyv6#3|3ihT4y4gJSY{m&=#nb{~`e0JkF>P^Uj@E(X~9Mc{} ztU`m4!KVq8AY7*-8ZZNQeux@s5sHR;P`~!0s0AomtP1sMUqS8FzKm*XAMuR#c~lFE TW=4N*kM?^}NrbQN>BxTpb1>Py diff --git a/erts/preloaded/src/prim_net.erl b/erts/preloaded/src/prim_net.erl index 389e159abaf0..7dc3b0b5f7bf 100644 --- a/erts/preloaded/src/prim_net.erl +++ b/erts/preloaded/src/prim_net.erl @@ -27,7 +27,7 @@ -export([ on_load/0, on_load/1, info/0, - command/1 + debug/1 ]). -export([ @@ -377,10 +377,8 @@ info() -> nif_info(). --spec command(Cmd :: term()) -> term(). - -command(Cmd) -> - nif_command(Cmd). +debug(D) -> + nif_command(#{command => ?FUNCTION_NAME, data => D}). From 64e0a2046e1d5c3272c8bb4e5194777685badd64 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 5 Jun 2024 10:57:45 +0200 Subject: [PATCH 03/37] [enet] Fixed debug Add a proper debug function for net to make it possible to enabling debug for the net nif. Also tweaked the debug for getifaddrs. --- erts/emulator/nifs/common/prim_net_nif.c | 136 +++++++++++--------- erts/emulator/nifs/common/prim_socket_nif.c | 2 +- lib/kernel/src/net.erl | 13 +- 3 files changed, 88 insertions(+), 63 deletions(-) diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c index a4ef12a8d134..f0027580adec 100644 --- a/erts/emulator/nifs/common/prim_net_nif.c +++ b/erts/emulator/nifs/common/prim_net_nif.c @@ -330,7 +330,8 @@ ENET_NIF_FUNCS /* And here comes the functions that does the actual work (for the most part) */ static ERL_NIF_TERM enet_command(ErlNifEnv* env, - ERL_NIF_TERM cmd); + ERL_NIF_TERM cmd, + ERL_NIF_TERM cdata); static ERL_NIF_TERM enet_gethostname(ErlNifEnv* env); @@ -565,13 +566,9 @@ static BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, static BOOLEAN_T decode_nameinfo_flags_list(ErlNifEnv* env, const ERL_NIF_TERM eflags, int* flags); -static -BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, - const ERL_NIF_TERM eString, - char** stringP); -static ERL_NIF_TERM decode_bool(ErlNifEnv* env, - ERL_NIF_TERM ebool, - BOOLEAN_T* ibool); +static BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, + const ERL_NIF_TERM eString, + char** stringP); static ERL_NIF_TERM encode_address_infos(ErlNifEnv* env, struct addrinfo* addrInfo); static ERL_NIF_TERM encode_address_info(ErlNifEnv* env, @@ -868,25 +865,37 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env, * Command - This is a general purpose command, of any type. * Currently, the only supported command is: * - * {debug, boolean()} + * debug: boolean() */ static ERL_NIF_TERM nif_command(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM ecmd, result; + ERL_NIF_TERM command, cdata, result; NDBG( ("NET", "command -> entry (%d)\r\n", argc) ); - if (argc != 1) + ESOCK_ASSERT( argc == 1 ); + + if (! GET_MAP_VAL(env, argv[0], esock_atom_command, &command)) { + NDBG( ("NET", + "nif_command -> field not found: command\r\n") ); return enif_make_badarg(env); + } - ecmd = argv[0]; + if (! GET_MAP_VAL(env, argv[0], esock_atom_data, &cdata)) { + NDBG( ("NET", + "nif_command -> field not found: data\r\n") ); + return enif_make_badarg(env); + } - NDBG( ("NET", "command -> ecmd: %T\r\n", ecmd) ); + NDBG( ("NET", "nif_command -> " + "\r\n command: %T" + "\r\n cdata: %T" + "\r\n", command, cdata) ); - result = enet_command(env, ecmd); + result = enet_command(env, command, cdata); NDBG( ("NET", "command -> result: %T\r\n", result) ); @@ -901,29 +910,33 @@ ERL_NIF_TERM nif_command(ErlNifEnv* env, */ static ERL_NIF_TERM enet_command(ErlNifEnv* env, - ERL_NIF_TERM cmd) + ERL_NIF_TERM cmd, + ERL_NIF_TERM cdata) { - const ERL_NIF_TERM* t; - int tsz; + NDBG( ("NET", "enet_command -> entry with %T\r\n", cmd) ); - if (IS_TUPLE(env, cmd)) { - /* Could be the debug tuple */ - if (!GET_TUPLE(env, cmd, &tsz, &t)) - return esock_make_error(env, esock_atom_einval); + if (COMPARE(cmd, esock_atom_debug) == 0) { + BOOLEAN_T dbg; - if (tsz != 2) - return esock_make_error(env, esock_atom_einval); + NDBG( ("NET", "enet_command -> debug command with" + "\r\n data: %T" + "\r\n", cdata) ); - /* First element should be the atom 'debug' */ - if (COMPARE(t[0], atom_debug) != 0) - return esock_make_error(env, esock_atom_einval); + if (! esock_decode_bool(cdata, &dbg)) + return esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); - return decode_bool(env, t[1], &data.debug); + NDBG( ("NET", "enet_command -> update debug (%T)\r\n", cdata) ); - } else { - return esock_make_error(env, esock_atom_einval); + data.debug = dbg; + + return esock_atom_ok; + } + NDBG( ("NET", "enet_command -> invalid command: %T\r\n", cmd) ); + + return esock_raise_invalid(env, MKT2(env, esock_atom_command, cmd)); + } @@ -1527,16 +1540,23 @@ ERL_NIF_TERM enet_getifaddrs_process(ErlNifEnv* env, struct ifaddrs* ifap) while (i < len) { ERL_NIF_TERM entry; + NDBG( ("NET", + "enet_getifaddrs_process -> encode entry %d\r\n", i) ); + encode_ifaddrs(env, p, &entry); - NDBG( ("NET", "enet_getifaddrs_process -> entry: %T\r\n", entry) ); + NDBG( ("NET", "enet_getifaddrs_process -> new entry (%d):" + "\r\n %T" + "\r\n", i, entry) ); array[i] = entry; p = p->ifa_next; i++; } - NDBG( ("NET", "enet_getifaddrs_process -> all entries processed\r\n") ); + NDBG( ("NET", + "enet_getifaddrs_process -> all (%d) entries processed\r\n", + len) ); result = esock_make_ok2(env, MKLA(env, array, len)); FREE(array); @@ -1587,29 +1607,40 @@ void encode_ifaddrs(ErlNifEnv* env, { ERL_NIF_TERM ename, eflags, eaddr, enetmask, eifu_key, eifu_value, edata; ERL_NIF_TERM eifAddrs; + BOOLEAN_T extraAddr; // This is just for debugging... ename = encode_ifaddrs_name(env, ifap->ifa_name); NDBG( ("NET", "encode_ifaddrs -> name: %T\r\n", ename) ); eflags = encode_ifaddrs_flags(env, ifap->ifa_flags); NDBG( ("NET", "encode_ifaddrs -> flags: %T\r\n", eflags) ); eaddr = encode_ifaddrs_addr(env, ifap->ifa_addr); - NDBG( ("NET", "encode_ifaddrs -> addr: %T\r\n", eaddr) ); + NDBG( ("NET", "encode_ifaddrs -> addr: " + "\r\n %T" + "\r\n", eaddr) ); enetmask = encode_ifaddrs_addr(env, ifap->ifa_netmask); - NDBG( ("NET", "encode_ifaddrs -> netmask: %T\r\n", enetmask) ); + NDBG( ("NET", "encode_ifaddrs -> netmask: " + "\r\n %T" + "\r\n", enetmask) ); if (ifap->ifa_dstaddr && (ifap->ifa_flags & IFF_POINTOPOINT)) { + extraAddr = TRUE; eifu_key = atom_dstaddr; eifu_value = encode_ifaddrs_addr(env, ifap->ifa_dstaddr); } else if (ifap->ifa_broadaddr && (ifap->ifa_flags & IFF_BROADCAST)) { + extraAddr = TRUE; eifu_key = atom_broadaddr; eifu_value = encode_ifaddrs_addr(env, ifap->ifa_broadaddr); } else { + extraAddr = FALSE; eifu_key = esock_atom_undefined; eifu_value = esock_atom_undefined; } - NDBG( ("NET", "encode_ifaddrs -> ifu: " - "\r\n key: %T" - "\r\n val: %T" - "\r\n", eifu_key, eifu_value) ); + if (extraAddr) { + NDBG( ("NET", "encode_ifaddrs -> ifu: " + "\r\n key: %T" + "\r\n val: %T" + "\r\n", eifu_key, eifu_value) ); + } + /* Don't know how to encode this yet... * We don't even know the size... */ @@ -1620,7 +1651,10 @@ void encode_ifaddrs(ErlNifEnv* env, eifu_key, eifu_value, edata, &eifAddrs); - NDBG( ("NET", "encode_ifaddrs -> encoded ifAddrs: %T\r\n", eifAddrs) ); + NDBG( ("NET", "encode_ifaddrs -> encoded ifAddrs: " + "\r\n %T" + "\r\n", eifAddrs) ); + *eifa = eifAddrs; } @@ -1760,7 +1794,9 @@ void make_ifaddrs(ErlNifEnv* env, idx++; /* *** Addr (can be 'undefined' = NULL) *** */ - NDBG( ("NET", "make_ifaddrs -> addr: %T\r\n", eaddr) ); + NDBG( ("NET", "make_ifaddrs -> addr: " + "\r\n %T" + "\r\n", eaddr) ); if (COMPARE(eaddr, esock_atom_undefined) != 0) { keys[idx] = esock_atom_addr; vals[idx] = eaddr; @@ -1770,7 +1806,9 @@ void make_ifaddrs(ErlNifEnv* env, } /* *** Netmask (can be 'undefined' = NULL) *** */ - NDBG( ("NET", "make_ifaddrs -> netmask: %T\r\n", enetmask) ); + NDBG( ("NET", "make_ifaddrs -> netmask: " + "\r\n %T" + "\r\n", enetmask) ); if (COMPARE(enetmask, esock_atom_undefined) != 0) { keys[idx] = atom_netmask; vals[idx] = enetmask; @@ -4830,24 +4868,6 @@ BOOLEAN_T restore_network_namespace(int ns, int* err) #endif // ifdef HAVE_SETNS -static -ERL_NIF_TERM decode_bool(ErlNifEnv* env, - ERL_NIF_TERM ebool, - BOOLEAN_T* ibool) -{ - if (COMPARE(ebool, esock_atom_true) == 0) { - *ibool = TRUE; - return esock_atom_ok; - } else if (COMPARE(ebool, esock_atom_false) == 0) { - *ibool = FALSE; - return esock_atom_ok; - } else { - return esock_make_error(env, esock_atom_einval); - } -} - - - /* ---------------------------------------------------------------------- * C a l l b a c k F u n c t i o n s * ---------------------------------------------------------------------- diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index a41e3b0cd216..f4c4e98563ea 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -4519,7 +4519,7 @@ ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) data.sockDbg = dbg; MUNLOCK(data.cntMtx); - return esock_atom_ok;; + return esock_atom_ok; } diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl index 9f6735f191fb..1cdc4ae3f160 100644 --- a/lib/kernel/src/net.erl +++ b/lib/kernel/src/net.erl @@ -29,7 +29,7 @@ This module provides an API for the network interface. %% Administrative and utility functions -export([ info/0, - command/1 + debug/1 ]). -export([ @@ -222,10 +222,15 @@ sleep(T) -> receive after T -> ok end. info() -> prim_net:info(). + -doc false. --spec command(Cmd :: term()) -> term(). -command(Cmd) -> - prim_net:command(Cmd). +-spec debug(D :: boolean()) -> 'ok'. +%% +debug(D) when is_boolean(D) -> + prim_net:debug(D); +debug(D) -> + erlang:error(badarg, [D]). + %% =========================================================================== %% From 857f003f635dec219a11b602a065d0b592e088f4 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 5 Jun 2024 15:38:46 +0200 Subject: [PATCH 04/37] [kernel|net] Update inet:getifaddrs/0,1 to work with 'net' Make it possible to "force" the inet:getifaddrs/0,1 functions to use the net:getifaddrs instead of the inet driver (prim_inet:getifaddrs). This is done either by providing the '{inet_backend, Backend}' option of by using the (kernel) application option 'inet_backend' (which is stored in a persistent term). --- lib/kernel/src/inet.erl | 269 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 249 insertions(+), 20 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 08a06186b180..1ffd6d001e7e 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1626,22 +1626,247 @@ Get interface names and addresses, in a specific namespace. Equivalent to `getifaddrs/0`, but accepts an `Option` `{netns, Namespace}` that, on platforms that support the feature (Linux), sets a network namespace for the OS call. +Also, +If the option 'inet_backend' is *first* in the options list, +the specified backend will be used (for 'inet', inet and +for 'socket' the equivalent net functions will be used). + See the socket option [`{netns, Namespace}`](#option-netns) under`setopts/2`. """. -doc(#{since => <<"OTP 21.2">>}). -spec getifaddrs( - [Option :: {netns, Namespace :: file:filename_all()}] + [Option :: inet_backend() | {netns, Namespace :: file:filename_all()}] | socket()) -> {'ok', [{Ifname :: string(), Ifopts :: getifaddrs_ifopts()}]} | {'error', posix()}. + +getifaddrs([{inet_backend, Backend}|Opts]) -> + do_getifaddrs(Backend, Opts); getifaddrs(Opts) when is_list(Opts) -> + do_getifaddrs(inet_backend(), Opts); +getifaddrs(?module_socket(GenSocketMod, _) = _Socket) + when is_atom(GenSocketMod) -> + do_getifaddrs('socket', []); +getifaddrs(Socket) when is_port(Socket) -> + do_getifaddrs('inet', Socket). + +do_getifaddrs('socket', []) -> + net_getifaddrs(net:getifaddrs(all)); +do_getifaddrs('socket', [{netns, Namespace}]) -> + net_getifaddrs(net:getifaddrs(all, Namespace)); +do_getifaddrs('inet', Opts) when is_list(Opts) -> withsocket(fun(S) -> prim_inet:getifaddrs(S) end, Opts); -getifaddrs(Socket) -> +do_getifaddrs('inet', Socket) when is_port(Socket) -> prim_inet:getifaddrs(Socket). + +net_unique_if_names(Ifs) -> + net_unique_if_names(Ifs, []). + +net_unique_if_names([], IfNames) -> + lists:reverse(IfNames); +net_unique_if_names([#{name := IfName}|Ifs], IfNames) -> + case lists:member(IfName, IfNames) of + true -> + net_unique_if_names(Ifs, IfNames); + false -> + net_unique_if_names(Ifs, [IfName|IfNames]) + end. + + +net_getifaddrs({ok, AllIfs}) -> + IfNames = net_unique_if_names(AllIfs), + {ok, net_collect_ifopts(IfNames, AllIfs)}; +net_getifaddrs({error, _} = ERROR) -> + ERROR. + + +net_collect_ifopts(IfNames, AllIfs) -> + net_collect_ifopts(IfNames, AllIfs, []). + +net_collect_ifopts([], _AllIfs, AllNameAndOpts) -> + lists:reverse(AllNameAndOpts); +net_collect_ifopts([IfName|IfNames], AllIfs, NameAndOpts) -> + %% Get the Ifs with the name IfName + io:format("~w -> entry with" + "~n IfName: ~p" + "~n", [?FUNCTION_NAME, IfName]), + Ifs = [If || #{name := N} = If <- AllIfs, (N =:= IfName)], + IfOpts = net_ifs2ifopts(Ifs), + net_collect_ifopts(IfNames, AllIfs, [{IfName, IfOpts}|NameAndOpts]). + +net_ifs2ifopts(Ifs) -> + net_ifs2ifopts(Ifs, #{flags => [], + addrs => [], + hwaddr => []}). + + +net_ifs2ifopts([], #{flags := Flags, + addrs := Addrs, + hwaddr := HwAddr}) -> + %% io:format("~w -> entry when done with" + %% "~n Flags: ~p" + %% "~n Addrs: ~p" + %% "~n HwAddr: ~p" + %% "~n", [?FUNCTION_NAME, Flags, Addrs, HwAddr]), + [{flags, net_flags_to_inet_flags(Flags)}] ++ + lists:reverse(Addrs) ++ + case HwAddr of + [] -> + []; + _ -> + [{hwaddr, HwAddr}] + end; +net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> + %% io:format("~w -> entry initial with" + %% "~n If: ~p" + %% "~n", [?FUNCTION_NAME, If]), + IfOpts = + case If of + #{flags := Flags, + addr := #{family := packet, + addr := HwAddrBin}} -> + %% io:format("~w(~w) -> packet entry" + %% "~n", [?FUNCTION_NAME, ?LINE]), + IfOpts0#{flags => Flags, + hwaddr => binary_to_list(HwAddrBin)}; + #{flags := Flags, + addr := #{family := Fam, + addr := Addr}, + netmask := #{family := Fam, + addr := Mask}} when (Fam =:= inet) orelse + (Fam =:= inet6) -> + %% io:format("~w(~w) -> ~w entry" + %% "~n", [?FUNCTION_NAME, ?LINE, Fam]), + %% We may also have broadcast or dest addr + BroadAddr = case maps:get(broadaddr, If, undefined) of + undefined -> + []; + #{addr := BA} -> + [{broadaddr, BA}] + end, + DstAddr = case maps:get(dstaddr, If, undefined) of + undefined -> + []; + #{addr := DA} -> + [{dstaddr, DA}] + end, + IfOpts0#{flags => Flags, + addrs => DstAddr ++ BroadAddr ++ [{netmask, Mask}, + {addr, Addr}]}; + #{flags := Flags} -> + %% io:format("~w(~w) -> only flags entry" + %% "~n", [?FUNCTION_NAME, ?LINE]), + IfOpts0#{flags => Flags} + end, + net_ifs2ifopts(Ifs, IfOpts); +net_ifs2ifopts([If|Ifs], IfOpts0) -> + %% We can only have one 'flags' entry + %% (they are supposed to be the same for all if:s of the same name). + %% For each 'addr' entry we can have one 'netmask' and 'broadcast' + %% or 'dstaddr' + %% io:format("~w -> entry with" + %% "~n If: ~p" + %% "~nwhen" + %% "~n IfOpts0: ~p" + %% "~n", [?FUNCTION_NAME, If, IfOpts0]), + IfOpts = + case If of + #{flags := Flags, + addr := #{family := packet, + addr := HwAddrBin}} -> + Flags0 = maps:get(flags, IfOpts0, []), + %% io:format("~w(~w) -> packet entry" + %% "~n", [?FUNCTION_NAME, ?LINE]), + IfOpts0#{flags => Flags0 ++ (Flags -- Flags0), + hwaddr => binary_to_list(HwAddrBin)}; + #{flags := Flags, + addr := #{family := Fam, + addr := Addr}, + netmask := #{family := Fam, + addr := Mask}} when (Fam =:= inet) orelse + (Fam =:= inet6) -> + %% io:format("~w(~w) -> ~w entry" + %% "~n", [?FUNCTION_NAME, ?LINE, Fam]), + Addrs0 = maps:get(addrs, IfOpts0, []), + Flags0 = maps:get(flags, IfOpts0, []), + %% We may also have broadcast or dest addr + BroadAddr = case maps:get(broadaddr, If, undefined) of + undefined -> + []; + #{addr := BA} -> + [{broadaddr, BA}] + end, + DstAddr = case maps:get(dstaddr, If, undefined) of + undefined -> + []; + #{addr := DA} -> + [{dstaddr, DA}] + end, + IfOpts0#{flags => Flags0 ++ (Flags -- Flags0), + addrs => + DstAddr ++ + BroadAddr ++ + [{netmask, Mask}, + {addr, Addr}] ++ + Addrs0}; + _ -> + %% io:format("~w(~w) -> nothing updated" + %% "~n", [?FUNCTION_NAME, ?LINE]), + IfOpts0 + end, + net_ifs2ifopts(Ifs, IfOpts). + +net_flags_to_inet_flags(Flags) -> + net_flags_to_inet_flags(Flags, []). + +net_flags_to_inet_flags([], OutFlags) -> + %% io:format("~w(~w) -> done when" + %% "~n OutFlags: ~p" + %% "~n", [?FUNCTION_NAME, ?LINE, OutFlags]), + lists:reverse(OutFlags); +net_flags_to_inet_flags([InFlag|InFlags], OutFlags) -> + %% io:format("~w(~w) -> entry with" + %% "~n InFlag: ~p" + %% "~n", [?FUNCTION_NAME, ?LINE, InFlag]), + case net_flag_to_inet_flag(InFlag) of + {value, OutFlag} -> + %% io:format("~w(~w) -> known flag => ~w" + %% "~n", [?FUNCTION_NAME, ?LINE, OutFlag]), + net_flags_to_inet_flags(InFlags, [OutFlag | OutFlags]); + false -> + %% io:format("~w(~w) -> unknown flag => skip" + %% "~n", [?FUNCTION_NAME, ?LINE]), + net_flags_to_inet_flags(InFlags, OutFlags) + end. + +%% Should we do this as map instead? +%% #{up => up, +%% broadcast => broadcast, +%% loopback => loopback, +%% pointopoint => pointtopoint, +%% running => running, +%% multicast => multicast}, +net_flag_to_inet_flag(InFlag) -> + InetFlags = [up, broadcast, loopback, + {pointopoint, pointtopoint}, + running, multicast], + net_flag_to_inet_flag(InFlag, InetFlags). + +net_flag_to_inet_flag(_InFlag, []) -> + false; +net_flag_to_inet_flag(InFlag, [InFlag|_]) -> + {value, InFlag}; +net_flag_to_inet_flag(InFlag, [{InFlag, OutFlag}|_]) -> + {value, OutFlag}; +net_flag_to_inet_flag(InFlag, [_|InetFlags]) -> + net_flag_to_inet_flag(InFlag, InetFlags). + + + -doc """ Get interface names and addresses. @@ -1654,11 +1879,13 @@ the type of the [`Ifopts`](`t:getifaddrs_ifopts/0`) value. """. -doc(#{since => <<"OTP R14B01">>}). -spec getifaddrs() -> - {'ok', [{Ifname :: string(), - Ifopts :: getifaddrs_ifopts()}]} - | {'error', posix()}. + {'ok', [{Ifname :: string(), + Ifopts :: getifaddrs_ifopts()}]} + | {'error', posix()}. + getifaddrs() -> - withsocket(fun(S) -> prim_inet:getifaddrs(S) end). + do_getifaddrs(inet_backend(), []). + -doc false. @@ -2218,13 +2445,14 @@ getservbyport(Port, Protocol) -> end. inet_getservbyport(Port, Protocol) -> - case inet_udp:open(0, []) of - {ok,U} -> - Res = prim_inet:getservbyport(U, Port, Protocol), - inet_udp:close(U), - Res; - Error -> Error - end. + %% case inet_udp:open(0, []) of + %% {ok,U} -> + %% Res = prim_inet:getservbyport(U, Port, Protocol), + %% inet_udp:close(U), + %% Res; + %% Error -> Error + %% end. + withsocket(fun(S) -> prim_inet:getservbyport(S, Port, Protocol) end). net_getservbyport(Port, Protocol) when is_list(Protocol) -> net_getservbyport(Port, list_to_atom(Protocol)); @@ -2247,13 +2475,14 @@ getservbyname(Name, Protocol) when is_list(Name) -> end. inet_getservbyname(Name, Protocol) -> - case inet_udp:open(0, []) of - {ok, U} -> - Res = prim_inet:getservbyname(U, Name, Protocol), - inet_udp:close(U), - Res; - Error -> Error - end. + %% case inet_udp:open(0, []) of + %% {ok, U} -> + %% Res = prim_inet:getservbyname(U, Name, Protocol), + %% inet_udp:close(U), + %% Res; + %% Error -> Error + %% end. + withsocket(fun(S) -> prim_inet:getservbyname(S, Name, Protocol) end). net_getservbyname(Name, Protocol) when is_list(Protocol) -> net_getservbyname(Name, list_to_atom(Protocol)); From 47638f95dc6d9665c12e532ee844637e2f974d13 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 18 Jun 2024 17:13:58 +0200 Subject: [PATCH 05/37] [kernel|test] Tweaked the gegifaddrs test case --- lib/kernel/test/inet_SUITE.erl | 88 ++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index fedcd3d50fa6..29115aa99a54 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1587,10 +1587,48 @@ getservbyname_overflow(Config) when is_list(Config) -> {error,einval} = inet:getservbyname(list_to_atom(lists:flatten(lists:duplicate(128, "x"))), tcp), ok. + %% Test inet:gifaddrs/0. getifaddrs(Config) when is_list (Config) -> - {ok,IfAddrs} = inet:getifaddrs(), - io:format("IfAddrs = ~p.~n", [IfAddrs]), + do_getifaddrs(default), + do_getifaddrs(inet), + do_getifaddrs(socket), + getifaddrs_verify_backends(). + +do_getifaddrs(default) -> + io:format("try 'default' getifaddrs~n", []), + do_getifaddrs2(inet:getifaddrs()); +do_getifaddrs(Backend) -> + case is_supported_backend(Backend) of + true -> + io:format("try '~w' getifaddrs~n", [Backend]), + do_getifaddrs2(inet:getifaddrs([{inet_backend, Backend}])); + false -> + io:format("skip '~w' getifaddrs: not supported~n", [Backend]), + ok + end. + +is_supported_backend(inet = _Backend) -> + true; +is_supported_backend(socket = _Backend) -> + is_socket_supported(). + +is_socket_supported() -> + try socket:info() of + #{} -> + true + catch + error : notsup -> + false; + error : undef -> + false + end. + + +do_getifaddrs2({ok, IfAddrs}) -> + io:format("IfAddrs: " + "~n ~p" + "~n", [IfAddrs]), case [If || {If,Opts} <- IfAddrs, lists:keymember(hwaddr, 1, Opts)] of [] -> case os:type() of @@ -1601,7 +1639,9 @@ getifaddrs(Config) when is_list (Config) -> [_|_] -> ok end, Addrs = ifaddrs(IfAddrs), - io:format("Addrs = ~p.~n", [Addrs]), + io:format("Addrs: " + "~n ~p" + "~n", [Addrs]), [check_addr(Addr) || Addr <- Addrs], ok. @@ -1707,6 +1747,48 @@ fold_ifopts(Fun, Acc, IfMap, Keys) -> Acc end. + +getifaddrs_verify_backends() -> + io:format("maybe attempt verify backends~n", []), + case is_supported_backend(inet) of + true -> + case is_supported_backend(socket) of + true -> + getifaddrs_verify_backends( + inet:getifaddrs([{inet_backend, inet}]), + inet:getifaddrs([{inet_backend, socket}])); + false -> + io:format("'socket' backend not supported: skip~n", []) + end; + false -> + io:format("'inet' backend not supported: skip~n", []) + end. + +getifaddrs_verify_backends({ok, IfAddrs}, + {ok, IfAddrs}) -> + io:format("IfAddrs are equal: " + "~n ~p" + "~n", [IfAddrs]), + ok; +getifaddrs_verify_backends({ok, IfAddrs_INET}, + {ok, IfAddrs_SOCKET}) -> + io:format("IfAddrs are *NOT* equal: " + "~n INET:" + "~n ~p" + "~n SOCKET:" + "~n ~p" + "~n INET -- SOCKET: " + "~n ~p" + "~n SOCKET -- INET: " + "~n ~p" + "~n", [IfAddrs_INET, IfAddrs_SOCKET, + IfAddrs_INET -- IfAddrs_SOCKET, + IfAddrs_SOCKET -- IfAddrs_INET]), + ct:fail(ifaddrs_not_equal). + + + + %% Works just like lists:member/2, except that any {127,_,_,_} tuple %% matches any other {127,_,_,_}. We do this to handle Linux systems %% that use (for instance) 127.0.1.1 as the IP address for the hostname. From e108dea8b4dce8843e7197462a72298628ea4a21 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 19 Jun 2024 12:50:49 +0200 Subject: [PATCH 06/37] [esock] Fixed encoding link layer socket address --- erts/emulator/nifs/common/socket_util.c | 63 +++++++++++++++++++++---- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index 6179f7453826..613288cf18ae 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -464,12 +464,18 @@ void esock_encode_sockaddr(ErlNifEnv* env, switch (family) { case AF_INET: len = SALEN(addrLen, sizeof(struct sockaddr_in)); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'inet' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_in(env, &sockAddrP->in4, len, eSockAddr); break; #if defined(HAVE_IN6) && defined(AF_INET6) case AF_INET6: len = SALEN(addrLen, sizeof(struct sockaddr_in6)); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'inet6' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_in6(env, &sockAddrP->in6, len, eSockAddr); break; #endif @@ -477,6 +483,9 @@ void esock_encode_sockaddr(ErlNifEnv* env, #ifdef HAS_AF_LOCAL case AF_LOCAL: len = sa_local_length(addrLen, &sockAddrP->un); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'local' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_un(env, &sockAddrP->un, len, eSockAddr); break; #endif @@ -484,6 +493,9 @@ void esock_encode_sockaddr(ErlNifEnv* env, #ifdef AF_UNSPEC case AF_UNSPEC: len = SALEN(addrLen, 0); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'unspec' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_native(env, &sockAddrP->sa, len, esock_atom_unspec, @@ -494,6 +506,9 @@ void esock_encode_sockaddr(ErlNifEnv* env, #if defined(HAVE_NETPACKET_PACKET_H) case AF_PACKET: len = SALEN(addrLen, sizeof(struct sockaddr_ll)); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'packet' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_ll(env, &sockAddrP->ll, len, eSockAddr); break; #endif @@ -501,6 +516,9 @@ void esock_encode_sockaddr(ErlNifEnv* env, #if defined(AF_IMPLINK) case AF_IMPLINK: len = SALEN(addrLen, 0); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'implink' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_native(env, &sockAddrP->sa, len, esock_atom_implink, @@ -511,6 +529,9 @@ void esock_encode_sockaddr(ErlNifEnv* env, #if defined(AF_PUP) case AF_PUP: len = SALEN(addrLen, 0); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'pup' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_native(env, &sockAddrP->sa, len, esock_atom_pup, @@ -521,6 +542,9 @@ void esock_encode_sockaddr(ErlNifEnv* env, #if defined(AF_CHAOS) case AF_CHAOS: len = SALEN(addrLen, 0); + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'chaos' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_native(env, &sockAddrP->sa, len, esock_atom_chaos, @@ -586,12 +610,18 @@ void esock_encode_sockaddr(ErlNifEnv* env, (CHARP(sockAddrP->dl.sdl_data) - CHARP(sockAddrP)) + sockAddrP->dl.sdl_nlen + sockAddrP->dl.sdl_alen); #endif + UDBG( ("SUTIL", "esock_encode_sockaddr -> 'link' family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_dl(env, &sockAddrP->dl, len, eSockAddr); break; #endif default: len = SALEN(addrLen, 0); + UDBG( ("SUTIL", "esock_encode_sockaddr -> default (native) family addr: " + "\r\n len: %d" + "\r\n", len) ); esock_encode_sockaddr_native(env, &sockAddrP->sa, len, MKI(env, family), @@ -1095,11 +1125,14 @@ void esock_encode_sockaddr_un(ErlNifEnv* env, * (beside the mandatory family attribute, which is "inherited" from * the "sockaddr" type): * - * protocol: integer() (should be an atom really) + * protocol: protocol() * ifindex: integer() - * hatype: integer() (should be an atom really) - * pkttype: integer() (should be an atom really) - * addr: list() (should be something useful...) + * hatype: hatype() + * pkttype: pkttype() + * addr: binary() + * + * Or if the address length is not enough, its encoded as a "native" + * packet (with type 'packet'). * */ @@ -1176,32 +1209,46 @@ void esock_encode_sockaddr_dl(ErlNifEnv* env, { ERL_NIF_TERM eindex, etype, enlen, ealen, eslen, edata; SOCKLEN_T dlen; + SOCKLEN_T ndsz = sizeof(struct sockaddr_dl)-sizeof(sockAddrP->sdl_data); UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> entry with" - "\r\n. addrLen: %d" - "\r\n", addrLen) ); + "\r\n. addrLen: %d" + "\r\n. non-data fields size: %d" + "\r\n", addrLen, ndsz) ); - /* There is a minumum length (defined by the size of the data field) */ - if (addrLen >= sizeof(struct sockaddr_dl)) { + /* Make sure the data field actually contains something */ + if (addrLen >= ndsz) { /* index - if != 0, system given index for interface */ + UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> index: %d" + "\r\n", sockAddrP->sdl_index) ); eindex = MKUI(env, sockAddrP->sdl_index); /* type - interface type */ + UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> type: %d" + "\r\n", sockAddrP->sdl_type) ); etype = MKUI(env, sockAddrP->sdl_type); /* nlen - interface name length, no trailing 0 reqd. */ + UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> nlen: %d" + "\r\n", sockAddrP->sdl_nlen) ); enlen = MKUI(env, sockAddrP->sdl_nlen); /* alen - link level address length */ + UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> alen: %d" + "\r\n", sockAddrP->sdl_alen) ); ealen = MKUI(env, sockAddrP->sdl_alen); /* slen - ink layer selector length */ + UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> slen: %d" + "\r\n", sockAddrP->sdl_slen) ); eslen = MKUI(env, sockAddrP->sdl_slen); /* data - minimum work area, can be larger; * * contains both if name and ll address */ dlen = addrLen - (CHARP(sockAddrP->sdl_data) - CHARP(sockAddrP)); + UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> data len: %d" + "\r\n", dlen) ); edata = esock_make_new_binary(env, &sockAddrP->sdl_data, dlen); make_sockaddr_dl(env, From d751af892b3fb2e0342a909d020980219b88dd9b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 19 Jun 2024 12:52:11 +0200 Subject: [PATCH 07/37] [kernel] Handling packet type 'link' as source for "hwaddr" --- lib/kernel/src/inet.erl | 46 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 1ffd6d001e7e..ba90386b774f 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1691,9 +1691,9 @@ net_collect_ifopts([], _AllIfs, AllNameAndOpts) -> lists:reverse(AllNameAndOpts); net_collect_ifopts([IfName|IfNames], AllIfs, NameAndOpts) -> %% Get the Ifs with the name IfName - io:format("~w -> entry with" - "~n IfName: ~p" - "~n", [?FUNCTION_NAME, IfName]), + %% io:format("~w -> entry with" + %% "~n IfName: ~p" + %% "~n", [?FUNCTION_NAME, IfName]), Ifs = [If || #{name := N} = If <- AllIfs, (N =:= IfName)], IfOpts = net_ifs2ifopts(Ifs), net_collect_ifopts(IfNames, AllIfs, [{IfName, IfOpts}|NameAndOpts]). @@ -1726,6 +1726,13 @@ net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> %% "~n", [?FUNCTION_NAME, If]), IfOpts = case If of + %% LINK or PACKET + %% - On some platforms LINK is used (FreeBSD for instance) + %% LINK does not include an explicit HW address. Instead + %% its part of the 'data', together with name and possibly + %% link layer selector (the lengths can be used to decode + %% the data).. + %% - On others PACKET is used. #{flags := Flags, addr := #{family := packet, addr := HwAddrBin}} -> @@ -1733,6 +1740,23 @@ net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> %% "~n", [?FUNCTION_NAME, ?LINE]), IfOpts0#{flags => Flags, hwaddr => binary_to_list(HwAddrBin)}; + #{flags := Flags, + addr := #{family := link, + nlen := NLen, + alen := ALen, + data := Data}} when (ALen > 0) -> + %% io:format("~w(~w) -> link entry with" + %% "~n NLen: ~w" + %% "~n ALen: ~w" + %% "~n Data: ~p" + %% "~n", [?FUNCTION_NAME, ?LINE, NLen, ALen, Data]), + case Data of + <<_:NLen/binary, ABin:ALen/binary, _/binary>> -> + IfOpts0#{flags => Flags, + hwaddr => binary_to_list(ABin)}; + _ -> + IfOpts0#{flags => Flags} + end; #{flags := Flags, addr := #{family := Fam, addr := Addr}, @@ -1827,7 +1851,7 @@ net_flags_to_inet_flags([], OutFlags) -> %% io:format("~w(~w) -> done when" %% "~n OutFlags: ~p" %% "~n", [?FUNCTION_NAME, ?LINE, OutFlags]), - lists:reverse(OutFlags); + lists:reverse(net_flags_maybe_add_running(OutFlags)); net_flags_to_inet_flags([InFlag|InFlags], OutFlags) -> %% io:format("~w(~w) -> entry with" %% "~n InFlag: ~p" @@ -1843,6 +1867,20 @@ net_flags_to_inet_flags([InFlag|InFlags], OutFlags) -> net_flags_to_inet_flags(InFlags, OutFlags) end. +net_flags_maybe_add_running(Flags) -> + case lists:member(running, Flags) of + true -> + Flags; + false -> + case lists:member(up, Flags) of + true -> + [running | Flags]; + false -> + Flags + end + end. + + %% Should we do this as map instead? %% #{up => up, %% broadcast => broadcast, From fdf7cc23311cea55f4d55d4520fef32c8b6c3fd0 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 19 Jun 2024 15:06:17 +0200 Subject: [PATCH 08/37] [kernel|test] Tweaked the getifaddrs test case Attempt to verify each interface to see if they are 'equal' even though they are not identical. --- lib/kernel/test/inet_SUITE.erl | 137 ++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 29115aa99a54..ff9b8ceed667 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1772,7 +1772,7 @@ getifaddrs_verify_backends({ok, IfAddrs}, ok; getifaddrs_verify_backends({ok, IfAddrs_INET}, {ok, IfAddrs_SOCKET}) -> - io:format("IfAddrs are *NOT* equal: " + io:format("IfAddrs are not *identical* - check what differs: " "~n INET:" "~n ~p" "~n SOCKET:" @@ -1784,9 +1784,144 @@ getifaddrs_verify_backends({ok, IfAddrs_INET}, "~n", [IfAddrs_INET, IfAddrs_SOCKET, IfAddrs_INET -- IfAddrs_SOCKET, IfAddrs_SOCKET -- IfAddrs_INET]), + getifaddrs_verify_backends2(IfAddrs_INET, IfAddrs_SOCKET). + +getifaddrs_verify_backends2(INET, SOCKET) -> + getifaddrs_verify_backends3(lists:keysort(1, INET), + lists:keysort(1, SOCKET)). + +getifaddrs_verify_backends3([] = _INET, [] = _SOCKET) -> + ok; +getifaddrs_verify_backends3([] = _INET, SOCKET) -> + io:format("'socket' backend contains extra interfaces: " + "~n ~p" + "~n", [SOCKET]), + ct:fail(ifaddrs_not_equal); +getifaddrs_verify_backends3(INET, [] = _SOCKET) -> + io:format("'inet' backend contains extra interfaces: " + "~n ~p" + "~n", [INET]), + ct:fail(ifaddrs_not_equal); +getifaddrs_verify_backends3([{IF, INFO}|INET], + [{IF, INFO}|SOCKET]) -> + io:format("backend(s) identical for ~p~n", [IF]), + getifaddrs_verify_backends3(INET, SOCKET); +getifaddrs_verify_backends3([{IF, I_INFO}|INET], + [{IF, S_INFO}|SOCKET]) -> + io:format("backend(s) not *identical* for ~p~n", [IF]), + getifaddrs_verify_backend(IF, I_INFO, S_INFO), + getifaddrs_verify_backends3(INET, SOCKET); +getifaddrs_verify_backends3([{I_IF, _}|_], [{S_IF, _}|_]) -> + io:format("not equal interfaces" + "~n ~p" + "~n ~p" + "~n", [I_IF, S_IF]), ct:fail(ifaddrs_not_equal). +getifaddrs_verify_backend(IF, [] = _I_INFO, [] = _S_INFO) -> + io:format("backend(s) *are* equal for ~p~n", [IF]), + ok; +getifaddrs_verify_backend(IF, + [{flags, I_Flags}|I_INFO], + [{flags, S_Flags}|S_INFO]) -> + case {I_Flags -- S_Flags, S_Flags -- I_Flags} of + {[], []} -> + io:format("flags for ~p *are* equal~n", [IF]), + getifaddrs_verify_backend(IF, I_INFO, S_INFO); + {IFD, SFD} -> + io:format("flags for ~p are *not* equal: " + "~n INET -- SOCKET: ~p" + "~n SOCKET -- INET: ~p" + "~n", [IF, IFD, SFD]), + ct:fail(ifaddrs_not_equal) + end; +getifaddrs_verify_backend(IF, + [{addr, I_A}|I_INFO], + [{addr, S_A}|S_INFO]) -> + if + (I_A =:= S_A) -> + io:format("addr for ~p equal~n", [IF]), + getifaddrs_verify_backend(IF, I_INFO, S_INFO); + true -> + io:format("addr for ~p *not* equal: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_A, S_A]), + ct:fail(ifaddrs_not_equal) + end; +getifaddrs_verify_backend(IF, + [{netmask, I_A}|I_INFO], + [{netmask, S_A}|S_INFO]) -> + if + (I_A =:= S_A) -> + io:format("netmask for ~p equal~n", [IF]), + getifaddrs_verify_backend(IF, I_INFO, S_INFO); + true -> + io:format("netmask for ~p *not* equal: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_A, S_A]), + ct:fail(ifaddrs_not_equal) + end; +getifaddrs_verify_backend(IF, + [{broadaddr, I_A}|I_INFO], + [{broadaddr, S_A}|S_INFO]) -> + if + (I_A =:= S_A) -> + io:format("broadaddr for ~p equal~n", [IF]), + getifaddrs_verify_backend(IF, I_INFO, S_INFO); + true -> + io:format("broadaddr for ~p *not* equal: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_A, S_A]), + ct:fail(ifaddrs_not_equal) + end; +getifaddrs_verify_backend(IF, + [{dstaddr, I_A}|I_INFO], + [{dstaddr, S_A}|S_INFO]) -> + if + (I_A =:= S_A) -> + io:format("dstaddr for ~p equal~n", [IF]), + getifaddrs_verify_backend(IF, I_INFO, S_INFO); + true -> + io:format("dstaddr for ~p *not* equal: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_A, S_A]), + ct:fail(ifaddrs_not_equal) + end; +getifaddrs_verify_backend(IF, + [{hwaddr, I_A}|I_INFO], + [{hwaddr, S_A}|S_INFO]) -> + if + (I_A =:= S_A) -> + io:format("hwaddr for ~p equal~n", [IF]), + getifaddrs_verify_backend(IF, I_INFO, S_INFO); + true -> + io:format("hwaddr for ~p *not* equal: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_A, S_A]), + ct:fail(ifaddrs_not_equal) + end; +getifaddrs_verify_backend(IF, + [], + [{hwaddr, _}]) -> + %% We accepts that net can get some more info. + %% That is, that we can get hwaddr for some + %% interfaces that the inet driver cannot... + io:format("hwaddr accepted for ~p~n", [IF]), + ok; +getifaddrs_verify_backend(IF, + I_INFO, S_INFO) -> + io:format("unexpected info for ~p: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_INFO, S_INFO]), + ct:fail(ifaddrs_not_equal). + %% Works just like lists:member/2, except that any {127,_,_,_} tuple From 550f3b39b17677e61b4ef98e1ca01aef10f1ab6d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 20 Jun 2024 13:43:20 +0200 Subject: [PATCH 09/37] [kernel|test] Skip test case if no valid hosts found --- lib/kernel/test/inet_SUITE.erl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index ff9b8ceed667..701228d10827 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -549,8 +549,14 @@ host_and_addr() -> [{timetrap,{minutes,5}}|required(hosts)]. host_and_addr(Config) when is_list(Config) -> - lists:foreach(fun try_host/1, get_hosts(Config)), - ok. + do_host_and_addr(get_hosts(Config)). + +do_host_and_addr(Hosts) when is_list(Hosts) andalso (Hosts =/= []) -> + lists:foreach(fun try_host/1, Hosts), + ok; +do_host_and_addr(Hosts) -> + exit({skip, {no_valid_hosts, Hosts}}). + try_host({Ip0, Host}) -> {ok, Ip} = inet:getaddr(Ip0, inet), @@ -1650,6 +1656,9 @@ check_addr(Addr) element(1, Addr) band 16#FFC0 =:= 16#FE80 -> io:format("Addr: ~p link local; SKIPPED!~n", [Addr]), ok; +check_addr({169, 254, 118, _} = Addr) -> + io:format("Addr: ~p reserved (not usable); SKIPPED!~n", [Addr]), + ok; check_addr(Addr) -> io:format("Addr: ~p.~n", [Addr]), Ping = "ping", @@ -1803,7 +1812,7 @@ getifaddrs_verify_backends3(INET, [] = _SOCKET) -> "~n", [INET]), ct:fail(ifaddrs_not_equal); getifaddrs_verify_backends3([{IF, INFO}|INET], - [{IF, INFO}|SOCKET]) -> + [{IF, INFO}|SOCKET]) -> io:format("backend(s) identical for ~p~n", [IF]), getifaddrs_verify_backends3(INET, SOCKET); getifaddrs_verify_backends3([{IF, I_INFO}|INET], From 060a1169e3d3093a6609df522cd1493a376d984e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 20 Jun 2024 15:02:07 +0200 Subject: [PATCH 10/37] [kernel|test] Reworked the ifaddrs info compare --- lib/kernel/test/inet_SUITE.erl | 269 +++++++++++++++++++++------------ 1 file changed, 171 insertions(+), 98 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 701228d10827..61aacb9f7f55 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1828,108 +1828,181 @@ getifaddrs_verify_backends3([{I_IF, _}|_], [{S_IF, _}|_]) -> ct:fail(ifaddrs_not_equal). -getifaddrs_verify_backend(IF, [] = _I_INFO, [] = _S_INFO) -> - io:format("backend(s) *are* equal for ~p~n", [IF]), - ok; -getifaddrs_verify_backend(IF, - [{flags, I_Flags}|I_INFO], - [{flags, S_Flags}|S_INFO]) -> - case {I_Flags -- S_Flags, S_Flags -- I_Flags} of +%% On windows the info may be in different order +%% (inet and net versions) because the information +%% comes from several sources. And the processing +%% is different on inet and net. +%% The info always starts with 'flags' and ends with +%% 'hwaddr'. So deal with those two first and the rest +%% can compared after. + +getifaddrs_verify_backend(IF, I_INFO, S_INFO) -> + {I_Rest1, S_Rest1} = + case {I_INFO, S_INFO} of + {[{flags, I_FLAGS}|IR1], [{flags, S_FLAGS}|SR1]} -> + case {I_FLAGS -- S_FLAGS, S_FLAGS -- I_FLAGS} of + {[], []} -> + io:format("flags for ~p *are* equal~n", [IF]), + {IR1, SR1}; + {IRem, SRem} -> + io:format("flags for ~p are *not* equal: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n INET -- SOCKET: ~p" + "~n SOCKET -- INET: ~p" + "~n", [IF, I_FLAGS, S_FLAGS, IRem, SRem]), + ct:fail(ifaddrs_not_equal) + end; + _ -> + io:format("flags for ~p missing for one or both backends: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_INFO, S_INFO]), + ct:fail(ifaddrs_not_equal) + end, + {I_Rest2, S_Rest2} = + case {lists:reverse(I_Rest1), lists:reverse(S_Rest1)} of + {[{hwaddr, HWADDR}|IR2], [{hwaddr, HWADDR}|SR2]} -> + io:format("hwaddr for ~p *is* equal~n", [IF]), + {lists:reverse(IR2), lists:reverse(SR2)}; + {[{hwaddr, I_HWADDR}|_IR2], [{hwaddr, S_HWADDR}|_SR2]} -> + io:format("hwaddr for ~p *not* equal:" + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_HWADDR, S_HWADDR]), + ct:fail(ifaddrs_not_equal); + {IR2, [{hwaddr, HWADDR}|SR2]} -> + io:format("hwaddr for ~p only for socket - accept: " + "~n ~p" + "~n", [IF, HWADDR]), + {lists:reverse(IR2), lists:reverse(SR2)}; + {[{hwaddr, HWADDR}|_IR2], _SR2} -> + io:format("hwaddr for ~p only for inet - fail: " + "~n ~p" + "~n", [IF, HWADDR]), + ct:fail(ifaddrs_not_equal); + _ -> + io:format("hwaddr for ~p missing for both backends - accept~n", + [IF]), + {I_Rest1, S_Rest1} + end, + case {I_Rest2 -- S_Rest2, S_Rest2 -- I_Rest2} of {[], []} -> - io:format("flags for ~p *are* equal~n", [IF]), - getifaddrs_verify_backend(IF, I_INFO, S_INFO); - {IFD, SFD} -> - io:format("flags for ~p are *not* equal: " + io:format("remaining info for ~p is equal~n", [IF]), + ok; + {I_Diff, S_Diff} -> + io:format("remaining info for ~p not equal: " + "~n INET: ~p" + "~n SOCKET: ~p" "~n INET -- SOCKET: ~p" "~n SOCKET -- INET: ~p" - "~n", [IF, IFD, SFD]), - ct:fail(ifaddrs_not_equal) - end; -getifaddrs_verify_backend(IF, - [{addr, I_A}|I_INFO], - [{addr, S_A}|S_INFO]) -> - if - (I_A =:= S_A) -> - io:format("addr for ~p equal~n", [IF]), - getifaddrs_verify_backend(IF, I_INFO, S_INFO); - true -> - io:format("addr for ~p *not* equal: " - "~n INET: ~p" - "~n SOCKET: ~p" - "~n", [IF, I_A, S_A]), - ct:fail(ifaddrs_not_equal) - end; -getifaddrs_verify_backend(IF, - [{netmask, I_A}|I_INFO], - [{netmask, S_A}|S_INFO]) -> - if - (I_A =:= S_A) -> - io:format("netmask for ~p equal~n", [IF]), - getifaddrs_verify_backend(IF, I_INFO, S_INFO); - true -> - io:format("netmask for ~p *not* equal: " - "~n INET: ~p" - "~n SOCKET: ~p" - "~n", [IF, I_A, S_A]), - ct:fail(ifaddrs_not_equal) - end; -getifaddrs_verify_backend(IF, - [{broadaddr, I_A}|I_INFO], - [{broadaddr, S_A}|S_INFO]) -> - if - (I_A =:= S_A) -> - io:format("broadaddr for ~p equal~n", [IF]), - getifaddrs_verify_backend(IF, I_INFO, S_INFO); - true -> - io:format("broadaddr for ~p *not* equal: " - "~n INET: ~p" - "~n SOCKET: ~p" - "~n", [IF, I_A, S_A]), - ct:fail(ifaddrs_not_equal) - end; -getifaddrs_verify_backend(IF, - [{dstaddr, I_A}|I_INFO], - [{dstaddr, S_A}|S_INFO]) -> - if - (I_A =:= S_A) -> - io:format("dstaddr for ~p equal~n", [IF]), - getifaddrs_verify_backend(IF, I_INFO, S_INFO); - true -> - io:format("dstaddr for ~p *not* equal: " - "~n INET: ~p" - "~n SOCKET: ~p" - "~n", [IF, I_A, S_A]), - ct:fail(ifaddrs_not_equal) - end; -getifaddrs_verify_backend(IF, - [{hwaddr, I_A}|I_INFO], - [{hwaddr, S_A}|S_INFO]) -> - if - (I_A =:= S_A) -> - io:format("hwaddr for ~p equal~n", [IF]), - getifaddrs_verify_backend(IF, I_INFO, S_INFO); - true -> - io:format("hwaddr for ~p *not* equal: " - "~n INET: ~p" - "~n SOCKET: ~p" - "~n", [IF, I_A, S_A]), + "~n", [IF, I_Rest2, S_Rest2, I_Diff, S_Diff]), ct:fail(ifaddrs_not_equal) - end; -getifaddrs_verify_backend(IF, - [], - [{hwaddr, _}]) -> - %% We accepts that net can get some more info. - %% That is, that we can get hwaddr for some - %% interfaces that the inet driver cannot... - io:format("hwaddr accepted for ~p~n", [IF]), - ok; -getifaddrs_verify_backend(IF, - I_INFO, S_INFO) -> - io:format("unexpected info for ~p: " - "~n INET: ~p" - "~n SOCKET: ~p" - "~n", [IF, I_INFO, S_INFO]), - ct:fail(ifaddrs_not_equal). + end. + + +%% getifaddrs_verify_backend(IF, [] = _I_INFO, [] = _S_INFO) -> +%% io:format("backend(s) *are* equal for ~p~n", [IF]), +%% ok; +%% getifaddrs_verify_backend(IF, +%% [{flags, I_Flags}|I_INFO], +%% [{flags, S_Flags}|S_INFO]) -> +%% case {I_Flags -- S_Flags, S_Flags -- I_Flags} of +%% {[], []} -> +%% io:format("flags for ~p *are* equal~n", [IF]), +%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); +%% {IFD, SFD} -> +%% io:format("flags for ~p are *not* equal: " +%% "~n INET -- SOCKET: ~p" +%% "~n SOCKET -- INET: ~p" +%% "~n", [IF, IFD, SFD]), +%% ct:fail(ifaddrs_not_equal) +%% end; +%% getifaddrs_verify_backend(IF, +%% [{addr, I_A}|I_INFO], +%% [{addr, S_A}|S_INFO]) -> +%% if +%% (I_A =:= S_A) -> +%% io:format("addr for ~p equal~n", [IF]), +%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); +%% true -> +%% io:format("addr for ~p *not* equal: " +%% "~n INET: ~p" +%% "~n SOCKET: ~p" +%% "~n", [IF, I_A, S_A]), +%% ct:fail(ifaddrs_not_equal) +%% end; +%% getifaddrs_verify_backend(IF, +%% [{netmask, I_A}|I_INFO], +%% [{netmask, S_A}|S_INFO]) -> +%% if +%% (I_A =:= S_A) -> +%% io:format("netmask for ~p equal~n", [IF]), +%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); +%% true -> +%% io:format("netmask for ~p *not* equal: " +%% "~n INET: ~p" +%% "~n SOCKET: ~p" +%% "~n", [IF, I_A, S_A]), +%% ct:fail(ifaddrs_not_equal) +%% end; +%% getifaddrs_verify_backend(IF, +%% [{broadaddr, I_A}|I_INFO], +%% [{broadaddr, S_A}|S_INFO]) -> +%% if +%% (I_A =:= S_A) -> +%% io:format("broadaddr for ~p equal~n", [IF]), +%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); +%% true -> +%% io:format("broadaddr for ~p *not* equal: " +%% "~n INET: ~p" +%% "~n SOCKET: ~p" +%% "~n", [IF, I_A, S_A]), +%% ct:fail(ifaddrs_not_equal) +%% end; +%% getifaddrs_verify_backend(IF, +%% [{dstaddr, I_A}|I_INFO], +%% [{dstaddr, S_A}|S_INFO]) -> +%% if +%% (I_A =:= S_A) -> +%% io:format("dstaddr for ~p equal~n", [IF]), +%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); +%% true -> +%% io:format("dstaddr for ~p *not* equal: " +%% "~n INET: ~p" +%% "~n SOCKET: ~p" +%% "~n", [IF, I_A, S_A]), +%% ct:fail(ifaddrs_not_equal) +%% end; +%% getifaddrs_verify_backend(IF, +%% [{hwaddr, I_A}|I_INFO], +%% [{hwaddr, S_A}|S_INFO]) -> +%% if +%% (I_A =:= S_A) -> +%% io:format("hwaddr for ~p equal~n", [IF]), +%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); +%% true -> +%% io:format("hwaddr for ~p *not* equal: " +%% "~n INET: ~p" +%% "~n SOCKET: ~p" +%% "~n", [IF, I_A, S_A]), +%% ct:fail(ifaddrs_not_equal) +%% end; +%% getifaddrs_verify_backend(IF, +%% [], +%% [{hwaddr, _}]) -> +%% %% We accepts that net can get some more info. +%% %% That is, that we can get hwaddr for some +%% %% interfaces that the inet driver cannot... +%% io:format("hwaddr accepted for ~p~n", [IF]), +%% ok; +%% getifaddrs_verify_backend(IF, +%% I_INFO, S_INFO) -> +%% io:format("unexpected info for ~p: " +%% "~n INET: ~p" +%% "~n SOCKET: ~p" +%% "~n", [IF, I_INFO, S_INFO]), +%% ct:fail(ifaddrs_not_equal). From d6cd17f15124238d89a17b66ba2fe5c40e253261 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 20 Jun 2024 15:40:07 +0200 Subject: [PATCH 11/37] [esock] Tweaked encode of sockaddr_in (IPv4) --- erts/emulator/nifs/common/socket_util.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index 613288cf18ae..778955ef4244 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -814,10 +814,16 @@ void esock_encode_sockaddr_in(ErlNifEnv* env, { ERL_NIF_TERM ePort, eAddr; int port; + /* The size of the actual data part, excluding padding */ + SOCKLEN_T minSz = sizeof(struct sockaddr_in) - + sizeof(sockAddrP->sin_zero); - UDBG( ("SUTIL", "esock_encode_sockaddr_in -> entry\r\n") ); + UDBG( ("SUTIL", "esock_encode_sockaddr_in -> entry with" + "\r\n addrLen: %d" + "\r\n required min size: %d" + "\r\n", addrLen, minSz) ); - if (addrLen >= sizeof(struct sockaddr_in)) { + if (addrLen >= minSz) { /* The port */ port = ntohs(sockAddrP->sin_port); @@ -833,7 +839,7 @@ void esock_encode_sockaddr_in(ErlNifEnv* env, UDBG( ("SUTIL", "esock_encode_sockaddr_in -> wrong size: " "\r\n addrLen: %d" "\r\n addr size: %d" - "\r\n", addrLen, sizeof(struct sockaddr_in)) ); + "\r\n", addrLen, minSz) ); esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, addrLen, esock_atom_inet, eSockAddr); } From e4023846bdc3fcbf6b0f00e45d2f8e67617b8d42 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 24 Jun 2024 16:04:45 +0200 Subject: [PATCH 12/37] [enet] Try handle OpenBSD netmask peculiarities --- erts/emulator/nifs/common/prim_net_nif.c | 33 ++++++++++++++++++------ erts/emulator/nifs/common/socket_util.c | 6 ++--- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c index f0027580adec..f8dc1856cd5b 100644 --- a/erts/emulator/nifs/common/prim_net_nif.c +++ b/erts/emulator/nifs/common/prim_net_nif.c @@ -559,7 +559,8 @@ static BOOLEAN_T enet_getifaddrs_netns(ErlNifEnv* env, static BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err); static BOOLEAN_T restore_network_namespace(int ns, int* err); #endif -static ERL_NIF_TERM encode_sockaddr(ErlNifEnv* env, struct sockaddr* sa); +static ERL_NIF_TERM encode_sockaddr(ErlNifEnv* env, + struct sockaddr* sa); static BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, const ERL_NIF_TERM eflags, int* flags); @@ -1617,6 +1618,20 @@ void encode_ifaddrs(ErlNifEnv* env, NDBG( ("NET", "encode_ifaddrs -> addr: " "\r\n %T" "\r\n", eaddr) ); + /* This is an ugly (OpenBSD?) hack... + * "For some reason" the netmask family is set to 'AF_UNSPEC' + * (when the addr family is AF_INET) on OpenBSD, + * which makes encoding the address "difficult"... + * So force the family to AF_INET in this case to allow encoding + * the netmask... + */ + if ((ifap->ifa_addr != NULL) && + (((ESockAddress*)ifap->ifa_addr)->sa.sa_family == AF_INET)) { + if ((ifap->ifa_netmask != NULL) && + (((ESockAddress*)ifap->ifa_netmask)->sa.sa_family == AF_UNSPEC)) { + ((ESockAddress*)ifap->ifa_netmask)->sa.sa_family = AF_INET; + } + } enetmask = encode_ifaddrs_addr(env, ifap->ifa_netmask); NDBG( ("NET", "encode_ifaddrs -> netmask: " "\r\n %T" @@ -1756,7 +1771,8 @@ ERL_NIF_TERM encode_ifaddrs_flags(ErlNifEnv* env, unsigned int flags) static -ERL_NIF_TERM encode_ifaddrs_addr(ErlNifEnv* env, struct sockaddr* sa) +ERL_NIF_TERM encode_ifaddrs_addr(ErlNifEnv* env, + struct sockaddr* sa) { return encode_sockaddr(env, sa); } @@ -2495,7 +2511,7 @@ static ERL_NIF_TERM encode_adapter_unicast_addr_sockaddr(ErlNifEnv* env, struct sockaddr* addrP) { - return encode_sockaddr(env, addrP); + return encode_sockaddr(env, addrP, -1); } #endif // __WIN32__ @@ -2700,7 +2716,7 @@ static ERL_NIF_TERM encode_adapter_anycast_addr_sockaddr(ErlNifEnv* env, struct sockaddr* addrP) { - return encode_sockaddr(env, addrP); + return encode_sockaddr(env, addrP, -1); } #endif // __WIN32__ @@ -2779,7 +2795,7 @@ static ERL_NIF_TERM encode_adapter_multicast_addr_sockaddr(ErlNifEnv* env, struct sockaddr* addrP) { - return encode_sockaddr(env, addrP); + return encode_sockaddr(env, addrP, -1); } #endif // __WIN32__ @@ -2843,7 +2859,7 @@ static ERL_NIF_TERM encode_adapter_dns_server_addr_sockaddr(ErlNifEnv* env, struct sockaddr* addrP) { - return encode_sockaddr(env, addrP); + return encode_sockaddr(env, addrP, -1); } #endif // __WIN32__ @@ -2987,7 +3003,7 @@ static ERL_NIF_TERM encode_adapter_prefix_sockaddr(ErlNifEnv* env, struct sockaddr* addrP) { - return encode_sockaddr(env, addrP); + return encode_sockaddr(env, addrP, -1); } #endif // __WIN32__ @@ -4466,7 +4482,8 @@ unsigned int enet_if_names_length(struct if_nameindex* p) */ static -ERL_NIF_TERM encode_sockaddr(ErlNifEnv* env, struct sockaddr* sa) +ERL_NIF_TERM encode_sockaddr(ErlNifEnv* env, + struct sockaddr* sa) { ERL_NIF_TERM esa; diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index 778955ef4244..5a7e99ef57bf 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -1218,8 +1218,8 @@ void esock_encode_sockaddr_dl(ErlNifEnv* env, SOCKLEN_T ndsz = sizeof(struct sockaddr_dl)-sizeof(sockAddrP->sdl_data); UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> entry with" - "\r\n. addrLen: %d" - "\r\n. non-data fields size: %d" + "\r\n addrLen: %d" + "\r\n non-data fields size: %d" "\r\n", addrLen, ndsz) ); /* Make sure the data field actually contains something */ @@ -1245,7 +1245,7 @@ void esock_encode_sockaddr_dl(ErlNifEnv* env, "\r\n", sockAddrP->sdl_alen) ); ealen = MKUI(env, sockAddrP->sdl_alen); - /* slen - ink layer selector length */ + /* slen - link layer selector length */ UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> slen: %d" "\r\n", sockAddrP->sdl_slen) ); eslen = MKUI(env, sockAddrP->sdl_slen); From ba624bd7a7a806ffa1006ec2348fb1ace71779d6 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 24 Jun 2024 16:08:13 +0200 Subject: [PATCH 13/37] [kernel|test] Tweak getifaddrs test case for Windows --- lib/kernel/test/inet_SUITE.erl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 61aacb9f7f55..3aba39a51562 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1844,8 +1844,25 @@ getifaddrs_verify_backend(IF, I_INFO, S_INFO) -> {[], []} -> io:format("flags for ~p *are* equal~n", [IF]), {IR1, SR1}; + {[], [multicast]} -> + io:format("flags for ~p are *not* equal - " + "extra multicast: " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_FLAGS, S_FLAGS]), + case lists:member(loopback, I_FLAGS) of + true -> + %% The net module getifaddrs contains + %% some more flags... + %% Happens on windows + io:format("flags for ~p *acceptably* " + "different~n", [IF]), + IR1, SR1; + _ -> + ct:fail(ifaddrs_not_equal) + end; {IRem, SRem} -> - io:format("flags for ~p are *not* equal: " + io:format("flags for ~p are *not* equal - check flags: " "~n INET: ~p" "~n SOCKET: ~p" "~n INET -- SOCKET: ~p" From 903efc0c5ddce477be0f930f52b99a8078cbbec0 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 25 Jun 2024 17:42:22 +0200 Subject: [PATCH 14/37] [kernel] getiflist, ifget and ifset with inet-backend Add inet_backend options for these functions. OTP-19132 --- erts/emulator/nifs/common/prim_socket_nif.c | 2 + erts/emulator/nifs/common/socket_int.h | 2 + erts/emulator/nifs/common/socket_util.c | 172 +++++++--- erts/emulator/nifs/common/socket_util.h | 5 + erts/emulator/nifs/unix/unix_socket_syncio.c | 123 ++++++-- erts/emulator/nifs/win32/win_socket_asyncio.c | 2 +- lib/kernel/src/inet.erl | 295 ++++++++++++++---- lib/kernel/src/socket.erl | 10 +- lib/kernel/test/inet_SUITE.erl | 48 ++- 9 files changed, 515 insertions(+), 144 deletions(-) diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index f4c4e98563ea..e19aa5133dd6 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -2057,6 +2057,7 @@ static const struct in6_addr in6addr_loopback = GLOBAL_ATOM_DECL(hoplimit); \ GLOBAL_ATOM_DECL(hopopts); \ GLOBAL_ATOM_DECL(host); \ + GLOBAL_ATOM_DECL(hwaddr); \ GLOBAL_ATOM_DECL(icmp); \ GLOBAL_ATOM_DECL(icmp6); \ GLOBAL_ATOM_DECL(ieee802); \ @@ -2186,6 +2187,7 @@ static const struct in6_addr in6addr_loopback = GLOBAL_ATOM_DECL(protocol); \ GLOBAL_ATOM_DECL(pup); \ GLOBAL_ATOM_DECL(raw); \ + GLOBAL_ATOM_DECL(rawip); \ GLOBAL_ATOM_DECL(rcvbuf); \ GLOBAL_ATOM_DECL(rcvbufforce); \ GLOBAL_ATOM_DECL(rcvlowat); \ diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h index 1a5818d7cf1e..82fbd85331a1 100644 --- a/erts/emulator/nifs/common/socket_int.h +++ b/erts/emulator/nifs/common/socket_int.h @@ -331,6 +331,7 @@ typedef long ssize_t; GLOBAL_ATOM_DEF(hoplimit); \ GLOBAL_ATOM_DEF(hopopts); \ GLOBAL_ATOM_DEF(host); \ + GLOBAL_ATOM_DEF(hwaddr); \ GLOBAL_ATOM_DEF(icmp); \ GLOBAL_ATOM_DEF(icmp6); \ GLOBAL_ATOM_DEF(ieee802); \ @@ -460,6 +461,7 @@ typedef long ssize_t; GLOBAL_ATOM_DEF(protocol); \ GLOBAL_ATOM_DEF(pup); \ GLOBAL_ATOM_DEF(raw); \ + GLOBAL_ATOM_DEF(rawip); \ GLOBAL_ATOM_DEF(rcvbuf); \ GLOBAL_ATOM_DEF(rcvbufforce); \ GLOBAL_ATOM_DEF(rcvlowat); \ diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index 5a7e99ef57bf..ba5791783347 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -654,77 +654,163 @@ void esock_encode_hwsockaddr(ErlNifEnv* env, SOCKLEN_T addrLen, ERL_NIF_TERM* eSockAddr) { - ERL_NIF_TERM efamily; - int family; + ERL_NIF_TERM efamily; + int family; - // Sanity check - if (addrLen < (char *)&sockAddrP->sa_data - (char *)sockAddrP) { - // We got crap, cannot even know the address family - esock_encode_sockaddr_broken(env, sockAddrP, addrLen, eSockAddr); - return; - } - family = sockAddrP->sa_family; + // Sanity check + if (addrLen < (char *)&sockAddrP->sa_data - (char *)sockAddrP) { + // We got crap, cannot even know the address family + esock_encode_sockaddr_broken(env, sockAddrP, addrLen, eSockAddr); + return; + } + family = sockAddrP->sa_family; - UDBG( ("SUTIL", "esock_encode_hwsockaddr -> entry with" - "\r\n family: %d" - "\r\n addrLen: %d" - "\r\n", family, addrLen) ); + UDBG( ("SUTIL", "esock_encode_hwsockaddr -> entry with" + "\r\n family: %d" + "\r\n addrLen: %d" + "\r\n", family, addrLen) ); - switch (family) { + switch (family) { #if defined(ARPHRD_NETROM) - case ARPHRD_NETROM: - efamily = esock_atom_netrom; - break; + case ARPHRD_NETROM: + efamily = esock_atom_netrom; + break; #endif #if defined(ARPHRD_ETHER) - case ARPHRD_ETHER: - efamily = esock_atom_ether; - break; + case ARPHRD_ETHER: + efamily = esock_atom_ether; + break; #endif #if defined(ARPHRD_IEEE802) - case ARPHRD_IEEE802: - efamily = esock_atom_ieee802; - break; + case ARPHRD_IEEE802: + efamily = esock_atom_ieee802; + break; #endif #if defined(ARPHRD_DLCI) - case ARPHRD_DLCI: - efamily = esock_atom_dlci; - break; + case ARPHRD_DLCI: + efamily = esock_atom_dlci; + break; #endif #if defined(ARPHRD_FRELAY) - case ARPHRD_FRELAY: - efamily = esock_atom_frelay; - break; + case ARPHRD_FRELAY: + efamily = esock_atom_frelay; + break; #endif #if defined(ARPHRD_IEEE1394) - case ARPHRD_IEEE1394: - efamily = esock_atom_ieee1394; - break; + case ARPHRD_IEEE1394: + efamily = esock_atom_ieee1394; + break; #endif #if defined(ARPHRD_LOOPBACK) - case ARPHRD_LOOPBACK: - efamily = esock_atom_loopback; - break; + case ARPHRD_LOOPBACK: + efamily = esock_atom_loopback; + break; +#endif + +#if defined(ARPHRD_RAWIP) + case ARPHRD_RAWIP: + efamily = esock_atom_rawip; + break; #endif #if defined(ARPHRD_NONE) - case ARPHRD_NONE: - efamily = esock_atom_none; - break; + case ARPHRD_NONE: + efamily = esock_atom_none; + break; #endif - default: - efamily = MKI(env, family); - break; - } + default: + efamily = MKI(env, family); + break; + } + + esock_encode_sockaddr_native(env, sockAddrP, addrLen, efamily, eSockAddr); +} + + + +extern +BOOLEAN_T esock_decode_hwsockaddr(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + ESockAddress* sockAddrP, + SOCKLEN_T* addrLen) +{ + ERL_NIF_TERM efamily; + int family = ARPHRD_VOID; + + if (!IS_MAP(env, eSockAddr)) + return FALSE; + + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_family, &efamily)) + return FALSE; + + /* This is a bit ugly, but if-defing this properly is + * a bit messy so for now... + */ +#if defined(ARPHRD_NETROM) + if (IS_IDENTICAL(efamily, esock_atom_netrom)) { + family = ARPHRD_NETROM; + } +#endif + +#if defined(ARPHRD_ETHER) + if (IS_IDENTICAL(efamily, esock_atom_ether)) { + family = ARPHRD_ETHER; + } +#endif + +#if defined(ARPHRD_IEEE802) + if (IS_IDENTICAL(efamily, esock_atom_ieee802)) { + family = ARPHRD_IEEE802; + } +#endif + +#if defined(ARPHRD_DLCI) + if (IS_IDENTICAL(efamily, esock_atom_dlci)) { + family = ARPHRD_DLCI; + } +#endif + +#if defined(ARPHRD_FRELAY) + if (IS_IDENTICAL(efamily, esock_atom_frelay)) { + family = ARPHRD_FRELAY; + } +#endif + +#if defined(ARPHRD_IEEE1394) + if (IS_IDENTICAL(efamily, esock_atom_ieee1394)) { + family = ARPHRD_IEEE1394; + } +#endif + +#if defined(ARPHRD_LOOPBACK) + if (IS_IDENTICAL(efamily, esock_atom_loopback)) { + family = ARPHRD_LOOPBACK; + } +#endif + +#if defined(ARPHRD_RAWIP) + if (IS_IDENTICAL(efamily, esock_atom_rawip)) { + family = ARPHRD_RAWIP; + } +#endif + +#if defined(ARPHRD_NONE) + if (IS_IDENTICAL(efamily, esock_atom_none)) { + family = ARPHRD_NONE; + } +#endif + + + return esock_decode_sockaddr_native(env, eSockAddr, + sockAddrP, family, addrLen); - esock_encode_sockaddr_native(env, sockAddrP, addrLen, efamily, eSockAddr); } diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h index c16803bbdc6b..5830128d0067 100644 --- a/erts/emulator/nifs/common/socket_util.h +++ b/erts/emulator/nifs/common/socket_util.h @@ -108,6 +108,11 @@ void esock_encode_sockaddr(ErlNifEnv* env, int addrLen, ERL_NIF_TERM* eSockAddr); extern +BOOLEAN_T esock_decode_hwsockaddr(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + ESockAddress* sockAddrP, + SOCKLEN_T* addrLen); +extern void esock_encode_hwsockaddr(ErlNifEnv* env, struct sockaddr* sockAddrP, SOCKLEN_T addrLen, diff --git a/erts/emulator/nifs/unix/unix_socket_syncio.c b/erts/emulator/nifs/unix/unix_socket_syncio.c index 639c82aaf633..411b7580f742 100644 --- a/erts/emulator/nifs/unix/unix_socket_syncio.c +++ b/erts/emulator/nifs/unix/unix_socket_syncio.c @@ -598,6 +598,13 @@ IOCTL_GET_FUNCS3_DEF #define IOCTL_SIFTXQLEN_FUNC_DEF #endif +/* esock_ioctl_sifhwaddr */ +#if defined(SIOCSIFHWADDR) +#define IOCTL_SIFHWADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifhwaddr) +#else +#define IOCTL_SIFHWADDR_FUNC_DEF +#endif + #define IOCTL_SET_FUNCS_DEF \ IOCTL_SIFFLAGS_FUNC_DEF; \ IOCTL_SIFADDR_FUNC_DEF; \ @@ -605,7 +612,8 @@ IOCTL_GET_FUNCS3_DEF IOCTL_SIFBRDADDR_FUNC_DEF; \ IOCTL_SIFNETMASK_FUNC_DEF; \ IOCTL_SIFMTU_FUNC_DEF; \ - IOCTL_SIFTXQLEN_FUNC_DEF; + IOCTL_SIFTXQLEN_FUNC_DEF; \ + IOCTL_SIFHWADDR_FUNC_DEF; #define IOCTL_SET_FUNC_DEF(F) \ static ERL_NIF_TERM essio_ioctl_##F(ErlNifEnv* env, \ ESockDescriptor* descP, \ @@ -655,6 +663,13 @@ static BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM eaddr, ESockAddress* addr); +#if defined(SIOCSIFHWADDR) +static +BOOLEAN_T decode_ioctl_hwaddr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eaddr, + ESockAddress* addr); +#endif #if defined(SIOCSIFMTU) static BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, ESockDescriptor* descP, @@ -4222,8 +4237,8 @@ ERL_NIF_TERM essio_ioctl4(ErlNifEnv* env, #if defined(SIOCSIFBRDADDR) case SIOCSIFBRDADDR: - return essio_ioctl_sifbrdaddr(env, descP, ename, eval); - break; + return essio_ioctl_sifbrdaddr(env, descP, ename, eval); + break; #endif #if defined(SIOCSIFNETMASK) @@ -4244,6 +4259,12 @@ ERL_NIF_TERM essio_ioctl4(ErlNifEnv* env, break; #endif +#if defined(SIOCSIFHWADDR) + case SIOCSIFHWADDR: + return essio_ioctl_sifhwaddr(env, descP, ename, eval); + break; +#endif + default: return esock_make_error(env, esock_atom_enotsup); break; @@ -4679,8 +4700,8 @@ ERL_NIF_TERM essio_ioctl_gifname(ErlNifEnv* env, /* *** essio_ioctl_sifbrdaddr *** */ #if defined(SIOCSIFBRDADDR) #define IOCTL_SIFBRDADDR_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifbrdaddr, SIOCSIFBRDADDR, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_broadaddr)) + IOCTL_SET_REQUEST_DECL(sifbrdaddr, SIOCSIFBRDADDR, sockaddr, \ + ((ESockAddress*) &ifreq.ifr_broadaddr)) #else #define IOCTL_SIFBRDADDR_FUNC_DECL #endif @@ -4718,13 +4739,23 @@ ERL_NIF_TERM essio_ioctl_gifname(ErlNifEnv* env, #define IOCTL_SIFTXQLEN_FUNC_DECL #endif +/* *** essio_ioctl_sifhqaddr *** */ +#if defined(SIOCSIFHWADDR) +#define IOCTL_SIFHWADDR_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(sifhwaddr, SIOCSIFHWADDR, hwaddr, \ + ((ESockAddress*) &ifreq.ifr_hwaddr)) +#else +#define IOCTL_SIFHWADDR_FUNC_DECL +#endif + #define IOCTL_SET_FUNCS \ IOCTL_SIFADDR_FUNC_DECL \ IOCTL_SIFDSTADDR_FUNC_DECL \ IOCTL_SIFBRDADDR_FUNC_DECL \ IOCTL_SIFNETMASK_FUNC_DECL \ IOCTL_SIFMTU_FUNC_DECL \ - IOCTL_SIFTXQLEN_FUNC_DECL + IOCTL_SIFTXQLEN_FUNC_DECL \ + IOCTL_SIFHWADDR_FUNC_DECL #define IOCTL_SET_REQUEST_DECL(OR, R, DF, UVP) \ static \ @@ -4996,16 +5027,16 @@ ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, ESockDescriptor* descP, struct sockaddr* addrP) { - ERL_NIF_TERM eaddr; - SOCKLEN_T sz = sizeof(struct sockaddr); + ERL_NIF_TERM eaddr; + SOCKLEN_T sz = sizeof(struct sockaddr); - esock_encode_hwsockaddr(env, addrP, sz, &eaddr); + esock_encode_hwsockaddr(env, addrP, sz, &eaddr); - SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_ifraddr -> done with" - "\r\n Sock Addr: %T" - "\r\n", eaddr) ); + SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_hwaddr -> done with" + "\r\n Sock Addr: %T" + "\r\n", eaddr) ); - return esock_make_ok2(env, eaddr);; + return esock_make_ok2(env, eaddr);; } #endif @@ -5033,8 +5064,8 @@ ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env, short flags) { int i, flag, num = esock_ioctl_flags_length; // NUM(ioctl_flags); - ERL_NIF_TERM eflags, eflag; - SocketTArray ta = TARRAY_CREATE(20); // Just to be on the safe side + ERL_NIF_TERM eflags, eflag; + SocketTArray ta = TARRAY_CREATE(20); // Just to be on the safe side if (flags == 0) { eflags = MKEL(env); @@ -5081,20 +5112,64 @@ BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, ERL_NIF_TERM eaddr, ESockAddress* addr) { - SOCKLEN_T addrLen; - BOOLEAN_T result; + SOCKLEN_T addrLen; + BOOLEAN_T result; - result = esock_decode_sockaddr(env, eaddr, (ESockAddress*) addr, &addrLen); + result = esock_decode_sockaddr(env, eaddr, (ESockAddress*) addr, &addrLen); - VOID(addrLen); + VOID(addrLen); - SSDBG( descP, - ("UNIX-ESSIO", "decode_ioctl_sockaddr {%d} -> decode result: %s" - "\r\n", descP->sock, B2S(result)) ); + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_sockaddr {%d} -> decode result: %s" + "\r\n", descP->sock, B2S(result)) ); - return result; + return result; } - + + +static +BOOLEAN_T decode_ioctl_hwaddr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eaddr, + ESockAddress* addr) +{ + SOCKLEN_T addrLen; + BOOLEAN_T result; + + result = esock_decode_hwsockaddr(env, eaddr, + (ESockAddress*) addr, &addrLen); + + VOID(addrLen); + + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_hwaddr {%d} -> decode result: %s" + "\r\n", descP->sock, B2S(result)) ); + + return result; +} + + +/* #if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) */ +/* static */ +/* ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, */ +/* ESockDescriptor* descP, */ +/* struct sockaddr* addrP) */ +/* { */ +/* ERL_NIF_TERM eaddr; */ +/* SOCKLEN_T sz = sizeof(struct sockaddr); */ + +/* esock_encode_hwsockaddr(env, addrP, sz, &eaddr); */ + +/* SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_hwaddr -> done with" */ +/* "\r\n Sock Addr: %T" */ +/* "\r\n", eaddr) ); */ + +/* return esock_make_ok2(env, eaddr);; */ +/* } */ +/* #endif */ + + + static BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, diff --git a/erts/emulator/nifs/win32/win_socket_asyncio.c b/erts/emulator/nifs/win32/win_socket_asyncio.c index 504e74543d26..ad02da668812 100644 --- a/erts/emulator/nifs/win32/win_socket_asyncio.c +++ b/erts/emulator/nifs/win32/win_socket_asyncio.c @@ -5862,7 +5862,7 @@ ERL_NIF_TERM esaio_ioctl_tcp_info(ErlNifEnv* env, } SSDBG( descP, - ("UNIX-ESSIO", "essio_ioctl_tcp_info(%d) -> done with" + ("WIN-ESAIO", "esaio_ioctl_tcp_info(%d) -> done with" "\r\n result: %T" "\r\n", descP->sock, result) ); diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index ba90386b774f..ce4dd4512c3c 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1620,6 +1620,8 @@ getopts(Socket, Opts) -> Other end. +%% -------------------------------------------------------------------------- + -doc """ Get interface names and addresses, in a specific namespace. @@ -1633,7 +1635,7 @@ for 'socket' the equivalent net functions will be used). See the socket option [`{netns, Namespace}`](#option-netns) -under`setopts/2`. +under `setopts/2`. """. -doc(#{since => <<"OTP 21.2">>}). -spec getifaddrs( @@ -1676,7 +1678,6 @@ net_unique_if_names([#{name := IfName}|Ifs], IfNames) -> net_unique_if_names(Ifs, [IfName|IfNames]) end. - net_getifaddrs({ok, AllIfs}) -> IfNames = net_unique_if_names(AllIfs), {ok, net_collect_ifopts(IfNames, AllIfs)}; @@ -1691,9 +1692,6 @@ net_collect_ifopts([], _AllIfs, AllNameAndOpts) -> lists:reverse(AllNameAndOpts); net_collect_ifopts([IfName|IfNames], AllIfs, NameAndOpts) -> %% Get the Ifs with the name IfName - %% io:format("~w -> entry with" - %% "~n IfName: ~p" - %% "~n", [?FUNCTION_NAME, IfName]), Ifs = [If || #{name := N} = If <- AllIfs, (N =:= IfName)], IfOpts = net_ifs2ifopts(Ifs), net_collect_ifopts(IfNames, AllIfs, [{IfName, IfOpts}|NameAndOpts]). @@ -1707,11 +1705,6 @@ net_ifs2ifopts(Ifs) -> net_ifs2ifopts([], #{flags := Flags, addrs := Addrs, hwaddr := HwAddr}) -> - %% io:format("~w -> entry when done with" - %% "~n Flags: ~p" - %% "~n Addrs: ~p" - %% "~n HwAddr: ~p" - %% "~n", [?FUNCTION_NAME, Flags, Addrs, HwAddr]), [{flags, net_flags_to_inet_flags(Flags)}] ++ lists:reverse(Addrs) ++ case HwAddr of @@ -1721,9 +1714,6 @@ net_ifs2ifopts([], #{flags := Flags, [{hwaddr, HwAddr}] end; net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> - %% io:format("~w -> entry initial with" - %% "~n If: ~p" - %% "~n", [?FUNCTION_NAME, If]), IfOpts = case If of %% LINK or PACKET @@ -1736,8 +1726,6 @@ net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> #{flags := Flags, addr := #{family := packet, addr := HwAddrBin}} -> - %% io:format("~w(~w) -> packet entry" - %% "~n", [?FUNCTION_NAME, ?LINE]), IfOpts0#{flags => Flags, hwaddr => binary_to_list(HwAddrBin)}; #{flags := Flags, @@ -1745,11 +1733,6 @@ net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> nlen := NLen, alen := ALen, data := Data}} when (ALen > 0) -> - %% io:format("~w(~w) -> link entry with" - %% "~n NLen: ~w" - %% "~n ALen: ~w" - %% "~n Data: ~p" - %% "~n", [?FUNCTION_NAME, ?LINE, NLen, ALen, Data]), case Data of <<_:NLen/binary, ABin:ALen/binary, _/binary>> -> IfOpts0#{flags => Flags, @@ -1763,8 +1746,6 @@ net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> netmask := #{family := Fam, addr := Mask}} when (Fam =:= inet) orelse (Fam =:= inet6) -> - %% io:format("~w(~w) -> ~w entry" - %% "~n", [?FUNCTION_NAME, ?LINE, Fam]), %% We may also have broadcast or dest addr BroadAddr = case maps:get(broadaddr, If, undefined) of undefined -> @@ -1782,8 +1763,6 @@ net_ifs2ifopts([If|Ifs], #{flags := []} = IfOpts0) -> addrs => DstAddr ++ BroadAddr ++ [{netmask, Mask}, {addr, Addr}]}; #{flags := Flags} -> - %% io:format("~w(~w) -> only flags entry" - %% "~n", [?FUNCTION_NAME, ?LINE]), IfOpts0#{flags => Flags} end, net_ifs2ifopts(Ifs, IfOpts); @@ -1792,19 +1771,12 @@ net_ifs2ifopts([If|Ifs], IfOpts0) -> %% (they are supposed to be the same for all if:s of the same name). %% For each 'addr' entry we can have one 'netmask' and 'broadcast' %% or 'dstaddr' - %% io:format("~w -> entry with" - %% "~n If: ~p" - %% "~nwhen" - %% "~n IfOpts0: ~p" - %% "~n", [?FUNCTION_NAME, If, IfOpts0]), IfOpts = case If of #{flags := Flags, addr := #{family := packet, addr := HwAddrBin}} -> Flags0 = maps:get(flags, IfOpts0, []), - %% io:format("~w(~w) -> packet entry" - %% "~n", [?FUNCTION_NAME, ?LINE]), IfOpts0#{flags => Flags0 ++ (Flags -- Flags0), hwaddr => binary_to_list(HwAddrBin)}; #{flags := Flags, @@ -1813,8 +1785,6 @@ net_ifs2ifopts([If|Ifs], IfOpts0) -> netmask := #{family := Fam, addr := Mask}} when (Fam =:= inet) orelse (Fam =:= inet6) -> - %% io:format("~w(~w) -> ~w entry" - %% "~n", [?FUNCTION_NAME, ?LINE, Fam]), Addrs0 = maps:get(addrs, IfOpts0, []), Flags0 = maps:get(flags, IfOpts0, []), %% We may also have broadcast or dest addr @@ -1838,8 +1808,6 @@ net_ifs2ifopts([If|Ifs], IfOpts0) -> {addr, Addr}] ++ Addrs0}; _ -> - %% io:format("~w(~w) -> nothing updated" - %% "~n", [?FUNCTION_NAME, ?LINE]), IfOpts0 end, net_ifs2ifopts(Ifs, IfOpts). @@ -1848,22 +1816,12 @@ net_flags_to_inet_flags(Flags) -> net_flags_to_inet_flags(Flags, []). net_flags_to_inet_flags([], OutFlags) -> - %% io:format("~w(~w) -> done when" - %% "~n OutFlags: ~p" - %% "~n", [?FUNCTION_NAME, ?LINE, OutFlags]), lists:reverse(net_flags_maybe_add_running(OutFlags)); net_flags_to_inet_flags([InFlag|InFlags], OutFlags) -> - %% io:format("~w(~w) -> entry with" - %% "~n InFlag: ~p" - %% "~n", [?FUNCTION_NAME, ?LINE, InFlag]), case net_flag_to_inet_flag(InFlag) of {value, OutFlag} -> - %% io:format("~w(~w) -> known flag => ~w" - %% "~n", [?FUNCTION_NAME, ?LINE, OutFlag]), net_flags_to_inet_flags(InFlags, [OutFlag | OutFlags]); false -> - %% io:format("~w(~w) -> unknown flag => skip" - %% "~n", [?FUNCTION_NAME, ?LINE]), net_flags_to_inet_flags(InFlags, OutFlags) end. @@ -1925,23 +1883,55 @@ getifaddrs() -> do_getifaddrs(inet_backend(), []). +%% -------------------------------------------------------------------------- -doc false. -spec getiflist( - [Option :: {netns, Namespace :: file:filename_all()}] + [Option :: inet_backend() | {netns, Namespace :: file:filename_all()}] | socket()) -> {'ok', [string()]} | {'error', posix()}. +getiflist([{inet_backend, Backend}|Opts]) -> + do_getiflist(Backend, Opts); getiflist(Opts) when is_list(Opts) -> - withsocket(fun(S) -> prim_inet:getiflist(S) end, Opts); -getiflist(Socket) -> + do_getiflist(inet_backend(), Opts); +getiflist(?module_socket(GenSocketMod, ESock) = _Socket) + when is_atom(GenSocketMod) -> + do_getiflist('socket', ESock); +getiflist(Socket) when is_port(Socket) -> + do_getiflist('inet', Socket). + +do_getiflist(Backend, Opts) when is_list(Opts) -> + withsocket(fun(S) -> do_getiflist2(Backend, S) end, Backend, Opts); +do_getiflist(Backend, Socket) -> + do_getiflist2(Backend, Socket). + + +do_getiflist2('socket' = _Backend, Socket) -> + net_getiflist(Socket); +do_getiflist2('inet' = _Backend, Socket) when is_port(Socket) -> + inet_getiflist(Socket). + +net_getiflist(Socket) -> + case socket:ioctl(Socket, gifconf) of + {ok, Interfaces} -> + {ok, [Name || #{name := Name} <- Interfaces]}; + {error, _} = ERROR -> + ERROR + end. + +inet_getiflist(Socket) -> prim_inet:getiflist(Socket). + -doc false. -spec getiflist() -> {'ok', [string()]} | {'error', posix()}. getiflist() -> - withsocket(fun(S) -> prim_inet:getiflist(S) end). + do_getiflist(inet_backend(), []). + + +%% -------------------------------------------------------------------------- -doc false. -spec ifget(Socket :: socket(), @@ -1949,23 +1939,109 @@ getiflist() -> Opts :: [if_getopt()]) -> {'ok', [if_getopt_result()]} | {'error', posix()}. -ifget(Socket, Name, Opts) -> +ifget(?module_socket(GenSocketMod, ESock) = _Socket, Name, Opts) + when is_atom(GenSocketMod) -> + do_ifget('socket', ESock, Name, Opts); +ifget(Socket, Name, Opts) when is_port(Socket) -> + do_ifget('inet', Socket, Name, Opts). + + +do_ifget('socket', Socket, Name, Opts) -> + esock_ifget(Socket, Name, Opts); +do_ifget('inet', Socket, Name, Opts) -> prim_inet:ifget(Socket, Name, Opts). + +esock_ifget(ESock, Name, Opts) -> + esock_ifget(ESock, Name, Opts, []). + +esock_ifget(_ESock, _Name, [] = _Opts, Acc) -> + {ok, lists:reverse(Acc)}; +esock_ifget(ESock, Name, [Opt|Opts], Acc) -> + case do_esock_ifget(ESock, Name, Opt) of + {ok, Value} -> + esock_ifget(ESock, Name, Opts, [{Opt, Value}|Acc]); + {error, _} = ERROR -> + ERROR + end. + +do_esock_ifget(ESock, Name, 'addr') -> + case socket:ioctl(ESock, gifaddr, Name) of + {ok, #{addr := Addr}} -> + {ok, Addr}; + {error, _} = ERROR -> + ERROR + end; +do_esock_ifget(ESock, Name, 'broadaddr') -> + case socket:ioctl(ESock, gifbrdaddr, Name) of + {ok, #{addr := Addr}} -> + {ok, Addr}; + {error, _} = ERROR -> + ERROR + end; +do_esock_ifget(ESock, Name, 'dstaddr') -> + case socket:ioctl(ESock, gifdstaddr, Name) of + {ok, #{addr := Addr}} -> + {ok, Addr}; + {error, _} = ERROR -> + ERROR + end; +do_esock_ifget(ESock, Name, 'mtu') -> + socket:ioctl(ESock, gifmtu, Name); +do_esock_ifget(ESock, Name, 'netmask') -> + case socket:ioctl(ESock, gifnetmask, Name) of + {ok, #{addr := Addr}} -> + {ok, Addr}; + {error, _} = ERROR -> + ERROR + end; +do_esock_ifget(ESock, Name, 'flags') -> + socket:ioctl(ESock, gifflags, Name); +do_esock_ifget(ESock, Name, 'hwaddr') -> + case socket:ioctl(ESock, gifhwaddr, Name) of + {ok, #{family := _Fam, + addr := <> = _Addr}} -> + {ok, binary_to_list(HWADDRBin)}; + {error, _} = ERROR -> + ERROR + end. + + -doc false. -spec ifget( Name :: string() | atom(), - Opts :: [if_getopt() | + Opts :: [inet_backend() | + if_getopt() | {netns, Namespace :: file:filename_all()}]) -> {'ok', [if_getopt_result()]} | {'error', posix()}. +ifget(Name, [{inet_backend, Backend}|Opts]) -> + do_ifget(Backend, Name, Opts); ifget(Name, Opts) -> - {NSOpts,IFOpts} = + do_ifget(inet_backend(), Name, Opts). + +do_ifget(Backend, Name, Opts) -> + {NSOpts, IFOpts} = lists:partition( fun ({netns,_}) -> true; (_) -> false end, Opts), - withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts). + withsocket(fun(S) -> + do_ifget(Backend, S, Name, IFOpts) + end, + Backend, NSOpts). + +%% ifget(Name, Opts) -> +%% {NSOpts,IFOpts} = +%% lists:partition( +%% fun ({netns,_}) -> true; +%% (_) -> false +%% end, Opts), +%% withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts). + + + +%% -------------------------------------------------------------------------- -doc false. -spec ifset(Socket :: socket(), @@ -1973,9 +2049,57 @@ ifget(Name, Opts) -> Opts :: [if_setopt()]) -> 'ok' | {'error', posix()}. -ifset(Socket, Name, Opts) -> +%% ifset(Socket, Name, Opts) -> +%% prim_inet:ifset(Socket, Name, Opts). + +ifset(?module_socket(GenSocketMod, ESock) = _Socket, Name, Opts) + when is_atom(GenSocketMod) -> + do_ifset('socket', ESock, Name, Opts); +ifset(Socket, Name, Opts) when is_port(Socket) -> + do_ifset('inet', Socket, Name, Opts). + +do_ifset('socket', Socket, Name, Opts) -> + esock_ifset(Socket, Name, Opts); +do_ifset('inet', Socket, Name, Opts) -> prim_inet:ifset(Socket, Name, Opts). +esock_ifset(_Socket, _Name, [] = _Opts) -> + ok; +esock_ifset(Socket, Name, [{Req, Value}|Opts]) -> + case do_esock_ifset(Socket, Name, Req, Value) of + ok -> + esock_ifset(Socket, Name, Opts); + {error, _} = ERROR -> + ERROR + end. + +do_esock_ifset(Socket, Name, 'addr' = _Req, Addr) -> + do_esock_ifset2(Socket, sifaddr, Name, Addr); +do_esock_ifset(Socket, Name, 'broadaddr' = _Req, Addr) -> + do_esock_ifset2(Socket, sifbrdaddr, Name, Addr); +do_esock_ifset(Socket, Name, 'dstdaddr' = _Req, Addr) -> + do_esock_ifset2(Socket, sifdstaddr, Name, Addr); +do_esock_ifset(Socket, Name, 'mtu' = _Req, MTU) -> + do_esock_ifset2(Socket, sifmtu, Name, MTU); +do_esock_ifset(Socket, Name, 'netmask' = _Req, Addr) -> + do_esock_ifset2(Socket, sifnetmask, Name, Addr); +do_esock_ifset(Socket, Name, 'flags' = _Req, Flags) -> + do_esock_ifset2(Socket, sifflags, Name, Flags); +do_esock_ifset(Socket, Name, 'hwaddr' = _Req, Addr) -> + do_esock_ifset2(Socket, sifhwaddr, Name, Addr). + +do_esock_ifset2(Socket, Name, Req, Value) -> + try socket:ioctl(Socket, Req, Name, Value) of + ok -> + ok; + {error, _} = ERROR -> % This is "einval" stuff... + ERROR + catch + error:notsup -> % These are siently ignored + ok + end. + + -doc false. -spec ifset( Name :: string() | atom(), @@ -1983,13 +2107,32 @@ ifset(Socket, Name, Opts) -> {netns, Namespace :: file:filename_all()}]) -> 'ok' | {'error', posix()}. +ifset(Name, [{inet_backend, Backend}|Opts]) -> + do_ifset(Backend, Name, Opts); ifset(Name, Opts) -> - {NSOpts,IFOpts} = + do_ifset(inet_backend(), Name, Opts). + +do_ifset(Backend, Name, Opts) -> + {NSOpts, IFOpts} = lists:partition( fun ({netns,_}) -> true; (_) -> false end, Opts), - withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts). + withsocket(fun(S) -> + do_ifset(Backend, S, Name, IFOpts) + end, + Backend, NSOpts). + +%% ifset(Name, Opts) -> +%% {NSOpts,IFOpts} = +%% lists:partition( +%% fun ({netns,_}) -> true; +%% (_) -> false +%% end, Opts), +%% withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts). + + +%% -------------------------------------------------------------------------- -doc false. -spec getif() -> @@ -2032,15 +2175,43 @@ withsocket(Fun) -> withsocket(Fun, []). %% withsocket(Fun, Opts) -> + inet_withsocket(Fun, Opts). + + +withsocket(Fun, 'socket', Opts) -> + esock_withsocket(Fun, Opts); +withsocket(Fun, 'inet', Opts) -> + inet_withsocket(Fun, Opts). + +esock_withsocket(Fun, Opts) -> + EOpts = + case Opts of + [{netns, Namespace}] -> + #{netns => Namespace}; + [] -> + #{} + end, + case socket:open(inet, dgram, default, EOpts) of + {ok, Socket} -> + Res = Fun(Socket), + socket:close(Socket), + Res; + {error, _} = ERROR -> + ERROR + end. + +inet_withsocket(Fun, Opts) -> case inet_udp:open(0, Opts) of - {ok,Socket} -> - Res = Fun(Socket), - inet_udp:close(Socket), - Res; - Error -> - Error + {ok,Socket} -> + Res = Fun(Socket), + inet_udp:close(Socket), + Res; + Error -> + Error end. + + -doc false. pushf(_Socket, Fun, _State) when is_function(Fun) -> {error, einval}. diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl index 57e319f907bd..5b1c189ec131 100644 --- a/lib/kernel/src/socket.erl +++ b/lib/kernel/src/socket.erl @@ -6457,11 +6457,14 @@ These operations require elevated privileges. point-to-point interface with the specified name. - **`sifbrdaddr`** - Set the broadcast address, `t:sockaddr/0`, - of the interface with the specified name. +of the interface with the specified name. - **`sifnetmask`** - Set the network mask, `t:sockaddr/0`, of the interface with the specified name. +- **`sifhwaddr`** - Set the hardware address, `t:sockaddr/0`, +of the interface with the specified name. + - **`sifmtu`** - Set the MTU (Maximum Transfer Unit), `t:integer/0`, for the interface with the specified name. @@ -6473,7 +6476,7 @@ These operations require elevated privileges. SetRequest :: 'sifflags' | 'sifaddr' | 'sifdstaddr' | 'sifbrdaddr' | 'sifnetmask' | 'sifhwaddr' | - 'gifmtu' | 'siftxqlen', + 'sifmtu' | 'siftxqlen', Name :: string(), Value :: term(), Reason :: posix() | 'closed'. @@ -6493,6 +6496,9 @@ ioctl(?socket(SockRef), sifbrdaddr = SetRequest, Name, BrdAddr) ioctl(?socket(SockRef), sifnetmask = SetRequest, Name, NetMask) when is_list(Name) andalso is_map(NetMask) -> prim_socket:ioctl(SockRef, SetRequest, Name, prim_socket:enc_sockaddr(NetMask)); +ioctl(?socket(SockRef), sifhwaddr = SetRequest, Name, HWAddr) + when is_list(Name) andalso is_map(HWAddr) -> + prim_socket:ioctl(SockRef, SetRequest, Name, prim_socket:enc_sockaddr(HWAddr)); ioctl(?socket(SockRef), sifmtu = SetRequest, Name, MTU) when is_list(Name) andalso is_integer(MTU) -> prim_socket:ioctl(SockRef, SetRequest, Name, MTU); diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 3aba39a51562..a0e948b9a8dd 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1536,41 +1536,65 @@ lookup_bad_search_option(Config) when is_list(Config) -> getif(Config) when is_list(Config) -> case os:type() of {unix,Osname} -> - do_getif(Osname); + do_getif(Osname, default), + do_getif(Osname, inet), + do_getif(Osname, socket); {_,_} -> {skip,"inet:getif/0 probably not supported"} end. -do_getif(Osname) -> - {ok,Hostname} = inet:gethostname(), - {ok,Address} = inet:getaddr(Hostname, inet), - {ok,Loopback} = inet:getaddr("localhost", inet), - {ok,Interfaces} = inet:getiflist(), +inet_getiflist(default) -> + inet:getiflist(); +inet_getiflist(Backend) -> + inet:getiflist([{inet_backend, Backend}]). + +inet_ifget(default, Name, Opts) -> + inet:ifget(Name, Opts); +inet_ifget(Backend, Name, Opts) -> + inet:ifget(Name, [{inet_backend, Backend}|Opts]). + + +do_getif(OsName, Backend) -> + io:format("~w(~w) -> entry with" + "~n OsName: ~p" + "~n", [?FUNCTION_NAME, Backend, OsName]), + {ok, Hostname} = inet:gethostname(), + {ok, Address} = inet:getaddr(Hostname, inet), + {ok, Loopback} = inet:getaddr("localhost", inet), + {ok, Interfaces} = inet_getiflist(Backend), HWAs = lists:sort( lists:foldl( fun (I, Acc) -> - case inet:ifget(I, [hwaddr]) of + case inet_ifget(Backend, I, [hwaddr]) of {ok,[{hwaddr,A}]} -> [A|Acc]; {ok,[]} -> Acc end end, [], Interfaces)), - io:format("HWAs = ~p~n", [HWAs]), - (Osname =/= sunos) + io:format("~w(~w) -> " + "~n HW Addrs:" + "~n ~p" + "~n", [?FUNCTION_NAME, Backend, HWAs]), + (OsName =/= sunos) andalso ((length(HWAs) > 0) orelse (ct:fail(no_HWAs))), Addresses = lists:sort( lists:foldl( fun (I, Acc) -> - case inet:ifget(I, [addr]) of - {ok,[{addr,A}]} -> [A|Acc]; - {ok,[]} -> Acc + case inet_ifget(Backend, I, [addr]) of + {ok, [{addr,A}]} -> [A|Acc]; + {ok, []} -> Acc end end, [], Interfaces)), + io:format("~w(~w) -> " + "~n Addresses: " + "~n ~p" + "~n", [?FUNCTION_NAME, Backend, Addresses]), {ok,Getif} = inet:getif(), Addresses = lists:sort([A || {A,_,_} <- Getif]), true = ip_member(Address, Addresses), true = ip_member(Loopback, Addresses), + io:format("~w(~w) -> done~n", [?FUNCTION_NAME, Backend]), ok. %% Test long interface names do not overrun buffer. From 67bdc4f74a0275d8b2e151e09004e256f371c0d7 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 26 Jun 2024 08:26:34 +0200 Subject: [PATCH 15/37] [kernel] Fixed socket ioctl use and getif with inet-backend OTP-18132 --- lib/kernel/src/inet.erl | 88 ++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index ce4dd4512c3c..f826a0db0914 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -2074,19 +2074,19 @@ esock_ifset(Socket, Name, [{Req, Value}|Opts]) -> end. do_esock_ifset(Socket, Name, 'addr' = _Req, Addr) -> - do_esock_ifset2(Socket, sifaddr, Name, Addr); + do_esock_ifset2(Socket, Name, sifaddr, Addr); do_esock_ifset(Socket, Name, 'broadaddr' = _Req, Addr) -> - do_esock_ifset2(Socket, sifbrdaddr, Name, Addr); + do_esock_ifset2(Socket, Name, sifbrdaddr, Addr); do_esock_ifset(Socket, Name, 'dstdaddr' = _Req, Addr) -> - do_esock_ifset2(Socket, sifdstaddr, Name, Addr); + do_esock_ifset2(Socket, Name, sifdstaddr, Addr); do_esock_ifset(Socket, Name, 'mtu' = _Req, MTU) -> - do_esock_ifset2(Socket, sifmtu, Name, MTU); + do_esock_ifset2(Socket, Name, sifmtu, MTU); do_esock_ifset(Socket, Name, 'netmask' = _Req, Addr) -> - do_esock_ifset2(Socket, sifnetmask, Name, Addr); + do_esock_ifset2(Socket, Name, sifnetmask, Addr); do_esock_ifset(Socket, Name, 'flags' = _Req, Flags) -> - do_esock_ifset2(Socket, sifflags, Name, Flags); + do_esock_ifset2(Socket, Name, sifflags, Flags); do_esock_ifset(Socket, Name, 'hwaddr' = _Req, Addr) -> - do_esock_ifset2(Socket, sifhwaddr, Name, Addr). + do_esock_ifset2(Socket, Name, sifhwaddr, Addr). do_esock_ifset2(Socket, Name, Req, Value) -> try socket:ioctl(Socket, Req, Name, Value) of @@ -2140,7 +2140,7 @@ do_ifset(Backend, Name, Opts) -> {'error', posix()}. getif() -> - withsocket(fun(S) -> getif(S) end). + withsocket(fun(S) -> getif(S) end, inet_backend(), []). %% backwards compatible getif -doc false. @@ -2150,27 +2150,60 @@ getif() -> {'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | {'error', posix()}. +getif([{inet_backend, Backend}|Opts]) -> + withsocket(fun(S) -> getif(Backend, S) end, Backend, Opts); getif(Opts) when is_list(Opts) -> - withsocket(fun(S) -> getif(S) end, Opts); -getif(Socket) -> - case prim_inet:getiflist(Socket) of - {ok, IfList} -> - {ok, lists:foldl( - fun(Name,Acc) -> - case prim_inet:ifget(Socket,Name, - [addr,broadaddr,netmask]) of - {ok,[{addr,A},{broadaddr,B},{netmask,M}]} -> - [{A,B,M}|Acc]; - %% Some interfaces does not have a b-addr + Backend = inet_backend(), + withsocket(fun(S) -> getif(Backend, S) end, Backend, Opts); +getif(?module_socket(GenSocketMod, ESock) = _Socket) + when is_atom(GenSocketMod) -> + getif('socket', ESock); +getif(Socket) when is_port(Socket) -> + getif('inet', Socket). + + +getif('socket', Socket) -> + net_getif(Socket); +getif('inet', Socket) -> + inet_getif(Socket). + +net_getif(Socket) -> + GetIfList = fun() -> net_getiflist(Socket) end, + IfGet = fun(Name) -> + esock_ifget(Socket, Name, + [addr, broadaddr, netmask]) + end, + do_getif(GetIfList, IfGet). + +inet_getif(Socket) -> + GetIfList = fun() -> inet_getiflist(Socket) end, + IfGet = fun(Name) -> + prim_inet:ifget(Socket, Name, + [addr, broadaddr, netmask]) + end, + do_getif(GetIfList, IfGet). + +do_getif(GetIfList, IfGet) -> + case GetIfList() of + {ok, IfList} -> + {ok, lists:foldl( + fun(Name,Acc) -> + case IfGet(Name) of + {ok, [{addr, A}, {broadaddr, B}, {netmask,M}]} -> + [{A, B, M}|Acc]; + %% Some interfaces does not have a b-addr {ok,[{addr,A},{netmask,M}]} -> [{A,undefined,M}|Acc]; - _ -> - Acc - end - end, [], IfList)}; - Error -> Error + _ -> + Acc + end + end, [], IfList)}; + Error -> Error end. + +%% -------------------------------------------------------------------------- + withsocket(Fun) -> withsocket(Fun, []). %% @@ -2654,13 +2687,6 @@ getservbyport(Port, Protocol) -> end. inet_getservbyport(Port, Protocol) -> - %% case inet_udp:open(0, []) of - %% {ok,U} -> - %% Res = prim_inet:getservbyport(U, Port, Protocol), - %% inet_udp:close(U), - %% Res; - %% Error -> Error - %% end. withsocket(fun(S) -> prim_inet:getservbyport(S, Port, Protocol) end). net_getservbyport(Port, Protocol) when is_list(Protocol) -> From d7606c294ef507786219dafe4ac192906ef2d0c1 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 26 Jun 2024 08:29:54 +0200 Subject: [PATCH 16/37] [kernel|test] Tweaked getif test case Use inet:getif/1 with (inet-) backend. OTP-19132 --- lib/kernel/test/inet_SUITE.erl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index a0e948b9a8dd..0e25e1f95a71 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1553,13 +1553,18 @@ inet_ifget(default, Name, Opts) -> inet_ifget(Backend, Name, Opts) -> inet:ifget(Name, [{inet_backend, Backend}|Opts]). +inet_getif(default) -> + inet:getif(); +inet_getif(Backend) -> + inet:getif([{inet_backend, Backend}]). + do_getif(OsName, Backend) -> io:format("~w(~w) -> entry with" "~n OsName: ~p" "~n", [?FUNCTION_NAME, Backend, OsName]), {ok, Hostname} = inet:gethostname(), - {ok, Address} = inet:getaddr(Hostname, inet), + {ok, Address} = inet:getaddr(Hostname, inet), {ok, Loopback} = inet:getaddr("localhost", inet), {ok, Interfaces} = inet_getiflist(Backend), HWAs = @@ -1590,7 +1595,7 @@ do_getif(OsName, Backend) -> "~n Addresses: " "~n ~p" "~n", [?FUNCTION_NAME, Backend, Addresses]), - {ok,Getif} = inet:getif(), + {ok,Getif} = inet_getif(Backend), Addresses = lists:sort([A || {A,_,_} <- Getif]), true = ip_member(Address, Addresses), true = ip_member(Loopback, Addresses), From ccef098a8ea8e0567d3157753ae7645696c5231c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 26 Jun 2024 08:42:20 +0200 Subject: [PATCH 17/37] [kernel] Diamyzer fixes OTP-19132 --- lib/kernel/src/inet.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index f826a0db0914..e119ae9657e7 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -2227,7 +2227,7 @@ esock_withsocket(Fun, Opts) -> case socket:open(inet, dgram, default, EOpts) of {ok, Socket} -> Res = Fun(Socket), - socket:close(Socket), + _ = socket:close(Socket), Res; {error, _} = ERROR -> ERROR From d891c38ccaa7617ffe3df603e80e1001e0c28d4b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 26 Jun 2024 14:51:12 +0200 Subject: [PATCH 18/37] [kernel] Update inet:send/2 and inet:gethostname/0,1 Make these functions handle socket backend. --- lib/kernel/src/inet.erl | 54 ++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index e119ae9657e7..b57fa6c57064 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -912,6 +912,9 @@ port(Socket) -> -spec send(Socket :: socket(), Packet :: iolist()) -> % iolist()? 'ok' | {'error', posix()}. +send(?module_socket(GenSocketMod, _) = Socket, Packet) + when is_atom(GenSocketMod) -> + GenSocketMod:?FUNCTION_NAME(Socket, Packet); send(Socket, Packet) -> prim_inet:send(Socket, Packet). @@ -2031,15 +2034,6 @@ do_ifget(Backend, Name, Opts) -> end, Backend, NSOpts). -%% ifget(Name, Opts) -> -%% {NSOpts,IFOpts} = -%% lists:partition( -%% fun ({netns,_}) -> true; -%% (_) -> false -%% end, Opts), -%% withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts). - - %% -------------------------------------------------------------------------- @@ -2049,9 +2043,6 @@ do_ifget(Backend, Name, Opts) -> Opts :: [if_setopt()]) -> 'ok' | {'error', posix()}. -%% ifset(Socket, Name, Opts) -> -%% prim_inet:ifset(Socket, Name, Opts). - ifset(?module_socket(GenSocketMod, ESock) = _Socket, Name, Opts) when is_atom(GenSocketMod) -> do_ifset('socket', ESock, Name, Opts); @@ -2103,7 +2094,8 @@ do_esock_ifset2(Socket, Name, Req, Value) -> -doc false. -spec ifset( Name :: string() | atom(), - Opts :: [if_setopt() | + Opts :: [inet_backend() | + if_setopt() | {netns, Namespace :: file:filename_all()}]) -> 'ok' | {'error', posix()}. @@ -2123,14 +2115,6 @@ do_ifset(Backend, Name, Opts) -> end, Backend, NSOpts). -%% ifset(Name, Opts) -> -%% {NSOpts,IFOpts} = -%% lists:partition( -%% fun ({netns,_}) -> true; -%% (_) -> false -%% end, Opts), -%% withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts). - %% -------------------------------------------------------------------------- @@ -2145,7 +2129,7 @@ getif() -> %% backwards compatible getif -doc false. -spec getif( - [Option :: {netns, Namespace :: file:filename_all()}] + [Option :: inet_backend() | {netns, Namespace :: file:filename_all()}] | socket()) -> {'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} | {'error', posix()}. @@ -2254,6 +2238,8 @@ popf(_Socket) -> {error, einval}. +%% -------------------------------------------------------------------------- + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % the hostname is not cached any more because this % could cause troubles on at least windows with plug-and-play @@ -2272,6 +2258,18 @@ Returns the local hostname. Never fails. %%% XXX gethostname() -> net:gethostname(). gethostname() -> + do_gethostname(inet_backend()). + +do_gethostname('socket') -> + case net:gethostname() of + {ok, Hostname} -> + %% If its a long name (including domain), shorten to only name + {H,_} = lists:splitwith(fun($.)->false;(_)->true end, Hostname), + {ok, H}; + {error, _} -> + {ok, "nohost.nodomain"} + end; +do_gethostname('inet') -> case inet_udp:open(0,[]) of {ok,U} -> {ok,Res} = gethostname(U), @@ -2286,9 +2284,18 @@ gethostname() -> -spec gethostname(Socket :: socket()) -> {'ok', string()} | {'error', posix()}. +%% The esock version of should never really be called. Its supposed to +%% be a utility function for gethostname/0. But just in case... +gethostname(?module_socket(GenSocketMod, _) = _Socket) + when is_atom(GenSocketMod) -> + %% We do not really need the socket for anything... + net:gethostname(); gethostname(Socket) -> prim_inet:gethostname(Socket). + +%% -------------------------------------------------------------------------- + -doc(#{equiv => getstat/2}). -spec getstat(Socket) -> {ok, OptionValues} | {error, posix()} when @@ -2339,6 +2346,9 @@ getstat(?module_socket(GenSocketMod, _) = Socket, What) getstat(Socket, What) -> prim_inet:getstat(Socket, What). + +%% -------------------------------------------------------------------------- + -doc """ Resolve a hostname to a [`#hostent{}`](`t:hostent/0`) record. From 88c3b7039d6a0d4a9962e8b143fe5e1c166bed5e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 26 Jun 2024 15:42:31 +0200 Subject: [PATCH 19/37] [kernel] Update inet:getfd/1 OTP-19132 --- lib/kernel/src/inet.erl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index b57fa6c57064..74357dca909a 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -2608,6 +2608,9 @@ getll(Socket) when is_port(Socket) -> -spec getfd(Socket :: socket()) -> {'ok', non_neg_integer()} | {'error', posix()}. +getfd(?module_socket(GenSocketMod, ESock) = _Socket) + when is_atom(GenSocketMod) -> + socket:getopt(ESock, otp, fd); getfd(Socket) -> prim_inet:getfd(Socket). From 7e346c38e0e67979e487aefde13682c2e48d92ef Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 26 Jun 2024 15:58:18 +0200 Subject: [PATCH 20/37] [kernel] Cleanup --- lib/kernel/src/inet.erl | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 74357dca909a..69014c32fe08 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -2723,13 +2723,6 @@ getservbyname(Name, Protocol) when is_list(Name) -> end. inet_getservbyname(Name, Protocol) -> - %% case inet_udp:open(0, []) of - %% {ok, U} -> - %% Res = prim_inet:getservbyname(U, Name, Protocol), - %% inet_udp:close(U), - %% Res; - %% Error -> Error - %% end. withsocket(fun(S) -> prim_inet:getservbyname(S, Name, Protocol) end). net_getservbyname(Name, Protocol) when is_list(Protocol) -> @@ -3840,7 +3833,6 @@ open_opts(Fd_or_OpenOpts, BAddr, BPort, Opts, Protocol, Family, Type, Module) -> %% open_setopts(S, BAddr, BPort, Opts, Module) -> %% ?DBG([{s, S}, {baddr, BAddr}, {bport, BPort}, {opts, Opts}, {mod, Module}]), - %% ok = prim_inet:setopts(S, [{debug, true}]), case prim_inet:setopts(S, Opts) of ok when BAddr =:= undefined -> %% ?DBG("ok -> register socket"), From f8653346fe638fbddbb18bbff5796b8467e415b1 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 2 Jul 2024 13:00:26 +0200 Subject: [PATCH 21/37] [esock] Fixed undef macro on Windows OTP-19132 --- erts/emulator/nifs/common/socket_util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index ba5791783347..81aa018ce3f2 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -742,7 +742,7 @@ BOOLEAN_T esock_decode_hwsockaddr(ErlNifEnv* env, SOCKLEN_T* addrLen) { ERL_NIF_TERM efamily; - int family = ARPHRD_VOID; + int family = -1; if (!IS_MAP(env, eSockAddr)) return FALSE; @@ -807,6 +807,8 @@ BOOLEAN_T esock_decode_hwsockaddr(ErlNifEnv* env, } #endif + if (family == -1) + return FALSE; return esock_decode_sockaddr_native(env, eSockAddr, sockAddrP, family, addrLen); From 5be10226b4bab955507aef3d12f892685dc98e1b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 3 Jul 2024 10:09:46 +0200 Subject: [PATCH 22/37] [kernel|test] Tweaked getifaddrs test case --- lib/kernel/test/inet_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 3aba39a51562..6e421c65475b 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1857,7 +1857,7 @@ getifaddrs_verify_backend(IF, I_INFO, S_INFO) -> %% Happens on windows io:format("flags for ~p *acceptably* " "different~n", [IF]), - IR1, SR1; + {IR1, SR1}; _ -> ct:fail(ifaddrs_not_equal) end; From f1d46ed85bc3603d6e6731f4374523a0e31947b0 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 3 Jul 2024 12:54:01 +0200 Subject: [PATCH 23/37] [kernal|test] Tweaked getifaddrs test case OTP-19132 --- lib/kernel/test/inet_SUITE.erl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 6e421c65475b..0801e53fdcfd 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1846,7 +1846,7 @@ getifaddrs_verify_backend(IF, I_INFO, S_INFO) -> {IR1, SR1}; {[], [multicast]} -> io:format("flags for ~p are *not* equal - " - "extra multicast: " + "extra flag 'multicast': " "~n INET: ~p" "~n SOCKET: ~p" "~n", [IF, I_FLAGS, S_FLAGS]), @@ -1861,6 +1861,23 @@ getifaddrs_verify_backend(IF, I_INFO, S_INFO) -> _ -> ct:fail(ifaddrs_not_equal) end; + {[], [running]} -> + io:format("flags for ~p are *not* equal - " + "extra flag 'running': " + "~n INET: ~p" + "~n SOCKET: ~p" + "~n", [IF, I_FLAGS, S_FLAGS]), + case lists:member(up, I_FLAGS) of + true -> + %% The net module getifaddrs contains + %% some more flags... + %% Happens on windows + io:format("flags for ~p *acceptably* " + "different~n", [IF]), + {IR1, SR1}; + _ -> + ct:fail(ifaddrs_not_equal) + end; {IRem, SRem} -> io:format("flags for ~p are *not* equal - check flags: " "~n INET: ~p" From d0536e47b17658e63a1fbf9c060bdeb8c2305fa9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Jul 2024 10:36:29 +0200 Subject: [PATCH 24/37] [kernel|net] Add 'link' filter for getifaddrs --- lib/kernel/src/net.erl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl index 1cdc4ae3f160..e6ef80d4db5a 100644 --- a/lib/kernel/src/net.erl +++ b/lib/kernel/src/net.erl @@ -421,6 +421,8 @@ getifaddrs_filter_map(inet6) -> getifaddrs_filter_map_inet6(); getifaddrs_filter_map(packet) -> getifaddrs_filter_map_packet(); +getifaddrs_filter_map(link) -> + getifaddrs_filter_map_link(); getifaddrs_filter_map(FilterMap) when is_map(FilterMap) -> maps:merge(getifaddrs_filter_map_default(), FilterMap). @@ -439,6 +441,9 @@ getifaddrs_filter_map_inet6() -> getifaddrs_filter_map_packet() -> #{family => packet, flags => any}. +getifaddrs_filter_map_link() -> + #{family => link, flags => any}. + -compile({nowarn_unused_function, getifaddrs_filter/2}). getifaddrs_filter(#{family := FFamily, flags := FFlags}, From 0f9ce440c58b9f58d7873f4930746d38b51e79c3 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Jul 2024 10:44:03 +0200 Subject: [PATCH 25/37] [kernel] Tweaked ifget OTP-19132 --- lib/kernel/src/inet.erl | 95 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 7 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 69014c32fe08..d6930794be12 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1964,10 +1964,15 @@ esock_ifget(ESock, Name, [Opt|Opts], Acc) -> case do_esock_ifget(ESock, Name, Opt) of {ok, Value} -> esock_ifget(ESock, Name, Opts, [{Opt, Value}|Acc]); - {error, _} = ERROR -> - ERROR + {error, _} -> + esock_ifget(ESock, Name, Opts, Acc) end. +%% We should really check if these ioctl get requests are supported: +%% socket:is_supported(ioctl_requests, Req). +%% But since the error will just result in a missing result value +%% anyway (which the user needs to handle), unless there is some +%% alternative method (see hwaddr) we just return it... do_esock_ifget(ESock, Name, 'addr') -> case socket:ioctl(ESock, gifaddr, Name) of {ok, #{addr := Addr}} -> @@ -2001,14 +2006,90 @@ do_esock_ifget(ESock, Name, 'netmask') -> do_esock_ifget(ESock, Name, 'flags') -> socket:ioctl(ESock, gifflags, Name); do_esock_ifget(ESock, Name, 'hwaddr') -> - case socket:ioctl(ESock, gifhwaddr, Name) of - {ok, #{family := _Fam, - addr := <> = _Addr}} -> - {ok, binary_to_list(HWADDRBin)}; + case use_ioctl_for_hwaddr() of + {ok, Req} -> + case socket:ioctl(ESock, Req, Name) of + {ok, #{family := _Fam, + addr := <> = _Addr}} -> + {ok, binary_to_list(HWADDRBin)}; + {error, _} -> + %% Last effort... + hwaddr_from_net_getifaddrs(Name) + end; + error -> + %% Try getifaddrs instead + hwaddr_from_net_getifaddrs(Name) + end. + +use_ioctl_for_hwaddr() -> + case socket:is_supported(ioctl_requests, gifhwaddr) of + true -> + {ok, gifhwaddr}; + false -> + case socket:is_supported(ioctl_requests, genhwaddr) of + true -> + {ok, genhwaddr}; + false -> + error + end + end. + +hwaddr_from_net_getifaddrs(Name) -> + %% Platforms "use" different Family. + %% FreeBSD use 'link', Linux use 'packet'. + Filter = fun(#{name := IF, + addr := #{family := Fam}}) + when (IF =:= Name) andalso + ((Fam =:= link) orelse (Fam =:= packet)) -> + %% io:format("+ right interface and family~n", []), + true; + (#{name := IF, + addr := #{family := _Fam}}) + when (IF =:= Name) -> + %% io:format("- right interface but wrong family: " + %% "~n Fam: ~p (link|packet)" + %% "~n", [_Fam]), + false; + (#{name := _IF, + addr := #{family := Fam}}) + when ((Fam =:= link) orelse (Fam =:= packet)) -> + %% io:format("- right family but wrong interface" + %% "~n IF: ~p (~p)" + %% "~n", [_IF, Name]), + false; + (#{name := _IF, + addr := #{family := _Fam}}) -> + %% io:format("- wrong interface and family: " + %% "~n IF: ~p (~p)" + %% "~n Fam: ~p (link|packet)" + %% "~n", [_IF, Name, _Fam]), + false; + (_X) -> + %% io:format("- just plain wrong: " + %% "~n X: ~p" + %% "~n", [_X]), + false + end, + case net:getifaddrs(Filter) of + {ok, [#{addr := #{family := packet, + addr := HwAddrBin}}|_]} -> + {ok, binary_to_list(HwAddrBin)}; + {ok, [#{addr := #{family := link, + nlen := NLen, + alen := ALen, + data := Data}}|_]} -> + case Data of + <<_:NLen/binary, ABin:ALen/binary, _/binary>> -> + {ok, binary_to_list(ABin)}; + _ -> %% Ouch - what is this? malformed data? + {error, unknown} + end; + {ok, _} -> %% Ouch - we got something but don't know how to decode it + {error, unknown}; {error, _} = ERROR -> ERROR end. - + -doc false. -spec ifget( From 2e9c75466b3bcf66b23069d6fb815076bcf9eeb9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Jul 2024 11:41:02 +0200 Subject: [PATCH 26/37] [kernel|net] Update filters for getifaddrs/1 OTP-19132 --- lib/kernel/src/net.erl | 62 ++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl index e6ef80d4db5a..f063badd1e15 100644 --- a/lib/kernel/src/net.erl +++ b/lib/kernel/src/net.erl @@ -113,10 +113,12 @@ Interface address filtering selector. - **default** - Interfaces with address family `inet` _or_ `inet6` -- **inet | inet6 | packet** - Interfaces with _only_ the specified address +- **inet | inet6 | packet| link** - Interfaces with _only_ the specified address family +- **hwaddr** - Interfaces with address family `packet` _or_ `link` """. --type ifaddrs_filter() :: all | default | inet | inet6 | packet | +-type ifaddrs_filter() :: all | default | inet | inet6 | + packet | link | hwaddr | ifaddrs_filter_map() | ifaddrs_filter_fun(). @@ -423,6 +425,8 @@ getifaddrs_filter_map(packet) -> getifaddrs_filter_map_packet(); getifaddrs_filter_map(link) -> getifaddrs_filter_map_link(); +getifaddrs_filter_map(hwaddr) -> + getifaddrs_filter_map_hwaddr(); getifaddrs_filter_map(FilterMap) when is_map(FilterMap) -> maps:merge(getifaddrs_filter_map_default(), FilterMap). @@ -444,29 +448,45 @@ getifaddrs_filter_map_packet() -> getifaddrs_filter_map_link() -> #{family => link, flags => any}. +getifaddrs_filter_map_hwaddr() -> + #{family => [link,packet], flags => any}. + -compile({nowarn_unused_function, getifaddrs_filter/2}). -getifaddrs_filter(#{family := FFamily, flags := FFlags}, - #{addr := #{family := Family}, flags := Flags} = _Entry) +getifaddrs_filter(#{family := FFamily, flags := FFlags} = _FilterMap, + #{addr := #{family := EFamily}, flags := EFlags} = _Entry) when (FFamily =:= default) andalso - ((Family =:= inet) orelse (Family =:= inet6)) -> - getifaddrs_filter_flags(FFlags, Flags); -getifaddrs_filter(#{family := FFamily, flags := FFlags}, - #{addr := #{family := Family}, flags := Flags} = _Entry) - when (FFamily =:= inet) andalso (Family =:= inet) -> - getifaddrs_filter_flags(FFlags, Flags); -getifaddrs_filter(#{family := FFamily, flags := FFlags}, - #{addr := #{family := Family}, flags := Flags} = _Entry) - when (FFamily =:= inet6) andalso (Family =:= inet6) -> - getifaddrs_filter_flags(FFlags, Flags); -getifaddrs_filter(#{family := FFamily, flags := FFlags}, - #{addr := #{family := Family}, flags := Flags} = _Entry) - when (FFamily =:= packet) andalso (Family =:= packet) -> - getifaddrs_filter_flags(FFlags, Flags); -getifaddrs_filter(#{family := FFamily, flags := FFlags}, - #{flags := Flags} = _Entry) + ((EFamily =:= inet) orelse (EFamily =:= inet6)) -> + getifaddrs_filter_flags(FFlags, EFlags); +getifaddrs_filter(#{family := FFamily, flags := FFlags} = _FilterMap, + #{addr := #{family := EFamily}, flags := EFlags} = _Entry) + when (FFamily =:= inet) andalso (EFamily =:= inet) -> + getifaddrs_filter_flags(FFlags, EFlags); +getifaddrs_filter(#{family := FFamily, flags := FFlags} = _FilterMap, + #{addr := #{family := EFamily}, flags := EFlags} = _Entry) + when (FFamily =:= inet6) andalso (EFamily =:= inet6) -> + getifaddrs_filter_flags(FFlags, EFlags); +getifaddrs_filter(#{family := FFamily, flags := FFlags} = _FilterMap, + #{addr := #{family := EFamily}, flags := EFlags} = _Entry) + when (FFamily =:= packet) andalso (EFamily =:= packet) -> + getifaddrs_filter_flags(FFlags, EFlags); +getifaddrs_filter(#{family := FFamily, flags := FFlags} = _FilterMap, + #{addr := #{family := EFamily}, flags := EFlags} = _Entry) + when (FFamily =:= link) andalso (EFamily =:= link) -> + getifaddrs_filter_flags(FFlags, EFlags); +getifaddrs_filter(#{family := FFamily, flags := FFlags} = _FilterMap, + #{flags := EFlags} = _Entry) when (FFamily =:= all) -> - getifaddrs_filter_flags(FFlags, Flags); + getifaddrs_filter_flags(FFlags, EFlags); +getifaddrs_filter(#{family := FFams, flags := FFlags} = _FilterMap, + #{addr := #{family := EFamily}, flags := EFlags} = _Entry) + when is_list(FFams) -> + case lists:member(EFamily, FFams) of + true -> + getifaddrs_filter_flags(FFlags, EFlags); + false -> + false + end; getifaddrs_filter(_Filter, _Entry) -> false. From f8b3ba6ed6d7b1dd1fabc83a76c6782b4e7d4362 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Jul 2024 12:04:04 +0200 Subject: [PATCH 27/37] [kernel|net] More filter tweaks for getifaddrs/1 OTP-19132 --- lib/kernel/src/net.erl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl index f063badd1e15..2f3fe5c83dc7 100644 --- a/lib/kernel/src/net.erl +++ b/lib/kernel/src/net.erl @@ -113,8 +113,8 @@ Interface address filtering selector. - **default** - Interfaces with address family `inet` _or_ `inet6` -- **inet | inet6 | packet| link** - Interfaces with _only_ the specified address - family +- **inet | inet6 | packet | link** - Interfaces with _only_ the specified + address family - **hwaddr** - Interfaces with address family `packet` _or_ `link` """. -type ifaddrs_filter() :: all | default | inet | inet6 | @@ -127,6 +127,10 @@ Interface address filtering selector map. The `family` field can only have the (above) specified values (and not all the values of socket:domain()). +It can also be a list of values, to cover the situation when +any of the specified families are accepted. +For example, family can be set to `[inet,inet6]` if either `inet` or `inet6` +is accepted. The use of the `flags` field is that any flag provided must exist for the interface. @@ -135,8 +139,9 @@ For example, if `family` is set to `inet` and `flags` to `[broadcast, multicast]` only interfaces with address family `inet` and the flags `broadcast` and `multicast` will be listed. """. --type ifaddrs_filter_map() :: #{family := default | local | - inet | inet6 | packet | all, +-type ifaddrs_filter_map() :: #{family := all | default | + local | inet | inet6 | packet | link | + [local | inet | inet6 | packet | link], flags := any | [ifaddrs_flag()]}. -doc """ From 44b25ee98c3ba0a51e787177396555967a9eef0c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Jul 2024 12:17:08 +0200 Subject: [PATCH 28/37] [esock] Configure for enaddr OTP-19132 --- erts/config.h.in | 3 +++ erts/configure | 17 +++++++++++++++++ erts/configure.ac | 9 +++++++++ 3 files changed, 29 insertions(+) diff --git a/erts/config.h.in b/erts/config.h.in index f60ea628b459..733e18434043 100644 --- a/erts/config.h.in +++ b/erts/config.h.in @@ -93,6 +93,9 @@ /* Socket address dl length */ #undef ESOCK_SDL_LEN +/* Interface hwaddr supported */ +#undef ESOCK_USE_ENADDR + /* Use extended error info */ #undef ESOCK_USE_EXTENDED_ERROR_INFO diff --git a/erts/configure b/erts/configure index 798868db8631..022cfe67ac68 100755 --- a/erts/configure +++ b/erts/configure @@ -16659,6 +16659,23 @@ printf "%s\n" "#define ESOCK_USE_HWADDR /**/" >>confdefs.h fi +ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_enaddr" "ac_cv_member_struct_ifreq_ifr_enaddr" "#ifdef __WIN32__ + #else + #include + #endif + +" +if test "x$ac_cv_member_struct_ifreq_ifr_enaddr" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_ENADDR 1" >>confdefs.h + + +printf "%s\n" "#define ESOCK_USE_ENADDR /**/" >>confdefs.h + +fi + + ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_ifindex" "ac_cv_member_struct_ifreq_ifr_ifindex" "#ifdef __WIN32__ #else #include diff --git a/erts/configure.ac b/erts/configure.ac index 61f9fe48a5f7..5029ad096fed 100644 --- a/erts/configure.ac +++ b/erts/configure.ac @@ -1447,6 +1447,15 @@ AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], #endif ]) +AC_CHECK_MEMBERS([struct ifreq.ifr_enaddr], + [AC_DEFINE(ESOCK_USE_ENADDR, [], [Interface hwaddr supported])], + [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + AC_CHECK_MEMBERS([struct ifreq.ifr_ifindex], [AC_DEFINE(ESOCK_USE_IFINDEX, [], [Interface ifindex supported])], [], From a2b2ffa033bbdc657c7b4d3b32990c3cf3f4e79d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Jul 2024 13:23:45 +0200 Subject: [PATCH 29/37] [esock] Use enaddr OTP-19132 --- erts/emulator/nifs/common/prim_socket_nif.c | 3 +++ erts/emulator/nifs/unix/unix_socket_syncio.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index e19aa5133dd6..c147c07b2223 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -2360,6 +2360,7 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket') LOCAL_ATOM_DECL(exclude); \ LOCAL_ATOM_DECL(false); \ LOCAL_ATOM_DECL(frag_needed); \ + LOCAL_ATOM_DECL(genhwaddr); \ LOCAL_ATOM_DECL(gifaddr); \ LOCAL_ATOM_DECL(gifbrdaddr); \ LOCAL_ATOM_DECL(gifconf); \ @@ -4934,6 +4935,8 @@ ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env) #if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) requests = MKC(env, MKT2(env, atom_gifhwaddr, MKUL(env, SIOCGIFHWADDR)), requests); +#elif defined(SIOCGENADDR) && defined(ESOCK_USE_ENADDR) + requests = MKC(env, MKT2(env, atom_genaddr, MKUL(env, SIOCGENADDR)), requests); #endif #if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) diff --git a/erts/emulator/nifs/unix/unix_socket_syncio.c b/erts/emulator/nifs/unix/unix_socket_syncio.c index 411b7580f742..fdf6bd658fcc 100644 --- a/erts/emulator/nifs/unix/unix_socket_syncio.c +++ b/erts/emulator/nifs/unix/unix_socket_syncio.c @@ -4523,8 +4523,10 @@ IOCTL_GET_FUNCS2 /* *** essio_ioctl_gifhwaddr *** */ #if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) #define IOCTL_GIFHWADDR_FUNC3_DECL \ - IOCTL_GET_REQUEST3_DECL(gifhwaddr, SIOCGIFHWADDR, hwaddr, &ifreq.ifr_hwaddr) -#else + IOCTL_GET_REQUEST3_DECL(gifhwaddr, SIOCGIFHWADDR, hwaddr, &ifreq.ifr_hwaddr) +#elif defined(SIOCGENHWADDR) && defined(ESOCK_USE_ENADDR) +#define IOCTL_GIFHWADDR_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifhwaddr, SIOCGENHWADDR, hwaddr, &ifreq.ifr_enaddr) #define IOCTL_GIFHWADDR_FUNC3_DECL #endif @@ -5127,6 +5129,7 @@ BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, } +#if defined(SIOCSIFHWADDR) static BOOLEAN_T decode_ioctl_hwaddr(ErlNifEnv* env, ESockDescriptor* descP, @@ -5147,6 +5150,7 @@ BOOLEAN_T decode_ioctl_hwaddr(ErlNifEnv* env, return result; } +#endif /* #if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) */ From 5ae23227e228cac60c0e621ee36d9dc9c2d4ad01 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 5 Jul 2024 16:44:50 +0200 Subject: [PATCH 30/37] [esock] Add support for ioctl request gifenaddr OTP-19132 --- erts/emulator/nifs/unix/unix_socket_syncio.c | 62 +++++++++++--------- lib/kernel/src/socket.erl | 11 +++- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/erts/emulator/nifs/unix/unix_socket_syncio.c b/erts/emulator/nifs/unix/unix_socket_syncio.c index fdf6bd658fcc..e1950cfb6ade 100644 --- a/erts/emulator/nifs/unix/unix_socket_syncio.c +++ b/erts/emulator/nifs/unix/unix_socket_syncio.c @@ -517,6 +517,13 @@ static ERL_NIF_TERM essio_ioctl_gifname(ErlNifEnv* env, #define IOCTL_GIFHWADDR_FUNC3_DEF #endif +/* esock_ioctl_gifenaddr */ +#if defined(SIOCGENHWADDR) && defined(ESOCK_USE_ENADDR) +#define IOCTL_GIFENADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifenaddr) +#else +#define IOCTL_GIFENADDR_FUNC3_DEF +#endif + /* esock_ioctl_gifmap */ #if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) #define IOCTL_GIFMAP_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifmap) @@ -540,6 +547,7 @@ static ERL_NIF_TERM essio_ioctl_gifname(ErlNifEnv* env, IOCTL_GIFNETMASK_FUNC3_DEF; \ IOCTL_GIFMTU_FUNC3_DEF; \ IOCTL_GIFHWADDR_FUNC3_DEF; \ + IOCTL_GIFENADDR_FUNC3_DEF; \ IOCTL_GIFMAP_FUNC3_DEF; \ IOCTL_GIFTXQLEN_FUNC3_DEF; #define IOCTL_GET_FUNC3_DEF(F) \ @@ -642,7 +650,8 @@ static ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, ESockDescriptor* descP, struct ifmap* mapP); #endif -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) +#if (defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR)) || \ + (defined(SIOCGIFENADDR) && defined(ESOCK_USE_ENADDR)) static ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, ESockDescriptor* descP, struct sockaddr* addrP); @@ -4164,8 +4173,14 @@ ERL_NIF_TERM essio_ioctl3(ErlNifEnv* env, #if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) case SIOCGIFHWADDR: - return essio_ioctl_gifhwaddr(env, descP, arg); - break; + return essio_ioctl_gifhwaddr(env, descP, arg); + break; +#endif + +#if defined(SIOCGENHWADDR) && defined(ESOCK_USE_ENADDR) + case SIOCGIFENADDR: + return essio_ioctl_gifenaddr(env, descP, arg); + break; #endif #if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) @@ -4524,12 +4539,18 @@ IOCTL_GET_FUNCS2 #if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) #define IOCTL_GIFHWADDR_FUNC3_DECL \ IOCTL_GET_REQUEST3_DECL(gifhwaddr, SIOCGIFHWADDR, hwaddr, &ifreq.ifr_hwaddr) -#elif defined(SIOCGENHWADDR) && defined(ESOCK_USE_ENADDR) -#define IOCTL_GIFHWADDR_FUNC3_DECL \ - IOCTL_GET_REQUEST3_DECL(gifhwaddr, SIOCGENHWADDR, hwaddr, &ifreq.ifr_enaddr) +#else #define IOCTL_GIFHWADDR_FUNC3_DECL #endif +/* *** essio_ioctl_gifenaddr *** */ +#if defined(SIOCGENADDR) && defined(ESOCK_USE_ENADDR) +#define IOCTL_GIFENADDR_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifenaddr, SIOCGENENADDR, hwaddr, &ifreq.ifr_enaddr) +#else +#define IOCTL_GIFENADDR_FUNC3_DECL +#endif + /* *** essio_ioctl_gifmap *** */ #if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) #define IOCTL_GIFMAP_FUNC3_DECL \ @@ -4546,7 +4567,7 @@ IOCTL_GET_FUNCS2 #define IOCTL_GIFTXQLEN_FUNC3_DECL #endif -#define IOCTL_GET_FUNCS3 \ +#define IOCTL_GET_FUNCS3 \ IOCTL_GIFINDEX_FUNC3_DECL \ IOCTL_GIFFLAGS_FUNC3_DECL \ IOCTL_GIFADDR_FUNC3_DECL \ @@ -4555,6 +4576,7 @@ IOCTL_GET_FUNCS2 IOCTL_GIFNETMASK_FUNC3_DECL \ IOCTL_GIFMTU_FUNC3_DECL \ IOCTL_GIFHWADDR_FUNC3_DECL \ + IOCTL_GIFENADDR_FUNC3_DECL \ IOCTL_GIFMAP_FUNC3_DECL \ IOCTL_GIFTXQLEN_FUNC3_DECL @@ -5023,7 +5045,8 @@ ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, #endif -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) +#if (defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR)) || \ + (defined(SIOCGIFENADDR) && defined(ESOCK_USE_ENADDR)) static ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, ESockDescriptor* descP, @@ -5153,28 +5176,8 @@ BOOLEAN_T decode_ioctl_hwaddr(ErlNifEnv* env, #endif -/* #if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) */ -/* static */ -/* ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, */ -/* ESockDescriptor* descP, */ -/* struct sockaddr* addrP) */ -/* { */ -/* ERL_NIF_TERM eaddr; */ -/* SOCKLEN_T sz = sizeof(struct sockaddr); */ - -/* esock_encode_hwsockaddr(env, addrP, sz, &eaddr); */ - -/* SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_hwaddr -> done with" */ -/* "\r\n Sock Addr: %T" */ -/* "\r\n", eaddr) ); */ - -/* return esock_make_ok2(env, eaddr);; */ -/* } */ -/* #endif */ - - - +#if defined(SIOCSIFMTU) static BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, ESockDescriptor* descP, @@ -5195,6 +5198,7 @@ BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, return result; } +#endif #if defined(SIOCSIFTXQLEN) diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl index 5b1c189ec131..01957581250a 100644 --- a/lib/kernel/src/socket.erl +++ b/lib/kernel/src/socket.erl @@ -6131,11 +6131,12 @@ the `GetRequest` argument. > #### Note {: .info } > +> Not all requests are supported by all platforms. > To see if a ioctl request is supported on the current platform: > > ```erlang > Request = nread, -> {ok, true} = socket:is_supported(ioctl_requests, Request), +> true = socket:is_supported(ioctl_requests, Request), > : > ``` """. @@ -6252,6 +6253,7 @@ This function retrieves a specific parameter, according to one of the following `GetRequest` arguments. The third argument is the (lookup) "key", identifying the interface, for most requests the name of the interface as a `t:string/0`. +Also, see the note above. - **`gifname`** - Get the name of the interface with the specified index (`t:integer/0`). @@ -6281,7 +6283,7 @@ the name of the interface as a `t:string/0`. Result; the network mask of the interface, `t:sockaddr/0`. -- **`gifhwaddr`** - Get the hardware address for the interface with the +- **`gifhwaddr` | `gifenaddr`** - Get the hardware address for the interface with the specified name. Result; the hardware address of the interface, `t:sockaddr/0`. @@ -6362,7 +6364,7 @@ the `Value` for the request parameter *(since OTP 26.1)*. Socket :: socket(), GetRequest :: 'gifname' | 'gifindex' | 'gifaddr' | 'gifdstaddr' | 'gifbrdaddr' | - 'gifnetmask' | 'gifhwaddr' | + 'gifnetmask' | 'gifhwaddr' | 'gifhwaddr' | 'gifmtu' | 'giftxqlen' | 'gifflags' | 'tcp_info', NameOrIndex :: string() | integer(), @@ -6403,6 +6405,9 @@ ioctl(?socket(SockRef), gifmtu = GetRequest, Name) ioctl(?socket(SockRef), gifhwaddr = GetRequest, Name) when is_list(Name) -> prim_socket:ioctl(SockRef, GetRequest, Name); +ioctl(?socket(SockRef), gifenaddr = GetRequest, Name) + when is_list(Name) -> + prim_socket:ioctl(SockRef, GetRequest, Name); ioctl(?socket(SockRef), giftxqlen = GetRequest, Name) when is_list(Name) -> prim_socket:ioctl(SockRef, GetRequest, Name); From 3097191aaecf6fda49fee501daee779c536a4e1f Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 5 Jul 2024 17:22:47 +0200 Subject: [PATCH 31/37] [kernel|test] Tweaked inet test suite Handle that socket may not be supported. Also that ioctl requests maybe not supported. OTP-19132 --- lib/kernel/test/inet_SUITE.erl | 149 +++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 35 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 0e25e1f95a71..0ca2e3fa89ad 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1546,51 +1546,104 @@ getif(Config) when is_list(Config) -> inet_getiflist(default) -> inet:getiflist(); inet_getiflist(Backend) -> - inet:getiflist([{inet_backend, Backend}]). + Func = getiflist, + Fun = fun() -> inet:Func([{inet_backend, Backend}]) end, + backend_conditional_run(Backend, Func, Fun). + + +backend_conditional_run(default = Backend, Func, Fun) + when is_atom(Func) andalso + is_function(Fun, 0) -> + io:format("try '~w' ~w~n", [Backend, Func]), + Fun(); +backend_conditional_run(Backend, Func, Fun) + when ((Backend =:= inet) orelse (Backend =:= socket)) andalso + is_atom(Func) andalso + is_function(Fun, 0) -> + try is_supported_backend(Backend) of + true -> + io:format("try '~w' ~w~n", [Backend, Func]), + Fun(); + false -> + io:format("skip '~w' ~w: not supported~n", [Backend, Func]), + throw({skip, {Func, Backend, notsup}}) + catch + C:E:S -> + %% Assume its because we run in a 'noesock' (or similar) system... + io:format("skipping ~p: " + "~n (Error) Class: ~p" + "~n Error: ~p" + "~n Stack: ~p" + "~n", [Backend, C, E, S]), + throw({skip, {Func, Backend, C, E}}) + end. + inet_ifget(default, Name, Opts) -> inet:ifget(Name, Opts); inet_ifget(Backend, Name, Opts) -> - inet:ifget(Name, [{inet_backend, Backend}|Opts]). + Func = ifget, + Fun = fun() -> inet:Func(Name, [{inet_backend, Backend}|Opts]) end, + backend_conditional_run(Backend, Func, Fun). inet_getif(default) -> inet:getif(); inet_getif(Backend) -> - inet:getif([{inet_backend, Backend}]). - + Func = getif, + Fun = fun() -> inet:Func([{inet_backend, Backend}]) end, + backend_conditional_run(Backend, Func, Fun). + do_getif(OsName, Backend) -> io:format("~w(~w) -> entry with" "~n OsName: ~p" "~n", [?FUNCTION_NAME, Backend, OsName]), + try do_getif2(OsName, Backend) of + ok -> + io:format("~w(~w) -> success~n", [?FUNCTION_NAME, Backend]), + ok + catch + throw:{skip, Reason} -> + io:format("~w(~w) -> skipping: " + "~n ~p" + "~n", [?FUNCTION_NAME, Backend, Reason]), + ok + end. + +do_getif2(OsName, Backend) -> + io:format("~w(~w) -> entry with" + "~n OsName: ~p" + "~n", [?FUNCTION_NAME, Backend, OsName]), + + %% For this to work with the 'socket' backend, we need to verify {ok, Hostname} = inet:gethostname(), {ok, Address} = inet:getaddr(Hostname, inet), {ok, Loopback} = inet:getaddr("localhost", inet), {ok, Interfaces} = inet_getiflist(Backend), HWAs = - lists:sort( - lists:foldl( - fun (I, Acc) -> - case inet_ifget(Backend, I, [hwaddr]) of - {ok,[{hwaddr,A}]} -> [A|Acc]; - {ok,[]} -> Acc - end - end, [], Interfaces)), + lists:sort( + lists:foldl( + fun (I, Acc) -> + case inet_ifget(Backend, I, [hwaddr]) of + {ok,[{hwaddr,A}]} -> [A|Acc]; + {ok,[]} -> Acc + end + end, [], Interfaces)), io:format("~w(~w) -> " "~n HW Addrs:" "~n ~p" "~n", [?FUNCTION_NAME, Backend, HWAs]), (OsName =/= sunos) - andalso ((length(HWAs) > 0) orelse (ct:fail(no_HWAs))), + andalso ((length(HWAs) > 0) orelse (ct:fail(no_HWAs))), Addresses = - lists:sort( - lists:foldl( - fun (I, Acc) -> - case inet_ifget(Backend, I, [addr]) of - {ok, [{addr,A}]} -> [A|Acc]; - {ok, []} -> Acc - end - end, [], Interfaces)), + lists:sort( + lists:foldl( + fun (I, Acc) -> + case inet_ifget(Backend, I, [addr]) of + {ok, [{addr,A}]} -> [A|Acc]; + {ok, []} -> Acc + end + end, [], Interfaces)), io:format("~w(~w) -> " "~n Addresses: " "~n ~p" @@ -1630,19 +1683,29 @@ getifaddrs(Config) when is_list (Config) -> do_getifaddrs(socket), getifaddrs_verify_backends(). -do_getifaddrs(default) -> - io:format("try 'default' getifaddrs~n", []), - do_getifaddrs2(inet:getifaddrs()); do_getifaddrs(Backend) -> - case is_supported_backend(Backend) of - true -> - io:format("try '~w' getifaddrs~n", [Backend]), - do_getifaddrs2(inet:getifaddrs([{inet_backend, Backend}])); - false -> - io:format("skip '~w' getifaddrs: not supported~n", [Backend]), + try do_getifaddrs2(Backend) of + ok -> + io:format("~w(~w) -> success~n", [?FUNCTION_NAME, Backend]), + ok + catch + throw:{skip, Reason} -> + io:format("~w(~w) -> skipping: " + "~n ~p" + "~n", [?FUNCTION_NAME, Backend, Reason]), ok end. + +do_getifaddrs2(default) -> + io:format("try 'default' getifaddrs~n", []), + do_getifaddrs3(inet:getifaddrs()); +do_getifaddrs2(Backend) -> + Func = getifaddrs, + Fun = fun() -> inet:Func([{inet_backend, Backend}]) end, + do_getifaddrs3(backend_conditional_run(Backend, Func, Fun)). + + is_supported_backend(inet = _Backend) -> true; is_supported_backend(socket = _Backend) -> @@ -1660,10 +1723,10 @@ is_socket_supported() -> end. -do_getifaddrs2({ok, IfAddrs}) -> - io:format("IfAddrs: " +do_getifaddrs3({ok, IfAddrs}) -> + io:format("~w(ok) -> IfAddrs: " "~n ~p" - "~n", [IfAddrs]), + "~n", [?FUNCTION_NAME, IfAddrs]), case [If || {If,Opts} <- IfAddrs, lists:keymember(hwaddr, 1, Opts)] of [] -> case os:type() of @@ -1788,18 +1851,34 @@ fold_ifopts(Fun, Acc, IfMap, Keys) -> getifaddrs_verify_backends() -> io:format("maybe attempt verify backends~n", []), - case is_supported_backend(inet) of + try is_supported_backend(inet) of true -> - case is_supported_backend(socket) of + try is_supported_backend(socket) of true -> getifaddrs_verify_backends( inet:getifaddrs([{inet_backend, inet}]), inet:getifaddrs([{inet_backend, socket}])); false -> io:format("'socket' backend not supported: skip~n", []) + catch + SC:SE:SS -> + io:format("skipping ~p: " + "~n (Error) Class: ~p" + "~n Error: ~p" + "~n Stack: ~p" + "~n", [socket, SC, SE, SS]), + ok end; false -> io:format("'inet' backend not supported: skip~n", []) + catch + IC:IE:IS -> + io:format("skipping ~p: " + "~n (Error) Class: ~p" + "~n Error: ~p" + "~n Stack: ~p" + "~n", [inet, IC, IE, IS]), + ok end. getifaddrs_verify_backends({ok, IfAddrs}, From 0fd82067a6627c45d7dc6339c5e4a48dd3a35a24 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 8 Jul 2024 14:12:42 +0200 Subject: [PATCH 32/37] [kernel|test] More getifaddrs test issues OTP-19132 --- lib/kernel/test/inet_SUITE.erl | 115 +++------------------------------ 1 file changed, 9 insertions(+), 106 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 0801e53fdcfd..192c14458218 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1931,115 +1931,18 @@ getifaddrs_verify_backend(IF, I_INFO, S_INFO) -> "~n INET -- SOCKET: ~p" "~n SOCKET -- INET: ~p" "~n", [IF, I_Rest2, S_Rest2, I_Diff, S_Diff]), - ct:fail(ifaddrs_not_equal) + %% Check if its a link local address, then ignore... + %% This is "a bit" loosey-goosey... + case lists:keysearch(addr, 1, S_Rest2) of + {value, {addr, {169, 254, _, _}}} -> + io:format("link local address for ~p - accept~n", [IF]), + ok; + _ -> + ct:fail(ifaddrs_not_equal) + end end. -%% getifaddrs_verify_backend(IF, [] = _I_INFO, [] = _S_INFO) -> -%% io:format("backend(s) *are* equal for ~p~n", [IF]), -%% ok; -%% getifaddrs_verify_backend(IF, -%% [{flags, I_Flags}|I_INFO], -%% [{flags, S_Flags}|S_INFO]) -> -%% case {I_Flags -- S_Flags, S_Flags -- I_Flags} of -%% {[], []} -> -%% io:format("flags for ~p *are* equal~n", [IF]), -%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); -%% {IFD, SFD} -> -%% io:format("flags for ~p are *not* equal: " -%% "~n INET -- SOCKET: ~p" -%% "~n SOCKET -- INET: ~p" -%% "~n", [IF, IFD, SFD]), -%% ct:fail(ifaddrs_not_equal) -%% end; -%% getifaddrs_verify_backend(IF, -%% [{addr, I_A}|I_INFO], -%% [{addr, S_A}|S_INFO]) -> -%% if -%% (I_A =:= S_A) -> -%% io:format("addr for ~p equal~n", [IF]), -%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); -%% true -> -%% io:format("addr for ~p *not* equal: " -%% "~n INET: ~p" -%% "~n SOCKET: ~p" -%% "~n", [IF, I_A, S_A]), -%% ct:fail(ifaddrs_not_equal) -%% end; -%% getifaddrs_verify_backend(IF, -%% [{netmask, I_A}|I_INFO], -%% [{netmask, S_A}|S_INFO]) -> -%% if -%% (I_A =:= S_A) -> -%% io:format("netmask for ~p equal~n", [IF]), -%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); -%% true -> -%% io:format("netmask for ~p *not* equal: " -%% "~n INET: ~p" -%% "~n SOCKET: ~p" -%% "~n", [IF, I_A, S_A]), -%% ct:fail(ifaddrs_not_equal) -%% end; -%% getifaddrs_verify_backend(IF, -%% [{broadaddr, I_A}|I_INFO], -%% [{broadaddr, S_A}|S_INFO]) -> -%% if -%% (I_A =:= S_A) -> -%% io:format("broadaddr for ~p equal~n", [IF]), -%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); -%% true -> -%% io:format("broadaddr for ~p *not* equal: " -%% "~n INET: ~p" -%% "~n SOCKET: ~p" -%% "~n", [IF, I_A, S_A]), -%% ct:fail(ifaddrs_not_equal) -%% end; -%% getifaddrs_verify_backend(IF, -%% [{dstaddr, I_A}|I_INFO], -%% [{dstaddr, S_A}|S_INFO]) -> -%% if -%% (I_A =:= S_A) -> -%% io:format("dstaddr for ~p equal~n", [IF]), -%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); -%% true -> -%% io:format("dstaddr for ~p *not* equal: " -%% "~n INET: ~p" -%% "~n SOCKET: ~p" -%% "~n", [IF, I_A, S_A]), -%% ct:fail(ifaddrs_not_equal) -%% end; -%% getifaddrs_verify_backend(IF, -%% [{hwaddr, I_A}|I_INFO], -%% [{hwaddr, S_A}|S_INFO]) -> -%% if -%% (I_A =:= S_A) -> -%% io:format("hwaddr for ~p equal~n", [IF]), -%% getifaddrs_verify_backend(IF, I_INFO, S_INFO); -%% true -> -%% io:format("hwaddr for ~p *not* equal: " -%% "~n INET: ~p" -%% "~n SOCKET: ~p" -%% "~n", [IF, I_A, S_A]), -%% ct:fail(ifaddrs_not_equal) -%% end; -%% getifaddrs_verify_backend(IF, -%% [], -%% [{hwaddr, _}]) -> -%% %% We accepts that net can get some more info. -%% %% That is, that we can get hwaddr for some -%% %% interfaces that the inet driver cannot... -%% io:format("hwaddr accepted for ~p~n", [IF]), -%% ok; -%% getifaddrs_verify_backend(IF, -%% I_INFO, S_INFO) -> -%% io:format("unexpected info for ~p: " -%% "~n INET: ~p" -%% "~n SOCKET: ~p" -%% "~n", [IF, I_INFO, S_INFO]), -%% ct:fail(ifaddrs_not_equal). - - - %% Works just like lists:member/2, except that any {127,_,_,_} tuple %% matches any other {127,_,_,_}. We do this to handle Linux systems %% that use (for instance) 127.0.1.1 as the IP address for the hostname. From 535e4a4e879bde009043b230c492c3cde1c6c7ec Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 9 Jul 2024 09:54:50 +0200 Subject: [PATCH 33/37] [esock] Rewrite ioctl gifconf encode function OTP-19132 --- erts/emulator/nifs/unix/unix_socket_syncio.c | 95 +++++++++++++++----- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/erts/emulator/nifs/unix/unix_socket_syncio.c b/erts/emulator/nifs/unix/unix_socket_syncio.c index e1950cfb6ade..1700be833f5a 100644 --- a/erts/emulator/nifs/unix/unix_socket_syncio.c +++ b/erts/emulator/nifs/unix/unix_socket_syncio.c @@ -4970,44 +4970,91 @@ ERL_NIF_TERM essio_ioctl_sifflags(ErlNifEnv* env, * */ +#if defined(AF_LINK) && !defined(NO_SA_LEN) +#define SIZEA(p) (((p).sa_len > sizeof(p)) ? (p).sa_len : sizeof(p)) +#else +#define SIZEA(p) (sizeof (p)) +#endif + static ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env, ESockDescriptor* descP, struct ifconf* ifcP) { - ERL_NIF_TERM result; - unsigned int len = ((ifcP == NULL) ? 0 : - (ifcP->ifc_len / sizeof(struct ifreq))); + ERL_NIF_TERM result; + unsigned int len = (ifcP == NULL) ? 0 : ifcP->ifc_len; - SSDBG( descP, - ("UNIX-ESSIO", - "encode_ioctl_ifconf -> entry (when len = %d)\r\n", len) ); + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> entry with" + "\r\n (total) len: %d\r\n", len) ); - if (len > 0) { - ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); - unsigned int i = 0; - struct ifreq* p = ifcP->ifc_req; + if (len > 0) { + ERL_NIF_TERM elem, array; + SocketTArray tarray = TARRAY_CREATE(32); + unsigned int n = 1; // Just for debugging + unsigned int i = 0; + unsigned int sz; + struct ifreq* ifrP; - for (i = 0 ; i < len ; i++) { - SSDBG( descP, - ("UNIX-ESSIO", - "encode_ioctl_ifconf -> encode ifreq entry %d\r\n", i) ); - array[i] = encode_ioctl_ifconf_ifreq(env, descP, &p[i]); - } + for (;;) { - SSDBG( descP, - ("UNIX-ESSIO", "encode_ioctl_ifconf -> all entries encoded\r\n", i) ); + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> encode entry %d at %d\r\n", n, i) ); - result = esock_make_ok2(env, MKLA(env, array, len)); - FREE(array); + ifrP = (struct ifreq*) VOIDP(ifcP->ifc_buf + i); + sz = sizeof(ifrP->ifr_name) + SIZEA(ifrP->ifr_addr); + if (sz < sizeof(*ifrP)) sz = sizeof(*ifrP); - } else { + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> " + "\r\n size: %d" + "\r\n Name len: %d" + "\r\n Addr len: %d" + "\r\n Rec len: %d" + "\r\n", + sz, + sizeof(ifrP->ifr_name), + SIZEA(ifrP->ifr_addr), + sizeof(*ifrP)) ); - result = esock_make_ok2(env, MKEL(env)); + i += sz; + if (i > len) break; - } + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> encode new entry\r\n") ); - return result; + elem = encode_ioctl_ifconf_ifreq(env, descP, ifrP); + + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> add new entry: " + "\r\n %T\r\n", elem) ); + + TARRAY_ADD(tarray, elem); + + n++; + } + + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> all entries encoded\r\n") ); + + TARRAY_TOLIST(tarray, env, &array); + result = esock_make_ok2(env, array); + + } else { + + result = esock_make_ok2(env, MKEL(env)); + + } + + SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_ifconf -> done\r\n") ); + + return result; } From c9e3f70afb21f59b629d49c4fea2de97c865da84 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 9 Jul 2024 09:55:40 +0200 Subject: [PATCH 34/37] [kernel] Filter out only inet and inet6 for getiflist (socket) OTP-19132 --- lib/kernel/src/inet.erl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index d6930794be12..4a943fe89fca 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -329,7 +329,10 @@ Function `parse_address/1` can be useful: element(1, Record) =:= element(1, RS), tuple_size(Record) =:= element(2, RS)). +%% Two kinds of debug macros (depnds on what you need to debug) %% -define(DBG(T), erlang:display({{self(), ?MODULE, ?LINE, ?FUNCTION_NAME}, T})). +%% -define(DBG(F, A), io:format("~w -> " ++ F ++ "~n", [?FUNCTION_NAME | A])). +%% -define(DBG(F), ?DBG(F, [])). %%% --------------------------------- @@ -1918,7 +1921,10 @@ do_getiflist2('inet' = _Backend, Socket) when is_port(Socket) -> net_getiflist(Socket) -> case socket:ioctl(Socket, gifconf) of {ok, Interfaces} -> - {ok, [Name || #{name := Name} <- Interfaces]}; + {ok, [Name || #{name := Name, + addr := #{family := Fam}} <- + Interfaces, ((Fam =:= inet) orelse + (Fam =:= inet6))]}; {error, _} = ERROR -> ERROR end. From 8610b63393a3500065b1a475f720b23a2cbfc03d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 9 Jul 2024 10:03:47 +0200 Subject: [PATCH 35/37] [kernel|test] Tweaked getif test case OTP-19132 --- lib/kernel/test/inet_SUITE.erl | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 0ca2e3fa89ad..6d60494f9b70 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1617,9 +1617,21 @@ do_getif2(OsName, Backend) -> %% For this to work with the 'socket' backend, we need to verify {ok, Hostname} = inet:gethostname(), + io:format("~w(~w) -> " + "~n Hostname: ~p" + "~n", [?FUNCTION_NAME, Backend, Hostname]), {ok, Address} = inet:getaddr(Hostname, inet), + io:format("~w(~w) -> " + "~n Address: ~p" + "~n", [?FUNCTION_NAME, Backend, Address]), {ok, Loopback} = inet:getaddr("localhost", inet), + io:format("~w(~w) -> " + "~n Loopback: ~p" + "~n", [?FUNCTION_NAME, Backend, Loopback]), {ok, Interfaces} = inet_getiflist(Backend), + io:format("~w(~w) -> " + "~n Interfaces: ~p" + "~n", [?FUNCTION_NAME, Backend, Interfaces]), HWAs = lists:sort( lists:foldl( @@ -1638,19 +1650,27 @@ do_getif2(OsName, Backend) -> Addresses = lists:sort( lists:foldl( - fun (I, Acc) -> + fun(I, Acc) -> case inet_ifget(Backend, I, [addr]) of {ok, [{addr,A}]} -> [A|Acc]; {ok, []} -> Acc end end, [], Interfaces)), - io:format("~w(~w) -> " + io:format("~w(~w) -> ifget result: " + "~n Addresses: " + "~n ~p" + "~n", [?FUNCTION_NAME, Backend, Addresses]), + {ok, Getif} = inet_getif(Backend), + io:format("~w(~w) -> ifget verify: " "~n Addresses: " "~n ~p" "~n", [?FUNCTION_NAME, Backend, Addresses]), - {ok,Getif} = inet_getif(Backend), Addresses = lists:sort([A || {A,_,_} <- Getif]), + io:format("~w(~w) -> verify address" + "~n", [?FUNCTION_NAME, Backend]), true = ip_member(Address, Addresses), + io:format("~w(~w) -> verify loopback" + "~n", [?FUNCTION_NAME, Backend]), true = ip_member(Loopback, Addresses), io:format("~w(~w) -> done~n", [?FUNCTION_NAME, Backend]), ok. From 3a5d2edd3959cfaaff2f6e3cfb693f22f913322e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 9 Jul 2024 12:03:23 +0200 Subject: [PATCH 36/37] [kernel] Ensure names unique in getiflist OTP-19132 --- lib/kernel/src/inet.erl | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 4a943fe89fca..ee4cbcc8101e 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1921,14 +1921,29 @@ do_getiflist2('inet' = _Backend, Socket) when is_port(Socket) -> net_getiflist(Socket) -> case socket:ioctl(Socket, gifconf) of {ok, Interfaces} -> - {ok, [Name || #{name := Name, - addr := #{family := Fam}} <- - Interfaces, ((Fam =:= inet) orelse - (Fam =:= inet6))]}; + Names = [Name || #{name := Name, + addr := #{family := Fam}} <- + Interfaces, ((Fam =:= inet) orelse + (Fam =:= inet6))], + {ok, ensure_unique_names(Names)}; {error, _} = ERROR -> ERROR end. +ensure_unique_names(Names) -> + ensure_unique_names(Names, []). + +ensure_unique_names([], Acc) -> + lists:reverse(Acc); +ensure_unique_names([Name|Names], Acc) -> + case lists:member(Name, Acc) of + true -> + ensure_unique_names(Names, Acc); + false -> + ensure_unique_names(Names, [Name|Acc]) + end. + + inet_getiflist(Socket) -> prim_inet:getiflist(Socket). From eddca2b05e80dc2ee64895c97fd33ab94db45151 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 11 Jul 2024 13:35:21 +0200 Subject: [PATCH 37/37] [esock|enet] Fixed net:getaddrinfo The socket type field of the address info map was incurrectly called 'type' sintead of 'socktype'. This has now been corrected. OTP-19132 --- erts/emulator/nifs/common/prim_net_nif.c | 15 +++++++++++---- erts/emulator/nifs/common/prim_socket_nif.c | 1 + erts/emulator/nifs/common/socket_int.h | 1 + lib/kernel/src/net.erl | 14 +++++++------- lib/kernel/test/net_SUITE.erl | 2 +- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c index f8dc1856cd5b..e5b4502e0ebf 100644 --- a/erts/emulator/nifs/common/prim_net_nif.c +++ b/erts/emulator/nifs/common/prim_net_nif.c @@ -4751,17 +4751,24 @@ ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, /* Convert an "native" socket type to an erlang socket type. * Note that this is not currently exhaustive, but only supports - * stream and dgram. Other values will be returned as is, that is - * in the form of an integer. + * stream, dgram, raw, seqpacket and rdm. + * Also, the value 0 (zero) has the special meaning: any. + * Other values will be returned as is, that is in the form of + * an integer. */ static ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, int socktype) { ERL_NIF_TERM etype; + ERL_NIF_TERM zero = MKI(env, 0); esock_encode_type(env, socktype, &etype); - return etype; + + if (IS_IDENTICAL(zero, etype)) + return esock_atom_any; + else + return etype; } @@ -4775,7 +4782,7 @@ void make_address_info(ErlNifEnv* env, ERL_NIF_TERM* ai) { ERL_NIF_TERM keys[] = {esock_atom_family, - esock_atom_type, + esock_atom_socktype, esock_atom_protocol, esock_atom_addr}; ERL_NIF_TERM vals[] = {fam, sockType, proto, addr}; diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index c147c07b2223..80d7072c9ae3 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -2260,6 +2260,7 @@ static const struct in6_addr in6addr_loopback = GLOBAL_ATOM_DECL(snd_wnd); \ GLOBAL_ATOM_DECL(sockaddr); \ GLOBAL_ATOM_DECL(socket); \ + GLOBAL_ATOM_DECL(socktype); \ GLOBAL_ATOM_DECL(spec_dst); \ GLOBAL_ATOM_DECL(staticarp); \ GLOBAL_ATOM_DECL(state); \ diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h index 82fbd85331a1..c88efdd02d0a 100644 --- a/erts/emulator/nifs/common/socket_int.h +++ b/erts/emulator/nifs/common/socket_int.h @@ -535,6 +535,7 @@ typedef long ssize_t; GLOBAL_ATOM_DEF(sockaddr); \ GLOBAL_ATOM_DEF(socket); \ GLOBAL_ATOM_DEF(socket_tag); \ + GLOBAL_ATOM_DEF(socktype); \ GLOBAL_ATOM_DEF(spec_dst); \ GLOBAL_ATOM_DEF(state); \ GLOBAL_ATOM_DEF(status); \ diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl index 2f3fe5c83dc7..1513516bac71 100644 --- a/lib/kernel/src/net.erl +++ b/lib/kernel/src/net.erl @@ -174,13 +174,13 @@ net:getifaddrs( %% The following (ext) flags has been removed %% (as they are deprecated by later version of gcc): %% idn_allow_unassigned | idn_use_std3_ascii_rules. --type name_info_flag_ext() :: idn. --type name_info() :: #{host := string(), - service := string()}. --type address_info() :: #{family := socket:domain(), - socktype := socket:type(), - protocol := socket:protocol(), - address := socket:sockaddr()}. +-type name_info_flag_ext() :: idn. +-type name_info() :: #{host := string(), + service := string()}. +-type address_info() :: #{family := socket:domain(), + socktype := any | socket:type() | integer(), + protocol := socket:protocol(), + address := socket:sockaddr()}. -type network_interface_name() :: string(). -type network_interface_index() :: non_neg_integer(). diff --git a/lib/kernel/test/net_SUITE.erl b/lib/kernel/test/net_SUITE.erl index 62bdbef7f468..a19666dd1a9a 100644 --- a/lib/kernel/test/net_SUITE.erl +++ b/lib/kernel/test/net_SUITE.erl @@ -763,7 +763,7 @@ verify_addr_info2([#{addr := #{addr := Addr, family := Domain, port := Port}, family := Domain, - type := _Type, + socktype := _Type, protocol := _Proto}|T], Domain) when is_integer(Port) andalso (((Domain =:= inet) andalso is_tuple(Addr) andalso (size(Addr) =:= 4)) orelse