aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/nifs/common/socket_nif.c
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-19 17:34:15 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commit6bb60f1fecef368991806e25a0022c63b8650f39 (patch)
tree92eabb798b7d0813dfe65e4b0f9369ba99e08264 /erts/emulator/nifs/common/socket_nif.c
parent7a5b320b5bb5ec45b21839005e8538172908fb57 (diff)
downloadotp-6bb60f1fecef368991806e25a0022c63b8650f39.tar.gz
otp-6bb60f1fecef368991806e25a0022c63b8650f39.tar.bz2
otp-6bb60f1fecef368991806e25a0022c63b8650f39.zip
[socket-nif] Add (partial) support for socket (level sctp) option rtoinfo
Added support for the SCTP option RTOINFO. We have the same questions for this option as for ASSOCINFO. Maybe the assoc field shall be made 'out' only (that is, it will be ignored for setopt). The assoc id used will be that which is stored in the descriptor (how do we get it to begin with?). Questions, questions... OTP-14831
Diffstat (limited to 'erts/emulator/nifs/common/socket_nif.c')
-rw-r--r--erts/emulator/nifs/common/socket_nif.c194
1 files changed, 178 insertions, 16 deletions
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);