aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/doc/src/socket.xml3
-rw-r--r--erts/doc/src/socket_usage.xml7
-rw-r--r--erts/emulator/nifs/common/socket_nif.c198
-rw-r--r--erts/preloaded/ebin/socket.beambin55460 -> 56044 bytes
-rw-r--r--erts/preloaded/src/socket.erl57
5 files changed, 236 insertions, 29 deletions
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index f6b25c8563..fe23eaa138 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -141,6 +141,9 @@
<name name="sctp_assocparams"/>
</datatype>
<datatype>
+ <name name="sctp_initmsg"/>
+ </datatype>
+ <datatype>
<name name="sctp_rtoinfo"/>
</datatype>
</datatypes>
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 21f5d17e84..e90e682e39 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -487,6 +487,13 @@
<cell>none</cell>
</row>
<row>
+ <cell>initmsg</cell>
+ <cell>sctp_initmsg()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>none</cell>
+ </row>
+ <row>
<cell>maxseg</cell>
<cell>non_neg_integer()</cell>
<cell>yes</cell>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index e84eb7aa8e..e8e1df0842 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -263,43 +263,43 @@
*
#if defined(__GNUC__) && defined(HAVE_SCTP_BINDX)
-static typeof(sctp_bindx) *p_sctp_bindx = NULL;
+static typeof(sctp_bindx) *esock_sctp_bindx = NULL;
#else
-static int (*p_sctp_bindx)
+static int (*esock_sctp_bindx)
(int sd, struct sockaddr *addrs, int addrcnt, int flags) = NULL;
#endif
#if defined(__GNUC__) && defined(HAVE_SCTP_PEELOFF)
-static typeof(sctp_peeloff) *p_sctp_peeloff = NULL;
+static typeof(sctp_peeloff) *esock_sctp_peeloff = NULL;
#else
-static int (*p_sctp_peeloff)
+static int (*esock_sctp_peeloff)
(int sd, sctp_assoc_t assoc_id) = NULL;
#endif
#if defined(__GNUC__) && defined(HAVE_SCTP_GETLADDRS)
-static typeof(sctp_getladdrs) *p_sctp_getladdrs = NULL;
+static typeof(sctp_getladdrs) *esock_sctp_getladdrs = NULL;
#else
-static int (*p_sctp_getladdrs)
+static int (*esock_sctp_getladdrs)
(int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
#endif
#if defined(__GNUC__) && defined(HAVE_SCTP_FREELADDRS)
-static typeof(sctp_freeladdrs) *p_sctp_freeladdrs = NULL;
+static typeof(sctp_freeladdrs) *esock_sctp_freeladdrs = NULL;
#else
-static void (*p_sctp_freeladdrs)(struct sockaddr *addrs) = NULL;
+static void (*esock_sctp_freeladdrs)(struct sockaddr *addrs) = NULL;
#endif
#if defined(__GNUC__) && defined(HAVE_SCTP_GETPADDRS)
-static typeof(sctp_getpaddrs) *p_sctp_getpaddrs = NULL;
+static typeof(sctp_getpaddrs) *esock_sctp_getpaddrs = NULL;
#else
-static int (*p_sctp_getpaddrs)
+static int (*esock_sctp_getpaddrs)
(int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
#endif
#if defined(__GNUC__) && defined(HAVE_SCTP_FREEPADDRS)
-static typeof(sctp_freepaddrs) *p_sctp_freepaddrs = NULL;
+static typeof(sctp_freepaddrs) *esock_sctp_freepaddrs = NULL;
#else
-static void (*p_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
+static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
#endif
*/
@@ -546,6 +546,7 @@ typedef union {
#define SOCKET_OPT_SCTP_AUTOCLOSE 8
#define SOCKET_OPT_SCTP_DISABLE_FRAGMENTS 12
#define SOCKET_OPT_SCTP_EVENTS 14
+#define SOCKET_OPT_SCTP_INITMSG 18
#define SOCKET_OPT_SCTP_MAXSEG 21
#define SOCKET_OPT_SCTP_NODELAY 23
#define SOCKET_OPT_SCTP_RTOINFO 29
@@ -1235,6 +1236,11 @@ static ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(SCTP_INITMSG)
+static ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(SCTP_MAXSEG)
static ERL_NIF_TERM nsetopt_lvl_sctp_maxseg(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1469,6 +1475,10 @@ static ERL_NIF_TERM ngetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_sctp_maxseg(ErlNifEnv* env,
SocketDescriptor* descP);
#endif
+#if defined(SCTP_INITMSG)
+static ERL_NIF_TERM ngetopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(SCTP_NODELAY)
static ERL_NIF_TERM ngetopt_lvl_sctp_nodelay(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1830,6 +1840,9 @@ 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_attempts[] = "max_attempts";
+static char str_max_init_timeo[] = "max_init_timeo";
+static char str_max_instreams[] = "max_instreams";
static char str_max_rxt[] = "max_rxt";
static char str_min[] = "min";
static char str_multiaddr[] = "multiaddr";
@@ -1837,6 +1850,7 @@ 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_outstreams[] = "num_outstreams";
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";
@@ -1935,6 +1949,9 @@ 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_attempts;
+static ERL_NIF_TERM atom_max_init_timeo;
+static ERL_NIF_TERM atom_max_instreams;
static ERL_NIF_TERM atom_max_rxt;
static ERL_NIF_TERM atom_min;
static ERL_NIF_TERM atom_multiaddr;
@@ -1942,6 +1959,7 @@ 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_outstreams;
static ERL_NIF_TERM atom_num_peer_dests;
static ERL_NIF_TERM atom_num_pip;
static ERL_NIF_TERM atom_num_psctp;
@@ -5585,6 +5603,12 @@ ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
break;
#endif
+#if defined(SCTP_INITMSG)
+ case SOCKET_OPT_SCTP_INITMSG:
+ result = nsetopt_lvl_sctp_initmsg(env, descP, eVal);
+ break;
+#endif
+
#if defined(SCTP_MAXSEG)
case SOCKET_OPT_SCTP_MAXSEG:
result = nsetopt_lvl_sctp_maxseg(env, descP, eVal);
@@ -5745,8 +5769,8 @@ ERL_NIF_TERM nsetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
#if defined(SCTP_EVENTS)
static
ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
- SocketDescriptor* descP,
- ERL_NIF_TERM eVal)
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
{
ERL_NIF_TERM result;
ERL_NIF_TERM eDataIn, eAssoc, eAddr, eSndFailure;
@@ -5838,6 +5862,90 @@ ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
#endif
+/* nsetopt_lvl_sctp_initmsg - Level SCTP INITMSG option
+ */
+#if defined(SCTP_INITMSG)
+static
+ERL_NIF_TERM nsetopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ ERL_NIF_TERM eNumOut, eMaxIn, eMaxAttempts, eMaxInitTO;
+ struct sctp_initmsg initMsg;
+ int res;
+ size_t sz;
+ unsigned int tmp;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_initmsg -> 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_initmsg -> extract attributes\r\n") );
+
+ if (!GET_MAP_VAL(env, eVal, atom_num_outstreams, &eNumOut))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_max_instreams, &eMaxIn))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_max_attempts, &eMaxAttempts))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_max_init_timeo, &eMaxInitTO))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_initmsg -> decode attributes\r\n") );
+
+ if (!GET_UINT(env, eNumOut, &tmp))
+ return esock_make_error(env, esock_atom_einval);
+ initMsg.sinit_num_ostreams = (uint16_t) tmp;
+
+ if (!GET_UINT(env, eMaxIn, &tmp))
+ return esock_make_error(env, esock_atom_einval);
+ initMsg.sinit_max_instreams = (uint16_t) tmp;
+
+ if (!GET_UINT(env, eMaxAttempts, &tmp))
+ return esock_make_error(env, esock_atom_einval);
+ initMsg.sinit_max_attempts = (uint16_t) tmp;
+
+ if (!GET_UINT(env, eMaxInitTO, &tmp))
+ return esock_make_error(env, esock_atom_einval);
+ initMsg.sinit_max_init_timeo = (uint16_t) tmp;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_initmsg -> set initmsg option\r\n") );
+
+ res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_INITMSG,
+ &initMsg, sizeof(initMsg));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_initmsg -> done with"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ return result;
+
+}
+#endif
+
+
/* nsetopt_lvl_sctp_maxseg - Level SCTP MAXSEG option
*/
#if defined(SCTP_MAXSEG)
@@ -7614,6 +7722,12 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env,
break;
#endif
+#if defined(SCTP_INITMSG)
+ case SOCKET_OPT_SCTP_INITMSG:
+ result = ngetopt_lvl_sctp_initmsg(env, descP);
+ break;
+#endif
+
#if defined(SCTP_MAXSEG)
case SOCKET_OPT_SCTP_MAXSEG:
result = ngetopt_lvl_sctp_maxseg(env, descP);
@@ -7677,7 +7791,7 @@ ERL_NIF_TERM ngetopt_lvl_sctp_associnfo(ErlNifEnv* env,
if (res != 0) {
result = esock_make_error_errno(env, sock_errno());
} else {
- ERL_NIF_TERM eAssocParams;
+ 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),
@@ -7732,6 +7846,56 @@ ERL_NIF_TERM ngetopt_lvl_sctp_disable_fragments(ErlNifEnv* env,
#endif
+/* ngetopt_lvl_sctp_initmsg - Level SCTP INITMSG option
+ *
+ */
+#if defined(SCTP_INITMSG)
+static
+ERL_NIF_TERM ngetopt_lvl_sctp_initmsg(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ struct sctp_initmsg val;
+ SOCKOPTLEN_T valSz = sizeof(val);
+ int res;
+
+ SSDBG( descP, ("SOCKET", "ngetopt_lvl_sctp_initmsg -> entry\r\n") );
+
+ sys_memzero((char*) &val, valSz);
+ res = sock_getopt(descP->sock, IPPROTO_SCTP, SCTP_INITMSG, &val, &valSz);
+
+ if (res != 0) {
+ result = esock_make_error_errno(env, sock_errno());
+ } else {
+ ERL_NIF_TERM eInitMsg;
+ ERL_NIF_TERM keys[] = {atom_num_outstreams, atom_max_instreams,
+ atom_max_attempts, atom_max_init_timeo};
+ ERL_NIF_TERM vals[] = {MKUI(env, val.sinit_num_ostreams),
+ MKUI(env, val.sinit_max_instreams),
+ MKUI(env, val.sinit_max_attempts),
+ MKUI(env, val.sinit_max_init_timeo)};
+ 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, &eInitMsg))
+ return esock_make_error(env, esock_atom_einval);;
+
+ result = esock_make_ok2(env, eInitMsg);
+ }
+
+ SSDBG( descP,
+ ("SOCKET", "ngetopt_lvl_sctp_initmsg -> done with"
+ "\r\n res: %d"
+ "\r\n result: %T"
+ "\r\n", res, result) );
+
+ return result;
+}
+#endif
+
+
/* ngetopt_lvl_sctp_maxseg - Level SCTP MAXSEG option
*/
#if defined(SCTP_MAXSEG)
@@ -10050,6 +10214,9 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_interface = MKA(env, str_interface);
atom_local_rwnd = MKA(env, str_local_rwnd);
atom_max = MKA(env, str_max);
+ atom_max_attempts = MKA(env, str_max_attempts);
+ atom_max_init_timeo = MKA(env, str_max_init_timeo);
+ atom_max_instreams = MKA(env, str_max_instreams);
atom_max_rxt = MKA(env, str_max_rxt);
atom_min = MKA(env, str_min);
atom_multiaddr = MKA(env, str_multiaddr);
@@ -10057,6 +10224,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
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_outstreams = MKA(env, str_num_outstreams);
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);
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 41b4201090..c4c830e051 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 cadbf1131c..03c87a6df5 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -96,16 +96,30 @@
ipv6_pmtudisc/0,
sctp_event_subscribe/0,
sctp_assocparams/0,
+ sctp_initmsg/0,
sctp_rtoinfo/0,
- msg_hdr/0
+ msg_hdr/0,
+
+ uint8/0,
+ uint16/0,
+ uint20/0,
+ uint32/0
]).
+
+-type uint8() :: 0..16#FF.
+-type uint16() :: 0..16#FFFF.
+-type uint20() :: 0..16#FFFFF.
+-type uint32() :: 0..16#FFFFFFFF.
+
+
%% We support only a subset of all domains.
-type domain() :: local | inet | inet6.
%% We support only a subset of all types.
+%% RDM - Reliably Delivered Messages
-type type() :: stream | dgram | raw | rdm | seqpacket.
%% We support only a subset of all protocols:
@@ -117,8 +131,6 @@
-type ip4_address() :: {0..255, 0..255, 0..255, 0..255}.
--type uint20() :: 0..16#FFFFF.
--type uint32() :: 0..16#FFFFFFFF.
-type in6_flow_info() :: uint20().
-type in6_scope_id() :: uint32().
@@ -190,16 +202,22 @@
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()}.
+ max_rxt := uint16(),
+ num_peer_dests := uint16(),
+ peer_rwnd := uint32(),
+ local_rwnd := uint32(),
+ cookie_life := uint32()}.
+
+-type sctp_initmsg() :: #{num_outstreams := uint16(),
+ max_instreams := uint16(),
+ max_attempts := uint16(),
+ max_init_timeo := uint16()
+ }.
-type sctp_rtoinfo() :: #{assoc_id := integer(),
- initial := non_neg_integer(),
- max := non_neg_integer(),
- min := non_neg_integer()}.
+ initial := uint32(),
+ max := uint32(),
+ min := uint32()}.
-type sockaddr_un() :: #{family := local,
path := binary() | string()}.
@@ -667,7 +685,7 @@
%% -define(SOCKET_OPT_SCTP_EXPLICIT_EOR, 15).
%% -define(SOCKET_OPT_SCTP_FRAGMENT_INTERLEAVE, 16).
%% -define(SOCKET_OPT_SCTP_GET_PEER_ADDR_INFO, 17).
-%% -define(SOCKET_OPT_SCTP_INITMSG, 18).
+-define(SOCKET_OPT_SCTP_INITMSG, 18).
%% -define(SOCKET_OPT_SCTP_I_WANT_MAPPED_V4_ADDR, 19).
%% -define(SOCKET_OPT_SCTP_LOCAL_AUTH_CHUNKS, 20).
-define(SOCKET_OPT_SCTP_MAXSEG, 21).
@@ -2293,6 +2311,17 @@ enc_setopt_value(sctp, events, #{data_in := DataIn,
is_boolean(SndDry) andalso
(P =:= sctp) ->
V;
+enc_setopt_value(sctp, initmsg, #{num_outstreams := NumOut,
+ max_instreams := MaxIn,
+ max_attempts := MaxAttempts,
+ max_init_timeo := MaxInitTO} = V,
+ _D, _T, P)
+ when is_integer(NumOut) andalso (NumOut >= 0) andalso
+ is_integer(MaxIn) andalso (MaxIn >= 0) andalso
+ is_integer(MaxAttempts) andalso (MaxAttempts >= 0) andalso
+ is_integer(MaxInitTO) andalso (MaxInitTO >= 0) andalso
+ (P =:= sctp) ->
+ V;
enc_setopt_value(sctp, maxseg, V, _D, _T, P)
when is_integer(V) andalso (V >= 0) andalso (P =:= sctp) ->
V;
@@ -2737,8 +2766,8 @@ enc_sockopt_key(sctp = L, fragment_interleave = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, get_peer_addr_info = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(sctp = L, initmsg = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(sctp = _L, initmsg = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_SCTP_INITMSG;
enc_sockopt_key(sctp = L, i_want_mapped_v4_addr = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, local_auth_chunks = Opt, _Dir, _D, _T, _P) ->