aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-19 16:39:13 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commit7a5b320b5bb5ec45b21839005e8538172908fb57 (patch)
treea901cc18fb10ed7fe6352a0205456f89f378c29a
parentf0a2e68a31ac585780ad05f777f1b7551770420e (diff)
downloadotp-7a5b320b5bb5ec45b21839005e8538172908fb57.tar.gz
otp-7a5b320b5bb5ec45b21839005e8538172908fb57.tar.bz2
otp-7a5b320b5bb5ec45b21839005e8538172908fb57.zip
[socket-nif] Add (partial) support for socket (level sctp) option associnfo
Added support for the SCTP option ASSOCINFO. This option is a bit tricky. As the underlying structure (sctp_assocparams) contains the assoc_id, it begs the question what happens if this option is fetched for: * The own assoc (which means that we might have the assoc id in the descriptor and can initiate that part of the struct accordningly). * Another assoc: From assoc A asks for info with assoc_id set to that of assoc B. * The "owning" endpoint. * Another endpoint (an endpoint to which the assoc does not belong). So, if the user calls socket:[getopt|setopt] for an association socket, shall we require that the assoc_id field is set to -1? Or not set at all and therefor filled in automatically by the nif-code? And, if the user calls socket:[getopt|setopt] for an endpoint socket, shall we require that the assoc_id field is set to a valid id? Or shall it not be allowed? Questions, questions... OTP-14831
-rw-r--r--erts/doc/src/socket.xml3
-rw-r--r--erts/doc/src/socket_usage.xml9
-rw-r--r--erts/emulator/nifs/common/socket_int.h1
-rw-r--r--erts/emulator/nifs/common/socket_nif.c224
-rw-r--r--erts/preloaded/ebin/socket.beambin52640 -> 53256 bytes
-rw-r--r--erts/preloaded/src/socket.erl31
-rw-r--r--lib/kernel/test/socket_server.erl8
7 files changed, 269 insertions, 7 deletions
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index 4ecf35b8ed..3e8e7af5c6 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -137,6 +137,9 @@
<datatype>
<name name="sctp_event_subscribe"/>
</datatype>
+ <datatype>
+ <name name="sctp_assocparams"/>
+ </datatype>
</datatypes>
<funcs>
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 9f25e2e9b9..60cb424cde 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -452,8 +452,15 @@
<cell><em>Other</em></cell>
</row>
<row>
+ <cell>associnfo</cell>
+ <cell>sctp_assocparams()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>none</cell>
+ </row>
+ <row>
<cell>autoclose</cell>
- <cell>integer()</cell>
+ <cell>non_neg_integer()</cell>
<cell>yes</cell>
<cell>yes</cell>
<cell>none</cell>
diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h
index 67e4baba27..28f42a7345 100644
--- a/erts/emulator/nifs/common/socket_int.h
+++ b/erts/emulator/nifs/common/socket_int.h
@@ -167,6 +167,7 @@ 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 MCREATE(N) enif_mutex_create((N))
#define MDESTROY(M) enif_mutex_destroy((M))
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 2a60a840c8..50e7ec5f5e 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -542,6 +542,7 @@ typedef union {
#define SOCKET_OPT_UDP_CORK 1
+#define SOCKET_OPT_SCTP_ASSOCINFO 2
#define SOCKET_OPT_SCTP_AUTOCLOSE 8
#define SOCKET_OPT_SCTP_DISABLE_FRAGMENTS 12
#define SOCKET_OPT_SCTP_EVENTS 14
@@ -1212,6 +1213,11 @@ static ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
SocketDescriptor* descP,
int eOpt,
ERL_NIF_TERM eVal);
+#if defined(SCTP_ASSOCINFO)
+static ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(SCTP_AUTOCLOSE)
static ERL_NIF_TERM nsetopt_lvl_sctp_autoclose(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1435,6 +1441,10 @@ static ERL_NIF_TERM ngetopt_lvl_udp_cork(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
SocketDescriptor* descP,
int eOpt);
+#if defined(SCTP_ASSOCINFO)
+static ERL_NIF_TERM ngetopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(SCTP_AUTOCLOSE)
static ERL_NIF_TERM ngetopt_lvl_sctp_autoclose(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1780,11 +1790,13 @@ static const struct in6_addr in6addr_loopback =
static char str_adaptation_layer[] = "adaptation_layer";
static char str_address[] = "address";
static char str_association[] = "association";
+static char str_assoc_id[] = "assoc_id";
static char str_authentication[] = "authentication";
// static char str_any[] = "any";
static char str_close[] = "close";
static char str_closed[] = "closed";
static char str_closing[] = "closing";
+static char str_cookie_life[] = "cookie_life";
static char str_data_in[] = "data_in";
static char str_do[] = "do";
static char str_dont[] = "dont";
@@ -1794,12 +1806,15 @@ static char str_in4_sockaddr[] = "in4_sockaddr";
static char str_in6_sockaddr[] = "in6_sockaddr";
static char str_iow[] = "iow";
static char str_interface[] = "interface";
+static char str_local_rwnd[] = "local_rwnd";
// static char str_loopback[] = "loopback";
+static char str_max_rxt[] = "max_rxt";
static char str_multiaddr[] = "multiaddr";
static char str_nif_abort[] = "nif_abort";
static char str_num_dlocal[] = "num_domain_local";
static char str_num_dinet[] = "num_domain_inet";
static char str_num_dinet6[] = "num_domain_inet6";
+static char str_num_peer_dests[] = "num_peer_dests";
static char str_num_pip[] = "num_proto_ip";
static char str_num_psctp[] = "num_proto_sctp";
static char str_num_ptcp[] = "num_proto_tcp";
@@ -1810,6 +1825,7 @@ static char str_num_tseqpkgs[] = "num_type_seqpacket";
static char str_num_tstreams[] = "num_type_stream";
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_select[] = "select";
static char str_sender_dry[] = "sender_dry";
@@ -1878,10 +1894,12 @@ ERL_NIF_TERM esock_atom_einval;
static ERL_NIF_TERM atom_adaptation_layer;
static ERL_NIF_TERM atom_address;
static ERL_NIF_TERM atom_association;
+static ERL_NIF_TERM atom_assoc_id;
static ERL_NIF_TERM atom_authentication;
static ERL_NIF_TERM atom_close;
static ERL_NIF_TERM atom_closed;
static ERL_NIF_TERM atom_closing;
+static ERL_NIF_TERM atom_cookie_life;
static ERL_NIF_TERM atom_data_in;
static ERL_NIF_TERM atom_do;
static ERL_NIF_TERM atom_dont;
@@ -1891,11 +1909,14 @@ static ERL_NIF_TERM atom_in4_sockaddr;
static ERL_NIF_TERM atom_in6_sockaddr;
static ERL_NIF_TERM atom_iow;
static ERL_NIF_TERM atom_interface;
+static ERL_NIF_TERM atom_local_rwnd;
+static ERL_NIF_TERM atom_max_rxt;
static ERL_NIF_TERM atom_multiaddr;
static ERL_NIF_TERM atom_nif_abort;
static ERL_NIF_TERM atom_num_dinet;
static ERL_NIF_TERM atom_num_dinet6;
static ERL_NIF_TERM atom_num_dlocal;
+static ERL_NIF_TERM atom_num_peer_dests;
static ERL_NIF_TERM atom_num_pip;
static ERL_NIF_TERM atom_num_psctp;
static ERL_NIF_TERM atom_num_ptcp;
@@ -1906,6 +1927,7 @@ static ERL_NIF_TERM atom_num_tseqpkgs;
static ERL_NIF_TERM atom_num_tstreams;
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_select;
static ERL_NIF_TERM atom_sender_dry;
@@ -2042,7 +2064,7 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env,
ERL_NIF_TERM vals[] = {BOOL2ATOM(data.dbg), BOOL2ATOM(data.iow), lgcnt};
ERL_NIF_TERM info;
unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
- unsigned int numVals = sizeof(keys) / sizeof(ERL_NIF_TERM);
+ unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
ESOCK_ASSERT( (numKeys == numVals) );
@@ -5513,6 +5535,12 @@ ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
"\r\n", eOpt) );
switch (eOpt) {
+#if defined(SCTP_ASSOCINFO)
+ case SOCKET_OPT_SCTP_ASSOCINFO:
+ result = nsetopt_lvl_sctp_associnfo(env, descP, eVal);
+ break;
+#endif
+
#if defined(SCTP_AUTOCLOSE)
case SOCKET_OPT_SCTP_AUTOCLOSE:
result = nsetopt_lvl_sctp_autoclose(env, descP, eVal);
@@ -5546,6 +5574,116 @@ ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
}
+/* nsetopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
+ */
+#if defined(SCTP_ASSOCINFO)
+static
+ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ ERL_NIF_TERM eAssocId, eMaxRxt, eNumPeerDests;
+ ERL_NIF_TERM ePeerRWND, eLocalRWND, eCookieLife;
+ struct sctp_assocparams assocParams;
+ int res;
+ size_t sz;
+ unsigned int tmp;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_associnfo -> 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 < 6))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_associnfo -> extract attributes\r\n") );
+
+ if (!GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_max_rxt, &eMaxRxt))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_num_peer_dests, &eNumPeerDests))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_peer_rwnd, &ePeerRWND))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_local_rwnd, &eLocalRWND))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_cookie_life, &eCookieLife))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_events -> decode attributes\r\n") );
+
+ if (!GET_INT(env, eAssocId, &assocParams.sasoc_assoc_id))
+ return esock_make_error(env, esock_atom_einval);
+
+ /*
+ * We should really make sure this is ok in erlang (to ensure that
+ * the value fits in 16-bits).
+ * The value should be a 16-bit unsigned int...
+ * Both sasoc_asocmaxrxt and sasoc_number_peer_destinations.
+ */
+
+ /*
+ if (!GET_UINT(env, eAssocId, (unsigned int*) &assocParams.sasoc_asocmaxrxt))
+ return esock_make_error(env, esock_atom_einval);
+ */
+ if (!GET_UINT(env, eAssocId, &tmp))
+ return esock_make_error(env, esock_atom_einval);
+ assocParams.sasoc_asocmaxrxt = (uint16_t) tmp;
+
+ /*
+ if (!GET_UINT(env, eAssocId, (unsigned int*) &assocParams.sasoc_number_peer_destinations))
+ return esock_make_error(env, esock_atom_einval);
+ */
+ if (!GET_UINT(env, eAssocId, &tmp))
+ return esock_make_error(env, esock_atom_einval);
+ assocParams.sasoc_number_peer_destinations = (uint16_t) tmp;
+
+ if (!GET_UINT(env, eAssocId, &assocParams.sasoc_peer_rwnd))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_UINT(env, eAssocId, &assocParams.sasoc_local_rwnd))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_UINT(env, eAssocId, &assocParams.sasoc_cookie_life))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_events -> set associnfo option\r\n") );
+
+ res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_ASSOCINFO,
+ &assocParams, sizeof(assocParams));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_associnfo -> done with"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ return result;
+
+}
+#endif
+
+
/* nsetopt_lvl_sctp_autoclose - Level SCTP AUTOCLOSE option
*/
#if defined(SCTP_AUTOCLOSE)
@@ -7330,7 +7468,18 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
{
ERL_NIF_TERM result;
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_sctp -> entry with"
+ "\r\n opt: %d"
+ "\r\n", eOpt) );
+
switch (eOpt) {
+#if defined(SCTP_ASSOCINFO)
+ case SOCKET_OPT_SCTP_ASSOCINFO:
+ result = ngetopt_lvl_sctp_associnfo(env, descP);
+ break;
+#endif
+
#if defined(SCTP_AUTOCLOSE)
case SOCKET_OPT_SCTP_AUTOCLOSE:
result = ngetopt_lvl_sctp_autoclose(env, descP);
@@ -7354,10 +7503,77 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
break;
}
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_sctp -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
return result;
}
+/* ngetopt_lvl_sctp_associnfo - Level SCTP ASSOCINFO option
+ *
+ * <KOLLA>
+ *
+ * We should really specify which association this relates to,
+ * as it is now we get assoc-id = 0. If this socket is an
+ * association (and not an endpoint) then it will have an
+ * assoc id. But since the sctp support at present is "limited",
+ * we leave it for now.
+ * What do we do if this is an endpoint? Invalid op?
+ *
+ * </KOLLA>
+ */
+#if defined(SCTP_ASSOCINFO)
+static
+ERL_NIF_TERM ngetopt_lvl_sctp_associnfo(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ struct sctp_assocparams val;
+ SOCKOPTLEN_T valSz = sizeof(val);
+ int res;
+
+ SSDBG( descP, ("SOCKET", "ngetopt_lvl_sctp_associnfo -> entry\r\n") );
+
+ sys_memzero((char*) &val, valSz);
+ res = sock_getopt(descP->sock, IPPROTO_SCTP, SCTP_ASSOCINFO, &val, &valSz);
+
+ if (res != 0) {
+ result = esock_make_error_errno(env, sock_errno());
+ } else {
+ ERL_NIF_TERM eAssocParams;
+ ERL_NIF_TERM keys[] = {atom_assoc_id, atom_max_rxt, atom_num_peer_dests,
+ atom_peer_rwnd, atom_local_rwnd, atom_cookie_life};
+ ERL_NIF_TERM vals[] = {MKUI(env, val.sasoc_assoc_id),
+ MKUI(env, val.sasoc_asocmaxrxt),
+ MKUI(env, val.sasoc_number_peer_destinations),
+ MKUI(env, val.sasoc_peer_rwnd),
+ MKUI(env, val.sasoc_local_rwnd),
+ MKUI(env, val.sasoc_cookie_life)};
+ 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, &eAssocParams))
+ return esock_make_error(env, esock_atom_einval);;
+
+ result = esock_make_ok2(env, eAssocParams);
+ }
+
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_sctp_associnfo -> done with"
+ "\r\n res: %d"
+ "\r\n result: %T"
+ "\r\n", res, result) );
+
+ return result;
+}
+#endif
+
+
/* ngetopt_lvl_sctp_autoclose - Level SCTP AUTOCLOSE option
*/
#if defined(SCTP_AUTOCLOSE)
@@ -9610,10 +9826,12 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_adaptation_layer = MKA(env, str_adaptation_layer);
atom_address = MKA(env, str_address);
atom_association = MKA(env, str_association);
+ atom_assoc_id = MKA(env, str_assoc_id);
atom_authentication = MKA(env, str_authentication);
atom_close = MKA(env, str_close);
atom_closed = MKA(env, str_closed);
atom_closing = MKA(env, str_closing);
+ atom_cookie_life = MKA(env, str_cookie_life);
atom_data_in = MKA(env, str_data_in);
atom_do = MKA(env, str_do);
atom_dont = MKA(env, str_dont);
@@ -9623,11 +9841,14 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_in6_sockaddr = MKA(env, str_in6_sockaddr);
atom_iow = MKA(env, str_iow);
atom_interface = MKA(env, str_interface);
+ atom_local_rwnd = MKA(env, str_local_rwnd);
+ atom_max_rxt = MKA(env, str_max_rxt);
atom_multiaddr = MKA(env, str_multiaddr);
atom_nif_abort = MKA(env, str_nif_abort);
atom_num_dinet = MKA(env, str_num_dinet);
atom_num_dinet6 = MKA(env, str_num_dinet6);
atom_num_dlocal = MKA(env, str_num_dlocal);
+ atom_num_peer_dests = MKA(env, str_num_peer_dests);
atom_num_pip = MKA(env, str_num_pip);
atom_num_psctp = MKA(env, str_num_psctp);
atom_num_ptcp = MKA(env, str_num_ptcp);
@@ -9637,6 +9858,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_num_tseqpkgs = MKA(env, str_num_tseqpkgs);
atom_num_tstreams = MKA(env, str_num_tstreams);
atom_partial_delivery = MKA(env, str_partial_delivery);
+ atom_peer_rwnd = MKA(env, str_peer_rwnd);
atom_peer_error = MKA(env, str_peer_error);
atom_probe = MKA(env, str_probe);
atom_select = MKA(env, str_select);
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 63887692f9..0c496443bf 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 e3fb417a35..feb2e25312 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -95,6 +95,7 @@
ipv6_mreq/0,
ipv6_pmtudisc/0,
sctp_event_subscribe/0,
+ sctp_assocparams/0,
msg_hdr/0
@@ -187,6 +188,13 @@
authentication := boolean(),
sender_dry := boolean()}.
+-type sctp_assocparams() :: #{assoc_id := integer(),
+ max_rxt := non_neg_integer(),
+ num_peer_dests := non_neg_integer(),
+ peer_rwnd := non_neg_integer(),
+ local_rwnd := non_neg_integer(),
+ cookie_life := non_neg_integer()}.
+
-type sockaddr_un() :: #{family := local,
path := binary() | string()}.
-type sockaddr_in4() :: #{family := inet,
@@ -637,7 +645,7 @@
-define(SOCKET_OPT_UDP_CORK, 1).
%% -define(SOCKET_OPT_SCTP_ADAPTION_LAYER, 1).
-%% -define(SOCKET_OPT_SCTP_ASSOCINFO, 2).
+-define(SOCKET_OPT_SCTP_ASSOCINFO, 2).
%% -define(SOCKET_OPT_SCTP_AUTH_ACTIVE_KEY, 3).
%% -define(SOCKET_OPT_SCTP_AUTH_ASCONF, 4).
%% -define(SOCKET_OPT_SCTP_AUTH_CHUNK, 5).
@@ -2172,8 +2180,23 @@ enc_setopt_value(udp, cork, V, _D, T, P)
enc_setopt_value(udp = L, Opt, _V, _D, _T, _P) ->
not_supported({L, Opt});
+enc_setopt_value(sctp, associnfo, #{assoc_id := AssocId,
+ asocmaxrxt := MaxRxt,
+ num_peer_dests := NumPeerDests,
+ peer_rwnd := PeerRWND,
+ local_rwnd := LocalRWND,
+ cookie_life := CLife} = V,
+ _D, _T, P)
+ when is_integer(AssocId) andalso
+ is_integer(MaxRxt) andalso (MaxRxt >= 0) andalso
+ is_integer(NumPeerDests) andalso (NumPeerDests >= 0) andalso
+ is_integer(PeerRWND) andalso (PeerRWND >= 0) andalso
+ is_integer(LocalRWND) andalso (LocalRWND >= 0) andalso
+ is_integer(CLife) andalso (CLife >= 0) andalso
+ (P =:= sctp) ->
+ V;
enc_setopt_value(sctp, autoclose, V, _D, _T, P)
- when is_integer(V) andalso (P =:= sctp) ->
+ when is_integer(V) andalso (V >= 0) andalso (P =:= sctp) ->
V;
enc_setopt_value(sctp, disable_fragments, V, _D, _T, P)
when is_boolean(V) andalso (P =:= sctp) ->
@@ -2595,8 +2618,8 @@ enc_sockopt_key(udp = L, UnknownOpt, _Dir, _D, _T, _P) ->
%% SCTP socket options
enc_sockopt_key(sctp = L, adaption_layer = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(sctp = L, associnfo = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(sctp = _L, associnfo = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_SCTP_ASSOCINFO;
enc_sockopt_key(sctp = L, auth_active_key = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, auth_asconf = Opt, _Dir, _D, _T, _P) ->
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index a9b4aca5f8..56200e0ae9 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -200,8 +200,14 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) ->
{error, R} -> f("error: ~p", [R])
end
end,
+ %% ok = socket:setopt(Sock, otp, debug, true),
i("Miscellaneous options: "
- "~n disable-fragments: ~s", [GO(disable_fragments)]),
+ "~n associnfo: ~s"
+ "~n autoclose: ~s"
+ "~n disable-fragments: ~s",
+ [GO(associnfo),
+ GO(autoclose),
+ GO(disable_fragments)]),
Events = #{data_in => true,
association => true,
address => true,