File 2022-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/guides/socket_usage.md
+++ b/lib/kernel/doc/guides/socket_usage.md
@@ -626,16 +626,19 @@ _Table: ipv6 options_
[](){: #socket_options_tcp }
Options for level `tcp`:
-| Option Name | Value Type | Set | Get | Other Requirements and comments |
-| ----------- | ---------- | --- | --- | -------------------------------------------------------------------------------------------------------- |
-| congestion | string() | yes | yes | none |
-| cork | boolean() | yes | yes | 'nopush' one some platforms (FreeBSD) |
-| keepcnt | integer() | yes | yes | On Windows (at least), it is illegal to set to a value greater than 255. |
-| keepidle | integer() | yes | yes | none |
-| keepintvl | integer() | yes | yes | none |
-| maxseg | integer() | yes | yes | Set not allowed on all platforms. |
-| nodelay | boolean() | yes | yes | none |
-| nopush | boolean() | yes | yes | 'cork' on some platforms (Linux). On Darwin this has a different meaning than on, for instance, FreeBSD. |
+| Option Name | Value Type | Set | Get | Other Requirements and comments |
+| ------------ | -------------- | --- | --- | ---------------------------------------------------- |
+| congestion | string() | yes | yes | none |
+| cork | boolean() | yes | yes | 'nopush' one some platforms (FreeBSD) |
+| keepcnt | integer() | yes | yes | On Windows (at least), it is illegal to set to |
+| | | | | a value greater than 255. |
+| keepidle | integer() | yes | yes | none |
+| keepintvl | integer() | yes | yes | none |
+| maxseg | integer() | yes | yes | Set not allowed on all platforms. |
+| nodelay | boolean() | yes | yes | none |
+| nopush | boolean() | yes | yes | 'cork' on some platforms (Linux). On Darwin this has |
+| | | | | a different meaning than on, for instance, FreeBSD. |
+| user_timeout | integer() >= 0 | yes | yes | none |
_Table: tcp options_
diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl
index 4b2b688787..aeb650f8ad 100644
--- a/lib/kernel/src/socket.erl
+++ b/lib/kernel/src/socket.erl
@@ -1266,10 +1266,20 @@ _Options for protocol level_ [_`tcp`:_](`t:level/0`)
- **`{tcp, cork}`** - `Value = boolean()`
+- **`{tcp, keepcnt}`** - `Value = integer()`
+
+- **`{tcp, keepidle}`** - `Value = integer()`
+
+- **`{tcp, keepintvl}`** - `Value = integer()`
+
- **`{tcp, maxseg}`** - `Value = integer()`
- **`{tcp, nodelay}`** - `Value = boolean()`
+- **`{tcp, nopush}`** - `Value = boolean()`
+
+- **`{tcp, user_timeout}`** - `Value = non_neg_integer()`
+
_Options for protocol level_ [_`udp`:_](`t:level/0`)
- **`{udp, cork}`** - `Value = boolean()`
--
2.51.0