aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/socket.xml3
-rw-r--r--erts/doc/src/socket_usage.xml14
-rw-r--r--erts/emulator/nifs/common/socket_nif.c194
-rw-r--r--erts/preloaded/ebin/socket.beambin53256 -> 53668 bytes
-rw-r--r--erts/preloaded/src/socket.erl26
-rw-r--r--lib/kernel/test/socket_server.erl6
6 files changed, 222 insertions, 21 deletions
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index 3e8e7af5c6..f6b25c8563 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -140,6 +140,9 @@
<datatype>
<name name="sctp_assocparams"/>
</datatype>
+ <datatype>
+ <name name="sctp_rtoinfo"/>
+ </datatype>
</datatypes>
<funcs>
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 60cb424cde..1e325016ff 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -50,6 +50,13 @@
<cell><em>Other</em></cell>
</row>
<row>
+ <cell>assoc_id</cell>
+ <cell>integer()</cell>
+ <cell>no</cell>
+ <cell>yes</cell>
+ <cell>type = seqpacket, protocol = sctp, is an association</cell>
+ </row>
+ <row>
<cell>debug</cell>
<cell>boolean()</cell>
<cell>yes</cell>
@@ -486,6 +493,13 @@
<cell>yes</cell>
<cell>none</cell>
</row>
+ <row>
+ <cell>rtoinfo</cell>
+ <cell>sctp_rtoinfo()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>none</cell>
+ </row>
</table>
</section>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 50e7ec5f5e..f9643cccbf 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -547,6 +547,7 @@ typedef union {
#define SOCKET_OPT_SCTP_DISABLE_FRAGMENTS 12
#define SOCKET_OPT_SCTP_EVENTS 14
#define SOCKET_OPT_SCTP_NODELAY 23
+#define SOCKET_OPT_SCTP_RTOINFO 29
/* =================================================================== *
@@ -1238,6 +1239,11 @@ static ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(SCTP_RTOINFO)
+static ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#endif // defined(HAVE_SCTP)
static ERL_NIF_TERM ngetopt(ErlNifEnv* env,
@@ -1457,6 +1463,10 @@ static ERL_NIF_TERM ngetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_sctp_nodelay(ErlNifEnv* env,
SocketDescriptor* descP);
#endif
+#if defined(SCTP_RTOINFO)
+static ERL_NIF_TERM ngetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#endif // defined(HAVE_SCTP)
static ERL_NIF_TERM nsockname(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1805,10 +1815,13 @@ static char str_global_counters[] = "global_counters";
static char str_in4_sockaddr[] = "in4_sockaddr";
static char str_in6_sockaddr[] = "in6_sockaddr";
static char str_iow[] = "iow";
+static char str_initial[] = "initial";
static char str_interface[] = "interface";
static char str_local_rwnd[] = "local_rwnd";
// static char str_loopback[] = "loopback";
+static char str_max[] = "max";
static char str_max_rxt[] = "max_rxt";
+static char str_min[] = "min";
static char str_multiaddr[] = "multiaddr";
static char str_nif_abort[] = "nif_abort";
static char str_num_dlocal[] = "num_domain_local";
@@ -1908,9 +1921,12 @@ static ERL_NIF_TERM atom_global_counters;
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_initial;
static ERL_NIF_TERM atom_interface;
static ERL_NIF_TERM atom_local_rwnd;
+static ERL_NIF_TERM atom_max;
static ERL_NIF_TERM atom_max_rxt;
+static ERL_NIF_TERM atom_min;
static ERL_NIF_TERM atom_multiaddr;
static ERL_NIF_TERM atom_nif_abort;
static ERL_NIF_TERM atom_num_dinet;
@@ -5565,6 +5581,12 @@ ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
break;
#endif
+#if defined(SCTP_RTOINFO)
+ case SOCKET_OPT_SCTP_RTOINFO:
+ result = nsetopt_lvl_sctp_rtoinfo(env, descP, eVal);
+ break;
+#endif
+
default:
result = esock_make_error(env, esock_atom_einval);
break;
@@ -5625,45 +5647,37 @@ ERL_NIF_TERM nsetopt_lvl_sctp_associnfo(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_events -> decode attributes\r\n") );
+ ("SOCKET", "nsetopt_lvl_sctp_associnfo -> 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 values (max-rxt and num-peer-dests) 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))
+ if (!GET_UINT(env, eMaxRxt, &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))
+ if (!GET_UINT(env, eNumPeerDests, &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))
+ if (!GET_UINT(env, ePeerRWND, &assocParams.sasoc_peer_rwnd))
return esock_make_error(env, esock_atom_einval);
- if (!GET_UINT(env, eAssocId, &assocParams.sasoc_local_rwnd))
+ if (!GET_UINT(env, eLocalRWND, &assocParams.sasoc_local_rwnd))
return esock_make_error(env, esock_atom_einval);
- if (!GET_UINT(env, eAssocId, &assocParams.sasoc_cookie_life))
+ if (!GET_UINT(env, eCookieLife, &assocParams.sasoc_cookie_life))
return esock_make_error(env, esock_atom_einval);
SSDBG( descP,
- ("SOCKET", "nsetopt_lvl_sctp_events -> set associnfo option\r\n") );
+ ("SOCKET", "nsetopt_lvl_sctp_associnfo -> set associnfo option\r\n") );
res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_ASSOCINFO,
&assocParams, sizeof(assocParams));
@@ -5821,6 +5835,85 @@ ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
#endif
+/* nsetopt_lvl_sctp_rtoinfo - Level SCTP RTOINFO option
+ */
+#if defined(SCTP_RTOINFO)
+static
+ERL_NIF_TERM nsetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ ERL_NIF_TERM eAssocId, eInitial, eMax, eMin;
+ struct sctp_rtoinfo rtoInfo;
+ int res;
+ size_t sz;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> 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 < 4))
+ 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_assoc_id, &eAssocId))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_initial, &eInitial))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_max, &eMax))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_min, &eMin))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> decode attributes\r\n") );
+
+ if (!GET_INT(env, eAssocId, &rtoInfo.srto_assoc_id))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_UINT(env, eInitial, &rtoInfo.srto_initial))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_UINT(env, eMax, &rtoInfo.srto_max))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_UINT(env, eMin, &rtoInfo.srto_min))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> set associnfo option\r\n") );
+
+ res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_RTOINFO,
+ &rtoInfo, sizeof(rtoInfo));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_rtoinfo -> done with"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ return result;
+
+}
+#endif
+
+
#endif // defined(HAVE_SCTP)
@@ -7498,6 +7591,12 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
break;
#endif
+#if defined(SCTP_RTOINFO)
+ case SOCKET_OPT_SCTP_RTOINFO:
+ result = ngetopt_lvl_sctp_rtoinfo(env, descP);
+ break;
+#endif
+
default:
result = esock_make_error(env, esock_atom_einval);
break;
@@ -7610,6 +7709,66 @@ ERL_NIF_TERM ngetopt_lvl_sctp_nodelay(ErlNifEnv* env,
#endif
+/* 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 (we can assume). 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_RTOINFO)
+static
+ERL_NIF_TERM ngetopt_lvl_sctp_rtoinfo(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ struct sctp_rtoinfo val;
+ SOCKOPTLEN_T valSz = sizeof(val);
+ int res;
+
+ SSDBG( descP, ("SOCKET", "ngetopt_lvl_sctp_rtoinfo -> entry\r\n") );
+
+ sys_memzero((char*) &val, valSz);
+ res = sock_getopt(descP->sock, IPPROTO_SCTP, SCTP_RTOINFO, &val, &valSz);
+
+ if (res != 0) {
+ result = esock_make_error_errno(env, sock_errno());
+ } else {
+ ERL_NIF_TERM eRTOInfo;
+ ERL_NIF_TERM keys[] = {atom_assoc_id, atom_initial, atom_max, atom_min};
+ ERL_NIF_TERM vals[] = {MKUI(env, val.srto_assoc_id),
+ MKUI(env, val.srto_initial),
+ MKUI(env, val.srto_max),
+ MKUI(env, val.srto_min)};
+ 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, &eRTOInfo))
+ return esock_make_error(env, esock_atom_einval);;
+
+ result = esock_make_ok2(env, eRTOInfo);
+ }
+
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_sctp_rtoinfo -> done with"
+ "\r\n res: %d"
+ "\r\n result: %T"
+ "\r\n", res, result) );
+
+ return result;
+}
+#endif
+
+
+
#endif // defined(HAVE_SCTP)
@@ -9840,9 +9999,12 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_in4_sockaddr = MKA(env, str_in4_sockaddr);
atom_in6_sockaddr = MKA(env, str_in6_sockaddr);
atom_iow = MKA(env, str_iow);
+ atom_initial = MKA(env, str_initial);
atom_interface = MKA(env, str_interface);
atom_local_rwnd = MKA(env, str_local_rwnd);
+ atom_max = MKA(env, str_max);
atom_max_rxt = MKA(env, str_max_rxt);
+ atom_min = MKA(env, str_min);
atom_multiaddr = MKA(env, str_multiaddr);
atom_nif_abort = MKA(env, str_nif_abort);
atom_num_dinet = MKA(env, str_num_dinet);
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 0c496443bf..427c08cd57 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 feb2e25312..0bc3ed8ec9 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -96,6 +96,7 @@
ipv6_pmtudisc/0,
sctp_event_subscribe/0,
sctp_assocparams/0,
+ sctp_rtoinfo/0,
msg_hdr/0
@@ -195,6 +196,11 @@
local_rwnd := non_neg_integer(),
cookie_life := non_neg_integer()}.
+-type sctp_rtoinfo() :: #{assoc_id := integer(),
+ initial := non_neg_integer(),
+ max := non_neg_integer(),
+ min := non_neg_integer()}.
+
-type sockaddr_un() :: #{family := local,
path := binary() | string()}.
-type sockaddr_in4() :: #{family := inet,
@@ -672,7 +678,7 @@
%% -define(SOCKET_OPT_SCTP_PEER_AUTH_CHUNKS, 26).
%% -define(SOCKET_OPT_SCTP_PRIMARY_ADDR, 27).
%% -define(SOCKET_OPT_SCTP_RESET_STREAMS, 28).
-%% -define(SOCKET_OPT_SCTP_RTOINFO, 29).
+-define(SOCKET_OPT_SCTP_RTOINFO, 29).
%% -define(SOCKET_OPT_SCTP_SET_PEER_PRIMARY_ADDR, 30).
%% -define(SOCKET_OPT_SCTP_STATUS, 31).
%% -define(SOCKET_OPT_SCTP_USE_EXT_RECVINFO, 32).
@@ -2226,7 +2232,21 @@ enc_setopt_value(sctp, events, #{data_in := DataIn,
enc_setopt_value(sctp, nodelay, V, _D, _T, P)
when is_boolean(V) andalso (P =:= sctp) ->
V;
+enc_setopt_value(sctp, rtoinfo, #{assoc_id := AssocId,
+ initial := Init,
+ max := Max,
+ min := Min} = V,
+ _D, _T, P)
+ when is_integer(AssocId) andalso
+ is_integer(Init) andalso (Init >= 0) andalso
+ is_integer(Max) andalso (Max >= 0) andalso
+ is_integer(Min) andalso (Min >= 0) andalso
+ (P =:= sctp) ->
+ V;
+enc_setopt_value(sctp = L, Opt, V, _D, _T, _P) ->
+ not_supported({L, Opt, V});
+%% Is this correct? What about getopt?
enc_setopt_value(L, Opt, V, _, _, _)
when is_integer(L) andalso is_integer(Opt) andalso is_binary(V) ->
V.
@@ -2672,8 +2692,8 @@ enc_sockopt_key(sctp = L, primary_addr = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, reset_streams = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(sctp = L, rtoinfo = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(sctp = _L, rtoinfo = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_SCTP_RTOINFO;
enc_sockopt_key(sctp = L, set_peer_primary_addr = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, status = Opt, _Dir, _D, _T, _P) ->
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index 56200e0ae9..7320192e6a 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -204,10 +204,12 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) ->
i("Miscellaneous options: "
"~n associnfo: ~s"
"~n autoclose: ~s"
- "~n disable-fragments: ~s",
+ "~n disable-fragments: ~s"
+ "~n rtoinfo: ~s",
[GO(associnfo),
GO(autoclose),
- GO(disable_fragments)]),
+ GO(disable_fragments),
+ GO(rtoinfo)]),
Events = #{data_in => true,
association => true,
address => true,