File 2982-Implement-TCP_USER_TIMEOUT-for-socket.patch of Package erlang

From 94b71711959b2ca07efa0d9b1b84461c75ef2433 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen <raimo@erlang.org>
Date: Mon, 17 Nov 2025 15:36:28 +0100
Subject: [PATCH 2/4] Implement TCP_USER_TIMEOUT for `socket`

Update the documentation to mention this option
and some other that were overlooked.
---
 erts/emulator/nifs/common/prim_socket_int.h |  5 ++
 erts/emulator/nifs/common/prim_socket_nif.c | 85 ++++++++++++++++++++-
 lib/kernel/doc/guides/socket_usage.md       | 23 +++---
 lib/kernel/src/socket.erl                   | 10 +++
 4 files changed, 112 insertions(+), 11 deletions(-)

diff --git a/erts/emulator/nifs/common/prim_socket_int.h b/erts/emulator/nifs/common/prim_socket_int.h
index 919cdaff5e..af8e5caab8 100644
--- a/erts/emulator/nifs/common/prim_socket_int.h
+++ b/erts/emulator/nifs/common/prim_socket_int.h
@@ -567,6 +567,11 @@ extern BOOLEAN_T esock_getopt_int(SOCKET sock,
                                   int    opt,
                                   int*   valP);
 
+extern BOOLEAN_T esock_getopt_uint(SOCKET        sock,
+                                   int           level,
+                                   int           opt,
+                                   unsigned int *valP);
+
 
 /* ** Socket Registry functions *** */
 extern void esock_send_reg_add_msg(ErlNifEnv*   env,
diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c
index 7a7ad9c272..4719e43e28 100644
--- a/erts/emulator/nifs/common/prim_socket_nif.c
+++ b/erts/emulator/nifs/common/prim_socket_nif.c
@@ -1310,6 +1310,10 @@ static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv*       env,
                                          ESockDescriptor* descP,
                                          int              level,
                                          int              opt);
+static ERL_NIF_TERM esock_getopt_uint_opt(ErlNifEnv*       env,
+                                          ESockDescriptor* descP,
+                                          int              level,
+                                          int              opt);
 static ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv*       env,
                                           ESockDescriptor* descP,
                                           int              level,
@@ -1719,6 +1723,11 @@ static ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv*       env,
                                          int              level,
                                          int              opt,
                                          ERL_NIF_TERM     eVal);
+static ERL_NIF_TERM esock_setopt_uint_opt(ErlNifEnv*       env,
+                                          ESockDescriptor* descP,
+                                          int              level,
+                                          int              opt,
+                                          ERL_NIF_TERM     eVal);
 #if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO))      \
     && defined(ESOCK_USE_RCVSNDTIMEO)
 static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv*       env,
@@ -3762,7 +3771,14 @@ static struct ESockOpt optLevelTCP[] =
 #endif
         &esock_atom_nopush},
         {0, NULL, NULL, &esock_atom_syncnt},
-        {0, NULL, NULL, &esock_atom_user_timeout}
+        {
+#ifdef TCP_USER_TIMEOUT
+            TCP_USER_TIMEOUT,
+            esock_setopt_uint_opt, esock_getopt_uint_opt,
+#else
+            0, NULL, NULL,
+#endif
+            &esock_atom_user_timeout}
 
     };
 
@@ -8286,6 +8302,31 @@ ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv*       env,
 
 
 
+/* esock_setopt_uint_opt - set an option that has an unsigned integer value
+ */
+
+static
+ERL_NIF_TERM esock_setopt_uint_opt(ErlNifEnv*       env,
+                                   ESockDescriptor* descP,
+                                   int              level,
+                                   int              opt,
+                                   ERL_NIF_TERM     eVal)
+{
+    ERL_NIF_TERM result;
+    unsigned int val;
+
+    if (GET_UINT(env, eVal, &val)) {
+        result =
+            esock_setopt_level_opt(env, descP, level, opt,
+                                   &val, sizeof(val));
+    } else {
+        result = esock_make_invalid(env, esock_atom_value);
+    }
+    return result;
+}
+
+
+
 /* esock_setopt_str_opt - set an option that has an string value
  */
 
@@ -9892,6 +9933,24 @@ ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv*       env,
 
 
 
+/* esock_getopt_uint_opt - get an unsigned integer option
+ */
+static
+ERL_NIF_TERM esock_getopt_uint_opt(ErlNifEnv*       env,
+                                   ESockDescriptor* descP,
+                                   int              level,
+                                   int              opt)
+{
+    unsigned int val;
+
+    if (! esock_getopt_uint(descP->sock, level, opt, &val))
+        return esock_make_error_errno(env, sock_errno());
+
+    return esock_make_ok2(env, MKUI(env, val));
+}
+
+
+
 /* esock_getopt_int - get an integer option
  */
 extern
@@ -9916,6 +9975,30 @@ BOOLEAN_T esock_getopt_int(SOCKET           sock,
 
 
 
+/* esock_getopt_uint - get an unsigned integer option
+ */
+extern
+BOOLEAN_T esock_getopt_uint(SOCKET           sock,
+                            int              level,
+                            int              opt,
+                            unsigned int    *valP)
+{
+    unsigned int val = 0;
+    SOCKOPTLEN_T valSz = sizeof(val);
+
+#ifdef __WIN32__
+    if (sock_getopt(sock, level, opt, (char*) &val, &valSz) != 0)
+#else
+    if (sock_getopt(sock, level, opt, &val, &valSz) != 0)
+#endif
+        return FALSE;
+
+    *valP = val;
+    return TRUE;
+}
+
+
+
 static
 ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv*       env,
                                    ESockDescriptor* descP,
diff --git a/lib/kernel/doc/guides/socket_usage.md b/lib/kernel/doc/guides/socket_usage.md
index 06184c9633..5efdb63712 100644
--- a/lib/kernel/doc/src/socket_usage.xml
+++ b/lib/kernel/doc/src/socket_usage.xml
@@ -976,6 +976,13 @@
 	  on, for instance, FreeBSD.
 	</cell>
       </row>
+      <row>
+	<cell>user_timeout</cell>
+	<cell>integer() &gt;= 0</cell>
+	<cell>yes</cell>
+	<cell>yes</cell>
+	<cell>none</cell>
+      </row>
       <tcaption>tcp options</tcaption>
     </table>
     
diff --git a/lib/kernel/doc/src/socket.xml b/lib/kerneldoc//src/socket.xml
index 4b2b688787..aeb650f8ad 100644
--- a/lib/kernel/doc/src/socket.xml
+++ b/lib/kernel/doc/src/socket.xml
@@ -1149,10 +1149,20 @@
 	  <item><p><c>Value = string()</c></p></item>
 	  <tag><c>{tcp, cork}</c></tag>
 	  <item><p><c>Value = boolean()</c></p></item>
+	  <tag><c>{tcp, keepcnt}</c></tag>
+	  <item><p><c>Value = integer()</c></p></item>
+	  <tag><c>{tcp, keepidle}</c></tag>
+	  <item><p><c>Value = integer()</c></p></item>
+	  <tag><c>{tcp, keepintvl}</c></tag>
+	  <item><p><c>Value = integer()</c></p></item>
 	  <tag><c>{tcp, maxseg}</c></tag>
 	  <item><p><c>Value = integer()</c></p></item>
 	  <tag><c>{tcp, nodelay}</c></tag>
 	  <item><p><c>Value = boolean()</c></p></item>
+	  <tag><c>{tcp, nopush}</c></tag>
+	  <item><p><c>Value = boolean()</c></p></item>
+	  <tag><c>{tcp, user_timeout}</c></tag>
+	  <item><p><c>Value = non_neg_integer()</c></p></item>
 	</taglist>
 	<p></p>
 	<!-- ## Protocol level 'udp' ######################### -->
-- 
2.51.0

openSUSE Build Service is sponsored by