aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/socket.xml9
-rw-r--r--erts/doc/src/socket_usage.xml18
-rw-r--r--erts/emulator/nifs/common/socket_int.h16
-rw-r--r--erts/emulator/nifs/common/socket_nif.c233
-rw-r--r--erts/preloaded/ebin/socket.beambin56044 -> 56284 bytes
-rw-r--r--erts/preloaded/src/socket.erl40
-rw-r--r--lib/kernel/test/socket_server.erl21
7 files changed, 308 insertions, 29 deletions
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index fe23eaa138..14a21823b8 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -117,6 +117,9 @@
<name name="sctp_socket_option"/>
</datatype>
<datatype>
+ <name name="timeval"/>
+ </datatype>
+ <datatype>
<name name="ip_tos_flag"/>
</datatype>
<datatype>
@@ -146,6 +149,12 @@
<datatype>
<name name="sctp_rtoinfo"/>
</datatype>
+ <datatype>
+ <name name="uint16"/>
+ </datatype>
+ <datatype>
+ <name name="uint32"/>
+ </datatype>
</datatypes>
<funcs>
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index e90e682e39..221561c3e2 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -114,7 +114,7 @@
<cell>integer()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>may require admin capability</cell>
+ <cell>require admin capability</cell>
</row>
<row>
<cell>domain</cell>
@@ -174,7 +174,14 @@
</row>
<row>
<cell>rcvbuf</cell>
- <cell>integer()</cell>
+ <cell>non_neg_integer()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>none</cell>
+ </row>
+ <row>
+ <cell>rcvtimeo</cell>
+ <cell>timeval()</cell>
<cell>yes</cell>
<cell>yes</cell>
<cell>none</cell>
@@ -200,6 +207,13 @@
<cell>yes</cell>
<cell>none</cell>
</row>
+ <row>
+ <cell>sndtimeo</cell>
+ <cell>timeval()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>none</cell>
+ </row>
</table>
<p>Options for level <c>ip</c>: </p>
diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h
index 28f42a7345..2d5049a9eb 100644
--- a/erts/emulator/nifs/common/socket_int.h
+++ b/erts/emulator/nifs/common/socket_int.h
@@ -152,6 +152,7 @@ extern ERL_NIF_TERM esock_atom_einval;
#define MKA(E,S) enif_make_atom((E), (S))
#define MKBIN(E,B) enif_make_binary((E), (B))
#define MKI(E,I) enif_make_int((E), (I))
+#define MKL(E,L) enif_make_long((E), (L))
#define MKLA(E,A,L) enif_make_list_from_array((E), (A), (L))
#define MKEL(E) enif_make_list((E), 0)
#define MKMA(E,KA,VA,L,M) enif_make_map_from_arrays((E), (KA), (VA), (L), (M))
@@ -167,7 +168,8 @@ extern ERL_NIF_TERM esock_atom_einval;
#define MKT8(E,E1,E2,E3,E4,E5,E6,E7,E8) \
enif_make_tuple8((E), (E1), (E2), (E3), (E4), (E5), (E6), (E7), (E8))
#define MKTA(E, A, AL) enif_make_tuple_from_array((E), (A), (AL))
-#define MKUI(E,I) enif_make_uint((E), (I))
+#define MKUI(E,UI) enif_make_uint((E), (UI))
+#define MKUL(E,UL) enif_make_ulong((E), (UL))
#define MCREATE(N) enif_mutex_create((N))
#define MDESTROY(M) enif_mutex_destroy((M))
@@ -194,16 +196,18 @@ extern ERL_NIF_TERM esock_atom_einval;
enif_get_atom_length((E), (TE), (LP), ERL_NIF_LATIN1)
#define GET_ATOM(E, TE, BP, MAX) \
enif_get_atom((E), (TE), (BP), (MAX), ERL_NIF_LATIN1)
-#define GET_BIN(E, TE, BP) enif_inspect_iolist_as_binary((E), (TE), (BP))
-#define GET_INT(E, TE, IP) enif_get_int((E), (TE), (IP))
+#define GET_BIN(E, TE, BP) enif_inspect_iolist_as_binary((E), (TE), (BP))
+#define GET_INT(E, TE, IP) enif_get_int((E), (TE), (IP))
#define GET_LIST_ELEM(E, L, HP, TP) enif_get_list_cell((E), (L), (HP), (TP))
#define GET_LIST_LEN(E, L, LP) enif_get_list_length((E), (L), (LP))
+#define GET_LONG(E, TE, LP) enif_get_long((E), (TE), (LP))
#define GET_LPID(E, T, P) enif_get_local_pid((E), (T), (P))
#define GET_STR(E, L, B, SZ) \
enif_get_string((E), (L), (B), (SZ), ERL_NIF_LATIN1)
-#define GET_UINT(E, TE, IP) enif_get_uint((E), (TE), (IP))
-#define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA))
-#define GET_MAP_VAL(E, M, K, V) enif_get_map_value((E), (M), (K), (V))
+#define GET_UINT(E, TE, UIP) enif_get_uint((E), (TE), (UIP))
+#define GET_ULONG(E, TE, ULP) enif_get_long((E), (TE), (ULP))
+#define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA))
+#define GET_MAP_VAL(E, M, K, V) enif_get_map_value((E), (M), (K), (V))
#define ALLOC_BIN(SZ, BP) enif_alloc_binary((SZ), (BP))
#define REALLOC_BIN(SZ, BP) enif_realloc_binary((SZ), (BP))
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index e8e1df0842..53122ab957 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -502,9 +502,11 @@ typedef union {
#define SOCKET_OPT_SOCK_PRIORITY 17
#define SOCKET_OPT_SOCK_PROTOCOL 18
#define SOCKET_OPT_SOCK_RCVBUF 19
+#define SOCKET_OPT_SOCK_RCVTIMEO 22
#define SOCKET_OPT_SOCK_REUSEADDR 23
#define SOCKET_OPT_SOCK_REUSEPORT 24
#define SOCKET_OPT_SOCK_SNDBUF 27
+#define SOCKET_OPT_SOCK_SNDTIMEO 30
#define SOCKET_OPT_SOCK_TYPE 32
#define SOCKET_OPT_IP_ADD_MEMBERSHIP 1
@@ -1010,6 +1012,11 @@ static ERL_NIF_TERM nsetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(SO_RCVTIMEO)
+static ERL_NIF_TERM nsetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(SO_REUSEADDR)
static ERL_NIF_TERM nsetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1025,6 +1032,11 @@ static ERL_NIF_TERM nsetopt_lvl_sock_sndbuf(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(SO_SNDTIMEO)
+static ERL_NIF_TERM nsetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
static ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
SocketDescriptor* descP,
int eOpt,
@@ -1339,6 +1351,10 @@ static ERL_NIF_TERM ngetopt_lvl_sock_protocol(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
SocketDescriptor* descP);
#endif
+#if defined(SO_RCVTIMEO)
+static ERL_NIF_TERM ngetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(SO_REUSEADDR)
static ERL_NIF_TERM ngetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1351,6 +1367,10 @@ static ERL_NIF_TERM ngetopt_lvl_sock_reuseport(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_sock_sndbuf(ErlNifEnv* env,
SocketDescriptor* descP);
#endif
+#if defined(SO_SNDTIMEO)
+static ERL_NIF_TERM ngetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(SO_TYPE)
static ERL_NIF_TERM ngetopt_lvl_sock_type(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1509,6 +1529,11 @@ static ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env,
int level,
int opt,
ERL_NIF_TERM eVal);
+static ERL_NIF_TERM nsetopt_timeval_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal);
static ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1523,6 +1548,10 @@ static ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
SocketDescriptor* descP,
int level,
int opt);
+static ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt);
static ERL_NIF_TERM send_check_result(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1864,6 +1893,7 @@ static char str_partial_delivery[] = "partial_delivery";
static char str_peer_error[] = "peer_error";
static char str_peer_rwnd[] = "peer_rwnd";
static char str_probe[] = "probe";
+static char str_sec[] = "sec";
static char str_select[] = "select";
static char str_sender_dry[] = "sender_dry";
static char str_send_failure[] = "send_failure";
@@ -1871,6 +1901,7 @@ static char str_shutdown[] = "shutdown";
static char str_sourceaddr[] = "sourceaddr";
static char str_timeout[] = "timeout";
static char str_true[] = "true";
+static char str_usec[] = "usec";
static char str_want[] = "want";
static char str_lowdelay[] = "lowdelay";
@@ -1973,6 +2004,7 @@ static ERL_NIF_TERM atom_partial_delivery;
static ERL_NIF_TERM atom_peer_error;
static ERL_NIF_TERM atom_peer_rwnd;
static ERL_NIF_TERM atom_probe;
+static ERL_NIF_TERM atom_sec;
static ERL_NIF_TERM atom_select;
static ERL_NIF_TERM atom_sender_dry;
static ERL_NIF_TERM atom_send_failure;
@@ -1980,6 +2012,7 @@ static ERL_NIF_TERM atom_shutdown;
static ERL_NIF_TERM atom_sourceaddr;
static ERL_NIF_TERM atom_timeout;
static ERL_NIF_TERM atom_true;
+static ERL_NIF_TERM atom_usec;
static ERL_NIF_TERM atom_want;
static ERL_NIF_TERM atom_lowdelay;
@@ -4346,6 +4379,12 @@ ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
break;
#endif
+#if defined(SO_RCVTIMEO)
+ case SOCKET_OPT_SOCK_RCVTIMEO:
+ result = nsetopt_lvl_sock_rcvtimeo(env, descP, eVal);
+ break;
+#endif
+
#if defined(SO_REUSEADDR)
case SOCKET_OPT_SOCK_REUSEADDR:
result = nsetopt_lvl_sock_reuseaddr(env, descP, eVal);
@@ -4364,11 +4403,22 @@ ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
break;
#endif
+#if defined(SO_SNDTIMEO)
+ case SOCKET_OPT_SOCK_SNDTIMEO:
+ result = nsetopt_lvl_sock_sndtimeo(env, descP, eVal);
+ break;
+#endif
+
default:
result = esock_make_error(env, esock_atom_einval);
break;
}
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_socket -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
return result;
}
@@ -4500,6 +4550,17 @@ ERL_NIF_TERM nsetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
#endif
+#if defined(SO_RCVTIMEO)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_timeval_opt(env, descP, SOL_SOCKET, SO_RCVTIMEO, eVal);
+}
+#endif
+
+
#if defined(SO_REUSEADDR)
static
ERL_NIF_TERM nsetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
@@ -4533,6 +4594,22 @@ ERL_NIF_TERM nsetopt_lvl_sock_sndbuf(ErlNifEnv* env,
#endif
+#if defined(SO_SNDTIMEO)
+static
+ERL_NIF_TERM nsetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sock_sndtimeo -> entry with"
+ "\r\n eVal: %T"
+ "\r\n", eVal) );
+
+ return nsetopt_timeval_opt(env, descP, SOL_SOCKET, SO_SNDTIMEO, eVal);
+}
+#endif
+
+
/* nsetopt_lvl_ip - Level *IP* option(s)
*/
@@ -6144,6 +6221,73 @@ ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
}
+/* nsetopt_timeval_opt - set an option that has an (timeval) bool value
+ */
+static
+ERL_NIF_TERM nsetopt_timeval_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ ERL_NIF_TERM eSec, eUSec;
+ struct timeval timeVal;
+ int res;
+ size_t sz;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_timeval_opt -> entry with"
+ "\r\n eVal: %T"
+ "\r\n", eVal) );
+
+ // It must be a map
+ if (!IS_MAP(env, eVal))
+ return esock_make_error(env, esock_atom_einval);
+
+ // It must have atleast ten attributes
+ if (!enif_get_map_size(env, eVal, &sz) || (sz < 2))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> extract attributes\r\n") );
+
+ if (!GET_MAP_VAL(env, eVal, atom_sec, &eSec))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_usec, &eUSec))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_timeval_opt -> decode attributes\r\n") );
+
+ if (!GET_LONG(env, eSec, &timeVal.tv_sec))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_LONG(env, eUSec, &timeVal.tv_usec))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_timeval_opt -> set timeval option\r\n") );
+
+ res = socket_setopt(descP->sock, level, opt, &timeVal, sizeof(timeVal));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_timeval_opt -> done with"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ return result;
+
+}
+
+
+
static
BOOLEAN_T elevel2level(BOOLEAN_T isEncoded,
int eLevel,
@@ -6719,6 +6863,12 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
break;
#endif
+#if defined(SO_RCVTIMEO)
+ case SOCKET_OPT_SOCK_RCVTIMEO:
+ result = ngetopt_lvl_sock_rcvtimeo(env, descP);
+ break;
+#endif
+
#if defined(SO_REUSEADDR)
case SOCKET_OPT_SOCK_REUSEADDR:
result = ngetopt_lvl_sock_reuseaddr(env, descP);
@@ -6737,6 +6887,12 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
break;
#endif
+#if defined(SO_SNDTIMEO)
+ case SOCKET_OPT_SOCK_SNDTIMEO:
+ result = ngetopt_lvl_sock_sndtimeo(env, descP);
+ break;
+#endif
+
#if defined(SO_TYPE)
case SOCKET_OPT_SOCK_TYPE:
result = ngetopt_lvl_sock_type(env, descP);
@@ -6748,6 +6904,11 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env,
break;
}
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_socket -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
return result;
}
@@ -6979,6 +7140,16 @@ ERL_NIF_TERM ngetopt_lvl_sock_rcvbuf(ErlNifEnv* env,
#endif
+#if defined(SO_RCVTIMEO)
+static
+ERL_NIF_TERM ngetopt_lvl_sock_rcvtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ return ngetopt_timeval_opt(env, descP, SOL_SOCKET, SO_RCVTIMEO);
+}
+#endif
+
+
#if defined(SO_REUSEADDR)
static
ERL_NIF_TERM ngetopt_lvl_sock_reuseaddr(ErlNifEnv* env,
@@ -7009,6 +7180,16 @@ ERL_NIF_TERM ngetopt_lvl_sock_sndbuf(ErlNifEnv* env,
#endif
+#if defined(SO_SNDTIMEO)
+static
+ERL_NIF_TERM ngetopt_lvl_sock_sndtimeo(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ return ngetopt_timeval_opt(env, descP, SOL_SOCKET, SO_SNDTIMEO);
+}
+#endif
+
+
#if defined(SO_TYPE)
static
ERL_NIF_TERM ngetopt_lvl_sock_type(ErlNifEnv* env,
@@ -8037,6 +8218,56 @@ ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
+/* ngetopt_timeval_opt - get an timeval option
+ */
+static
+ERL_NIF_TERM ngetopt_timeval_opt(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ int level,
+ int opt)
+{
+ ERL_NIF_TERM result;
+ struct timeval val;
+ SOCKOPTLEN_T valSz = sizeof(val);
+ int res;
+
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_timeval_opt -> entry with"
+ "\r\n level: %d"
+ "\r\n opt: %d"
+ "\r\n", level, opt) );
+
+ sys_memzero((char*) &val, valSz);
+ res = sock_getopt(descP->sock, level, opt, &val, &valSz);
+
+ if (res != 0) {
+ result = esock_make_error_errno(env, sock_errno());
+ } else {
+ ERL_NIF_TERM eTimeVal;
+ ERL_NIF_TERM keys[] = {atom_sec, atom_usec};
+ ERL_NIF_TERM vals[] = {MKL(env, val.tv_sec), MKL(env, val.tv_usec)};
+
+ unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
+ unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
+
+ ESOCK_ASSERT( (numKeys == numVals) );
+
+ if (!MKMA(env, keys, vals, numKeys, &eTimeVal))
+ return esock_make_error(env, esock_atom_einval);;
+
+ result = esock_make_ok2(env, eTimeVal);
+ }
+
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_timeval_opt -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ return result;
+}
+
+
+
/* ngetopt_str_opt - get an string option
*
* We provide the max size of the string. This is the
@@ -10238,6 +10469,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_peer_rwnd = MKA(env, str_peer_rwnd);
atom_peer_error = MKA(env, str_peer_error);
atom_probe = MKA(env, str_probe);
+ atom_sec = MKA(env, str_sec);
atom_select = MKA(env, str_select);
atom_sender_dry = MKA(env, str_sender_dry);
atom_send_failure = MKA(env, str_send_failure);
@@ -10245,6 +10477,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_sourceaddr = MKA(env, str_sourceaddr);
atom_timeout = MKA(env, str_timeout);
atom_true = MKA(env, str_true);
+ atom_usec = MKA(env, str_usec);
atom_want = MKA(env, str_want);
/* Global atom(s) */
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index c4c830e051..cd4feb8a46 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 03c87a6df5..15f9693490 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -88,6 +88,7 @@
udp_socket_option/0,
sctp_socket_option/0,
+ timeval/0,
ip_tos_flag/0,
ip_mreq/0,
ip_mreq_source/0,
@@ -101,7 +102,7 @@
msg_hdr/0,
-
+
uint8/0,
uint16/0,
uint20/0,
@@ -154,6 +155,16 @@
%%
%% </KOLLA>
+-type timeval() :: #{sec := integer(),
+ usec := integer()}.
+
+%% If the integer value is used its up to the caller to ensure its valid!
+-type ip_tos_flag() :: lowdeley |
+ throughput |
+ reliability |
+ mincost |
+ integer().
+
%% This type is used when requesting to become member of a multicast
%% group with a call to setopt. Example:
%%
@@ -166,13 +177,6 @@
%% interface => any}).
%%
-%% If the integer value is used its up to the caller to ensure its valid!
--type ip_tos_flag() :: lowdeley |
- throughput |
- reliability |
- mincost |
- integer().
-
-type ip_mreq() :: #{multiaddr := ip4_address(),
interface := any | ip4_address()}.
%% -type ip_mreqn() :: #{multiaddr := ip4_address(),
@@ -572,7 +576,7 @@
-define(SOCKET_OPT_SOCK_RCVBUF, 19).
%% -define(SOCKET_OPT_SOCK_RCVBUFFORCE, 20).
%% -define(SOCKET_OPT_SOCK_RCVLOWAT, 21).
-%% -define(SOCKET_OPT_SOCK_RCVTIMEO, 22).
+-define(SOCKET_OPT_SOCK_RCVTIMEO, 22).
-define(SOCKET_OPT_SOCK_REUSEADDR, 23).
-define(SOCKET_OPT_SOCK_REUSEPORT, 24).
%% -define(SOCKET_OPT_SOCK_RXQ_OVFL, 25).
@@ -580,7 +584,7 @@
-define(SOCKET_OPT_SOCK_SNDBUF, 27).
%% -define(SOCKET_OPT_SOCK_SNDBUFFORCE, 28).
%% -define(SOCKET_OPT_SOCK_SNDLOWAT, 29).
-%% -define(SOCKET_OPT_SOCK_SNDTIMEO, 30).
+-define(SOCKET_OPT_SOCK_SNDTIMEO, 30).
%% -define(SOCKET_OPT_SOCK_TIMESTAMP, 31).
-define(SOCKET_OPT_SOCK_TYPE, 32).
@@ -2121,12 +2125,18 @@ enc_setopt_value(socket, priority, V, _D, _T, _P) when is_integer(V) ->
V;
enc_setopt_value(socket, rcvbuf, V, _D, _T, _P) when is_integer(V) ->
V;
+enc_setopt_value(socket, rcvtimeo, #{sec := Sec, usec := USec} = V, _D, _T, _P)
+ when is_integer(Sec) andalso is_integer(USec) ->
+ V;
enc_setopt_value(socket, reuseaddr, V, _D, _T, _P) when is_boolean(V) ->
V;
enc_setopt_value(socket, reuseport, V, _D, _T, _P) when is_boolean(V) ->
V;
enc_setopt_value(socket, sndbuf, V, _D, _T, _P) when is_integer(V) ->
V;
+enc_setopt_value(socket, sndtimeo, #{sec := Sec, usec := USec} = V, _D, _T, _P)
+ when is_integer(Sec) andalso is_integer(USec) ->
+ V;
enc_setopt_value(socket = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
@@ -2515,8 +2525,8 @@ enc_sockopt_key(socket = L, rcvbufforce = Opt, _Dir, _D, _T, _P) ->
%% May not work on linux.
enc_sockopt_key(socket = L, rcvlowat = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(socket, rcvtimeo = Opt, _Dir, _D, _T, _P) ->
- not_supported(Opt);
+enc_sockopt_key(socket = _L, rcvtimeo = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_SOCK_RCVTIMEO;
enc_sockopt_key(socket = _L, reuseaddr = _Opt, _Dir, _D, _T, _P) ->
?SOCKET_OPT_SOCK_REUSEADDR;
enc_sockopt_key(socket = _L, reuseport = _Opt, _Dir, D, _T, _P)
@@ -2526,15 +2536,15 @@ enc_sockopt_key(socket = L, rxq_ovfl = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(socket = L, setfib = Opt, set = _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(socket, sndbuf = _Opt, _Dir, _D, _T, _P) ->
+enc_sockopt_key(socket = _L, sndbuf = _Opt, _Dir, _D, _T, _P) ->
?SOCKET_OPT_SOCK_SNDBUF;
enc_sockopt_key(socket = L, sndbufforce = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
%% Not changeable on linux.
enc_sockopt_key(socket = L, sndlowat = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(socket = L, sndtimeo = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(socket = _L, sndtimeo = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_SOCK_SNDTIMEO;
enc_sockopt_key(socket = L, timestamp = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(socket = _L, type = _Opt, _Dir, _D, _T, _P) ->
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index 986363b56d..80de3574d1 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -141,11 +141,14 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) ->
"~n debug: ~s"
"~n prio: ~s"
"~n rcvbuf: ~s"
+ "~n rcvtimeo: ~s"
"~n sndbuf: ~s"
+ "~n sndtimeo: ~s"
"~n => try find (local) address",
[F(domain), F(type), F(protocol),
F(broadcast), F(dontroute), F(keepalive), F(reuseaddr), F(linger),
- F(debug), F(priority), F(rcvbuf), F(sndbuf)]),
+ F(debug), F(priority),
+ F(rcvbuf), F(rcvtimeo), F(sndbuf), F(sndtimeo)]),
Addr = which_addr(Domain),
SA = #{family => Domain,
addr => Addr},
@@ -315,7 +318,7 @@ manager_stream_init(Sock, ID, NumAcceptors, Acc)
case acceptor_start(Sock, ID) of
{ok, {Pid, MRef}} ->
i("acceptor ~w (~p) started", [ID, Pid]),
- ?LIB:sleep(5000),
+ ?LIB:sleep(2000),
manager_stream_init(Sock, ID+1, NumAcceptors-1,
[{ID, Pid, MRef}|Acc]);
{error, Reason} ->
@@ -593,8 +596,10 @@ handler_init(Manager, ID, Peek, Sock) ->
RA = GSO(reuseaddr),
RP = GSO(reuseport),
OOBI = GSO(oobinline),
- SndBuf = GSO(sndbuf),
RcvBuf = GSO(rcvbuf),
+ RcvTO = GSO(rcvtimeo),
+ SndBuf = GSO(sndbuf),
+ SndTO = GSO(sndtimeo),
Linger = GSO(linger),
MTU = GIP(mtu),
MTUDisc = GIP(mtu_discover),
@@ -613,8 +618,10 @@ handler_init(Manager, ID, Peek, Sock) ->
"~n (socket) Reuse Port: ~s"
"~n (socket) Bind To Device: ~s"
"~n (socket) OOBInline: ~s"
- "~n (socket) SndBuf: ~s"
"~n (socket) RcvBuf: ~s"
+ "~n (socket) RcvTO: ~s"
+ "~n (socket) SndBuf: ~s"
+ "~n (socket) SndTO: ~s"
"~n (socket) Linger: ~s"
"~n (ip) MTU: ~s"
"~n (ip) MTU Discovery: ~s"
@@ -626,10 +633,12 @@ handler_init(Manager, ID, Peek, Sock) ->
"~n (ip) Recv TOS: ~s"
"~n (ip) Recv TTL: ~s",
[Domain, Type, Proto,
- RA, RP, B2D, OOBI, SndBuf, RcvBuf, Linger,
+ RA, RP, B2D, OOBI,
+ RcvBuf, RcvTO, SndBuf, SndTO,
+ Linger,
MTU, MTUDisc, MALL, MIF, MLoop, MTTL,
NF, RecvTOS, RecvTTL]),
- %% socket:setopt(Sock, otp, debug, true),
+
handler_loop(#handler{peek = Peek,
manager = Manager,
type = Type,