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() >= 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