File 5784-enet-Add-getservbyport.patch of Package erlang

From 11687229df4f6aeb9d6e6a0da917924294f2ef18 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Mon, 15 Apr 2024 18:58:20 +0200
Subject: [PATCH 04/18] [enet] Add getservbyport

---
 erts/emulator/nifs/common/prim_net_nif.c | 99 +++++++++++++++++++++++-
 lib/kernel/src/net.erl                   | 36 +++++++++
 2 files changed, 134 insertions(+), 1 deletion(-)

diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c
index ed088aaed6..77f1d881e1 100644
--- a/erts/emulator/nifs/common/prim_net_nif.c
+++ b/erts/emulator/nifs/common/prim_net_nif.c
@@ -208,8 +208,12 @@ ERL_NIF_INIT(prim_net, net_funcs, on_load, NULL, NULL, NULL)
     gethostname((__buf__), (__bufSz__))
 #define net_getservbyname(__name__, __proto__)  \
     getservbyname((__name__), (__proto__))
+#define net_getservbyport(__port__, __proto__)  \
+    getservbyport((__port__), (__proto__))
 #define net_ntohs(x)                            \
     ntohs((x))
+#define net_htons(x)                            \
+    htons((x))
 
 #else
 
@@ -217,8 +221,12 @@ ERL_NIF_INIT(prim_net, net_funcs, on_load, NULL, NULL, NULL)
     gethostname((__buf__), (__bufSz__))
 #define net_getservbyname(__name__, __proto__)  \
     getservbyname((__name__), (__proto__))
+#define net_getservbyport(__port__, __proto__)  \
+    getservbyport((__port__), (__proto__))
 #define net_ntohs(x)                            \
     ntohs((x))
+#define net_htons(x)                            \
+    htons((x))
 
 #endif // __WIN32__
 
@@ -307,6 +315,7 @@ extern char* erl_errno_id(int error);
     ENET_NIF_FUNC_DEF(get_interface_info);   \
     ENET_NIF_FUNC_DEF(get_ip_address_table); \
     ENET_NIF_FUNC_DEF(getservbyname);        \
+    ENET_NIF_FUNC_DEF(getservbyport);        \
     ENET_NIF_FUNC_DEF(if_name2index);        \
     ENET_NIF_FUNC_DEF(if_index2name);        \
     ENET_NIF_FUNC_DEF(if_names);
@@ -487,6 +496,9 @@ static void make_ip_address_row(ErlNifEnv*    env,
 static ERL_NIF_TERM enet_getservbyname(ErlNifEnv*   env,
                                        ERL_NIF_TERM ename,
                                        ERL_NIF_TERM eproto);
+static ERL_NIF_TERM enet_getservbyport(ErlNifEnv*   env,
+                                       ERL_NIF_TERM eport,
+                                       ERL_NIF_TERM eproto);
 
 #if defined(HAVE_IF_NAMETOINDEX)
 static ERL_NIF_TERM enet_if_name2index(ErlNifEnv* env,
@@ -811,6 +823,7 @@ static ErlNifResourceTypeInit netInit = {
  * nif_get_interface_info/1
  * nif_get_ip_address_table/1
  * nif_getservbyname/2
+ * nif_getservbyport/2
  * nif_if_name2index/1
  * nif_if_index2name/1
  * nif_if_names/0
@@ -3976,7 +3989,7 @@ ERL_NIF_TERM nif_getservbyname(ErlNifEnv*         env,
     ERL_NIF_TERM result, ename, eproto;
     BOOLEAN_T    dbg = FALSE;
 
-    NDBG( ("NET", "nif_get_ip_address_table -> entry (%d)\r\n", argc) );
+    NDBG( ("NET", "nif_getservbyname -> entry (%d)\r\n", argc) );
 
     if (argc != 2)
         return enif_make_badarg(env);
@@ -4033,6 +4046,89 @@ ERL_NIF_TERM enet_getservbyname(ErlNifEnv*   env,
 
 
 
+/* ----------------------------------------------------------------------
+ * nif_getservbyport
+ *
+ * Description:
+ * Get service by name.
+ * This is a lookup function that translates a port number to its
+ * (registered) service name.
+ *
+ * Arguments:
+ * PortNumber - Port number for which we want to know the service name
+ * Protocol   - The the protocol for which we want to service name
+ *
+ * Returns:
+ * {ok, Name :: string()} | {error, Reason :: term()}
+ */
+
+static
+ERL_NIF_TERM nif_getservbyport(ErlNifEnv*         env,
+                               int                argc,
+                               const ERL_NIF_TERM argv[])
+{
+    ERL_NIF_TERM result, eport, eproto;
+    BOOLEAN_T    dbg = FALSE;
+
+    NDBG( ("NET", "nif_getservbyport -> entry (%d)\r\n", argc) );
+
+    if (argc != 2)
+        return enif_make_badarg(env);
+
+    eport  = argv[0];
+    eproto = argv[1];
+
+    NDBG2( dbg,
+           ("NET",
+            "nif_getservbyport -> args: "
+            "\r\n   eport:  %T"
+            "\r\n   eproto: %T"
+            "\r\n", eport, eproto) );
+
+    result = enet_getservbyport(env, eport, eproto);
+
+    NDBG2( dbg,
+           ("NET",
+            "nif_getservbyport -> done when result: "
+            "\r\n   %T\r\n", result) );
+
+    return result;
+}
+
+
+static
+ERL_NIF_TERM enet_getservbyport(ErlNifEnv*   env,
+                                ERL_NIF_TERM eport,
+                                ERL_NIF_TERM eproto)
+{
+    char            proto[256];
+    struct servent* srv;
+    unsigned short  port;
+    unsigned int    len;
+
+    if (0 >= GET_UINT(env, eport, &port))
+        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);
+
+    port = net_htons(port);
+
+    if ( strcmp(proto, "any") == 0 )
+        srv = net_getservbyport(port, NULL);
+    else
+        srv = net_getservbyport(port, proto);
+
+    if (srv == NULL)
+        return esock_make_error(env, esock_atom_einval);
+
+    len = strlen(srv->s_name);
+
+    return esock_make_ok2(env, MKSL(env, srv->s_name, len));
+}
+
+
+
 /* ----------------------------------------------------------------------
  * nif_if_name2index
  *
@@ -4798,6 +4894,7 @@ ErlNifFunc net_funcs[] =
     {"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},
+    {"nif_getservbyport", 2, nif_getservbyport, 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 f51f4fb51a..dc04cee4af 100644
--- a/lib/kernel/src/net.erl
+++ b/lib/kernel/src/net.erl
@@ -38,6 +38,7 @@ This module provides an API for the network interface.
          getaddrinfo/1,   getaddrinfo/2,
          getifaddrs/0,    getifaddrs/1, getifaddrs/2,
          getservbyname/1, getservbyname/2,
+         getservbyport/1, getservbyport/2,
 
          if_name2index/1,
          if_index2name/1,
@@ -934,6 +935,41 @@ getservbyname(Name, Protocol)
     prim_net:getservbyname(Name, atom_to_list(Protocol)).
 
 
+%% ===========================================================================
+%%
+%% getservbyport - Get service by name
+%%
+%% Get service name for the given port number.
+%%
+
+-doc(#{equiv => getservbyport(PortNumber, any)}).
+-doc(#{since => <<"OTP FOOBAR">>}).
+-spec getservbyport(PortNumber) ->
+          {ok, Name} | {error, Reason} when
+      PortNumber :: socket:port_number(),
+      Name       :: atom() | string(),
+      Reason     :: term().
+getservbyport(PortNumber) ->
+    getservbyport(PortNumber, any).
+
+-doc """
+Get service by name.
+
+This function is used to get the service name of the specified protocol
+for the given port number.
+""".
+-doc(#{since => <<"OTP FOOBAR">>}).
+-spec getservbyport(PortNumber, Protocol) ->
+          {ok, Name} | {error, Reason} when
+      PortNumber :: socket:port_number(),
+      Protocol   :: any | socket:protocol(),
+      Name       :: atom() | string(),
+      Reason     :: term().
+getservbyport(PortNumber, Protocol)
+  when is_integer(PortNumber) andalso is_atom(Protocol) ->
+    prim_net:getservbyport(PortNumber, atom_to_list(Protocol)).
+
+
 %% ===========================================================================
 %%
 %% if_name2index - Mappings between network interface names and indexes:
-- 
2.35.3

openSUSE Build Service is sponsored by