File 5782-enet-Add-net-getservbyname.patch of Package erlang
From 7f86a1e5c57ac47a368b092d766465fc44f07a96 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Mon, 15 Apr 2024 16:55:18 +0200
Subject: [PATCH 02/18] [enet] Add net:getservbyname
---
erts/emulator/nifs/common/prim_net_nif.c | 111 ++++++++++++++++++++++-
lib/kernel/src/net.erl | 47 +++++++++-
2 files changed, 150 insertions(+), 8 deletions(-)
diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c
index 8655c561e3..ed088aaed6 100644
--- a/erts/emulator/nifs/common/prim_net_nif.c
+++ b/erts/emulator/nifs/common/prim_net_nif.c
@@ -203,9 +203,23 @@ ERL_NIF_INIT(prim_net, net_funcs, on_load, NULL, NULL, NULL)
#ifdef __WIN32__
-#define net_gethostname(__buf__, __bufSz__) gethostname((__buf__), (__bufSz__))
+
+#define net_gethostname(__buf__, __bufSz__) \
+ gethostname((__buf__), (__bufSz__))
+#define net_getservbyname(__name__, __proto__) \
+ getservbyname((__name__), (__proto__))
+#define net_ntohs(x) \
+ ntohs((x))
+
#else
-#define net_gethostname(__buf__, __bufSz__) gethostname((__buf__), (__bufSz__))
+
+#define net_gethostname(__buf__, __bufSz__) \
+ gethostname((__buf__), (__bufSz__))
+#define net_getservbyname(__name__, __proto__) \
+ getservbyname((__name__), (__proto__))
+#define net_ntohs(x) \
+ ntohs((x))
+
#endif // __WIN32__
@@ -266,7 +280,7 @@ static NetData data;
* ----------------------------------------------------------------------
*/
-/* THIS IS JUST TEMPORARY */
+/* THIS IS JUST TEMPORARY...maybe */
extern char* erl_errno_id(int error);
/* All the nif "callback" functions for the net API has
@@ -292,6 +306,7 @@ extern char* erl_errno_id(int error);
ENET_NIF_FUNC_DEF(get_if_entry); \
ENET_NIF_FUNC_DEF(get_interface_info); \
ENET_NIF_FUNC_DEF(get_ip_address_table); \
+ ENET_NIF_FUNC_DEF(getservbyname); \
ENET_NIF_FUNC_DEF(if_name2index); \
ENET_NIF_FUNC_DEF(if_index2name); \
ENET_NIF_FUNC_DEF(if_names);
@@ -467,7 +482,11 @@ static void make_ip_address_row(ErlNifEnv* env,
ERL_NIF_TERM eReasmSize,
ERL_NIF_TERM* iar);
-#endif
+#endif // defined(__WIN32__)
+
+static ERL_NIF_TERM enet_getservbyname(ErlNifEnv* env,
+ ERL_NIF_TERM ename,
+ ERL_NIF_TERM eproto);
#if defined(HAVE_IF_NAMETOINDEX)
static ERL_NIF_TERM enet_if_name2index(ErlNifEnv* env,
@@ -791,6 +810,7 @@ static ErlNifResourceTypeInit netInit = {
* nif_get_if_entry/1
* nif_get_interface_info/1
* nif_get_ip_address_table/1
+ * nif_getservbyname/2
* nif_if_name2index/1
* nif_if_index2name/1
* nif_if_names/0
@@ -3932,6 +3952,86 @@ void make_ip_address_row(ErlNifEnv* env,
+/* ----------------------------------------------------------------------
+ * nif_getservbyname
+ *
+ * Description:
+ * Get service by name.
+ * This is a lookup function that translates a service name to its
+ * registered port number.
+ *
+ * Arguments:
+ * Name - The name of the service.
+ * Protocol - The name of the service.
+ *
+ * Returns:
+ * {ok, PortNumber :: port_number()} | {error, Reason :: term()}
+ */
+
+static
+ERL_NIF_TERM nif_getservbyname(ErlNifEnv* env,
+ int argc,
+ const ERL_NIF_TERM argv[])
+{
+ ERL_NIF_TERM result, ename, eproto;
+ BOOLEAN_T dbg = FALSE;
+
+ NDBG( ("NET", "nif_get_ip_address_table -> entry (%d)\r\n", argc) );
+
+ if (argc != 2)
+ return enif_make_badarg(env);
+
+ ename = argv[0];
+ eproto = argv[1];
+
+ NDBG2( dbg,
+ ("NET",
+ "nif_getservbyname -> args: "
+ "\r\n ename: %T"
+ "\r\n eproto: %T"
+ "\r\n", ename, eproto) );
+
+ result = enet_getservbyname(env, ename, eproto);
+
+ NDBG2( dbg,
+ ("NET",
+ "nif_getservbyname -> done when result: "
+ "\r\n %T\r\n", result) );
+
+ return result;
+}
+
+
+static
+ERL_NIF_TERM enet_getservbyname(ErlNifEnv* env,
+ ERL_NIF_TERM ename,
+ ERL_NIF_TERM eproto)
+{
+ char name[256];
+ char proto[256];
+ struct servent* srv;
+ short port;
+
+ if (0 >= GET_STR(env, ename, name, sizeof(name)))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (0 >= GET_STR(env, eproto, proto, sizeof(proto)))
+ return esock_make_error(env, esock_atom_einval);
+
+ if ( strcmp(proto, "any") == 0 )
+ srv = net_getservbyname(name, NULL);
+ else
+ srv = net_getservbyname(name, proto);
+
+ if (srv == NULL)
+ return esock_make_error(env, esock_atom_einval);
+
+ port = net_ntohs(srv->s_port);
+
+ return esock_make_ok2(env, MKI(env, port));
+}
+
+
/* ----------------------------------------------------------------------
* nif_if_name2index
@@ -4697,6 +4797,7 @@ ErlNifFunc net_funcs[] =
{"nif_get_if_entry", 1, nif_get_if_entry, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"nif_get_interface_info", 1, nif_get_interface_info, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"nif_get_ip_address_table", 1, nif_get_ip_address_table, ERL_NIF_DIRTY_JOB_IO_BOUND},
+ {"nif_getservbyname", 2, nif_getservbyname, ERL_NIF_DIRTY_JOB_IO_BOUND},
/* Network interface (name and/or index) functions */
{"nif_if_name2index", 1, nif_if_name2index, 0},
diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl
index e642b89d5a..f51f4fb51a 100644
--- a/lib/kernel/src/net.erl
+++ b/lib/kernel/src/net.erl
@@ -34,9 +34,10 @@ This module provides an API for the network interface.
-export([
gethostname/0,
- getnameinfo/1, getnameinfo/2,
- getaddrinfo/1, getaddrinfo/2,
- getifaddrs/0, getifaddrs/1, getifaddrs/2,
+ getnameinfo/1, getnameinfo/2,
+ getaddrinfo/1, getaddrinfo/2,
+ getifaddrs/0, getifaddrs/1, getifaddrs/2,
+ getservbyname/1, getservbyname/2,
if_name2index/1,
if_index2name/1,
@@ -320,6 +321,7 @@ getaddrinfo(Host, Service)
(not ((Service =:= undefined) andalso (Host =:= undefined))) ->
prim_net:getaddrinfo(Host, Service).
+
%% ===========================================================================
%%
%% getifaddrs - Get interface addresses
@@ -893,6 +895,45 @@ iat_broadaddr({A1, A2, A3, A4}, {M1, M2, M3, M4}) ->
addr => {BA1, BA2, BA3, BA4},
port => 0}.
+
+%% ===========================================================================
+%%
+%% getservbyname - Get service by name
+%%
+%% Get the port number for the named service.
+%%
+
+-doc(#{equiv => getservbyname(Name, any)}).
+-doc(#{since => <<"OTP FOOBAR">>}).
+-spec getservbyname(Name) ->
+ {ok, PortNumber} | {error, Reason} when
+ Name :: atom() | string(),
+ PortNumber :: socket:port_number(),
+ Reason :: term().
+getservbyname(Name) ->
+ getservbyname(Name, any).
+
+-doc """
+Get service by name.
+
+This function is used to get the port number of the specified protocol
+for the named service.
+""".
+-doc(#{since => <<"OTP FOOBAR">>}).
+-spec getservbyname(Name, Protocol) ->
+ {ok, PortNumber} | {error, Reason} when
+ Name :: atom() | string(),
+ PortNumber :: socket:port_number(),
+ Protocol :: any | socket:protocol(),
+ Reason :: term().
+getservbyname(Name, Protocol)
+ when is_atom(Name) ->
+ getservbyname(atom_to_list(Name), Protocol);
+getservbyname(Name, Protocol)
+ when is_list(Name) andalso is_atom(Protocol) ->
+ prim_net:getservbyname(Name, atom_to_list(Protocol)).
+
+
%% ===========================================================================
%%
%% if_name2index - Mappings between network interface names and indexes:
--
2.35.3