diff options
author | Micael Karlberg <[email protected]> | 2018-07-20 12:28:19 +0200 |
---|---|---|
committer | Micael Karlberg <[email protected]> | 2018-09-18 14:50:18 +0200 |
commit | 3f1d17f3031b71ca6ff1f8e051859ad55e55822b (patch) | |
tree | 3939712ac67454970e3fa3501705aa5e9cd4ede5 | |
parent | bd36af21717b138c91724128e592b3fc587bb07a (diff) | |
download | otp-3f1d17f3031b71ca6ff1f8e051859ad55e55822b.tar.gz otp-3f1d17f3031b71ca6ff1f8e051859ad55e55822b.tar.bz2 otp-3f1d17f3031b71ca6ff1f8e051859ad55e55822b.zip |
[socket-nif] Add support for socket (level socket) option(s) [rcv|snd]timeo
Added support for socket level socket option RCVTIMEO and SNDTIMEO.
These are both a little strange, at least on linux. See the man
pages for more info.
OTP-14831
-rw-r--r-- | erts/doc/src/socket.xml | 9 | ||||
-rw-r--r-- | erts/doc/src/socket_usage.xml | 18 | ||||
-rw-r--r-- | erts/emulator/nifs/common/socket_int.h | 16 | ||||
-rw-r--r-- | erts/emulator/nifs/common/socket_nif.c | 233 | ||||
-rw-r--r-- | erts/preloaded/ebin/socket.beam | bin | 56044 -> 56284 bytes | |||
-rw-r--r-- | erts/preloaded/src/socket.erl | 40 | ||||
-rw-r--r-- | lib/kernel/test/socket_server.erl | 21 |
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 Binary files differindex c4c830e051..cd4feb8a46 100644 --- a/erts/preloaded/ebin/socket.beam +++ b/erts/preloaded/ebin/socket.beam 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, |